정적 이미지파일 React - Spring 업데이트 데이터 전송

2022. 2. 14. 10:58Technology[Front]

이번 게시글에서는 이전 게시글에서 알아보았던 정적 이미지파일 저장, 정적 이미지파일 가져와서 화면에 보여주기와 더불어서 React에서 사용자의 요청을 받아 해당 게시글을 업데이트 하게 되면 이미지파일이 변경된 경우 변경된 이미지파일을 Spring에 데이터를 전송해서 해당 파일을 업데이트 하고 React에서 업데이트된 파일을 화면에 보여주는 방식을 살펴보겠습니다.

 

(1) React

import React, { useState, useEffect, Link, BrowserRouter , Route} from 'react';
import axios from 'axios';
import {array} from '../../BoardData';
import $ from 'jquery';


const ItemUpdate= ({ match,history }) =>{

const [userId, setUserId] = useState(null);
const [userName, setUserName] = useState(null);
const [userClass, setUserClass] = useState(null);
const [dataList, setDataList] = useState([]);
const [ data, setData ] = useState({});
const [TitleValue, setTitleValue] = useState(""); 
const [ContentValue, setContentValue] = useState(""); 
const [check, setCheck] = useState(false);
const [ServerValue, setServerValue] = useState(""); 
const [JobValue, setJobValue] = useState(""); 
const [PartsValue, setPartsValue] = useState(""); 
const [LevelValue, setLevelValue] = useState(""); 
const { no } = match.params;
const nameRef = React.createRef();

  const getFreeByNo = no => {
    const arr = array.filter(x => x.no == no);
    if (arr.length == 1) {
      return arr[0];
    }
    return null;
  }

  var input = "http://localhost:8088/img?no=" + no;
  useEffect(() => {
    setData(getFreeByNo(no));
    setPreviewImag(input);
  }, []);
  
  window.onload = () => {
    setServerValue(data.SERVER);
    setJobValue(data.Job);
    setPartsValue(data.Parts);
    setLevelValue(data.ILevel);
    setContentValue(data.content);
    setTitleValue(data.title);
  }

const onChangeTitle = (e) => {
  setTitleValue(e.target.value);
  setCheck(false);
};
const onChangeContent = (e) => {
  setContentValue(e.target.value);
  setCheck(false);
};

const onChangeData = (e) => {
  setData(e.target.value);
  setCheck(false);
};
const onChangeServer = (e) => {
  setServerValue(e.target.value);
  setCheck(false);
};
const onChangeJob = (e) => {
  setJobValue(e.target.value);
  setCheck(false);
};
const onChangeParts = (e) => {
  setPartsValue(e.target.value);
  setCheck(false);
};
const onChangeLevel = (e) => {
  setLevelValue(e.target.value);
  setCheck(false);
};
 
// 이미지 업로드
const [previewImg, setPreviewImag] = useState(null);
const [postImg, setPostImg] = useState(null);
const inputImgHandler = (event) => {
    const loadImg = event.target.files[0];
    setPostImg(loadImg);

    let fd = new FileReader();

    if (loadImg) {
        fd.readAsDataURL(loadImg);
        console.log(fd);
    }

    fd.onloadend = () => {
        const previewImgUrl = fd.result;

        if (previewImgUrl) {
            setPreviewImag(previewImgUrl);
        }
    }
}

//보낼 값 설정 
const TitleV = TitleValue;
const ContentV = ContentValue;
const divide = "아이템";
var today = new Date();//현재날짜 찍어줌 
var year = today.getFullYear();
var month = ('0' + (today.getMonth() + 1)).slice(-2);
var day = ('0' + today.getDate()).slice(-2);
const week = ['일', '월', '화', '수', '목', '금', '토'];
let dayOfWeek = week[today.getDay()];
let hours = today.getHours()
let minutes = today.getMinutes();
var dateString = year + '년 ' + month + '월 ' + day + '일 ' + dayOfWeek + '요일 ' 
+ hours + '시 ' + minutes + '분';
const bdate = dateString;
const server = ServerValue;
const job = JobValue;
const Parts = PartsValue;
const level = LevelValue;
const updateData = () => {
  const userData = {

    BNUMBER : no,
    BHEADER : TitleV,
    BCONTENT : ContentV,
    BCLASS : divide,
    BDATE: bdate,
    SERVER : server,
    JOB : job,
    PARTS : Parts,
    ILEVEL : level,
    USERID : urlparams[0],
    IMGNAME : postImg.name.substring(0,postImg.name.indexOf("."))
  }
  const file = new FormData();
  file.append('file', postImg);
  file.append("userData", new Blob([JSON.stringify(userData)], {type: "application/json"}))

  const updateURL = "http://localhost:8088/updateItemBoard";
  axios
  .post(updateURL, file,
  {

  }
  ).then((response) => {
    console.log(response);
    alert("변경 완료!");
  })
  .catch(error => {
      console.log("error");
      console.error('There was an error!', error);
  });

  history.push('/item?'+urlparams[0])

};

// 이미지 삭제
let deleteImgHandler = () => {
  setPreviewImag(null);
  setPostImg(null);
}


  
  return (
    <div id="create"> 
    <br /> 
    <label><b>제목:</b>     &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</label> 
    <input class="title" id="namem" name="TitleValue" value={TitleValue} onChange={onChangeTitle} placeholder="제목 입력"/>
    <br/><br/>

    <div className={mypageCss.inputImageContainer}>

                        <div className={mypageCss.previewImg}>
                            <img src={`${previewImg}`} />
                        </div>


                        <button onClick={deleteImgHandler}>❌</button>

                        <form encType='multipart/form-data'>
                            <label htmlFor='file'>이미지 업로드</label>
                            <input type="file" id="file" accept='image/*'
                                onChange={inputImgHandler}
                                onClick={(event) => {
                                    event.target.value = null;
                                }} />
                        </form>

                    </div>
          

          <label><b>서버</b>     &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</label> 

        <form >
        <select name="server"  class="server" value={ServerValue} onChange={onChangeServer}>
        <option value="none">선택</option>
        <option value="오로라">오로라</option>
        <option value="레드">레드</option>
        <option value="이노시스">이노시스</option>
        <option value="유니온">유니온</option>
        <option value="스카니아">스카니아</option>
        </select>
        </form><br/>

          <label><b>직업</b>     &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</label> 

        <form >
      <select class="job" name="job"  value={JobValue} onChange={onChangeJob}>
      <option value="none">선택</option>
      <option value="마법사">마법사</option>
      <option value="도적">도적</option>
      <option value="전사">전사</option>
      <option value="해적">해적</option>
      <option value="궁수">궁수</option>
      <option value="펫">펫</option>
      </select>
      </form><br/>


      <label><b>부위</b>     &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</label> 
      <form  >
      <select class="parts" name="parts"  value={PartsValue} onChange={onChangeParts}>
      <option value="none">선택</option>
      <option value="상의">상의</option>
      <option value="하의">하의</option>
      <option value="무기">무기</option>
      <option value="신발">신발</option>
      <option value="펫">펫</option>
     
      </select>
      </form><br/>


      <label><b>레벨</b>     &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</label> 
      <form >
      <select class="level" name="Level"  value={LevelValue} onChange={onChangeLevel}>
      <option value="none">선택</option>
      <option value="110">110</option>
      <option value="120">120</option>
      <option value="150">150</option>
  
      </select>
      </form>


    <h3>내용</h3>
      <input class="content" id ="content_input" name="ContentValue" value={ContentValue} onChange={onChangeContent} placeholder="내용 입력"/>
    <div>
     
    
    </div> 
    <br/>
              <button id="write_btn" onClick={updateData}>수정하기</button>
              <button id="list_btn" onClick={() => history.push("/item?"+urlparams[0])} >목록</button>
      </div> 
  )
}
export default ItemUpdate;

