之前我们说过,MyBatis是一款优秀的支持自定义SQL查询、存储过程和高级映射的持久层框架,而且,与JDBC相比,MyBatis简化了相关的代码,使得代码更加简洁。所以,MyBatis最常用的地方就是结合数据库一起进行相关CRUD操作。在正式进行增删改查操作前,我们需要准备一下需要的数据库和其他文件。

我们假设一个场景,来设定一个简单的权限控制需求,采用RBAC(Role-Based Access Control,基于角色的访问控制方式),这个简单的权限管理将会是我后续文章的基础示例。那么这个权限管理都有哪些需求呢?我们结合现实考虑一下,一个用户通常拥有若干个角色,一个角色通常也拥有若干个权限(即对某种资源的某种基于但不限于增删改查的操作),于是就构成了“用户-角色-权限”的模型。在这种模型中,用户与角色之间是一对多的关系,即一个用户对应拥有多种角色,角色与权限之间也是一对多的关系。在现实中也常有这样的场景,普通用户一般拥有登录和查询等基础权限,而管理员除了拥有普通用户拥有的登录和查询等基础权限外,它还可以对普通用户进行管理,即有权决定谁是普通用户,或是可以对普通用户进行增删操作。

根据我们描述的需求,显而易见会有五张数据表产生,即用户表、角色表和权限表,以及用户角色联系表和角色权限联系表。那么接下来我们就在数据库中创建这五张表,创建代码如下:

//创建数据库study
CREATE DATABASE study;
USE study;//创建用户表t_user
CREATE TABLE t_user(
id BIGINT NOT NULL auto_increment COMMENT '用户ID',
user_name VARCHAR(50) COMMENT '用户名',
user_password VARCHAR(50) COMMENT '密码',
user_email VARCHAR(50) COMMENT '邮箱',
user_info text COMMENT '简介',
head_img BLOB COMMENT '头像',
create_time datetime COMMENT '创建时间',
PRIMARY KEY(id)
);
ALTER TABLE t_user COMMENT '用户表';//创建角色表t_role
CREATE TABLE t_role(
id BIGINT NOT NULL auto_increment COMMENT '角色ID',
role_name VARCHAR(50) COMMENT '角色名',
enabled INT COMMENT '有效标志',
create_author BIGINT COMMENT '创建者',
create_time datetime COMMENT '创建时间',
PRIMARY KEY(id)
);
ALTER TABLE t_role COMMENT '角色表';//创建权限表t_privilege
CREATE TABLE t_privilege(
id BIGINT NOT NULL auto_increment COMMENT '权限ID',
privilege_name VARCHAR(50) COMMENT '权限名称',
privilege_url VARCHAR(50) COMMENT '权限url',
PRIMARY KEY(id)
);
ALTER TABLE t_privilege COMMENT '权限表';//创建用户角色联系表t_user_role
CREATE TABLE t_user_role(
user_id BIGINT COMMENT '用户ID',
role_id BIGINT COMMENT '角色ID'
);
ALTER TABLE t_user_role COMMENT '用户角色关联表';//创建角色权限联系表t_role_privilege
CREATE TABLE t_role_privilege(
role_id BIGINT COMMENT '角色ID',
privilege_id BIGINT COMMENT '权限ID'
);
ALTER TABLE t_role_privilege COMMENT '角色权限关联表';

我们要习惯使用SQL语句来进行数据库表的创建,尽量减少那种直接在数据库中创建表的方式。我们看到,上面创建数据库表的代码中,很明显有COMMENT,其实COMMENT就相当于注释、备注的意思,即对数据库表中的各个字段进行解释,我们以后在创建数据库表的时候也要多多使用这种有好的创建数据库表方式。

创建完成后的数据库中的五张表的结构是这样的:

以上这五张表示的字段可以根据自身情况自行决定,包括表明,各字段的命名都可自行改变。本人的这五张表的结构完全参考自刘增辉老师的《MyBatis从入门到精通》一书。

