Spring Boot | A Simple Guide to Spring MVC
Mapping Requests and Responses
- By default, both requests and responses are mapped as JSON.
- Mapping is handled by Jackson, so mapping behavior can be adjusted with Jackson annotations.
Write the Code
src/main/java/sample/springboot/web/Hoge.java
package sample.springboot.web;
public class Hoge {
public int id;
public String value;
@Override
public String toString() {
return "Hoge [id=" + id + ", value=" + value + "]";
}
}
src/main/java/sample/springboot/web/HelloController.java
package sample.springboot.web;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/hello")
public class HelloController {
@RequestMapping(method=RequestMethod.POST)
public Hoge hello(@RequestBody Hoge param) {
System.out.println(param);
Hoge hoge = new Hoge();
hoge.id = 20;
hoge.value = "Response";
return hoge;
}
}
Run the Application
Test with curl
$ curl -H "Content-type: application/json" -X POST -d '{"id": 10, "value": "Request"}' http://localhost:8080/hello
{"id":20,"value":"Response"}
Hoge [id=10, value=Request]
Requests
URL Mapping
@RequestMappingmaps a method or class to a path.- Specify the path in the
valueattribute. - Specify the HTTP method in the
methodattribute.
src/main/java/sample/springboot/web/HelloController.java
package sample.springboot.web;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/hello")
public class HelloController {
@RequestMapping(method=RequestMethod.GET)
public String getMethod() {
return "get";
}
@RequestMapping(method=RequestMethod.POST)
public String postMethod1() {
return "post";
}
@RequestMapping(value="/hey", method=RequestMethod.POST)
public String postMethod2() {
return "hey post";
}
}
Execution result
Check the result with the curl command.
$ curl http://localhost:8080/hello
get
$ curl http://localhost:8080/hello -X POST
post
$ curl http://localhost:8080/hello/hey -X POST
hey post
Getting Path Variable Values with @PathVariable
- Define parameters in the path by wrapping them in braces (
{}). - Define method arguments with the same names.
- Add the
@PathVariableannotation.
src/main/java/sample/springboot/web/HelloController.java
package sample.springboot.web;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/hello")
public class HelloController {
@RequestMapping(value="/{id}/{name}", method=RequestMethod.GET)
public void getMethod(@PathVariable int id, @PathVariable String name) {
System.out.println("id=" + id + ", name=" + name);
}
}
Execution result
Check the result with the curl command.
$ curl http://localhost:8080/hello/100/hoge
id=100, name=hoge
Getting Query Parameter Values with @RequestParam
- Add
@RequestParamto a method argument to get query parameters. - If the argument type is
Map, query parameter information can be obtained as a Map. - If multiple values are set for one parameter, they can be received with Spring’s
MultiValueMap.
Code src/main/java/sample/springboot/web/HelloController.java
package sample.springboot.web;
import java.util.Map;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/hello")
public class HelloController {
@RequestMapping(method=RequestMethod.GET)
public void getMethod(
@RequestParam String id,
@RequestParam Map<String, String> queryParameters,
@RequestParam MultiValueMap<String, String> multiMap) {
System.out.println("id=" + id);
System.out.println(queryParameters);
System.out.println(multiMap);
}
}
Execution result Test with curl.
$ curl "http://localhost:8080/hello?id=100&name=hoge&name=fuga"
id=100
{id=100, name=hoge}
{id=[100], name=[hoge, fuga]}
Getting Request Header Values with @RequestHeader
- You can get header information with
@RequestHeader.
src/main/java/sample/springboot/web/HelloController.java
package sample.springboot.web;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/hello")
public class HelloController {
@RequestMapping(method=RequestMethod.GET)
public void getMethod(@RequestHeader("Test-Header") String value) {
System.out.println("Test-Header=" + value);
}
}
Execution result Test with curl.
$ curl -H "Test-Header: hoge" http://localhost:8080/hello
Test-Header=hoge
Getting Request Body Values with @RequestBody
- You can get the request body with
@RequestBody.
src/main/java/sample/springboot/web/HelloController.java
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/hello")
public class HelloController {
@RequestMapping(method=RequestMethod.POST)
public void getMethod(@RequestBody String body) {
System.out.println("body=" + body);
}
}
Execution result Test with curl.
$ curl http://localhost:8080/hello -X POST -d "Request Body"
body=Request Body
Responses
Specifying a Response Status Code with @ResponseStatus
- Add
@ResponseStatusto a method and specify a status code invalueto set the response status code. - If nothing is specified,
200 OKis returned.
src/main/java/sample/springboot/web/HelloController.java
package sample.springboot.web;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/hello")
public class HelloController {
@RequestMapping(method=RequestMethod.GET)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public void getMethod() {
}
}
Execution result Test with curl.
$ curl http://localhost:8080/hello -v
( omitted )
< HTTP/1.1 400 Bad Request
* Server Apache-Coyote/1.1 is not blacklisted
< Server: Apache-Coyote/1.1
< Content-Length: 0
< Date: Wed, 29 Apr 2015 11:50:08 GMT
< Connection: close
( omitted )
Various Ways to Return Responses
This section explains the return values that can be used in Spring MVC controller methods and the available response methods.
Difference Between @Controller and @RestController
In Spring MVC, controller classes are annotated with either @Controller or @RestController.
@Controller is mainly used for web page controllers. Because a web page controller switches to a JSP or template engine View and generates response HTML, the method return value is basically used to specify the View destination.
@RestController is used for Web API controllers that return JSON, XML, and similar content. Because it does not switch to a View, the method return value becomes the response content.
@Controller
Return a String
This is the simplest way to specify the page to move to as a View.
@RequestMapping("/method1")
public String method1() {
return "/index.html";
}
Return a ModelAndView
With ModelAndView, you can return information to pass to the View together with the View name.
@RequestMapping("/method2")
public ModelAndView method2() {
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject(new User("kimkc"));
modelAndView.setViewName("/index.html");
return modelAndView;
}
Forward
If you add forward: to the destination specified as the return value, processing moves to another controller method.
@RequestMapping("/forward1")
public String forward1() {
return "forward:method1";
}
Redirect
To redirect, add redirect:.
@RequestMapping("/redirect1")
public String redirect1() {
return "redirect:method1";
}
You can also specify an external URL.
@RequestMapping("/redirect2")
public String redirect2() {
return "redirect:https://www.google.co.jp/";
}
Return Text Content Directly from a Controller
If you add @ResponseBody to the method, the return value is returned directly as the response content.
@RequestMapping("/text1")
@ResponseBody
public String text1() {
return "text content";
}
Return Text Content with HttpServletResponse
If the return value is void and HttpServletResponse is received as an argument, you can write the response directly.
@RequestMapping("/text2")
public void text2(HttpServletResponse res) throws IOException {
res.getWriter().write("text content");
}
@RestController
Return Text Content
In controller methods annotated with @RestController, the return value becomes response content without using @ResponseBody.
@RequestMapping("/text1")
public String text1() {
return "text content";
}
Return Text Content with HttpServletResponse
As with @Controller, you can write content directly with HttpServletResponse.
@RequestMapping("/text2")
public void text2(HttpServletResponse res) throws IOException {
res.getWriter().write("text content");
}
Specify the Content Type
Specify the content type with the produces attribute of @RequestMapping.
@RequestMapping(value = "/xml1", produces = "application/xml")
public String xml1() {
return "<a><b>content</b></a>";
}
Constants for content types are defined in the org.springframework.http.MediaType class, so using them is convenient.
@RequestMapping(value = "/xml2", produces = MediaType.APPLICATION_XML_VALUE)
public String xml2() {
return "<a><b>content</b></a>";
}
Specify HTTP Status and Response Headers
When you want to specify HTTP status or response headers other than the content type, return ResponseEntity.
@RequestMapping("/responseEntity")
public ResponseEntity<String> responseEntity() {
HttpHeaders headers = new HttpHeaders();
headers.add("header1", "heaer1-value");
HttpStatus status = HttpStatus.NOT_FOUND;
return new ResponseEntity<String>("text content", headers, status);
}
Return JSON
If a controller method returns an arbitrary class, Spring MVC converts it to JSON with Jackson and returns it.
@RequestMapping("/json")
public List<User> json() {
return Arrays.asList(new User("kim", "kc"), new User("kim", "sj"));
}
[
{
"lastName": "kim",
"firstName": "kc"
},
{
"lastName": "kim",
"firstName": "sj"
}
]
File Download
Many common samples write directly to HttpServletResponse.
@RequestMapping("/file1")
public void file1(HttpServletResponse res) throws IOException {
File file = new File("pom.xml");
res.setContentLength((int) file.length());
res.setContentType(MediaType.APPLICATION_XML_VALUE);
FileCopyUtils.copy(new FileInputStream(file), res.getOutputStream());
}
It can be implemented more easily by returning the org.springframework.core.io.Resource interface.
@RequestMapping(value = "/file2", produces = MediaType.APPLICATION_XML_VALUE public Resource file2() {
return new FileSystemResource("pom.xml");
}
If the return value is Resource, Content-Length is set automatically.
Commonly used implementations of org.springframework.core.io.Resource include the following.
- FileSystemResource
- ClassPathResource
- ServletContextResource
- ByteArrayResource
- InputStreamResource
More
There are many other possible approaches. For more details, refer to the Spring Framework documentation.