【问题标题】:Is there any option to add a default value to all @RequestHeaders in spring boot?是否有任何选项可以在 Spring Boot 中为所有 @RequestHeaders 添加默认值?
【发布时间】:2021-03-08 00:56:24
【问题描述】:

是否有任何选项可以在 Spring Boot 中为所有 @RequestHeader 添加默认值?

@RequestHeader(value = "User-Accept-Language", defaultValue = "en-IN") String localeCd

我正在复制/粘贴到所有 API。避免代码重复的任何帮助!

【问题讨论】:

  • 你可以使用过滤器

标签: java spring spring-boot header request-headers


【解决方案1】:

这是一个关于如何使用 spring WebFlux 为 header 提供默认值的示例

@Component
public class CorrelationIdFilter implements WebFilter {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
        var correlationId = exchange.getRequest().getHeaders().getFirst(CORRELATION_ID_HEADER);
        if (correlationId == null || correlationId.isEmpty()) {
            correlationId = UUID.randomUUID().toString();
            ServerHttpRequest mutatedRequest = exchange.getRequest()
                    .mutate()
                    .header(CORRELATION_ID_HEADER, correlationId)
                    .build();
            exchange = exchange
                    .mutate()
                    .request(mutatedRequest)
                    .build();
        }
        exchange.getResponse().getHeaders().add(CORRELATION_ID_HEADER, correlationId);
        return chain.filter(exchange);
    }
}

这是针对 Spring web 的

@Component
public class CorrelationIdFilter implements Filter {

    static final String CORRELATION_ID_HEADER = "X-Correlation-ID";

    @Override
    public void init(FilterConfig filterConfig) {
        // empty
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {

        HttpServletRequest httpRequest = (HttpServletRequest) request;
        String correlationId = httpRequest.getHeader(CORRELATION_ID_HEADER);
        if (correlationId == null) {
           correlationId = XidFactory.nextXid();
           ((HttpServletResponse) response).addHeader(CORRELATION_ID_HEADER, correlationId);
        }
        
        chain.doFilter(request, response);
    }

    @Override
    public void destroy() {
        // empty
    }
}

【讨论】:

  • 如果已经有标头,最好使用OncePerRequestFilter并跳过过滤
  • 我收到[org.springframework.web.bind.MissingRequestHeaderException: Missing request header 'User-Accept-Language' for method parameter of type String] 异常
  • 检查过滤器是否被执行。如果您有该错误,则很可能不会执行过滤器。您也可以遵循@EugeneMakarenko 的建议,您可以将此过滤器转换为 OncePerRequestFilter。为此,您所要做的就是从 OncePerRequestFilter 扩展您的过滤器并实现方法 doFilterInternal
【解决方案2】:

我没有发现任何已经为添加带有值的标头的注释所做的任何事情,所以我自己做了。下面是代码,很简单,我是用spring AOP做的

  1. 我创建了注释类

    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.METHOD)
    public @interface ResponseHeader {
    
        public String key() default "";
    
        public String value() default "";
    }
    

    还有一个用于包含一组标头注释的

    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.METHOD)
    public @interface ResponseHeaders {
    
        public ResponseHeader[] headers();
    }
    
  2. 用于捕获 restControllers 的 AOP 类(您可以自定义 AOP 以根据需要设置自己的切入点:

    import YOUR_PACKAGE_ANNOTATION.ResponseHeaders;
    import org.aspectj.lang.annotation.After;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Pointcut;
    import org.springframework.stereotype.Component;
    import org.springframework.web.context.request.RequestContextHolder;
    import org.springframework.web.context.request.ServletRequestAttributes;
    
    import javax.servlet.http.HttpServletResponse;
    import java.util.List;
    
    /**
     * Aspect for inserting headers on the methods of the @RestController         
     annotated classes
     */
     @Aspect
     @Component
     public class ResponseHeadersAnnotation {
    
     /**
     * Pointcut for filtering just classes with @RestController annotation
     */
    @Pointcut("@within(org.springframework.web.bind.annotation.RestController)")
    public void restControllerClass() {
    }
    
    /**
     * It adds the headers to the response of the method of the controller
     *
     * @param responseHeaders
     */
    @After("restControllerClass() && @annotation(responseHeaders)")
    public void addHeaders(final ResponseHeaders responseHeaders) {
        final HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
        List.of(responseHeaders.headers()).forEach(responseHeader -> response.setHeader(responseHeader.key(), responseHeader.value()));
     }
    }
    
  3. 这是一个如何在控制器中使用它的示例:

    @GetMapping(value = {"/ServiceTicketCollection", "/ServiceRequestCollection"})
    @ResponseHeaders(headers = {
            @ResponseHeader(key = "cookie1", value = "value1"),
            @ResponseHeader(key = "cookie2, value = "value2")
    })
    public Object restControllerMethod() {
        ...
    }
    

【讨论】:

    猜你喜欢
    • 2020-02-20
    • 2021-08-03
    • 1970-01-01
    • 2017-05-11
    • 2023-04-05
    • 2020-03-24
    • 2021-02-18
    • 2019-04-05
    • 1970-01-01
    相关资源
    最近更新 更多