作者:zhrowable
https://www.jianshu.com/p/5f6abd08ee08
SpringMVC請求引數接收
其實一般的表單或者JSON資料的請求都是相對簡單的,一些復雜的處理主要包括URL路徑引數、檔案上傳、陣列或者串列型別資料等,
另外,關于引數型別中存在日期型別屬性(例如java.util.Date、java.sql.Date、java.time.LocalDate、java.time.LocalDateTime),決議的時候一般需要自定義實作的邏輯實作String->日期型別的轉換,
其實道理很簡單,日期相關的型別對于每個國家、每個時區甚至每個使用者來說認知都不一定相同,在演示一些例子主要用到下面的模特類:
@Datapublic class User {
private String name;
private Integer age;
private List<Contact> contacts;}@Datapublic class Contact {
private String name;
private String phone;
}
表單引數
非物件型別單個引數接收:
這種是最常用的表單引數提交,ContentType指定為application/x-www-form-urlencoded,也就是會進行URL編碼,

對應的控制器如下:
@PostMapping(value = "https://www.cnblogs.com/post")public String post(@RequestParam(name = "name") String name,
@RequestParam(name = "age") Integer age) {
String content = String.format("name = %s,age = %d", name, age);
log.info(content);
return content;
}
說實話,如果有毅力的話,所有的復雜引數的提交最終都可以轉化為多個單引數接收,不過這樣做會產生十分多冗余的代碼,而且可維護性比較低,這種情況下,用到的引數處理器是RequestParamMapMethodArgumentResolver,
物件型別引數接收:
我們接著寫一個介面用于提交用戶資訊,用到的是上面提到的模特類,主要包括用戶姓名、年齡和聯系人資訊串列,這個時候,我們目標的控制器最終編碼如下:
@PostMapping(value = "https://www.cnblogs.com/user")
public User saveUser(User user) {
log.info(user.toString());
return user;
}
我們還是指定ContentType為application/x-www-form-urlencoded,接著我們需要構造請求引數:

因為沒有使用注解,最終的引數處理器為ServletModelAttributeMethodProcessor,主要是把HttpServletRequest中的表單引數封裝到MutablePropertyValues實體中,再通過引數型別實體化(通過構造反射創建User實體),反射匹配屬性進行值的填充,
另外,請求復雜引數里面的串列屬性請求引數看起來比較奇葩,實際上和在.properties檔案中添加最終映射到Map型別的引數的寫法是一致的,那么,能不能把整個請求引數塞在一個欄位中提交呢?

直接這樣做是不行的,因為實際提交的form表單,key是user,value實際上是一個字串,缺少一個String->User型別的轉換器,實際上RequestParamMethodArgumentResolver依賴WebConversionService中Converter串列進行引數轉換:

解決辦法還是有的,添加一個org.springframework.core.convert.converter.Converter實作即可:
@Componentpublic class StringUserConverter implements Converter<String, User> {
private static final ObjectMapper MAPPER = new ObjectMapper();
@Override
public User convert(String source) {
try {
return MAPPER.readValue(source, User.class);
} catch (IOException e) {
throw new IllegalArgumentException(e);
}
}
}
上面這種做法屬于曲線救國的做法,不推薦使用在生產環境,但是如果有些第三方介面的對接無法避免這種引數,可以選擇這種實作方式,
JSON引數
一般來說,直接POST一個JSON字串這種方式對于SpringMVC來說是比較友好的,只需要把ContentType設定為application/json,提交一個原始的JSON字串即可:

Spring Boot 回傳 JSON 資料,一分鐘搞定!
后端控制器的代碼也比較簡單:
@PostMapping(value = "https://www.cnblogs.com/user-2")
public User saveUser2(@RequestBody User user) {
log.info(user.toString());
return user;
}
因為使用了@RequestBody注解,最終使用到的引數處理器為RequestResponseBodyMethodProcessor,實際上會用到MappingJackson2HttpMessageConverter進行引數型別的轉換,底層依賴到Jackson相關的包,
URL引數
URL引數,或者叫請求路徑引數是基于URL模板獲取到的引數,例如/user/{userId}是一個URL模板(URL模板中的引數占位符是{}),實際請求的URL為/user/1,那么通過匹配實際請求的URL和URL模板就能提取到userId為1,
在SpringMVC中,URL模板中的路徑引數叫做PathVariable,對應注解@PathVariable,對應的引數處理器為PathVariableMethodArgumentResolver,
注意一點是,@PathVariable的決議是按照value(name)屬性進行匹配,和URL引數的順序是無關的,舉個簡單的例子:

