苍穹外卖项目实战(日记八)-记录实战教程及问题的解决方法-(day3-1)公共字段自动填充功能

完整代码在我的gitee仓库中(主页有地址),需要的码友可以自行下载使用!

编写不易,如若帮助到你,请帮我点个赞吧!谢谢!!!

1、公共字段自动填充

(1)问题分析

(2)代码开发一

1、annotation/AutoFill.java创建

1、创建包和类:sky-server/src/main/java/com/sky/annotation/AutoFill.java

填充的代码为:

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;
 
/**
 * 自定义注解,用于标识某个方法需要进行功能字段自动填充处理
 * @author sky
 * @Target:可使用的值定义在ElementType枚举类中,常用值如下:TYPE,类,接口 / FIELD, 成员变量 / METHOD, 成员方法
 */
@Target(ElementType.METHOD)//表示注解只能作用于方法上.
@Retention(RetentionPolicy.RUNTIME)//表示注解在运行时可以获取
public @interface AutoFill {
    //OperationType导入包的位置:sky-common/src/main/java/com/sky/enumeration/OperationType.java
    OperationType value();//自定义数据库操作类型,如UPDATE、INSERT
}

2、aspect/AutoFillAspect.java创建

位置:sky-server/src/main/java/com/sky/aspect/AutoFillAspect.java

具体代码:

package com.sky.aspect;
 
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.springframework.stereotype.Component;
 
@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("开始进行公共字段自动填充...");
    }
}

示意图:

3、添加代码

位置:sky-server/src/main/java/com/sky/mapper/EmployeeMapper.java

添加的代码:

第一条:

@AutoFill(value = OperationType.INSERT)

第二条:

@AutoFill(value = OperationType.UPDATE)

示意图:下图的33行和47行位置

3、测试自定义切面类(通知类)

打上断点,启动(DeBug)项目,打开前端网页添加员工

在图示位置输入数据,点击保存

回到控制台查看,发现已成功拦截插入(insert)员工信息

(3)代码开发二

1、AutoFillAspect代码完善

位置:sky-server/src/main/java/com/sky/aspect/AutoFillAspect.java

具体代码:

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();
        //为了方便,约定使用注解时,第一个参数的类型是实体类
        Object entity = args[0];
        //准备赋值的数据
        LocalDateTime now = LocalDateTime.now();
        Long currentId = BaseContext.getCurrentId();
        //根据数据库操作类型,进行赋值
        if (OperationType.UPDATE.equals(operationType)) {
            //更新操作,需要更新更新时间
            try {
                //为2个公共字段赋值
                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();
            }
        } else if (OperationType.INSERT.equals(operationType)) {
            //插入操作,需要插入创建时间和更新时间
            try {
                //为4个公共字段赋值
                Method setUpdateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);
                Method setUpdateUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);
                Method setCreateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_TIME, LocalDateTime.class);
                Method setCreateUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_USER, Long.class);
                //设置更新时间
                setUpdateTime.invoke(entity, now);
                //设置更新用户
                setUpdateUser.invoke(entity, currentId);
                //设置创建时间
                setCreateTime.invoke(entity, now);
                //设置创建用户
                setCreateUser.invoke(entity, currentId);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        log.info("公共字段自动填充完成...");
    }
}

示意图:

2、EmployeeServiceImpl注销公共属性代码

