이번에는 구글 소셜 로그인으로부터 제공받은 이름, 이메일, 프로필 이미지를 데이터베이스에 저장할 수 있도록 구현하였다. 이때 회원가입을 하지 않은 구글 계정의 경우, 성별, 나이대, 성별/나이대 공개 여부 필드를 더 추가해야하므로 회원가입 여부를 확인해서 로직을 두개로 나누었다.
현재까지 구현한 도메인 계층구조는 다음과 같다. 이번에 중점적으로 볼 것은 LoginController.java, User.java, MemberStatusResponse, SaveUserRequest.java, UserService.java 이다.

기존에 단순히 유저 정보를 로드했던 방식에서, 회원 여부를 확인하고 비회원일 경우 회원 가입 절차를 거칠 수 있도록 구글 이메일을 통해 여부를 파악하는 방식으로 변경하였다.
@GetMapping("/login/oauth2/code/google")
public ResponseEntity<MemberStatusResponse> requestUserInfo(@RequestParam(name="code") String code) throws Exception{
final String accessToken = socialOAuth.requestAccessToken(code);
String userInfo = socialOAuth.getUserInfo(accessToken);
try{
JSONObject jsonObject = new JSONObject(userInfo);
Optional<User> user = userService.findByEmail(jsonObject.getString("email"));
if (!user.isPresent()) {
String name = jsonObject.getString("name");
String email = jsonObject.getString("email");
String picture = jsonObject.getString("picture");
return ResponseEntity.ok()
.body(new MemberStatusResponse(Role.GUEST.name(), name, email,picture,accessToken));
}else{
return ResponseEntity.ok()
.body(new MemberStatusResponse(Role.USER.name(),accessToken));
}
}catch (Exception e){
return ResponseEntity.internalServerError()
.body(new MemberStatusResponse(Role.GUEST.name(),"false","false","false","false"));
}
}
user 변수에 getUserInfo 메서드를 통해 얻은 유저 정보 중 이메일을 통해 찾은 User 객체를 담는다. 회원이라면 이메일을 통해 발견된 객체가 담길 것이고 비회원이라면 일치하는 정보가 없으므로 null 이 담길 것이다.user 가 null 이라면 (if (!user.isPresent()))그럼 반환 dto 형식이 어떻게 되어있는지 확인해보자
@AllArgsConstructor
@RequiredArgsConstructor
@Getter
public class MemberStatusResponse {
@NonNull
private String role;
private String name;
private String email;
private String picture;
@NonNull
private String accessToken;
public User toEntity() {
return User.builder()
.role(Role.GUEST)
.name(name)
.email(email)
.accessToken(accessToken)
.build();
}
}
✅ @RequiredArgsConstructor 은 클래스 객체 생성 시 생성자에 @NonNull 어노테이션이 붙어있는 변수만 전달 인자로 담길 수 있도록 한다. 따라서 이미 회원인 계정인 경우에는 @NonNull 인 role과 accessToken 만 response에 담을 수 있게 돼고 비회원인 경우에는 @AllArgsConstructor 로 모든 필드를 response에 담아 보내게 되는 것이다.
이제 비회원인 구글 계정이 이 서비스의 회원이 될 수 있도록 회원가입 기능을 추가한다.
@PostMapping("/api/signup")
public ResponseEntity signUp(@RequestBody SaveUserRequest request) {
User save = userService.save(request);
try {
return ResponseEntity.status(HttpStatus.CREATED)
.body(save);
}catch (Exception e){
return ResponseEntity.internalServerError()
.body(save);
}
}
SaveUserRequest dto 형식대로 작성된 json을 request로 받으면 이것을 save 해준다.UserService 클래스는 JpaRepository<User,Long> 을 상속한다. 이렇게 코드가 간단해질 수가..✅ LoginController.java 의 requestUserInfo 메서드에서 회원 여부 확인 시에 사용된 findByEmail 도 jpaRepository의 기능을 이용한 것이다. findBy + 엔티티의 필드명 으로 메서드 이름을 짜면 해당 엔티티의 필드로 검색한 쿼리 결과를 반환한다. 좋다..
- 참고로countBy + 엔티티의 필드명 은 쿼리 결과의 레코드 수를 반환한다.
@Getter
public class SaveUserRequest {
private String name;
private String email;
private String picture;
private char gender;
private String age;
private boolean genderVisible;
private boolean ageVisible;
public User toEntity() {
return User.builder()
.name(name)
.email(email)
.picture(picture)
.gender(gender)
.age(age)
.genderVisible(genderVisible)
.ageVisible(ageVisible)
.build();
}
}
name, email, picture, gender, age, genderVisible, ageVisible 필드가 있다. 이때 name, email, picture 는 구글 로그인 시 반환 받는 정보이다. 나머지는 추가적으로 이 서비스를 이용하기 위해 필요한 필드들이므로 받아준다.
데이터베이스에 잘 저장되었음을 확인할 수 있다.
SecurityConfig 에서 http.csrf().disable() 를 사용하지 않아서 오류가 발생하였다. csrf() 는 사용자 간 위조 요청을 방지하는 기능인데