Spring Boot:實現MyBatis動態創建表


綜合概述

在有些應用場景中,我們會有需要動態創建和操作表的需求。比如因為單表數據存儲量太大而采取分表存儲的情況,又或者是按日期生成日志表存儲系統日志等等。這個時候就需要我們動態的生成和操作數據庫表了。而我們都知道,以往我們使用MyBatis是需要提前生成包括Model,Mapper和XML映射文件的,顯然因為動態生成和操作表的需求一開始表都是不存在的,所以也就不能直接通過MyBatis連接數據庫來生成我們的數據訪問層代碼並用來訪問數據庫了。還好MyBatis提供了動態SQL,我們可以通過動態SQL,傳入表名等信息然組裝成建表和操作語句,接下來,我們就通過一個具體的案例來了解一下。

實現案例

先說一下我們要實現的案例,本案例中每個用戶都會有一個自己日志表,其中的user_log_config表就是用戶名和對應的日志表配置,每次往這個表添加配置的時候,系統就會根據配置信息給該用戶生成一個日志存儲表,表名是獲取日志配置表里配置的表名稱,並統一提供對這個日志表的操作接口。本教程案例基於 Spring Boot + Mybatis + MySQL 實現。

生成項目模板

為方便我們初始化項目,Spring Boot給我們提供一個項目模板生成網站。

1.  打開瀏覽器,訪問:https://start.spring.io/

2.  根據頁面提示,選擇構建工具,開發語言,項目信息等。

3.  點擊 Generate the project,生成項目模板,生成之后會將壓縮包下載到本地。

4.  使用IDE導入項目,我這里使用Eclipse,通過導入Maven項目的方式導入。

創建數據庫表

這里使用MySQL數據庫,版本是8.0.16,在項目根目錄下新建db目錄,然后在其中編寫一個數據庫腳本文件。

在MySQL數據庫新建一個springboot數據庫,然后在此數據庫中執行下面的腳本創建項目相關的表。

腳本文件

SQL腳本內容,注意,這里的user_log並不需要用到,事實上,user_log就是我們要生成的表結構,但為了一會兒MyBatis代碼的生成,先創建一下,具體后續會講到。

springboot.sql

-- ----------------------------
-- Table structure for user_log_config
-- ----------------------------
DROP TABLE IF EXISTS `user_log_config`;
CREATE TABLE `user_log_config` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '編號',
  `name` varchar(50) NOT NULL COMMENT '用戶名',
  `table_name` varchar(150) DEFAULT NULL COMMENT '用戶對應的日志存儲表',
  PRIMARY KEY (`id`),
  UNIQUE KEY `name` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=34 DEFAULT CHARSET=utf8 COMMENT='用戶日志表配置';
-- ----------------------------
-- Table structure for user_log
-- ----------------------------
DROP TABLE IF EXISTS `user_log`;
CREATE TABLE `user_log` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '編號',
  `user_name` varchar(50) DEFAULT NULL COMMENT '用戶名',
  `operation` varchar(50) DEFAULT NULL COMMENT '用戶操作',
  `method` varchar(200) DEFAULT NULL COMMENT '請求方法',
  `params` varchar(5000) DEFAULT NULL COMMENT '請求參數',
  `time` bigint(20) NOT NULL COMMENT '執行時長(毫秒)',
  `ip` varchar(64) DEFAULT NULL COMMENT 'IP地址',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2897 DEFAULT CHARSET=utf8 COMMENT='用戶操作日志';

添加相關依賴

需要添加Spring Boot,Mybatis,MySQL,Swagger相關依賴。Swagger方便用來測試接口。

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>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.5.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.louis.springboot</groupId>
    <artifactId>demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>demo</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <!-- web -->
        <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
         </dependency>
        <!-- swagger -->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>2.9.2</version>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>2.9.2</version>
        </dependency>
        <!-- mybatis -->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.0.0</version>
        </dependency>
        <!-- mysql -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </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>
        <!-- 打包時拷貝MyBatis的映射文件 -->
        <resources>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/sqlmap/*.xml</include>
                </includes>
                <filtering>false</filtering>
            </resource>
            <resource>  
                <directory>src/main/resources</directory>  
                    <includes> 
                        <include>**/*.*</include>  
                    </includes> 
                    <filtering>true</filtering>  
            </resource> 
        </resources>
    </build>

