介紹
在項目中,如果需要在 Header 中擷取請求頭,一般使用 RequestHeader 注解。代碼案例如下:
@RequestMapping("/normalHeaders")
public Map<String, Object> normalHeaders(@RequestHeader("user-id")Long userId,
@RequestHeader("tenant-id")Long tenantId,
@RequestHeader("user-name")String userName){
Map<String, Object> map = new HashMap<>();
map.put("userId", userId);
map.put("tenantId", tenantId);
map.put("userName", userName);
return map;
}
請求curl
curl -X POST \
http://127.0.0.1:8080/normalHeaders \
-H 'tenant-id: 12' \
-H 'user-id: 1' \
-H 'user-name: buger'
使用 RequestHeader 注解擷取請求頭,如果擷取一兩個到不會寫很多重複代碼,但是如果需要擷取很多個請求時,代碼會變得重複。 下面介紹一種新的解決方案;不但減少了很多重複的代碼,而且使得代碼變得更簡潔。
pom.xml 檔案引入依賴
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.olive</groupId>
<artifactId>springmvc-headers</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>springmvc-headers</name>
<url>http://maven.apache.org</url>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.14</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
</project>
解析請求頭,并包裝
實作 HandlerMethodArgumentResolver 類;解析請求頭,包裝成 HeadersWrapperDTO 類
package com.olive.config;
import com.olive.dto.HeadersWrapperDTO;
import org.springframework.core.MethodParameter;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;
public class RequestHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver {
@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.getParameterType().isAssignableFrom(HeadersWrapperDTO.class);
}
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest,
WebDataBinderFactory binderFactory) throws Exception {
String userId = webRequest.getHeader("user-id");
String tenantId = webRequest.getHeader("tenant-id");
String userName = webRequest.getHeader("user-name");
HeadersWrapperDTO headersWrapperDTO = new HeadersWrapperDTO();
if(StringUtils.hasText(userId)){
headersWrapperDTO.setUserId(Long.parseLong(userId));
}
if(StringUtils.hasText(tenantId)){
headersWrapperDTO.setTenantId(Long.parseLong(tenantId));
}
headersWrapperDTO.setUserName(userName);
return headersWrapperDTO;
}
}
HeadersWrapperDTO POJO類
package com.olive.dto;
import lombok.Data;
import java.io.Serializable;
@Data
public class HeadersWrapperDTO implements Serializable {
private Long userId;
private Long tenantId;
private String userName;
}
注冊 RequestHandlerMethodArgumentResolver 到 Controller 參數解析器裡,即添加自己的參數解析器
package com.olive.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.util.List;
@Configuration
public class MethodArgumentResolverConfig {
@Bean
public WebMvcConfigurer getWebMvcConfigurer() {
return new WebMvcConfigurer() {
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
resolvers.add(new RequestHandlerMethodArgumentResolver());
}
};
}
}
測試
編碼 Springboot 啟動引導類
package com.olive;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class);
}
}
編寫測試 Controller
package com.olive.controller;
import java.util.HashMap;
import java.util.Map;
import com.olive.dto.HeadersWrapperDTO;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class TestController {
@RequestMapping("/normalHeaders")
public Map<String, Object> normalHeaders(@RequestHeader("user-id")Long userId,
@RequestHeader("tenant-id")Long tenantId,
@RequestHeader("user-name")String userName){
Map<String, Object> map = new HashMap<>();
map.put("userId", userId);
map.put("tenantId", tenantId);
map.put("userName", userName);
return map;
}
@RequestMapping("/wrapperHeaders")
public Map<String, Object> wrapperHeaders(HeadersWrapperDTO headers){
Map<String, Object> map = new HashMap<>();
map.put("userId", headers.getUserId());
map.put("tenantId", headers.getTenantId());
map.put("userName", headers.getUserName());
return map;
}
}
測試curl
curl -X POST \
http://127.0.0.1:8080/wrapperHeaders \
-H 'tenant-id: 12' \
-H 'user-id: 1' \
-H 'user-name: buger'
通過 RequestHandlerMethodArgumentResolver 可以對請求頭進行解析并封裝到 HeadersWrapperDTO 類中,這樣減少了在 Controller 使用大量的 RequestHeader 注解擷取請求頭。