<aside> 📝 - 게시글 작성 API에 룰 기반 파일 업로드 적용
KISA의 ‘소프트웨어 개발 보안가이드’에 따라 화이트 리스트 확장자만 파일 업로드 허용
화이트 리스트 확장자 : gif, jpg, jpeg, png
</aside>
⌨ 코드 : 서비스 계층
@RestController
@RequestMapping("posts")
@RequiredArgsConstructor
public class PostController {
private final PostService postService;
/**
*** 6. 게시글 작성 API**
* [POST] /posts/:userId
* @return BaseResponse()
*/
@PostMapping("/{userIdx}")
public BasicResponse createProduct(@PathVariable("userIdx") Long userIdx,
@RequestPart(value = "content", required = false) String content,
@RequestPart(value = "imageNumberlist", required = false) List<Integer> imageNumberlist,
@RequestPart(value = "multipartFile", required = false) List<MultipartFile> multipartFile) {
**/* 유효성 검사 구현부 */**
if(content == null || content.length() > 1000){
return new BasicResponse(REQ_ERROR_INVALID_POSTS_CONTENT);
}
if(imageNumber == null || imageNumber.size() > 10 ){
return new BasicResponse(REQ_ERROR_INVALID_POSTS_IMAGE_NUMBER);
}
if(multipartFile.isEmpty() || multipartFile.size() > 10) {
return new BasicResponse(REQ_ERROR_INVALID_POSTS_IMAGE_FILE);
}
if(imageNumber.size() != multipartFile.size() ) {
return new BasicResponse(REQ_ERROR_DIFFERENT_SIZE_IMAGE_FILE_AND_IMAGE_NUMBER);
}
for(int i=0; i<multipartFile.size(); i++){
String fileExt = multipartFile.get(i).getOriginalFilename().substring(multipartFile.get(i).getOriginalFilename().lastIndexOf(".")+1).toLowerCase();
**//이미지 파일의 확장자가 git, jpg, jpeg, png가 아니면 예외 발생**
if(! "gif".equals(fileExt) && ! "jpg".equals(fileExt) && ! "jpeg".equals(fileExt) && ! "png".equals(fileExt)){
return new BasicResponse(REQ_ERROR_INVALID_POSTS_IMAGE_FILE_EXTENSION);
}
//이미지 파일 크기 제한 (10MB)
if(multipartFile.get(i).getSize() > 10485760){
return new BasicResponse(REQ_ERROR_INVALID_POSTS_IMAGE_FILE_SIZE);
}
}
/* 유효성 검사 구현 끝 */
try {
//DB에 게시글 등록
String responseMessage = postService.createProduct(userIdx, content, imageNumberlist, multipartFile);
return new BasicResponse(responseMessage);
} catch (BasicException exception) {
return new BasicResponse(exception.getStatus());
}
}
}
🖥️ API 실행 결과
<aside> 📝 - 이미지 파일명에 UUID v4를 적용해 파일명 중복 방지
</aside>
⌨ 코드 : 서비스 계층
@Service
@RequiredArgsConstructor
public class PostService {
private final PostDao postDao;
private final PostImageDao postImageDao;
private final UserDao userDao;
private final AwsS3Service awsS3Service;
**/* 6. 게시글 작성 */**
@Transactional(rollbackFor = {Exception.class})
public String createProduct(Long userIdX, String content, List<Integer> imageNumberlist, List<MultipartFile> multipartFile ) throws BasicException {
//DB에 게시글 등록 (내용 ,이미지, 이미지 번호)
try{
User Writer = userDao.findByIdx(userIdX);
//post DB에 저장 (생략)
****
//postImage DB에 저장
**** List<PostImage> postImageListCreation = new ArrayList<>();
List<String> UUID_fileNameList = new ArrayList<>();;
for(int i=0; i<imageNumber.size(); i++){
//UUID가 적용된 이미지 파일명 리턴
UUID_fileNameList.add(awsS3Service.createFileNameToDB(multipartFile.get(i))); //UUID.randomUUID().toString() + "-" + multipartFile.get(i).getOriginalFilename(); //이미지 파일명에 UUID 적용
PostImage postImageCreation = PostImage.builder()
.image(Secret.AWS_S3_CONNECT_URL+UUID_fileNameList.get(i))
.imageNumber(imageNumberlist.get(i))
.post(postCreation)
.build();
postImageListCreation.add(postImageCreation);
}
postImageDao.saveAll(postImageListCreation);
return "게시글 등록 성공";
} catch (Exception exception) {
throw new BasicException(DATABASE_ERROR_CREATE_POST); //게시글 등록 실패
}
}
}
@Service
@RequiredArgsConstructor
public class AwsS3Service {
**//UUID를 포함하는 이미지 파일명 리턴**
public String createFileNameToDB(MultipartFile imageFile) {
String UUID_fileName = UUID.randomUUID().toString() + "." + fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase(); //UUID+파일 확장자
return UUID_fileName; //UUID 파일명 리턴
}
}