티스토리 뷰

Back-end/Spring

Spring 파일업로드 하기

이안_ian 2019. 2. 23. 22:42




반응형

오늘은 스프링에서 파일 업로드를 해볼 계획이다. 전체적으로 MVC1패턴과 유사하게 진행된다. 하지만 중간에 service부분에서 기존의 방식과는 좀 다른 방식으로 진행되는 부분이 있으니 그 점에서 유의하면 될 것 같다.


1. 라이브러리 추가하기

1
2
3
4
5
6
7
8
9
10
11
12
13
        <!-- 파일업로드 라이브러리 -->        
        <!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.6</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->
        <dependency>
            <groupId>commons-fileupload</groupId>
            <artifactId>commons-fileupload</artifactId>
            <version>1.3.3</version>
        </dependency>
cs


2.Controller에서 여러가지 처리하기

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
@RequestMapping("/board/boardFormEnd.do")
    public String boardFormEnd(String boardTitle, String boardWriter,String boardContent, MultipartFile[] upFile, HttpServletRequest request) 
    {
        Map<String,String> board = new HashMap();
        
        board.put("title",boardTitle);
        board.put("writer" ,boardWriter);
        board.put("content ", boardContent);
        
        ArrayList<Attachment> files = new ArrayList();
        String saveDir = request.getSession().getServletContext().getRealPath("/resources/upload/board");
        
        for(MultipartFile f:upFile) 
        {
            if(!f.isEmpty()) 
            {
                //파일 생성
                String orifileName = f.getOriginalFilename();
                //확장자 짤라줌
                String ext = orifileName.substring(orifileName.indexOf("."));
                //reName 규칙 설정
                SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd_HHmmssSSS");
                int rdv = (int)(Math.random()*1000);
                
                String reName = sdf.format(System.currentTimeMillis())+"_"+rdv+ext;
                
                //파일 서버에 저장하기
                try {
                    f.transferTo(new File(saveDir+"/"+reName));
                }catch (Exception e) {
                    e.printStackTrace();// TODO: handle exception
                }
                Attachment att = new Attachment();
                att.setRenamedFileName(reName);
                att.setOriginalFileName(orifileName);
                files.add(att);
            }
            /*log.debug(f.getOriginalFilename());
            log.debug(f.getName());
            log.debug(""+f.getSize());*/
        }
        log.info(""+board);
        log.info(""+files);
        int result = service.insertBoard(board,files);
        return "redirect:/board/boardList.do";
    }
cs

파일을 매개변수로 받을 땐 MultipartFile로 받는데 위에 배열로 선언된 이유는 파일이 2개 이상일 경우 저렇게 해주고 1개만 받는거라면 배열없이 받아두된다. 그리고 13번째 줄부터 받은 파일이 있으면 돌아가는 로직인데 서버에 파일을 저장하고 디비에는 그 이름만 저장하는 형식인데 만약 파일의 이름이 서로 중복이 되면 그 파일은 덮혀서 이전에의 파일 내용이 없어진다. 그렇기 때문에 절대 겹치지 않을 내용으로 reName해주고 저장하고 원래의 파일 이름과 reName을 같이 저장하는 것이다.


20번째는 확장자만 빼놓고 reName하고 나중에 뒤에다 다시 붙이기위해 임시로 떼어냈다. 그리고 rename은 절대 겹치지않을 내용으로만 구성하면 어떻게하든 상관없다. 그러고 25번째 줄에 다시 합쳐주기만 하면된다.

그리고 서버에 저장하고 Attachment객체에 원래 파일이름과 새로지은 파일이름을 List<attachment>에 넣어서 디비로~ 


뒷단에 넘어가는 로직을 먼저 간단히 설명하자면 게시제목, 작성자, 게시내용을 board라는 DB에 넣고 Board에는 시퀀스 번호가 있는데 그 번호로 attachment라는 파일만 관리하는 DB에 넣는다. board와 attachment는 시퀀스번호로 연결되어 있다.


3.service처리

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
@Override
    public int insertBoard(Map<StringString> board, List<Attachment> files) {
        // TODO Auto-generated method stub
        //dao에 여러 번 가야한다.
        int result=0;
        try {
            result = dao.insertBoard(board);
            
            if(result==0throw new BoardException();
            
            for(Attachment t:files) 
            {
                //리턴값이 스트링이라 파싱처리해줘야함
                t.setBoardNo(Integer.parseInt(board.get("boardNo")));
                result = dao.insertAttach(t);
                if(result==0throw new BoardException();
            }
        }catch (Exception e) {
            e.printStackTrace();// TODO: handle exception
        }
        
        return result;
    }
cs

먼저 board에 데이터를 저장해야한다. seq_boardno.nextval로 시퀀스 번호가 하나씩 올라가는데 그때 생성된 boardno를 set으로 넣어줘서 attachment에 넣을 것이다. 


4.mapper에서 selectKey

1
2
3
4
5
6
7
8
9
10
    <insert id="insertBoard" parameterType="map">
        insert into board values(seq_boardno.nextval, #{title}, #{writer}, #{content}, default, default)
        <selectKey keyProperty="boardNo" resultType="string" order="AFTER">
            select seq_boardno.currval from dual
        </selectKey>
    </insert>
    
    <insert id="insertAttach" parameterType="com.kh.spring.board.model.vo.Attachment">
        insert into attachment values(seq_attachmentno.nextval, #{boardNo}, #{originalFileName}, #{renamedFileName}, default,default,default)
    </insert>
cs

처음에 board에 일반적으로 데이터를 넣는건 똑같으며 selectKey라는걸 이용해 처음 insert문을 실행하고 현재의 boardno값을 리턴 받을 수 있다. keyProperty가 key가 되고 resultType은 string으로 문자다. 그리고 order=after는 위 로직이 끝난 이후에 실행 하라는 의미다.

그럼 3번의 board라는 map에 담겨서 돌아온다. 그렇기 때문에 15번째 줄에서 스트링을 파싱처리해서 t.setBoardNo를 해준 것이다. 또한 12번째 줄에 for-in문 처리 해준것은 하나의 게시판에 여러 파일을 올릴 경우 boardno에 하나에 여러 파일이 같이 맞물려 있어야하기에 저런식으로 처리해 하나씩 넣어주는 것이다.





반응형

'Back-end > Spring' 카테고리의 다른 글

Spring 파일 다운받기  (0) 2019.03.02
Spring WEB Socket  (2) 2019.02.24
Spring MVC2 패턴으로 페이징 구성하기  (0) 2019.02.23
Spring AOP  (0) 2019.02.20
Spring Interceptor (중간에 가로채기)  (0) 2019.02.19
댓글
반응형
최근에 달린 댓글
글 보관함
Total
Today
Yesterday
최근에 올라온 글
«   2024/12   »
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