위의 코드는 실제 프로젝트에서 일부 발췌한 것으로 실제 사용시 일부 수정해서 사용하시면 됩니다. 앞선 React 코드의 ItemCreate와 유사하지만 위의 경우 기존에 작성했던 게시글을 수정하는 것이므로 DB에서 게시글 정보를 받아와서 match.params로 얻은 no값으로 받아온 array에 filter를 적용해서 해당 게시글에 해당하는 정보만을 data에 set한 후 해당 data로 window.onload 함수로 window가 로드되었을 때 set을 이용해 기존 게시글의 다양한 정보를 모두 set하고 이를 return 에서의 html select 태그에 value로 값을 전달하고 있습니다. 또한 이미지파일의 경우도 useEffect로 처음 랜더링 되었을 때 input에 저장된 주소값으로 Spring에 접근하여 정적 이미지 파일의 byte 배열값을 전달받은 후 이를 setPreviewImag를 이용해 미리보기 사진을 화면에 출력합니다. 이후 값을 사용자가 수정한 후 수정하기 버튼을 누르면 updateData 함수가 실행되고 지금까지 수정된 값이 onChange함수를 통해 모두 변수에 set 되었고 이를 Spring에 전달해 기존의 게시글 정보를 수정하게 됩니다.

 

(2) Spring

