三层架构

1、什么是三层架构?

  • 在项目开发中,遵循的一种形式模式,分为三层

    • 界面层:用啦接受客户端的输入,调用业务逻辑层进行功能处理,返回结果给客户端,过去的servlet就是界面层的功能
    • 业务逻辑层:用来进行整个项目的业务逻辑处理,向上为界面层提供处理结果,向下问数据访问层要数据
    • 数据访问层:专门用来进行数据库的增删查改操作,向上为业务逻辑层提供数据
  • 各层之间的调用顺序是固定的,不允许跨层访问
    • 界面层<—->业务逻辑层<—–>数据访问层

SSM框架

常用的况框架SSM

  • Spring:它是整合其他框架的框架,它的核心是IOC和AOP,它由20多个模块构成的,在很多领域都提供了很好的解决方案,是一个很强大的存在

  • SpriingMVC:他是Spring家族的医院,专门用来优化控制器(Servlet)的,提供了极其简单数据提交,数据携带,页面跳转等功能

  • MyBatis:是持久化层的一个框架,用来进行数据库的访问哟话,专注于SQL语句,极大的简化了JDBC的访问

什么是框架?

  • 它是一个半成品软件,将所有的公共的,重复的功能解决掉,帮助程序员快速高效的进行开发,他是可复用的,可扩展的

什么是MyBatis框架

  • 是Apache的一个开源项目iBatis

  • MyBaits最主要用来完成数据访问层的优化,它专注于sql语句,简化了过去JDBC繁琐的访问机制

  • 添加框架的步骤

    • 添加依赖
    • 添加配置
    • 创建ssm数据库,添加student表,并且插入数据
create database ssm default charset utf8;
use ssm;
create table student(
id int(11) AUTO_INCREMENT primary key,
name varchar(255) default null,
email varchar(255) default null,
age int(11) default null
) ENGINE=InnoDB default charset=utf8;
insert into student(name,email,age) values("张三",'zhangsan@126.com',22);
insert into student(name,email,age) values("李四",'lisi@126.com',21);
insert into student(name,email,age) values("王五",'wangwu@126.com',22);
insert into student(name,email,age) values("赵六",'zhaoliu@126.com',24);
select * from student;

配置SqlMapConfig.xml文件

<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0/EN""http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration><!--读取属性文件,jdbc.properties属性:resource:从resource目录下找执行名称的文件加载url:使用绝对路径加载属性文件--><properties resource="jdbc.properties"></properties><!--配置数据库环境变量(数据库连接配置)--><!--environments里面可以配置多套environmentdefault:使用下面的environment标签的id属性进行执行配置--><environments default="development"><!--id:就是提供给environment的default属性是有--><environment id="development"><!--配置事务管理器type属性:指定事务管理的方式   JDBC:事务的控制交托给程序员处理MANAGED:由容器(Spring)来管理事务--><transactionManager type="JDBC"></transactionManager><!--配置数据源type:指定不同的配置方式JNDI:Java命名目录接口,在服务器端进行数据库连接池的管理POOLED:使用数据库连接池进行数据库的连接配置UNPOLLED:不使用数据库连接池--><dataSource type="POOLED"><!--配置数据库连接的基本参数--><property name="driver" value="${jdbc.driverClassName}"/><property name="url" value="${jdbc.url}"/><property name="username" value="${jdbc.username}"/><property name="password" value="${jdbc.password}"/></dataSource></environment></environments><!--注册mapper.xml文件resource:从resource目录下找指定名称文件注册url:使用绝对路径找文件注册class:动态代理方式下的注册--><mappers><mapper resource="StudentMapper.xml"></mapper></mappers></configuration>

配置StudentMapper.xml文件

