AOP基础及其进阶-案例实现

1.AOP基础-快速入门

1.1.AOP概述

  • AOP:Aspect Oriented Programming(面向切面编程,面向方面编程),其实就是面向特定方法编程。
  • 实现:
    • 动态代理是面向切面编程最主流的实现。而SpringAOP是Spring框架的高级技术,旨在管理bean对象的过程中,主要通过底层的动态代理机制,对特定的方法进行编程。
  • 场景:
    • 记录操作日志
    • 权限控制
    • 事务管理
  • 优势:
    • 代码无侵入
    • 减少重复代码
    • 提高开发效率
    • 维护方便

1.2.Spring AOP快速入门:统计各个业务层方法执行耗时

1.2.1导入依赖

  • 在pom.xml中导入AOP的依赖

    <!--AOP依赖-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-aop</artifactId>
    </dependency>
    

1.2.2编写AOP程序

  • 针对于特定的方法根据业务需要进行编程

    package com.dxc.aop;
    
    import lombok.extern.slf4j.Slf4j;
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.Around;
    import org.aspectj.lang.annotation.Aspect;
    import org.springframework.stereotype.Component;
    
    /**
     * ClassName: TimeAspect
     * Package: com.dxc.aop
     * Description:
     * <p>
     * {@code @Author} 段
     * {@code @Create} 2024/5/15 9:22
     * {@code @Version} 1.0
     */
    @Slf4j
    @Component  //将该类交给spring容器管理
    @Aspect //AOP类
    public class TimeAspect {
        @Around("execution(* com.dxc.service.*.*(..))") //切入点表达式
        public Object recordTime(ProceedingJoinPoint joinPoint) throws Throwable {
            //1.记录开始时间
            long begin = System.currentTimeMillis();
    
            //2.调用原始方法运行
            Object result = joinPoint.proceed();
    
            //3.记录结束时间,计算方法执行耗时
            long end = System.currentTimeMillis();
            log.info(joinPoint.getSignature() + "方法执行耗时:{}ms",end - begin);
    
            return result;
        }
    }
    

2.AOP基础-核心概念

  • 连接点:JoinPoint,可以被AOP控制的方法(暗含方法执行时的相关信息)
  • 通知:Advice,指那些重复的逻辑,也就是共性功能(最终体现为一个方法)
  • 切入点:PointCut,匹配连接点的条件,通知仅会在切入点方法执行时被应用
  • 切面:Aspect,描述通知与切入点的对应关系(通知+切入点)
  • 目标对象:Target,通知所应用的对象

注意:运用AOP开发后,最终运行的就不是原始的目标对象,而是spring底层基于目标对象所生成的代理对象

3.AOP进阶

3.1通知类型

  1. @Around:环绕通知,此注解标注的通知方法在目标方法前,后都被执行
  2. @Before:前置通知,此注解标注的通知方法在目标方法前被执行
  3. @After:后置通知(最终通知),此注解标注的通知方法在目标方法后被执行,无论是否有异常都会执行
  4. AfterReturning:返回通知,此注解标注的通知方法在目标方法后被执行,有异常不会执行
  5. AfterThrowing:异常后通知,此注解标注的通知方法发生异常后执行
  • 注意事项

    • @Around环绕通知需要自己调用ProceedingJoinPoint.proceed()来让原始方法执行,其他通知不需要考虑目标方法执行
    • @Around环绕通知方法的返回值必须指定为Object,来接收原始方法的返回值
  • @PointCut

    • 该注解的作用是将公共的切点表达式抽取出来,需要用到时引用该切点表达式即可。
    @Pointcut("execution(* com.dxc.service.impl.DeptServiceImpl.*(..))" ) //抽取切入点表达式
    public void pt() {}	//权限修饰符 private:仅能在当前切面类中引用该表达式;public:在其他外部的切面类中也可以引用该表达式
    
    @Around("com.dxc.aop.MyAspect1.pt()")
    public Object recordTime(ProceedingJoinPoint joinPoint) throws Throwable {
        //1.记录开始时间
        long begin = System.currentTimeMillis();
    
        //2.调用原始方法运行
        Object result = joinPoint.proceed();
    
        //3.记录结束时间,计算方法执行耗时
        long end = System.currentTimeMillis();
        log.info(joinPoint.getSignature() + "方法执行耗时:{}ms",end - begin);
    
        return result;
    }
    