后臺的控制器如下:
@GetMapping(value = "https://www.cnblogs.com/user/{name}/{age}")
public String findUser1(@PathVariable(value = "https://www.cnblogs.com/javastack/p/age") Integer age, @PathVariable(value = "https://www.cnblogs.com/javastack/p/name") String name) {
String content = String.format("name = %s,age = %d", name, age);
log.info(content);
return content;
}
這種用法被廣泛使用于Representational State Transfer(REST)的軟體架構風格,個人覺得這種風格是比較靈活和清晰的(從URL和請求方法就能完全理解介面的意義和功能),下面再介紹兩種相對特殊的使用方式,
帶條件的URL引數
其實路徑引數支持正則運算式,例如我們在使用/sex/sex}介面的時候,要求sex必須是F(Female)或者M(Male),那么我們的URL模板可以定義為/sex/{sex:MF,代碼如下:
@GetMapping(value = "https://www.cnblogs.com/sex/{sex:M|F}")
public String findUser2(@PathVariable(value = "https://www.cnblogs.com/javastack/p/sex") String sex){
log.info(sex);
return sex;
}
只有/sex/F或者/sex/M的請求才會進入findUser2控制器方法,其他該路徑前綴的請求都是非法的,會回傳404狀態碼,這里僅僅是介紹了一個最簡單的URL引數正則運算式的使用方式,更強大的用法可以自行摸索,
@MatrixVariable的使用
MatrixVariable也是URL引數的一種,對應注解@MatrixVariable,不過它并不是URL中的一個值(這里的值指定是兩個"/"之間的部分),而是值的一部分,它通過";"進行分隔,通過"="進行K-V設定,
說起來有點抽象,舉個例子:假如我們需要打電話給一個名字為doge,性別是男,分組是碼畜的程式員,GET請求的URL可以表示為:/call/doge;gender=male;group=programmer,我們設計的控制器方法如下:
@GetMapping(value = "https://www.cnblogs.com/call/{name}")
public String find(@PathVariable(value = "https://www.cnblogs.com/javastack/p/name") String name,
@MatrixVariable(value = "https://www.cnblogs.com/javastack/p/gender") String gender,
@MatrixVariable(value = "https://www.cnblogs.com/javastack/p/group") String group) {
String content = String.format("name = %s,gender = %s,group = %s", name, gender, group);
log.info(content);
return content;
}
當然,如果你按照上面的例子寫好代碼,嘗試請求一下該介面發現是報錯的:400 Bad Request - Missing matrix variable 'gender' for method parameter of type String,
這是因為@MatrixVariable注解的使用是不安全的,在SpringMVC中默認是關閉對其支持,要開啟對@MatrixVariable的支持,需要設定RequestMappingHandlerMapping#setRemoveSemicolonContent方法為false:
@Configurationpublic class CustomMvcConfiguration implements InitializingBean {
@Autowired
private RequestMappingHandlerMapping requestMappingHandlerMapping;
@Override
public void afterPropertiesSet() throws Exception {
requestMappingHandlerMapping.setRemoveSemicolonContent(false);
}
}
除非有很特殊的需要,否則不建議使用@MatrixVariable,
檔案上傳
檔案上傳在使用POSTMAN模擬請求的時候需要選擇form-data,POST方式進行提交:

假設我們在D盤有一個圖片檔案叫doge.jpg,現在要通過本地服務介面把檔案上傳,控制器的代碼如下:
@PostMapping(value = "https://www.cnblogs.com/file1")
public String file1(@RequestPart(name = "file1") MultipartFile multipartFile) {
String content = String.format("name = %s,originName = %s,size = %d",
multipartFile.getName(), multipartFile.getOriginalFilename(), multipartFile.getSize());
log.info(content);
return content;
}
控制臺輸出是:
name = file1,originName = doge.jpg,size = 68727
可能有點疑惑,引數是怎么來的,我們可以用Fildder抓個包看下:

可知MultipartFile實體的主要屬性分別來自Content-Disposition、content-type和content-length,另外,InputStream用于讀取請求體的最后部分(檔案的位元組序列),引數處理器用到的是RequestPartM
ethodArgumentResolver(記住一點,使用了@RequestPart和MultipartFile一定是使用此引數處理器),
在其他情況下,使用@RequestParam和MultipartFile或者僅僅使用MultipartFile(引數的名字必須和POST表單中的Content-Disposition描述的name一致)也可以接收上傳的檔案資料,主要是通過RequestParamMethodArgumentResolver進行決議處理的,它的功能比較強大,具體可以看其supportsParameter方法,這兩種情況的控制器方法代碼如下:
@PostMapping(value = "https://www.cnblogs.com/file2")
public String file2(MultipartFile file1) {
String content = String.format("name = %s,originName = %s,size = %d",
file1.getName(), file1.getOriginalFilename(), file1.getSize());
log.info(content);
return content;}@PostMapping(value = "https://www.cnblogs.com/file3")
public String file3(@RequestParam(name = "file1") MultipartFile multipartFile) {
String content = String.format("name = %s,originName = %s,size = %d",
multipartFile.getName(), multipartFile.getOriginalFilename(), multipartFile.getSize());
log.info(content);
return content;
}
其他引數
其他引數主要包括請求頭、Cookie、Model、Map等相關引數,還有一些并不是很常用或者一些相對原生的屬性值獲取(例如HttpServletRequest、HttpServletResponse等)不做討論,
請求頭
請求頭的值主要通過@RequestHeader注解的引數獲取,引數處理器是RequestHeaderMethodArgumentResolver,需要在注解中指定請求頭的Key,簡單實用如下:

控制器方法代碼:
@PostMapping(value = "https://www.cnblogs.com/header")
public String header(@RequestHeader(name = "Content-Type") String contentType) {
return contentType;
}
Cookie
Cookie的值主要通過@CookieValue注解的引數獲取,引數處理器為ServletCookieValueMethodArgumentResolver,需要在注解中指定Cookie的Key,控制器方法代碼如下:
@PostMapping(value = "https://www.cnblogs.com/cookie")
public String cookie(@CookieValue(name = "JSESSIONID") String sessionId) {
return sessionId;
}
Model型別引數
Model型別引數的處理器是ModelMethodProcessor,實際上處理此引數是直接回傳ModelAndViewContainer實體中的Model(ModelMap型別),因為要橋接不同的介面和類的功能,因此回呼的實體是BindingAwareModelMap型別,此型別繼承自ModelMap同時實作了Model介面,舉個例子:
@GetMapping(value = "https://www.cnblogs.com/model")
public String model(Model model, ModelMap modelMap) {
log.info("{}", model == modelMap);
return "success";
}
注意呼叫此介面,控制臺輸出Info日志內容為:true,ModelMap或者Model中添加的屬性項會附加到HttpRequestServlet中帶到頁面中進行渲染,
@ModelAttribute引數
@ModelAttribute注解處理的引數處理器為ModelAttributeMethodProcessor,@ModelAttribute的功能原始碼的注釋如下:
Annotation that binds a method parameter or method return value to a named model attribute, exposed to a web view.
簡單來說,就是通過key-value形式系結方法引數或者方法回傳值到Model(Map)中,區別下面三種情況:
-
1、@ModelAttribute使用在方法(回傳值)上,方法沒有回傳值(void型別), Model(Map)引數需要自行設定,
-
2、@ModelAttribute使用在方法(回傳值)上,方法有回傳值(非void型別),回傳值會添加到Model(Map)引數,key由@ModelAttribute的value指定,否則會使用回傳值型別字串(首寫字母變為小寫),
-
3、@ModelAttribute使用在方法引數中,
在一個控制器(使用了@Controller)中,如果存在一到多個使用了@ModelAttribute的方法,這些方法總是在進入控制器方法之前執行,并且執行順序是由加載順序決定的(具體的順序是帶引數的優先,并且按照方法首字母升序排序),舉個例子:
@Slf4j
@RestController
public class ModelAttributeController {
@ModelAttribute
public void before(Model model) {
log.info("before..........");
model.addAttribute("before", "beforeValue");
}
@ModelAttribute(value = "https://www.cnblogs.com/javastack/p/beforeArg")
public String beforeArg() {
log.info("beforeArg..........");
return "beforeArgValue";
}
@GetMapping(value = "https://www.cnblogs.com/modelAttribute")
public String modelAttribute(Model model, @ModelAttribute(value = "https://www.cnblogs.com/javastack/p/beforeArg") String beforeArg) {
log.info("modelAttribute..........");
log.info("beforeArg..........{}", beforeArg);
log.info("{}", model);
return "success";
}
@ModelAttribute
public void after(Model model) {
log.info("after..........");
model.addAttribute("after", "afterValue");
}
@ModelAttribute(value = "https://www.cnblogs.com/javastack/p/afterArg")
public String afterArg() {
log.info("afterArg..........");
return "afterArgValue";
}
}
呼叫此介面,控制臺輸出日志如下:
after..........
before..........
afterArg..........
beforeArg..........
modelAttribute..........
beforeArg..........beforeArgValue
{after=afterValue, before=beforeValue, afterArg=afterArgValue, beforeArg=beforeArgValue}
可以印證排序規則和引數設定、獲取,
Errors或者BindingResult引數
Errors其實是BindingResult的父介面,BindingResult主要用于回呼JSR引數校驗例外的屬性項,如果JSR校驗例外,一般會拋出MethodArgumentNotValidException例外,并且會回傳400(Bad Request),見全域例外處理器DefaultHandlerExceptionResolver,Errors型別的引數處理器為ErrorsMethodArgumentResolver,舉個例子:
@PostMapping(value = "https://www.cnblogs.com/errors")
public String errors(@RequestBody @Validated ErrorsModel errors, BindingResult bindingResult) {
if (bindingResult.hasErrors()) {
for (ObjectError objectError : bindingResult.getAllErrors()) {
log.warn("name={},message={}", objectError.getObjectName(), objectError.getDefaultMessage());
}
}
return errors.toString();}//ErrorsModel@Data@NoArgsConstructorpublic class ErrorsModel {
@NotNull(message = "id must not be null!")
private Integer id;
@NotEmpty(message = "errors name must not be empty!")
private String name;
}
呼叫介面控制臺Warn日志如下:
name=errors,message=errors name must not be empty!
一般情況下,不建議用這種方式處理JSR校驗例外的屬性項,因為會涉及到大量的重復的硬編碼作業,建議直接繼承ResponseEntityExceptionHandler,覆寫對應的方法,
@Value引數
控制器方法的引數可以是@Value注解修飾的引數,會從Environment中裝配和轉換屬性值到對應的引數中(也就是引數的來源并不是請求體),引數處理器為ExpressionValueMethodArgumentResolver,舉個例子:
@GetMapping(value = "https://www.cnblogs.com/value")
public String value(@Value(value = "https://www.cnblogs.com/javastack/p/${spring.application.name}") String name) {
log.info("spring.application.name={}", name);
return name;
}
Map型別引數
Map型別引數的范圍相對比較廣,對應一系列的引數處理器,注意區別使用了上面提到的部分注解的Map型別和完全不使用注解的Map型別引數,兩者的處理方式不相同,下面列舉幾個相對典型的Map型別引數處理例子,
不使用任何注解的Map<String,Object>引數
這種情況下引數實際上直接回呼ModelAndViewContainer中的ModelMap實體,引數處理器為MapMethodProcessor,往Map引數中添加的屬性將會帶到頁面中,
使用@RequestParam注解的Map<String,Object>引數
這種情況下的引數處理器為RequestParamMapMethodArgumentResolver,使用的請求方式需要指定ContentType為x-www-form-urlencoded,不能使用application/json的方式:

