Java Spring Boot 005-7 | CRUD 복습 (2)

Yunny.Log ·2022년 3월 6일
0

Spring Boot

목록 보기
32/80
post-thumbnail
  • crud(1) 에 사진 파일을 추가할 것

MediaController (test 용)

@RestController
@RequestMapping("media")
public class MediaController {
    private static final Logger logger = LoggerFactory.getLogger(MediaController.class);

    @PostMapping("test")
    public void uploadMedia(
            @RequestParam("file")MultipartFile file
            ) throws IOException {
        String basePath="./media"; //저장될 기본 경로
        File directory = new File(basePath);
        if (!directory.exists()) directory.mkdir();
        Path newFilePath = Path.of(basePath, file.getOriginalFilename());
        try{
            file.transferTo(newFilePath);
        } catch (IOException e){
            e.printStackTrace();
        }
    }

service 패키지 만들기, ModelService 인터페이스 정의

public interface ModelService {
    void saveFile(MultipartFile file);
    void saveFileBulk(MultipartFile[] files);
    byte[] getFileAsBytes(String resourcePath);
}

LocalMediaService

public class LocalMediaService implements MedialService{
    @Override
    public void saveFile(MultipartFile file) {
    }
    @Override
    public void saveFileBulk(MultipartFile[] files) {

    }
    @Override
    public byte[] getFileAsBytes(String resourcePath) {
        return new byte[0];
    }
}
  • save 됐을 때 파일을 어디서 불러올 수 있는지 알려줄 애 필요
  • 이를 위해 media dto 만들어주기

MediaDescriptorDto

public class MediaDescriptorDto {
    private Integer status;
    private String message;
    private String originalName;
    private String resourcePath;

=> Dto 정의해주었으니깐 Service에서도 dto 다루도록 수정

MediaService

public interface MedialService {
    MediaDescriptorDto saveFile(MultipartFile file);
    Collection<MediaDescriptorDto> saveFileBulk(MultipartFile[] files);
    byte[] getFileAsBytes(String resourcePath);
}

LocalMediaService 도 위에 달라진 메소드들에 새롭게 오버라이드
LocalMediaService (+)

@Service
public class LocalMediaService implements MedialService{

    private static final Logger logger = LoggerFactory.getLogger(LocalMediaService.class);
    //저장 경로 위해 추가
    private final String basePath = "./media";

    @Override
    public MediaDescriptorDto saveFile(MultipartFile file) {
        //미디어 파일이 하나만 들어오는 경우
        return this.saveToDir(file);
    }

    @Override
    public Collection<MediaDescriptorDto> saveFileBulk(MultipartFile[] files) {
        //미디어 파일이 다수로 들어오는 경우
        Collection<MediaDescriptorDto> resultList = new ArrayList<>();
        for(MultipartFile file : files){
            resultList.add(this.saveToDir(file));
        }
        return resultList;
    }

    @Override
    public byte[] getFileAsBytes(String resourcePath) {
        return new byte[0];
    }

    private MediaDescriptorDto saveToDir(MultipartFile file){
        MediaDescriptorDto dto = new MediaDescriptorDto();
        dto.setStatus(200);
        dto.setOriginalName(file.getOriginalFilename());

        try{
            LocalDateTime now = LocalDateTime.now();
            //날짜별로 파일을 나누기 위해 시간 받아오기
            //now로 디렉토리를 생성하고, 거기에다 파일 저장할 것
            String targetDir = Path.of(
                    basePath,
                    now.format(DateTimeFormatter.ISO_DATE)
            ).toString();
            //현재 시간을 어떤 형식으로 나타내줄지 정하는 것
            String newFileName = now.format(DateTimeFormatter.ofPattern("HHmmss"))
                    + "_"
                    //업로드한 파일의 이름을 구한다.
                    + file.getOriginalFilename();
            File dirNow = new File(targetDir);
            if(!dirNow.exists()) dirNow.mkdir();//디렉토리 없으면 만들기

            //업로드한 파일 데이터를 지정한 파일에 저장
            // MultipartFile.transferTo() 메서드를 사용
            file.transferTo(Path.of(
                    targetDir,
                    newFileName
            ));

            dto.setResourcePath(Path.of(
                    targetDir,
                    newFileName
            ).toString().substring(1));

            return dto;

        } catch (IOException e) {
            e.printStackTrace();
            logger.error(e.getMessage());
            dto.setMessage("failed");
            dto.setStatus(500);
            return dto;
        }

    }
}

MediaController

