Spring Boot 1.4.1 - RestController

1. Hello World

コントローラクラスを作成します。

最初にテストを記述します。

package com.example;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.test.context.junit4.SpringRunner;

import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class DemoApplicationTests {

    @Autowired
    TestRestTemplate template;

    @Test
    public void contextLoads() {
        ResponseEntity<String> res = template.getForEntity("/", String.class);
        assertThat(res.getStatusCode(), is(HttpStatus.OK));
        assertThat(res.getBody(), is("Hello World!!"));
    }

}

次に、IndexControllerを作成します。

package com.example;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class IndexController {

    @GetMapping("/")
    public String index() {
        return "Hello World!!";
    }
}

REST のコントローラには、@RestController アノテーションを使ってクラスを作成します。 コントローラのメソッドには URL のマッピングを設定します。 ここで使用している GetMapping 以外に、PostMapping や、PutMpping、DeleteMapping 等があります。

最初のステップでは、Hello World!! という文字列を返しました。

2. コントローラのメソッドの引数

コントローラのメソッドは、HttpServletRequest や HttpServletResponse やその他さまざまなオブジェクトを受け取ることができます。

package com.example;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Objects;

@RestController
public class IndexController {

    @GetMapping("/")
    public String index(HttpServletRequest req, HttpServletResponse res) {
        Objects.nonNull(req);
        Objects.nonNull(res);
        return "Hello World!!";
    }
}

3. PathVariable

URLパスの変数の値を受け取ることができます。

package com.example;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class IndexController {

    @GetMapping("/{id}")
    public String index(@PathVariable String id) {
        return "ID: " + id;
    }
}
package com.example;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.test.context.junit4.SpringRunner;

import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class DemoApplicationTests {

    @Autowired
    TestRestTemplate template;

    @Test
    public void contextLoads() {
        ResponseEntity<String> res = template.getForEntity("/123", String.class);
        assertThat(res.getStatusCode(), is(HttpStatus.OK));
        assertThat(res.getBody(), is("ID: 123"));
    }

}

4. Request パラメータ

Request パラメータを受け取ることももちろんできます。

package com.example;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class IndexController {

    @GetMapping("/foo")
    public String index(@RequestParam String id) {
        return "ID: " + id;
    }
}
package com.example;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.test.context.junit4.SpringRunner;

import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class DemoApplicationTests {

    @Autowired
    TestRestTemplate template;

    @Test
    public void contextLoads() {
        ResponseEntity<String> res = template.getForEntity("/foo?id=bar", String.class);
        assertThat(res.getStatusCode(), is(HttpStatus.OK));
        assertThat(res.getBody(), is("ID: bar"));
    }

}

ModelAttribute

Request パラメータが多い場合等は、ModelAttribute を使って、Request パラメータの値が設定されたオブジェクトを受け取ることができるようにすることができます。

package com.example;

public class Foo {

    private String id;

    public void setId(String id) {
        this.id = id;
    }

    public String getId() {
        return id;
    }
}
package com.example;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class IndexController {

    @GetMapping("/foo")
    public String index(@ModelAttribute Foo foo) {
        return "ID: " + foo.getId();
    }
}
package com.example;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.test.context.junit4.SpringRunner;

import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class DemoApplicationTests {

    @Autowired
    TestRestTemplate template;

    @Test
    public void contextLoads() {
        ResponseEntity<String> res = template.getForEntity("/foo?id=bar", String.class);
        assertThat(res.getStatusCode(), is(HttpStatus.OK));
        assertThat(res.getBody(), is("ID: bar"));
    }

}

5. HandlerMethodArgumentResolver

HandlerMethodArgumentResolver の実装クラスを作成して、任意のオブジェクトをコントローラのメソッドで受け取ることができるようにすることができます。 Spring Security を使ってログインしているユーザの Principal をコントローラで受け取る場合などこの仕組みが多く使用されています。

package com.example;

public class Foo {

    public final String foo = "foo";

}
package com.example;

import org.springframework.core.MethodParameter;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;

public class FooHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver {

    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        return Foo.class.isAssignableFrom(parameter.getParameterType());
    }

    @Override
    public Object resolveArgument(MethodParameter parameter, 
                                  ModelAndViewContainer mavContainer,
                                  NativeWebRequest webRequest,
                                  WebDataBinderFactory binderFactory)
            throws Exception {
        return new Foo();
    }
}
package com.example;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

import java.util.List;

@SpringBootApplication
public class DemoApplication extends WebMvcConfigurerAdapter {

    @Override
    public void addArgumentResolvers(
            List<HandlerMethodArgumentResolver> argumentResolvers) {
        argumentResolvers.add(new FooHandlerMethodArgumentResolver());
    }

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}
package com.example;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class IndexController {

    @GetMapping("/")
    public String index(Foo foo) {
        return foo.foo;
    }
}
package com.example;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.test.context.junit4.SpringRunner;

import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class DemoApplicationTests {

    @Autowired
    TestRestTemplate template;

    @Test
    public void contextLoads() {
        ResponseEntity<String> res = template.getForEntity("/", String.class);
        assertThat(res.getStatusCode(), is(HttpStatus.OK));
        assertThat(res.getBody(), is("foo"));
    }

}