接下来我们给这五张表插入一些数据,为了后续程序运行需要,每张表插入一两条数据即可,不必过多。当然如果有自己的想法,则可以根据需要多多插入几条数据。

//给t_user用户表插入数据
INSERT INTO t_user VALUES
('1001','张三','123123','123456@study','我是张三',NULL,NOW());
INSERT INTO t_user VALUES
('1002','李四','123456','456456@study','我是李四',NULL,NOW());//给t_role角色表插入数据
INSERT INTO t_role VALUES('1','管理员','1','1',NOW());
INSERT INTO t_role VALUES('2','普通用户','1','1',NOW());//给t_privilege权限表插入数据
INSERT INTO t_privilege VALUES('1','用户管理','/users');
INSERT INTO t_privilege VALUES('2','角色管理','/roles');
INSERT INTO t_privilege VALUES('3','系统日志','/logs');
INSERT INTO t_privilege VALUES('4','人员维护','/persons');
INSERT INTO t_privilege VALUES('5','单位维护','/companiess');//给t_user_role用户角色关联表插入数据
INSERT INTO t_user_role VALUES('1001','1');
INSERT INTO t_user_role VALUES('1001','2');
INSERT INTO t_user_role VALUES('1002','2');//给t_role_privilege角色权限关联表插入数据
INSERT INTO t_role_privilege VALUES('1','1');
INSERT INTO t_role_privilege VALUES('1','3');
INSERT INTO t_role_privilege VALUES('1','2');
INSERT INTO t_role_privilege VALUES('2','4');
INSERT INTO t_role_privilege VALUES('2','5');

插入若干条数据之后的五张表展示如下:

                    

上述插入数据的方法在后续工作中也是用得到的,之前说过,要习惯使用SQL语句!!!结合插入的数据,我们有以下信息:

  • 用户ID为1001的张三,既是管理员,也是普通用户,所以拥有用户管理、角色管理、系统日志、人员维护、单位维护的所有权限;
  • 用户ID为1002的李四,只是普通用户,所以只拥有人员维护和单位维护两个权限。

以上数据仅为后续工作工作,并不具有实际意义,请不要对号入座。

接下来,我们在IDEA中新建一个maven项目,命名方式自选,本人在这里命名为Mybatis-CRUD。然后,先在pom.xml文件中导入相关依赖。完整的pom.xml文件如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>org.example</groupId><artifactId>Mybatis-CRUD</artifactId><version>1.0-SNAPSHOT</version><!--导入依赖--><dependencies><!--mysql驱动--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.21</version></dependency><!--mybatis--><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.5</version></dependency><!--JUnit--><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.13</version><scope>test</scope></dependency></dependencies>
</project>

然后,我们还需要完成上面说过的五个数据库表的实体类。为便于管理,我们在src/main/java目录下先创建一个包,命名为pojo,然后将五个数据库表的实体类(分别命名为User、Role、Privileg、UserRole、RolePrivilege)放在这个pojo包下。需要说明的是,MyBatis默认是遵循“下划线转驼峰”的命名方式的。怎么说呢,就是如果我们在数据库中创建表的时候各字段的命名是以下划线的方式来命名的,那么在MyBatis中,我们应该遵循MyBatis的命名方式,使用驼峰命名的方法。举个例子,我们在t_user表中对于用户名的命名方式是user_name的下划线方式的,那么在实体类中,我们使用userName小驼峰的命名方式。其实,为了方便和统一,我们也可以将数据库表中的字段以小驼峰的方式命名,避免在后续工作中混淆。

User实体类的代码如下,包含了User的属性和各属性的get()和set()方法,以及toString()方法。写toString()方法是为了将查询结果成功输出到控制台。