控制器代碼為:
@PostMapping(value = "https://www.cnblogs.com/map")
public String mapArgs(@RequestParam Map<String, Object> map) {
log.info("{}", map);
return map.toString();
}
使用@RequestHeader注解的Map<String,Object>引數
這種情況下的引數處理器為RequestHeaderMapMethodArgumentResolver,作用是獲取請求的所有請求頭的Key-Value,
使用@PathVariable注解的Map<String,Object>引數
這種情況下的引數處理器為PathVariableMapMethodArgumentResolver,作用是獲取所有路徑引數封裝為Key-Value結構,
MultipartFile集合-批量檔案上傳
批量檔案上傳的時候,我們一般需要接收一個MultipartFile集合,可以有兩種選擇:
-
1、使用MultipartHttpServletRequest引數,直接呼叫
getFiles方法獲取MultipartFile串列, -
2、使用@RequestParam注解修飾MultipartFile串列,引數處理器是RequestParamMethodArgumentResolver,其實就是第一種的封裝而已,

控制器方法代碼如下:
@PostMapping(value = "https://www.cnblogs.com/parts")
public String partArgs(@RequestParam(name = "file") List<MultipartFile> parts) {
log.info("{}", parts);
return parts.toString();
}
日期型別引數處理
日期處理個人認為是請求引數處理中最復雜的,因為一般日期處理的邏輯不是通用的,過多的定制化處理導致很難有一個統一的標準處理邏輯去處理和轉換日期型別的引數,
不過,這里介紹幾個通用的方法,以應對各種奇葩的日期格式,下面介紹的例子中全部使用Jdk8中引入的日期時間API,圍繞java.util.Date為核心的日期時間API的使用方式類同,另外推薦大家關注下微信公眾號Java技術堆疊,在后臺回復Java可以獲取我整理的 N 篇 Java 8+ 教程,都是干貨,
一、統一以字串形式接收
這種是最原始但是最奏效的方式,統一以字串形式接收,然后自行處理型別轉換,下面給個小例子:
@PostMapping(value = "https://www.cnblogs.com/date1")
public String date1(@RequestBody UserDto userDto) {
UserEntity userEntity = new UserEntity();
userEntity.setUserId(userDto.getUserId());
userEntity.setBirthdayTime(LocalDateTime.parse(userDto.getBirthdayTime(), FORMATTER));
userEntity.setGraduationTime(LocalDateTime.parse(userDto.getGraduationTime(), FORMATTER));
log.info(userEntity.toString());
return "success";
}
@Datapublic class UserDto {
private String userId;
private String birthdayTime;
private String graduationTime;}@Datapublic class UserEntity {
private String userId;
private LocalDateTime birthdayTime;
private LocalDateTime graduationTime;
}