注意:注销到涉及到insert、update方法的公共属性(时间和修改人ID

文件位置:sky-server/src/main/java/com/sky/service/impl/EmployeeServiceImpl.java

代码位置:

3、CategoryServiceImpl注解公共属性代码

注意:注解掉涉及到insert、update方法的公共属性(时间和修改人ID

文件位置:sky-server/src/main/java/com/sky/service/impl/CategoryServiceImpl.java

代码位置:

4、功能测试(前后端联调)

(1)设置断点,启动(DeBug)项目

(2)打开前端网页工作台

(3)选择“员工管理”|任意选择一名员工进行“修改”操作|填写修改信息|点击“保存”,查看控制台信息

按F8或者F6,执行下一步,信息显示已拦截到com.sky.mapper.EmployeeMapper.update(com.sky.entity.Employee); 即“update”方法

方法类型为“Update”

获取具体的员工

跳过断点

员工信息已发生改变,至此,公共字段自动填充功能已完成!

在“苍穹外卖”系统中实现公共字段自动填充功能,主要依赖于 Spring AOP(面向切面编程)和自定义注解。该功能的核心思想是在执行数据库操作前,通过拦截带有特定注解的方法,使用反射机制为实体类中的公共字段自动赋值,避免在每个业务逻辑中重复编写相同的赋值代码。 ### 实现步骤如下: #### 1. 定义自定义注解 `@AutoFill` 首先创建一个自定义注解,用于标记需要进行公共字段自动填充方法。 ```java @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface AutoFill { } ``` #### 2. 创建切面类 `AutoFillAspect` 接下来编写一个切面类,使用 Spring AOP 拦截所有被 `@AutoFill` 注解标记的方法,并在方法执行前自动填充公共字段。 ```java @Aspect @Component @Slf4j public class AutoFillAspect { /** * 定义切入点:拦截所有 service 包下的方法,并且这些方法必须有 @AutoFill 注解 */ @Pointcut("execution(* com.sky.service.*.*(..)) && @annotation(com.sky.annotation.AutoFill)") public void autoFillPointcut() {} /** * 在目标方法执行前进行公共字段填充 */ @Before("autoFillPointcut()") public void autoFill(JoinPoint joinPoint) { log.info("开始公共字段自动填充"); // 获取方法参数中的实体对象 Object[] args = joinPoint.getArgs(); if (args == null || args.length == 0) { return; } // 假设第一个参数为实体对象 Object entity = args[0]; // 使用反射设置公共字段值 try { // 获取当前登录用户ID(示例) Long currentUserId = getCurrentUserId(); // 设置更新人字段 Method setUpdateUser = entity.getClass().getMethod("setUpdateUser", Long.class); setUpdateUser.invoke(entity, currentUserId); // 设置创建人字段(如果是新增操作) Method getCreateTime = entity.getClass().getMethod("getCreateTime"); if (getCreateTime.invoke(entity) == null) { Method setCreateUser = entity.getClass().getMethod("setCreateUser", Long.class); setCreateUser.invoke(entity, currentUserId); } } catch (Exception e) { log.error("公共字段填充失败", e); } } /** * 获取当前登录用户 ID(需结合项目实际获取方式) */ private Long getCurrentUserId() { // 示例返回固定值,实际应从 ThreadLocal 或 SecurityContext 中获取 return 1L; } } ``` #### 3. 在实体类中定义公共字段 确保实体类中包含常见的公共字段,如创建时间、创建人、更新时间、更新人等,并提供相应的 getter 和 setter 方法。 ```java public class Dish { private Long id; private String name; private LocalDateTime createTime; private LocalDateTime updateTime; private Long createUser; private Long updateUser; // Getter and Setter methods } ``` #### 4. 在 Service 层方法上添加 `@AutoFill` 注解 最后,在需要自动填充公共字段的业务方法上添加 `@AutoFill` 注解,Spring AOP 将会自动拦截并执行填充逻辑。 ```java @Service public class DishService { @AutoFill public void save(Dish dish) { // 执行保存逻辑 } @AutoFill public void update(Dish dish) { // 执行更新逻辑 } } ``` --- ### 注意事项 - **ThreadLocal 用户信息**:为了获取当前登录用户的信息,通常会使用 `ThreadLocal` 来存储用户上下文,确保线程安全[^3]。 - **异常处理**:在实际部署时,应完善日志记录和异常捕获机制,确保系统的健壮性。 - **性能优化**:如果数据量较大或并发较高,可以考虑对反射操作进行缓存,提升性能。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值