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等工具對應用接口進行測試。 具體測試方法和代碼就不在這裏一一講述了。