spring mvc reference (二)

URI Template Patterns

URI templates can be used for convenient access to selected parts of a URL in a @RequestMapping method.

A URI Template is a URI-like string, containing one or more variable names. When you substitute values for these variables, the template becomes a URI.

In Spring MVC you can use the @PathVariable annotation on a method argument to bind it to the value of a URI template variable:

 

@GetMapping("/owners/{ownerId}")
public String findOwner(@PathVariable String ownerId, Model model) {
    Owner owner = ownerService.findOwner(ownerId);
    model.addAttribute("owner", owner);
    return "displayOwner";
}

//or

@GetMapping("/owners/{ownerId}")
public String findOwner(@PathVariable("ownerId") String theOwner, Model model) {
    // implementation omitted
}

//A method can have any number of @PathVariable annotations:
@GetMapping("/owners/{ownerId}/pets/{petId}")
public String findPet(@PathVariable String ownerId, @PathVariable String petId, Model model) {
    Owner owner = ownerService.findOwner(ownerId);
    Pet pet = owner.getPet(petId);
    model.addAttribute("pet", pet);
    return "displayPet";
}

//or
@Controller
@RequestMapping("/owners/{ownerId}")
public class RelativePathUriTemplateController {

    @RequestMapping("/pets/{petId}")
    public void findPet(@PathVariable String ownerId, @PathVariable String petId, Model model) {
        // implementation omitted
    }

}

URI Template Patterns with Regular Expressions

 The @RequestMapping annotation supports the use of regular expressions in URI template variables. The syntax is {varName:regex} where the first part defines the variable name and the second - the regular expression. 

@RequestMapping("/spring-web/{symbolicName:[a-z-]+}-{version:\\d\\.\\d\\.\\d}{extension:\\.[a-z]+}")
public void handle(@PathVariable String version, @PathVariable String extension) {
    // ...
}

 

Path Pattern Comparison

When a URL matches multiple patterns, a sort is used to find the most specific match.

