Spring Boot集成Mybatis實現數據庫操作

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等

Web依賴包

SQL、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運行命令, 如下操作:

配置Maven運行

上圖中點Edit Configuration按鈕, 進入運行配置界面, 選擇左上角的“+”號按鈕, 選擇Maven插件:

選擇Maven運行編譯

在彈出的Maven運行配置界面中添加名稱和命令行參數mybatis-generator:generate -e

配置名稱和參數

完成上述配置後, IntelliJ Idea工具下會生成運行名稱, 如下所示:

MyBatis自動代碼生成

點擊剛配置完成的Table-Generator右邊的運行按鈕即可執行生成相關的Entity和Dao代碼包。

5. 查看生成的代碼包

自動生成的MyBatis代碼包

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章