
💡 RestTemplate 란?
- 개념
Spring Framework에서 제공하는 클래스- 역할
RESTful 웹 서비스를 호출하기 위한 HTTP 클라이언트 역할- 주요 기능
1. HTTP 요청 보내기
➡GET,POST,PUT,DELETE등 다양한 HTTP 메서드를 지원하여 RESTful 서비스와의 통신
2. 응답 처리
➡ HTTP 응답을 자동으로 변환하여 객체로 반환
3. 헤더 설정
➡ 요청에 필요한 HTTP 헤더 설정 가능
4. 요청 본문 설정
➡POST,PUT등의 요청에 데이터를 포함 가능- 장점
1. 간편하게 HTTP 요청을 보낼 수 있음
2. JSON과 같은 형식으로 반환된 응답을 JAVA 객체로 자동 변환
3. 다양한 HTTP 메서드를 지원하고, HTTP 요청에 대한 헤더 및 본문 설정이 가능하여 유연하게 사용 가능
User-service의 EUserServiceApplication 수정package com.example.euserservice;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.context.annotation.Bean;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.web.client.RestTemplate;
@SpringBootApplication
@EnableDiscoveryClient
public class EUserServiceApplication {
public static void main(String[] args) {
SpringApplication.run(EUserServiceApplication.class, args);
}
@Bean
public BCryptPasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
@Bean
public RestTemplate getRestTemplate(){ //추가
return new RestTemplate();
}
}
User-service의 UserServiceImpl.java 수정/users/{userId} 엔드포인트를 통해 사용자의 정보 호출 시, 해당 사용자의 주문 내역도 함께 호출하고자 함
//추가
Environment env;
RestTemplate restTemplate;
//생성자 수정
@Autowired
public UserServiceImpl(UserRepository userRepository, BCryptPasswordEncoder passwordEncoder, Environment env, RestTemplate restTemplate) {
this.userRepository = userRepository;
this.passwordEncoder = passwordEncoder;
this.env = env;
this.restTemplate = restTemplate;
}
@Override
public UserDto getUserByUserId(String userId) {
UserEntity userEntity = userRepository.findByUserId(userId);
if(userEntity == null){
//로그인 인증 시 사용하는 것이나, 사용자가 없다는 비슷한 의미로 해당 예시에서 사용
throw new UsernameNotFoundException("User not found");
}
UserDto userDto = new ModelMapper().map(userEntity, UserDto.class);
// List<ResponseOrder> orders = new ArrayList<>();
/* Using as rest template */
String orderUrl = "http://127.0.0.1:8000/order-service/%s/orders";
ResponseEntity<List<ResponseOrder>> orderListResponse = restTemplate.exchange(orderUrl, HttpMethod.GET, null,
new ParameterizedTypeReference<List<ResponseOrder>>() {
});
List<ResponseOrder> orderList = orderListResponse.getBody();
userDto.setOrders(orderList);
/* End */
return userDto;
}
🤔 UserServiceImpl의
getUserByUserId수정 이유?
getUser메서드에서는userService.getUserByUserId(userId)메서드를 호출하여
주문 서비스에서 해당userId가 주문한 내역들을 가져옴UserServiceImpl에서 구현한getUserByUserId(userId)메서드에서 주문 서비스를 호출하고 있음- 기존에는 주문 서비스와 통신하지 않고 주문 정보들을 담는 배열을 만들어서 해당 배열에 주문 정보들을 저장해두었으나, 이제는 주문 서비스와 연동하여 데이터를 가져오는 작업을 하기 위해 수정 작업 진행
💡 추가 설명
Environment와RestTemplate추가 이유
1.Environment: 설정에 저장해 둔 정보(Order-service의 URL)를 가져오기 위함
2.RestTemplate: 빈으로 등록해 둔RestTemplate를 사용하기 위함orderUrl
Order-service의getOrder메서드를 호출하는 URL를 직접 입력
URL 주소가 하드코딩 되어 있기 때문에, 주소가 변경 시 해당 URL 주소도 함께 변경 필요
➡ 지양하는 방법이며 추후에 하드코딩 된 주소를 마이크로서비스의 이름으로 변경 예정
👇 참고:getOrder()메서드는 다음과 같음
➡getOrder()의 반환값이ResponseEntity<List<ResponseOrder>>이기 때문에restTemplate를 통해 주문 서비스와 연동하여 주문 내역을 가져온 데이터 타입을 동일한ResponseEntity<List<ResponseOrder>>로 받아서 원하는 데이터를 사용exchange()
RestTemplate의exchange메서드는 HTTP 요청을 수행하고 그 응답을ResponseEntity로 받음
일반적으로 아래와 같은 네 가지 인자를 받음
1. 첫 번째 인자 : 요청을 보낸 URL
2. 두 번째 인자 : HTTP 메서드 설정
3. 세 번째 인자 : HTTP 요청의 본문(body)에 포함될 내용 (여기선GET요청이라 null 전달)
4. 네 번째 인자 : 반환되는 응답의 타입을 지정
➡ParameterizedTypeReference: 제네릭 타입을 정확히 지정하기 위해 사용
➡List<ResponseOrder>: 응답 본문이ResponseOrder객체를 포함하는 리스트 형식임을 나타냄
➡new ParameterizedTypeReference<List<ResponseOrder>>() {}: 익명 클래스 구문orderListResponse.getBody()
➡getBody()를 통해 HTTP 응답의 본문만 추출
Config 설정 파일의 user-service.yml 수정spring:
datasource:
driver-class-name: org.h2.Driver
url: jdbc:h2:mem:testdb
username: sa
password: '{cipher}AQA7s+ZM9LN/Jgo3adyUNHTa52h4/j4yhK98qhPnl6srDiDcT5ClW2wmSXI501GXS/Gy25BjRjHyKiIPoONk36jPsRIozYbfdr1coPrnSmNRiyU0mhVsUzcXlsRDRZAUrtd9nA0p3NI4quxozHov7a8fXwmnUfjB4NlQoXiXOAs0QtjcpaUpfdr0/6HOhaDhfjXjy8atmmsfiGaNByVgP49ddF/gKfk4Wj93GPR6zsvFnvq7zANhVuxvf0Q6xtOekHP1M1gWMTwG600EznUy/xVdgTKREYbvTDvgegKmMEKCKNEpn4CeHMn9cCQatOeoCI5Kan38WWFOAUaavdRZrhLPogfXZq4ZZYZUc3f+G1zUjR7oYvsuD4rheEC/2yJ3Q+Q='
token:
expiration_time: 86400000
secret: my_secret_token_by_1126_#2
gateway:
ip: 192.168.0.100
order_service:
url: http://127.0.0.1:8000/order-service/%s/orders #추가
User-service의 UserServiceImpl.java 수정@Override
public UserDto getUserByUserId(String userId) {
UserEntity userEntity = userRepository.findByUserId(userId);
if(userEntity == null){
//로그인 인증 시 사용하는 것이나, 사용자가 없다는 비슷한 의미로 해당 예시에서 사용
throw new UsernameNotFoundException("User not found");
}
UserDto userDto = new ModelMapper().map(userEntity, UserDto.class);
// List<ResponseOrder> orders = new ArrayList<>();
/* Using as rest template */
String orderUrl = String.format(env.getProperty("order_service.url"), userId); //변경
ResponseEntity<List<ResponseOrder>> orderListResponse = restTemplate.exchange(orderUrl, HttpMethod.GET, null,
new ParameterizedTypeReference<List<ResponseOrder>>() {
});
List<ResponseOrder> orderList = orderListResponse.getBody();
userDto.setOrders(orderList);
/* End */
return userDto;
}
➡ 메서드에 하드코딩을 했던 URL 주소를 설정 파일로 관리하여, 설정 파일의 주소를 불러옴
💡 한 눈에 보기
- 변경 전
String orderUrl = "http://127.0.0.1:8000/order-service/%s/orders";
- 변경 후
//변경 후 String orderUrl = String.format(env.getProperty("order_service.url"), userId);
- 설정 파일
order_service: url: http://127.0.0.1:8000/order-service/%s/orders
➡ Eureka Server, GW Server, Config Server, User-service, Order-service 기동 필요
회원 가입

