拙見–springMVC的controller接受的請求參數
- 2022 年 6 月 16 日
- 筆記
1-這種是最常用的表單參數提交,ContentType指定為application/x-www-form-urlencoded,也就是會進行URL編碼。
1.1-對象類型實體Bean接收請求參數(表單實體也可以用@ModelAttribute(“UserForm”))
@Controller @RequestMapping("/user") public class UserController { @RequestMapping("/login") public String login(UserForm userForm, HttpSession session, Model model){ if("wangguodong".equals(userForm.getUname()) && "123".equals(userForm.getUpass())){ //用戶名和密碼都相等 session.setAttribute("u", userForm); return "main" ; //登錄成功,跳到主頁面 }else{ model.addAttribute("messageError", "用戶名或密碼錯誤") ; return "login" ; } }
拓展底層:1>因為沒有使用註解,最終的參數處理器為ServletModelAttributeMethodProcessor,主要是把HttpServletRequest中的表單參數封裝到MutablePropertyValues實例中,
再通過參數類型實例化(通過構造反射創建UserForm實例),反射匹配屬性進行值的填充
2>實際上RequestParamMethodArgumentResolver依賴WebConversionService中Converter列表進行參數轉換:因為沒有UserForm到String的轉換器,添加一個
org.springframework.core.convert.converter.Converter實現即可
1.2-非對象類型單個參數接收:通過處理方法的形參接收請求參數(就是直接把表單參數寫在控制類相應方法的形參中,形參名稱與請求參數名稱可以不一致時用@RequestParam(name = "name"))
@PostMapping(value = "/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; }
拓展底層:1>這種情況下,用到的參數處理器是RequestParamMapMethodArgumentResolver。
2-其他參數主要包括請求頭、Cookie、Model、Map等相關參數,還有一些並不是很常用或者一些相對原生的屬性值獲取;例如HttpServletRequest、HttpServletResponse等)
2.1HttpServletRequest
@Controller @RequestMapping("/user") public class UserController { @RequestMapping("/login") public String login(HttpServletRequest request, Model model){ String uname = request.getParameter("uname") ; String upass = request.getParameter("upass") ; if("wangguodong".equals(uname) && "123".equals(upass)){ //用戶名和密碼都相等 return "main" ; //登錄成功,跳到主頁面 }else{ model.addAttribute("messageError", "用戶名或密碼錯誤") ; return "login" ; } }
2.2請求頭的值主要通過@RequestHeader註解的參數獲取,
@PostMapping(value = "/header") public String header(@RequestHeader(name = "Content-Type") String contentType) { return contentType; }
拓展底層:1>參數處理器是RequestHeaderMethodArgumentResolver,需要在註解中指定請求頭的Key。
2.3Cookie的值主要通過@CookieValue註解的參數獲取,
@PostMapping(value = "/cookie") public String cookie(@CookieValue(name = "JSESSIONID") String sessionId) { return sessionId;}
拓展底層:1>參數處理器為ServletCookieValueMethodArgumentResolver,需要在註解中指定Cookie的Key。
2.4Model類型參數
@GetMapping(value = "/model") public String model(Model model, ModelMap modelMap) { log.info("{}", model == modelMap); return "success"; }
拓展底層:1>Model類型參數的處理器是ModelMethodProcessor,實際上處理此參數是直接返回ModelAndViewContainer實例中的Model(ModelMap類型),因為要橋接不
同的介面和類的功能,因此回調的實例是BindingAwareModelMap類型,此類型繼承自ModelMap同時實現了Model介面。ModelMap或者Model中添加的屬性項會附加到
HttpRequestServlet中帶到頁面中進行渲染。
2.5Errors或者BindingResult參數
@PostMapping(value = "/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; }
拓展底層:1>Errors其實是BindingResult的父介面,BindingResult主要用於回調JSR參數校驗異常的屬性項,如果JSR校驗異常,一般會拋出
MethodArgumentNotValidException異常,並且會返回400(Bad Request),見全局異常處理器DefaultHandlerExceptionResolver。Errors類型
的參數處理器為ErrorsMethodArgumentResolver。
2.6Value參數
@GetMapping(value = "/value") public String value(@Value(value = "${spring.application.name}") String name) { log.info("spring.application.name={}", name); return name; }
拓展底層:1>控制器方法的參數可以是@Value註解修飾的參數,會從Environment中裝配和轉換屬性值到對應的參數中(也就是參數的來源並不是請求體),
參數處理器為ExpressionValueMethodArgumentResolver。
2.7Map類型參數的範圍相對比較廣,對應一系列的參數處理器,
注意區別使用了上面提到的部分註解的Map類型和完全不使用註解的Map類型參數,兩者的處理方式不相同。下面列舉幾個相對典型的Map類型參數處理例子。
不使用任何註解的Map<String,Object>參數
這種情況下參數實際上直接回調ModelAndViewContainer中的ModelMap實例,參數處理器為MapMethodProcessor,往Map參數中添加的屬性將會帶到頁面中。
使用@RequestParam註解的Map<String,Object>參數
這種情況下的參數處理器為RequestParamMapMethodArgumentResolver,使用的請求方式需要指定ContentType為x-www-form-urlencoded,不能使用application/json的
@PostMapping(value = "/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結構。
3-直接POST一個JSON字元串這種方式對於SpringMVC來說是比較友好的,只需要把ContentType設置為application/json,提交一個原始的JSON字元串即可:
@PostMapping(value = "/user-2") public User saveUser2(@RequestBody User user) { log.info(user.toString()); return user; }
拓展底層:1>使用了@RequestBody註解,最終使用到的參數處理器為RequestResponseBodyMethodProcessor,實際上會用到
MappingJackson2HttpMessageConverter進行參數類型的轉換,底層依賴到Jackson相關的包。
4-帶請求路徑參數(例如/user/{userId}是一個URL模板(URL模板中的參數佔位符是{}),實際請求的URL為/user/1,那麼通過匹配實際請求的URL和URL模板就能提取到userId為1)
@GetMapping(value = "/user/{name}/{age}") public String findUser1(@PathVariable(value = "age") Integer age, @PathVariable(value = "name") String name) { String content = String.format("name = %s,age = %d", name, age); log.info(content); return content; }
注意一點是,@PathVariable的解析是按照value(name)屬性進行匹配,和URL參數的順序是無關的。
其實路徑參數支援正則表達式,例如我們在使用/sex/sex}介面的時候,要求sex必須是F(Female)或者M(Male)
@GetMapping(value = "/sex/{sex:M|F}") public String findUser2(@PathVariable(value = "sex") String sex){ log.info(sex); return sex; }
拓展底層:1>對應的參數處理器為PathVariableMethodArgumentResolver。
5-文件上傳在使用POSTMAN模擬請求的時候需要選擇form-data,POST方式進行提交:
@PostMapping(value = "/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; }
拓展底層:1>可知MultipartFile實例的主要屬性分別來自Content-Disposition、content-type和content-length,另外,InputStream用於讀取請求體的最後部分
(文件的位元組序列)。參數處理器用到的是RequestPartMethodArgumentResolver(記住一點,使用了@RequestPart和MultipartFile一定是使用此參數處理器)。
6-批量文件上傳,我們一般需要接收一個MultipartFile集合,使用MultipartHttpServletRequest參數,直接調用getFiles
方法獲取MultipartFile列表
@PostMapping(value = "/parts") public String partArgs(@RequestParam(name = "file") List<MultipartFile> parts) { log.info("{}", parts); return parts.toString(); }