4 changed files with 317 additions and 40 deletions
@ -1,40 +1,166 @@ |
|||||
//package com.epmet.jmreport.aop;
|
package com.epmet.jmreport.aop; |
||||
//
|
|
||||
//import com.epmet.commons.tools.aspect.BaseRequestLogAspect;
|
import com.alibaba.fastjson.JSON; |
||||
//import org.aspectj.lang.ProceedingJoinPoint;
|
import com.epmet.jmreport.constants.JmReportConstants; |
||||
//import org.aspectj.lang.annotation.Around;
|
import com.epmet.jmreport.constants.ThreadLocalConstant; |
||||
//import org.aspectj.lang.annotation.Aspect;
|
import com.epmet.jmreport.utils.ExceptionUtils; |
||||
//import org.springframework.core.annotation.Order;
|
import lombok.extern.slf4j.Slf4j; |
||||
//import org.springframework.stereotype.Component;
|
import org.aspectj.lang.ProceedingJoinPoint; |
||||
//import org.springframework.web.context.request.RequestAttributes;
|
import org.aspectj.lang.annotation.Around; |
||||
//import org.springframework.web.context.request.RequestContextHolder;
|
import org.aspectj.lang.annotation.Aspect; |
||||
//import org.springframework.web.context.request.ServletRequestAttributes;
|
import org.jeecg.modules.jmreport.common.vo.Result; |
||||
//
|
import org.slf4j.MDC; |
||||
//import javax.servlet.http.HttpServletRequest;
|
import org.springframework.core.annotation.Order; |
||||
//
|
import org.springframework.stereotype.Component; |
||||
///**
|
import org.springframework.web.context.request.RequestAttributes; |
||||
// * 日志/异常处理切面实现,调用父类方法完成日志记录和异常处理。
|
import org.springframework.web.context.request.RequestContextHolder; |
||||
// */
|
import org.springframework.web.context.request.ServletRequestAttributes; |
||||
//@Aspect
|
import org.springframework.web.multipart.MultipartFile; |
||||
//@Component
|
|
||||
//@Order(0)
|
import javax.servlet.ServletRequest; |
||||
//public class RequestLogAspect {
|
import javax.servlet.ServletResponse; |
||||
//
|
import javax.servlet.http.HttpServletRequest; |
||||
// @Override
|
import java.time.Duration; |
||||
// @Around(value = "execution(* com...*Controller*.*(..)) ")
|
import java.time.LocalDateTime; |
||||
// public Object proceed(ProceedingJoinPoint point) throws Throwable {
|
import java.util.Arrays; |
||||
// return super.proceed(point, getRequest());
|
import java.util.Enumeration; |
||||
// }
|
import java.util.HashMap; |
||||
//
|
import java.util.Map; |
||||
// /**
|
|
||||
// * 获取Request对象
|
/** |
||||
// *
|
* 日志/异常处理切面实现,调用父类方法完成日志记录和异常处理。 |
||||
// * @return
|
*/ |
||||
// */
|
@Aspect |
||||
// private HttpServletRequest getRequest() {
|
@Component |
||||
// RequestAttributes ra = RequestContextHolder.getRequestAttributes();
|
@Order(0) |
||||
// ServletRequestAttributes sra = (ServletRequestAttributes) ra;
|
@Slf4j |
||||
// return sra.getRequest();
|
public class RequestLogAspect { |
||||
// }
|
|
||||
//
|
@Around(value = "execution(* org.jeecg..*.*(..)) " + |
||||
//}
|
"&& (@annotation(org.springframework.web.bind.annotation.RequestMapping)) " + |
||||
|
"|| @annotation(org.springframework.web.bind.annotation.GetMapping)" + |
||||
|
"|| @annotation(org.springframework.web.bind.annotation.PostMapping)") |
||||
|
public Object proceed(ProceedingJoinPoint point) throws Throwable { |
||||
|
HttpServletRequest request = getRequest(); |
||||
|
|
||||
|
String requestURI = request.getRequestURI(); |
||||
|
String method = request.getMethod(); |
||||
|
// 获取事务流水号
|
||||
|
String transactionSerial = request.getHeader(JmReportConstants.TRANSACTION_SERIAL_KEY); |
||||
|
|
||||
|
Map<String, String> requestHeaders = getRequestHeaders(request); |
||||
|
|
||||
|
// 设置traceId,日志链路追踪
|
||||
|
MDC.put(JmReportConstants.TRANSACTION_SERIAL_KEY, transactionSerial); |
||||
|
|
||||
|
Object result; |
||||
|
LocalDateTime startTime = LocalDateTime.now(); |
||||
|
|
||||
|
try { |
||||
|
Object[] args = point.getArgs(); |
||||
|
ThreadLocalConstant.requestParam.set(Arrays.toString(point.getArgs())); |
||||
|
log.info(">>>>>>>>请求信息>>>>>>>>:事务流水号:{},url:{} ,method:{},请求参数:{},请求头:{}", |
||||
|
transactionSerial, requestURI, method, objectsToString(args), requestHeaders); |
||||
|
result = point.proceed(); |
||||
|
resultInfoLog(transactionSerial, getExecPeriod(startTime), result); |
||||
|
} catch (Throwable e) { |
||||
|
result = Result.FAIL("请求失败", null); |
||||
|
String exceptionMsg = ExceptionUtils.getThrowableErrorStackTrace(e); |
||||
|
resultErrorLog(transactionSerial, getExecPeriod(startTime), result, e.getMessage(), exceptionMsg); |
||||
|
} |
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取Request对象 |
||||
|
* |
||||
|
* @return |
||||
|
*/ |
||||
|
private HttpServletRequest getRequest() { |
||||
|
RequestAttributes ra = RequestContextHolder.getRequestAttributes(); |
||||
|
ServletRequestAttributes sra = (ServletRequestAttributes) ra; |
||||
|
return sra.getRequest(); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* @Description 获取请求头信息 |
||||
|
* @return |
||||
|
* @author wxz |
||||
|
* @date 2021.03.31 13:59 |
||||
|
*/ |
||||
|
private Map<String, String> getRequestHeaders(HttpServletRequest request) { |
||||
|
Enumeration<String> headerNames = request.getHeaderNames(); |
||||
|
HashMap<String, String> headerMap = new HashMap<>(); |
||||
|
while (headerNames.hasMoreElements()) { |
||||
|
String headerName = headerNames.nextElement(); |
||||
|
String headerValue = request.getHeader(headerName); |
||||
|
headerMap.put(headerName, headerValue); |
||||
|
} |
||||
|
return headerMap; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 将请求对象转换为String |
||||
|
* @param args |
||||
|
* @return |
||||
|
*/ |
||||
|
private String objectsToString(Object[] args) { |
||||
|
if (args == null) { |
||||
|
return null; |
||||
|
} else { |
||||
|
StringBuilder builder = new StringBuilder("["); |
||||
|
for (Object object : args) { |
||||
|
if (object != null |
||||
|
&& !(object instanceof ServletRequest) |
||||
|
&& !(object instanceof ServletResponse) |
||||
|
&& !(object instanceof MultipartFile) |
||||
|
) { |
||||
|
try { |
||||
|
// 尝试作为json解析
|
||||
|
String objectString = JSON.toJSONString(object); |
||||
|
builder.append(objectString); |
||||
|
} catch (Exception e) { |
||||
|
builder.append(object.toString()); |
||||
|
} |
||||
|
builder.append(","); |
||||
|
} |
||||
|
} |
||||
|
builder.append("]"); |
||||
|
return builder.toString(); |
||||
|
} |
||||
|
} |
||||
|
/** |
||||
|
* info日志 |
||||
|
* @param transactionSerial |
||||
|
* @param execTimeMillis |
||||
|
* @param result |
||||
|
*/ |
||||
|
private void resultInfoLog(String transactionSerial, Long execTimeMillis, Object result) { |
||||
|
log.info("<<<<<<<<正常响应<<<<<<<<:事务流水号:{}, 执行时长:{}ms, 响应数据:{}", |
||||
|
transactionSerial, execTimeMillis, result == null ? result : result.toString()); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 计算执行周期 |
||||
|
* @param startTime |
||||
|
* @return |
||||
|
*/ |
||||
|
private Long getExecPeriod(LocalDateTime startTime) { |
||||
|
LocalDateTime endTime = LocalDateTime.now(); |
||||
|
return Duration.between(startTime, endTime).toMillis(); |
||||
|
} |
||||
|
/** |
||||
|
* 异常错误级别日志 |
||||
|
* @param transactionSerial |
||||
|
* @param execTimeMillis |
||||
|
* @param result |
||||
|
* @param exceptionMsg |
||||
|
* @param exceptionDetail |
||||
|
*/ |
||||
|
private void resultErrorLog(String transactionSerial, Long execTimeMillis, Object result, String exceptionMsg, String exceptionDetail) { |
||||
|
log.error("<<<<<<<<异常响应<<<<<<<<:事务流水号:{}, 执行时长:{}ms, 响应数据:{}, 异常信息:{}, 堆栈信息:{}", |
||||
|
transactionSerial, execTimeMillis, result == null ? result : result.toString(), exceptionMsg, exceptionDetail); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
} |
||||
|
@ -0,0 +1,71 @@ |
|||||
|
package com.epmet.jmreport.constants; |
||||
|
|
||||
|
/** |
||||
|
* 公用参数常量 |
||||
|
*/ |
||||
|
public interface JmReportConstants { |
||||
|
|
||||
|
/** |
||||
|
* app类型-居民端端 |
||||
|
*/ |
||||
|
String APP_RESI = "resi"; |
||||
|
/** |
||||
|
* app类型-政府端 |
||||
|
*/ |
||||
|
String APP_GOV = "gov"; |
||||
|
/** |
||||
|
* app类型-运营端 |
||||
|
*/ |
||||
|
String APP_OPER = "oper"; |
||||
|
|
||||
|
/** |
||||
|
* 基层治理平台端 |
||||
|
*/ |
||||
|
String APP_IC = "ic"; |
||||
|
|
||||
|
/** |
||||
|
* PC端:web |
||||
|
*/ |
||||
|
String CLIENT_WEB = "web"; |
||||
|
/** |
||||
|
* 微信小程序:wxmp |
||||
|
*/ |
||||
|
String CLIENT_WXMP = "wxmp"; |
||||
|
|
||||
|
/** |
||||
|
* 客户来源App |
||||
|
* */ |
||||
|
String APP = "app"; |
||||
|
|
||||
|
/** |
||||
|
* 用户Id |
||||
|
* */ |
||||
|
String USER_ID = "userId"; |
||||
|
|
||||
|
/** |
||||
|
* 客户端 |
||||
|
* */ |
||||
|
String CLIENT = "client"; |
||||
|
|
||||
|
/** |
||||
|
* 客户ID |
||||
|
*/ |
||||
|
String CUSTOMER_ID = "customerId"; |
||||
|
|
||||
|
/** |
||||
|
* 事务流水号,每次请求串起来的多个服务拥有相同的流水号,便于日志追踪 |
||||
|
*/ |
||||
|
String TRANSACTION_SERIAL_KEY = "Transaction-Serial"; |
||||
|
/** |
||||
|
* app类型-工作端 |
||||
|
*/ |
||||
|
String APP_WORK = "work"; |
||||
|
/** |
||||
|
* 来源类型-话题:topic |
||||
|
*/ |
||||
|
String TOPIC = "topic"; |
||||
|
/** |
||||
|
* 来源类型-议题:issue |
||||
|
*/ |
||||
|
String ISSUE = "issue"; |
||||
|
} |
@ -0,0 +1,23 @@ |
|||||
|
package com.epmet.jmreport.constants; |
||||
|
|
||||
|
/** |
||||
|
* ThreadLocal常亮 |
||||
|
*/ |
||||
|
public class ThreadLocalConstant { |
||||
|
|
||||
|
/** |
||||
|
* 存储所需操作权限的 ThreadLocal |
||||
|
*/ |
||||
|
public static final ThreadLocal<String> requirePermissionTl = new ThreadLocal<>(); |
||||
|
|
||||
|
/** |
||||
|
* 用于向DataFilterInterceptor传递权限过滤的sql片段(需要在Controller相关的AOP中进行清理,防止变量残留) |
||||
|
*/ |
||||
|
public static final ThreadLocal<String> sqlFilter = new ThreadLocal(); |
||||
|
|
||||
|
/** |
||||
|
* 用于本次的获取请求参数 |
||||
|
*/ |
||||
|
public static final ThreadLocal<String> requestParam = new ThreadLocal(); |
||||
|
|
||||
|
} |
@ -0,0 +1,57 @@ |
|||||
|
/** |
||||
|
* Copyright (c) 2018 人人开源 All rights reserved. |
||||
|
* |
||||
|
* https://www.renren.io
|
||||
|
* |
||||
|
* 版权所有,侵权必究! |
||||
|
*/ |
||||
|
|
||||
|
package com.epmet.jmreport.utils; |
||||
|
|
||||
|
import java.io.IOException; |
||||
|
import java.io.PrintWriter; |
||||
|
import java.io.StringWriter; |
||||
|
|
||||
|
/** |
||||
|
* Exception工具类 |
||||
|
* |
||||
|
* @author Mark sunlightcs@gmail.com |
||||
|
*/ |
||||
|
public class ExceptionUtils { |
||||
|
|
||||
|
/** |
||||
|
* 获取异常信息 |
||||
|
* @param ex 异常 |
||||
|
* @return 返回异常信息 |
||||
|
*/ |
||||
|
public static String getErrorStackTrace(Exception ex){ |
||||
|
return getThrowableErrorStackTrace(ex); |
||||
|
} |
||||
|
|
||||
|
public static String getThrowableErrorStackTrace(Throwable ex) { |
||||
|
StringWriter sw = null; |
||||
|
PrintWriter pw = null; |
||||
|
try { |
||||
|
sw = new StringWriter(); |
||||
|
pw = new PrintWriter(sw, true); |
||||
|
ex.printStackTrace(pw); |
||||
|
}finally { |
||||
|
try { |
||||
|
if(pw != null) { |
||||
|
pw.close(); |
||||
|
} |
||||
|
} catch (Exception e) { |
||||
|
|
||||
|
} |
||||
|
try { |
||||
|
if(sw != null) { |
||||
|
sw.close(); |
||||
|
} |
||||
|
} catch (IOException e) { |
||||
|
|
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return sw.toString(); |
||||
|
} |
||||
|
} |
Loading…
Reference in new issue