자바 웹/MVC

MVC - 서블릿(컨트롤러)/답변형 게시판 2(글쓰기, 상세내용)

수풀속의고라니 2022. 6. 26. 12:12
728x90

게시글 작성

  1. 글쓰기창에서 새 글 전송시 컨트롤러의 upload() 메서드를 호출해 새 글 정보를 Map으로 반환 받고 첨부한 파일은 임시로 temp 폴더에 업로드
  2. 컨트롤러는 서비스 클래스의 addNewArticle() 메서드를 호출하면서 새 글 정보를 인자로 전달해 테이블에 추가한 후 새 글 번호를 반환받음
  3. 컨트롤러에서 반환 받은 새 글 번호를 이용해 파일 저장소에 새 글 번호로 폴더를 생성하고 temp 폴더의 파일을 새 글 번호 폴더로 이동

 

 

글쓰기 페이지로 들어와서 이미지 파일을 첨부하게 되면, 제이쿼리를 통해서 첨부한 이미지 파일을 미리볼 수 있도록 할 수 있음

 

 

또 이런 식으로 처음에 temp라는 임시파일에 저장해 두었다가 글 번호에 해당하는 폴더를 생성한 뒤 이 폴더로 temp에 있는 이미지 파일을 옮기는 방식으로 첨부파일을 저장하는 방식으로 기능하게 됨.

 

이미지가 한 폴더에 담겨서 구분이 어려운 일이 없도록 할 수 있다는 장점이 있음

 

글 상세 기능

글 상세 기능을 구현하기 위해서 이에 필요한 첨부  이미지를 표시하기 위해 FileDownloadController 클래스를 하나 생성한다.

 

 

글 목록에서 게시글을 선택하면 위와 같이 정보들이 출력된다.

 


 

BoardController

 

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
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
@WebServlet("/board/*")
public class BoardController extends HttpServlet {
    
    private static String ARTICLE_IMG_REPO = "C:\\pra_board\\article_img";//이미지 저장 위치
    BoardService boardService;
    ArticleVO articleVO;
    
