서버 용도로 프로젝트 한개 만들고 다른 프로젝트에서 Resttemplate을 통해 요청을 보내는 방식으로 진행
실습 환경에서는 컴퓨터안에 두개의 프로젝트 가동시키기에 톰캣의 포트를 변경해야 함
서버 프로젝트의 포트 번호는 9090으로 설정
Member Dto
public class MemberDto {
private String name;
private String email;
private String organization;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getOrganization() {
return organization;
}
public void setOrganization(String organization) {
this.organization = organization;
}
@Override
public String toString() {
return "MemberDto{" +
"name='" + name + '\'' +
", email='" + email + '\'' +
", organization='" + organization + '\'' +
'}';
}
}
컨트롤러
@RestController
@RequestMapping("/api/v1/crud-api")
public class CrudController {
// 아무 파라미터가 없는 경우
@GetMapping
public String getName(){
return "Flature";
}
// PathVariable
@GetMapping(value = "/{variable}")
public String getVariable(@PathVariable String variable){
return variable;
}
// RequestParam 사용 경우
@GetMapping("/param")
public String getNameWithParam(@RequestParam String name){
return "Hello. " + name + "!";
}
// 요청 파라미터와 요청 바디를 같이 받는 경우
@PostMapping
public ResponseEntity<MemberDto> getMember(
@RequestBody MemberDto request,
@RequestParam String name,
@RequestParam String email,
@RequestParam String organization
){
System.out.println(request.getName());
System.out.println(request.getEmail());
System.out.println(request.getOrganization());
MemberDto memberDto = new MemberDto();
memberDto.setName(name);
memberDto.setEmail(email);
memberDto.setOrganization(organization);
return ResponseEntity.status(HttpStatus.OK).body(memberDto);
}
// 임의의 HTTP 헤더를 받도록 함
@PostMapping(value = "/add-header")
public ResponseEntity<MemberDto> addHeader(@RequestHeader("my-header") String header,
@RequestBody MemberDto memberDto){
System.out.println(header);
return ResponseEntity.status(HttpStatus.OK).body(memberDto);
}
}
RestTemplate는 별도의 유틸리티 클래스 생성하거나, 서비스 or 비즈니스
계층에서 구현됨
앞 서 생성한 서버 프로젝트에 요청을 날리기 위해 서버의 역할을 수행
하면서 다른 서버로 요청
을 보내는 클라이언트의 역할도 수행하는 새로운 프로젝트 생성
RestTemplate는 spring-boot-starter-web 모듈에 포함돼 있는 기능으로 별도의 의존성 추가 필요 X
구조 : 클라이언트로 요청을 받는 컨트롤러
+ RestTemplate를 활용해 다른 서버에 통신 요청을 하는 서비스 계층
@Service
public class RestTemplateService {
public String getName(){
URI uri = UriComponentsBuilder
.fromUriString("http://localhost:9090")
.path("/api/v1/crud-api")
.encode()
.build()
.toUri();
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> responseEntity = restTemplate.getForEntity(uri, String.class);
return responseEntity.getBody();
}
public String getNameWithPathVariable(){
URI uri = UriComponentsBuilder
.fromUriString("http://localhost:9090")
.path("/api/v1/crud-api/{name}")
.encode()
.build()
.expand("Flature") // 복수의 값을 넣어야 할 경우 ,를 추가하여 구분
.toUri();
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> responseEntity = restTemplate.getForEntity(uri, String.class);
return responseEntity.getBody();
}
public String getNameWithParameter(){
URI uri = UriComponentsBuilder
.fromUriString("http://localhost:9090")
.path("/api/v1/crud-api/param")
.queryParam("name", "Flature")
.encode()
.build()
.toUri();
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> responseEntity = restTemplate.getForEntity(uri, String.class);
return responseEntity.getBody();
}
}
RestTemplate 생성 시 보통 UriComponenetsBuilder
를 사용함
-> 파라미터를 연결하여 URI를 만듬
fromUriString
에서는 호출부의 URL 입력
path()
메서드에는 세부 경로 입력
encode()
에는 인코딩 문자셋 설정하는데 디폴트 값은 UTF-8
build
를 통해 빌더 생성 종료하고 UriComponent 타입이 리턴
-> 이것을 toURI 메서드를 통해 URI 타입으로 리턴 받음
생성한 uri는 외부 API를 요청하는데 사용됨
-> getForEntity() 의 파라미터로 사용하였음
path()내에 중괄호로 변수명을 입력한 후, expand에서 순서대로 값 입력 하면 됨(여러개 나열 가능)
queyrParam메서드를 통해 (키,값) 형식으로 파라미터 추가 가능
public ResponseEntity<MemberDto> postwithParamAndBody(){
URI uri = UriComponentsBuilder
.fromUriString("http://localhost:9090")
.path("/api/v1/crud-api")
.queryParam("name", "Flature")
.queryParam("email", "flature@wikibooks.co.kr")
.queryParam("organization", "WikiBooks")
.encode()
.build()
.toUri();
MemberDto memberDto = new MemberDto();
memberDto.setName("flature!!");
memberDto.setEmail("flature@gmail.com");
memberDto.setOrganization("Around Hub Studio");
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<MemberDto> responseEntity = restTemplate.postForEntity(
uri, memberDto, MemberDto.class
);
return responseEntity;
}
public ResponseEntity<MemberDto> postWithHeader(){
URI uri = UriComponentsBuilder
.fromUriString("http://localhost:9090")
.path("/api/v1/crud-api/add-header")
.encode()
.build()
.toUri();
MemberDto memberDto = new MemberDto();
memberDto.setName("flature");
memberDto.setEmail("flature@wikibooks.co.kr");
memberDto.setOrganization("Around Hub Studio");
RequestEntity<MemberDto> requestEntity = RequestEntity
.post(uri)
.header("my-header", "wikibooks API")
.body(memberDto);
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<MemberDto> responseEntity = restTemplate.exchange(
requestEntity, MemberDto.class
);
return responseEntity;
}
첫 메서드는 외부 API에 요청할 때 Body값과 파라미터 값을 담는 방법
두번째 메서드는 헤더를 추가하는 예제
-> 대부분의 외부 API는 토큰키를 받아 서비스 접근을 인증하는 방식으로 작동
-> 이때 토큰값을 보통 헤더에 담음
헤더 설정을 위해선 보통 RequestEntity를 정의해서 사용하는 방법이 가장 편리
post()로 URI 설정
header() 메서드에서 키 이름과 값을 설정
exchange()
메서드는 모든 형식의 HTTP 요청 생성 가능
-> post() 메서드 대신 다른 형식의 메서드로 정의만 하면 exchange() 메서드로 쉽게 사용할 수 있기에 대부분 사용함
@Configuration
@EnableSwagger2
public class SwaggerConfiguration {
@Bean
public Docket api(){
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("com.springboot.rest"))
.paths(PathSelectors.any())
.build();
}
private ApiInfo apiInfo(){
return new ApiInfoBuilder()
.title("Spring Boot Open API Test with Swagger")
.description("설명 부분")
.version("1.0.0")
.build();
}
}
앞서 작성한 서비스 코드를 연결하는 컨트롤러 코드 작성
@RestController
@RequestMapping("/rest-template")
public class RestTemplateController {
private final RestTemplateService restTemplateService;
public RestTemplateController(RestTemplateService restTemplateService){
this.restTemplateService = restTemplateService;
}
@GetMapping
public String getName(){
return restTemplateService.getName();
}
@GetMapping("/path-variable")
public String getNameWithPathVariable(){
return restTemplateService.getNameWithPathVariable();
}
@GetMapping("/parameter")
public String getNameWithParameter(){
return restTemplateService.getNameWithParameter();
}
@PostMapping
public ResponseEntity<MemberDto> postDto(){
return restTemplateService.postWithParamAndBody();
}
@PostMapping("/header")
public ResponseEntity<MemberDto> postWithHeader(){
return restTemplateService.postWithHeader();
}
}
POST 호출 결과