Skip to content

Commit 0125a02

Browse files
jaehyeon4406kjhh26052jiyong
authored
Feat/4 명함 작성 api (#6)
* feat: UserControllerDocs 추가 * 프로필 작성 api * feat: 로그 aop 추가 * enum refactoring * refactor: 이름 변경 * refactor: 사용하지 않는 메서드 제거 * refactor: unique 칼럼 제거 및 메서드 추가 * refactor: 메서드 추가 * refactor: illegalArgumentException 수정 -> GlobalHandler로 --------- Co-authored-by: 김준호 <2171168@hansung.ac.kr> Co-authored-by: 2jiyong <jdragon2000@naver.com>
1 parent cc6a829 commit 0125a02

File tree

17 files changed

+372
-10
lines changed

17 files changed

+372
-10
lines changed
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package com.devpath.domain.user.contorller;
2+
3+
import com.devpath.domain.user.dto.CardPrevDto;
4+
import com.devpath.domain.user.dto.MyCardDto;
5+
import com.devpath.domain.user.dto.UserProfileRequest;
6+
import com.devpath.domain.user.dto.UserProfileResponse;
7+
import com.devpath.domain.user.entity.User;
8+
import com.devpath.domain.user.service.UserService;
9+
import com.devpath.global.apiPayload.ApiResponse;
10+
import com.devpath.global.apiPayload.code.status.GeneralSuccessCode;
11+
import jakarta.validation.Valid;
12+
import lombok.RequiredArgsConstructor;
13+
import org.springframework.web.bind.annotation.PostMapping;
14+
import org.springframework.web.bind.annotation.RequestBody;
15+
import org.springframework.web.bind.annotation.RequestMapping;
16+
import org.springframework.web.bind.annotation.RestController;
17+
18+
@RestController
19+
@RequestMapping("/api/v1/users")
20+
@RequiredArgsConstructor
21+
public class UserController implements UserControllerDocs{
22+
23+
private final UserService userProfileCommandService;
24+
25+
@Override
26+
public ApiResponse<MyCardDto> getMyCard() {
27+
return null;
28+
}
29+
30+
@Override
31+
public ApiResponse<CardPrevDto> getCards() {
32+
return null;
33+
}
34+
35+
@Override
36+
@PostMapping("/profile")
37+
public ApiResponse<UserProfileResponse> createProfile(
38+
@Valid @RequestBody UserProfileRequest request
39+
) {
40+
User user = userProfileCommandService.createProfile(request);
41+
return ApiResponse.onSuccess(GeneralSuccessCode._CREATED, UserProfileResponse.from(user));
42+
}
43+
}
44+
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package com.devpath.domain.user.contorller;
2+
3+
import com.devpath.domain.user.dto.CardPrevDto;
4+
import com.devpath.domain.user.dto.MyCardDto;
5+
import com.devpath.domain.user.dto.UserProfileRequest;
6+
import com.devpath.domain.user.dto.UserProfileResponse;
7+
import com.devpath.global.apiPayload.ApiResponse;
8+
import io.swagger.v3.oas.annotations.Operation;
9+
import io.swagger.v3.oas.annotations.media.Content;
10+
import io.swagger.v3.oas.annotations.media.Schema;
11+
import io.swagger.v3.oas.annotations.responses.ApiResponses;
12+
import io.swagger.v3.oas.annotations.tags.Tag;
13+
14+
@Tag(name = "User", description = "사용자 명함 관리 API")
15+
public interface UserControllerDocs {
16+
17+
@Operation(
18+
summary = "내 명함 조회",
19+
description = "현재 로그인한 사용자의 명함 정보를 조회합니다."
20+
)
21+
@ApiResponses({
22+
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "200", description = "명함 조회 성공"),
23+
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "401", description = "인증되지 않은 사용자"),
24+
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "404", description = "사용자 정보를 찾을 수 없음")
25+
})
26+
ApiResponse<MyCardDto> getMyCard();
27+
28+
@Operation(
29+
summary = "명함 목록 조회",
30+
description = "최신순으로 교환한 명함 목록을 조회합니다. (직군을 선택하여 필터링 가능)"
31+
)
32+
@ApiResponses({
33+
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "200", description = "명함 조회 성공"),
34+
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "401", description = "인증되지 않은 사용자"),
35+
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "404", description = "사용자 정보를 찾을 수 없음")
36+
})
37+
ApiResponse<CardPrevDto> getCards();
38+
39+
@Operation(
40+
summary = "프로필 작성",
41+
description = "사용자의 프로필 정보를 작성합니다. 모든 필드는 필수이며, 기술 스택은 최소 1개 이상 선택해야 합니다."
42+
)
43+
@ApiResponses({
44+
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "200", description = "프로필 작성 성공"),
45+
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "400", description = "유효성 검증 실패"),
46+
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "409", description = "이미 존재하는 닉네임 또는 이메일")
47+
})
48+
ApiResponse<UserProfileResponse> createProfile(
49+
@io.swagger.v3.oas.annotations.parameters.RequestBody(
50+
description = "프로필 작성 정보",
51+
required = true,
52+
content = @Content(schema = @Schema(implementation = UserProfileRequest.class))
53+
)
54+
UserProfileRequest request
55+
);
56+
57+
}
58+
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
package com.devpath.domain.user.dto;
2+
3+
public class CardPrevDto {
4+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
package com.devpath.domain.user.dto;
2+
3+
public class MyCardDto {
4+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package com.devpath.domain.user.dto;
2+
3+
import com.devpath.domain.user.enums.JobGroup;
4+
import com.devpath.domain.user.enums.Level;
5+
import com.devpath.domain.user.enums.TechStackName;
6+
import jakarta.validation.constraints.NotBlank;
7+
import jakarta.validation.constraints.NotEmpty;
8+
import jakarta.validation.constraints.NotNull;
9+
import lombok.Getter;
10+
import lombok.NoArgsConstructor;
11+
12+
import java.util.List;
13+
14+
@Getter
15+
@NoArgsConstructor
16+
public class UserProfileRequest {
17+
18+
@NotBlank(message = "이름은 필수입니다")
19+
private String name;
20+
21+
@NotBlank(message = "닉네임은 필수입니다")
22+
private String nickname;
23+
24+
@NotBlank(message = "전화번호는 필수입니다")
25+
private String phone;
26+
27+
@NotBlank(message = "이메일은 필수입니다")
28+
private String email;
29+
30+
@NotBlank(message = "링크는 필수입니다")
31+
private String link;
32+
33+
@NotNull(message = "직무를 선택해주세요")
34+
private JobGroup jobGroup;
35+
36+
@NotNull(message = "경력을 선택해주세요")
37+
private Level level;
38+
39+
@NotEmpty(message = "기술 스택은 최소 1개 이상 선택해야 합니다")
40+
private List<TechStackName> techStackNames;
41+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package com.devpath.domain.user.dto;
2+
3+
import com.devpath.domain.user.entity.User;
4+
import lombok.AllArgsConstructor;
5+
import lombok.Builder;
6+
import lombok.Getter;
7+
8+
@Getter
9+
@Builder
10+
@AllArgsConstructor
11+
public class UserProfileResponse {
12+
13+
private Long userId;
14+
15+
public static UserProfileResponse from(User user) {
16+
return UserProfileResponse.builder()
17+
.userId(user.getUserId())
18+
.build();
19+
}
20+
}

src/main/java/com/devpath/domain/user/entity/TechStack.java

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@
22

33
import com.devpath.domain.user.enums.TechStackName;
44
import jakarta.persistence.*;
5-
import lombok.AccessLevel;
6-
import lombok.Getter;
7-
import lombok.NoArgsConstructor;
5+
import lombok.*;
86

97
@Entity
108
@Table(name = "tech_stacks")
119
@Getter
1210
@NoArgsConstructor(access = AccessLevel.PROTECTED)
11+
@AllArgsConstructor
12+
@Builder
1313
public class TechStack {
1414

1515
@Id
@@ -24,4 +24,8 @@ public class TechStack {
2424
@ManyToOne(fetch = FetchType.LAZY)
2525
@JoinColumn(name = "user_id", nullable = false)
2626
private User user;
27+
28+
public void setUser(User user) {
29+
this.user = user;
30+
}
2731
}

src/main/java/com/devpath/domain/user/entity/User.java

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
import com.devpath.domain.user.enums.JobGroup;
44
import com.devpath.domain.user.enums.Level;
55
import jakarta.persistence.*;
6-
import lombok.AccessLevel;
7-
import lombok.Getter;
8-
import lombok.NoArgsConstructor;
6+
import lombok.*;
7+
8+
99
import org.springframework.data.annotation.CreatedDate;
1010
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
1111

@@ -17,6 +17,8 @@
1717
@Table(name = "users")
1818
@Getter
1919
@NoArgsConstructor(access = AccessLevel.PROTECTED)
20+
@AllArgsConstructor
21+
@Builder
2022
@EntityListeners(AuditingEntityListener.class)
2123
public class User {
2224

@@ -28,7 +30,7 @@ public class User {
2830
@Column(name = "name", nullable = false)
2931
private String name;
3032

31-
@Column(name = "nickname", nullable = false, unique = true)
33+
@Column(name = "nickname", nullable = false)
3234
private String nickname;
3335

3436
@Enumerated(EnumType.STRING)
@@ -53,6 +55,12 @@ public class User {
5355
@Column(name = "created_at", updatable = false)
5456
private LocalDateTime createdAt;
5557

58+
@Builder.Default
5659
@OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true)
5760
private List<TechStack> techStacks = new ArrayList<>();
61+
62+
public void addTechStack(TechStack techStack) {
63+
techStacks.add(techStack);
64+
techStack.setUser(this);
65+
}
5866
}

src/main/java/com/devpath/domain/user/enums/JobGroup.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
package com.devpath.domain.user.enums;
22

3+
import com.devpath.global.apiPayload.code.status.GeneralErrorCode;
4+
import com.devpath.global.apiPayload.exception.handler.GlobalHandler;
5+
import com.fasterxml.jackson.annotation.JsonCreator;
6+
import com.fasterxml.jackson.annotation.JsonValue;
7+
38
public enum JobGroup {
49
PM("기획(PM)"),
510
DESIGNER("디자인"),
@@ -14,7 +19,18 @@ public enum JobGroup {
1419
this.description = description;
1520
}
1621

22+
@JsonValue
1723
public String getDescription() {
1824
return description;
1925
}
26+
27+
@JsonCreator
28+
public static JobGroup from(String value) {
29+
for (JobGroup jobGroup : JobGroup.values()) {
30+
if (jobGroup.description.equals(value) || jobGroup.name().equals(value)) {
31+
return jobGroup;
32+
}
33+
}
34+
throw new GlobalHandler(GeneralErrorCode.JOB_GROUP_NOT_FOUND);
35+
}
2036
}

src/main/java/com/devpath/domain/user/enums/Level.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
package com.devpath.domain.user.enums;
22

3+
import com.devpath.global.apiPayload.code.status.GeneralErrorCode;
4+
import com.devpath.global.apiPayload.exception.handler.GlobalHandler;
5+
import com.fasterxml.jackson.annotation.JsonCreator;
6+
import com.fasterxml.jackson.annotation.JsonValue;
7+
38
public enum Level {
49
JOB_SEEKING("취업준비중"),
510
ENTRY("신입(1년 미만)"),
@@ -12,7 +17,18 @@ public enum Level {
1217
this.description = description;
1318
}
1419

20+
@JsonValue
1521
public String getDescription() {
1622
return description;
1723
}
24+
25+
@JsonCreator
26+
public static Level from(String value) {
27+
for (Level level : Level.values()) {
28+
if (level.description.equals(value) || level.name().equals(value)) {
29+
return level;
30+
}
31+
}
32+
throw new GlobalHandler(GeneralErrorCode.LEVEL_NOT_FOUND);
33+
}
1834
}

0 commit comments

Comments
 (0)