package pojo;import java.util.Arrays;
import java.util.Date;public class User {private Long id;                    //用户IDprivate String userName;            //用户名private String userPassword;        //密码private String userEmail;           //Emailprivate String userInfo;            //简介private byte[] headImg;             //头像private Date createTime;            //创建时间public User() {}public User(Long id, String userName, String userPassword,String userEmail, String userInfo, byte[] headImg, Date createTime) {this.id = id;this.userName = userName;this.userPassword = userPassword;this.userEmail = userEmail;this.userInfo = userInfo;this.headImg = headImg;this.createTime = createTime;}public Long getId() {return id;}public void setId(Long id) {this.id = id;}public String getUserName() {return userName;}public void setUserName(String userName) {this.userName = userName;}public String getUserPassword() {return userPassword;}public void setUserPassword(String userPassword) {this.userPassword = userPassword;}public String getUserEmail() {return userEmail;}public void setUserEmail(String userEmail) {this.userEmail = userEmail;}public String getUserInfo() {return userInfo;}public void setUserInfo(String userInfo) {this.userInfo = userInfo;}public byte[] getHeadImg() {return headImg;}public void setHeadImg(byte[] headImg) {this.headImg = headImg;}public Date getCreateTime() {return createTime;}public void setCreateTime(Date createTime) {this.createTime = createTime;}@Overridepublic String toString() {return "User{" +"id=" + id +", userName='" + userName + '\'' +", userPassword='" + userPassword + '\'' +", userEmail='" + userEmail + '\'' +", userInfo='" + userInfo + '\'' +", headImg=" + Arrays.toString(headImg) +", createTime=" + createTime +'}';}
}

Role实体类的代码如下:

package pojo;import java.util.Date;public class Role {private Long id;                //角色IDprivate String roleName;        //角色名private int enabled;            //有效标志private Long createAuthor;      //创建者private Date createTime;        //创建时间public Role() {}public Role(Long id, String roleName, int enabled,Long createAuthor, Date createTime) {this.id = id;this.roleName = roleName;this.enabled = enabled;this.createAuthor = createAuthor;this.createTime = createTime;}public Long getId() {return id;}public void setId(Long id) {this.id = id;}public String getRoleName() {return roleName;}public void setRoleName(String roleName) {this.roleName = roleName;}public int getEnabled() {return enabled;}public void setEnabled(int enabled) {this.enabled = enabled;}public Long getCreateAuthor() {return createAuthor;}public void setCreateAuthor(Long createAuthor) {this.createAuthor = createAuthor;}public Date getCreateTime() {return createTime;}public void setCreateTime(Date createTime) {this.createTime = createTime;}@Overridepublic String toString() {return "Role{" +"id=" + id +", roleName='" + roleName + '\'' +", enabled=" + enabled +", createAuthor=" + createAuthor +", createTime=" + createTime +'}';}
}

Privilege实体类代码如下:

package pojo;public class Privilege {private Long id;                //权限IDprivate String privilegeName;   //权限名称private String privilegeUrl;    //权限urlpublic Privilege() {}public Privilege(Long id, String privilegeName, String privilegeUrl) {this.id = id;this.privilegeName = privilegeName;this.privilegeUrl = privilegeUrl;}public Long getId() {return id;}public void setId(Long id) {this.id = id;}public String getPrivilegeName() {return privilegeName;}public void setPrivilegeName(String privilegeName) {this.privilegeName = privilegeName;}public String getPrivilegeUrl() {return privilegeUrl;}public void setPrivilegeUrl(String privilegeUrl) {this.privilegeUrl = privilegeUrl;}@Overridepublic String toString() {return "Privilege{" +"id=" + id +", privilegeName='" + privilegeName + '\'' +", privilegeUrl='" + privilegeUrl + '\'' +'}';}
}

UserRole实体类代码如下:

package pojo;public class UserRole {private Long userId;        //用户IDprivate Long roleId;        //角色IDpublic UserRole() {}public UserRole(Long userId, Long roleId) {this.userId = userId;this.roleId = roleId;}public Long getUserId() {return userId;}public void setUserId(Long userId) {this.userId = userId;}public Long getRoleId() {return roleId;}public void setRoleId(Long roleId) {this.roleId = roleId;}@Overridepublic String toString() {return "UserRole{" +"userId=" + userId +", roleId=" + roleId +'}';}
}

