亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

我可以強制要求在 Spring 中至少包含兩個標頭之一嗎?

我可以強制要求在 Spring 中至少包含兩個標頭之一嗎?

蝴蝶不菲 2023-06-04 17:40:07
我的一個標題拼寫錯誤,我想在向后兼容的同時更改它。@RequestHeader(value = "Custmer-Key") String customerKey我想添加一個拼寫正確的標題Customer-Key,并至少強制其中一個。有任何想法嗎?
查看完整描述

3 回答

?
慕的地8271018

TA貢獻1796條經驗 獲得超4個贊

我會在這里做一些假設。在您的具體情況下,每一個都可能正確,也可能不正確,但目的是提供更好的背景信息,說明此類解決方案何時可行并且使用起來有意義。

  1. 你需要保持向后兼容性(這個很簡單......你寫的)

  2. 您有一個相當大的代碼庫,可能基于微服務并由多個開發人員維護,并且您希望避免跨越多個團隊的大量提交,將修復集中在一個所有服務都打算使用的公共共享庫中

  3. 您的標頭不僅使用 Spring 獲取,有時還通過直接訪問請求來獲取

  4. 你在一個生產應用程序中工作,你希望盡可能少地更改代碼,因為它的一些內部工作很難理解

該解決方案包括連接自定義過濾器及其配置。過濾器會將HttpServletRequest實例與另一個允許操作標頭的實例交換。


首先,創建自己的過濾器,如下所示:

import org.springframework.context.annotation.Configuration;

import org.springframework.core.Ordered;

import org.springframework.core.annotation.Order;


import javax.servlet.*;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletRequestWrapper;

import javax.servlet.http.HttpServletResponse;

import java.io.IOException;

import java.util.*;


@Configuration

@Order(Ordered.HIGHEST_PRECEDENCE)

public class HeadersFilter implements Filter {


    private static final String WRONG_HEADER = "Custmer-Key";

    private static final String RIGHT_HEADER = "Customer-Key";


    @Override

    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {


        HttpServletRequest request = (HttpServletRequest) servletRequest;

        HttpServletResponse response = (HttpServletResponse) servletResponse;


        String newHeaderValue = request.getHeader(RIGHT_HEADER);

        String headerValue;

        if(newHeaderValue != null) {

            headerValue = newHeaderValue;

        }

        else {

            headerValue = request.getHeader(WRONG_HEADER);

        }


        HeadersRewriteHttpServletRequestWrapper requestWrapper = new HeadersRewriteHttpServletRequestWrapper(request);

        requestWrapper.setCustomHeader(WRONG_HEADER, headerValue);


        filterChain.doFilter(requestWrapper, response);

    }


    public static class HeadersRewriteHttpServletRequestWrapper extends HttpServletRequestWrapper {


        private Map<String, String> customHeaders;


        HeadersRewriteHttpServletRequestWrapper(HttpServletRequest request) {

            super(request);

            customHeaders = new HashMap<>();

        }


        void setCustomHeader(String name, String value) {

            customHeaders.put(name, value);

        }


        private String getCustomHeader(String name) {

            return customHeaders.get(name);

        }


        @Override

        public String getHeader(String name) { // not needed by spring but useful if someone uses this method directly

            String header = super.getHeader(name);

            if(header != null) {

                return header;

            }

            return getCustomHeader(name);

        }


        @Override

        public Enumeration<String> getHeaderNames() {

            Set<String> names = new HashSet<>(Collections.list(super.getHeaderNames()));

            names.addAll(customHeaders.keySet());

            return Collections.enumeration(names);

        }


        @Override

        public Enumeration<String> getHeaders(String name) {

            List<String> headers = Collections.list(super.getHeaders(name));

            String customHeader = getCustomHeader(name);

            if(headers.isEmpty() && customHeader != null) {

                headers.add(customHeader);

            }

            return Collections.enumeration(headers);

        }

    }

}

其次,連接 Spring 配置以創建此過濾器的實例并在必要時注入它。


import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;


@Configuration

public class FilterConfiguration {

    @Bean

    public HeadersFilter headersFilterBean() {

        return new HeadersFilter();

    }

}

就是這樣。Customer-Key假設您的應用程序沒有阻止它工作的怪癖(在這種情況下祝您調試順利),此代碼將采用和的內容,優先考慮Custmer-Key并將Customer-Key它們寫入假Custmer-Key標頭中。這樣你就不必觸摸任何控制器,它們應該繼續透明地工作。


