詳解AOP與Filter攔截請(qǐng)求打印日志實(shí)用例子
相信各位同道在寫(xiě)代碼的時(shí)候,肯定會(huì)寫(xiě)一些日志打印,因?yàn)檫@對(duì)往后的運(yùn)維而言,至關(guān)重要的。
那么我們請(qǐng)求一個(gè)restfull接口的時(shí)候,哪些信息是應(yīng)該被日志記錄的呢?
以下做了一個(gè)基本的簡(jiǎn)單例子,這里只是示例說(shuō)明基本常規(guī)實(shí)現(xiàn)記錄的信息,根據(jù)項(xiàng)目的真實(shí)情況選用:
1 . Http請(qǐng)求攔截器(Filter) : 從HttpServletRequest獲取基本的請(qǐng)求信息
import name.ealen.util.HttpUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* Created by EalenXie on 2018/9/7 15:56.
* Http請(qǐng)求攔截器,日志打印請(qǐng)求基本相關(guān)信息
*/
@Configuration
public class FilterConfiguration {
private static final Logger log = LoggerFactory.getLogger(FilterConfig.class);
@Bean
@Order(Integer.MIN_VALUE)
@Qualifier("filterRegistration")
public FilterRegistrationBean filterRegistration() {
FilterRegistrationBean<Filter> registration = new FilterRegistrationBean<>();
registration.setFilter(controllerFilter());
registration.addUrlPatterns("/*");
return registration;
}
private Filter controllerFilter() {
return new Filter() {
@Override
public void init(FilterConfig filterConfig) {
log.info("ControllerFilter init Success");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
String requestId = request.getHeader("Request-Id");
if (requestId == null) requestId = request.getRequestedSessionId();
System.out.println();
log.info("Http Request Request-Id : " + requestId);
log.info("Http Request Information : {\"URI\":\"" + request.getRequestURL() +
"\",\"RequestMethod\":\"" + request.getMethod() +
"\",\"ClientIp\":\"" + HttpUtil.getIpAddress(request) +
"\",\"Content-Type\":\"" + request.getContentType() +
"\"}");
chain.doFilter(request, response);
}
@Override
public void destroy() {
log.info("ControllerFilter destroy");
}
};
}
}
2 . Controller的攔截AOP : 獲取 請(qǐng)求的對(duì)象,請(qǐng)求參數(shù),返回?cái)?shù)據(jù),請(qǐng)求返回狀態(tài),內(nèi)部方法耗時(shí)。
import com.alibaba.fastjson.JSON;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.env.Environment;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
/**
* Created by EalenXie on 2018/9/7 14:19.
* AOP打印日志 : 請(qǐng)求的對(duì)象,請(qǐng)求參數(shù),返回?cái)?shù)據(jù),請(qǐng)求狀態(tài),內(nèi)部方法耗時(shí)
*/
@Aspect
@Component
public class ControllerInterceptor {
private static final Logger log = LoggerFactory.getLogger(ControllerInterceptor.class);
@Resource
private Environment environment;
@Around(value = "execution (* name.ealen.web.*.*(..))")
public Object processApiFacade(ProceedingJoinPoint pjp) {
String appName;
try {
appName = environment.getProperty("spring.application.name").toUpperCase();
} catch (Exception e) {
appName = "UNNAMED";
}
long startTime = System.currentTimeMillis();
String name = pjp.getTarget().getClass().getSimpleName();
String method = pjp.getSignature().getName();
Object result = null;
HttpStatus status = null;
try {
result = pjp.proceed();
log.info("RequestTarget : " + appName + "." + name + "." + method);
log.info("RequestParam : " + JSON.toJSON(pjp.getArgs()));
if (result instanceof ResponseEntity) {
status = ((ResponseEntity) result).getStatusCode();
} else {
status = HttpStatus.OK;
}
} catch (Throwable throwable) {
status = HttpStatus.INTERNAL_SERVER_ERROR;
result = new ResponseEntity<>("{\"Internal Server Error\" : \"" + throwable.getMessage() + "\"}", status);
throwable.printStackTrace();
} finally {
log.info("ResponseEntity : {" + "\"HttpStatus\":\"" + status.toString() + "\"" + ",\"ResponseBody\": " + JSON.toJSON(result) + "}");
log.info("Internal Method Cost Time: {}ms", System.currentTimeMillis() - startTime);
}
return result;
}
}
3 . 提供一個(gè)簡(jiǎn)單的restfull接口 :
package name.ealen.web;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* Created by EalenXie on 2018/9/7 14:24.
*/
@RestController
public class SayHelloController {
@RequestMapping("/sayHello")
public String sayHello() {
return "hello world";
}
@RequestMapping("/say")
public ResponseEntity<?> say(@RequestBody Object o) {
return new ResponseEntity<>(o, HttpStatus.OK);
}
}
4 . 使用Postman進(jìn)行基本測(cè)試 :

