첨부파일 - project: ex03
1. UUID 랜덤값으로 첨부파일 생성
1) pom.xml --> 추가
<!-- 첨부파일 -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
</dependency>
<!-- 썸네일 -->
<dependency>
<groupId>org.imgscalr</groupId>
<artifactId>imgscalr-lib</artifactId>
<version>4.2</version>
</dependency>
<!-- @Resource 인식 -->
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>1.3.2</version>
</dependency>
2) resources 에 upload 폴더 생성
3) servlet-context.xml --> 추가
ㄴ> upload 폴더 경로 확인할 것(c드라이브 -> spring -> ....)
<!-- 첨부파일 용량 제한 및 경로 -->
<beans:bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<beans:property name="maxUploadSize" value="10485760"></beans:property>
</beans:bean>
<beans:bean id="uploadPath" class="java.lang.String">
<beans:constructor-arg value="C:\\spring\\ex03\\src\\main\\webapp\\resources\\upload"></beans:constructor-arg>
</beans:bean>
4) UploadControllerA.java
package org.zerock.controller;
import java.io.File;
import java.util.UUID;
import javax.annotation.Resource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
@Controller
public class UploadControllerA {
private static final Logger logger = LoggerFactory.getLogger(UploadControllerA.class);
// 첨부파일 저장 경로
@Resource(name = "uploadPath") // servlet-context.xml에 있는 bean id="uploadPath" 경로 매칭
private String uploadPath;
@RequestMapping(value = "/uploadForm", method = RequestMethod.GET)
public void uploadFormGet() { // void이므로 uploadForm.jsp forward
}
//한글 파일 이름이 깨진다면 web.xml에 한글 처리용 필터를 적용
@RequestMapping(value = "/uploadForm", method = RequestMethod.POST)
public String uploadFormPost(MultipartFile file, RedirectAttributes rttr) throws Exception {
logger.info("originalName: " + file.getOriginalFilename());
logger.info("size: " + file.getSize()); //byte 단위
logger.info("contentType: " + file.getContentType());
String savedName = uploadFile(file.getOriginalFilename(), file.getBytes());
rttr.addFlashAttribute("savedName",savedName);
return "redirect:/uploadForm";
}
// UUID 중복되지 않는 고유한 키 값을 설정할 때 사용
// uploadFile()은 원본 파일의 이름과 파일 데이터를 byte[]로 변환한 정보를 파라미터로 처리해서 실제로 파일 업로드한다.
private String uploadFile(String originalName, byte[] fileData) throws Exception {
UUID uid = UUID.randomUUID();
String savedName = uid.toString() + "_" + originalName;
// import java.io.File;
File target = new File(uploadPath, savedName);
// FileCopyUtils는 'org.springframework.util' 패키지에 설정된 클래스(실제 파일 처리)
FileCopyUtils.copy(fileData, target);
return savedName;
}
}
5) uploadForm.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ include file="/WEB-INF/views/include/header.jsp" %>
<hr>
<form method="post" enctype="multipart/form-data">
<input multiple="multiple" type="file" name='file'> <!-- spring에서는 input에 multiple="multiple" 필수로 적어야함 -->
<input type='submit' value="확인">
</form>
<hr>
업로드 성공 파일명 : ${savedName }
</body>
</html>
6) header.jsp --> 추가
<a href="/uploadAjax">[uploadAjax]</a>
<a href="/uploadForm2">[uploadForm2]</a>
<a href="/uploadForm">[uploadForm]</a>
2. 년월일시분초로 생성
1) UploadControllerB.java
package org.zerock.controller;
import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.annotation.Resource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.multipart.MultipartFile;
@Controller
public class UploadControllerB {
private static final Logger logger = LoggerFactory.getLogger(UploadControllerB.class);
// 첨부파일 저장 경로
// servlet-context.xml에 있는 bean id="uploadPath" 경로 매칭
@Resource(name = "uploadPath")
private String uploadPath;
@RequestMapping(value = "/uploadForm2", method = RequestMethod.GET)
public void uploadFormGet() {
logger.info("============= uploadForm2 : get ================");
}
//한글 파일 이름이 깨진다면 web.xml에 한글 처리용 필터를 적용
@RequestMapping(value = "/uploadForm2", method = RequestMethod.POST)
public String uploadFormPost(MultipartFile[] file, Model model) throws Exception {
logger.info("============= uploadForm2 : post ================");
logger.info("============= file.length ====:"+file.length);
String savedName[] = new String[file.length]; //저장 파일명 배열 처리
for(int i=0; i<file.length; i++) {
if(file[i].getSize() > 0) { //파일크기가 0보다 크다면 : 파일 유무 (처리안하면 안올렸을 때도 이상한 이미지 들어감)
logger.info("originalName: " + file[i].getOriginalFilename());
logger.info("size: " + file[i].getSize()); //byte 단위
logger.info("contentType: " + file[i].getContentType());
Date today = new Date();
SimpleDateFormat cal = new SimpleDateFormat("yyyyMMddhhmmss");
String signdate = cal.format(today);
savedName[i] = signdate + "_" + file[i].getOriginalFilename(); //날짜_파일명 처리
byte[] fileData = file[i].getBytes();
logger.info("============= savedName["+i+"] ====:"+savedName[i]);
File target = new File(uploadPath, savedName[i]);
FileCopyUtils.copy(fileData, target); //파일 업로드
}
}
return "redirect:/uploadForm2";
}
}
2) uploadForm2.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ include file="/WEB-INF/views/include/header.jsp" %>
<hr>
<form method="post" enctype="multipart/form-data">
<input multiple="multiple" type='file' name='file'> <!-- name은 동일하게 file로! -->
<input multiple="multiple" type='file' name='file'> <input type='submit' value="확인">
</form>
<hr>
</body>
</html>
3. 썸네일 구현
1) UploadControllerB.java --> 추가
//복사 붙여넣기 하자 (썸네일 import 세개)
import java.awt.Graphics;
import java.awt.Image;
import java.awt.image.BufferedImage;
// 첫 이미지 썸네일
if(i == 0) {
String new_name = "thum_" + savedName[0]; //썸네일 파일 이름
//사이즈 크기
int w = 50;
int h = 50;
String imgFormat = "jpg"; //기본 설정 초기화
Image image = ImageIO.read(new File(uploadPath+"\\"+savedName[0])); //원본 이미지
if(image != null) { //이미지 파일이 아닌 경우 null
Image resizeImage = image.getScaledInstance(w,h,Image.SCALE_SMOOTH);
BufferedImage newImage = new BufferedImage(w,h,BufferedImage.TYPE_INT_BGR);
Graphics g = newImage.getGraphics();
g.drawImage(resizeImage, 0, 0, null);
g.dispose();
ImageIO.write(newImage, imgFormat, new File(uploadPath+"\\"+new_name)); //파일 올리기
}
}
4. ajax 이용
ㄴ> js로 유효성 검사 하기(이미지 파일을 올렸는지 다른 파일인지)
ㄴ> restcontroller
ㄴ> controller 사용 -- @ResponseBody 필요
1) UploadController.java
package org.zerock.controller;
import java.io.File;
import java.util.UUID;
import javax.annotation.Resource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
@Controller
public class UploadController {
private static final Logger logger = LoggerFactory.getLogger(UploadController.class);
// 첨부파일 저장 경로
// servlet-context.xml에 있는 bean id="uploadPath" 경로 매칭
@Resource(name = "uploadPath")
private String uploadPath;
@RequestMapping(value = "/uploadAjax", method = RequestMethod.GET)
public void uploadAjax() {
}
// @ResponseBody : 요청이 온 데이터(JSON, XML)가 그대로 전송될 것임을 명시한다.
@ResponseBody
@RequestMapping(value ="/uploadAjax", method=RequestMethod.POST, produces = "text/plain;charset=UTF-8")
public ResponseEntity<String> uploadAjax(MultipartFile file) throws Exception{
logger.info("originalName: " + file.getOriginalFilename());
logger.info("size: " + file.getSize());
logger.info("contentType: " + file.getContentType());
return new ResponseEntity<>(file.getOriginalFilename(),HttpStatus.CREATED);
// HttpStatus.OK, HttpStatus.CREATED 정상적으로 생성되었다는 상태 코드
}
// UUID 중복되지 않는 고유한 키 값을 설정할 때 사용
// uploadFile()은 원본 파일의 이름과 파일 데이터를 byte[]로 변환한 정보를 파라미터로 처리해서 실제로 파일 업로드한다.
private String uploadFile(String originalName, byte[] fileData) throws Exception {
UUID uid = UUID.randomUUID();
String savedName = uid.toString() + "_" + originalName;
File target = new File(uploadPath, savedName);
// FileCopyUtils는 'org.springframework.util' 패키지에 설정된 클래스(실제 파일 처리)
FileCopyUtils.copy(fileData, target);
return savedName;
}
}
2) uploadAjax.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<style>
.fileDrop {
width: 100%;
height: 200px;
border: 1px dotted blue;
}
small {
margin-left: 3px;
font-weight: bold;
color: gray;
}
</style>
<script src="http://code.jquery.com/jquery-1.12.4.min.js"></script>
<script src="http://code.jquery.com/jquery-migrate-1.4.1.min.js"></script>
<h3>Ajax File Upload</h3>
<!-- 파일을 Drop and Down 영역 -->
<div class='fileDrop'></div>
<div class='uploadedList'></div>
<script>
$(".fileDrop").on("dragenter dragover", function(event) {
// 이벤트 처리를 제한한다.
// 파일을 영역에 끌어다 놓아도 아무런 변화가 없게 처리
event.preventDefault();
});
$(".fileDrop").on("drop", function(event){
event.preventDefault();
// event.originalEvent : 전달된 파일 데이터를 가져오는 부분
// event.dataTransfer : 이벤트와 같이 전돨된 데이터를 의미하고,
// 그 안에 포함된 파일 데이터를 찾아내기 위해서 dataTransfer.files를 이용한다.
var files = event.originalEvent.dataTransfer.files;
var file = files[0];
console.log(file);
// formData : <form> 태그로 만든 데이터 전송 방식과 동일하게 데이터를 전송할 수 있다.
var formData = new FormData();
formData.append("file", file); // 파일 객체를 추가
// 파일 데이터를 전송하기 위해서 processData, contentType 두 옵션을 반드시 false 지정
// 두개의 옵션은 데이터 전송을 <form> 태그를 이용하는 파일 업로드와 동일하게 해주는 역활
$.ajax({
url: '/uploadAjax',
data: formData,
dataType:'text',
processData: false,
contentType: false,
type: 'POST',
success: function(data){
alert(data);
}
});
});
</script>
</body>
</html>
3) package 생성 --> org.zerock.util
(1) UploadFileUtils.java
package org.zerock.util;
import java.io.File;
import java.text.DecimalFormat;
import java.util.Calendar;
import java.util.UUID;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import org.imgscalr.Scalr;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.FileCopyUtils;
public class UploadFileUtils {
private static final Logger logger = LoggerFactory.getLogger(UploadFileUtils.class);
// 파일 업로드 (저장 경로,원본 파일 이름,파일 데이터) 필요 요소 세가지
public static String uploadFile(String uploadPath, String originalName, byte[] fileData) throws Exception{
UUID uid = UUID.randomUUID();
String savedName = uid.toString() +"_"+originalName; //파일명 리네임
String savedPath = calcPath(uploadPath); //날짜별 폴더 생성 및 경로 설정(아래 메서드 참조)
File target = new File(uploadPath +savedPath,savedName);
FileCopyUtils.copy(fileData, target); //임시 폴더에 업로드된 파일을 지정 폴더로 복사
String formatName = originalName.substring(originalName.lastIndexOf(".")+1); //확장자
String uploadedFileName = null;
if(MediaUtils.getMediaType(formatName) != null){ //이미지 관련 확장자
uploadedFileName = makeThumbnail(uploadPath, savedPath, savedName);
}else{
uploadedFileName = makeIcon(uploadPath, savedPath, savedName);
}
return uploadedFileName;
}
// 이미지 타입의 파일이 아닌 경우 실행 문자열의 치환 용도에 불과
private static String makeIcon(String uploadPath, String path, String fileName)throws Exception{
String iconName = uploadPath + path + File.separator+ fileName;
return iconName.substring(uploadPath.length()).replace(File.separatorChar, '/');
}
// 썸네일 생성
private static String makeThumbnail(String uploadPath, String path, String fileName) throws Exception{
BufferedImage sourceImg = ImageIO.read(new File(uploadPath + path, fileName));
BufferedImage destImg =
Scalr.resize(sourceImg,
Scalr.Method.AUTOMATIC,
Scalr.Mode.FIT_TO_HEIGHT,100);
String thumbnailName = uploadPath + path + File.separator +"s_"+ fileName;
File newFile = new File(thumbnailName);
String formatName = fileName.substring(fileName.lastIndexOf(".")+1);
ImageIO.write(destImg, formatName.toUpperCase(), newFile);
return thumbnailName.substring(uploadPath.length()).replace(File.separatorChar, '/');
}
// 년/월/일 폴더 생성,파일저장
// 작성된 calcPath()의 리턴 값은 최종 결과 폴더를 반환하는데,
// 내부적으로 폴더를 생성해 주는 기능이 필요하기 때문에 기본적인 경로 uploadPath를 파라미터로 전달 받는다.
private static String calcPath(String uploadPath){
Calendar cal = Calendar.getInstance();
String yearPath = File.separator+cal.get(Calendar.YEAR);
String monthPath = yearPath + File.separator + new DecimalFormat("00").format(cal.get(Calendar.MONTH)+1);
String datePath = monthPath + File.separator + new DecimalFormat("00").format(cal.get(Calendar.DATE));
// 얻어낸 날짜 정보는 기본 경로롸 함께 makeDir()에 전달되어 폴더 생성된다.
makeDir(uploadPath,yearPath,monthPath,datePath);
logger.info(datePath);
return datePath;
}
//폴더 생성
private static void makeDir(String uploadPath, String... paths){
if(new File(uploadPath + paths[paths.length-1]).exists()){
return;
}
for (String path : paths) {
File dirPath = new File(uploadPath + path);
if(! dirPath.exists() ){
dirPath.mkdir();
}
}
}
}
(2) MediaUtils.java
package org.zerock.util;
import java.util.HashMap;
import java.util.Map;
import org.springframework.http.MediaType;
public class MediaUtils {
private static Map<String, MediaType> mediaMap;
static{
mediaMap = new HashMap<String, MediaType>();
mediaMap.put("JPG", MediaType.IMAGE_JPEG);
mediaMap.put("GIF", MediaType.IMAGE_GIF);
mediaMap.put("PNG", MediaType.IMAGE_PNG);
}
public static MediaType getMediaType(String type){
return mediaMap.get(type.toUpperCase()); // toUpperCase() 대문자로 변경
}
}
6) UploadController.java --> 수정 & 추가
@ResponseBody 부분
//return new ResponseEntity<>(file.getOriginalFilename(),HttpStatus.CREATED);
// HttpStatus.OK, HttpStatus.CREATED 정상적으로 생성되었다는 상태 코드
return new ResponseEntity<>(
UploadFileUtils.uploadFile(uploadPath,
file.getOriginalFilename(),
file.getBytes()),
HttpStatus.CREATED);
7) UploadController.java --> 추가
// 파일 화면 출력 부분
@ResponseBody
@RequestMapping("/displayFile")
public ResponseEntity<byte[]> displayFile(String fileName)throws Exception{
InputStream in = null;
ResponseEntity<byte[]> entity = null;
logger.info("FILE NAME: " + fileName);
try{
String formatName = fileName.substring(fileName.lastIndexOf(".")+1);
MediaType mType = MediaUtils.getMediaType(formatName);
HttpHeaders headers = new HttpHeaders();
in = new FileInputStream(uploadPath+fileName);
if(mType != null){
headers.setContentType(mType);
}else{
fileName = fileName.substring(fileName.indexOf("_")+1);
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
headers.add("Content-Disposition", "attachment; filename=\""+
new String(fileName.getBytes("UTF-8"), "ISO-8859-1")+"\"");
}
entity = new ResponseEntity<byte[]>(IOUtils.toByteArray(in),
headers,
HttpStatus.CREATED);
}catch(Exception e){
e.printStackTrace();
entity = new ResponseEntity<byte[]>(HttpStatus.BAD_REQUEST);
}finally{
in.close();
}
return entity;
}
// 첨부파일 삭제
@ResponseBody
@RequestMapping(value = "/deleteFile", method=RequestMethod.POST)
public ResponseEntity<String> deleteFile(String fileName){
logger.info("delete file: " + fileName);
String formatName = fileName.substring(fileName.lastIndexOf(".")+1);
MediaType mType = MediaUtils.getMediaType(formatName);
if(mType != null) {
String front = fileName.substring(0, 12);
String end = fileName.substring(14);
new File(uploadPath + (front + end).replace('/', File.separatorChar)).delete();
}
new File(uploadPath + fileName.replace('/', File.separatorChar)).delete();
return new ResponseEntity<String>("deleted", HttpStatus.OK);
}
8) uploadAjax.jsp --> 추가
수정
//alert(data);
//추가 페이지
var str ="";
if(checkImageType(data)){
str ="<div><a href=displayFile?fileName="+getImageLink(data)+">"
+"<img src='displayFile?fileName="+data+"'/>"
+"</a><small data-src="+data+">X</small></div>";
}else{
str = "<div><a href='displayFile?fileName="+data+"'>"
+ getOriginalName(data)+"</a>"
+"<small data-src="+data+">X</small></div></div>";
}
$(".uploadedList").append(str);
추가
//파일 삭제
$(".uploadedList").on("click", "small", function(event){
var that = $(this);
$.ajax({
url:"deleteFile",
type:"post",
data: {fileName:$(this).attr("data-src")},
dataType:"text",
success:function(result){
if(result == 'deleted'){
that.parent("div").remove(); //화면에서 삭제처리
}
}
});
});
<script>
// 파일 첨부시 이름만 뽑아오는 코드
function getOriginalName(fileName){
if(checkImageType(fileName)){
return;
}
var idx = fileName.indexOf("_") + 1 ;
return fileName.substr(idx);
}
function getImageLink(fileName){
if(!checkImageType(fileName)){
return;
}
var front = fileName.substr(0,12); //년,월,일 경로 추출하는 용도
var end = fileName.substr(14); //파일 이름 앞의 's_'까지의 값
return front + end; //'s_'값을 제외한 결과 값
}
//전송 문자열이 이미지 파일인지 확인 여부
function checkImageType(fileName){
var pattern = /jpg|gif|png|jpeg/i;
return fileName.match(pattern);
}
</script>
5. 트랜잭션
1) pom.xml
<!-- 트랜잭션 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${org.springframework-version}</version>
</dependency>
2) root-context.xml
(1) namespaces에서 tx 활성화하기
(2) 추가
<!-- 트랜젝션 처리 추가 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<tx:annotation-driven />
3) 첨부파일 table 생성
create table tbl_attach (
fullName varchar(150) not null, // 이름
bno int not null, // 부모값
regdate timestamp default now(), // 생성일
primary key(fullName)
);
4) BoardVO.java --> 추가
private String[] files;
5) BoardDAO.java --> 추가
public void addAttach(String fullName) throws Exception; //첨부파일 추가
6) BoardDAOImpl.java --> 추가
@Override
public void addAttach(String fullName) throws Exception {
session.insert(namespace+".addAttach",fullName);
}
7) boardMapper.xml --> 추가
<insert id="addAttach">
insert into tbl_attach (fullName, bno) values (#{fullName},LAST_INSERT_ID())
</insert>
8) BoardServiceImpl.java --> regist 수정
@Transactional
@Override
public void regist(BoardVO board) throws Exception {
dao.create(board);
//파일첨부
String[] files = board.getFiles();
if(files == null) { return; }
for(String fileName : files) {
dao.addAttach(fileName);
}
}
9) UploadSboardController.java
package org.zerock.controller;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import javax.annotation.Resource;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
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.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import org.zerock.util.MediaUtils;
import org.zerock.util.UploadFileUtils;
@Controller
@RequestMapping("/sboard/")
public class UploadSboardController {
private static final Logger logger = LoggerFactory.getLogger(UploadSboardController.class);
@Resource(name = "uploadPath")
private String uploadPath;
@RequestMapping(value = "/uploadAjax", method = RequestMethod.GET)
public void uploadAjax() {
}
// @ResponseBody : 요청이 온 데이터(JSON, XML)가 그대로 전송될 것임을 명시한다.
@ResponseBody
@RequestMapping(value ="/uploadAjax", method=RequestMethod.POST, produces="text/plain;charset=UTF-8")
public ResponseEntity<String> uploadAjax(MultipartFile file) throws Exception{
logger.info("originalName: " + file.getOriginalFilename());
logger.info("size: " + file.getSize());
logger.info("contentType: " + file.getContentType());
//return new ResponseEntity<>(file.getOriginalFilename(),HttpStatus.CREATED);
// HttpStatus.OK, HttpStatus.CREATED 정상적으로 생성되었다는 상태 코드
return new ResponseEntity<String>(
UploadFileUtils.uploadFile(uploadPath,
file.getOriginalFilename(),
file.getBytes()),
HttpStatus.CREATED);
}
// 파일 화면 출력 부분
@ResponseBody
@RequestMapping("/displayFile")
public ResponseEntity<byte[]> displayFile(String fileName)throws Exception{
InputStream in = null;
ResponseEntity<byte[]> entity = null;
logger.info("FILE NAME: " + fileName);
try{
String formatName = fileName.substring(fileName.lastIndexOf(".")+1);
MediaType mType = MediaUtils.getMediaType(formatName);
HttpHeaders headers = new HttpHeaders();
in = new FileInputStream(uploadPath+fileName);
if(mType != null){
headers.setContentType(mType);
}else{
fileName = fileName.substring(fileName.indexOf("_")+1);
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
headers.add("Content-Disposition", "attachment; filename=\""+
new String(fileName.getBytes("UTF-8"), "ISO-8859-1")+"\"");
}
entity = new ResponseEntity<byte[]>(IOUtils.toByteArray(in),
headers,
HttpStatus.CREATED);
}catch(Exception e){
e.printStackTrace();
entity = new ResponseEntity<byte[]>(HttpStatus.BAD_REQUEST);
}finally{
in.close();
}
return entity;
}
// 첨부파일 삭제
@ResponseBody
@RequestMapping(value = "/deleteFile", method=RequestMethod.POST)
public ResponseEntity<String> deleteFile(String fileName){
logger.info("delete file: " + fileName);
String formatName = fileName.substring(fileName.lastIndexOf(".")+1);
MediaType mType = MediaUtils.getMediaType(formatName);
if(mType != null) {
String front = fileName.substring(0, 12);
String end = fileName.substring(14);
new File(uploadPath + (front + end).replace('/', File.separatorChar)).delete();
}
new File(uploadPath + fileName.replace('/', File.separatorChar)).delete();
return new ResponseEntity<String>("deleted", HttpStatus.OK);
}
}
10) /sboard/register.jsp --> 추가
<!-- 아래 추가 -->
<style>
.fileDrop {
width: 80%;
height: 100px;
border: 1px dotted gray;
background-color: lightslategrey;
margin: auto;
}
small {
margin-left: 3px;
font-weight: bold;
color: gray;
}
</style>
<form id='registerForm' role="form" method="post"> <!-- 아이디 추가 -->
<tr>
<td>파일첨부</td>
<td><label for="exampleInputEmail1">File DROP Here</label>
<div class="fileDrop"></div>
<ul class="uploadedList"></ul>
</td>
</tr>
<!-- 아래 <스크립트> 모두 추가 -->
<script>
$(".fileDrop").on("dragenter dragover", function(event) {
// 이벤트 처리를 제한한다.
// 파일을 영역에 끌어다 놓아도 아무런 변화가 없게 처리
event.preventDefault();
});
$(".fileDrop").on("drop", function(event){
event.preventDefault();
// event.originalEvent : 전달된 파일 데이터를 가져오는 부분
// event.dataTransfer : 이벤트와 같이 전돨된 데이터를 의미하고,
// 그 안에 포함된 파일 데이터를 찾아내기 위해서 dataTransfer.files를 이용한다.
var files = event.originalEvent.dataTransfer.files;
var file = files[0];
//console.log(file);
// formData : <form> 태그로 만든 데이터 전송 방식과 동일하게 데이터를 전송할 수 있다.
var formData = new FormData();
formData.append("file", file); // 파일 객체를 추가
// 파일 데이터를 전송하기 위해서 processData, contentType 두 옵션을 반드시 false 지정
// 두개의 옵션은 데이터 전송을 <form> 태그를 이용하는 파일 업로드와 동일하게 해주는 역활
//url: 절대경로 슬러시 삭제
$.ajax({
url: 'uploadAjax',
data: formData,
dataType:'text',
processData: false,
contentType: false,
type: 'POST',
success: function(data){
//alert(data);
//추가 페이지
var str ="";
if(checkImageType(data)){
str ="<div><a href=displayFile?fileName="+getImageLink(data)+">"
+"<img src='displayFile?fileName="+data+"'/>"
+"</a><small data-src="+data+" style='cursor:pointer' title='삭제'>X</small></div>";
}else{
str = "<div><a href='displayFile?fileName="+data+"'>"
+ getOriginalName(data)+"</a>"
+"<small data-src="+data+" style='cursor:pointer' title='삭제'>X</small></div></div>";
}
$(".uploadedList").append(str);
}
});
});
$(".uploadedList").on("click", "small", function(event){
var that = $(this);
//url: 절대경로 슬러시 삭제
$.ajax({
url:"deleteFile",
type:"post",
data: {fileName:$(this).attr("data-src")},
dataType:"text",
success:function(result){
if(result == 'deleted'){
that.parent("div").remove();//화면에서 삭제처리
}
}
});
});
//삭제 설명
//사용자가 <small>태그로 처리된 'x'를 클릭하면
//'data-src'속성값으로 사용된 파일의 이름을 얻어와서 POST 방식으로 호출처리
//글쓰기 버튼 클릭시 첨부내용 <input>태크 포함 처리
$("#registerForm").submit(function(event){
event.preventDefault();
var that = $(this);
var str ="";
$(".uploadedList small").each(function(index){
str += "<input type='text' name='files["+index+"]' value='"+$(this).attr("data-src") +"'> ";
});
alert(str);
that.append(str);
that.get(0).submit();
});
</script>
<script>
// 파일 첨부시 이름만 뽑아오는 코드
function getOriginalName(fileName){
if(checkImageType(fileName)){
return;
}
var idx = fileName.indexOf("_") + 1 ;
return fileName.substr(idx);
}
function getImageLink(fileName){
if(!checkImageType(fileName)){
return;
}
var front = fileName.substr(0,12); //년,월,일 경로 추출하는 용도
var end = fileName.substr(14); //파일 이름 앞의 's_'까지의 값
return front + end; //'s_'값을 제외한 결과 값
}
//전송 문자열이 이미지 파일인지 확인 여부
function checkImageType(fileName){
var pattern = /jpg|gif|png|jpeg/i;
return fileName.match(pattern);
}
</script>
11) BoardDAO.java --> 추가
public List<String> getAttach(Integer bno) throws Exception; // 첨부파일 list 보기(view 페이지에서)
12) BoardDAOImpl.java --> 추가
@Override
public List<String> getAttach(Integer bno) throws Exception {
return session.selectList(namespace+".getAttach", bno);
}
13) boardMapper.xml --> 추가
<select id="getAttach" resultType="string">
select fullName from tbl_attach where bno = #{bno} order by fullName asc
</select>
14) BoardService.java --> 추가
public List<String> getAttach(Integer bno) throws Exception;
15) BoardServiceImpl.java --> 추가
@Override
public List<String> getAttach(Integer bno) throws Exception {
return dao.getAttach(bno);
}
16) SearchBoardController.java --> 추가
@ResponseBody
@RequestMapping("/getAttach/{bno}")
public List<String> getAttach(@PathVariable("bno") Integer bno)throws Exception{
return service.getAttach(bno);
}
17) /sboard/read.jsp --> 추가
<!-- 이미지를 보여주기 위해 화면상 히든 처리 -->
<style type="text/css">
.popup { position: absolute;}
.back { background-color: gray; opacity:0.5; width: 10%; height: 20%; overflow:hidden; z-index:1101;}
.front {
z-index:1110; opacity:1; boarder:1px; margin: auto;
}
.show{
position:relative;
max-width: 100%;
max-height: 100%;
overflow: auto;
}
</style>
<div class='popup back' style="display:none;"></div>
<div id="popup_front" class='popup front' style="display:none;">
<img id="popup_img">
</div>
<center>
~~
<!-- 첨부파일 출력 부분 추가 -->
<table class="uploadedList"></table>
<!-- 첨부파일 출력에 관한 스크립트 -->
<script>
//첨부파일 정보
var bno = ${boardVO.bno}; //객체명 매칭 처리
$.getJSON("/sboard/getAttach/"+bno,function(list){
$(list).each(function(){
var fileInfo = getFileInfo(this);
var str_content = "";
if(checkImageType(this)){
str_content = "<tr><td class='info'><a href="+fileInfo.getLink+">"
+"<img src=/upload/"+fileInfo.fullName+"></td></tr>";
}else{
str_content = "<tr><td><a href="+fileInfo.getLink+">"+fileInfo.fullName+"</td></tr>";
}
$(".uploadedList").append(str_content);
});
});
//파일첨부 히든 영역에 큰 이미지로 보여주기
$(".uploadedList").on("click", ".info a", function(event){
var fileLink = $(this).attr("href");
if(checkImageType(fileLink)){
event.preventDefault();
var imgTag = $("#popup_img");
imgTag.attr("src", fileLink);
console.log(imgTag.attr("src"));
$(".popup").show('slow');
imgTag.addClass("show");
}
});
$("#popup_img").on("click", function(){
$(".popup").hide('slow');
});
//파일 정보 (이미지 판별)
function checkImageType(fileName){
var pattern = /jpg|gif|png|jpeg/i;
return fileName.match(pattern);
}
function getFileInfo(fullName){
var fileName,imgsrc, getLink;
var fileLink;
if(checkImageType(fullName)){
imgsrc = "/displayFile?fileName="+fullName;
fileLink = fullName.substr(14);
var front = fullName.substr(0,12); // /2021/08/11/
var end = fullName.substr(14); // 's_'
getLink = "/displayFile?fileName="+front + end;
}else{
imgsrc ="/resources/dist/img/file.png";
fileLink = fullName.substr(12);
getLink = "/displayFile?fileName="+fullName;
}
fileName = fileLink.substr(fileLink.indexOf("_")+1);
return {fileName:fileName, imgsrc:imgsrc, getLink:getLink, fullName:fullName};
}
</script>
<!-- 추가 끝 2 -->
<%@ include file="/WEB-INF/views/sboard/test.jsp" %>
</center>
'JAVA > spring' 카테고리의 다른 글
member_fullcode (0) | 2023.05.09 |
---|---|
이클립스에 spring 연동시키는 법 (0) | 2023.05.08 |
스프링 댓글 구현 (0) | 2023.05.04 |
스프링 member 구현 (0) | 2023.05.03 |
스프링 Board 구현_넘버링, 검색 (0) | 2023.05.03 |