티스토리 뷰

MSA

Section 4: Users Microservice -1

✨✨✨✨✨✨✨ 2023. 6. 7. 16:52
반응형

 

사용자 요청을 [API Gateway] 통해 들어오고 [Eureka]를 통해 해당 서비스를 찾습니다.

그 3가지 중 [User Service]라는 Micro Service를 JPA를 활용하여, H2 DB로 개발할 예정입니다.

단, UI없이 작업없이 진행할 예정입니다.

API는 아래와 같습니다

기능 URI(API Gateway 사용 시) URI(API Gateway 미사용 시) HTTP Method

사용자 정보 등록 /user-service/users /users POST
전체 사용자 조회 /user-service/users /users GET
사용자 정보,      
주문 내역 조회 /user-service/users/{user_id} /users/{user_id} GET
작동 상태 확인 /user-service/users/health_check /users/health_check GET
환영 메시지 /user-service/users/welcome /users/welcome GE

User Microservice 프로젝트 생성

java 11

spring boot: 2.6.3

spring-cloud: 2021.0.7

mysql Ver 8.0.33

dependency

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-devtools</artifactId>
    <scope>runtime</scope>
    <optional>true</optional>
</dependency>
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>

UserServiceApplication.java

@SpringBootApplication
@EnableDiscoveryClient
public class UserServiceApplication {
    public static void main(String[] args) {
        SpringApplication.run(UserServiceApplication.class, args);
    }
}
  • application.yml에 uereka 서버에 등록한 후, DiscoveryClient로 등록한다.

application.yml

server:
  port: 0

spring:
  application:
    name: user-service
  database:
    jdbc-url: jdbc:mysql://localhost:3030/testdb?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTC
    username: root
    password: 
    driver-class-name: com.mysql.jdbc.Driver

eureka:
  instance:
    instance-id: ${spring.application.name}:${spring.application.instance_id:${random.value}}
  client:
    register-with-eureka: true
    fetch-registry: true
    service-url:
      defaultZone: <http://localhost:8761/eureka>

greeting:
  message: Welcom to the Simple E-commerce.

참고로 eureka서버는 아래와 같이 설정되어있다.

application.yml

server:
  port: 8761

spring:
  application:
    name: discoveryservice

eureka:
  client:
    register-with-eureka: false
    fetch-registry: false

Application.java

@SpringBootApplication
@EnableEurekaServer
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

}

 


Users MicroService - JPA

  기능 URI(API Gateway 사용 시) URI(API Gateway 미사용 시) HTTP
Method
1 사용자 정보 등록 /user-service/users /users POST
2 전체 사용자 조회 /user-service/users /users GET
3 사용자 정보, 주문 내역 조회 /user-service/users/{user_id} /users/{user_id} GET
4 작동 상태 확인 /user-service/users/health_check /users/health_check GET
5 환영 메시지 /user-service/users/welcome /users/welcome GET

 

아래 그림과 같이 용도별로 Entity를 만들것

  • RequestUser, ResponseUser는 Controller에서 요청 및 응답 시 사용
  • UserDto의 경우 Request, Response와 Entity 사이 DTO역할
  • UserEntity : JPA @Entity 객체

RequestUser → UserDto → UserEntity → UserDto → ResponseUser

위 흐름으로 객체들이 흘러간다.

또한 함께 Spring Security도 간단하게 추가한다.

 

 

 

pom.xml

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
        <scope>runtime</scope>
        <optional>true</optional>
    </dependency>
    
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-validation</artifactId>
        <version>3.0.4</version>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>

    <dependency>
        <groupId>org.modelmapper</groupId>
        <artifactId>modelmapper</artifactId>
        <version>3.0.0</version>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>

    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.28</version>
    </dependency>
</dependencies>

UserServiceApplication.java

@SpringBootApplication
@EnableDiscoveryClient
public class UserServiceApplication {

    public static void main(String[] args) {
        SpringApplication.run(UserServiceApplication.class, args);
    }

    @Bean
    public BCryptPasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}

WebSecurity.java

@Configuration
@EnableWebSecurity
public class WebSecurity extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable();
        http.authorizeRequests().antMatchers("/users/*").permitAll();
    }
}

UserController.java

@RestController
@RequestMapping("/")
@RequiredArgsConstructor
public class UserController {
    private final Greeting greeting;
    private final UserService userService;

    @GetMapping("/health_check")
    public String status(){
        return "It's Working in User Service";
    }

    @GetMapping("/greeting")
    public String getGreeting(){
        return greeting.getMessage();
    }

    @PostMapping("/users")
    public ResponseEntity<?> createUser(@RequestBody UserRequest userRequest){
        ModelMapper modelMapper = new ModelMapper();
        modelMapper.getConfiguration().setMatchingStrategy(MatchingStrategies.STRICT);

        UserDto userDto = modelMapper.map(userRequest, UserDto.class);
        userDto = userService.createUser(userDto);
        UserResponse userResponse = modelMapper.map(userDto, UserResponse.class);
        return new ResponseEntity<>(userResponse, HttpStatus.CREATED);
    }
}

