본문 바로가기
멀티캠퍼스 풀스택 과정/백엔드

Spring:16 자료실 구현하기(자료실 목록보기, 등록하기)-2

by 이쟝 2022. 3. 22.
더보기

1.  상단 메뉴의 자료실을 클릭하면 자료실 글 목록(list)을 보인다.

1. data 폴더 안에 dataLibList.jsp 생성

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<style>
	#dataLibList>li{
		float:left;
		width:10%;
		height:40px;
		line-height:40px;
		border-bottom:1px solid black;
	}
	#dataLibList>li:nth-child(5n+2){ /*제목*/
		width:60%
	}
</style>
<div class="container">
	<h1>자료실 목록</h1>
	<a href="">글쓰기</a>
	<ul id="dataLibList">
		<li>번호</li>
		<li>제목</li>
		<li>작성자</li>
		<li>첨부파일</li>
		<li>등록일</li>
		
		<li>번호1</li>
		<li>제목1</li>
		<li>작성자1</li>
		<li>첨부파일1</li>
		<li>등록일1</li>
	</ul>
</div>

2. header.jspf와 연결(맵핑 주소 연결)

<li><a href="${url}/data/dataLibList">자료실</a></li>
//<li><a href="/myappy/data/dataLibList">자료실</a></li>

3. Controller로 주소 맵핑하기

package com.mycampus.myappy.controller;

//import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.ModelAndView;

//import com.mycampus.myappy.service.DataLibService;

@RestController
public class DataLibController {
	
	//@Autowired
	//DataLibService service;
	
	@GetMapping("/data/dataLibList")
	public ModelAndView dataLibraryList() {
		ModelAndView mav = new ModelAndView();
		mav.setViewName("data/dataLibList");
		return mav;
	}
}


2. 자료실 글 등록 폼 만들기(글쓰기를 누르면 글 등록 폼이 보이게 한다.) 

dataLibList.jsp

	<a href="/myappy/data/dataLibWrite">글쓰기</a>

dataLibWrite.jsp 파일 생성

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<style>
	#subject{width:99%}
	#boardFrm li{
		padding:10px 5px;
	}
</style>
<script src="//cdn.ckeditor.com/4.17.2/standard/ckeditor.js"></script>
<script>
	$(function(){
		CKEDITOR.replace("content");
		
		$("#dataLibrary").submit(function(){
			if($("#subject").val()==''){
				alert("글제목을 입력하세요");
				return false;
			}
			if(CKEDITOR.instances.content.getData() == ''){
				alert("글내용을 입력하세요");
				return false;
			}
			
			// 첨부파일 선택 갯수
			let fileCount = 0;
			
			if($("#filename1").val()!=''){ // 파일을 선택했을 경우
				fileCount++;
			}
			if($("#filename2").val()!=''){ // 파일을 선택했을 경우
				fileCount++;
			}
			if(fileCount<1){ // 파일을 안골랐다. 초기값이 0
				alert("첨부파일은 반드시 1개이상이어야 합니다.")
				return false;
			}
		});
	});
</script>
<div class="container">
	<h1>자료실 글 등록 폼</h1>
	<!-- 파일 업로드의 기능이 있는 폼은 반드시 enctype속성을 명시하여야 한다. -->
	<form method="post" id="dataLibrary" action="/myappy/data/dataWriteOk" enctype="multipart/form-data">
	<ul>
		<li>제목</li>
		<li><input type="text" name="subject" id="subject"/></li>
		<li>글 내용</li>
		<li><textarea name = "content" id="content"></textarea></li>
		<li>첨부파일</li>
		<li>
			<input type="file" name="filename" id="filename1"/><br/>
			<input type="file" name="filename" id="filename2"/>
		</li>
		<li><input type="submit" value="자료실글 등록"/></li>
	</ul>
	</form>
</div>

DataLibController

	@GetMapping("/data/dataLibWrite")
	public ModelAndView dataLibraryWrite() {
		ModelAndView mav = new ModelAndView();
		mav.setViewName("data/dataLibWrite");
		return mav;
	}

