2023. 1. 26. 01:39ㆍProject/시네마그램
11. Popular 페이지 렌더링 포스팅에 이어 추가적으로 마우스 hover 시 좋아요 카운드를 보여주고
프로필 사진 등록 구현까지 해서 Popular페이지와 Profile페이지를 마무리 짓도록 하겠습니다.
마우스 hover 시 좋아요 카운드 보여주기
좋아요 기능 구현에서 만든 likesCount를 여기서 활용할 수 있습니다.
기능 구현할 수 있는 두 가지 방법 소개
이렇게 찍어내는 방법에는 두 가지가 있습니다.
- html에 바로 로직을 넣는 방법
- 서버에서 로직을 짜고 html에는 결과만 넘기는 방법
Case 1. html에 바로 로직 넣기
<span th:text="${image.likes.size()}"></span>
Case 2. 서버에서 로직을 짜고 html에는 결과만 넘기는 방법
흐름 파악
UserController
@GetMapping("/user/{pageUserId}")
public String profile(@PathVariable int pageUserId, Model model, @AuthenticationPrincipal CustomUserDetails customUserDetails) {
UserProfileDto userProfileDto = userService.profile(pageUserId, customUserDetails.getUser().getId());
model.addAttribute("dto", userProfileDto);
return "user/profile";
}
UserProfileDto에 User가 있고
@Data
public class UserProfileDto {
...
private User user;
}
User안에 images가 있고
@Entity
public class User extends BaseTimeEntity {
...
@OneToMany(mappedBy = "user")
@JsonIgnoreProperties({"user"})
private List<Image> images;
}
Image안에 likeCount가 있습니다. 이걸 활용하면 됩니다.
@Entity
public class Image extends BaseTimeEntity {
...
@Transient
@Setter
private int likesCount;
}
UserService
userEntity.getImages().forEach((image) -> {
image.setLikesCount(image.getLikes().size());
});
html
<span th:text="${image.likesCount}"></span>
어느 방법을 써도 상관없습니다. 하지만 약간 귀찮더라도 로직을 서버에서 만들고 model에 담아 html는 결과만 던지는 게 좀 더 유지보수할 때 좋을 것 같다는 생각입니다.
프로필 사진 등록
마지막으로는 간단하게 프로필 사진 등록을 해보겠습니다.
고려해야 할 부분
- pageUserId, principalId를 비교한 후 같은 경우만 동작하게 처리
- 이미지를 put방식으로 서버로 전송
해당 코드 부분, profile.html
<button th:onclick="'profileImageUpload(' + ${dto.user.id} + ', ' + ${sessionId} + ')'">사진 업로드</button>
profile.js
function profileImageUpload(pageUserId, sessionId) {
if(pageUserId != sessionId) {
alert("자신의 프로필 사진만 수정할 수 있습니다.")
return;
}
...
let profileImageForm = $("#userProfileImageForm")[0];
let formData = new FormData(profileImageForm);
$.ajax({
type: "put",
url: "/api/user/" + sessionId + "/profileImageUrl",
data: formData,
contentType: false, // default : x-www-form-urlencoded로 파싱되는 것을 방지 (사진 전송 못 함)
processData: false, // default : contentType을 false로 주면 QueryString 자동 설정되는 거 해제.
enctype: "multipart/form-data",
dataType: "json",
success: function(res) {
// 사진 전송 성공시 이미지 변경
let reader = new FileReader();
reader.onload = (e) => {
$("#userProfileImage").attr("src", e.target.result);
}
reader.readAsDataURL(f);
},
error: function(error) {
console.log("프로필 사진 변경 오류", error);
}
});
}
- form 태그 자체를 가져옴
- let profileImageForm = $("#userProfileImageForm")[0];
- FormData 객체를 이용하면 form 태그의 필드와 그 값을 나타내는 일련의 key/value 쌍을 담을 수 있습니다.
즉, form태그가 들고 있는 값들만 담기게 됩니다.- let formData = new FormData(profileImageForm);
1. form태그의 사진 데이터 전송 시
formData사용
2. 사진이 아닌 그 외 form태그의 key value 던질 때는
.serialize() 사용
하지만, 이번 토이프로젝트에서 중요한 것은 js가 아니다. 쿼리나 jpa집중
UserApiController
@PutMapping("/api/user/{sessionId}/profileImageUrl")
public ResponseEntity<?> profileImageUpdate(@PathVariable int sessionId, MultipartFile profileImageFile,
@AuthenticationPrincipal CustomUserDetails customUserDetails) {
User userEntity = userService.profileImageUpdate(sessionId, profileImageFile);
customUserDetails.setUser(userEntity); // 세션변경
return new ResponseEntity<>(new ResDto<>(1, "회원 프로필 사진 변경 성공", null), HttpStatus.OK);
}
MultipartFile
사진만 받아서 처리할 것이므로 변수에 MultipartFile을 받았습니다.
그런데 저번 ImageContoller > imageUpload에서는 MultipartFile가 아니라 데이터를 DTO로 받았습니다.
@PostMapping("/image")
public String imageUpload(@AuthenticationPrincipal CustomUserDetails customUserDetails, ImageUploadDto imageUploadDto) {
imageService.imageUpload(customUserDetails, imageUploadDto);
return "redirect:/user/"+customUserDetails.getUser().getId();
}
❗❗ 딱 정해줄게
보내야 할 게 두 개 이상이면 DTO
보내야 할 게 한 개면 MultipartFile를 이용합니다.
중요한 건, MultipartFile 변수명
변수명은 해당 html의 form태그 안의 name과 같아야 합니다!
<form id="userProfileImageForm">
<input type="file" name="profileImageFile" style="display: none;"
id="userProfileImageInput" />
</form>
UserService
@Transactional
public User profileImageUpdate(int sessionId, MultipartFile profileImageFile) {
// 사진 업로드 한 부분 똑같이 ImageService > imageUpload 복사
UUID uuid = UUID.randomUUID();
String imageFileName = uuid+"_"+profileImageFile.getOriginalFilename();
Path imageFilePath = Paths.get(imageUploadRoute+imageFileName);
try{
Files.write(imageFilePath, profileImageFile.getBytes());
}catch (Exception e){
e.printStackTrace();
}
// DB에 넣기기
User userEntity = userRepository.findById(sessionId).orElseThrow(
() -> new CustomApiException("유저를 찾을 수 없습니다."));
userEntity.setProfileImageUrl(imageFileName);
return userEntity;
} // 더티체킹으로 업데이트 됨
github에 최종적으로 push 하기 전 체크목록
- 회원가입, 로그인
- profile 페이지
- 이미지 추가, 게시글 카운팅 적용
- 회원정보 변경
- 다른 유저 팔로우, 언팔로우(페이지 이동, 모달)
- 로그아웃
- /image/upload에서 profile페이지로 못 가는 이슈 발견
- Controller에서 해당 API에 sessionId 넘기는 것으로 해결
- 마우스 hover시 좋아요 카운트 보임
- 프로필 사진 등록 (나의 프로필만 수정 가능)
- feed 페이지
- 내가 팔로우한 유저가 등록한 이미지 스크롤하면 다 보임
- 좋아요, 좋아요 취소, 카운트 적용
- popular 페이지
- 좋아요 한 순으로 출력
- 이미지 클릭 시 등록한 유저 profile페이지로 이동
여기까지 해서 드디어 좋아요 기능, Popular 페이지 렌더링, hover효과 및 프로필 사진 등록으로 push 했습니다.
다음 포스팅에는 소셜로그인을 공부 후 구현해 보도록 하겠습니다.
'Project > 시네마그램' 카테고리의 다른 글
[Cinemagram] 소셜 로그인 (구글) - (13) (1) | 2023.01.29 |
---|---|
[Git] .gitignore가 작동하지 않을때 (0) | 2023.01.29 |
[Cinemagram] Popular 페이지 렌더링 - (11) (0) | 2023.01.26 |
[Cinemagram] 좋아요 기능 구현 - (10) (0) | 2023.01.25 |
[Trouble Shooting] 무한 순환참조 이슈 (0) | 2023.01.18 |