UserRequest.java

@Data
public class UserRequest {
    @NotNull(message = "Email cannot be null")
    @Size(min = 2, message = "Email not be less than two characters")
    @Email
    private String email;

    @NotNull(message = "Name cannot be null")
    @Size(min = 2, message = "Name not be less than two characters")
    private String name;

    @NotNull(message = "Password cannot be null")
    @Size(min = 8, message = "Password must be equal or grater than 8 characters and less than 16 characters")
    private String pwd;
}

UserDto.java

@Data
public class UserDto {
    private String email;
    private String name;
    private String userId;
    private String pwd;
    private String encryptedPwd;
    private Date createAt;
}

UserEntity.java

@Data
@Entity
@Table(name = "users")
public class UserEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(nullable = false, length = 50, unique = true)
    private String email;
    @Column(nullable = false, length = 50)
    private String name;
    @Column(nullable = false, unique = true)
    private String userId;
    @Column(nullable = false)
    private String encryptedPwd;
    @Column(nullable = false)
    private Date createAt;
}

UserRepository.java

@Repository
public interface UserRepository extends CrudRepository<UserEntity, Long> {

}

UserResponse.java

@Data
public class UserResponse {
    private String email;
    private String name;
    private String userId;
}

UserService.java

public interface UserService {
    UserDto createUser(UserDto userDto);
}

UserServiceImpl.java

@Service
@RequiredArgsConstructor
public class UserServiceImpl implements UserService{
    private final UserRepository userRepository;
    private final BCryptPasswordEncoder passwordEncoder;

    @Override
    public UserDto createUser(UserDto userDto) {
        ModelMapper modelMapper = new ModelMapper();
        modelMapper.getConfiguration().setMatchingStrategy(MatchingStrategies.STRICT);
        UserEntity userEntity = modelMapper.map(userDto, UserEntity.class);

        userEntity.setUserId(UUID.randomUUID().toString());
        userEntity.setEncryptedPwd(passwordEncoder.encode(userDto.getPwd()));
        userEntity.setCreateAt(Timestamp.valueOf(LocalDateTime.now()));

        userRepository.save(userEntity);

        return modelMapper.map(userEntity, UserDto.class);
    }
}

 


하면서 모르겠는부분

RequestUser → UserDto(Service넘김) → UserEntity ( userRepository.save(userEntity) )

  RequestUser  UserDto  UserEntity
id     O
email O O O
name O O O
userId   O O
pwd O O  
encryptedPwd   O O
createAt   O O

 

createUser

ModelMapper mapper = new ModelMapper();
maper.getConfiguration().setMatchingStrategy(MatchingStrategies.STRICT);
@Data
@Entity
@Table(name = "users")
public class UserEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(nullable = false, length = 50, unique = true)
    private String email;
    @Column(nullable = false, length = 50)
    private String name;
    @Column(nullable = false, unique = true)
    private String userId;
    @Column(nullable = false)
    private String encryptedPwd;
    @Column(nullable = false)
    private Date createAt;
}

@Entity ⇒ JPA가 관리할 객체

@Table(name = "users") ⇒ 테이블명

@Id ⇒ 해당 Table의 PK

@GeneratedValue(strategy = GenerationType.IDENTITY)

@GeneratedValue - strategy

 

 

public interface UserRepository extends CrudRepository<UserEntity, Long> {
    
}
public class UserServiceImpl implements UserService{
    private final UserRepository userRepository;

@Override
    public UserDto createUser(UserDto userDto) {
userRepository.save(userEntity);
spring.jpa.hibernate.ddl-auto=update 
  -> create 하면 table 다 drop삭제되고 다시 만들어짐
	-> create-drop 하면 종료시점에 drop
	-> update 재시작 시 변경된 table alter 함
	   drop 은 안됨
	-> validate => 확인만함 db랑 구조 확인 

 

개발초기  create, update
stage(테스트 서버) update, validate
운영 validate, none
spring.jpa.generate-ddl=false
spring.jpa.show-sql=true
server.port=0

# DataSource Setting
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/testdb?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=gbitkim

# JPA Setting
spring.jpa.hibernate.ddl-auto=update
spring.jpa.generate-ddl=false
spring.jpa.show-sql=true
spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect
spring.jpa.properties.hibernate.format_sql=true

# Logging Setting
logging.level.org.hibernate=info

eureka.instance.instance-id=${spring.application.name}:${spring.application.instance_id:${random.value}}
eureka.client.register-with-eureka=true
eureka.client.fetch-registry=true
eureka.client.service-url.defaultZone=http://localhost:8761/eureka

greeting.message: Welcom to the Simple E-commerce.
반응형

'MSA' 카테고리의 다른 글

Section 7: Configuration Service  (0) 2023.06.07
Section 6: Users Microservice-2  (1) 2023.06.07
Section 3: E-commerce 애플리케이션  (0) 2023.06.07
Section 2: API Gateway Service  (0) 2023.06.07
Section 1: Service Discovery  (0) 2023.06.07
반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/12   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
글 보관함