3.2通知顺序

  • 当有多个切面的切入点都匹配到了目标方法,目标方法运行时,多个通知方法都会被执行
    在这里插入图片描述

3.2.1执行顺序

  1. 不同切面类中,默认按照切面类的类名字母排序:
    • 目标方法前的通知方法:字母排名靠前的先执行
    • 目标方法后的通知方法:字母排名靠后的先执行
  2. 用@Order(数字)加在切面类上来控制顺序
    • 目标方法前的通知方法:数字小的先执行
    • 目标方法后的通知方法:数字小的后执行

在这里插入图片描述

@Order(1)
@Slf4j
@Component
@Aspect
public class MyAspect4 {
@Order(2)
@Slf4j
@Component
@Aspect
public class MyAspect2 {
@Order(3)
@Slf4j
@Component
@Aspect
public class MyAspect3 {

3.3切入点表达式

  • 切入点表达式:描述切入点方法的一种表达式
  • 作用:主要用来决定项目中的那些方法需要加入通知
  • 常见形式:

3.3.1execution(…):根据方法的签名来匹配

  • execution主要根据方法的返回值,包名,类名,方法名,方法参数等信息来匹配,语法为:

    execution(访问修饰符? 返回值 包名.类名.?方法名(方法参数) throws 异常?)

  • 可以使用通配符描述切入点

    • *:单个独立的任意符号,可以统配任意返回值,包名,类名,方法名,任意类型的一个参数,也可以通配包,类,方法名的一部分

      • execution(* com.*.service.*.update*(*))
        
    • …:多个连续的任意符号,可以通配任意层级的包,或任意类型,任意个数的参数

