티스토리 뷰

728x90
반응형

Step01 - www.dropzonejs.com/#installation 

해당 링크로 이동하여 dropzone을 다운로드 받는다. 다운로드 받은 dropzone을 자신의 프로젝트 폴더에 담아두고 경로 설정

1
2
<link href="/resources/plugins/dropzone-5.7.0/dist/dropzone.css" rel="stylesheet">
<script src="/resources/plugins/dropzone-5.7.0/dist/dropzone.js"></script>
cs

 

Step02 - 해당 프로젝트의 pom.xml 설정

1
2
3
4
5
6
<!-- 파일업로드 관련-->
<dependency>
    <groupId>commons-fileupload</groupId>
    <artifactId>commons-fileupload</artifactId>
    <version>1.3.2</version>
</dependency>
cs

 

Step03 - servlet-context.xml에 multipart 설정

1
2
3
4
5
6
7
<!-- 파일 업로드를 처리하는 객체 생성-->
<beans:bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    <beans:property name="defaultEncoding" value="utf-8"></beans:property>
    <beans:property name="maxUploadSize" value="104857560"></beans:property>
    <beans:property name="uploadTempDir" value="file:C:\upload\tmp"></beans:property>
    <beans:property name="maxInMemorySize" value="10485756"></beans:property>
</beans:bean>
cs

 

Step04 - Database 생성

ㆍfk_code - 게시판의 참조 code

ㆍorigin_name - 첨부파일 이름

ㆍthumb_name - 첨부파일 썸네일 이름

 

Step05 - Vo Class 생성

1
2
3
4
5
6
7
8
9
10
11
12
package com.kdg.domain;
 
import lombok.Data;
 
@Data
public class CommonFileVo {
    private int code;
    private int fk_code;
    private String origin_name;
    private String thumb_name;
}
 
cs

 

Step06 - 쿼리문 작성을 위한 Mapper Interface 생성

ㆍ write() - 첨부파일 등록

ㆍ write_code() - 첨부파일 등록한 insert 쿼리문의 code

ㆍ view() - 첨부파일 조회

ㆍ delete() - 첨부파일 삭제

ㆍ CommonFileList() - 첨부파일 리스트

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package com.kdg.mapper;
 
import 생략...
 
public interface CommonFileMapper {
    
    public boolean write(CommonFileVo commonFileVo);
    
    public CommonFileVo write_code(int fk_code);
 
    public CommonFileVo view(int code);
    
    public boolean delete (int code);
    
    public List<Map<String, Object>> CommonFileList(int fk_code);
}
 
cs

 

