Skip to content

Commit

Permalink
Merge branch 'develop' of https://github.com/Wedit-project/Server int…
Browse files Browse the repository at this point in the history
…o feat/#15-이미지-저장
  • Loading branch information
leeseulgi0208 committed Jan 18, 2025
2 parents 6b2f76e + 7847fc8 commit 6579d6d
Show file tree
Hide file tree
Showing 12 changed files with 427 additions and 35 deletions.
15 changes: 1 addition & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
#### [백엔드 노션 링크](https://www.notion.so/Spring-16edb6b0994880d7ad84e491d7440f2c)

## BE Members
<img width="160px" src="https://avatars.githubusercontent.com/u/105594739?v=4"/> | <img width="160px" src="https://avatars.githubusercontent.com/u/106726806?v=4"/> | <img width="160px" src="https://avatars.githubusercontent.com/u/105594739?v=4"/> | <img width="160px" src="https://avatars.githubusercontent.com/u/105594739?v=4"/> |
<img width="160px" src="https://avatars.githubusercontent.com/u/106726806?v=4"/> | <img width="160px" src="https://avatars.githubusercontent.com/u/106726806?v=4"/> | <img width="160px" src="https://avatars.githubusercontent.com/u/106726806?v=4"/> | <img width="160px" src="https://avatars.githubusercontent.com/u/106726806?v=4"/> |
|:-----:|:-----:|:-----:|:-----:|
|[동구 (김동윤)](https://github.com/dyk-im)|[동동 (김동섭)](https://github.com/dogsub)|[위즈 (이슬기)](https://github.com/leeseulgi0208)|[환이 (최경환)](https://github.com/KyunghwanChoi)|
|리드 👨🏻‍💻|팀원 👨🏻‍💻|팀원 👨🏻‍💻|팀원 👨🏻‍💻|
Expand Down Expand Up @@ -37,24 +37,16 @@
- develop: 기본 브랜치로, 기능을 개발하는 브랜치
2. **작업 순서**
1. **작업할 이슈 작성**

2. **작업 브랜치 생성**
- 기능 개발: `feature/#[이슈번호]-title`
- ex) feature/#111-login
- 버그 수정: `fix/#[이슈번호]-title`
- ex) fix/#111-login
- 리팩토링: `refactor/#[이슈번호]-title`
- ex) refactor/#111-login