      • execution(* com.dxc..DeptService.*(..)
        
  • 其中带?的表示可省略的部分

    • 访问修饰符:可省略(比如:public,protected)
    • 包名.类名:可省略
    • throws 异常:可省略(注意是方法上声明抛出的异常,不是实际抛出的异常)
    package com.dxc.aop;
    
    import lombok.extern.slf4j.Slf4j;
    import org.aspectj.lang.annotation.After;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Before;
    import org.aspectj.lang.annotation.Pointcut;
    import org.springframework.core.annotation.Order;
    import org.springframework.stereotype.Component;
    
    /**
     * ClassName: MyAspect1
     * Package: com.dxc.aop
     * Description:
     * <p>
     * {@code @Author} 段春喜
     * {@code @Create} 2024/5/16 9:26
     * {@code @Version} 1.0
     */
    @Slf4j
    @Component
    @Aspect
    public class MyAspect5 {
    
    //    @Pointcut("execution(public void com.dxc.service.impl.DeptServiceImpl.deleteById(java.lang.Integer) throws Exception)")
    //    @Pointcut("execution(void com.dxc.service.impl.DeptServiceImpl.deleteById(java.lang.Integer))")
    //    @Pointcut("execution(void deleteById(java.lang.Integer))")//包名.类名不建议省略(省略后匹配范围过大,影响匹配效率)
    //    @Pointcut("execution(void com.dxc.service.DeptService.deleteById(java.lang.Integer))")
    //    @Pointcut("execution(void com.dxc.service.DeptService.*(java.lang.Integer))")
    //    @Pointcut("execution(* com.*.service.DeptService.*(*))")
    //    @Pointcut("execution(* com.dxc.service.*Service.delete*(*))")
    
    //    @Pointcut("execution(* com.dxc.service.DeptService.*(..))")
    //    @Pointcut("execution(* com..DeptService.*(..))")
    //    @Pointcut("execution(* com..*.*(..))")
    //    @Pointcut("execution(* *(..))")//慎用
        @Pointcut("execution(* com.dxc.service.DeptService.list()) || " +
                "execution(* com.dxc.service.DeptService.deleteById(java.lang.Integer))")
        private void pt() {
        }
    
        @Before("pt()")  //前置通知,在DeptServiceImpl该类中所有的方法执行前执行
        public void before() {
            log.info("MyAspect5 ... before ...5");
        }
    
    
        @After("pt()")//后置通知,在原始方法运行之后运行
        public void after() {
            log.info("MyAspect5 ... after ...5");
        }
    
    }
    
    
    package com.dxc;
    
    import com.dxc.pojo.Dept;
    import com.dxc.service.DeptService;
    import org.junit.jupiter.api.Test;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.context.SpringBootTest;
    
    import java.util.List;
    
    /**
     * ClassName: SpringbootAopTest
     * Package: com.dxc
     * Description:
     * <p>
     * {@code @Author} 段
     * {@code @Create} 2024/5/16 19:39
     * {@code @Version} 1.0
     */
    @SpringBootTest
    public class SpringbootAopTest {
    
        @Autowired
        private DeptService deptService;
    
        @Test
        public void testAopDelete() throws Exception {
            deptService.deleteById(10);
        }
    
        @Test
        public void testAopList() {
            List<Dept> list = deptService.list();
            System.out.println(list);
        }
    }
    
    

    在这里插入图片描述

注意事项:根据业务需要,可以使用且(&&)、或(||),非(!)来组合比较复杂的切入点表达式

书写建议:

  • 所有业务方法名在命名时尽量规范,方便切入点表达式快速匹配。如查询类方法都是find开头,更新类方法都是update开头。
  • 描述切入点方法通常基于接口描叙,而不是直接描述实现类,增强拓展性。
  • 在满足业务需要的前提下,尽量缩小切入点的匹配范围。如:包名匹配尽量不要使用…,使用*匹配单个包

3.3.2@annotation(…):切入点表达式,用于匹配标识有特定注解的方法。(注解全类名)

  • @annotation(com.dxc.anno.Log)

    package com.dxc.aop;
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    /**
    
     * ClassName: MyLog
    
     * Package: com.dxc.aop
    
     * Description:
    
     * <p>
    
     * {@code @Author} 段
    
     * {@code @Create} 2024/5/20 14:52
    
     * {@code @Version} 1.0
       */
       @Retention(RetentionPolicy.RUNTIME) //该注解指定运行时才会生效
       @Target(ElementType.METHOD) //标注该注解可以作用在方法上
       public @interface MyLog {
       }
    
    package com.dxc.aop;
    import lombok.extern.slf4j.Slf4j;
    import org.aspectj.lang.annotation.After;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Before;
    import org.aspectj.lang.annotation.Pointcut;
    import org.springframework.core.annotation.Order;
    import org.springframework.stereotype.Component;
    
    /**
         * ClassName: MyAspect1
         * Package: com.dxc.aop
         * Description:
         * <p>
         * {@code @Author} 段
         * {@code @Create} 2024/5/16 9:26
         * {@code @Version} 1.0
         */
    
    @Slf4j
    @Component
    @Aspect
    public class MyAspect6 {
    
        //匹配DeptServiceImpl中的list() 和delete(Integer id)方法
        //    @Pointcut("execution(* com.dxc.service.DeptService.list()) || execution(* com.dxc.service.DeptService.deleteById())")
        @Pointcut("@annotation(com.dxc.aop.MyLog)")
        private void pt() {}
    
        @Before("pt()")  //前置通知,在DeptServiceImpl该类中所有的方法执行前执行
        public void before() {
            log.info("Mybefore ...6");
        }
    
    
        @After("pt()")//后置通知,在原始方法运行之后运行
        public void after() {
            log.info("Myafter ...6");
        }
    
    }
    
    package com.dxc;
    
    import com.dxc.pojo.Dept;
    import com.dxc.service.DeptService;
    import org.junit.jupiter.api.Test;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.context.SpringBootTest;
    
    import java.util.List;
    
    /**
     * ClassName: SpringbootAopTest
     * Package: com.dxc
     * Description:
     * <p>
     * {@code @Author} 段春喜
     * {@code @Create} 2024/5/16 19:39
     * {@code @Version} 1.0
     */
    @SpringBootTest
    public class SpringbootAopTest {
    
        @Autowired
        private DeptService deptService;
    
        @Test
        public void testAopDelete() throws Exception {
            deptService.deleteById(10);
        }
    
        @Test
        public void testAopList() {
            List<Dept> list = deptService.list();
            System.out.println(list);
        }
    }
    

3.4连接点

  • 在spring中用JoinPoint抽象了连接点,用它可以获得方法执行时的相关信息,如目标类名,方法名,方法参数等。

    • 对于@Around通知,获取连接点信息只能使用ProceedingJoinPoint
    • 对于其他四种通知,获取连接点信息只能使用JoinPoint,它是ProceedingJoinPoint的父类型
    package com.dxc.aop;
    
    import lombok.extern.slf4j.Slf4j;
    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.*;
    import org.springframework.stereotype.Component;
    
    import java.util.Arrays;
    
    /**
     * ClassName: MyAspect1
     * Package: com.dxc.aop
     * Description:
     * <p>
     * {@code @Author} 段
     * {@code @Create} 2024/5/16 9:26
     * {@code @Version} 1.0
     */
    
    @Slf4j
    @Component
    @Aspect
    public class MyAspect7 {
    
    
        @Pointcut("execution(* com.dxc.service.DeptService.*(..))")
        private void pt() {}
    
        @Before("pt()")
        public void before(JoinPoint joinPoint) {
            log.info("MyAspect7 ...before ...");
        }
    
        @Around("pt()")
        public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
            log.info("MyAspect7 around before ...");
    
            //1.获取目标对象的类名
            String className = joinPoint.getTarget().getClass().getName();
            log.info("目标对象的类名:{}",className);
    
            //2.获取目标方法的方法名
            String methodName = joinPoint.getSignature().getName();
            log.info("目标方法的方法名:{}",methodName);
    
            //3.获取目标方法运行时传入的参数
            Object[] args = joinPoint.getArgs();
            log.info("目标方法运行时传入的参数:{}", Arrays.toString(args));
    
            //4.放行 目标方法执行
            Object result = joinPoint.proceed();
          	//Object result = joinPoint.proceed(args);带参数	  
    
            //5.获取 目标方法运行的返回值
            log.info("目标方法运行的返回值:{}",result);
    
            log.info("MyAspect7 around after ...");
            return result;
        }
    
    }
    
