公共字段自动填充的分析与实现

java中实现公共字段自动填充功能的问题分析与实现

问题分析:代码冗余,不便于后期维护

        · 在我们的很多业务中存在一些公共的字段,当我们需要对这些字段进行赋值操作的时候,会重复且平凡的执行赋值语句,导致我们的java代码中出现很多的冗余代码。如果我们后期的表结构发生变化,那我们的这些代码都需要进行改动,不便于代码的后期维护。


一、实现思路

         · 首先明确公共字段属于哪种操作类型,我们什么时候去操作它,例如1、2两个字段见明知意是我们执行 insert 语句时需要进行赋值操作,2、4两个字段是我们在执行 insert 和 update 语句时需要进行操作赋值操作

        · 以上公共字段在我们的java种可以统一来处理 也就是通过  aop 切面编程来处理,因为对公共字段的填充的处理在我们的持久层也就是 mapper 层中进行,在 mapper 层执行 insert 和 update 来插入和更新数据。此时可以通过切面来同意拦截我们的 mapper 层,来统一为我们的公共字段进行赋值,为 mapper 层的方法来加入我们自定义的注解之后,就可以对当前方法进行统一拦截并进行统一赋值。


二、实现步骤

1.自定义注解AutoFill

· 自定义注解AutoFill,用于标识需要进行公共字段自动填充的方法:

package com.sky.annotation;

import com.sky.enumeration.OperationType;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 自定义注解,用于某个方法上需要进行功能字段自动填充处理
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AutoFill {
    //数据库操作类型,INSERT UPDATE
    OperationType value();
}

· 创建annotation包(注意与mapper包同级)用于存放自定义注解AutoFill(使用Annotation注解关键字声明)

· 注解@Target(ElementType.METHOD) 用于指定AutoFill只能加在方法上

· 注解Retention(RetentionPolicy.RUNTIME) 固定写法

· OperationType 为声明的枚举类 具体声明如下:

package com.sky.enumeration;

/**
 * 数据库操作类型
 */
public enum OperationType {

    /**
     * 更新操作
     */
    UPDATE,

    /**
     * 插入操作
     */
    INSERT

}

· 创建enumeration包(注意与mapper包同级)用于存放自定义枚举类OperationType(使用enum枚举关键字声明) 


2.自定义切面类AutoFillAspect

·自定义切面类AutoFillAspect,统一拦截加入了AutoFill注解的方法,通过反射为公共字段进行赋值

package com.sky.aspect;

import com.sky.annotation.AutoFill;
import com.sky.constant.AutoFillConstant;
import com.sky.context.BaseContext;
import com.sky.enumeration.OperationType;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.time.LocalDateTime;

/**
 * 自定义切面,实现公共字段自动填充逻辑
 */
@Aspect
@Component
@Slf4j
public class AutoFillAspect {
    /**
     * 定义切入点,execution(* com.sky.mapper.*.*(..))指定拦截com.sky.mapper包下的所有方法
     * 并且只拦截 @annotation(com.sky.annotation.AutoFill) 带AutoFill注解的方法
     */

    @Pointcut("execution(* com.sky.mapper.*.*(..)) && @annotation(com.sky.annotation.AutoFill)")
    public void autoFillPointCut(){}

    /**
     * 前置通知,在通知中进行公共字段填充
     * @param joinPoint
     */
    @Before("autoFillPointCut()")
    public void autoFill(JoinPoint joinPoint){
        log.info("开始进行公共字段自动填充...");

        //获取当前被拦截的方法上的数据库操作类型
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();//方法签名对象
        AutoFill autoFill = signature.getMethod().getAnnotation(AutoFill.class);//获取方法上的注解对象
        OperationType operationType = autoFill.value();//获取数据库操作类型
        //获取当前被拦截的方法的参数--实体对象
        Object[] args = joinPoint.getArgs();
        if (args == null || args.length == 0){
            return;
        }
        Object entity = args[0];
        //准备赋值的数据
        LocalDateTime now = LocalDateTime.now();//时间
        Long currentId = BaseContext.getCurrentId();//当前登录用户的id

        //根据当前不同的操作类型,把对应的属性通过反射进行赋值
        if (operationType == OperationType.INSERT){
            try {
                Method setCreatTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_TIME, LocalDateTime.class);
                Method setCreatUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_USER, Long.class);
                Method setUpdateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);
                Method setUpdateUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);

                //通过反射为对象属性赋值
                setCreatTime.invoke(entity,now);
                setCreatUser.invoke(entity,currentId);
                setUpdateTime.invoke(entity,now);
                setUpdateUser.invoke(entity,currentId);
            } catch (Exception e) {
                log.info("INSERT公共字段填充失败");
                throw new RuntimeException(e);
            }

        }else if (operationType == OperationType.UPDATE){
            try {
                Method setUpdateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);
                Method setUpdateUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);

                //通过反射为对象属性复制
                setUpdateTime.invoke(entity,now);
                setUpdateUser.invoke(entity,currentId);
            } catch (Exception e) {
                log.info("UPDATE公共字段填充失败");
                throw new RuntimeException(e);
            }

        }

    }
}

 · 创建aspect包(注意与mapper包同级)用于存放自定义切面类AutoFillAspect(使用class类关键字声明)

 · 注意:根据不同操作类型反射赋值的时候,获取实体中的方法名称和方法类型的时候,方法名我这里使用了一个常量类,具体的方法名在常量类里(此处也可以直接定义方法名)


 3.在mapper的方法上加入AutoFill注解即可

· @AutoFill(OperationType.INSERT) 


总结

技术要点:枚举、注解、AOP、反射

  • 24
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java实现公共字段填充的具体步骤如下: 1. 首先,定义一个包含公共字段的基类,所有需要填充公共字段的类都应该继承于该基类; 2. 在基类中定义一个静态方法,该方法用于填充公共字段。在该方法中,可以使用反射获取所有继承于基类的子类,并遍历所有子类的公共字段,将其填充为指定的值; 3. 在子类中调用基类的静态方法,即可实现公共字段填充。 具体的实现代码如下: ```java public class BaseClass { public String commonField1; public String commonField2; public static void fillCommonFields(String value1, String value2) { // 使用反射获取所有继承于BaseClass的子类 Class<?>[] classes = BaseClass.class.getClasses(); for (Class<?> clazz : classes) { // 遍历所有公共字段,将其填充为指定的值 Field[] fields = clazz.getDeclaredFields(); for (Field field : fields) { if (Modifier.isPublic(field.getModifiers())) { try { field.set(null, value1); } catch (IllegalAccessException e) { e.printStackTrace(); } } } } } } public class SubClass extends BaseClass { public String subField1; public String subField2; public static void main(String[] args) { // 在子类中调用基类的静态方法,即可实现公共字段填充 BaseClass.fillCommonFields("value1", "value2"); } } ``` 在上述代码中,BaseClass是包含公共字段的基类,SubClass是继承于BaseClass的子类。fillCommonFields方法用于填充公共字段,其中使用反射获取所有继承于BaseClass的子类,并遍历所有子类的公共字段,将其填充为指定的值。在SubClass中,通过调用BaseClass的静态方法,即可实现公共字段填充

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值