    @Override
    public void init(ServletConfig config) throws ServletException {
        //서블릿 초기화 시 BoardService 객체 생성
        boardService = new BoardService();
        articleVO = new ArticleVO();
    }
    
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doHandle(request, response);
    }
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doHandle(request, response);
    }
    
    private void doHandle(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String nextPage ="";
        request.setCharacterEncoding("utf-8");
        response.setContentType("text/html; charset=utf-8");
        String action = request.getPathInfo();//요청명을 가져옴
        
        try {
            List<ArticleVO> articleList = new ArrayList<ArticleVO>();
            if(action == null) {
                articleList = boardService.listArticles();
                request.setAttribute("articleList", articleList);
                nextPage = "/board01/listArticles.jsp";
            }
            //액션 값이 아래와 같으면 전체 글을 조회
            else if(action.equals("/listArticles.do")) {
                articleList = boardService.listArticles();//전체 글 조회
                request.setAttribute("articleList", articleList);//articleList로 바인딩
                nextPage = "/board01/listArticles.jsp";//listArticles.jsp로 포워딩
            }
            //액션 값이 아래와 같으면 글쓰기 페이지로 이동
            else if(action.equals("/articleForm.do")) {
                nextPage = "/board01/articleForm.jsp";
            }        
            //액션 값이 아래와 같으면 새 글 추가 작업 실행
            else if(action.equals("/addArticle.do")) {
                int articleno = 0;
                //파일 업로드 기능을 사용하기 위해서 upload()로 요청을 전달
                Map<StringString> articleMap = upload(request,response);
                //articleMap에 저장한 글 정보를 다시 가져옴
                String title = articleMap.get("title");
                String content = articleMap.get("content");
                String imagefilename = articleMap.get("imagefilename");
                System.out.println(title+","+content+","+imagefilename);
                
                //글쓰기 창에서 입력된 정보를 VO 객체에 설정한 후 addArticle()로 전달
                articleVO.setParentno(0);//새 글의 부모 글 번호를 0으로 설정
                articleVO.setId("hong");//새 글 작성자 ID를 hong으로 설정
                articleVO.setTitle(title);
                articleVO.setContent(content);
                articleVO.setImagefilename(imagefilename);
                articleno = boardService.addArticle(articleVO);//테이블에 새 글을 추가한 후 새 글에 대한 글 번호 가져옴
                System.out.println("articleno = "+articleno);
                
                //파일을 첨부한 경우에만 수행
                if(imagefilename != null && imagefilename.length() != 0) {
                    //temp 폴더에 임시로 업로드 될 파일 객체를 생성
                    File srcFile = new File(ARTICLE_IMG_REPO+"\\"+"temp"+"\\"+imagefilename);
                    System.out.println("srcFile = "+srcFile);
                    
                    //CURR_IMAGE_REPO_PATH의 경로 하위에 글 번호로 폴더를 생성
                    File destDir = new File(ARTICLE_IMG_REPO+"\\"+articleno);
                    System.out.println("destDir = "+destDir);
                    destDir.mkdirs();
                    
                    //temp 폴더의 파일을 글 번호를 이름으로 하는 폴더로 이동
                    FileUtils.moveFileToDirectory(srcFile, destDir, true);
                }
                //새 글 등록 메시지를 나타낸 후 자바스크립트 location 객체의 href 속성을 이용해 글 목록을 요청
                PrintWriter writer = response.getWriter();
                writer.print("<script>" + " alert('새 글을 추가했습니다.');"
                                        + " location.href='"
                                        + request.getContextPath()
                                        + "/board/listArticles.do';"+"</script>");
                return;
                
            }
            else if(action.equals("/viewArticle.do")) {
                String articleno = request.getParameter("articleno");//글 상세창을 요청할 경우 articleno 값을 가져옴
                
                //articleno에 대한 글 정보를 조회하고 article 속성으로 바인딩
                articleVO = boardService.viewArticle(Integer.parseInt(articleno));
                request.setAttribute("article", articleVO);
                
                nextPage = "/board01/viewArticle.jsp";
            }
            else {
                nextPage = "/board01/listArticles.jsp";
            }
            RequestDispatcher dispatch = request.getRequestDispatcher(nextPage);
            dispatch.forward(request, response);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    private Map<StringString> upload(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        Map<StringString> articleMap = new HashMap<StringString>();
        String encoding = "utf-8";
        File currentDirPath = new File(ARTICLE_IMG_REPO);//글 이미지 저장 폴더에 대해 파일 객체를 생성
        DiskFileItemFactory factory = new DiskFileItemFactory();
        factory.setRepository(currentDirPath);
        factory.setSizeThreshold(1024*1024);
        ServletFileUpload upload = new ServletFileUpload(factory);
        
        try {
            List items = upload.parseRequest(request);//request 객체에서 매개변수를 List로 가져옴
            for (int i = 0; i < items.size(); i++) {
                FileItem fileItem = (FileItem) items.get(i);//파일 업로드창에서 업로드된 항목들을 하나씩 가져옴
                
                //폼 필드면 전송된 매개변수 값을 출력
                if (fileItem.isFormField()) {
                    System.out.println(fileItem.getFieldName()+"="+fileItem.getString(encoding));
                    //파일 업로드로 같이 전송된 새 글 관련 매개변수를 Map에 저장한 후 반환하고, 새 글과 관련된 title, content를 Map에 저장
                    articleMap.put(fileItem.getFieldName(), fileItem.getString(encoding));
                }
                else {
                    //업로드한 파일이 존재하는 경우 업로드한 파일의 파일 이름으로 저장소에 업로드
                    if(fileItem.getSize() > 0) {
                        int idx = fileItem.getName().lastIndexOf("\\");
                        
                        if(idx == -1) {
                            idx = fileItem.getName().lastIndexOf("/");
                        }
                        //첨부한 파일을 먼저 temp 폴더에 업로드,
                        String fileName = fileItem.getName().substring(idx+1);
                        System.out.println("파일명 = "+fileName);
                        articleMap.put(fileItem.getFieldName(), fileName);//익스플로러에서 업로드 파일의 경로 제거 후 map에 파일명 저장
                        File uploadFile = new File(currentDirPath+"\\temp\\"+fileName);
                        
                        fileItem.write(uploadFile);
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return articleMap;
    }
}
cs

 

FIleDownloadController

 

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
@WebServlet("/download.do")
public class FileDownloadController extends HttpServlet{
    
    /*이 클래스는 viewArticle.jsp에서 전송한 글 번호와 이미지 파일 이름으로 파일 경로를 만든 후 해당 파일을 내려받음*/
    
    private static String ARTICLE_IMAGE_REPO = "C:\\pra_board\\article_img";
    
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doHandle(request, response);
    }
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doHandle(request, response);
    }
    
    private void doHandle(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("utf-8");
        response.setContentType("text/html; charset=utf-8");
        
        //이미지 파일 이름과 글 번호를 가져옴
        String imagefilename = request.getParameter("imagefilename");
        String articleno = request.getParameter("articleno");
        
        OutputStream out = response.getOutputStream();
        String path = ARTICLE_IMAGE_REPO+"\\"+articleno+"\\"+imagefilename;//글 번호에 대한 파일 경로 설정
        File imageFile = new File(path);
        
        response.setHeader("Cache-Control""no-cache");
        //이미지 파일을 내려받는 데 필요한 response에 헤더 정보를 설정
        response.addHeader("Content-dispositon""attachment;fileName="+imagefilename);
        
        FileInputStream in = new FileInputStream(imageFile);
        byte[] buffer = new byte[1024*8];
        
        //버퍼를 이용해 한번에 8kb씩 전송
        while(true) {
            int count = in.read(buffer);
            if (count == -1) {
                break;
            }
            out.write(buffer, 0, count);
        }
        in.close();
        out.close();
    }
}
cs

 

서비스

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class BoardService {
    BoardDAO boardDAO;
 
    public BoardService() {
        //생성자 호출 시 BoardDAO()객체 생성
        boardDAO = new BoardDAO();
    }
 
    public List<ArticleVO> listArticles() {
        List<ArticleVO> articleList = boardDAO.selectAllArticles();
        return articleList;
    }
    
    public int addArticle(ArticleVO article) {
        return boardDAO.insertNewArticle(article);
    }
    
    public ArticleVO viewArticle(int articleno) {
        ArticleVO article = null;
        article = boardDAO.selectArticle(articleno);
        return article;
    }
}
cs

 

DAO

 

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
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
public class BoardDAO {
    private static BoardDAO instance = new BoardDAO();
    private Connection con = null;
    private PreparedStatement pstmt = null;
    private ResultSet rs = null;
 
    public static BoardDAO getInstance() {
        return instance;
    }
 
    public Connection getConnection() throws Exception {
        Context ctx = new InitialContext();
        DataSource ds = (DataSource) ctx.lookup("java:/comp/env/jdbc/oracle");
        return ds.getConnection();
    }
    
    public List<ArticleVO> selectAllArticles() {
        List<ArticleVO> articleList = new ArrayList<ArticleVO>();
        
        try{
            con = getConnection();
            //오라클 계층형 SQL문 실행
            String sql = "select level, articleno, parentno, title, content, id, writedate from t_board "
                    + "start with parentno=0 "
                    + "connect by prior articleno=parentno "
                    + "order siblings by articleno desc";
            pstmt = con.prepareStatement(sql);
            rs = pstmt.executeQuery();
 
            while (rs.next()) {
                int level = rs.getInt("level");//각 글의 계층을 저장
                int articleno = rs.getInt("articleno");
                int parentno = rs.getInt("parentno");
                String title = rs.getString("title");
                String content = rs.getString("content");
                String id = rs.getString("id");
                Date writedate = rs.getDate("writedate");
                //글 정보를 ArticleVO 객체의 속성에 설정
                ArticleVO article = new ArticleVO();
                article.setLevel(level);
                article.setArticleno(articleno);
                article.setParentno(parentno);
                article.setTitle(title);
                article.setContent(content);
                article.setId(id);
                article.setWritedate(writedate);
 
                articleList.add(article);
            }
            rs.close();
            pstmt.close();
            con.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return articleList;
    }
    
    //insertNewArticle 메서드의 쿼리를 실행하기 전에 새 글에 대한 글 번호를 먼저 가져옴
    private int getNewArticleNO() {
        int re = 0;
        try{
            con = getConnection();
            String sql = "select max(articleno) from t_board";//기본 글 번호 중 가장 큰 번호 조회
            System.out.println(sql);
            pstmt = con.prepareStatement(sql);
            rs = pstmt.executeQuery();
 
            //가장 큰 번호에 1을 더한 번호를 반환
            if (rs.next()) {
                re = rs.getInt(1)+1;
                return re;
            }
            rs.close();
            pstmt.close();
            con.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return re;
    }
 
    public int insertNewArticle(ArticleVO article) {
        int articleno = getNewArticleNO();//새 글을 추가하기 전에 새 글에 대한 글 번호를 가져옴
 
        try{
            con = getConnection();
            
            int parentno = article.getParentno();
            String title = article.getTitle();
            String content = article.getContent();
            String id = article.getId();
            String imagefilename = article.getImagefilename();
 
            String sql = "insert into t_board (articleno, parentno, title, content, id, imagefilename) values(?,?,?,?,?,?)";
            pstmt = con.prepareStatement(sql);
            pstmt.setInt(1, articleno);
            pstmt.setInt(2, parentno);
            pstmt.setString(3, title);
            pstmt.setString(4, content);
            pstmt.setString(5, id);
            pstmt.setString(6, imagefilename);
            System.out.println("dao imagefilename = "+imagefilename);
            pstmt.executeUpdate();
            
            pstmt.close();
            con.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("dao articleno = "+articleno);
        return articleno;
    }
    
    public ArticleVO selectArticle(int articleno) {
        ArticleVO article = new ArticleVO();
 
        try{
            con = getConnection();
            String sql = "select articleno, parentno, title, content, imagefilename, id, writedate from t_board where articleno=?";
            pstmt = con.prepareStatement(sql);
            pstmt.setInt(1,articleno);
            rs = pstmt.executeQuery();
 
            if (rs.next()) {
                int _articleno = rs.getInt("articleno");
                int parentno = rs.getInt("parentno");
                String title = rs.getString("title");
                String content = rs.getString("content");
                String imagefilename = rs.getString("imagefilename");
                String id = rs.getString("id");
                Date writedate = rs.getDate("writedate");
 
                article.setArticleno(_articleno);
                article.setParentno(parentno);
                article.setTitle(title);
                article.setContent(content);
                article.setImagefilename(imagefilename);
                article.setId(id);
                article.setWritedate(writedate);
            }
            rs.close();
            pstmt.close();
            con.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return article;
    }
}
cs

 

viewArticle.jsp

 

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
59
60
61
62
63
64
65
66
67
68
69
70
71
72
<%@ page language="java" contentType="text/html; charset=utf-8"
    pageEncoding="utf-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>  
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>  
<%request.setCharacterEncoding("utf-8"); %>      
<c:set var="contextPath" value="${pageContext.request.contextPath}"/>    
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Insert title here</title>
<script  src="http://code.jquery.com/jquery-latest.min.js"></script>
<script type="text/javascript">
    function readURL(input) {
        if(input.files && input.files[0]){
            var reader = new FileReader();
            reader.onload = function (e) {
                $('#preview').attr('src', e.target.result);
            }
            reader.readAsDataURL(input.files[0]);
        }
    }
</script>
</head>
<body>
    <form name="frmArticle" method="post" enctype="multipart/form-data">
        <table>
            <tr>
                <td width="150" align="center">글번호</td>
                <td><input type="text" value="${article.articleno}" disabled name="articleno"></td>
            </tr>
            <tr>
                <td width="150" align="center">작성자 아이디</td>
                <td><input type="text" value="${article.id}" disabled name="id"></td>
            </tr>
            <tr>
                <td width="150" align="center">제목</td>
                <td><input type="text" value="${article.title}" disabled name="title" id="i_title"></td>
            </tr>
            <tr>
                <td width="150" align="center">내용</td>
                <td>
                    <textarea rows="20" cols="60"  name="content"  id="i_content"  disabled />${article.content }</textarea>
                </td>
            </tr>
        <!-- imagefilename 값이 있으면 이미지를 표시 -->
        <!-- hidden 태그에 원래 이미지 파일 이름을 저장 -->
        <!-- FileDownloadController 서블릿에 이미지 파일 이름과 글 번호를 전송해서 이미지를 img 태그에 표시 -->
        <c:if test="${not empty article.imagefilename && article.imagefilename != 'null'}">
            <tr>
                <td width="20%" align="center" rowspan="2">이미지</td>
                <td>
                    <input type="hidden" name="originalFileName" value="${article.imagefilename }">
                    <img src="${contextPath}/download.do?imagefilename=${article.imagefilename}&articleno=${article.articleno}" id="preview">
                </td>
            </tr>
            <tr>
                <td>
                    <input type="file" name="imagefilename" id="i_imagefilename" onchange="readURL(this);" disabled>
                </td>
            </tr>
        </c:if>
            <tr>
                <td width="20%" align="center">등록일자</td>
                <td>
                    <input type="text" value='<fmt:formatDate value="${article.writedate}"/>' disabled>
                </td>
            </tr>
        </table>
    </form>
</body>
</html>
cs

 

 

728x90