</project>

添加配置類

1. 添加swagger 配置

添加一個swagger 配置類,在工程下新建 config 包並添加一個 SwaggerConfig 配置類。

SwaggerConfig.java

package com.louis.springboot.demo.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

@Configuration
@EnableSwagger2
public class SwaggerConfig {

    @Bean
    public Docket createRestApi(){
        return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo())
                .select()
                .apis(RequestHandlerSelectors.any())
                .paths(PathSelectors.any()).build();
    }

    private ApiInfo apiInfo(){
        return new ApiInfoBuilder()
                .title("SpringBoot API Doc")
                .description("This is a restful api document of Spring Boot.")
                .version("1.0")
                .build();
    }

}

2.添加MyBatis配置

添加MyBatis配置類,配置相關掃描路徑,包括DAO,Model,XML映射文件的掃描。

在config包下新建一個MyBatis配置類,MybatisConfig.java。

MybatisConfig.java

package com.louis.springboot.demo.config;
import javax.sql.DataSource;

import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;

@Configuration
@MapperScan("com.louis.springboot.**.dao")    // 掃描DAO
public class MybatisConfig {
  @Autowired
  private DataSource dataSource;

  @Bean
  public SqlSessionFactory sqlSessionFactory() throws Exception {
    SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
    sessionFactory.setDataSource(dataSource);
    sessionFactory.setTypeAliasesPackage("com.louis.springboot.**.model");    // 掃描Model
    
    PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
    sessionFactory.setMapperLocations(resolver.getResources("classpath*:**/sqlmap/*.xml"));    // 掃描映射文件
    
    return sessionFactory.getObject();
  }
}

3.添加數據源配置

將application.properties文件改名為application.yml ,並在其中添加MySQL數據源連接信息。

注意:

這里需要首先創建一個MySQL數據庫,並輸入自己的用戶名和密碼。這里的數據庫是springboot。

另外,如果你使用的是MySQL 5.x及以前版本,驅動配置driverClassName是com.mysql.jdbc.Driver。

application.yml 

server:
  port: 8080
spring:
  datasource:
    driverClassName: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/springboot?useUnicode=true&zeroDateTimeBehavior=convertToNull&autoReconnect=true&characterEncoding=utf-8
    username: root
    password: 123456

生成MyBatis模塊

由於手動編寫MyBatis的Model、DAO、XML映射文件比較繁瑣,通常都會通過一些生成工具來生成。MyBatis官方也提供了生成工具(MyBaits Generator),另外還有一些基於官方基礎上改進的第三方工具,比如MyBatis Plus就是國內提供的一款非常優秀的開源工具,網上相關教程比較多,這里就不再贅述了。

這里提供一些資料作為參考。

Mybatis Generator 官網:http://www.mybatis.org/generator/index.html

Mybatis Generator 教程:https://blog.csdn.net/testcs_dn/article/details/77881776

MyBatis Plus 官網: http://mp.baomidou.com/#/

MyBatis Plus 官網: http://mp.baomidou.com/#/quick-start

代碼生成好之后,分別將MODEL、DAO、XML映射文件拷貝到相應的包里。

生成的Model,如下是user_log_config表對應的Model對象UserLogConfig。

UserLogConfig.java

package com.louis.springboot.demo.model;

public class UserLogConfig {
    private Long id;

    private String name;

    private String tableName;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name == null ? null : name.trim();
    }

    public String getTableName() {
        return tableName;
    }

    public void setTableName(String tableName) {
        this.tableName = tableName == null ? null : tableName.trim();
    }
}

打開Mapper,我們看到MyBatis Generator給我們默認生成了一些增刪改查的方法,另外添加一個查詢全部的方法。

UserLogConfigMapper.java

package com.louis.springboot.demo.dao;

import java.util.List;

