diff --git a/.DS_Store b/.DS_Store index 281e3db..2b11931 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/build.gradle b/build.gradle index 2ff8e85..89141c4 100644 --- a/build.gradle +++ b/build.gradle @@ -35,8 +35,12 @@ dependencies { // S3 implementation 'org.springframework.cloud:spring-cloud-starter-aws:2.2.6.RELEASE' - // h2 db 추가 - implementation "com.h2database:h2" + + //ModelMapper 라이브러리 추가 + implementation 'org.modelmapper:modelmapper:2.4.2' + + //파일 관련 + implementation 'org.apache.pdfbox:pdfbox:2.0.24' } tasks.named('test') { diff --git a/build/libs/BE-ver_230228.jar b/build/libs/BE-ver_230228.jar deleted file mode 100644 index cc38cb3..0000000 Binary files a/build/libs/BE-ver_230228.jar and /dev/null differ diff --git a/build/libs/BE-ver_230301.jar b/build/libs/BE-ver_230301.jar deleted file mode 100644 index 980901d..0000000 Binary files a/build/libs/BE-ver_230301.jar and /dev/null differ diff --git a/src/main/java/Remoa/BE/Member/Controller/FollowController.java b/src/main/java/Remoa/BE/Member/Controller/FollowController.java index 9e20bdd..a16b415 100644 --- a/src/main/java/Remoa/BE/Member/Controller/FollowController.java +++ b/src/main/java/Remoa/BE/Member/Controller/FollowController.java @@ -4,18 +4,13 @@ import Remoa.BE.Member.Service.FollowService; import Remoa.BE.Member.Service.MemberService; import Remoa.BE.exception.CustomMessage; -import Remoa.BE.exception.response.ErrorResponse; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; -import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.web.bind.annotation.*; import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpSession; -import java.util.Arrays; import java.util.List; import java.util.Objects; @@ -27,7 +22,6 @@ @RestController @Slf4j @RequiredArgsConstructor -@CrossOrigin(origins = "*") public class FollowController { private final FollowService followService; diff --git a/src/main/java/Remoa/BE/Member/Controller/KakaoController.java b/src/main/java/Remoa/BE/Member/Controller/KakaoController.java index be74e54..c06ad46 100644 --- a/src/main/java/Remoa/BE/Member/Controller/KakaoController.java +++ b/src/main/java/Remoa/BE/Member/Controller/KakaoController.java @@ -5,21 +5,21 @@ import Remoa.BE.Member.Dto.Res.ResSignupDto; import Remoa.BE.Member.Service.KakaoService; import Remoa.BE.Member.Service.MemberService; +import Remoa.BE.Member.Service.ProfileService; import Remoa.BE.exception.CustomMessage; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; -import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpSession; import java.io.IOException; import java.util.Map; import java.util.Optional; +import java.util.Random; import static Remoa.BE.exception.CustomBody.*; import static Remoa.BE.utill.MemberInfo.*; @@ -28,12 +28,13 @@ @RestController @Slf4j @RequiredArgsConstructor -@CrossOrigin(origins = "*") // 프론트에서 추가 요청 public class KakaoController { + + private final KakaoService ks; private final MemberService memberService; - private final HttpSession httpSession; + private final ProfileService profileService; /** * 카카오 로그인을 통해 code를 query string으로 받아오면, 코드를 통해 토큰, 토큰을 통해 사용자 정보를 얻어와 db에 해당 사용자가 존재하는지 여부를 @@ -62,7 +63,7 @@ public ResponseEntity getCI(@RequestParam String code, HttpServletReques if (member.isPresent()) { securityLoginWithoutLoginForm(member.get(), request); //if문에 걸리지 않았다면 이미 회원가입이 진행돼 db에 kakaoId가 있는 유저이므로 kakaoMember가 존재하므로 LoginController처럼 로그인 처리 하면 됩니다. - return successResponse(CustomMessage.OK, userInfo); + return successResponse(CustomMessage.OK, member.get().getNickname()); } else { //kakaoId가 db에 없으므로 kakaoMember가 null이므로 회원가입하지 않은 회원. 따라서 회원가입이 필요하므로 회원가입하는 uri로 redirect 시켜주어야 함. @@ -70,33 +71,33 @@ public ResponseEntity getCI(@RequestParam String code, HttpServletReques } } - /** - * 카카오 로그인을 우회해 테스트 하기 위한 용도로 추가됨. - * @param kakaoId - * @return ResponseEntity - */ - @PostMapping("/login/kakao/test") - public ResponseEntity testLogin(@RequestBody Integer kakaoId, HttpServletRequest request) { - log.warn("kakaoId = {}", kakaoId); - Optional findMember = memberService.findByKakaoId(Long.valueOf(kakaoId)); - if (findMember.isPresent()) { - Member member = findMember.get(); - securityLoginWithoutLoginForm(member, request); - return successResponse(CustomMessage.OK, member); - } - return failResponse(CustomMessage.VALIDATED, "User Not Exist"); - } - /** * front-end에서 회원가입에 필요한 정보를 넘겨주면 KakaoSignupForm으로 받아 회원가입을 진행시켜줌 */ @PostMapping("/signup/kakao") - public ResponseEntity signupKakaoMember(@RequestBody @Validated ReqSignupDto form, HttpServletRequest request) { + public ResponseEntity signupKakaoMember(@RequestBody @Validated ReqSignupDto form, HttpServletRequest request) throws IOException { Member member = new Member(); + + member.setNickname(form.getNickname()); + + //닉네임 사용 가능하면 그대로 진행, 불가능하면 임의 닉네임 "유저-{randomInt}로 지정. + Boolean nicknameDuplicate = memberService.isNicknameDuplicate(form.getNickname()); + while (nicknameDuplicate) { //특수문자는 닉네임에 사용할 수 없으나 임의로 지정하는 닉네임에는 사용 가능하게 해서 또 다른 중복 문제 없게끔. + Random random = new Random(); + String randomNumber = Integer.toString((random.nextInt(900_000) + 100_000)); // 100_000 ~ 999_999 + nicknameDuplicate = memberService.isNicknameDuplicate("유저-" + randomNumber); + member.setNickname("유저-" + randomNumber); + } + + form.setProfileImage(profileService.editProfileImg(form.getNickname(), form.getProfileImage())); + + //카카오에서 받은 프로필 사진 url 링크를 토대로 s3에 저장 + if (memberService.findByKakaoId(form.getKakaoId()).isPresent()) { + return failResponse(CustomMessage.VALIDATED, "kakaoId가 이미 가입되어 있습니다."); + } member.setKakaoId(form.getKakaoId()); member.setEmail(form.getEmail()); - member.setNickname(form.getNickname()); member.setProfileImage(form.getProfileImage()); member.setTermConsent(form.getTermConsent()); @@ -114,39 +115,22 @@ public ResponseEntity signupKakaoMember(@RequestBody @Validated ReqSignu return successResponse(CustomMessage.OK,result); } - /** - *자동 로그인 추후에 - */ -/* - @GetMapping("/login") - public ResponseEntity autoLogin(){ - Long kaKaoId = getKaKaoId(); - Optional member = memberService.findByKakaoId(kaKaoId); - if(member.isPresent()){ - return successResponse(CustomMessage.OK,member); - } - else{ - return errorResponse(CustomMessage.UNAUTHORIZED); - } - - } -*/ - /** * 로그아웃 기능 세션무효화, jsession쿠키를 제거, */ - @PostMapping("/user/logout") - public ResponseEntity logout(HttpServletResponse response){ + @PostMapping ("/user/logout") + public ResponseEntity logout(HttpServletRequest request){ + if(authorized(request)) { + + SecurityContextHolder.clearContext(); + request.getSession().invalidate(); - SecurityContextHolder.clearContext(); // 현재 SecurityContext를 제거합니다. - httpSession.invalidate(); // HttpSession을 무효화합니다. + return new ResponseEntity<>(HttpStatus.OK); + + } - Cookie myCookie = new Cookie("JSESSIONID", null); - myCookie.setMaxAge(0); // 쿠키의 expiration 타임을 0으로 하여 없앤다. - myCookie.setPath("/"); // 모든 경로에서 삭제 됬음을 알린다. - response.addCookie(myCookie); - return successResponse(CustomMessage.OK,myCookie); + return errorResponse(CustomMessage.UNAUTHORIZED); } diff --git a/src/main/java/Remoa/BE/Member/Controller/ProfileController.java b/src/main/java/Remoa/BE/Member/Controller/ProfileController.java index c8bebb4..492d16b 100644 --- a/src/main/java/Remoa/BE/Member/Controller/ProfileController.java +++ b/src/main/java/Remoa/BE/Member/Controller/ProfileController.java @@ -1,74 +1,148 @@ package Remoa.BE.Member.Controller; +import Remoa.BE.Member.Domain.AwsS3; import Remoa.BE.Member.Domain.Member; import Remoa.BE.Member.Dto.Req.EditProfileForm; +import Remoa.BE.Member.Dto.Res.ResUserInfoDto; +//import Remoa.BE.Member.Service.ImageService; +import Remoa.BE.Member.Service.AwsS3Service; import Remoa.BE.Member.Service.MemberService; import Remoa.BE.Member.Service.ProfileService; import Remoa.BE.exception.CustomMessage; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpSession; + + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.multipart.MultipartFile; + +import java.io.IOException; +import java.net.MalformedURLException; + import static Remoa.BE.exception.CustomBody.*; +import static Remoa.BE.utill.MemberInfo.authorized; +import static Remoa.BE.utill.MemberInfo.getMemberId; @Slf4j @RestController @RequiredArgsConstructor -@CrossOrigin(origins = "*") public class ProfileController { private final ProfileService profileService; - private final MemberService memberService; + private final AwsS3Service awsS3Service; // 프로필 수정 범위 : 닉네임(중복확인), 핸드폰번호, 대학교, 한줄소개 @GetMapping("/user") - public ResponseEntity userHome(HttpServletRequest request) { - - HttpSession session = request.getSession(); - // 현재 로그인한 사용자의 세션 가져오기 - Member loginMember = (Member) session.getAttribute("loginMember"); - - // 세션이 없으면 로그인 페이지로 이동 - if (loginMember == null) { - return failResponse(CustomMessage.VALIDATED, "redirect:/login/kakao"); + public ResponseEntity userInfo(HttpServletRequest request) { + + if(authorized(request)) { + Long memberId = getMemberId(); + // 로그인된 사용자의 정보를 db에서 다시 불러와 띄워줌. + Member member = memberService.findOne(memberId); + ResUserInfoDto resUserInfoDto = ResUserInfoDto.builder() + .email(member.getEmail()) + .nickname(member.getNickname()) + .phoneNumber(member.getPhoneNumber()) + .university(member.getUniversity()) + .oneLineIntroduction(member.getOneLineIntroduction()) + .build(); + return successResponse(CustomMessage.OK, resUserInfoDto); } - // 로그인된 사용자의 정보를 db에서 다시 불러와 띄워줌. - Member member = memberService.findOne(loginMember.getMemberId()); - return successResponse(CustomMessage.OK, member); + return errorResponse(CustomMessage.UNAUTHORIZED); + } - // RESTful API에서 PUT 매핑은 수정할 리소스를 명확하게 지정해야 하는데 이 경우에는 URL에 리소스 ID를 명시하는 것이 일반적이다. - // 그런데 우리는 수정할 사용자의 정보를 모두 입력받아 수정하는 형태이기 때문에 - // URL에 리소스 ID를 명시할 필요가 없어서 PUT대신 POST 매핑을 사용하였습니다. - @PostMapping("/user") + @PutMapping("/user") public ResponseEntity editProfile(@RequestBody EditProfileForm form, HttpServletRequest request) { - HttpSession session = request.getSession(); - Member loginMember = (Member) session.getAttribute("loginMember"); - if (loginMember == null) { - // 로그인되어 있지 않은 경우 로그인 페이지로 이동 - return failResponse(CustomMessage.VALIDATED, "로그인하지 않은 회원입니다. 로 redirect"); + if(authorized(request)){ + Long memberId = getMemberId(); + + Member myMember = memberService.findOne(memberId); + log.info(myMember.getNickname()); + if(memberService.isNicknameDuplicate(myMember.getNickname())) { + + // 사용자의 입력 정보를 DTO에 담아 서비스로 전달 + profileService.editProfile(memberId, form); + ResUserInfoDto resUserInfoDto = ResUserInfoDto.builder() + .email(myMember.getEmail()) + .nickname(myMember.getNickname()) + .phoneNumber(myMember.getPhoneNumber()) + .university(myMember.getUniversity()) + .oneLineIntroduction(myMember.getOneLineIntroduction()) + .build(); + + return successResponse(CustomMessage.OK, resUserInfoDto); + } + + return errorResponse(CustomMessage.BAD_DUPLICATE); + } - if (memberService.isNicknameDuplicate(form.getNickname())) { - return failResponse(CustomMessage.VALIDATED, "닉네임이 중복됩니다."); + // 수정이 완료되면 프로필 페이지로 이동 + return errorResponse(CustomMessage.UNAUTHORIZED); + } + + + // 프로필 사진 불러오기 + @GetMapping("/user/img") + public ResponseEntity showImage(HttpServletRequest request) { + if(authorized(request)) { + Long memberId = getMemberId(); + Member myMember = memberService.findOne(memberId); + return successResponse(CustomMessage.OK, myMember.getProfileImage()); } + return errorResponse(CustomMessage.UNAUTHORIZED); + } - // 사용자의 입력 정보를 DTO에 담아 서비스로 전달 - EditProfileForm profileInfo = new EditProfileForm( - form.getNickname(), form.getPhoneNumber(), form.getUniversity(), form.getOneLineIntroduction()); - profileService.editProfile(loginMember.getMemberId(), profileInfo); + // 프로필 사진 업로드 + @PutMapping("/user/img") + public ResponseEntity upload(@RequestPart("file") MultipartFile multipartFile, HttpServletRequest request) throws IOException { - // 수정이 완료되면 프로필 페이지로 이동 - return successResponse(CustomMessage.OK, "redirect:/user"); + if(authorized(request)) { + + Long memberId = getMemberId(); + Member myMember = memberService.findOne(memberId);; + + String editProfileImg = awsS3Service.editProfileImg(myMember.getProfileImage(), multipartFile); + myMember.setProfileImage(editProfileImg); + memberService.join(myMember); + return new ResponseEntity<>(HttpStatus.OK); + } + return errorResponse(CustomMessage.UNAUTHORIZED); + } + + // 프로필 사진 삭제 + @DeleteMapping("/user/img") + public ResponseEntity remove(HttpServletRequest request) throws MalformedURLException { + if(authorized(request)) { + + Long memberId = getMemberId(); + Member myMember = memberService.findOne(memberId); + if(myMember.getProfileImage() == null){ + return errorResponse(CustomMessage.BAD_PROFILE_IMG); + } + + awsS3Service.removeProfileUrl(myMember.getProfileImage()); + myMember.setProfileImage(null); + memberService.join(myMember); + return new ResponseEntity<>(HttpStatus.OK); + } + return errorResponse(CustomMessage.UNAUTHORIZED); } + + + /** * 프론트에서 닉네임 중복 검사를 할 때 사용할 메서드 * @param nickname diff --git a/src/main/java/Remoa/BE/Member/Controller/WithdrewController.java b/src/main/java/Remoa/BE/Member/Controller/WithdrewController.java index e6922b7..65bf374 100644 --- a/src/main/java/Remoa/BE/Member/Controller/WithdrewController.java +++ b/src/main/java/Remoa/BE/Member/Controller/WithdrewController.java @@ -15,7 +15,6 @@ @RestController @Slf4j @RequiredArgsConstructor -@CrossOrigin(origins = "*") public class WithdrewController { private final WithdrewService withdrewService; diff --git a/src/main/java/Remoa/BE/Member/Domain/AwsS3.java b/src/main/java/Remoa/BE/Member/Domain/AwsS3.java new file mode 100644 index 0000000..64b5fa8 --- /dev/null +++ b/src/main/java/Remoa/BE/Member/Domain/AwsS3.java @@ -0,0 +1,22 @@ +package Remoa.BE.Member.Domain; + +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class AwsS3 { + private String key; + private String path; + + public AwsS3() { + + } + + @Builder + public AwsS3(String key, String path) { + this.key = key; + this.path = path; + } +} \ No newline at end of file diff --git a/src/main/java/Remoa/BE/Member/Domain/Comment.java b/src/main/java/Remoa/BE/Member/Domain/Comment.java index d9a1e07..8b299a0 100644 --- a/src/main/java/Remoa/BE/Member/Domain/Comment.java +++ b/src/main/java/Remoa/BE/Member/Domain/Comment.java @@ -3,11 +3,12 @@ import Remoa.BE.Post.Domain.Post; import lombok.Getter; import lombok.Setter; -import org.hibernate.annotations.SQLDelete; import org.hibernate.annotations.Where; import javax.persistence.*; +import java.time.LocalDateTime; + import static javax.persistence.FetchType.LAZY; @Entity @@ -17,7 +18,7 @@ public class Comment { @Id - @GeneratedValue + @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "comment_id") private Long commentId; @@ -38,13 +39,21 @@ public class Comment { /** * Comment의 내용 */ + @Lob private String comment; + /** + * 대댓글 기능을 위해 부모 댓글과의 연관관계 세팅. 부모댓글인 경우 null. + */ + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "parent_comment_id") + private Comment parentComment = null; + /** * Comment가 작성된 시간 */ @Column(name = "commented_time") - private String commentedTime; + private LocalDateTime commentedTime; /** * Comment의 좋아요 숫자 diff --git a/src/main/java/Remoa/BE/Member/Domain/CommentBookmark.java b/src/main/java/Remoa/BE/Member/Domain/CommentBookmark.java index b90ffc6..b888e13 100644 --- a/src/main/java/Remoa/BE/Member/Domain/CommentBookmark.java +++ b/src/main/java/Remoa/BE/Member/Domain/CommentBookmark.java @@ -14,6 +14,7 @@ @Setter @Entity @NoArgsConstructor(access = AccessLevel.PROTECTED) +@Deprecated public class CommentBookmark { @Id diff --git a/src/main/java/Remoa/BE/Member/Domain/Feedback.java b/src/main/java/Remoa/BE/Member/Domain/Feedback.java index 1bcb965..1d80641 100644 --- a/src/main/java/Remoa/BE/Member/Domain/Feedback.java +++ b/src/main/java/Remoa/BE/Member/Domain/Feedback.java @@ -7,6 +7,8 @@ import javax.persistence.*; +import java.time.LocalDateTime; + import static javax.persistence.FetchType.LAZY; @Entity @@ -16,7 +18,7 @@ public class Feedback { @Id - @GeneratedValue + @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "feedback_id") private Long feedbackId; @@ -40,13 +42,22 @@ public class Feedback { /** * Feedback의 내용 */ + @Lob private String feedback; + /** + * 대댓글 기능을 위해 부모 댓글과의 연관관계 세팅. 부모댓글인 경우 null. + */ + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "parent_feedback_id") + private Feedback parentFeedback = null; + + /** * Feedback이 작성된 시간 */ @Column(name = "feedback_time") - private String feedbackTime; + private LocalDateTime feedbackTime; /** * Feedback의 좋아요 숫자 diff --git a/src/main/java/Remoa/BE/Member/Domain/FeedbackBookmark.java b/src/main/java/Remoa/BE/Member/Domain/FeedbackBookmark.java index be94dfb..cfe1fbe 100644 --- a/src/main/java/Remoa/BE/Member/Domain/FeedbackBookmark.java +++ b/src/main/java/Remoa/BE/Member/Domain/FeedbackBookmark.java @@ -14,6 +14,7 @@ @Setter @Entity @NoArgsConstructor(access = AccessLevel.PROTECTED) +@Deprecated public class FeedbackBookmark { @Id diff --git a/src/main/java/Remoa/BE/Member/Domain/Follow.java b/src/main/java/Remoa/BE/Member/Domain/Follow.java index f84b161..dc6dbd3 100644 --- a/src/main/java/Remoa/BE/Member/Domain/Follow.java +++ b/src/main/java/Remoa/BE/Member/Domain/Follow.java @@ -2,7 +2,6 @@ import lombok.Getter; import lombok.Setter; -import org.hibernate.annotations.SQLDelete; import org.hibernate.annotations.Where; import javax.persistence.*; diff --git a/src/main/java/Remoa/BE/Member/Domain/Member.java b/src/main/java/Remoa/BE/Member/Domain/Member.java index 2d71b83..a58af9f 100644 --- a/src/main/java/Remoa/BE/Member/Domain/Member.java +++ b/src/main/java/Remoa/BE/Member/Domain/Member.java @@ -1,10 +1,8 @@ package Remoa.BE.Member.Domain; import Remoa.BE.Post.Domain.Post; -import com.fasterxml.jackson.annotation.JsonIgnore; import lombok.Getter; import lombok.Setter; -import org.hibernate.annotations.SQLDelete; import org.hibernate.annotations.Where; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; @@ -67,6 +65,7 @@ public class Member implements UserDetails { * 한 줄 소개 */ @Column(name = "one_line_introduction") + @Lob private String oneLineIntroduction; /** @@ -81,25 +80,25 @@ public class Member implements UserDetails { @Column(name = "profile_image") private String profileImage; - @OneToMany(mappedBy = "member") + @OneToMany(mappedBy = "member",fetch = FetchType.LAZY) private List posts = new ArrayList<>(); - @OneToMany(mappedBy = "member") + @OneToMany(mappedBy = "member",fetch = FetchType.LAZY) private List comments = new ArrayList<>(); - @OneToMany(mappedBy = "member") + @OneToMany(mappedBy = "member",fetch = FetchType.LAZY) private List feedbacks = new ArrayList<>(); - @OneToMany(mappedBy = "member", cascade = {CascadeType.ALL}) + @OneToMany(mappedBy = "member", cascade = {CascadeType.ALL},fetch = FetchType.LAZY) private List memberCategories = new ArrayList<>(); - @OneToMany(mappedBy = "member", cascade = {CascadeType.ALL}) + @OneToMany(mappedBy = "member", cascade = {CascadeType.ALL},fetch = FetchType.LAZY) private List commentBookmarks = new ArrayList<>(); - @OneToMany(mappedBy = "member", cascade = {CascadeType.ALL}) + @OneToMany(mappedBy = "member", cascade = {CascadeType.ALL},fetch = FetchType.LAZY) private List commentLikes = new ArrayList<>(); - @OneToMany(mappedBy = "fromMember", cascade = {CascadeType.ALL}) + @OneToMany(mappedBy = "fromMember", cascade = {CascadeType.ALL},fetch = FetchType.LAZY) private List follows = new ArrayList<>(); /** diff --git a/src/main/java/Remoa/BE/Member/Dto/Res/ResMemberInfoDto.java b/src/main/java/Remoa/BE/Member/Dto/Res/ResMemberInfoDto.java new file mode 100644 index 0000000..8048aa3 --- /dev/null +++ b/src/main/java/Remoa/BE/Member/Dto/Res/ResMemberInfoDto.java @@ -0,0 +1,13 @@ +package Remoa.BE.Member.Dto.Res; + +import lombok.*; + +@Getter +@AllArgsConstructor +@NoArgsConstructor +public class ResMemberInfoDto { + + private Long memberId; + private String nickname; + private String profileImage; +} diff --git a/src/main/java/Remoa/BE/Member/Dto/Res/ResSignupDto.java b/src/main/java/Remoa/BE/Member/Dto/Res/ResSignupDto.java index b4b390c..4a20807 100644 --- a/src/main/java/Remoa/BE/Member/Dto/Res/ResSignupDto.java +++ b/src/main/java/Remoa/BE/Member/Dto/Res/ResSignupDto.java @@ -3,8 +3,6 @@ import lombok.Builder; import lombok.Getter; -import javax.validation.constraints.NotBlank; - @Builder @Getter public class ResSignupDto { diff --git a/src/main/java/Remoa/BE/Member/Dto/Res/ResUserInfoDto.java b/src/main/java/Remoa/BE/Member/Dto/Res/ResUserInfoDto.java new file mode 100644 index 0000000..58f37df --- /dev/null +++ b/src/main/java/Remoa/BE/Member/Dto/Res/ResUserInfoDto.java @@ -0,0 +1,19 @@ +package Remoa.BE.Member.Dto.Res; + +import lombok.Builder; +import lombok.Getter; + +@Getter +@Builder +public class ResUserInfoDto { + + private String email; + + private String nickname; + private String phoneNumber; + + private String university; + + private String oneLineIntroduction; + +} diff --git a/src/main/java/Remoa/BE/Member/Repository/MemberRepository.java b/src/main/java/Remoa/BE/Member/Repository/MemberRepository.java index 3f07bcd..d6a8dfd 100644 --- a/src/main/java/Remoa/BE/Member/Repository/MemberRepository.java +++ b/src/main/java/Remoa/BE/Member/Repository/MemberRepository.java @@ -4,16 +4,11 @@ import Remoa.BE.Member.Domain.Member; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.data.jpa.repository.Modifying; -import org.springframework.data.jpa.repository.Query; -import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; import javax.persistence.EntityManager; -import javax.persistence.EntityNotFoundException; import java.util.List; import java.util.Optional; -import java.util.stream.Collectors; @Repository @Slf4j diff --git a/src/main/java/Remoa/BE/Member/Service/AwsS3Service.java b/src/main/java/Remoa/BE/Member/Service/AwsS3Service.java new file mode 100644 index 0000000..197961b --- /dev/null +++ b/src/main/java/Remoa/BE/Member/Service/AwsS3Service.java @@ -0,0 +1,74 @@ +package Remoa.BE.Member.Service; + +import Remoa.BE.Member.Domain.AwsS3; +import com.amazonaws.services.s3.AmazonS3; +import com.amazonaws.services.s3.model.AmazonS3Exception; +import com.amazonaws.services.s3.model.CannedAccessControlList; +import com.amazonaws.services.s3.model.ObjectMetadata; +import com.amazonaws.services.s3.model.PutObjectRequest; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Optional; +import java.util.UUID; + +@Service +@RequiredArgsConstructor +@Slf4j +public class AwsS3Service { + + private final AmazonS3 amazonS3; + + @Value("${cloud.aws.s3.bucket}") + private String bucket; + + public String editProfileImg(String profileImgUrl,MultipartFile multipartFile) throws IOException { + + if(profileImgUrl != null) { + //기존 프로필 사진 s3에서 삭제 + removeProfileUrl(profileImgUrl); + } + + //파일 타입과 사이즈 저장 + ObjectMetadata objectMetadata = new ObjectMetadata(); + objectMetadata.setContentType("image/jpeg"); + log.info(multipartFile.getContentType()); + objectMetadata.setContentLength(multipartFile.getSize()); + + //파일 이름 + String originalFilename = multipartFile.getOriginalFilename(); + + //파일 이름이 겹치지 않게 + String uuid = UUID.randomUUID().toString(); + + //post 폴더에 따로 넣어서 보관 + String s3name = "img/"+uuid+"_"+originalFilename; + + try (InputStream inputStream = multipartFile.getInputStream()) { + amazonS3.putObject(new PutObjectRequest(bucket, s3name, inputStream, objectMetadata) + .withCannedAcl(CannedAccessControlList.PublicRead)); + } catch (IOException e) { + //파일을 제대로 받아오지 못했을때 + //Todo 예외처리 custom 따로 만들기 + throw new RuntimeException(e); + } + + return amazonS3.getUrl(bucket,s3name).toString().replaceAll("\\+", "+"); + + } + + public void removeProfileUrl(String profileImgUrl) throws MalformedURLException { + URL fileUrl = new URL(profileImgUrl); + String objectKey = fileUrl.getPath().replaceAll("^/", ""); + amazonS3.deleteObject(bucket,objectKey); + } +} \ No newline at end of file diff --git a/src/main/java/Remoa/BE/Member/Service/FollowService.java b/src/main/java/Remoa/BE/Member/Service/FollowService.java index a90ae23..93624af 100644 --- a/src/main/java/Remoa/BE/Member/Service/FollowService.java +++ b/src/main/java/Remoa/BE/Member/Service/FollowService.java @@ -9,7 +9,6 @@ import org.springframework.transaction.annotation.Transactional; import java.util.List; -import java.util.Optional; @Service @Slf4j diff --git a/src/main/java/Remoa/BE/Member/Service/KakaoService.java b/src/main/java/Remoa/BE/Member/Service/KakaoService.java index 79a2ed0..389734c 100644 --- a/src/main/java/Remoa/BE/Member/Service/KakaoService.java +++ b/src/main/java/Remoa/BE/Member/Service/KakaoService.java @@ -1,19 +1,19 @@ package Remoa.BE.Member.Service; -import Remoa.BE.Member.Domain.Member; import Remoa.BE.Member.Repository.MemberRepository; +import com.amazonaws.services.s3.AmazonS3; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.json.simple.JSONObject; import org.json.simple.parser.JSONParser; import org.json.simple.parser.ParseException; +import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import java.io.*; import java.net.HttpURLConnection; -import java.net.MalformedURLException; -import java.net.ProtocolException; import java.net.URL; +import java.nio.charset.StandardCharsets; import java.util.HashMap; import java.util.Map; @@ -24,7 +24,6 @@ public class KakaoService { //카카오 로그인시 접속해야 할 링크 : https://kauth.kakao.com/oauth/authorize?client_id=139febf9e13da4d124d1c1faafcf3f86&redirect_uri=http://localhost:8080/login/kakao&response_type=code - private final MemberRepository MemberRepository; /** * 카카오 인증 서버에 code를 보내고 token을 발급받는 메서드 @@ -104,7 +103,8 @@ public String getToken(String code) throws IOException { * @return 카카오 사용자 정보((kakao)id, nickname, email, profileImage) * @throws IOException */ - public Map getUserInfo(String access_token) throws IOException { + public Map getUserInfo(String access_token) { + //사용자 정보를 받아올 카카오 api 서버. 레모아 서버가 클리아언트로, 카카오 api 서버가 서버로 동작한다고 보면 됩니다. String host = "https://kapi.kakao.com/v2/user/me"; //사용자 정보를 받을 Map 객체 생성 @@ -121,7 +121,7 @@ public Map getUserInfo(String access_token) throws IOException { int responseCode = urlConnection.getResponseCode(); log.debug("responseCode = {}", responseCode); - BufferedReader br = new BufferedReader(new InputStreamReader(urlConnection.getInputStream())); + BufferedReader br = new BufferedReader(new InputStreamReader(urlConnection.getInputStream(), StandardCharsets.UTF_8)); String line = ""; String res = ""; //다양한 형식(한 줄 이상의 JSON 데이터)를 받기 위한 작업 @@ -157,6 +157,9 @@ public Map getUserInfo(String access_token) throws IOException { return result; } + + + /** * 사용자의 카카오 api 동의 내역을 확인하는 메서드. * kakao developers 공식문서 <- 참고 @@ -186,28 +189,10 @@ public String getAgreementInfo(String access_token) // result는 json 포멧. br.close(); - } catch (MalformedURLException e) { - e.printStackTrace(); - } catch (ProtocolException e) { - e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return result; } - /** - * kakaoId가 db에 있는지 확인해주는 메서드 - * @param kakaoId - * @return db에 존재 -> Member, 없으면 -> null - */ - public Member distinguishKakaoId(Long kakaoId) { - - if (!MemberRepository.findByKakaoId(kakaoId).isPresent()) { - return null; - } - Member kakaoMember = MemberRepository.findByKakaoId(kakaoId).get(); - - return kakaoMember; - } -} +} \ No newline at end of file diff --git a/src/main/java/Remoa/BE/Member/Service/MemberService.java b/src/main/java/Remoa/BE/Member/Service/MemberService.java index d007af6..f629ee1 100644 --- a/src/main/java/Remoa/BE/Member/Service/MemberService.java +++ b/src/main/java/Remoa/BE/Member/Service/MemberService.java @@ -38,13 +38,10 @@ private void validateDuplicateMember(Member member) { } } + public Boolean isNicknameDuplicate(String nickname) { List findMembers = memberRepository.findByNickname(nickname); - if (findMembers.isEmpty()) { - return false; - } else { - return true; - } + return !(findMembers.size()==0); } diff --git a/src/main/java/Remoa/BE/Member/Service/ProfileService.java b/src/main/java/Remoa/BE/Member/Service/ProfileService.java index 5755031..788a010 100644 --- a/src/main/java/Remoa/BE/Member/Service/ProfileService.java +++ b/src/main/java/Remoa/BE/Member/Service/ProfileService.java @@ -1,14 +1,29 @@ package Remoa.BE.Member.Service; import Remoa.BE.Member.Dto.Req.EditProfileForm; -import Remoa.BE.Member.Repository.MemberRepository; +import com.amazonaws.services.s3.AmazonS3; + +import com.amazonaws.services.s3.model.ObjectMetadata; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import Remoa.BE.Member.Domain.Member; +import org.springframework.util.FileCopyUtils; + +import javax.imageio.ImageIO; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.util.UUID; @Service @@ -18,7 +33,9 @@ public class ProfileService { private final MemberService memberService; - + @Value("${cloud.aws.s3.bucket}") + private String bucket; + private final AmazonS3 amazonS3; @Transactional public void editProfile(Long memberId, EditProfileForm profile) { @@ -34,4 +51,30 @@ public void editProfile(Long memberId, EditProfileForm profile) { member.setUniversity(profile.getUniversity()); member.setOneLineIntroduction(profile.getOneLineIntroduction()); } + + public String editProfileImg(String nickname,String profileImageUrl) throws IOException { + // 프로필사진을 jpg로 변환하기 + URL profileURL = new URL(profileImageUrl); + InputStream is = profileURL.openStream(); + + // 이미지 파일 생성 + BufferedImage image = ImageIO.read(is); + File outputFile = new File(nickname+".jpg"); + ImageIO.write(image, "jpg", outputFile); + + // 사진으로 바꾼뒤 바로 S3로 업로드하기 + String url = uploadProfileImg(outputFile); + outputFile.delete(); + return url; + } + + // 프로필 사진 초기설정 - S3에 저장하기 + public String uploadProfileImg(File file){ + String s3FileName = UUID.randomUUID() + "-" + file.getName(); + ObjectMetadata objMeta = new ObjectMetadata(); + objMeta.setContentLength(file.length()); + amazonS3.putObject(bucket, "img/"+s3FileName,file); + return amazonS3.getUrl(bucket,"img/"+s3FileName).toString().replaceAll("\\+", "+"); + + } } \ No newline at end of file diff --git a/src/main/java/Remoa/BE/Post/Controller/CommentController.java b/src/main/java/Remoa/BE/Post/Controller/CommentController.java new file mode 100644 index 0000000..21f7d9d --- /dev/null +++ b/src/main/java/Remoa/BE/Post/Controller/CommentController.java @@ -0,0 +1,73 @@ +package Remoa.BE.Post.Controller; + +import Remoa.BE.Member.Domain.Member; +import Remoa.BE.Member.Service.MemberService; +import Remoa.BE.Post.Service.CommentService; +import Remoa.BE.exception.CustomMessage; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletRequest; +import java.util.Map; + +import static Remoa.BE.exception.CustomBody.errorResponse; +import static Remoa.BE.exception.CustomBody.successResponse; +import static Remoa.BE.utill.MemberInfo.authorized; +import static Remoa.BE.utill.MemberInfo.getMemberId; + +@Slf4j +@RestController +@RequiredArgsConstructor +public class CommentController { + + private final MemberService memberService; + + private final CommentService commentService; + + @PostMapping("/reference/{reference_id}/comment") + public ResponseEntity registerComment(@RequestBody Map comment, @PathVariable("reference_id") Long postId, HttpServletRequest request){ + String myComment = comment.get("comment"); + if(authorized(request)){ + Long memberId = getMemberId(); + Member myMember = memberService.findOne(memberId); + commentService.registerComment(myMember, myComment, postId, null); + return new ResponseEntity<>(HttpStatus.OK); + } + return errorResponse(CustomMessage.UNAUTHORIZED); + } + + @PostMapping("/reference/{reference_id}/comment/{comment_id}") + public ResponseEntity registerCommentReply(@RequestBody Map comment, @PathVariable("reference_id") Long postId, @PathVariable("comment_id") Long commentId, HttpServletRequest request){ + String myComment = comment.get("comment"); + if(authorized(request)){ + Long memberId = getMemberId(); + Member myMember = memberService.findOne(memberId); + commentService.registerComment(myMember, myComment, postId, commentId); + return new ResponseEntity<>(HttpStatus.OK); + } + return errorResponse(CustomMessage.UNAUTHORIZED); + } + @PutMapping("/reference/comment/{comment_id}") + public ResponseEntity modifyComment(@RequestBody Map comment, @PathVariable("comment_id") Long commentId, HttpServletRequest request){ + String myComment = comment.get("comment"); + + if(authorized(request)){ + commentService.modifyComment(myComment, commentId); + return new ResponseEntity<>(HttpStatus.OK); + } + return errorResponse(CustomMessage.UNAUTHORIZED); + } + + @DeleteMapping("/comment/{comment_id}") + public ResponseEntity deleteComment(@PathVariable("comment_id") Long commentId, HttpServletRequest request){ + if(authorized(request)){ + + commentService.deleteComment(commentId); + return new ResponseEntity<>(HttpStatus.OK); + } + return errorResponse(CustomMessage.UNAUTHORIZED); + } +} \ No newline at end of file diff --git a/src/main/java/Remoa/BE/Post/Controller/FeedbackController.java b/src/main/java/Remoa/BE/Post/Controller/FeedbackController.java new file mode 100644 index 0000000..06c0ecc --- /dev/null +++ b/src/main/java/Remoa/BE/Post/Controller/FeedbackController.java @@ -0,0 +1,60 @@ +package Remoa.BE.Post.Controller; + +import Remoa.BE.Member.Domain.Member; +import Remoa.BE.Member.Service.MemberService; +import Remoa.BE.Post.Service.FeedbackService; +import Remoa.BE.exception.CustomMessage; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +import javax.servlet.http.HttpServletRequest; +import java.util.Map; + +import static Remoa.BE.exception.CustomBody.errorResponse; +import static Remoa.BE.utill.MemberInfo.authorized; +import static Remoa.BE.utill.MemberInfo.getMemberId; + +@Slf4j +@RestController +@RequiredArgsConstructor +public class FeedbackController { + + private final FeedbackService feedbackService; + private final MemberService memberService; + + @PostMapping("/reference/{reference_id}/{page_number}") // 레퍼런스에 피드백 등록 + public ResponseEntity registerFeedback(@RequestBody Map feedback, + @PathVariable("reference_id") Long postId, + @PathVariable("page_number") Integer pageNumber, + HttpServletRequest request){ + String myFeedback = feedback.get("feedback"); + if(authorized(request)){ + Long memberId = getMemberId(); + Member myMember = memberService.findOne(memberId); + feedbackService.registerFeedback(myMember, myFeedback, postId, pageNumber, null); + return new ResponseEntity<>(HttpStatus.OK); + } + return errorResponse(CustomMessage.UNAUTHORIZED); + } + + @PostMapping("/reference/{reference_id}/feedback/{feedback_id}") // 레퍼런스에 피드백 등록 + public ResponseEntity registerFeedbackReply(@RequestBody Map feedback, + @PathVariable("reference_id") Long postId, + @PathVariable("feedback_id") Long feedbackId, + HttpServletRequest request){ + String myFeedback = feedback.get("feedback"); + if(authorized(request)){ + Long memberId = getMemberId(); + Member myMember = memberService.findOne(memberId); + feedbackService.registerFeedback(myMember, myFeedback, postId, null, feedbackId); + return new ResponseEntity<>(HttpStatus.OK); + } + return errorResponse(CustomMessage.UNAUTHORIZED); + } +} \ No newline at end of file diff --git a/src/main/java/Remoa/BE/Post/Controller/MyFeedbackController.java b/src/main/java/Remoa/BE/Post/Controller/MyFeedbackController.java new file mode 100644 index 0000000..2a0ab81 --- /dev/null +++ b/src/main/java/Remoa/BE/Post/Controller/MyFeedbackController.java @@ -0,0 +1,25 @@ +package Remoa.BE.Post.Controller; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import javax.servlet.http.HttpServletRequest; + +@RestController +@RequiredArgsConstructor +@Slf4j +public class MyFeedbackController { + + @GetMapping("/user/feedback") + public ResponseEntity receivedFeedback(HttpServletRequest request, + @RequestParam(required = false, defaultValue = "all") String category) { + + + return null; + } + +} diff --git a/src/main/java/Remoa/BE/Post/Controller/MyPostController.java b/src/main/java/Remoa/BE/Post/Controller/MyPostController.java new file mode 100644 index 0000000..6791fa9 --- /dev/null +++ b/src/main/java/Remoa/BE/Post/Controller/MyPostController.java @@ -0,0 +1,153 @@ +package Remoa.BE.Post.Controller; + +import Remoa.BE.Member.Domain.Member; +import Remoa.BE.Member.Dto.Res.ResMemberInfoDto; +import Remoa.BE.Member.Service.MemberService; +import Remoa.BE.Post.Domain.Post; +import Remoa.BE.Post.Dto.Response.ResPostDto; +import Remoa.BE.Post.Service.CommentService; +import Remoa.BE.Post.Service.MyPostService; +import Remoa.BE.exception.CustomMessage; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.modelmapper.ModelMapper; +import org.springframework.data.domain.Page; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import javax.servlet.http.HttpServletRequest; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static Remoa.BE.exception.CustomBody.errorResponse; +import static Remoa.BE.exception.CustomBody.successResponse; +import static Remoa.BE.utill.MemberInfo.authorized; +import static Remoa.BE.utill.MemberInfo.getMemberId; + +@Slf4j +@RestController +@RequiredArgsConstructor +public class MyPostController { + + private final MemberService memberService; + private final CommentService commentService; + private final MyPostService myPostService; + + // Entity <-> DTO 간의 변환을 편리하게 하고자 ModelMapper 사용.(build.gradle에 의존성 주입 완료) +// private final ModelMapper modelMapper = new ModelMapper(); + + + /** + * 내 작업물 목록 페이지 + */ + @GetMapping("/user/reference") + public ResponseEntity myReference(HttpServletRequest request, + @RequestParam(required = false, defaultValue = "all") String category, + @RequestParam(required = false, defaultValue = "1", name = "page") int pageNumber, + @RequestParam(required = false, defaultValue = "newest") String sort) { + if (authorized(request)) { + Long memberId = getMemberId(); + Member myMember = memberService.findOne(memberId); + + pageNumber -= 1; + if (pageNumber < 0) { + return errorResponse(CustomMessage.PAGE_NUM_OVER); + } + + Page posts; + + if (category.equals("idea") || + category.equals("marketing") || + category.equals("design") || + category.equals("video") || + category.equals("etc")) { + posts = sortAndPaginatePostsByCategoryAndMember(category, pageNumber, sort, myMember); + } else { + posts = sortAndPaginatePostsByMember(pageNumber, sort, myMember); + } + + //조회할 레퍼런스가 db에 있으나, 현재 페이지에 조회할 데이터가 없는 경우 == 페이지 번호를 잘못 입력 + if ((posts.getContent().isEmpty()) && (posts.getTotalElements() > 0)) { + return errorResponse(CustomMessage.PAGE_NUM_OVER); + } + + List result = new ArrayList<>(); + + for (Post post : posts) { + ResPostDto map = ResPostDto.builder() + .postingTime(post.getPostingTime().toString()) + .postMember(new ResMemberInfoDto(post.getMember().getMemberId(), + post.getMember().getNickname(), + post.getMember().getProfileImage())) + .postId(post.getPostId()) + .views(post.getViews()) + .categoryName(post.getCategory().getName()) + .likeCount(post.getLikeCount()) + .thumbnail(post.getThumbnail().getStoreFileUrl()) + .scrapCount(post.getScrapCount()) + .title(post.getTitle()).build(); + result.add(map); + } + //프론트에서 쓰일 조회한 레퍼런스들과 페이지 관련한 값들 map에 담아서 return. + Map referencesAndPageInfo = new HashMap<>(); + referencesAndPageInfo.put("references", result); //조회한 레퍼런스들 + referencesAndPageInfo.put("totalPages", posts.getTotalPages()); //전체 페이지의 수 + referencesAndPageInfo.put("totalOfAllReferences", posts.getTotalElements()); //모든 레퍼런스의 수 + referencesAndPageInfo.put("totalOfPageElements", posts.getNumberOfElements()); //현 페이지의 레퍼런스 수 + + return successResponse(CustomMessage.OK, referencesAndPageInfo); + } + return errorResponse(CustomMessage.UNAUTHORIZED); + } + + private Page sortAndPaginatePostsByMember(int pageNumber, String sort, Member myMember) { + Page posts; + //switch문을 통해 각 옵션에 맞게 sorting + switch (sort) { + case "newest": + posts = myPostService.getNewestPosts(pageNumber, myMember); + break; + case "oldest": + posts = myPostService.getOldestPosts(pageNumber, myMember); + break; + case "like": + posts = myPostService.getMostLikedPosts(pageNumber, myMember); + break; + case "scrap": + posts = myPostService.getMostScrapedPosts(pageNumber, myMember); + break; + default: + //sort 문자열이 잘못됐을 경우 default인 최신순으로 정렬 + posts = myPostService.getNewestPosts(pageNumber, myMember); + break; + } + return posts; + } + + private Page sortAndPaginatePostsByCategoryAndMember(String category, int pageNumber, String sort, Member myMember) { + Page posts; + switch (sort) { + case "newest": + posts = myPostService.getNewestPostsSortCategory(pageNumber, myMember, category); + break; + case "oldest": + posts = myPostService.getOldestPostsSortCategory(pageNumber, myMember, category); + break; + case "like": + posts = myPostService.getMostLikedPostsSortCategory(pageNumber, myMember, category); + break; + case "scrap": + posts = myPostService.getMostScrapedPostsSortCategory(pageNumber, myMember, category); + break; + default: + //sort 문자열이 잘못됐을 경우 default인 최신순으로 정렬 + posts = myPostService.getNewestPostsSortCategory(pageNumber, myMember, category); + break; + } + return posts; + } +} diff --git a/src/main/java/Remoa/BE/Post/Controller/PostController.java b/src/main/java/Remoa/BE/Post/Controller/PostController.java index 8d81335..95def09 100644 --- a/src/main/java/Remoa/BE/Post/Controller/PostController.java +++ b/src/main/java/Remoa/BE/Post/Controller/PostController.java @@ -1,23 +1,27 @@ package Remoa.BE.Post.Controller; -import Remoa.BE.Member.Domain.Member; -import Remoa.BE.Member.Service.MemberService; +import Remoa.BE.Member.Dto.Res.ResMemberInfoDto; import Remoa.BE.Post.Domain.Post; -import Remoa.BE.Post.Service.FileService; +import Remoa.BE.Post.Domain.UploadFile; +import Remoa.BE.Post.Dto.Request.UploadPostForm; +import Remoa.BE.Post.Dto.Response.ResHomeReferenceDto; +import Remoa.BE.Post.Dto.Response.ResReferenceRegisterDto; import Remoa.BE.Post.Service.PostService; -import Remoa.BE.Post.form.Request.UploadPostForm; -import Remoa.BE.exception.CustomBody; import Remoa.BE.exception.CustomMessage; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.data.domain.Page; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpSession; import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; import static Remoa.BE.exception.CustomBody.errorResponse; import static Remoa.BE.exception.CustomBody.successResponse; @@ -27,51 +31,134 @@ @Slf4j @RestController @RequiredArgsConstructor -@CrossOrigin(origins = "*") public class PostController { - private final FileService fileService; - private final PostService postService; +// private final ModelMapper modelMapper; - private final MemberService memberService; + @GetMapping("/reference") + public ResponseEntity searchPost(@RequestParam(required = false, defaultValue = "all") String category, + @RequestParam(required = false, defaultValue = "newest") String sort, + @RequestParam(required = false, defaultValue = "1", name = "page") int pageNumber) { - //Todo 게시글 작성중 파일 업로드만 작성 - @PostMapping("/post") - public void posting(Post post, @RequestParam("files") List multipartFile){ - fileService.saveUploadFiles(post,multipartFile); - } + Map responseData = new HashMap<>(); - /** - * @param fileId file PK - * @return file이 저장된 url 반환 - */ - @GetMapping("/post/file/{fileId}/url") - public String getFileUrl(@PathVariable("fileId") Long fileId ){ - return fileService.getUrl(fileId); - } + pageNumber -= 1; + + Page allPosts; + if (category.equals("idea") || + category.equals("marketing") || + category.equals("design") || + category.equals("video") || + category.equals("etc")) { + //sort -> 최신순 : newest, 좋아요순 : like, 스크랩순 : scrap, 조회순 : view + allPosts = sortAndPaginatePostsByCategory(category, sort, pageNumber); + } else { + //sort -> 최신순 : newest, 좋아요순 : like, 스크랩순 : scrap, 조회순 : view + allPosts = sortAndPaginatePosts(sort, pageNumber); + } + + List result = new ArrayList<>(); - /** - * @param fileId file PK - * @return file을 바로 다운로드 할 수 있다 - */ - @GetMapping("/post/file/{fileId}") - public ResponseEntity getFileDownload(@PathVariable("fileId") Long fileId ) throws IOException { - return fileService.getObject(fileId); + for (Post post : allPosts) { + ResHomeReferenceDto map = ResHomeReferenceDto.builder() + .postThumbnail(post.getThumbnail().getStoreFileUrl()) + .postId(post.getPostId()) + .title(post.getTitle()) + .views(post.getViews()) + .likeCount(post.getLikeCount()) + .scrapCount(post.getScrapCount()) + .postMember(new ResMemberInfoDto(post.getMember().getMemberId(), + post.getMember().getNickname(), + post.getMember().getProfileImage())) + .build(); + + result.add(map); + } + + responseData.put("references", result); //조회한 레퍼런스들 + responseData.put("totalPages", allPosts.getTotalPages()); //전체 페이지의 수 + responseData.put("totalOfAllReferences", allPosts.getTotalElements()); //모든 레퍼런스의 수 + responseData.put("totalOfPageElements", allPosts.getNumberOfElements()); //현 페이지의 레퍼런스 수 + + return successResponse(CustomMessage.OK, responseData); } + @PostMapping("/reference") // 게시물 등록 - public ResponseEntity share(@RequestPart UploadPostForm uploadPostForm, - @RequestPart List uploadFiles, HttpServletRequest request){ - //TODO postingTime 설정. 로그인 여부 거르는 건 Spring Security 설정으로 가능해서 우선 없어도 괜찮을듯함. + public ResponseEntity share(@RequestPart("data") UploadPostForm uploadPostForm, + @RequestPart("thumbnail")MultipartFile thumbnail, + @RequestPart("file") List uploadFiles, HttpServletRequest request) throws IOException { if(authorized(request)){ Long memberId = getMemberId(); - Member myMember = memberService.findOne(memberId); - postService.registPost(uploadPostForm,uploadFiles,myMember); - return successResponse(CustomMessage.OK,myMember); + + Post savePost = postService.registerPost(uploadPostForm,thumbnail,uploadFiles,memberId); + + //잘못된 파일 유형 + if(savePost == null){ + return errorResponse(CustomMessage.BAD_FILE); + } + + Post post = postService.findOne(savePost.getPostId()); + + ResReferenceRegisterDto resReferenceRegisterDto = ResReferenceRegisterDto.builder() + .postId(post.getPostId()) + .title(post.getTitle()) + .category(post.getCategory().getName()) + .contestAwardType(post.getContestAwareType()) + .contestName(post.getContestName()) + .pageCount(post.getPageCount()) + .fileNames(post.getUploadFiles().stream().map(UploadFile::getOriginalFileName).collect(Collectors.toList())) + .build(); + return successResponse(CustomMessage.OK, resReferenceRegisterDto); + + } return errorResponse(CustomMessage.UNAUTHORIZED); } -} + private Page sortAndPaginatePosts(String sort, int pageNumber) { + Page allPosts; + switch (sort) { + case "newest": + allPosts = postService.findAllPostsWithPaginationForHomepageNewest(pageNumber); + break; + case "like": + allPosts = postService.findAllPostsWithPaginationForHomepageMostLiked(pageNumber); + break; + case "scrap": + allPosts = postService.findAllPostsWithPaginationForHomepageMostScraped(pageNumber); + break; + case "view": + allPosts = postService.findAllPostsWithPaginationForHomepageMostViewed(pageNumber); + default: + //sort 문자열이 잘못됐을 경우 default인 최신순으로 정렬 + allPosts = postService.findAllPostsWithPaginationForHomepageNewest(pageNumber); + break; + } + return allPosts; + } + + private Page sortAndPaginatePostsByCategory(String category, String sort, int pageNumber) { + Page allPosts; + switch (sort) { + case "newest": + allPosts = postService.findAllPostsWithPaginationForHomepageSortByCategoryNewest(pageNumber, category); + break; + case "like": + allPosts = postService.findAllPostsWithPaginationForHomepageSortByCategoryMostLiked(pageNumber, category); + break; + case "scrap": + allPosts = postService.findAllPostsWithPaginationForHomepageSortByCategoryMostScraped(pageNumber, category); + break; + case "view": + allPosts = postService.findAllPostsWithPaginationForHomepageSortByCategoryMostViewed(pageNumber, category); + default: + //sort 문자열이 잘못됐을 경우 default인 최신순으로 정렬 + allPosts = postService.findAllPostsWithPaginationForHomepageSortByCategoryNewest(pageNumber, category); + break; + } + return allPosts; + } +} \ No newline at end of file diff --git a/src/main/java/Remoa/BE/Post/Domain/Post.java b/src/main/java/Remoa/BE/Post/Domain/Post.java index e9753b4..eea6d99 100644 --- a/src/main/java/Remoa/BE/Post/Domain/Post.java +++ b/src/main/java/Remoa/BE/Post/Domain/Post.java @@ -6,6 +6,7 @@ import org.hibernate.annotations.Where; import javax.persistence.*; +import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; @@ -21,8 +22,7 @@ public class Post { @Id - @GeneratedValue - @Column(name = "post_id") + @GeneratedValue(strategy = GenerationType.IDENTITY) private Long postId; /** @@ -37,6 +37,9 @@ public class Post { */ private String title; + @OneToOne + private UploadFile thumbnail; + /** * 참여 공모전의 이름 */ @@ -48,11 +51,6 @@ public class Post { */ private String deadline; - /** - * 참여한 공모전의 수상 내역 - */ - @Column(name = "contest_award") - private Boolean ContestAward; /** * pm쪽에 문의해야할듯. @@ -70,13 +68,17 @@ public class Post { * Post가 작성된 시간 */ @Column(name = "posting_time") - private String postingTime; + private LocalDateTime postingTime; /** * Post의 조회수 */ private Integer views = 0; + private Integer scrapCount = 0; + + private Integer pageCount; + /** * Post에 작성되어진 Comment */ @@ -87,7 +89,7 @@ public class Post { * Post에서 쓰인 files */ @OneToMany(mappedBy = "post") - private List uploadFiles = new ArrayList<>(); + private List uploadFiles; @OneToMany(mappedBy = "post", cascade = CascadeType.ALL) private List postScarps = new ArrayList<>(); diff --git a/src/main/java/Remoa/BE/Post/Domain/PostLike.java b/src/main/java/Remoa/BE/Post/Domain/PostLike.java index d2d112e..b7ee5dd 100644 --- a/src/main/java/Remoa/BE/Post/Domain/PostLike.java +++ b/src/main/java/Remoa/BE/Post/Domain/PostLike.java @@ -5,7 +5,6 @@ import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; -import org.hibernate.annotations.SQLDelete; import org.hibernate.annotations.Where; import javax.persistence.*; diff --git a/src/main/java/Remoa/BE/Post/Domain/PostScarp.java b/src/main/java/Remoa/BE/Post/Domain/PostScarp.java index 49fc0ac..3562575 100644 --- a/src/main/java/Remoa/BE/Post/Domain/PostScarp.java +++ b/src/main/java/Remoa/BE/Post/Domain/PostScarp.java @@ -5,7 +5,6 @@ import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; -import org.hibernate.annotations.SQLDelete; import org.hibernate.annotations.Where; import javax.persistence.*; diff --git a/src/main/java/Remoa/BE/Post/Domain/UploadFile.java b/src/main/java/Remoa/BE/Post/Domain/UploadFile.java index eeb155f..6337ff5 100644 --- a/src/main/java/Remoa/BE/Post/Domain/UploadFile.java +++ b/src/main/java/Remoa/BE/Post/Domain/UploadFile.java @@ -2,7 +2,6 @@ import lombok.Getter; import lombok.Setter; -import org.hibernate.annotations.SQLDelete; import org.hibernate.annotations.Where; import javax.persistence.*; @@ -16,12 +15,8 @@ public class UploadFile { @Id @GeneratedValue - @Column(name = "file_id") private Long uploadFileId; - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "post_id") - private Post post; /** * 업로드된 파일의 원본 이름 @@ -48,6 +43,10 @@ public class UploadFile { @Column(name = "store_file_url") private String storeFileUrl; + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "post_id") + private Post post; + private Boolean deleted = Boolean.FALSE; //이후 업로드 날짜 및 시간, 컨텐츠 타입, 사이즈 등의 필드등이 필요할 때 손봐야할듯. diff --git a/src/main/java/Remoa/BE/Post/Dto/Request/UploadPostForm.java b/src/main/java/Remoa/BE/Post/Dto/Request/UploadPostForm.java new file mode 100644 index 0000000..aff7c66 --- /dev/null +++ b/src/main/java/Remoa/BE/Post/Dto/Request/UploadPostForm.java @@ -0,0 +1,20 @@ +package Remoa.BE.Post.Dto.Request; + +import lombok.*; + +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Setter +@Builder +public class UploadPostForm { + + private String title; // Post name + + private String contestName; + + private String contestAwardType; + + private String category; // Category name + +} diff --git a/src/main/java/Remoa/BE/Post/Dto/Response/ResHomeReferenceDto.java b/src/main/java/Remoa/BE/Post/Dto/Response/ResHomeReferenceDto.java new file mode 100644 index 0000000..96345b1 --- /dev/null +++ b/src/main/java/Remoa/BE/Post/Dto/Response/ResHomeReferenceDto.java @@ -0,0 +1,18 @@ +package Remoa.BE.Post.Dto.Response; + +import Remoa.BE.Member.Dto.Res.ResMemberInfoDto; +import lombok.Builder; +import lombok.Data; + +@Data +@Builder +public class ResHomeReferenceDto { + + private String postThumbnail; + private Long postId; + private String title; + private int views; + private int likeCount; + private int scrapCount; + private ResMemberInfoDto postMember; +} diff --git a/src/main/java/Remoa/BE/Post/Dto/Response/ResPostDto.java b/src/main/java/Remoa/BE/Post/Dto/Response/ResPostDto.java new file mode 100644 index 0000000..1b02c5b --- /dev/null +++ b/src/main/java/Remoa/BE/Post/Dto/Response/ResPostDto.java @@ -0,0 +1,24 @@ +package Remoa.BE.Post.Dto.Response; + +import Remoa.BE.Member.Dto.Res.ResMemberInfoDto; +import lombok.*; + +/** + * 작업물 목록을 보여줄 때 쓰일 Post의 간단한 정보만을 담은 Dto. + */ +@Setter +@Getter +@Builder +public class ResPostDto { + + public Long postId; + public ResMemberInfoDto postMember; + public String thumbnail; + public String title; + public Integer likeCount; + public String postingTime; + public Integer views; + public Integer scrapCount; + public String categoryName; + +} diff --git a/src/main/java/Remoa/BE/Post/Dto/Response/ResReferenceRegisterDto.java b/src/main/java/Remoa/BE/Post/Dto/Response/ResReferenceRegisterDto.java new file mode 100644 index 0000000..fc4e9c5 --- /dev/null +++ b/src/main/java/Remoa/BE/Post/Dto/Response/ResReferenceRegisterDto.java @@ -0,0 +1,27 @@ +package Remoa.BE.Post.Dto.Response; + +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; + +import java.util.List; + +@Builder +@Getter +@Setter +public class ResReferenceRegisterDto { + + private Long postId; + + private String title; // Post name + + private String contestName; + + private String category; // Category name + + private String contestAwardType; + + private Integer pageCount; + + private List fileNames; +} diff --git a/src/main/java/Remoa/BE/Post/Repository/CommentRepository.java b/src/main/java/Remoa/BE/Post/Repository/CommentRepository.java index cf7049d..889cd9e 100644 --- a/src/main/java/Remoa/BE/Post/Repository/CommentRepository.java +++ b/src/main/java/Remoa/BE/Post/Repository/CommentRepository.java @@ -19,13 +19,15 @@ public class CommentRepository { private final EntityManager em; - + public Optional findOne(Long id) { + return Optional.ofNullable(em.find(Comment.class, id)); + } public void saveComment(Comment comment) { em.persist(comment); } - public Comment findByCommentId(Long commentId) { - return em.find(Comment.class, commentId); + public Optional findByCommentId(Long commentId) { + return Optional.ofNullable(em.find(Comment.class, commentId)); } /** @@ -87,4 +89,12 @@ public Integer findCommentBookmark(Comment comment) { .getResultList() .size(); }*/ + + public void updateComment(Comment newComment){ + em.merge(newComment); + } + + public void deleteComment(Comment comment){ + em.remove(comment); + } } diff --git a/src/main/java/Remoa/BE/Post/Repository/FeedbackRepository.java b/src/main/java/Remoa/BE/Post/Repository/FeedbackRepository.java index 703c21c..bed5ac8 100644 --- a/src/main/java/Remoa/BE/Post/Repository/FeedbackRepository.java +++ b/src/main/java/Remoa/BE/Post/Repository/FeedbackRepository.java @@ -24,8 +24,8 @@ public void saveFeedback(Feedback feedback) { em.persist(feedback); } - public Feedback findByFeedbackId(Long feedbackId) { - return em.find(Feedback.class, feedbackId); + public Optional findByFeedbackId(Long feedbackId) { + return Optional.ofNullable(em.find(Feedback.class, feedbackId)); } /** diff --git a/src/main/java/Remoa/BE/Post/Repository/PostPagingRepository.java b/src/main/java/Remoa/BE/Post/Repository/PostPagingRepository.java new file mode 100644 index 0000000..c15ee91 --- /dev/null +++ b/src/main/java/Remoa/BE/Post/Repository/PostPagingRepository.java @@ -0,0 +1,35 @@ +package Remoa.BE.Post.Repository; + +import Remoa.BE.Member.Domain.Member; +import Remoa.BE.Post.Domain.Category; +import Remoa.BE.Post.Domain.Post; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.repository.PagingAndSortingRepository; +import org.springframework.stereotype.Repository; + +import java.time.LocalDateTime; + +/** + * JPA Query Creation을 사용해서 post data sorting & slicing + */ +@Repository +public interface PostPagingRepository extends PagingAndSortingRepository { + + Page findAllByMemberOrderByPostingTimeDesc(Pageable pageable, Member member); + + Page findAllByMemberOrderByPostingTimeAsc(Pageable pageable, Member member); + + Page findAllByMemberOrderByLikeCountDesc(Pageable pageable, Member member); + + Page findAllByMemberOrderByScrapCountDesc(Pageable pageable, Member member); + + Page findAllByMemberAndCategory(Pageable pageable, Member member, Category category); + + Page findAllByMember(Pageable pageable, Member member); + + Page findAll(Pageable pageable); + + Page findAllByCategory(Pageable pageable, Category category); + +} diff --git a/src/main/java/Remoa/BE/Post/Repository/PostRepository.java b/src/main/java/Remoa/BE/Post/Repository/PostRepository.java index a31258a..83816ac 100644 --- a/src/main/java/Remoa/BE/Post/Repository/PostRepository.java +++ b/src/main/java/Remoa/BE/Post/Repository/PostRepository.java @@ -1,5 +1,6 @@ package Remoa.BE.Post.Repository; +import Remoa.BE.Member.Domain.Comment; import Remoa.BE.Member.Domain.Member; import Remoa.BE.Post.Domain.Category; import Remoa.BE.Post.Domain.Post; @@ -10,6 +11,10 @@ import org.springframework.stereotype.Repository; import javax.persistence.EntityManager; +import javax.persistence.TypedQuery; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Root; import java.util.List; import java.util.Optional; @@ -24,15 +29,27 @@ public void savePost(Post post) { em.persist(post); } - public Post findByPostId(Long postId) { - return em.find(Post.class, postId); + public List findAll(){ + return em.createQuery("SELECT p FROM Post p", Post.class).getResultList(); } - public Optional findByMemberId(Member member) { + + public Optional findOne(Long postId) { // 위 findByPostId와 거의 같음 반환형을 Optional로 하기 위함 + return Optional.ofNullable(em.find(Post.class, postId)); + } + + public List findByMember(Member member) { return em.createQuery("select p from Post p where p.member = :member", Post.class) .setParameter("member", member) - .getResultStream() - .findAny(); + .getResultList(); + } + + public List findByTitleContaining(String name){ + CriteriaBuilder cb = em.getCriteriaBuilder(); + CriteriaQuery query = cb.createQuery(Post.class); + Root root = query.from(Post.class); + query.select(root).where(cb.like(root.get("title"), "%" + name + "%")); + return em.createQuery(query).getResultList(); } public void savePostScrap(PostScarp postScarp) { @@ -63,6 +80,8 @@ public List findPostsByCategory(Category category) { .getResultList(); } - + public void saveComment(Comment comment) { + em.persist(comment); + } } diff --git a/src/main/java/Remoa/BE/Post/Service/CommentService.java b/src/main/java/Remoa/BE/Post/Service/CommentService.java index 93744ed..f191d83 100644 --- a/src/main/java/Remoa/BE/Post/Service/CommentService.java +++ b/src/main/java/Remoa/BE/Post/Service/CommentService.java @@ -8,10 +8,15 @@ import Remoa.BE.Post.Repository.CommentRepository; import Remoa.BE.Post.Repository.PostRepository; import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.server.ResponseStatusException; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; import java.util.List; +import java.util.Optional; @Service @Transactional(readOnly = true) @@ -19,7 +24,7 @@ public class CommentService { private final CommentRepository commentRepository; - private final PostRepository postRepository; + private final PostService postService; @Transactional public Long writeComment(Comment comment) { @@ -27,10 +32,7 @@ public Long writeComment(Comment comment) { return comment.getCommentId(); } - public List loadCommentsByPostId(Long postId) { - Post post = postRepository.findByPostId(postId); - return commentRepository.findByPost(post); - } + @Transactional public Long commentLikeAction(Comment comment, Member member) { @@ -39,10 +41,55 @@ public Long commentLikeAction(Comment comment, Member member) { return commentLike.getCommentLikeId(); } + @Transactional + public Comment findOne(Long commentId) { + Optional comment = commentRepository.findOne(commentId); + return comment.orElseThrow(() -> new ResponseStatusException(HttpStatus.BAD_REQUEST, "Comment not found")); + } + @Transactional public Long commentBookmarkAction(Comment comment, Member member) { CommentBookmark commentBookmark = CommentBookmark.createCommentBookmark(member, comment); commentRepository.saveCommentBookmark(commentBookmark); return commentBookmark.getCommentBookmarkId(); } -} + + @Transactional + public Post registerComment(Member member, String comment, Long postId, Long commentId){ + + Comment parentComment = null; + + if (commentId != null) { + parentComment = commentRepository.findByCommentId(commentId) + .orElseThrow(() -> new ResponseStatusException(HttpStatus.BAD_REQUEST, "Comment not found")); + } + + Comment commentObj = new Comment(); +// String formatDate = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); + Post post = postService.findOne(postId); + + commentObj.setPost(post); + commentObj.setMember(member); + commentObj.setParentComment(parentComment); //대댓글인 경우 원 댓글의 Feedback, 댓글인 경우 null + commentObj.setComment(comment); + commentObj.setCommentLikeCount(0); + commentObj.setCommentedTime(LocalDateTime.now()); + commentRepository.saveComment(commentObj); + + return post; + } + + @Transactional + public void modifyComment(String comment, Long commentId){ + Comment commentObj = findOne(commentId); + commentObj.setComment(comment); + commentRepository.updateComment(commentObj); + } + + + @Transactional + public void deleteComment(Long commentId){ + Comment commentObj = findOne(commentId); + commentRepository.deleteComment(commentObj); + } +} \ No newline at end of file diff --git a/src/main/java/Remoa/BE/Post/Service/FeedbackService.java b/src/main/java/Remoa/BE/Post/Service/FeedbackService.java new file mode 100644 index 0000000..5d3b811 --- /dev/null +++ b/src/main/java/Remoa/BE/Post/Service/FeedbackService.java @@ -0,0 +1,58 @@ +package Remoa.BE.Post.Service; + +import Remoa.BE.Member.Domain.Feedback; +import Remoa.BE.Member.Domain.Member; +import Remoa.BE.Post.Domain.Post; +import Remoa.BE.Post.Domain.UploadFile; +import Remoa.BE.Post.Repository.FeedbackRepository; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.server.ResponseStatusException; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.stream.Collectors; + +@Slf4j +@Service +@RequiredArgsConstructor +@Transactional(readOnly = true) +public class FeedbackService { + private final FeedbackRepository feedbackRepository; + private final PostService postService; + + @Value("${cloud.aws.s3.bucket}") + private String bucketName; + + @Transactional + public void registerFeedback(Member member, String feedback, Long postId, Integer pageNumber, Long feedbackId){ + + Feedback parentFeedback = null; + if (feedbackId != null) { + parentFeedback = feedbackRepository.findByFeedbackId(feedbackId) + .orElseThrow(() -> new ResponseStatusException(HttpStatus.BAD_REQUEST, "Feedback not found")); + } + + + Feedback feedbackObj = new Feedback(); + Post post = postService.findOne(postId); + +// String formatDate = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); + feedbackObj.setPost(post); + feedbackObj.setMember(member); + feedbackObj.setParentFeedback(parentFeedback); //대댓글인 경우 원 댓글의 Feedback, 댓글인 경우 null + feedbackObj.setPageNumber(pageNumber); //대댓글인 경우 null. parentFeedback.getPageNumber()통헤서 값 넣어도 됩니다. + feedbackObj.setFeedback(feedback); + feedbackObj.setFeedbackLikeCount(0); + feedbackObj.setFeedbackTime(LocalDateTime.now()); + + feedbackRepository.saveFeedback(feedbackObj); + } +} \ No newline at end of file diff --git a/src/main/java/Remoa/BE/Post/Service/FileService.java b/src/main/java/Remoa/BE/Post/Service/FileService.java index 14d7553..6fa26ae 100644 --- a/src/main/java/Remoa/BE/Post/Service/FileService.java +++ b/src/main/java/Remoa/BE/Post/Service/FileService.java @@ -22,6 +22,7 @@ import java.io.InputStream; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; +import java.util.ArrayList; import java.util.List; import java.util.Optional; import java.util.UUID; @@ -47,11 +48,18 @@ public class FileService { * 파일들을 저장해준다 */ @Transactional - public void saveUploadFiles(Post post,List multipartFile){ + public void saveUploadFiles(Post post,MultipartFile thumbnail, List multipartFile){ - multipartFile.forEach(item -> saveUploadFile(post,item)); + //썸네일 파일 저장 추가 + saveUploadFile(thumbnail,post,"thumbnail"); + multipartFile.forEach(file -> saveUploadFile(file, post,"post")); - post.setUploadFiles(uploadFileList); + + //새로운 인스턴스 만들어서 set하지 않으면 clear 되면서 null이 계속 저장됨. + UploadFile uploadFile = uploadFileList.get(0); + post.setThumbnail(uploadFile); + + post.setUploadFiles(new ArrayList<>(uploadFileList.subList(1, uploadFileList.size()))); postRepository.savePost(post); uploadFileList.clear(); @@ -59,18 +67,18 @@ public void saveUploadFiles(Post post,List multipartFile){ /** * - * @param post 게시글 * @param multipartFile 파일 - * saveUploadFiles 에서 파일 하나씩 가져와서 s3에 넣는다 */ @Transactional - public void saveUploadFile(Post post, MultipartFile multipartFile){ + public void saveUploadFile(MultipartFile multipartFile, Post post,String folderName){ //파일 타입과 사이즈 저장 ObjectMetadata objectMetadata = new ObjectMetadata(); objectMetadata.setContentType(multipartFile.getContentType()); objectMetadata.setContentLength(multipartFile.getSize()); + log.info(multipartFile.getContentType()); + //파일 이름 String originalFilename = multipartFile.getOriginalFilename(); @@ -82,8 +90,8 @@ public void saveUploadFile(Post post, MultipartFile multipartFile){ //파일 이름이 겹치지 않게 String uuid = UUID.randomUUID().toString(); - //postId 폴더에 따로 넣어서 보관 - String s3name = uuid+"_"+originalFilename; + //post 폴더에 따로 넣어서 보관 + String s3name = folderName+"/"+uuid+"_"+originalFilename; try (InputStream inputStream = multipartFile.getInputStream()) { amazonS3.putObject(new PutObjectRequest(bucket, s3name, inputStream, objectMetadata) @@ -97,14 +105,17 @@ public void saveUploadFile(Post post, MultipartFile multipartFile){ //파일 보관 url String storeFileUrl = amazonS3.getUrl(bucket,s3name).toString().replaceAll("\\+", "+"); UploadFile uploadFile = new UploadFile(); - uploadFile.setPost(post); uploadFile.setOriginalFileName(originalFilename); uploadFile.setSaveFileName(s3name); uploadFile.setStoreFileUrl(storeFileUrl); uploadFile.setExtension(ext); + uploadFile.setPost(post); + uploadFileList.add(uploadFile); - log.info(storeFileUrl); + uploadFileRepository.saveFile(uploadFile); + + log.info(storeFileUrl); } public String getUrl(Long fileId){ @@ -132,7 +143,8 @@ public ResponseEntity getObject(Long fileId) throws IOException { String fileOriginalName = file.get().getOriginalFileName(); //encode 메서드에 두 번째 파라메터에 StandardCharsets.UTF_8만 쓰면 오류가 나서 뒤에 name을 임사방편으로 붙임. 기능상 문제는 없을듯 함 - String fileNameFix = URLEncoder.encode(fileOriginalName, StandardCharsets.UTF_8.name()).replaceAll("\\+", "%20"); + String fileNameFix = URLEncoder.encode(fileOriginalName, StandardCharsets.UTF_8.name()) + .replaceAll("\\+", "%20"); HttpHeaders httpHeaders = new HttpHeaders(); httpHeaders.setContentType(MediaType.APPLICATION_OCTET_STREAM); httpHeaders.setContentLength(bytes.length); diff --git a/src/main/java/Remoa/BE/Post/Service/MyPostService.java b/src/main/java/Remoa/BE/Post/Service/MyPostService.java new file mode 100644 index 0000000..1707f85 --- /dev/null +++ b/src/main/java/Remoa/BE/Post/Service/MyPostService.java @@ -0,0 +1,113 @@ +package Remoa.BE.Post.Service; + +import Remoa.BE.Member.Domain.Member; +import Remoa.BE.Post.Domain.Category; +import Remoa.BE.Post.Domain.Post; +import Remoa.BE.Post.Repository.CategoryRepository; +import Remoa.BE.Post.Repository.PostPagingRepository; +import Remoa.BE.Post.Repository.PostRepository; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Sort; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +@Slf4j +@Service +@RequiredArgsConstructor +@Transactional(readOnly = true) +public class MyPostService { + + private final PostRepository postRepository; + private final PostPagingRepository postPagingRepository; + private final CategoryRepository categoryRepository; + private static final int PAGE_SIZE = 5; + + /** + * 특정 member의 post들 전체 조회 + * @param member + * @return + */ + public List showOnesPosts(Member member) { + return postRepository.findByMember(member); + } + + /** + * paging : 특정 member의 post들 5개씩 조회 + * sorting : 최신순으로 정렬 + * @param page : 조회하려는 페이지 번호 + * @param member : 조회하려는 작성자 + * @return Page + */ + public Page getNewestPosts(int page, Member member) { +// PageRequest pageable = PageRequest.of(page, pageSize, Sort.by("postingTime").descending()); +// return postPagingRepository.findAllByMember(pageable, member); + + PageRequest pageable = PageRequest.of(page, PAGE_SIZE); + return postPagingRepository.findAllByMemberOrderByPostingTimeDesc(pageable, member); + } + + /** + * paging : 특정 member의 post들 5개씩 조회 + * sorting : 과거순으로 정렬 + * @param page : 조회하려는 페이지 번호 + * @param member : 조회하려는 작성자 + * @return Page + */ + public Page getOldestPosts(int page, Member member) { +// PageRequest pageable = PageRequest.of(page, pageSize, Sort.by("postingTime").ascending()); +// return postPagingRepository.findAllByMember(pageable, member); + + PageRequest pageable = PageRequest.of(page, PAGE_SIZE); + return postPagingRepository.findAllByMemberOrderByPostingTimeAsc(pageable, member); + } + + /** + * paging : 특정 member의 post들 5개씩 조회 + * sorting : 좋아요 순으로 정렬 + * @param page : 조회하려는 페이지 번호 + * @param member : 조회하려는 작성자 + * @return Page + */ + public Page getMostLikedPosts(int page, Member member) { + PageRequest pageable = PageRequest.of(page, PAGE_SIZE); + return postPagingRepository.findAllByMemberOrderByLikeCountDesc(pageable, member); + } + + /** + * paging : 특정 member의 post들 5개씩 조회 + * sorting : 스크랩 순으로 정렬 + * @param page : 조회하려는 페이지 번호 + * @param member : 조회하려는 작성자 + * @return Page + */ + public Page getMostScrapedPosts(int page, Member member) { + PageRequest pageable = PageRequest.of(page, PAGE_SIZE); + return postPagingRepository.findAllByMemberOrderByScrapCountDesc(pageable, member); + } + + public Page getNewestPostsSortCategory(int page, Member member, String category) { + PageRequest pageable = PageRequest.of(page, PAGE_SIZE, Sort.by("postingTime").descending()); + return postPagingRepository.findAllByMemberAndCategory(pageable, member, categoryRepository.findByCategoryName(category)); + } + + public Page getOldestPostsSortCategory(int page, Member member, String category) { + PageRequest pageable = PageRequest.of(page, PAGE_SIZE, Sort.by("postingTime").ascending()); + return postPagingRepository.findAllByMemberAndCategory(pageable, member, categoryRepository.findByCategoryName(category)); + } + + public Page getMostLikedPostsSortCategory(int page, Member member, String category) { + PageRequest pageable = PageRequest.of(page, PAGE_SIZE, Sort.by("likeCount").descending()); + return postPagingRepository.findAllByMemberAndCategory(pageable, member, categoryRepository.findByCategoryName(category)); + } + + public Page getMostScrapedPostsSortCategory(int page, Member member, String category) { + PageRequest pageable = PageRequest.of(page, PAGE_SIZE, Sort.by("scrapCount").descending()); + return postPagingRepository.findAllByMemberAndCategory(pageable, member, categoryRepository.findByCategoryName(category)); + } + +} \ No newline at end of file diff --git a/src/main/java/Remoa/BE/Post/Service/PostService.java b/src/main/java/Remoa/BE/Post/Service/PostService.java index 9f962fa..fdd84cd 100644 --- a/src/main/java/Remoa/BE/Post/Service/PostService.java +++ b/src/main/java/Remoa/BE/Post/Service/PostService.java @@ -1,56 +1,154 @@ package Remoa.BE.Post.Service; import Remoa.BE.Member.Domain.Member; +import Remoa.BE.Member.Service.MemberService; import Remoa.BE.Post.Domain.Category; import Remoa.BE.Post.Domain.Post; -import Remoa.BE.Post.Domain.UploadFile; -import Remoa.BE.Post.Repository.PostRepository; -import Remoa.BE.Post.Repository.UploadFileRepository; +import Remoa.BE.Post.Dto.Request.UploadPostForm; import Remoa.BE.Post.Repository.CategoryRepository; -import Remoa.BE.Post.form.Request.UploadPostForm; +import Remoa.BE.Post.Repository.PostPagingRepository; +import Remoa.BE.Post.Repository.PostRepository; +import Remoa.BE.exception.CustomMessage; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.apache.pdfbox.pdmodel.PDDocument; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.core.parameters.P; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.multipart.MultipartFile; +import org.springframework.web.server.ResponseStatusException; +import java.io.IOException; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; import java.util.List; +import java.util.Optional; + +import static Remoa.BE.exception.CustomBody.successResponse; @Slf4j @Service @RequiredArgsConstructor +@Transactional(readOnly = true) public class PostService { - private final UploadFileRepository uploadFileRepository; + + private final MemberService memberService; private final PostRepository postRepository; private final CategoryRepository categoryRepository; - private final List uploadFileList; - private final FileService fileService; - public Post dtoToEntity(UploadPostForm uploadPostForm, Member member){ // dto를 db에 저장하기 위해 entity로 변환 + private final PostPagingRepository postPagingRepository; - // String category를 이용해 Category 엔티티를 찾기 - Category category = categoryRepository.findByCategoryName(uploadPostForm.getCategory()); + private static final int HOME_PAGE_SIZE = 12; - return Post.builder() - .title(uploadPostForm.getTitle()) - .member(member) - .contestName(uploadPostForm.getContestName()) - .category(category) - .contestAwareType(uploadPostForm.getContestAward()) - .build(); + public Post findOne(Long postId) { + Optional post = postRepository.findOne(postId); + return post.orElseThrow(() -> new ResponseStatusException(HttpStatus.BAD_REQUEST, "Post not found")); } @Transactional - public void registPost(UploadPostForm uploadPostForm, List uploadFiles, Member member){ + public Post registerPost(UploadPostForm uploadPostForm,MultipartFile thumbnail ,List uploadFiles, Long memberId) throws IOException { + + Category category = categoryRepository.findByCategoryName(uploadPostForm.getCategory()); + + Member member = memberService.findOne(memberId); + +// String formatDate = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); + + //확장자 확인 + String fileName = uploadFiles.get(0).getOriginalFilename(); + assert fileName != null; + int lastIndex = fileName.lastIndexOf("."); + String extension = fileName.substring(lastIndex + 1); + if(extension.equals("pdf") || extension.equals("jpg")){ + int pageCount; + if(extension.equals("pdf")){ + PDDocument document = PDDocument.load(uploadFiles.get(0).getInputStream()); + pageCount = document.getNumberOfPages(); + } + else{ + pageCount = uploadFiles.size(); + } + Post post = Post.builder() + .title(uploadPostForm.getTitle()) + .member(member) + .contestName(uploadPostForm.getContestName()) + .category(category) + .contestAwareType(uploadPostForm.getContestAwardType()) + .pageCount(pageCount) + .postingTime(LocalDateTime.now()) + .likeCount(0) + .views(0) + .scrapCount(0) + .deleted(false) + .build(); + + fileService.saveUploadFiles(post, thumbnail ,uploadFiles); + return post; + } + else{ + return null; + } + + + } + + public List searchPost(String name) { + return postRepository.findByTitleContaining(name); + } + + public List findAll(){ + return postRepository.findAll(); + } + + public Page findAllPostsWithPaginationForHomepageNewest(int page) { + Pageable pageable = PageRequest.of(page, HOME_PAGE_SIZE, Sort.by("postingTime").descending()); + return postPagingRepository.findAll(pageable); + } + + public Page findAllPostsWithPaginationForHomepageMostViewed(int page) { + Pageable pageable = PageRequest.of(page, HOME_PAGE_SIZE, Sort.by("views").descending()); + return postPagingRepository.findAll(pageable); + } + + public Page findAllPostsWithPaginationForHomepageMostLiked(int page) { + Pageable pageable = PageRequest.of(page, HOME_PAGE_SIZE, Sort.by("likeCount").descending()); + return postPagingRepository.findAll(pageable); + } + + public Page findAllPostsWithPaginationForHomepageMostScraped(int page) { + Pageable pageable = PageRequest.of(page, HOME_PAGE_SIZE, Sort.by("scrapCount").descending()); + return postPagingRepository.findAll(pageable); + } + + public Page findAllPostsWithPaginationForHomepageSortByCategoryNewest(int page, String category) { + Pageable pageable = PageRequest.of(page, HOME_PAGE_SIZE, Sort.by("postingTime").descending()); + return postPagingRepository.findAllByCategory(pageable, categoryRepository.findByCategoryName(category)); + } + + public Page findAllPostsWithPaginationForHomepageSortByCategoryMostViewed(int page, String category) { + Pageable pageable = PageRequest.of(page, HOME_PAGE_SIZE, Sort.by("views").descending()); + return postPagingRepository.findAllByCategory(pageable, categoryRepository.findByCategoryName(category)); + } - Post post = dtoToEntity(uploadPostForm, member); - postRepository.savePost(post); - fileService.saveUploadFiles(post, uploadFiles); + public Page findAllPostsWithPaginationForHomepageSortByCategoryMostLiked(int page, String category) { + Pageable pageable = PageRequest.of(page, HOME_PAGE_SIZE, Sort.by("likeCount").descending()); + return postPagingRepository.findAllByCategory(pageable, categoryRepository.findByCategoryName(category)); } + public Page findAllPostsWithPaginationForHomepageSortByCategoryMostScraped(int page, String category) { + Pageable pageable = PageRequest.of(page, HOME_PAGE_SIZE, Sort.by("scrapCount").descending()); + return postPagingRepository.findAllByCategory(pageable, categoryRepository.findByCategoryName(category)); + } } diff --git a/src/main/java/Remoa/BE/Post/form/Request/UploadPostForm.java b/src/main/java/Remoa/BE/Post/form/Request/UploadPostForm.java deleted file mode 100644 index bcecf18..0000000 --- a/src/main/java/Remoa/BE/Post/form/Request/UploadPostForm.java +++ /dev/null @@ -1,27 +0,0 @@ -package Remoa.BE.Post.form.Request; - -import Remoa.BE.Post.Domain.Category; -import Remoa.BE.Post.Domain.Post; -import lombok.Builder; -import lombok.Getter; -import lombok.Setter; -import org.springframework.web.multipart.MultipartFile; - -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.Size; -import java.util.List; - -@Getter -@Setter -public class UploadPostForm { - - private String title; // Post name - - private String contestName; - - private String category; // Category name - - private String contestAward; - - //private List uploadFiles; -} diff --git a/src/main/java/Remoa/BE/config/AppConfig.java b/src/main/java/Remoa/BE/config/AppConfig.java new file mode 100644 index 0000000..d930292 --- /dev/null +++ b/src/main/java/Remoa/BE/config/AppConfig.java @@ -0,0 +1,13 @@ +package Remoa.BE.config; + +import org.modelmapper.ModelMapper; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class AppConfig { + @Bean + public ModelMapper modelMapper() { + return new ModelMapper(); + } +} \ No newline at end of file diff --git a/src/main/java/Remoa/BE/config/CorsConfig.java b/src/main/java/Remoa/BE/config/CorsConfig.java index a369d88..ade0a09 100644 --- a/src/main/java/Remoa/BE/config/CorsConfig.java +++ b/src/main/java/Remoa/BE/config/CorsConfig.java @@ -11,14 +11,16 @@ public class CorsConfig { @Bean public CorsFilter corsFilter() { + UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); CorsConfiguration config = new CorsConfiguration(); + config.setAllowCredentials(true); - config.addAllowedOrigin("*"); + config.addAllowedOriginPattern("*"); // addAllowedOriginPattern("*") 대신 사용 config.addAllowedHeader("*"); config.addAllowedMethod("*"); + source.registerCorsConfiguration("/**", config); - source.registerCorsConfiguration("*", config); return new CorsFilter(source); } } \ No newline at end of file diff --git a/src/main/java/Remoa/BE/config/DbInit.java b/src/main/java/Remoa/BE/config/DbInit.java index e1350be..98462bf 100644 --- a/src/main/java/Remoa/BE/config/DbInit.java +++ b/src/main/java/Remoa/BE/config/DbInit.java @@ -1,6 +1,5 @@ package Remoa.BE.config; -import Remoa.BE.Member.Domain.Role; import Remoa.BE.Post.Domain.Category; import Remoa.BE.Member.Domain.Member; import Remoa.BE.Post.Service.CategoryService; diff --git a/src/main/java/Remoa/BE/config/SecureConfig.java b/src/main/java/Remoa/BE/config/SecureConfig.java index 8bff517..2c60b10 100644 --- a/src/main/java/Remoa/BE/config/SecureConfig.java +++ b/src/main/java/Remoa/BE/config/SecureConfig.java @@ -15,7 +15,7 @@ @Configuration public class SecureConfig { - private final CorsFilter corsFilter; + /** * Spring Security에서 사용할 password encoder로 BCryptPasswordEncoder 지정 @@ -31,7 +31,6 @@ public PasswordEncoder passwordEncoder() { @Bean public SecurityFilterChain configure(HttpSecurity http) throws Exception { - http.addFilter(corsFilter); http.formLogin().disable(); diff --git a/src/main/java/Remoa/BE/exception/CustomMessage.java b/src/main/java/Remoa/BE/exception/CustomMessage.java index e1da644..e333f0c 100644 --- a/src/main/java/Remoa/BE/exception/CustomMessage.java +++ b/src/main/java/Remoa/BE/exception/CustomMessage.java @@ -2,13 +2,16 @@ import lombok.Getter; import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; @Getter public enum CustomMessage { //200 정상처리 상태코드 OK(HttpStatus.OK,"올바른 요청","정상적으로 처리되었습니다"), + OK_DUPLICATE(HttpStatus.OK,"올바른 요청","닉네임이 중복되었습니다"), + + OK_UN_DUPLICATE(HttpStatus.OK,"올바른 요청","사용가능한 닉네임 입니다"), + OK_UNFOLLOW(HttpStatus.OK,"올바른 요청","회원을 언팔로잉 합니다"), //201 한 api에서 정상처리상 구분이 필요할떄 사용 @@ -18,13 +21,21 @@ public enum CustomMessage { //400 잘못된 요청 VALIDATED(HttpStatus.BAD_REQUEST,"잘못된 요청","요청한 값이 유효성검사를 통과하지 못했습니다"), - NO_MEMBER(HttpStatus.BAD_REQUEST,"잘못된 요청","요청한 memberId가 존재하지 않습니다"), + NO_ID(HttpStatus.BAD_REQUEST,"잘못된 요청","요청한 Id가 존재하지 않습니다"), - //401권한오류 - UNAUTHORIZED(HttpStatus.UNAUTHORIZED,"권한이 없습니다","인증에 필요한 쿠키 정보가 없습니다"), + FOLLOW_ME(HttpStatus.BAD_REQUEST,"서비스 로직상 오류","자신을 팔로우할 수 없습니다"), + + BAD_DUPLICATE(HttpStatus.BAD_REQUEST,"서비스 로직상 오류","닉네임이 중복되었습니다"), - //409 상태 충돌 - FOLLOW_ME(HttpStatus.CONFLICT,"서비스 로직상 오류","자신을 팔로우할 수 없습니다"); + BAD_PROFILE_IMG(HttpStatus.BAD_REQUEST,"서비스 로직상 오류","해당 멤버의 프로필사진이 존재하지 않습니다"), + + BAD_FILE(HttpStatus.BAD_REQUEST,"서비스 로직상 오류","해당 파일 유형은 지원하지 않습니다"), + + BAD_PAGE_NUM(HttpStatus.BAD_REQUEST, "피드백 등록시 페이지 넘버 오류", "존재하지 않는 페이지에 피드백을 등록하려 합니다"), + + PAGE_NUM_OVER(HttpStatus.BAD_REQUEST, "레퍼런스 조회시 페이지 넘버 오류", "올바르지 않는 페이지 번호입니다."), + //401권한오류 + UNAUTHORIZED(HttpStatus.UNAUTHORIZED,"권한이 없습니다","인증에 필요한 쿠키 정보가 없습니다"); private final HttpStatus httpStatus; diff --git a/src/main/java/Remoa/BE/exception/CustomizedExceptionHandler.java b/src/main/java/Remoa/BE/exception/CustomizedExceptionHandler.java index 922f7f7..f5e3ac0 100644 --- a/src/main/java/Remoa/BE/exception/CustomizedExceptionHandler.java +++ b/src/main/java/Remoa/BE/exception/CustomizedExceptionHandler.java @@ -1,6 +1,5 @@ package Remoa.BE.exception; -import Remoa.BE.exception.response.FailResponse; import lombok.extern.slf4j.Slf4j; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.MethodArgumentNotValidException; @@ -31,6 +30,6 @@ public ResponseEntity methodValidException(MethodArgumentNotValidExcepti @ExceptionHandler public ResponseEntity responseStatusException(ResponseStatusException ex){ - return errorResponse(CustomMessage.NO_MEMBER); + return errorResponse(CustomMessage.NO_ID); } } diff --git a/src/main/java/Remoa/BE/utill/MemberInfo.java b/src/main/java/Remoa/BE/utill/MemberInfo.java index b04ff16..4ae2b6b 100644 --- a/src/main/java/Remoa/BE/utill/MemberInfo.java +++ b/src/main/java/Remoa/BE/utill/MemberInfo.java @@ -1,6 +1,7 @@ package Remoa.BE.utill; import Remoa.BE.Member.Domain.Member; +import lombok.extern.slf4j.Slf4j; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; @@ -16,6 +17,7 @@ import java.util.List; import java.util.Optional; +@Slf4j public class MemberInfo { public static Long getMemberId() { Member member = (Member) SecurityContextHolder.getContext().getAuthentication().getPrincipal();