RolePrivilege实体类代码如下:

package pojo;public class RolePrivilege {private Long roleId;        //角色IDprivate Long privilegeId;   //权限IDpublic RolePrivilege() {}public RolePrivilege(Long roleId, Long privilegeId) {this.roleId = roleId;this.privilegeId = privilegeId;}public Long getRoleId() {return roleId;}public void setRoleId(Long roleId) {this.roleId = roleId;}public Long getPrivilegeId() {return privilegeId;}public void setPrivilegeId(Long privilegeId) {this.privilegeId = privilegeId;}@Overridepublic String toString() {return "RolePrivilege{" +"roleId=" + roleId +", privilegeId=" + privilegeId +'}';}
}

创建实体类的过程很枯燥,只是简单的工作重复做的过程。但是为了节省时间,我们可以使用Alt+Insert快捷键来快速选择我们要生成的构造函数以及get()和set()方法,以及toString()方法。具体操作方法为:在实体类中先写完各个属性,之后在实体类中(注意一定要在实体类中)鼠标右击选择Generate或者直接使用Alt+Insert快捷键进入选择界面,之后选择我们需要生成的函数类型就行。

当五个实体类都创建完成之后,我们来讨论一下MyBatis的映射语句,为后续程序编写做好准备。MyBatis的真正强大之处就在于它的映射语句,这也是MyBatis的魔力所在。由于它的映射语句异常强大,映射器的XML文件就显得相对简单。如果将其与具有相同功能的JDBC代码进行对比,就会发现,使用这种方法可节省大约95%的代码量。后续我们会使用到更多的xxxMapper文件和xxxMapper.xml文件。MyBatis通常使用接口配合XML文件使用,后续我们会体会到这种方式的工作流程的顺畅。不过在此之前呢,我们需要先配置一下MyBatis的核心配置文件,通常给它命名为Mybatis-config.xml,并放在src/main/resources文件下。其核心配置文件的内容如下:

<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd"><configuration><environments default="development"><environment id="development"><transactionManager type="JDBC"/><dataSource type="POOLED"><property name="driver" value="com.mysql.cj.jdbc.Driver"/><property name="url" value="jdbc:mysql://localhost:3306/study"/><property name="username" value="root"/><property name="password" value="123456"/></dataSource></environment></environments>
</configuration>

其实我们不难发现,Mybatis核心配置文件中主要就是连接数据库的内容,什么连接数据库的驱动、用户名和密码之类的。

接下来,我们创建与数据库中的五个表相对应的各自的XML文件,分别命名为UserMapper.xml、RoleMapper.xml、PrivilegeMapper.xml、UserRoleMapper.xml、RolePrivilegeMapper.xml。同样,为了便于管理,我们选择将这五个xml文件放在一个Mapper包下统一管理,Mapper包需要我们自己创建,我们选择让其位于src/main/resources文件夹下。然后我们还需要这五个XML文件的对应的接口类,还是和上面一样,为了便于管理,我们将其放在新建包Interface下,位于src/main/java下,分别命名为UserMapper、RoleMapper、PrivilegeMapper、UserRoleMapper、RolePrivilegeMapper,全部都是接口类文件,.java类型的。可能这样命名为xxxMapper的命名方式不是很规范,放在名为Interface的包下也显得不是很规范,其实正确的应该放在dao文件夹下,但是由于我目前还未接触到数据持久层Dao层,所以暂时就命名一个不太规范的包吧。

那么此时这五个接口类的内容都是空的,后续我们会写一些增删改查的方法在里边。

//接口类UserMapper
package Interface;public interface UserMapper{}//接口类RoleMapper
package Interface;public interface RoleMapper{}//接口类PrivilegeMapper
package Interface;public interface PrivilegeMapper{}//接口类UserRoleMapper
package Interface;public interface UserRoleMapper{}//接口类RolePrivilegeMapper
package Interface;public interface RolePrivilegeMapper {}

