精华内容
下载资源
问答
  • * 自定义 Mybatis 插件,自动设置 createTime 和 updatTime 的值。 * 拦截 update 操作(添加和修改) */ @Intercepts({ @Signature(type = Executor.class, method = "update", args = { MappedStatement.class...

    原文地址:Mybatis 插件实现动态设置参数
    博客地址:http://www.extlight.com

    一、背景

    笔者在搭建架构时,通常会利用泛型对 dao 层 和 service 层公共的代码(增删改)进行抽取,但是遇到一个尴尬的问题,就是实体类中的时间设置。

    解决办法有很多,简单的方法就是在 web 层接收实体类参数后直接设置时间即可。但是,web 层理论上只是调用 service 层代码而已,设置时间的操作应该放在 service 层来实现,且设置时间又是一个简单的、重复性的操作,因此在网上查阅了一些资料,个人感觉比较友好的方式就是使用 Mybatis 插件。

    本文介绍使用 Mybatis 插件动态设置参数。

    二、Mybatis 插件简单介绍

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

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

    其关系如下图:

    image

    解释:

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

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

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

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

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

    三、案例演示

    案例主要演示如何编写 Mybatis 自定义插件来实现动态设置时间参数,解决上文提到的问题。

    3.1 自定义注解

    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.FIELD})
    public @interface CreateTime {
    
        String value() default "";
    }
    
    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.FIELD})
    public @interface UpdateTime {
    
        String value() default "";
    }

    将两个注解添加到实体类的 Date 类型成员变量上。

    @Data
    public class Category {
    
        private Integer id;
    
        private String name;
    
        private String descr;
    
        @CreateTime
        private Date createTime;
    
        @UpdateTime
        private Date updateTime;
    
    }

    3.2 自定义插件

    /**
     * 自定义 Mybatis 插件,自动设置 createTime 和 updatTime 的值。
     * 拦截 update 操作(添加和修改)  
     */
    @Intercepts({ @Signature(type = Executor.class, method = "update", args = { MappedStatement.class, Object.class }) })
    public class CustomInterceptor implements Interceptor {
    
        private final Logger logger = LoggerFactory.getLogger(this.getClass());
    
        @Override
        public Object intercept(Invocation invocation) throws Throwable {
    
            MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];
            
            // 获取 SQL 命令
            SqlCommandType sqlCommandType = mappedStatement.getSqlCommandType();
            
            // 获取参数
            Object parameter = invocation.getArgs()[1];
            
            // 获取私有成员变量
            Field[] declaredFields = parameter.getClass().getDeclaredFields();
    
            for (Field field : declaredFields) {
                if (field.getAnnotation(CreateTime.class) != null) {
                    if (SqlCommandType.INSERT.equals(sqlCommandType)) { // insert 语句插入 createTime
                        field.setAccessible(true);
                        field.set(parameter, new Date());
                    }
                }
    
                if (field.getAnnotation(UpdateTime.class) != null) { // insert 或 update 语句插入 updateTime
                    if (SqlCommandType.INSERT.equals(sqlCommandType) || SqlCommandType.UPDATE.equals(sqlCommandType)) {
                        field.setAccessible(true);
                        field.set(parameter, new Date());
                    }
                }
            }
    
            return invocation.proceed();
        }
    
        @Override
        public Object plugin(Object target) {
            return Plugin.wrap(target, this);
        }
    
        @Override
        public void setProperties(Properties properties) {
        }
    }

    3.3 注册插件

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE configuration
            PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-config.dtd">
    <configuration>
        <settings>
            <!-- 获取数据库自增主键值 -->
            <setting name="useGeneratedKeys" value="true"/>
            <!-- 使用列别名替换列名,默认为 true -->
            <setting name="useColumnLabel" value="true"/>
            <!-- 开启驼峰命名转换:Table(create_time) => Entity(createTime) -->
            <setting name="mapUnderscoreToCamelCase" value="true"/>
        </settings>
    
        <plugins>
            <plugin interceptor="com.extlight.plugin.CustomInterceptor">
            </plugin>
        </plugins>
    </configuration>

    通过这三个步骤就解决问题了。

    四、参考资料

    转载于:https://www.cnblogs.com/moonlightL/p/9177511.html

    展开全文
  • } 拦截器 /** * 自定义 Mybatis 插件,自动设置 createTime 和 updatTime 的值。 * 拦截 update 操作(添加和修改) */ @Component @Intercepts({@Signature(type = Executor.class, method = "update", args = {...

    注解

    /**
     * 自动设置创建人
     */
    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.FIELD})
    public @interface CreateBy {
        String value() default "";
    }
    /**
     * 自动设置创建时间
     */
    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.FIELD})
    public @interface CreateTime {
        String value() default "";
    }
    /**
     * 自动设置修改人
     */
    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.FIELD})
    public @interface UpdateBy {
        String value() default "";
    }
    /**
     * 自动设置修改时间
     */
    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.FIELD})
    public @interface UpdateTime {
        String value() default "";
    }
    

    拦截器

    /**
     * 自定义 Mybatis 插件,自动设置 createTime 和 updatTime 的值。
     * 拦截 update 操作(添加和修改)
     */
    @Component
    @Intercepts({@Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class})})
    public class CustomInterceptor implements Interceptor {
        private static final Logger logger = LoggerFactory.getLogger(CustomInterceptor.class);
    
        @Override
        public Object intercept(Invocation invocation) throws Throwable {
            MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];
    
            // 获取 SQL 命令
            SqlCommandType sqlCommandType = mappedStatement.getSqlCommandType();
            //只判断新增和修改
            if (SqlCommandType.INSERT.equals(sqlCommandType) || SqlCommandType.UPDATE.equals(sqlCommandType)) {
                // 获取参数
                Object parameter = invocation.getArgs()[1];
                //批量操作时
                if (parameter instanceof MapperMethod.ParamMap) {
                    MapperMethod.ParamMap map = (MapperMethod.ParamMap) parameter;
                    Object obj = map.get("list");
                    List<?> list = (List<?>) obj;
                    if (list != null) {
                        for (Object o : list) {
                            setParameter(o, sqlCommandType);
                        }
                    }
                } else {
                    setParameter(parameter, sqlCommandType);
                }
            }
            return invocation.proceed();
        }
    
        public void setParameter(Object parameter, SqlCommandType sqlCommandType) throws Throwable {
            Class<?> aClass = parameter.getClass();
            Field[] declaredFields;
            //如果常用字段提取了公共类 BaseEntity
            //判断BaseEntity是否是父类
            if (BaseEntity.class.isAssignableFrom(aClass)) {
            // 获取父类私有成员变量
                declaredFields = aClass.getSuperclass().getDeclaredFields();
            } else {
                // 获取私有成员变量
                declaredFields = aClass.getDeclaredFields();
            }
            for (Field field : declaredFields) {
                if (SqlCommandType.INSERT.equals(sqlCommandType)) { // insert 语句插入 createBy
                    if (field.getAnnotation(CreateBy.class) != null) {
                        field.setAccessible(true);
                        field.set(parameter, SecurityUtils.getUsername());
                    }
    
                    if (field.getAnnotation(CreateTime.class) != null) { // insert 语句插入 createTime
                        field.setAccessible(true);
                        field.set(parameter, new Timestamp(System.currentTimeMillis()));
                    }
                }
    
                if (SqlCommandType.UPDATE.equals(sqlCommandType)) {
                    if (field.getAnnotation(UpdateTime.class) != null) { // update 语句插入 updateTime
                        field.setAccessible(true);
                        field.set(parameter, new Timestamp(System.currentTimeMillis()));
                    }
                    if (field.getAnnotation(UpdateBy.class) != null) { // update 语句插入 updateBy
                        field.setAccessible(true);
                        field.set(parameter, SecurityUtils.getUsername());
                    }
                }
            }
        }
    }
    
    展开全文
  • 前两天了解了一下mybatis插件这个东西,为了加深一下印象,突然想给当前代码做一个简化操作,通过插件的形式统一处理createTime,createBy,updateBy。 首先定义一个BaseEntity,里面放入这些参数 ...

    前两天了解了一下mybatis插件这个东西,为了加深一下印象,突然想给当前代码做一个简化操作,通过插件的形式统一处理createTime,createBy,updateBy。
    首先定义一个BaseEntity,里面放入这些参数,需要处理的实体类只需要继承即可

    import java.io.Serializable;
    import java.util.Date;
    import com.fasterxml.jackson.annotation.JsonFormat;
    import lombok.Data;
    
    @Data
    public class BaseEntity implements Serializable{
    
    	private static final long serialVersionUID = 1L;
    
    	@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    	private Date updateTime;
    	
    	@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
        private Date createTime;
    	
    	private String createBy;
    	
    	private String updateBy;
    	
    }
    

    处理逻辑代码

    import java.util.Date;
    import java.util.Properties;
    
    import org.apache.ibatis.executor.Executor;
    import org.apache.ibatis.mapping.MappedStatement;
    import org.apache.ibatis.mapping.SqlCommandType;
    import org.apache.ibatis.plugin.Interceptor;
    import org.apache.ibatis.plugin.Intercepts;
    import org.apache.ibatis.plugin.Invocation;
    import org.apache.ibatis.plugin.Plugin;
    import org.apache.ibatis.plugin.Signature;
    import org.springframework.stereotype.Component;
    
    import com.spring.framework.entity.BaseEntity;
    import com.spring.framework.utils.UserUtil;
    
    
    
    /**
     *  Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)   拦截执行器的方法
    	ParameterHandler (getParameterObject, setParameters)	拦截参数的处理
    	ResultSetHandler (handleResultSets, handleOutputParameters)	拦截结果集的处理
    	StatementHandler (prepare, parameterize, batch, update, query) 拦截Sql语法构建的处理
     * @author Administrator
     *
     */
    @Intercepts({@Signature(type = Executor.class,method = "update",args = {MappedStatement.class,Object.class})})
    @Component
    public class HandleTimeInterceptor implements Interceptor {
    
    	@Override
    	public Object intercept(Invocation invocation) throws Throwable {
    		 Object[] args = invocation.getArgs();
    		 MappedStatement mappedStatement = (MappedStatement) args[0];
    		 SqlCommandType sqlCommandType = mappedStatement.getSqlCommandType();
    		 if(sqlCommandType== SqlCommandType.UPDATE) {
    			 if(args[1] instanceof BaseEntity) {
    				BaseEntity baseEntity = (BaseEntity) args[1];
    				baseEntity.setUpdateTime(new Date());
    				baseEntity.setUpdateBy(UserUtil.getUsername());
    			 }
    		 }else if(sqlCommandType==SqlCommandType.INSERT) {
    			 if(args[1] instanceof BaseEntity) {
    					BaseEntity baseEntity = (BaseEntity) args[1];
    					baseEntity.setCreateTime(new Date());
    					baseEntity.setCreateBy(UserUtil.getUsername());
    			}
    		 }
    	     
    		return invocation.proceed();
    	}
    
    	@Override
    	public Object plugin(Object target) {
    		return Plugin.wrap(target, this);
    	}
    
    	@Override
    	public void setProperties(Properties properties) {
    	}
    }
    

    简单测试了一下,是没有问题的,具体还存在哪些bug暂时还不知道,先这样吧
    参考地址:https://blog.csdn.net/weixin_43850799/article/details/106745494

    2020-06-21,代码出bug了,项目中集成了mybatis-plus后,更新数据的时候发现updateBy和updateTime不会被赋值了,debug看了一下,发现由于使用的时候mp自带的修改方法,他把参数结构修改了,所以代码也要随之改变一下,增加个判断。(手写xml和使用tk的时候没有发现这个问题的出现)

    import java.util.Date;
    import java.util.Map;
    import java.util.Map.Entry;
    import java.util.Properties;
    
    import org.apache.ibatis.executor.Executor;
    import org.apache.ibatis.mapping.MappedStatement;
    import org.apache.ibatis.mapping.SqlCommandType;
    import org.apache.ibatis.plugin.Interceptor;
    import org.apache.ibatis.plugin.Intercepts;
    import org.apache.ibatis.plugin.Invocation;
    import org.apache.ibatis.plugin.Plugin;
    import org.apache.ibatis.plugin.Signature;
    
    import com.ruoyi.common.core.domain.BaseEntity;
    import com.ruoyi.common.utils.SecurityUtils;
    
    /**
     * 公共字段统一处理
     * @author ljw
     * 2021年6月19日14:56:21
     *
     */
    @Intercepts({@Signature(type = Executor.class,method = "update",args = {MappedStatement.class,Object.class})})
    public class HandleCommonInterceptor implements Interceptor {
    
    	
    	@SuppressWarnings("unchecked")
    	@Override
    	public Object intercept(Invocation invocation) throws Throwable {
    		Object[] args = invocation.getArgs();
    		MappedStatement mappedStatement = (MappedStatement) args[0];
    		SqlCommandType sqlCommandType = mappedStatement.getSqlCommandType();
    		if(sqlCommandType== SqlCommandType.UPDATE) {
    			System.err.println(args[1]);
    			 if(args[1] instanceof BaseEntity) {
    				BaseEntity baseEntity = (BaseEntity) args[1];
    				baseEntity.setUpdateTime(new Date());
    				if(SecurityUtils.getAuthentication()!=null) {//主要处理在执行插入日志的时候会获取不到用户信息,问题暂时不清楚为啥
    					baseEntity.setUpdateBy(SecurityUtils.getUsername());
    				}
    				//调用mp的更新方法时,参数会变成如下形式:{param1=Receive(id=16, dh=1244, qzh=null, postId=1)} 正常的应该是Receive(id=16, dh=1244, qzh=null, postId=1)
    			 }else if(args[1] instanceof Map){
    				 Map<String,Object> map = (Map<String, Object>) args[1];
    				 Object object = getFirstOrNull(map);
    				 if(object instanceof BaseEntity) {
    					BaseEntity baseEntity = (BaseEntity) object;
    					baseEntity.setUpdateTime(new Date());
    					if(SecurityUtils.getAuthentication()!=null) {//主要处理在执行插入日志的时候会获取不到用户信息,问题暂时不清楚为啥
    						baseEntity.setUpdateBy(SecurityUtils.getUsername());
    					}
    				 }
    				 
    			 }
    		 }else if(sqlCommandType==SqlCommandType.INSERT) {
    			 if(args[1] instanceof BaseEntity) {
    				BaseEntity baseEntity = (BaseEntity) args[1];
    				baseEntity.setCreateTime(new Date());
    				if(SecurityUtils.getAuthentication()!=null) {
    					baseEntity.setCreateBy(SecurityUtils.getUsername());
    				}
    			}
    		 }
    		return invocation.proceed();
    	}
    	
    	@Override
    	public Object plugin(Object target) {
    		return Plugin.wrap(target, this);
    	}
    
    	@Override
    	public void setProperties(Properties properties) {
    	}
    
    	/**
    	 * 获取第一个key的值
    	 * @param map
    	 * @return
    	 */
    	private static Object getFirstOrNull(Map<String, Object> map) {
            Object obj = null;
            for (Entry<String, Object> entry : map.entrySet()) {
                obj = entry.getValue();
                if (obj != null) {
                    break;
                }
            }
            return  obj;
        }
    }
    
    展开全文
  • 时间戳转特定时间格式函数 // time:时间戳;cFormat:指定格式(例如:'{y}-{m}-{d}','{y}/{m}/{d}','{y}-{m}-{d} {h}:{i}:{s} 星期{a}') function parseTime(time, cFormat) { if (arguments.length === 0) { ...

    时间戳转特定时间格式函数

    // time:时间戳;cFormat:指定格式(例如:'{y}-{m}-{d}','{y}/{m}/{d}','{y}-{m}-{d} {h}:{i}:{s} 星期{a}')
    function parseTime(time, cFormat) {
      if (arguments.length === 0) {
        return null
      }
      const format = cFormat || '{y}-{m}-{d} {h}:{i}:{s}'
      let date
      if (typeof time === 'object') {
        date = time
      } else {
        if (('' + time).length === 10) time = parseInt(time) * 1000
        date = new Date(time)
      }
      const formatObj = {
        y: date.getFullYear(),
        m: date.getMonth() + 1,
        d: date.getDate(),
        h: date.getHours(),
        i: date.getMinutes(),
        s: date.getSeconds(),
        a: date.getDay()
      }
      const time_str = format.replace(/{(y|m|d|h|i|s|a)+}/g, (result, key) => {
        let value = formatObj[key]
        if (key === 'a') { return ['日', '一', '二', '三', '四', '五', '六'][value ] }
        if (result.length > 0 && value < 10) {
          value = '0' + value
        }
        return value || 0
      })
      return time_str
    }
    
    展开全文
  • ORA-00904: "UPDATETIME": 标识符无效

    千次阅读 2018-10-28 21:42:53
    特别坑爹,运行的时候出现了这个:   网上说是因为用一些自动建表的软件,生成的sql,做出来的表带有引号,导致的错误,好像之前插入数据的时候都没问题,应该不是这个原因导致的,仔细一看:ORA-00904: "...
  • Arduino提高篇24—摇杆调节时钟时间

    千次阅读 2020-05-22 10:03:59
    // 开显示 } void updatTime()//更新时间数据 { Time tim = rtc.time(); //从DS1302获取时间数据 set_temp = tim;//获取时间数据已备调节 if (tim.sec != sec_temp) { //一秒刷新一次 show_time(tim); } sec_temp =...
  • WebSocket

    2018-12-27 10:10:50
    import java.util.Set; import javax.websocket.Endpoint; import javax.websocket.server.ServerApplicationConfig; import javax.websocket.server.ServerEndpointConfig;... * ServerApplicationConfig这个接口.....
  • Arduino提高篇23—OLED电子时钟

    千次阅读 2020-05-20 12:13:48
    //向DS1302设置时间数据 } void updatTime()//打印时间数据 { Time tim = rtc.time(); //从DS1302获取时间数据 char date[20]; char timer[20]; snprintf(date, sizeof(date), "%04d-%02d-%02d", tim.yr, tim.mon, ...
  • select id,taskCode,taskSign,riskCode,classCode,policyCodes,createTime,updatTime from f_policytask 导入之后查询出数据的字段变成了小写,我建索引的时候写的是驼峰,所以模糊查询的时候查询不出来。 ![图片...
  • //执行获取到的函数 } if (menu == 0)//只有在首页才进行时间刷新 { updatTime(); } } 连接开发板,设置好对应端口号和开发板类型,进行程序下载。 程序下载 4 实验现象 摇杆操作调节时间,效果如下: 实验现象 ...
  • //向DS1302设置时间数据 } void updatTime()//打印时间数据{ Time tim = rtc.time(); //从DS1302获取时间数据 char date[20]; char timer[20]; snprintf(date, sizeof(date), "%04d-%02d-%02d", tim.yr, ...
  • updatedAt: 'updattime' // 升级时间 }}); var schema = mongoose.model('User',userSchema); module.exports = schema; 然后在routers下的user.js里面引入创建的model const User = require('../public/...
  • @Temporal(TemporalType.TIMESTAMP) private Date updatTime; public User() { } 2.处理实体类与实体类之间的关系 处理的原则:“多”的一端作为关系维护端,“一”的一端作为关系被维护端 例如:Blog类和Type类,...
  • 规则日志、结构化的整理、用户行为日志:operationTime creator type target Timeline、调用链路 invoker Time targetMethod args returnVal throw、持续增量(id+updatTime)、文件存储:GirdFS(文件存储系统) ...
  • var userSchema = new Schema({ username: String, password: String, },{ timestamps: { createdAt: 'createtime', // 创建时间 updatedAt: 'updattime' // 升级时间 }}); var schema = mongoose.model('User',...
  •  插入对象的时候,注意不要忘记set createTime 更新的时候 updatTime   四、 打包打小包 <groupId>org.springframework.boot <artifactId>spring-boot-maven-plugin true <layout>ZIP ...
  • 1.引入JSTL标签库(确定jstl-*.jar包引入进来) 2.格式化日期 <td>> ${updatTime}" pattern="yyyy-MM-dd HH:mm:ss" /> 3.格式化小数 ${hzt50+hzt70+hzt90}" pattern="#0.0#"/>
  • 这个时候居然得到了我一开始天真想要得到的效果,忽略了updattime的存在。如果我把updatetime这个字段加上,VersionNumber就会重复。而这样的写法至少oracle会给一个大叉吧,告诉你不是Group by 语句。难道mysql 这...

空空如也

空空如也

1 2
收藏数 24
精华内容 9
热门标签
关键字:

updattime