3 분 소요

User Service

마이크로서비스로 등록할 유저 서비스를 만들어 보자.

마이크로서비스 환경에 집중하기 위해 프론트엔드단은 작업하지 않는다. 1

1

스프링 부트 프로젝트를 생성하자. Dependencies로 다음을 추가해주자.

Dependencies : DevTools, Lombok, Spring Web, Eureka Discovery Client

프로젝트 생성 후 유레카 서버에 등록하기 위해 어플리케이션 클래스에 애노테이션을 추가하자.

@SpringBootApplication
@EnableDiscoveryClient
public class UserServiceApplication {

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

}

application.yml 파일을 설정하자.

server:
  port: 0

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

greeting:
  message: Welcome to the Simple E-commerce

유저 컨트롤러를 만들어 보자.

@RestController
@RequestMapping("/")
public class UserController {
    private Environment env;

    @Autowired
    public UserController(Environment env){
        this.env=env;
    }

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

    @GetMapping("/welcome")
    public String welcome(){
        return env.getProperty("greeting.message");
    }
}

Environment 객체로 application.yml 의 값을 가져왔는데 @Value 어노테이션을 이용해 가져와보자.

@Component
@Data
//@AllArgsConstructor
//@NoArgsConstructor
public class Greeting {
    @Value("${greeting.message}")
    private String message;
}

User Controller

@GetMapping("/welcome")
    public String welcome(){
        //return env.getProperty("greeting.message");
        return greeting.getMessage();
    }

H2 Database 연동

H2 데이터베이스에 연동하기 위해 dependencies에 다음을 추가하자. h2 버전은 1.3.176 을 사용하였다.

<dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
    <version>1.3.176</version>
    <scope>runtime</scope>
</dependency>

application.yml h2 설정을 추가해주자.

spring:
  application:
    name: user-service
  h2:
    console:
      enabled: true
      settings:
        web-allow-others: true
      path: /h2-console

회원 가입

  • POST -> /users/

1

dependencies 추가

<dependency>
    <groupId>jakarta.validation</groupId>
    <artifactId>jakarta.validation-api</artifactId>
</dependency>

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

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

RequestUser

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

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

    @NotNull(message = "Password cannot be null")
    @Size(min=6,message = "Password must be equal or greater than 6 characters")
    private String pwd;
}

RequestUser 클래스는 json으로 사용자의 입력을 받을 클래스이다.

UserDto

@Data
public class UserDto {
    private String email;
    private String name;
    private String pwd;
    private String userId;
    private Date createdAt;

    private String encryptedPwd;
}

UserEntity

@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,unique = true)
    private String encryptedPwd;
}

UserRepository

public interface UserRepository extends CrudRepository<UserEntity, Long> {
}

RequestUser <-> UserDto<-> UserEntity 사이 객체를 다른 객체로 바꿔주기 위해 modelMapper를 이용할 것이다. 일일히 getter 와 setter을 이용해 변환해 주어도 되지만 번거롭기 때문이다.

userService

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

userServiceImpl

@Service
public class UserServiceImpl implements UserService{

    @Autowired
    UserRepository userRepository;

    @Override
    public UserDto createdUser(UserDto userDto) {
        userDto.setUserId(UUID.randomUUID().toString());

        ModelMapper mapper = new ModelMapper();
        mapper.getConfiguration().setMatchingStrategy(MatchingStrategies.STRICT);
        UserEntity userEntity = mapper.map(userDto, UserEntity.class);
        userEntity.setEncryptedPwd("encrypted_password");

        UserDto returnUserDto = mapper.map(userEntity, UserDto.class);
        return returnUserDto;
    }
}

사용자의 비밀번호를 암호화 해야한다. 이후 추가할 것이다.

UserController

@RestController
@RequestMapping("/")
public class UserController {
    private Environment env;
    private UserService userService;

    @Autowired
    public UserController(Environment env,UserService userService) {
        this.env = env;
        this.userService = userService;
    }

    @PostMapping("/users")
    public ResponseEntity<ResponseUser> createUser(@RequestBody RequestUser user) {
        ModelMapper mapper = new ModelMapper();
        mapper.getConfiguration().setMatchingStrategy(MatchingStrategies.STRICT);

        UserDto userDto = mapper.map(user, UserDto.class);
        userService.createdUser(userDto);

        ResponseUser responseUser = mapper.map(userDto, ResponseUser.class);

        //return new ResponseEntity(responseUser, HttpStatus.CREATED);
        return ResponseEntity.status(HttpStatus.CREATED).body(responseUser);
    }
}

ResponseUser

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

1 1

Spring Security 연동

사용자의 비밀번호 암호화를 위해 Spring Security를 이용하자

WebSecurityConfigurerAdapter 를 상속받는 Security Configuration 클래스를 생성하고 @EnableWebSecurity 어노테이션을 추가

Authentication -> configure(AuthenticationManagerBuilder auth) 메서드를 재정의

Password encode를 위한 BCryptPasswordEncoder 빈 정의

Authorization -> configure(HttpSecurity http) 매서드 재정의

dependencies 추가

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

WebSecurity

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

        http.headers().frameOptions().disable();
    }
}

UserServiceApplication

@SpringBootApplication
@EnableDiscoveryClient
public class UserServiceApplication {

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

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

UserServiceimpl 수정

@Service
@RequiredArgsConstructor
public class UserServiceImpl implements UserService{

    private final UserRepository userRepository;
    private final BCryptPasswordEncoder passwordEncoder;


    @Override
    public UserDto createdUser(UserDto userDto) {
        userDto.setUserId(UUID.randomUUID().toString());

        ModelMapper mapper = new ModelMapper();
        mapper.getConfiguration().setMatchingStrategy(MatchingStrategies.STRICT);
        UserEntity userEntity = mapper.map(userDto, UserEntity.class);
        userEntity.setEncryptedPwd(passwordEncoder.encode(userDto.getPwd()));

        userRepository.save(userEntity);

        UserDto returnUserDto = mapper.map(userEntity, UserDto.class);
        return returnUserDto;
    }
}

결과 1

비밀번호가 암호화 되었다.