springmvccontroller⾃动打印出⼊参数以及打印其他有⽤信
息
使⽤说明
<包下
加了@RestController注解的controller
打印的⽇志规格如下:
包含:ip地址、url、全限定类名+⽅法名、请求时间、请求参数(⽀持多个)、响应时间、响应参数、响应时间(毫秒)、关键字、序列号(⽤于和响应打印匹配)
# 请求打印
2020-12-22 16:15:08.473 INFO 9920 --- [nio-9600-exec-8] p.DefaltControllerPrintInputOutputAcpect : xxxx_cloud_aop_request: {
"ipaddr":"127.0.0.1:9600",
"url":"/testcfg4",
"method":"biz.stcfg4",
"requestTime":"2020-12-22 16:15:08",
"request":"[{\"a\":\"aa\",\"b\":\"bb\",\"c\":\"cc\"}]",
"keyword":"zxp",
"sn":"1608624908470_58"
}
# 响应打印
2020-12-22 16:15:08.474 INFO 9920 --- [nio-9600-exec-8] p.DefaltControllerPrintInputOutputAcpect : xxxx_cloud_aop_response: {
"ipaddr":"127.0.0.1:9600",
"url":"/testcfg4",
"method":"biz.stcfg4",
"responseTime":"2020-12-22 16:15:08",
"response":"{\"code\":200,\"msg\":\"\"}",
"rt":4,
"keyword":"zxp",
"sn":"1608624908470_58"
}
打印个性配置@PrintControllerLog
不打印请求报⽂
@RequestMapping(value = "/testdown", method = RequestMethod.GET)
@PrintControllerLog(notPrintRequest = true)
public Result downloadFile(HttpServletResponse response) {
不打印响应报⽂
@RequestMapping(value = "/testdown", method = RequestMethod.GET)
@PrintControllerLog(notPrintResponse = true)
public Result downloadFile(HttpServletResponse response) {
都不打印
@PrintControllerLog(notPrintResponse = true,notPrintRequest = true)
配置keyword
@RequestMapping(value = "/testdown", method = RequestMethod.GET)
@PrintControllerLog(keyword = "zxp")
public Result downloadFile(HttpServletResponse response) {
输出
2020-12-22 16:15:08.474 INFO 9920 --- [nio-9600-exec-8] p.DefaltControllerPrintInputOutputAcpect : xxxx_cloud_aop_response: {
"ipaddr":"127.0.0.1:9600",
"url":"/testcfg4",
"method":"biz.stcfg4",
"responseTime":"2020-12-22 16:15:08",
"response":"{\"code\":200,\"msg\":\"\"}",
"rt":4,
"keyword":"zxp",
"sn":"1608624908470_58"
}
配置pretty
可以配置输出是否格式化json,默认格式化
@PrintControllerLog(pretty = false)
2020-12-22 17:02:07.922 INFO 13516 --- [nio-9600-exec-1] p.DefaltControllerPrintInputOutputAcpect : xxxx_cloud_aop_response: {
"ipaddr":"127.0.0.1:9600",
"url":"/dict/batchcode",
"method":"biz.BatchCode",
"authorization":"Bearer 02c28b9e-e554-453d-836d-0968f9c48e3c",
"responseTime":"2020-12-22 17:02:07",
"rt":287,
"keyword":"",
"sn":"1608627727565_70",
"response":{
"code":200,
"data":{
"opLogLevel":{
"1":"提⽰",
"2":"警告",
"3":"严重",
"4":"致命"
}
},
"msg":""
}
}
关键实现思路
1. 切⾯切RestController,且可以限定包名
2. 通过ThreadLocal实现rt计算以及sn,并在完成计算后remove ThreadLocal
3. 可以根据PrintControllerLog做⼀些更灵活的配置
注解PrintControllerLog
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface PrintControllerLog {
//是否美化json输出
public boolean pretty() default true;
//是否打印请求
public boolean notPrintRequest() default false;
//是否打印返回
public boolean notPrintResponse() default false;
//斌哥提的需求,设置keyword⽅便统⼀查
public String keyword() default "";
}
切⾯类DefaltControllerPrintInputOutputAcpect实现@Aspect
@Component
@Slf4j
public class DefaltControllerPrintInputOutputAcpect {
private ThreadLocal<PrintRunnerInfo> SN_CONTEXT = new ThreadLocal<>();
/**
* XXX包下的切⾯
*/
@Pointcut("within(com.XXX..*)")
public void anController0() {
}
/**
* 加了RestController注解的切⾯
*/
@Pointcut("@within(org.springframework.web.bind.annotation.RestController)")
public void anController99() {
}
@Before("anController99() && anController0()")
public void before(JoinPoint joinPoint) {
try{
printBaseAndRequest(joinPoint);
}catch (Exception e){ }
}
@AfterReturning(returning = "ret",pointcut="anController99() && anController0()")
public void after(JoinPoint joinPoint,Object ret){
try{
printResponse(ret,joinPoint);
}catch (Exception e){ }
}
/**
* 执⾏前打印
* @param joinPoint
*/
public void printBaseAndRequest(JoinPoint joinPoint) {
PrintReqInfo printReqInfo = new PrintReqInfo();
//设置开始时间
printReqInfo.setRequestTime(genNow());
//获取⼀个sn,并对TL中的执⾏情况对象做相应设置
printReqInfo.setSn(getAndSetupSn());
// 设定⽅法路径
printReqInfo.setMethod(getMethod(joinPoint));
// 取配置
MethodSignature methodSignature = (MethodSignature) Signature();
PrintControllerLog printControllerLog = Method().getAnnotation(PrintControllerLog.class); PrintCfgInfo printCfgInfo = getCfg(printControllerLog);
printReqInfo.Keyword());
//设置url
printReqInfo.setUrl(getUrl());
//设置Authorization
printReqInfo.setAuthorization(getAuthorization());
//设置IpAddr
printReqInfo.setIpaddr(getIpAddr());
//设置请求参数
fillPrintReqInfo(joinPoint,PrintRequest);
//打印请求参数
if (!printCfgInfo.isNotPrintRequest()) {
if(printCfgInfo.isPretty()){
log.info("xxxx_cloud_aop_request: {}", JSONString(printReqInfo,true));
}else{
log.info("xxxx_cloud_aop_request: {}", JSONString(printReqInfo));
}
}
}
/**
mvc的controller* 获取配置
* @param printControllerLog
* @return
*/
private PrintCfgInfo getCfg(PrintControllerLog printControllerLog){
PrintCfgInfo printCfgInfo = new PrintCfgInfo();
if (printControllerLog != null) {
printCfgInfo.setKeyword(printControllerLog.keyword());
printCfgInfo.PrintRequest());
printCfgInfo.PrintResponse());
printCfgInfo.setPretty(printControllerLog.pretty());
}else{
printCfgInfo.setKeyword("");
printCfgInfo.setNotPrintRequest(false);
printCfgInfo.setNotPrintResponse(false);
printCfgInfo.setPretty(true);
}
return printCfgInfo;
}
/**
* 执⾏后打印
* @param joinPoint
*/
public void printResponse(Object ret,JoinPoint joinPoint) {
PrintResInfo printResInfo = new PrintResInfo();
/
/设置开始时间
printResInfo.setResponseTime(genNow());
//获取⼀个sn,并对TL中的执⾏情况对象做相应设置
printResInfo.setSn(getAndSetupSn());
//设置rt
printResInfo.setRt(getRt());
//清理TL
cleanTL();
// 设定⽅法路径
printResInfo.setMethod(getMethod(joinPoint));
// 取配置
MethodSignature methodSignature = (MethodSignature) Signature();
PrintControllerLog printControllerLog = Method().getAnnotation(PrintControllerLog.class); PrintCfgInfo printCfgInfo = getCfg(printControllerLog);
printResInfo.Keyword());
//设置url
printResInfo.setUrl(getUrl());
//设置Authorization
printResInfo.setAuthorization(getAuthorization());
//设置IpAddr
printResInfo.setIpaddr(getIpAddr());
//设置返回参数
fillPrintResInfo(ret,PrintResponse);
//打印返回结果
if (!printCfgInfo.isNotPrintResponse()) {
if(printCfgInfo.isPretty()) {
log.info("xxxx_cloud_aop_response: {}", JSONString(printResInfo, true));
}else{
log.info("xxxx_cloud_aop_response: {}", JSONString(printResInfo));
}
}
}
/**
* 填充剩余信息
* @param joinPoint
* @param printReqInfo
* @param notPrintReq
*/
private void fillPrintReqInfo(JoinPoint joinPoint,PrintReqInfo printReqInfo,boolean notPrintReq){
Object[] args = Args();
if(args != null && args.length > 0 ) {
List<Object> objects = Arrays.asList(args).stream().filter(s -> !isFile(s)).List());
if (objects != null && objects.size() > 0 && !notPrintReq) {
try {
printReqInfo.setRequest(args);
}catch(Exception e){}
}
}
}
/**
* 填充剩余信息
* @param ret
* @param printResInfo
* @param notPrintRes
*/
private void fillPrintResInfo(Object ret,PrintResInfo printResInfo,boolean notPrintRes){
if (ret != null && !notPrintRes) {
try {
printResInfo.setResponse(ret);
}catch(Exception e){}
}
}
private boolean isFile(Object obj){
if(obj instanceof MultipartFile){
return true;
}
return false;
}
/**
* 获取⼀个sn,并对TL中的执⾏情况对象做相应设置
* 当第⼆次执⾏TL中已经有相应信息
* 此sn不能保证唯⼀,为了对应打印⽇志的请求和响应
* @return
*/
private String getAndSetupSn(){
if(() != null && !StringUtils.isEmpty(().getSn())){
().setEnd(System.currentTimeMillis());
().setRt(().getEnd()-().getStart());
return ().getSn();
}else{
String sn = System.currentTimeMillis()+"_"+new Random().nextInt(100);
SN_CONTEXT.set(PrintRunnerInfo.builder().sn(sn).start(System.currentTimeMillis()).build());
return sn;
}
}
/**
* 获取rt
* @return
*/
private Long getRt(){
if(() != null){
return ().getRt();
}else{
return 0L;
}
}
/**
* 清楚TL
*/
private void cleanTL(){
ve();
}
private String genNow(){
return DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").w());
}
/**
* 获取当前请求的url
* @return
*/
private String getUrl(){
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestAttributes(); HttpServletRequest request = Request();
String requestURL = RequestURI();
return requestURL;
}
/**
* 获取当前请求的Authorization
* @return
*/
private String getAuthorization(){
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) Re
questAttributes(); HttpServletRequest request = Request();
Header("Authorization");
}
/**
* 获取IpAddr
* @return
*/
private String getIpAddr(){
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestAttributes(); HttpServletRequest request = Request();
// 取得服务器IP
String ip = LocalAddr();
// 取得服务器端⼝
int port = LocalPort();
return ip+":"+port;
}
/**
* 获得⽅法名称
* @param joinPoint
* @return
*/
private String getMethod(JoinPoint joinPoint){
String method = "";
try{
MethodSignature methodSignature = (MethodSignature) Signature();
String methodPackage = DeclaringTypeName();
method = methodPackage;
Method() != null){
method+="."+Method().getName();
}
return method;
}catch (Exception e){
return method;
}
}
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论