From c21074601322f7536041810bea1c7e05c7fe2a5f Mon Sep 17 00:00:00 2001 From: dogsub Date: Sat, 11 Jan 2025 01:25:53 +0900 Subject: [PATCH 01/11] =?UTF-8?q?[feat]=20#5=20=EB=A1=9C=EA=B7=B8=EC=9D=B8?= =?UTF-8?q?=20=EA=B4=80=EB=A0=A8=20Dto,=20Repository,=20Service,=20Control?= =?UTF-8?q?ler=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../member/controller/MemberController.java | 32 +++++++++++++++++++ .../weditapp/domain/member/domain/Member.java | 13 +++----- .../domain/repository/MemberRepository.java | 11 +++++++ .../domain/member/dto/LoginRequestDto.java | 11 +++++++ .../domain/member/dto/MemberRequestDto.java | 12 +++++++ .../domain/member/dto/MemberResponseDto.java | 28 ++++++++++++++++ .../domain/member/service/MemberService.java | 4 +++ .../global/config/SecurityConfig.java | 7 ++-- 8 files changed, 105 insertions(+), 13 deletions(-) create mode 100644 src/main/java/com/wedit/weditapp/domain/member/controller/MemberController.java create mode 100644 src/main/java/com/wedit/weditapp/domain/member/domain/repository/MemberRepository.java create mode 100644 src/main/java/com/wedit/weditapp/domain/member/dto/LoginRequestDto.java create mode 100644 src/main/java/com/wedit/weditapp/domain/member/dto/MemberRequestDto.java create mode 100644 src/main/java/com/wedit/weditapp/domain/member/dto/MemberResponseDto.java create mode 100644 src/main/java/com/wedit/weditapp/domain/member/service/MemberService.java diff --git a/src/main/java/com/wedit/weditapp/domain/member/controller/MemberController.java b/src/main/java/com/wedit/weditapp/domain/member/controller/MemberController.java new file mode 100644 index 0000000..59adf5d --- /dev/null +++ b/src/main/java/com/wedit/weditapp/domain/member/controller/MemberController.java @@ -0,0 +1,32 @@ +package com.wedit.weditapp.domain.member.controller; + +import com.wedit.weditapp.domain.member.domain.Member; +import com.wedit.weditapp.domain.member.domain.repository.MemberRepository; +import com.wedit.weditapp.domain.member.dto.LoginRequestDto; +import com.wedit.weditapp.domain.member.dto.MemberRequestDto; +import com.wedit.weditapp.domain.member.dto.MemberResponseDto; +import com.wedit.weditapp.domain.shared.MemberRole; +import com.wedit.weditapp.domain.shared.MemberStatus; +import com.wedit.weditapp.global.error.ErrorCode; +import com.wedit.weditapp.global.error.exception.CommonException; +import com.wedit.weditapp.global.response.GlobalResponseDto; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +@RestController +@RequestMapping("/api/members") +@RequiredArgsConstructor +public class MemberController { + +} + + diff --git a/src/main/java/com/wedit/weditapp/domain/member/domain/Member.java b/src/main/java/com/wedit/weditapp/domain/member/domain/Member.java index d56b6ca..e4f79e9 100644 --- a/src/main/java/com/wedit/weditapp/domain/member/domain/Member.java +++ b/src/main/java/com/wedit/weditapp/domain/member/domain/Member.java @@ -32,30 +32,25 @@ public class Member extends BaseTimeEntity { @Column(name = "role", nullable = false) private MemberRole role; - @Column(nullable = false, unique = true) - private String refresh_token; - @Enumerated(EnumType.STRING) @Column(name = "status", nullable = false) private MemberStatus status; // Builder를 통해서만 객체를 생성하도록 (일반 생성자는 protected) @Builder - private Member(String kakaoId, String email, String name, MemberRole role, String password, MemberStatus status) { + private Member(String email, String password, String name, MemberRole role, MemberStatus status) { this.email = email; + this.password = password; this.name = name; this.role = role != null ? role : MemberRole.USER; // 유저 역할 기본값 USER - this.password = password; this.status = status != null ? status : MemberStatus.ACTIVE; // 유저 상태 기본값 ACTIVE } - public static Member createUser(String email, String name, String password) { + public static Member createUser(String email, String password, String name) { return Member.builder() .email(email) - .name(name) .password(password) - .role(MemberRole.USER) // 기본값 USER - .status(MemberStatus.ACTIVE) // 기본값 ACTIVE + .name(name) .build(); } diff --git a/src/main/java/com/wedit/weditapp/domain/member/domain/repository/MemberRepository.java b/src/main/java/com/wedit/weditapp/domain/member/domain/repository/MemberRepository.java new file mode 100644 index 0000000..f402a20 --- /dev/null +++ b/src/main/java/com/wedit/weditapp/domain/member/domain/repository/MemberRepository.java @@ -0,0 +1,11 @@ +package com.wedit.weditapp.domain.member.domain.repository; + +import com.wedit.weditapp.domain.member.domain.Member; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.Optional; + +public interface MemberRepository extends JpaRepository { + // 임시 로그인용 : 이메일로 회원 찾기 + Optional findByEmail(String email); +} diff --git a/src/main/java/com/wedit/weditapp/domain/member/dto/LoginRequestDto.java b/src/main/java/com/wedit/weditapp/domain/member/dto/LoginRequestDto.java new file mode 100644 index 0000000..f9aea6b --- /dev/null +++ b/src/main/java/com/wedit/weditapp/domain/member/dto/LoginRequestDto.java @@ -0,0 +1,11 @@ +package com.wedit.weditapp.domain.member.dto; + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class LoginRequestDto { // 임시 로그인Dto - 나중에 수정해야 함 + private String email; + private String password; +} diff --git a/src/main/java/com/wedit/weditapp/domain/member/dto/MemberRequestDto.java b/src/main/java/com/wedit/weditapp/domain/member/dto/MemberRequestDto.java new file mode 100644 index 0000000..c3f1734 --- /dev/null +++ b/src/main/java/com/wedit/weditapp/domain/member/dto/MemberRequestDto.java @@ -0,0 +1,12 @@ +package com.wedit.weditapp.domain.member.dto; + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class MemberRequestDto { + private String email; + private String password; // 임시 비밀번호 + private String name; +} diff --git a/src/main/java/com/wedit/weditapp/domain/member/dto/MemberResponseDto.java b/src/main/java/com/wedit/weditapp/domain/member/dto/MemberResponseDto.java new file mode 100644 index 0000000..aeec959 --- /dev/null +++ b/src/main/java/com/wedit/weditapp/domain/member/dto/MemberResponseDto.java @@ -0,0 +1,28 @@ +package com.wedit.weditapp.domain.member.dto; + +import com.wedit.weditapp.domain.member.domain.Member; +import com.wedit.weditapp.domain.shared.MemberRole; +import com.wedit.weditapp.domain.shared.MemberStatus; +import lombok.Builder; +import lombok.Getter; + +@Getter +@Builder +public class MemberResponseDto { + private Long id; + private String email; + private String name; + private MemberRole role; + private MemberStatus status; + + public static MemberResponseDto from(Member member) { + return MemberResponseDto.builder() + .id(member.getId()) + .email(member.getEmail()) + .name(member.getName()) + .role(member.getRole()) + .status(member.getStatus()) + .build(); + } +} + diff --git a/src/main/java/com/wedit/weditapp/domain/member/service/MemberService.java b/src/main/java/com/wedit/weditapp/domain/member/service/MemberService.java new file mode 100644 index 0000000..8bff7df --- /dev/null +++ b/src/main/java/com/wedit/weditapp/domain/member/service/MemberService.java @@ -0,0 +1,4 @@ +package com.wedit.weditapp.domain.member.service; + +public class MemberService { +} diff --git a/src/main/java/com/wedit/weditapp/global/config/SecurityConfig.java b/src/main/java/com/wedit/weditapp/global/config/SecurityConfig.java index fe2fc20..2998270 100644 --- a/src/main/java/com/wedit/weditapp/global/config/SecurityConfig.java +++ b/src/main/java/com/wedit/weditapp/global/config/SecurityConfig.java @@ -40,7 +40,7 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { authorize -> authorize .requestMatchers( "/v3/api-docs/**", "/swagger-ui/**").permitAll() // swagger-ui 접근 허용 - .anyRequest().authenticated() + .anyRequest().permitAll() ); return http.build(); @@ -50,11 +50,10 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { public CorsConfigurationSource corsConfigurationSource() { CorsConfiguration configuration = new CorsConfiguration(); - configuration.setAllowedOrigins(Arrays.asList()); + configuration.setAllowedOrigins(Arrays.asList("http://localhost:3000")); configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PATCH", "DELETE")); configuration.setAllowedHeaders(Arrays.asList("*")); - configuration.setExposedHeaders(Arrays.asList("Authorization, Authorization_refresh", "accept")); - configuration.setAllowedOrigins(Arrays.asList("http://localhost:3000", "http://localhost:8080")); + configuration.setExposedHeaders(Arrays.asList("Authorization", "Authorization_refresh", "accept")); configuration.setAllowCredentials(true); UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); From 47eaaacb022db5dfdf6fe43e1cd87c7507c30e57 Mon Sep 17 00:00:00 2001 From: dogsub Date: Sat, 11 Jan 2025 13:56:53 +0900 Subject: [PATCH 02/11] =?UTF-8?q?[feat]=20#5=20=ED=9A=8C=EC=9B=90=EA=B0=80?= =?UTF-8?q?=EC=9E=85=20API,=20=EC=A0=84=EC=B2=B4=20=ED=9A=8C=EC=9B=90=20?= =?UTF-8?q?=EC=A1=B0=ED=9A=8C=20API,=20=EB=8B=A8=EC=9D=BC=20=ED=9A=8C?= =?UTF-8?q?=EC=9B=90=20=EC=A1=B0=ED=9A=8C=20API=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../member/controller/MemberController.java | 69 +++++++++++++++++-- .../domain/member/dto/MemberRequestDto.java | 8 +++ 2 files changed, 70 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/wedit/weditapp/domain/member/controller/MemberController.java b/src/main/java/com/wedit/weditapp/domain/member/controller/MemberController.java index 59adf5d..4a7f4a0 100644 --- a/src/main/java/com/wedit/weditapp/domain/member/controller/MemberController.java +++ b/src/main/java/com/wedit/weditapp/domain/member/controller/MemberController.java @@ -1,25 +1,21 @@ package com.wedit.weditapp.domain.member.controller; import com.wedit.weditapp.domain.member.domain.Member; -import com.wedit.weditapp.domain.member.domain.repository.MemberRepository; import com.wedit.weditapp.domain.member.dto.LoginRequestDto; import com.wedit.weditapp.domain.member.dto.MemberRequestDto; import com.wedit.weditapp.domain.member.dto.MemberResponseDto; -import com.wedit.weditapp.domain.shared.MemberRole; -import com.wedit.weditapp.domain.shared.MemberStatus; -import com.wedit.weditapp.global.error.ErrorCode; -import com.wedit.weditapp.global.error.exception.CommonException; +import com.wedit.weditapp.domain.member.service.MemberService; import com.wedit.weditapp.global.response.GlobalResponseDto; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.responses.ApiResponses; +import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import java.util.List; -import java.util.Optional; import java.util.stream.Collectors; @RestController @@ -27,6 +23,65 @@ @RequiredArgsConstructor public class MemberController { -} + private final MemberService memberService; + // 회원 가입 API + @Operation(summary = "회원가입", description = "새로운 유저를 등록합니다.") + @ApiResponses(value = { + @ApiResponse(responseCode = "201", description = "회원 가입 성공"), + @ApiResponse(responseCode = "409", description = "이미 가입된 이메일입니다."), + @ApiResponse(responseCode = "500", description = "서버 에러") + }) + @PostMapping("/signup") + public ResponseEntity> createMember(@Valid @RequestBody MemberRequestDto requestDto) { + Member saved = memberService.createMember(requestDto); + return ResponseEntity + .status(HttpStatus.CREATED) + .body(GlobalResponseDto.success(MemberResponseDto.from(saved), 201)); + } + + // 임시 로그인 API + @Operation(summary = "임시 로그인", description = "해당 서비스에 로그인합니다.") + @ApiResponses(value = { + @ApiResponse(responseCode = "201", description = "로그인 성공"), + @ApiResponse(responseCode = "401", description = "로그인에 실패하였습니다."), + @ApiResponse(responseCode = "404", description = "유저를 찾을 수 없습니다."), + @ApiResponse(responseCode = "500", description = "서버 에러") + }) + @PostMapping("/login") + public ResponseEntity> login(@RequestBody LoginRequestDto loginRequest) { + String message = memberService.login(loginRequest); + return ResponseEntity.ok(GlobalResponseDto.success(message)); + } + + // 모든 회원 조회 API + @Operation(summary = "모든 회원 조회", description = "등록된 모든 회원의 정보를 조회합니다.") + @ApiResponses(value = { + @ApiResponse(responseCode = "201", description = "조회 성공"), + @ApiResponse(responseCode = "404", description = "유저를 찾을 수 없습니다."), + @ApiResponse(responseCode = "500", description = "서버 에러") + }) + @GetMapping + public ResponseEntity>> findAllMembers() { + List members = memberService.findAllMembers(); + List memberResponses = members.stream() + .map(MemberResponseDto::from) + .collect(Collectors.toList()); + + return ResponseEntity.ok(GlobalResponseDto.success(memberResponses)); + } + + // 단일 회원 조회 API + @Operation(summary = "단일 회원 조회", description = "해당 id를 가진 회원의 정보를 조회합니다.") + @ApiResponses(value = { + @ApiResponse(responseCode = "201", description = "조회 성공"), + @ApiResponse(responseCode = "404", description = "유저를 찾을 수 없습니다."), + @ApiResponse(responseCode = "500", description = "서버 에러") + }) + @GetMapping("/{userId}") + public ResponseEntity> findMemberById(@PathVariable Long userId) { + Member member = memberService.findMemberById(userId); + return ResponseEntity.ok(GlobalResponseDto.success(MemberResponseDto.from(member))); + } +} \ No newline at end of file diff --git a/src/main/java/com/wedit/weditapp/domain/member/dto/MemberRequestDto.java b/src/main/java/com/wedit/weditapp/domain/member/dto/MemberRequestDto.java index c3f1734..abbed86 100644 --- a/src/main/java/com/wedit/weditapp/domain/member/dto/MemberRequestDto.java +++ b/src/main/java/com/wedit/weditapp/domain/member/dto/MemberRequestDto.java @@ -1,12 +1,20 @@ package com.wedit.weditapp.domain.member.dto; +import jakarta.validation.constraints.Email; +import jakarta.validation.constraints.NotBlank; import lombok.Getter; import lombok.Setter; @Getter @Setter public class MemberRequestDto { + @Email(message = "이메일 형식을 지켜야 합니다.") + @NotBlank(message = "이메일을 반드시 입력해야 합니다.") private String email; + + @NotBlank(message = "비밀번호를 반드시 입력해야 합니다.") private String password; // 임시 비밀번호 + + @NotBlank(message = "이름을 반드시 입력해야 합니다.") private String name; } From c88b51daf86e50a4f8a441c47a42a7adc19784d5 Mon Sep 17 00:00:00 2001 From: dogsub Date: Sun, 12 Jan 2025 20:06:34 +0900 Subject: [PATCH 03/11] =?UTF-8?q?[feat]=20#5=20JWT=20=EC=9D=B8=EC=A6=9D?= =?UTF-8?q?=EC=9D=84=20=ED=86=B5=ED=95=9C=20=EC=9E=84=EC=8B=9C=20=EB=A1=9C?= =?UTF-8?q?=EA=B7=B8=EC=9D=B8=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../member/controller/MemberController.java | 7 +- .../domain/member/service/MemberService.java | 58 +++++++++++++ .../global/config/SecurityConfig.java | 26 +++++- .../security/jwt/JwtAuthenticationFilter.java | 58 +++++++++++++ .../global/security/jwt/JwtProvider.java | 81 +++++++++++++++++++ 5 files changed, 226 insertions(+), 4 deletions(-) create mode 100644 src/main/java/com/wedit/weditapp/global/security/jwt/JwtAuthenticationFilter.java create mode 100644 src/main/java/com/wedit/weditapp/global/security/jwt/JwtProvider.java diff --git a/src/main/java/com/wedit/weditapp/domain/member/controller/MemberController.java b/src/main/java/com/wedit/weditapp/domain/member/controller/MemberController.java index 4a7f4a0..258ee2b 100644 --- a/src/main/java/com/wedit/weditapp/domain/member/controller/MemberController.java +++ b/src/main/java/com/wedit/weditapp/domain/member/controller/MemberController.java @@ -51,8 +51,11 @@ public ResponseEntity> createMember(@Valid }) @PostMapping("/login") public ResponseEntity> login(@RequestBody LoginRequestDto loginRequest) { - String message = memberService.login(loginRequest); - return ResponseEntity.ok(GlobalResponseDto.success(message)); + // 로그인 로직 → 토큰 발급 + String token = memberService.login(loginRequest); + + // 토큰을 응답 바디로 전달 + return ResponseEntity.ok(GlobalResponseDto.success(token)); } // 모든 회원 조회 API diff --git a/src/main/java/com/wedit/weditapp/domain/member/service/MemberService.java b/src/main/java/com/wedit/weditapp/domain/member/service/MemberService.java index 8bff7df..8f04d38 100644 --- a/src/main/java/com/wedit/weditapp/domain/member/service/MemberService.java +++ b/src/main/java/com/wedit/weditapp/domain/member/service/MemberService.java @@ -1,4 +1,62 @@ package com.wedit.weditapp.domain.member.service; +import com.wedit.weditapp.domain.member.domain.Member; +import com.wedit.weditapp.domain.member.domain.repository.MemberRepository; +import com.wedit.weditapp.domain.member.dto.LoginRequestDto; +import com.wedit.weditapp.domain.member.dto.MemberRequestDto; +import com.wedit.weditapp.global.error.ErrorCode; +import com.wedit.weditapp.global.error.exception.CommonException; +import com.wedit.weditapp.global.security.jwt.JwtProvider; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +@RequiredArgsConstructor public class MemberService { + private final MemberRepository memberRepository; + private final JwtProvider jwtProvider; // JWT 발급을 위해 + + // [회원가입 관련] - 이미 존재하는 이메일인지 검사 + Member 엔티티 생성 + DB저장 및 반환 + public Member createMember(MemberRequestDto requestDto) { + if (memberRepository.findByEmail(requestDto.getEmail()).isPresent()) { + throw new CommonException(ErrorCode.MEMBER_ALREADY_EXISTS); + } + + Member member = Member.createUser( + requestDto.getEmail(), + requestDto.getPassword(), + requestDto.getName() + ); + + return memberRepository.save(member); + } + + public String login(LoginRequestDto loginRequest) { + // 이메일로 회원 조회 + Member member = memberRepository.findByEmail(loginRequest.getEmail()) + .orElseThrow(() -> new CommonException(ErrorCode.USER_NOT_FOUND)); + + // 비밀번호 검증 (임시: 평문 비교) + if (!member.getPassword().equals(loginRequest.getPassword())) { + throw new CommonException(ErrorCode.LOGIN_FAIL); + } + + // JWT Access Token 생성 + return jwtProvider.createAccessToken(member.getEmail()); + } + + // [모든 회원 조회] + public List findAllMembers() { + return memberRepository.findAll(); + } + + // [단일 회원 조회] + public Member findMemberById(Long userId) { + return memberRepository.findById(userId) + .orElseThrow(() -> new CommonException(ErrorCode.USER_NOT_FOUND) + ); + } + } diff --git a/src/main/java/com/wedit/weditapp/global/config/SecurityConfig.java b/src/main/java/com/wedit/weditapp/global/config/SecurityConfig.java index 2998270..571a296 100644 --- a/src/main/java/com/wedit/weditapp/global/config/SecurityConfig.java +++ b/src/main/java/com/wedit/weditapp/global/config/SecurityConfig.java @@ -4,13 +4,19 @@ import java.util.Arrays; +import com.wedit.weditapp.global.security.jwt.JwtAuthenticationFilter; +import com.wedit.weditapp.global.security.jwt.JwtProvider; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer; +import org.springframework.security.config.http.SessionCreationPolicy; +import org.springframework.security.crypto.factory.PasswordEncoderFactories; +import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.SecurityFilterChain; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.cors.CorsConfigurationSource; import org.springframework.web.cors.UrlBasedCorsConfigurationSource; @@ -22,6 +28,8 @@ @RequiredArgsConstructor public class SecurityConfig { + private final JwtAuthenticationFilter jwtAuthenticationFilter; + @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http @@ -29,6 +37,10 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { .httpBasic(AbstractHttpConfigurer::disable) .cors(withDefaults()) .csrf(AbstractHttpConfigurer::disable) + + // 세션 관련 정책 추가 : 세션 방식 사용 X (오직 JWT만 사용) + .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) + .headers( headersConfigurer -> headersConfigurer @@ -39,10 +51,13 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { .authorizeHttpRequests( authorize -> authorize - .requestMatchers( "/v3/api-docs/**", "/swagger-ui/**").permitAll() // swagger-ui 접근 허용 - .anyRequest().permitAll() + .requestMatchers( "/v3/api-docs/**", "/swagger-ui/**", "/api/members/login", "/api/members/signup").permitAll() // swagger-ui 접근 허용 + 로그인과 회원가입까지만 허용 + .anyRequest().authenticated() // 그외에는 Access Token을 가진 유저만 접근 가능 ); + // JWT 인증 필터 등록 + http.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class); + return http.build(); } @@ -60,4 +75,11 @@ public CorsConfigurationSource corsConfigurationSource() { source.registerCorsConfiguration("/**", configuration); return source; } + + // 회원가입 시 사용 + @Bean + public PasswordEncoder passwordEncoder() { + return PasswordEncoderFactories.createDelegatingPasswordEncoder(); + } + } diff --git a/src/main/java/com/wedit/weditapp/global/security/jwt/JwtAuthenticationFilter.java b/src/main/java/com/wedit/weditapp/global/security/jwt/JwtAuthenticationFilter.java new file mode 100644 index 0000000..b17269d --- /dev/null +++ b/src/main/java/com/wedit/weditapp/global/security/jwt/JwtAuthenticationFilter.java @@ -0,0 +1,58 @@ +package com.wedit.weditapp.global.security.jwt; + +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.stereotype.Component; +import org.springframework.util.StringUtils; +import org.springframework.web.filter.OncePerRequestFilter; +import java.io.IOException; + + +@Slf4j +@Component +@RequiredArgsConstructor +public class JwtAuthenticationFilter extends OncePerRequestFilter { + + private final JwtProvider jwtProvider; + + @Override + protected void doFilterInternal(HttpServletRequest request, + HttpServletResponse response, + FilterChain filterChain) + throws ServletException, IOException { + + // 헤더에서 토큰 추출 + String token = resolveToken(request); + + // 토큰 검증 + if (token != null && jwtProvider.validateToken(token)) { + // 토큰에서 사용자 정보 추출 + String email = jwtProvider.getEmail(token); + + // 임시로 Role없이 Authentication 객체 생성 -> 추후 추가 예정 + UsernamePasswordAuthenticationToken authentication = + new UsernamePasswordAuthenticationToken(email, null, null); + + // SecurityContext에 저장 + SecurityContextHolder.getContext().setAuthentication(authentication); + } + + // 다음 필터로 진행 + filterChain.doFilter(request, response); + } + + // "Authorization: Bearer " 헤더에서 token만 파싱 + private String resolveToken(HttpServletRequest request) { + String bearerToken = request.getHeader("Authorization"); + if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) { + return bearerToken.substring(7); + } + return null; + } +} diff --git a/src/main/java/com/wedit/weditapp/global/security/jwt/JwtProvider.java b/src/main/java/com/wedit/weditapp/global/security/jwt/JwtProvider.java new file mode 100644 index 0000000..7dc347d --- /dev/null +++ b/src/main/java/com/wedit/weditapp/global/security/jwt/JwtProvider.java @@ -0,0 +1,81 @@ +package com.wedit.weditapp.global.security.jwt; + +import io.jsonwebtoken.*; +import io.jsonwebtoken.security.Keys; +import jakarta.annotation.PostConstruct; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import javax.crypto.SecretKey; +import java.nio.charset.StandardCharsets; +import java.security.Key; +import java.util.Date; + +@Slf4j +@Component +public class JwtProvider { + + @Value("${jwt.secretKey}") + private String secretKey; + + @Value("${jwt.access.expiration}") + private long accessTokenExpiry; // 만료 시간 : 3600000 (1시간) + + private Key key; // 실제 사용할 HMAC용 key 객체 + + // Bean 생성 직후 secretKey를 Key 객체로 변환 + @PostConstruct + protected void init() { + this.key = Keys.hmacShaKeyFor(secretKey.getBytes(StandardCharsets.UTF_8)); + } + + + // JWT Access Token 생성 + /* + * - subject로 email (또는 userId 등) 지정 + * - 만료시간 설정 + * - 서명 알고리즘: HS256 + */ + public String createAccessToken(String email) { + Date now = new Date(); + Date expiry = new Date(now.getTime() + accessTokenExpiry); + + return Jwts.builder() + .subject(email) + .issuedAt(now) + .expiration(expiry) + .signWith(key, SignatureAlgorithm.HS256) + .compact(); + } + + // JWT Access Token 유효성 검증 + public boolean validateToken(String token) { + try { + // 토큰 파싱 -> 에러 없으면 유효 + Jwts.parser() + .verifyWith((SecretKey) key) + .build() + .parseSignedClaims(token); + return true; + } catch (SecurityException | MalformedJwtException e) { + log.error("Invalid JWT signature: {}", e.getMessage()); + } catch (ExpiredJwtException e) { + log.error("Expired JWT token: {}", e.getMessage()); + } catch (UnsupportedJwtException e) { + log.error("Unsupported JWT token: {}", e.getMessage()); + } catch (IllegalArgumentException e) { + log.error("JWT token compact of handler are invalid: {}", e.getMessage()); + } + return false; + } + + // 토큰에서 email(Subject) 추출 + public String getEmail(String token) { + return Jwts.parser() + .verifyWith((SecretKey) key) + .build() + .parseSignedClaims(token).getPayload() + .getSubject(); + } +} \ No newline at end of file From c7ff124394daefee5a82a516719670e67fdffec6 Mon Sep 17 00:00:00 2001 From: dogsub Date: Fri, 17 Jan 2025 18:17:34 +0900 Subject: [PATCH 04/11] =?UTF-8?q?[fix]=20#5=20Member=20=EC=97=94=ED=8B=B0?= =?UTF-8?q?=ED=8B=B0=20=EC=88=98=EC=A0=95=5Fpassword=20=EC=82=AD=EC=A0=9C,?= =?UTF-8?q?=20createMember=20=EC=88=98=EC=A0=95,=20=EC=88=98=EC=A0=95=20Me?= =?UTF-8?q?thod=204=EA=B0=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../weditapp/domain/member/domain/Member.java | 40 ++++++++++++++----- .../domain/member/service/MemberService.java | 6 --- 2 files changed, 30 insertions(+), 16 deletions(-) diff --git a/src/main/java/com/wedit/weditapp/domain/member/domain/Member.java b/src/main/java/com/wedit/weditapp/domain/member/domain/Member.java index e4f79e9..ab380a6 100644 --- a/src/main/java/com/wedit/weditapp/domain/member/domain/Member.java +++ b/src/main/java/com/wedit/weditapp/domain/member/domain/Member.java @@ -22,9 +22,6 @@ public class Member extends BaseTimeEntity { @Column(nullable = false) private String email; - @Column(nullable = false) - private String password; - @Column(nullable = false) private String name; @@ -38,24 +35,47 @@ public class Member extends BaseTimeEntity { // Builder를 통해서만 객체를 생성하도록 (일반 생성자는 protected) @Builder - private Member(String email, String password, String name, MemberRole role, MemberStatus status) { + private Member(String email, String name) { this.email = email; - this.password = password; this.name = name; - this.role = role != null ? role : MemberRole.USER; // 유저 역할 기본값 USER - this.status = status != null ? status : MemberStatus.ACTIVE; // 유저 상태 기본값 ACTIVE + this.role = MemberRole.USER; + this.status = MemberStatus.ACTIVE; } - public static Member createUser(String email, String password, String name) { + // 사용자 생성 Method + public static Member createUser(String email, String name) { return Member.builder() .email(email) - .password(password) .name(name) .build(); } - // 상태 변경 예시 메서드 + // 사용자 이메일 변경 Method + public void updateEmail(String newEmail) { + if (newEmail == null || newEmail.trim().isEmpty()) { + throw new IllegalArgumentException("공백이면 안됩니다."); + } + this.name = newEmail; + } + + // 사용자 이름 변경 Method + public void updateName(String newName) { + if (newName == null || newName.trim().isEmpty()) { + throw new IllegalArgumentException("공백이면 안됩니다."); + } + this.name = newName; + } + + // 사용자 상태 변경 Method public void deactivate() { this.status = MemberStatus.INACTIVE; } + + // 사용자 역할 변경 Method + public void updateRole(MemberRole newRole) { + if (newRole == null) { + throw new IllegalArgumentException("공백이면 안됩니다."); + } + this.role = newRole; + } } diff --git a/src/main/java/com/wedit/weditapp/domain/member/service/MemberService.java b/src/main/java/com/wedit/weditapp/domain/member/service/MemberService.java index 8f04d38..4266a82 100644 --- a/src/main/java/com/wedit/weditapp/domain/member/service/MemberService.java +++ b/src/main/java/com/wedit/weditapp/domain/member/service/MemberService.java @@ -26,7 +26,6 @@ public Member createMember(MemberRequestDto requestDto) { Member member = Member.createUser( requestDto.getEmail(), - requestDto.getPassword(), requestDto.getName() ); @@ -38,11 +37,6 @@ public String login(LoginRequestDto loginRequest) { Member member = memberRepository.findByEmail(loginRequest.getEmail()) .orElseThrow(() -> new CommonException(ErrorCode.USER_NOT_FOUND)); - // 비밀번호 검증 (임시: 평문 비교) - if (!member.getPassword().equals(loginRequest.getPassword())) { - throw new CommonException(ErrorCode.LOGIN_FAIL); - } - // JWT Access Token 생성 return jwtProvider.createAccessToken(member.getEmail()); } From 562763310d6281d5a78ec712f005775130fa36da Mon Sep 17 00:00:00 2001 From: dogsub Date: Fri, 17 Jan 2025 18:25:40 +0900 Subject: [PATCH 05/11] =?UTF-8?q?[fix]=20#5=20RequestDto=20=EC=88=98?= =?UTF-8?q?=EC=A0=95=5FSetter=20=EC=82=AD=EC=A0=9C=20=EB=B0=8F=20NoArgsCon?= =?UTF-8?q?structor=20=EC=82=AC=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/member/dto/LoginRequestDto.java | 13 +++++++++---- .../domain/member/dto/MemberRequestDto.java | 15 ++++++++++----- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/wedit/weditapp/domain/member/dto/LoginRequestDto.java b/src/main/java/com/wedit/weditapp/domain/member/dto/LoginRequestDto.java index f9aea6b..659ba1a 100644 --- a/src/main/java/com/wedit/weditapp/domain/member/dto/LoginRequestDto.java +++ b/src/main/java/com/wedit/weditapp/domain/member/dto/LoginRequestDto.java @@ -1,11 +1,16 @@ package com.wedit.weditapp.domain.member.dto; +import lombok.Builder; import lombok.Getter; -import lombok.Setter; +import lombok.NoArgsConstructor; @Getter -@Setter -public class LoginRequestDto { // 임시 로그인Dto - 나중에 수정해야 함 +@NoArgsConstructor +public class LoginRequestDto { private String email; - private String password; + + @Builder + public LoginRequestDto(String email) { + this.email = email; + } } diff --git a/src/main/java/com/wedit/weditapp/domain/member/dto/MemberRequestDto.java b/src/main/java/com/wedit/weditapp/domain/member/dto/MemberRequestDto.java index abbed86..e560b76 100644 --- a/src/main/java/com/wedit/weditapp/domain/member/dto/MemberRequestDto.java +++ b/src/main/java/com/wedit/weditapp/domain/member/dto/MemberRequestDto.java @@ -2,19 +2,24 @@ import jakarta.validation.constraints.Email; import jakarta.validation.constraints.NotBlank; +import lombok.Builder; import lombok.Getter; -import lombok.Setter; +import lombok.NoArgsConstructor; + @Getter -@Setter +@NoArgsConstructor public class MemberRequestDto { @Email(message = "이메일 형식을 지켜야 합니다.") @NotBlank(message = "이메일을 반드시 입력해야 합니다.") private String email; - @NotBlank(message = "비밀번호를 반드시 입력해야 합니다.") - private String password; // 임시 비밀번호 - @NotBlank(message = "이름을 반드시 입력해야 합니다.") private String name; + + @Builder + public MemberRequestDto(String email, String name) { + this.email = email; + this.name = name; + } } From ecf18cfff23a75a2b7cd46588712c52e7e4c5810 Mon Sep 17 00:00:00 2001 From: dogsub Date: Fri, 17 Jan 2025 18:36:35 +0900 Subject: [PATCH 06/11] =?UTF-8?q?[fix]=20#5=20ResponseDto=20=EB=B0=8F=20Se?= =?UTF-8?q?rvice=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/member/dto/MemberResponseDto.java | 18 ++++++++++-------- .../domain/member/service/MemberService.java | 2 ++ 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/wedit/weditapp/domain/member/dto/MemberResponseDto.java b/src/main/java/com/wedit/weditapp/domain/member/dto/MemberResponseDto.java index aeec959..d4d49d5 100644 --- a/src/main/java/com/wedit/weditapp/domain/member/dto/MemberResponseDto.java +++ b/src/main/java/com/wedit/weditapp/domain/member/dto/MemberResponseDto.java @@ -5,9 +5,10 @@ import com.wedit.weditapp.domain.shared.MemberStatus; import lombok.Builder; import lombok.Getter; +import lombok.NoArgsConstructor; @Getter -@Builder +@NoArgsConstructor public class MemberResponseDto { private Long id; private String email; @@ -15,14 +16,15 @@ public class MemberResponseDto { private MemberRole role; private MemberStatus status; + @Builder public static MemberResponseDto from(Member member) { - return MemberResponseDto.builder() - .id(member.getId()) - .email(member.getEmail()) - .name(member.getName()) - .role(member.getRole()) - .status(member.getStatus()) - .build(); + MemberResponseDto responseDto = new MemberResponseDto(); + responseDto.id = member.getId(); + responseDto.email = member.getEmail(); + responseDto.name = member.getName(); + responseDto.role = member.getRole(); + responseDto.status = member.getStatus(); + return responseDto; } } diff --git a/src/main/java/com/wedit/weditapp/domain/member/service/MemberService.java b/src/main/java/com/wedit/weditapp/domain/member/service/MemberService.java index 4266a82..94b9e67 100644 --- a/src/main/java/com/wedit/weditapp/domain/member/service/MemberService.java +++ b/src/main/java/com/wedit/weditapp/domain/member/service/MemberService.java @@ -9,11 +9,13 @@ import com.wedit.weditapp.global.security.jwt.JwtProvider; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import java.util.List; @Service @RequiredArgsConstructor +@Transactional public class MemberService { private final MemberRepository memberRepository; private final JwtProvider jwtProvider; // JWT 발급을 위해 From 88e30ea402c0fc6eb4e5f7ee56f54e3c1783d9d2 Mon Sep 17 00:00:00 2001 From: dogsub Date: Fri, 17 Jan 2025 18:56:52 +0900 Subject: [PATCH 07/11] =?UTF-8?q?[fix]=20#5=20Service=EC=99=80=20Controlle?= =?UTF-8?q?r=20=EB=A1=9C=EC=A7=81=20=EC=B2=98=EB=A6=AC=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../member/controller/MemberController.java | 26 +++++++++---------- .../domain/member/service/MemberService.java | 17 +++++++----- 2 files changed, 24 insertions(+), 19 deletions(-) diff --git a/src/main/java/com/wedit/weditapp/domain/member/controller/MemberController.java b/src/main/java/com/wedit/weditapp/domain/member/controller/MemberController.java index 258ee2b..f9bf39e 100644 --- a/src/main/java/com/wedit/weditapp/domain/member/controller/MemberController.java +++ b/src/main/java/com/wedit/weditapp/domain/member/controller/MemberController.java @@ -33,12 +33,12 @@ public class MemberController { @ApiResponse(responseCode = "500", description = "서버 에러") }) @PostMapping("/signup") - public ResponseEntity> createMember(@Valid @RequestBody MemberRequestDto requestDto) { + public ResponseEntity> + createMember( + @Valid @RequestBody MemberRequestDto requestDto) { Member saved = memberService.createMember(requestDto); - return ResponseEntity - .status(HttpStatus.CREATED) - .body(GlobalResponseDto.success(MemberResponseDto.from(saved), 201)); + return ResponseEntity.status(HttpStatus.OK).body(GlobalResponseDto.success()); } // 임시 로그인 API @@ -50,7 +50,9 @@ public ResponseEntity> createMember(@Valid @ApiResponse(responseCode = "500", description = "서버 에러") }) @PostMapping("/login") - public ResponseEntity> login(@RequestBody LoginRequestDto loginRequest) { + public ResponseEntity> + login( + @RequestBody LoginRequestDto loginRequest) { // 로그인 로직 → 토큰 발급 String token = memberService.login(loginRequest); @@ -67,11 +69,7 @@ public ResponseEntity> login(@RequestBody LoginRequest }) @GetMapping public ResponseEntity>> findAllMembers() { - List members = memberService.findAllMembers(); - List memberResponses = members.stream() - .map(MemberResponseDto::from) - .collect(Collectors.toList()); - + List memberResponses = memberService.findAllMembers(); return ResponseEntity.ok(GlobalResponseDto.success(memberResponses)); } @@ -83,8 +81,10 @@ public ResponseEntity>> findAllMembers @ApiResponse(responseCode = "500", description = "서버 에러") }) @GetMapping("/{userId}") - public ResponseEntity> findMemberById(@PathVariable Long userId) { - Member member = memberService.findMemberById(userId); - return ResponseEntity.ok(GlobalResponseDto.success(MemberResponseDto.from(member))); + public ResponseEntity> + findMemberById( + @PathVariable Long userId) { + MemberResponseDto memberResponse = memberService.findMemberById(userId); + return ResponseEntity.ok(GlobalResponseDto.success(memberResponse)); } } \ No newline at end of file diff --git a/src/main/java/com/wedit/weditapp/domain/member/service/MemberService.java b/src/main/java/com/wedit/weditapp/domain/member/service/MemberService.java index 94b9e67..6fd3a9a 100644 --- a/src/main/java/com/wedit/weditapp/domain/member/service/MemberService.java +++ b/src/main/java/com/wedit/weditapp/domain/member/service/MemberService.java @@ -4,6 +4,7 @@ import com.wedit.weditapp.domain.member.domain.repository.MemberRepository; import com.wedit.weditapp.domain.member.dto.LoginRequestDto; import com.wedit.weditapp.domain.member.dto.MemberRequestDto; +import com.wedit.weditapp.domain.member.dto.MemberResponseDto; import com.wedit.weditapp.global.error.ErrorCode; import com.wedit.weditapp.global.error.exception.CommonException; import com.wedit.weditapp.global.security.jwt.JwtProvider; @@ -12,6 +13,7 @@ import org.springframework.transaction.annotation.Transactional; import java.util.List; +import java.util.stream.Collectors; @Service @RequiredArgsConstructor @@ -44,15 +46,18 @@ public String login(LoginRequestDto loginRequest) { } // [모든 회원 조회] - public List findAllMembers() { - return memberRepository.findAll(); + public List findAllMembers() { + return memberRepository.findAll() + .stream() + .map(MemberResponseDto::from) + .collect(Collectors.toList()); } // [단일 회원 조회] - public Member findMemberById(Long userId) { - return memberRepository.findById(userId) - .orElseThrow(() -> new CommonException(ErrorCode.USER_NOT_FOUND) - ); + public MemberResponseDto findMemberById(Long userId) { + Member member = memberRepository.findById(userId) + .orElseThrow(() -> new CommonException(ErrorCode.USER_NOT_FOUND)); + return MemberResponseDto.from(member); } } From 39e3b18ae8793772336ec8ff2961e4c13e0f6f90 Mon Sep 17 00:00:00 2001 From: dogsub Date: Sat, 18 Jan 2025 15:50:46 +0900 Subject: [PATCH 08/11] =?UTF-8?q?[fix]=20#5=20RequestDto=20Builder=20?= =?UTF-8?q?=ED=8C=A8=ED=84=B4=20=EC=82=AD=EC=A0=9C=20=EB=B0=8F=20=EC=BB=A4?= =?UTF-8?q?=EC=8A=A4=ED=85=80=20=EC=97=90=EB=9F=AC=20=ED=95=B8=EB=93=A4?= =?UTF-8?q?=EB=A7=81=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../wedit/weditapp/domain/member/domain/Member.java | 10 ++++++---- .../weditapp/domain/member/dto/LoginRequestDto.java | 4 ---- .../weditapp/domain/member/dto/MemberRequestDto.java | 6 ------ .../com/wedit/weditapp/global/error/ErrorCode.java | 1 + 4 files changed, 7 insertions(+), 14 deletions(-) diff --git a/src/main/java/com/wedit/weditapp/domain/member/domain/Member.java b/src/main/java/com/wedit/weditapp/domain/member/domain/Member.java index ab380a6..ea7cf4f 100644 --- a/src/main/java/com/wedit/weditapp/domain/member/domain/Member.java +++ b/src/main/java/com/wedit/weditapp/domain/member/domain/Member.java @@ -3,6 +3,8 @@ import com.wedit.weditapp.domain.shared.BaseTimeEntity; import com.wedit.weditapp.domain.shared.MemberRole; import com.wedit.weditapp.domain.shared.MemberStatus; +import com.wedit.weditapp.global.error.ErrorCode; +import com.wedit.weditapp.global.error.exception.CommonException; import jakarta.persistence.*; import lombok.AccessLevel; import lombok.Builder; @@ -53,15 +55,15 @@ public static Member createUser(String email, String name) { // 사용자 이메일 변경 Method public void updateEmail(String newEmail) { if (newEmail == null || newEmail.trim().isEmpty()) { - throw new IllegalArgumentException("공백이면 안됩니다."); + throw new CommonException(ErrorCode.EMPTY_FIELD); } - this.name = newEmail; + this.email = newEmail; } // 사용자 이름 변경 Method public void updateName(String newName) { if (newName == null || newName.trim().isEmpty()) { - throw new IllegalArgumentException("공백이면 안됩니다."); + throw new CommonException(ErrorCode.EMPTY_FIELD); } this.name = newName; } @@ -74,7 +76,7 @@ public void deactivate() { // 사용자 역할 변경 Method public void updateRole(MemberRole newRole) { if (newRole == null) { - throw new IllegalArgumentException("공백이면 안됩니다."); + throw new CommonException(ErrorCode.EMPTY_FIELD); } this.role = newRole; } diff --git a/src/main/java/com/wedit/weditapp/domain/member/dto/LoginRequestDto.java b/src/main/java/com/wedit/weditapp/domain/member/dto/LoginRequestDto.java index 659ba1a..178a5c0 100644 --- a/src/main/java/com/wedit/weditapp/domain/member/dto/LoginRequestDto.java +++ b/src/main/java/com/wedit/weditapp/domain/member/dto/LoginRequestDto.java @@ -9,8 +9,4 @@ public class LoginRequestDto { private String email; - @Builder - public LoginRequestDto(String email) { - this.email = email; - } } diff --git a/src/main/java/com/wedit/weditapp/domain/member/dto/MemberRequestDto.java b/src/main/java/com/wedit/weditapp/domain/member/dto/MemberRequestDto.java index e560b76..d04d880 100644 --- a/src/main/java/com/wedit/weditapp/domain/member/dto/MemberRequestDto.java +++ b/src/main/java/com/wedit/weditapp/domain/member/dto/MemberRequestDto.java @@ -16,10 +16,4 @@ public class MemberRequestDto { @NotBlank(message = "이름을 반드시 입력해야 합니다.") private String name; - - @Builder - public MemberRequestDto(String email, String name) { - this.email = email; - this.name = name; - } } diff --git a/src/main/java/com/wedit/weditapp/global/error/ErrorCode.java b/src/main/java/com/wedit/weditapp/global/error/ErrorCode.java index c41c3ac..8ed47ee 100644 --- a/src/main/java/com/wedit/weditapp/global/error/ErrorCode.java +++ b/src/main/java/com/wedit/weditapp/global/error/ErrorCode.java @@ -14,6 +14,7 @@ public enum ErrorCode { INVALID_FILE_FORMAT(400, "INVALID_FILE_FORMAT", "올바르지 않은 파일 형식입니다."), INVALID_TOKEN(401, "INVALID_TOKEN", "유효하지 않은 토큰입니다."), REJECT_DUPLICATION(409, "REJECT_DUPLICATION", "중복된 값입니다."), + EMPTY_FIELD(400, "EMPTY_FIELD", "공백이면 안됩니다."), //회원 LOGIN_FAIL(401, "LOGIN_FAIL", "로그인에 실패하였습니다."), From afe341610afcc70ce60d309f5a4f14c553514714 Mon Sep 17 00:00:00 2001 From: dogsub Date: Sat, 18 Jan 2025 16:22:43 +0900 Subject: [PATCH 09/11] =?UTF-8?q?[fix]=20#5=20ResponseDto=20Builder=20?= =?UTF-8?q?=ED=8C=A8=ED=84=B4=20=EC=82=AD=EC=A0=9C=20=EB=B0=8F=20=EC=BB=A4?= =?UTF-8?q?=EC=8A=A4=ED=85=80=20=EC=97=90=EB=9F=AC=20=ED=95=B8=EB=93=A4?= =?UTF-8?q?=EB=A7=81=20=EC=B6=94=EA=B0=80,=20Service=EC=99=80=20Controller?= =?UTF-8?q?=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../member/controller/MemberController.java | 22 +++++++------------ .../domain/member/dto/MemberResponseDto.java | 22 +++++++++++++------ .../domain/member/service/MemberService.java | 4 ++-- .../weditapp/global/error/ErrorCode.java | 3 ++- 4 files changed, 27 insertions(+), 24 deletions(-) diff --git a/src/main/java/com/wedit/weditapp/domain/member/controller/MemberController.java b/src/main/java/com/wedit/weditapp/domain/member/controller/MemberController.java index f9bf39e..22459b9 100644 --- a/src/main/java/com/wedit/weditapp/domain/member/controller/MemberController.java +++ b/src/main/java/com/wedit/weditapp/domain/member/controller/MemberController.java @@ -16,7 +16,6 @@ import org.springframework.web.bind.annotation.*; import java.util.List; -import java.util.stream.Collectors; @RestController @RequestMapping("/api/members") @@ -33,11 +32,9 @@ public class MemberController { @ApiResponse(responseCode = "500", description = "서버 에러") }) @PostMapping("/signup") - public ResponseEntity> - createMember( - @Valid @RequestBody MemberRequestDto requestDto) { - Member saved = memberService.createMember(requestDto); - + public ResponseEntity> createMember( + @Valid @RequestBody MemberRequestDto requestDto) { + memberService.createMember(requestDto); // 반환값 사용 X -> 추후 OAuth2 구현하면서 변동 가능성 O return ResponseEntity.status(HttpStatus.OK).body(GlobalResponseDto.success()); } @@ -50,9 +47,8 @@ public class MemberController { @ApiResponse(responseCode = "500", description = "서버 에러") }) @PostMapping("/login") - public ResponseEntity> - login( - @RequestBody LoginRequestDto loginRequest) { + public ResponseEntity> login( + @RequestBody LoginRequestDto loginRequest) { // 로그인 로직 → 토큰 발급 String token = memberService.login(loginRequest); @@ -81,10 +77,8 @@ public ResponseEntity>> findAllMembers @ApiResponse(responseCode = "500", description = "서버 에러") }) @GetMapping("/{userId}") - public ResponseEntity> - findMemberById( - @PathVariable Long userId) { - MemberResponseDto memberResponse = memberService.findMemberById(userId); - return ResponseEntity.ok(GlobalResponseDto.success(memberResponse)); + public ResponseEntity> findMemberById( + @PathVariable Long userId) { + return ResponseEntity.ok(GlobalResponseDto.success(memberService.findMember(userId))); } } \ No newline at end of file diff --git a/src/main/java/com/wedit/weditapp/domain/member/dto/MemberResponseDto.java b/src/main/java/com/wedit/weditapp/domain/member/dto/MemberResponseDto.java index d4d49d5..3388c46 100644 --- a/src/main/java/com/wedit/weditapp/domain/member/dto/MemberResponseDto.java +++ b/src/main/java/com/wedit/weditapp/domain/member/dto/MemberResponseDto.java @@ -17,14 +17,22 @@ public class MemberResponseDto { private MemberStatus status; @Builder + private MemberResponseDto(Long id, String email, String name, MemberRole role, MemberStatus status) { + this.id = id; + this.email = email; + this.name = name; + this.role = role; + this.status = status; + } + public static MemberResponseDto from(Member member) { - MemberResponseDto responseDto = new MemberResponseDto(); - responseDto.id = member.getId(); - responseDto.email = member.getEmail(); - responseDto.name = member.getName(); - responseDto.role = member.getRole(); - responseDto.status = member.getStatus(); - return responseDto; + return MemberResponseDto.builder() + .id(member.getId()) + .email(member.getEmail()) + .name(member.getName()) + .role(member.getRole()) + .status(member.getStatus()) + .build(); } } diff --git a/src/main/java/com/wedit/weditapp/domain/member/service/MemberService.java b/src/main/java/com/wedit/weditapp/domain/member/service/MemberService.java index 6fd3a9a..1e01958 100644 --- a/src/main/java/com/wedit/weditapp/domain/member/service/MemberService.java +++ b/src/main/java/com/wedit/weditapp/domain/member/service/MemberService.java @@ -25,7 +25,7 @@ public class MemberService { // [회원가입 관련] - 이미 존재하는 이메일인지 검사 + Member 엔티티 생성 + DB저장 및 반환 public Member createMember(MemberRequestDto requestDto) { if (memberRepository.findByEmail(requestDto.getEmail()).isPresent()) { - throw new CommonException(ErrorCode.MEMBER_ALREADY_EXISTS); + throw new CommonException(ErrorCode.EMAIL_ALREADY_EXISTS); } Member member = Member.createUser( @@ -54,7 +54,7 @@ public List findAllMembers() { } // [단일 회원 조회] - public MemberResponseDto findMemberById(Long userId) { + public MemberResponseDto findMember(Long userId) { Member member = memberRepository.findById(userId) .orElseThrow(() -> new CommonException(ErrorCode.USER_NOT_FOUND)); return MemberResponseDto.from(member); diff --git a/src/main/java/com/wedit/weditapp/global/error/ErrorCode.java b/src/main/java/com/wedit/weditapp/global/error/ErrorCode.java index 8ed47ee..5c8f38e 100644 --- a/src/main/java/com/wedit/weditapp/global/error/ErrorCode.java +++ b/src/main/java/com/wedit/weditapp/global/error/ErrorCode.java @@ -19,7 +19,8 @@ public enum ErrorCode { //회원 LOGIN_FAIL(401, "LOGIN_FAIL", "로그인에 실패하였습니다."), USER_NOT_FOUND(404, "USER_NOT_FOUND", "유저를 찾을 수 없습니다."), - MEMBER_ALREADY_EXISTS(409, "MEMBER_ALREADY_EXISTS", "이미 가입된 이메일입니다."), + MEMBER_ALREADY_EXISTS(409, "MEMBER_ALREADY_EXISTS", "이미 존재하는 회원입니다."), + EMAIL_ALREADY_EXISTS(409, "EMAIL_ALREADY_EXISTS", "이미 가입된 이메일입니다."), DUPLICATE_NICKNAME(409, "NICKNAME_ALREADY_EXISTS", "이미 존재하는 닉네임입니다."), //작업 From 8cc46cacd0ac32639d934cfa3bb328404b3a6417 Mon Sep 17 00:00:00 2001 From: dogsub Date: Sat, 18 Jan 2025 18:26:37 +0900 Subject: [PATCH 10/11] =?UTF-8?q?[fix]=20#5=20findMember=20=EB=A9=94?= =?UTF-8?q?=EC=84=9C=EB=93=9C=20=EB=AA=85=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../weditapp/domain/member/controller/MemberController.java | 2 +- .../wedit/weditapp/domain/member/service/MemberService.java | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/wedit/weditapp/domain/member/controller/MemberController.java b/src/main/java/com/wedit/weditapp/domain/member/controller/MemberController.java index 22459b9..f01dff1 100644 --- a/src/main/java/com/wedit/weditapp/domain/member/controller/MemberController.java +++ b/src/main/java/com/wedit/weditapp/domain/member/controller/MemberController.java @@ -77,7 +77,7 @@ public ResponseEntity>> findAllMembers @ApiResponse(responseCode = "500", description = "서버 에러") }) @GetMapping("/{userId}") - public ResponseEntity> findMemberById( + public ResponseEntity> findMember( @PathVariable Long userId) { return ResponseEntity.ok(GlobalResponseDto.success(memberService.findMember(userId))); } diff --git a/src/main/java/com/wedit/weditapp/domain/member/service/MemberService.java b/src/main/java/com/wedit/weditapp/domain/member/service/MemberService.java index 1e01958..bdec2de 100644 --- a/src/main/java/com/wedit/weditapp/domain/member/service/MemberService.java +++ b/src/main/java/com/wedit/weditapp/domain/member/service/MemberService.java @@ -59,5 +59,4 @@ public MemberResponseDto findMember(Long userId) { .orElseThrow(() -> new CommonException(ErrorCode.USER_NOT_FOUND)); return MemberResponseDto.from(member); } - -} +} \ No newline at end of file From 04d63102ebea52057c397a764e2ed0400849bb53 Mon Sep 17 00:00:00 2001 From: dogsub Date: Sat, 18 Jan 2025 18:43:46 +0900 Subject: [PATCH 11/11] =?UTF-8?q?[fix]=20#5=20=EA=B0=9C=ED=96=89=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../weditapp/domain/member/controller/MemberController.java | 2 +- .../com/wedit/weditapp/domain/member/service/MemberService.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/wedit/weditapp/domain/member/controller/MemberController.java b/src/main/java/com/wedit/weditapp/domain/member/controller/MemberController.java index f01dff1..c14c2b1 100644 --- a/src/main/java/com/wedit/weditapp/domain/member/controller/MemberController.java +++ b/src/main/java/com/wedit/weditapp/domain/member/controller/MemberController.java @@ -81,4 +81,4 @@ public ResponseEntity> findMember( @PathVariable Long userId) { return ResponseEntity.ok(GlobalResponseDto.success(memberService.findMember(userId))); } -} \ No newline at end of file +} diff --git a/src/main/java/com/wedit/weditapp/domain/member/service/MemberService.java b/src/main/java/com/wedit/weditapp/domain/member/service/MemberService.java index bdec2de..d0ce78f 100644 --- a/src/main/java/com/wedit/weditapp/domain/member/service/MemberService.java +++ b/src/main/java/com/wedit/weditapp/domain/member/service/MemberService.java @@ -59,4 +59,4 @@ public MemberResponseDto findMember(Long userId) { .orElseThrow(() -> new CommonException(ErrorCode.USER_NOT_FOUND)); return MemberResponseDto.from(member); } -} \ No newline at end of file +}