OncePerRequestFilter 是Spring框架提供的一個過濾器類別,用於實現一次請求僅執行一次過濾的功能。這個過濾器可以在需要保證過濾器只執行一次的情況下使用。
使用 OncePerRequestFilter 需要繼承這個類別,並實現其中的 doFilterInternal() 方法。在 doFilterInternal() 方法中可以定義需要執行的過濾邏輯。
以下是一個簡單的 OncePerRequestFilter 範例:
```java
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
@Order(1)
@Component
public class MyFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
// 在這裡實現過濾邏輯
// 呼叫 filterChain.doFilter() 繼續執行過濾器鏈
filterChain.doFilter(request, response);
}
}
```
如果希望在某些條件下不執行過濾器,可以在 MyFilter 中重寫 shouldNotFilter() 方法,該方法返回 true 則表示不執行過濾器:
```java
@Override
protected boolean shouldNotFilter(HttpServletRequest request) {
// 在這裡判斷是否不執行過濾器的條件
return true;
}
```
通過使用 OncePerRequestFilter,可以確保過濾器在一次請求中只執行一次,並且還可以根據不同的條件來控制過濾器的執行。
### [Spring 攔截處理器](https://www.tpisoftware.com/tpu/articleDetails/1929)
Filter
```java
@WebFilter(filterName = "RequestFilter", urlPatterns = "/book")
public class RequestFilter implements Filter {
private static final Logger LOGGER = LoggerFactory.getLogger(RequestFilter.class);
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
LOGGER.info("Request do filter ...");
chain.doFilter(request, response);
}
}
```
Interceptor
```java
@Component
public class DemoInterceptor implements HandlerInterceptor {
private static final Logger LOGGER = LoggerFactory.getLogger(DemoInterceptor.class);
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
LOGGER.info("Interceptor do preHandle ...");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
LOGGER.info("Interceptor do postHandle ...");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
LOGGER.info("Interceptor do afterCompletion ...");
}
}
```
### AOP
```java
@Aspect
@Order(1)
@Component
public class ControllerAspect {
private static final Logger LOGGER = LoggerFactory.getLogger(ControllerAspect.class);
@Around(value = "within(@org.springframework.web.bind.annotation.RestController *)")
public Object controllerAround(ProceedingJoinPoint jp) throws Throwable {
LOGGER.info("Aop do controller around before method ...");
Object result = jp.proceed();
LOGGER.info("Aop do controller around after method ...");
return result;
}
@Pointcut("execution(* com.example.api.*.*(..))") // 替換成你的API包名和方法
public void apiMethods() {}
@Before("apiMethods()")
public void beforeApiMethod(JoinPoint joinPoint) {
}
}
```
@Around 注解用於定義環繞增強方法,即在目標方法執行前後都執行的方法。使用 @Around 可以完全控制目標方法的執行,可以在目標方法執行之前進行一些前置處理,並在執行之後進行後置處理。在 @Around 注解的方法內部,你可以通過調用 ProceedingJoinPoint.proceed() 方法來執行目標方法。
@Pointcut 注解應用於一個方法上,該方法的內容可以是一個切點表達式,也可以是一個命名的切點,以便在其他切面中引用。使用 @Pointcut 可以將切點的定義集中在一個地方,以便在不同的切面中重複使用。
@Before 注解用於定義在目標方法執行之前應該執行的增強方法。當目標方法被調用之前,@Before 指定的方法將被執行。這種增強方法通常用於進行一些前置處理操作。
* execution(* com.example.service.*.*(..)): 匹配 com.example.service 包中的所有類的任意方法。
* execution(public * com.example.service.UserService.*(..)): 匹配 com.example.service.UserService 類中的所有公開方法。
* execution(* save*(..)): 匹配方法名以 "save" 開頭的所有方法。
* within(com.example.repository.*): 匹配 com.example.repository 包中的所有方法。
* args(java.lang.String): 匹配接受一個 String 參數的方法。
* @annotation(org.springframework.web.bind.annotation.GetMapping): 匹配標註有 @GetMapping 註解的方法。