1.相关依赖
< ! -- 私人工具包 -- > < dependency> < groupId> cn. changeforyou< / groupId> < artifactId> location< / artifactId> < version> 1.13 - SNAPSHOT < / version> < / dependency> < ! -- hutool工具依赖 -- > < dependency> < groupId> cn. hutool< / groupId> < artifactId> hutool- crypto< / artifactId> < version> 5.5 .0 < / version> < / dependency> < dependency> < groupId> org. projectlombok< / groupId> < artifactId> lombok< / artifactId> < optional> true < / optional> < / dependency> < dependency> < groupId> org. springframework. boot< / groupId> < artifactId> spring- boot- starter- validation< / artifactId> < / dependency>
2.添加日志过滤类LogFilter.java
package com. abliner. test. common. log ; import cn. changeforyou. web. utils. http. ServletUtils ;
import cn. changeforyou. web. utils. http. warpper. BufferedHttpResponseWrapper ;
import cn. hutool. json. JSONUtil ;
import org. apache. commons. collections. CollectionUtils ;
import org. slf4j. Logger ;
import org. slf4j. LoggerFactory ;
import org. springframework. beans. factory. annotation. Autowired ;
import org. springframework. http. HttpHeaders ;
import org. springframework. http. HttpMethod ;
import org. springframework. http. MediaType ;
import org. springframework. stereotype. Component ;
import org. springframework. util. AntPathMatcher ;
import org. springframework. web. filter. OncePerRequestFilter ;
import org. springframework. web. multipart. MultipartFile ;
import org. springframework. web. multipart. MultipartHttpServletRequest ;
import org. springframework. web. multipart. MultipartResolver ;
import org. springframework. web. multipart. support. StandardServletMultipartResolver ;
import com. abliner. test. common. log. LogRecordConfig . InterfaceLogConfig ; import javax. servlet. FilterChain ;
import javax. servlet. ServletException ;
import javax. servlet. http. HttpServletRequest ;
import javax. servlet. http. HttpServletResponse ;
import java. io. IOException ;
import java. nio. charset. StandardCharsets ;
import java. util. * ;
import java. util. concurrent. ConcurrentHashMap ; @Component
public class LogFilter extends OncePerRequestFilter { Logger log = LoggerFactory . getLogger ( "reqResp" ) ; @Autowired private LogRecordConfig logRecordConfig; private final Set < String > urls; private final AntPathMatcher antPathMatcher; private final Map < String , InterfaceLogConfig > url2Config = new ConcurrentHashMap < > ( ) ; public LogRecordConfig getLogRecordConfig ( ) { return logRecordConfig; } public LogRecordConfig addInterfaceLogConfig ( InterfaceLogConfig config) { logRecordConfig. getInterfaceLogConfigs ( ) . add ( config) ; initMatcher ( ) ; return logRecordConfig; } public LogRecordConfig removeInterfaceLogConfig ( String url) { if ( url2Config. containsKey ( url) ) { InterfaceLogConfig config = url2Config. remove ( url) ; logRecordConfig. getInterfaceLogConfigs ( ) . remove ( config) ; initMatcher ( ) ; } return logRecordConfig; } public LogRecordConfig updateDefaultInterfaceLogLevel ( InterfaceLogConfig config) { logRecordConfig. setDefaultInterfaceLogConfig ( config) ; return logRecordConfig; } public LogFilter ( ) { urls = Collections . synchronizedSet ( new HashSet < > ( ) ) ; antPathMatcher = new AntPathMatcher ( ) ; } private InterfaceLogConfig matches ( String url) { if ( urls. isEmpty ( ) ) { return null ; } for ( String s : urls) { if ( antPathMatcher. match ( s, url) ) { return url2Config. get ( s) ; } } return null ; } @Override protected void doFilterInternal ( HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException , IOException { long requestTime = System . currentTimeMillis ( ) ; String uri = request. getRequestURI ( ) ; String contextPath = request. getContextPath ( ) ; String url = uri. substring ( contextPath. length ( ) ) ; InterfaceLogConfig thisConfig = matches ( url) ; if ( null == thisConfig) { thisConfig = logRecordConfig. getDefaultInterfaceLogConfig ( ) ; } if ( ! thisConfig. printLog ( ) ) { filterChain. doFilter ( request, response) ; return ; } String requestBody = "" ; String requestContentType = request. getHeader ( HttpHeaders . CONTENT_TYPE ) ; if ( requestContentType != null ) { if ( ( requestContentType. startsWith ( MediaType . APPLICATION_JSON_VALUE ) || requestContentType. startsWith ( MediaType . APPLICATION_XML_VALUE ) ) && request. getMethod ( ) . equalsIgnoreCase ( "POST" ) ) { StringBuilder sb = new StringBuilder ( ) ; request = ServletUtils . getRequestBody ( request, sb) ; requestBody = sb. toString ( ) ; } else if ( requestContentType. startsWith ( MediaType . APPLICATION_FORM_URLENCODED_VALUE ) ) { requestBody = toJson ( request. getParameterMap ( ) ) ; } else if ( requestContentType. startsWith ( MediaType . MULTIPART_FORM_DATA_VALUE ) ) { requestBody = getFormParam ( request) ; } else { requestBody = toJson ( request. getParameterMap ( ) ) ; } } else if ( request. getMethod ( ) . equals ( HttpMethod . GET . name ( ) ) ) { requestBody = toJson ( request. getParameterMap ( ) ) ; } BufferedHttpResponseWrapper responseWrapper = new BufferedHttpResponseWrapper ( response) ; if ( thisConfig. printReq ( ) ) { if ( thisConfig. isDebugEnabled ( ) ) { log. debug ( "URL: {}, requestBody: {}" , url, requestBody) ; } else { log. info ( "URL: {}, requestBody: {}" , url, requestBody) ; } } filterChain. doFilter ( request, responseWrapper) ; long costTime = System . currentTimeMillis ( ) - requestTime; String responseBody = "" ; String contentType = responseWrapper. getContentType ( ) ; if ( contentType != null && contentType. startsWith ( MediaType . APPLICATION_JSON_VALUE ) ) { responseBody = new String ( responseWrapper. getBuffer ( ) , StandardCharsets . UTF_8 ) ; } StringBuilder sb = new StringBuilder ( ) ; sb. append ( "URL:" ) . append ( url) . append ( ", total time:" ) . append ( costTime) . append ( " ms, " ) ; if ( thisConfig. printRes ( ) ) { sb. append ( ", responseBody:" ) . append ( responseBody) ; } if ( responseWrapper. getStatus ( ) >= 200 && responseWrapper. getStatus ( ) < 1000 ) { if ( thisConfig. isDebugEnabled ( ) ) { log. debug ( sb. toString ( ) ) ; } else { log. info ( sb. toString ( ) ) ; } } else { log. error ( sb. toString ( ) ) ; } response. getOutputStream ( ) . write ( responseWrapper. getBuffer ( ) ) ; } private String getFormParam ( HttpServletRequest request) { MultipartResolver resolver = new StandardServletMultipartResolver ( ) ; MultipartHttpServletRequest mRequest = resolver. resolveMultipart ( request) ; Map < String , Object > param = new HashMap < > ( ) ; Map < String , String [ ] > parameterMap = mRequest. getParameterMap ( ) ; if ( ! parameterMap. isEmpty ( ) ) { param. putAll ( parameterMap) ; } Map < String , MultipartFile > fileMap = mRequest. getFileMap ( ) ; if ( ! fileMap. isEmpty ( ) ) { for ( Map. Entry < String , MultipartFile > fileEntry : fileMap. entrySet ( ) ) { MultipartFile file = fileEntry. getValue ( ) ; param. put ( fileEntry. getKey ( ) , file. getOriginalFilename ( ) + "(" + file. getSize ( ) + " byte)" ) ; } } return toJson ( param) ; } @Override public void afterPropertiesSet ( ) throws ServletException { super . afterPropertiesSet ( ) ; initMatcher ( ) ; } private void initMatcher ( ) { List < InterfaceLogConfig > configs = logRecordConfig. getInterfaceLogConfigs ( ) ; this . urls. clear ( ) ; if ( CollectionUtils . isNotEmpty ( configs) ) { for ( InterfaceLogConfig config : configs) { this . urls. add ( config. getUrl ( ) ) ; url2Config. put ( config. getUrl ( ) , config) ; } } } private static String toJson ( Object object) { return JSONUtil . toJsonStr ( object) ; } }
3.添加日志配置类LogRecordConfig.java
package com. abliner. test. common. log ; import com. abliner. test. common. validator. InStrings ;
import com. abliner. test. common. validator. ValidatorConstant ;
import lombok. Data ;
import org. springframework. boot. context. properties. ConfigurationProperties ;
import org. springframework. boot. context. properties. NestedConfigurationProperty ;
import org. springframework. stereotype. Component ; import javax. validation. constraints. NotEmpty ;
import java. util. List ; @ConfigurationProperties ( prefix = "log.record" )
@Data
@Component
public class LogRecordConfig { private InterfaceLogConfig defaultInterfaceLogConfig; @NestedConfigurationProperty private List < InterfaceLogConfig > interfaceLogConfigs; @Data public static class InterfaceLogConfig { @NotEmpty ( groups = ValidatorConstant. InsertAndUpdate . class ) @NotEmpty ( groups = ValidatorConstant. Delete . class ) private String url; @NotEmpty ( groups = ValidatorConstant. InsertAndUpdate . class ) @InStrings ( in= { "info" , "debug" } , groups = ValidatorConstant. InsertAndUpdate . class ) @InStrings ( in= { "info" , "debug" } , groups = ValidatorConstant. UpdateDefault . class ) private String logLevel; @NotEmpty ( groups = ValidatorConstant. InsertAndUpdate . class ) @InStrings ( in= { "res" , "req" , "all" , "none" } , groups = ValidatorConstant. InsertAndUpdate . class ) @InStrings ( in= { "res" , "req" , "all" , "none" } , groups = ValidatorConstant. UpdateDefault . class ) private String print; public boolean isDebugEnabled ( ) { return "debug" . equalsIgnoreCase ( logLevel) ; } public boolean printLog ( ) { return ! "none" . equalsIgnoreCase ( print) ; } public boolean printRes ( ) { return "res" . equalsIgnoreCase ( print) || "all" . equalsIgnoreCase ( print) ; } public boolean printReq ( ) { return "req" . equalsIgnoreCase ( print) || "all" . equalsIgnoreCase ( print) ; } } }
4.添加使用到的注解类InStrings.java
package com. abliner. test. common. validator ; import javax. validation. Constraint ;
import javax. validation. Payload ;
import java. lang. annotation. Documented ;
import java. lang. annotation. Repeatable ;
import java. lang. annotation. Retention ;
import java. lang. annotation. Target ; import static java. lang. annotation. ElementType . * ;
import static java. lang. annotation. ElementType . TYPE_USE ;
import static java. lang. annotation. RetentionPolicy . RUNTIME ; @Documented
@Constraint ( validatedBy = { InStringsValidator . class } )
@Target ( { METHOD , FIELD , ANNOTATION_TYPE , CONSTRUCTOR , PARAMETER , TYPE_USE } )
@Retention ( RUNTIME )
@Repeatable ( InStrings. List . class )
public @interface InStrings { String message ( ) default "字符串不在设定范围内" ; String [ ] in ( ) ; Class < ? > [ ] groups ( ) default { } ; Class < ? extends Payload > [ ] payload ( ) default { } ; @Target ( { METHOD , FIELD , ANNOTATION_TYPE , CONSTRUCTOR , PARAMETER , TYPE_USE } ) @Retention ( RUNTIME ) @Documented @interface List { InStrings [ ] value ( ) ; }
}
5.添加InStringsValidator.java
package com. abliner. test. common. validator ; import cn. changeforyou. utils. string. StringUtils ; import javax. validation. ConstraintValidator ;
import javax. validation. ConstraintValidatorContext ; public class InStringsValidator implements ConstraintValidator < InStrings , String > { private String [ ] mustIn; @Override public void initialize ( InStrings constraintAnnotation) { mustIn = constraintAnnotation. in ( ) ; } @Override public boolean isValid ( String s, ConstraintValidatorContext constraintValidatorContext) { if ( StringUtils . isEmpty ( s) ) { return false ; } return StringUtils . in ( s, mustIn) ; }
}
6.添加常量ValidatorConstant.java
package com. abliner. test. common. validator ; public interface ValidatorConstant { interface Insert { } interface Update { } interface Delete { } interface Select { } interface InsertAndUpdate { } interface SelectAndDelete { } interface UpdateDefault { }
}
7.项目结构图
8.在主配置文件application.yml
添加代码
log: record: defaultInterfaceLogConfig: logLevel: infoprint: req
9.测试打印