-
[Spring] 게시판 만들기(19) - 파일 업로드(MultipartHttpServletRequest)Spring/4.3.x - 게시판 만들기 2018. 12. 20. 14:00반응형
스프링 프레임워크의 내장 객체인 CommonsMultipartResolver과 jquery.form.js를 이용한 파일 업로드 방식을 진행하겠습니다.
1. TALBE 생성
첨부파일 정보를 저장할 테이블을 생성하세요. 첨부파일을 저장할 테이블은 한 개의 게시물에 여러 개에 첨부파일을 등록할 수 있도록 FILE_NO 컬럼을 추가하세요.
더보기1234567891011121314151617181920-- TB_BOARD_FILE 테이블 생성 및 코멘트 추가CREATE TABLE BOARD.TB_BOARD_FILE (BOARD_SEQ INT Not Null COMMENT '게시글 번호', FILE_NO INT Not Null COMMENT '첨부파일 번호', FILE_NAME_KEY VARCHAR(200) COMMENT '첨부파일 암호화명', FILE_NAME VARCHAR(100) COMMENT '첨부파일명', FILE_PATH VARCHAR(200) COMMENT '첨부파일 경로', FILE_SIZE VARCHAR(50) COMMENT '첨부파일 크기', REMARK VARCHAR(1000) COMMENT '비고', DEL_YN VARCHAR(1) COMMENT '삭제유무', INS_USER_ID VARCHAR(20) COMMENT '입력자ID', INS_DATE DATETIME COMMENT '입력일시', UPD_USER_ID VARCHAR(20) COMMENT '수정자ID', UPD_DATE DATETIME COMMENT '수정일시', PRIMARY KEY (BOARD_SEQ, FILE_NO)) COMMENT '게시판 첨부파일';-- TB_BOARD 테이블 샘플 데이터 조회SELECT *FROM BOARD.TB_BOARD_FILE;cs 2. 설정 파일 수정
2_1) pom.xml에 의존성 추가
commons-fileupload, ommons-io 의존성을 추가하세요.
더보기123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.spring</groupId><artifactId>board</artifactId><name>board</name><packaging>war</packaging><version>1.0.0-BUILD-SNAPSHOT</version><properties><java-version>1.8</java-version><org.springframework-version>4.3.6.RELEASE</org.springframework-version><junit.version>4.12</junit.version><org.aspectj-version>1.6.10</org.aspectj-version><org.slf4j.version>1.7.21</org.slf4j.version><logback.version>1.1.7</logback.version><mysql.version>5.1.46</mysql.version><mybatis.version>3.4.6</mybatis.version><mybatis.spring.version>1.3.2</mybatis.spring.version><jackson.version>2.9.5</jackson.version><cglib.version>3.2.3</cglib.version></properties><dependencies><!-- Spring --><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>${org.springframework-version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>${org.springframework-version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>${org.springframework-version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><version>${org.springframework-version}</version></dependency><!-- AspectJ --><dependency><groupId>org.aspectj</groupId><artifactId>aspectjrt</artifactId><version>${org.aspectj-version}</version></dependency><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>${org.aspectj-version}</version></dependency><!-- CGLIB --><dependency><groupId>cglib</groupId><artifactId>cglib-nodep</artifactId><version>${cglib.version}</version></dependency><!-- Logging --><dependency><groupId>org.slf4j</groupId><artifactId>jcl-over-slf4j</artifactId><version>${org.slf4j.version}</version></dependency><dependency><groupId>ch.qos.logback</groupId><artifactId>logback-classic</artifactId><version>${logback.version}</version></dependency><!-- @Inject --><dependency><groupId>javax.inject</groupId><artifactId>javax.inject</artifactId><version>1</version></dependency><!-- Servlet --><dependency><groupId>javax.servlet</groupId><artifactId>servlet-api</artifactId><version>2.5</version><scope>provided</scope></dependency><dependency><groupId>javax.servlet.jsp</groupId><artifactId>jsp-api</artifactId><version>2.1</version><scope>provided</scope></dependency><dependency><groupId>javax.servlet</groupId><artifactId>jstl</artifactId><version>1.2</version></dependency><!-- Test --><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>${junit.version}</version><scope>test</scope></dependency><!-- MySQL --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>${mysql.version}</version></dependency><!-- MyBatis --><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>${mybatis.version}</version></dependency><dependency><groupId>org.mybatis</groupId><artifactId>mybatis-spring</artifactId><version>${mybatis.spring.version}</version></dependency><!-- Jackson --><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-annotations</artifactId><version>${jackson.version}</version></dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>${jackson.version}</version></dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-core</artifactId><version>${jackson.version}</version></dependency><!-- Apache Commons file upload --><dependency><groupId>commons-fileupload</groupId><artifactId>commons-fileupload</artifactId><version>1.2.2</version></dependency><!-- Apache Commons IO --><dependency><groupId>org.apache.commons</groupId><artifactId>commons-io</artifactId><version>1.3.2</version></dependency></dependencies><build><plugins><plugin><artifactId>maven-eclipse-plugin</artifactId><version>2.9</version><configuration><additionalProjectnatures><projectnature>org.springframework.ide.eclipse.core.springnature</projectnature></additionalProjectnatures><additionalBuildcommands><buildcommand>org.springframework.ide.eclipse.core.springbuilder</buildcommand></additionalBuildcommands><downloadSources>true</downloadSources><downloadJavadocs>true</downloadJavadocs></configuration></plugin><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>2.5.1</version><configuration><source>1.8</source><target>1.8</target><compilerArgument>-Xlint:all</compilerArgument><showWarnings>true</showWarnings><showDeprecation>true</showDeprecation></configuration></plugin><plugin><groupId>org.codehaus.mojo</groupId><artifactId>exec-maven-plugin</artifactId><version>1.2.1</version><configuration><mainClass>org.test.int1.Main</mainClass></configuration></plugin><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-surefire-plugin</artifactId><version>2.19.1</version><configuration><skipTests>true</skipTests></configuration></plugin></plugins></build></project>cs 2_2) servlet-context.xml 수정
Multipart을 사용하기 위해 MultipartResolver를 servlet-context.xml에 추가하고, 스프링에서 기본으로 제공하는 MultipartResolver는 CommonsMultipartResolver이므로 multipartResolver으로 빈 이름을 등록하세요.
- maxUploadSize : 한 번에 최대 올릴 수 있는 파일 사이즈
- maxInMemorySize : 해당 경로에 최대로 저장할 수 있는 파일 사이즈더보기123456789101112131415161718192021222324252627282930313233343536373839404142434445464748<?xml version="1.0" encoding="UTF-8"?><beans:beans xmlns="http://www.springframework.org/schema/mvc"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:beans="http://www.springframework.org/schema/beans"xmlns:context="http://www.springframework.org/schema/context"xmlns:mvc="http://www.springframework.org/schema/mvc"xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsdhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd"><!-- DispatcherServlet Context: defines this servlet's request-processing infrastructure --><!-- Enables the Spring MVC @Controller programming model --><annotation-driven /><!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the $/resources directory --><resources mapping="/resources/**" location="/resources/" /><resources mapping="/css/**" location="/css/" /><resources mapping="/img/**" location="/img/" /><resources mapping="/js/**" location="/js/" /><!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory --><beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"><beans:property name="prefix" value="/WEB-INF/views/" /><beans:property name="suffix" value=".jsp" /></beans:bean><context:component-scan base-package="com.spring.board" use-default-filters="false"><context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" /></context:component-scan><mvc:interceptors><mvc:interceptor><mvc:mapping path="/**"/><beans:bean id="loggerInterceptor" class="com.spring.board.common.LoggerInterceptor"></beans:bean></mvc:interceptor></mvc:interceptors><beans:bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter" /><!-- MultipartResolver 설정 --><beans:bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"><beans:property name="maxUploadSize" value="100000000" /><beans:property name="maxInMemorySize" value="100000000" /></beans:bean></beans:beans>cs 3. Back-End 파일 수정 및 추가
3_1) boardMapper.xml
TB_BOARD 테이블에 1개의 게시글을 저장할 때 첨부파일이 존재하는 경우는 TB_BOARD_FILE 테이블에도 첨부파일 정보를 저장해야합니다. TB_BOARD_FILE 테이블는 TB_BOARD 테이블에 BOARD_SEQ 컬럼을 참조하기 때문에 TB_BOARD 테이블에 BOARD_SEQ 컬럼에 값을 알아야합니다.
MySQL의 AUTO_INCREMENT로 설정된 컬럼(BOARD_SEQ)에 값을 먼저 가져올 수 없기 때문에 INSERT 후에 값을 가지고 와야합니다. 이런 경우에는 MySQL에서는 가장 최근에 성공적으로 실행된 INSERT 구문의 첫 번째 AUTO_INCREMENT 컬럼(BOARD_SEQ)의 값을 반환하는 LAST_INSERT_ID()라는 함수를 사용하여 TB_BOARD 테이블에 BOARD_SEQ 컬럼에 값을 알 수 있습니다.더보기123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.spring.board.boardMapper"><select id="getBoardCnt" parameterType="com.spring.board.form.BoardForm" resultType="int">SELECT COUNT(*)FROM BOARD.TB_BOARD</select><select id="getBoardList" parameterType="com.spring.board.form.BoardForm" resultType="com.spring.board.dto.BoardDto">SELECT *FROM ( SELECT BOARD_SEQ, BOARD_RE_REF, BOARD_RE_LEV, BOARD_RE_SEQ, BOARD_WRITER, BOARD_SUBJECT, BOARD_CONTENT, BOARD_HITS, DEL_YN, INS_USER_ID, CAST( DATE_FORMAT( INS_DATE, '%Y-%m-%d %H:%i:%s' ) AS CHAR(19) ) AS INS_DATE, UPD_USER_ID, CAST( DATE_FORMAT( UPD_DATE, '%Y-%m-%d %H:%i:%s' ) AS CHAR(19) ) AS UPD_DATEFROM BOARD.TB_BOARDORDER BY BOARD_RE_REF DESC, BOARD_RE_SEQ ASC) T1LIMIT #{limit} OFFSET #{offset}</select><delete id="updateBoardHits" parameterType="com.spring.board.form.BoardForm">UPDATE BOARD.TB_BOARDSET BOARD_HITS = BOARD_HITS + 1, UPD_USER_ID = 'NONMEMBER', UPD_DATE = NOW()WHERE BOARD_SEQ = #{board_seq}</delete><select id="getBoardDetail" parameterType="com.spring.board.form.BoardForm" resultType="com.spring.board.dto.BoardDto">SELECT BOARD_SEQ, BOARD_RE_REF, BOARD_RE_LEV, BOARD_RE_SEQ, BOARD_WRITER, BOARD_SUBJECT, BOARD_CONTENT, BOARD_HITS, DEL_YN, INS_USER_ID, CAST( DATE_FORMAT( INS_DATE, '%Y-%m-%d %H:%i:%s' ) AS CHAR(19) ) AS INS_DATE, UPD_USER_ID, CAST( DATE_FORMAT( UPD_DATE, '%Y-%m-%d %H:%i:%s' ) AS CHAR(19) ) AS UPD_DATEFROM BOARD.TB_BOARDWHERE BOARD_SEQ = #{board_seq}</select><select id="getBoardReRef" parameterType="com.spring.board.form.BoardForm" resultType="int">SELECT IFNULL(MAX(BOARD_RE_REF), 0) + 1FROM BOARD.TB_BOARD</select><insert id="insertBoard" parameterType="com.spring.board.form.BoardForm"><selectKey resultType="int" keyProperty="board_seq" order="AFTER">SELECT LAST_INSERT_ID()</selectKey>INSERTINTO BOARD.TB_BOARD(BOARD_RE_REF, BOARD_RE_LEV, BOARD_RE_SEQ, BOARD_WRITER, BOARD_SUBJECT, BOARD_CONTENT, INS_USER_ID, INS_DATE, UPD_USER_ID, UPD_DATE)VALUES(#{board_re_ref}, 0, 0, #{board_writer}, #{board_subject}, #{board_content}, 'NONMEMBER', NOW(), 'NONMEMBER', NOW())</insert><insert id="insertBoardFile" parameterType="com.spring.board.form.BoardFileForm"><selectKey resultType="int" keyProperty="file_no" order="BEFORE">SELECT IFNULL(MAX(FILE_NO), 0) + 1FROM BOARD.TB_BOARD_FILEWHERE BOARD_SEQ = #{board_seq}</selectKey>INSERTINTO TB_BOARD_FILE(BOARD_SEQ, FILE_NO, FILE_NAME_KEY, FILE_NAME, FILE_PATH, FILE_SIZE, DEL_YN, INS_USER_ID, INS_DATE, UPD_USER_ID, UPD_DATE)VALUES(#{board_seq}, #{file_no}, #{file_name_key}, #{file_name}, #{file_path}, #{file_size}, 'N', 'NONMEMBER', NOW(), 'NONMEMBER', NOW())</insert><insert id="insertBoardFail" parameterType="com.spring.board.form.BoardForm">INSERTINTO BOARD.TB_BOARD(BOARD_RE_REF, BOARD_RE_LEV, BOARD_RE_SEQ, BOARD_WRITER, BOARD_SUBJECT, BOARD_CONTENT, INS_USER_ID, INS_DATE, UPD_USER_ID, UPD_DATE)VALUES(0, 0, 0, #{board_writer1}, #{board_subject}, #{board_content}, 'NONMEMBER', NOW(), 'NONMEMBER', NOW())</insert><delete id="deleteBoard" parameterType="com.spring.board.form.BoardForm">DELETEFROM BOARD.TB_BOARDWHERE BOARD_SEQ = #{board_seq}</delete><delete id="updateBoard" parameterType="com.spring.board.form.BoardForm">UPDATE BOARD.TB_BOARDSET BOARD_SUBJECT = #{board_subject}, BOARD_CONTENT = #{board_content}, UPD_USER_ID = 'NONMEMBER', UPD_DATE = NOW()WHERE BOARD_SEQ = #{board_seq}</delete><select id="getBoardReplyInfo" parameterType="com.spring.board.form.BoardForm" resultType="com.spring.board.dto.BoardDto">SELECT BOARD_SEQ, BOARD_RE_REF, BOARD_RE_LEV, BOARD_RE_SEQFROM TB_BOARDWHERE BOARD_SEQ = #{board_parent_seq}</select><delete id="updateBoardReSeq" parameterType="com.spring.board.form.BoardForm">UPDATE TB_BOARDSET BOARD_RE_SEQ = BOARD_RE_SEQ + 1, UPD_USER_ID = 'NONMEMBER', UPD_DATE = NOW()WHERE BOARD_RE_REF = #{board_re_ref}AND BOARD_RE_SEQ > #{board_re_seq}</delete><insert id="insertBoardReply" parameterType="com.spring.board.form.BoardForm">INSERTINTO BOARD.TB_BOARD(BOARD_RE_REF, BOARD_RE_LEV, BOARD_RE_SEQ, BOARD_WRITER, BOARD_SUBJECT, BOARD_CONTENT, INS_USER_ID, INS_DATE, UPD_USER_ID, UPD_DATE)VALUES(#{board_re_ref}, #{board_re_lev} + 1, #{board_re_seq} + 1, #{board_writer}, #{board_subject}, #{board_content}, 'NONMEMBER', NOW(), 'NONMEMBER', NOW())</insert></mapper>cs 3_2) BoardForm.java
스프링 프레임워크는 업로드 된 파일의 파일 내용을 가져오는데 사용할 수 있는 MultipartFile 클래스를 제공하므로 여러 개의 첨부파일 정보를 가지고 올 수 있도록 MultipartFile를 List로 선언하여 GET/SET을 추가하세요.더보기123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163package com.spring.board.form;import java.util.Date;import java.util.List;import org.springframework.web.multipart.MultipartFile;public class BoardForm extends CommonForm {List<MultipartFile> files;int board_seq;int board_parent_seq;int board_re_ref;int board_re_lev;int board_re_seq;String board_writer;String board_subject;String board_content;int board_hits;String del_yn;String ins_user_id;Date ins_date;String upd_user_id;Date upd_date;String search_type;String board_file;public List<MultipartFile> getFiles() {return files;}public void setFiles(List<MultipartFile> files) {this.files = files;}public int getBoard_seq() {return board_seq;}public void setBoard_seq(int board_seq) {this.board_seq = board_seq;}public int getBoard_parent_seq() {return board_parent_seq;}public void setBoard_parent_seq(int board_parent_seq) {this.board_parent_seq = board_parent_seq;}public int getBoard_re_ref() {return board_re_ref;}public void setBoard_re_ref(int board_re_ref) {this.board_re_ref = board_re_ref;}public int getBoard_re_lev() {return board_re_lev;}public void setBoard_re_lev(int board_re_lev) {this.board_re_lev = board_re_lev;}public int getBoard_re_seq() {return board_re_seq;}public void setBoard_re_seq(int board_re_seq) {this.board_re_seq = board_re_seq;}public String getBoard_writer() {return board_writer;}public void setBoard_writer(String board_writer) {this.board_writer = board_writer;}public String getBoard_subject() {return board_subject;}public void setBoard_subject(String board_subject) {this.board_subject = board_subject;}public String getBoard_content() {return board_content;}public void setBoard_content(String board_content) {this.board_content = board_content;}public int getBoard_hits() {return board_hits;}public void setBoard_hits(int board_hits) {this.board_hits = board_hits;}public String getDel_yn() {return del_yn;}public void setDel_yn(String del_yn) {this.del_yn = del_yn;}public String getIns_user_id() {return ins_user_id;}public void setIns_user_id(String ins_user_id) {this.ins_user_id = ins_user_id;}public Date getIns_date() {return ins_date;}public void setIns_date(Date ins_date) {this.ins_date = ins_date;}public String getUpd_user_id() {return upd_user_id;}public void setUpd_user_id(String upd_user_id) {this.upd_user_id = upd_user_id;}public Date getUpd_date() {return upd_date;}public void setUpd_date(Date upd_date) {this.upd_date = upd_date;}public String getSearch_type() {return search_type;}public void setSearch_type(String search_type) {this.search_type = search_type;}public String getBoard_file() {return board_file;}public void setBoard_file(String board_file) {this.board_file = board_file;}}cs 3_3) BoardFileForm.java
더보기1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192package com.spring.board.form;import java.util.Date;public class BoardFileForm {int board_seq;int file_no;String file_name_key;String file_name;String file_path;String file_size;String remark;String del_yn;String ins_user_id;Date ins_date;String upd_user_id;Date upd_date;public int getBoard_seq() {return board_seq;}public void setBoard_seq(int board_seq) {this.board_seq = board_seq;}public int getFile_no() {return file_no;}public void setFile_no(int file_no) {this.file_no = file_no;}public String getFile_name_key() {return file_name_key;}public void setFile_name_key(String file_name_key) {this.file_name_key = file_name_key;}public String getFile_name() {return file_name;}public void setFile_name(String file_name) {this.file_name = file_name;}public String getFile_path() {return file_path;}public void setFile_path(String file_path) {this.file_path = file_path;}public String getFile_size() {return file_size;}public void setFile_size(String file_size) {this.file_size = file_size;}public String getRemark() {return remark;}public void setRemark(String remark) {this.remark = remark;}public String getDel_yn() {return del_yn;}public void setDel_yn(String del_yn) {this.del_yn = del_yn;}public String getIns_user_id() {return ins_user_id;}public void setIns_user_id(String ins_user_id) {this.ins_user_id = ins_user_id;}public Date getIns_date() {return ins_date;}public void setIns_date(Date ins_date) {this.ins_date = ins_date;}public String getUpd_user_id() {return upd_user_id;}public void setUpd_user_id(String upd_user_id) {this.upd_user_id = upd_user_id;}public Date getUpd_date() {return upd_date;}public void setUpd_date(Date upd_date) {this.upd_date = upd_date;}}cs 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192package com.spring.board.form;import java.util.Date;public class BoardFileForm {int board_seq;int file_no;String file_name_key;String file_name;String file_path;String file_size;String remark;String del_yn;String ins_user_id;Date ins_date;String upd_user_id;Date upd_date;public int getBoard_seq() {return board_seq;}public void setBoard_seq(int board_seq) {this.board_seq = board_seq;}public int getFile_no() {return file_no;}public void setFile_no(int file_no) {this.file_no = file_no;}public String getFile_name_key() {return file_name_key;}public void setFile_name_key(String file_name_key) {this.file_name_key = file_name_key;}public String getFile_name() {return file_name;}public void setFile_name(String file_name) {this.file_name = file_name;}public String getFile_path() {return file_path;}public void setFile_path(String file_path) {this.file_path = file_path;}public String getFile_size() {return file_size;}public void setFile_size(String file_size) {this.file_size = file_size;}public String getRemark() {return remark;}public void setRemark(String remark) {this.remark = remark;}public String getDel_yn() {return del_yn;}public void setDel_yn(String del_yn) {this.del_yn = del_yn;}public String getIns_user_id() {return ins_user_id;}public void setIns_user_id(String ins_user_id) {this.ins_user_id = ins_user_id;}public Date getIns_date() {return ins_date;}public void setIns_date(Date ins_date) {this.ins_date = ins_date;}public String getUpd_user_id() {return upd_user_id;}public void setUpd_user_id(String upd_user_id) {this.upd_user_id = upd_user_id;}public Date getUpd_date() {return upd_date;}public void setUpd_date(Date upd_date) {this.upd_date = upd_date;}}cs 3_4) BoardDao.java
더보기12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394package com.spring.board.dao;import java.util.List;import javax.annotation.Resource;import org.apache.ibatis.session.SqlSession;import org.springframework.stereotype.Repository;import com.spring.board.dto.BoardDto;import com.spring.board.form.BoardFileForm;import com.spring.board.form.BoardForm;@Repositorypublic class BoardDao {@Resource(name = "sqlSession")private SqlSession sqlSession;private static final String NAMESPACE = "com.spring.board.boardMapper";/** 게시판 - 목록 수 */public int getBoardCnt(BoardForm boardForm) throws Exception {return sqlSession.selectOne(NAMESPACE + ".getBoardCnt", boardForm);}/** 게시판 - 목록 조회 */public List<BoardDto> getBoardList(BoardForm boardForm) throws Exception {return sqlSession.selectList(NAMESPACE + ".getBoardList", boardForm);}/** 게시판 - 조회 수 수정 */public int updateBoardHits(BoardForm boardForm) throws Exception {return sqlSession.update(NAMESPACE + ".updateBoardHits", boardForm);}/** 게시판 - 상세 조회 */public BoardDto getBoardDetail(BoardForm boardForm) throws Exception {return sqlSession.selectOne(NAMESPACE + ".getBoardDetail", boardForm);}/** 게시판 - 그룹 번호 조회 */public int getBoardReRef(BoardForm boardForm) throws Exception {return sqlSession.selectOne(NAMESPACE + ".getBoardReRef", boardForm);}/** 게시판 - 등록 */public int insertBoard(BoardForm boardForm) throws Exception {return sqlSession.insert(NAMESPACE + ".insertBoard", boardForm);}/** 게시판 - 첨부파일 등록 */public int insertBoardFile(BoardFileForm boardFileForm) throws Exception {return sqlSession.insert(NAMESPACE + ".insertBoardFile", boardFileForm);}/** 게시판 - 등록 실패(트랜잭션 테스트) */public int insertBoardFail(BoardForm boardForm) throws Exception {return sqlSession.insert(NAMESPACE + ".insertBoardFail", boardForm);}/** 게시판 - 삭제 */public int deleteBoard(BoardForm boardForm) throws Exception {return sqlSession.delete(NAMESPACE + ".deleteBoard", boardForm);}/** 게시판 - 수정 */public int updateBoard(BoardForm boardForm) throws Exception {return sqlSession.update(NAMESPACE + ".updateBoard", boardForm);}/** 게시판 - 답글 정보 조회 */public BoardDto getBoardReplyInfo(BoardForm boardForm) throws Exception {return sqlSession.selectOne(NAMESPACE + ".getBoardReplyInfo", boardForm);}/** 게시판 - 답글의 순서 수정 */public int updateBoardReSeq(BoardForm boardForm) throws Exception {return sqlSession.update(NAMESPACE + ".updateBoardReSeq", boardForm);}/** 게시판 - 답글 등록 */public int insertBoardReply(BoardForm boardForm) throws Exception {return sqlSession.insert(NAMESPACE + ".insertBoardReply", boardForm);}}cs 3_5) BoardService.java
Mybatis에 ServiceKey를 중복하여 사용할 수 없기 때문에 BoardReRef를 조회하는 쿼리를 추가하세요.더보기123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235package com.spring.board.service;import java.io.File;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.UUID;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;import org.springframework.web.multipart.MultipartFile;import com.spring.board.common.PagingUtil;import com.spring.board.common.ResultUtil;import com.spring.board.dao.BoardDao;import com.spring.board.dto.BoardDto;import com.spring.board.dto.CommonDto;import com.spring.board.form.BoardFileForm;import com.spring.board.form.BoardForm;import com.spring.board.form.CommonForm;@Servicepublic class BoardService {@Autowiredprivate BoardDao boardDao;/** 게시판 - 목록 조회 */public ResultUtil getBoardList(BoardForm boardForm) throws Exception {ResultUtil resultUtil = new ResultUtil();CommonDto commonDto = new CommonDto();int totalCount = boardDao.getBoardCnt(boardForm);if (totalCount != 0) {CommonForm commonForm = new CommonForm();commonForm.setFunction_name(boardForm.getFunction_name());commonForm.setCurrent_page_no(boardForm.getCurrent_page_no());commonForm.setCount_per_page(10);commonForm.setCount_per_list(10);commonForm.setTatal_list_count(totalCount);commonDto = PagingUtil.setPageUtil(commonForm);}boardForm.setLimit(commonDto.getLimit());boardForm.setOffset(commonDto.getOffset());List<BoardDto> list = boardDao.getBoardList(boardForm);HashMap<String, Object> resultMap = new HashMap<String, Object>();resultMap.put("list", list);resultMap.put("totalCount", totalCount);resultMap.put("pagination", commonDto.getPagination());resultUtil.setData(resultMap);resultUtil.setState("SUCCESS");return resultUtil;}/** 게시판 - 목록 조회 *//** public List<BoardDto> getBoardList(BoardForm boardForm) throws Exception {** return boardDao.getBoardList(boardForm); }*//** 게시판 - 상세 조회 */public BoardDto getBoardDetail(BoardForm boardForm) throws Exception {BoardDto boardDto = new BoardDto();String searchType = boardForm.getSearch_type();if ("S".equals(searchType)) {int updateCnt = boardDao.updateBoardHits(boardForm);if (updateCnt > 0) {boardDto = boardDao.getBoardDetail(boardForm);}} else {boardDto = boardDao.getBoardDetail(boardForm);}return boardDto;}/** 게시판 - 등록 */public BoardDto insertBoard(BoardForm boardForm) throws Exception {BoardDto boardDto = new BoardDto();int insertCnt = 0;int boardReRef = boardDao.getBoardReRef(boardForm);boardForm.setBoard_re_ref(boardReRef);insertCnt = boardDao.insertBoard(boardForm);List<BoardFileForm> boardFileList = getBoardFileInfo(boardForm);for (BoardFileForm boardFileForm : boardFileList) {boardDao.insertBoardFile(boardFileForm);}if (insertCnt > 0) {boardDto.setResult("SUCCESS");} else {boardDto.setResult("FAIL");}return boardDto;}/** 게시판 - 첨부파일 정보 조회 */public List<BoardFileForm> getBoardFileInfo(BoardForm boardForm) throws Exception {List<MultipartFile> files = boardForm.getFiles();List<BoardFileForm> boardFileList = new ArrayList<BoardFileForm>();BoardFileForm boardFileForm = new BoardFileForm();int boardSeq = boardForm.getBoard_seq();String fileName = null;String fileExt = null;String fileNameKey = null;String fileSize = null;// 파일이 저장될 Path 설정String filePath = "C:\\board\\file";if (files != null && files.size() > 0) {File file = new File(filePath);// 디렉토리가 없으면 생성if (file.exists() == false) {file.mkdirs();}for (MultipartFile multipartFile : files) {fileName = multipartFile.getOriginalFilename();fileExt = fileName.substring(fileName.lastIndexOf("."));// 파일명 변경(uuid로 암호화) + 확장자fileNameKey = getRandomString() + fileExt;fileSize = String.valueOf(multipartFile.getSize());// 설정한 Path에 파일 저장file = new File(filePath + "/" + fileNameKey);multipartFile.transferTo(file);boardFileForm = new BoardFileForm();boardFileForm.setBoard_seq(boardSeq);boardFileForm.setFile_name(fileName);boardFileForm.setFile_name_key(fileNameKey);boardFileForm.setFile_path(filePath);boardFileForm.setFile_size(fileSize);boardFileList.add(boardFileForm);}}return boardFileList;}/** 게시판 - 삭제 */public BoardDto deleteBoard(BoardForm boardForm) throws Exception {BoardDto boardDto = new BoardDto();int deleteCnt = boardDao.deleteBoard(boardForm);if (deleteCnt > 0) {boardDto.setResult("SUCCESS");} else {boardDto.setResult("FAIL");}return boardDto;}/** 게시판 - 수정 */public BoardDto updateBoard(BoardForm boardForm) throws Exception {BoardDto boardDto = new BoardDto();int deleteCnt = boardDao.updateBoard(boardForm);if (deleteCnt > 0) {boardDto.setResult("SUCCESS");} else {boardDto.setResult("FAIL");}return boardDto;}/** 게시판 - 답글 등록 */public BoardDto insertBoardReply(BoardForm boardForm) throws Exception {BoardDto boardDto = new BoardDto();BoardDto boardReplayInfo = boardDao.getBoardReplyInfo(boardForm);boardForm.setBoard_seq(boardReplayInfo.getBoard_seq());boardForm.setBoard_re_lev(boardReplayInfo.getBoard_re_lev());boardForm.setBoard_re_ref(boardReplayInfo.getBoard_re_ref());boardForm.setBoard_re_seq(boardReplayInfo.getBoard_re_seq());int insertCnt = 0;insertCnt += boardDao.updateBoardReSeq(boardForm);insertCnt += boardDao.insertBoardReply(boardForm);if (insertCnt > 0) {boardDto.setResult("SUCCESS");} else {boardDto.setResult("FAIL");}return boardDto;}/** 32글자의 랜덤한 문자열(숫자포함) 생성 */public static String getRandomString() {return UUID.randomUUID().toString().replaceAll("-", "");}}cs MulripartFile 인터페이스의 주요 메서드
String getName() : 파라미터 이름을 리턴
String getOriginalFilename() : 업로드 한 파일의 이름을 리턴
String isEmpty() : 업로드 한 파일이 존재하지 않는 경우 true를 리턴
long getSize() : 업로드 한 파일의 크기를 리턴
byte[ ] getBytes() throws IOExcetion : 업로드 한 파일 데이터를 리턴
InputStream getInputStream() throws IOException : 업로드한 파일 데이터를 읽어노는 InputStream을 리턴
void transferTo(File dest) throws IOException : 업로드 한 파일 데이터를 지정한 파일에 저장3_6) BoardController.java 수정
더보기123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117package com.spring.board.controller;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.ResponseBody;import com.spring.board.common.ResultUtil;import com.spring.board.dto.BoardDto;import com.spring.board.form.BoardForm;import com.spring.board.service.BoardService;@Controller@RequestMapping(value = "/board")public class BoardController {@Autowiredprivate BoardService boardService;/** 게시판 - 목록 페이지 이동 */@RequestMapping(value = "/boardList")public String boardList(HttpServletRequest request, HttpServletResponse response) throws Exception {return "board/boardList";}/** 게시판 - 목록 조회 */@RequestMapping(value = "/getBoardList")@ResponseBodypublic ResultUtil getBoardList(HttpServletRequest request, HttpServletResponse response, BoardForm boardForm) throws Exception {ResultUtil resultUtils = boardService.getBoardList(boardForm);return resultUtils;}/** 게시판 - 상세 페이지 이동 */@RequestMapping(value = "/boardDetail")public String boardDetail(HttpServletRequest request, HttpServletResponse response) throws Exception {return "board/boardDetail";}/** 게시판 - 상세 조회 */@RequestMapping(value = "/getBoardDetail")@ResponseBodypublic BoardDto getBoardDetail(HttpServletRequest request, HttpServletResponse response, BoardForm boardForm) throws Exception {BoardDto boardDto = boardService.getBoardDetail(boardForm);return boardDto;}/** 게시판 - 작성 페이지 이동 */@RequestMapping(value = "/boardWrite")public String boardWrite(HttpServletRequest request, HttpServletResponse response) throws Exception {return "board/boardWrite";}/** 게시판 - 등록 */@RequestMapping(value = "/insertBoard")@ResponseBodypublic BoardDto insertBoard(HttpServletRequest request, HttpServletResponse response, BoardForm boardForm) throws Exception {BoardDto boardDto = boardService.insertBoard(boardForm);return boardDto;}/** 게시판 - 삭제 */@RequestMapping(value = "/deleteBoard")@ResponseBodypublic BoardDto deleteBoard(HttpServletRequest request, HttpServletResponse response, BoardForm boardForm) throws Exception {BoardDto boardDto = boardService.deleteBoard(boardForm);return boardDto;}/** 게시판 - 수정 페이지 이동 */@RequestMapping(value = "/boardUpdate")public String boardUpdate(HttpServletRequest request, HttpServletResponse response) throws Exception {return "board/boardUpdate";}/** 게시판 - 수정 */@RequestMapping(value = "/updateBoard")@ResponseBodypublic BoardDto updateBoard(HttpServletRequest request, HttpServletResponse response, BoardForm boardForm) throws Exception {BoardDto boardDto = boardService.updateBoard(boardForm);return boardDto;}/** 게시판 - 답글 페이지 이동 */@RequestMapping(value = "/boardReply")public String boardReply(HttpServletRequest request, HttpServletResponse response) throws Exception {return "board/boardReply";}/** 게시판 - 답글 등록 */@RequestMapping(value = "/insertBoardReply")@ResponseBodypublic BoardDto insertBoardReply(HttpServletRequest request, HttpServletResponse response, BoardForm boardForm) throws Exception {BoardDto boardDto = boardService.insertBoardReply(boardForm);return boardDto;}}cs 4. Front-End 파일 수정 및 추가
4_1) jquery.form.js 추가
jquery.form.js룰 다운로드 후 추가하세요.
4_2) boardWrite.jsp 수정
- ajaxForm을 사용하기 위해서 jquery.form.js를 추가한 후에 import 하세요.
- <form> 태그에 enctype="multipart/form-data"을 추가하세요.
- <form> 태그에 method="POST"로 설정하세요.
- <input> 태그에 name은 BoardForm에 추가한 GET/SET명에 배열로 추가하세요. 예) files[0], files[1], files[2]더보기123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>게시판 작성</title><!-- 공통 CSS --><link rel="stylesheet" type="text/css" href="/css/common/common.css"/><!-- 공통 JavaScript --><script type="text/javascript" src="/js/common/jquery.js"></script><script type="text/javascript" src="/js/common/jquery.form.js"></script><script type="text/javascript">$(document).ready(function(){});/** 게시판 - 목록 페이지 이동 */function goBoardList(){location.href = "/board/boardList";}/** 게시판 - 작성 */function insertBoard(){var boardSubject = $("#board_subject").val();var boardContent = $("#board_content").val();if (boardSubject == ""){alert("제목을 입력해주세요.");$("#board_subject").focus();return;}if (boardContent == ""){alert("내용을 입력해주세요.");$("#board_content").focus();return;}var yn = confirm("게시글을 등록하시겠습니까?");if(yn){var filesChk = $("input[name='files[0]']").val();if(filesChk == ""){$("input[name='files[0]']").remove();}$("#boardForm").ajaxForm({url : "/board/insertBoard",enctype : "multipart/form-data",cache : false,async : true,type : "POST",success : function(obj) {insertBoardCallback(obj);},error : function(xhr, status, error) {}}).submit();}}/** 게시판 - 작성 콜백 함수 */function insertBoardCallback(obj){if(obj != null){var result = obj.result;if(result == "SUCCESS"){alert("게시글 등록을 성공하였습니다.");goBoardList();} else {alert("게시글 등록을 실패하였습니다.");return;}}}</script></head><body><div id="wrap"><div id="container"><div class="inner"><h2>게시글 작성</h2><form id="boardForm" name="boardForm" action="/board/insertBoard" enctype="multipart/form-data" method="post" onsubmit="return false;"><table width="100%" class="table02"><caption><strong><span class="t_red">*</span> 표시는 필수입력 항목입니다.</strong></caption><colgroup><col width="20%"><col width="*"></colgroup><tbody id="tbody"><tr><th>제목<span class="t_red">*</span></th><td><input id="board_subject" name="board_subject" value="" class="tbox01"/></td></tr><tr><th>작성자<span class="t_red">*</span></th><td><input id="board_writer" name="board_writer" value="" class="tbox01"/></td></tr><tr><th>내용<span class="t_red">*</span></th><td><textarea id="board_content" name="board_content" cols="10" rows="5" class="textarea01"></textarea></td></tr><tr><th scope="row">첨부파일</th><td><input type="file" id="files[0]" name="files[0]" value=""></td></tr></tbody></table></form><div class="btn_right mt15"><button type="button" class="btn black mr5" onclick="javascript:goBoardList();">목록으로</button><button type="button" class="btn black" onclick="javascript:insertBoard();">등록하기</button></div></div></div></div></body></html>cs 5. 첨부파일 업로드 확인
FILE_PATH 위치에 업로드한 첨부파일이 존재하는지 확인하세요.소스 코드는 Github Repository - https://github.com/tychejin1218/board_v1 (branch : section19) 를 참조하세요.
Github에서 프로젝트 가져오기 - https://tychejin.tistory.com/33반응형'Spring > 4.3.x - 게시판 만들기' 카테고리의 다른 글
[Spring] 게시판 만들기(21) - 게시글 수정(첨부파일 등록 및 삭제) (5) 2019.05.10 [Spring] 게시판 만들기(20) - 파일 다운로드(BeanNameViewResolver) (9) 2018.12.20 [Spring] 게시판 만들기(18) - 계층형 게시판(답글쓰기) 적용 (11) 2018.12.19 [Spring] 게시판 만들기(17) - 페이징(Paging) 처리 (31) 2018.12.19 [Spring] 게시판 만들기(16) - 트랜잭션(Transaction) 설정 (11) 2018.12.19