Spring/CRUD Project

[CRUD] 파일 업로드 및 조회 2 : 수정 및 출력

v조아리v 2023. 12. 5. 16:11
반응형
검색 > 페이징 > Ajax > 파일 업로드 > 파일 다운로드

 

저번 시간에는 파일 업로드에 대해서 알아봤습니다. 이번 시간에는 업로드한 이미지 파일을 웹 페이지에서 볼 수 있게 해보겠습니다.

1. FileUpload 수정

package com.JoAri.CRUD.img;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;

import javax.servlet.ServletContext;

import org.springframework.web.multipart.MultipartFile;

public class FileUpload {

	private String UPLOAD_PATH = "/resources/images";

	public void fileUpload(MultipartFile file, String savedFileName, ServletContext servletContext) {
		if (!file.isEmpty()) {
			try {
				String realPath = servletContext.getRealPath(UPLOAD_PATH);
				Path uploadPath = new File(realPath + File.separator + savedFileName).toPath();
				Files.copy(file.getInputStream(), uploadPath, StandardCopyOption.REPLACE_EXISTING);
			} catch (IOException e) {
				e.printStackTrace(); // 예외 처리
			}
		}
	}

	public String getUploadPath() {
		return UPLOAD_PATH;
	}
}

기존에는 서버의 폴더에 저장되게 했으나 오늘은 프로젝트의 내부 폴더에 저장되게 해보겠습니다. UPLOAD_PATH가 바뀌었으며 filUpload 메소드에 파라미터가 늘어났습니다.

2. 기존 코드 수정

// Img Service
	void uploadImg(List<MultipartFile> imgs, int boardSeq, ServletContext servletContext);

// Img ServiceImpl
	@Override
	public void uploadImg(List<MultipartFile> imgs, int boardSeq, ServletContext servletContext) {
		List<Map<String, Object>> imgList = new ArrayList<Map<String,Object>>();
		
		for(MultipartFile file : imgs) {
			String ariginalFileName = file.getOriginalFilename();
			String extension = ariginalFileName.substring(ariginalFileName.lastIndexOf("."));
			String savedFileName = UUID.randomUUID().toString()+extension;
			
			Map<String, Object> imgMap = new HashMap<String, Object>();
			imgMap.put("saveName", savedFileName);
			imgMap.put("realName", ariginalFileName);
			imgMap.put("boardSeq", boardSeq);
			
			FileUpload fileUpload = new FileUpload();
			fileUpload.fileUpload(file, savedFileName, servletContext);
			
			imgMap.put("savePath", fileUpload.getUploadPath());
			
			imgList.add(imgMap);
		}
		
		imgDao.uploadImg(imgList);
	}

// Board ServiceImpl
    @Autowired
    private ServletContext servletContext;
	
	@Override
	public void createBoard(Map<String, Object> param) {
		Map<String, Object> boardMap = new HashMap<String, Object>();
		
		boardMap.put("writer", param.get("writer"));
		boardMap.put("title", param.get("title"));
		boardMap.put("content", param.get("content"));
		
		int boardSeq = boardDao.getMaxSeq();
		
		boardDao.createBoard(param);
		
		@SuppressWarnings("unchecked")
		List<MultipartFile> imgFiles = (List<MultipartFile>) param.get("imgs");
		imgSer.uploadImg(imgFiles, boardSeq, servletContext);
	}

업로드 경로가 바뀌었으니 기존 코드들도 약간 씩 수정해 주도록 합니다.

3. Img Mapper 작성

    <select id='getImgList' resultMap='imgMap'>
        SELECT
            FILE_SEQ,
            REAL_NAME,
            SAVE_NAME,
            REG_DATE,
            SAVE_PATH,
            BOARD_SEQ
        FROM BOARD_IMG
        WHERE BOARD_SEQ = #{boardSeq}
    </select>

    <select id='getImgCount' resultType='int'>
        SELECT
        	COUNT(BOARD_SEQ)
        FROM BOARD_IMG
        WHERE BOARD_SEQ = #{boardSeq}
    </select>

 

4. Img Dao, DaoImpl 작성

