[개발일지] 취미 커뮤니티 - 사용자 프로필 설정 및 변경

zwon·2023년 10월 27일
0

개발일지

목록 보기
23/23

사용자 프로필 설정 기능이다.
롬복 어노테이션들은 생략하고 포스팅하고자 한다.

User

public class User extends BaseTimeEntity {
  ...
  @OneToOne(mappedBy = "user", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
  private Profile profile;

  public void updateProfile(Profile newProfile) {
    this.profile = newProfile;
    newProfile.setUser(this);
  }
  ...
  • 회원 탈퇴 시 프로필 사진도 삭제되게 CascadeType.ALL로 설정하였다.

Profile

public class Profile {

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Long id;

  private String originFilename; // 업로드된 파일 이름
  private String storeFilename; // 저장한 파일명 ex) 132-5sdf-23451-1as.png -> UUID로 식별자 생성 + 확장자

  @OneToOne(fetch = FetchType.EAGER)
  @JoinColumn(name = "user_id")
  private User user;

  public void setUser(User user) {
    this.user = user;
  }
}

ImgController

@Controller
@RequiredArgsConstructor
public class ImgController {
  private final FileStore fileStore;
  private final FileService fileService;


  @PostMapping("/profile/update") // 프로필 사진 변경과 삭제
  public String profileUpdate(@ModelAttribute ProfileUpdateDto profileUpdateDto,
                              HttpSession session) throws IOException {
    User loginUser = (User) session.getAttribute("loginUser");

    if (profileUpdateDto.getProfile().isEmpty()) { 
      fileService.deleteBeforeProfile(loginUser.getNickname());
    } else {
      fileService.transferProfile(profileUpdateDto.getProfile(), loginUser.getNickname());
    }

    return "redirect:/my-page";
  }
  // 프로필 이미지 보여주기
  @ResponseBody
  @GetMapping("/profile/{filename}")
  public Resource downloadProfile(@PathVariable String filename)
      throws MalformedURLException {
    return new UrlResource("file:" + fileStore.getProfileFullPath(filename));
  }
}

FileStore

  • 첨부파일 업로드 포스팅과 별 차이 없다.
  • 추가된 부분만 정리하겠다.
  // 프로필 이미지
  @Value("${profile.dir}")
  private String profileDir;

  // 파일 저장 경로 Full
  public String getProfileFullPath(String filename){
    return profileDir + filename;
  }

  public Profile profileImgStore(MultipartFile multipartFile) throws IOException {
    if (multipartFile.isEmpty()){
      return null;
    }
    String originalFileName = multipartFile.getOriginalFilename();
    String ext = extractedExt(originalFileName);
    String storeFileName = createStoreFileName(ext);
    multipartFile.transferTo(new File(getProfileFullPath(storeFileName)));

    return Profile.builder()
        .originFilename(originalFileName)
        .storeFilename(storeFileName)
        .build();
  }
  • 첨부파일 구현과 똑같고 약간 다른거는 파일 경로 가져오는거나(따로 폴더를 생성함) ,, 말고는 없다.

FileService

@Service
@RequiredArgsConstructor
@Slf4j
public class FileService {
  private final FileStore fileStore;
  private final FileRepository fileRepository; 
  private final UserRepository userRepository;
  private final ProfileRepository profileRepository;


  // 프로필 이미지 변경
  @Transactional
  public Profile transferProfile(MultipartFile profile, String nickname) throws IOException {
    User user = userRepository.findUserByNickname(nickname).orElseThrow(IllegalArgumentException::new);
    Profile profileImg = fileStore.profileImgStore(profile);
    user.updateProfile(profileImg);
    return profileImg;
  }

  public void deleteBeforeProfile(String nickname) {
    User user = userRepository.findUserByNickname(nickname).orElseThrow(IllegalArgumentException::new);

    if (user.getProfile() != null) {
      Profile profile = user.getProfile();

      File imgFileOnDisk = new File(fileStore.getProfileFullPath(profile.getStoreFilename()));
      if (imgFileOnDisk.exists()) {
        imgFileOnDisk.delete();
      }
      user.updateProfile(null);
      profileRepository.delete(profile);
    }
  }

}
  • 이 부분도 첨부파일과는 별 차이 없다.

마이페이지

<img id="profile" th:src="|/profile/profile.png|" alt="프로필 사진" th:if="${loginUser.profile == null}">
<img th:src="|/profile/${loginUser.profile.getStoreFilename()}|" th:if="${loginUser.profile != null}"/>
  • 기본 이미지 같은 경우는 프로필을 저장하는 로컬 폴더에 저장해두고 사용자의 profile에 사용자가 저장판 프로필 사진이 없으면 기본 이미지가 보이도록 구현하였다ㅏ.

화면

  • 프로필을 설정하지 않은 경우

  • 프로필을 설정한 경우
  • 프로필 수정을 누르면 수정폼이 나오도록 자바스크립트 코드를 작성했다. (코드 생략)

  • 프로필 설정을 하면 다음과 같이 크루 상세 조회에서 크루원 정보를 나타낼 때 프로필 사진도 나오도록 했다.

  • 프로필 설정 안한 경우

크루의 Banner이미지도 사용자 프로필 설정하는 코드와 거의 매서드명이랑 반환타입만 다르고 동일한 방식으로 구현해서 크루의 배너 설정의 포스팅은 생략하겠다.


깨달음..

객체가 영속성 컨텍스트에 있는줄 알았는데 없어서 원하는대로 결과가 나오지 않는 일을 많이 겪으면서 영속성 컨텍스트의 동작과정을 잘 이해해야함을 너무나 깨달았다.

자꾸 session에서 로그인한 user를 가져오면서 사용하고있는데, 영속성 컨텍스트에 올라가있는줄 착각하고 개발을 하다보다 잘못된 방식으로 작성한 코드가 많으거같아서 하나씩 수정하고자한다.

나중에 OAuth로 로그인 구현 후 전체적인 리펙토링이 필요할꺼라고 생각하고있는데 계속 기능 개발하면서 수정해야겠다.

profile
Backend 관련 지식을 정리하는 Back과사전

0개의 댓글