3.1 Spring Boot 集成 MyBatis
通过 SpringBoot +MyBatis 实现对数据库学生表的查询操作
3.1.1 案例思路
1、添加依赖(Mybatis、连接数据库的驱动)
2、连接数据库的配置
3、通过Mabatis逆向工程生成:数据持久层和实体Bean
3.1.2 实现步骤
(1) 准备数据库
1、通过idea本身的工具连接本地Mysql数据库
点击在最右侧这个按钮:
创建连接:
Name:随便取,作为连接名
Host:因为连接的是本地的数据库,所以直接localhost,端口号默认3306
User:自己在配置数据库或者闲暇的时候创建的用户
Password:用户的密码
URL:默认写有,不过最好加一个参数serverTimezone=UTC,不然胡子哎Test Connection时极大概率出现时区的报错
2、创建新的数据库 springboot并向表中添加数据
create database springboot;
create table t_student
(
id int(10) not null auto_increment,
stu_name varchar(20) null,
stu_age int(10) null,
constraint PK_T_STUDENT primary key clustered (id)
);
insert into t_student(stu_name,stu_age) values("zhangsan",25);
insert into t_student(stu_name,stu_age) values("lisi",28);
insert into t_student(stu_name,stu_age) values("wangwu",23);
insert into t_student(stu_name,stu_age) values("Tom",21);
insert into t_student(stu_name,stu_age) values("Jck",55);
insert into t_student(stu_name,stu_age) values("Lucy",27);
insert into t_student(stu_name,stu_age) values("zhaoliu",75);
3、创建完成
(2)实现Mybatis逆向生成
1、GeneratorMapper.xml文件
先在项目根目录下创建GeneratorMapper.xml文件,用于指定Mybatis逆向生成的相关配置
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<!--上面会报红,不过不要紧,实际是指涉及一个dto的配置-->
<generatorConfiguration>
<!-- 指定连接数据库的 JDBC 驱动包所在位置,指定到你本机的完整路径 -->
<classPathEntry location="C:\Users\15998\.m2\repository\mysql\mysql-connector-java\8.0.25\mysql-connector-java-8.0.25.jar"/>
<!-- 配置 table 表信息内容体,targetRuntime 指定采用 MyBatis3 的版本 -->
<context id="tables" targetRuntime="MyBatis3">
<!-- 抑制生成注释器,因为生成的注释都是英文的,可以不让它生成 -->
<commentGenerator>
<property name="suppressAllComments" value="true" />
</commentGenerator>
<!-- 配置数据库连接信息 -->
<jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
connectionURL="jdbc:mysql://localhost:3306/springboot"
userId="root"
password="qks218126">
</jdbcConnection>
<!-- 生成 model 类,targetPackage 指定 model 类的包名, targetProject 指定
生成的 model 放在 eclipse 的哪个工程下面-->
<javaModelGenerator targetPackage="com.example.springbootworkspace.model"
targetProject="src/main/java">
<property name="enableSubPackages" value="false" />
<property name="trimStrings" value="false" />
</javaModelGenerator>
<!-- 生成 MyBatis 的 Mapper.xml 文件,targetPackage 指定 mapper.xml 文件的
包名, targetProject 指定生成的 mapper.xml 放在 eclipse 的哪个工程下面 -->
<sqlMapGenerator targetPackage="com.example.springbootworkspace.mapper"
targetProject="src/main/java">
<property name="enableSubPackages" value="false" />
</sqlMapGenerator>
<!-- 生成 MyBatis 的 Mapper 接口类文件,targetPackage 指定 Mapper 接口类的包
名, targetProject 指定生成的 Mapper 接口放在 eclipse 的哪个工程下面 -->
<javaClientGenerator type="XMLMAPPER"
targetPackage="com.example.springbootworkspace.mapper"
targetProject="src/main/java">
<property name="enableSubPackages" value="false" />
</javaClientGenerator>
<!-- 数据库表名及对应的 Java 模型类名 -->
<table tableName="t_student" domainObjectName="Student"
enableCountByExample="false"
enableUpdateByExample="false"
enableDeleteByExample="false"
enableSelectByExample="false"
selectByExampleQueryId="false"/>
</context>
</generatorConfiguration>
2、添加Mysql反向工程依赖
注意别放错位置
<!--mybatis 代码自动生成插件-->
<plugin>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.3.6</version>
<configuration>
<!--配置文件的位置-->
<configurationFile>GeneratorMapper.xml</configurationFile>
<verbose>true</verbose>
<overwrite>true</overwrite>
</configuration>
</plugin>
3、生成实体类和映射文件
点开Maven配置,找到图中蓝色的那个东东,双击:
成功生成:
生成的实体Bean和数据持久层以及映射文件:
4、生成的代码
实体类
public class Student {
private Integer id;
private String stuName;
private Integer stuAge;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getStuName() {
return stuName;
}
public void setStuName(String stuName) {
this.stuName = stuName;
}
public Integer getStuAge() {
return stuAge;
}
public void setStuAge(Integer stuAge) {
this.stuAge = stuAge;
}
}
数据持久层接口
注意,原本是没有@Mapper注解的,需要我们手动添加
@Mapper
public interface StudentMapper {
int deleteByPrimaryKey(Integer id);
int insert(Student record);
int insertSelective(Student record);
Student selectByPrimaryKey(Integer id);
int updateByPrimaryKeySelective(Student record);
int updateByPrimaryKey(Student record);
}
数据持久层的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 namespace="com.example.springbootworkspace.mapper.StudentMapper">
<resultMap id="BaseResultMap" type="com.example.springbootworkspace.model.Student">
<id column="id" jdbcType="INTEGER" property="id" />
<result column="stu_name" jdbcType="VARCHAR" property="stuName" />
<result column="stu_age" jdbcType="INTEGER" property="stuAge" />
</resultMap>
<sql id="Base_Column_List">
id, stu_name, stu_age
</sql>
<select id="selectByPrimaryKey" parameterType="java.lang.Integer" resultMap="BaseResultMap">
select
<include refid="Base_Column_List" />
from t_student
where id = #{id,jdbcType=INTEGER}
</select>
<delete id="deleteByPrimaryKey" parameterType="java.lang.Integer">
delete from t_student
where id = #{id,jdbcType=INTEGER}
</delete>
<insert id="insert" parameterType="com.example.springbootworkspace.model.Student">
insert into t_student (id, stu_name, stu_age
)
values (#{id,jdbcType=INTEGER}, #{stuName,jdbcType=VARCHAR}, #{stuAge,jdbcType=INTEGER}
)
</insert>
<insert id="insertSelective" parameterType="com.example.springbootworkspace.model.Student">
insert into t_student
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="id != null">
id,
</if>
<if test="stuName != null">
stu_name,
</if>
<if test="stuAge != null">
stu_age,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="id != null">
#{id,jdbcType=INTEGER},
</if>
<if test="stuName != null">
#{stuName,jdbcType=VARCHAR},
</if>
<if test="stuAge != null">
#{stuAge,jdbcType=INTEGER},
</if>
</trim>
</insert>
<update id="updateByPrimaryKeySelective" parameterType="com.example.springbootworkspace.model.Student">
update t_student
<set>
<if test="stuName != null">
stu_name = #{stuName,jdbcType=VARCHAR},
</if>
<if test="stuAge != null">
stu_age = #{stuAge,jdbcType=INTEGER},
</if>
</set>
where id = #{id,jdbcType=INTEGER}
</update>
<update id="updateByPrimaryKey" parameterType="com.example.springbootworkspace.model.Student">
update t_student
set stu_name = #{stuName,jdbcType=VARCHAR},
stu_age = #{stuAge,jdbcType=INTEGER}
where id = #{id,jdbcType=INTEGER}
</update>
</mapper>
(3) 在 pom.xml 中添加相关 jar 依赖
<!--MyBatis整合SpringBoot的起步依赖-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.0.1</version>
</dependency>
<!--MySQL的驱动依赖-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
(4) 在application.properties中配置数据源(连接数据库)
mysql8之后的class-name已经改为: com.mysql.cj.jdbc.Driver
要注意时区,可以设置成Asia/Shanghai
根据自己数据库的信息修改以下内容,需要改的就是url的地址,以及username和password
#配置内嵌Tomcat端口号
server.port=9090
#配置数据库的连接信息
#注意这里的驱动类有变化
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/springboot?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2B8
spring.datasource.username=root
spring.datasource.password=123456
(5)开发代码
1、控制层
在 web 包下创建 StudentController 并编写代码
@Controller
public class StudentController {
@Autowired
private StudentService studentService;
@RequestMapping(value = "/student/details")
public @ResponseBody Object student(Integer id) {
Student student = studentService.queryStudentById(id);
return student;
}
}
2、业务层
在service包下编写StudentService接口
编写方法queryStudentById,根据学生id获取学生信息
public interface StudentService {
/*
* 根据学生id获取学生详情
* */
Student queryStudentById(Integer id);
}
service包下创建一个Impl类,用于放置接口实现类
并在业务层里注入数据持久层接口
记得写@Service注解
@Service
public class StudentServiceImpl implements StudentService {
@Autowired
private StudentMapper studentMapper;
@Override
public Student queryStudentById(Integer id) {
//这里接收的参数就是前端传过来的参数
return studentMapper.selectByPrimaryKey(id);
}
}
注意
pom.xml的改动
StudentMapper.xml是Mybatis逆向工程生成的配置文件,注意这是配置文件(看.xml后缀),而Springboot对于配置文件的要求是要放在resources目录下,所以直接运行时会出现如下报错(这是因为没有找到配置文件的原因)
org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.example.springbootworkspace.mapper.StudentMapper.selectByPrimaryKey
所以我们需要做出如下改动,在pom.xml文件中加入如下代码,指定资源文件:
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
重新编译文件就可以看到它已经出现在target里面了:
此时还有一个需要注意的地方,如果pom指定了resources标签,那么他就只会去这个标签里面找子标签resource所指定的资源文件。
如果这个时候恰巧运行了maven的clean命令,并且重新compile命令,那么就会发现在target文件夹下,application.properties文件已经无了。
所以除了上面这个resource标签所指定的内容以外,还要加上另一部分(上保险):
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.*</include>
</includes>
</resource>
上面的代码指定application.properties也作为配置文件的一部分,这个时候我们如果learn、conpile的话,就会发现它又回来了,并且原来的StudentMapper.xml也没有消失。
@Service
之前我们在service层中添加过这个注解,这个注解告诉springboot其声名的类属于业务层,该类会放在容器中,用于在控制层注入
该注解用于实现类
主要的几种用法:
- 最常用的用法
@Service
public class TestServiceImp implements TestService {
//
}
@RestController
public class TestController {
@AutoWired
private TestService testService;
}
- 当一个interface有多个实现类的时候的用法
@Service("testService")
public class TestServiceImp implements TestService {
//
}
@RestController
public class TestController {
@AutoWired
// 这个变量名testService和@Service()的命名(即参数)一致
private TestService testService;
}
当然这种情况还有其他方式
@Service("testService")
public class TestServiceImp implements TestService {
//
}
@RestController
public class TestController {
@Resource(name = "testService") // 这个值testService和@Service("")的命名一致
private TestService testService;
}
@Mapper
作用是将标注的DAO接口交给Spring进行管理,并且为该接口生成一个实现类放在容器中,给业务层的实现类使用
该注解用于数据持久层的接口
方法参数有多个的时候,需要使用@Param,单参数方法不需要
(6)测试
成功拿到数据库的数据
(7)总结过程描述
整个过程,其实就是控制层接收前端传来的参数之后,调用studentService的queryStudentById方法,该方法返回一个Student实例,Springboot会去容器中找到被@Service注解标注的studentService接口的实现类StudentServiceImpl,然后调用里面的queryStudentById放方法,StudentMapper接口由于被@Mapper标注,所以会在Spring容器中实例化一个实现类,所以queryStudentById方法就可调用持久层中的studentMapper实例的selectByPrimaryKey方法,该方法在StudentMapper.xml配置文件中返回BaseResultMap值,Mybatis会根据查询语句,返回一个符合条件的对象。
3.1.3 DAO 的第二种开发方式
上面的连接方式是只有一个DAO的情况下,当我们有多个DAO的时候,我们可以用另一种写法,而不是在每一个DAO里面写@Mapper
(1)添加@MapperScan
第二种方式我们主要使用原来的方法:对包扫描映射文件,此时需要用到注解@MapperScan,其参数通常指定到数据持久层包即可
在运行主类 Application 上加@MapperScan(basePackages = “com.example.springbootworkspace.mapper”)
@SpringBootApplication
@MapperScan(basePackages = "com.example.springbootworkspace.mapper")
public class SpringbootWorkspaceApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootWorkspaceApplication.class, args);
}
}
注意,此时DAO接口(mapper包里的接口)上就不需要加@Mapper注解了。
(2)将接口和映射文件分开
这个时候因为不使用@Mapper了,Springboot不能自动编译接口映射的xml文件了,这个时候也不像上个案例那样子通过@Mapper在容器中生成持久层实例放入业务层中了,所以我们还需要做一点小小的改动
找到resources文件夹,我们在它下面创建一个mapper文件夹,接下来我们需要把mapper包下的StudentMapper.xml文件放到mapper文件夹下:
(3)指定Mybatis映射文件路径
这个时候我们发现:接口和映射文件分开了,这种情况Springboot要求我们要在application.properties中指定映射文件的位置
mybatis.mapper-locations=classpath:mapper/*.xml
(4)测试
运行项目进行测试,可以看到冇问题: