拦截器
java
import org.springframework.web.servlet.HandlerInterceptor;
/**
* MVC 拦截器 for 汉服换脸
*/
@Component
@Slf4j
public class ApiSignInterceptorForHanfu implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
...
以上是一个MVC拦截器的声明,org.springframework.web.servlet.config.annotation.WebMvcConfigurer的路径拦截配置(如下)也没有问题。奇怪的是,用上面的拦截器拦截非流式方法时,这拦截器的com.zju.design.config.ApiSignInterceptorForHanfu#preHandle方法只会运行一次,如果用它拦截流式方法,则preHandle方法会运行两次,其中第二次是Controller方法运行结束后。注:此项目同时有SpringMVC和spring webflux依赖。
java
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Resource
private ApiSignInterceptorForHanfu apiSignInterceptorForHanfu;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(apiSignInterceptorForHanfu).addPathPatterns("/hanfu/generating/**");
}
-
豆包的解释:

-
Q: 有没有与MVC 拦截器对应的webflux拦截器,我用它来拦截流式方法,使拦截器的关键代码只运行一次?
A:据说在spring webflux环境中,可以使用org.springframework.web.reactive.function.server.HandlerFilterFunction + org.springframework.web.reactive.config.WebFluxConfigurer
过滤器
若项目存在 spring-boot-starter-web 依赖(MVC 核心),且没有 spring-boot-starter-webflux依赖,则项目是 MVC 环境,WebFlux过滤器(WebFilter)必然不生效,只会生效 MVC的过滤器;
若两者都存在,Spring 会默认使用 MVC 容器(Tomcat),WebFlux 过滤器也不会生效。
我的SpringMVC过滤器:
java
/**
* MVC 过滤器
*/
@Component
@Slf4j
public class HttpParameterFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
String requestURI = request.getRequestURI();
filterChain.doFilter(request, response);
}
。。。
豆包的解释: https://www.doubao.com/thread/w70fcca28c363d4d2
下面是一个WebFlux 过滤器实例:
java
package com.zju.design.config;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;
/**
* WebFlux 过滤器(WebFilter)for 汉服换脸
*/
@Component
@Slf4j
public class ApiSignWebFilterForHanfu implements WebFilter {
public ApiSignWebFilterForHanfu() {
log.info("ApiSignWebFilterForHanfu init");
}
@Override
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
log.info("filter");
// 1. 放行 OPTIONS 预检请求(核心修改)
if ("OPTIONS".equalsIgnoreCase(exchange.getRequest().getMethod().name())) {
return chain.filter(exchange);
}
String path = exchange.getRequest().getPath().value();
if (!path.startsWith("/hanfu/generating/stream/swapFace")) {
log.info("filter no path:{}", path);
return chain.filter(exchange);
}
// 检查标志位,如果已经执行过,则直接放行. 为了回避重复执行
if (Boolean.TRUE.equals(exchange.getAttribute("checkSignExecuted"))) {
log.info("checkSignExecuted, skip");
return chain.filter(exchange);
}
// 设置标志位为 true
exchange.getAttributes().put("checkSignExecuted", Boolean.TRUE);
return chain.filter(exchange);
}
}