로그인이 되어 있지 있으면 글쓰기를 못하게 하기 위해서 interceptor에 추가한다. 

intercept-context.xml (src > main > webapp > WEB-INF > spring > appServlet)

맨 마지막에 추가한다.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:mybatis-spring="http://mybatis.org/schema/mybatis-spring"
	xmlns:mvc="http://www.springframework.org/schema/mvc"
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://mybatis.org/schema/mybatis-spring http://mybatis.org/schema/mybatis-spring-1.2.xsd
		http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd
		http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
	<!-- Interceptor 처리를 위한 컨트롤러 목록을 등록할 객체를 생성한다.namespaes에서 context, mvc를 추가한다. -->
	<mvc:interceptors>
		<mvc:interceptor>
			<mvc:mapping path="/board/bulletinBrdWrite"/>
			<mvc:mapping path="/board/bulletinBrdWriteOk"/>
			<mvc:mapping path="/board/boardDelete"/>
			<mvc:mapping path="/board/multiChkDel"/>
			<mvc:mapping path="/data/dataLibWrite"/>
			<bean class="com.mycampus.myappy.interceptor.SigninInterceptor"/>
		</mvc:interceptor>
	</mvc:interceptors>
</beans>


클라이언트가 업로드를 하면 자동으로 upload 폴더에 저장이 된다. (업로드한 파일이 보고 싶으면 저 경로로 들어가면 된다.) + DB에 저장이 된다. 

 

실제 업로드를 구현할 맵핑 주소는 dataLibWrite.jsp에 있다.

첨부되어있는 파일은 서버로 넘어가야 한다. 첨부파일이 있다면 enctype 꼭 명시해줘야 한다. 

	<form method="post" id="dataLibrary" action="/myappy/data/dataWriteOk" enctype="multipart/form-data">

3. 자료실 글 등록하기(DB 연결)

제목, 글 내용은 일반 데이터로 request 해서 서버에게 넘겨준다. 

DB 등록 중 에러나면 다시 글등록 폼으로 DB등록 중 성공하면 다시 자료실 리스트로 맵핑 주소를 연결한다. 

DataLibController

	// 글 등록 하고 난 후
	@PostMapping("/data/dataWriteOk")
	public ResponseEntity<String> dataWriteOk(DataLibVO vo, HttpServletRequest request){
		// 제목과 내용을 request한다.(VO안에)
		// request로 session에서 아이디 구하기
		vo.setUserid((String)request.getSession().getAttribute("logId"));
		
		ResponseEntity<String> entity = null;
		HttpHeaders headers = new HttpHeaders(); // 성공, 실패 둘 다 js 파일안에
		headers.setContentType(new MediaType("text", "html", Charset.forName("UTF-8")));
		
		// 파일 업로드를 위한 업로드 위치의 절대주소(upload폴더)
		String path = request.getSession().getServletContext().getRealPath("/upload");
		System.out.println("경로: " + path);
		
		try { // 성공했을 때
			 // 파일 업로드를 처리하기 위해서는 request객체에서 multipart객체로 형변환 필요함
			MultipartHttpServletRequest mp = (MultipartHttpServletRequest)request;
			// mp에 파일의 수만큼 multipartfile 객체가 존재하기 때문에 파일의 수만큼 multipartfile의 객체를 가져온다.
			// getFiles(String name) : List<MultipartFile>
			// String name은 첨부파일의 name(dataLibWrite.jsp에서)
			List<MultipartFile> files = mp.getFiles("filename");
			System.out.println("업로드 파일 수 : " + files.size());
			
			entity = null;
		} catch(Exception e) {
			e.printStackTrace();
			entity = null;
		}
		return entity;
	}
}

서버를 실행하면 절대 경로가 위에 파일 탐색기를 통해 간 것과 동일한 것을 볼 수 있다. 

1. VO에 toString 생성

	@Override
	public String toString() {
		return "userid: " + userid + " " + "subject: " + subject + " " + "content: " 
			+ content + " " + "filename1: " + filename1 + " " + "filename2: " + filename2;
	}

