百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术教程 > 正文

NamedParameterJdbcTemplate用法

csdh11 2024-11-30 14:14 4 浏览

  • jdbcTemplate.queryForObject方法入参不支持以Map的形式传递参数,需要按照sql语句中参数的顺序组织入参的List。
  • jdbcTemplate.queryForObject方法直接不支持的in查询。只支持Integer.class String.class 这种单数据类型的入参。
    • 例如:
    List<Long> idList = ...;
    String name = ...;
    StringBuilder idListSb = new StringBuilder();
    for(Long id : idList){
      idListSb.append(id + ",");
    }
    String sql = "select count(*) from user where id in (?) and name = ?";
    List<Object> objects = new ArrayList<>();
    objects.add(idListSb.toString().RTrim(','));
    object.add (name);
    jdbcTemplate.queryForObject(sb.toString(),objects,Long.class);

    而NamedParameterJdbcTemplate时,其本来就支持in查询和Map类型的入参。

    List<Long> idList = ...;
    String name = ...;
    String sql = "select * from user where id in (:ids) and name = :name";
    Map<String, Object> param  = new HashMap<>();
    param.put("ids", idList);
    param.put("name", name);
    namedParameterJdbcTemplate.queryForObject(sb.toString(),param,Long.class);

    一、JdbcTemplate

    Spring对数据库的操作在jdbc上面做了深层次的封装,提供了一个 Jdbc Template 类,我们可以直接使用。只需要把DataSource注册到JdbcTemplate之中,其全限定命名为org.springframework.jdbc.core.JdbcTemplate。要使用JdbcTemlate一般还需要事务和异常的控制。

    JdbcTemplate的几类方法

    • execute方法:可以用于执行任何SQL语句,一般用于执行DDL语句;
    • update方法及batchUpdate方法:update方法用于执行新增、修改、删除等语句;batchUpdate方法用于执行批处理相关语句;
    • query方法及queryForXXX方法:用于执行查询相关语句;
    • call方法:用于执行存储过程、函数相关语句。

    JdbcTemplate的常用方法

    //update操作单个增删改
    int update(String sql,Object[] args)
    int update(String sql,Objcet... args)
    
    //batchUpdate批量增删改
    int[] batchUpdate(String[] sql)
    int[] batchUpdate(String sql,List<Object[]>)
    
    //单个简单查询
    T queryForObjcet(String sql,Class<T> type)
    T queryForObjcet(String sql,Object[] args,Class<T> type)
    T queryForObjcet(String sql,Class<T> type,Object... arg)
    
    //获取多个
    List<T> queryForList(String sql,Class<T> type)
    List<T> queryForList(String sql,Object[] args,Class<T> type)
    List<T> queryForList(String sql,Class<T> type,Object... arg)

    查询复杂对象(封装为Map)

    //获取单个
    Map queryForMap(String sql)
    Map queryForMap(String sql,Objcet[] args)
    Map queryForMap(String sql,Object... arg)
    
    //获取多个
    List<Map<String,Object>> queryForList(String sql)
    List<Map<String,Object>> queryForList(String sql,Obgject[] args)
    List<Map<String,Object>> queryForList(String sql,Obgject... arg)

    查询复杂对象(封装为实体对象)

    Spring JdbcTemplate是通过实现org.springframework.jdbc.core.RowMapper这个接口来完成对entity对象映射。

    //获取单个
    T queryForObject(String sql,RowMapper<T> mapper)
    T queryForObject(String sql,object[] args,RowMapper<T> mapper)
    T queryForObject(String sql,RowMapper<T> mapper,Object... arg)
    
    //获取多个
    List<T> query(String sql,RowMapper<T> mapper)
    List<T> query(String sql,Object[] args,RowMapper<T> mapper)
    List<T> query(String sql,RowMapper<T> mapper,Object... arg)

    Spring JDBC中目前有两个主要的RowMapper实现,使用它们应该能解决大部分的场景了:SingleColumnRowMapper和BeanPropertyRowMapper。
    SingleColumnRowMapper:返回单列数据
    BeanPropertyRowMapper:当查询数据库返回的是多列数据,且需要将这些多列数据映射到某个具体的实体类上。

    //示例:
    String sql = "select name from test_student where id = ?";
    jdbcTemplate.queryForObject(sql, new Object[]{id}, new SingleColumnRowMapper<>(String.class));
    
    String sql = "select name, gender from test_student where name = ?";
    jdbcTemplate.queryForObject(sql, new Object[]{name},new BeanPropertyRowMapper<>(Student.class));
    • 定义自己的RowMapper

    如果你SQL查询出来的数据列名就是和实体类的属性名不一样,或者想按照自己的规则来装配实体类,那么就可以定义并使用自己的Row Mapper。

    //自定义
    public class StudentRowMapper implements RowMapper<Student> {
    
        @Override
        public Student mapRow(ResultSet rs, int i) throws SQLException {
            Student student = new Student();
            student.setName(rs.getString("name"));
            student.setGender(rs.getString("gender"));
            student.setEmail(rs.getString("email"));
            return student;
        }
    }
    
    //使用
    String sql = "select name, gender, email from test_student where name = ?";
    jdbcTemplate.queryForObject(sql, new Object[]{name}, new StudentRowMapper());

    批量修改

    public int[] batchInsert(List<Map<String, Object>> dataList) {
        String sql = "INSERT INTO test_info(name, create_time, age) VALUES(?, NOW(), ?)";
        List<Object[]> paramArray = new ArrayList<>();
        for (Map<String, Object> dataInfo : dataList) {
            Object[] obj = new Object[2];
            obj[0] = dataInfo.get("name");
            obj[1] = dataInfo.get("age");
            paramArray.add(obj);
        }
        if (CollectionUtils.isNotEmpty(paramArray)) {
            return jdbcTemplate.batchUpdate(sql, paramArray);
        }
        return new int[0];
    }

    JdbcTemplate支持的回调类

    预编译语句及存储过程创建回调:用于根据JdbcTemplate提供的连接创建相应的语句

    PreparedStatementCreator:通过回调获取JdbcTemplate提供的Connection,由用户使用该Conncetion创建相关的PreparedStatement;
    CallableStatementCreator:通过回调获取JdbcTemplate提供的Connection,由用户使用该Conncetion创建相关的CallableStatement;

    import java.sql.Connection;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.dao.DataAccessException;
    import org.springframework.jdbc.core.JdbcTemplate;
    import org.springframework.jdbc.core.PreparedStatementCallback;
    import org.springframework.jdbc.core.PreparedStatementCreator;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    
    @RunWith(SpringJUnit4ClassRunner.class) // 关联Spring与Junit
    @ContextConfiguration(locations = { "classpath:applicationContext.xml" }) // 加载配置spring配置文件
    public class AppTest {
    
        @Autowired
        private JdbcTemplate jdbcTemplate;
    
        @Test
        public void testPpreparedStatement1() {
            int count = jdbcTemplate.execute(new PreparedStatementCreator() {
                public java.sql.PreparedStatement createPreparedStatement(Connection conn) throws SQLException {
                    return conn.prepareStatement("select count(*) from user");
                }
            }, new PreparedStatementCallback<Integer>() {
                public Integer doInPreparedStatement(java.sql.PreparedStatement pstmt)
                        throws SQLException, DataAccessException {
                    pstmt.execute();
                    ResultSet rs = pstmt.getResultSet();
                    rs.next();
                    return rs.getInt(1);
                }
            });
            System.out.println(count);
        }
    }

    首先使用PreparedStatementCreator创建一个预编译语句,其次由JdbcTemplate通过PreparedStatementCallback回调传回,由用户决定如何执行该PreparedStatement。此处我们使用的是execute方法。

    预编译语句设值回调:用于给预编译语句相应参数设值

    PreparedStatementSetter:通过回调获取JdbcTemplate提供的PreparedStatement,由用户来对相应的预编译语句相应参数设值;
    BatchPreparedStatementSetter:;类似于PreparedStatementSetter,但用于批处理,需要指定批处理大小;

    import java.sql.PreparedStatement;
    import java.sql.SQLException;
    import org.junit.Assert;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.jdbc.core.JdbcTemplate;
    import org.springframework.jdbc.core.PreparedStatementSetter;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    
    @RunWith(SpringJUnit4ClassRunner.class) // 关联Spring与Junit
    @ContextConfiguration(locations = { "classpath:applicationContext.xml" }) // 加载配置spring配置文件
    public class AppTest {
    
        @Autowired
        private JdbcTemplate jdbcTemplate;
    
        @Test
        public void testPreparedStatement2() {
            String insertSql = "insert into user(user_name) values (?)";
            int count = jdbcTemplate.update(insertSql, new PreparedStatementSetter() {
                public void setValues(PreparedStatement pstmt) throws SQLException {
                    pstmt.setObject(1, "mmNN");
                }
            });
            Assert.assertEquals(1, count);
            String deleteSql = "delete from user where user_name=?";
            count = jdbcTemplate.update(deleteSql, new Object[] { "mmNN" });
            Assert.assertEquals(1, count);
        }
    }

    通过JdbcTemplate的int update(String sql, PreparedStatementSetter pss)执行预编译sql,其中sql参数为“insert into user(user_name) values (?) ”,该sql有一个占位符需要在执行前设值,PreparedStatementSetter实现就是为了设值,使用setValues(PreparedStatement pstmt)回调方法设值相应的占位符位置的值。JdbcTemplate也提供一种更简单的方式“update(String sql, Object... args)”来实现设值,所以只要当使用该种方式不满足需求时才应使用PreparedStatementSetter。

    自定义功能回调:提供给用户一个扩展点,用户可以在指定类型的扩展点执行任何数量需要的操作

    ConnectionCallback:通过回调获取JdbcTemplate提供的Connection,用户可在该Connection执行任何数量的操作;
    StatementCallback:通过回调获取JdbcTemplate提供的Statement,用户可以在该Statement执行任何数量的操作;
    PreparedStatementCallback:通过回调获取JdbcTemplate提供的PreparedStatement,用户可以在该PreparedStatement执行任何数量的操作;
    CallableStatementCallback:通过回调获取JdbcTemplate提供的CallableStatement,用户可以在该CallableStatement执行任何数量的操作;

    结果集处理回调:通过回调处理ResultSet或将ResultSet转换为需要的形式

    RowMapper:用于将结果集每行数据转换为需要的类型,用户需实现方法mapRow(ResultSet rs, int rowNum)来完成将每行数据转换为相应的类型。
    RowCallbackHandler:用于处理ResultSet的每一行结果,用户需实现方法processRow(ResultSet rs)来完成处理,在该回调方法中无需执行rs.next(),该操作由JdbcTemplate来执行,用户只需按行获取数据然后处理即可。
    ResultSetExtractor:用于结果集数据提取,用户需实现方法extractData(ResultSet rs)来处理结果集,用户必须处理整个结果集;

    @Test
    public void testResultSet1() {
        jdbcTemplate.update("insert into user(user_name) values('name7')");
        String listSql = "select * from user where user_name=?";
        List result = jdbcTemplate.query(listSql,new Object[]{"name7"}, new RowMapper<Map>() {
            public Map mapRow(ResultSet rs, int rowNum) throws SQLException {
                Map row = new HashMap();
                row.put(rs.getInt("user_id"), rs.getString("user_name"));
                return row;
            }
        });
        Assert.assertEquals(1, result.size());//查询结果数量为1才向下执行
        jdbcTemplate.update("delete from user where user_name='name7'");
    }

    RowMapper接口提供mapRow(ResultSet rs, int rowNum)方法将结果集的每一行转换为一个Map,当然可以转换为其他类。

    @Test
    public void testResultSet2() {
        jdbcTemplate.update("insert into user(user_name) values('name5')");
        String listSql = "select * from user";
        final List result = new ArrayList();
        jdbcTemplate.query(listSql, new RowCallbackHandler() {
            public void processRow(ResultSet rs) throws SQLException {
                Map row = new HashMap();
                row.put(rs.getInt("user_id"), rs.getString("user_name"));
                result.add(row);
            }
        });
        Assert.assertEquals(1, result.size());
        jdbcTemplate.update("delete from user where user_name='name5'");
    }

    RowCallbackHandler接口也提供方法processRow(ResultSet rs),能将结果集的行转换为需要的形式。

    @Test
    public void testResultSet3() {
        jdbcTemplate.update("insert into test(name) values('name5')");
        String listSql = "select * from test";
        List result = jdbcTemplate.query(listSql, new ResultSetExtractor<List>() {
            public List extractData(ResultSet rs) throws SQLException, DataAccessException {
                List result = new ArrayList();
                while (rs.next()) {
                    Map row = new HashMap();
                    row.put(rs.getInt("id"), rs.getString("name"));
                    result.add(row);
                }
                return result;
            }
        });
        Assert.assertEquals(0, result.size());
        jdbcTemplate.update("delete from test where name='name5'");
    }

    ResultSetExtractor使用回调方法extractData(ResultSet rs)提供给用户整个结果集,让用户决定如何处理该结果集。

    当然JdbcTemplate提供更简单的queryForXXX方法,来简化开发:

    //1.查询一行数据并返回int型结果  
    jdbcTemplate.queryForInt("select count(*) from test");  
    //2. 查询一行数据并将该行数据转换为Map返回  
    jdbcTemplate.queryForMap("select * from test where name='name5'");  
    //3.查询一行任何类型的数据,最后一个参数指定返回结果类型  
    jdbcTemplate.queryForObject("select count(*) from test", Integer.class);  
    //4.查询一批数据,默认将每行数据转换为Map       
    jdbcTemplate.queryForList("select * from test");  
    //5.只查询一列数据列表,列类型是String类型,列名字是name  
    jdbcTemplate.queryForList("  
    select name from test where name=?", new Object[]{"name5"}, String.class);  
    //6.查询一批数据,返回为SqlRowSet,类似于ResultSet,但不再绑定到连接上  
    SqlRowSet rs = jdbcTemplate.queryForRowSet("select * from test");  

    返回新增的自增ID

    @Test
    public void test(){
    
        String sql = "insert into sp_user(name) values (?)";
        KeyHolder keyHolder = new GeneratedKeyHolder();
        jdbcTemplate.update(new PreparedStatementCreator() {
    
            @Override
            public PreparedStatement createPreparedStatement(Connection connection) throws SQLException {
                // 设置返回的主键字段名
                PreparedStatement ps = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
                ps.setString(1, "harvey");
                return ps;
            }
        }, keyHolder);
        // 获取到插入数据生成的ID
        int num = keyHolder.getKey().intValue();
        System.out.println(num);
    }

    二、NamedParameterJdbcTemplate

    什么是具名参数

    在经典的 JDBC 用法中, SQL 参数是用占位符 ? 表示,并且受到位置的限制。定位参数的问题在于, 一旦参数的顺序发生变化, 就必须改变参数绑定。
    在 Spring JDBC 框架中, 绑定 SQL 参数的另一种选择是使用具名参数(named parameter)。

    具名参数:SQL 按名称(以冒号开头)而不是按位置进行指定,具名参数更易于维护,,也提升了可读性。具名参数由框架类在运行时用占位符取代,
    具名参数只在 NamedParameterJdbcTemplate 中得到支持。

    NamedParameterJdbcTemplate类拓展了JdbcTemplate类,可以使用全部jdbcTemplate方法。

    NamedParameterJdbcTemplate主要提供以下三类方法:execute方法、query及queryForXXX方法、update及batchUpdate方法。

    NamedParameterJdbcTemplate可以使用DataSource或JdbcTemplate 对象作为构造器参数初始化。

    常用API传入参数类型介绍

    NamedParameterJdbcTemplate类为命名参数设值有两种方式:java.util.Map 、RowMapper 和 SqlParameterSource。

    Map<String,?> paramMap

    就是一个hash表,好处是可以根据参数名传参,paramMap.put("sqlparamName",value)。

    RowMapper rowMapper

    这个接口为了实现sql查询结果和对象间的转换,可以自己实现,也可以使用系统实现,主要实现类有:

    • SingleColumnRowMapper ,sql结果为一个单列的数据,如List<String> , List<Integer>,String,Integer等
    • BeanPropertyRowMapper, sql结果匹配到对象 List< XxxVO> , XxxVO

    SqlParameterSource

    其作用和Map一样,就是为sql中的条件参数赋值,默认实现有 :

    • MapSqlParameterSource实现非常简单,只是封装了java.util.Map。
    • BeanPropertySqlParameterSource封装了一个JavaBean对象,通过JavaBean对象属性来决定命名参数的值。
    • EmptySqlParameterSource 一个空的SqlParameterSource ,常用来占位使用。
    //BeanPropertySqlParameterSource传参方式
    SqlParameterSource sps = new BeanPropertySqlParameterSource(javaBean);
    
    //MapSqlParameterSource传参方式
    SqlParameterSource sps = new MapSqlParameterSource();
    //保证参数名和key相同
    sps.addValue("key",value);

    API介绍

    查询

    返回单行单列数据

    public < T > T queryForObject(String sql, Map<String, ?> paramMap, Class<T> requiredType)
    public < T > T queryForObject(String sql, SqlParameterSource paramSource, Class<T> requiredType)

    Integer count = template.queryForObject("select count(*) from student", new HashMap<>(), Integer.class);
    String name = template.queryForObject( "select name from student where home_address  limit 1 ", EmptySqlParameterSource.INSTANCE, String.class); 

    返回 (多行)单列 数据

    public < T> List< T> queryForList(String sql, Map<String, ?> paramMap, Class< T > elementType)
    public < T> List< T> queryForList(String sql, SqlParameterSource paramSource, Class< T> elementType)

    List< String> namelist = template.queryForList("select name from student", new HashMap<>(), String.class);

    返回单行数据

    public < T> T queryForObject(String sql, Map< String, ?> paramMap, RowMapper< T>rowMapper)
    public < T> T queryForObject(String sql, SqlParameterSource paramSource, RowMapper< T> rowMapper)

    Student  stu = template.queryForObject(
                    "select * from student limit 1", new HashMap<>(), new BeanPropertyRowMapper<Student>(Student.class));
    //BeanPropertyRowMapper会把下划线转化为驼峰属性
    //结果对象可比实际返回字段多或者少

    注意:这两个API也可以使用SingleColumnRowMapper返回单行单列数据

    String name = template.queryForObject(
                    "select name from student limit 1", EmptySqlParameterSource.INSTANCE, new SingleColumnRowMapper<>(String.class));

    返回Map形式的单行数据

    public Map< String, Object> queryForMap(String sql, Map< String, ?> paramMap)
    public Map< String, Object> queryForMap(String sql, SqlParameterSource paramSource)

    Map< String, Object> studentMap = template.queryForMap("select * from student limit 1", new HashMap<>());

    注意:queryForMap这个方法要求结果必须是有数据的,否则会报错。

    返回多行数据

    public < T> List< T> query(String sql, Map< String, ?> paramMap, RowMapper< T> rowMapper)
    public < T> List< T> query(String sql, SqlParameterSource paramSource, RowMapper< T> rowMapper)
    public < T> List< T> query(String sql, RowMapper< T> rowMapper)

    List< Student> studentList = template.query(
                    "select * from student",  
                    new BeanPropertyRowMapper<>(Student.class)
    );     

    同理,也可以使用SingleColumnRowMapper返回单行列表List< String>,List< Integer>等。

    返回多行数据(Map)

    public List< Map< String, Object>> queryForList(String sql, Map< String, ?> paramMap)
    public List< Map< String, Object>> queryForList(String sql, SqlParameterSource paramSource)

    List<Map<String, Object>> mapList = template.queryForList(
                    "select * from student", new HashMap<>());

    插入/修改/删除数据,使用updateXXX方法

    使用Map作为参数

    int update(String sql, Map<String, ?> paramMap)

    Map<String, Object> paramMap = new HashMap<>();
    paramMap.put("id", UUID.randomUUID().toString());
    paramMap.put("name", "小明");
    paramMap.put("age", 33);
    paramMap.put("homeAddress", "乐山");
    paramMap.put("birthday", new Date());
    template.update( 
         "insert into student(id,name,age,home_address,birthday) values (:id,:name,:age,:homeAddress,:birthday)",
         paramMap
    );

    使用SqlParameterSource作为参数

    int update(String sql, SqlParameterSource paramSource)

    //使用 BeanPropertySqlParameterSource作为参数
    StudentDTO dto=new StudentDTO();//这个DTO为传入数据
    dto.setId(UUID.randomUUID().toString());
    dto.setName("小红");
    dto.setHomeAddress("成都");
    //------------------------------
    template.update("insert into student(id,name,home_address) values (:id,:name,:homeAddress)",
                    new BeanPropertySqlParameterSource(dto));
    
    
    //使用MapSqlParameterSource 作为参数
    MapSqlParameterSource mapSqlParameterSource = new MapSqlParameterSource()
            .addValue("id", UUID.randomUUID().toString())
            .addValue("name", "小王")
            .addValue("homeAddress", "美国");
    template.update("insert into student(id,name,home_address) values    
                       (:id,:name,:homeAddress)",mapSqlParameterSource);

    开发中尽量使用NamedParameterJdbcTemplate代替JdbcTemplate,如果想使用JdbcTemplate,也可以通过NamedParameterJdbcTemplate#getJdbcOperations()获取

    不建议使用查询结构为Map的API

    相关推荐

    Micheal Nielsen&#39;s神经网络学习之二

    依然是跟着MichaelNielsen的神经网络学习,基于前一篇的学习,已经大概明白了神经网络的基本结构和BP算法,也能通过神经网络训练数字识别功能,之后我试验了一下使用神经网络训练之前的文本分类,...

    CocoaPods + XCTest进行单元测试 c单元测试工具

    在使用XCTest进行单元测试时,我们经常会遇到一些CocoaPods中的开源框架的调用,比如“Realm”或“Alamofire”在测试的时候,如果配置不当,会导致“frameworknotfo...

    Java基础知识回顾第四篇 java基础讲解

    1、&和&&的区别作为逻辑运算符:&(不管左边是什么,右边都参与运算),&&(如果左边为false,右边则不参与运算,短路)另外&可作为位运算符...

    项目中的流程及类似业务的设计模式总结

    说到业务流程,可能是我做过的项目中涉及业务最多的一个方面了。除了在流程设计之外,在一些考核系统、产业审批、还有很多地方,都用到相似的设计思路,在此一并总结一下。再说到模式,并不是因为流行才用这个词,而...

    联想三款显示器首批获得 Eyesafe Certified 2.0 认证

    IT之家7月31日消息,据外媒报道,三款全新联想显示器是全球首批满足EyesafeCertified2.0的设备。据报道,联想获得EyesafeCertified2.0认证的显...

    maven的生命周期,插件介绍(二) 一个典型的maven构建生命周期

    1.maven生命周期一个完整的项目构建过程通常包括清理、编译、测试、打包、集成测试、验证、部署等步骤,Maven从中抽取了一套完善的、易扩展的生命周期。Maven的生命周期是抽象的,其中的具体任务都...

    多线程(3)-基于Object的线程等待与唤醒

    概述在使用synchronized进行线程同步中介绍了依赖对象锁定线程,本篇文章介绍如何依赖对象协调线程。同synchronized悲观锁一样,线程本身不能等待与唤醒,也是需要对象才能完成等待与唤醒的...

    jquery mobile + 百度地图 + phonegap 写的一个&quot;校园助手&quot;的app

    1jquerymobile+百度地图+phonegap写的一个"校园助手"的app,使用的是基于Flat-UI的jQueryMobile,请参考:https://github.com/...

    Apache 服务启动不了 apache系统服务启动不了

    {我是新手,从未遇到此问题,请各位大大勿喷}事由:今天早上上班突然发现公司网站出现问题。经过排查,发现是Apache出现问题。首先检查配置文件没有出问题后,启动服务发现Apache服务能启动,但是没法...

    健康债和技术债都不能欠 公众号: 我是攻城师(woshigcs)

    在Solr4.4之后,Solr提供了SolrCloud分布式集群的模式,它带来的主要好处是:(1)大数据量下更高的性能(2)更好扩展性(3)更高的可靠性(4)更简单易用什么时候应该使用Sol...

    Eye Experience怎么用?HTC告诉你 eyebeam怎么用

    IT之家(www.ithome.com):EyeExperience怎么用?HTC告诉你HTC上周除了发布HTCDesireEYE自拍机和HTCRE管状运动相机之外,还发布了一系列新的智能手机...

    Android系统应用隐藏和应用禁止卸载

    1、应用隐藏与禁用Android设置中的应用管理器提供了一个功能,就是【应用停用】功能,这是针对某些系统应用的。当应用停用之后,应用的图标会被隐藏,但apk还是存在,不会删除,核心接口就是Packag...

    计算机软件技术分享--赠人玫瑰,手遗余香

    一、Netty介绍Netty是由JBOSS提供的一个java开源框架。Netty提供异步的、事件驱动的网络应用程序框架和工具,用以快速开发高性能、高可靠性的网络服务器和客户端程序。也就是说,Netty...

    Gecco爬虫框架的线程和队列模型 爬虫通用框架

    简述爬虫在抓取一个页面后一般有两个任务,一个是解析页面内容,一个是将需要继续抓取的url放入队列继续抓取。因此,当爬取的网页很多的情况下,待抓取url的管理也是爬虫框架需要解决的问题。本文主要说的是g...

    一点感悟(一) 初识 初读感知的意思

    时间过得很快,在IT业已从业了两年多。人这一辈子到底需要什么,在路边看着人来人往,大部分人脸上都是很匆忙。上海真是一个魔都,它有魅力,有底蕴,但是一个外地人在这里扎根置业,真的是举全家之力,还贷3...