当前位置: 首页 > news >正文

Springboot 自定义注解AOP实现时间参数格式转换

前言

场景:

前端传过来的时间参数,我们后端自定义时间格式转化使用,想转成什么就转成什么。

不同业务场景,跟前端对接,一种控件基本时间参数是固定格式的,为了避免前端去转换时间参数的格式,跟前端约定好,让他们固定传递一种格式,后端自己看需求转换格式使用即可。

效果:

① 从 yyyy-MM-dd HH:mm:ss 转换成 yyyy-MM-dd 使用:

② 从 yyyyMMddHHmmss 转换成 yyyy-MM-dd HH:mm:ss 使用:

③不再举例,其实就是自己想怎么转就怎么转。



正文

实战

pom.xml (aop依赖、lombok依赖):
 

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.20</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>5.2.7.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjtools</artifactId>
            <version>1.9.5</version>
        </dependency>
        <dependency>
            <groupId>aopalliance</groupId>
            <artifactId>aopalliance</artifactId>
            <version>1.0</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.0</version>
        </dependency>
        <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>3.3.0</version>
        </dependency>

核心(自定义注解+拦截器):

 

 

自定义注解 一 :  

DateField.java

用途: 用于标记哪个字段需要进行时间格式转换,配置旧格式,新格式(都可写默认值)。

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

/**
 * @Author: JCccc
 * @Date: 2022-4-11 18:45
 * @Description:
 */

