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: | spring: | ||||||
|   application: |   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
	
	 陈景阳
						陈景阳