1. 개요
이 기사는 Spring에서 REST 를 설정 하는 방법 – 컨트롤러 및 HTTP 응답 코드, 페이로드 마샬링 구성 및 콘텐츠 협상을 보여줍니다.
2. Spring에서의 REST 이해
Spring 프레임 워크는 RESTful 서비스를 생성하는 두 가지 방법을 지원합니다.
- ModelAndView 와 함께 MVC 사용
- HTTP 메시지 변환기 사용
의 ModelAndView 접근 방식은 나이가 훨씬 더 문서화뿐만 아니라, 더 자세한 정보 및 구성 무겁습니다. REST 패러다임을 이전 모델로 통합하려고 시도하지만 문제가없는 것은 아닙니다. Spring 팀은 이것을 이해하고 Spring 3.0부터 일류 REST 지원을 제공했습니다.
HttpMessageConverter 및 어노테이션을 기반으로하는 새로운 접근 방식 은 훨씬 더 가볍고 구현하기 쉽습니다. 구성은 최소한이며 RESTful 서비스에서 기대할 수있는 적절한 기본값을 제공합니다.
3. 자바 구성
@Configuration
@EnableWebMvc
public class WebConfig{
//
}
새로운 @EnableWebMvc 어노테이션은 몇 가지 유용한 작업을 수행합니다. 특히 REST의 경우 클래스 경로에서 Jackson 및 JAXB 2의 존재를 감지하고 기본 JSON 및 XML 변환기를 자동으로 만들고 등록합니다. 어노테이션의 기능은 XML 버전과 동일합니다.
<mvc : 어노테이션 기반 />
이것은 지름길이며 많은 상황에서 유용 할 수 있지만 완벽하지는 않습니다. 더 복잡한 구성이 필요한 경우 어노테이션을 제거하고 WebMvcConfigurationSupport를 직접 확장 하십시오 .
3.1. Spring Boot 사용
우리가 사용하는 경우 @SpringBootApplication의 어노테이션과 스프링 webmvc의 라이브러리가 클래스 경로에 다음 @EnableWebMvc의 어노테이션에 자동으로 추가됩니다 기본 자동 .
@Configuration 어노테이션이있는 클래스 에 WebMvcConfigurer 인터페이스를 구현하여이 구성에 MVC 기능을 추가 할 수 있습니다 . WebMvcRegistrationsAdapter 인스턴스를 사용하여 자체 RequestMappingHandlerMapping , RequestMappingHandlerAdapter 또는 ExceptionHandlerExceptionResolver 구현 을 제공 할 수도 있습니다 .
마지막으로 Spring Boot의 MVC 기능을 버리고 사용자 정의 구성을 선언하려면 @EnableWebMvc 어노테이션 을 사용하여 그렇게 할 수 있습니다 .
4. 스프링 컨텍스트 테스트
Spring 3.1부터 @Configuration 클래스에 대한 최고 수준의 테스트 지원을받습니다 .
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(
classes = {WebConfig.class, PersistenceConfig.class},
loader = AnnotationConfigContextLoader.class)
public class SpringContextIntegrationTest {
@Test
public void contextLoads(){
// When
}
}
@ContextConfiguration 어노테이션을 사용하여 Java 구성 클래스를 지정합니다 . 새로운 AnnotationConfigContextLoader 는 @Configuration 클래스 에서 빈 정의를로드합니다 .
것을 알 수 WebConfig의 가 제공되지 않는 서블릿 컨텍스트에서 실행해야하기 때문에 구성 클래스가 테스트에 포함되지 않았습니다.
4.1. Spring Boot 사용
Spring Boot는 보다 직관적 인 방식으로 테스트를 위해 Spring ApplicationContext 를 설정하는 몇 가지 어노테이션을 제공합니다 .
애플리케이션 구성의 특정 슬라이스 만로드하거나 전체 컨텍스트 시작 프로세스를 시뮬레이션 할 수 있습니다.
예를 들어 서버를 시작하지 않고 전체 컨텍스트를 생성 하려면 @SpringBootTest 어노테이션을 사용할 수 있습니다 .
그런 다음 @AutoConfigureMockMvc 를 추가하여 MockMvc 인스턴스 를 주입하고 HTTP 요청을 보낼 수 있습니다 .
@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
public class FooControllerAppIntegrationTest {
@Autowired
private MockMvc mockMvc;
@Test
public void whenTestApp_thenEmptyResponse() throws Exception {
this.mockMvc.perform(get("/foos")
.andExpect(status().isOk())
.andExpect(...);
}
}
전체 컨텍스트 생성을 방지하고 MVC 컨트롤러 만 테스트하려면 @WebMvcTest 를 사용할 수 있습니다 .
@RunWith(SpringRunner.class)
@WebMvcTest(FooController.class)
public class FooControllerWebLayerIntegrationTest {
@Autowired
private MockMvc mockMvc;
@MockBean
private IFooService service;
@Test()
public void whenTestMvcController_thenRetrieveExpectedResult() throws Exception {
// ...
this.mockMvc.perform(get("/foos")
.andExpect(...);
}
}
이 주제에 대한 자세한 정보는 'Testing in Spring Boot'기사에서 찾을 수 있습니다 .
5. 컨트롤러
@RestController는 평온한 API의 전체 웹 계층의 중심 유물이다. 이 게시물의 목적을 위해 컨트롤러는 간단한 REST 리소스 Foo를 모델링하고 있습니다 .
@RestController
@RequestMapping("/foos")
class FooController {
@Autowired
private IFooService service;
@GetMapping
public List<Foo> findAll() {
return service.findAll();
}
@GetMapping(value = "/{id}")
public Foo findById(@PathVariable("id") Long id) {
return RestPreconditions.checkFound(service.findById(id));
}
@PostMapping
@ResponseStatus(HttpStatus.CREATED)
public Long create(@RequestBody Foo resource) {
Preconditions.checkNotNull(resource);
return service.create(resource);
}
@PutMapping(value = "/{id}")
@ResponseStatus(HttpStatus.OK)
public void update(@PathVariable( "id" ) Long id, @RequestBody Foo resource) {
Preconditions.checkNotNull(resource);
RestPreconditions.checkNotNull(service.getById(resource.getId()));
service.update(resource);
}
@DeleteMapping(value = "/{id}")
@ResponseStatus(HttpStatus.OK)
public void delete(@PathVariable("id") Long id) {
service.deleteById(id);
}
}
내가 직관적 인 Guava 스타일 RestPreconditions 유틸리티를 사용하고 있음을 눈치 채 셨을 것입니다 .
public class RestPreconditions {
public static <T> T checkFound(T resource) {
if (resource == null) {
throw new MyResourceNotFoundException();
}
return resource;
}
}
컨트롤러 구현은 공개되지 않습니다. 이는 공개 할 필요가 없기 때문입니다.
일반적으로 컨트롤러는 의존성 체인에서 마지막입니다. Spring 프론트 컨트롤러 ( DispatcherServlet ) 로부터 HTTP 요청을 수신 하고 단순히 서비스 계층에 전달합니다. 컨트롤러를 직접 참조를 통해 주입하거나 조작해야하는 사용 사례가없는 경우 공개로 선언하지 않는 것이 좋습니다.
요청 매핑은 간단합니다. 다른 컨트롤러와 마찬가지로 매핑 의 실제 값 과 HTTP 메서드는 요청의 대상 메서드를 결정합니다. @ RequestBody 는 메서드의 매개 변수를 HTTP 요청의 본문에 바인딩하는 반면 @ResponseBody 는 응답 및 반환 유형에 대해 동일한 작업을 수행합니다.
@RestController는 A는 속기 둘 다 포함 할 수 @ResponseBody 와 @Controller 우리의 클래스에 어노테이션을 .
또한 리소스가 올바른 HTTP 변환기를 사용하여 마샬링되고 마샬링되지 않도록합니다. 콘텐츠 협상은 대부분 Accept 헤더를 기반으로 사용할 활성 변환기 중 하나를 선택하기 위해 발생 하지만, 다른 HTTP 헤더도 표현을 결정하는 데 사용될 수 있습니다.
6. HTTP 응답 코드 매핑
HTTP 응답의 상태 코드는 REST 서비스에서 가장 중요한 부분 중 하나이며 주제는 금방 매우 복잡해질 수 있습니다. 이러한 권리를 얻는 것은 서비스를 만들거나 중단시킬 수 있습니다.
6.1. 매핑되지 않은 요청
Spring MVC가 매핑이없는 요청을 받으면 요청이 허용되지 않는 것으로 간주하고 405 METHOD NOT ALLOWED를 클라이언트에 반환합니다.
허용 되는 작업을 지정하기 위해 클라이언트에 405 를 반환 할 때 Allow HTTP 헤더 를 포함하는 것도 좋은 방법 입니다. 이것은 Spring MVC의 표준 동작이며 추가 구성이 필요하지 않습니다.
6.2. 유효한 매핑 된 요청
매핑이있는 요청에 대해 Spring MVC는 요청이 유효한 것으로 간주하고 다른 상태 코드가 지정되지 않으면 200 OK로 응답합니다.
이 컨트롤러가 다른 선언 있음이 때문에의 @ResponseStatus (가)에 대한 생성 , 갱신 및 삭제 에 대한 작업이 아닌 GET 실제로 기본 200 OK를 반환해야합니다.
6.3. 클라이언트 오류
클라이언트 오류의 경우 사용자 지정 예외가 정의되고 적절한 오류 코드에 매핑됩니다.
웹 계층의 모든 계층에서 이러한 예외를 던지기 만하면 Spring이 HTTP 응답에 해당 상태 코드를 매핑 할 수 있습니다.
@ResponseStatus(HttpStatus.BAD_REQUEST)
public class BadRequestException extends RuntimeException {
//
}
@ResponseStatus(HttpStatus.NOT_FOUND)
public class ResourceNotFoundException extends RuntimeException {
//
}
이러한 예외는 REST API의 일부이므로 REST에 해당하는 적절한 계층에서만 사용해야합니다. 예를 들어 DAO / DAL 계층이 존재하는 경우 예외를 직접 사용해서는 안됩니다.
또한 이것들은 체크 된 예외가 아니라 런타임 예외라는 점에 유의하십시오 – Spring 관행 및 관용구와 일치합니다.
6.4. @ExceptionHandler 사용
특정 상태 코드에 대한 사용자 지정 예외를 매핑하는 또 다른 옵션 은 컨트롤러에서 @ExceptionHandler 어노테이션 을 사용하는 것 입니다. 이 접근 방식의 문제점은 어노테이션이 정의 된 컨트롤러에만 적용된다는 것입니다. 즉, 각 컨트롤러에서 개별적으로 선언해야합니다.
물론 더 많은 유연성을 제공하는 Spring과 Spring Boot 모두에서 오류를 처리 하는 더 많은 방법이 있습니다 .
7. 추가 Maven 의존성
표준 웹 애플리케이션에 필요한 spring-webmvc 의존성 외에도 REST API에 대한 콘텐츠 마샬링 및 언 마샬링을 설정해야합니다.
<dependencies>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.8</version>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.1</version>
<scope>runtime</scope>
</dependency>
</dependencies>
REST 리소스의 표현을 JSON 또는 XML로 변환하는 데 사용되는 라이브러리입니다.
7.1. Spring Boot 사용
JSON 형식의 리소스를 검색하려는 경우 Spring Boot는 Jackson, Gson 및 JSON-B와 같은 다른 라이브러리에 대한 지원을 제공합니다.
자동 구성은 클래스 경로에 매핑 라이브러리를 포함하여 수행됩니다.
일반적으로 웹 애플리케이션을 개발하는 경우 spring-boot-starter-web 의존성을 추가하고 여기에 의존하여 프로젝트에 필요한 모든 아티팩트를 포함합니다 .
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.4.0</version>
</dependency>
Spring Boot는 기본적으로 Jackson을 사용합니다.
리소스를 XML 형식으로 직렬화하려면 Jackson XML 확장 ( jackson-dataformat-xml )을 의존성에 추가하거나 JAXB 구현 (기본적으로 JDK에서 제공됨)에 다음을 사용하여 폴백해야합니다. 리소스의 @XmlRootElement 어노테이션.
8. 결론
이 튜토리얼에서는 Spring 및 Java 기반 구성을 사용하여 REST 서비스를 구현하고 구성하는 방법을 설명했습니다.
시리즈의 다음 기사 에서는 API의 검색 가능성 , 고급 콘텐츠 협상 및 리소스의 추가 표현 작업 에 중점을 둘 것 입니다.
이 기사의 모든 코드는 Github에서 사용할 수 있습니다 . 이것은 Maven 기반 프로젝트이므로 그대로 가져 와서 실행할 수 있어야합니다.
- https://docs.spring.io/spring-framework/docs/current/reference/html
- https://www.baeldung.com/building-a-restful-web-service-with-spring-and-java-based-configuration
'Java' 카테고리의 다른 글
Thymeleaf를 사용한 Spring Boot CRUD 애플리케이션 (0) | 2021.03.17 |
---|---|
스프링 Security로그인시 추가 필드 추가하는방법 (0) | 2021.03.16 |
Spring Boot Ehcache 예제 (0) | 2021.03.16 |
Spring Security : 유저 Role 확인 방법 (0) | 2021.03.15 |
Apache Meecrowave로 마이크로 서비스 구축 (0) | 2021.03.15 |