2. Controller 파일명 rename 하기(동일한 파일명일 때 rename 하기)

DataLibController

// 글 등록 하고 난 후
@PostMapping("/data/dataWriteOk")
public ResponseEntity<String> dataWriteOk(DataLibVO vo, HttpServletRequest request){
    // 제목과 내용을 request한다.(VO안에)
    // request로 session에서 아이디 구하기
    vo.setUserid((String)request.getSession().getAttribute("logId"));

    ResponseEntity<String> entity = null;
    HttpHeaders headers = new HttpHeaders(); // 성공, 실패 둘 다 js 파일안에
    headers.setContentType(new MediaType("text", "html", Charset.forName("UTF-8")));

    // 파일 업로드를 위한 업로드 위치의 절대주소(upload폴더)
    String path = request.getSession().getServletContext().getRealPath("/upload");
    System.out.println("경로: " + path);

    try { // 성공했을 때
         // 파일 업로드를 처리하기 위해서는 request객체에서 multipart객체로 형변환 필요함
        MultipartHttpServletRequest mp = (MultipartHttpServletRequest)request;
        // mp에 파일의 수만큼 multipartfile 객체가 존재하기 때문에 파일의 수만큼 multipartfile의 객체를 가져온다.
        List<MultipartFile> files = mp.getFiles("filename");
        System.out.println("업로드 파일 수 : " + files.size());

        // null이 아닐 때만 작업한다.(files의 개수만큼 업로드)
        if(files!=null) { // if 1
            int cnt = 1;  // 업로드 순서에 따라 filename1, filename2 파일명을 대입하기 위한 변수

            //첨부파일 수 만큼 반복해서 업로드
            for(int i=0; i<files.size(); i++) { // for 2
            
                // 1. MultipartFile 객체 얻어오기
                MultipartFile mf = files.get(i); 
                
                // 2. 업로드한 실제 파일명을 구하기
                String originFileName = mf.getOriginalFilename();
                System.out.println("originFileName : " + originFileName);

                // 3. rename하기(동일한 이름이 존재하면 rename하고 없으면 하지 않음)
                // rename이란 동일이름에 (1), (2), 이렇게 붙이는 것
                if(originFileName!=null && !originFileName.equals("")) { // if 3
                    File f = new File(path, originFileName);

                    // 파일이 존재하는지 확인 
                    // return true -> 파일 존재, false : 파일 존재 xx
                    if(f.exists()) { // if 4 파일객체가 있으면
                        for(int renameNum =1; ;renameNum++) { // for 5
                             // 반복문 때문에 1부터 무제한으로 만들어진다.
                             // 확장자와 파일을 분리한다.(마지막 점의 위치를 구하기)
                            int dot = originFileName.lastIndexOf(".");
                            String fileName = originFileName.substring(0,dot); // 파일명
                            String ext = originFileName.substring(dot+1);      // 확장자

                            // rename(새로운 이름 짓기)
                            f = new File(path, fileName+ "(" + renameNum + ")" + ext);

                            if(!f.exists()) { // 새로 생성된 파일객체가 없으면
                                originFileName = f.getName();  // 파일명만 구하는게 getName
                                break;
                            }
                        } // for 5 끝
                    } // if 4 (파일객체가 있는 경우)

                    // 4. 파일 업로드 구현
                    try { // mf 객체 안에 업로드하려는 메서드를 사용
                        mf.transferTo(f);  // 실제 업로드가 발생, 업로드한 파일 데이터를 지정한 파일에 저장

                    }catch(Exception e) {}
                    
                    // 5. 업로드한(새로운 파일명)파일 VO에 세팅
                    if(cnt==1) vo.setFilename1(originFileName);
                    if(cnt==2) vo.setFilename2(originFileName);
                    cnt++;
                }// if 3 // rename하기
            }// for 2 //첨부파일 수 만큼 반복해서 업로드
        }// if 1 // 업로드 끝
        System.out.println(vo.toString());
        entity = null;
        
    } catch(Exception e) {
        e.printStackTrace();
        entity = null;
    }
    return entity;
}

