什么是AOP,Spring AOP?
- AOP是面向切面编程,AOP不是单独指某一种技术,而是一种编程思想,AOP是OOP的补充,用于处理业务逻辑中的横切关注点,比如日志记录,事务控制,性能统计,异常处理等等。AOP的主要功能是将大量的通用行为从业务逻辑中抽取出来,封装成独立的非业务方法,用于横向切入,这些行为不会对已有的业务逻辑代码产生影响。
- AOP是一种设计思想,而Spring AOP则是符合AOP思想的一种框架实现。
为什么使用Spring AOP实现日记记录?
- Spring AOP是Spring框架的两大核心之一,是Spring框架的一部分,Spring AOP可以直接在Spring应用中直接使用。
- Spring AOP是一种极其优秀的AOP思想实现,对业务逻辑代码完全无侵入性,代码可维护性高。
使用Spring AOP实现日志记录
搭建项目环境
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
| <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.4.RELEASE</version> </parent>
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.0.5</version> </dependency> </dependencies>
<build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build>
|
创建数据库日志表
1 2 3 4 5 6 7 8 9 10 11 12
| CREATE TABLE `log` ( `id` int(10) NOT NULL AUTO_INCREMENT, `visit_time` datetime DEFAULT NULL, `username` varchar(20) DEFAULT NULL, `ip` varchar(20) DEFAULT NULL, `uri` varchar(50) DEFAULT NULL, `method` varchar(100) DEFAULT NULL, `execution_time` bigint(20) DEFAULT NULL, `exception_name` varchar(50) DEFAULT NULL, `exception_message` varchar(20) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=19 DEFAULT CHARSET=utf8;
|
创建日志实体类
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| @Data @TableName("log") public class Log { @TableId(type = IdType.AUTO) private Long id; private Date visitTime; private String username; private String ip; private String uri; private String method; private Long executionTime; private String exceptionName; private String exceptionMessage; }
|
Controller层的接口编写
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| @RestController @RequestMapping("user") public class UserController {
@Autowired private UserService userService;
@GetMapping("page/{currentPage}") public ResponseEntity<IPage<User>> findUserByPage( @PathVariable("currentPage") Integer currentPage, @RequestParam(defaultValue = "5") Integer size) throws Exception { int i = 1/0; return ResponseEntity.ok(userService.findUserByPage(currentPage, size)); }
@PostMapping("add") public ResponseEntity<Void> saveUser(User user) throws Exception { userService.saveUser(user); return ResponseEntity.status(HttpStatus.OK).build(); }
@DeleteMapping("{id}") public ResponseEntity<Void> delUserById(@PathVariable("id") Long id) throws Exception { userService.delUserById(id); return ResponseEntity.status(HttpStatus.OK).build(); }
@PutMapping("update") public ResponseEntity<Void> updateUser(User user) throws Exception { userService.updateUser(user); return ResponseEntity.status(HttpStatus.OK).build(); } }
|
AOP切面类的编写
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| @Aspect @Component public class LogAop {
@Autowired private HttpServletRequest request;
@Autowired private LogDao logDao;
private Log log;
@Pointcut("execution(* com.hrp.web.*.*(..))") public void controllerAOP(){}
@Before("controllerAOP()") public void doBefore(){ log = new Log(); log.setVisitTime(new Date()); }
@After("controllerAOP()") public void doAfter(JoinPoint joinPoint){ log.setExecutionTime(System.currentTimeMillis() - log.getVisitTime().getTime()); log.setIp(request.getRemoteAddr()); log.setUri(request.getRequestURI()); log.setMethod("[类名]"+joinPoint.getTarget().getClass()+"[方法名]"+joinPoint.getSignature().getName()); }
@AfterReturning("controllerAOP()") public void doAfterReturning(){ logDao.insert(log); }
@AfterThrowing(value = "controllerAOP()",throwing = "e") public void doException(Exception e){ log.setExceptionName(e.getClass().getName()); log.setExceptionMessage(e.getMessage()); logDao.insert(log); } }
|
功能测试
启动项目,访问/user/page/2
接口,分页查询用户数据。
访问/user/2
接口,删除id为2的用户信息。
最终数据库中的日志记录数据如下: