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

  • @RequestMapping maps a method or class to a path.
  • Specify the path in the value attribute.
  • Specify the HTTP method in the method attribute.

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 @PathVariable annotation.

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 @RequestParam to 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 @ResponseStatus to a method and specify a status code in value to set the response status code.
  • If nothing is specified, 200 OK is 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.