二、使用注解@DateTimeFormat或者@JsonFormat
@DateTimeFormat注解配合@RequestBody的引數使用的時候,會發現拋出InvalidFormatException例外,提示轉換失敗,這是因為在處理此注解的時候,只支持form提交(ContentType為x-www-form-urlencoded),例子如下:

@Datapublic class UserDto2 {
private String userId;
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime birthdayTime;
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime graduationTime;
}
@PostMapping(value = "https://www.cnblogs.com/date2")
public String date2(UserDto2 userDto2) {
log.info(userDto2.toString());
return "success";
}
//或者像下面這樣
@PostMapping(value = "https://www.cnblogs.com/date2")
public String date2(@RequestParam("name"="userId")String userId,
@RequestParam("name"="birthdayTime")LocalDateTime birthdayTime,
@RequestParam("name"="graduationTime")LocalDateTime graduationTime) {
return "success";
}
而@JsonFormat注解可使用在form或者Json請求引數的場景,因此更推薦使用@JsonFormat注解,不過注意需要指定時區(timezone屬性,例如在中國是東八區"GMT+8"),否則有可能導致出現"時差",舉個例子:
@PostMapping(value = "https://www.cnblogs.com/date2")
public String date2(@RequestBody UserDto2 userDto2) {
log.info(userDto2.toString());
return "success";
}
@Data
public class UserDto2 {
private String userId;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private LocalDateTime birthdayTime;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private LocalDateTime graduationTime;
}
三、Jackson序列化和反序列化定制
因為SpringMVC默認使用Jackson處理@RequestBody的引數轉換,因此可以通過定制序列化器和反序列化器來實作日期型別的轉換,這樣我們就可以使用application/json的形式提交請求引數,關于Java序列化你應該知道的一切,這篇推薦看下,
這里的例子是轉換請求Json引數中的字串為LocalDateTime型別,屬于Json反序列化,因此需要定制反序列化器:
@PostMapping(value = "https://www.cnblogs.com/date3")public String date3(@RequestBody UserDto3 userDto3) {
log.info(userDto3.toString());
return "success";
}
@Data
public class UserDto3 {
private String userId;
@JsonDeserialize(using = CustomLocalDateTimeDeserializer.class)
private LocalDateTime birthdayTime;
@JsonDeserialize(using = CustomLocalDateTimeDeserializer.class)
private LocalDateTime graduationTime;
}
public class CustomLocalDateTimeDeserializer extends LocalDateTimeDeserializer {
public CustomLocalDateTimeDeserializer() {
super(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
}
}
四、最佳實踐
前面三種方式都存在硬編碼等問題,其實最佳實踐是直接修改MappingJackson2HttpMessageConverter中的ObjectMapper對于日期型別處理默認的序列化器和反序列化器,這樣就能全域生效,不需要再使用其他注解或者定制序列化方案(當然,有些時候需要特殊處理定制),或者說,在需要特殊處理的場景才使用其他注解或者定制序列化方案,使用鉤子介面Jackson2ObjectMapperBuilderCustomizer可以實作ObjectMapper的屬性定制:
@Bean
public Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer(){
return customizer->{
customizer.serializerByType(LocalDateTime.class,new LocalDateTimeSerializer(
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
customizer.deserializerByType(LocalDateTime.class,new LocalDateTimeDeserializer(
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
};
}
這樣就能定制化MappingJackson2HttpMessageConverter中持有的ObjectMapper,上面的LocalDateTime序列化和反序列化器對全域生效,
請求URL匹配
前面基本介紹完了主流的請求引數處理,其實SpringMVC中還會按照URL的模式進行匹配,使用的是Ant路徑風格,處理工具類為org.springframework.util.AntPathMatcher,從此類的注釋來看,匹配規則主要包括下面四點:
-
1、
?匹配1個字符, -
2、
*匹配0個或者多個字符, -
3、
**匹配路徑中0個或者多個目錄, -
4、
{spring:[a-z]+}將正則運算式[a-z]+匹配到的值,賦值給名為spring的路徑變數,
舉些例子:
?形式的URL:
@GetMapping(value = "https://www.cnblogs.com/pattern?")public String pattern() {
return "success";
}
/pattern 404 Not Found
/patternd 200 OK
/patterndd 404 Not Found
/pattern/ 404 Not Found
/patternd/s 404 Not Found
*形式的URL:
@GetMapping(value = "https://www.cnblogs.com/pattern*")
public String pattern() {
return "success";
}
/pattern 200 OK
/pattern/ 200 OK
/patternd 200 OK
/pattern/a 404 Not Found
形式的URL:
@GetMapping(value = "https://www.cnblogs.com/pattern/**/p")public String pattern() {
return "success";
}
/pattern/p 200 OK
/pattern/x/p 200 OK
/pattern/x/y/p 200 OK
{spring:[a-z]+}形式的URL:
@GetMapping(value = "https://www.cnblogs.com/pattern/{key:/[a-c/]+}")
public String pattern(@PathVariable(name = "key") String key) {
return "success";
}
/pattern/a 200 OK
/pattern/ab 200 OK
/pattern/abc 200 OK
/pattern 404 Not Found
/pattern/abcd 404 Not Found
上面的四種URL模式可以組合使用,千變萬化,RESTful API設計技巧經驗總結推薦看看,
URL匹配還遵循精確匹配原則,也就是存在兩個模式對同一個URL都能夠匹配成功,則選取最精確的URL匹配,進入對應的控制器方法,舉個例子:
@GetMapping(value = "https://www.cnblogs.com/pattern/**/p")
public String pattern1() {
return "success";
}
@GetMapping(value = "https://www.cnblogs.com/pattern/p")
public String pattern2() {
return "success";
}
上面兩個控制器,如果請求URL為/pattern/p,最終進入的方法為pattern2,
最后,org.springframework.util.AntPathMatcher作為一個工具類,可以單獨使用,不僅僅可以用于匹配URL,也可以用于匹配系統檔案路徑,不過需要使用其帶引數構造改變內部的pathSeparator變數,例如:
AntPathMatcher antPathMatcher = new AntPathMatcher(File.separator);
小結
筆者在前一段時間曾經花大量時間梳理和分析過Spring、SpringMVC的原始碼,但是后面一段很長的時間需要進行業務開發,對架構方面的東西有點生疏了,畢竟東西不用就會生疏,這個是常理,
這篇文章基于一些SpringMVC的原始碼經驗總結了請求引數的處理相關的一些知識,希望幫到自己和大家,
關注公眾號Java技術堆疊回復"面試"獲取我整理的2020最全面試題及答案,
推薦去我的博客閱讀更多:
1.Java JVM、集合、多執行緒、新特性系列教程
2.Spring MVC、Spring Boot、Spring Cloud 系列教程
3.Maven、Git、Eclipse、Intellij IDEA 系列工具教程
4.Java、后端、架構、阿里巴巴等大廠最新面試題
覺得不錯,別忘了點贊+轉發哦!
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/146913.html
標籤:Java
下一篇:【HDFS篇11】HA高可用