@Target({ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface DateField {

    String oldPattern() default DateUtil.YYYY_MM_DD_HH_MM_SS;
    
    //新格式可以写默认也可以不写,如果业务比较固定,那么新时间格式和旧时间格式都可以固定写好
    String newPattern() default "";
}

自定义注解 二 :

NeedDateFormatConvert.java

用途: 用于标记哪个接口需要进行AOP方式 时间格式转换。

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

/**
 * @Author: JCccc
 * @Date: 2022-4-11 18:44
 * @Description:
 */
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface NeedDateFormatConvert {

}

拦截器:

DateFormatAspect.java

用途: 核心转换实现逻辑。

import com.jctest.dotestdemo.util.DateUtil;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.lang.reflect.Field;
import java.util.Objects;


/**
 * @Author: JCccc
 * @Date: 2022-4-11 18:57
 * @Description:
 */
@Aspect
@Component
public class DateFormatAspect {
    private static Logger log = LoggerFactory.getLogger(DateFormatAspect.class);

    @Pointcut("@annotation(com.jctest.dotestdemo.aop.dateFormat.NeedDateFormatConvert)")
    public void pointCut() {
    }

    @Around("pointCut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        //转换
        dateFormat(joinPoint);
        return joinPoint.proceed();
    }

    public void dateFormat(ProceedingJoinPoint joinPoint) {
        Object[] objects = null;
        try {
            objects = joinPoint.getArgs();
            if (objects.length != 0) {
                for (int i = 0; i < objects.length; i++) {
                    //当前只支持判断对象类型参数
                    convertObject(objects[i]);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("参数异常");

        }
    }

    /**
     * 转换对象里面的值
     *
     * @param obj
     * @throws IllegalAccessException
     */
    private void convertObject(Object obj) throws IllegalAccessException {

        if (Objects.isNull(obj)) {
            log.info("当前需要转换的object为null");
            return;
        }
        Field[] fields = obj.getClass().getDeclaredFields();
        for (Field field : fields) {
            boolean containFormatField = field.isAnnotationPresent(DateField.class);
            if (containFormatField) {
                //获取访问权
                field.setAccessible(true);
                DateField annotation = field.getAnnotation(DateField.class);
                String oldPattern = annotation.oldPattern();
                String newPattern = annotation.newPattern();
                Object dateValue = field.get(obj);
                if (Objects.nonNull(dateValue) && StringUtils.hasLength(oldPattern) && StringUtils.hasLength(newPattern)) {
                    String newDateValue = DateUtil.strFormatConvert(String.valueOf(dateValue), oldPattern, newPattern);
                    if (Objects.isNull(newDateValue)){
                        log.info("当前需要转换的日期数据转换失败 dateValue = {}",dateValue.toString());
                        throw new RuntimeException("参数转换异常");
                    }
                    field.set(obj, newDateValue);
                }
            }
        }
    }
    
}

工具类:
DateUtil.java

用途: 时间格式转换函数、定义各种时间格式。

import lombok.extern.slf4j.Slf4j;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

/**
 * @Author: JCccc
 * @Date: 2022-4-1 14:48
 * @Description:
 */
@Slf4j
public class DateUtil {

    public static final String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss";
    public static final String YYYY_MM_DD = "yyyy-MM-dd";
    public static final String YYYY_MM = "yyyy-MM";
    public static final String YYYY = "yyyy";
    public static final String MM = "MM";
    public static final String DD = "dd";
    public static final String YYYYMMDDHHMMSS = "yyyyMMddHHmmss";
    public static final String YYYYMMDD = "yyyyMMdd";

    /**
     * 指定日期格式转换
     *
     * @param dateStr
     * @param oldPattern
     * @return
     */
    public static String strFormatConvert(String dateStr, String oldPattern,String newPattern) {
        try {
            DateTimeFormatter oldFormatter = DateTimeFormatter.ofPattern(oldPattern);
            DateTimeFormatter newFormatter = DateTimeFormatter.ofPattern(newPattern);
            return LocalDateTime.parse(dateStr, oldFormatter).format(newFormatter);
        } catch (Exception e) {
            log.error("strToDate is Exception. e:", e);
            return null;
        }
    }
}

使用 :

UserQueryVO.java 

import com.jctest.dotestdemo.aop.dateFormat.DateField;
import com.jctest.dotestdemo.util.DateUtil;
import lombok.Data;

import java.io.Serializable;

/**
 * @Author: JCccc
 * @Date: 2022-4-1 14:48
 * @Description:
 */
@Data
public class UserQueryVO implements Serializable {
    /**
     * 开始时间
     */
    @DateField(oldPattern =DateUtil.YYYY_MM_DD_HH_MM_SS, newPattern = DateUtil.YYYY_MM_DD)
    private String startDate;
    /**
     * 结束时间
     */
    @DateField(oldPattern =DateUtil.YYYY_MM_DD_HH_MM_SS,newPattern = DateUtil.YYYY_MM_DD)
    private String endDate;
}

接口:

import com.jctest.dotestdemo.aop.dateFormat.NeedDateFormatConvert;
import com.jctest.dotestdemo.vo.UserQueryVO;
import org.springframework.web.bind.annotation.*;

/**
 * @Author: JCccc
 * @Date: 2022-4-18 11:52
 * @Description:
 */
@RestController
public class UserController {

    @NeedDateFormatConvert
    @PostMapping("/test")
    public String test( @RequestBody UserQueryVO userQueryVO){
        System.out.println("时间格式转化完成:");
        System.out.println(userQueryVO.getStartDate());
        System.out.println(userQueryVO.getEndDate());
        return userQueryVO.toString();
    }
}

调用:

 

 

PS: 也许很多人知道,有些框架也提供了这些类似的使用注解,就会想,为什么不直接用框架?

总有你不能使用的时候,不做回应。

好了,该篇就到这吧。

相关文章:

  • 看什么看啊,你不会还不会抓HTTPS请求报文吧?
  • 做一个合格的开发,从玩转Apipost开始
  • Springboot 整合 企业微信机器人助手推送消息
  • Springboot 同一次调用日志怎么用ID串起来,方便最终查找
  • IDEA 运行Tomcat项目 控制台乱码
  • Springboot 整合 xxljob 使用定时任务调度(新手入门篇)
  • Springboot @SpringBootTest 单元测试执行两次的问题
  • Amazon ElastiCache 飞速搭建缓存服务集群,这才叫快
  • Springboot 整合 xxljob 动态API调度任务(进阶篇)
  • getReader() has already been called for this request
  • (Redis使用系列) Springboot 使用redis实现接口幂等性拦截 十一
  • 客观看待mybatis 中使用 where 1=1
  • MySql 怎么查出符合条件的最新的数据行?
  • Springboot 手动分页查询,分批批量插入数据
  • SpringBoot (走读源码)静态方法中调用spring注入的对象,注入对象为null?
  • 0基础学习移动端适配
  • CAP理论的例子讲解
  • es6--symbol
  • java架构面试锦集:开源框架+并发+数据结构+大企必备面试题
  • jQuery(一)
  • Node 版本管理
  • Storybook 5.0正式发布:有史以来变化最大的版本\n
  • 分布式熔断降级平台aegis
  • 开源SQL-on-Hadoop系统一览
  • 力扣(LeetCode)965
  • 区块链技术特点之去中心化特性
  • 我是如何设计 Upload 上传组件的
  • 限制Java线程池运行线程以及等待线程数量的策略
  • 验证码识别技术——15分钟带你突破各种复杂不定长验证码
  • 移动端解决方案学习记录
  • 在weex里面使用chart图表
  • #include
  • #Linux(帮助手册)
  • (10)STL算法之搜索(二) 二分查找
  • (C语言)深入理解指针2之野指针与传值与传址与assert断言
  • (iPhone/iPad开发)在UIWebView中自定义菜单栏
  • (论文阅读32/100)Flowing convnets for human pose estimation in videos
  • (免费领源码)Python#MySQL图书馆管理系统071718-计算机毕业设计项目选题推荐
  • (三)Pytorch快速搭建卷积神经网络模型实现手写数字识别(代码+详细注解)
  • (转)nsfocus-绿盟科技笔试题目
  • *(长期更新)软考网络工程师学习笔记——Section 22 无线局域网
  • .gitignore文件_Git:.gitignore
  • .NET CF命令行调试器MDbg入门(一)
  • .NET Core WebAPI中使用Log4net 日志级别分类并记录到数据库
  • .Net Remoting常用部署结构
  • .NET 编写一个可以异步等待循环中任何一个部分的 Awaiter
  • .NET开源的一个小而快并且功能强大的 Windows 动态桌面软件 - DreamScene2
  • .net中的Queue和Stack
  • .w文件怎么转成html文件,使用pandoc进行Word与Markdown文件转化
  • @Async注解的坑,小心
  • @JsonSerialize注解的使用
  • @selector(..)警告提示
  • [ C++ ] STL_stack(栈)queue(队列)使用及其重要接口模拟实现
  • [.NET]桃源网络硬盘 v7.4
  • [Android Studio 权威教程]断点调试和高级调试