it编程 > 编程语言 > Java

SpringBoot自定义注解如何解决公共字段填充问题

2人参与 2025-03-10 Java

1.1 问题分析

新增员工或者新增菜品分类时需要设置创建时间、创建人、修改时间、修改人等字段,在编辑员工或者编辑菜品分类时需要设置修改时间、修改人等字段。

这些字段属于公共字段,也就是也就是在我们的系统中很多表中都会有这些字段,如下:

序号字段名含义数据类型
1create_time创建时间datetime
2create_user创建人idbigint
3update_time修改时间datetime
4update_user修改人idbigint

而针对于这些字段,我们的赋值方式为:

1). 在新增数据时, 将createtime、updatetime 设置为当前时间, createuser、updateuser设置为当前登录用户id。

2). 在更新数据时, 将updatetime 设置为当前时间, updateuser设置为当前登录用户id。

目前,在我们的项目中处理这些字段都是在每一个业务方法中进行赋值操作,如下:

新增员工方法:

	/**
     * 新增员工
     *
     * @param employeedto
     */
    public void save(employeedto employeedto) {
        //.......................
		//
        //设置当前记录的创建时间和修改时间
        employee.setcreatetime(localdatetime.now());
        employee.setupdatetime(localdatetime.now());

        //设置当前记录创建人id和修改人id
        employee.setcreateuser(basecontext.getcurrentid());//目前写个假数据,后期修改
        employee.setupdateuser(basecontext.getcurrentid());
		///
        employeemapper.insert(employee);
    }

编辑员工方法:

	/**
     * 编辑员工信息
     *
     * @param employeedto
     */
    public void update(employeedto employeedto) {
       //........................................
	   ///
        employee.setupdatetime(localdatetime.now());
        employee.setupdateuser(basecontext.getcurrentid());
       ///

        employeemapper.update(employee);
    }

新增菜品分类方法:

	/**
     * 新增分类
     * @param categorydto
     */
    public void save(categorydto categorydto) {
       //....................................
       //
        //设置创建时间、修改时间、创建人、修改人
        category.setcreatetime(localdatetime.now());
        category.setupdatetime(localdatetime.now());
        category.setcreateuser(basecontext.getcurrentid());
        category.setupdateuser(basecontext.getcurrentid());
        ///

        categorymapper.insert(category);
    }

修改菜品分类方法:

	/**
     * 修改分类
     * @param categorydto
     */
    public void update(categorydto categorydto) {
        //....................................
        
		//
        //设置修改时间、修改人
        category.setupdatetime(localdatetime.now());
        category.setupdateuser(basecontext.getcurrentid());
        //

        categorymapper.update(category);
    }

如果都按照上述的操作方式来处理这些公共字段, 需要在每一个业务方法中进行操作, 编码相对冗余、繁琐,那能不能对于这些公共字段在某个地方统一处理,来简化开发呢?

答案是可以的,我们使用aop切面编程,实现功能增强,来完成公共字段自动填充功能。

1.2 实现思路

在实现公共字段自动填充,也就是在插入或者更新的时候为指定字段赋予指定的值,使用它的好处就是可以统一对这些字段进行处理,避免了重复代码。

在上述的问题分析中,我们提到有四个公共字段,需要在新增/更新中进行赋值操作, 具体情况如下:

序号字段名含义数据类型操作类型
1create_time创建时间datetimeinsert
2create_user创建人idbigintinsert
3update_time修改时间datetimeinsert、update
4update_user修改人idbigintinsert、update

实现步骤:

1). 自定义注解 autofill,用于标识需要进行公共字段自动填充的方法

2). 自定义切面类 autofillaspect,统一拦截加入了 autofill 注解的方法,通过反射为公共字段赋值

3). 在 mapper 的方法上加入 autofill 注解

若要实现上述步骤,需掌握以下知识(之前课程内容都学过)

**技术点:**枚举、注解、aop、反射

1.3 代码开发

按照上一小节分析的实现步骤依次实现,共三步。

1.3.1 步骤一

自定义注解 autofill

进入到sky-server模块,创建com.sky.annotation包。

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 {
    //数据库操作类型:update insert
    operationtype value();
}

其中operationtype已在sky-common模块中定义

package com.sky.enumeration;

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

    /**
     * 更新操作
     */
    update,

    /**
     * 插入操作
     */
    insert
}

1.3.2 步骤二

自定义切面 autofillaspect

在sky-server模块,创建com.sky.aspect包。

package com.sky.aspect;

/**
 * 自定义切面,实现公共字段自动填充处理逻辑
 */
@aspect
@component
@slf4j
public class autofillaspect {

    /**
     * 切入点
     */
    @pointcut("execution(* com.sky.mapper.*.*(..)) && @annotation(com.sky.annotation.autofill)")
    public void autofillpointcut(){}

    /**
     * 前置通知,在通知中进行公共字段的赋值
     */
    @before("autofillpointcut()")
    public void autofill(joinpoint joinpoint){
        /重要
        //可先进行调试,是否能进入该方法 提前在mapper方法添加autofill注解
        log.info("开始进行公共字段自动填充...");

    }
}

完善自定义切面 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 {

    /**
     * 切入点
     */
    @pointcut("execution(* com.sky.mapper.*.*(..)) && @annotation(com.sky.annotation.autofill)")
    public void autofillpointcut(){}

    /**
     * 前置通知,在通知中进行公共字段的赋值
     */
    @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();

        //根据当前不同的操作类型,为对应的属性通过反射来赋值
        if(operationtype == operationtype.insert){
            //为4个公共字段赋值
            try {
                method setcreatetime = entity.getclass().getdeclaredmethod(autofillconstant.set_create_time, localdatetime.class);
                method setcreateuser = 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);

                //通过反射为对象属性赋值
                setcreatetime.invoke(entity,now);
                setcreateuser.invoke(entity,currentid);
                setupdatetime.invoke(entity,now);
                setupdateuser.invoke(entity,currentid);
            } catch (exception e) {
                e.printstacktrace();
            }
        }else if(operationtype == operationtype.update){
            //为2个公共字段赋值
            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) {
                e.printstacktrace();
            }
        }
    }
}

1.3.3 步骤三

在mapper接口的方法上加入 autofill 注解

categorymapper为例,分别在新增和修改方法添加@autofill()注解,也需要employeemapper做相同操作

package com.sky.mapper;

@mapper
public interface categorymapper {
    /**
     * 插入数据
     * @param category
     */
    @insert("insert into category(type, name, sort, status, create_time, update_time, create_user, update_user)" +
            " values" +
            " (#{type}, #{name}, #{sort}, #{status}, #{createtime}, #{updatetime}, #{createuser}, #{updateuser})")
    @autofill(value = operationtype.insert)
    void insert(category category);
    /**
     * 根据id修改分类
     * @param category
     */
    @autofill(value = operationtype.update)
    void update(category category);

}

同时,将业务层为公共字段赋值的代码注释掉。

1). 将员工管理的新增和编辑方法中的公共字段赋值的代码注释。

2). 将菜品分类管理的新增和修改方法中的公共字段赋值的代码注释。

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。

(0)
打赏 微信扫一扫 微信扫一扫

您想发表意见!!点此发布评论

推荐阅读

Java利用Jsoup解析和操作HTML的技术指南

03-10

使用EasyPOI实现多sheet动态列导出

03-10

SpringBoot如何使用redis

03-10

Java实现FIFO功能的完整代码实践

03-10

对象存储服务MinIO快速入门(集成项目的详细过程)

03-10

Java格式化小数并保留两位小数的四种方法

03-10

猜你喜欢

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论