<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0/EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--
mapper:是整个文件的大标签,用来开始和结束xml
属性:namespace:指定命名空间(相当于包名),用来区分不同mapper.xml文件中相同的id属性
-->
<mapper namespace="su"><!--完成查询全部学生的功能resultType:指定查询返回结果集的类型,如果是集合,则必须是泛型的类型parameterType:如果有参数,则通过它来指定参数类型--><select id="getAll" resultType="com.bjpowernode.pojo.Student">select id,name,email,agefrom student</select>
</mapper>

测试

        //使用文件流的读取核心配置文件SqlMapConfigInputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");//创建SqlSessionFactory工厂SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);//取出SqlSession的对象SqlSession sqlSession = factory.openSession();//完成查询操作List<Student> list = sqlSession.selectList("su.getAll");list.forEach(student -> System.out.println(student));//关闭SqlSessionsqlSession.close();

使用mybatis进行增删查改

SqlMapConfig配置文件

    <!--按主键id查询学生信息--><select id="getById" parameterType="int" resultType="com.bjpowernode.pojo.Student">select id,name,email,age from student where id=#{id}</select><!--按学生名称模糊查询--><select id="getByName" parameterType="string" resultType="com.bjpowernode.pojo.Student">select id,name,email,age from student where name  like '%${name}%'</select><!--增加学生--><insert id="insert" parameterType="com.bjpowernode.pojo.Student">insert into student(name,email,age) values (#{name},#{email},#{age})</insert><!--按主键删除学生--><delete id="delete" parameterType="int">delete from student where id = #{id}</delete><!--修改学生--><update id="update" parameterType="com.bjpowernode.pojo.Student">update student set name=#{name},email=#{email},age=#{age} where id = #{id}</update>

测试程序

//读取核心配置文件
InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
//创建SqlSessionFactory工厂对象
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
//取出SqlSession
SqlSession sqlSession = factory.openSession();//完成查询操作List<Student> list = sqlSession.selectList("su.getAll");list.forEach(student -> System.out.println(student));/*for (Student x : list){System.out.println(x);}*///关闭SqlSessionsqlSession.close();//按主键查询学生Student stu = sqlSession.selectOne("su.getById",1);System.out.println(stu);//关闭SqlSessionsqlSession.close();
//执行模糊查询List<Student> list = sqlSession.selectList("su.getByName","李");for (Student x : list){System.out.println(x);}//list.forEach(student -> System.out.println(student));//关闭SqlSessionsqlSession.close();
//增加学生int num = sqlSession.insert("su.insert", new Student("苏叶", "210469@qq.com", 21));sqlSession.commit();sqlSession.close();
//删除学生int delete = sqlSession.delete("su.delete", 5);sqlSession.commit();sqlSession.close();
//修改学生int update = sqlSession.update("su.update", new Student(2, "王麻子", "wm@126.com", 18));sqlSession.commit();sqlSession.close();

注意:执行增删改语句一定要提交事务

Mybatis对象分析

1、Resources类

  • 就是解析SqlMapConfig.xml文件,创建出相应的对象
  • InputStream in = Resources.getResourceAsStream(“SqlMapConfig.xml”);

2、SqlSessionFactoryBuilder接口

  • 使用ctrl+h查看本接口的子接口及实现类
  • DefaultSqlSessionFactory是实现类
  • SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);

3、SqlSession接口

  • DefaultSqlSession实现类
  • SqlSession sqlSession = factory.openSession();

为实体类注册别名

1、单个注册

在SqlMapConfig.xml文件中properties 标签后 environments 前面加入标签,注册之后就可以在Mapper.xml文件中的resultType属性或者parameterType属性中使用这个别名

    <!--注册实体类的别名--><typeAliases><!--单个注册--><typeAlias type="com.bjpowernode.pojo.Student" alias="student"></typeAlias></typeAliases>

2、批量注册

        <!--批量注册别名别名是类名的驼峰命名规范--><package name="com.bjpowernode.pojo"/>

批量把这个目录下的所有实体类都注册别名,别名是类名的驼峰命名规范

