Spring Boot | Spring MVCの簡単な使い方

リクエストとレスポンスのマッピング

  • デフォルトでは、リクエストとレスポンスはどちらもJSONとしてマッピングされます。
  • マッピングはJacksonで行われているため、マッピングの調整はJacksonアノテーションで可能です。

コード作成

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;
    }
}

アプリケーション実行

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]

リクエスト

URLマッピング

  • @RequestMapping はメソッドまたはクラスとパスをマッピングします。
  • value 属性にパスを指定します。
  • method 属性にHTTPメソッドを指定します。

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";
    }
}

実行結果 curlコマンドで実行結果を確認します。

$ curl http://localhost:8080/hello
get

$ curl http://localhost:8080/hello -X POST
post

$ curl http://localhost:8080/hello/hey -X POST
hey post

パス変数(@PathVariable)の値を取得する

  • パス定義で中括弧 ({}) に囲んだパラメータを定義します。
  • メソッドの引数として同じ名前の引数を定義します。
  • @PathVariable アノテーションを付与します。

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);
    }
}

実行結果 curlコマンドで実行結果を確認します。

$ curl http://localhost:8080/hello/100/hoge
id=100, name=hoge

クエリパラメータ(@RequestParam)の値を取得する

  • メソッド引数に @RequestParam アノテーションを付与すると、クエリパラメータを取得できます。
  • 引数の型が Map であれば、クエリパラメータ情報をMap形式で取得できます。
  • 1つのパラメータに複数の値が設定されている場合は、Springが提供する MultiValueMap で受け取れます。

コード作成 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);
    }
}

実行結果 curlでテストします。

$ curl "http://localhost:8080/hello?id=100&name=hoge&name=fuga"
id=100
{id=100, name=hoge}
{id=[100], name=[hoge, fuga]}

リクエストヘッダー(@RequestHeader)の値を取得する

  • @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);
    }
}

実行結果 curlでテストします。

$ curl -H "Test-Header: hoge" http://localhost:8080/hello
Test-Header=hoge

リクエストボディ(@RequestBody)の値を取得する

  • @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);
    }
}

実行結果 curlでテストします。

$ curl http://localhost:8080/hello -X POST -d "Request Body"
body=Request Body

レスポンス

レスポンスステータスコード(@ResponseStatus)を指定する

  • メソッドに @ResponseStatus アノテーションを付与し、valueにステータスコードを指定すると、そのレスポンスのステータスコードを指定できます。
  • 何も指定しなければ 200 OK が返されます。

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() {
    }
}

実行結果 curlでテストします。

$ curl http://localhost:8080/hello -v
( 省略 )

< 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

( 省略 )

さまざまなレスポンスの返し方

Spring MVCのコントローラーメソッドで使用できる戻り値と、レスポンスを返す方法について説明します。

@Controllerと@RestControllerの違い

Spring MVCでは、コントローラークラスに @Controller または @RestController を付与します。

@Controller は主にWebページのコントローラーで使用します。Webページ用コントローラーはJSPやテンプレートエンジンのViewへ切り替えてレスポンスHTMLを生成するため、基本的にメソッドの戻り値はViewの遷移先を指定するために使われます。

@RestController はJSONやXMLなどを返すWeb API用コントローラーとして使用します。Viewへ切り替えないため、メソッドの戻り値はレスポンスの内容になります。

@Controller

戻り値をStringにする

Viewの移動先ページを指定する最も簡単な方法です。

@RequestMapping("/method1")
public String method1() {
    return "/index.html";
}
戻り値をModelAndViewにする

ModelAndView を使うと、Viewに渡したい情報も一緒に返せます。

@RequestMapping("/method2")
public ModelAndView method2() {
    ModelAndView modelAndView = new ModelAndView();
    modelAndView.addObject(new User("kimkc"));
    modelAndView.setViewName("/index.html");
    return modelAndView;
}
フォワード

戻り値で指定する移動先に forward: を付けると、別のコントローラーメソッドへ移動します。

@RequestMapping("/forward1")
public String forward1() {
    return "forward:method1";
}
リダイレクト

リダイレクトするには redirect: を付けます。

@RequestMapping("/redirect1")
public String redirect1() {
    return "redirect:method1";
}

外部URLを指定する場合もあります。

@RequestMapping("/redirect2")
public String redirect2() {
    return "redirect:https://www.google.co.jp/";
}
コントローラーから直接テキストコンテンツを返す

メソッドに @ResponseBody を付けると、戻り値を直接レスポンス内容として返せます。

    @RequestMapping("/text1")
    @ResponseBody
    public String text1() {
        return "text content";
    }
HttpServletResponseでテキストコンテンツを返す

戻り値を void にし、HttpServletResponse を引数として受け取ると、レスポンスを直接書き込むこともできます。

@RequestMapping("/text2")
public void text2(HttpServletResponse res) throws IOException {
    res.getWriter().write("text content");
}

@RestController

戻り値でテキストコンテンツを返す

@RestController を付けたコントローラーメソッドでは、@ResponseBody を使わなくても戻り値がレスポンス内容になります。

@RequestMapping("/text1")
public String text1() {
        return "text content";
}
HttpServletResponseでテキストコンテンツを返す

@Controller の場合と同様に、HttpServletResponse で直接コンテンツを書き込めます。

@RequestMapping("/text2")
public void text2(HttpServletResponse res) throws IOException {
    res.getWriter().write("text content");
}
コンテンツ形式を指定する

コンテンツ形式は @RequestMappingproduces で指定します。

@RequestMapping(value = "/xml1", produces = "application/xml")
public String xml1() {
    return "<a><b>content</b></a>";
}

org.springframework.http.MediaType クラスにコンテンツ形式の定数が定義されているため、それを使うと便利です。

@RequestMapping(value = "/xml2", produces = MediaType.APPLICATION_XML_VALUE)
public String xml2() {
    return "<a><b>content</b></a>";
}
HTTPステータスとレスポンスヘッダーを指定する

HTTPステータスやコンテンツ形式以外のレスポンスヘッダーを指定したい場合は、戻り値を 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);
}
JSONを返す

メソッドの戻り値を任意のクラスにすると、Spring MVCがJacksonを使ってJSONへ変換して返します。

@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"
    }
]

ファイルダウンロード

よくあるサンプルでは、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());
}

戻り値を org.springframework.core.io.Resource インターフェースにすると、より簡単に実装できます。

@RequestMapping(value = "/file2", produces = MediaType.APPLICATION_XML_VALUE  public Resource file2() {
    return new FileSystemResource("pom.xml");
}

戻り値が Resource であれば、Content-Length は自動で設定されます。

org.springframework.core.io.Resource の実装クラスでよく使いそうなものは次のとおりです。

  • FileSystemResource
  • ClassPathResource
  • ServletContextResource
  • ByteArrayResource
  • InputStreamResource

その他

このほかにも、さまざまな方法があります。詳しく知りたい場合は、Spring Frameworkドキュメント などを参照してください。