import com.louis.springboot.demo.model.UserLogConfig;

public interface UserLogConfigMapper {
    int deleteByPrimaryKey(Long id);

    int insert(UserLogConfig record);

    int insertSelective(UserLogConfig record);

    UserLogConfig selectByPrimaryKey(Long id);

    int updateByPrimaryKeySelective(UserLogConfig record);

    int updateByPrimaryKey(UserLogConfig record);
    
    public List<UserLogConfig> selectAll();
}

在UserLogConfigMapper.xml中編寫selectAll的SQL語句。

UserLogConfigMapper.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.louis.springboot.demo.dao.UserLogConfigMapper">
  <resultMap id="BaseResultMap" type="com.louis.springboot.demo.model.UserLogConfig">
    <id column="id" jdbcType="BIGINT" property="id" />
    <result column="name" jdbcType="VARCHAR" property="name" />
    <result column="table_name" jdbcType="VARCHAR" property="tableName" />
  </resultMap>
  <sql id="Base_Column_List">
    id, name, table_name
  </sql>
  <select id="selectByPrimaryKey" parameterType="java.lang.Long" resultMap="BaseResultMap">
    select 
    <include refid="Base_Column_List" />
    from user_log_config
    where id = #{id,jdbcType=BIGINT}
  </select>
  <delete id="deleteByPrimaryKey" parameterType="java.lang.Long">
    delete from user_log_config
    where id = #{id,jdbcType=BIGINT}
  </delete>
  <insert id="insert" parameterType="com.louis.springboot.demo.model.UserLogConfig">
    insert into user_log_config (id, name, table_name
      )
    values (#{id,jdbcType=BIGINT}, #{name,jdbcType=VARCHAR}, #{tableName,jdbcType=VARCHAR}
      )
  </insert>
  <insert id="insertSelective" parameterType="com.louis.springboot.demo.model.UserLogConfig">
    insert into user_log_config
    <trim prefix="(" suffix=")" suffixOverrides=",">
      <if test="id != null">
        id,
      </if>
      <if test="name != null">
        name,
      </if>
      <if test="tableName != null">
        table_name,
      </if>
    </trim>
    <trim prefix="values (" suffix=")" suffixOverrides=",">
      <if test="id != null">
        #{id,jdbcType=BIGINT},
      </if>
      <if test="name != null">
        #{name,jdbcType=VARCHAR},
      </if>
      <if test="tableName != null">
        #{tableName,jdbcType=VARCHAR},
      </if>
    </trim>
  </insert>
  <update id="updateByPrimaryKeySelective" parameterType="com.louis.springboot.demo.model.UserLogConfig">
    update user_log_config
    <set>
      <if test="name != null">
        name = #{name,jdbcType=VARCHAR},
      </if>
      <if test="tableName != null">
        table_name = #{tableName,jdbcType=VARCHAR},
      </if>
    </set>
    where id = #{id,jdbcType=BIGINT}
  </update>
  <update id="updateByPrimaryKey" parameterType="com.louis.springboot.demo.model.UserLogConfig">
    update user_log_config
    set name = #{name,jdbcType=VARCHAR},
      table_name = #{tableName,jdbcType=VARCHAR}
    where id = #{id,jdbcType=BIGINT}
  </update>
  <select id="selectAll" resultMap="BaseResultMap">
    select 
    <include refid="Base_Column_List" />
    from user_log_config
  </select>
</mapper>

編寫UserLogConfig的服務接口。

UserLogConfigService.java

package com.louis.springboot.demo.service;
import java.util.List;

import com.louis.springboot.demo.model.UserLogConfig;

public interface UserLogConfigService {

    /**
     * 保存用戶日志配置
     * @return
     */
    void save(UserLogConfig userLogConfig);
    
    /**
     * 查找全部用戶日志配置
     * @return
     */
    List<UserLogConfig> findAll();

}

編寫UserLogConfig的服務實現類。

UserLogConfigServiceImpl.java

package com.louis.springboot.demo.service.impl;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.louis.springboot.demo.dao.UserLogConfigMapper;
import com.louis.springboot.demo.model.UserLogConfig;
import com.louis.springboot.demo.service.UserLogConfigService;

