spring AOP 之五:Spring MVC通过AOP切面编程来拦截controller

示例1:通过包路径及类名规则为应用增加切面

该示例是通过拦截所有com.dxz.web.aop包下的以Controller结尾的所有类的所有方法,在方法执行前后打印和记录日志到数据库。

新建一个springboot项目

1:首先定义maven

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.dxz.auth</groupId><artifactId>auth-demo1</artifactId><version>0.0.1-SNAPSHOT</version><packaging>jar</packaging><name>auth-demo1</name><description>Demo project for Spring Boot</description><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>1.5.9.RELEASE</version><relativePath/> <!-- lookup parent from repository --></parent><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><java.version>1.8</java.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-core</artifactId></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-context-support</artifactId></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-web</artifactId></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc-portlet</artifactId></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-beans</artifactId></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-aspects</artifactId></dependency><dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>

2:在拦截controller之前需要自定义一个注解,该注解是放在需要通过AOP织入系统日志的方法上。

package com.dxz.web.aop;import java.lang.annotation.*;@Target({ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SystemLog {String module()  default "";String methods()  default "";
}

3:定义记录日志的切面

package com.dxz.web.aop;import java.lang.reflect.Method;
import java.util.Date;import javax.servlet.http.HttpServletRequest;import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
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 org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;@Component
@Aspect
public class LogAopAction {// 获取开始时间private long BEGIN_TIME;// 获取结束时间private long END_TIME;// 定义本次log实体private LogModel logModel = new LogModel();@Pointcut("execution(* com.dxz.web.aop.*Controller.*(..))")private void controllerMethodAspect() {}/*** 方法开始执行*/@Before("controllerMethodAspect()")public void doBefore() {BEGIN_TIME = new Date().getTime();System.out.println("aop--开始");}/*** 方法结束执行*/@After("controllerMethodAspect()")public void after() {END_TIME = new Date().getTime();System.out.println("aop--结束");}/*** 方法结束执行后的操作*/@AfterReturning("controllerMethodAspect()")public void doAfter() {if (logModel.getState() == 1 || logModel.getState() == -1) {logModel.setActionTime(END_TIME - BEGIN_TIME);logModel.setGmtCreate(new Date(BEGIN_TIME));System.out.println("aop--将logModel="+logModel +",存入到数据库");} else {System.out.println(logModel);System.out.println("aop-->>>>>>>>不存入到数据库");}}/*** 方法有异常时的操作*/@AfterThrowing("controllerMethodAspect()")public void doAfterThrow() {System.out.println("aop--例外通知-----------------------------------");}/*** 方法执行* * @param pjp* @return* @throws Throwable*/@Around("controllerMethodAspect()")public Object around(ProceedingJoinPoint pjp) throws Throwable {// 日志实体对象HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();// 获取当前登陆用户信息String uid = request.getParameter("uid");if (uid == null) {logModel.setLoginAccount("—— ——");} else {logModel.setLoginAccount(uid);}// 拦截的实体类,就是当前正在执行的controllerObject target = pjp.getTarget();// 拦截的方法名称。当前正在执行的方法String methodName = pjp.getSignature().getName();// 拦截的方法参数Object[] args = pjp.getArgs();// 拦截的放参数类型Signature sig = pjp.getSignature();MethodSignature msig = null;if (!(sig instanceof MethodSignature)) {throw new IllegalArgumentException("该注解只能用于方法");}msig = (MethodSignature) sig;Class[] parameterTypes = msig.getMethod().getParameterTypes();Object object = null;Method method = null;try {method = target.getClass().getMethod(methodName, parameterTypes);} catch (NoSuchMethodException e1) {// TODO Auto-generated catch block
            e1.printStackTrace();} catch (SecurityException e1) {// TODO Auto-generated catch block
            e1.printStackTrace();}if (null != method) {// 判断是否包含自定义的注解,说明一下这里的SystemLog就是我自己自定义的注解if (method.isAnnotationPresent(SystemLog.class)) {SystemLog systemlog = method.getAnnotation(SystemLog.class);logModel.setModule(systemlog.module());logModel.setMethod(systemlog.methods());logModel.setLoginIp(getIp(request));logModel.setActionUrl(request.getRequestURI());try {object = pjp.proceed();logModel.setDescription("执行成功");logModel.setState((short) 1);} catch (Throwable e) {// TODO Auto-generated catch blocklogModel.setDescription("执行失败");logModel.setState((short) -1);}} else {// 没有包含注解object = pjp.proceed();logModel.setDescription("此操作不包含注解");logModel.setState((short) 0);}} else { // 不需要拦截直接执行object = pjp.proceed();logModel.setDescription("不需要拦截直接执行");logModel.setState((short) 0);}return object;}/*** 获取ip地址* * @param request* @return*/private String getIp(HttpServletRequest request) {if (request.getHeader("x-forwarded-for") == null) {return request.getRemoteAddr();}return request.getHeader("x-forwarded-for");}
}

 其中我的LogModel实体类如下:

package com.dxz.web.aop;import java.util.Date;public class LogModel {/**日志id */private Integer id;/** * 当前操作人id */private String loginAccount;/**当前操作人ip */private String loginIp;/**操作请求的链接     */private String actionUrl;/**执行的模块 */private String module;/**执行的方法 */private String method;/**执行操作时间 */private Long actionTime;/** 描述     */private String description;/** 执行的时间 */private Date gmtCreate;/** 该操作状态,1表示成功,-1表示失败! */private Short state;//set()/get()
}

4:业务controller中增加@SystemLog注解

package com.dxz.web.aop;import javax.servlet.http.HttpServletRequest;import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;@RestController
@RequestMapping("/user")
public class LoginController {/*** 登录方法* @param request* @return*/@RequestMapping(value="/toLogin", method = RequestMethod.GET, produces = {"application/json;charset=UTF-8"})@SystemLog(methods="用户管理", module = "用户登录")public String toLogin(HttpServletRequest request) {System.out.println("biz--登录验证中");return "login";}
}

5、springboot配置类

package com.dxz;import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.EnableAspectJAutoProxy;@SpringBootApplication
@EnableAspectJAutoProxy
@ComponentScan
public class AuthDemo1Application {public static void main(String[] args) {new SpringApplicationBuilder(AuthDemo1Application.class).web(true).run(args);}
}

启动springboot后,

通过浏览器访问:http://localhost:8080/user/toLogin?uid=duanxz后的结果如下:

二、@Pointcut("execution(* com.dxz.web.aop.*Controller.*(..))")是“com.dxz.web.aop”包下所有以Controller结尾的类的所有方法,为了验证,我再增加2个controller如下:

package com.dxz.web.aop;import javax.servlet.http.HttpServletRequest;import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;@RestController
@RequestMapping("/user")
public class LogoutController {/*** 退出方法* @param request* @return*/@RequestMapping(value="/logout", method = RequestMethod.GET, produces = {"application/json;charset=UTF-8"})@SystemLog(methods="用户管理", module = "用户退出")public String logout(HttpServletRequest request) {System.out.println("biz--退出逻辑");return "logout";}
}
package com.dxz.web.aop;import javax.servlet.http.HttpServletRequest;import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;@RestController
@RequestMapping("/user")
public class TestController2 {/*** test方法* @param request* @return*/@RequestMapping(value="/test", method = RequestMethod.GET, produces = {"application/json;charset=UTF-8"})@SystemLog(methods="用户管理", module = "用户测试")public String test(HttpServletRequest request) {System.out.println("biz--test");return "test";}
}

结果:

 示例2:通过within()指定所有@RestController注解类 + @annotation()指定方法上有@Auth注解

package com.dxz.web.aop.auth;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Order(Ordered.HIGHEST_PRECEDENCE) //优先级,暂定最高级
public @interface Auth {boolean login() default false;
}package com.dxz.web.aop.auth;import javax.servlet.http.HttpServletRequest;import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;@Aspect
@Component
public class AuthAopAction {@Before("within(@org.springframework.web.bind.annotation.RestController *) && @annotation(authParam)")public void requestLimit(JoinPoint joinPoint, Auth authParam) throws AuthException {HttpServletRequest request = null;try {Object[] args = joinPoint.getArgs();for (int i = 0; i < args.length; i++) {if (args[i] instanceof HttpServletRequest) {request = (HttpServletRequest) args[i];break;}}if (null == request) {System.out.println("auth handler error : target:[{}] no param : HttpServletRequest");throw new AuthException("HttpServletRequest is null error.");}if (null != authParam && authParam.login()) {// 登录权限验证开启//Object userId = request.getSession().getAttribute("uid");Object userId = request.getParameter("uid");if ("duanxz".equals(userId)) {System.out.println("账号正确,成功登录");} else {System.out.println("账号不正确,需要重新登录");throw new AuthException("NEED_LOGIN");}}} catch (Exception e) {System.out.println("auth handler error : exception:{}" + e.getMessage());throw e;}}
}
package com.dxz.web.aop.auth;
public class AuthException extends Exception {private static final long serialVersionUID = -1341655401594111052L;public AuthException() {super();}public AuthException(String message) {super(message);}}

下面的交易controller用于是否登录的权限验证

package com.dxz.web.aop;import javax.servlet.http.HttpServletRequest;import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;import com.dxz.web.aop.auth.Auth;@Controller
@RestController
@RequestMapping("/pay")
public class PayController {@Auth(login = true)@RequestMapping(value="prePay", method = RequestMethod.GET, produces = {"application/json;charset=UTF-8"})public String prePay(HttpServletRequest request) {String result = "预交易,uid=" + request.getParameter("uid");System.out.println(result);return result;}
}

浏览器访问:

http://localhost:8080/pay/prePay?uid=duanxz

及   http://localhost:8080/pay/prePay?uid=duanxz2的结果如下:

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/398833.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数据结构杂谈(二)

本文的所有代码均由C编写 如果你已经看完这篇杂谈&#xff0c;可以前往下一篇→数据结构杂谈&#xff08;三&#xff09;_尘鱼好美的小屋-CSDN博客 文章目录2 顺序表2.1 线性表的类型定义2.2 类C语言有关操作补充2.2.1 ElemType的解释2.2.2 数组定义2.2.3 建立链表可能会用到的…

2月份Web服务器份额:排名不变 仅Microsoft份额上扬

IDC评述网&#xff08;idcps.com&#xff09;02月29日报道&#xff1a;近日&#xff0c;Netcraft公布了全球Web服务器最新数据。根据显示&#xff0c;2016年2月&#xff0c;Netcraft收到调查的网站共计933,892,520家&#xff0c;相比上月增加3%。在全球主流Web服务器市场上&…

每日一题——剑指offer18单链表的删除

如果您是第一次看我写的博客&#xff0c;可以给我点个赞并关注我吗&#xff0c;我会持续分享更多有意思的干货。 每日一题系列从今天开始&#xff0c;由于我是个算法小白&#xff0c;所以我会给你看看小白是怎么学的。&#x1f487; 文章目录1 题目2 思路3 代码4 小结1 题目 剑…

王道操作系统考研笔记——1.1.1 操作系统的概念、功能和目标

如果这篇博客对您有用的话&#xff0c;可以给我点个赞吗&#xff0c;这对我很重要&#xff0c;谢谢&#xff01;❤️ 文章目录1.1.1 操作系统的概念、功能和目标1.1.1.1 操作系统的概念1.1.1.2 作为系统资源的管理者1.1.1.3 作为用户和计算机硬件之间的接口1.1.1.4 作为最接近硬…

《从零开始学Swift》学习笔记(Day 8)——小小常量、变量大作用

原创文章&#xff0c;欢迎转载。转载请注明&#xff1a;关东升的博客计算机语言学习中都有常量和变量&#xff0c;他们几乎是我编写代码的灵魂了&#xff0c;离开他们我真的是“活不了”常量是标识符的前面加上关键字let。常量其值在使用过程中不会发生变化的量&#xff0c;下面…

王道操作系统考研笔记——1.1.2 操作系统的特征

如果这篇博客对您有用的话&#xff0c;可以给我点个赞吗&#xff0c;这对我很重要&#xff0c;谢谢&#xff01;❤️ 1.1.2 操作系统的特征 文章目录1.1.2 操作系统的特征1.1.2.1 并发1.1.2.2 共享1.1.2.3 并发和共享的关系1.1.2.4 虚拟1.1.2.5 异步1.1.2.6 小结我们接下来讲的…

linux新起之秀-linux文件属性

2019独角兽企业重金招聘Python工程师标准>>> 从做到右&#xff1a;1为inode 的节点号&#xff1b;2为文件类型及权限&#xff1b;3为文件或目录的硬链接数&#xff1b;4为属主及所归属的组(属主就想象似地主&#xff0c;属组就像奴才的部分)&#xff1b;5为文件或者…

王道操作系统考研笔记——1.1.3 操作系统的发展及分类

如果这篇博客对您有用的话&#xff0c;可以给我点个赞吗&#xff0c;这对我很重要&#xff0c;谢谢&#xff01;❤️ 文章目录1.1.3 操作系统的发展及分类1.1.3.1 手工操作阶段1.1.3.2 单道批处理系统1.1.3.3 多道批处理系统1.1.3.4 分时操作系统1.1.3.5 实时操作系统1.1.3.6 其…

iOS开发之如何将字典转为模型

2019独角兽企业重金招聘Python工程师标准>>> 刚刚学习了如何读取plist&#xff0c;将plist中的字典对象转成数组对象。字典和模型都可以存储数据&#xff0c;既然都可以存储对象&#xff0c;那么为什么要把plist中的字典转成模型呢&#xff1f; 字典 &#xff1a;通…

王道操作系统考研笔记——1.1.4 操作系统的运行机制和体系结构

如果这篇博客对您有用的话&#xff0c;可以给我点个赞吗&#xff0c;这对我很重要&#xff0c;谢谢&#xff01;❤️ 文章目录1.1.4 操作系统的运行机制和体系结构1.1.4.1 两种指令、两种处理器状态、两种程序1.1.4.2 操作系统的内核1.1.4.3 操作系统的体系结构1.1.4.4 小结1.1…

How to remove replication in SyteLine V2

以前曾经写了一篇《How to remove replication in Syteline》http://www.cnblogs.com/insus/archive/2011/12/20/2294831.html 过于简单。 由于SyteLine采用共享License的授技术&#xff0c;如果你从一个正式的数据库复制一个备份&#xff0c;恢复至另外一个站点上&#xff0c…

【Keras】基于SegNet和U-Net的遥感图像语义分割

上两个月参加了个比赛&#xff0c;做的是对遥感高清图像做语义分割&#xff0c;美其名曰“天空之眼”。这两周数据挖掘课期末project我们组选的课题也是遥感图像的语义分割&#xff0c;所以刚好又把前段时间做的成果重新整理和加强了一下&#xff0c;故写了这篇文章&#xff0c…

每日一题——剑指 Offer24反转链表

如果您是第一次看我写的博客&#xff0c;可以给我点个赞并关注我吗&#xff0c;我会持续分享更多有意思的干货。 文章目录1 题目2 思路3 代码4 小结1 题目 剑指 Offer 24. 反转链表 定义一个函数&#xff0c;输入一个链表的头节点&#xff0c;反转该链表并输出反转后链表的头…

手把手教你写专利申请书/怎样申请专利

手把手教你写专利申请书怎样申请专利摘要小前言&#xff08;一&#xff09;申请前的准备工作 1、申请前查询 2、其它方面的考虑 3、申请文件准备&#xff08;二&#xff09;填写专利申请系列文档 1、实际操作步骤 2、详细操作 3、经验分享、注意事项&#xf…

计算机无法更新正在撤销更改,win7系统无法完成更新正在撤销更改的解决办法...

win7系统无法完成更新正在撤销更改的解决办法&#xff1f;如果我们在使用win7更新系统的时候&#xff0c;出现了win7无法完成更新正在撤销更改请不要关闭你的计算机这样的提示&#xff0c;而且不关闭提醒就会一直收到提示。小编觉得可以在win7设置中的更新和安全里面进行高级选…

王道操作系统考研笔记——1.1.6 系统调用

如果这篇博客对您有用的话&#xff0c;可以给我点个赞吗&#xff0c;这对我很重要&#xff0c;谢谢&#xff01;❤️ 文章目录1.1.6 系统调用1.1.6.1 系统调用和作用1.1.6.2 系统调用和库函数1.1.6.3 系统调用背后的过程1.1.6.4 小结1.1.6 系统调用 知识总览 1.1.6.1 系统调用…

计算机设备行业特征,自动装配机在自动化设备行业具有的特点

伴随着社会经济的不断发展&#xff0c;工业生产的市场规模越来越大&#xff0c;人们的需求也越来越大。自动装配机在自动化设备行业具有哪些特点?鲁工自动化小编对自动装配机的特点进行了分析。1.自动装配机需要由多台工作台进行扩展和分级。上层控制器&#xff0c;用来控制二…

Netty实例-简单的服务端-client实现,凝视具体

书籍推荐&#xff1a; 实例代码 &#xff1a; http://download.csdn.net/detail/jiangtao_st/7677503Netty Server端实现/*** * <p>* Netty Server Simple* </p>* * author 卓轩* 创建时间&#xff1a;2014年7月7日* versi…

数据结构杂谈(四)

本文的所有代码均由C编写 4 双链表、循环链表和静态链表 文章目录4 双链表、循环链表和静态链表4.1 双链表4.1.1 双链表的定义4.1.2 双链表的初始化4.1.2 双链表的后插操作4.1.3 双链表的后删操作4.1.4 双链表的销毁操作4.2 循环链表4.2.1 循环链表的概念4.2.2 循环单链表4.2.2…