這篇文章主要介紹springMVC如何自定義注解并使用AOP來實現日志記錄,文中介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們一定要看完!
需求背景
最近的一個項目,在項目基本完工的階段,客戶提出要將所有業務操作的日志記錄到數據庫中,并且要提取一些業務的關鍵信息(比如交易單號)體現在日志中。
為了保證工期,在查閱了資料以后,決定用AOP+自定義注解的方式來完成這個需求。
準備工作
自定義注解需要依賴的jar包有 aspectjrt-XXX.jar ,aspectjweaver-XXX.jar,XXX代表版本號。
自定義注解
在項目下單獨建立了一個log包,來存放日志相關的內容
**.common.log.annotation //自定義注解存放位置 **.common.log.aop //aop工具類存放位置
在annotation包下面新建自定義注解類:
package **.common.log.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
public @interface XXXOperateLog {
/**
* 操作類型描述
* @return
*/
String operateTypeDesc() default "";
/**
* 操作類型
* @return
*/
long operateType() default -1;
/**
* 模塊編碼
* @return
*/
String moudleCode() default "M30";
/**
* 模塊名稱
* @return
*/
String moudleName() default "XX模塊";
/**
* 業務類型
* @return
*/
String bussType() default "";
/**
* 業務類型描述
* @return
*/
String bussTypeDesc() default "";
}在aop包下新建XXXOperateLogAop
package **.common.log.aop;
import ** ;//省略
@Aspect
@Component
public class XXXOperateLogAop{
@Autowired
SystemLogService systemLogService;
HttpServletRequest request = null;
Logger logger = LoggerFactory.getLogger(XXXOperateLogAop.class);
ThreadLocal<Long> time = new ThreadLocal<Long>();
//用于生成操作日志的唯一標識,用于業務流程審計日志調用
public static ThreadLocal<String> tag = new ThreadLocal<String>();
//聲明AOP切入點,凡是使用了XXXOperateLog的方法均被攔截
@Pointcut("@annotation(**.common.log.annotation.XXXOperateLog)")
public void log() {
System.out.println("我是一個切入點");
}
/**
* 在所有標注@Log的地方切入
* @param joinPoint
*/
@Before("log()")
public void beforeExec(JoinPoint joinPoint) {
time.set(System.currentTimeMillis());
info(joinPoint);
//設置日志記錄的唯一標識號
tag.set(UUID.randomUUID().toString());
request= ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
}
@After("log()")
public void afterExec(JoinPoint joinPoint) {
MethodSignature ms = (MethodSignature) joinPoint.getSignature();
Method method = ms.getMethod();
logger.debug("標記為" + tag.get() + "的方法" + method.getName()
+ "運行消耗" + (System.currentTimeMillis() - time.get()) + "ms");
}
//在執行目標方法的過程中,會執行這個方法,可以在這里實現日志的記錄
@Around("log()")
public Object aroundExec(ProceedingJoinPoint pjp) throws Throwable {
Object ret = pjp.proceed();
try {
Object[] orgs = pjp.getArgs();
SystemLog valueReturn = null;
for (int i = 0; i < orgs.length; i++) {
if(orgs[i] instanceof SystemLog){
valueReturn = (SystemLog) orgs[i];
}
}
if(valueReturn==null){
valueReturn = new SystemLog();
}
if(valueReturn!=null&&request!=null){
MethodSignature ms = (MethodSignature) pjp.getSignature();
Method method = ms.getMethod();
//獲取注解的操作日志信息
XXXOperateLog log = method.getAnnotation(XXXOperateLog.class);
String businessType = log.bussType();
String businessDesc = log.bussTypeDesc();
HashMap requestMap = ServletUtils.getParametersToHashMap(request) ;
//從參數中尋找業務類型
if(businessType.equals(""))
{
Object objBusinessType = requestMap.get("business_type");
businessType = objBusinessType == null ? "" : objBusinessType.toString();
}
//從執行結果的申請單中找業務類型
Object apply = request.getAttribute("apply") ;
if(apply != null){
JSONObject obj = JSONFactory.toJSONAbstractEntity(apply);
if(obj != null)
{
valueReturn.setOtherDesc("申請單號:"+obj.getString("apply_no"));
if(businessType.equals(""))
{
businessType = obj.getString("business_type");
}
}
}
//從方法的執行過程參數中找業務類型(一般是手動設置)
if(businessType.equals(""))
{
businessType = (String) request.getAttribute("business_type");
businessType = businessType == null ? "" : businessType;
}
if(!businessType.equals("") && businessDesc.equals(""))
{
businessDesc = XXXSysConstant.BUSINESS_TYPE.getName(businessType);
}
valueReturn.setBussType(XXXSysConstant.BUSINESS_TYPE.getNumber(businessType));
valueReturn.setBussTypeDesc(businessDesc);
valueReturn.setMoudleCode(log.moudleCode());
valueReturn.setMoudleName(log.moudleName());
valueReturn.setOperateResult(XXXSysConstant.YesOrNo.YES);
valueReturn.setOperateType(log.operateType());
valueReturn.setInputUserId(((UserContext)WebUtils.getSessionAttribute(request, "XXXuserContext")).getSysUser().getId());
valueReturn.setOperateTypeDesc(log.operateTypeDesc());
valueReturn.setRequestIp(getRemoteHost(request));
valueReturn.setRequestUrl(request.getRequestURI());
valueReturn.setServerIp(request.getLocalAddr());
valueReturn.setUids(tag.get());
//保存操作日志
systemLogService.saveSystemLog(valueReturn);
}else{
logger.info("不記錄日志信息");
}
//保存操作結果
} catch (Exception e) {
e.printStackTrace();
}
return ret;
}
//記錄異常日志
@AfterThrowing(pointcut = "log()",throwing="e")
public void doAfterThrowing(JoinPoint joinPoint, Throwable e) {
try {
info(joinPoint);
Object[] orgs = joinPoint.getArgs();
SystemLog valueReturn = null;
for (int i = 0; i < orgs.length; i++) {
if(orgs[i] instanceof SystemLog){
valueReturn = (SystemLog) orgs[i];
}
}
if(valueReturn==null){
valueReturn = new SystemLog();
}
if(valueReturn!=null&&request!=null){
MethodSignature ms = (MethodSignature) joinPoint.getSignature();
Method method = ms.getMethod();
XXXOperateLog log = method.getAnnotation(XXXOperateLog.class);
String businessType = log.bussType();
String businessDesc = log.bussTypeDesc();
if(businessType.equals(""))
{
Object objBusinessType = ServletUtils.getParametersToHashMap(request).get("business_type");
businessType = objBusinessType == null ? "" : objBusinessType.toString();
businessDesc = XXXSysConstant.BUSINESS_TYPE.getName(businessType);
}
valueReturn.setBussType(XXXSysConstant.BUSINESS_TYPE.getNumber(businessType));
valueReturn.setBussTypeDesc(businessDesc);
valueReturn.setMoudleCode(log.moudleCode());
valueReturn.setMoudleName(log.moudleName());
valueReturn.setOperateType(log.operateType());
valueReturn.setOperateTypeDesc(log.operateTypeDesc());
valueReturn.setInputUserId(((UserContext)WebUtils.getSessionAttribute(request, "XXXuserContext")).getSysUser().getId());
valueReturn.setOperateResult(XXXSysConstant.YesOrNo.NO);
String errMes = e.getMessage();
if(errMes!=null && errMes.length()>800){
errMes = errMes.substring(0, 800);
}
valueReturn.setErrorMessage(errMes);
valueReturn.setRequestIp(getRemoteHost(request));
valueReturn.setRequestUrl(request.getRequestURI());
valueReturn.setServerIp(request.getLocalAddr());
valueReturn.setUids(tag.get());
systemLogService.saveSystemLog(valueReturn);
}else{
logger.info("不記錄日志信息");
}
} catch (Exception e1) {
e1.printStackTrace();
}
}
private void info(JoinPoint joinPoint) {
logger.debug("--------------------------------------------------");
logger.debug("King:\t" + joinPoint.getKind());
logger.debug("Target:\t" + joinPoint.getTarget().toString());
Object[] os = joinPoint.getArgs();
logger.debug("Args:");
for (int i = 0; i < os.length; i++) {
logger.debug("\t==>參數[" + i + "]:\t" + os[i].toString());
}
logger.debug("Signature:\t" + joinPoint.getSignature());
logger.debug("SourceLocation:\t" + joinPoint.getSourceLocation());
logger.debug("StaticPart:\t" + joinPoint.getStaticPart());
logger.debug("--------------------------------------------------");
}
/**
* 獲取遠程客戶端Ip
* @param request
* @return
*/
private String getRemoteHost(javax.servlet.http.HttpServletRequest request){
String ip = request.getHeader("x-forwarded-for");
if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)){
ip = request.getHeader("Proxy-Client-IP");
}
if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)){
ip = request.getHeader("WL-Proxy-Client-IP");
}
if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)){
ip = request.getRemoteAddr();
}
return ip.equals("0:0:0:0:0:0:0:1")?"127.0.0.1":ip;
}
}修改配置文件spring-mvc.xml,添加如下配置
<!-- 開啟AOP攔截 --> <aop:aspectj-autoproxy proxy-target-class="true" /> <mvc:annotation-driven /> <!-- 定義Spring描述Bean的范圍 --> <context:component-scan base-package="**.common.log" > <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/> </context:component-scan>
需要注意的是,上述配置必須放在同一個xml文件里面,要么spring-mvc.xml,要么spring-context.xml,否則可能不生效,暫時還未查明是為什么。
注解的使用
@XXXOperateLog(
bussType=XXXSysConstant.BUSINESS_TYPE.YYYY
,bussTypeDesc="業務類型描述"
,operateType = XXXSysConstant.LogOperateType.QUERY
,operateTypeDesc = "操作描述"
)
@RequestMapping(value = "/**/**/queryXXXXX4DataGrid.json", method = RequestMethod.POST)
public void queryXXXXX4DataGrid(HttpServletRequest request, HttpServletResponse arg1, Model model, Writer writer)
{
logger.info("==========驗票查詢(出庫)交易信息 開始=====================");
try {
//do something for business
} catch (SystemException se) {
throw se;
} catch (BusinessException be) {
throw be;
} catch (Exception e) {
throw new SystemException(e);
}
}以上是“springMVC如何自定義注解并使用AOP來實現日志記錄”這篇文章的所有內容,感謝各位的閱讀!希望分享的內容對大家有幫助,更多相關知識,歡迎關注億速云行業資訊頻道!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。