@Slf4j
@Aspect
@Order(2)
@Configuration
public class AuthCheckerAspect {
private ThreadLocal<HashMap<String, Object>> currentThreadLocal = new ThreadLocal();
@Value("${yylc.auth.appKey}")
private String appKey;
@Value("${yylc.auth.appSecret}")
private String appSecret;
@Pointcut("execution(* com.consume.yylc.controller.api..*.*(..)) && @within(com.consume.yylc.common.annotation.AuthChecker)")
public void authCheckerPointcut() {
}
/*
* 方法调用前触发
* @param joinPoint
*/
@Before("authCheckerPointcut()")
public void doBeforeAuthChecker(JoinPoint joinPoint) {
HashMap<String, Object> hash = new HashMap<>();
hash.put("beginTimeMillis", System.currentTimeMillis());
currentThreadLocal.set(hash);
}
/*
*
* @Title:doAfterInServiceLayer
* @Description: 方法调用后触发
* 记录结束时间
* @param joinPoint*/
@After("authCheckerPointcut()")
public void doAfterAuthChecker(JoinPoint joinPoint) {
long beginTimeMillis = (long) currentThreadLocal.get().get("beginTimeMillis");
long endTimeMillis = System.currentTimeMillis();
log.info("-------------------->验签用时:" + (endTimeMillis - beginTimeMillis) + "ms");
}
/*
*
* @Title:doAround
* @Description: 环绕触发
* @return
* @throws Throwable
*/
@Around("authCheckerPointcut()")
public Object doAround(ProceedingJoinPoint pjoinPoint) throws Throwable {
// 接收到请求,记录请求内容
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
HttpServletResponse response = attributes.getResponse();
String uri = request.getRequestURI();
String method = request.getMethod();
log.info("--------------------> uri=" + uri + "; 参数验签开始......");
if ("POST".equals(method)) {
Object[] paramsArray = pjoinPoint.getArgs();
Object param1 = paramsArray[0];
String body = "";
if (param1 instanceof JSONObject) {
body = ((JSONObject) param1).toJSONString();
} else {
SerializeConfig config = SerializeConfig.getGlobalInstance();
body = JSON.toJSONString(param1, config, SerializerFeature.SortField);//@JSONField(serialize = false)
}
if (!SignUtils.validSign(body, request, appSecret)) {
response.setHeader("Content-Type", "application/json;charset=UTF-8");
//422 Unprocessable Entry - 请求数据验证错误
response.setStatus(422);
log.info("--------------------> uri=" + uri + "; 参数验签失败......");
return new ApiResult(422, "请求数据验证错误");
} else {
return pjoinPoint.proceed();
}
} else {
log.info("--------------------> uri=" + uri + "; 参数验签失败......");
return new ApiResult(422, "请求方式有误");
}
}
}
@Slf4j
@Aspect
@Order(1)
@Component
public class WebRequestLogAspect {
private ThreadLocal<RequestLogs> currentThreadLocal = new ThreadLocal<RequestLogs>();
@Autowired
private IRequestLogsService requestLogsService;
@Pointcut(value = "execution(* com.consume.yylc.controller..*.*(..)) && @annotation(com.consume.yylc.common.annotation.WebRequestLog)")
public void webRequestLogPoint() {
}
@Before("webRequestLogPoint() && @annotation(webRequestLog)")
public void doBefore(JoinPoint joinPoint, WebRequestLog webRequestLog) {
try {
LocalDateTime beginTime = LocalDateTime.now();
// 接收到请求,记录请求内容
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
String beanName = joinPoint.getSignature().getDeclaringTypeName();
String methodName = joinPoint.getSignature().getName();
String uri = request.getRequestURI();
String remoteAddr = getIpAddr(request);
String method = request.getMethod();
String params = "";
if ("POST".equals(method)) {
Object[] paramsArray = joinPoint.getArgs();
params = argsArrayToString(paramsArray);
} else {
Map<?, ?> paramsMap = (Map<?, ?>) request.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE);
params = paramsMap.toString();
}
log.info("===============>接口请求数据: uri=" + uri + "; beanName=" + beanName + "; ip=" + remoteAddr + ";" +
"; methodName=" + methodName + "; params=" + params);
RequestLogs optLog = new RequestLogs();
optLog.setUrl(uri);
optLog.setIp(remoteAddr);
optLog.setParams(params != null ? params : "");
optLog.setCreateTime(beginTime);
optLog.setInterfaceName(webRequestLog.interfaceEnum().getInterfaceName());
optLog.setBusinessId(getBusinessId(joinPoint, webRequestLog));
currentThreadLocal.set(optLog);
} catch (Exception e) {
log.error("===============>接口请求日志记录失败doBefore()***", e);
}
}
@AfterReturning(returning = "result", pointcut = "webRequestLogPoint()")
public void doAfterReturning(Object result) {
try {
RequestLogs optLog = currentThreadLocal.get();
optLog.setResponse(result.toString());
long beginTime = optLog.getCreateTime().toInstant(ZoneOffset.of("+8")).toEpochMilli();
long costTime = (System.currentTimeMillis() - beginTime) / 1000;
optLog.setCostTime((int) costTime);
ApiResult apiResult = (ApiResult) result;
optLog.setCode(apiResult.getCode().toString());
log.info("===============>接口url:" + optLog.getUrl() + " 响应数据:" + result);
requestLogsService.save(optLog);
} catch (Exception e) {
log.error("===============>接口请求日志记录失败doAfterReturning()", e);
}
}
/**
* @param joinPoint
* @param e
*/
@AfterThrowing(pointcut = "webRequestLogPoint()", throwing = "e")
public void doAfterThrowing(JoinPoint joinPoint, Throwable e) {
try {
// 接收到请求,记录请求内容
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
String beanName = joinPoint.getSignature().getDeclaringTypeName();
String methodName = joinPoint.getSignature().getName();
String uri = request.getRequestURI();
String remoteAddr = getIpAddr(request);
String params = "";
log.error("===============>接口请求出现异常");
log.error("uri=" + uri + "; beanName=" + beanName + "; ip=" + remoteAddr + ";" +
"; methodName=" + methodName + "; params=" + params);
log.error("异常信息:" + e.getMessage());
log.error("==============================");
} catch (Exception ee) {
log.error("===============>接口请求日志记录失败doAfterReturning()***", ee);
}
}
private String getBusinessId(JoinPoint joinPoint, WebRequestLog requestLog) {
String businessId = requestLog.businessId();
if (businessId == "") {
return "";
}
try {
ExpressionParser parser = new SpelExpressionParser();
EvaluationContext ec = new StandardEvaluationContext();
int i = 0;
for (Object obj : joinPoint.getArgs()) {
ec.setVariable("arg" + (i++), obj);
}
if (businessId.contains("arg")) {
businessId = parser.parseExpression(businessId).getValue(ec, java.lang.String.class);
} else {
return businessId;
}
} catch (Exception e) {
log.error("解析SpEL表达式异常", e);
}
return businessId;
}
/**
* 获取登录用户远程主机ip地址
*
* @param request
* @return
*/
private String getIpAddr(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();
}
final String[] arr = ip.split(",");
for (final String str : arr) {
if (!"unknown".equalsIgnoreCase(str)) {
ip = str;
}
break;
}
return ip;
}
/**
* 请求参数拼装
*
* @param paramsArray
* @return
*/
private String argsArrayToString(Object[] paramsArray) {
String params = "";
if (paramsArray != null && paramsArray.length > 0) {
for (int i = 0; i < paramsArray.length; i++) {
String body;
Object curParam = paramsArray[i];
if (curParam instanceof HttpServletRequest || curParam instanceof HttpServletResponse) {
continue;
}
if (curParam instanceof JSONObject) {
body = ((JSONObject) curParam).toJSONString();
} else {
SerializeConfig config = SerializeConfig.getGlobalInstance();
body = JSON.toJSONString(curParam, config, SerializerFeature.SortField);//@JSONField(serialize = false)
}
params += body + " ";
}
}
return params.trim();
}
}
@Slf4j
@ControllerAdvice
@ResponseBody
public class GlobalDefaultException {
@ExceptionHandler(Exception.class)
public ApiResult handle(HttpServletRequest req, Exception e) {
log.error("===================错误的异常请求url " + req.getRequestURL(),e);
if(e instanceof MethodArgumentNotValidException) {
MethodArgumentNotValidException ee=(MethodArgumentNotValidException)e;
//按需重新封装需要返回的错误信息
List<ArgumentInvalidResult> invalidArguments = new ArrayList<>();
//解析原错误信息,封装后返回,此处返回非法的字段名称,原始值,错误信息
for (FieldError error : ee.getBindingResult().getFieldErrors()) {
ArgumentInvalidResult invalidArgument = new ArgumentInvalidResult();
invalidArgument.setDefaultMessage(error.getDefaultMessage());
invalidArgument.setField(error.getField());
invalidArgument.setRejectedValue(error.getRejectedValue());
invalidArguments.add(invalidArgument);
}
return new ApiResult(422,"参数传入有问题",invalidArguments);
}else if (e instanceof BusinessException) {
BusinessException businessException = (BusinessException) e;
log.error("==============业务逻辑异常 " + businessException.getMsg(),e);
return new ApiResult(ResultInfoEnum.BUSINESS_ERROR.getCode(),
ResultInfoEnum.BUSINESS_ERROR.getMsg());
} else if (e instanceof DataDoException) {
DataDoException dataDoException = (DataDoException) e;
log.error("=============sql,数据库操作异常 " + dataDoException.getMsg(),e);
return new ApiResult(ResultInfoEnum.SQL_ERROR.getCode(), ResultInfoEnum.SQL_ERROR.getMsg());
} else {
log.error("============系统异常" + e.getMessage(),e);
return new ApiResult(ResultInfoEnum.SYSTEM_ERROR.getCode(), ResultInfoEnum.SYSTEM_ERROR.getMsg());
}
}
}