Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/main' into dev/refactor/jobpost/#64
Browse files Browse the repository at this point in the history
  • Loading branch information
YooJHyun committed Oct 4, 2024
2 parents 644dd5b + 9b581a3 commit e653162
Show file tree
Hide file tree
Showing 9 changed files with 129 additions and 19 deletions.
1 change: 1 addition & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ dependencies {
implementation 'mysql:mysql-connector-java:8.0.33'
implementation 'org.projectlombok:lombok'
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.6.0'
implementation 'net.coobird:thumbnailator:0.4.8'

compileOnly 'org.projectlombok:lombok'
developmentOnly 'org.springframework.boot:spring-boot-devtools'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import com.prgrms2.java.bitta.member.dto.MemberDTO;
import com.prgrms2.java.bitta.member.dto.SignInDTO;
import com.prgrms2.java.bitta.member.dto.SignUpDTO;
import com.prgrms2.java.bitta.member.exception.NoChangeException;
import com.prgrms2.java.bitta.member.service.MemberService;
import com.prgrms2.java.bitta.security.JwtToken;
import com.prgrms2.java.bitta.security.JwtTokenProvider;
Expand Down Expand Up @@ -135,8 +136,10 @@ public ResponseEntity<MemberDTO> updateMemberById(@PathVariable Long id,
MemberDTO memberDTO = objectMapper.readValue(dtoJson, MemberDTO.class);
MemberDTO updatedMember = memberService.updateMember(id, memberDTO, profileImage, removeProfileImage);
return ResponseEntity.ok(updatedMember);
} catch (NoChangeException e) {
return ResponseEntity.ok().body(null);
} catch (IOException e) {
log.error("Failed to update member profile", e);
log.error("파일 업데이트에 실패하였습니다.", e);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(null);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import lombok.*;

@Getter
@Setter
@ToString
@AllArgsConstructor
@NoArgsConstructor
Expand All @@ -17,6 +18,9 @@ public class MemberDTO {
@Schema(title = "아이디", description = "로그인에 사용할 회원 아이디입니다.", example = "username")
private String username;

@Schema(title = "비밀번호", description = "로그인에 사용할 회원 비밀번호입니다.", example = "password")
private String password;

@Schema(title = "별명", description = "회원의 별명입니다.", example = "Nickname")
private String nickname;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.prgrms2.java.bitta.member.exception;

public class NoChangeException extends RuntimeException {
public NoChangeException(String message) {
super(message);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@
import com.prgrms2.java.bitta.member.dto.MemberDTO;
import com.prgrms2.java.bitta.member.dto.SignUpDTO;
import com.prgrms2.java.bitta.member.entity.Member;
import com.prgrms2.java.bitta.member.exception.NoChangeException;
import com.prgrms2.java.bitta.member.repository.MemberRepository;
import com.prgrms2.java.bitta.security.JwtToken;
import com.prgrms2.java.bitta.security.JwtTokenProvider;
import com.prgrms2.java.bitta.security.exception.InvalidTokenException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import net.coobird.thumbnailator.Thumbnails;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
Expand All @@ -20,6 +22,7 @@

import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
Expand All @@ -39,7 +42,7 @@ public class MemberServiceImpl implements MemberService{

@Value("${file.root.path}")
private String fileRootPath;

@Transactional
@Override
public JwtToken signIn(String username, String password) {
Expand Down Expand Up @@ -99,8 +102,16 @@ public MemberDTO getMemberById(Long id) {
.orElseThrow(() -> new IllegalArgumentException("회원 정보를 찾을 수 없습니다."));

String profile = member.getProfile() != null ? member.getProfile() : defaultProfileImg;
File thumbnailFile = getThumbnailFile(profile);

if (thumbnailFile.exists()) {
profile = thumbnailFile.getPath();
}

MemberDTO memberDTO = new MemberDTO(member);
memberDTO.setProfile(profile);

return new MemberDTO(member);
return memberDTO;
}

@Transactional
Expand All @@ -109,19 +120,56 @@ public MemberDTO updateMember(Long id, MemberDTO memberDTO, MultipartFile profil
Member member = memberRepository.findById(id)
.orElseThrow(() -> new IllegalArgumentException("회원 정보를 찾을 수 없습니다."));

if (removeProfileImage || profileImage == null) {
boolean isUpdated = false;

if (removeProfileImage) {
deleteProfileImage(member.getProfile());
member.setProfile(defaultProfileImg);
} else {
isUpdated = true;
} else if (profileImage != null && !profileImage.isEmpty()) {
deleteProfileImage(member.getProfile());
String imagePath = saveProfileImage(profileImage);

String thumbnailPath = createThumbnail(imagePath);
member.setProfile(imagePath);
isUpdated = true;
}

member.setNickname(memberDTO.getNickname());
member.setAddress(memberDTO.getAddress());
if (memberDTO.getNickname() != null && !memberDTO.getNickname().isBlank()) {
member.setNickname(memberDTO.getNickname());
isUpdated = true;
}

if (memberDTO.getAddress() != null && !memberDTO.getAddress().isBlank()) {
member.setAddress(memberDTO.getAddress());
isUpdated = true;
}

if (memberDTO.getPassword() != null && !memberDTO.getPassword().isBlank()) {
member.setPassword(passwordEncoder.encode(memberDTO.getPassword()));
isUpdated = true;
}

if (!isUpdated) {
throw new NoChangeException("변경된 내용이 없습니다.");
}

memberRepository.save(member);
return MemberDTO.toDTO(member);
}

@Transactional
@Override
public void deleteMember(Long id) {
Member member = memberRepository.findById(id)
.orElseThrow(() -> new IllegalArgumentException("ID가 " + id + "인 회원을 찾을 수 없습니다."));
memberRepository.delete(member);
}

private File getProfileImageFile(String profileImg) {
return new File(profileImg);
}

private String saveProfileImage(MultipartFile profileImage) throws IOException {
String directory = fileRootPath + "/uploads/profile_images/";
Path uploadPath = Paths.get(directory);
Expand All @@ -137,21 +185,68 @@ private String saveProfileImage(MultipartFile profileImage) throws IOException {
return directory + fileName;
}


public void deleteProfileImage(String profileImg) {
if (!profileImg.equals(defaultProfileImg)) {
File file = new File(profileImg);
if (file.exists()) {
file.delete();
if (profileImg != null && !profileImg.equals(defaultProfileImg)) {
File profileFile = getProfileImageFile(profileImg);
File thumbnailFile = getThumbnailFile(profileImg);

if (profileFile.exists() && profileFile.isFile()) {
profileFile.delete();
}

if (thumbnailFile.exists() && thumbnailFile.isFile()) {
thumbnailFile.delete();
}
}
}

@Transactional
@Override
public void deleteMember(Long id) {
Member member = memberRepository.findById(id)
.orElseThrow(() -> new IllegalArgumentException("ID가 " + id + "인 회원을 찾을 수 없습니다."));
memberRepository.delete(member);
private String createThumbnail(String imagePath) throws IOException {
String thumbnailDirectory = fileRootPath + "/uploads/profile_images/thumbnail/";
Path thumbnailPath = Paths.get(thumbnailDirectory);

if (!Files.exists(thumbnailPath)) {
Files.createDirectories(thumbnailPath);
}

String originalFileName = Paths.get(imagePath).getFileName().toString();
String thumbnailFileName = "thumb_" + originalFileName;
Path thumbnailFilePath = thumbnailPath.resolve(thumbnailFileName);

Thumbnails.of(new File(imagePath))
.size(200, 200)
.keepAspectRatio(true)
.toFile(thumbnailFilePath.toFile());

return thumbnailFilePath.toString();
}

public void outputThumbnail(String profileImagePath, OutputStream outputStream) throws IOException {
File thumbnailFile = getThumbnailFile(profileImagePath);
if (thumbnailFile.exists() && thumbnailFile.isFile()) {
Thumbnails.of(thumbnailFile)
.size(200, 200)
.keepAspectRatio(true)
.outputFormat("jpg")
.toOutputStream(outputStream);
} else {
throw new IOException("썸네일 파일을 찾을 수 없습니다: " + thumbnailFile.getAbsolutePath());
}
}

private File getThumbnailFile(String profileImg) {
String thumbnailImgPath = profileImg.replace("profile_images", "profile_images/thumbnail");
String thumbnailFileName = "thumb_" + Paths.get(profileImg).getFileName().toString();
return new File(thumbnailImgPath.replace(Paths.get(profileImg).getFileName().toString(), thumbnailFileName));
}

private Path getThumbnailDirectory() throws IOException {
String thumbnailDirectory = fileRootPath + "/uploads/profile_images/thumbnail/";
Path thumbnailPath = Paths.get(thumbnailDirectory);

if (!Files.exists(thumbnailPath)) {
Files.createDirectories(thumbnailPath);
}

return thumbnailPath;
}
}
}
Binary file added src/main/resources/test.images/test1-avatar.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/main/resources/test.images/test2-avatar.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/main/resources/test.images/test3_avatar.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/main/resources/test.images/test4_avatar.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit e653162

Please sign in to comment.