스프링 부트 게시판 만들기
제9강 File Upload
게시글 등록에서 업그레이드하여, 파일을 업로드 하는 예제를 만들어 보겠습니다.
boardarticleadd.jsp파일은 수정할 필요가 없습니다.
이미 enctype을 multipar/form-data로 설정했기 때문에.
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <!-- jstl을 사용하기 위한 선언 -->
<!DOCTYPE html>
<html lang="ko">
<head>
<!-- bootstrap을 css cdn -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" type="text/css" />
<!-- jquery cdn -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
</head>
<body>
<div class="container">
<!-- 파일 등록을 위해 enctype="multipart/form-data" 을 선언 -->
<form action="boardarticlein.sd" class="form-horizontal" id="frm" name="frm" method="post" enctype="multipart/form-data">
<!-- class에 사용되는 form-group, row 등은 부트스트랩에서 사용되는 class -->
<div class="form-group row">
<label class="col-sm-2 col-xs-12 col-form-label" for="title">제목</label>
<div class="col-sm-10 col-xs-12">
<input class="form-control" id="title" name="title" placeholder="제목" type="text" value="" />
</div>
</div>
<div class="form-group row">
<label class="col-sm-2 col-xs-12 col-form-label" for="content">내용</label>
<div class="col-sm-10 col-xs-12">
<textarea rows="5" class="form-control" id="content" name="content" placeholder="내용"></textarea>
</div>
</div>
<div class="form-group row">
<label class="col-sm-2 col-xs-12 col-form-label" for="bfile">파일</label>
<div class="col-sm-10 col-xs-12">
<input class="form-control" id="bfile" name="bfile" type="file"/>
</div>
</div>
<div class="form-group row">
<div class="col-sm-12">
<a class="btn btn-success" href="#" onclick="boardIn();return false;" role="button" title="저장"><i class="fa fa-save"></i> 저장</a>
<a class="btn btn-primary" href="boardarticlelist.sd" role="button" title="리스트"><i class="fa fa-list-ul"></i> 리스트</a>
</div>
</div>
</form>
</div>
<script type="text/javascript">
function boardIn(){
$('#frm').submit();
}
</script>
</body>
</html>
브라우저에서 "http://localhost:8080/boardarticle/boardarticleadd.sd" 로 접속했을 때 아래와 같은 화면이 나타납니다.
테스트하실 때 파일만 선택해주시고 저장버튼을 누르면 됩니다.
BoardarticleCtrl.java는 아래와 같이 수정이 필요합니다.
package com.soledot.board.boardarticle;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
/**
* @author soledot
* @since 20191108
* @version soledot
* @description boardarticle Controller
*
*/
@Controller
@RequestMapping("/boardarticle/*")
public class BoardarticleCtrl {
private static final Logger logger = LoggerFactory.getLogger(BoardarticleCtrl.class);
@Autowired BoardarticleSvc boardarticleSvc;
//---* 저장
//--- MultipartFile을 추가로 전달받았습니다. 중요한 것은 boardarticleadd.jsp에서의 file input명과 @RequestParam("bfile")의 "bfile"이 같은 이름을 사용해야 합니다.
@RequestMapping("boardarticlein.sd")
public String in( HttpServletRequest request, @RequestParam Map<String, Object> param, @RequestParam("bfile") MultipartFile mFile, ModelMap model ){
try{
boardarticleSvc.in( request, param, mFile, model );
}catch( Exception e ){
logger.error( e.toString(), e );
}
return "redirect:/boardarticle/boardarticlelist.sd";
}
}
boardarticleSvc.in으로 MultipartFile을 넘겨 줍니다. *설명의 편의를 위해 불필요한 부분은 제거했습니다.
package com.soledot.board.boardarticle;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
/**
* @author soledot
* @since 20191108
* @version soledot
* @description boardarticle Service Interface
*
*/
public interface BoardarticleSvc {
//---*fo 저장
public boolean in( HttpServletRequest request, Map<String, Object> param, ModelMap model )throws Exception;
public boolean in( HttpServletRequest request, Map<String, Object> param, MultipartFile mFile, ModelMap model )throws Exception;
}
interface BoardarticleSvc입니다. 오버로딩으로 in method를 추가했습니다.
package com.soledot.board.boardarticle;
import java.io.File;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.ui.ModelMap;
import org.springframework.web.multipart.MultipartFile;
/**
* @author soledot
* @since 20191108
* @version soledot
* @description boardarticle Service 구현 클래스
*
*/
@Service("BoardarticleSvc")
public class BoardarticleSvcImpl implements BoardarticleSvc {
private static final Logger logger = LoggerFactory.getLogger(BoardarticleSvcImpl.class);
@Autowired HttpSession ss;
@Autowired BoardarticleDao boardarticleDao;
@Override
public boolean in( HttpServletRequest request, Map<String, Object> param, MultipartFile mFile, ModelMap model )throws Exception{
Map<String, Object> svcMap = new HashMap<>();
if( !mFile.isEmpty() ) { //---파일이 없으면 true를 리턴. false일 경우에만 처리함.
String filename = mFile.getOriginalFilename(); //--- 파일명을 얻어옴.
mFile.transferTo( new File( "f:/"+filename ) ); //--- 저장할 경로를 설정 해당 경로는 각자 원하는 위치로 설정하면 됩니다. 다만, 해당 경로에 접근할 수 있는 권한이 없으면 에러 발생
svcMap.put( "filename", filename ); //--- 파일명을 저장합니다. 큰 규모의 사이트는 잘 모르겠으나, 보통 파일의 경로는 저장하지 않음. 일반적으로 고정 된 경로에 저장하기 때문에...
}
//---* 게시글 저장
svcMap.put( "title", param.get("title") );
svcMap.put( "content", param.get("content") );
svcMap.put( "readcnt", 0 );
svcMap.put( "commentcnt", 0 );
svcMap.put( "recommendcnt", 0 );
svcMap.put( "groupnum", 0 );
svcMap.put( "levelnum", 0 );
svcMap.put( "stepnum", 0 );
svcMap.put( "inip", request.getRemoteAddr() );
boardarticleDao.in( svcMap );
//--- 게시글 저장 끝
//---* 그룹번호 업데이트
int seq = Integer.parseInt( svcMap.get( "seq" ).toString() );
svcMap.put( "seq", seq );
svcMap.put( "groupnum", seq );
boardarticleDao.up( svcMap );
//---* 그룹번호 업데이트 끝
return true;
}
}
워낙 간단하게 업로드 처리가 가능해서 몇 줄밖에 추가되지 않았습니다.
벌써 끝났습니다. Dao는 수정할 필요없습니다. 그래도 내용을 추가해드리겠습니다.
package com.soledot.board.boardarticle;
import java.util.List;
import java.util.Map;
/**
* @author soledot
* @since 20191108
* @version soledot
* @description boardarticle Dao Interface
*
*/
public interface BoardarticleDao {
//---*저장
public int in( Map<String, Object> param );
}
인터페이스 BoardarticleDao내용입니다.
package com.soledot.board.boardarticle;
import java.util.List;
import java.util.Map;
import org.apache.ibatis.session.SqlSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
/**
* @author soledot
* @since 20191108
* @version soledot
* @description boardarticle Dao 구현 클래스
*
*/
@Repository("BoardarticleDao")
public class BoardarticleDaoImpl implements BoardarticleDao {
@Autowired private SqlSession sqlSession;
//---*저장
@Override
public int in( Map<String, Object> param ){
return sqlSession.insert( "boardarticle.in", param );
}
}
BoardarticleDaoImpl 소스입니다.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="boardarticle">
<insert id="in" parameterType="hashmap" useGeneratedKeys="true" keyProperty="seq" >
INSERT INTO BOARDARTICLE
(
SEQ
,TITLE
,CONTENT
,FILENAME
,READCNT
,COMMENTCNT
,RECOMMENDCNT
,GROUPNUM
,LEVELNUM
,STEPNUM
,INIP
,INDATE
)values(
#{ seq, jdbcType=NUMERIC }
,#{ title, jdbcType=VARCHAR }
,#{ content, jdbcType=VARCHAR }
,#{ filename, jdbcType=VARCHAR }
,#{ readcnt, jdbcType=NUMERIC }
,#{ commentcnt, jdbcType=NUMERIC }
,#{ recommendcnt, jdbcType=NUMERIC }
,#{ groupnum, jdbcType=NUMERIC }
,#{ levelnum, jdbcType=NUMERIC }
,#{ stepnum, jdbcType=NUMERIC }
,#{ inip, jdbcType=VARCHAR }
,SYSDATE()
)
</insert>
</mapper>
boardarticle.xml 내용입니다.
이제, 테스트만 진행해보면 됩니다.
http://localhost:8080/boardarticle/boardarticleadd.sd로 접속해서
위 이미지처럼 파일이 없이 저장을 해보시고
파일을 선택해서 저장해보세요~
파일을 등록한 경우 파일명이 저장됩니다.
게시글 두 개가 잘 등록되었습니다!
그리고 파일저장 경로를 가서 파일이 잘 있는지 확인해보세요~
다음에는 파일다운로드 처리를 알아보겠습니다!