주문

주문내역 확인
#1. 데이터베이스에서 확인
➡ 127.0.0.1:{order-service의 port 번호}/h2-console

#2. User-service를 통해 확인

✅ 주의 사항
1.Token값 등록하여 권한 부여 필수
2. 이미user-service가 기동 중에 설정 파일(user-service.yml)을 변경했다면 적용 필요
➡127.0.0.1:8000/e-user-service/actuator/busrefresh실행
#3. Order-service를 통해 확인

🤔 주문내역 확인 차이점
user-service를 통해 주문내역 확인 시
사용자 정보 + 주문 내역 확인 가능order-service를 통해 주문내역 확인 시
주문 내용만 확인 가능
➡ 기존에 127.0.0.1:8000 으로 주소를 하드코딩 했던 부분을 마이크로서비스의 이름으로 변경
User-service의 EUserServiceApplication 수정package com.example.euserservice;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.web.client.RestTemplate;
@SpringBootApplication
@EnableDiscoveryClient
public class EUserServiceApplication {
public static void main(String[] args) {
SpringApplication.run(EUserServiceApplication.class, args);
}
@Bean
public BCryptPasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
@Bean
@LoadBalanced //추가
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
}
💡
@LoadBalanced란?
RestTemplate또는WebClient에 부하 분산 기능을 추가- 부하 분산 기능은 일반적으로
Eureka,Consul,Zookeeper와 같은 서비스 디스커버리 시스템을 기반으로 동작
Config 설정 파일의 user-service.yml 수정spring:
datasource:
driver-class-name: org.h2.Driver
url: jdbc:h2:mem:testdb
username: sa
password: '{cipher}AQA7s+ZM9LN/Jgo3adyUNHTa52h4/j4yhK98qhPnl6srDiDcT5ClW2wmSXI501GXS/Gy25BjRjHyKiIPoONk36jPsRIozYbfdr1coPrnSmNRiyU0mhVsUzcXlsRDRZAUrtd9nA0p3NI4quxozHov7a8fXwmnUfjB4NlQoXiXOAs0QtjcpaUpfdr0/6HOhaDhfjXjy8atmmsfiGaNByVgP49ddF/gKfk4Wj93GPR6zsvFnvq7zANhVuxvf0Q6xtOekHP1M1gWMTwG600EznUy/xVdgTKREYbvTDvgegKmMEKCKNEpn4CeHMn9cCQatOeoCI5Kan38WWFOAUaavdRZrhLPogfXZq4ZZYZUc3f+G1zUjR7oYvsuD4rheEC/2yJ3Q+Q='
token:
expiration_time: 86400000
secret: my_secret_token_by_1126_#2
gateway:
ip: 192.168.0.100
order_service:
url: http://order-service/order-service/%s/orders #마이크로서비스 이름으로 주소 변경

➡ 다른 테스트값으로 진행 시 정상작동 함을 확인 가능