[Spring Boot, React] 사진 파일 띄우기

씩씩한 조약돌·2023년 5월 16일
0

코드 기록🤓

목록 보기
14/31

[스프링부트 & 리액트]
관리자페이지에서 DB로 사진데이터 insert 후 유저페이지에서 출력하기

요구사항

  • api에서 받은 이미지와 파일첨부로 직접 insert한 이미지를 구분하여 출력

1. 스프링부트 - controller

import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

import org.springframework.core.io.InputStreamResource;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
	
	@Value("${spring.servlet.multipart.location}")
	private String filepath;

	//상품 이미지 가져오기
	@GetMapping("/prod/getimage/{filename}")
	public ResponseEntity<Resource> downloadExecute(@PathVariable("filename") String filename) throws IOException {
		System.out.println(filename);
		
		String fileName = filename.substring(filename.indexOf("_")+1);
		System.out.println(fileName);
		//파일명이 한글일 때 인코딩 작업
		String str = URLEncoder.encode(fileName, "UTF-8");
		
		//원본파일명에서 공백이 있을 때, +로 표시되므로 공백으로 처리
		str = str.replaceAll("\\+", "%20");
		
		Path path = Paths.get(filepath+"\\"+filename);
		Resource resource = new InputStreamResource(Files.newInputStream(path));
		System.out.println("resource : "+ resource.getFilename());
		
		return ResponseEntity.ok()
				.header(HttpHeaders.CONTENT_TYPE, "application/octect-stream")
				.header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename="+str+";")
				.body(resource);
	}

2. 리액트

2-1. prod_action

//상품이미지
function getImage(upload, config) {
  return async (dispatch) => {
    const data = await axios
      .get(`${baseUrl}/prod/getimage/${upload}`, {
        responseType: "blob",
        config,
      })
      .then((response) => response.data);
    //dispatch(boardActions.getBoardDownload(data));

    return data;
  };
}

export const prodActions = {
  getImage,
};

2-2. prod_reducers

import { createSlice } from "@reduxjs/toolkit";

let initialState = {
  /생략/
  imageFile: null,
};

const ProdSlice = createSlice({
  name: "prod",
  initialState,

  reducers: {
	/생략/
    getImage(state, action) {
      state.imageFile = action.payload.data;
    },
  },
});

export const prodReducers = ProdSlice.actions;
export default ProdSlice.reducer;

2-3. detail페이지

  function isHttpUrl(url) {
    return url.startsWith("https://");
  }

  const [imageUrl, setImageUrl] = useState("");

  const getImage = async (imagename) => {
    try {
      const imageFile = await dispatch(prodActions.getImage(imagename));
      const url = window.URL.createObjectURL(imageFile);
      setImageUrl(url);
    } catch (error) {
      console.error(error);
    }
  };

  useEffect(() => {
    if (prodDetail.prodImage) {
      if (isHttpUrl(prodDetail.prodImage)) {
        setImageUrl(prodDetail.prodImage);
      } else {
        getImage(prodDetail.prodImage);
      }
    }
  }, [prodDetail.prodImage]);

---
    <img src={imageUrl} />

2-4. list페이지

  function isHttpUrl(url) {
    return url.startsWith("https://");
  }
  const [imageUrls, setImageUrls] = useState({});

  const getImage = async (prod) => {
    try {
      const imageFile = await dispatch(prodActions.getImage(prod.prodImage));
      const url = window.URL.createObjectURL(imageFile);
      setImageUrls((prevState) => ({
        ...prevState,
        [prod.prodKeyNum]: url,
      }));
    } catch (error) {
      console.error(error);
    }
  };

  useEffect(() => {
    if (prodList) {
      prodList.forEach((prod) => {
        if (prod.prodImage) {
          if (isHttpUrl(prod.prodImage)) {
            setImageUrls((prevState) => ({
              ...prevState,
              [prod.prodKeyNum]: prod.prodImage,
            }));
          } else {
            getImage(prod);
          }
        }
      });
    }
  }, [prodList]);

----
<img src={imageUrls[prod.prodKeyNum]} />

3. 실행화면


profile
씩씩하게 공부중 (22.11~)

1개의 댓글

comment-user-thumbnail
2023년 5월 23일

조약돌 화이팅~!!

답글 달기