지난 글에 큰 문제를 만나 약 이틀을 그 문제를 해결하는 데에 소비했습니다.
아무튼 문제의 원인을 추측해서 문제를 해결을 했으니 다음에 비슷한 문제를 만나면
하나의 원인을 더 생각해볼 수 있게 되었습니다.
이번에는 지난 번 연동한 데이터베이스에 데이터 값을 전송합니다.
목적은 'SignupDto'의 데이터를 'User' 테이블의 필드에 맞게 넣는 것입니다.
함수를 하나 만들어 줍니다.
@Data
public class SignupDto {
private String username;
private String password;
private String email;
private String name;
public User toEntity() {
return User.builder() // 빌더패턴 사용
.username(username)
.password(password)
.email(email)
.name(name)
.build();
}
}
4개의 데이터를 기반으로 유저 객체가 만들어집니다.
지난번에 만든 'POST' 회원가입 도메인에 코드를 추가합니다.
@PostMapping("/auth/signup")
public String signup(SignupDto signupDto) {
log.info(signupDto.toString());
User user = signupDto.toEntity();
log.info(user.toString()); // 데이터가 잘 넘어오는지 콘솔창에서 확인
return "auth/signin";
}
그리고 도메인에 접속해 회원가입을 시도하면 데이터가 필드에 맞게 넘어오는 것을 확인할 수 있습니다.
데이터가 입력되지 않은 필드는 null 값이 들어갔습니다.
이제 이렇게 넘어오는 데이터를 데이터베이스에 넘길텐데, 그러기 위해서는 서비스가 필요합니다.
'com.cos.photogramstart' 아래에 'service' 패키지를 만들고 그 안에 'AutoService' 클래스를 만듭니다.
그리고 회원가입 메서드는 회원가입 진행을 하는데, 그러기 위해서는 레파지토리가 필요합니다.
package com.cos.photogramstart.service;
import org.springframework.stereotype.Service;
import com.cos.photogramstart.domain.user.User;
@Service // 1.IoC 등록, 2. 트랜잭션 관리
public class AuthService {
public void 회원가입(User user) {
// 회원가입 진행을 위해서는 repository 가 필요합니다.
}
}
'domain.user' 아래에 이 클래스를 만듭니다.
package com.cos.photogramstart.domain.user;
import org.springframework.data.jpa.repository.JpaRepository;
// 어노테이션이 없어도 'JpaRepository'를 상속하면 IoC 등이 자동으로 됩니다.
public interface UserRepository extends JpaRepository<User, Integer>{
}
'AuthController'에 아래의 코드를 추가합니다.
@RequiredArgsConstructor // final 필드를 DI 할 때 사용합니다.
@Controller // 1. IoC 등록, 2. 파일을 리턴합니다.
public class AuthController {
private static final Logger log = LoggerFactory.getLogger(AuthController.class);
@Autowired
private final AuthService authService;
'AutoService'의 코드를 수정합니다.
package com.cos.photogramstart.service;
import org.springframework.stereotype.Service;
import com.cos.photogramstart.domain.user.User;
import com.cos.photogramstart.domain.user.UserRepository;
import lombok.RequiredArgsConstructor;
@RequiredArgsConstructor
@Service // 1.IoC 등록, 2. 트랜잭션 관리
public class AuthService {
private final UserRepository userRepository;
public User 회원가입(User user) {
// 회원가입 진행을 위해서는 repository 가 필요합니다.
User userEntity = userRepository.save(user); // 데이터를 받아 저장합니다.
return userEntity;
}
}
'AutoController'의 코드를 수정합니다.
@PostMapping("/auth/signup")
public String signup(SignupDto signupDto) {
log.info(signupDto.toString());
User user = signupDto.toEntity();
log.info(user.toString());
User userEntity = authService.회원가입(user);
System.out.println(userEntity);
return "auth/signin";
}
지금 상태로 가입을 시도하면, id 값이 없다는 오류가 나게 됩니다.
지난번에 id 값을 자동으로 데이터베이스에 쌓이도록 했는데 이상합니다.
테이블의 스키마를 변경하려면 ddl-auto: create
로 저장해야해서 다시 실행해야합니다.
그러면 콘솔창에 'Hibernate: create table User (id integer not null auto_increment, ...)이 뜨게 됩니다.
사실 저는 이미 되어있습니다. 이후 ddl-auto: update
로 수정하고 저장합니다.
이 'ddl' 설정은 'application.yml'에 있습니다.
이제 회원가입을 시도하면 id 값이 1이되고 잘 들어갑니다.
실제로 잘 들어갔는지 DB를 확인해보면 잘 들어가있습니다.
위 프로그램은 'Sequel Pro'라는 데이터베이스 GUI 프로그램입니다.
photogram 데이터베이스의 User 테이블에 필드와 데이터가 잘 들어갔습니다!
하지만 비밀번호가 암호화되지 않았습니다.
'AutoService'의 회원가입 메서드에 어노테이션을 추가합니다.
@Transactional // 함수가 실행되고 종료될 때까지 트랜잭션 관리합니다. Write(Insert, Update, Delete)
public User 회원가입(User user) {
User userEntity = userRepository.save(user);
return userEntity;
}
'BCrypt' 암호화를 하며 이곳에 빈 등록을 합니다.
'SecurityConfig'가 IoC에 등록될 때 'Bean' 어노테이션을 읽어서 암호화인코더를 들고있습니다.
@Bean
public BCryptPasswordEncoder encode() {
return new BCryptPasswordEncoder();
}
'AuthService'에서 위의 암호화인코더를 사용합니다.
@RequiredArgsConstructor
@Service
public class AuthService {
private final UserRepository userRepository;
private final BCryptPasswordEncoder bCryptPasswordEncoder;
@Transactional
public User 회원가입(User user) {
String rawPassword = user.getPassword();
String encPassword = bCryptPasswordEncoder.encode(rawPassword);
// 입력한 비밀번호를 encPassword에 넣을 때 해시로 암호화합니다.
user.setPassword(encPassword);
...
}
바로 위의 'AuthService'의 회원가입 메서드 코드에 권한 설정 코드를 추가합니다.
...
String rawPassword = user.getPassword();
String encPassword = bCryptPasswordEncoder.encode(rawPassword);
user.setPassword(encPassword);
user.setRole("ROLE_USER"); // 회원가입 하는 모든 사용자의 권한을 ROLE_USER, 관리자는 ROLE_ADMIN
User userEntity = userRepository.save(user);
return userEntity;
}
}
비밀번호가 암호화되고 이 캡쳐에선 안보이지만 권한도 설정되었습니다.
다만 아직 문제가 남았는데, 중복이 걸러지지 않습니다.
계정을 만들 때 계정을 고유의 것인데, 같은 아이디로 만들어도 계정은 만들어 집니다.
일단 'ddl-auto: create'로 변경해서 저장합니다.
이 클래스의 속성값 username 위에 제한조건을 설정합니다.
그리고 'ddl-auto: update'로 변경해서 저장합니다.
콘솔창에 이런 문장이 하나 추가로 뜹니다.
'Hibernate: alter table User add constraint UK_jreodf78a7pl5qidfh43axdfb unique (username)'
그럼 이제 중복을 인정하지 않습니다. 어노테이션이 참 편리합니다.
@Column(unique = true)
private String username;
private String password;
콘솔창에서의 쿼리문 말고도, 아래처럼 'DESC user;' 이라는 쿼리문을 통해
username 이 unique인지 확인할 수 있습니다.
이제 만약 중복되는 username으로 가입을 시도한다면 500번 오류 창이 나타납니다.