使用ProceedingJoinPoint獲取當前請求的方法等引數——spring mvc攔截器
阿新 • • 發佈:2019-02-10
在專案中常常需要顧慮請求引數中的特殊字元,比如+,<,>等
解決方案是可以使用spring mvc 的攔截器,配合aspectJ使用
package com.cpic.core.web; import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.math.BigDecimal; import java.util.Date; import java.util.Enumeration; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import javax.servlet.http.HttpServletRequest; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.reflect.MethodSignature; import org.jfree.util.Log; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.servlet.ModelAndView; import com.cpic.caf.compon.business.common.entity.CodeEntryEO; import com.cpic.caf.compon.tech.utils.JsonUtils; import com.cpic.caf.compon.tech.utils.StringUtils; import com.cpic.caf.pub.app.context.SpringAppContextUtil; import com.cpic.caf.pub.security.context.SecurityContext; import com.cpic.core.cache.DataCacheManager; import com.cpic.core.filter.FilterUtils; import com.cpic.core.httpHandler.entity.Response; import com.cpic.cxyb.entity.LogManager; import com.cpic.cxyb.entity.RybAuditLog; import com.cpic.cxyb.service.LogManagerService; import com.cpic.cxyb.service.RybAuditLogService; import com.cpic.cxyb.threads.RybAuditLogSyncToDBThread; import com.cpic.framework.entity.ResponseContent; import com.cpic.xybx.security.MyUserInfoImpl; import com.cpic.xybx.tools.CpicmIPUtil; public class FilterTextSpecialString { public static final Logger logger = LoggerFactory.getLogger ( FilterTextSpecialString.class ); DataCacheManager dataCacheManager; LogManagerService logManagerService; @Autowired RybAuditLogService rybAuditLogService; public static final String[] APP_METHOD = {"innerServerController.submit,innerServerController.submitContent"}; public static final String RETURN_TYPE_AJAX = "ResponseContent"; public static final String RETURN_TYPE_MV = "ModelAndView"; public static final String RETURN_TYPE_MAP = "Map"; public static final String RETURN_TYPE_VOID = "void"; public static final String RETURN_TYPE_STRING = "String"; //特殊字元的判斷 public Object doAround(ProceedingJoinPoint pjp) throws Throwable { this.dataCacheManager = (DataCacheManager)SpringAppContextUtil.getBean("dataCacheManager"); this.logManagerService = (LogManagerService)SpringAppContextUtil.getBean("logManagerService"); //從資料庫獲取文字框特殊字元過濾資訊 CodeEntryEO codeEntry = null; String speCharactor = ""; String method = pjp.getTarget().getClass().getName() + "." + pjp.getSignature().getName(); //獲取對映方法 try{ String returnType = pjp.getSignature().toString().split(" ")[0]; if(StringUtils.isNotBlank(returnType) && RETURN_TYPE_MV.equals(returnType)){ Method targetMethod = ((MethodSignature)(pjp.getSignature())).getMethod(); Class<?> classtest = targetMethod.getDeclaringClass(); String classAnnotationValue = ""; String methodAnnotationValue = ""; Annotation[] classAnnotation = classtest.getAnnotations(); for (int i = 0; i < classAnnotation.length; i++) { if(classAnnotation[i] instanceof RequestMapping){ RequestMapping requestmap = (RequestMapping) classAnnotation[i]; if(requestmap.value()[0] != null){ classAnnotationValue = (requestmap.value())[0]; } break; } } if(StringUtils.isNotBlank(classAnnotationValue)){ Annotation[] methodAnnotation = targetMethod.getAnnotations(); for (int i = 0; i < methodAnnotation.length; i++) { if(methodAnnotation[i] instanceof RequestMapping){ RequestMapping requestmap = (RequestMapping) methodAnnotation[i]; if(requestmap.value()[0] != null){ methodAnnotationValue = (requestmap.value())[0]; } break; } } String catalog = classAnnotationValue+"/"+methodAnnotationValue; //增加審計日誌 if(RybAuditLogSyncToDBThread.menuMap.get(catalog) != null){ MyUserInfoImpl user = (MyUserInfoImpl) SecurityContext.getCurrentUser(); //UserDefault user = (UserDefault)servletRequest.getAttribute("user"); RybAuditLog auditLog = new RybAuditLog(); auditLog.setDatetime(new Date()); auditLog.setInterfacecode(catalog); auditLog.setKind("web"); String requestName = (String) RybAuditLogSyncToDBThread.menuMap.get(catalog); if(StringUtils.isNotBlank(requestName))auditLog.setInterfacename(requestName); if(user != null){ String usertype = user.getUserType(); auditLog.setUnitcode(user.getOrgCode()); auditLog.setUsercode(user.getUserCode()); auditLog.setUsername(user.getUsername()); auditLog.setUsertype(usertype); auditLog.setOrgid(user.getOrgId()); if(StringUtils.isNotBlank(usertype) && "CPICUser".equals(user.getUserType())){ auditLog.setUnitname((String)(RybAuditLogSyncToDBThread.orgMap).get(user.getOrgCode())); }else{ auditLog.setUnitname((String)(RybAuditLogSyncToDBThread.outsideOrgMap).get(user.getOrgCode())); } } this.rybAuditLogService.log(auditLog); } } } }catch(Exception e){ Log.error("記錄審計日誌出錯"+e.getMessage()); } boolean appFlag = false; //判斷是否是app for(int i = 0 ; i < APP_METHOD.length ; i++){ if(method.indexOf(APP_METHOD[i]) >= 0){ appFlag = true; break; } } //文字過濾器不過濾類和方法,配置在資料庫中為:類名.方法名,類名.方法名 CodeEntryEO codeEntryEO = dataCacheManager.getCodeEntryCacheByName("FilterConfig","TextSpecialCharactersException"); String exception = ""; if(codeEntryEO != null){ exception = codeEntryEO.getName(); } String[] exceptions = exception.split(","); boolean exec = true; for(int i = 0 ; i < exceptions.length ; i ++){ if(method.indexOf(exceptions[i]) >= 0){ exec = false; break; } } boolean flag = false;//預設為假,有可能該Ctrl為例外或者沒有引數則不作校驗 if(exec){ if(appFlag ){ codeEntry = dataCacheManager.getCodeEntryCacheByName("FilterConfig","appTextSpecialCharacters"); }else{ codeEntry = dataCacheManager.getCodeEntryCacheByName("FilterConfig","TextSpecialCharacters"); } if (codeEntry != null){ speCharactor = codeEntry.getName(); } String[] list = {}; //如果過濾規則為空,則不過濾 if(StringUtils.isNotEmpty(speCharactor)){ //特殊字串陣列 list = speCharactor.split(","); } if(list.length > 0 && pjp.getArgs() != null && pjp.getArgs().length > 0){ for (int i = 0; i < pjp.getArgs().length; i++) { if(pjp.getArgs()[i] instanceof LinkedHashMap){ Map<String,Object> map = (Map<String,Object>)pjp.getArgs()[i]; flag = typeJudge(map,list,method); }else if(pjp.getArgs()[i] instanceof HttpServletRequest){ HttpServletRequest req = ((HttpServletRequest)pjp.getArgs()[i]); Enumeration enu = req.getParameterNames(); while(enu.hasMoreElements()){ String paraName=(String)enu.nextElement(); if(req.getParameter(paraName) != null){ flag = FilterUtils.checkTextStringValue(req.getParameter(paraName).toUpperCase(),list); } //包含特殊字元退出迴圈 if(flag){ logger.info(method + "引數名為:"+paraName+" 的值為:"+req.getParameter(paraName)+" 中包含特殊字元。"); break; } } }else if(pjp.getArgs()[i] instanceof String){ flag = FilterUtils.checkTextStringValue(pjp.getArgs()[i].toString().toUpperCase(),list); } //包含特殊字元退出迴圈,不校驗下一個引數 if(flag){ break; } } } } //沒有特殊字元校驗通過,呼叫ctrl方法執行業務 Object retVal = null; if(!flag){ try{ retVal = pjp.proceed(); }catch(Exception e){ StackTraceElement stackTraceElement= e.getStackTrace()[e.getStackTrace().length-1]; stackTraceElement.getLineNumber(); logger.error ( "\n=========執行{}方法的{}行異常資訊為:=========={}",method,stackTraceElement.getLineNumber(),e.fillInStackTrace ( ).toString ( ) ); //記錄錯誤日誌到資料庫 LogManager logManager = new LogManager(); logManager.setErrormsg("執行" + method + "方法的" + stackTraceElement.getLineNumber() + "行發生錯誤:" + e.fillInStackTrace ( ).toString ( )); logManager.setIp(CpicmIPUtil.getServerIp()); logManager.setCreattime(new Date()); String requestStr = getRequestStr(pjp); logManager.setRequestmsg(requestStr); logManager.setResponsemsg("系統異常:請聯絡系統管理員"); this.logManagerService.log(logManager); //針對異常的處理 if(appFlag ){ Response response = new Response(); response.setStatus(Response.STATUS_ERROR); response.setErrorCode(Response.ERROR_CODE_SYSTEM); response.setErrorMessage("系統異常:請聯絡系統管理員"); retVal = response; }else{ String returnType = pjp.getSignature().toString().split(" ")[0]; if(RETURN_TYPE_AJAX.equals(returnType)){ ResponseContent responseContent = new ResponseContent(); responseContent.setResultState(false); responseContent.setErrorCode("-88888"); responseContent.setMsg("系統異常:請聯絡系統管理員"); retVal = responseContent; }else if(RETURN_TYPE_MV.equals(returnType)){ //返回管理後臺錯誤頁面 ModelAndView mv = new ModelAndView("systemError"); mv.addObject("msg", "系統異常:請聯絡系統管理員"); retVal = mv; }else if(RETURN_TYPE_STRING.equals(returnType)){ //返回管理後臺錯誤頁面 retVal = "systemError"; }else if(returnType.indexOf(RETURN_TYPE_MAP) >= 0){ Map responseContent = new HashMap(); responseContent.put("resultState",false); responseContent.put("errorCode","-88888"); responseContent.put("msg","系統異常:請聯絡系統管理員"); retVal = responseContent; }else if(returnType.indexOf(RETURN_TYPE_VOID) >= 0){ //void目前不作處理,如果掃描出問題,則在進行處理,把HttpServletResponse獲得到,直接向頁面輸出以下字串 // Map responseContent = new HashMap(); // responseContent.put("resultState",false); // responseContent.put("errorCode","-88888"); // responseContent.put("msg","系統異常:請聯絡系統管理員"); // retVal = responseContent; } } } }else{//包含特殊字元 LogManager logManager = new LogManager(); logManager.setErrormsg("請求異常:請求引數不合法或請求引數被篡改"); logManager.setIp(CpicmIPUtil.getServerIp()); logManager.setCreattime(new Date()); String requestStr = getRequestStr(pjp); logManager.setRequestmsg(requestStr); logManager.setResponsemsg("請求異常:請求引數不合法或請求引數被篡改"); this.logManagerService.log(logManager); if(appFlag ){ Response response = new Response(); response.setStatus(Response.STATUS_ERROR); response.setErrorCode(Response.ERROR_CODE_SPECIAL_TEXT); response.setErrorMessage("請求異常:請求引數不合法或請求引數被篡改"); retVal = response; }else{ String returnType = pjp.getSignature().toString().split(" ")[0]; if(returnType.indexOf(RETURN_TYPE_AJAX) >= 0){ ResponseContent responseContent = new ResponseContent(); responseContent.setResultState(false); responseContent.setErrorCode("-88888"); responseContent.setMsg("請求異常:請求引數不合法或請求引數被篡改"); retVal = responseContent; }else if(returnType.indexOf(RETURN_TYPE_MV) >= 0){ //返回管理後臺錯誤頁面 ModelAndView mv = new ModelAndView("permissionError"); mv.addObject("msg", "請求異常:請求引數不合法或請求引數被篡改"); retVal = mv; }else if(RETURN_TYPE_STRING.equals(returnType)){ //返回管理後臺錯誤頁面 retVal = "permissionError"; }else if(returnType.indexOf(RETURN_TYPE_MAP) >= 0){ Map responseContent = new HashMap(); responseContent.put("resultState",false); responseContent.put("errorCode","-88888"); responseContent.put("msg","請求異常:請求引數不合法或請求引數被篡改"); retVal = responseContent; }else if(returnType.indexOf(RETURN_TYPE_VOID) >= 0){ //void目前不作處理,如果掃描出問題,則在進行處理,把HttpServletResponse獲得到,直接向頁面輸出以下字串 // Map responseContent = new HashMap(); // responseContent.put("resultState",false); // responseContent.put("errorCode","-88888"); // responseContent.put("msg","請求異常:請求引數不合法或請求引數被篡改"); // retVal = responseContent; } } } return retVal; } public static boolean checkTextStringValue(String str,String[] list){ boolean flag = true; if(str!=null&&!"".equals(str)){ for(int i=0;i<list.length;i++){ if(str.indexOf(list[i])>-1){ flag = false; break; } } } return flag; } /** * 型別判斷 * @param map * @return */ public boolean typeJudge(Map<String, Object> map,String[] list,String method) { boolean flag = false; for (String key : map.keySet()) { try{ if(map.get(key) instanceof Integer){ continue; }else if(map.get(key) instanceof Long){ continue; }else if(map.get(key) instanceof String){ flag = FilterUtils.checkTextStringValue(map.get(key).toString().toUpperCase(),list); if(flag){ logger.info(method + "|引數名為:"+key+" 的值為:"+map.get(key).toString()+" 中包含特殊字元。"); break; } }else if(map.get(key) instanceof Date){ continue; }else if(map.get(key) instanceof BigDecimal){ continue; }else if(map.get(key) instanceof List){//型別為list continue; }else if(map.get(key) instanceof Map){//型別為map try{ if(map.get(key) != null && !"".equals ( map.get(key) )){ flag = typeJudge((Map<String,Object>)map.get(key),list,method); if(flag){ logger.info(method + "|引數名為:"+key+" 的值為:"+map.get(key).toString()+" 中包含特殊字元。"); break; } } }catch (Exception e) { logger.error ( "\n=========異常資訊為:==========\n{}",e.fillInStackTrace ( ).toString ( ) ); } } }catch(Exception e){ logger.error ( "\n=========異常資訊為:==========\n{}",e.fillInStackTrace ( ).toString ( ) ); } } return flag; } private String getRequestStr(ProceedingJoinPoint pjp){ String requestStr = ""; if(pjp.getArgs() != null && pjp.getArgs().length > 0){ for (int i = 0; i < pjp.getArgs().length; i++) { if(pjp.getArgs()[i] instanceof LinkedHashMap){ Map<String,Object> map = (Map<String,Object>)pjp.getArgs()[i]; requestStr += "Map引數值為:" + JsonUtils.objToJson(map) + "|"; }else if(pjp.getArgs()[i] instanceof HttpServletRequest){ HttpServletRequest req = ((HttpServletRequest)pjp.getArgs()[i]); Enumeration enu = req.getParameterNames(); requestStr += "HttpServletRequest引數值為:" + JsonUtils.objToJson(enu) + "|"; }else if(pjp.getArgs()[i] instanceof String){ requestStr += "HttpServletRequest引數值為:" + pjp.getArgs()[i].toString() + "|"; } } } return requestStr; } }