Step07 - Mapper Interface를 이용한 Mapper.xml 생성

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
         PUBLIC "-//mybatis.org//DTO Mapper 3.0//EN"
         "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.kdg.mapper.CommonFileMapper">
    <insert id="write">
        INSERT INTO common_file (fk_code, origin_name, thumb_name) VALUES (#{fk_code}, #{origin_name}, #{thumb_name})
    </insert>
    
    <select id="write_code" resultType="com.kdg.domain.CommonFileVo">
        SELECT * FROM common_file WHERE fk_code = #{fk_code} ORDER BY CODE DESC LIMIT 1 OFFSET 0
    </select>
    
    <select id="view" resultType="com.kdg.domain.CommonFileVo">
        select * from common_file where code = #{code}
    </select>
    
    <delete id="delete">
        delete from common_file where code = #{code}
    </delete>
    
    <select id="CommonFileList" resultType="hashmap">
        SELECT * FROM common_file WHERE fk_code = #{fk_code} 
    </select>
</mapper>
cs

 

Step08 - Mapper Interface를 이용한 Service Interface 생성

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package com.kdg.service;
 
import 생략...;
 
public interface CommonFileService {
    
    public boolean write(CommonFileVo commonFileVo);
    
    public CommonFileVo write_code(int fk_code);
    
    public CommonFileVo view(int code);
    
    public boolean delete(int code);
    
    public List<Map<String, Object>> CommonFileList(int fk_code);
}
 
cs

 

Step09 - Service Interface를 구현한 ServiceImpl Class 생성

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
package com.kdg.service;
 
import 생략...
 
@Service
@AllArgsConstructor
public class CommonFileServiceImpl implements CommonFileService{
    
    @Setter(onMethod_ = @Autowired)
    private CommonFileMapper commonFileMapper;
    
    @Override
    public boolean write(CommonFileVo commonFileVo) {
        return commonFileMapper.write(commonFileVo);
    }
    
    @Override
    public CommonFileVo write_code(int fk_code) {
        return commonFileMapper.write_code(fk_code);
    }
    
    @Override
    public CommonFileVo view(int code) {
        return commonFileMapper.view(code);
    }
 
    @Override
    public boolean delete(int code) {
        return commonFileMapper.delete(code);
    }
 
    @Override
    public List<Map<String, Object>> CommonFileList(int fk_code) {
        return commonFileMapper.CommonFileList(fk_code);
    }
}
 
cs

 

Step10 - 첨부파일을 컨트롤하는 CommonFileController Class 생성

ㆍ Ajax를 이용하여 첨부파일을 등록하므로 메서드 상단에 @ResponseBody를 추가해야한다. 이거 안해서 30분을 날렸다ㅠㅠ

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
package com.kdg.controller;
 
import 생략...
 
@Controller
@RequestMapping("/commonfile/*")
@AllArgsConstructor
public class CommonFileController {
    private static final String UPLOAD_PATH = "C:\\upload\\tmp";
    private CommonFileService commonFileService;
 
    @PostMapping("/do_upload")
    @ResponseBody
    public int do_upload(MultipartFile files, int fk_code, CommonFileVo commonFileVo) {
        String thumb_name = saveFile(files);
        
        commonFileVo.setFk_code(fk_code);
        commonFileVo.setOrigin_name(files.getOriginalFilename());
        commonFileVo.setThumb_name(thumb_name);
        
        commonFileService.write(commonFileVo); // 첨부파일 등록
        
        return commonFileService.write_code(fk_code).getCode(); // 등록한 첨부파일의 code return
    }
    
    private String saveFile(MultipartFile file){
        
        UUID uuid = UUID.randomUUID();
        String saveName = uuid + "_" + file.getOriginalFilename();
        
        // 저장할 File 객체를 생성(껍데기 파일)
        File saveFile = new File(UPLOAD_PATH,saveName); // 저장할 폴더 이름, 저장할 파일 이름
 
        try {
            file.transferTo(saveFile); // 업로드 파일에 saveFile이라는 껍데기 입힘
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
 
        return saveName;
    } 
    
    @PostMapping("/do_delete")
    @ResponseBody
    public boolean do_delete(int code) {
        CommonFileVo commonFileVo = commonFileService.view(code);
        
        File file = new File(UPLOAD_PATH +"\\"+ commonFileVo.getThumb_name());
        
        if(file.exists()){ 
            file.delete(); //파일 삭제
        }
        
        return commonFileService.delete(code);
    }
}
 
cs

 

Step11 - 첨부파일을 올리는 jsp 파일

1
2
3
4
5
6
7
8
9
10
<div class="form-group row">
    <label class="col-sm-2">첨부파일</label>    
    <div class="col-sm-10">
        <div class="dropzone" id="fileDropzone">
            <div class="dz-message needsclick">
                여기에 파일을 끌어 놓거나 업로드하려면 클릭하십시오.
            </div>
        </div>
    </div>
</div>
cs

 

스크립트 부분

ㆍ해당 게시물의 첨부파일의 갯수를 가져오는 부분은 BoardController Class에 있다. 하단 스크룰 시 첨부

ㆍ${fn:length()} 를 사용하기 위해서는 아래의 jstl이 필요하다.

1
 <%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
cs

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
<script type="text/javascript">
Dropzone.autoDiscover = false;
  $(document).ready(function(){
      var fileCount = ${fn:length(commonFileList)}; //해당 게시물의 첨부파일의 갯수
      
      Dropzone.autoDiscover = false;
      var myDropzone = new Dropzone(".dropzone", {
        url: '/commonfile/do_upload'// 파일 업로드할 url
        method: "POST",
        paramName: 'files',
        params: {
            fk_code:${board.code}
        },
        addRemoveLinks: true,
        dictRemoveFile: "삭제",
        init: function() {
            if(fileCount > 0){
                 var thisDropzone = this;
                 
                 <c:forEach items="${commonFileList}" var="files">
                    var mockFile = {
                          code: "${files.code}",
                          name"${files.origin_name}",
                          path: "/resources/imgs/${files.thumb_name}"
                        };
                    thisDropzone.emit("addedfile", mockFile);
                    thisDropzone.emit("thumbnail", mockFile, mockFile.path);
                    thisDropzone.emit("complete", mockFile);
                    thisDropzone.files.push(mockFile);
                </c:forEach>
            }
        },
        removedfile: function(file) {
          // 파일 삭제 시
          var code = file.code == undefined ? file.temp : file.code; // 파일 업로드시 return 받은 code값
          console.log('code: ' + code);
            $.ajax({
                type: 'POST',
                url: '/commonfile/do_delete'// 파일 삭제할 url
                data: {code: code},
                success: function(data) {
                    console.log('success: ' + data);
                }
            });
     
            var _ref;
            return (_ref = file.previewElement) != null ? _ref.parentNode.removeChild(file.previewElement) : void 0;
        }
        , success: function (file, response) {
          // 파일 업로드 성공 시
           file.temp = JSON.parse(response); // 파일을 삭제할 수도 있으므로 변수로 저장
        }
      });
  });
</script>
 
cs

 

Step11 - BoardController Class 수정

ㆍ해당 게시물에 접근 시 첨부파일의 리스트를 가져와서 view단으로 데이터를 넘겨준다.

ㆍcommonFileService.CommonFileList();

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package com.kdg.controller;
 
@Controller
@RequestMapping("/board/*")
@AllArgsConstructor
public class BoardController {
    
    private BoardService service;
    private CommonFileService commonFileService;
    
    @GetMapping({"/get""/modify"})
    public void get(@RequestParam("code"int code, Model model) {
        
        model.addAttribute("board", service.get(code));
        model.addAttribute("commonFileList", commonFileService.CommonFileList(code));
    }
}
 
cs

 

Step12 - 결과 화면

ㆍ해당 게시물로 들어오면 Dropzone의 init function이 먼저 실행되어 첨부파일 리스트 출력

ㆍ삭제 버튼 클릭시 Dropzone의 removedfile function이 살행되어 CommonFileController 호출, 호출할때 컨트롤러 단에서 작성시 return 받은 자신의 code를 가지고 감

728x90
반응형