프로그래밍 언어/자바 웹

글 수정 기능 구현

· 코딩마이데이

이번에는 기존에 작성한 글을 수정하는 기능을 구현해 보겠습니다.

글 수정 기능을 구현하는 과정은 다음과 같습니다.

글 상세창(viewArticle.jsp)에서 수정하기를 클릭해 글 정보를 표시하는 입력창들을 활성화합니다.

글 정보와 이미지를 수정한 후 수정반역하기를 클릭해 컨트롤러에 /board/modArticle.do로 요청합니다.

컨트롤러는 요청애 대해 upload() 메서드를 이용하여 수정된 데이터를 Map에 저장하고 반환합니다.

컨트롤러는 수정된 데이터를 테이블에 반영한 후 temp 폴더에 업로드된 수정 이미지를 글 번호 폴더로 이동합니다.

마지막으로 글 번호 폴더에 있던 원래 이미지 파일을 삭제합니다.

 

1. sec03.brd05 패키지를 만들고 글 수정 기능과 관련된 클래스를 다음과 같이 추가합니다.

실습 파일 위치

 

2. BoardController 클래스를 다음과 같이 작성합니다. 컨트롤러에서 수정을 요청하면 upload() 메서드를 이용해 수정 데이터를 Map으로 가져옵니다. Map의 데이터를 다시 ArticleVO 객체의 속성에 저장한 후 SQL문으로 전달하여 수정 데이터를 반영합니다. 마지막으로 temp 폴더에 업로드된 수정 이미지를 다시 글 번호 폴더로 이동하고 글 번호 폴더의 원래 이미지를 삭제합니다.

package sec03.brd05;

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.RequestDispatcher;
import javax.servlet.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.io.FileUtils;

/**
 * Servlet implementation class BoardController
 */

@WebServlet("/board/*")
public class BoardController extends HttpServlet {
    private static String ARTICLE_IMAGE_REPO = "C:\\board\\article_image";
    BoardService boardService;
    ArticleVO articleVO;

    /**
     * @see Servlet#init(ServletConfig)
     */
    public void init(ServletConfig config) throws ServletException {
        boardService = new BoardService();
        articleVO = new ArticleVO();
    }

    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
     *      response)
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doHandle(request, response);
    }

    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
     *      response)
     */
    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();
        System.out.println("action:" + action);
        try {
            List<ArticleVO> articlesList = new ArrayList<ArticleVO>();
            if (action == null) {
                articlesList = boardService.listArticles();
                request.setAttribute("articlesList", articlesList);
                nextPage = "/board04/listArticles.jsp";
            } else if (action.equals("/listArticles.do")) {
                articlesList = boardService.listArticles();
                request.setAttribute("articlesList", articlesList);
                nextPage = "/board04/listArticles.jsp";
            } else if (action.equals("/articleForm.do")) {
                nextPage = "/board04/articleForm.jsp";
            } else if (action.equals("/addArticle.do")) {
                int articleNO = 0;
                Map<String, String> articleMap = upload(request, response);
                String title = articleMap.get("title");
                String content = articleMap.get("content");
                String imageFileName = articleMap.get("imageFileName");

                articleVO.setParentNO(0);
                articleVO.setId("hong");
                articleVO.setTitle(title);
                articleVO.setContent(content);
                articleVO.setImageFileName(imageFileName);
                articleNO = boardService.addArticle(articleVO);
                if (imageFileName != null && imageFileName.length() != 0) {
                    File srcFile = new File(ARTICLE_IMAGE_REPO + "\\" + "temp" + "\\" + imageFileName);
                    File destDir = new File(ARTICLE_IMAGE_REPO + "\\" + articleNO);
                    destDir.mkdirs();
                    FileUtils.moveFileToDirectory(srcFile, destDir, true);
                    srcFile.delete();
                }
                PrintWriter pw = response.getWriter();
                pw.print("<script>" + "  alert('새글을 추가했습니다.');" + " location.href='" + request.getContextPath()
                        + "/board/listArticles.do';" + "</script>");

                return;
            } else if (action.equals("/viewArticle.do")) {
                String articleNO = request.getParameter("articleNO");
                articleVO = boardService.viewArticle(Integer.parseInt(articleNO));
                request.setAttribute("article", articleVO);
                nextPage = "/board04/viewArticle.jsp";
            } else if (action.equals("/modArticle.do")) {
                Map<String, String> articleMap = upload(request, response);
                int articleNO = Integer.parseInt(articleMap.get("articleNO"));
                articleVO.setArticleNO(articleNO);
                String title = articleMap.get("title");
                String content = articleMap.get("content");
                String imageFileName = articleMap.get("imageFileName");
                articleVO.setParentNO(0);
                articleVO.setId("hong");
                articleVO.setTitle(title);
                articleVO.setContent(content);
                articleVO.setImageFileName(imageFileName);
                boardService.modArticle(articleVO);
                if (imageFileName != null && imageFileName.length() != 0) {
                    String originalFileName = articleMap.get("originalFileName");
                    File srcFile = new File(ARTICLE_IMAGE_REPO + "\\" + "temp" + "\\" + imageFileName);
                    File destDir = new File(ARTICLE_IMAGE_REPO + "\\" + articleNO);
                    destDir.mkdirs();
                    FileUtils.moveFileToDirectory(srcFile, destDir, true);
                    ;
                    File oldFile = new File(ARTICLE_IMAGE_REPO + "\\" + articleNO + "\\" + originalFileName);
                    oldFile.delete();
                }
                PrintWriter pw = response.getWriter();
                pw.print("<script>" + "  alert('글을 수정했습니다.');" + " location.href='" + request.getContextPath()
                        + "/board/viewArticle.do?articleNO=" + articleNO + "';" + "</script>");
                return;

            }else {
                nextPage = "/board04/listArticles.jsp";
            }

            RequestDispatcher dispatch = request.getRequestDispatcher(nextPage);
            dispatch.forward(request, response);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private Map<String, String> upload(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        Map<String, String> articleMap = new HashMap<String, String>();
        String encoding = "utf-8";
        File currentDirPath = new File(ARTICLE_IMAGE_REPO);
        DiskFileItemFactory factory = new DiskFileItemFactory();
        factory.setRepository(currentDirPath);
        factory.setSizeThreshold(1024 * 1024);
        ServletFileUpload upload = new ServletFileUpload(factory);
        try {
            List items = upload.parseRequest(request);
            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));
                    articleMap.put(fileItem.getFieldName(), fileItem.getString(encoding));
                } else {
                    System.out.println("파라미터명:" + fileItem.getFieldName());
                    //System.out.println("파일명:" + fileItem.getName());
                    System.out.println("파일크기:" + fileItem.getSize() + "bytes");
                    //articleMap.put(fileItem.getFieldName(), fileItem.getName());
                    if (fileItem.getSize() > 0) {
                        int idx = fileItem.getName().lastIndexOf("\\");
                        if (idx == -1) {
                            idx = fileItem.getName().lastIndexOf("/");
                        }

                        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);

                    } // end if
                } // end if
            } // end for
        } catch (Exception e) {
            e.printStackTrace();
        }
        return articleMap;
    }

}

 