    package com.dxc;
    
    import com.dxc.pojo.Dept;
    import com.dxc.service.DeptService;
    import org.junit.jupiter.api.Test;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.context.SpringBootTest;
    
    import java.util.List;
    
    /**
     * ClassName: SpringbootAopTest
     * Package: com.dxc
     * Description:
     * <p>
     * {@code @Author} 段
     * {@code @Create} 2024/5/16 19:39
     * {@code @Version} 1.0
     */
    @SpringBootTest
    public class SpringbootAopTest {
    
        @Autowired
        private DeptService deptService;
    
        @Test
        public void testAopDelete() throws Exception {
            deptService.deleteById(10);
        }
    
        @Test
        public void testAopList() {
            List<Dept> list = deptService.list();
            System.out.println(list);
        }
    }
    

4.AOP案例

  • 将案例中增,删,改相关接口的操作日志记录到数据库表中。
  • 日志信息包含:操作人,操作时间,执行方法的全类名,执行方法名,方法运行时参数,返回值,方法执行时长
  • 需要对所有业务类中的增,删,改方法添加一些功能,使用AOP技术最为方便 @Around 环绕通知
  • 由于增,删,改方法名没有规律,可以自定义@Log注解完成目标方法匹配

4.1步骤

4.1.1准备

  • 在案例工程中引入AOP的相关依赖

  • 导入资料中准备好的数据库表结构,并引入对应的实体类

    -- 操作日志表
    create table operate_log(
        id int unsigned primary key auto_increment comment 'ID',
        operate_user int unsigned comment '操作人ID',
        operate_time datetime comment '操作时间',
        class_name varchar(100) comment '操作的类名',
        method_name varchar(100) comment '操作的方法名',
        method_params varchar(1000) comment '方法参数',
        return_value varchar(2000) comment '返回值',
        cost_time bigint comment '方法执行耗时, 单位:ms'
    ) comment '操作日志表';
    
