우선 User와 1대1질문 그리고 1대1질문 첨부파일 엔티티를 만들어줍니다.
각 엔티티에 CascadeType.Remove를 추가해서 user가 회원탈퇴할 때 1대1질문이나 파일들이 같이 삭제될 수 있도록 만들어줍니다.
public class User {
@Id
@Column(name = "USER_UUID")
private String userUuid;
@JsonIgnore
private String password;
@OneToMany(mappedBy = "user", cascade = {CascadeType.REMOVE},fetch = FetchType.LAZY)
@JsonIgnoreProperties({"user"})
private List<Inquiry> inquiry;
@Column(name = "CREATE_DATE")
private LocalDateTime createDate;
}
public class Inquiry {
@Id
@SequenceGenerator(name = "INQUIRY_SEQ_GENERATOR", sequenceName = "INQUIRY_SEQUENCE", allocationSize = 1, initialValue = 20000)
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "INQUIRY_SEQ_GENERATOR")
@Column(name = "INQUIRY_ID")
private Long id;
@JsonIgnoreProperties({"inquiry"})
@JoinColumn(name = "USER_UUID")
@ManyToOne
private User user;
@JsonIgnoreProperties({"inquiry"})
@OneToMany(mappedBy = "inquiry", cascade = {CascadeType.REMOVE}, fetch = FetchType.LAZY)
private List<Inquiry_file> inquiry_file;
}
public class Inquiry_file {
@Id
@SequenceGenerator(name = "INQUIRY_FILE_SEQ_GENERATOR", sequenceName = "INQUIRY_FILE_SEQUENCE", allocationSize = 1, initialValue = 20000)
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "INQUIRY_FILE_SEQ_GENERATOR")
@Column(name = "INQUIRY_FILE_ID")
private Long id;
@Column(name = "INQUIRY_FILE_URL")
private String url;
@Column(name = "INQUIRY_FILE_TYPE")
private String type;
@Column(name = "INQUIRY_FILE_NAME")
private String name;
@Column(name = "INQUIRY_FILE_SIZE")
private Long size;
@ManyToOne
@JoinColumn(name = "INQUIRY_ID")
@JsonIgnoreProperties({"inquiry_file"})
private Inquiry inquiry;
}
@Transactional
public Inquiry createInquiry(CreateInquiryDto createInquiryDto, PrincipalDetails principalDetails) {
List<MultipartFile> fileList = createInquiryDto.getFileList();
Optional<User> userOptional = userRepository.findByEmail(principalDetails.getEmail());
User userEntity= userOptional.get();
Inquiry inquiry =
Inquiry.builder()
.user(userEntity)
.content(createInquiryDto.getContent())
.status(createInquiryDto.getStatus())
.title(createInquiryDto.getTitle())
.type(createInquiryDto.getType())
.build();
inquiryRepository.save(inquiry);
for(int i=0; i<createInquiryDto.getFileList().size(); i++){
String fileName = UUID.randomUUID().toString() + "_" + createInquiryDto.getFileList().get(i).getOriginalFilename();
Path imageFilePath = Paths.get(uploadFolder + fileName);
Inquiry_file inquiry_file = Inquiry_file.builder()
.name(createInquiryDto.getFileList().get(i).getOriginalFilename().replaceFirst("[.][^.]+$", "")) // 확장자 지우기
.size(createInquiryDto.getFileList().get(i).getSize())
.url(fileName)
.type(createInquiryDto.getFileList().get(i).getContentType())
.inquiry(inquiry)
.build();
try {
Files.write(imageFilePath, createInquiryDto.getFileList().get(i).getBytes());
} catch (Exception e) {
e.printStackTrace();
}
inquiryFileRepository.save(inquiry_file);
}
return inquiry;
}
DTO로 전달된 inquriy는 그대로 save하고 filelist size만큼 for문을 돌면서 inquiry_file table에 row를 하나씩 쌓아줍니다. 이미지 이름이 중복되었을 경우, 덮어써질 수 도 있으므로 앞에 UuId를 붙여서 만들어줍니다. 또한 프론트에서 이미지 이름을 보여주므로 확장자를 뗀 순수 이미지 이름만을 따로 칼럼으로 저장합니다.
@GetMapping(value="/inquiry/attachment")
public ResponseEntity<Resource> attachment(@Param("filename") String filename){
String temp = path;
Path filePath = null;
filePath = Paths.get(temp+filename);
HttpHeaders header = new HttpHeaders();
Tika tika = new Tika();
String mimeType;
try {
mimeType = tika.detect(filePath);
header.add("Content-Type", mimeType);
} catch (Exception e) {
}
Resource resource = new FileSystemResource(filePath);
return new ResponseEntity<Resource>(resource,header, HttpStatus.OK);
}
아래 포스트맨으로 잘 나오는것을 확인할 수 있습니다
이때 동영상 파일이 스프링 부트에서 약 1mb로 제한이 걸려있는데, application.properties 아래 설정으로 해결이 가능합니다.
spring.servlet.multipart.maxFileSize=8MB
spring.servlet.multipart.maxRequestSize=8MB
1대1 문의 수정 로직도 create랑 비슷합니다. 단지 해당 질문이 유저가 만든 질문인지 한번 확인하고 기존 질문의 첨부파일은 삭제하고 새로 만들어주면 됩니다.
이 때, 바뀌는 부분만 프론트가 보내주는게 아니라 전체 데이터를 다시 보내주어야합니다.
@Transactional
public String modify(@AuthenticationPrincipal PrincipalDetails principalDetails, ModifyInquiryDto modifyInquiryDto ) {
List<Long> inquiryIdList = inquiryRepository.findAllIdByUserUuid(principalDetails.getUserUuid());
if (!inquiryIdList.contains(modifyInquiryDto.getId())) {
return "유저가 생성한 질문이 아닙니다.";
}
Optional<UserMaster> userMasterOptional = userRepository.findByUserUuid(principalDetails.getUserUuid());
UserMaster userMaster = userMasterOptional.get();
Optional<Inquiry> inquiryOptional = inquiryRepository.findByInquiryId(modifyInquiryDto.getId());
Inquiry inquiry = inquiryOptional.get();
inquiry.setUserMaster(userMaster);
// 기존의 파일 스토리지에서 delete
for(int i =0; i < inquiry.getInquiry_file().size(); i++) {
String url = inquiry.getInquiry_file().get(i).getUrl();
Path filePath = Paths.get(uploadFolder + url);
try {
Files.delete(filePath);
} catch (NoSuchFileException e) {
System.out.println("삭제하려는 파일이 없습니다");
} catch (IOException e) {
e.printStackTrace();
}
}
// 새로 만들기
for(int i=0; i<modifyInquiryDto.getFileList().size(); i++){
String fileName = UUID.randomUUID().toString() + "_" + modifyInquiryDto.getFileList().get(i).getOriginalFilename();
Path imageFilePath = Paths.get(uploadFolder + fileName);
Inquiry_file inquiry_file = Inquiry_file.builder()
.name(modifyInquiryDto.getFileList().get(i).getOriginalFilename().replaceFirst("[.][^.]+$", ""))
.size(modifyInquiryDto.getFileList().get(i).getSize())
.url(fileName)
.type(modifyInquiryDto.getFileList().get(i).getContentType())
.inquiry(inquiry)
.build();
try {
Files.write(imageFilePath, modifyInquiryDto.getFileList().get(i).getBytes());
} catch (Exception e) {
e.printStackTrace();
}
inquiryFileRepository.save(inquiry_file);
}
return "True";
}