| 스프링 부트에서 스프링 웹 MVC 컨트롤러 구현
프로젝트 구조
| pom.xml
+---src
| +---main
| | +---java
| | | \---com
| | | \---tutorial
| | | \---sptringbootmvc
| | | | SptringBootMvcApplication.java
| | | |
| | | \---user
| | | UserController.java
| | |
| | \---resources
| | application.properties
| |
| \---test
| \---java
| \---com
| \---tutorial
| \---sptringbootmvc
| \---user
| UserControllerTest.java
테스트 코드
@RunWith(SpringRunner.class)
@WebMvcTest(UserController.class)
public class UserControllerTest {
@Autowired
MockMvc mockMvc;
@Test
public void hello() throws Exception {
mockMvc.perform(get("/hello"))
.andExpect(status().isOk())
.andExpect(content().string("hello saelobi"));
}
}
참조글 : [Spring/Spring Boot] - [Spring Boot #12] 스프링부트에서 테스트 작성하기( Spring Boot Test )
소스 코드
@SpringBootApplication
public class SptringBootMvcApplication {
public static void main(String[] args) {
SpringApplication.run(SptringBootMvcApplication.class, args);
}
}
@RestController
public class UserController {
@GetMapping("/hello")
// @ResponseBody 가 생략이 되어 있음
public String hello(){
// @RestController가 아닌 @Controller가 어노테이션으로 붙어 있을 경우
// 아래 return되는 문자열은 ViewResolver를 통해 jsp 파일을 찾게 된다.
// 하지만 @RestController가 붙어있으면 자동적으로 StringMessageConverter가 사용되어
// HTTP 응답 본문에 들어가게 된다.
return "hello saelobi";
}
}
- @RestController : 스프링 4부터 기존 특정한 JSP를 만들어 내는 뷰를 반환하는 방식이 아닌 데이터 자체를 서비스 하는 것을 지원하는 어노테이션. @ResponseBody을 생략해도 HttpMessageConverter 인터페이스를 통해 자동적으로 반환 객체를 HTTP 응답 본문으로 변환한다. 위 예시에서는 StringMessageConverter 구현체가 사용되어 String 객체를 HTTP 응답 본문으로 변환해준다.
- @GetMapping : @RequestMapping(method=RequestMethod.GET)의 축약형
| @RequestBody 어노테이션을 통한 HTTP 메세지와 객체 매핑
프로젝트 구조
| pom.xml
+---src
| +---main
| | +---java
| | | \---com
| | | \---tutorial
| | | \---sptringbootmvc
| | | | SptringBootMvcApplication.java
| | | |
| | | \---user
| | | User.java
| | | UserController.java
| | |
| | \---resources
| | application.properties
| |
| \---test
| \---java
| \---com
| \---tutorial
| \---sptringbootmvc
| \---user
| UserControllerTest.java
테스트 코드
@RunWith(SpringRunner.class)
@WebMvcTest(UserController.class)
public class UserControllerTest {
@Autowired
MockMvc mockMvc;
@Test
public void hello() throws Exception {
mockMvc.perform(get("/hello"))
.andExpect(status().isOk())
.andExpect(content().string("hello saelobi"));
}
@Test
public void createUser_JSON() throws Exception {
String userJson = "{\"username\":\"saelobi\", \"password\":\"123\"}";
mockMvc.perform(post("/users/create")
.contentType(MediaType.APPLICATION_JSON_UTF8)
.accept(MediaType.APPLICATION_JSON_UTF8)
.content(userJson))
.andExpect(status().isOk())
.andExpect(jsonPath("$.username", is(equalTo("saelobi"))))
.andExpect(jsonPath("$.password", is(equalTo("123"))));
}
}
- MediaType.[데이터_형식] : 스프링 3부터 지원. HTTP 명세에 정의된 데이터 전달 형식을 나타내는 HTTP Response의 Content-type 리스트
- jsonPath : https://github.com/json-path/JsonPath 의 경로 규칙을 따라서 response-body의 json 포맷에 접근할 수 있게 지원하는 메서드
소스 코드
public class User {
private Long id;
private String username;
private String password;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
@RestController
public class UserController {
@GetMapping("/hello")
// @ResponseBody 가 생략이 되어 있음
public String hello(){
// @RestController가 아닌 @Controller가 어노테이션으로 붙어 있을 경우
// 아래 return되는 문자열은 ViewResolver를 통해 jsp 파일을 찾게 된다.
// 하지만 @RestController가 붙어있으면 자동적으로 StringMessageConverter가 사용되어
// HTTP 응답 본문에 들어가게 된다.
return "hello saelobi";
}
// HttpMessageConverters는 스프링 프레임워크에서 제공하는 인터페이스며
// 스프링 MVC의 일부분
// HTTP 응답 본문을 객체로 변환하거나 그 반대로 변환
// 만일 HTTP에 content-type으로 JSON이 들어오면 (또한 본문도 JSON) JsonConverter로 바뀜
// content-type이 문자열이면 StringMessageConverter가 사용됨
@PostMapping("/users/create")
public User create(@RequestBody User user){
return user;
}
}
- @PostMapping : @GetMapping과 비슷하게 @RequestMapping(method=RequestMethod.POST)의 축약형
- Controller 단에서 따로 json 타입에 대한 정보를 명시하지 않아도 아래에서 설명할 ContentNegotiatingViewResolver를 통해 자동적으로 json 형식으로 데이터를 반환하도록 스프링 부트에서 제공. 이 ViewResolver는 Converter와 연관되어 있어 Content-type을 기준으로 어떤 Converter를 쓸 지 결정
| 스프링부트 ViewResolver : ContentNegotiatingViewResolver
- ViewResolver : 스프링에서 Controller에서 반환한 값(ModelAndView 혹은 Model)을 통해 뷰를 만드는 역할
- ContentNegotiatingViewResolver : 동일한 URI에서 HTTP Request에 있는 Content-type 및 Accept 헤더를 기준으로 다양한 Content-type으로 응답할 수 있게 하는 ViewResolver
다음과 같이 요청(Json) 및 응답(XML) 형식이 다를 때도 잘 동작함.
테스트 코드
@RunWith(SpringRunner.class)
@WebMvcTest(UserController.class)
public class UserControllerTest {
@Autowired
MockMvc mockMvc;
@Test
public void hello() throws Exception {
mockMvc.perform(get("/hello"))
.andExpect(status().isOk())
.andExpect(content().string("hello saelobi"));
}
@Test
public void createUser_JSON() throws Exception {
String userJson = "{\"username\":\"saelobi\", \"password\":\"123\"}";
mockMvc.perform(post("/users/create")
.contentType(MediaType.APPLICATION_JSON_UTF8)
.accept(MediaType.APPLICATION_JSON_UTF8)
.content(userJson))
.andExpect(status().isOk())
.andExpect(jsonPath("$.username", is(equalTo("saelobi"))))
.andExpect(jsonPath("$.password", is(equalTo("123"))));
}
@Test
public void createUser_XML() throws Exception {
String userJson = "{\"username\":\"saelobi\", \"password\":\"123\"}";
mockMvc.perform(post("/users/create")
.contentType(MediaType.APPLICATION_JSON_UTF8)
.accept(MediaType.APPLICATION_XML)
.content(userJson))
.andExpect(status().isOk())
.andExpect(xpath("/User/username").string("saelobi"))
.andExpect(xpath("/User/password").string("123"));
}
}
참고자료 : https://www.inflearn.com/course/스프링부트
'Spring > Spring Boot' 카테고리의 다른 글
[Spring Boot #15] 스프링 웹 MVC : 인덱스 페이지와 파비콘 (0) | 2019.01.03 |
---|---|
[Spring Boot #14] 스프링 웹 MVC : 정적 리소스 지원 (0) | 2019.01.03 |
[Spring Boot #12] 스프링부트에서 테스트 작성하기( Spring Boot Test ) (1) | 2019.01.01 |
[Spring Boot #11] 스프링 부트 로깅( Spring Boot Logging ) (0) | 2019.01.01 |
[Spring Boot #10] 스프링 부트 프로파일(Spring Boot Profile) (0) | 2018.12.31 |
이 글을 공유하기