Spring AOP + 自定义注解 实现公共字段的填充

news/2024/9/17 16:12:33

Spring AOP + 自定义注解 实现公共字段的填充

在这里插入图片描述

代码冗,不利于后期维护.

定义操作这些字段的方法类型

在这里插入图片描述

实现步骤:

  • 自定义注解AutoFill,用于表示操作这些公共字段的方法
  • 自定义切面类AutoFillAspect,统一拦截,通过反射获取方法入参,并填充公共字段
  • 在Mapper的insert、update的方法上加上自定义的AutoFill注解

代码:

- 不使用mybatis-plus自带的填充注解

必要依赖

 <dependency>
     <groupId>org.aspectj</groupId>
     <artifactId>aspectjweaver</artifactId>
     <version>1.8.7</version>
</dependency>
 <dependency>
     <groupId>com.baomidou</groupId>
     <artifactId>mybatis-plus-boot-starter</artifactId>
     <version>3.1.0</version>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.11</version>
</dependency>
  <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter</artifactId>
      <version>2.7.5</version>
</dependency>
  <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <version>1.18.18</version>
</dependency>

1、自定义注解AutoFill,用于表示操作这些公共字段的方法

import com.cwh.mpdemo.enums.OpreaType;

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 {

    /**
     * 操作类型
     *
     * @return
     */
    OpreaType value() default OpreaType.INSERT;
}

2、自定义切面类AutoFillAspect,统一拦截,通过反射获取方法入参,并填充公共字段


import com.cwh.mpdemo.annotation.AutoFill;
import com.cwh.mpdemo.enums.OpreaType;
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.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.Date;

/**
 * @Aspect 标注为切面类
 */
@Aspect
@Component
@Slf4j
public class AutoFillaspect {
    
    // 定义切点
    @Pointcut("execution(* com.cwh.mpdemo.mapper.*.*(..)) && @annotation(com.cwh.mpdemo.annotation.AutoFill)")
    public void pointcut(){}

    // 定义通知
    @Before("pointcut()")
    public void before(JoinPoint joinPoint){
        log.info("auto fill start...");
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        AutoFill annotation = signature.getMethod().getAnnotation(AutoFill.class);
        OpreaType value = annotation.value();
        //获取签名方法的入参
        Object[] args = joinPoint.getArgs();
        if (args.length ==0 ||args == null)  {
            return;
        }
        Object arg = args[0];
        try {
        // 填充字段
        if (value == OpreaType.INSERT){
            //通过反射给入参对象的字段赋值
        arg.getClass().getDeclaredMethod("setCreateTime", Date.class)
            .invoke(arg, Date.from(LocalDateTime.now().toInstant(ZoneOffset.UTC)));
  //实际中从ThreadLocal获取用户id          
          arg.getClass().getDeclaredMethod("setCreateUser",String.class).invoke(arg,"test");
        } 
          arg.getClass(). getDeclaredMethod("setUpdateTime",Date.class).invoke(arg,Date.from(LocalDateTime.now().toInstant(ZoneOffset.UTC)));
            //实际中从ThreadLocal获取用户id
        arg.getClass().getDeclaredMethod("setUpdateUser",String.class).invoke(arg,"test");
        }catch (Exception exception){
            log.error("auto fill error:{}",exception.getMessage());
        }

        log.info("auto fill end...");
    }
}
public enum OpreaType {
    INSERT,
    UPDATE;
}

3、在Mapper的insert、update的方法上加上自定义的AutoFill注解

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.cwh.mpdemo.annotation.AutoFill;
import com.cwh.mpdemo.domain.SessionDomain;

public interface SessionLoginMapper extends BaseMapper<SessionDomain> {

    @AutoFill
    void insertData(SessionDomain sessionDomain);
}

- 使用mybatis-plus自带的填充注解

首先在实体对象上加自动填充属性注解fill = FieldFill.INSERT

@Data
@TableName("session_login")
public class SessionDomain {
    @TableId(value = "id", type = IdType.AUTO)
    private Long id;
    @TableField
    private String userName;
    @TableField(fill = FieldFill.INSERT)
    private Date createTime;
    @TableField(fill = FieldFill.INSERT)
    private String createUser;
    @TableField(fill = FieldFill.UPDATE)
    private Date updateTime;
    @TableField(fill = FieldFill.UPDATE)
    private String updateUser;
}