폴더안에 자동으로 rename한 파일이 들어가있다.

3. DB 작업하기(DB에 정보를 넣기)

Mapper, DAO, Service, ServiceImpl, Controller 매핑 작성

<?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="com.mycampus.myappy.dao.DataLibDAO">
	<insert id="dataInsert">
		insert into dataLibrary(userid, subject, content, filename1, filename2)
		values(#{userid}, #{subject}, #{content}, #{filename1}, #{filename2})
	</insert>
</mapper>
package com.mycampus.myappy.dao;
import com.mycampus.myappy.vo.DataLibVO;
public interface DataLibDAO {
	public int dataInsert(DataLibVO vo); // 파일명, 제목, 글내용 등이 있다. 
}
package com.mycampus.myappy.service;
import com.mycampus.myappy.vo.DataLibVO;
public interface DataLibService {
	public int dataInsert(DataLibVO vo); 
}
package com.mycampus.myappy.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.mycampus.myappy.dao.DataLibDAO;
import com.mycampus.myappy.vo.DataLibVO;

@Service
public class DataLibServiceImpl implements DataLibService {

	@Autowired
	DataLibDAO dao;

	@Override
	public int dataInsert(DataLibVO vo) {
		return dao.dataInsert(vo);
	}
	
}

Controller(DataLibController)

			}// if 1 // 업로드 끝
			System.out.println(vo.toString());
			
			// DB등록
			service.dataInsert(vo);
			
			// 레코드 추가 성공
			String msg = "<script>alert('자료실에 글이 등록되었습니다.');";
			msg += "location.href='/myappy/data/dataLibList';</script>";
			entity = new ResponseEntity<String>(msg, headers, HttpStatus.OK);
		} catch(Exception e) { // 레코드 추가 실패
			e.printStackTrace();
			// 데이터가 DB에 정상적으로 들어가지 않았다면 이미 upload폴더에 업로드한 파일을 지워야 한다.
			// 삭제할 파일명은 vo안에 있다.(vo.filename1과 vo.filename2)
			fileDelete(path, vo.getFilename1());
			fileDelete(path, vo.getFilename2());
			
			// 메세지
			String msg = "<script>alert('자료실에 글 등록이 실패하였습니다.');";
			msg += "history.back();</script>";
			entity = new ResponseEntity<String>(msg, headers, HttpStatus.BAD_REQUEST);
		}
		return entity;
	}
	
	// 파일 삭제 메서드
	// 파일 경로와 파일명을 매개변수로 받아서 지운다.
	public void fileDelete(String path, String fileName) {
		if(fileName!=null) { //파일명이 존재하면
			File file = new File(path, fileName); // 파일 객체 생성
			file.delete();  // 파일 내장 메서드
		}
	}


3. 레코드 전체 선택(레코드 목록 보이기)

Mapper, DAO, Service, ServiceImpl, Controller 매핑 작성

<?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="com.mycampus.myappy.dao.DataLibDAO">
	<select id="dataAllSelect" resultType="com.mycampus.myappy.vo.dataLibVO">
		select no, userid, subject, data_format(createdate, '%m-%d %H:%i')createdate, 
		filename1, filename2
		from dataLibrary order by no desc
	</select>
</mapper>
package com.mycampus.myappy.dao;
import java.util.List;
import com.mycampus.myappy.vo.DataLibVO;
public interface DataLibDAO {
	public List<DataLibVO> dataAllSelect();
}
package com.mycampus.myappy.service;
import java.util.List;
import com.mycampus.myappy.vo.DataLibVO;
public interface DataLibService {
	public List<DataLibVO> dataAllSelect();
}
package com.mycampus.myappy.service;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.mycampus.myappy.dao.DataLibDAO;
import com.mycampus.myappy.vo.DataLibVO;

@Service
public class DataLibServiceImpl implements DataLibService {

	@Autowired
	DataLibDAO dao;

