parent
f688a44e77
commit
614d3fc273
12 changed files with 289 additions and 8 deletions
@ -0,0 +1,150 @@ |
||||
package org.anyin.gitee.shiro.advisor; |
||||
|
||||
import cn.hutool.json.JSONUtil; |
||||
import lombok.extern.slf4j.Slf4j; |
||||
import org.anyin.gitee.shiro.base.BusinessCodeEnum; |
||||
import org.anyin.gitee.shiro.base.BusinessException; |
||||
import org.anyin.gitee.shiro.base.Response; |
||||
import org.anyin.gitee.shiro.utils.RequestIdUtils; |
||||
import org.aspectj.lang.ProceedingJoinPoint; |
||||
import org.aspectj.lang.annotation.Around; |
||||
import org.aspectj.lang.annotation.Aspect; |
||||
import org.slf4j.MDC; |
||||
import org.springframework.core.annotation.Order; |
||||
import org.springframework.util.StringUtils; |
||||
import org.springframework.web.context.request.RequestContextHolder; |
||||
import org.springframework.web.context.request.ServletRequestAttributes; |
||||
import org.springframework.web.multipart.commons.CommonsMultipartFile; |
||||
|
||||
import javax.servlet.http.HttpServletRequest; |
||||
import javax.servlet.http.HttpServletResponse; |
||||
import java.util.Optional; |
||||
import java.util.UUID; |
||||
|
||||
@Aspect |
||||
@Order |
||||
@Slf4j |
||||
public class ApiMessageAdvisor { |
||||
|
||||
|
||||
@Around("execution(public * org.anyin.gitee.shiro.controller..*Controller.*(..))") |
||||
public Object invokeAPI(ProceedingJoinPoint pjp) { |
||||
String apiName = this.getApiName(pjp); |
||||
String requestId = this.getRequestId(); |
||||
// 配置日志文件打印 REQUEST_ID
|
||||
MDC.put("REQUEST_ID", requestId); |
||||
Object returnValue = null; |
||||
try{ |
||||
this.printRequestParam(apiName, pjp); |
||||
returnValue = pjp.proceed(); |
||||
this.handleRequestId(returnValue); |
||||
}catch (BusinessException ex){ |
||||
returnValue = this.handleBusinessException(apiName, ex); |
||||
}catch (Throwable ex){ |
||||
returnValue = this.handleSystemException(apiName, ex); |
||||
}finally { |
||||
this.printResponse(apiName, returnValue); |
||||
RequestIdUtils.removeRequestId(); |
||||
MDC.clear(); |
||||
} |
||||
return returnValue; |
||||
} |
||||
|
||||
/** |
||||
* 处理系统异常 |
||||
* @param apiName 接口名称 |
||||
* @param ex 系统异常 |
||||
* @return 返回参数 |
||||
*/ |
||||
private Response handleSystemException(String apiName, Throwable ex){ |
||||
log.error("@Meet unknown error when do " + apiName + ":" + ex.getMessage(), ex); |
||||
Response response = new Response(BusinessCodeEnum.UNKNOWN_ERROR.getCode(), BusinessCodeEnum.UNKNOWN_ERROR.getMsg()); |
||||
response.setRequestId(RequestIdUtils.getRequestId().toString()); |
||||
return response; |
||||
} |
||||
|
||||
/** |
||||
* 处理业务异常 |
||||
* @param apiName 接口名称 |
||||
* @param ex 业务异常 |
||||
* @return 返回参数 |
||||
*/ |
||||
private Response handleBusinessException(String apiName, BusinessException ex){ |
||||
log.error("@Meet error when do " + apiName + "[" + ex.getCode() + "]:" + ex.getMsg(), ex); |
||||
Response response = new Response(ex.getCode(), ex.getMsg()); |
||||
response.setRequestId(RequestIdUtils.getRequestId().toString()); |
||||
return response; |
||||
} |
||||
|
||||
/** |
||||
* 填充RequestId |
||||
* @param returnValue 返回参数 |
||||
*/ |
||||
private void handleRequestId(Object returnValue){ |
||||
if(returnValue instanceof Response){ |
||||
Response response = (Response)returnValue; |
||||
response.setRequestId(RequestIdUtils.getRequestId().toString()); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 打印响应参数信息 |
||||
* @param apiName 接口名称 |
||||
* @param returnValue 返回值 |
||||
*/ |
||||
private void printResponse(String apiName, Object returnValue){ |
||||
if (log.isInfoEnabled()) { |
||||
log.info("@@{} done, response: {}", apiName, JSONUtil.toJsonStr(returnValue)); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 打印请求参数信息 |
||||
* @param apiName 接口名称 |
||||
* @param pjp 切点 |
||||
*/ |
||||
private void printRequestParam(String apiName, ProceedingJoinPoint pjp){ |
||||
Object[] args = pjp.getArgs(); |
||||
if(log.isInfoEnabled() && args != null&& args.length > 0){ |
||||
for(Object o : args) { |
||||
if(!(o instanceof HttpServletRequest) && !(o instanceof HttpServletResponse) && !(o instanceof CommonsMultipartFile)) { |
||||
log.info("@@{} started, request: {}", apiName, JSONUtil.toJsonStr(o)); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 获取RequestId |
||||
* 优先从header头获取,如果没有则自己生成 |
||||
* @return RequestId |
||||
*/ |
||||
private String getRequestId(){ |
||||
UUID existUUID = RequestIdUtils.getRequestId(); |
||||
if(existUUID != null){ |
||||
return existUUID.toString(); |
||||
} |
||||
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); |
||||
if(attributes == null || !StringUtils.hasText(attributes.getRequest().getHeader("x-request-id"))) { |
||||
RequestIdUtils.generateRequestId(); |
||||
return RequestIdUtils.getRequestId().toString(); |
||||
} |
||||
// 因为如果有网关,则一般会从网关传递过来,所以优先从header头获取
|
||||
HttpServletRequest request = attributes.getRequest(); |
||||
String requestId = request.getHeader("x-request-id"); |
||||
UUID uuid = UUID.fromString(requestId); |
||||
RequestIdUtils.generateRequestId(uuid); |
||||
return requestId; |
||||
} |
||||
|
||||
/** |
||||
* 获取当前接口对应的类名和方法名 |
||||
* @param pjp 切点 |
||||
* @return apiName |
||||
*/ |
||||
private String getApiName(ProceedingJoinPoint pjp){ |
||||
String apiClassName = pjp.getTarget().getClass().getSimpleName(); |
||||
String methodName = pjp.getSignature().getName(); |
||||
return apiClassName.concat(":").concat(methodName); |
||||
} |
||||
} |
@ -0,0 +1,14 @@ |
||||
package org.anyin.gitee.shiro.config; |
||||
|
||||
import org.anyin.gitee.shiro.advisor.ApiMessageAdvisor; |
||||
import org.springframework.context.annotation.Bean; |
||||
import org.springframework.context.annotation.Configuration; |
||||
|
||||
@Configuration |
||||
public class AppConfig { |
||||
|
||||
@Bean |
||||
public ApiMessageAdvisor apiMessageAdvisor(){ |
||||
return new ApiMessageAdvisor(); |
||||
} |
||||
} |
@ -0,0 +1,27 @@ |
||||
package org.anyin.gitee.shiro.controller; |
||||
|
||||
import org.anyin.gitee.shiro.base.BusinessCodeEnum; |
||||
import org.anyin.gitee.shiro.base.Response; |
||||
import org.springframework.web.bind.annotation.GetMapping; |
||||
import org.springframework.web.bind.annotation.RequestMapping; |
||||
import org.springframework.web.bind.annotation.RestController; |
||||
|
||||
@RestController |
||||
@RequestMapping("/log-test") |
||||
public class LogTestController { |
||||
|
||||
@GetMapping("/success") |
||||
public Response<String> success(){ |
||||
return new Response<>("success"); |
||||
} |
||||
|
||||
@GetMapping("/business-exception") |
||||
public Response<String> businessException(){ |
||||
throw BusinessCodeEnum.PWD_NOT_MATCH.getException(); |
||||
} |
||||
|
||||
@GetMapping("/system-exception") |
||||
public Response<String> systemException(){ |
||||
throw new NullPointerException("空指针异常"); |
||||
} |
||||
} |
@ -0,0 +1,26 @@ |
||||
package org.anyin.gitee.shiro.utils; |
||||
|
||||
import java.util.UUID; |
||||
|
||||
public class RequestIdUtils { |
||||
private static final ThreadLocal<UUID> requestIdHolder = new ThreadLocal<>(); |
||||
|
||||
public RequestIdUtils() { |
||||
} |
||||
|
||||
public static void generateRequestId() { |
||||
requestIdHolder.set(UUID.randomUUID()); |
||||
} |
||||
|
||||
public static void generateRequestId(UUID uuid) { |
||||
requestIdHolder.set(uuid); |
||||
} |
||||
|
||||
public static UUID getRequestId() { |
||||
return (UUID)requestIdHolder.get(); |
||||
} |
||||
|
||||
public static void removeRequestId() { |
||||
requestIdHolder.remove(); |
||||
} |
||||
} |
@ -1,3 +1,9 @@ |
||||
spring: |
||||
application: |
||||
name: shiro-to-token |
||||
name: shiro-to-token |
||||
|
||||
logging: |
||||
level: |
||||
root: info |
||||
file: |
||||
path: ./logs/shiro-to-token.log |
@ -0,0 +1,34 @@ |
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<configuration debug="false" scan="true" scanPeriod="1 seconds"> |
||||
|
||||
<contextName>logback</contextName> |
||||
<springProperty scope="context" name="level" source="logging.level.root"/> |
||||
<springProperty scope="context" name="path" source="logging.file.path"/> |
||||
|
||||
|
||||
<appender name="console" class="ch.qos.logback.core.ConsoleAppender"> |
||||
<Target>System.out</Target> |
||||
<filter class="ch.qos.logback.classic.filter.ThresholdFilter" > |
||||
<level>DEBUG</level> |
||||
</filter> |
||||
<encoder> |
||||
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%X{REQUEST_ID}] [%thread] [%-5level] [%logger{0}:%L] : %msg%n</pattern> |
||||
</encoder> |
||||
</appender> |
||||
|
||||
<appender name="file" class="ch.qos.logback.core.rolling.RollingFileAppender"> |
||||
<file>${path}</file> |
||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> |
||||
<fileNamePattern>${path}.%d{yyyy-MM-dd}.zip</fileNamePattern> |
||||
</rollingPolicy> |
||||
<encoder> |
||||
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%X{REQUEST_ID}] [%thread] [%-5level] [%logger{0}:%L] : %msg%n</pattern> |
||||
</encoder> |
||||
</appender> |
||||
|
||||
<root level="${level}"> |
||||
<appender-ref ref="console"/> |
||||
<appender-ref ref="file"/> |
||||
</root> |
||||
|
||||
</configuration> |
Loading…
Reference in new issue