3. BoardService 클래스를 다음과 같이 작성합니다. 컨트롤러에서 modArticle() 메서드를 호출하면 다시 BoardDAO의 updateArticle() 메서드를 호출하면서 수정 데이터를 전달합니다.

package sec03.brd05;

import java.util.List;

public class BoardService {
    BoardDAO boardDAO;

    public BoardService() {
        boardDAO = new BoardDAO();
    }

    public List<ArticleVO> listArticles() {
        List<ArticleVO> articlesList = boardDAO.selectAllArticles();
        return articlesList;
    }

    public int addArticle(ArticleVO article) {
        return boardDAO.insertNewArticle(article);
    }

    public ArticleVO viewArticle(int articleNO) {
        ArticleVO article = null;
        article = boardDAO.selectArticle(articleNO);
        return article;
    }

    public void modArticle(ArticleVO article) {
        boardDAO.updateArticle(article);
    }
}

 

4. BoardDAO 클래스를 다음과 같이 작성합니다. 전달된 수정 데이터에 대해 이미지 파일을 수정하지 않는 경우를 동적으로 SQL문을 생성하여 수정 데이터를 반영합니다.

package sec03.brd05;

import java.net.URLEncoder;
import java.sql.Connection;
import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.sql.DataSource;


public class BoardDAO {
    private DataSource dataFactory;
    Connection conn;
    PreparedStatement pstmt;

    public BoardDAO() {
        try {
            Context ctx = new InitialContext();
            Context envContext = (Context) ctx.lookup("java:/comp/env");
            dataFactory = (DataSource) envContext.lookup("jdbc/oracle");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public List<ArticleVO> selectAllArticles() {
        List<ArticleVO> articlesList = new ArrayList<ArticleVO>();
        try {
            conn = dataFactory.getConnection();
            String query = "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";
            System.out.println(query);
            pstmt = conn.prepareStatement(query);
            ResultSet 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 article = new ArticleVO();
                article.setLevel(level);
                article.setArticleNO(articleNO);
                article.setParentNO(parentNO);
                article.setTitle(title);
                article.setContent(content);
                article.setId(id);
                article.setWriteDate(writeDate);
                articlesList.add(article);
            }
            rs.close();
            pstmt.close();
            conn.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return articlesList;
    }

    private int getNewArticleNO() {
        try {
            conn = dataFactory.getConnection();
            String query = "SELECT  max(articleNO) from t_board ";
            System.out.println(query);
            pstmt = conn.prepareStatement(query);
            ResultSet rs = pstmt.executeQuery(query);
            if (rs.next())
                return (rs.getInt(1) + 1);
            rs.close();
            pstmt.close();
            conn.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return 0;
    }

    public int insertNewArticle(ArticleVO article) {
        int articleNO = getNewArticleNO();
        try {
            conn = dataFactory.getConnection();
            int parentNO = article.getParentNO();
            String title = article.getTitle();
            String content = article.getContent();
            String id = article.getId();
            String imageFileName = article.getImageFileName();
            String query = "INSERT INTO t_board (articleNO, parentNO, title, content, imageFileName, id)"
                    + " VALUES (?, ? ,?, ?, ?, ?)";
            System.out.println(query);
            pstmt = conn.prepareStatement(query);
            pstmt.setInt(1, articleNO);
            pstmt.setInt(2, parentNO);
            pstmt.setString(3, title);
            pstmt.setString(4, content);
            pstmt.setString(5, imageFileName);
            pstmt.setString(6, id);
            pstmt.executeUpdate();
            pstmt.close();
            conn.close();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return articleNO;
    }

    public ArticleVO selectArticle(int articleNO) {
        ArticleVO article = new ArticleVO();
        try {
            conn = dataFactory.getConnection();
            String query = "select articleNO,parentNO,title,content, NVL(imageFileName, 'null') as imageFileName,id, writeDate" + " from t_board"
                    + " where articleNO=?";
            System.out.println(query);
            pstmt = conn.prepareStatement(query);
            pstmt.setInt(1, articleNO);
            ResultSet rs = pstmt.executeQuery();
            rs.next();
            int _articleNO = rs.getInt("articleNO");
            int parentNO = rs.getInt("parentNO");
            String title = rs.getString("title");
            String content = rs.getString("content");
            String imageFileName = URLEncoder.encode(rs.getString("imageFileName"), "UTF-8"); //�����̸��� Ư�����ڰ� ���� ��� ���ڵ��մϴ�.
            if(imageFileName.equals("null")) {
                imageFileName = null;
            }

            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();
            conn.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return article;
    }

    public void updateArticle(ArticleVO article) {
        int articleNO = article.getArticleNO();
        String title = article.getTitle();
        String content = article.getContent();
        String imageFileName = article.getImageFileName();
        try {
            conn = dataFactory.getConnection();
            String query = "update t_board  set title=?,content=?";
            if (imageFileName != null && imageFileName.length() != 0) {
                query += ",imageFileName=?";
            }
            query += " where articleNO=?";

            System.out.println(query);
            pstmt = conn.prepareStatement(query);
            pstmt.setString(1, title);
            pstmt.setString(2, content);
            if (imageFileName != null && imageFileName.length() != 0) {
                pstmt.setString(3, imageFileName);
                pstmt.setInt(4, articleNO);
            } else {
                pstmt.setInt(3, articleNO);
            }
            pstmt.executeUpdate();
            pstmt.close();
            conn.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

 

5. viewArticle.jsp를 다음과 같이 작성합니다. 수정하기를 클릭해 fn_enable() 함수를 호출하여 비활성화된 텍스트 박스를 수정할 수 있도록 활성화시킵니다. 또한 글 정보와 이미지를 수정한 후 수정반영하기를 클릭하면 fn_modify_article() 함수를 호출하여 컨트롤러로 수정 데이터를 전송합니다.

<%@ page language="java" contentType="text/html; charset=UTF-8"
         pageEncoding="UTF-8"
         isELIgnored="false" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%
    request.setCharacterEncoding("UTF-8");
%>
<c:set var="contextPath"  value="${pageContext.request.contextPath}"  />
<head>
    <meta charset="UTF-8">
    <title>글보기</title>
    <style>
        #tr_btn_modify{
            display:none;
        }

    </style>
    <script  src="http://code.jquery.com/jquery-latest.min.js"></script>
    <c:choose>
        <c:when test="${not empty article.imageFileName && article.imageFileName!='null' }">
            <script type="text/javascript" >
                function fn_enable(obj){
                    document.getElementById("i_title").disabled=false;
                    document.getElementById("i_content").disabled=false;
                    document.getElementById("i_imageFileName").disabled=false;
                    document.getElementById("tr_btn_modify").style.display="block";
                    document.getElementById("tr_btn").style.display="none";
                }
            </script>
        </c:when>
        <c:otherwise>
            <script type="text/javascript" >
                function fn_enable(obj){
                    document.getElementById("i_title").disabled=false;
                    document.getElementById("i_content").disabled=false;

                    document.getElementById("tr_btn_modify").style.display="block";
                    document.getElementById("tr_btn").style.display="none";
                }
            </script>
        </c:otherwise>
    </c:choose>




    <script type="text/javascript" >
        function backToList(obj){
            obj.action="${contextPath}/board/listArticles.do";
            obj.submit();
        }

        /*
        function fn_enable(obj){
            document.getElementById("i_title").disabled=false;
            document.getElementById("i_content").disabled=false;

            document.getElementById("i_imageFileName").disabled=false;
            document.getElementById("tr_btn_modify").style.display="block";
            document.getElementById("tr_btn").style.display="none";
        }
        */
        function fn_modify_article(obj){
            obj.action="${contextPath}/board/modArticle.do";
            obj.submit();
        }

        function fn_remove_article(url,articleNO){
            var form = document.createElement("form");
            form.setAttribute("method", "post");
            form.setAttribute("action", url);
            var articleNOInput = document.createElement("input");
            articleNOInput.setAttribute("type","hidden");
            articleNOInput.setAttribute("name","articleNO");
            articleNOInput.setAttribute("value", articleNO);

            form.appendChild(articleNOInput);
            document.body.appendChild(form);
            form.submit();

        }

        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"  action="${contextPath}"  enctype="multipart/form-data">
    <table  border="0" align="center" >
        <tr>
            <td width="150" align="center" bgcolor="#FF9933">
                글번호
            </td>
            <td >
                <input type="text"  value="${article.articleNO }"  disabled />
                <input type="hidden" name="articleNO" value="${article.articleNO}"  />
            </td>
        </tr>
        <tr>
            <td width="150" align="center" bgcolor="#FF9933">
                작성자 아이디
            </td>
            <td >
                <input type=text value="${article.id }" name="writer"  disabled />
            </td>
        </tr>
        <tr>
            <td width="150" align="center" bgcolor="#FF9933">
                제목
            </td>
            <td>
                <input type="text" value="${article.title }"  name="title"  id="i_title" disabled />
            </td>
        </tr>
        <tr>
            <td width="150" align="center" bgcolor="#FF9933">
                내용
            </td>
            <td>
                <textarea rows="20" cols="60"  name="content"  id="i_content"  disabled />${article.content }</textarea>
            </td>
        </tr>

        <c:if test="${not empty article.imageFileName && article.imageFileName!='null' }">
            <tr>
                <td width="150" align="center" bgcolor="#FF9933"  rowspan="2">
                    이미지
                </td>
                <td>
                    <input  type= "hidden"   name="originalFileName" value="${article.imageFileName }" />
                    <img src="${contextPath}/download.do?articleNO=${article.articleNO}&imageFileName=${article.imageFileName}" id="preview"  /><br>

                </td>
            </tr>
            <tr>
                <td>
                    <input  type="file"  name="imageFileName " id="i_imageFileName"   disabled   onchange="readURL(this);"   />
                </td>
            </tr>
        </c:if>
        <tr>
            <td width="150" align="center" bgcolor="#FF9933">
                등록일자
            </td>
            <td>
                <input type=text value="<fmt:formatDate value="${article.writeDate}" />" disabled />
            </td>
        </tr>
        <tr   id="tr_btn_modify"  >
            <td colspan="2"   align="center" >
                <input type=button value="수정반영하기"   onClick="fn_modify_article(frmArticle)"  >
                <input type=button value="취소"  onClick="backToList(frmArticle)">
            </td>
        </tr>

        <tr  id="tr_btn"    >
            <td colspan=2 align=center>
                <input type=button value="수정하기" onClick="fn_enable(this.form)">
                <input type=button value="삭제하기" onClick="fn_remove_article('${contextPath}/board/removeArticle.do', ${article.articleNO})">
                <input type=button value="리스트로 돌아가기"  onClick="backToList(this.form)">
                <input type=button value="답글쓰기"  onClick="fn_reply_form('${contextPath}/board/replyForm.do', ${article.articleNO})">
            </td>
        </tr>
    </table>
</form>
</body>
</html>

 

6. 글 상세창에서 수정하기를 클릭해 글 정보가 표시된 텍스트 박스를 활성화시킵니다.

 

7. 글 정보와 이미지 파일을 수정한 후 수정반영하기를 클릭해 /board/modArticle.do로 요청합니다.

 

8. 글 수정 후 수정된 내용으로 글 상세 화면에 표시합니다.