输出日志:固定的写法

    <!--设置日志输出底层执行的代码--><settings><setting name="logImpl" value="STDOUT_LOGGING"/></settings>

动态代理

1、动态代理存在的意义

  • 在三层架构中,业务逻辑层需要通过接口访问数据访问层的功能,可以使用动态代理

2、动态代理的实现规范

  • UserMapper.xml文件与UserMapper.java的接口必须在同一个目录。
  • UserMapper.xml文件与UserMapper.java接口的文件名必须一致,后缀可以不管
  • UserMapper.xml文件中的标签id的值与UserMapper.java的接口中方法名称完全一致
  • UserMapper.xml文件中的标签的parameterType属性值与UserMapper.java的接口中方法参数类型完全一致
  • UserMapper.xml文件中标签的resultType值与UserMapper.java的接口方法的返回值类型必须一致
  • UserMapper.xml文件中标签的namespace属性必须是接口的完全限定名称,例如com.bjpowernode.mapper.UserMapper
  • 在SqlMapConfig.xml文件中注册mapper文件时,使用class=接口的完全限定名称,例如com.bjpowernode.mapper.UserMapper

3、动态代理的访问

InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);sqlSession = factory.openSession();uMapper = sqlSession.getMapper(UsersMapper.class);//直接调用方法List<Users> list = uMapper.getAll();for(Users x : list){System.out.println(x);}}
//
//原来的方式public void testGetAll() throws IOException {//完成查询操作//只能通过namespace标注下id的值来调用方法,而且不同的语句使用不同的sqlsession方法List<Student> list = sqlSession.selectList("su.getAll");list.forEach(student -> System.out.println(student));}

使用动态代理的方式进行获取数据

#{}和${}的区别

#{}占位符

  • 传参的时候大部分使用#{}传参,它的底层使用的是PreparedStatement对象,是安全的数据库访问,防止sql注入

  • #{}里面写什么东西,主要看parameterType参数的类型

    • 如果parameterType的类型是简单类型(8种基本(封装)+String),则#{}里面随便写
 <select id="getById" resultType="users" parameterType="int"> >入参类型是简单类型select id,username,birthday,sex,address from users where id = #{id} >这个里面可以随便写</select>
  • parameterType的类型如果是实体类型,则#{}里面只能是类中的成员变量的名称,并且区分大小写