@PostMapping(value = "/updateItemBoard", consumes = {MediaType.APPLICATION_JSON_VALUE, MediaType.MULTIPART_FORM_DATA_VALUE})
	public String updateItemBoard(@RequestPart HashMap<String,Object> userData,
								  @RequestPart(required = false) MultipartFile file)
			throws IOException, SQLException {

		final String uploadPath = "C:\\project2\\src\\main\\resources\\static\\Images";
		String systemName = "";
		String imgname = (String)userData.get("IMGNAME");

		BOARD board = boardrepository.findById(Long.parseLong((String)userData.get("BNUMBER"))).get();
		board.setBHEADER((String)userData.get("BHEADER"));
		board.setBCONTENT((String)userData.get("BCONTENT"));
		board.setBCLASS((String)userData.get("BCLASS"));
		board.setBDATE((String)userData.get("BDATE"));
		board.setSERVER((String)userData.get("SERVER"));
		board.setJOB((String)userData.get("JOB"));
		board.setPARTS((String)userData.get("PARTS"));
		board.setILEVEL((String)userData.get("ILEVEL"));
		board.setIdmanage(IdManagerepository.findById(Long.parseLong((String)userData.get("USERID"))).get());
		boardrepository.flush();
		try {
			MultipartFile serverFile = file;
			String requestName = serverFile.getName();

			if (serverFile.isEmpty()) {
				// 파일이 없는 경우
			} else {
				// 파일이 있는 경우
				File Folder = new File(uploadPath + File.separator + board.getBNUMBER());
				File[] files = Folder.listFiles();
				for(File file2 : files) {
					file2.delete();
				}
				Folder.delete();
				Folder.mkdir();
				systemName = String.format("%s.%s", imgname, "jpg");
				String fullFilePath = uploadPath + File.separator + board.getBNUMBER() + File.separator + systemName;
				Path path = Paths.get(fullFilePath).toAbsolutePath();
				serverFile.transferTo(path.toFile());
			}

		} catch (Exception e) {
			e.printStackTrace();
		}
		return "Spring -----> 저장완료";
	}

위의 코드는 실제 프로젝트에서 일부 발췌한 것으로 실제 사용시 일부 수정해서 사용하시면 됩니다. 앞선 Spring 코드의 createItemBoard와 유사하지만 이 경우 기존에 게시글 정보가 존재하는 경우기 때문에 boardrepository의 findById 메소드로 기존에 존재하던 값을 가져온 후 받아온 data를 setter를 통해 업데이트해서 db에 저장하게 됩니다. 이미지파일 또한 기존에 정적 이미지파일이 존재하기 때문에 해당 경로의 폴더와 파일을 데이터에 저장한 후 delete 메소드를 이용해 삭제하고 mkdir을 통해 파일디렉토리와 해당 파일을 새로 만들고 있습니다. 이후 저장완료 문자열을 return합니다.

 

이번 게시글에서는 저번 게시글에 이어서 기존에 존재하던 데이터를 받아와서 화면에 출력해주고 사용자가 해당 값을 수정 후 수정하기 버튼을 클릭하면 axios를 이용해 Spring에 해당 값을 전달 후 Spring에서 기존에 존재하던 데이터를 db에서 받아와서 set을 통해 업데이트하고 이미지파일의 경우 기존에 존재하던 파일을 삭제하고 새로 만들고 난 뒤 저장완료를 return하면서 종료되는 일련의 업데이트 과정을 살펴보았습니다.