์ด ๊ธ์ 2๊ฐ์ ๊ธ๋ก ๋๋์ด์ ธ ์์ต๋๋ค.
- ๋ง์ดํฌ๋ก์๋น์ค์์ ์๋น์ค๊ฐ ํต์ ์ ์ํ 2๊ฐ์ง ๋ฐฉ๋ฒ ๋น๊ต [OpenFeign vs Rest Template] - ์๋น์ค ๊ตฌํ
- ๋ง์ดํฌ๋ก์๋น์ค์์ ์๋น์ค๊ฐ ํต์ ์ ์ํ 2๊ฐ์ง ๋ฐฉ๋ฒ ๋น๊ต [OpenFeign vs Rest Template] - ๊ฐ๊ฐ์ ๋น๊ต
ํด๋น ๊ธ์์ ๋์ค๋ ์ค์ต ๋ด์ฉ์ Spring Cloud๋ฅผ ์ด์ฉํ MSA ๊ตฌ์ฑ์ ์ ๋ฐ์ ์ธ ์ดํด๊ฐ ํ์ํ ๋ด์ฉ์ ๋๋ค.
์ค์ต์ Eureka + Gateway + Microservices (2)๋ฅผ ์ด์ฉํ ํ๊ฒฝ์ผ๋ก ํด๋น ๊ธ์์๋ Eureka์ Gateway ์ค์ ์ ๋ํด์๋ ์ธ๊ธํ์ง ์ง๋ง ๋ง์ฝ Eureka๋ Gateway์ ์ดํด๊ฐ ๋ถ์กฑํ์ ๋ถ๋ค์ด๋ ๋ ์์๋ณด๊ณ ์ค์ต ํ๊ฒฝ์ ๋ฐ๋ผ ํด๋ณด๊ณ ์ถ์ ์ฌ๋์ ์๋์ ์ค์ต ๊ณผ์ ์ ์กด์ฌํ๋ URL์์ ํ์ธํ์ค ์ ์์ต๋๋ค.
๋ชฉ์ฐจ
์ด๋ฒ ์๊ฐ
- ์๋น์ค๊ฐ ํต์
- ์๋น์ค ๊ตฌ์กฐ
- ํต์ ๊ณผ์
- ์๋น์ค ๊ตฌํ
- ์๋น์ค ๊ตฌ์ฑ
- Eureka Service
- Gateway Service
- User Service
- Team Service
- ์๋น์ค ๊ตฌ์ฑ
๋ค์ ์๊ฐ
- Rest Template ์ผ๋ก ํต์ ํ๊ธฐ
- Spring Cloud OpenFeign ์ผ๋ก ํต์ ํ๊ธฐ
- ๋ ํต์ ๋ฐฉ๋ฒ์ ์ฐจ์ด
- ์ ์ธ ๋ฐฉ์๊ณผ ์ฝ๋ ๊ฐ๋ ์ฑ
- ์์ธ ์ฒ๋ฆฌ
- ์ ์ง๋ณด์
- ํ ์คํธ ์ฝ๋
- ์ข
ํฉ ์ ๋ฆฌ ๋ฐ ๊ฒฐ๋ก
- ํ๋ก ์ ๋ฆฌ
- rest template deprecated
Microservices ์์ ์๋น์ค๊ฐ์ ํต์
๋ง์ดํฌ๋ก์๋น์ค์์๋ ํ๋์ ๊ธฐ๋ฅ์ ์ํํ๊ธฐ ์ํด์ ๊ฐ๊ฐ์ ๋ง์ดํฌ๋ก์๋น์ค ์ธ์คํด์ค๋ค์ด ์ ๊ธฐ์ ์ผ๋ก ์ํธ์์ฉ์ ํด์ ์ ์ ํ ๋ฐ์ดํฐ๋ฅผ ์ฌ์ฉ์์๊ฒ ๋ด๋ ค์ฃผ๋ ๋ฐฉ์์ ์ทจํ๋ค.
๋ณดํต์ MSA ์์ ๊ฐ๊ฐ์ ์๋น์ค๋ RESTful ํ API๋ฅผ ์ ๊ณตํ๋๋ฐ, ์ด ๋ ๊ฐ๊ฐ์ ์๋น์ค๋ ํน์ ์๋น์ค๊ฐ ๋ ธ์ถํ๋ Endpoint ์ API ํธ์ถ์ ํตํด์ ๋ฐ์ดํฐ๋ฅผ ์กฐ์ํ๋ค.
๋ํ์ ์ผ๋ก MSA ์์ ์ฌ์ฉํ๋ 2๊ฐ์ง ํต์ ๋ฐฉ์์ด ์กด์ฌํ๋ค.
- Rest Template
- Spring Cloud OpenFeign
์ค๋์ ์ง์ ์๋น์ค๋ฅผ ๋ง๋ค๋ฉด์ ๊ฐ๊ฐ์ ๋ฐฉ์์ ์ฐจ์ด์ ์ ๋ํด์ ์์๋ณด๊ณ ์ด๋ค ์๋น์ค๊ฐ ์ด๋์ ํจ๊ณผ์ ์ธ์ง ์ ๋ฆฌ๋ฅผ ํด๋ณด๋ ์๊ฐ์ ๊ฐ์ ธ๋ณด๋๋ก ํ๊ฒ ๋ค.
์ด๋ฒ ๊ธ์ ์ค์ต์ด ํต์ฌ์ธ ๋ด์ฉ์ด๋ฏ๋ก ์๋น์ค ๊ตฌ์ฑ์ ์กฐ๊ธ ์ ๊ฒฝ์ ์จ๋ณด์.
์๋น์ค ๊ตฌํ
์ฐ๋ฆฌ๋ ์ถ๊ตฌ ํ ๊ด๋ฆฌ ์๋น์ค์์ ์ฌ์ฉ์ id ๋ฅผ ๋ฐ์ผ๋ฉด ํ์ ์ ์ฅํ๋ ๋ฉ์๋๋ฅผ ๊ตฌํํด๋ณผ ๊ฒ์ด๋ค.
๋ฌด์์ ๋ง๋ค ๊ฒ์ธ๊ฐ?
- ์ถ๊ตฌ ํ ๊ด๋ฆฌ ์๋น์ค์ ํ ์ ์ฅ ์๋น์ค
์ด๋ป๊ฒ ๋ง๋ค ๊ฒ์ธ๊ฐ?
- 2๊ฐ์ Service Mesh์ 2 ๊ฐ์ Microservices
- Service Mesh
Discovery Service
Gateway Service
- Microservices
User Service
: ์ฌ์ฉ์ ์๋น์คTeam Service
: ํ ์๋น์ค
- Service Mesh
์ด๋ ํ End Point๋ฅผ ๋ ธ์ถํ ๊ฒ์ธ๊ฐ
- Discovery Service
http://localhost:8761/eureka
- Gateway Service
http://localhost:8000/
- User Service
- ์ ์ ์์ฑ :
http://localhost:50010/users
POST - ์ ์ ์กฐํ :
http://localhost:50010/users/{userId}
GET
- ์ ์ ์์ฑ :
- Team Service
- ํ ์์ฑ :
http://localhost:60010/teams
POST - ํ์ ์ถ๊ฐ :
http://localhost:60010/{userId}/teams
POST - ์ฌ์ฉ์ ๋ฒํธ๋ก ํ ๊ฒ์ :
http://localhost:60010/{userId}/teams
GET
- ํ ์์ฑ :
์ค์ง์ ์ธ ์๋ฒ์ ํฌํธ๋ 50010๊ณผ 60010๋ฒ์ด์ง๋ง ์ฐ๋ฆฌ๋ Gateway๋ฅผ ์ด์ฉํด์ 8000 ๋ฒ์ผ๋ก Endpoint๋ฅผ ํฉ์ณ๋ณด์
๊ฐ Endpoint๋ ์ด๋ ํ API ์๋ต์ ๋ฐํํ ๊ฒ์ธ๊ฐ
// ์ ์ ์์ฑ : http://localhost:50010/users POST
REQUEST
{
"username": "์ฅ์์ต",
}
RESPONSE
{
"userId": "1",
"username": "์ฅ์์ต",
}
// ์ ์ ์กฐํ : http://localhost:50010/users/{userId} GET
RESPONSE
{
"userId": "1",
"username": "์ฅ์์ต",
"name": [null, "๋ฆฌ๋ฒํ"]
}
// ํ ์์ฑ : http://localhost:60010/teams POST
REQUEST
{
"name": "๋ฆฌ๋ฒํ",
"address": "์๊ตญ ๋จธ์ง์ฌ์ด๋"
}
RESPONSE
{
"teamId": "1",
"name": "๋ฆฌ๋ฒํ",
"address": "์๊ตญ ๋จธ์ง์ฌ์ด๋"
}
// ํ์ ์ถ๊ฐ : http://localhost:60010/{userId}/teams POST
REQUEST
{
"teamname": "๋ฆฌ๋ฒํ"
}
RESPONSE : 204 No Content
// ์ฌ์ฉ์ ๋ก ํ ๊ฒ์ : http://localhost:60010/{userId}/teams GET
RESPONSE
{
"teamId": "1",
"name": "๋ฆฌ๋ฒํ",
"address": "์๊ตญ ๋จธ์ง์ฌ์ด๋"
}
๊ตฌํ ์์
- Eureka Server ๊ธฐ๋
- Gateway Server ๊ธฐ๋
- User Service ๊ตฌํ (API ํธ์ถ ์ ์ธ)
- Order Service ๊ตฌํ
- User Service ์์ Order Service๋ก API ํธ์ถ (Rest Template vs Feign)
Eureka Server
์ ๋ ์นด ์๋ฒ๋ Service Discovery๋ฅผ ์ํด์ ์ฌ์ฉ๋๋ค.
๊ธฐ๋ณธ ์ค์ ๋ง์ผ๋ก๋ ์ฐ๋ฆฌ๊ฐ ํ๋ ค๋ ๊ฒ์ฆ์ ์ํ ์ค๋น๊ฐ ์ถฉ๋ถํ๋ ๋ค์๊ณผ ๊ฐ์ด Application.java.์ application.yml ๋ง ์์ ํด๋๋ก ํ์.
์์ธํ ์์กด์ฑ๊ณผ ์ค์ ์ Service Discover Server๋ก Netflix Eureka ์ด์ฉํ๊ธฐ ์์ ํ์ธํ ์์๋ค.
EurekaServerApplication.java
@SpringBootApplication
@EnableEurekaServer
public class EurekaServiceApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaApplication.class, args);
}
}
yml ์๋ ์๊ธฐ ์ค์ค๋ก๋ฅผ eureka instance ๋ก ๋ฑ๋กํ์ง ๋ง๋ผ๋ 2๊ฐ์ ์ค์ ์ false ๋ก ์ง์ ํ๋ค.
server:
port: 8761
spring:
application:
name: discovery-service
eureka:
client:
register-with-eureka: false
fetch-registry: false
Gateway Server
Gateway ์๋ฒ๋ ๋ง์ดํฌ๋ก์๋น์ค๋ค์ Endpoint๋ฅผ ํ๋๋ก ๋ชจ์์ฃผ๋ ์ฉ๋ ํ์ฌ ์ฌ์ฉ๋๋ค.
API Gateway ํจํด์์ ์ฌ์ฉ๋๋ Gateway๋ ๋ค์ํ ๊ธฐ๋ฅ (๋ก๋๋ฐธ๋ฐ์ฑ, ์ธ์ฆ, ๋ก๊น
)์ด ์์ง๋ง ํ์ฌ๋ก์จ๋ Endpoint๋ฅผ ๋จ์ผํ ํ๋ ์ฉ๋๋ก๋ง ์ฌ์ฉํ ๊ฒ์ด๋ค.
๋ง์ฐฌ๊ฐ์ง๋ก Spring Cloud Gateway ๋ ๋ค์ ๋งํฌ๋ค์์ ํ์ธํ ์ ์๋ค.
- Spring Cloud Gateway ๋ฅผ ์ด์ฉํด API Gateway๋ฅผ ๊ตฌ์ฑํ๊ณ ์ค์ตํด๋ณด์
- Spring Cloud Gateway ์์ Built-in Route๋ก Predicates์ Filter ์กฐ์ํ๊ธฐ
- Custom Filter ๋ก ๊ฐ๋จํ Authentiction ํํฐ ๋ง๋ค๊ณ ์ธ์ฆ ์ฒ๋ฆฌํ๊ธฐ
GatewayServiceApplication.java
@SpringBootApplication
@EnableDiscoveryClient
public class GatewayServiceApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayServiceApplication.class, args);
}
}
Gateway ์ ๋ํ ์ค์ ํ์ผ์์ ๊ณ ๋ คํด์ผํ ์ฌํญ์ 2๊ฐ์ง์ด๋ค.
- Eureka Instance ๋ฑ๋ก
- Gateway Route ์ ๋ณด ์์
Route ์ ๋ณด ์์ ์์๋ /user
๋ก ํธ์ถ๋๋ ๋ชจ๋ url ์ USER-SERVICE ๋ก ๋ฐ์ธ๋ฉ ์ํค๊ณ /team
์ผ๋ก ํธ์ถ๋๋ url ์ TEAM-SERVICE ๋ก ๋ฐ์ธ๋ฉ ์์ผ์ฃผ์
application.yml
server:
port: 8000
eureka:
client:
fetch-registry: true
register-with-eureka: true
service-url:
defaultZone: http://localhost:8761/eureka
spring:
application:
name: gateway-service
cloud:
gateway:
routes:
- id: user-service
uri: lb://USER-SERVICE
predicates:
- Path=/user/**
filters:
- RewritePath=/user/?(?<segment>.*), /$\{segment}
- id: team-service
uri: lb://TEAM-SERVICE
predicates:
- Path=/team/**
filters:
- RewritePath=/team/?(?<segment>.*), /$\{segment}
User Service ๊ตฌํ (API ํธ์ถ ์ ์ธ)
User Service ์์๋ API ํธ์ถ์ ์ํํ๋ ์ ์ ์กฐํ ๋ง ๋นผ๊ณ ์์ฑํด๋ณด์.
๊ฐ๋จํ๊ฒ ๋ค์๊ณผ ๊ฐ์ Layered Architecture ๋ก ๊ตฌ์ฑ์ ํ๋ ค ํ๋ค.
- ์์กด์ฑ ์ถ๊ฐ & application.yml
- Controller
- UserController
- Domain
- Entity
- User
- Repository
- UserRepository
- dto
- UserRegisterRequestData
- UserResponseData
- Entity
- Service
- UserService
์์กด์ฑ ์ถ๊ฐ & application.yml
build.gradle ์ ๋ค์๊ณผ ๊ฐ์ด ์์กด์ฑ์ ์ถ๊ฐํด์ฃผ๋๋ก ํ์.
์ด ์ค์ ์ Team Service ๋ User Service ๋ ๋์ผํ๋ฏ๋ก Team Service ์์๋ ์๋ตํ๋๋ก ํ๊ฒ ๋ค. port ๋ง ๋ค๋ฅด๊ฒ ์ง์ ํ์
ext {
set('springCloudVersion', "2020.0.2")
}
dependencies {
// web
implementation 'org.springframework.boot:spring-boot-starter-web'
// jpa
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
// h2 database
runtimeOnly 'org.h2database:h2'
// eureka
implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-client'
// lombok
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
dependencyManagement {
imports {
mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
}
}
๊ทธ๋ฆฌ๊ณ ์ด์ ํด๋น ์๋น์ค๋ฅผ Eureka ํด๋ผ์ด์ธํธ๋ก ๋ฑ๋ก์ํค๊ธฐ ์ํ ์์ ๊ณผ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฐ๋ ์์ ์ ์ํด์ applicaton.yml ์ ๋ค์๊ณผ ๊ฐ์ด ์์ฑํ๋ค.
server:
port: 50010
spring:
application:
name: user-service
datasource:
url: jdbc:h2:mem:userdb
username: sa
password:
h2:
console:
enabled: true
settings:
web-allow-others: true
path: /h2-console
eureka:
client:
register-with-eureka: true
fetch-registry: true
service-url:
defaultZone: http://localhost:8761/eureka
๋ํ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ h2๋ก ์ฌ์ฉํ๊ณ ์ธ๋ฉ๋ชจ๋ฆฌ์์๋ง ๋์ํ๊ฒ ํ๊ธฐ ์ํ ์ค์ ๋ ์ถ๊ฐํ์๋ค.
Domain ์์ฑํ๊ธฐ
Domain ์๋ 3๊ฐ์ ํด๋์ค๊ฐ ์์นํ ๊ฒ์ด๋ค.
- ์์์ฑ ์ปจํ ์คํธ์ ๋ฑ๋ก์ํฌ Entity ๊ฐ์ฒด
- Data Jpa ์์ ์ ๊ณตํ๋ JpaRepository ์ธํฐํ์ด์ค๋ฅผ ์์๋ฐ๋ ์ปค์คํ Repository
- ๋ฐ์ดํฐ ์ ์ก์ ์ํ ๋ฐ์ดํฐ ๊ฐ์ฒด
๊ฐ๊ฐ์ ํด๋์ค๋ฅผ ๋ค์๊ณผ ๊ฐ์ด ๊ตฌํํด์ฃผ์.
// lombok ์ด๋
ธํ
์ด์
์๋ต
public class UserResponseData {
private Long userId;
private String username;
private TeamResponseData team;
}
// lombok ์ด๋
ธํ
์ด์
์๋ต
public class UserCreateData {
private String username;
}
// lombok ์ด๋
ธํ
์ด์
์๋ต
public class TeamResponseData {
private Long teamId;
private String name;
private String address;
}
@Entity(name = "users")
// lombok ์ด๋
ธํ
์ด์
์๋ต
public class User {
@Id @GeneratedValue
private Long id;
private String username;
}
public interface UserRepository extends JpaRepository<User, Long> {
}
UserService.class
User-Service ์ ๋น์ฆ๋์ค ๋ก์ง์ ๋ด๋นํ ํด๋์ค์ด๋ค.
ํด๋น ๋ถ๋ถ์ Rest Template๋ Feign Client ๊ฐ ํฌํจ๋ ์์ ์ด๋ค.
@Service
@Transcational
public class UserService {
private final UserRepository userRepository;
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
/**
* ์ฌ์ฉ์๋ฅผ ์ ์ฅํ๋ค
*
* @param userCreateData ์ ์ฅํ๋ ค๋ ์ฌ์ฉ์ ์ด๋ฆ
* @return ์ ์ฅ๋ ์ฌ์ฉ์
*/
public UserResponseData save(UserCreateData userCreateData) {
User user = User.builder()
.username(userCreateData.getUsername())
.build();
user = userRepository.save(user);
// Rest Template or Feign Client ์์
์ฒ๋ฆฌ
return UserResponseData.builder()
.userId(user.getId())
.username(user.getUsername())
.team(null) // Rest Template or Feign Client
.build();
}
/**
* ์ฌ์ฉ์๋ฅผ ์กฐํํ๋ค.
*
* @param id ์ฌ์ฉ์ id
* @return ์ ์ฅ๋ ์ฌ์ฉ์์ ํ ์ ๋ณด
* @throws RuntimeException
*/
public UserResponseData getUserById(Long id) {
User userOptional = userRepository.findById(id)
.orElseThrow(RuntimeException::new);
// Rest Template or Feign Client ์์
์ฒ๋ฆฌ
return UserResponseData.builder()
.userId(userOptional.getId())
.username(userOptional.getUsername())
.team(null)
.build();
}
}
Service ์ด๋ ธํ ์ด์ ๊ณผ ํจ๊ผ Transaction Boundary๋ฅผ ๊ฑธ์ด์ค๋ค.
์์ ์กด์ฌํ๋ .team(null)
์ ์ฐ๋ฆฌ๊ฐ ๋ค๋ฅธ ์๋ฒ๋ก ๋ถํฐ ๋ฐ์์จ ๋ฐ์ดํฐ๋ฅผ ๋ฃ์ด์ค ๊ฒ์ด๋ค.
UserController.class
์ธ๋ถ๋ก ๋ ธ์ถ์ํฌ User-Service ์ API Endpoint๋ฅผ ์์ฑํด์ค๋ค.
@RestController
public class UserController {
private final UserService userService;
public UserController(UserService userService) {
this.userService = userService;
}
@PostMapping("/users")
public UserResponseData createUser(@RequestBody UserCreateData userCreateData) {
return userService.save(userCreateData);
}
@GetMapping("/users/{userId}")
public UserResponseData getUser(@PathVariable("userId") Long id) {
return userService.getUserById(id);
}
}
์ด์ Eureka, Gateway ์ ํจ๊ป User-Service ๋ ์คํ์์ผ์ ๊ฐ๊ฐ์ Endpoint ๊ฐ ์ ์๋ํ๋์ง ๋ธ๋ผ์ฐ์ ๋ Api Tester ๋ก ํ ์คํธํด๋ณด์.
Team Service ๊ตฌํ
Team Service ๋ ์ญ์ Layered ๋ก ๊ตฌ์ฑํ๊ณ ํ์ ์์ฑ, ํ์ ์ฌ์ฉ์ ์ถ๊ฐ, ํ ์กฐํ ๋น์ฆ๋์ค๋ง ์๋ค๊ณ ๊ฐ์ ํด๋ณด์.
- Controller
- TeamController
- Domain
- Entity
- Team
- Repository
- TeamRepository
- dto
- TeamCreateData
- Entity
- Service
- TeamService
Domain ์์ฑํ๊ธฐ
DTO classes
public class TeamCreateData {
private String name;
private String address;
}
public class TeamMemberAddData {
private String name;
}
public class TeamResponseData {
private Long teamId;
private String name;
private String address;
}
Entity & Jpa Repository class and interface
public class Team {
@Id @GeneratedValue
private Long id;
private String name;
private String address;
}
public class TeamMember {
@Id @GeneratedValue
private Long id;
private Long userId;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "teamId")
private Team team;
}
public interface TeamRepository extends JpaRepository<Team, Long> {
Team findByName(String name);
}
public interface TeamMemberRepository extends JpaRepository<TeamMember, Long> {
TeamMember findByUserId(Long userId);
}
TeamService.class
Team ์ ๋น์ฆ๋์ค ๋ก์ง์ ๋ด๋นํ ํด๋์ค์ด๋ค.
User-Service ๊ฐ API ํธ์ถ์ ํ ์๋ํฌ์ธํธ๋ getTeamByUserId
์ด๋ค.
@Service
@Transactional
public class TeamService {
private final TeamRepository teamRepository;
private final TeamMemberRepository teamMemberRepository;
public TeamService(TeamRepository teamRepository, TeamMemberRepository teamMemberRepository) {
this.teamRepository = teamRepository;
this.teamMemberRepository = teamMemberRepository;
}
/**
* ํ์ ์์ฑํ๋ค.
*
* @param teamCreateData ํ ์์ฑ์ ํ์ํ ์ ๋ณด๊ฐ ๋ด๊ธด ๊ฐ์ฒด
* @return TeamResponseData (teamId, name, address)
*/
public TeamResponseData save(TeamCreateData teamCreateData) {
Team team = Team.builder()
.name(teamCreateData.getName())
.address(teamCreateData.getAddress())
.build();
team = teamRepository.save(team);
return TeamResponseData.builder()
.teamId(team.getId())
.name(team.getName())
.address(team.getAddress())
.build();
}
/**
* ํ ์ด๋ฆ๊ณผ ์ฌ์ฉ์ Id๋ฅผ ๋ฐ์ ํ์ ์ ์๋ก ๋ฑ๋กํ๋ค.
*
* @param userId ์ฌ์ฉ์ Id
* @param teamName ํ ์ด๋ฆ
*/
public void addTeamMember(Long userId, String teamName) {
Team selectedTeam = teamRepository.findByName(teamName);
TeamMember teamMember = TeamMember.builder()
.team(selectedTeam)
.userId(userId)
.build();
teamMemberRepository.save(teamMember);
}
/**
* ์ฌ์ฉ์ ๋ฒํธ๋ก ํ์ ๋ฐํํ๋ค.
*
* @param userId ์กฐํํ๋ ค๋ ์ฌ์ฉ์ ๋ฒํธ
* @return ๋ฐํํ ํ ๊ฐ์ฒด
*/
public TeamResponseData getTeamByUserId(Long userId) {
TeamMember teamMember = teamMemberRepository.findByUserId(userId);
Team team = teamMember.getTeam();
return TeamResponseData.builder()
.teamId(team.getId())
.name(team.getName())
.address(team.getAddress())
.build();
}
}
TeamController.class
@RestController
public class TeamController {
private final TeamService teamService;
public TeamController(TeamService teamService) {
this.teamService = teamService;
}
@PostMapping("/teams")
public TeamResponseData create(@RequestBody TeamCreateData teamCreateData) {
return teamService.save(teamCreateData);
}
@PostMapping("/{userId}/teams")
public ResponseEntity addTeamMember(@PathVariable("userId") Long id,
@RequestBody TeamMemberAddData requestData) {
teamService.addTeamMember(id, requestData.getName());
return ResponseEntity.noContent().build();
}
@GetMapping("/{userId}/teams")
public TeamResponseData getTeamByUserId(@PathVariable("userId") Long userId) {
return teamService.getTeamByUserId(userId);
}
}
์ด์ Team-Service์ ๋น์ฆ๋์ค ๋ก์ง์ ๋ค ๊ตฌํ์ด ๋์์ผ๋ API Tester๋ก ํ ์คํธ๋ฅผ ํด๋ณด์.
์ ์์ ์ผ๋ก ์ ๋์ํ๋ ๊ฒ์ ๋ณผ ์ ์๋ค.
์ด์ ๋ค์ ์๊ฐ๋ถํฐ ๋ณธ๊ฒฉ์ ์ผ๋ก Feign ๊ณผ RestTemplate ์ ๋น๊ตํ์
๋๊ธ