查看完整回答
反對 回復 2023-06-04
?
人到中年有點甜

TA貢獻1895條經驗 獲得超7個贊

下一個方法是創建一個注釋 OneOf 或其他東西。我使用了一種比使用 Aspect 更簡單的方法。使用這種方法,您可以驗證請求參數、Requestbody 和 RequestHeader


@Target({TYPE, ANNOTATION_TYPE})

@Retention(RUNTIME)

@Constraint(validatedBy = OneOfValidator.class)

@Documented

public @interface OneOf {


    String message() default "";

    String[] value();

}

創建如下所示的驗證器類。


public class OneOfValidator implements ConstraintValidator<OneOf, Object> {


    private String[] fields;

    private String fieldList;


    public void initialize(OneOf annotation) {

        this.fields = annotation.value();

        fieldList = Arrays.toString(fields);

    }


    public boolean isValid(Object value, ConstraintValidatorContext context) {


        BeanWrapper wrapper = PropertyAccessorFactory.forBeanPropertyAccess(value);

        int matches = countNumberOfMatches(wrapper);

        if (matches > 1) {

            setErrorMessage(context, <your message>);

            return false;

        } else if (matches == 0) {

            setErrorMessage(context, <your message>);

            return false;

        }


        return true;

    }


    private int countNumberOfMatches(BeanWrapper wrapper) {

        int matches = 0;

        for (String field : fields) {

            Object value = wrapper.getPropertyValue(field);

            boolean isPresent = detectOptionalValue(value);


            if (value != null && isPresent) {

                matches++;

            }

        }

        return matches;

    }


    private boolean detectOptionalValue(Object value) {

        if (value instanceof Optional) {

            return ((Optional)value).isPresent();

        }

        if (value instanceof String) {

            return StringUtils.hasText((String)value);

        }

        return true;

    }

    private void setErrorMessage(ConstraintValidatorContext context, String template) {

        context.disableDefaultConstraintViolation();

        context

                .buildConstraintViolationWithTemplate(template)

                .addNode(fieldList)

                .addConstraintViolation();

    }


在控制器中,您可以創建如下所示的內容。


    @GetMapping(value = "your path")

    public ResponseEntity<HeaderDataDTO> getBuildDetails(@RequestHeader(value = "Custmer-Key") String custmerKey,@RequestHeader(value = "Customer-Key") String customerKey

            ) {

        HeaderDataDTO data = new HeaderDataDTO();

data.setCustomerKey(customerKey);

data.setCustmerKey(custmerKey);

data.validate();

        return new ResponseEntity<>(data,

                HttpStatus.OK);

    }

您可以如下定義 DTO。


@Valid

@OneOf(value = {"customerKey", "custmerKey"})

public class HeaderDataDTO extends HeaderValidator {


    private String customerKey;

    private String custmerKey;

//getter and setter

HeaderValidator 應該如下所示。Validate 方法將驗證對象。


import org.springframework.util.CollectionUtils;

import javax.validation.ConstraintViolation;

import javax.validation.Valid;

import javax.validation.Validation;

import javax.validation.Validator;


public abstract class HeaderValidator {


    public boolean validate() {

        Validator validator = Validation

                .buildDefaultValidatorFactory()

                .getValidator();

        Set<ConstraintViolation<HeaderValidator>> violations = validator.validate(this);

        if (!CollectionUtils.isEmpty(violations)) {

            throw <your exception>

        }

        return true;

    }


查看完整回答
反對 回復 2023-06-04
?
小唯快跑啊

TA貢獻1863條經驗 獲得超2個贊

您可以像下面這樣創建一個攔截器。


@Component

@Primary

public class HeadersInterceptor extends HandlerInterceptorAdapter {


    public boolean preHandle(HttpServletRequest request,

            HttpServletResponse response,

            Object handler) throws Exception {

            HttpInputMessage inputMessage=new ServletServerHttpRequest(request);          

HttpHeaders httpHeaders = inputMessage.getHeaders();

//validation code for header goes here.

//return true if validation is successful    

return true;


    }

 }

并將攔截器添加到您的配置中。


 @Configuration

public class InterceptorConfig implements WebMvcConfigurer {


    @Autowired

    HeadersInterceptor headersInterceptor;


    public void addInterceptors(InterceptorRegistry registry) {


        registry.addInterceptor(headersInterceptor);

    }

}`

現在您可以以任何方式自定義您的驗證。


查看完整回答
反對 回復 2023-06-04
  • 3 回答
  • 0 關注
  • 178 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號