💻 뚝딱뚝딱/북북클럽
[개발일지 #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