    package com.dxc.pojo;
    
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    import java.time.LocalDateTime;
    
    
    /**
     * ClassName: OperateLog
     * Package: com.dxc.pojo
     * Description:日志操作类
     * <p>
     * {@code @Author} 段
     * {@code @Create} 2024/5/20 16:19
     * {@code @Version} 1.0
     */
    
    
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public class OperateLog {
        private Integer id; //ID
        private Integer operateUser; //操作人ID
        private LocalDateTime operateTime; //操作时间
        private String className; //操作类名
        private String methodName; //操作方法名
        private String methodParams; //操作方法参数
        private String returnValue; //操作方法返回值
        private Long costTime; //操作耗时
    }
    
    package com.dxc.mapper;
    
    /**
     * ClassName: OperateLogMapper
     * Package: com.dxc.mapper
     * Description:插入日志数据
     * <p>
     * {@code @Author} 段
     * {@code @Create} 2024/5/20 16:21
     * {@code @Version} 1.0
     */
    import com.dxc.pojo.OperateLog;
    import org.apache.ibatis.annotations.Insert;
    import org.apache.ibatis.annotations.Mapper;
    
    @Mapper
    public interface OperateLogMapper {
    
        //插入日志数据
        @Insert("insert into operate_log (operate_user, operate_time, class_name, method_name, method_params, return_value, cost_time) " +
                "values (#{operateUser}, #{operateTime}, #{className}, #{methodName}, #{methodParams}, #{returnValue}, #{costTime});")
        public void insert(OperateLog log);
    
    }
    

4.1.2编码

  • 自定义注解@Log

    package com.dxc.anno;
    
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    /**
     * ClassName: Log
     * Package: com.dxc.anno
     * Description:
     * <p>
     * {@code @Author} 段
     * {@code @Create} 2024/5/20 16:24
     * {@code @Version} 1.0
     */
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.METHOD)
    public @interface Log {
    }
    
  • 定义切面类,完成记录操作日志的逻辑

    package com.dxc.aop;
    
    import com.alibaba.fastjson.JSONObject;
    import com.dxc.mapper.OperateLogMapper;
    import com.dxc.pojo.OperateLog;
    import com.dxc.utils.JwtUtils;
    import io.jsonwebtoken.Claims;
    import jakarta.servlet.http.HttpServletRequest;
    import lombok.extern.slf4j.Slf4j;
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.Around;
    import org.aspectj.lang.annotation.Aspect;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    
    import java.time.LocalDateTime;
    import java.util.Arrays;
    
    /**
     * ClassName: LogAspect
     * Package: com.dxc.aop
     * Description:
     * <p>
     * {@code @Author} 段
     * {@code @Create} 2024/5/20 16:27
     * {@code @Version} 1.0
     */
    @Slf4j
    @Component
    @Aspect //切面类
    public class LogAspect {
    
        @Autowired
        private HttpServletRequest request;
    
        @Autowired
        private OperateLogMapper operateLogMapper;
    
        @Around("@annotation(com.dxc.anno.Log)")
        public Object recordLod(ProceedingJoinPoint joinPoint) throws Throwable {
    
            //操作人ID - 当前登录员工ID
            //获取请求头中的jwt令牌,解析令牌
            String jwt = request.getHeader("token");
            Claims claims = JwtUtils.parseJWT(jwt);
            Integer operateUser = (Integer)claims.get("id");
    
            //操作时间
            LocalDateTime operateTime = LocalDateTime.now();
    
            //操作类的类名
            String className = joinPoint.getTarget().getClass().getName();
    
            //操作的方法名
            String methodName = joinPoint.getSignature().getName();
    
            //操作方法参数
            Object[] args = joinPoint.getArgs();
            String methodParams = Arrays.toString(args);
    
            long begin = System.currentTimeMillis();
            //调用原始目标方法运行
            Object result = joinPoint.proceed();
            System.currentTimeMillis();
            long end = System.currentTimeMillis();
    
            //方法返回值
            String returnValue = JSONObject.toJSONString(result);
    
            //方法操作耗时
            long costTime = end - begin;
    
    
            //记录操作日志
            OperateLog operateLog = new OperateLog(null,operateUser,operateTime,className,methodName,methodParams,returnValue,costTime);
            operateLogMapper.insert(operateLog);
    
            log.info("AOP记录操作日志:{}",operateLog);
    
            return result;
        }
    }
    