实现元数据对象处理器接口MetaObjectHandler,实现insertFill,updateFill逻辑

import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.Date;

@Component
public class AutoFillHandler implements MetaObjectHandler {
    @Override
    public void insertFill(MetaObject metaObject) {

        // 设置属性值
         this.setFieldValByName("createTime", Date.from(LocalDateTime.now().toInstant(ZoneOffset.UTC)), metaObject);
         this.setFieldValByName("updateTime", Date.from(LocalDateTime.now().toInstant(ZoneOffset.UTC)), metaObject);
         //实际中从ThreadLocal获取用户id
         this.setFieldValByName("createUser", "1", metaObject);
         this.setFieldValByName("updateUser", "1", metaObject);
    }

    @Override
    public void updateFill(MetaObject metaObject) {
        //实际中从ThreadLocal获取用户id
        this.setFieldValByName("updateTime", Date.from(LocalDateTime.now().toInstant(ZoneOffset.UTC)), metaObject);
        this.setFieldValByName("updateUser", "1", metaObject);
    }
}	

剩下就是在service层使用mapper接口insert、update数据即可。


http://lihuaxi.xjx100.cn/news/2142345.html

相关文章

Tauri 进阶使用与实践指南

Tauri 进阶使用与实践指南 调试技术 在 Tauri 应用开发中&#xff0c;调试分为两大部分&#xff1a;Web 端与 Rust 控制台。 Web 端调试 在 Web 端界面&#xff0c;可以直接采用浏览器内置的开发者工具进行调试。在 Windows 上&#xff0c;可以通过快捷键 Ctrl Shift i 打…

LabVIEW专栏二、调用子VI

该节目标是创建带子vi&#xff0c;修改vi属性&#xff0c;测试可重入和不可重入的区别 一 、设置子VI 把VI封装成为子VI&#xff0c;可以帮助模块化程序&#xff0c;简化代码结构。 任何VI本身都可以成为别的VI的子VI。 1.1、设置输入输出端子 1、在前面板空白处&#xff0…

Vue3:使用Pinia存储、读取、修改数据

一、存储数据 Pinia插件中&#xff0c;存储数据的配置项是state count.ts import {defineStore} from piniaexport const useCountStore defineStore(count,{// 真正存储数据的地方state(){return {sum:6}} })loveTalk.ts import {defineStore} from piniaexport const use…

WebKit结构简介

WebKit是一款开源的浏览器引擎&#xff0c;用于渲染网页内容。它负责将HTML、CSS和JavaScript等网络资源转换为用户在屏幕上看到的图形界面。WebKit是一个跨平台的引擎&#xff0c;可以在多种操作系统上运行&#xff0c;如Windows、macOS、Linux等。 以下是一篇关于WebKit结构…

Mini-React

jsx jsx 是React中对于JavaScript的语法扩展&#xff0c;允许在JavaScript中去写类似于HTML的代码。使得开发者能够以一种更直观和声明式的方式去编写用户界面 vdom vdom是React为了提高性能而去引入的一个虚拟的dom表示。 它是一个轻量级的 JavaScript 对象&#xff0c;用于…

软考高级架构师:系统性能设计-阿姆达尔定律概念和例题

一、AI 讲解 系统性能设计中的一个重要概念是阿姆达尔定律&#xff08;Amdahl’s Law&#xff09;。阿姆达尔定律是由吉恩阿姆达尔&#xff08;Gene Amdahl&#xff09;在1967年提出的&#xff0c;用于评估系统性能提升的理论上限&#xff0c;特别是在考虑并行计算时。该定律表…

MySQL两表联查之分组成绩第几问题

MySQL 数据库操作实践&#xff1a;两表联查之分组成绩第几问题 在本篇博客中&#xff0c;我将展示MySQL 从创建表、到插入数据&#xff0c;并进行一些复杂的查询操作。 1. 建立表格 首先&#xff0c;我们创建两个表&#xff1a;department&#xff08;部门&#xff09;和 em…

Vue3:重构Pinia的store,使用组合式写法实现

一、情景说明 之前的count.ts和loveTalk.ts都是选项式写法 这里&#xff0c;重构成Vue3官方建议的组合式写法(Composition) 二、案例 以loveTalk.ts为例 1、选项式(Options)写法 import {defineStore} from pinia import axios from axios import {nanoid} from nanoidexpo…