1.5 整合Mybatis
1.5.1 配置工程
SpringBoot2.* 整合Mybatis 总体工作流程为:
- (1)修改POM文件,添加Maven依赖
<!-- mybatis -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>${mybatis-spring.version}</version>
</dependency>
<!-- mybatis -->
<!-- mybatis通用mapper -->
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper</artifactId>
<version>${mybatis-mapper.version}</version>
</dependency>
<!-- mybatis通用mapper -->
<!-- mybatis pagehelper分页支持 -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>${mybatis-pagehelper.version}</version>
</dependency>
<!-- mybatis pagehelper -->
<!—阿里的druid 数据库连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>${druid-starte.version}</version>
</dependency>
<!--druid-->
<!— mysql驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
<!-- mysql -->
- (2)修改配置文件 application-dev.properties
#================== mybatis =====================#
mybatis.mapper-locations=classpath:mappers/**/*.xml
mybatis.configuration.map-underscore-to-camel-case=true
#================ mybatis pagehelper 分页配置 ==============#
pagehelper.helper-dialect=mysql
pagehelper.reasonable=true
pagehelper.support-methods-arguments=true
pagehelper.params=count=countSql
#================== 数据源配置database ===================#
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/zone7-demo
spring.datasource.username=root
spring.datasource.password=zgq
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.druid.initial-size=5
spring.datasource.druid.min-idle=5
spring.datasource.druid.max-active=20
spring.datasource.druid.max-wait=60000
spring.datasource.druid.time-between-eviction-runs-millis=60000
spring.datasource.druid.min-evictable-idle-time-millis=300000
spring.datasource.druid.validation-query='select 'x'
spring.datasource.druid.test-while-idle=true
spring.datasource.druid.test-on-borrow=false
spring.datasource.druid.test-on-return=false
spring.datasource.druid.pool-prepared-statements=true
spring.datasource.druid.max-pool-prepared-statement-per-connection-size=20
spring.datasource.druid.filters=stat,wall
1.5.2 创建数据库
我们以mysql数据库为例,创建一个系统用户表。
CREATE TABLE `zone7-demo`.`sys_user` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'id',
`name` varchar(50) NOT NULL COMMENT '用户名',
`password` varchar(255) COMMENT '密码',
`phone` varchar(20) COMMENT '电话',
`score` int(11) COMMENT '积分',
`star` int(11) COMMENT '星级',
`department` varchar(50) COMMENT '部门名称',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_bin AUTO_INCREMENT=1000;
1.5.3 代码生成
mybatis 代码生成方式可以使用命令行方式和IDE方式,我们可以采用IDE执行逆向生成。
相关配置和生成代码步骤如下所示:
-
(1) 在工程根目录新建专门用于逆袭工程相关的文件夹
-
(2) 配置Pom文件增加plugin
<!-- mybatis generator 自动生成代码插件 -->
<plugin>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.3.2</version>
<configuration>
<configurationFile>
${basedir}/generator_tool/mybatis-generator-sys.xml
</configurationFile>
<overwrite>true</overwrite>
<verbose>true</verbose>
</configuration>
</plugin>
- (3) 配置pom.xml中generator 插件所对应的配置文件
${basedir}/generator_tool/mybatis-generator-sys.xml,详细配置说明可查看以下配置文件注释内容。
<?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">
<generatorConfiguration>
<!-- TODO: 1.数据库驱动包位置 -->
<!-- 在MBG工作的时候,需要额外加载的依赖包,location属性指明加载jar/zip包的全路径 -->
<classPathEntry location="/Users/zgq/IdeaProjects/demo/helloworld/generator_tool/libs/mysql-connector-java-8.0.11.jar"/>
<!--
context:生成一组对象的环境
id:必选,上下文id,用于在生成错误时提示
defaultModelType:指定生成对象的样式
1,conditional:类似hierarchical;
2,flat:所有内容(主键,blob)等全部生成在一个对象中;
3,hierarchical:主键生成一个XXKey对象(key class),Blob等单独生成一个对象,其他简单属性在一个对象中(record class)
targetRuntime:
1,MyBatis3:默认的值,生成基于MyBatis3.x以上版本的内容,包括XXXBySample;
2,MyBatis3Simple:类似MyBatis3,只是不生成XXXBySample;
introspectedColumnImpl:类全限定名,用于扩展MBG
-->
<context id="DB2Tables" targetRuntime="MyBatis3">
<!--是否使用Lombok标准生成实体类 需要开发自定义LombokPlugin ,暂时不用 -->
<!--<plugin type="org.mybatis.generator.plugins.LombokPlugin">-->
<!--<property name="hasLombok" value="true"/>-->
<!--</plugin>-->
<!--去掉生成类的注释-->
<commentGenerator>
<property name="suppressDate" value="true"/>
<property name="suppressAllComments" value="true"/>
</commentGenerator>
<!-- TODO: 2.数据库链接URL、用户名、密码 -->
<jdbcConnection driverClass="com.mysql.jdbc.Driver"
connectionURL="jdbc:mysql://localhost:3306/zone7-demo"
userId="root"
password="zgq">
</jdbcConnection>
<!-- java类型处理器
用于处理DB中的类型到Java中的类型,默认使用JavaTypeResolverDefaultImpl;
注意一点,默认会先尝试使用Integer,Long,Short等来对应DECIMAL和 NUMERIC数据类型;
-->
<javaTypeResolver type="org.mybatis.generator.internal.types.JavaTypeResolverDefaultImpl">
<!--
true:使用BigDecimal对应DECIMAL和 NUMERIC数据类型
false:默认,
scale>0;length>18:使用BigDecimal;
scale=0;length[10,18]:使用Long;
scale=0;length[5,9]:使用Integer;
scale=0;length<5:使用Short;
-->
<property name="forceBigDecimals" value="false"/>
</javaTypeResolver>
<!-- TODO: 3.生成模型的包名和位置 -->
<!-- java模型创建器,是必须要的元素
负责:1,key类(见context的defaultModelType);2,java类;3,查询类
targetPackage:生成的类要放的包,真实的包受enableSubPackages属性控制;
targetProject:目标项目,指定一个存在的目录下,生成的内容会放到指定目录中,如果目录不存在,MBG不会自动建目录
-->
<javaModelGenerator targetPackage="com.zone7.demo.helloworld.sys.pojo"
targetProject="/Users/zgq/IdeaProjects/demo/helloworld/src/main/java">
<!-- for MyBatis3/MyBatis3Simple
自动为每一个生成的类创建一个构造方法,构造方法包含了所有的field;而不是使用setter;
-->
<property name="constructorBased" value="false"/>
<!-- 在targetPackage的基础上,根据数据库的schema再生成一层package,最终生成的类放在这个package下,默认为false -->
<property name="enableSubPackages" value="true"/>
<!-- 设置一个根对象,
如果设置了这个根对象,那么生成的keyClass或者recordClass会继承这个类;在Table的rootClass属性中可以覆盖该选项
注意:如果在key class或者record class中有root class相同的属性,MBG就不会重新生成这些属性了,包括:
1,属性名相同,类型相同,有相同的getter/setter方法;
-->
<!--<property name="rootClass" value=""/>-->
<!-- 设置是否在getter方法中,对String类型字段调用trim()方法 -->
<property name="trimStrings" value="true"/>
</javaModelGenerator>
<!-- TODO: 4.生成的映射文件包名和位置 -->
<!-- 这里的目标包和路径必须与application.properties配置的mybatis.mapper-locations=classpath:mappers/**/*.xml 一致,
一般我们存放在resources/mappers目录下 -->
<sqlMapGenerator targetPackage="mappers.sys"
targetProject="/Users/zgq/IdeaProjects/demo/helloworld/src/main/resources">
<property name="enableSubPackages" value="true"/>
</sqlMapGenerator>
<!-- TODO: 5.生成DAO的包名和位置 -->
<javaClientGenerator type="XMLMAPPER"
targetPackage="com.zone7.demo.helloworld.sys.dao"
targetProject="/Users/zgq/IdeaProjects/demo/helloworld/src/main/java">
<property name="enableSubPackages" value="true"/>
<!-- 可以为所有生成的接口添加一个父接口,但是MBG只负责生成,不负责检查
<property name="rootInterface" value=""/>
-->
</javaClientGenerator>
<!-- TODO: 6.要生成那些表(更改tableName和domainObjectName就可以) -->
<table tableName="SYS_USER" domainObjectName="SysUser"
enableCountByExample="false"
enableUpdateByExample="false"
enableDeleteByExample="false"
enableSelectByExample="false"
selectByExampleQueryId="false"/>
</context>
</generatorConfiguration>
- (4) 执行代码生成命令
首先打开Edit Configurations… , 执行RUN生成代码,也可以使用java 命令生成代码。
-
方式一、Java命令
java -jar libs/mybatis-generator-core-1.3.5.jar -configfile mybatis-generator-rule.xml -overwrite -
方式二、配置mvn命令
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ydje1isr-1582190290922)(https://zone-7.github.io/img/springboot/1.5.3b.png)]配置Command Line: mybatis-generator:generate -e
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-56OF85kU-1582190290923)(https://zone-7.github.io/img/springboot/1.5.3c.png)]
执行完生成代码效果如下:
1.5.4 案例开发
以下部分以《用户管理模块》为例,开发持久层、服务层和控制层,并通过Postman测试。
1.5.4.1 增加配置类
在包com.zone7.demo.helloworld.commons 中新增mapper包,并新建通用Mapper“BaseMapper.java”。
package com.zone7.demo.helloworld.commons.mapper;
import tk.mybatis.mapper.common.Mapper;
/**
* BaseMapper
* mybatis通用mapper
*
* @author: zone7
* @time: 2019.01.02
*/
public interface BaseMapper<T> extends Mapper<T> {
}
在com.zone7.demo.helloworld.config中新建mybatis包,并新增MyBatisMapperScannerConfig.java 作为扫描类。
package com.zone7.demo.helloworld.config.mybatis;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import tk.mybatis.spring.mapper.MapperScannerConfigurer;
import java.util.Properties;
/**
* MyBatisMapperScannerConfig
* mybatis mapper扫描配置
*
* @author: zone7
* @time: 2019.01.02
*/
@Configuration
public class MyBatisMapperScannerConfig {
/**
* 配置mybatis通用mapper
*
* @return
*/
@Bean
public MapperScannerConfigurer mapperScannerConfigurer() {
MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();
mapperScannerConfigurer.setSqlSessionFactoryBeanName("sqlSessionFactory");
//扫描该路径下的mapper
mapperScannerConfigurer.setBasePackage("com.zone7.demo.helloworld.sys.dao, com.zone7.demo.helloworld.*.dao");
Properties properties = new Properties();
//通用mapper
properties.setProperty("mappers", "com.zone7.demo.helloworld.commons.mapper.BaseMapper");
properties.setProperty("notEmpty", "false");
mapperScannerConfigurer.setProperties(properties);
return mapperScannerConfigurer;
}
}
代码中mapperScannerConfigurer.setBasePackage("com.zone7.demo.helloworld.sys.dao, com.zone7.demo.helloworld..dao")的参数为需要扫描的mapper所在的包名,可以使用 作为通配符。
1.5.4.2 持久层开发
- (1)修改SysUser.java 添加注解@Builder
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
/**
* Created by Mybatis Generator 2019/06/18
*/
@Builder
@Getter
@Setter
@ToString
public class SysUser {
private Integer id;
private String name;
private String password;
private String phone;
private Integer score;
private Integer star;
private String department;
}
- (2)修改SysUserMapper.java 添加函数SysUser findByName(String name);
package com.zone7.demo.helloworld.sys.dao;
import com.zone7.demo.helloworld.sys.pojo.SysUser;
import java.util.List;
/**
* Created by Mybatis Generator 2019/06/18
*/
public interface SysUserMapper {
int deleteByPrimaryKey(Integer id);
int insert(SysUser entity);
int insertSelective(SysUser entity);
SysUser selectByPrimaryKey(Integer id);
int updateByPrimaryKeySelective(SysUser entity);
int updateByPrimaryKey(SysUser entity);
/**
* 根据用户名查询
* @param name
* @return
*/
List<SysUser> findByName(String name);
}
- (3)修改SysUserMapper.xml 文件,增加findByName
<select id="findByName" resultMap="BaseResultMap">
select
<include refid="Base_Column_List" />
from SYS_USERS
where name like #{name}
</select>
1.5.4.3 服务层开发
- (1)添加vo类
新增com.zone7.demo.helloworld.sys.vo 包,接口传输对象统一放到vo包中。开发过程中可以拷贝实体类并修改细节,例如拷贝SysUser对象到vo包并改名为SysUserVo , 并给类增加可序列化接口:public class SysUserVo implements Serializable
package com.zone7.demo.helloworld.sys.vo;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import java.io.Serializable;
/**
* Created by Mybatis Generator 2019/06/18
*/
@Getter
@Setter
@ToString
public class SysUserVo implements Serializable{
private Integer id;
private String name;
private String password;
private String phone;
private Integer score;
private Integer star;
private String department;
}
- (2)开发服务层代码
新增com.zone7.demo.helloworld.sys.service包和com.zone7.demo.helloworld.sys.service.impl包,用于存放服务层的接口和实现类。将服务层划分为接口和实现类有利于提高系统的可扩展性。在示例里我们准备实现用户的增删改查操作,接口如下:
package com.zone7.demo.helloworld.sys.service;
import com.zone7.demo.helloworld.sys.pojo.SysUser;
import com.zone7.demo.helloworld.sys.vo.SysUserVo;
import java.util.List;
/**
* SysUserService
*
* @author: zone7
* @time: 2019.02.17
*/
public interface SysUserService {
/**
* 保存
* @param userVo
*/
void save(SysUserVo userVo);
/**
* 修改
* @param userVo
*/
void update(SysUserVo userVo);
/**
* 根据用户ID查找
* @param id
* @return
*/
SysUserVo findByKeyword(String id);
/**
* 根据用户名模糊查找
* @param name
* @return
*/
List<SysUserVo> findByName(String name);
/**
* 加载所有用户
* @return
*/
List<SysUserVo> findAll();
/**
* 删除用户
* @param id
*/
void delete(String id);
}
实现类的代码如下:
package com.zone7.demo.helloworld.sys.service.impl;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.zone7.demo.helloworld.commons.exception.AddOPException;
import com.zone7.demo.helloworld.commons.exception.DeleteOPException;
import com.zone7.demo.helloworld.commons.exception.UpdateOPException;
import com.zone7.demo.helloworld.commons.mapper.PageModel;
import com.zone7.demo.helloworld.sys.dao.SysUserMapper;
import com.zone7.demo.helloworld.sys.pojo.SysUser;
import com.zone7.demo.helloworld.sys.service.SysUserService;
import com.zone7.demo.helloworld.sys.vo.SysUserVo;
import com.zone7.demo.helloworld.utils.MD5Util;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
/**
* SysUserServiceImpl
* 用户管理
* @author: zone7
* @time: 2019.02.17
*/
@Service
public class SysUserServiceImpl implements SysUserService {
@Value("${system.default.password}")
private String defaultPassword;
@Autowired
private SysUserMapper sysUserMapper;
@Override
@Transactional(rollbackFor = AddOPException.class)
public void save(SysUserVo userVo) {
try {
String password = defaultPassword;
String md5Password = MD5Util.encode(password);
SysUser sysUser = SysUser.builder()
.name(userVo.getName()).password(md5Password)
.phone(userVo.getPhone())
.department(userVo.getDepartment())
.build();
// 存储用户信息
sysUserMapper.insertSelective(sysUser);
} catch (Exception e) {
throw new AddOPException("新增用户操作出错,错误原因: " + e.getMessage());
}
}
@Override
@Transactional(rollbackFor = UpdateOPException.class)
public void update(SysUserVo userVo) {
try {
SysUser after = SysUser.builder()
.id(userVo.getId())
.name(userVo.getName())
.phone(userVo.getPhone())
.department(userVo.getDepartment()).build();
sysUserMapper.updateByPrimaryKeySelective(after);
} catch (Exception e) {
throw new UpdateOPException("更新用户操作出错,错误原因: " + e.getMessage());
}
}
@Override
public SysUserVo findById(Integer id) {
SysUser user = sysUserMapper.selectByPrimaryKey(id);
SysUserVo vo=new SysUserVo();
BeanUtils.copyProperties(user,vo);
return vo;
}
@Override
public List<SysUserVo> findByName( String name) {
List<SysUser> users = sysUserMapper.findByName(name);
List<SysUserVo> userList = new ArrayList<SysUserVo>();
users.forEach(sysUser -> {
// 查询角色信息
SysUserVo vo=new SysUserVo();
BeanUtils.copyProperties(sysUser,vo);
userList.add(vo);
});
return userList;
}
@Override
@Transactional(rollbackFor = DeleteOPException.class)
public void delete(Integer id) {
try {
sysUserMapper.deleteByPrimaryKey(id);
} catch (Exception e) {
e.printStackTrace();
throw new DeleteOPException("删除用户操作出错,错误原因: " + e.getMessage());
}
}
}
值得注意的是,代码中的方法采用了注解@Transactional, 例如:@Transactional(rollbackFor = AddOPException.class)表示事务控制当方法抛出AddOPException异常时进行事务回滚。
1.5.4.4 控制层开发
在第一个工程中我们已经介绍了控制层的开发,这个部分我们将新增用户管理模块的控制层代码,并调用服务层的功能。控制层代码我们统一放在模块的controller包下面。控制层代码如下:
package com.zone7.demo.helloworld.sys.controller;
import com.zone7.demo.helloworld.commons.response.ResponseData;
import com.zone7.demo.helloworld.sys.service.SysUserService;
import com.zone7.demo.helloworld.sys.vo.SysUserVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* SysUserController
* 用户管理
* @author: zone7
* @time: 2019.02.17
*/
@RestController
@RequestMapping("/sys/user")
public class SysUserController {
@Autowired
private SysUserService sysUserService;
/**
* 保存
* @param userVo
* @return
*/
@RequestMapping("/save")
public ResponseData save(SysUserVo userVo) {
sysUserService.save(userVo);
return ResponseData.successMessage("新增用户成功");
}
/**
* 更新
* @param userVo
* @return
*/
@RequestMapping("/update")
public ResponseData updateDept(SysUserVo userVo) {
sysUserService.update(userVo);
return ResponseData.successMessage("更新用户成功");
}
/**
* 查找
* @param name
* @return
*/
@RequestMapping("/findByName")
public ResponseData findByName(@RequestParam(value = "name") String name) {
List<SysUserVo> result = sysUserService.findByName(name);
return ResponseData.success(result);
}
/**
* 删除
* @param id
* @return
*/
@RequestMapping("/delete")
public ResponseData delete(Integer id) {
sysUserService.delete(id);
return ResponseData.successMessage("删除用户成功");
}
}
1.5.4.5 测试
在IDEA中运行HelloworldApplication类
可以看到系统启动端口是8080,与application.properties配置的一致。接下来可打开Postman (postman是web开发常用的测试工具)测试新增用户、修改用户、查询用户、删除用户四个功能。
查询刚才新增加的用户:
修改用户
删除用户
至此SpringBoot完成了与Mybatis的整合工作。