接下来,我们再看看五个XML文件。其实此时我们还没有进行相关的查询呢,所以此时XML文件其实也是空的。

//UserMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="Interface.UserMapper"></mapper>//RoleMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="Interface.RoleMapper"></mapper>//PrivilegeMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="Interface.PrivilegeMapper"></mapper>//UserRoleMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="Interface.UserRoleMapper"></mapper>//RolePrivilegeMapper
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="Interface.RolePrivilegeMapper"></mapper>

我们需要注意的是<mapper>根标签的namespace属性。当Mapper接口和XML文件关联的时候,命名空间namespace的值就需要配置成接口的全限定名称,例如UserMapper对应的Interface.UserMapper,Mybatis内部就是通过这个值将接口和XML关联起来的。

接下来,我们需要在Mybatis的配置文件Mybatis-config.xml中的mappers元素中配置所有的刚才写了的XML文件。

<mappers><mapper resource="mapper/UserMapper.xml"/><mapper resource="mapper/RoleMapper.xml"/><mapper resource="mapper/PrivilegeMapper.xml"/><mapper resource="mapper/UserRoleMapper.xml"/><mapper resource="mapper/RolePrivilegeMapper.xml"/>
</mappers><!--
<mappers><package name = "mapper"/>
</mappers>
-->

注意将<mappers>写在<configuration>里边,但写在<environments>外边。以上两种书写方式都能让XML文件和接口对应。但是第一种方式需要将所有映射文件一一列举出来,操作起来比较麻烦。第二种书写方式就看起来挺简单的,这种配置方式会先查找mapper包下所有的接口,并循环对接口以下操作:(1)判断接口对应的命名空间是否已经配置过,如果配置过就抛出异常,没有配置过就继续;(2)加载接口对应的XML文件,将接口的全限定名称转换为路径,即将接口Interface/UserMapper转换为mapper.UserMapper.xml,以.xml为后缀搜索XML资源,如果找到就解析XML。

增加内容之后的Mybatis-config.xml的全部内容为:

<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd"><configuration><environments default="development"><environment id="development"><transactionManager type="JDBC"/><dataSource type="POOLED"><property name="driver" value="com.mysql.cj.jdbc.Driver"/><property name="url" value="jdbc:mysql://localhost:3306/study"/><property name="username" value="root"/><property name="password" value="123456"/></dataSource></environment></environments><mappers><mapper resource="mapper/UserMapper.xml"/><mapper resource="mapper/RoleMapper.xml"/><mapper resource="mapper/PrivilegeMapper.xml"/><mapper resource="mapper/UserRoleMapper.xml"/><mapper resource="mapper/RolePrivilegeMapper.xml"/></mappers>
</configuration>

此时,我们对于正式的增删改查的准备工作已经完成。接下来,我们开始着手进行正式的增删改查工作。

需要注意的,本人在进行后续博文更新的时候,参照的内容和代码完全来自于刘增辉老师的《MyBatis从入门到精通》一书,书上的关于数据库的操作是非常连贯的,所以需要及时做好记录和注释,避免代码过多之后容易混乱。

Mybatis基本查询准备相关推荐

  1. MyBatis关联查询、多条件查询

    MyBatis关联查询.多条件查询 1.一对一查询 任务需求; 根据班级的信息查询出教师的相关信息 1.数据库表的设计 班级表: 教师表: 2.实体类的设计 班级表: public class Cla ...

  2. Mybatis联合查询

    为什么80%的码农都做不了架构师?>>>    案例 一个博客系统中,用户可以任意发表博文(Post),用户还可以对博文进行评论(Comment).于是在这个系统中,存在以下的关系: ...

  3. Mybatis like查询的写法--转载

    原文地址:http://lavasoft.blog.51cto.com/62575/1386870 Mybatis like查询官方文档没有明确的例子可循,网上搜索了很多,都不正确. Mybatis ...

  4. association 实现MyBatis分步查询与延迟加载

    一.分步查询 1.1什么时候可以用到分步查询 有的时候需要我们对数据库进行关联查询,比如Employee 持有另一个Department对象的一个引用,我们希望在查询Employee 的时候把Depa ...

  5. MyBatis基础:MyBatis关联查询(4)

    1. MyBatis关联查询简介 MyBatis中级联分为3中:association.collection及discriminator. ◊ association:一对一关联 ◊ collecti ...

  6. mybatis嵌套查询和嵌套结果有什么区别_Java面试专题之九:Mybatis面试5个大概率被问到的问题...

    1.为什么说 Mybatis 是半自动 ORM 映射工具?它与全自动的区别在哪里? Hibernate 属于全自动 ORM 映射工具,使用 Hibernate 查询关联对象或者关联集合对象时,可以根据 ...

  7. MyBatis之查询缓存

    MyBatis之查询缓存 2017/09/30 正如大多数持久层框架一样,MyBatis同样也提供了对查询数据的缓存支持.今后我们要学习的SpringMVC框架属于系统控制层,它也有它的缓存区域,对响 ...

  8. Mybatis in查询List或数组 场景实例

    1.mybatis in 查询List时 业务代码示例如下: List<String> list=new ArrayList<String>(); ...;//向list中填装 ...

  9. mybatis 取查询值_MyBatis面试题集合,90%会遇到这些问题

    点击蓝字关注我们吧! 1.#{}和${}的区别是什么? ${}是Properties文件中的变量占位符,它可以用于标签属性值和sql内部,属于静态文本替换,比如${driver}会被静态替换为com. ...

  10. Mybatis的查询、关联查询

    使用Mybatis进行查询 查询结果的映射 Mybatis通过<select>进行查询.通过<resultMap>将查询结果封装成实体类: <resultMap id=& ...

最新文章

  1. 如何判断数据库中的两个表是否相同(相等)?比较数据库中的两个表是否完全相同,包括字段和每条记录
  2. PHP 使用 Redis
  3. iOS中 UITableViewCell cell划线那些事 韩俊强的博客
  4. MySQL使用 IN 查询取出数据排序问题(与in排序相同、不排序)
  5. python自学网站有哪些-Python自学之路-前期准备
  6. 《python3网络爬虫开发实战》--基本库的使用
  7. AngularJS学习篇(十九)
  8. CUDA 中 FFT 的使用
  9. 统计数组中每个数字出现的次数_剑指Offer(二十八) 数组中次数出现超过一半的数字...
  10. [diary]极度自恋?
  11. python post 远程主机强迫关闭了一个现有的连接_ConnectionResetError:[WinError10054远程主机强迫关闭一个现有连接...
  12. Git之checkout到别的分支提示Your local changes to the following files would be overwritten by checkout:
  13. 小米用户画像_腾讯企鹅智库发布手机品牌用户画像:华为一二线城市用户少于小米...
  14. Android(java)学习笔记164:开发一个多界面的应用程序之不同界面间互相传递数据(短信助手案例)...
  15. vnc安装linux教程,Centos7安装配置vncserver详细教程
  16. Cross compile webrtc for ios on mac os.
  17. Google翻译插件不能用解决方案
  18. 使用原配的SSD安装和引导DSM5.2 5644 基于zmouse和Formater教程
  19. NGINX脚本语言原理及源码分析(三)
  20. 【Unity】基于顶点色的海边波浪效果(适用移动端)

热门文章

  1. 韩国三星集团会长转入普通病房 媒体曾称其已死
  2. java mybatis的SpringBoot博客论坛管理系统
  3. Java项目运维与监控调优
  4. Android P 中的网络安全配置指南 network-security-config
  5. HDU4751 -(广义孪生素数猜想)
  6. 杰理之PAP接口【篇】
  7. 高等工程数学(张韵华,汪琥庭,宋立功)—— 第二篇:数值计算
  8. 视频无法播放是怎么回事
  9. RGB显示屏的辐射超标问题点及解决方案
  10. 视频镜头分割与关键帧提取