博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
spring AOP 之五:Spring MVC通过AOP切面编程来拦截controller
阅读量:5301 次
发布时间:2019-06-14

本文共 14570 字,大约阅读时间需要 48 分钟。

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

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

新建一个springboot项目

1:首先定义maven

4.0.0
com.dxz.auth
auth-demo1
0.0.1-SNAPSHOT
jar
auth-demo1
Demo project for Spring Boot
org.springframework.boot
spring-boot-starter-parent
1.5.9.RELEASE
UTF-8
UTF-8
1.8
org.springframework.boot
spring-boot-starter
org.springframework
spring-core
org.springframework
spring-context-support
org.springframework
spring-web
org.springframework
spring-context
org.springframework
spring-webmvc
org.springframework
spring-webmvc-portlet
org.springframework
spring-test
org.springframework
spring-beans
org.springframework
spring-aspects
javax.servlet
javax.servlet-api
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-maven-plugin

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

package com.dxz.web.aop;import java.lang.annotation.*;@Target({ElementType.PARAMETER, ElementType.METHOD})@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @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@Aspectpublic 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);        }        // 拦截的实体类,就是当前正在执行的controller        Object 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 block                    logModel.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@ComponentScanpublic class AuthDemo1Application {    public static void main(String[] args) {        new SpringApplicationBuilder(AuthDemo1Application.class).web(true).run(args);    }}

启动springboot后,

通过浏览器访问:后的结果如下:

二、@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@Componentpublic 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;    }}

浏览器访问:

及   的结果如下:

 

转载于:https://www.cnblogs.com/duanxz/p/5226304.html

你可能感兴趣的文章
MySQL各版本的区别
查看>>
[poj1006]Biorhythms
查看>>
迭代器
查看>>
elasticsearch type类型创建时注意项目,最新的elasticsearch已经不建议一个索引下多个type...
查看>>
jQury 跳出each循环的方法
查看>>
spring AOP 之五:Spring MVC通过AOP切面编程来拦截controller
查看>>
在编译安装程序时候遇到/usr/bin/ld: cannot find -lxxx的时候的解决办法。
查看>>
使用 INSERT 和 SELECT 子查询插入行
查看>>
ubuntu重装mysql
查看>>
English trip -- VC(情景课)1 C What's your name?(review)
查看>>
redirect的错误用法asp.net怎么使用自定义错误
查看>>
在MyEclipse下统计工程的代码(package、行数、类个数)
查看>>
Erlcron分析学习
查看>>
idea 快捷键
查看>>
SimpleDateFormate的使用
查看>>
菜鸟运维笔记:Windows上用Xshell管理你的云主机
查看>>
JavaScript中的this
查看>>
Activity生命周期
查看>>
jsp
查看>>
OpenNI / NITE的Stable版更新
查看>>