카테고리 없음
[Project][Spring] 이미지 파일 업로드 기능
321
2021. 4. 1. 23:15
pom.xml에 추가할 dependency
- commons-fileupload
- commons-io
<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>
servlet-context.xml에 추가할 bean
- multipartResolver - org.springframework.web.multipart.commons.CommonsMultipartResolver
- property항목 : maxUploadSize, maxInMemorySize, defaultEncoding
<beans:bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<beans:property name="maxUploadSize" value="52428800"/>
<beans:property name="maxInMemorySize" value="1000000"/>
<beans:property name="defaultEncoding" value="utf-8"/>
</beans:bean>
spring에서 지원하는 commons multipart resolver기능을 이용해 업로드 기능을 구현할 때 사용되는 프로퍼티를 추가해 준다.
ImageVO 클래스 작성
package kr.co.vo;
import java.util.Date;
public class ImageVO {
private String fileName;
private String uploadPath;
private String uuid;
private boolean isImage;
private int gno;
private String title;
private String content;
private String writer;
private Date bdate;
public ImageVO() { }
public ImageVO(String fileName, String uploadPath, String uuid, boolean isImage) {
super();
this.fileName = fileName;
this.uploadPath = uploadPath;
this.uuid = uuid;
this.isImage = isImage;
}
public int getGno() {
return gno;
}
public void setGno(int gno) {
this.gno = gno;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public String getWriter() {
return writer;
}
public void setWriter(String writer) {
this.writer = writer;
}
public Date getBdate() {
return bdate;
}
public void setBdate(Date bdate) {
this.bdate = bdate;
}
public String getFileName() {
return fileName;
}
public void setFileName(String fileName) {
this.fileName = fileName;
}
public String getUploadPath() {
return uploadPath;
}
public void setUploadPath(String uploadPath) {
this.uploadPath = uploadPath;
}
public String getUuid() {
return uuid;
}
public void setUuid(String uuid) {
this.uuid = uuid;
}
public boolean isImage() {
return isImage;
}
public void setImage(boolean isImage) {
this.isImage = isImage;
}
@Override
public String toString() {
return "ImageVO [fileName=" + fileName + ", uploadPath=" + uploadPath + ", gno=" + gno + ", title=" + title + ", content=" + content + ", writer=" + writer + ", bdate=" + bdate + "]";
}
}
galleyMapper.xml
<?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="galleryMapper">
<insert id="insert">
<![CDATA[
insert into myfile(gno, title, content, writer, filename, uploadpath)
values
(myfile_seq.nextVal, #{title}, #{content}, #{writer}, #{fileName}, #{uploadPath})
]]>
</insert>
<select id="select" resultType="kr.co.vo.ImageVO">
<![CDATA[
select gno, title, content, writer, bdate, filename, uploadpath
from
myfile
order by
gno desc ]]>
</select>
</mapper>
GalleryDAO
package kr.co.dao;
import java.util.List;
import kr.co.vo.ImageVO;
public interface GalleryDAO {
public void insert(ImageVO vo) throws Exception;
public List<ImageVO> select() throws Exception;
}
GalleryDAOImpl
package kr.co.dao;
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;
import kr.co.vo.ImageVO;
@Repository
public class GalleryDAOImpl implements GalleryDAO {
@Autowired
private SqlSession sqlSession;
@Override
public void insert(ImageVO vo) throws Exception {
sqlSession.insert("galleryMapper.insert", vo);
}
@Override public List<ImageVO> select() throws Exception {
return sqlSession.selectList("galleryMapper.select");
}
}
GalleryService
package kr.co.service;
import java.util.List;
import kr.co.vo.BoardVO;
import kr.co.vo.ImageVO;
public interface GalleryService {
public void insert(ImageVO vo) throws Exception;
public List<ImageVO> select() throws Exception;
}
GalleryServiceImpl
package kr.co.service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import kr.co.dao.GalleryDAO;
import kr.co.vo.ImageVO;
@Service
public class GalleryServiceImpl implements GalleryService {
@Autowired
public GalleryDAO dao;
@Override public void insert(ImageVO vo) throws Exception {
dao.insert(vo);
}
@Override public List<ImageVO> select() throws Exception {
return dao.select();
}
}
GalleryController
package kr.co.controller;
import java.io.File;
import java.util.ArrayList;
import java.util.UUID;
import javax.inject.Inject;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;
import kr.co.service.GalleryService;
import kr.co.util.GalleryUtils;
import kr.co.vo.ImageVO;
import net.coobird.thumbnailator.Thumbnails;
@Controller
@RequestMapping("/gallery/*")
public class GalleryController {
private static final Logger logger = LoggerFactory.getLogger(GalleryController.class);
@Inject
public GalleryService service;
private static final String uploadPath = "C:\\Program Files\\sts-3.9.14.RELEASE\\workspace\\001MyProject\\src\\main\\webapp" + "\\WEB-INF\\resources\\uploadImage";
private static final String thumbnailPath = "C:\\Program Files\\sts-3.9.14.RELEASE\\workspace\\001MyProject\\src\\main\\webapp" + "\\WEB-INF\\resources\\thumbnails";
private static ArrayList<ImageVO> uploadList = new ArrayList<ImageVO>();
@RequestMapping(value = "/list", method = RequestMethod.GET)
private ModelAndView thumbnailView(HttpServletResponse response) throws Exception {
ModelAndView mv = new ModelAndView();
mv.addObject("list", service.select());
mv.setViewName("gallery/list");
return mv;
}
@RequestMapping(value = "/write", method = RequestMethod.GET)
public String write() throws Exception {
return "gallery/write";
}
@ResponseBody
@RequestMapping(value = "/upload", method = RequestMethod.POST)
public ArrayList<ImageVO> uploadAjax(@RequestParam MultipartFile[] uploadFile) throws Exception {
File uploadFolder = GalleryUtils.makeFolder(uploadPath);
for (MultipartFile multipartFile : uploadFile) {
String fileName = multipartFile.getOriginalFilename();
logger.info("name " + fileName + " size " + multipartFile.getSize());
String uuid = UUID.randomUUID().toString();
fileName = uuid + "_" + fileName;
File saveFile = new File(uploadFolder, fileName);
ImageVO vo = new ImageVO(fileName, uploadFolder.toString(), uuid, true);
if (GalleryUtils.checkImage(saveFile)) {
uploadList.add(vo);
multipartFile.transferTo(saveFile);
}
if(saveFile.getName().equals(uploadList.get(0).getFileName())) {
String thumbnailName="thumbnail_"+uploadList.get(0).getFileName();
File thumbnailFile = new File(thumbnailPath, thumbnailName);
Thumbnails.of(saveFile).size(250, 250).toFile(thumbnailFile);
}
}
return uploadList;
}
@RequestMapping(value = "/uploadContent", method = RequestMethod.POST)
public String send(HttpServletRequest request) throws Exception {
ImageVO uploadVO = new ImageVO();
uploadVO.setFileName(uploadList.get(0).getFileName());
uploadVO.setUploadPath(uploadList.get(0).getUploadPath());
logger.info("---------send success-------------");
String title = (String) request.getParameter("title");
String content = (String) request.getParameter("content");
uploadVO.setTitle(title);
uploadVO.setContent(content);
uploadVO.setWriter("글쓴ㅇㅣ");
logger.info(title + content + uploadList.toString());
service.insert(uploadVO); return "redirect:/gallery/list";
}
}
- upload(이미지업로드)
- 1. uploadPath라는 경로에 폴더를 하나 만들고
- 2. upload 할 다중파일을 가져와서
- 3. 원래 이름과 새로 만든 랜덤아이디(uuid)를 합쳐서 파일이름을 만들어준다.
- 4. 파일을 saveFile이라는 이름으로 새로 정의하면서 3의 새로 만든 이름과 1번에서 만든 폴더에 만들어주고
- 5. 이것들을 VO에 담아서(이미지인지 체크하고 맞으면) uploadList에 담아준다.
- 6. 4번의 파일은 그냥 파일껍데기였으므로 아까 받아온 multipartFile을 transfer 해서 담아준다.
- 7. 계속 for문이 돌아가고 있는 상태이므로 첫 번째 파일만 썸네일로 만들고 싶어서 저장한 파일의 이름이 uploadList의 첫 번째인지 확인하고 맞다면 썸네일을 만들어준다.
- 8. 썸네일파일 이름과 파일은 saveFile과 비슷한 방법으로 만들어주지만 Thumbnails.of(파일이름). size(가로, 세로). toFile(썸파일껍데기); -> 썸네일 파일 사진 크기를 만들어주는 것.
- uploadContent(글 업로드)
- 위에서 업로드한 이미지를 글이랑 같이 올려야 하므로 jsp에서 글제목, 글내용, 글쓴이 등의 데이터를 받아와서 업로드한 파일의 첫 번째 이름, 경로와 함께 DB에 등록한다.
GalleryUtils
- 컨트롤러에서 기능하는 세세한 것들을 밖으로 빼서 코드가 너무 길어지거나 복잡해지지 않게 함
package kr.co.util;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.multipart.MultipartFile;
import kr.co.controller.GalleryController;
import net.coobird.thumbnailator.Thumbnailator;
public class GalleryUtils {
private static final Logger logger = LoggerFactory.getLogger(GalleryController.class);
private static int folderNameIndex = 0;
public static String getFolderName() {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
String folderName = sdf.format(new Date());
folderName = folderName.replace("-", File.separator) +"_" + folderNameIndex;
return folderName;
}
public static File makeFolder(String uploadPath) {
logger.info(GalleryUtils.getFolderName());
File uploadFolder = new File(uploadPath, getFolderName());
if (!uploadFolder.exists()) {
uploadFolder.mkdirs(); folderNameIndex++;
}
return uploadFolder;
}
public static void makeThumbnail(MultipartFile multipartFile, String thumbnailPath, String fileName) throws Exception {
FileOutputStream thumbnail = new FileOutputStream(new File(thumbnailPath, "thumbnail_" + fileName));
Thumbnailator.createThumbnail(multipartFile.getInputStream(), thumbnail, 2048, 2048);
thumbnail.write(200);
thumbnail.close();
}
public static boolean checkImage(File file) throws Exception {
boolean returnValue = false;
String type = Files.probeContentType(file.toPath());
if (type.startsWith("image")) {
returnValue = true;
}
return returnValue;
}
}
todo
- 원본파일과 썸파일을 분리해야 할까?
- uploadContent의 setFileName을 설정할 때 썸네일파일만 올라가나? 2개 이상의 파일이름을 db에 담아줘야 하지 않을까? 경로만 저장해도 괜찮을까?
- 글쓴이 부분 로그인하면 바뀌도록 설정.
- upload주소를 /uploadImage로 바꾸면 더 명확해질 것