// Img Dao
	List<Map<String, Object>> getImgList(int boardSeq);
	int getImgCount(int boardSeq);

// Img DaoImpl
	@Override
	public List<Map<String, Object>> getImgList(int boardSeq){
		return sqlSession.selectList("ImgMapper.getImgList", boardSeq);
	}
	@Override
	public int getImgCount(int boardSeq) {
		return sqlSession.selectOne("ImgMapper.getImgCount", boardSeq);
	}

 

5. Img Service, ServiceImpl 작성

// Img Service
	List<Map<String, Object>> getImgList(int boardSeq);
	int getImgCount(int boardSeq);
    
// Img ServiceImpl
	@Override
	public List<Map<String, Object>> getImgList(int boardSeq){
		return imgDao.getImgList(boardSeq);
	}
	@Override
	public int getImgCount(int boardSeq) {
		return imgDao.getImgCount(boardSeq);
	}

 

6. BoardController 작성

	@RequestMapping(value = "/read/{seq}", method = RequestMethod.GET)
	public ModelAndView readBoard(@PathVariable("seq") int seq, ModelAndView mav) {
		Map<String, Object> boardMap = boardSer.showBoard(seq);

		if (boardMap != null) {
			boardSer.incViewCnt(seq);
		}

		int countImg = imgSer.getImgCount(seq);
		mav.addObject("imgNum", countImg);

		List<Map<String, Object>> imgList = imgSer.getImgList(seq);
		mav.addObject("imgList", imgList);

		mav.addObject("board", boardMap);
		mav.setViewName("read");

		return mav;
	}

이미지를 여러 개 업로드가 가능하니, 하나의 게시물에 해당하는 이미지의 갯수와 이미지 정보들(List)을 View에 넘겨줍니다.

7. read.jsp 수정

<!-- 이전 코드 -->
    </tbody>

        <tfoot>
            <tr>
                <td colspan='4'>
                    <c:forEach items='${imgList }' var='imgs' varStatus='status'>
                        <c:if test='${status.count <= imgNum }'>
                            <img src="${imgs.savePath}/${imgs.saveName}" />
                            <c:if test="${status.count != imgNum}">
                            	<br>
                            </c:if>
                        </c:if>
                    </c:forEach>
                </td>
            </tr>
        </tfoot>
    </table>
<!-- 이전 코드 -->

<img> 태그를 이용해서 이미지를 출력해 주도록 하고 경로는 savePath와 saveName을 이용해서 지정해 줍니다.

8. 결과물

이미지 다중 업로드 및 출력

 

후기

경로를 바꾸면서 많이 고생을 했었습니다. 기존에는 그냥 서버 컴퓨터 내에 있는 폴더 경로를 쓰면 그냥 됐지만, 프로젝트의 내부 경로에 저장돼야 하는 것이라 그런지 ServletContext 이라는 것을 추가해줘야 했습니다. 이를 알기 전에는 절대경로를 구하면서 될 때 까지 / 지우고 디렉토리 지우고 를 반복하며 테스트를 했었습니다... 휴....

*ServletContext*
Java 웹 어플리케이션에서 웹 어플리케이션 자체에 대한 정보를 제공하고, 서블릿 간의 통신을 도와주는 인터페이스입니다. Spring 프레임워크에서도 이를 활용하여 웹 어플리케이션의 환경 정보에 접근하거나 서블릿 간의 데이터를 주고받을 수 있습니다.

드디어 폴더 이동을 성공한 후, 실제로 어디에 업로드 되는지 확인해봤습니다.
[FIleUpload.java]
System.out.println("Real Path: " + realPath);
[결과물]
Real Path:C:\work_space\.metadata\.plugins\org.eclipse.wst.server.core\tmp4\wtpwebapps\CRUD_Project\resources\images
직접 찾아봤을 때는 왜 안 보이는지 realPath를 출력해 보고 알게 됐습니다...

오늘은 뭐든 직접 하는 것은 제대로 안 되는 날이네요... 여러 모로 고생이 많은 날 이었습니다.
다음엔 파일(이미지) 다운로드로 돌아오겠습니다. 빠잇~!
반응형