    package com.dxc.controller;
    
    import com.dxc.anno.Log;
    import com.dxc.pojo.Dept;
    import com.dxc.pojo.Result;
    import com.dxc.service.DeptService;
    import lombok.extern.slf4j.Slf4j;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.*;
    
    import java.util.List;
    
    /**
     * ClassName: DeptController
     * Package: com.dxc.controller
     * Description: 部门管理Controller
     * <p>
     * {@code @Author} 段
     * {@code @Create} 2024/4/8 13:32
     * {@code @Version} 1.0
     */
    @Slf4j
    @RestController //将该类作为控制器,交给Spring容器管理
    @RequestMapping("/depts")   //指定该类公共访问路径
    public class DeptController {
    
    //    private static Logger log = LoggerFactory.getLogger(DeptController.class);    直接引入Lombok框架的日志框架即可
    
        //注入service
        @Autowired
        private DeptService deptService;
    
    
        /**
         * 部门查询:
         *     查询全部数据,由于部门数据比较少,不考虑分页
         *     //1.接受请求
         *     //2.调用service查询部门
         *     //3.响应Result
         * @return
         */
    
    //    @RequestMapping(value = "depts",method = RequestMethod.GET)//指定请求方式为GET
        @GetMapping //1.接受请求
        public Result list() {
            log.info("查询全部部门数据");
    
            //2.调用service查询部门
            List<Dept> deptList =  deptService.list();
    
            //3.响应Result
            return Result.success(deptList);
        }
    
    
        /**
         * 根据ID删除部门
         */
        @Log
        @DeleteMapping("/{id}")
        public Result deleteById(@PathVariable Integer id) throws Exception {
            log.info("根据id删除部门:{}",id);
            deptService.deleteById(id);//根据id删除部门数据
            return Result.success();
        }
    
        /**
         *  添加部门
         * @param dept
         * @return
         */
        @Log
        @PostMapping
        public Result add(@RequestBody Dept dept) {
            log.info("添加部门:{}",dept);
            deptService.add(dept);
            return Result.success();
        }
    
        /**
         * 根据ID查询部门
         * @param id
         * @return
         */
        @GetMapping("/{id}")
        public Result getById(@PathVariable Integer id) {
            log.info("根据id查询部门:{}",id);
            Dept dept = deptService.getById(id);
            return Result.success(dept);
        }
    
    
        /**
         * 修改部门信息
         * @param dept
         * @return
         */
        @Log
        @PutMapping
        public Result update(@RequestBody Dept dept) {
            log.info("修改部门:{}",dept);
            deptService.update(dept);
            return Result.success();
        }
    }
    
    package com.dxc.controller;
    
    import com.dxc.anno.Log;
    import com.dxc.pojo.Emp;
    import com.dxc.pojo.PageBean;
    import com.dxc.pojo.Result;
    import com.dxc.service.EmpService;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.format.annotation.DateTimeFormat;
    import org.springframework.web.bind.annotation.*;
    
    import java.time.LocalDate;
    import java.util.List;
    
    /**
     * ClassName: EmpController
     * Package: com.dxc.controller
     * Description:员工管理Controller
     * <p>
     * {@code @Author} 段
     * {@code @Create} 2024/4/8 13:32
     * {@code @Version} 1.0
     */
    @Slf4j
    @RestController //将该类标注为控制层 ,交给Spring容器管理
    @RequestMapping("/emps")    //指定该类的公共访问路径
    public class EmpController {
    
        //注入EmpService
        @Autowired
        private EmpService empService;
    