3. **생성한 브랜치에서 작업 수행**
4. **원격 저장소에 작업 브랜치 푸시**
5. **Pull Request 생성**
- `develop` 브랜치 대상으로 Pull Request 생성
- 리뷰어의 리뷰를 받은 후 PR을 승인 받고 `develop` 브랜치에 병합 후 브랜치 삭제
---
## 🧑‍💻 Code Convention 🧑‍💻
[🔗 Code Convention Notion Link 🔗](https://www.notion.so/Code-Convention-46691e85ccdd46748495cea00fdd3b37)

**네이밍 규칙**
- **변수/상수**: 카멜케이스 (예: `userName`)
- **클래스/구조체**: 파스칼케이스 (예: `UserProfile`)
Expand All @@ -64,11 +56,6 @@
## 💬 Issue Convention 💬
## 🫷 PR Convention 🫸
## 🙏 Commit Convention 🙏
[🔗 Relational Convention Notion Link 🔗](https://www.notion.so/Git-Convention-bafdbc76528045599eb5439a9b958726)

---
## 📁 Foldering Convention 📁
[🔗 Foldering Convention Notion Link 🔗](https://www.notion.so/8ac46c75c4a1462b84c890fd6f9a7ffb)

---

Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package com.wedit.weditapp.domain.member.controller;

import com.wedit.weditapp.domain.member.domain.Member;
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.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;

@RestController
@RequestMapping("/api/members")
@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<GlobalResponseDto<MemberResponseDto>> createMember(
@Valid @RequestBody MemberRequestDto requestDto) {
memberService.createMember(requestDto); // 반환값 사용 X -> 추후 OAuth2 구현하면서 변동 가능성 O
return ResponseEntity.status(HttpStatus.OK).body(GlobalResponseDto.success());
}

// 임시 로그인 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<GlobalResponseDto<String>> login(
@RequestBody LoginRequestDto loginRequest) {
// 로그인 로직 → 토큰 발급
String token = memberService.login(loginRequest);

// 토큰을 응답 바디로 전달
return ResponseEntity.ok(GlobalResponseDto.success(token));
}

// 모든 회원 조회 API
@Operation(summary = "모든 회원 조회", description = "등록된 모든 회원의 정보를 조회합니다.")
@ApiResponses(value = {
@ApiResponse(responseCode = "201", description = "조회 성공"),
@ApiResponse(responseCode = "404", description = "유저를 찾을 수 없습니다."),
@ApiResponse(responseCode = "500", description = "서버 에러")
})
@GetMapping
public ResponseEntity<GlobalResponseDto<List<MemberResponseDto>>> findAllMembers() {
List<MemberResponseDto> memberResponses = memberService.findAllMembers();
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<GlobalResponseDto<MemberResponseDto>> findMember(
@PathVariable Long userId) {
return ResponseEntity.ok(GlobalResponseDto.success(memberService.findMember(userId)));
}
}
47 changes: 32 additions & 15 deletions src/main/java/com/wedit/weditapp/domain/member/domain/Member.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -22,45 +24,60 @@ public class Member extends BaseTimeEntity {
@Column(nullable = false)
private String email;

@Column(nullable = false)
private String password;

@Column(nullable = false)
private String name;

@Enumerated(EnumType.STRING)
@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 name) {
this.email = email;
this.name = name;
this.role = role != null ? role : MemberRole.USER; // 유저 역할 기본값 USER
this.password = password;
this.status = status != null ? status : MemberStatus.ACTIVE; // 유저 상태 기본값 ACTIVE
this.role = MemberRole.USER;
this.status = MemberStatus.ACTIVE;
}

public static Member createUser(String email, String name, String password) {
// 사용자 생성 Method
public static Member createUser(String email, String name) {
return Member.builder()
.email(email)
.name(name)
.password(password)
.role(MemberRole.USER) // 기본값 USER
.status(MemberStatus.ACTIVE) // 기본값 ACTIVE
.build();
}

// 상태 변경 예시 메서드
// 사용자 이메일 변경 Method
public void updateEmail(String newEmail) {
if (newEmail == null || newEmail.trim().isEmpty()) {
throw new CommonException(ErrorCode.EMPTY_FIELD);
}
this.email = newEmail;
}

// 사용자 이름 변경 Method
public void updateName(String newName) {
if (newName == null || newName.trim().isEmpty()) {
throw new CommonException(ErrorCode.EMPTY_FIELD);
}
this.name = newName;
}

// 사용자 상태 변경 Method
public void deactivate() {
this.status = MemberStatus.INACTIVE;
}

// 사용자 역할 변경 Method
public void updateRole(MemberRole newRole) {
if (newRole == null) {
throw new CommonException(ErrorCode.EMPTY_FIELD);
}
this.role = newRole;
}
}
Original file line number Diff line number Diff line change
@@ -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<Member, Long> {
// 임시 로그인용 : 이메일로 회원 찾기
Optional<Member> findByEmail(String email);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.wedit.weditapp.domain.member.dto;

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

@Getter
@NoArgsConstructor
public class LoginRequestDto {
private String email;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.wedit.weditapp.domain.member.dto;

import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;


@Getter
@NoArgsConstructor
public class MemberRequestDto {
@Email(message = "이메일 형식을 지켜야 합니다.")
@NotBlank(message = "이메일을 반드시 입력해야 합니다.")
private String email;

@NotBlank(message = "이름을 반드시 입력해야 합니다.")
private String name;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
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;
import lombok.NoArgsConstructor;

@Getter
@NoArgsConstructor
public class MemberResponseDto {
private Long id;
private String email;
private String name;
private MemberRole role;
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) {
return MemberResponseDto.builder()
.id(member.getId())
.email(member.getEmail())
.name(member.getName())
.role(member.getRole())
.status(member.getStatus())
.build();
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +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.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;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
@Transactional
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.EMAIL_ALREADY_EXISTS);
}

Member member = Member.createUser(
requestDto.getEmail(),
requestDto.getName()
);

return memberRepository.save(member);
}

public String login(LoginRequestDto loginRequest) {
// 이메일로 회원 조회
Member member = memberRepository.findByEmail(loginRequest.getEmail())
.orElseThrow(() -> new CommonException(ErrorCode.USER_NOT_FOUND));

// JWT Access Token 생성
return jwtProvider.createAccessToken(member.getEmail());
}

// [모든 회원 조회]
public List<MemberResponseDto> findAllMembers() {
return memberRepository.findAll()
.stream()
.map(MemberResponseDto::from)
.collect(Collectors.toList());
}

// [단일 회원 조회]
public MemberResponseDto findMember(Long userId) {
Member member = memberRepository.findById(userId)
.orElseThrow(() -> new CommonException(ErrorCode.USER_NOT_FOUND));
return MemberResponseDto.from(member);
}
}
Loading

0 comments on commit 6579d6d

Please sign in to comment.