@Service
public class UserLogConfigServiceImpl implements UserLogConfigService {
    
    @Autowired
    private UserLogConfigMapper userLogConfigMapper;
    
    @Override
    public void save(UserLogConfig userLogConfig) {
        if(userLogConfig.getId() != null && !"".equals(userLogConfig.getId())) {
            // 更新
            userLogConfigMapper.updateByPrimaryKeySelective(userLogConfig);
        } else {
            // 插入
            userLogConfigMapper.insertSelective(userLogConfig);
        }
    }
    
    @Override
    public List<UserLogConfig> findAll() {
        return userLogConfigMapper.selectAll();
    }
}

編寫UserLogConfig的控制器。

UserLogConfigController.java

package com.louis.springboot.demo.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.louis.springboot.demo.model.UserLogConfig;
import com.louis.springboot.demo.service.UserLogConfigService;

@RestController
@RequestMapping("user/log/config")
public class UserLogConfigController {

    @Autowired
    private UserLogConfigService userLogConfigService;
    
    @PostMapping(value="/save")
    public Object save(@RequestBody UserLogConfig userLogConfig) {
        userLogConfigService.save(userLogConfig);
        return 1;
    }
    
    @GetMapping(value="/findAll")
    public Object findAll() {
        return userLogConfigService.findAll();
    }
}

現在我們來講解如何動態實現動態生成用戶日志存儲表(user_log的表結構),之前我們通過MyBatis生成了user_log的服務訪問層代碼,下面是Model類UserLog,你可以直接用或改個名稱都行,我們這里就不改了。

UserLog.java

package com.louis.springboot.demo.model;

public class UserLog {
    private Long id;

    private String userName;

    private String operation;

    private String method;

    private String params;

    private Long time;

    private String ip;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName == null ? null : userName.trim();
    }

    public String getOperation() {
        return operation;
    }

    public void setOperation(String operation) {
        this.operation = operation == null ? null : operation.trim();
    }

    public String getMethod() {
        return method;
    }

    public void setMethod(String method) {
        this.method = method == null ? null : method.trim();
    }

    public String getParams() {
        return params;
    }

    public void setParams(String params) {
        this.params = params == null ? null : params.trim();
    }

    public Long getTime() {
        return time;
    }

    public void setTime(Long time) {
        this.time = time;
    }

    public String getIp() {
        return ip;
    }

    public void setIp(String ip) {
        this.ip = ip == null ? null : ip.trim();
    }
}

修改UserLogMapper,將原有的接口都加上tableName參數,傳入表名以確定要操作的表。另外額外添加了三個跟建表有關的方法。

UserLogMapper.java

package com.louis.springboot.demo.dao;

import java.util.List;

import org.apache.ibatis.annotations.Param;

import com.louis.springboot.demo.model.UserLog;

public interface UserLogMapper {
    int deleteByPrimaryKey(@Param("tableName")String tableName, @Param("id")Long id);

    int insert(@Param("tableName")String tableName, @Param("userLog") UserLog userLog);

    int insertSelective(@Param("tableName")String tableName, @Param("userLog") UserLog record);

    UserLog selectByPrimaryKey(@Param("tableName")String tableName, @Param("id")Long id);

    int updateByPrimaryKeySelective(@Param("tableName")String tableName, @Param("userLog") UserLog record);

    int updateByPrimaryKey(@Param("tableName")String tableName, @Param("userLog") UserLog record);
    
    /**
     * 查找全部
     * @param tableName
     * @return
     */
    List<UserLog> selectAll(@Param("tableName")String tableName);
    
    /**
     * 是否存在表
     * @param tableName
     * @return
     */
    int existTable(@Param("tableName")String tableName);
    /**
     * 刪除表
     * @param tableName
     * @return
     */
    int dropTable(@Param("tableName")String tableName);
    /**
     * 創建表
     * @param tableName
     * @return
     */
    int createTable(@Param("tableName")String tableName);
}

