데일리로그C:
article thumbnail
Published 2023. 5. 8. 14:12
스프링 첨부파일 구현 JAVA/spring

첨부파일 - 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
profile

데일리로그C:

@망밍

포스팅이 도움됐다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!

profile on loading

Loading...