springboot 啟動(dòng)項(xiàng)目打印接口列表的實(shí)現(xiàn)
springboot 啟動(dòng)項(xiàng)目打印接口列表
環(huán)境
- springboot 2.3.2.RELEASE
修改配置文件
logging:
level:
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping: trace
結(jié)果:

Springboot項(xiàng)目添加接口入?yún)⒔y(tǒng)一打印
需求:要求接口被調(diào)用時(shí)要打印被調(diào)用方法名,以及入?yún)⑶闆r,參數(shù)格式化時(shí)選擇fastjson
注:使用fastjson序列化時(shí)脫敏,建議入?yún)⒔y(tǒng)一使用自定義的對(duì)象類型作為入?yún)?/p>
如果不需要參數(shù)脫敏,直接使用增強(qiáng)中相關(guān)代碼,并去除參數(shù)脫敏相關(guān)代碼即可
新建注解,用于實(shí)現(xiàn)參數(shù)打印功能的增強(qiáng)
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ParamInfo {
/**
* 取消統(tǒng)一打印參數(shù)
* 默認(rèn)為false統(tǒng)一打印
* 如需自定義參數(shù)打印 請(qǐng)賦值為true
*/
boolean unPrint() default false;
/**
* 需要脫敏的字段,如密碼等
*/
String[] fields() default {};
}
自定義序列化規(guī)則
/**
* 序列化過濾器:值替換
*
*/
public class ReplaceFieldFilter implements ValueFilter {
/**
* 需要進(jìn)行替換的屬性名和替換值
* key:屬性名
* value:替換值
*/
private Map<String, Object> fieldMap;
public ReplaceFieldFilter() {
}
public ReplaceFieldFilter(Map<String, Object> fieldMap) {
this.fieldMap = fieldMap;
}
@Override
public Object process(Object o, String name, Object value) {
if(!CollectionUtils.isEmpty(fieldMap)){
Iterator<Map.Entry<String, Object>> iterator = fieldMap.entrySet().iterator();
while (iterator.hasNext()){
Map.Entry<String, Object> next = iterator.next();
if(next.getKey().equalsIgnoreCase(name)){
return next.getValue();
}
}
}
return value;
}
public Map<String, Object> getFieldMap() {
return fieldMap;
}
public void setFieldMap(Map<String, Object> fieldMap) {
this.fieldMap = fieldMap;
}
/**
* 傳入需要脫敏的字段名,序列化時(shí)格式化為 * 號(hào)
*/
public ReplaceFieldFilter(String... fields) {
String str = "******";
fieldMap = new HashMap<>(4);
for (String field : fields) {
fieldMap.put(field, str);
}
}
}
寫參數(shù)打印增強(qiáng),這里選擇環(huán)繞增強(qiáng)
@Component
@Aspect
//表示增強(qiáng)的執(zhí)行順序,如果多個(gè)增強(qiáng),數(shù)值小的先被執(zhí)行
@Order(0)
public class ParamInfoAspect {
private static final Logger LOGGER = LoggerFactory.getLogger(ParamInfoAspect.class);
@Around("execution(* com.service.impl.*.*(..))")
public Object printParam(ProceedingJoinPoint joinPoint) throws Throwable {
long startTime = System.currentTimeMillis();
String requestId = RandomStringUtils.randomAlphanumeric(16);
Object returnValue = null;
try {
Object[] args = joinPoint.getArgs();
// 獲取方法對(duì)象
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
//通過注解獲取脫敏字段,之后初始化fieldMap,完成字段脫敏
ParamInfo annotation = method.getAnnotation(ParamInfo.class);
Map<String, Object> fieldMap = new HashMap<>(4);
fieldMap.put("password", "******");
if (annotation != null) {
//獲取需要脫敏的字段名數(shù)組
String[] fields = annotation.fields();
for (String field : fields) {
fieldMap.put(field, "******");
}
}
String param;
//參數(shù)整合,多字段入?yún)⒄蠟閷?duì)象,單個(gè)對(duì)象入?yún)⒏袷讲蛔?
if (args.length > 1 || (args.length == 1 && args[0].getClass() == String.class)) {
Map<String, Object> paramMap = new LinkedHashMap<>();
String[] parameterNames = signature.getParameterNames();
for (int i = 0; i < parameterNames.length; i++) {
paramMap.put(parameterNames[i], args[i]);
}
param = "[" + JSON.toJSONString(paramMap, new ReplaceFieldFilter(fieldMap)) + "]";
} else {
param = JSON.toJSONString(args, new ReplaceFieldFilter(fieldMap));
}
String methodName = method.getName();
LOGGER.info("method:[{}], parameter:{}, requestId:[{}]", methodName, param, requestId);
returnValue = joinPoint.proceed();
return returnValue;
} catch (Exception e) {
LOGGER.error("system is error:", e);
//可在這里定義程序異常時(shí)的錯(cuò)誤返回值
returnValue = ErrorCode.SYSTEM_ERROR;
return returnValue;
} finally {
LOGGER.info("request cost:{}ms, requestId:[{}]", System.currentTimeMillis() - startTime, requestId);
LOGGER.info("returnValue:[{}], requestId:[{}]", returnValue, requestId);
}
}
}
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
- IntelliJ IDEA下SpringBoot如何指定某一個(gè)配置文件啟動(dòng)項(xiàng)目
- 詳解SpringBoot啟動(dòng)項(xiàng)目后執(zhí)行方法的幾種方式
- springboot+dubbo啟動(dòng)項(xiàng)目時(shí)報(bào)錯(cuò) zookeeper not connected的問題及解決方案
- IDEA下SpringBoot指定配置文件啟動(dòng)項(xiàng)目的全過程
- SpringBoot實(shí)現(xiàn)啟動(dòng)項(xiàng)目后立即執(zhí)行的方法總結(jié)
- java?-jar命令及SpringBoot通過java?-jav啟動(dòng)項(xiàng)目的過程
- idea沒有services窗口、沒有springboot啟動(dòng)項(xiàng)問題
相關(guān)文章
java Spring 5 新特性函數(shù)式Web框架詳細(xì)介紹
正如昨天Juergen博客中所提到的,Spring 5.0的第二個(gè)里程碑是引入了一個(gè)新的函數(shù)式web框架。在這篇文章中,我們將給出關(guān)于這個(gè)框架的更多信息,,需要的朋友可以參考下2016-12-12
深入解析Java的Hibernate框架中的一對(duì)一關(guān)聯(lián)映射
這篇文章主要介紹了Java的Hibernate框架的一對(duì)一關(guān)聯(lián)映射,包括對(duì)一對(duì)一外聯(lián)映射的講解,需要的朋友可以參考下2016-01-01
java正則表達(dá)式處理花括號(hào)內(nèi)容替換賦值問題
這篇文章主要介紹了java正則表達(dá)式處理花括號(hào)內(nèi)容替換賦值問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-05-05
spring的同一定時(shí)任務(wù)上一次的任務(wù)未結(jié)束前不會(huì)啟動(dòng)這次任務(wù)問題
這篇文章主要介紹了spring的同一定時(shí)任務(wù)上一次的任務(wù)未結(jié)束前不會(huì)啟動(dòng)這次任務(wù)問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-12-12
IntelliJ IDEA下Maven創(chuàng)建Scala項(xiàng)目的方法步驟
這篇文章主要介紹了IntelliJ IDEA下Maven創(chuàng)建Scala項(xiàng)目的方法步驟,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-06-06
SpringBoot @PropertySource與@ImportResource有什么區(qū)別
這篇文章主要介紹了SpringBoot @PropertySource與@ImportResource有什么區(qū)別,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧2023-01-01

