原文連接:https://www.codemore.top/cates/Backend/post/2018-04-21/spring-mvc-handler-methodshtml
由註解@RequestMapping
註解修飾的處理請求的函數的簽名很是的靈活,可使用controller函數支持的一系列參數和返回值。java
下列表格列出了controller方法能夠接受的參數,稍後會對其進行詳細的解釋。 對於 JDK 8的java.util.Optional
能夠在包含required
屬性的註解中使用,例如:@RequestParam
,@RequestHeader
等,至關於required=false
web
函數參數 | 解釋 |
---|---|
WebRequest ,NativeWebRequest |
無需直接使用Servlet API來訪問請求參數,請求屬性和session的屬性。 |
javax.servlet.ServletRequest ,javax.servlet.ServletResponse |
能夠是指定的請求和響應類型例如ServletRequest ,HttpServletRequest ,也能夠是Spring的MultipartRequest ,MultipartHttpServletRequest |
HttpSession |
參數永不爲null,訪問session非線程安全,若是多個請求訪問一個session,須要設置RequestMappingHandlerAdapter 的synchronizeOnSession 爲true。 |
PushBuilder |
Servlet 4.0 支持HTTP/2 push的API,若是客戶端不支持則爲null |
Principal |
當前受權用戶。 |
HttpMethod |
請求的HTTP方法 |
Locale |
當前請求的區域,由LocaleResolver 解析 |
TimeZone,ZoneId |
由LocaleContextResolver 解析的當前請求的時區 |
InputStream ,Reader |
訪問由Servlet API暴露的請求體 |
OutputStream ,Writer |
訪問由Servlet API 暴露的響應體 |
@PathVairable |
訪問URI變量 |
@MatrixVariable |
訪問URI中的name-value值。例如 pets/42;q=11 @MatrixVariable int q |
@Requestparam |
訪問請求中參數 |
@RequestHeader |
訪問請求頭 |
@CookieValue |
訪問cookie值 |
@RequestBody |
訪問請求體,將請求體轉換爲相應類型 |
HttpEntity<B> |
訪問請求頭和請求體 |
Map ,Model ,ModelMap |
訪問會在渲染模板時使用的變量。 |
RedirectAttributes |
重定向時使用的屬性 |
@ModelAttribute |
訪問model中的屬性,同時進行數據綁定和校驗 |
Errors, BindingResult | 訪問在數據綁定和校驗是出現的錯誤。 |
類級別的 @SessionAttributes
,SessionStatus | 在不一樣的請求中存儲session UriComponentsBuilder
| 相對於當前請求的host,port,scheme等 @SessionAttribute
| 訪問session中的屬性 @RequestAttribute
| 訪問請求的屬性。 其餘類型
| 若是參數非上述類型,那麼將當成@RequestParam
來處理spring
下列表格列出了支持的返回類型json
返回值類型 | 解釋 |
---|---|
@ResponseBody |
返回值由HttpMessageConverters 轉換,直接寫到響應體 |
HttpEntity<B> , ResponseEntity<B> |
返回值包括,http header和body |
HttpHeaders |
只返回HTTP header |
String |
由ViewResolver 解析出具體的模板渲染。 |
View |
返回具體的視圖 |
Map ,Model |
model包含的屬性,視圖由RequestToViewNameTranslator 解析 |
@ModelAttribute |
返回添加到Model的屬性,視圖由RequestToViewNameTranslator 解析. |
ModelAndView |
返回具體視圖和添加的model |
void |
返回void,則Spring MVC會認爲Controller內部已經處理好響應內容了。 |
DeferredResult<V> |
異步返回結果,能夠由任意線程處理 |
Callback<V> |
異步返回,現成由Spring MVC管理 |
ListenableFuture<V> ,CompletionStage<V> ,CompletableFuture<V> |
同DefferedResult |
ResponseBodyEmitter ,SseEmitter |
使用HttpMessageConverter 異步將對象以流的方式發到響應。 |
StreamingResponseBody |
異步將響應發送的輸出流 |
Reactor, RxJava, 等Reactive類型 | 同DeferredResult |
其餘類型 | 若是不返回以上類型,默認看成視圖名稱處理。 |
一些須要參數的註解,例如@RequestParam
,@RequestHeader
,@PathVariabl
,@MatrixVariable
和@CookieValue
,若是他麼的參數並不是String,那麼久須要進行類型轉換。 類型轉換自動由Spring MVC中註冊的轉換器來進行轉換,默認狀況下支持,int,long,Date等簡單類型。對於不支持的類型能夠經過WebDataBinder
或者由FormattingConversionService
註冊的Formatter
來進行轉換。瀏覽器
RFC 3986規定了在路徑中添加name-value對。在Spring MVC中,將其定義爲matrix變量。 Matrix變量能夠出如今任意的路徑中,每一個變量由分號隔開,多個值由逗號隔開,例如:/cars;color=red,green;year=2012
。多個值一樣可也但是經過分離名字來指定,例如:color=red;color=green
。 若是想要在路徑中添加Matrix變量,那麼就必須保證相應的controller方法包含接收matrix變量,而且請求映射不收到Matrix變量的影響。例如:spring-mvc
// GET /pets/42;q=11;r=22 @GetMapping("/pets/{petId}") public void findPet(@PathVariable String petId, @MatrixVariable int q) { // petId == 42 // q == 11 }
由於全部的路徑都有可能包辦Matrix變量,能夠經過指定路徑的形式分辨某個Matrix變量屬於哪一個路徑例如:安全
@GetMapping("/owners/{ownerId}/pets/{petId}") public void findPet( @MatrixVariable(name="q", pathVar="ownerId") int q1, @MatrixVariable(name="q", pathVar="petId") int q2) { // q1 == 11 // q2 == 22 }
Matrix變量能夠是可選的,指定默認值.例如:cookie
// GET /pets/42 @GetMapping("/pets/{petId}") public void findPet(@MatrixVariable(required=false, defaultValue="1") int q) { // q == 1 }
可使用MultiValueMap
獲取全部的Matrix變量,例如:session
// GET /owners/42;q=11;r=12/pets/21;q=22;s=23 @GetMapping("/owners/{ownerId}/pets/{petId}") public void findPet( @MatrixVariable MultiValueMap<String, String> matrixVars, @MatrixVariable(pathVar="petId") MultiValueMap<String, String> petMatrixVars) { // matrixVars: ["q" : [11,22], "r" : 12, "s" : 23] // petMatrixVars: ["q" : 22, "s" : 23] }
默認狀況下Spring MVC是不啓用Matrix變量的,若是是用Java配置,能夠經過配置UrlPathHelper
的removeSemicolonContent=false
啓用,若是是使用XML配置,可使用<mvc:annotation-driven enable-matrix=variable="true"/>
啓用。
@RequestParam
能夠將Servlet請求參數綁定到controller函數中的變量.例如:
@Controller @RequestMapping("/pets") public class EditPetForm { // ... @GetMapping public String setupForm(@RequestParam("petId") int petId, Model model) { Pet pet = this.clinic.loadPet(petId); model.addAttribute("pet", pet); return "petForm"; } // ... }
@RequestParam
的變量required
默認狀況下是true
,若是不但願必須指定某個參數能夠設置required=false
或者若是使用Java 8 可使用java.util.Optional
。 若是函數的參數非String類型,那麼將會進行自動類型轉換。 若是@RequsetParam
修飾的是Map<String,String>
或者MultiValueMap<String,String>
那麼就會獲取全部的請求參數。
@RequestHeader
將header的值綁定到controller的方法參數中。 例如一下做爲請求header:
Host localhost:8080 Accept text/html,application/xhtml+xml,application/xml;q=0.9 Accept-Language fr,en-gb;q=0.7,en;q=0.3 Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 Keep-Alive 300
下列代碼就能夠獲取Accept-Encoding
和Keep-Alive
header
@GetMapping("/demo") public void handle( @RequestHeader("Accept-Encoding") String encoding, @RequestHeader("Keep-Alive") long keepAlive) { //... }
一樣,若是參數非String類型,也會自動進行類型轉換,若是修飾的是Map<String,String>
,MultiValueMap<String,String>
或者HttpHeaders
,也是獲取全部的header值
使用@CookieValue
將cookie值綁定到controller的方法參數中 例如如下cookie:
JSESSIONID=415A4AC178C59DACE0B2C9CA727CDD84
下列代碼便可獲取:
@GetMapping("/demo") public void handle(@CookieValue("JSESSIONID") String cookie) { //... }
一樣的,若是參數類型非String,會自動進行類型轉換。
使用@ModelAttribute
修飾的函數參數能夠訪問Model中的屬性,或者其未初始化是初始化。方法參數名和請求參數名相同,model 屬性一樣也能夠覆蓋其請求參數,這樣就不須要本身再從請求參數中解析了。例如:
@PostMapping("/owners/{ownerId}/pets/{petId}/edit") public String processSubmit(@ModelAttribute Pet pet) { }
Pet 示例的獲取:
@SessionAttributes
獲取@ConstructorProperties
獲取或者字節碼獲取。固然通常都是使用Model來填充其值的,另外一個選擇使用URI的路徑變量,其值經過註冊的Converter<String,T>
轉換。下面這個例子就是@ModelAttribute
修飾的值和路徑匹配,經過Converter<String,Account>
進行類型轉換。
@PutMapping("/accounts/{account}") public String save(@ModelAttribute("account") Account account) { // ... }
獲取了屬性值的實例後就能夠開始進行數據綁定了。WebDataBinder
類經過匹配Servlet 的請求參數名(查詢參數和form字段)來將字段名對應到對象中。當類型轉換完以後填充匹配的字段。DataBinder
和Validation
將在後面章節詳細描述。 數據綁定是會產生錯誤的,默認狀況下會拋出BindException
異常,爲了在controller的方法中捕獲這個異常,能夠在方法參數中加入BindingResult
獲取異常。例如:
@PostMapping("/owners/{ownerId}/pets/{petId}/edit") public String processSubmit(@ModelAttribute("pet") Pet pet, BindingResult result) { if (result.hasErrors()) { return "petForm"; } // ... }
某些狀況下只想要訪問屬性之而不須要數據綁定。這種狀況下能夠將設置@ModelAttribute(binding=false)
。例如:
@ModelAttribute public AccountForm setUpForm() { return new AccountForm(); } @ModelAttribute public Account findAccount(@PathVariable String accountId) { return accountRepository.findOne(accountId); } @PostMapping("update") public String update(@Valid AccountUpdateForm form, BindingResult result, @ModelAttribute(binding=false) Account account) { // ... }
添加javax.util.validation.Valid
或者Spring的@Validated
註解,在數據綁定完成後會自動校驗。例如:
@PostMapping("/owners/{ownerId}/pets/{petId}/edit") public String processSubmit(@Valid @ModelAttribute("pet") Pet pet, BindingResult result) { if (result.hasErrors()) { return "petForm"; } // ... }
@SessionAttributes
用於在不一樣的請求間存儲Servlet session的屬性值。主要是列出須要在接下來的請求訪問的session的值自動的保存到session中。例如:
@Controller @SessionAttributes("pet") public class EditPetForm { // ... }
第一次請求後這個帶有pet
名字的屬性值將會自動的存到session中。直到另一個帶有SessionStatus
參數的方法將其清除。例如:
@Controller @SessionAttributes("pet") public class EditPetForm { // ... @PostMapping("/pets/{id}") public String handle(Pet pet, BindingResult errors, SessionStatus status) { if (errors.hasErrors) { // ... } status.setComplete(); // ... } } }
若是想要訪問一個以前存在的session的屬性,可使用@SessionAttribute
訪問。例如:
@RequestMapping("/") public String handle(@SessionAttribute User user) { // ... }
請他狀況下,須要添加或者刪除session的時候,能夠經過注入org.springframework.web.context.request.WebRequest
或者javax.servlet.http.HttpSession
實現Session的管理。
和@SessionAttribute
類似,@RequestAttribute
能夠訪問請求以前(例如,Filter
,HandlerInterceptor
)建立的請求屬性。例如:
@GetMapping("/") public String handle(@RequestAttribute Client client) { // ... }
默認狀況下,在重定向url中全部的屬性值都經過URI的模版變量暴露。 例如:
@PostMapping("/files/{path}") public String upload(...) { // ... return "redirect:files/{path}"; }
Flash屬性值能夠保存一個請求的數據使得另外一個請求可使用他的數據。最經常使用的場景就是重定向,例如:Post/Redirect/Get模式。在重定向以前臨時將Flash屬性保存(通常保存在session中)。這樣在另外一個請求中就能夠獲取保存值,以後就會被當即刪除。 Spring MVC 經過FlashMap
和FlashMapManager
支持Flash屬性。FlashMap
保存值,FlashMapManager
用來保存,查詢,管理FlashMap
實例。 Flash屬性默認開啓,若是不使用則不會建立HTTP session。對於每一個請求來講都有一個input的FlashMap
,包含了上一個請求傳遞的屬性和一個output的FlashMap
包含須要傳遞的屬性。這兩個FlashMap均可以經過RequestContextUtils
中的靜態方法來獲取。 通常來說controller不會直接使用FlashMap
。其方法參數RedirectAttributes
默認狀況下使用flash map存儲須要重定向的數據,保存到output的FlashMap
中,重定向後,自動從input的FlashMap中獲取數據添加到Model中。
啓用MultipartResolver
後,若是POST請求包含了multipart/form-data
,則其將會解析請求參數,獲取Multipart。下面是上次文件的示例:
@Controller public class FileUploadController { @PostMapping("/form") public String handleFormUpload(@RequestParam("name") String name, @RequestParam("file") MultipartFile file) { if (!file.isEmpty()) { byte[] bytes = file.getBytes(); // store the bytes somewhere return "redirect:uploadSuccess"; } return "redirect:uploadFailure"; } }
若是使用Servlet 3.0 則能夠用javax.servlet.http.Part
代替Spring的MultipartFile
。 Multipart 的內容一樣能夠做爲數據綁定的一部分,例如:
class MyForm { private String name; private MultipartFile file; // ... } @Controller public class FileUploadController { @PostMapping("/form") public String handleFormUpload(MyForm form, BindingResult errors) { if (!form.getFile().isEmpty()) { byte[] bytes = form.getFile().getBytes(); // store the bytes somewhere return "redirect:uploadSuccess"; } return "redirect:uploadFailure"; } }
Multipart請求一樣能夠經過非瀏覽器提交,例如:下面是一個JSON的示例:
POST /someUrl
Content-Type: multipart/mixed
--edt7Tfrdusa7r3lNQc79vXuhIIMlatb7PQg7Vp
Content-Disposition: form-data; name="meta-data" Content-Type: application/json; charset=UTF-8 Content-Transfer-Encoding: 8bit { "name": "value" } --edt7Tfrdusa7r3lNQc79vXuhIIMlatb7PQg7Vp Content-Disposition: form-data; name="file-data"; filename="file.properties" Content-Type: text/xml Content-Transfer-Encoding: 8bit ... File Data ...
能夠經過@RequestParam
來獲取元信息,可是更好的作法是使用@RequestPart
來獲取其元信息。例如:
@PostMapping("/") public String handle(@RequestPart("meta-data") MetaData metadata, @RequestPart("file-data") MultipartFile file) { // ... }
@RequestPart
能夠和javax.validation.Valid
或者Spring的@Validated
註解一同使用,經過標準的bean驗證來校驗數據的準確性。默認狀況下校驗錯誤拋出MethodArgumentNotValidException
的異常,會直接返回404的錯誤。一樣能夠經過BindingResult
來本身處理異常狀況。
使用了@RequestBody
的參數經過HttpMessageConverter
來將請求體反序列化成一個對象。下面是使用@RequestBody
的示例:
@PostMapping("/accounts") public void handle(@RequestBody Account account) { // ... }
@RequestBody
一樣能夠和javax.validation.Valid
或者Spring的@Validated
註解一同使用。默認拋出的異常是MethodArgumentNotValidException
處理方法同@RequestPart
@PostMapping("/accounts") public void handle(@Valid @RequestBody Account account, BindingResult result) { // ... }
HttpEntity
的使用和@RequestBody
類似,不過他能夠同時包含header和body。使用方法以下:
@PostMapping("/accounts") public void handle(HttpEntity<Account> entity) { // ... }
在方法中使用@ResponseBody
修飾,則會自動的將返回值經過HttpMessageConverter
的轉換寫入到響應體中。 使用方法以下:
@GetMapping("/accounts/{id}") @ResponseBody public Account handle() { // ... }
@ResponseBody
一樣支持類級別,若是修飾controller類,那麼全部的方法都會繼承這個註解。這個和@RestController
同樣,@RestController
就是@Controller
和@RequestBody
的組合。
ResponseEntity
同@ResponseBody
類似,只是其同時包含了響應的header和body。使用以下:
@PostMapping("/something") public ResponseEntity<String> handle() { // ... URI location = ... ; return ResponseEntity.created(location).build(); }
Spring MVC 內監了對Jackson序列化視圖的支持。在使用ResponseEntity
和@ResponseBody
的時候可使用@JsonView來啓動序列化的視圖類。使用以下:
public class UserController { @GetMapping("/user") @JsonView(User.WithoutPasswordView.class) public User getUser() { return new User("eric", "7!jd#h23"); } } public class User { public interface WithoutPasswordView {}; public interface WithPasswordView extends WithoutPasswordView {}; private String username; private String password; public User() { } public User(String username, String password) { this.username = username; this.password = password; } @JsonView(WithoutPasswordView.class) public String getUsername() { return this.username; } @JsonView(WithPasswordView.class) public String getPassword() { return this.password; } }
若是controller的方法返回的是一個字符串的視圖,能夠將其放到model中啓用:
@Controller public class UserController extends AbstractController { @GetMapping("/user") public String getUser(Model model) { model.addAttribute("user", new User("eric", "7!jd#h23")); model.addAttribute(JsonView.class.getName(), User.WithoutPasswordView.class); return "userView"; } }
爲了開啓@ResponseBody
和ResonseEntity
的JSONP的支持,能夠經過定義一個@ControllerAdvice
的bean繼承AbstractJsonpResponseBodyAdvice
,其默認構造參數就是JSONP的查詢參數,使用以下:
@ControllerAdvice public class JsonpAdvice extends AbstractJsonpResponseBodyAdvice { public JsonpAdvice() { super("callback"); } }