解决spring mvc设置controller切面无效
maven 的pem.xml配置
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>4.1.1.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>4.1.1.RELEASE</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.8.9</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjrt</artifactId> <version>1.8.9</version> </dependency>
在applicationContext.xml 配置
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:task="http://www.springframework.org/schema/task" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd"> <!-- 扫描除controller以外的注解--> <context:component-scan base-package="com"> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller" /> </context:component-scan>
在spring-mvc.xml 一定要加入aop:aspectj-autoproxy, 不要把这个配置加在applicationContext.xml ,否则不起作用
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:task="http://www.springframework.org/schema/task" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd"> <!-- 自动扫描且只扫描@Controller --> <context:component-scan base-package="com" use-default-filters="false"> <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/> </context:component-scan> <!-- 找到事务无用的问题,问题出在设置了两次context:component 查找了一样的类。 如这里之前是只这样设置<context:component-scan base-package="com"/>,但这样会跟application-mybatis.xml里的 <context:component-scan base-package="com"> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller" /> </context:component-scan> 设置的查找类的范围相冲突,也就是它找一遍上面设置过的类,这样就会把事务的AOP去掉 --> <!--把代理从jdk交换给aspect切面代理 --> <aop:aspectj-autoproxy proxy-target-class="true"/>
方法1:
然后写一个java代码切面
package com.core.controlleraop; import com.alibaba.fastjson.JSONObject; import lombok.extern.slf4j.Slf4j; 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.springframework.stereotype.Component; import org.springframework.validation.BeanPropertyBindingResult; import org.springframework.validation.BindingResult; import org.springframework.validation.support.BindingAwareModelMap; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import org.springframework.web.multipart.MultipartHttpServletRequest; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.util.*; import java.util.stream.Collectors; /** * 切面 ,记录日志 */ @Slf4j @Aspect @Component public class ControllerAspect { @Before(value = "execution(public * com.test.controller.*.*(..))") public void beforeMethod(JoinPoint point) { System.out.println("------test aop before"); } @Pointcut("execution(* com.hkps.*.controller.*.*(..)) || execution(* com.hkps.*.*.controller.*.*(..)) || execution(* com.test.controller.*Controller.*(..))") // public void controllerMethods() { } /** * ** 支持get POST 的提交,但不支持formData提交 */ @Around("controllerMethods()&& args(.., @RequestBody requestBody)") // public Object aroundControllerMethods(ProceedingJoinPoint joinPoint, Object requestBody) throws Throwable { // // 在这里获取到 POST 请求体中的参数 // requestBody 就是 POST 请求体中的参数 HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); String reqUrl=request.getServletPath(); String data = getFormData(joinPoint, request, requestBody); // log.warn("ControllerAspect aroundControllerMethods url:{},body:{}",reqUrl,data); Date startDate = new Date(); try { // 执行原始方法 Object result = joinPoint.proceed(); // 可以对原始方法的返回值进行拦截和修改 return result; } catch (Throwable e) { log.error("aroundControllerMethods url:{},errormsg:{},e :{}",reqUrl,e.getMessage(),e); // 处理异常情况 throw e; } finally { HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()) .getResponse(); Date endDate = new Date(); Long costTime = endDate.getTime() - startDate.getTime(); //耗时 int status= response.getStatus(); // if(response!=null&&status==HttpServletResponse.SC_OK){ // log.info("aroundControllerMethods url:{},Response Status Code:{},Response Body:{},cost :{} ",reqUrl,status,response.getWriter().toString(),costTime); // }else{ log.info("aroundControllerMethods url:{},Response Status Code:{},cost :{} ",reqUrl,status,costTime); // } // // // 获取并处理Response对象 // System.out.println("Response Status Code: " + response.getStatus()); // System.out.println("Response Content Type: " + response.getContentType()); // System.out.println("Response Body: " + response.getWriter().toString()); // //写入日志到数据库 // int responseStatue = response.getStatus(); // } } // /** // * 解决前端用formData提交没有记录日志问题 ,注意MultipartFile 在方法中的参数一定要放在最后面,不然参数位置不对,会没反应 // */ // @Around("controllerMethods() && args(.., mulList)") // public Object aroundControllerMethods2(ProceedingJoinPoint joinPoint, @RequestPart List<MultipartFile> mulList) throws Throwable { // // 在这里获取到 POST 请求体中的参数 // // requestBody 就是 POST 请求体中的参数 // HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); // String data = getFormData(joinPoint, request, null); // log.info("url:{},body:{}",request.getServletPath(),data); // Date startDate = new Date(); // try { // // 执行原始方法 // Object result = joinPoint.proceed(); // // // 可以对原始方法的返回值进行拦截和修改 // // return result; // } catch (Exception e) { // // 处理异常情况 // throw e; // } finally { // HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()) // .getResponse(); // Date endDate = new Date(); // Long costTime = endDate.getTime() - startDate.getTime(); //耗时 // log.info("url:{},Response Status Code:{},Response Body:{},cost :{} ",request.getServletPath(),response.getStatus(),response.getWriter().toString(),costTime); //// // 获取并处理Response对象 //// System.out.println("Response Status Code: " + response.getStatus()); //// System.out.println("Response Content Type: " + response.getContentType()); //// System.out.println("Response Body: " + response.getWriter().toString()); //// //写入日志到数据库 //// int responseStatue = response.getStatus(); // // } // } // /** * 解决前端后端特殊类处理 */ // @Around("controllerMethods() && args(.., reqVo)") // public Object aroundControllerMethods3(ProceedingJoinPoint joinPoint, BaseFormData reqVo) throws Throwable { // // 在这里获取到 POST 请求体中的参数 // // requestBody 就是 POST 请求体中的参数 // HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); // String data=getFormData(joinPoint,request,requestBody); // Date startDate=new Date(); // try { // // 执行原始方法 // Object result = joinPoint.proceed(); // // // 可以对原始方法的返回值进行拦截和修改 // // return result; // } catch (Exception e) { // // 处理异常情况 // throw e; // } finally { // HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse() // // Date endDate=new Date(); // // 获取并处理Response对象 // System.out.println("Response Status Code: " + response.getStatus()); // System.out.println("Response Content Type: " + response.getContentType()); // System.out.println("Response Body: " + response.getWriter().toString()); // //写入日志到数据库 // int responseStatue=response.getStatus(); // Long costTime=endDate.getTime()-startDate.getTime(); //耗时 // } // } /** * * 获取POST GET的data数据 * @param request * @return大 */ public static String getFormData(ProceedingJoinPoint joinPoint, HttpServletRequest request, Object requestBody) { if ("POST".equalsIgnoreCase(request.getMethod())) { if (existFileUpload(request)) { Map<String, Object> mapData = new HashMap<>(); request.getParameterMap().entrySet().stream().forEach(entry -> { mapData.put(entry.getKey(), entry.getValue()); }); return JSONObject.toJSONString(mapData); } else { if (requestBody == null) { Object[] args = joinPoint.getArgs(); if (args != null && args.length > 0) { List<Object> newArgs = new ArrayList<>(); for (Object arg : args) { if (arg instanceof HttpServletRequest) { } else if (arg instanceof BindingResult) { } else { newArgs.add(arg); } } return JSONObject.toJSONString(newArgs); } } else if (requestBody instanceof BeanPropertyBindingResult) { return JSONObject.toJSONString(((BeanPropertyBindingResult) requestBody).getTarget()); } else if (requestBody instanceof MultipartHttpServletRequest) { Enumeration<String> parameterNames = request.getParameterNames(); Map<String, String> map = new HashMap<>(); while (parameterNames.hasMoreElements()) { String paramName = (String) parameterNames.nextElement(); String paramValue = request.getParameter(paramName); map.put(paramName, paramValue); } return JSONObject.toJSONString(map); } else if( requestBody instanceof BindingAwareModelMap){ Map<String,Object> map=(BindingAwareModelMap) requestBody; Map<String,Object> newmap=new HashMap<>(); for(Map.Entry<String,Object> mapentry : map.entrySet()){ if( mapentry.getValue() instanceof BeanPropertyBindingResult){ }else{ newmap.put(mapentry.getKey(),mapentry.getValue()); } // if(!"org.springframework.validation.BindingResult.user".equals(mapentry.getKey()) ){ // newmap.put(mapentry.getKey(),mapentry.getValue()); // } } return JSONObject.toJSONString(newmap); }else { return "{}"; //return JSONObject.toJSONString(requestBody); } } } String data = request.getParameterMap().entrySet().stream().map(entry -> { String result; String[] value = entry.getValue(); if (value != null && value.length > 1) { result = Arrays.stream(value).map(s -> entry.getKey() + "=" + s).collect(Collectors.joining("&")); } else { result = entry.getKey() + "=" + value[0]; } return result; }).collect(Collectors.joining("&")); return data; } /***是否是上传文件* @param request* @return*/ static boolean existFileUpload(HttpServletRequest request) { String contentType = request.getContentType(); if (contentType != null && (contentType.startsWith("multipart/") || contentType.contains("boundary="))) { return true; // 是上传文件的诗求 } else { return false; // 不是上传文件的请求 } } }
方法2:在spring-mvc.xml加上一个bean切面
<bean id="controllerAspect" class="com.core.controllaop.ControllerAspect"></bean> <aop:config proxy-target-class="true"> <aop:aspect id="webContronllerAspect" ref="controllerAspect"> <aop:pointcut id="printController" expression="execution(* com.test.controller.*.*(..))"/> <aop:around method="aroundControllerMethods" pointcut-ref="printController"/> </aop:aspect> </aop:config>
然后再代码里面加上
package com.core.controlleraop; import com.alibaba.fastjson.JSONObject; import lombok.extern.slf4j.Slf4j; import org.aspectj.lang.JoinPoint; 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.springframework.stereotype.Component; import org.springframework.validation.BeanPropertyBindingResult; import org.springframework.validation.BindingResult; import org.springframework.validation.support.BindingAwareModelMap; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import org.springframework.web.multipart.MultipartHttpServletRequest; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.util.*; import java.util.stream.Collectors; /** * 切面 ,记录日志 */ @Slf4j public class ControllerAspect { public void beforeMethod(JoinPoint point) { System.out.println("------test aop before"); } /** * ** 支持get POST 的提交,但不支持formData提交 */ public Object aroundControllerMethods(ProceedingJoinPoint joinPoint) throws Throwable { // // 在这里获取到 POST 请求体中的参数 // requestBody 就是 POST 请求体中的参数 HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); String reqUrl=request.getServletPath(); String data = getFormData(joinPoint, request, null); // log.warn("ControllerAspect aroundControllerMethods url:{},body:{}",reqUrl,data); Date startDate = new Date(); try { // 执行原始方法 Object result = joinPoint.proceed(); // 可以对原始方法的返回值进行拦截和修改 return result; } catch (Throwable e) { log.error("aroundControllerMethods url:{},errormsg:{},e :{}",reqUrl,e.getMessage(),e); // 处理异常情况 throw e; } finally { HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()) .getResponse(); Date endDate = new Date(); Long costTime = endDate.getTime() - startDate.getTime(); //耗时 int status= response.getStatus(); // if(response!=null&&status==HttpServletResponse.SC_OK){ // log.info("aroundControllerMethods url:{},Response Status Code:{},Response Body:{},cost :{} ",reqUrl,status,response.getWriter().toString(),costTime); // }else{ log.info("aroundControllerMethods url:{},Response Status Code:{},cost :{} ",reqUrl,status,costTime); // } // // // 获取并处理Response对象 // System.out.println("Response Status Code: " + response.getStatus()); // System.out.println("Response Content Type: " + response.getContentType()); // System.out.println("Response Body: " + response.getWriter().toString()); // //写入日志到数据库 // int responseStatue = response.getStatus(); // } } // /** // * 解决前端用formData提交没有记录日志问题 ,注意MultipartFile 在方法中的参数一定要放在最后面,不然参数位置不对,会没反应 // */ // @Around("controllerMethods() && args(.., mulList)") // public Object aroundControllerMethods2(ProceedingJoinPoint joinPoint, @RequestPart List<MultipartFile> mulList) throws Throwable { // // 在这里获取到 POST 请求体中的参数 // // requestBody 就是 POST 请求体中的参数 // HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); // String data = getFormData(joinPoint, request, null); // log.info("url:{},body:{}",request.getServletPath(),data); // Date startDate = new Date(); // try { // // 执行原始方法 // Object result = joinPoint.proceed(); // // // 可以对原始方法的返回值进行拦截和修改 // // return result; // } catch (Exception e) { // // 处理异常情况 // throw e; // } finally { // HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()) // .getResponse(); // Date endDate = new Date(); // Long costTime = endDate.getTime() - startDate.getTime(); //耗时 // log.info("url:{},Response Status Code:{},Response Body:{},cost :{} ",request.getServletPath(),response.getStatus(),response.getWriter().toString(),costTime); //// // 获取并处理Response对象 //// System.out.println("Response Status Code: " + response.getStatus()); //// System.out.println("Response Content Type: " + response.getContentType()); //// System.out.println("Response Body: " + response.getWriter().toString()); //// //写入日志到数据库 //// int responseStatue = response.getStatus(); // // } // } // /** * 解决前端后端特殊类处理 */ // @Around("controllerMethods() && args(.., reqVo)") // public Object aroundControllerMethods3(ProceedingJoinPoint joinPoint, BaseFormData reqVo) throws Throwable { // // 在这里获取到 POST 请求体中的参数 // // requestBody 就是 POST 请求体中的参数 // HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); // String data=getFormData(joinPoint,request,requestBody); // Date startDate=new Date(); // try { // // 执行原始方法 // Object result = joinPoint.proceed(); // // // 可以对原始方法的返回值进行拦截和修改 // // return result; // } catch (Exception e) { // // 处理异常情况 // throw e; // } finally { // HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse() // // Date endDate=new Date(); // // 获取并处理Response对象 // System.out.println("Response Status Code: " + response.getStatus()); // System.out.println("Response Content Type: " + response.getContentType()); // System.out.println("Response Body: " + response.getWriter().toString()); // //写入日志到数据库 // int responseStatue=response.getStatus(); // Long costTime=endDate.getTime()-startDate.getTime(); //耗时 // } // } /** * * 获取POST GET的data数据 * @param request * @return大 */ public static String getFormData(ProceedingJoinPoint joinPoint, HttpServletRequest request, Object requestBody) { if ("POST".equalsIgnoreCase(request.getMethod())) { if (existFileUpload(request)) { Map<String, Object> mapData = new HashMap<>(); request.getParameterMap().entrySet().stream().forEach(entry -> { mapData.put(entry.getKey(), entry.getValue()); }); return JSONObject.toJSONString(mapData); } else { if (requestBody == null) { Object[] args = joinPoint.getArgs(); if (args != null && args.length > 0) { List<Object> newArgs = new ArrayList<>(); for (Object arg : args) { if (arg instanceof HttpServletRequest) { } else if (arg instanceof BindingResult) { } else { newArgs.add(arg); } } return JSONObject.toJSONString(newArgs); } } else if (requestBody instanceof BeanPropertyBindingResult) { return JSONObject.toJSONString(((BeanPropertyBindingResult) requestBody).getTarget()); } else if (requestBody instanceof MultipartHttpServletRequest) { Enumeration<String> parameterNames = request.getParameterNames(); Map<String, String> map = new HashMap<>(); while (parameterNames.hasMoreElements()) { String paramName = (String) parameterNames.nextElement(); String paramValue = request.getParameter(paramName); map.put(paramName, paramValue); } return JSONObject.toJSONString(map); } else if( requestBody instanceof BindingAwareModelMap){ Map<String,Object> map=(BindingAwareModelMap) requestBody; Map<String,Object> newmap=new HashMap<>(); for(Map.Entry<String,Object> mapentry : map.entrySet()){ if( mapentry.getValue() instanceof BeanPropertyBindingResult){ }else{ newmap.put(mapentry.getKey(),mapentry.getValue()); } // if(!"org.springframework.validation.BindingResult.user".equals(mapentry.getKey()) ){ // newmap.put(mapentry.getKey(),mapentry.getValue()); // } } return JSONObject.toJSONString(newmap); }else { return "{}"; //return JSONObject.toJSONString(requestBody); } } } String data = request.getParameterMap().entrySet().stream().map(entry -> { String result; String[] value = entry.getValue(); if (value != null && value.length > 1) { result = Arrays.stream(value).map(s -> entry.getKey() + "=" + s).collect(Collectors.joining("&")); } else { result = entry.getKey() + "=" + value[0]; } return result; }).collect(Collectors.joining("&")); return data; } /***是否是上传文件* @param request* @return*/ static boolean existFileUpload(HttpServletRequest request) { String contentType = request.getContentType(); if (contentType != null && (contentType.startsWith("multipart/") || contentType.contains("boundary="))) { return true; // 是上传文件的诗求 } else { return false; // 不是上传文件的请求 } } }
感谢 springAop不能切入controller层的解决方法 给的想法