A pattern with a lower count of URI variables and wild cards is considered more specific. For example /hotels/{hotel}/* has 1 URI variable and 1 wild card and is considered more specific than /hotels/{hotel}/** which as 1 URI variable and 2 wild cards.

If two patterns have the same count, the one that is longer is considered more specific. For example /foo/bar* is longer and considered more specific than/foo/*.

When two patterns have the same count and length, the pattern with fewer wild cards is considered more specific. For example /hotels/{hotel} is more specific than /hotels/*.

There are also some additional special rules:

  • The default mapping pattern /** is less specific than any other pattern. For example /api/{a}/{b}/{c} is more specific.
  • prefix pattern such as /public/** is less specific than any other pattern that doesn’t contain double wildcards. For example/public/path3/{a}/{b}/{c} is more specific.

Matrix Variables

Matrix variables can appear in any path segment, each matrix variable separated with a ";" (semicolon). For example: "/cars;color=red;year=2012". Multiple values may be either "," (comma) separated "color=red,green,blue" or the variable name may be repeated "color=red;color=green;color=blue".

 

If a URL is expected to contain matrix variables, the request mapping pattern must represent them with a URI template. This ensures the request can be matched correctly regardless of whether matrix variables are present or not and in what order they are provided.

// GET /pets/42;q=11;r=22

@GetMapping("/pets/{petId}")
public void findPet(@PathVariable String petId, @MatrixVariable int q) {

    // petId == 42
    // q == 11

}

 

// GET /owners/42;q=11/pets/21;q=22

@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

}
// GET /pets/42

@GetMapping("/pets/{petId}")
public void findPet(@MatrixVariable(required=false, defaultValue="1") int q) {

    // q == 1

}

 

// 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" : 11, "s" : 23]

}

 

Note that to enable the use of matrix variables, you must set the removeSemicolonContent property of RequestMappingHandlerMapping to false. By default it is set to true.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <mvc:annotation-driven enable-matrix-variables="true"/>

</beans>

 

 

Supported method argument types

 

org.springframework.web.context.request.WebRequest  request/session attribute access

java.util.Locale for the current request locale

java.io.OutputStream / java.io.Writer for generating the response’s content. 

java.io.InputStream / java.io.Reader for access to the request’s content.

java.util.Map / org.springframework.ui.Model / org.springframework.ui.ModelMap

@PathVariable access to URI template variables.

@MatrixVariable access to name-value pairs located in URI path segments.

@RequestParam access to specific Servlet request parameters.

@RequestPart access to the content of a "multipart/form-data" request part.

@SessionAttribute access to existing, permanent session attributes (e.g. user authentication object)

@RequestAttribute access to request attributes.

java.util.Map / org.springframework.ui.Model / org.springframework.ui.ModelMap 

The Errors or BindingResult parameters have to follow the model object that is being bound immediately as the method signature might have more than one model object and Spring will create a separate BindingResult instance for each of them so the following sample won’t work:

Invalid ordering of BindingResult and @ModelAttribute. 

@PostMapping
public String processSubmit(@ModelAttribute("pet") Pet pet, Model model, BindingResult result) { ... }

 

Note, that there is a Model parameter in between Pet and BindingResult. To get this working you have to reorder the parameters as follows:

@PostMapping
public String processSubmit(@ModelAttribute("pet") Pet pet, BindingResult result, Model model) { ... }

 

Supported method return types

ModelAndView object

Model object

Map object for exposing a model

View object

String value that is interpreted as the logical view name

void if the method handles the response itself (by writing the response content directly, declaring an argument of type ServletResponse /HttpServletResponse for that purpose) 

If the method is annotated with @ResponseBody, the return type is written to the response HTTP body.

An HttpHeaders  object to return a response with no body.

Any other return type is considered to be a single model attribute to be exposed to the view, using the attribute name specified through @ModelAttribute at the method level

 

Binding request parameters to method parameters with @RequestParam

Use the @RequestParam annotation to bind request parameters to a method parameter in your controller.

@Controller
@RequestMapping("/pets")
@SessionAttributes("pet")
public class EditPetForm {
    // ...
    @GetMapping
    public String setupForm(@RequestParam("petId") int petId, ModelMap model) {
        Pet pet = this.clinic.loadPet(petId);
        model.addAttribute("pet", pet);
        return "petForm";
    }
    // ...

}

Parameters using this annotation are required by default, but you can specify that a parameter is optional by setting @RequestParam's required attribute tofalse (e.g., @RequestParam(name="id", required=false)).

When an @RequestParam annotation is used on a Map<String, String> or MultiValueMap<String, String> argument, the map is populated with all request parameters.

 

Mapping the request body with the @RequestBody annotation

The @RequestBody method parameter annotation indicates that a method parameter should be bound to the value of the HTTP request body. 

@PutMapping("/something")
public void handle(@RequestBody String body, Writer writer) throws IOException {
    writer.write(body);
}

 

Mapping the response body with the @ResponseBody annotation

The @ResponseBody annotation is similar to @RequestBody. This annotation can be placed on a method and indicates that the return type should be written straight to the HTTP response body (and not placed in a Model, or interpreted as a view name). 

@GetMapping("/something")
@ResponseBody
public String helloWorld() {
    return "Hello World";
}

 

 

Creating REST Controllers with the @RestController annotation

It’s a very common use case to have Controllers implement a REST API, thus serving only JSON, XML or custom MediaType content. For convenience, instead of annotating all your @RequestMapping methods with @ResponseBody, you can annotate your controller Class with @RestController.

 

@RestController is a stereotype annotation that combines @ResponseBody and @Controller. More than that, it gives more meaning to your Controller and also may carry additional semantics in future releases of the framework.

 

Using HttpEntity

The HttpEntity is similar to @RequestBody and @ResponseBody. Besides getting access to the request and response body, HttpEntity (and the response-specific subclass ResponseEntity) also allows access to the request and response headers.

@RequestMapping("/something")
public ResponseEntity<String> handle(HttpEntity<byte[]> requestEntity) throws UnsupportedEncodingException {
    String requestHeader = requestEntity.getHeaders().getFirst("MyRequestHeader"));
    byte[] requestBody = requestEntity.getBody();

    // do something with request header and body

    HttpHeaders responseHeaders = new HttpHeaders();
    responseHeaders.set("MyResponseHeader", "MyValue");
    return new ResponseEntity<String>("Hello World", responseHeaders, HttpStatus.CREATED);
}

 

 

 

猜你喜欢

转载自jaesonchen.iteye.com/blog/2333979