diff --git a/src/main/java/com/example/fixlog/config/SecurityConfig.java b/src/main/java/com/example/fixlog/config/SecurityConfig.java new file mode 100644 index 0000000..2c7be84 --- /dev/null +++ b/src/main/java/com/example/fixlog/config/SecurityConfig.java @@ -0,0 +1,31 @@ +package com.example.fixlog.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.HttpMethod; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.web.SecurityFilterChain; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; + +@Configuration +public class SecurityConfig { + + @Bean + public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { + http + .csrf(csrf -> csrf.disable()) + .authorizeHttpRequests(auth -> auth + .requestMatchers(HttpMethod.POST, "/api/members/signup").permitAll() + .requestMatchers(HttpMethod.GET, "/api/members/check-email").permitAll() + .requestMatchers(HttpMethod.GET, "/api/members/check-nickname").permitAll() + .anyRequest().authenticated() + ); + return http.build(); + } + + @Bean + public PasswordEncoder passwordEncoder() { + return new BCryptPasswordEncoder(); + } +} diff --git a/src/main/java/com/example/fixlog/controller/member/MemberController.java b/src/main/java/com/example/fixlog/controller/member/MemberController.java new file mode 100644 index 0000000..cf01613 --- /dev/null +++ b/src/main/java/com/example/fixlog/controller/member/MemberController.java @@ -0,0 +1,38 @@ +package com.example.fixlog.controller.member; + + +import com.example.fixlog.dto.Response; +import com.example.fixlog.dto.member.SignupRequestDto; +import com.example.fixlog.dto.member.DuplicateCheckResponseDto; +import com.example.fixlog.service.member.MemberService; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequestMapping("/api/members") +@RequiredArgsConstructor +public class MemberController { + + private final MemberService memberService; + + @PostMapping("/signup") + public ResponseEntity> signup(@RequestBody SignupRequestDto request) { + memberService.signup(request); + return ResponseEntity.ok(Response.success("회원가입이 완료되었습니다.", null)); + } + + @GetMapping("/check-email") + public ResponseEntity> checkEmail(@RequestParam String email) { + boolean exists = memberService.isEmailDuplicated(email); + String msg = exists ? "이미 사용 중인 이메일입니다." : "사용 가능한 이메일입니다."; + return ResponseEntity.ok(Response.success(msg, new DuplicateCheckResponseDto(exists))); + } + + @GetMapping("/check-nickname") + public ResponseEntity> checkNickname(@RequestParam String nickname) { + boolean exists = memberService.isNicknameDuplicated(nickname); + String msg = exists ? "이미 사용 중인 닉네임입니다." : "사용 가능한 닉네임입니다."; + return ResponseEntity.ok(Response.success(msg, new DuplicateCheckResponseDto(exists))); + } +} diff --git a/src/main/java/com/example/FixLog/controller/post/PostController.java b/src/main/java/com/example/fixlog/controller/post/PostController.java similarity index 100% rename from src/main/java/com/example/FixLog/controller/post/PostController.java rename to src/main/java/com/example/fixlog/controller/post/PostController.java diff --git a/src/main/java/com/example/fixlog/domain/member/Member.java b/src/main/java/com/example/fixlog/domain/member/Member.java index de790f9..810d65d 100644 --- a/src/main/java/com/example/fixlog/domain/member/Member.java +++ b/src/main/java/com/example/fixlog/domain/member/Member.java @@ -42,18 +42,28 @@ public class Member { private SocialType socialType = SocialType.EMAIL; @CreatedDate + @Column(updatable = false) private LocalDateTime createdAt; @LastModifiedDate + @Column private LocalDateTime updatedAt; + // 프로필 사진 url, 지금은 nullable 이지만 나중에 기본값 설정 + @Column + private String profileImageUrl; + + @Column(length = 200) + private String bio; + @OneToMany(mappedBy = "member", cascade = CascadeType.ALL, orphanRemoval = true) private List posts = new ArrayList<>(); - // 북마크 폴더 + // 북마크 폴더 @OneToMany(mappedBy = "owner", cascade = CascadeType.ALL, orphanRemoval = true) private List bookmarkFolders = new ArrayList<>(); + // Member 객체를 정적 팩토리 방식으로 회원가입 시에 생성하는 메서드 // Member 객체를 정적 팩토리 방식으로 생성하는 메서드 // Creates a Member object using a static factory method public static Member of(String email, String password, String nickname, SocialType socialType) { diff --git a/src/main/java/com/example/fixlog/dto/member/DuplicateCheckResponseDto.java b/src/main/java/com/example/fixlog/dto/member/DuplicateCheckResponseDto.java new file mode 100644 index 0000000..79a9572 --- /dev/null +++ b/src/main/java/com/example/fixlog/dto/member/DuplicateCheckResponseDto.java @@ -0,0 +1,10 @@ +package com.example.fixlog.dto.member; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public class DuplicateCheckResponseDto { + private boolean duplicated; +} \ No newline at end of file diff --git a/src/main/java/com/example/fixlog/dto/member/SignupRequestDto.java b/src/main/java/com/example/fixlog/dto/member/SignupRequestDto.java new file mode 100644 index 0000000..4e0e8e8 --- /dev/null +++ b/src/main/java/com/example/fixlog/dto/member/SignupRequestDto.java @@ -0,0 +1,13 @@ +package com.example.fixlog.dto.member; + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class SignupRequestDto { + private String email; + //비밀번호 재확인은 프론트단에서 확인 + private String password; + private String nickname; +} \ No newline at end of file diff --git a/src/main/java/com/example/FixLog/exception/ErrorCode.java b/src/main/java/com/example/fixlog/exception/ErrorCode.java similarity index 93% rename from src/main/java/com/example/FixLog/exception/ErrorCode.java rename to src/main/java/com/example/fixlog/exception/ErrorCode.java index 3321ccc..2759866 100644 --- a/src/main/java/com/example/FixLog/exception/ErrorCode.java +++ b/src/main/java/com/example/fixlog/exception/ErrorCode.java @@ -13,8 +13,8 @@ public enum ErrorCode { CANNOT_UNFOLLOW_SELF(HttpStatus.BAD_REQUEST, "자기 자신은 언팔로우할 수 없습니다"), ALREADY_FOLLOWING(HttpStatus.CONFLICT, "이미 팔로우 중입니다"), FOLLOW_NOT_FOUND(HttpStatus.NOT_FOUND, "팔로우 관계가 존재하지 않습니다"), - ID_DUPLICATED(HttpStatus.CONFLICT, "중복된 아이디입니다"), EMAIL_DUPLICATED(HttpStatus.CONFLICT, "중복된 이메일입니다"), + NICKNAME_DUPLICATED(HttpStatus.CONFLICT, "중복된 닉네임입니다"), USER_ID_NOT_FOUND(HttpStatus.NOT_FOUND,"존재하지 않는 사용자 아이디입니다."), POST_NOT_FOUND(HttpStatus.NOT_FOUND, "존재하지 않는 게시글입니다."); diff --git a/src/main/java/com/example/FixLog/repository/MemberRepository.java b/src/main/java/com/example/fixlog/repository/MemberRepository.java similarity index 85% rename from src/main/java/com/example/FixLog/repository/MemberRepository.java rename to src/main/java/com/example/fixlog/repository/MemberRepository.java index 9f4b76a..afe2dda 100644 --- a/src/main/java/com/example/FixLog/repository/MemberRepository.java +++ b/src/main/java/com/example/fixlog/repository/MemberRepository.java @@ -7,4 +7,5 @@ public interface MemberRepository extends JpaRepository { Optional findByEmail(String email); // 이메일로 회원 조회 + Optional findByNickname(String nickname); } \ No newline at end of file diff --git a/src/main/java/com/example/FixLog/repository/bookmark/BookmarkRepository.java b/src/main/java/com/example/fixlog/repository/bookmark/BookmarkRepository.java similarity index 100% rename from src/main/java/com/example/FixLog/repository/bookmark/BookmarkRepository.java rename to src/main/java/com/example/fixlog/repository/bookmark/BookmarkRepository.java diff --git a/src/main/java/com/example/FixLog/repository/like/PostLikeRepository.java b/src/main/java/com/example/fixlog/repository/like/PostLikeRepository.java similarity index 100% rename from src/main/java/com/example/FixLog/repository/like/PostLikeRepository.java rename to src/main/java/com/example/fixlog/repository/like/PostLikeRepository.java diff --git a/src/main/java/com/example/FixLog/repository/post/PostRepository.java b/src/main/java/com/example/fixlog/repository/post/PostRepository.java similarity index 100% rename from src/main/java/com/example/FixLog/repository/post/PostRepository.java rename to src/main/java/com/example/fixlog/repository/post/PostRepository.java diff --git a/src/main/java/com/example/fixlog/service/member/MemberService.java b/src/main/java/com/example/fixlog/service/member/MemberService.java new file mode 100644 index 0000000..12f5e88 --- /dev/null +++ b/src/main/java/com/example/fixlog/service/member/MemberService.java @@ -0,0 +1,49 @@ +package com.example.fixlog.service.member; + +import com.example.fixlog.domain.member.Member; +import com.example.fixlog.domain.member.SocialType; +import com.example.fixlog.dto.member.SignupRequestDto; +import com.example.fixlog.exception.CustomException; +import com.example.fixlog.exception.ErrorCode; +import com.example.fixlog.repository.MemberRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +public class MemberService { + + private final MemberRepository memberRepository; + private final PasswordEncoder passwordEncoder; + + public void signup(SignupRequestDto request) { + // 이메일 중복 검사 + if (isEmailDuplicated(request.getEmail())) { + throw new CustomException(ErrorCode.EMAIL_DUPLICATED); + } + + // 닉네임 중복 검사 + if (isNicknameDuplicated(request.getNickname())) { + throw new CustomException(ErrorCode.NICKNAME_DUPLICATED); + } + + // 문제 없으면 저장 + Member member = Member.of( + request.getEmail(), + passwordEncoder.encode(request.getPassword()), + request.getNickname(), + SocialType.EMAIL + ); + + memberRepository.save(member); + } + + public boolean isEmailDuplicated(String email) { + return memberRepository.findByEmail(email).isPresent(); + } + + public boolean isNicknameDuplicated(String nickname) { + return memberRepository.findByNickname(nickname).isPresent(); + } +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 378e722..3b3f9fe 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -12,4 +12,8 @@ spring.datasource.password= spring.jpa.show-sql=true spring.jpa.hibernate.ddl-auto=update -spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.H2Dialect \ No newline at end of file +spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.H2Dialect + +# JWT +jwt.secret-key=fixlogfixlogfixlogfixlogfixlog1234 +jwt.expiration-time=86400000 \ No newline at end of file