springboot 整合 mybatis自定义插件实现字段的属性注入


一、技术简介

自定义mybatis插件可以帮助我们省去某些频繁的操作,如数据库表的有更新时间和修改时间的,我们可以通过插件来处理,而不需要再controller层或serevice层手动判断和设置两个时间。当然自定义插件的应用远不止于此,这里不过多赘述。

二、介绍技术的难点和关键知识点

首先是定义插件时的参数介绍,不同的参数决定了我们的拦截器拦截的位置。

Mybatis 提供 Interceptor 接口,配合 @Intercepts 注解可以拦截如下 4 个对象的方法调用:

1 Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
2 ParameterHandler (getParameterObject, setParameters)
3 ResultSetHandler (handleResultSets, handleOutputParameters)
4 StatementHandler (prepare, parameterize, batch, update, query)

其关系如下图:

解释:

  1. Executor 是 Mybatis 的内部执行器,它负责调用 StatementHandler 操作数据库,并把结果集通过 ResultSetHandler 进行自动映射,另外,它还处理了二级缓存的操作。

  2. StatementHandler 是 Mybatis 直接和数据库执行 sql 脚本的对象,另外,它也实现了 Mybatis 的一级缓存。

  3. ParameterHandler 是 Mybatis 实现 sql 入参设置的对象。

  4. ResultSetHandler 是 Mybatis 把 ResultSet 集合映射成 POJO 的接口对象。

本篇不陈述 Mybatis 的内部原理,感兴趣的读取请自行查阅相关资料。

三、搭建一个springboot的demo,能够实现基本的数据库操作。

项目架构:

 

 

controller层:

/**
 * @version: 1.0
 * @author: tesla
 * @className: UserController
 * @packageName: com.tesla.mybatis.controller
 * @description:
 * @data: 2020/7/6 11:30
 */

@RestController
@RequestMapping("/sysuser")
public class UserController {

    @Resource
    UserService userService;

    @RequestMapping("/insert")
    public String insert(){
        SysUser sysUser = new SysUser();
        sysUser.setLoginName("weng");
        sysUser.setUserName("1230");
        userService.insert(sysUser);
        return "success";
    }


}

service层:

/**
 * @version: 1.0
 * @author: tesla
 * @className: UserServices
 * @packageName: com.tesla.mybatis.service
 * @description:
 * @data: 2020/7/6 10:00
 */

@Service
public class UserServiceImpl implements UserService {

    @Resource
    SysUserMapper sysUserMapper;

    private final static Logger log = LoggerFactory.getLogger(UserServiceImpl.class);

    public int insert(SysUser record){
        int result = 0;try{
            result = sysUserMapper.insert(record);
        }catch (Exception e){
            log.error(e+"插入用户出错");
            throw e;
        }

        return result;
    }
}

mapper层:

@Mapper
public interface SysUserMapper {
    int deleteByPrimaryKey(Long userId);

    int insert(SysUser record);

    int insertSelective(SysUser record);

    SysUser selectByPrimaryKey(Long userId);

    int updateByPrimaryKeySelective(SysUser record);