	@Override
	public List<DataLibVO> dataAllSelect() {
		return dao.dataAllSelect();
	}
}

Controller(DataLibController)

mav.addObject("list", service.dataAllSelect( )); 추가하기

	// 자료실리스트
	@GetMapping("/data/dataLibList")
	public ModelAndView dataLibraryList() {
		ModelAndView mav = new ModelAndView();
		mav.addObject("list",service.dataAllSelect());
		mav.setViewName("data/dataLibList");
		return mav;
	}

디스크 이미지 저장하기

  1. webapp 폴더 밑에 img 폴더 생성하고 disk.png(이미지) 저장하기
  2. servlet-context.xml 
<resources mapping="/img/**" location="/img/"/>

dataLibList.jsp

    <c:forEach var="vo" items="${list}">
        <li>${vo.no}</li>
        <li><a href="#?no=${vo.no}">${vo.subject}</a></li>
        <li>${vo.userid}</li>
        <li><!-- 첨부파일 기준 -->
            <!-- 첫번째 첨부파일 -->
            <a href="/myappy/upload/${vo.filename1}" download>
            <img src="/myappy/img/disk.png" title="${vo.filename1}"/></a>
            <!-- 두번째 첨부파일 있을 경우 -->
            <c:if test="${vo.filename2!=null && vo.filename2!=''}">
            <a href="/myappy/upload/${vo.filename2}" download>
            <img src="/myappy/img/disk.png" title="${vo.filename2}"/></a>
            </c:if>
        </li>
        <li>${vo.createdate}</li>
    </c:forEach>


4. 자료실 글 내용 보기 구현하기

맵핑 주소 정하기(dataLibList.jsp)

	<li><a href="/myappy/data/dataLibView?no=${vo.no}">${vo.subject}</a></li>

Mapper, DAO, Service, ServiceImpl, Controller 매핑 작성

<?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="com.mycampus.myappy.dao.DataLibDAO">
	</select>
	<select id="dataView"resultType="com.mycampus.myappy.vo.DataLibVO">
		select no, userid, subject, content, createdate, filename1, filename2
		from dataLibrary where no=${param1}
	</select>
</mapper>
package com.mycampus.myappy.dao;
import com.mycampus.myappy.vo.DataLibVO;
public interface DataLibDAO {
	public DataLibVO dataView(int no);
}
package com.mycampus.myappy.service;
import com.mycampus.myappy.vo.DataLibVO;
public interface DataLibService {
	public DataLibVO dataView(int no);
}
package com.mycampus.myappy.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.mycampus.myappy.dao.DataLibDAO;
import com.mycampus.myappy.vo.DataLibVO;

@Service
public class DataLibServiceImpl implements DataLibService {

	@Autowired
	DataLibDAO dao;

	@Override
	public DataLibVO dataView(int no) {
		return dao.dataView(no);
	}
}

Controller(DataLibController)

	// 글 내용 보기
	@GetMapping("data/dataLibView")
	public ModelAndView view(int no) {
		ModelAndView mav = new ModelAndView();
		mav.addObject("dataLibVO", service.dataView(no));
		mav.setViewName("data/dataLibView");
		return mav;
	}

dataLibView.jsp 파일 생성

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<div class="container">
	<h1>자료실 글 내용보기</h1>
	<ul>
		<li>번호 : ${dataLibVO.no}</li>
		<li>작성자 : ${dataLibVO.userid}</li>
		<li>등록일 : ${dataLibVO.createdate}</li>
		<li>제목 : ${dataLibVO.subject}</li>
		<li>글내용</li>
		<li>${dataLibVO.content}</li>
		<li>첨부파일 : <a href="/myappy/upload/${dataLibVO.filename1}" download>${dataLibVO.filename1}</a>
			<c:if test="${dataLibVO.filename2!=null && dataLibVO.filename2!=''}">
				<a href='myappy/upload/${dataLibVO.filename2}' download>${dataLibVO.filename2}</a>
			</c:if>
		</li>
	</ul>
</div>