实现类似mybatis-plus中@TableId(type = IdType.ASSIGN_ID)自动填充id的效果
好处是:基于mybatis原生插件,且预留了IdCreator接口,可以自定义id格式
拦截器源码
package com.nfcpwl.efarm.aop;
import com.nfcpwl.efarm.aop.annotation.DistributedInsert;
import com.nfcpwl.efarm.aop.annotation.IdWorker;
import com.nfcpwl.efarm.ds.IdCreator;
import lombok.extern.slf4j.Slf4j;
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.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Properties;
/**
* mybatis插件
*
* @author JGMa
*/
@Slf4j
@Intercepts({@Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class})})
public class IdWorkerInterceptor implements Interceptor {
IdCreator idCreator;
public IdCreator getIdCreator() {
return idCreator;
}
public void setIdCreator(IdCreator idCreator) {
this.idCreator = idCreator;
}
@Override
public Object intercept(Invocation invocation) throws Throwable {
Object[] args = invocation.getArgs();
/// mapper.xml
MappedStatement arg = (MappedStatement) args[0];
if (SqlCommandType.INSERT.name().equals(arg.getSqlCommandType().name())) {
for (Object entity : args) {
Class<?> aClass = entity.getClass();
DistributedInsert distributedInsert = aClass.getAnnotation(DistributedInsert.class);
if (distributedInsert != null) {
Field[] fields = aClass.getDeclaredFields();
for (Field field : fields) {
IdWorker annotation = field.getAnnotation(IdWorker.class);
if (annotation != null) {
// long snowflakeNextId = IdUtil.getSnowflakeNextId();
Integer distributedId10 = idCreator.nextIdInt();
setField(entity, field.getName(), distributedId10);
}
break;
}
}
}
}
return invocation.proceed();
}
@Override
public Object plugin(Object o) {
return Plugin.wrap(o, this);
}
@Override
public void setProperties(Properties properties) {
log.warn(properties.toString());
}
public static void setField(Object o, String args, Object attributeValue) {
Class cls = o.getClass();
//判断该属性是否存在
Field field = null;
try {
field = cls.getDeclaredField(args);
if (field == null) {
field = cls.getField(args);
}
if (field == null) {
return;
}
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
String fieldName = "set" + args.substring(0, 1).toUpperCase() + (args.length() > 1 ? args.substring(1) : "");
Method method = null;
try {
method = cls.getMethod(fieldName, attributeValue.getClass());
method.invoke(o, attributeValue);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
接口
package com.nfcpwl.efarm.ds;
public interface IdCreator {
String nextIdStr();
Long nextIdLong();
Integer nextIdInt();
}
///
package com.nfcpwl.efarm.ds;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
/**
* @author JGMa
*/
@Component("defIdCreator")
public class DefIdCreator implements IdCreator {
@Autowired
StringRedisTemplate redisTemplate;
@Override
public synchronized String nextIdStr() {
return null;
}
@Override
public Long nextIdLong() {
return null;
}
@Override
public Integer nextIdInt() {
/// TODO 从最大的id进行重置
Boolean my_mjg_id = redisTemplate.opsForValue().setIfAbsent("MY_MJG_ID", "1000000000");
if (my_mjg_id){
Long resultId = redisTemplate.opsForValue().increment("MY_MJG_ID", 1);
return resultId.intValue();
}else {
Long resultId = redisTemplate.opsForValue().increment("MY_MJG_ID", 1);
return resultId.intValue();
}
}
}
注解
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface DistributedInsert {
}
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface IdWorker {
}
配置mybatis插件
package com.nfcpwl.efarm.ds;
import com.nfcpwl.efarm.aop.IdWorkerInterceptor;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import javax.annotation.PostConstruct;
/**
* @author JGMa
*/
@Configuration
public class MybatisInterceptorConfig {
@Autowired
private SqlSessionFactory sqlSessionFactory;
@Autowired
IdWorkerInterceptor idWorkerInterceptor;
@PostConstruct
public void addInterceptor() {
this.sqlSessionFactory.getConfiguration().addInterceptor(idWorkerInterceptor);
}
}
使用
在实体上加入注解即可
@DistributedInsert
public class StudentInfo implements Serializable {
/**
* 编号
*/
@IdWorker
private Integer stuNo;
}
效果
这时候在执行sql之前会拦截参数,如果stuNo为null就会自动生成id并设置进去;需要注意的是你的sql插入时需要有这个字段;