[Spring] 게시글 상세보기, 파일 download

dh·2022년 11월 22일
0

구디샵 프로젝트

목록 보기
3/5

게시판 목록에서 제목을 클릭시 상세페이지로 넘어가서 글을 볼수있고 첨부파일을 다운로드하는 기능을 구현해보겠습니다.

게시글 상세정보 가져오기 SQL

게시글에 파일이 첨부되어 있으면 파일정보도 가져와야 하기 때문에 NoticeVO에 private List<NoticeFileVO> fileVOs; 멤버변수를 추가합니다.

@Data
public class NoticeVO  {
	private Long noticeNum;
	private String id;
	private String title;
	private String contents;
	private Date regDate;
	private Long hit;
	private MultipartFile[] files;
	private List<NoticeFileVO> fileVOs;
}

파일이 첨부되어있는 글일때만 파일을 가져오기 위해 LEFT JOIN을 합니다.

<select id="getDetail" parameterType="NoticeVO" resultMap="getDetailResult">
		SELECT N.*, NF.* 
		FROM NOTICE N
			LEFT JOIN
			NOTICE_FILE NF 
			ON N.NOTICENUM=NF.NOTICENUM
		WHERE N.NOTICENUM=#{noticeNum} 
	</select>
	<resultMap type="NoticeVO" id="getDetailResult">
		<id column="noticeNum" property="noticeNum"/>
		<result column="id" property="id"/>
		<result column="title" property="title"/>
		<result column="contents" property="contents"/>
		<result column="regDate" property="regDate"/>
		<result column="hit" property="hit"/>
		<collection property="fileVOs" javaType="List" ofType="NoticeFileVO">
			<id column="fileNum" property="fileNum"/>
			<result column="fileName" property="fileName"/>
			<result column="oriName" property="oriName"/>
		</collection>
	</resultMap>

getDetail메서드를 NoticeMapper.java, NoticeService.java에 등록합니다.

Controller

컨트롤러에서 해당하는 게시글 객체를 가져와 noticeVO로 넘겨줍니다.

	@GetMapping("detail")
	public ModelAndView getDetail(NoticeVO noticeVO)throws Exception{
		ModelAndView mv = new ModelAndView();
		noticeVO = noticeService.getDetail(noticeVO);
		mv.addObject("noticeVO",noticeVO);
		
		return mv;
	}

detail.jsp

게시글 내용과 파일의 내용을 화면에 보여줍니다. 파일은 다운받을 수 있는 링크를 걸어줍니다.

<div id="title">
  <h1>${noticeVO.title}</h3>
  <h1>${noticeVO.id}</h3>
  <h1>${noticeVO.regDate}</h3>
</div>
<div id="files">
  <c:forEach items="${noticeVO.fileVOs}" var="fileVOs">
     <a href="/fileDown/notice?fileNum=${fileVOs.fileNum}">${fileVOs.oriName}</a> 
  </c:forEach>             
</div>
<div id="contents" style="height: 100%;">
    ${noticeVO.contents}
</div>

FileManageController

파일 다운을 관리할 FileManageController를 만듭니다.

@PathVarialbe은 Rest api에서 값을 호출할 때 주로 많이 사용하는데 URI를 이용해 파라미터를 처리합니다.
파일다운로드의 링크 URI가 /fileDown/notice?fileNum=${fileVOs.fileNum}이므로 {path}에는 notice가 들어갑니다. 그리고 fileNum을 받아서 파일의 상세정보를 받아옵니다.(getFileDetail)

@Controller
@Slf4j
public class FIleManageController {
	
	@Autowired
	private NoticeService noticeService;
	
	@GetMapping("/fileDown/{path}")
	public ModelAndView fileDown(@PathVariable("path") String path,NoticeFileVO noticeFileVO)throws Exception{
		log.info("=====================================");
		log.info("path => {}",path);
		
		noticeFileVO = noticeService.getFileDetail(noticeFileVO);
		log.info("noticeFIleVO =>{}",noticeFileVO);
		
		ModelAndView mv = new ModelAndView();
		
		mv.addObject("fileVO",noticeFileVO);
		mv.addObject("path",path);
		mv.setViewName("fileManager"); // FileManager renderMergedOutputModel에서 받음
		
		return mv;
	}
}


path에 notice가 들어간것을 확인할 수 있습니다.
그리고 이 path와 noticeFileVO의 파일정보를 fileManager로 보냅니다.
view의 이름을 CustomView의 이름으로 설정 합니다.
modelAndView.setViewName("CustomView의 bean name")

FileManager

FileManager클래스는 view기능이 없어서 AbstractView를 상속 받음
renderMergedOutputModel를 오버라이드해서 파일을 다운받을수 있도록 코드를 작성
application.properties에 등록했던 다운로드 경로 base(D:/gdshop/) + fileManager에서의 path(notice) =D:/gdshop/notice에서 파일을 가져올수 있도록함

@Component
@Slf4j
public class FileManager extends AbstractView {
	@Value("${app.download.base}") //  (D:/gdshop/) application.properties에서 설정한 경로
	private String base;
	
	@Override
	protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		// TODO Auto-generated method stub
		NoticeFileVO noticeFileVO = (NoticeFileVO)model.get("fileVO");
		String path = (String)model.get("path");
		log.info("===========================");
		log.info("FileVO =>{}",noticeFileVO);
		log.info("===========================");
		
		File file = new File(base+path, noticeFileVO.getFileName());
		
		//한글 처리
		response.setCharacterEncoding("UTF-8");
		
		//총 파일의 크기
		response.setContentLengthLong(file.length());
		
		//다운로드시 파일의 이름을 인코딩
		String oriName = URLEncoder.encode(noticeFileVO.getOriName(),"UTF-8");
		
		//header 설정
		response.setHeader("Content-Disposition", "attachment;filename=\""+oriName+"\"");
		response.setHeader("Content-Transfer-Encoding", "binary");
		
		//HDD에서 파일을 읽고
		FileInputStream fi = new FileInputStream(file);
		//Client로 전송 준비
		OutputStream os = response.getOutputStream();
		
		//전송
		FileCopyUtils.copy(fi, os);
		
		//자원 해제
		os.close();
		fi.close();
	}

결과

그 결과 파일 링크를 클릭시 다운로드가 잘 됩니다.

0개의 댓글