AOP日志组件 多次获取post参数

来源:互联网 发布:淘宝店铺怎么增加分类 编辑:程序博客网 时间:2024/06/06 03:28

AOP日志组件 多次获取post参数

  • 需求:新增接口日志组件。通过拦截器对接口URL进行拦截处理,然后将接口post请求的参数与结果,写入日志表。
  • 问题:POST方法的参数是存储在request.getInputStream中,只能读一次,不能多次读取。从中读取post请求参数,只能读取一次。在filter中获取之后,controller无法获取post请求参数。
  • 解决办法:继承HttpServletRequest,先获取到请求参数,再加参数重新set到inputStream。

1.拦截器记录日志

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {        HttpServletRequest httpRequest = (HttpServletRequest)request;        String requestPath  = httpRequest.getServletPath().split("\\?")[0];        if(request  == null){            chain.doFilter(request, response);            return ;        }         for (String noFilter : NO_FILETER_LIST) {             if(requestPath.toLowerCase().contains(noFilter)){                 chain.doFilter(request, response);                 return ;             }         }         Pattern pattern = Pattern.compile(".*[api|interface].*");         Matcher matcher = pattern.matcher(requestPath);         if(matcher.matches()){             LoggerManager loggerManager = SpringLoadListener.getBean("loggerManager",LoggerManager.class);             //扩展request,防止字符注入等             XssSqlHttpServletRequestWrapper xssRequest = new XssSqlHttpServletRequestWrapper((HttpServletRequest)request);             ResponseWrapper wrapResponse = new ResponseWrapper((HttpServletResponse)response);             //继续请求处理类             chain.doFilter(xssRequest, wrapResponse);             //获取URL的参数 get请求             Map<Object, Object> urlParam = xssRequest.getParameterMap();             //获取post参数             String param = xssRequest.getRequestParams();             JSONObject jObject = JSONObject.fromObject(urlParam);             jObject.put("postParam", param.toString());             String params = jObject.toString();             //获取接口处理类返回结果             byte[] data = wrapResponse.getResponseData();              String result = new String(data,"UTF-8");              //保存日志              loggerManager.operateInterfaceLogger("", params, requestPath, result);              ServletOutputStream out = response.getOutputStream();              out.write(data);              out.flush();         }else{             chain.doFilter(request, response);         }    }

2.处理request请求,先获取inputStream,将请求参数复制给其他方法,同时再将获取的inputStream赋值回request中。

public class XssSqlHttpServletRequestWrapper extends HttpServletRequestWrapper {         HttpServletRequest orgRequest = null;         private byte[] bytes;         private WrappedServletInputStream  wrappedServletInputStream;   public XssSqlHttpServletRequestWrapper(HttpServletRequest request) throws IOException {           super(request);           this.orgRequest = request;           //读取输入流的请求参数,保存到bytes中           bytes = IOUtils.toByteArray(request.getInputStream());           ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);           this.wrappedServletInputStream = new WrappedServletInputStream(byteArrayInputStream);           //把post参数重新写入请求流           reWriteInputStream();   }   /**    * 把参数重新写进请求里    */    public void reWriteInputStream() {       wrappedServletInputStream.setStream(new ByteArrayInputStream(bytes != null ? bytes : new byte[0]));   }    @Override    public ServletInputStream getInputStream() throws IOException {        return wrappedServletInputStream;    }    @Override    public BufferedReader getReader() throws IOException {        return new BufferedReader(new InputStreamReader(wrappedServletInputStream));    }    /**     * 获取post参数     */    public String getRequestParams() throws IOException {        return new String(bytes, this.getCharacterEncoding());    }   //清洗参数,防止xss注入   public String[] getParameterValues(String parameter)   {           String[] values = super.getParameterValues(parameter);           if (values == null) {             return null;     }           int count = values.length;           String[] encodedValues = new String[count];           for (int i = 0; i < count; i++) {             encodedValues[i] = xssEncode(values[i]);     }           return encodedValues;   }   public String getParameter(String name)   {           String value = super.getParameter(xssEncode(name));           if (value != null) {             value = xssEncode(value);     }           return value;   }   public String getHeader(String name)   {           String value = super.getHeader(xssEncode(name));           if (value != null) {             value = xssEncode(value);     }           return value;   }   private static String xssEncode(String s)   {           return StringUtil.xssEncode(s);   }   public HttpServletRequest getOrgRequest()   {           return this.orgRequest;   }   public static HttpServletRequest getOrgRequest(HttpServletRequest req)   {           if ((req instanceof XssSqlHttpServletRequestWrapper)) {             return ((XssSqlHttpServletRequestWrapper)req).getOrgRequest();     }         return req;   }   private class WrappedServletInputStream extends ServletInputStream {       public void setStream(InputStream stream) {           this.stream = stream;       }       private InputStream stream;       public WrappedServletInputStream(InputStream stream) {           this.stream = stream;       }       public int read() throws IOException {           return stream.read();       }       public boolean isFinished() {           return true;       }       public boolean isReady() {           return true;       }       public void setReadListener(ReadListener readListener) {       }   } }

3.Manager保存日志记录。对LoggerAnnotation自定义注解,实现AOP日志保存。

@LoggerAnnotation(type="INTERFACE", name="#name", params="#params", desc="#pageLink")public String operateInterfaceLogger(String name, String params, String pageLink, String result){    return result;} @Component @Aspect @Async public class LoggerOperationAop {   private static final Logger logger = LoggerFactory.getLogger(LoggerOperationAop.class);   @Autowired   private LoggerManager loggerManager;   @Autowired   private UserManager userManager;   @Autowired   private JdbcTemplateImpl jdbcTemplate;   public LoggerOperationAop() {}   @Pointcut("@annotation(LoggerAnnotation)")   private void serviceAspect(LoggerAnnotation LoggerAnnotation) {}   @Around("serviceAspect(LoggerAnnotation)")   public Object process(ProceedingJoinPoint point, LoggerAnnotation LoggerAnnotation)     throws Throwable   {     String targetName = point.getTarget().getClass().getName();     String methodName = point.getSignature().getName();     Object[] arguments = point.getArgs();     String operationType = LoggerAnnotation.type();     String message = LoggerAnnotation.desc();     String params = LoggerAnnotation.params();     String name = LoggerAnnotation.name();     String id = LoggerAnnotation.id();     String[] paramNames = ReflectParamNames.getNames(targetName, methodName);     if ((StringUtil.isNotBlank(name)) && (name.startsWith("#"))) {       String value = SpelParser.getKey(name, "", paramNames, arguments);       if (StringUtil.isNotBlank(value)) {         targetName = value;       }     }     String methodParams = "";     if ((StringUtil.isNotBlank(params)) && (params.startsWith("#"))) {       methodParams = SpelParser.getKey(params, "", paramNames, arguments);     }     if ((StringUtil.isNotBlank(message)) && (message.startsWith("#"))) {       String value = SpelParser.getKey(message, "", paramNames, arguments);       if (StringUtil.isNotBlank(value)) {         message = value;       }     }     String userId = null;     String userName = "游客";     try {         Subject currentSubject = SecurityUtils.getSubject();         if (currentSubject != null) {           Object tmpObj = currentSubject.getSession().getAttribute("authorizeUser");           if ((tmpObj != null) && ("INTERFACE".equals(operationType))) {             userName = StringUtil.parseAny2String(tmpObj);           } else if (currentSubject.getPrincipal() != null) {             ShiroDbRealm.ShiroUser shiroUser = (ShiroDbRealm.ShiroUser)currentSubject.getPrincipal();             userId = shiroUser.getUserId();             userName = shiroUser.getLoginName();           }         }       } catch (Exception e) {         logger.info("不支持shiro技术框架");         logger.error("异常信息:{}", e.getMessage());       }     Object target = point.proceed();     try     {       String extName = DateUtil.getYearMonth(new Date());       String sql = " INSERT INTO T_E4S_DB_LOG_MESSAGE_" + extName +          " (USER_ID,USER_NAME,CLASS_NAME,METHOD_NAME,METHOD_PARAMS,LOG_DATE,LOG_MESSAGE,OPERATION_TYPE,REMARK) " +          " VALUES(?,?,?,?,?,?,?,?,?) ";       Object[] object = { userId, userName, targetName, methodName, methodParams,          new Date(), message, operationType, target };       this.jdbcTemplate.beginTranstaion();       this.jdbcTemplate.update(sql, object);       this.jdbcTemplate.commit();     }     catch (Exception ex) {       logger.error("==异常通知异常==");       logger.error("异常信息:{}", ex.getMessage());       this.jdbcTemplate.rollback();     }     return target;   } }

LoggerFilter里一个实现了XssSqlHttpServletRequestWrapper类,其构造器自动读取了servletRequest里的输入流,并把数据保存了下来,最后又把数据重新写入servletRequest里,在filter中可以读取post请求参数,cotroller也可以再次从request里读取到post请求参数。

原创粉丝点击