<insert id="add" parameterType="users">insert into users(username,birthday,sex,address) values(#{userName},#{birthday},#{sex},#{address})</insert>

${}字符串拼接或字符串替换

  • 字符串拼接,一般用于模糊查询中,建议少用,因为有sql注入的风险

  • 也分为两种情况,同样看parameterType类型

    • 如果parameterType类型是简单类型,则${}里面随便写,但是分版本,如果是3.5.1及以下版本,只能写value
<select id="getByLike" parameterType="string" resultType="users">  >传参是简单类型select id,username,birthday,sex,address from users where username like '%${userName}%'    >${}里面可以随便写</select>
  • parameterType的类型如果是实体类型,则${}里面只能是类中的成员变量的名称(溴铵在已经很少用了)

优化模糊查询,因为直接使用${}这个进行拼接会有sql注入危险,所以以后我们使用concat()函数来进行模糊查询

<select id="getByNameGood" parameterType="string" resultType="users">select id,username,birthday,sex,address from users where username like concat('%',#{name},'%')</select>

字符串替换使用${}

在有的时候我们需要进行模糊查询的时候,不仅仅是根据用户名,有的时候根据地址进行模糊查询,这个时候我们肯定是不能写两个不同的sql语句,这样太麻烦了,所以这个时候我们就要需要用到注解

List<Users> getByNameOrAddress(@Param("columnName") String columnName,@Param("columnValue") String columnValue);
<!---->    <!--如果参数超过一个则parameterType不用写--><select id="getByNameOrAddress" resultType="users">select id,username,birthday,sex,address from users where${columnName} like concat('%',#{columnValue},'%')</select>

然后进行测试,要查询哪个字段,就靠自己传参

@Testpublic  void  testGetByNameGoodOrAddress(){List<Users> list = uMapper.getByNameOrAddress("address","南");for (Users x:list){System.out.println(x);}}

返回主键业务

假如在有的时候,我们插入一行数据,但是主键是自增的,并且关联了其他表,且也要为其增加数据,这样我们还要先查询自增的主键是多少再进行增加另一个表的数据,这样很麻烦,所以我们可以在插入数据的时候返回主键

 <insert id="add" parameterType="users"><selectKey keyProperty="id" resultType="int" order="AFTER">select last_insert_id()</selectKey>insert into users(username,birthday,sex,address) values(#{userName},#{birthday},#{sex},#{address})</insert>
  • selectKey标签的详解:

    • keyProperty:users对象的哪个属性来返回主键值
    • resultType:返回主键的类型
    • order:在插入语句前还是后返回主键的值

动态SQL

  • 什么是动态sql

    • 可以定义代码片段,可以进行逻辑判断,可以进行循环处理(批量处理),使条件判断更简单
  • :用来定义代码片段,可以将所有的列名,或者复杂的条件定义为代码片段,供使用时调用

  • :用来引用标签定义的代码片段

    <!--定义代码片段--><sql id="allColumns">id,username,birthday,sex,address</sql><!--在sql语句中引用--><select id="getAll" resultType="users">select <include refid="allColumns"></include> from users</select>
  • 进行条件判断

  • 进行多条件拼接,在查询,删除,更新中使用

    • 强化select查询,使用if进行判断
    <select id="getByCondition" parameterType="users" resultType="users">select <include refid="allColumns"></include> from users<where><if test="userName != null and userName !=''">and username like concat('%',#{userName},'%')</if><if test="birthday != null">and birthday = #{birthday}</if><if test="sex != null and sex != ''">and sex = #{sex}</if><if test="address != null and address != ''">and address like concat('%',#{address},'%')</if></where></select>

测试

   @Testpublic void testGetByCondition(){Users users = new Users();users.setUserName("小");List<Users> list = uMapper.getByCondition(users);for (Users x : list){System.out.println(x);}}
  • :有选择的进行更新处理,至少更新一列
    <update id="updateBySet" parameterType="users" >update users<set><if test="userName != null and userName != ''">username = #{userName},</if><if test="birthday != null">birthday = #{birthday},</if><if test="sex != null and sex != ''">sex = #{sex},</if><if test="address != null and address != ''">address = #{address},</if></set>where id = #{id}</update>

测试

   @Testpublic void testUpdateBySet(){Users users = new Users();users.setId(6);users.setUserName("TheShy");int i = uMapper.updateBySet(users);sqlSession.commit();}

:用来进行循环遍历,完成循环条件查询,批量删除,批量增减,批量更新

  • collection:用来指定入参的类型,如果是List集合则为小写的list,Map为map,数组Array是array

  • item:每次循环遍历出来的值或者对象

  • separator:多个值或者多个对象之间的分隔符

  • open:整个循环前的前括号

  • close:整个循环的后括号

    <select id="getByIds" resultType="users">select <include refid="allColumns"></include>from userswhere id in (<foreach collection="array" item="id" separator="," open="(" close=")">#{id}</foreach>)</select>

使用foreach实现批量删除

    <delete id="deleteBatch">delete from userswhere id in<foreach collection="array" item="id" separator="," open="(" close=")">#{id}</foreach></delete>

测试

   @Testpublic void testDeleteBatch(){Integer[] array = {4,7};int i = uMapper.deleteBatch(array);sqlSession.commit();}

注意:如果要使用批量更新,需要再properties配置文件中的url后加上 &allowMultiQueries=true

指定参数位置

如果入参是多个,可以通过指定参数位置进行传参,是实体类包含不住的条件,实体类只能封装住成员变量的条件,如果某个成员变量需要有区间范围之内的判断,或者两个值进行处理,则实体类包不住

  • 例如:查询指定日期范围内的用户信息
  • 首先定义接口中的方法,因为是在一个区间之内,所以需要两个参数的方法
List<Users> getByBirthday(Date beigin,Date end);
  • 然后在Mapper.xml文件中编写sql语句
    <select id="getByBirthday" resultType="users">select <include refid="allColumns"></include>from userswhere birthday between #{arg0} and #{arg1}</select>

在进行多个参数查询的时候,我们可以用 arg0 开始指定,从零开始,依次递增

  • 测试
   @Testpublic void testGetByBirthday() throws ParseException {Date begin = sf.parse("2001-01-1");Date end = sf.parse("2003-01-1");List<Users> byBirthday = uMapper.getByBirthday(begin, end);for (Users x : byBirthday){System.out.println(x);}}

入参为Map

  • 如果入参超过一个以上,使用map封装查询条件,更有语义,查询条件更明确
List<Users> getByMap(Map map);
    <!--#{birthdayBegin}  为map集合的key#{birthdayEnd}     为map集合的value--><select id="getByMap" resultType="users">select <include refid="allColumns"></include>from userswhere birthday between #{birthdayBegin} and #{birthdayEnd}</select>
   @Testpublic void testGetByMap() throws ParseException {Date begin = sf.parse("2001-01-1");Date end = sf.parse("2003-01-1");Map map = new HashMap<>();map.put("birthdayBegin",begin);map.put("birthdayEnd",end);List<Users> byBirthday = uMapper.getByMap(map);for (Users x : byBirthday){System.out.println(x);}}

返回值是map

  • 如果返回的数据实体类无法包含,可以使用map返回多张表中若干的数据,然后后这些数据之间没有任何关系,就是Object类型,map的key就是列名或者别名
    //返回值是map(一行)Map getReturnMap(Integer id);//返回值为多行mapList<Map> getAllMap();
    <!--返回值为一行map--><select id="getReturnMap" parameterType="int" resultType="map">select username,address from userswhere id = #{id}</select><!--返回值为多行map--><select id="getAllMap" resultType="map">select username,address from users</select>
   //返回值为一行map@Testpublic void testGetReturnMap(){Map returnMap = uMapper.getReturnMap(2);System.out.println(returnMap.get("username"));System.out.println(returnMap.get("address"));}//返回多行Map@Testpublic void testGetAllMap(){List<Map> allMap = uMapper.getAllMap();for (Map x : allMap){System.out.println(x);}}

resultMap的用法

  • 在有的时候实体类的属性和数据库表的字段不一样的情况下,可以使用resultMap进行关系映射
    <!--实体类和表中的字段不一样的情况下,可以使用resultMap手工完成映射--><resultMap id="bookmap" type="book"><!--id是你在sql语句中设置的id type是你映射的类型--><!--主键绑定--><!--property为你实体类中的属性,column为你数据库中对应的字段名--><id property="id" column="bookid"></id><!--非主键绑定--><result property="name" column="bookname"></result></resultMap><select id="getAllBook" resultMap="bookmap"> <!--设置返回值为resultMap,并且设置名字,为你resultMap中的id-->select bookid,bookname from book</select>

表的关联关系

关联关系是有方向的

  • 一对多关联:一个老师可以教多个学生,多个学生只有一个老师来教,站在老师方向,就是一对多关联

  • 多对一关联:一个老师可以教多个学生,多个学生只有一个老师来教,站在学生的方向,这就是多对一的关系

  • 一对一关联:一个老师辅导一个学生,一个学生只请教一个老师,学生和老师一对一

  • 多对多关联:园区划线的车位和园区的任意一辆车,一个车位可以停任意一辆车,任意一辆车可以停在任意的一个车位。

  • 一对多的关联管理

    • 客户和订单就是典型的一对多关联关系,一个客户名下可以有多个订单,客户表是一方,订单表是多方
  • 使用一对多的关联关系,可以按组查询客户的同时查询该客名下所有的订单

    • 把两个表创建实体类,客户表可以创建一个订单类型的属性
//客户表private Integer id;private String name;private Integer age;private List<Orders> ordersList;
//订单orders表private Integer id;private String orderNumber;private Double orderPrice;

因为返回的数据不仅仅有客户表中的信息,还有订单表中的信息,所以数据库要多表连接查询,查询的数据的不同,所以要使用resultMap进行一个绑定

    <resultMap id="customermap" type="customer"><id property="id" column="cid"></id><result property="name" column="name"></result><result property="age" column="age"></result><!--orders属性绑定--><collection property="ordersList" ofType="orders"><id property="id" column="oid"></id><result property="orderNumber" column="orderNumber"></result><result property="orderPrice" column="orderPrice"></result></collection></resultMap><select id="getById" parameterType="int" resultMap="customermap">select c.id cid,name,age,o.id oid,orderNumber,orderPrice,customer_idfrom customer c left join orders o on c.id = o.customer_idwhere c.id = #{id}</select>

多对一关联关系:订单和客户就是多对一关联,站在订单的方向查询同时将客户信息查询出来这就是多对一查询,同理可以在订单的实体类中设置用户customer为属性,然后创建订单的接口和其Mapper.xml文件

总结:无论什么关联关系,如果某一方持有另一方的集合,则使用标签完成映射,如果某方持有另一方对象,则使用标签完成映射

事务

多个操作同时完成,或者同时失败成为事务处理

  • 事务有四个特性:一致性,持久性,原子性,隔离性
  • 在mybatis中是设置事务,设置为程序员自己处理的提交和回滚
<transactionManager type="JDBC"></transactionManager>
  • 也就可以设置为自动提交
sqlSession = factory.openSession(); //默认是手工提交事务,设置为false也是手动提交事务,设置为true为自动提交事务
sqlSession = factory.openSession(true);//设置为自动提交,在增删改后面不需要commit()

缓存

  • mybatis框架提供了两级缓存,一级缓存和二级缓存,默认开启一级缓存
  • 缓存就是为了提高查询效率,如果数据库中发生改变,那么将会清空缓存
  • 使用缓存后查询的流程:
  • 查询时先到缓存里面查,如果没有则去数据库查询,放在缓存一份,然后返回给客户端,下次再查询的时候,不再访问数据库,直接在缓存里面拿。如果数据库发生了commit()操作,那么将会清空缓存。
  • 一级缓存,使用的是sqlSession的作用域,同一个sqlSession共享一级缓存的数据
  • 二级缓存使用的是mapper的作用域,不同的sqlSession只要访问的是同一个mapper.xml文件,则共享二级缓存作用域

ORM

  • ORM(Object Relational Mapping):对象映射关系
  • mybatis框架是ORM非常优秀的框架
  • Java语言中以对象的方式操作数据,存到数据库中是以表的方式进行存储,对象中的成员变量与表中的列之间的数据互换成为映射,整个这套操作就是ORM
  • 持久化的操作:将对象保存到关系型数据库中,将关系型数据库中的数据读出来以对象的形式封装
  • mybatis是持久化层优秀的框架

SSM框架之mybaitis框架详解相关推荐

  1. java集合框架史上最详解(list set 以及map)

    title: Java集合框架史上最详解(list set 以及map) tags: 集合框架 list set map 文章目录 一.集合框架总体架构 1.1 集合框架在被设计时需满足的目标 1.2 ...

  2. 超轻量级DI容器框架Google Guice与Spring框架的区别教程详解及其demo代码片段分享...

    超轻量级DI容器框架Google Guice与Spring框架的区别教程详解及其demo代码片段分享 DI框架 Google-Guice入门介绍 转载于:https://www.cnblogs.com ...

  3. 自动化测试框架[Cypress元素操作详解]

    前提 已经熟练掌握了Cypress的基本知识,请参考自动化测试框架[Cypress概述]和自动化测试框架[各自动化测试框架比较] 已经熟练掌握Cypress环境配置,请参考自动化测试框架[Cypres ...

  4. androidentity什么用_Android ORM 框架:GreenDao 使用详解(进阶篇)

    前言 在 Android ORM 框架:GreenDao 使用详解(基础篇) 中,我们了解了 GreenDao 的基本使用,本文我们将深入讲解 GreenDao 的使用 . 一.复杂表结构 a, 使用 ...

  5. java 线程同步的list_java集合框架线程同步代码详解

    List接口的大小可变数组的实现.实现了所有可选列表操作,并允许包括null在内的所有元素.除了实现List接口外,此类还提供一些方法来操作内部用来存储列表的数组的大小.(此类大致上等同于Vector ...

  6. SpringSecurity权限管理框架系列(六)-Spring Security框架自定义配置类详解(二)之authorizeRequests配置详解

    1.预置演示环境 这个演示环境继续沿用 SpringSecurit权限管理框架系列(五)-Spring Security框架自定义配置类详解(一)之formLogin配置详解的环境. 2.自定义配置类 ...

  7. Android Binder框架实现之Parcel详解之基本数据的读写

       Android Binder框架实现之Parcel详解之基本数据的读写 Android Binder框架实现目录: Android Binder框架实现之Binder的设计思想 Android ...

  8. Android Binder框架实现之bindService详解

        Android Binder框架实现之bindService详解 Android Binder框架实现目录: Android Binder框架实现之Binder的设计思想 Android Bi ...

  9. spring cloud tencent:框架概括及组件详解(一)

    0.引言 近期腾讯开源了自己的spring cloud体系技术,称职的技术从业者除做好自己的本职工作外,还需要紧跟技术潮流,实时了解前沿技术,所以本期我们就来一起学习spring cloud tenc ...

最新文章

  1. php字符串处理函数大全
  2. python urllib3离线安装_全球Python库下载前10名
  3. android配置开发环境ubuntu
  4. Java继承概述以及Java继承案例和继承的好处
  5. 红队技巧-域渗透的协议利用
  6. java excel 电话号码_数值或者电话号码被EXCEL转成了科学计数法,用XSSFCell 如何读取...
  7. L3-020 至多删三个字符 (30 分)-PAT 团体程序设计天梯赛 GPLT
  8. 【免费毕设】成绩查询系统(系统+论文+答辩PPT)
  9. 《流畅的Python》读书笔记——Python序列的修改、散列和切片
  10. Windows 10 超过Windows 7成为最受欢迎的操作系统
  11. python小波包分解_小波包变换(Wavelet Packet Transform)的学习笔记
  12. 软件工程专业如何论文选题?
  13. 线性回归相关系数c语言,线性回归中的相关系数;
  14. 如何有效的获得高质量的大规模标注数据?
  15. html自动增加文本框,html创建文本框
  16. 【矩阵论笔记】相似对角化、特征子空间(几何重数和代数重数)
  17. STM32——C语言基础
  18. vue的微信语音功能,录音+对接口返回amr音频播放
  19. python生成字符画_Python生成字符画 | 文艺数学君
  20. ubuntu16启用daytime服务

热门文章

  1. kyo酱的博客--回溯法
  2. win10 体验 日志
  3. Flink入门第十二课:DataStream api/Flink sql实现每隔5分钟统计最近一小时热门商品小案例
  4. 服务器维护中启动不了怎么办,服务器不能正常启动了怎么办
  5. 移动行业EOMS系统
  6. 逻辑学三大定律是什么?
  7. 14岁男孩玩手机上瘾,家长说了也不管用
  8. 树莓派4B基于OpenWrt安装安朗蝴蝶实现校园上网自由
  9. Python元组,列表,字典,集合
  10. outlook 2007 帐户为Exchange时更改邮件存储路径