💻 뚝딱뚝딱/북북클럽

[개발일지 #013] 회원 프로필 사진 등록 기능 구현

뚜루리 2025. 4. 24. 16:56
728x90
320x100

🎯 오늘의 목표

  • 회원 프로필 사진 등록 기능 구현

⚙️ 진행한 작업

  • 회원 프로필 사진 등록 기능 구현

🛠️ 개발내용

✅ 개발 흐름

  • 로컬에 프로필 사진을 저장할 수 있도록 구현하고 추후 AWS S3와 같은 스토리지에 저장되도록 전환할 예정.

 

📌  User 엔티티 필드 추가 (User.java)

@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor
@EntityListeners(AuditingEntityListener.class)
public class User {
	
    //생략//
    
    @Setter
    @Column(length = 1000)
    private String profileImageUrl;

    //생략//

}

 

📌  ProfileImageService.java 생성

  • 확장자 및 파일 제한 유효성검사 추가
@Service
public class ProfileImageService {

    private static final String PROFILE_IMAGE_DIR = "uploads/profile-images";
    private static final String BASE_URL = "/images/profile-images/";

    public String store(MultipartFile file, Long userId) {

        // 확장자 검사
        if (!file.getContentType().startsWith("image/")) {
            throw new IllegalArgumentException("이미지 파일만 업로드 가능합니다.");
        }
        // 파일 크기 제한 (5MB 이하)
        if (file.getSize() > 5 * 1024 * 1024) {
            throw new IllegalArgumentException("파일 용량은 5MB 이하만 가능합니다.");
        }

        String filename = UUID.randomUUID() + "_" + file.getOriginalFilename();

        Path dirPath = Paths.get(PROFILE_IMAGE_DIR);
        try {
            if (!Files.exists(dirPath)) {
                Files.createDirectories(dirPath);
            }
            Path filePath = dirPath.resolve(filename);
            try (InputStream in = file.getInputStream()) {
                Files.copy(in, filePath, StandardCopyOption.REPLACE_EXISTING);
            }
        } catch (IOException e) {
            throw new RuntimeException("파일 저장 실패", e);
        }

        return BASE_URL + filename;
    }
}

 

 

📌  application.yml 추가

  • 기본 프로필 이미지를 지정하기 위한 설정
custom:
  user:
    default-profile-image: /images/profile-images/default.jpg

 

📌  UserService.java 수정

@Service
@RequiredArgsConstructor
public class UserService {
	
    //생략//
    
    @Value("${custom.user.default-profile-image}")
    private String defaultProfileImageUrl;

    //생략//
    
    @Transactional
    public void updateProfileImage(Long userId, String imageUrl) {
        User user = userRepository.findById(userId)
                .orElseThrow(() -> new IllegalArgumentException("해당 유저가 없습니다."));
        user.setProfileImageUrl(imageUrl);
    }

}

 

📌  UserController.java 수정

@RestController
@RequiredArgsConstructor
@RequestMapping("/api/users")
public class UserController {

    //생략//
    
    private final ProfileImageService profileImageService;
   
	//생략//
    
    @PostMapping("/{userId}/profile-image")
    public ApiResponse<String> uploadProfileImage(@AuthenticationPrincipal CustomUserDetails userDetails,
                                                  @RequestParam("file") MultipartFile file) {
        Long userId = userDetails.getUser().getId();
        String imageUrl = profileImageService.store(file, userId);
        userService.updateProfileImage(userId, imageUrl);
        return ApiResponse.success(imageUrl);
    }
}
  • uploadProfileImage() 메서드 추가
  • @AuthenticationPrincipal CustomUserDetails userDetails 인증 받은 아이디에 대한 프로필만 수정할 수 있도록 함.

 

 

 


[Postman을 활용한 테스트]

먼저 로그인해서 토큰을 발급 받은 후에 진행해야 함.

 

POST http://localhost:8080/api/users/{userId}/profile-image
Authorization: Bearer {accessToken}
Type: form-data
Key : file 
Value : 이미지 파일 선택

 

 

 

데이터베이스를 확인해보면 디폴트 이미지였다가 변경된 이미지로 바뀐것을 알 수 있음.

728x90
320x100