본문 바로가기

Backend/Spring

4. STS / Mybatis 게시판에 이미지 업로드하고 다운로드 받기

결과 샷

1. 한글 이름의 파일은 미리보기가 불가능하고, 영어이름의 파일은 미리보기가 가능.

2. 다운로드는 당연히 모두다 가능

3. sqldeveloper에도 잘 올라가있음

 

1. pom.xml

<dependency>

    <groupId>org.mybatis</groupId>

    <artifactId>mybatis</artifactId>

    <version>3.2.8</version>

</dependency>

 

<dependency>

    <groupId>org.mybatis</groupId>

    <artifactId>mybatis-spring</artifactId>

    <version>1.2.2</version>

</dependency>

 

<dependency>

    <groupId>org.springframework</groupId>

    <artifactId>spring-jdbc</artifactId>

    <version>${org.springframework-version}</version>

</dependency>

 

 

<!-- 파일업로드를 위한 2개 디펜던시 -->

<dependency>

    <groupId>commons-fileupload</groupId>

    <artifactId>commons-fileupload</artifactId>

    <version>1.3.1</version>

</dependency>

 

<dependency>

    <groupId>commons-io</groupId>

    <artifactId>commons-io</artifactId>

    <version>2.4</version>

</dependency>

 

 

2. root-context.xml

 

<!-- MyBatis용 3개 bean -->

<bean id= "dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">

<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />

<property name="url" value="jdbc:oracle:thin:@자신의 오라클주소" />

<property name="username" value="오라클계정" />

<property name="password" value="오라클비밀번호" />

</bean>

 

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">

<property name="dataSource" ref="dataSource" />

<property name="mapperLocations" value="classpath:com/koreait/mybatis02/dao/mapper/*.xml" />

</bean>

 

<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">

<constructor-arg ref="sqlSessionFactory"/>

</bean>

 

<!-- 파일업로드 : CommonsMultipartResolver -->

<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">

<property name="defaultEncoding" value="utf-8" />

<property name="maxUploadSize" value="10485760" />  <!-- 10MB = 1024 * 1024 * 10 -->

</bean>

 

 

3. mapper.xml

 

<mapper namespace="com.koreait.mybatis02.dao.ImageboardDao"> // 매퍼가 들어있는 위치

 

<insert id="imageboardInsert">

INSERT

  INTO IMAGEBOARD

VALUES (IMAGEBOARD_SEQ.NEXTVAL, #{param1}, #{param2}, #{param3}, #{param4}, SYSDATE)

</insert>

 

<select id="imageboardList" resultType="com.koreait.mybatis02.dto.ImageboardDto"

SELECT *

  FROM IMAGEBOARD

</select>

 

</mapper>

 

 

4. controller 

 

 

5. Command

 

1) 리스트를 보여주는 커맨드

 

public class ImageboardListCommand implements ImageboardCommand {

 

@Override

public void execute(SqlSession sqlSession, Model model) {

 

ImageboardDao iDao = sqlSession.getMapper(ImageboardDao.class);

model.addAttribute("list", iDao.imageboardList());

 

}

 

}

 

2) 이미지를 업로드하는 커맨드 

public class ImageboardInsertCommand implements ImageboardCommand {

 

@Override

public void execute(SqlSession sqlSession, Model model) {

 

 

// model -> map -> multipartRequest -> each parameter

Map<String, Object> map = model.asMap();

MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) map.get("multipartRequest");

String writer = multipartRequest.getParameter("writer");

String title = multipartRequest.getParameter("title");

String content = multipartRequest.getParameter("content");

 

// if attached files are multiple, will save in List

// A type of attached files is MultipartFile

List<MultipartFile> fileList = multipartRequest.getFiles("files");

 

// checking whether attached files exists or not

if (fileList != null) {

 

// taking attachment file out from the list

for (MultipartFile file: fileList) {

 

// rechecking 

if ( file != null && !file.isEmpty() ) {

 

// separate name/ file extension from original file

// 1) no duplicate file name

// 2) 업로드할 파일의 제한

 

String originalFilename= file.getOriginalFilename();

String extName = originalFilename.substring(originalFilename.lastIndexOf(".")+1); // file extension

String saveFilename = null;

 

try {

// to avoid duplicated filename : originalfilename_uploadtime.file

saveFilename = originalFilename.substring(0, originalFilename.lastIndexOf("."))  // original filename

+ "_"  // _

+ System.currentTimeMillis()  // upload time

+ "."  // .

+ extName;  // file extension

// to get the path attachment will be saved

String realPath = multipartRequest.getSession().getServletContext().getRealPath("/resources/storage");

 

// to create a new path if there is no realPath(/resources/storage) on server

File directory = new File(realPath);

if ( !directory.exists() ) {

directory.mkdirs();

}

 

// to create a saveFile 

File saveFile = new File(realPath, saveFilename);

 

// to execute upload (save a file on server)

file.transferTo(saveFile);

 

// to save filename on DB

ImageboardDao iDao = sqlSession.getMapper(ImageboardDao.class);

iDao.imageboardInsert(writer, title, content, saveFilename);

 

} catch (Exception e) {

e.printStackTrace();

}

 

}

}

}

}

 

}

 

 

3) 다운로드이미지 커맨드

public class ImageboardDownloadCommand implements ImageboardCommand {

 

@Override

public void execute(SqlSession sqlSession, Model model) {

Map<String, Object> map = model.asMap();

HttpServletRequest request = (HttpServletRequest) map.get("request");

HttpServletResponse response = (HttpServletResponse) map.get("response");

 

String realPath = request.getServletContext().getRealPath("/resources/storage");

 

// 다운로드 파일 이름

// filename

// 업로드 할 때 파일 이름 : car.jpg

// 실제 저장된 파일 이름 : car_123456789.jpg

String filename = request.getParameter("filename");

 

// 확장자 분리

String extName = filename.substring(filename.lastIndexOf(".") + 1);  // 확장자 extName

 

// 마지막 밑줄(_) 이전까지 파일명 분리

String downloadFilename = filename.substring(0, filename.lastIndexOf("_")) +

  "." +

  extName;

// 다운로드 할 파일 준비

File file = new File(realPath, filename);

 

// 입출력 스트림 준비

BufferedInputStream bis = null;

BufferedOutputStream bos = null;

 

try {

// 다운로드는 사용자에게 돌려주는 응답의 개념이므로,

// response 처리를 해야 한다.

response.setHeader("Content-Type", "application/x-msdownload");

response.setHeader("Content-Disposition", "attachment; filename=" + new String(URLEncoder.encode(downloadFilename, "utf-8")));

response.setHeader("Content-Length", file.length() + "");

 

// 입출력 스트림 생성

bis = new BufferedInputStream(new FileInputStream(file));  // 다운로드 할 파일을 읽는 스트림

bos = new BufferedOutputStream(response.getOutputStream());  // 사용자와 연결된(사용자에게 출력하는) 스트림

 

// 입력스트림 -> 출력스트림 : 복사

FileCopyUtils.copy(bis, bos);

 

// 혹시 남아 있는 출력스트림의 데이터 모두 보내기

bos.flush();

 

} catch (Exception e) {

e.printStackTrace();

} finally {

try {

if (bos != null) { bos.close(); } // 입출력 스트림 닫아주기

if (bis != null) { bis.close();

} catch (Exception e) {

// TODO: handle exception

}

}

 

}

 

}

 

 

6. view (JSP)

jsp 로는 해당 컨트롤러로 이동하는 스크립트만 짜놨기 때문에 생략.