修改UserLogMapper.xml,將原來用表名user_log的地方替換成${tableName},表示表名由外部方法傳入。另外編寫另外三個建表相關的語句,檢查表是否存在和刪除表的語句比較簡單,創建表的只要把建表語句拷貝過來,然后把表名替換成${tableName}就行了。

UserLogMapper.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.louis.springboot.demo.dao.UserLogMapper">
  <resultMap id="BaseResultMap" type="com.louis.springboot.demo.model.UserLog">
    <id column="id" jdbcType="BIGINT" property="id" />
    <result column="user_name" jdbcType="VARCHAR" property="userName" />
    <result column="operation" jdbcType="VARCHAR" property="operation" />
    <result column="method" jdbcType="VARCHAR" property="method" />
    <result column="params" jdbcType="VARCHAR" property="params" />
    <result column="time" jdbcType="BIGINT" property="time" />
    <result column="ip" jdbcType="VARCHAR" property="ip" />
  </resultMap>
  <sql id="Base_Column_List">
    id, user_name, operation, method, params, time, ip
  </sql>
  <select id="selectByPrimaryKey" parameterType="java.lang.Long" resultMap="BaseResultMap">
    select 
    <include refid="Base_Column_List" />
    from ${tableName}
    where id = #{id,jdbcType=BIGINT}
  </select>
  <delete id="deleteByPrimaryKey" parameterType="java.lang.Long">
    delete from ${tableName}
    where id = #{id,jdbcType=BIGINT}
  </delete>
  <insert id="insert" parameterType="com.louis.springboot.demo.model.UserLog">
    insert into ${tableName} (id, user_name, operation, 
      method, params, time, 
      ip)
    values (#{id,jdbcType=BIGINT}, #{userName,jdbcType=VARCHAR}, #{operation,jdbcType=VARCHAR}, 
      #{method,jdbcType=VARCHAR}, #{params,jdbcType=VARCHAR}, #{time,jdbcType=BIGINT}, 
      #{ip,jdbcType=VARCHAR})
  </insert>
  <insert id="insertSelective" parameterType="com.louis.springboot.demo.model.UserLog">
    insert into ${tableName}
    <trim prefix="(" suffix=")" suffixOverrides=",">
      <if test="id != null">
        id,
      </if>
      <if test="userName != null">
        user_name,
      </if>
      <if test="operation != null">
        operation,
      </if>
      <if test="method != null">
        method,
      </if>
      <if test="params != null">
        params,
      </if>
      <if test="time != null">
        time,
      </if>
      <if test="ip != null">
        ip,
      </if>
    </trim>
    <trim prefix="values (" suffix=")" suffixOverrides=",">
      <if test="id != null">
        #{id,jdbcType=BIGINT},
      </if>
      <if test="userName != null">
        #{userName,jdbcType=VARCHAR},
      </if>
      <if test="operation != null">
        #{operation,jdbcType=VARCHAR},
      </if>
      <if test="method != null">
        #{method,jdbcType=VARCHAR},
      </if>
      <if test="params != null">
        #{params,jdbcType=VARCHAR},
      </if>
      <if test="time != null">
        #{time,jdbcType=BIGINT},
      </if>
      <if test="ip != null">
        #{ip,jdbcType=VARCHAR},
      </if>
    </trim>
  </insert>
  <update id="updateByPrimaryKeySelective" parameterType="com.louis.springboot.demo.model.UserLog">
    update ${tableName}
    <set>
      <if test="userName != null">
        user_name = #{userName,jdbcType=VARCHAR},
      </if>
      <if test="operation != null">
        operation = #{operation,jdbcType=VARCHAR},
      </if>
      <if test="method != null">
        method = #{method,jdbcType=VARCHAR},
      </if>
      <if test="params != null">
        params = #{params,jdbcType=VARCHAR},
      </if>
      <if test="time != null">
        time = #{time,jdbcType=BIGINT},
      </if>
      <if test="ip != null">
        ip = #{ip,jdbcType=VARCHAR},
      </if>
    </set>
    where id = #{id,jdbcType=BIGINT}
  </update>
  <update id="updateByPrimaryKey" parameterType="com.louis.springboot.demo.model.UserLog">
    update ${tableName}
    set user_name = #{userName,jdbcType=VARCHAR},
      operation = #{operation,jdbcType=VARCHAR},
      method = #{method,jdbcType=VARCHAR},
      params = #{params,jdbcType=VARCHAR},
      time = #{time,jdbcType=BIGINT},
      ip = #{ip,jdbcType=VARCHAR}
    where id = #{id,jdbcType=BIGINT}
  </update>
  
  <select id="selectAll" resultMap="BaseResultMap">
    select 
    <include refid="Base_Column_List" />
    from ${tableName}
  </select>
  
  <select id="existTable" parameterType="String" resultType="Integer">  
    select count(*)  
    from information_schema.TABLES  
    where table_name=#{tableName} 
  </select>
  
  <update id="dropTable">  
    DROP TABLE IF EXISTS ${tableName} 
  </update>  
  
  <update id="createTable" parameterType="String">  
    CREATE TABLE ${tableName} (
      `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '編號',
      `user_name` varchar(50) DEFAULT NULL COMMENT '用戶名',
      `operation` varchar(50) DEFAULT NULL COMMENT '用戶操作',
      `method` varchar(200) DEFAULT NULL COMMENT '請求方法',
      `params` varchar(5000) DEFAULT NULL COMMENT '請求參數',
      `time` bigint(20) NOT NULL COMMENT '執行時長(毫秒)',
      `ip` varchar(64) DEFAULT NULL COMMENT 'IP地址',
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=2897 DEFAULT CHARSET=utf8 COMMENT='用戶操作日志';
  </update> 
</mapper>

編寫用戶日志的服務接口,包含一個保存方法和一個查詢方法。

UserLogService.java

package com.louis.springboot.demo.service;
import java.util.List;

import com.louis.springboot.demo.model.UserLog;

public interface UserLogService {

    /**
     * 保存用戶日志
     * @return
     */
    void save(String tableName, UserLog userLog);
    
    /**
     * 查找全部用戶日志
     * @return
     */
    List<UserLog> findAll(String tableName);

}

編寫用戶日志的服務實現類,包含保存方法和查詢方法的實現。

UserLogServiceImpl.java

package com.louis.springboot.demo.service.impl;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.louis.springboot.demo.dao.UserLogMapper;
import com.louis.springboot.demo.model.UserLog;
import com.louis.springboot.demo.service.UserLogService;

@Service
public class UserLogServiceImpl implements UserLogService {
    
    @Autowired
    private UserLogMapper userLogMapper;
    
    @Override
    public void save(String tableName, UserLog userLog) {
        // 插入
        userLogMapper.insertSelective(tableName, userLog);
    }
    
    @Override
    public List<UserLog> findAll(String tableName) {
        return userLogMapper.selectAll(tableName);
    }
}

為了接口傳表名方便,我們這里在UserLog類里加入一個tableName屬性,用來給接口傳入表名。

UserLog.java

package com.louis.springboot.demo.model;

public class UserLog {
    private Long id;

    private String userName;

    private String operation;

    private String method;

    private String params;

    private Long time;

    private String ip;
    
    private String tableName;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName == null ? null : userName.trim();
    }

    public String getOperation() {
        return operation;
    }

    public void setOperation(String operation) {
        this.operation = operation == null ? null : operation.trim();
    }

    public String getMethod() {
        return method;
    }

    public void setMethod(String method) {
        this.method = method == null ? null : method.trim();
    }

    public String getParams() {
        return params;
    }

    public void setParams(String params) {
        this.params = params == null ? null : params.trim();
    }

    public Long getTime() {
        return time;
    }

    public void setTime(Long time) {
        this.time = time;
    }

    public String getIp() {
        return ip;
    }

    public void setIp(String ip) {
        this.ip = ip == null ? null : ip.trim();
    }

    public String getTableName() {
        return tableName;
    }

    public void setTableName(String tableName) {
        this.tableName = tableName;
    }
    
}

編寫服務控制器UserLogController並調用服務的相關接口。

UserLogController.java

package com.louis.springboot.demo.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.louis.springboot.demo.model.UserLog;
import com.louis.springboot.demo.service.UserLogService;

@RestController
@RequestMapping("user/log")
public class UserLogController {

    @Autowired
    private UserLogService userLogService;
    
    @PostMapping(value="/save")
    public Object save(@RequestBody UserLog userLog) {
        String tableName = userLog.getTableName();
        userLogService.save(tableName, userLog);
        return 1;
    }
    
    @GetMapping(value="/findAll")
    public Object findAll(String tableName) {
        return userLogService.findAll(tableName);
    }
}

修改UserLogConfigServiceImpl的save方法,實現在添加配置的時候生成對應的表。

UserLogConfigServiceImpl.java

package com.louis.springboot.demo.service.impl;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.louis.springboot.demo.dao.UserLogConfigMapper;
import com.louis.springboot.demo.dao.UserLogMapper;
import com.louis.springboot.demo.model.UserLogConfig;
import com.louis.springboot.demo.service.UserLogConfigService;

@Service
public class UserLogConfigServiceImpl implements UserLogConfigService {
    
    @Autowired
    private UserLogConfigMapper userLogConfigMapper;
    @Autowired
    private UserLogMapper userLogMapper;
    
    @Override
    public void save(UserLogConfig userLogConfig) {
        // 插入
        userLogConfigMapper.insertSelective(userLogConfig);
        // 添加配置時,創建日志存儲表
        String tableName = userLogConfig.getTableName();
        if(userLogMapper.existTable(tableName) > 0) {
            userLogMapper.dropTable(tableName);
        }
        userLogMapper.createTable(tableName);
    }
    
    @Override
    public List<UserLogConfig> findAll() {
        return userLogConfigMapper.selectAll();
    }
}

 

編譯測試運行

1.  右鍵項目 -> Run as -> Maven install,開始執行Maven構建,第一次會下載Maven依賴,可能需要點時間,如果出現如下信息,就說明項目編譯打包成功了。

2.  右鍵文件 DemoApplication.java -> Run as -> Java Application,開始啟動應用,當出現如下信息的時候,就說明應用啟動成功了,默認啟動端口是8080。

3.  打開瀏覽器,訪問:http://localhost:8080/swagger-ui.html,進入swagger接口文檔界面。

4.  測試UserLogConfigMapper的save保存接口,輸入以下參數進行測試。

{
  "id": 1,
  "name": "xiaoming",
  "tableName": "xiaoming"
}

成功之后調UserLogConfigMapper的findAll接口,可以看到配置信息已經成功插入。

並且我們可以通過MySQL客戶端查看到,在配置生成的同時生成了一個表名為xiaoming的數據庫表。

5.  測試UserLogController的save保存接口,輸入以下參數進行測試。

{
  "id": 1,
  "ip": "139.123.123.100",
  "method": "save",
  "operation": "save",
  "params": "string name",
  "tableName": "xiaoming",
  "time": 0,
  "userName": "xiaoming"
}

成功之后調UserLogController的findAll接口,可以看到配置信息已經成功插入。

測試到此,我們成功的保存了配置信息,並且動態創建了一個表,然后成功的往表里插入了一點數據,並通過接口查詢出了插入的數據。

 

參考資料

MyBatis 官網:http://www.mybatis.org/mybatis-3/zh/index.html

MyBatis Generator 官網:http://www.mybatis.org/generator/index.html

MyBatis Plus 官網: http://mp.baomidou.com/#/quick-start

相關導航

Spring Boot 系列教程目錄導航

Spring Boot:快速入門教程

Spring Boot:整合Swagger文檔

Spring Boot:整合MyBatis框架

Spring Boot:實現MyBatis分頁

源碼下載

碼雲:https://gitee.com/liuge1988/spring-boot-demo.git


作者:朝雨憶輕塵
出處:https://www.cnblogs.com/xifengxiaoma/ 
版權所有,歡迎轉載,轉載請注明原文作者及出處。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM