diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java b/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java index e27906e..fdebfa5 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/MemberController.java @@ -1,7 +1,9 @@ package com.tikitaka.naechinso.domain.member; import com.tikitaka.naechinso.domain.member.dto.MemberCommonJoinRequestDto; -import com.tikitaka.naechinso.domain.member.dto.MemberCommonJoinResponseDto; +import com.tikitaka.naechinso.domain.member.dto.MemberCommonResponseDto; +import com.tikitaka.naechinso.domain.member.dto.MemberDetailJoinRequestDto; +import com.tikitaka.naechinso.domain.member.dto.MemberDetailResponseDto; import com.tikitaka.naechinso.domain.member.entity.Member; import com.tikitaka.naechinso.global.annotation.AuthMember; import com.tikitaka.naechinso.global.config.CommonApiResponse; @@ -11,9 +13,11 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.*; +import springfox.documentation.annotations.ApiIgnore; import javax.servlet.http.HttpServletRequest; import javax.validation.Valid; +import java.util.List; @Slf4j @RestController @@ -24,22 +28,59 @@ public class MemberController { private final MemberService memberService; @GetMapping("/") - @ApiOperation(value = "유저 자신의 정보를 가져온다 (AccessToken 필요)") - public CommonApiResponse getMyInformation(HttpServletRequest request, @AuthMember Member member) { + @ApiOperation(value = "유저 자신의 모든 정보를 가져온다 (AccessToken 필요)") + public CommonApiResponse getMyInformation( + HttpServletRequest request, @ApiIgnore @AuthMember Member member) { + //로그인 상태가 아닌 경우 401 if (member == null) { throw new UnauthorizedException(ErrorCode.UNAUTHORIZED_USER); } - return CommonApiResponse.of(MemberCommonJoinResponseDto.of(member)); + return CommonApiResponse.of(MemberCommonResponseDto.of(member)); } + @PostMapping("/join") + @ApiOperation(value = "공통 유저를 기본 정보로 회원가입 시킨다") + public CommonApiResponse joinCommonMember( + @Valid @RequestBody MemberCommonJoinRequestDto dto) + { + final MemberCommonResponseDto res = memberService.createCommonMember(dto); + return CommonApiResponse.of(res); + } + @GetMapping("/detail") + @ApiOperation(value = "회원가입 세부 정보를 가져온다 (AccessToken 필요)") + public CommonApiResponse getMemberDetail( + @ApiIgnore @AuthMember Member member) + { + //로그인 상태가 아닌 경우 401 + if (member == null) { + throw new UnauthorizedException(ErrorCode.UNAUTHORIZED_USER); + } + final MemberDetailResponseDto res = memberService.readDetail(member); + return CommonApiResponse.of(res); + } - @PostMapping("/join") - public CommonApiResponse joinCommonMember(@Valid @RequestBody MemberCommonJoinRequestDto dto) { - final MemberCommonJoinResponseDto res = memberService.joinCommonMember(dto); + @PostMapping("/detail") + @ApiOperation(value = "회원가입 세부 정보를 입력한다 (AccessToken 필요)") + public CommonApiResponse setMemberDetail( + @Valid @RequestBody MemberDetailJoinRequestDto dto, + @ApiIgnore @AuthMember Member member) + { + //로그인 상태가 아닌 경우 401 + if (member == null) { + throw new UnauthorizedException(ErrorCode.UNAUTHORIZED_USER); + } + final MemberDetailResponseDto res = memberService.createDetail(member, dto); return CommonApiResponse.of(res); } + //페이징 처리 추가할 예정 + @GetMapping("/find") + @ApiOperation(value = "현재 가입한 모든 유저를 불러온다") + public CommonApiResponse> getMyInformation() { + return CommonApiResponse.of(memberService.findAll()); + } + // @PostMapping("/login") diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java b/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java index cbe743f..eb096d1 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/MemberService.java @@ -1,14 +1,18 @@ package com.tikitaka.naechinso.domain.member; import com.tikitaka.naechinso.domain.member.dto.MemberCommonJoinRequestDto; -import com.tikitaka.naechinso.domain.member.dto.MemberCommonJoinResponseDto; +import com.tikitaka.naechinso.domain.member.dto.MemberCommonResponseDto; +import com.tikitaka.naechinso.domain.member.dto.MemberDetailJoinRequestDto; +import com.tikitaka.naechinso.domain.member.dto.MemberDetailResponseDto; import com.tikitaka.naechinso.domain.member.entity.Member; +import com.tikitaka.naechinso.domain.member.entity.MemberDetail; import com.tikitaka.naechinso.global.common.response.TokenResponseDTO; import com.tikitaka.naechinso.global.config.security.MemberAdapter; import com.tikitaka.naechinso.global.config.security.dto.JwtDTO; import com.tikitaka.naechinso.global.config.security.jwt.JwtTokenProvider; import com.tikitaka.naechinso.global.error.ErrorCode; import com.tikitaka.naechinso.global.error.exception.BadRequestException; +import com.tikitaka.naechinso.global.error.exception.NotFoundException; import lombok.RequiredArgsConstructor; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; @@ -17,8 +21,10 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.util.Arrays; import java.util.List; import java.util.Optional; +import java.util.stream.Collectors; @Service @RequiredArgsConstructor @@ -30,7 +36,14 @@ public class MemberService { private final AuthenticationManagerBuilder authenticationManagerBuilder; private final JwtTokenProvider jwtTokenProvider; - public MemberCommonJoinResponseDto joinCommonMember(MemberCommonJoinRequestDto dto) { + public List findAll() { + List memberList = memberRepository.findAll().stream() + .map(member -> MemberCommonResponseDto.of(member)).collect(Collectors.toList()); + return memberList; + } + + + public MemberCommonResponseDto createCommonMember(MemberCommonJoinRequestDto dto) { //이미 존재하는 유저일 경우 400 Optional checkMember = memberRepository.findByPhone(dto.getPhone()); @@ -41,13 +54,12 @@ public MemberCommonJoinResponseDto joinCommonMember(MemberCommonJoinRequestDto d Member member = MemberCommonJoinRequestDto.toCommonMember(dto); memberRepository.save(member); - MemberCommonJoinResponseDto res = MemberCommonJoinResponseDto.of(member); + MemberCommonResponseDto res = MemberCommonResponseDto.of(member); return res; } public TokenResponseDTO login(String phone) { - System.out.println("phone = " + phone); Member checkMember = memberRepository.findByPhone(phone) .orElseThrow(() -> new BadRequestException(ErrorCode.USER_NOT_FOUND)); @@ -63,6 +75,26 @@ public TokenResponseDTO login(String phone) { return tokenResponseDTO; } + + public MemberDetailResponseDto readDetail(Member member) { +// +// Member checkMember = memberRepository.findByPhone(phone) +// .orElseThrow(() -> new BadRequestException(ErrorCode.USER_NOT_FOUND)); + + MemberDetailResponseDto dto = MemberDetailResponseDto.of(member); + + return dto; + } + + public MemberDetailResponseDto createDetail(Member authMember, MemberDetailJoinRequestDto dto) { + //영속성 유지를 위한 fetch + Member member = memberRepository.findById(authMember.getId()) + .orElseThrow(() -> new NotFoundException(ErrorCode.USER_NOT_FOUND)); + MemberDetail detail = MemberDetail.of(member, dto); + memberDetailRepository.save(detail); + return MemberDetailResponseDto.of(detail); + } + // // public MemberCommonJoinResponseDto joinMemberWithDetail(MemberCommonJoinRequestDto dto) { // //이미 존재하는 유저일 경우 400 diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberCommonJoinRequestDto.java b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberCommonJoinRequestDto.java index 46cba24..ad4ea66 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberCommonJoinRequestDto.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberCommonJoinRequestDto.java @@ -3,8 +3,8 @@ import com.tikitaka.naechinso.domain.member.constant.Gender; import com.tikitaka.naechinso.domain.member.entity.Member; import com.tikitaka.naechinso.global.annotation.Enum; +import io.swagger.annotations.ApiModelProperty; import lombok.*; -import org.hibernate.validator.constraints.Length; import javax.validation.constraints.*; @@ -18,16 +18,20 @@ @Builder @ToString public class MemberCommonJoinRequestDto { + @ApiModelProperty(example = "01010001000") @NotBlank(message = "전화번호를 입력해주세요") @Pattern(regexp = "[0-9]{10,11}", message = "하이픈 없는 10~11자리 숫자를 입력해주세요") private String phone; + @ApiModelProperty(example = "닉") @NotBlank(message = "이름을 입력해주세요") private String name; + @ApiModelProperty(example = "M") @Enum(enumClass = Gender.class, message = "성별 입력이 올바르지 않습니다. M 또는 W가 필요합니다") private Gender gender; + @ApiModelProperty(example = "25") @Min(value = 25, message = "25-33세까지만 가입 가능합니다") @Max(value = 33, message = "25-33세까지만 가입 가능합니다") private int age; @@ -50,12 +54,15 @@ public class MemberCommonJoinRequestDto { @NotNull(message = "마케팅 동의 여부가 필요합니다") private boolean acceptsMarketing; + @ApiModelProperty(example = "카카오") @NotBlank(message = "직장명을 입력해주세요") private String jobName; + @ApiModelProperty(example = "개발자") @NotBlank(message = "직장 부서를 입력해주세요") private String jobPart; + @ApiModelProperty(example = "판교") @NotBlank(message = "직장 위치를 입력해주세요") private String jobLocation; diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberCommonJoinResponseDto.java b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberCommonResponseDto.java similarity index 65% rename from src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberCommonJoinResponseDto.java rename to src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberCommonResponseDto.java index 09945ae..7a2281b 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberCommonJoinResponseDto.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberCommonResponseDto.java @@ -4,11 +4,6 @@ import com.tikitaka.naechinso.domain.member.entity.Member; import lombok.*; -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Pattern; -import javax.validation.constraints.Size; - /** * 추천인 및 추천 받는 사람 공통 가입을 위한 Dto입니다 * @author gengminy 220924 @@ -18,7 +13,7 @@ @Getter @Builder @ToString -public class MemberCommonJoinResponseDto { +public class MemberCommonResponseDto { private String phone; private String name; @@ -27,8 +22,8 @@ public class MemberCommonJoinResponseDto { private int age; - public static MemberCommonJoinResponseDto of(Member member) { - MemberCommonJoinResponseDto res = MemberCommonJoinResponseDto.builder() + public static MemberCommonResponseDto of(Member member) { + MemberCommonResponseDto res = MemberCommonResponseDto.builder() .phone(member.getPhone()) .name(member.getName()) .gender(member.getGender()) diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDTO.java b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDTO.java new file mode 100644 index 0000000..dbbc0b3 --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDTO.java @@ -0,0 +1,4 @@ +package com.tikitaka.naechinso.domain.member.dto; + +public class MemberDTO { +} diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailJoinRequestDto.java b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailJoinRequestDto.java index be122c5..ade8873 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailJoinRequestDto.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailJoinRequestDto.java @@ -2,8 +2,11 @@ import com.tikitaka.naechinso.domain.member.constant.Gender; import com.tikitaka.naechinso.domain.member.entity.Member; +import io.swagger.annotations.ApiModelProperty; import lombok.*; +import org.hibernate.validator.constraints.Length; +import javax.persistence.Column; import javax.validation.constraints.*; /** @@ -16,61 +19,57 @@ @Builder @ToString public class MemberDetailJoinRequestDto { - @NotBlank(message = "전화번호를 입력해주세요") - @Pattern(regexp = "[0-9]{10,11}", message = "하이픈 없는 10~11자리 숫자를 입력해주세요") - private String phone; + //추천인 정보 + // + @ApiModelProperty(example = "180") + @Positive(message = "키는 양수여야 합니다") + private int height; - @NotBlank(message = "이름을 입력해주세요") - private String name; + @ApiModelProperty(example = "서울시 강남구") + @NotBlank(message = "주소 정보를 입력해야 합니다") + private String address; - @NotNull(message = "성별을 입력해주세요") - private Gender gender; + @NotBlank(message = "종교 정보를 입력해야 합니다") + private String religion; - @Min(value = 25, message = "25-33세까지만 가입 가능합니다") - @Max(value = 33, message = "25-33세까지만 가입 가능합니다") - private int age; + @NotBlank(message = "음주 정보를 입력해야 합니다") + private String drink; - @NotNull(message = "서비스 이용약관 동의가 필요합니다") - @AssertTrue(message = "서비스 이용약관 동의가 필요합니다") - private boolean acceptsService; + @NotBlank(message = "흡연 정보를 입력해야 합니다") + private String smoke; - @NotNull(message = "개인정보 이용 동의가 필요합니다") - @AssertTrue(message = "개인정보 이용 동의가 필요합니다") - private boolean acceptsInfo; + @ApiModelProperty(example = "ESTJ") + @Length(max = 4, message = "올바를 MBTI 정보를 입력하세요") + private String mbti = ""; - @NotNull(message = "종교 정보 제공 동의가 필요합니다") - @AssertTrue(message = "종교 정보 제공 동의가 필요합니다") - private boolean acceptsReligion; + @NotBlank(message = "성격 정보를 입력해야 합니다") + private String personality; - @NotNull(message = "위치 정보 제공 동의 여부가 필요합니다") - private boolean acceptsLocation; + @NotBlank(message = "자기 소개를 입력해야 합니다") + private String introduce = ""; - @NotNull(message = "마케팅 동의 여부가 필요합니다") - private boolean acceptsMarketing; + @NotBlank(message = "취미 정보를 입력해야 합니다") + private String hobby = ""; - @NotBlank(message = "직장명을 입력해주세요") - private String jobName; + @NotBlank(message = "연애 스타일을 입력해야 합니다") + private String style = ""; - @NotBlank(message = "직장 부서를 입력해주세요") - private String jobPart; + @NotBlank(message = "사진을 업로드해야 합니다") + private String picture; + + @ApiModelProperty(example = "서울") + private String school; + + @ApiModelProperty(example = "컴퓨터공학과") + private String major; + + @ApiModelProperty(example = "대학교") + private String eduLevel; - @NotBlank(message = "직장 위치를 입력해주세요") - private String jobLocation; public static Member toCommonMember(MemberDetailJoinRequestDto dto) { Member member = Member.builder() - .phone(dto.phone) - .name(dto.name) - .gender(dto.gender) - .age(dto.age) - .acceptsService(dto.acceptsService) - .acceptsInfo(dto.acceptsInfo) - .acceptsReligion(dto.acceptsReligion) - .acceptsLocation(dto.acceptsLocation) - .acceptsMarketing(dto.acceptsMarketing) - .jobName(dto.jobName) - .jobPart(dto.jobPart) - .jobLocation(dto.jobLocation) + .build(); return member; diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailResponseDto.java b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailResponseDto.java new file mode 100644 index 0000000..193610a --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/domain/member/dto/MemberDetailResponseDto.java @@ -0,0 +1,98 @@ +package com.tikitaka.naechinso.domain.member.dto; + +import com.tikitaka.naechinso.domain.member.constant.Gender; +import com.tikitaka.naechinso.domain.member.entity.Member; +import com.tikitaka.naechinso.domain.member.entity.MemberDetail; +import lombok.*; + +import javax.persistence.Column; +import javax.persistence.EnumType; +import javax.persistence.Enumerated; + +/** + * 추천인 및 추천 받는 사람 공통 가입을 위한 Dto입니다 + * @author gengminy 220924 + * */ +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Builder +@ToString +public class MemberDetailResponseDto { + +// private Member member; + //추천인 정보 + private String phone; + + private String name; + + private Gender gender; + + private int age; + + + + private int height; + + private String address; + + private String religion; + + private String drink; + + private String smoke; + + private String mbti; + + private String personality; + + private String introduce; + + private String hobby; + + private String style; + + private String picture; + + private Long point; + + private String school; + + private String major; + + private String eduLevel; + + public static MemberDetailResponseDto of(Member member) { + MemberDetail detail = member.getDetail(); + //회원가입 정보가 없으면 null + if (detail == null) { + return null; + } + return buildDetail(detail); + } + + public static MemberDetailResponseDto of(MemberDetail memberDetail) { + return buildDetail(memberDetail); + } + + private static MemberDetailResponseDto buildDetail(MemberDetail detail) { + return MemberDetailResponseDto.builder() + .height(detail.getHeight()) + .address(detail.getAddress()) + .religion(detail.getReligion()) + .drink(detail.getDrink()) + .smoke(detail.getSmoke()) + .mbti(detail.getMbti()) + .personality(detail.getPersonality()) + .introduce(detail.getIntroduce()) + .hobby(detail.getHobby()) + .style(detail.getStyle()) + .picture(detail.getPicture()) + .point(detail.getPoint()) + .school(detail.getSchool()) + .major(detail.getMajor()) + .eduLevel(detail.getEduLevel()) + .build(); + } + +} diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java b/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java index dcea98c..2549f6d 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/entity/Member.java @@ -1,10 +1,14 @@ package com.tikitaka.naechinso.domain.member.entity; import com.tikitaka.naechinso.domain.member.constant.Gender; +import com.tikitaka.naechinso.domain.point.entity.Point; +import com.tikitaka.naechinso.domain.recommend.entity.Recommend; import com.tikitaka.naechinso.global.config.entity.BaseEntity; import lombok.*; import javax.persistence.*; +import java.util.ArrayList; +import java.util.List; /** * 멤버 공통 정보를 담당하는 엔티티입니다 @@ -38,23 +42,23 @@ public class Member extends BaseEntity { @Column(name = "mem_age") private int age; - @Column(name = "mem_accpets_service") + @Column(name = "mem_accepts_service") @Builder.Default private boolean acceptsService = false; - @Column(name = "mem_accpets_info") + @Column(name = "mem_accepts_info") @Builder.Default private boolean acceptsInfo = false; - @Column(name = "mem_accpets_religion") + @Column(name = "mem_accepts_religion") @Builder.Default private boolean acceptsReligion = false; - @Column(name = "mem_accpets_location") + @Column(name = "mem_accepts_location") @Builder.Default private boolean acceptsLocation = false; - @Column(name = "mem_accpets_marketing") + @Column(name = "mem_accepts_marketing") @Builder.Default private boolean acceptsMarketing = false; @@ -72,12 +76,19 @@ public class Member extends BaseEntity { @JoinColumn(name = "mem_detail") private MemberDetail detail; + //소개해준 사람들 -> recommend 로 넣으면 됨 + //mapped by 에는 연관관계 엔티티의 필드명을 적어줌 + @OneToMany(mappedBy = "sender") + private List recommends = new ArrayList<>(); + //소개해준 사람들 -> recommend 로 넣으면 됨 + @OneToOne(mappedBy = "receiver") + private Recommend recommend_received; + + + public void setDetail(MemberDetail memberDetail) { + this.detail = memberDetail; + } -// //소개해준 사람들 -// @OneToMany -// @JoinColumn -// @Builder.Default -// private List receivers = new ArrayList<>(); } diff --git a/src/main/java/com/tikitaka/naechinso/domain/member/entity/MemberDetail.java b/src/main/java/com/tikitaka/naechinso/domain/member/entity/MemberDetail.java index 7caf770..2ec417f 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/member/entity/MemberDetail.java +++ b/src/main/java/com/tikitaka/naechinso/domain/member/entity/MemberDetail.java @@ -1,10 +1,15 @@ package com.tikitaka.naechinso.domain.member.entity; +import com.tikitaka.naechinso.domain.member.dto.MemberDetailJoinRequestDto; +import com.tikitaka.naechinso.domain.point.entity.Point; import com.tikitaka.naechinso.global.config.entity.BaseEntity; import com.tikitaka.naechinso.global.config.entity.BaseTimeEntity; +import io.swagger.annotations.ApiModelProperty; import lombok.*; import javax.persistence.*; +import java.util.ArrayList; +import java.util.List; /** * 추천 받은 멤버 가입 정보를 담당하는 엔티티입니다 @@ -30,7 +35,7 @@ public class MemberDetail extends BaseEntity { // private Member recommender; @Column(name = "mem_height") - private Integer height; + private int height; @Column(name = "mem_address") private String address; @@ -55,11 +60,20 @@ public class MemberDetail extends BaseEntity { @Builder.Default private String introduce = ""; + @Column(name = "mem_hobby") + @Builder.Default + private String hobby = ""; + + @Column(name = "mem_style") + @Builder.Default + private String style = ""; + @Column(name = "mem_picture") private String picture; @Column(name = "mem_point") - private Long point; + @Builder.Default + private Long point = 0L; @Column(name = "mem_school") private String school; @@ -70,8 +84,9 @@ public class MemberDetail extends BaseEntity { @Column(name = "mem_edu_level") private String eduLevel; - - + // 포인트 내역 + @OneToMany(mappedBy = "member") + private List points = new ArrayList<>(); // Member Entity 와 1:1 조인 // Member PK 그대로 사용 @@ -79,4 +94,45 @@ public class MemberDetail extends BaseEntity { @MapsId @JoinColumn(name = "mem_id") private Member member; + + + public static MemberDetail of(MemberDetailJoinRequestDto dto) { + return MemberDetail.builder() + .height(dto.getHeight()) + .address(dto.getAddress()) + .religion(dto.getReligion()) + .drink(dto.getDrink()) + .smoke(dto.getSmoke()) + .mbti(dto.getMbti()) + .personality(dto.getPersonality()) + .introduce(dto.getIntroduce()) + .hobby(dto.getHobby()) + .style(dto.getStyle()) + .picture(dto.getPicture()) + .school(dto.getSchool()) + .major(dto.getMajor()) + .eduLevel(dto.getEduLevel()) + .build(); + } + + public static MemberDetail of(Member member, MemberDetailJoinRequestDto dto) { + return MemberDetail.builder() + .height(dto.getHeight()) + .address(dto.getAddress()) + .religion(dto.getReligion()) + .drink(dto.getDrink()) + .smoke(dto.getSmoke()) + .mbti(dto.getMbti()) + .personality(dto.getPersonality()) + .introduce(dto.getIntroduce()) + .hobby(dto.getHobby()) + .style(dto.getStyle()) + .picture(dto.getPicture()) + .school(dto.getSchool()) + .major(dto.getMajor()) + .eduLevel(dto.getEduLevel()) + .member(member) + .build(); + } + } diff --git a/src/main/java/com/tikitaka/naechinso/domain/point/entity/Point.java b/src/main/java/com/tikitaka/naechinso/domain/point/entity/Point.java index 21e168e..86ffcce 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/point/entity/Point.java +++ b/src/main/java/com/tikitaka/naechinso/domain/point/entity/Point.java @@ -34,8 +34,7 @@ public class Point extends BaseEntity { @Column(name = "poi_type") private String type; -// -// @ManyToOne -// @PrimaryKeyJoinColumn -// private Member member; + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "mem_id") + private MemberDetail member; } diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendController.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendController.java index fd454c6..eae4116 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendController.java +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendController.java @@ -1,7 +1,52 @@ package com.tikitaka.naechinso.domain.recommend; +import com.tikitaka.naechinso.domain.member.dto.MemberCommonResponseDto; +import com.tikitaka.naechinso.domain.member.entity.Member; +import com.tikitaka.naechinso.domain.recommend.dto.RecommendListResponseDTO; +import com.tikitaka.naechinso.domain.recommend.dto.RecommendRequestDTO; +import com.tikitaka.naechinso.global.annotation.AuthMember; +import com.tikitaka.naechinso.global.config.CommonApiResponse; +import com.tikitaka.naechinso.global.error.ErrorCode; +import com.tikitaka.naechinso.global.error.exception.UnauthorizedException; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.*; +import springfox.documentation.annotations.ApiIgnore; -@Controller +import javax.servlet.http.HttpServletRequest; + +@Slf4j +@RestController +@RequestMapping("/recommend") +@RequiredArgsConstructor public class RecommendController { + + private final RecommendService recommendService; + + @GetMapping("/") + @ApiOperation(value = "내 추천사 정보를 가져온다 (AccessToken 필요)") + public CommonApiResponse getRecommends( + HttpServletRequest request, + @ApiIgnore @AuthMember Member member) + { + if (member == null) { + throw new UnauthorizedException(ErrorCode.UNAUTHORIZED_USER); + } + return CommonApiResponse.of(recommendService.getRecommendList(member)); + } + + @PostMapping("/") + @ApiOperation(value = "추천사를 작성한다 (AccessToken 필요)") + public CommonApiResponse writeRecommend( + HttpServletRequest request, + @RequestBody RecommendRequestDTO dto, + @ApiIgnore @AuthMember Member member) + { + if (member == null) { + throw new UnauthorizedException(ErrorCode.UNAUTHORIZED_USER); + } + return CommonApiResponse.of(MemberCommonResponseDto.of(member)); + } } diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendRepository.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendRepository.java index fb80185..5bb4fb8 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendRepository.java +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendRepository.java @@ -1,4 +1,10 @@ package com.tikitaka.naechinso.domain.recommend; -public interface RecommendRepository { +import com.tikitaka.naechinso.domain.member.entity.MemberDetail; +import com.tikitaka.naechinso.domain.recommend.entity.Recommend; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface RecommendRepository extends JpaRepository { } diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendService.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendService.java index 42c1315..6310d77 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendService.java +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/RecommendService.java @@ -1,7 +1,70 @@ package com.tikitaka.naechinso.domain.recommend; +import com.tikitaka.naechinso.domain.member.MemberRepository; +import com.tikitaka.naechinso.domain.member.entity.Member; +import com.tikitaka.naechinso.domain.recommend.dto.RecommendListResponseDTO; +import com.tikitaka.naechinso.domain.recommend.dto.RecommendRequestDTO; +import com.tikitaka.naechinso.domain.recommend.entity.Recommend; +import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Optional; @Service +@RequiredArgsConstructor +@Transactional public class RecommendService { + + private final RecommendRepository recommendRepository; + private final MemberRepository memberRepository; + + public RecommendListResponseDTO getRecommendList(Member member) { + return RecommendListResponseDTO.of(member); + } + + /** + * 추천사를 작성한다 + * @param member 로그인한 사용자인지 가져옴 + * @param dto 추천하려는 사람의 정보 dto + * */ + public RecommendListResponseDTO recommendMember( + Member member, + RecommendRequestDTO dto) + { + Member sender; + //작성자가 회원일 경우 그대로 저장 + if (member != null && member.getDetail() != null) { + sender = member; + } + //작성자가 회원이 아닐 경우 + else { + sender = member.builder() + + .build(); + } + + //작성자가 회원일 경우, + //추천할 사람이 이미 가입하여 요청했을 경우, + //둘 모두 회원이 아닐 경우 + + Optional checkMember = memberRepository.findByPhone(dto.getPhone()); + Member receiver; + //상대가 이미 있는 유저면 FK 로 저장 + if (checkMember.isPresent()) { + receiver = checkMember.get(); + } + //상대가 없는 유저면 새로 만든 후 FK 저장 + else { + receiver = Member.builder() + .build(); + } + + Recommend recommend = Recommend.builder() + .sender(sender) + .phone(receiver.getPhone()) + + .build(); + return RecommendListResponseDTO.of(receiver); + } } diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendDTO.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendDTO.java new file mode 100644 index 0000000..2bf4c39 --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendDTO.java @@ -0,0 +1,43 @@ +package com.tikitaka.naechinso.domain.recommend.dto; + +import com.tikitaka.naechinso.domain.member.constant.Gender; +import com.tikitaka.naechinso.domain.member.entity.Member; +import com.tikitaka.naechinso.domain.recommend.entity.Recommend; +import lombok.*; + +import javax.persistence.*; + +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Builder +@ToString +public class RecommendDTO { + + private String phone; + + private Member sender; + + private Member receiver; + + private String name; + + private Gender gender; + + private String meet; + + private String appeal; + + + public static RecommendDTO of(Recommend recommend) { + return RecommendDTO.builder() + .phone(recommend.getPhone()) + .sender(recommend.getSender()) + .receiver(recommend.getReceiver()) + .name(recommend.getName()) + .gender(recommend.getGender()) + .meet(recommend.getMeet()) + .appeal(recommend.getAppeal()) + .build(); + } +} diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendListResponseDTO.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendListResponseDTO.java new file mode 100644 index 0000000..609c920 --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendListResponseDTO.java @@ -0,0 +1,30 @@ +package com.tikitaka.naechinso.domain.recommend.dto; + +import com.tikitaka.naechinso.domain.member.entity.Member; +import com.tikitaka.naechinso.domain.recommend.entity.Recommend; +import lombok.*; + +import java.util.ArrayList; +import java.util.List; + +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Builder +@ToString +public class RecommendListResponseDTO { + List recommends = new ArrayList<>(); + + + public static RecommendListResponseDTO of(Member member) { + List recommendDTOList = new ArrayList<>(); + + member.getRecommends().stream().forEach(recommend -> + recommendDTOList.add(RecommendDTO.of(recommend)) + ); + + return RecommendListResponseDTO.builder() + .recommends(recommendDTOList) + .build(); + } +} diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendRequestDTO.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendRequestDTO.java new file mode 100644 index 0000000..264a202 --- /dev/null +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/dto/RecommendRequestDTO.java @@ -0,0 +1,43 @@ +package com.tikitaka.naechinso.domain.recommend.dto; + +import com.tikitaka.naechinso.domain.member.constant.Gender; +import com.tikitaka.naechinso.global.annotation.Enum; +import lombok.*; + +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.Pattern; + +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Builder +@ToString +public class RecommendRequestDTO { + @NotBlank(message = "친구의 전화번호를 입력해주세요") + @Pattern(regexp = "[0-9]{10,11}", message = "하이픈 없는 10~11자리 숫자를 입력해주세요") + private String phone; + + @NotBlank(message = "친구의 이름을 입력해주세요") + private String name; + + @Enum(enumClass = Gender.class, message = "친구의 성별 입력이 올바르지 않습니다. M 또는 W가 필요합니다") + private Gender gender; + + @Min(value = 25, message = "25-33세까지만 추천 및 가입 가능합니다") + @Max(value = 33, message = "25-33세까지만 추천 및 가입 가능합니다") + private int age; + + @NotBlank(message = "만나게 된 계기를 입력해주세요") + private String meet; + + @NotBlank(message = "친구의 성격 키워드를 입력해주세요") + private String personality; + + @NotBlank(message = "친구의 매력을 입력해주세요") + private String appeal; + + + +} diff --git a/src/main/java/com/tikitaka/naechinso/domain/recommend/entity/Recommend.java b/src/main/java/com/tikitaka/naechinso/domain/recommend/entity/Recommend.java index 7fe04cb..dee7999 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/recommend/entity/Recommend.java +++ b/src/main/java/com/tikitaka/naechinso/domain/recommend/entity/Recommend.java @@ -1,5 +1,7 @@ package com.tikitaka.naechinso.domain.recommend.entity; +import com.tikitaka.naechinso.domain.member.constant.Gender; +import com.tikitaka.naechinso.domain.member.entity.Member; import com.tikitaka.naechinso.global.config.entity.BaseEntity; import com.tikitaka.naechinso.global.config.entity.BaseTimeEntity; import lombok.*; @@ -23,4 +25,29 @@ public class Recommend extends BaseEntity { @GeneratedValue @Column(name = "rec_id") private Long id; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "mem_id") + private Member sender; + + /* 받는 사람이 아직 가입 안했으면 NULL 일수도 있음 */ + @OneToOne + @JoinColumn(name = "rec_target_id") + private Member receiver; + + @Column(name = "rec_name") + private String name; + + @Column(name = "rec_gender") + @Enumerated(EnumType.STRING) + private Gender gender; + + @Column(name = "rec_meet") + private String meet; + + @Column(name = "rec_appeal") + private String appeal; + + @Column(name = "rec_phone") + private String phone; } diff --git a/src/main/java/com/tikitaka/naechinso/domain/sms/SmsCertificationServiceImpl.java b/src/main/java/com/tikitaka/naechinso/domain/sms/SmsCertificationServiceImpl.java index 1ead487..1f47e92 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/sms/SmsCertificationServiceImpl.java +++ b/src/main/java/com/tikitaka/naechinso/domain/sms/SmsCertificationServiceImpl.java @@ -90,7 +90,7 @@ public String sendVerificationMessage(String to) { /** * 인증번호를 검증한다 * @param smsCertificationRequestDto {phoneNumber: 휴대폰 번호, code: 인증번호} - * @return 전송 성공시 메세지 + * @return TokenResponseDTO { accessToken, refreshToken } */ @Override public TokenResponseDTO verifyCode(SmsCertificationRequestDTO smsCertificationRequestDto) { @@ -110,12 +110,31 @@ public TokenResponseDTO verifyCode(SmsCertificationRequestDTO smsCertificationRe //redis 인증 필터 성공하면 try { + /* VERIFY FLOW + * -> 아직 MemberDetail 작성한 회원이 아닐 경우 + * 1. 이미 추천사를 받은 신규회원 + * 2. 추천사를 받아야 하는 신규회원 + * 3. 추천사 써주려는 신규회원 + * 4. 추천 요청을 받아서 추천사를 써주는 신규회원 + * * 입력이 다 되었는지 검증, 안되면 register 토큰 발급 + * + * -> MemberDetail 검증 완료된 회원 + * 5. 즉시 마이페이지 이동 + * */ + + //가입 안된 회원일 경우 null 리턴 Optional checkMember = memberRepository.findByPhone(phoneNumber); if (checkMember.isEmpty()) { return null; } + if (checkMember.get().getDetail() != null) { + System.out.println("checkMember.get().getDetail() = " + checkMember.get().getDetail()); + } else { + System.out.println("detail is null"); + } + //이미 가입한 회원이면 //인증한 휴대폰 번호로 로그인 후 토큰 생성 TokenResponseDTO tokenResponseDTO = memberService.login(phoneNumber); diff --git a/src/main/java/com/tikitaka/naechinso/domain/sms/dto/SmsCertificationRequestDTO.java b/src/main/java/com/tikitaka/naechinso/domain/sms/dto/SmsCertificationRequestDTO.java index 85b983e..7a6db02 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/sms/dto/SmsCertificationRequestDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/sms/dto/SmsCertificationRequestDTO.java @@ -1,5 +1,6 @@ package com.tikitaka.naechinso.domain.sms.dto; +import io.swagger.annotations.ApiModelProperty; import lombok.*; import javax.validation.constraints.NotBlank; @@ -13,10 +14,12 @@ @ToString public class SmsCertificationRequestDTO { + @ApiModelProperty(example = "01010001000") @NotBlank(message = "전화번호를 입력해주세요") @Pattern(regexp = "[0-9]{10,11}", message = "하이픈 없는 10~11자리 숫자를 입력해주세요") String phoneNumber; + @ApiModelProperty(example = "000000") @NotBlank(message = "인증번호를 입력해주세요") @Pattern(regexp = "[0-9]{6}", message = "인증번호 6자리를 입력해주세요") String code; diff --git a/src/main/java/com/tikitaka/naechinso/domain/sms/dto/SmsVerificationCodeRequestDTO.java b/src/main/java/com/tikitaka/naechinso/domain/sms/dto/SmsVerificationCodeRequestDTO.java index 99a12bd..af1cb83 100644 --- a/src/main/java/com/tikitaka/naechinso/domain/sms/dto/SmsVerificationCodeRequestDTO.java +++ b/src/main/java/com/tikitaka/naechinso/domain/sms/dto/SmsVerificationCodeRequestDTO.java @@ -1,5 +1,6 @@ package com.tikitaka.naechinso.domain.sms.dto; +import io.swagger.annotations.ApiModelProperty; import lombok.*; import javax.validation.constraints.NotBlank; @@ -11,6 +12,7 @@ @Builder @ToString public class SmsVerificationCodeRequestDTO { + @ApiModelProperty(example = "01010001000") @NotBlank(message = "전화번호를 입력해주세요") @Pattern(regexp = "[0-9]{10,11}", message = "하이픈 없는 10~11자리 숫자를 입력해주세요") String phoneNumber; diff --git a/src/main/java/com/tikitaka/naechinso/global/annotation/AuthMember.java b/src/main/java/com/tikitaka/naechinso/global/annotation/AuthMember.java index de5cec8..230c3ab 100644 --- a/src/main/java/com/tikitaka/naechinso/global/annotation/AuthMember.java +++ b/src/main/java/com/tikitaka/naechinso/global/annotation/AuthMember.java @@ -1,18 +1,22 @@ package com.tikitaka.naechinso.global.annotation; import org.springframework.security.core.annotation.AuthenticationPrincipal; +import springfox.documentation.annotations.ApiIgnore; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; -/** - * request 의 Authorization 헤더를 가지고 +/* +* request 의 Authorization 헤더를 가지고 * JwtAuthenticationFilter 를 통과하면서 - * SecurityContextHolder 에 로그인 된 유저의 + * SecurityContextHolder 에 로그인 된 유저의 ... +* */ + +/** * UserDetails 의 커스텀 구현체 MemberAdapter 를 가져온 후 - * member property 를 추출하는 어노테이션 + * member 객체 프로퍼티를 추출하는 어노테이션 * @author gengimny 220926 * */ @Target(ElementType.PARAMETER) diff --git a/src/main/java/com/tikitaka/naechinso/global/annotation/Enum.java b/src/main/java/com/tikitaka/naechinso/global/annotation/Enum.java index eabebdf..6832a19 100644 --- a/src/main/java/com/tikitaka/naechinso/global/annotation/Enum.java +++ b/src/main/java/com/tikitaka/naechinso/global/annotation/Enum.java @@ -7,6 +7,10 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +/** + * RequestBody 의 Enum 검증을 위한 어노테이션 입니다 + * @author gengminy 220927 + * */ /* 해당 annotation이 실행 할 ConstraintValidator 구현체를 `EnumValidator`로 지정합니다. */ @Constraint(validatedBy = {EnumValidator.class}) /* 해당 annotation은 메소드, 필드, 파라미터에 적용 할 수 있습니다. */ diff --git a/src/main/java/com/tikitaka/naechinso/global/config/security/jwt/JwtAuthenticationEntryPoint.java b/src/main/java/com/tikitaka/naechinso/global/config/security/jwt/JwtAuthenticationEntryPoint.java index 8859703..e54eec2 100644 --- a/src/main/java/com/tikitaka/naechinso/global/config/security/jwt/JwtAuthenticationEntryPoint.java +++ b/src/main/java/com/tikitaka/naechinso/global/config/security/jwt/JwtAuthenticationEntryPoint.java @@ -13,6 +13,12 @@ import javax.servlet.http.HttpServletResponse; import java.io.IOException; + +/** + * ControllerAdvice 에서는 Spring Security 예외를 잡아낼 수 없기 때문에 + * AuthenticationEntryPoint 구현체를 통해 예외처리를 커스텀한다 + * @author gengminy 220926 + * */ @Slf4j @Component public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint { @@ -22,8 +28,10 @@ public void commence( HttpServletResponse response, AuthenticationException e ) throws IOException { + String exception = (String)request.getAttribute("exception"); + //토큰이 없을 경우 if(exception == null || exception.equals(ErrorCode.NO_TOKEN.getCode())) { setResponse(response, ErrorCode.NO_TOKEN); }