  • 서비스에서 구현해서 데이터에 데려놓은 애들을 데려다가 이제 dispatcher에게 데려다줘야해
@RestController
@RequestMapping("media")
public class MediaController {
    private static final Logger logger = LoggerFactory.getLogger(MediaController.class);
    private final MedialService medialService;

    public MediaController(MedialService  medialService){
        this.medialService=medialService;
    }

    @PostMapping("upload")
    public ResponseEntity<MediaDescriptorDto> uploadMedia(
            @RequestParam("file") MultipartFile file
    ){
        MediaDescriptorDto dto = this.medialService.saveFile(file);
        return ResponseEntity
                .status(dto.getStatus())
                .body(dto);
    }

    @PostMapping("upload-bulk")
    public ResponseEntity<Collection<MediaDescriptorDto>> uploadMediaBulk(
            @RequestParam("file") MultipartFile[] files
            //이름 동일한게 여러개 들어오면 알아서 배열로 인식
    ){
        return ResponseEntity
                .status(HttpStatus.MULTI_STATUS)
                .body(this.medialService.saveFileBulk(files));
    }
}

  • media 디렉토리를 만들어주고 포스트맨 해주기

  • 위와 같이 적절한 폴더, 파일명으로 저장됨

  • 이제 get으로 가져왔을 때 binary로 보이는게 아닌 사진 파일로 보이도록 코드 refactor

MediaController

  • 가져오기 위한 메소드 추가 구현
    @GetMapping("**")
    public byte[] staticLikeEndpoint(
            HttpServletRequest request, HttpServletResponse response
    ){
        response.setHeader("Content-type", MediaType.IMAGE_PNG_VALUE);
        //미디어타입과 같은 확장자 정해줄 때 잘 정해줘야 함
        return this.medialService.getFileAsBytes(request.getRequestURI().split("media")[1]);
    }

MediaService

  • getFileAsBytes 메소드 구현 덜해줬기 때문에 얘 구현 마무리
    @Override
    public byte[] getFileAsBytes(String resourcePath) {
        try{
            return Files.readAllBytes(Path.of(basePath, resourcePath));
        } catch (IOException e) {
            e.printStackTrace();
            //읽는 과정에서 에러
            throw new ResponseStatusException(HttpStatus.NOT_FOUND);
        }
    }

  • 근데 데려오면 이렇게 출력됨,
  • content 타입을 이미지로 설정안해줘서
  • 우린 사진을 원하기 때문에 코드 다시 수정
  • response를 받을 때 image type으로 받을 수 있게 하기

MediaController

    @GetMapping("**")
    public ResponseEntity<byte[]> staticLikeEndpoint(
            HttpServletRequest request){
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.IMAGE_PNG);
        //미디어타입과 같은 확장자 정해줄 때 잘 정해줘야 함
        return new ResponseEntity<>(
                this.medialService.getFileAsBytes(request.getRequestURI().split("media")[1]),
                headers,
                HttpStatus.OK
                );
    }


(+)jsb 파일 업로드 설명 추가

private FileOutputStream fos = null;
        
public String uploadResult(@RequestParam("selFile") MultipartFile mFile) throws Exception, IOException {
    String fileExtension = mFile.getOriginalFilename().substring(mFile.getOriginalFilename().lastIndexOf("."));
    String storedFileName = UUID.randomUUID().toString().replaceAll("-",  "") + fileExtension;
    String filePath = "C:\\eclipse\\workspace\\memPid\\src\\main\\webapp\\resources\\";
    File file = new File(filePath + storedFileName);
    //첫 번째 방법, MultipatrFile클래스의 transferTo()를 사용하여 업로드하려는 파일을 특정파일로 저장
    //MultipartFile.transferTo(File file) - Byte형태의 데이터를 File객체에 설정한 파일 경로에 전송한다.
    mFile.transferTo(file);
    
    //두 번째 방법, MultipatrFile클래스의 getBytes()로 multipartFile의 데이터를 바이트배열로 추출한 후, FileOutputStream클래스의 write()로 파일을 저장
    try {
        //MultipatrFile클래스의 getBytes()를 사용해서 multipartFile의 데이터를 바이트배열로 추출
        byte fileData[] = mFile.getBytes();
        fos = new FileOutputStream(filePath + mFile.getOriginalFilename());
        //FileOutputStream클래스의 write()로 파일을 filePath에 저장
        fos.write(fileData);
    } catch (Exception e) {
        e.printStackTrace();
    }finally {
        if(fos != null) {
            fos.close();
        }
    }
    return "upload_result";
}

화면

<!--화면단(JSP)-->
<form action="submitReport1" method="POST" enctype="multipart/form-data">
            학번 : <input type="text" name="studentNumber" /><br/>
            리포트 파일 : <input type="file" name="reportFile" /><br/>
              <input type="submit" />
</form>

서비스

String filePath    ,                //파일을 저장할 경로
String originalFile,            //원본 파일명
String originalFileExtension,    //원본파일의 확장자명
String storedFileName,            //filePath/DB에 저장할 파일명
MultipartFile multipartFile,    //화면단에서 전달되는 파일 받을 객체
File file    //java.io.File        //전달받은 파일을 저장할 때 사용하는 객체
 
String filePath =
//            "C:\\Users\\FUTURE\\Documents\\hkedu_project\\final_project\\src\\main\\webapp\\WEB-INF\\resource\\";
            "C:\\Users\\HKEDU\\Documents\\hkedu_project\\final_project\\src\\main\\webapp\\WEB-INF\\resource\\";
//            "C:\\Users\\HKEDU\\Documents\\hkedu_project\\final_project\\src\\main\\webapp\\WEB-INF\\resource\\";
//            "C:\\Users\\hotelalpha\\Documents\\hkedu_project\\final_project\\src\\main\\webapp\\WEB-INF\\resource\\";
File file = New File(filePath);

화면단에서 업로드한 파일(foodImage)을 전달받아서 지정 경로에 저장하고, 파일의 정보를 DB에 저장하는 방법

  1. command객체(FoodRegCommand) 사용
MultipartFile multipartFile = foodRegCommand.getFoodImage();
//*커맨드객체 사용 시 커맨드객체 내의 필드타입은 MultipartFile이어야한다.
//private MultipartFile report;
  1. @RequestParam 어노테이션과 MultipartFile 타입의 파라미터를 이용
public String submitReport1(@RequestParam("studentNumber") String studentNumber, @RequestParam("report") MultipartFile multipartFile) throws IOException {    
//command객체가 아닌 request로 submit한 값 받아오기     
//studentNumber - submissionForm의 속성 name
  1. MultipartHttpServletRequest를 이용한 업로드 파일 접근
public String submitReport2(MultipartHttpServletRequest request) {
        String studentNumber = request.getParameter("studentNumber");
        MultipartFile report = request.getFile("report");
//파일명
String originalFile = multipartFile.getOriginalFilename();
//파일명 중 확장자만 추출
//fileuploadtest.doc
//lastIndexOf(".") = 14(index는 0번부터)
//substring(14) = .doc
String  originalFileExtension = originalFile.substring(originalFile.lastIndexOf("."));
//업무에서 사용하는 리눅스, UNIX는 한글지원이 안 되는 운영체제 
//파일업로드시 파일명은 ASCII코드로 저장되므로, 한글명으로 저장 필요
//UUID클래스 - (특수문자를 포함한)문자를 랜덤으로 생성                    "-"라면 생략으로 대체
String  storedFileName = UUID.randomUUID().toString().replaceAll("-", "") + originalFileExtension;
//파일을 저장하기 위한 File객체 생성
//java.io.File
File file = new File(filePath + storedFileName);
//업로드요청으로 전달받은 파일을 위에서 설정한 특정 경로에 특정 파일명으로 저장
multiFile.transferTo(file);
//전달받아 저장한 파일의 이름 및 저장된 경로, 용량을 DB에 저장
 foodReview = new FoodReview();
                foodReview.setMemberEmail(memberEmail);
                foodReview.setFoodNo(foodReviewWriteCommand.getFoodNo());
                foodReview.setSellerEmail(foodReviewWriteCommand.getSellerEmail());
                ...
                foodReview.setFoodReviewSize(multiFile.getSize());
                foodReview.setFoodReviewOriginal(originalFile);
                foodReview.setFoodReviewStored(storedFileName);
                
                int k = foodRepository.insertFoodReview(foodReview);

0개의 댓글