    int updateByPrimaryKey(SysUser record);

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.tesla.mybatis.mapper.SysUserMapper">
  <resultMap id="BaseResultMap" type="com.tesla.mybatis.entity.SysUser">
    <id column="user_id" jdbcType="BIGINT" property="userId" />
    <result column="dept_id" jdbcType="BIGINT" property="deptId" />
    <result column="login_name" jdbcType="VARCHAR" property="loginName" />
    <result column="user_name" jdbcType="VARCHAR" property="userName" />
    <result column="user_type" jdbcType="VARCHAR" property="userType" />
    <result column="email" jdbcType="VARCHAR" property="email" />
    <result column="phonenumber" jdbcType="VARCHAR" property="phonenumber" />
    <result column="sex" jdbcType="CHAR" property="sex" />
    <result column="avatar" jdbcType="VARCHAR" property="avatar" />
    <result column="password" jdbcType="VARCHAR" property="password" />
    <result column="salt" jdbcType="VARCHAR" property="salt" />
    <result column="status" jdbcType="CHAR" property="status" />
    <result column="del_flag" jdbcType="CHAR" property="delFlag" />
    <result column="login_ip" jdbcType="VARCHAR" property="loginIp" />
    <result column="login_date" jdbcType="TIMESTAMP" property="loginDate" />
    <result column="create_by" jdbcType="VARCHAR" property="createBy" />
    <result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
    <result column="update_by" jdbcType="VARCHAR" property="updateBy" />
    <result column="update_time" jdbcType="TIMESTAMP" property="updateTime" />
    <result column="remark" jdbcType="VARCHAR" property="remark" />
  </resultMap>
  <sql id="Base_Column_List">
    user_id, dept_id, login_name, user_name, user_type, email, phonenumber, sex, avatar, 
    password, salt, status, del_flag, login_ip, login_date, create_by, create_time, update_by, 
    update_time, remark
  </sql>
  <select id="selectByPrimaryKey" parameterType="java.lang.Long" resultMap="BaseResultMap">
    select 
    <include refid="Base_Column_List" />
    from sys_user
    where user_id = #{userId,jdbcType=BIGINT}
  </select>
  <delete id="deleteByPrimaryKey" parameterType="java.lang.Long">
    delete from sys_user
    where user_id = #{userId,jdbcType=BIGINT}
  </delete>
  <insert id="insert" parameterType="com.tesla.mybatis.entity.SysUser">
    insert into sys_user (user_id, dept_id, login_name, 
      user_name, user_type, email, 
      phonenumber, sex, avatar, 
      password, salt, status, 
      del_flag, login_ip, login_date, 
      create_by, create_time, update_by, 
      update_time, remark)
    values (#{userId,jdbcType=BIGINT}, #{deptId,jdbcType=BIGINT}, #{loginName,jdbcType=VARCHAR}, 
      #{userName,jdbcType=VARCHAR}, #{userType,jdbcType=VARCHAR}, #{email,jdbcType=VARCHAR}, 
      #{phonenumber,jdbcType=VARCHAR}, #{sex,jdbcType=CHAR}, #{avatar,jdbcType=VARCHAR}, 
      #{password,jdbcType=VARCHAR}, #{salt,jdbcType=VARCHAR}, #{status,jdbcType=CHAR}, 
      #{delFlag,jdbcType=CHAR}, #{loginIp,jdbcType=VARCHAR}, #{loginDate,jdbcType=TIMESTAMP}, 
      #{createBy,jdbcType=VARCHAR}, #{createTime,jdbcType=TIMESTAMP}, #{updateBy,jdbcType=VARCHAR}, 
      #{updateTime,jdbcType=TIMESTAMP}, #{remark,jdbcType=VARCHAR})
  </insert>
  <insert id="insertSelective" parameterType="com.tesla.mybatis.entity.SysUser">
    insert into sys_user
    <trim prefix="(" suffix=")" suffixOverrides=",">
      <if test="userId != null">
        user_id,
      </if>
      <if test="deptId != null">
        dept_id,
      </if>
      <if test="loginName != null">
        login_name,
      </if>
      <if test="userName != null">
        user_name,
      </if>
      <if test="userType != null">
        user_type,
      </if>
      <if test="email != null">
        email,
      </if>
      <if test="phonenumber != null">
        phonenumber,
      </if>
      <if test="sex != null">
        sex,
      </if>
      <if test="avatar != null">
        avatar,
      </if>
      <if test="password != null">
        password,
      </if>
      <if test="salt != null">
        salt,
      </if>
      <if test="status != null">
        status,
      </if>
      <if test="delFlag != null">
        del_flag,
      </if>
      <if test="loginIp != null">
        login_ip,
      </if>
      <if test="loginDate != null">
        login_date,
      </if>
      <if test="createBy != null">
        create_by,
      </if>
      <if test="createTime != null">
        create_time,
      </if>
      <if test="updateBy != null">
        update_by,
      </if>
      <if test="updateTime != null">
        update_time,
      </if>
      <if test="remark != null">
        remark,
      </if>
    </trim>
    <trim prefix="values (" suffix=")" suffixOverrides=",">
      <if test="userId != null">
        #{userId,jdbcType=BIGINT},
      </if>
      <if test="deptId != null">
        #{deptId,jdbcType=BIGINT},
      </if>
      <if test="loginName != null">
        #{loginName,jdbcType=VARCHAR},
      </if>
      <if test="userName != null">
        #{userName,jdbcType=VARCHAR},
      </if>
      <if test="userType != null">
        #{userType,jdbcType=VARCHAR},
      </if>
      <if test="email != null">
        #{email,jdbcType=VARCHAR},
      </if>
      <if test="phonenumber != null">
        #{phonenumber,jdbcType=VARCHAR},
      </if>
      <if test="sex != null">
        #{sex,jdbcType=CHAR},
      </if>
      <if test="avatar != null">
        #{avatar,jdbcType=VARCHAR},
      </if>
      <if test="password != null">
        #{password,jdbcType=VARCHAR},
      </if>
      <if test="salt != null">
        #{salt,jdbcType=VARCHAR},
      </if>
      <if test="status != null">
        #{status,jdbcType=CHAR},
      </if>
      <if test="delFlag != null">
        #{delFlag,jdbcType=CHAR},
      </if>
      <if test="loginIp != null">
        #{loginIp,jdbcType=VARCHAR},
      </if>
      <if test="loginDate != null">
        #{loginDate,jdbcType=TIMESTAMP},
      </if>
      <if test="createBy != null">
        #{createBy,jdbcType=VARCHAR},
      </if>
      <if test="createTime != null">
        #{createTime,jdbcType=TIMESTAMP},
      </if>
      <if test="updateBy != null">
        #{updateBy,jdbcType=VARCHAR},
      </if>
      <if test="updateTime != null">
        #{updateTime,jdbcType=TIMESTAMP},
      </if>
      <if test="remark != null">
        #{remark,jdbcType=VARCHAR},
      </if>
    </trim>
  </insert>
  <update id="updateByPrimaryKeySelective" parameterType="com.tesla.mybatis.entity.SysUser">
    update sys_user
    <set>
      <if test="deptId != null">
        dept_id = #{deptId,jdbcType=BIGINT},
      </if>
      <if test="loginName != null">
        login_name = #{loginName,jdbcType=VARCHAR},
      </if>
      <if test="userName != null">
        user_name = #{userName,jdbcType=VARCHAR},
      </if>
      <if test="userType != null">
        user_type = #{userType,jdbcType=VARCHAR},
      </if>
      <if test="email != null">
        email = #{email,jdbcType=VARCHAR},
      </if>
      <if test="phonenumber != null">
        phonenumber = #{phonenumber,jdbcType=VARCHAR},
      </if>
      <if test="sex != null">
        sex = #{sex,jdbcType=CHAR},
      </if>
      <if test="avatar != null">
        avatar = #{avatar,jdbcType=VARCHAR},
      </if>
      <if test="password != null">
        password = #{password,jdbcType=VARCHAR},
      </if>
      <if test="salt != null">
        salt = #{salt,jdbcType=VARCHAR},
      </if>
      <if test="status != null">
        status = #{status,jdbcType=CHAR},
      </if>
      <if test="delFlag != null">
        del_flag = #{delFlag,jdbcType=CHAR},
      </if>
      <if test="loginIp != null">
        login_ip = #{loginIp,jdbcType=VARCHAR},
      </if>
      <if test="loginDate != null">
        login_date = #{loginDate,jdbcType=TIMESTAMP},
      </if>
      <if test="createBy != null">
        create_by = #{createBy,jdbcType=VARCHAR},
      </if>
      <if test="createTime != null">
        create_time = #{createTime,jdbcType=TIMESTAMP},
      </if>
      <if test="updateBy != null">
        update_by = #{updateBy,jdbcType=VARCHAR},
      </if>
      <if test="updateTime != null">
        update_time = #{updateTime,jdbcType=TIMESTAMP},
      </if>
      <if test="remark != null">
        remark = #{remark,jdbcType=VARCHAR},
      </if>
    </set>
    where user_id = #{userId,jdbcType=BIGINT}
  </update>
  <update id="updateByPrimaryKey" parameterType="com.tesla.mybatis.entity.SysUser">
    update sys_user
    set dept_id = #{deptId,jdbcType=BIGINT},
      login_name = #{loginName,jdbcType=VARCHAR},
      user_name = #{userName,jdbcType=VARCHAR},
      user_type = #{userType,jdbcType=VARCHAR},
      email = #{email,jdbcType=VARCHAR},
      phonenumber = #{phonenumber,jdbcType=VARCHAR},
      sex = #{sex,jdbcType=CHAR},
      avatar = #{avatar,jdbcType=VARCHAR},
      password = #{password,jdbcType=VARCHAR},
      salt = #{salt,jdbcType=VARCHAR},
      status = #{status,jdbcType=CHAR},
      del_flag = #{delFlag,jdbcType=CHAR},
      login_ip = #{loginIp,jdbcType=VARCHAR},
      login_date = #{loginDate,jdbcType=TIMESTAMP},
      create_by = #{createBy,jdbcType=VARCHAR},
      create_time = #{createTime,jdbcType=TIMESTAMP},
      update_by = #{updateBy,jdbcType=VARCHAR},
      update_time = #{updateTime,jdbcType=TIMESTAMP},
      remark = #{remark,jdbcType=VARCHAR}
    where user_id = #{userId,jdbcType=BIGINT}
  </update>
</mapper>

实体类SysUser:

package com.tesla.mybatis.entity;

import org.springframework.stereotype.Repository;

import java.util.Date;


@Repository
public class SysUser {
    private Long userId;

    private Long deptId;

    private String loginName;

    private String userName;

    private String userType;

    private String email;

    private String phonenumber;

    private String sex;

    private String avatar;

    private String password;

    private String salt;

    private String status;

    private String delFlag;

    private String loginIp;

    private Date loginDate;

    private String createBy;

    private Date createTime;

    private String updateBy;

    private Date updateTime;

    private String remark;

    public Long getUserId() {
        return userId;
    }

    public void setUserId(Long userId) {
        this.userId = userId;
    }

    public Long getDeptId() {
        return deptId;
    }

    public void setDeptId(Long deptId) {
        this.deptId = deptId;
    }

    public String getLoginName() {
        return loginName;
    }

    public void setLoginName(String loginName) {
        this.loginName = loginName == null ? null : loginName.trim();
    }

    public String getUserName() {
        return userName;
    }

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

    public String getUserType() {
        return userType;
    }

    public void setUserType(String userType) {
        this.userType = userType == null ? null : userType.trim();
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email == null ? null : email.trim();
    }

    public String getPhonenumber() {
        return phonenumber;
    }

    public void setPhonenumber(String phonenumber) {
        this.phonenumber = phonenumber == null ? null : phonenumber.trim();
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex == null ? null : sex.trim();
    }

    public String getAvatar() {
        return avatar;
    }

    public void setAvatar(String avatar) {
        this.avatar = avatar == null ? null : avatar.trim();
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password == null ? null : password.trim();
    }

    public String getSalt() {
        return salt;
    }

    public void setSalt(String salt) {
        this.salt = salt == null ? null : salt.trim();
    }

    public String getStatus() {
        return status;
    }

    public void setStatus(String status) {
        this.status = status == null ? null : status.trim();
    }

    public String getDelFlag() {
        return delFlag;
    }

    public void setDelFlag(String delFlag) {
        this.delFlag = delFlag == null ? null : delFlag.trim();
    }

    public String getLoginIp() {
        return loginIp;
    }

    public void setLoginIp(String loginIp) {
        this.loginIp = loginIp == null ? null : loginIp.trim();
    }

    public Date getLoginDate() {
        return loginDate;
    }

    public void setLoginDate(Date loginDate) {
        this.loginDate = loginDate;
    }

    public String getCreateBy() {
        return createBy;
    }

    public void setCreateBy(String createBy) {
        this.createBy = createBy == null ? null : createBy.trim();
    }

    public Date getCreateTime() {
        return createTime;
    }

    public void setCreateTime(Date createTime) {
        this.createTime = createTime;
    }

    public String getUpdateBy() {
        return updateBy;
    }

    public void setUpdateBy(String updateBy) {
        this.updateBy = updateBy == null ? null : updateBy.trim();
    }

    public Date getUpdateTime() {
        return updateTime;
    }

    public void setUpdateTime(Date updateTime) {
        this.updateTime = updateTime;
    }

    public String getRemark() {
        return remark;
    }

    public void setRemark(String remark) {
        this.remark = remark == null ? null : remark.trim();
    }
}

配置文件:

server:
  port: 8081
spring:
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3306/huhutong?characterEncoding=utf8&useSSL=false
    password: w308557035
    username: root
  application:
    name:
mybatis:
  # 搜索指定包别名
  typeAliasesPackage: com.tesla.**.entity
  # 配置mapper的扫描,找到所有的mapper.xml映射文件
  mapperLocations: classpath*:/mappers/*Mapper.xml
# 加载全局的配置文件
#  configLocation: classpath:mybatis/mybatis-config.xml

这里为了大家方便,我贴出了demo几乎所有的代码,如果读者觉得太复杂,完全可以自己定义。到此为止spirngboot的demo就结束,我们可以来测试一下没有插件的情况下,执行插入的结果。浏览器输入http://localhost:8081/sysuser/insert,查看数据库变化

 

 可以看到createTime为空。

四、自定义mybatis插件,同时使用@Conponent注解交给spring来管理

package com.tesla.mybatis.plugin;

import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.plugin.*;

import java.lang.reflect.Field;
import java.util.Date;
import java.util.Properties;

/**
 * @version: 1.0
 * @author: tesla
 * @className: Myplugin
 * @packageName: com.tesla.mybatis.plugin
 * @description: 自定义插件拦截器,实现字段的属性注入
 * @data: 2020/7/6 15:10
 */

@Intercepts(
        @Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class})
)
@Component
public class Myplugin implements Interceptor { //获取到拦截的对象,底层也是通过代理来实现的,实际上是拿到一个目标的代理对象 @Override public Object plugin(Object target) { return Plugin.wrap(target,this); } //获取配置文件中设置的阈值等参数 @Override public void setProperties(Properties properties) { } @Override public Object intercept(Invocation invocation) throws Throwable { MappedStatement mappedStatement = (MappedStatement)invocation.getArgs()[0]; //获取操作类型,crud SqlCommandType sqlCommandType = mappedStatement.getSqlCommandType(); //获取参数 Object parameter = invocation.getArgs()[1]; Field[]fields = parameter.getClass().getDeclaredFields(); for(Field field: fields){ //注入对应的属性值 if (field.getName().equals("createTime")&&SqlCommandType.INSERT.equals(sqlCommandType)){ field.setAccessible(true); field.set(parameter,new Date()); } if (field.getName().equals("updateTime")&&SqlCommandType.UPDATE.equals(sqlCommandType)){ field.setAccessible(true); field.set(parameter,new Date()); } } Object object = invocation.proceed(); return object; } }

 

这里我们插件内的逻辑是根据反射设置参数中含有createTime和updateTime属性的值。

 

重启idea,再次访问接口,http://localhost:8081/sysuser/insert

 

 可以看到,这次有创建时间了。

五、总结和补充或拓展

在自动注入时,根据属性名称设置值有局限性且,优化方向是自定义注解,然后将注解打在需要注入的字段上,拦截器中根据属性上的注解来判断是否设置parameter的值。


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM