본문 바로가기

JAVA/Spring

[JAVA] 이미지 URL 변환 후 화면에 보여주기(가져오기) (feat.미리보기)

 

 

 

나는 클라이언트에서 특정 url 로 이미지를 요청하면 이미지를 보내주는 방식을 만들고 싶었다.

Vue Axios 와 REST API, InputStream, URL.createObjectURL() 을(를) 이용하였다.

 

 

1. JAVA Spring Server

 

1) Controller

 

@GetMapping(path = "image/{imgId}/show")
public void getImageFileById(@PathVariable(name = "imgId") String imgId, HttpServletResponse response) throws IOException {
    service.getImageFileById(imgId, response);
}

 

 

요청 받을 url path 설정해주고, url에 따라서 @PathVariable 을 받아주면 된다.

나는 ID 값을 받아서 사용할거라 ID만 받았다.

 

 

2) Service

 

public void getImageFileById(String imgId, HttpServletResponse response) throws IOException {
    AttachFile file = fileQuery.getAttachFileList(imgId);
    
    if (file != null) {
        String atcFileOid = file.getAtcOid();
        String filePath = prop.getUploadDir() + file.getFileRestoNm();

        try (InputStream inputStream = new FileInputStream(filePath)) {
            IOUtils.copy(inputStream, response.getOutputStream());
            response.setContentType(MediaType.IMAGE_JPEG_VALUE); // 이미지 타입에 따라 변경
            response.setHeader("Content-Disposition", "inline; filename=" + "/" + atcFileOid);
        } catch (IOException e) {
            response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
            e.printStackTrace();
        }
    } else {
        response.setStatus(HttpStatus.NOT_FOUND.value());
    }
}

 

 

DB상에 존재하는 해당 파일 정보를 InputStream으로 읽어오고,

response.getOutputStream() 을 통해 내보낸다.

 

response.setContentType()은 전달할 이미지 타입을 설정,

response.setHeader()는 header 값을 설정한다.

 

사실 response 는 Controller 에서 처리했어야 하는데 귀찮아서 service에서 몰아서 끝냈다.

이렇게 하면 안 좋다. (추후 수정할 예정)

 

 

2. Vue.js Client

 

const loadImage = async (imgId) => {
  const imageUrl = await getImageUrl(imgId);
  image.value.url = imageUrl;
};

const getImageUrl = async (imgId) => {
  try {
    const response =
      await $axios
        .get(util.format(....getImageFileById, imgId), {
          responseType: 'arraybuffer',
      });
    const blob = new Blob([response.data], { type: response.headers['content-type'] });
    const imageUrl = URL.createObjectURL(blob);
    return imageUrl;
  } catch (err) {
    console.error(err);
    return null;
  }
};

 

 

loadImage() 를 호출하면 axios 를 통해 서버로 이미지를 요청한다.

전달 받은 response 를 blob 형태로 변환한다.

 

Blob 이란?
javascript에서 이미지, 사운드, 비디오 같은 멀티 데이터를 다룰 때 사용한다.

 

 

blob 형태로 변환한 데이터를 URL.createObjectUrl() 로 url을 생성해준다.

URL.createObjectURL() 메소드는 주어진 객체를 가리키는 URL을 DOMString으로 변환하는 기능을 한다.

해당 url은 window 창이 사라지면 함께 사라지고, 다른 window에서 재사용이 불가능하다.

한 마디로 미리보기에 사용하기 적합하다. 호출 시 마다 새로운 url이 생성된다.

 

 

 

 

 

 

호출하면 우측 사진처럼 미리보기가 나온다.

 

 

 

+

 

 

서버에서 Response를 Controller로 옮겨서 소스를 수정했다.

 

 

 

1) Controller

 

@GetMapping(path = "image/{imgId}/show")
public void getImageFileById(@PathVariable(name = "imgId") String imgId, HttpServletResponse response) throws IOException {
    InputStream inputStream = service.getImageFileById(imgId);

    if(inputStream != null) {
        String atcFileOid = service.getAtcFileOid(imgId);
        IOUtils.copy(inputStream, response.getOutputStream());

        response.setContentType(MediaType.IMAGE_JPEG_VALUE); // 이미지 타입에 따라 변경
        response.setHeader("Content-Disposition", "inline; filename=" + "/" + atcFileOid);			
    }else {
        response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
    }
}

 

 

 

2) Service

 

public InputStream getImageFileById(String imgId) throws IOException {
    AttachFile file = fileQuery.getAttachFileList(imgId);

    if (file != null) {
        String filePath = prop.getUploadDir() + file.getFileRestoNm();
        return new FileInputStream(filePath);
    }else {
        return null;	    	
    }
}

 

 

 

서비스에서 필요한 정보를 제공하는 역할과 컨트롤러에서 응답을 처리하는 역할이 분리되어야,

코드의 가독성이 향상된다고 생각한다.

아직 부족하지만 조금이나마 깔끔한 코드를 짜려고 노력중이다.