5 . 控制臺(tái)可以看到基本效果 :

以上只是關(guān)于Controller應(yīng)該記錄日志的一個(gè)簡(jiǎn)單的例子,完整代碼可見(jiàn) https://github.com/EalenXie/springboot-controller-logger
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Spring框架實(shí)現(xiàn)AOP添加日志記錄功能過(guò)程詳解
這篇文章主要介紹了Spring框架實(shí)現(xiàn)AOP添加日志記錄功能過(guò)程詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-12-12
Java將數(shù)字金額轉(zhuǎn)為大寫(xiě)中文金額
這篇文章主要為大家詳細(xì)介紹了Java將數(shù)字金額轉(zhuǎn)為大寫(xiě)中文金額,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-08-08
SpringMVC中@RequestMapping注解的實(shí)現(xiàn)
RequestMapping是一個(gè)用來(lái)處理請(qǐng)求地址映射的注解,本文主要介紹了SpringMVC中@RequestMapping注解的實(shí)現(xiàn),具有一定的參考價(jià)值,感興趣的可以了解一下2024-01-01
SpringBoot集成SQL?Server的詳細(xì)指南
SQL?Server是由Microsoft開(kāi)發(fā)和推廣的以客戶(hù)/服務(wù)器(c/s)模式訪問(wèn)、使用Transact-SQL語(yǔ)言的關(guān)系數(shù)據(jù)庫(kù)管理系統(tǒng)(DBMS),本文給大家介紹了Spring?Boot集成SQL?Server的詳細(xì)指南,需要的朋友可以參考下2024-11-11
出現(xiàn)次數(shù)超過(guò)一半(50%)的數(shù)
給出n個(gè)數(shù),需要我們找出出現(xiàn)次數(shù)超過(guò)一半的數(shù),下面小編給大家分享下我的實(shí)現(xiàn)思路及關(guān)鍵代碼,感興趣的朋友一起學(xué)習(xí)吧2016-07-07
MyBatis實(shí)現(xiàn)動(dòng)態(tài)SQL的實(shí)現(xiàn)方法
這篇文章主要介紹了MyBatis實(shí)現(xiàn)動(dòng)態(tài)SQL的實(shí)現(xiàn)方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-12-12
Java 前臺(tái)加后臺(tái)精品圖書(shū)管理系統(tǒng)的實(shí)現(xiàn)
相信每一個(gè)學(xué)生學(xué)編程的時(shí)候,應(yīng)該都會(huì)寫(xiě)一個(gè)小項(xiàng)目——圖書(shū)管理系統(tǒng)。為什么這么說(shuō)呢?我認(rèn)為一個(gè)學(xué)校的氛圍很大一部分可以從圖書(shū)館的氛圍看出來(lái),而圖書(shū)管理系統(tǒng)這個(gè)不大不小的項(xiàng)目,接觸的多,也比較熟悉,不會(huì)有陌生感,能夠練手,又有些難度,所以我的小項(xiàng)目也來(lái)了2021-11-11

