diff --git a/src/main/java/com/xit/biz/cmm/service/ICmmFileService.java b/src/main/java/com/xit/biz/cmm/service/ICmmFileService.java new file mode 100644 index 0000000..da917f4 --- /dev/null +++ b/src/main/java/com/xit/biz/cmm/service/ICmmFileService.java @@ -0,0 +1,19 @@ +package com.xit.biz.cmm.service; + +import com.xit.biz.ctgy.entity.MinInfoBoard680; +import org.springframework.web.multipart.MultipartFile; + +import javax.annotation.Nonnull; +import java.util.List; + +/** + * @author Lim, Jong Uk (minuk926) + * @since 2021-07-16 + */ +public interface ICmmFileService { + MinInfoBoard680 findFiles(Long inCode); + + List saveFiles(@Nonnull MinInfoBoard680 minInfoBoard680, MultipartFile[] files); + + void removePublicBoardFile(Long inCode); +} diff --git a/src/main/java/com/xit/biz/cmm/service/impl/CmmFileService.java b/src/main/java/com/xit/biz/cmm/service/impl/CmmFileService.java new file mode 100644 index 0000000..ba672c1 --- /dev/null +++ b/src/main/java/com/xit/biz/cmm/service/impl/CmmFileService.java @@ -0,0 +1,177 @@ +package com.xit.biz.cmm.service.impl; + +import com.xit.biz.cmm.service.ICmmFileService; +import com.xit.biz.ctgy.CtgyConstants; +import com.xit.biz.ctgy.entity.MinInfoBoard680; +import com.xit.biz.ctgy.repository.IPublicBoardRepository; +import com.xit.core.constant.ErrorCode; +import com.xit.core.exception.CustomBaseException; +import com.xit.core.support.jpa.JpaUtil; +import com.xit.core.util.AssertUtils; +import com.xit.core.util.Checks; +import com.xit.core.util.DateUtil; +import io.jsonwebtoken.lang.Assert; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.StringUtils; +import org.springframework.web.multipart.MultipartFile; + +import javax.annotation.Nonnull; +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +@Slf4j +@Service +@RequiredArgsConstructor +public class CmmFileService implements ICmmFileService { + + @Value("${file.cmm.upload.root:c:/data/file/upload}") + private String rootPath; + + @Value("${file.cmm.upload.path:/kangnamSIM/simUpFile/}") + private String uploadPath; + + @Value("${file.cmm.upload.url}") + private String serviceUrl; + + @Value("${file.cmm.upload.allow.ext:}") + private String allowExt; + + @Value("${file.cmm.upload.max.size:1024}") + private long maxSize; + + private final IPublicBoardRepository repository; + + @Override + public MinInfoBoard680 findFiles(Long inCode) { + Assert.notNull(inCode, "대상 게시글[inCode]을 선택해 주세요."); + + return repository.findById(inCode).orElse(null); + } + + /** + * 파일 등록 + * 신규등록시는 CmmFileMst.fileMstId가 null, 변경시 not null + * 변경시 동일한 파일 이름이 존재하면 DB 및 해당 파일 삭제후 신규로 생성 + * + * @param entity MinInfoBoard680 + * @param files MultipartFile[] + * @return CmmFileMst + */ + @Override + @Transactional + public List saveFiles(@Nonnull MinInfoBoard680 entity, MultipartFile[] files) { + List entityList = new ArrayList<>(); + + if(files != null && files.length > 0){ + String makePath = File.separator + DateUtil.getToday(""); + + // 파일 경로 : upload root 제외 + String urlPath = this.uploadPath + makePath; + // 물리적인 파일 저장 위치 + String fileUploadPath = this.rootPath + urlPath; + File file = new File(fileUploadPath); + if(!file.exists()) file.mkdirs(); + + for(MultipartFile mf : files) { + if (!mf.isEmpty()) { + String orgFileName = ""; + try { + orgFileName = StringUtils.cleanPath(Objects.requireNonNull(mf.getOriginalFilename())); + MinInfoBoard680 savedEntity = null; + + // 파일 저장 && 전송 + if(Checks.isEmpty(entity.getInCode())) + savedEntity = new MinInfoBoard680(); + else + savedEntity = repository.findById(entity.getInCode()).orElseGet(MinInfoBoard680::new); + savedEntity.setInFilename(orgFileName); + savedEntity.setInFilesize(mf.getSize()); + savedEntity.setInFileurl(serviceUrl + urlPath); + setEntity(savedEntity, entity); + JpaUtil.saveIfNullId(entity.getInCode(), repository, savedEntity); + + entityList.add(savedEntity); + mf.transferTo(new File(fileUploadPath + File.separator + orgFileName)); + + // inputStream을 가져와 + // copyOfLocation (저장위치)로 파일을 쓴다. + // copy의 옵션은 기존에 존재하면 REPLACE(대체한다), 오버라이딩 한다 + //Files.copy(multipartFile.getInputStream(), copyOfLocation, StandardCopyOption.REPLACE_EXISTING); + + } catch (IOException e) { + String errMsg = String.format("File Upload Error :: %s", orgFileName); + //TODO : 에러처리 + //return RestError.of(String.format("File Upload Error :: %s", orgFileName)); + AssertUtils.isTrue(false, String.format("File Upload Error :: %s", orgFileName)); + } + } + } + }else{ + MinInfoBoard680 savedEntity = null; + if(Checks.isEmpty(entity.getInCode())) + savedEntity = new MinInfoBoard680(); + else + savedEntity = repository.findById(entity.getInCode()).orElseGet(MinInfoBoard680::new); + + setEntity(savedEntity, entity); + JpaUtil.saveIfNullId(entity.getInCode(), repository, savedEntity); + } + return entityList; + } + + @Override + @Transactional + public void removePublicBoardFile(Long inCode) { + + MinInfoBoard680 savedEntity = repository.findById(inCode).orElseThrow(() -> new CustomBaseException(ErrorCode.NOT_FOUND)); + repository.delete(savedEntity); + + // 정보 삭제후 파일 삭제 : 에러 발생시 skip + if(Checks.isNotEmpty(savedEntity.getInFilename())){ + String absFile = rootPath + savedEntity.getInFileurl().split(serviceUrl)[1]+File.separator + savedEntity.getInFilename(); + try { + File file = new File(absFile); + if (Checks.isNotEmpty(file) && file.exists()) file.delete(); + }catch(Exception e){ + // + } + } + + } + + private void setEntity(MinInfoBoard680 savedEntity, MinInfoBoard680 entity){ + savedEntity.setInBgubun(CtgyConstants.PublicBoard.GUBUN.getCode()); + savedEntity.setInDept(entity.getInDept()); + savedEntity.setInTitle(entity.getInTitle()); + savedEntity.setInContents(entity.getInContents()); + + if(Checks.isEmpty(entity.getInCode())) { + savedEntity.setInCode(repository.getInCodeByInBgubun()); + savedEntity.setInContentno(savedEntity.getInCode()); + } + } +} + + + +/* + // File.seperator 는 OS종속적이다. + // Spring에서 제공하는 cleanPath()를 통해서 ../ 내부 점들에 대해서 사용을 억제한다 + Path copyOfLocation = Paths.get(uploadDir + File.separator + StringUtils.cleanPath(multipartFile.getOriginalFilename())); + try { + // inputStream을 가져와서 + // copyOfLocation (저장위치)로 파일을 쓴다. + // copy의 옵션은 기존에 존재하면 REPLACE(대체한다), 오버라이딩 한다 + Files.copy(multipartFile.getInputStream(), copyOfLocation, StandardCopyOption.REPLACE_EXISTING); + } catch (IOException e) { + e.printStackTrace(); + throw new FileStorageException("Could not store file : " + multipartFile.getOriginalFilename()); + } +*/ diff --git a/src/main/java/com/xit/biz/ctgy/controller/ResidentController.java b/src/main/java/com/xit/biz/ctgy/controller/ResidentController.java index 8e1659d..0b73fd8 100644 --- a/src/main/java/com/xit/biz/ctgy/controller/ResidentController.java +++ b/src/main/java/com/xit/biz/ctgy/controller/ResidentController.java @@ -1,9 +1,7 @@ package com.xit.biz.ctgy.controller; import com.xit.biz.ctgy.dto.GnRecallScDto; -import com.xit.biz.ctgy.dto.MinInfoBoard680Dto; import com.xit.biz.ctgy.dto.struct.GnRecallScMapstruct; -import com.xit.biz.ctgy.entity.MinInfoBoard680; import com.xit.biz.ctgy.service.IResidentService; import com.xit.core.api.IRestResponse; import com.xit.core.api.RestResponse;