1. 引言
在项目开发中, 我们经常需要使用数据库操作, 而针对Java开发中的数据库持久化技术和框架包括:基础JDBC、JPA、MyBatis、Hibernate等。 近期接手一个项目开发工作, 使用Spring Boot + Mybatis技术进行开发, 现就Spring Boot与Mybatis集成的相关配置与操作记录做一下记录。
1.1 开发环境
- JDK 1.8
- Intellij IDEA 2017
- MySQL 5.1.7
- Spring Boot 2.0.0.RELEASE
- MyBatis 3
2. Spring Boot 与 MyBatis 集成配置
1. 创建Spring Boot 项目
使用Intellij Idea中的Spring Initializr创建Spring Boot项目
配置项目元数据: 项目包信息、项目名、项目编译打包工具(Maven、Gradle,此处选择Maven)、JDK版本、打包方式(Jar或War)等
配置项目所依赖的组件信息,根据项目需要选择相关的项目依赖包, 选择的项目组件包括: Web、JDBC、MySQL和MyBatis等
项目创建完成后, Intellij Idea生成相关的项目文件, 查看生成的Maven依赖文件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>com.garyond.hurricane</groupId>
<artifactId>info-manager</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>info-manager</name>
<description>Information Manager project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!-- Druid Pool -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.9</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.9</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
2. 配置项目application.yml配置文件
Spring Boot支持application.properties和application.yml两种配置文件, 从配置文件的可读性考虑, 项目采用了application.yml配置文件方式, 配置文件中添加数据源连接、MyBatis配置等,如下所示:
# Server Port and Encoding
server:
port: 9969
servlet:
context-path: /infoMgr
# Spring Datasource Settings
spring:
datasource:
name: druidDataSource
type: com.alibaba.druid.pool.DruidDataSource
druid:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://192.168.202.17:3306/auth_service?useUnicode=true&characterEncoding=UTF-8
username: root
password: 123456
filters: stat
max-active: 100
initial-size: 1
max-wait: 60000
min-idle: 1
time-between-eviction-runs-millis: 60000
min-evictable-idle-time-millis: 300000
validation-query: select 'x'
test-while-idle: true
test-on-borrow: false
test-on-return: false
pool-prepared-statements: true
max-open-prepared-statements: 50
max-pool-prepared-statement-per-connection-size: 20
# Mybatis config
mybatis:
mapper-locations: classpath:mapping/*.xml
type-aliases-package: com.garyond.hurricane.infomanager.model
3. 创建项目数据库
配置完项目开发环境后,根据项目整体设计, 创建项目数据库, 如下示例代码:
create database infoMgr;
create table base_user
(
user_id varchar(64) not null,
dept_id int,
user_name varchar(50),
password varchar(64),
real_name varchar(50),
phone varchar(30),
mobile varchar(30),
email varchar(50),
create_time timestamp,
user_status int,
primary key (user_id)
);
... ...
4. 使用 MyBatis Generator自动生成相关的代码
我们在项目pom.xml文件中可以添加MyBatis Generator插件, 并配置Generator插件对应的配置文件${basedir}/src/main/resources/generator/generator.config.xml
, 该配置文件用于指定MyBatis下模型、DAO生成的映射包名和位置等信息:
<?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>
<!-- 数据库驱动:选择你的本地硬盘上面的数据库驱动包-->
<classPathEntry location="D:\JarLibrary\mysql-connector-java-5.1.45.jar"/>
<context id="DB2Tables" targetRuntime="MyBatis3">
<commentGenerator>
<property name="suppressDate" value="true"/>
<!-- 是否去除自动生成的注释 true:是 : false:否 -->
<property name="suppressAllComments" value="true"/>
</commentGenerator>
<!--数据库链接URL,用户名、密码 -->
<jdbcConnection driverClass="com.mysql.jdbc.Driver" connectionURL="jdbc:mysql://192.168.202.17/info_manager" userId="info" password="info123">
</jdbcConnection>
<javaTypeResolver>
<property name="forceBigDecimals" value="false"/>
</javaTypeResolver>
<!-- 生成模型的包名和位置-->
<javaModelGenerator targetPackage="com.garyond.hurricane.infomanager.model" targetProject="src/main/java">
<property name="enableSubPackages" value="true"/>
<property name="trimStrings" value="true"/>
</javaModelGenerator>
<!-- 生成映射文件的包名和位置-->
<sqlMapGenerator targetPackage="mapping" targetProject="src/main/resources">
<property name="enableSubPackages" value="true"/>
</sqlMapGenerator>
<!-- 生成DAO的包名和位置-->
<javaClientGenerator type="XMLMAPPER" targetPackage="com.garyond.hurricane.infomanager.dao" targetProject="src/main/java">
<property name="enableSubPackages" value="true"/>
</javaClientGenerator>
<!-- 要生成的表 tableName是数据库中的表名或视图名 domainObjectName是实体类名-->
<table tableName="base_user" domainObjectName="User" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"></table>
<table tableName="base_organization" domainObjectName="Department" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"></table>
</context>
</generatorConfiguration>
配置完MyBatis自动代码生成配置文件后,需要在Pom.xml中添加MyBatis Generator相应的依赖包,用于对MyBatis Generator进行自动代码生成。
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<!-- MyBatis Generator -->
<plugin>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.3.6</version>
<configuration>
<configurationFile>${basedir}/src/main/resources/generator/generator.config.xml</configurationFile>
<overwrite>true</overwrite>
<verbose>true</verbose>
</configuration>
</plugin>
</plugins>
</build>
下一步, 在Intellij Idea开发工具中配置Maven运行命令, 如下操作:
上图中点Edit Configuration
按钮, 进入运行配置界面, 选择左上角的“+”号按钮, 选择Maven
插件:
在弹出的Maven运行配置界面中添加名称和命令行参数mybatis-generator:generate -e
:
完成上述配置后, IntelliJ Idea工具下会生成运行名称, 如下所示:
点击刚配置完成的Table-Generator
右边的运行按钮即可执行生成相关的Entity和Dao代码包。
5. 查看生成的代码包
User.java
import java.util.Date;
public class User{
private String userId ;
private Integer unitId;
private String unitName;
private String userName;
private String password;
private String realName;
private String phone;
private String mobile;
private String email;
private Date createTime;
private Integer userStatus;
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public Integer getUnitId() {
return unitId;
}
public void setUnitId(Integer unitId) {
this.unitId = unitId;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName == null ? null : userName.trim();
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password == null ? null : password.trim();
}
public String getRealName() {
return realName;
}
public void setRealName(String realName) {
this.realName = realName == null ? null : realName.trim();
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone == null ? null : phone.trim();
}
public String getMobile() {
return mobile;
}
public void setMobile(String mobile) {
this.mobile = mobile == null ? null : mobile.trim();
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email == null ? null : email.trim();
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
public Integer getUserStatus() {
return userStatus;
}
public void setUserStatus(Integer userStatus) {
this.userStatus = userStatus;
}
public String getUnitName() {
return unitName;
}
public void setUnitName(String unitName) {
this.unitName = unitName;
}
}
UserMapper.java
public interface UserMapper {
int deleteByPrimaryKey(String userId);
int insert(User record);
int insertSelective(User record);
User selectByPrimaryKey(String userId);
int updateByPrimaryKeySelective(User record);
int updateByPrimaryKey(User record);
}
UserMapper.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.garyond.hurricane.infomanager.dao.UserMapper">
<resultMap id="BaseResultMap" type="com.garyond.hurricane.infomanager.model.User">
<id column="user_id" jdbcType="VARCHAR" property="userId" />
<result column="unit_id" jdbcType="INTEGER" property="unitId" />
<result column="user_name" jdbcType="VARCHAR" property="userName" />
<result column="password" jdbcType="VARCHAR" property="password" />
<result column="real_name" jdbcType="VARCHAR" property="realName" />
<result column="phone" jdbcType="VARCHAR" property="phone" />
<result column="mobile" jdbcType="VARCHAR" property="mobile" />
<result column="email" jdbcType="VARCHAR" property="email" />
<result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
<result column="user_status" jdbcType="INTEGER" property="userStatus" />
</resultMap>
<sql id="Base_Column_List">
user_id, unit_id, user_name, password, real_name, phone, mobile, email,
create_time, user_status
</sql>
<select id="selectByPrimaryKey" parameterType="java.lang.String" resultMap="BaseResultMap">
select
<include refid="Base_Column_List" />
from base_user
where user_id = #{userId,jdbcType=VARCHAR}
</select>
<delete id="deleteByPrimaryKey" parameterType="java.lang.String">
delete from base_user
where user_id = #{userId,jdbcType=VARCHAR}
</delete>
<insert id="insert" parameterType="com.garyond.hurricane.infomanager.model.User">
insert into base_user (user_id, unit_id, user_name,
password, real_name, phone,
mobile, email,
create_time, user_status)
values (#{userId,jdbcType=VARCHAR}, #{unitId,jdbcType=INTEGER}, #{userName,jdbcType=VARCHAR},
#{password,jdbcType=VARCHAR}, #{realName,jdbcType=VARCHAR}, #{phone,jdbcType=VARCHAR},
#{mobile,jdbcType=VARCHAR}, #{email,jdbcType=VARCHAR},
#{createTime,jdbcType=TIMESTAMP}, #{userStatus,jdbcType=INTEGER})
</insert>
<insert id="insertSelective" parameterType="com.garyond.hurricane.infomanager.model.User">
insert into base_user
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="userId != null">
user_id,
</if>
<if test="unitId != null">
unit_id,
</if>
<if test="userName != null">
user_name,
</if>
<if test="password != null">
password,
</if>
<if test="realName != null">
real_name,
</if>
<if test="phone != null">
phone,
</if>
<if test="mobile != null">
mobile,
</if>
<if test="email != null">
email,
</if>
<if test="createTime != null">
create_time,
</if>
<if test="userStatus != null">
user_status,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="userId != null">
#{userId,jdbcType=VARCHAR},
</if>
<if test="unitId != null">
#{unitId,jdbcType=INTEGER},
</if>
<if test="userName != null">
#{userName,jdbcType=VARCHAR},
</if>
<if test="password != null">
#{password,jdbcType=VARCHAR},
</if>
<if test="realName != null">
#{realName,jdbcType=VARCHAR},
</if>
<if test="phone != null">
#{phone,jdbcType=VARCHAR},
</if>
<if test="mobile != null">
#{mobile,jdbcType=VARCHAR},
</if>
<if test="email != null">
#{email,jdbcType=VARCHAR},
</if>
<if test="createTime != null">
#{createTime,jdbcType=TIMESTAMP},
</if>
<if test="userStatus != null">
#{userStatus,jdbcType=INTEGER},
</if>
</trim>
</insert>
<update id="updateByPrimaryKeySelective" parameterType="com.garyond.hurricane.infomanager.model.User">
update base_user
<set>
<if test="unitId != null">
unit_id = #{unitId,jdbcType=INTEGER},
</if>
<if test="userName != null">
user_name = #{userName,jdbcType=VARCHAR},
</if>
<if test="password != null">
password = #{password,jdbcType=VARCHAR},
</if>
<if test="realName != null">
real_name = #{realName,jdbcType=VARCHAR},
</if>
<if test="phone != null">
phone = #{phone,jdbcType=VARCHAR},
</if>
<if test="mobile != null">
mobile = #{mobile,jdbcType=VARCHAR},
</if>
<if test="email != null">
email = #{email,jdbcType=VARCHAR},
</if>
<if test="createTime != null">
create_time = #{createTime,jdbcType=TIMESTAMP},
</if>
<if test="userStatus != null">
user_status = #{userStatus,jdbcType=INTEGER},
</if>
</set>
where user_id = #{userId,jdbcType=VARCHAR}
</update>
<update id="updateByPrimaryKey" parameterType="com.garyond.hurricane.infomanager.model.User">
update base_user
set unit_id = #{unitId,jdbcType=INTEGER},
user_name = #{userName,jdbcType=VARCHAR},
password = #{password,jdbcType=VARCHAR},
real_name = #{realName,jdbcType=VARCHAR},
phone = #{phone,jdbcType=VARCHAR},
mobile = #{mobile,jdbcType=VARCHAR},
email = #{email,jdbcType=VARCHAR},
create_time = #{createTime,jdbcType=TIMESTAMP},
user_status = #{userStatus,jdbcType=INTEGER}
where user_id = #{userId,jdbcType=VARCHAR}
</update>
</mapper>
6. 编写业务逻辑代码及业务展现层
根据业务模型实现各个业务的业务逻辑和业务展现层, 以用户管理为例, 实现用户管理相关的操作逻辑。
用户业务服务接口: UserService.java
public interface UserService {
public int save(User user);
public int update(User user);
public int remove(User user);
public User getUserById(String userId);
}
用户业务服务实现:UserServiceImpl.java
@Service
public class UserServiceImpl implements UserService{
@Resource
private UserMapper userMapper;
@Resource
private DepartmentMapper departmentMapper;
@Override
public int save(User user) {
return userMapper.insert(user);
}
@Override
public int update(User user) {
return userMapper.updateByPrimaryKeySelective(user);
}
@Override
public int remove(User user) {
return userMapper.deleteByPrimaryKey(user.getUserId());
}
@Override
public User getUserById(String userId) {
return userMapper.selectByPrimaryKey(userId);
}
}
用户业务展示:UserController.java
@RestController
@RequestMapping("/user")
public class UserPageController extends BaseController {
@Autowired
private UserService userService;
@RequestMapping(method = RequestMethod.GET)
public String toPage(Model model) {
return "userPage";
}
/*
* 删除用户
*/
@RequestMapping("/create")
public @ResponseBody JsonResult saveUser(User user) {
User checkedUser = userService.getUserByUsername(user.getUserName());
if (null != checkedUser) {
return this.renderError("用户名:" + user.getUserName() + "已存在");
}
checkedUser = userService.getUserByEmail(user.getEmail());
if (null != checkedUser) {
return this.renderError("电子邮件:" + user.getEmail() + "已存在");
}
checkedUser = userService.getUserByMobile(user.getMobile());
if (null != checkedUser) {
return this.renderError("手机号码:" + user.getMobile() + "已存在");
}
String passwordDigest = new MD5().getTwiceMD5ofString(user.getPassword());
user.setPassword(passwordDigest);
userService.save(user);
return this.renderSuccess();
}
/*
* 更新用户
*/
@RequestMapping("/update")
public @ResponseBody JsonResult updateUser(User user) {
User checkedUser = userService.getUserById(user.getUserId());
if (null == checkedUser) {
return this.renderError("该用户不存在");
}
userService.update(user);
return this.renderSuccess();
}
/*
* 删除用户
*/
@RequestMapping("/remove")
public @ResponseBody JsonResult delete(String[] ids) {
for(String id: ids) {
userService.removeByUserId(id);
}
return this.renderSuccess();
}
}
7. 在Spring Boot应用启动类中启用MyBatis配置
在启动Spring Boot应用过程中, 需要在启动类中添加@Mapper
注解,将MyBatis中的Mapper类路径进行启动加载, 否则MyBatis无法加载相应的数据持久化操作。
package com.garyond.hurricane.infomanager;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@MapperScan("com.garyond.hurricane.infomanager.dao")
public class InfoManagerApplication {
public static void main(String[] args) {
SpringApplication.run(InfoManagerApplication.class, args);
}
}
8. 应用测试
完成上述步骤后, 启动Spring Boot应用, 我们可以编写jUnit对相应的业务API接口进行测试, 并且可以通过Postman等工具对应用接口进行测试。 具体测试方法和代码就不在这里一一讲述了。