1. 程式人生 > >使用ProceedingJoinPoint獲取當前請求的方法等引數——spring mvc攔截器

使用ProceedingJoinPoint獲取當前請求的方法等引數——spring mvc攔截器

在專案中常常需要顧慮請求引數中的特殊字元,比如+,<,>等

解決方案是可以使用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;
	    }
}