        /**
         * 员工信息分页查询
         *
         * @param page
         * @param pageSize
         * @return
         */
        @GetMapping                 //@RequestParam注解中的defaultValue属性,表示请求参数没有传递时,默认值为1
        public Result page(@RequestParam(defaultValue = "1") Integer page,
                           @RequestParam(defaultValue = "10") Integer pageSize,
                           String name,
                           Short gender,
                           @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate begin,
                           @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate end) {
            //接受请求参数
            log.info("分页查询,参数:{},{},{},{},{},{}", page, pageSize, name, gender, begin, end);
    
            //调用service分页查询,封装pageBean对象
            PageBean pageBean = empService.page(page, pageSize, name, gender, begin, end);
    
            //响应结果
            return Result.success(pageBean);
        }
    
    
        /**
         * 批量删除员工信息
         *
         * @param ids
         * @return
         */
        @Log
        @DeleteMapping("/{ids}")
        public Result deleteById(@PathVariable List<Integer> ids) {
            log.info("批量删除员工信息,ids:{}", ids);
            empService.delete(ids);
            return Result.success();
        }
    
    
        /**
         * 新增员工信息
         *
         * @param emp
         * @return
         */
        @Log
        @PostMapping
        public Result save(@RequestBody Emp emp) {
            log.info("新增员工信息,{}", emp);
            empService.save(emp);
            return Result.success();
        }
    
        /**
         * 根据id查询员工信息
         * @param id
         * @return
         */
        @GetMapping("/{id}")
        public Result getById(@PathVariable Integer id) {
            log.info("根据id查询员工信息,id:{}",id);
            Emp emp = empService.getById(id);
            return Result.success(emp);
        }
    
        /**
         * 修改员工信息
         * @param emp
         * @return
         */
        @Log
        @PutMapping
        public Result update(@RequestBody Emp emp) {
            log.info("修改员工信息:{}",emp);
            empService.update(emp);
            return Result.success();
        }
    }
    

    jwt工具类

    package com.dxc.utils;
    
    import io.jsonwebtoken.Claims;
    import io.jsonwebtoken.Jwts;
    import io.jsonwebtoken.SignatureAlgorithm;
    import java.util.Date;
    import java.util.Map;
    
    public class JwtUtils {
    
        private static String signKey = "itheima";
        private static Long expire = 43200000L;
    
        /**
         * 生成JWT令牌
         * @param claims JWT第二部分负载 payload 中存储的内容
         * @return
         */
        public static String generateJwt(Map<String, Object> claims){
            String jwt = Jwts.builder()
                    .addClaims(claims)
                    .signWith(SignatureAlgorithm.HS256, signKey)
                    .setExpiration(new Date(System.currentTimeMillis() + expire))
                    .compact();
            return jwt;
        }
    
        /**
         * 解析JWT令牌
         * @param jwt JWT令牌
         * @return JWT第二部分负载 payload 中存储的内容
         */
        public static Claims parseJWT(String jwt){
            Claims claims = Jwts.parser()
                    .setSigningKey(signKey)
                    .parseClaimsJws(jwt)
                    .getBody();
            return claims;
        }
    }
    

    import java.util.Date;
    import java.util.Map;

    public class JwtUtils {

    private static String signKey = "itheima";
    private static Long expire = 43200000L;
    
    /**
     * 生成JWT令牌
     * @param claims JWT第二部分负载 payload 中存储的内容
     * @return
     */
    public static String generateJwt(Map<String, Object> claims){
        String jwt = Jwts.builder()
                .addClaims(claims)
                .signWith(SignatureAlgorithm.HS256, signKey)
                .setExpiration(new Date(System.currentTimeMillis() + expire))
                .compact();
        return jwt;
    }
    
    /**
     * 解析JWT令牌
     * @param jwt JWT令牌
     * @return JWT第二部分负载 payload 中存储的内容
     */
    public static Claims parseJWT(String jwt){
        Claims claims = Jwts.parser()
                .setSigningKey(signKey)
                .parseClaimsJws(jwt)
                .getBody();
        return claims;
    }
    

    }

    
    

在这里插入图片描述

  • 29
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值