Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.example.interviewPrep.quiz.emitter.repository;

import org.springframework.stereotype.Service;

@Service
public class EmitterService {

private final EmitterRepository emitterRepository;

public EmitterService(EmitterRepository emitterRepository){
this.emitterRepository = emitterRepository;
}

public void deleteMemberEmitter(String memberId){
emitterRepository.deleteById(memberId);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public enum ErrorCode {

MISSING_PARAMETER("missing_parameter", ""),

NOT_FOUND_LOGIN("not_found_LOGIN", "id, password를 확인해 주세요."),
NOT_FOUND_LOGIN("not_found_LOGIN", "email, password를 확인해 주세요."),
NON_LOGIN("non_login", "로그인 상태가 아닙니다."),

WRONG_ID_TOKEN("wrong_id_token", "로그아웃된 사용자의 토큰입니다."),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,75 +1,81 @@
package com.example.interviewPrep.quiz.member.controller;

import com.example.interviewPrep.quiz.member.domain.Member;
import com.example.interviewPrep.quiz.member.dto.*;
import com.example.interviewPrep.quiz.member.service.AuthenticationService;
import com.example.interviewPrep.quiz.member.service.MemberService;
import com.example.interviewPrep.quiz.member.social.service.OauthService;
import com.example.interviewPrep.quiz.response.ResultResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import javax.validation.constraints.NotNull;

@RestController
@RequestMapping("/members/")
@RequiredArgsConstructor
@CrossOrigin(origins = "*")
@Slf4j
public class MemberController {
private final AuthenticationService authService;
private final MemberService memberService;
private final OauthService oauthService;

@PostMapping("signup")
public ResultResponse<?> signUp(@RequestBody SignUpRequestDTO memberDTO) throws Exception {
public MemberController(AuthenticationService authService, MemberService memberService, OauthService oauthService){
this.authService = authService;
this.memberService = memberService;
this.oauthService = oauthService;
}

@PostMapping("/api/v1/members/signup")
public ResultResponse<Member> signUp(@RequestBody SignUpRequestDTO memberDTO) throws Exception {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍
근데 뒤에 throws Excpetion은 무슨 역할을 하고 있을까요 ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

아무런 역할을 하고 있지 않아서 제외시켰습니다

return ResultResponse.success(memberService.createMember(memberDTO));
}

@GetMapping("userInfo")
public ResultResponse<?> getUserInfo(){
@GetMapping("/api/v1/members/userInfo")
public ResultResponse<Member> getUserInfo(){
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ResultResponse로 전부 감싸져있는 것 같은데, 이 구조로 얻을 수 있는 장점과 단점은 어떤게 있을까요 ?

Copy link
Collaborator Author

@LeeJaeYun7 LeeJaeYun7 Jul 31, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

장점
-개발자가 원하는대로 커스텀해서 사용할 수 있다
-통일된 양식으로 ResponseEntity를 만들 수 있다

단점
-추상 계층이 하나가 추가된다
-코드 오버헤드가 늘어난다
-스프링의 built-in 기능을 사용할 수 없다
(ex) 컨텐츠 negotiation, HTTP 헤더 조작, 자동 응답 코드 핸들링 등)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

멘토링 시간에 말씀 드리긴 했지만, 이 구조는 api를 사용하는 클라이언트 입장에서 가장 불편을 크게 느끼는 구조에요, 공통된 레이어가 꼭 필요하거나 (페이징 응답이라던지) 합의 된 경우가 아니라면 응답객체를 그대로 리턴하는 걸 추천합니다!

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

응답 객체를 그대로 리턴

return ResultResponse.success(memberService.getUserInfo());
}

@PostMapping("login")
public ResultResponse<?> login(@RequestBody @NotNull LoginRequestDTO memberDTO, HttpServletResponse response){
@PostMapping("/api/v1/members/login")
public ResultResponse<LoginResponseDTO> login(@RequestBody @NotNull LoginRequestDTO memberDTO, HttpServletResponse response){
return ResultResponse.success(authService.login(memberDTO, response));
}

@PutMapping("/change")
public ResultResponse<?> changeNickNameAndEmail(@RequestBody @NotNull MemberDTO memberDTO){
return ResultResponse.success(memberService.changeNickNameAndEmail(memberDTO));
@PutMapping("/api/v1/members/change")
public ResultResponse<Member> updateNickNameAndEmail(@RequestBody @NotNull MemberDTO memberDTO, @AuthenticationPrincipal Authentication authentication){
return ResultResponse.success(memberService.updateNickNameAndEmail(memberDTO, authentication));
}

@PutMapping("/password/change")
public ResultResponse<?> changePassword(@RequestBody @NotNull MemberDTO memberDTO){
return ResultResponse.success(memberService.changePassword(memberDTO));
@PutMapping("/api/v1/members/password/change")
public ResultResponse<Member> updatePassword(@RequestBody @NotNull MemberDTO memberDTO){
return ResultResponse.success(memberService.updatePassword(memberDTO));
}

@GetMapping(value="auth/{socialType}")
@GetMapping("/api/v1/members/auth/{socialType}")
public void socialLoginType(@PathVariable String socialType){
oauthService.request(socialType);
}

@GetMapping(value="auth/{socialType}/callback")
public ResultResponse<?> callback(@PathVariable String socialType, @RequestParam(name="code") String code){
@GetMapping("/api/v1/members/auth/{socialType}/callback")
public ResultResponse<LoginResponseDTO> callback(@PathVariable String socialType, @RequestParam(name="code") String code){
return ResultResponse.success(oauthService.socialLogin(socialType, code));
}

@GetMapping(value="logout")
@GetMapping("/api/v1/members/logout")
public ResultResponse<?> logout(HttpServletRequest request){
String accessToken = request.getHeader(HttpHeaders.AUTHORIZATION);
authService.logout(accessToken);
return ResultResponse.success(ResponseEntity.noContent().build());
}


@GetMapping(value="reissue")
@GetMapping("/api/v1/members/reissue")
public ResultResponse<LoginResponseDTO> reissueToken(@CookieValue(value="refreshToken", defaultValue = "0" ) String cookie){
return ResultResponse.success(authService.reissue(cookie));
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,34 +1,21 @@
package com.example.interviewPrep.quiz.member.domain;

import com.example.interviewPrep.quiz.answer.domain.Answer;
import com.example.interviewPrep.quiz.notification.domain.Notification;
import com.example.interviewPrep.quiz.domain.BaseTimeEntity;
import com.example.interviewPrep.quiz.member.dto.Role;
import com.example.interviewPrep.quiz.notification.domain.Notification;
import com.fasterxml.jackson.annotation.*;
import lombok.*;

import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;

@Setter
@Entity
@Getter
@Builder
@RequiredArgsConstructor
@AllArgsConstructor
@NoArgsConstructor
@Table(indexes = @Index(name= "i_member", columnList = "email"))
@JsonIdentityInfo(generator = ObjectIdGenerators.IntSequenceGenerator.class)
public class Member extends BaseTimeEntity {

public Member(String email, String password, String nickName){
this.email = email;
this.password = password;
this.nickName = nickName;
this.role = Role.USER;
}

@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name="MEMBER_ID")
private Long id;
Expand All @@ -49,6 +36,29 @@ public Member(String email, String password, String nickName){
@Enumerated(EnumType.STRING)
private Role role;


public void setEmail(String email){
if(email == null){
throw new NullPointerException("email이 없습니다");
}
this.email = email;
}
public void setPassword(String password){
this.password = password;
}
public void setType(String type){
if(type == null){
throw new NullPointerException("type이 없습니다");
}
this.type = type;
}
public void setNickName(String nickName){
if(nickName == null){
throw new NullPointerException("nickName이 없습니다");
}
this.nickName = nickName;
}

public Member update(String name, String picture){
this.name = name;
this.picture = picture;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
package com.example.interviewPrep.quiz.member.domain;

import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import lombok.NoArgsConstructor;

@Entity
@AllArgsConstructor
@NoArgsConstructor
public class RefreshToken {

Expand All @@ -17,4 +14,5 @@ public class RefreshToken {
private Long memberId;

private String refreshToken;

}
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
package com.example.interviewPrep.quiz.member.dto;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Builder
@Getter
@AllArgsConstructor
@NoArgsConstructor
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@NoArgsConstructor@AllArgsConstructor@RequiredArgsConstructor 같은 문제가 없어서 쓰는게 오히려 아래 코드를 볼 때 유익할 것 같아요 :)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

넵 확인했습니다~

public class LoginRequestDTO {

String email;
String password;

public LoginRequestDTO(String email, String password){
this.email = email;
this.password = password;
}
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
package com.example.interviewPrep.quiz.member.dto;


import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;

@Builder
@Getter
@AllArgsConstructor
public class LoginResponseDTO {

private String accessToken;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,34 @@
import javax.validation.constraints.NotNull;

@Getter
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class MemberDTO {

private Long id;

@NotNull
private String email;
@NotNull

private String password;
@NotNull

private String nickName;
@NotNull

private String newPassword;
@NotNull

private String type;

@Builder
public MemberDTO(Long id, String email, String password, String nickName, String newPassword, String type) {
if (email == null || password == null || nickName == null || newPassword == null || type == null) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

생성자에서 잡아주실거면 위에 @NotNull 은 필요 없을 것 같아요 ?
그리고 이렇게 검사하면 어떤 값이 null인지 메세지로 파악이 안되지 않을까요 ?
저는 보통 Objects.requireNonNull 메서드를 이용하는 편입니다.

throw new NullPointerException();
}
this.id = id;
this.email = email;
this.password = password;
this.nickName = nickName;
this.newPassword = newPassword;
this.type = type;
}




}
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
package com.example.interviewPrep.quiz.member.dto;

import lombok.Getter;
import lombok.RequiredArgsConstructor;

@Getter
@RequiredArgsConstructor
public enum Role {

MENTOR("ROLE_MENTOR", "멘토"),
USER("ROLE_USER", "일반 사용자");

private final String key;
private final String title;

Role(String key, String title) {
this.key = key;
this.title = title;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
public interface MemberRepository extends JpaRepository<Member, Long> {

Optional<Member> findByEmail(String email);

Optional<Member> findByNickName(String nickName);
Optional<Member> findByEmailAndType(String email, String type);

Optional<Member> findById(Long id);
Expand Down
Loading