위키에서는 인터넷에 오른 원문(하나의 게시물)에 대하여 짤막하게 답하여 올리는 글.

같은 말로는 '답글'이라고 정의한다.

댓글은 하나의 게시물에 대하여 작성한 글이기 때문에 글읽기 페이지에서 대부분의 기능이 이루어진다.

하나의 게시물 번호(BRDNO)에 대하여 다수의 댓글(RENO)을 가지는 형태로 구성된다.

댓글을 저장하는 테이블(TBL_BOARDREPLY )은

게시판과 유사한 테이블 구조로 다음 SQL문과 같이 구성되어 있다.

CREATE TABLE TBL_BOARDREPLY (
      BRDNO INT(11) NOT NULL,                       -- 게시물 번호
      RENO INT(11) NOT NULL,                         -- 댓글 번호
      REWRITER VARCHAR(10) NOT NULL,            -- 작성자
      REMEMO VARCHAR(500) DEFAULT NULL,       -- 댓글내용
      REDATE DATETIME DEFAULT NULL,              -- 작성일자
      REDELETEFLAG VARCHAR(1) NOT NULL,        -- 삭제여부
      PRIMARY KEY (RENO)
)


댓글 테이블 처리를 위해 다음과 같이 BoardReplyVO를 생성해야 한다.

public class BoardReplyVO {

    private String brdno;

    private String reno;

    private String rewriter;

    private String redeleteflag;

    private String rememo;

    private String redate;

   

    public String getBrdno() {

        return brdno;

    }

   

    public void setBrdno(String brdno) {

        this.brdno = brdno;

    }

    ~~ 생략 ~~

BoardReplyVO.java

하나의 게시물 번호(BRDNO)에 대하여 다수의 댓글(RENO)을 가지는 형태이기 때문에

키 구성은 게시물 번호(BRDNO)와 댓글번호(RENO)의 복합키로 구성하는 것이

데이터베이스 설계원칙에 맞지만 여기서는 댓글번호(RENO)만 키로 구성한다.

복합키를 사용하면 매 처리마다 키값들을 가지고 다니면서 처리해야 하기 때문에 프로그램이 복잡해 진다.

간편한 개발을 위해 댓글번호(RENO)만 기본키로 구성하였다.


글읽기 화면 하단에

댓글 작성을 위한 입력 화면이 있고, 그 아래에 기존에 작성된 댓글의 리스트가 출력된다.

댓글 리스트는 수정/삭제를 하기 위한 버튼이 필요하고

수정일 경우에는 댓글 수정을 위한 입력 화면이 있어야 한다.

글을 작성한 작성자만이 해당 댓글을 수정할 수 있게 하기 위해서는

현재 로그인한 사용자가 필요한데 여기서는 게시판만 만들기 때문에 이러한 기능이 없다.

따라서 작성자 이름과 내용을 입력하고 아무나 수정/삭제 할 수 있게 구성하였다.

비밀번호를 입력 받아서 처리하는 것도 좋은 방법인데

개념 파악을 위해 간단하게 구현하였고

이 소스를 실제 개발에 사용할 경우 작성자 이름(REWRITER)을 작성자 아이디(ID)로 바꿔서 사용할 수 있다는 걸 고려했다.


삭제는 댓글 번호(RENO)를 받아서 삭제 처리하면 간단하게 처리되지만

수정은 자바 스크립트와 관련된 조금의 기교가 필요하다.

예로, 열 개의 댓글이 있을 경우

열 개의 입력상자(Text, TextArea)를 만드는 경우가 대부분이다.

열 개의 입력상자를 숨겨놓고(display:none)

사용자가 수정 버튼을 누르면 해당 입력 상자를 보여주는(display:””) 방식으로 개발한다.

댓글 리스트는 페이징 처리를 하지 않는 경우가 많은데

100개의 댓글이 있으면 100개의 입력상자가 생성되기 때문에 선호하지 않는다.

개인적으로

하나의 입력상자를 이용하여 수정하고자 하는 해당 댓글 위치에 옮겨 넣는 방식을 선호한다.


마지막으로 게시판 리스트에서 해당 게시물의 댓글 수를 보여주면 된다.


'Java > 게시판 5: 댓글' 카테고리의 다른 글

2. 댓글 쓰기  (2) 2016.05.15
3. 댓글 리스트 / 삭제  (0) 2016.05.15
4. 댓글 수정  (1) 2016.05.15

기존 게시판 읽기(board5Read)의 기본 기능 뒤에

다음과 같이 댓글을 작성할 수 있는 화면 구성을 추가해 준다.

<a href="board5List">돌아가기</a>
<a href="board5Delete?brdno=<c:out value="${boardInfo.brdno}"/>">삭제</a>
<a href="board5Form?brdno=<c:out value="${boardInfo.brdno}"/>">수정</a>
<p>&nbsp;</p>
<div style="border: 1px solid; width: 600px; padding: 5px">
    <form name="form1" action="board5ReplySave" method="post">
        <input type="hidden" name="brdno" value="<c:out value="${boardInfo.brdno}"/>">
        작성자: <input type="text" name="rewriter" size="20" maxlength="20"> <br/>
        <textarea name="rememo" rows="3" cols="60" maxlength="500" placeholder="댓글을 달아주세요."></textarea>
        <a href="#" onclick="fn_formSubmit()">저장</a>
    </form>
</div>

BoardRead.jsp


숨겨진 값으로(hidden) 게시물 번호(BRDNO)가 있다. 

게시물 번호는 현재 읽고 있는 글 번호를 의미하며

사용자가 입력한 작성자명과 댓글 내용과 같이 서버로 전송(fn_formSubmit) 된다.

새로 작성되는 댓글은 댓글 번호(RENO)가 부여 되지 않았고

여기서는 수정 없이 새 글만 작성하기 때문에 댓글 번호(RENO)와 관련된 처리를 하지 않는다.


전송된 내용을 저장하기 위해 board5ReplySave 컨트롤을 작성한다.

전송 받은 내용을 서비스에 전달하고

데이터 베이스에 저장이 되면 다시 해당 글읽기 페이지로 이동한다.

해당 글을 가져오기 위해 게시 글 번호(brdno)를 파라메터로 넘겨줘야 한다.

    /**
     * 댓글 저장.
     */
    @RequestMapping(value = "/board5ReplySave")
    public String board5ReplySave(HttpServletRequest request, BoardReplyVO boardReplyInfo) {
       
        boardSvc.insertBoardReply(boardReplyInfo);

        return "redirect:/board5Read?brdno=" + boardReplyInfo.getBrdno();
    }

Board5Ctr.java

서비스(insertBoardReply)에서는

댓글 번호(reno)가 없으면 SQL의 Insert문을, 있으면 Update문을 실행하도록 처리해준다.

    public void insertBoardReply(BoardReplyVO param) {
        if (param.getReno()==null || "".equals(param.getReno())) {
            sqlSession.insert("insertBoard5Reply", param);
        } else {
            sqlSession.insert("updateBoard5Reply", param);
        }
    }

Board5Svc.java

댓글 번호(reno)는 게시판과 동일하게 저장된 댓글 번호 중 최대값(+1)을 계산하여 저장한다.

수정일 때는 댓글 내용(rememo)만 수정해 주면 된다.

<insert id="insertBoard5Reply" parameterType="gu.board5.BoardReplyVO" >
    <selectKey resultType="String" keyProperty="reno" order="BEFORE">
        SELECT IFNULL(MAX(RENO),0)+1 FROM TBL_BOARDREPLY
    </selectKey>
       
    INSERT INTO TBL_BOARDREPLY(BRDNO, RENO, REWRITER, REDELETEFLAG, REMEMO, REDATE)
    VALUES (#{brdno}, #{reno}, #{rewriter}, 'N', #{rememo}, NOW())
</insert>

<update id="updateBoard5Reply" parameterType="gu.board5.BoardReplyVO">
    UPDATE TBL_BOARDREPLY
       SET REMEMO=#{rememo}
     WHERE RENO=#{reno}
</update>

board5.xml

실행해서 댓글을 달아보고

데이터 베이스에 잘 저장되었는지 확인하면 된다.

수정은 제법 복잡한 화면 처리를 필요로 해서 지금 처리하지 않는다.


'Java > 게시판 5: 댓글' 카테고리의 다른 글

1. 댓글 시작하기  (1) 2016.05.15
3. 댓글 리스트 / 삭제  (0) 2016.05.15
4. 댓글 수정  (1) 2016.05.15

댓글 리스트는 해당 게시물에 맞는 댓글을 읽어서 게시판 리스트처럼 뿌려주면 된다.

다음 그림처럼 댓글 입력 화면 뒤에 리스트를 나열 하였다.


먼저 댓글 리스트는 해당 게시물을 가져올 때(board5Read 컨트롤 처리시) 같이 가져와야 한다.

다음 코드처럼 글 읽기 컨트롤(board5Read)에

댓글 리스트를 가져오는 서비스(selectBoard5ReplyList)를 추가해 주고

반환 받은 리스트(replylist)를 JSP로 전달해(modelMap) 준다.

public String board5Read(HttpServletRequest request, ModelMap modelMap) {
   
    String brdno = request.getParameter("brdno");
   
    boardSvc.updateBoard5Read(brdno);
    BoardVO boardInfo = boardSvc.selectBoardOne(brdno);
    List<?> listview = boardSvc.selectBoard5FileList(brdno);
    List<?> replylist = boardSvc.selectBoard5ReplyList(brdno);
   
    modelMap.addAttribute("boardInfo", boardInfo);
    modelMap.addAttribute("listview", listview);
    modelMap.addAttribute("replylist", replylist);
   
    return "board5/BoardRead";
}

Board5Ctr.java

public List<?> selectBoard5ReplyList(String param) {

        return sqlSession.selectList("selectBoard5ReplyList", param);

}

Board5Svc.java

JSP 파일에서 다음과 같이 앞서 추가했던 댓글 입력 코드 뒤에

댓글 리스트를 출력하는 코드를 작성한다.

<div style="border: 1px solid; width: 600px; padding: 5px">
    <form name="form1" action="board5ReplySave" method="post">
        <input type="hidden" name="brdno" value="<c:out value="${boardInfo.brdno}"/>">
        <input type="hidden" name="reno">
        작성자: <input type="text" name="rewriter" size="20" maxlength="20"> <br/>
        <textarea name="rememo" rows="3" cols="60" maxlength="500" placeholder="댓글을 달아주세요."></textarea>
        <a href="#" onclick="fn_formSubmit()">저장</a>
    </form>
</div>

<c:forEach var="replylist" items="${replylist}" varStatus="status">
    <div style="border: 1px solid gray; width: 600px; padding: 5px; margin-top: 5px;">   
        <c:out value="${replylist.rewriter}"/> <c:out value="${replylist.redate}"/>
        <a href="#" onclick="fn_replyDelete('<c:out value="${replylist.reno}"/>')">삭제</a>
        <a href="#" onclick="fn_replyUpdate('<c:out value="${replylist.reno}"/>')">수정</a>
        <br/>
        <div id="reply<c:out value="${replylist.reno}"/>"><c:out value="${replylist.rememo}"/></div>
    </div>
</c:forEach>

<div id="replyDiv" style="width: 99%; display:none">
    <form name="form2" action="board5ReplySave" method="post">
        <input type="hidden" name="brdno" value="<c:out value="${boardInfo.brdno}"/>">
        <input type="hidden" name="reno">
        <textarea name="rememo" rows="3" cols="60" maxlength="500"></textarea>
        <a href="#" onclick="fn_replyUpdateSave()">저장</a>
        <a href="#" onclick="fn_replyUpdateCancel()">취소</a>
    </form>
</div>

BoardRead.jsp

리스트(replylist)의 개수만큼 반복해서(forEach) 개별 댓글들을 출력해 준다.

게시판 리스트에서는 Table 테그를 이용했지만

여기서는 DIV를 사용했다.

예전에는 많은 개발자들이 리스트를 Table 테그로 생성했지만 근래에는 DIV를 많이 사용한다.


replyDiv는 수정을 위한 입력 폼으로 삭제시 댓글번호를 전달하기 위해 사용한다.

자세한 내용은 댓글 수정 부분에서 설명할 것이다.


삭제는 fn_replyDelete, 수정은 fn_replyUpdate 함수를 호출하고 파라메터로 댓글 번호(reno)를 넘겨준다.

삭제는 다음과 같이 댓글 번호(reno)를 숨겨진 필드에 넣어서

삭제 컨트롤(board5ReplyDelete)를 호출(submit)하면 된다.

function fn_replyDelete(reno){
    if (!confirm("삭제하시겠습니까?")) {
        return;
    }
    var form = document.form2;

    form.action="board5ReplyDelete";
    form.reno.value=reno;
    form.submit();   
}

BoardRead.jsp


컨트롤에서는 전송 받은 내용을 서비스에 전달하여

해당 댓글을 삭제 한 뒤 다시 해당 글읽기 페이지로 이동한다.

해당 글을 가져오기 위해 게시 글 번호(brdno)를 파라메터로 넘겨준다.

    @RequestMapping(value = "/board5ReplyDelete")
    public String board5ReplyDelete(HttpServletRequest request, BoardReplyVO boardReplyInfo) {
       
        boardSvc.deleteBoard5Reply(boardReplyInfo.getReno());

        return "redirect:/board5Read?brdno=" + boardReplyInfo.getBrdno();
    }

Board5Ctr.java

'Java > 게시판 5: 댓글' 카테고리의 다른 글

1. 댓글 시작하기  (1) 2016.05.15
2. 댓글 쓰기  (2) 2016.05.15
4. 댓글 수정  (1) 2016.05.15

수정과 관련된 입력 폼은 앞서 삭제에서 같이 만들었다.

삭제에서는 댓글 번호를 넣어 전달했고

수정에서는 댓글 번호와 댓글 내용을 넣어서 전달한다.

다만, 댓글 쓰기에서 같은 형태의 입력처리를 했기 때문에 충돌을 막기 위해

댓글 쓰기에서는 form1으로 폼 태그의 이름을 부여했고

댓글 수정에서는 form2으로 폼 태그의 이름을 부여했다.

즉, 게시물에 대하여 작성하는 댓글의 댓글내용(rememo)와

수정시 사용하는 댓글내용(rememo)의 컨트롤(HTML Tag) 이름이 동일해도 문제가 생기지 않는 것은

컨트롤들이 속한 폼 이름이 달라서 그런 것이다.

폼 이름이 다르면 각 폼 안의 컨트롤은 이름이 같아도 구별되어 사용된다.

댓글 내용인 rememo은 form1.rememo와 form2.rememo로 다르게 처리한다.


수정 SQL(UPDATE)문은 댓글 쓰기 처리시 같이 작성했다 (updateBoard5Reply). 


따라서 남아 있는 것이 화면 처리이고,

이 화면 처리는 자바 스크립트를 이용하여 다소 복잡하게 구현해야 한다.

사용된 자바 스크립트 함수는 3가지로

수정 버튼을 누르면 수정 폼을 화면에 보여주는 함수(fn_replyUpdate),

수정 후 저장 버튼을 누르면 서버로 전송하는 함수(fn_replyUpdateSave),

수정하나 취소 버튼을 눌러서 입력 폼을 감추는 함수(fn_replyUpdateCancel) 로 구성되어 있다.

var updateReno = updateRememo = null;
function fn_replyUpdate(reno){
    var form = document.form2;
    var reply = document.getElementById("reply"+reno);
    var replyDiv = document.getElementById("replyDiv");
    replyDiv.style.display = "";
   
    if (updateReno) {
        document.body.appendChild(replyDiv);
        var oldReno = document.getElementById("reply"+updateReno);
        oldReno.innerText = updateRememo;
    }
   
    form.reno.value=reno;
    form.rememo.value = reply.innerText;
    reply.innerText ="";
    reply.appendChild(replyDiv);
    updateReno   = reno;
    updateRememo = form.rememo.value;
    form.rememo.focus();
}

function fn_replyUpdateSave(){
    var form = document.form2;
    if (form.rememo.value=="") {
        alert("글 내용을 입력해주세요.");
        form.rememo.focus();
        return;
    }
   
    form.action="board5ReplySave";
    form.submit();   
}

function fn_replyUpdateCancel(){
    var form = document.form2;
    var replyDiv = document.getElementById("replyDiv");
    document.body.appendChild(replyDiv);
    replyDiv.style.display = "none";
   
    var oldReno = document.getElementById("reply"+updateReno);
    oldReno.innerText = updateRememo;
    updateReno = updateRememo = null;
}

BoardRead.jsp


저장 버튼 처리는 댓글 입력 여부만 확인하는 단순한 코드로 작성했다.

수정 폼을 화면에 보여주는 기능과 숨기는 기능은 제법 복잡한 처리를 해야 한다.

자바 스크립트의 document.body, document.form2, document.getElementById,.appendChild 등은 찾아보길 바라고 여기서는 간단하게 넘어간다.


수정 폼을 화면에 보여주는 함수(fn_replyUpdate)는

숨겨져 있는 댓글 입력창(id=replyDiv)을 사용자에게 보여주는 것이 핵심 기능이다.

댓글 입력창을 보여주며 입력박스(rememo)에 기존에 입력한 댓글 내용을 넣어줘야 한다.

댓글 번호를 이용해서 Ajax로 서버에서 댓글 내용을 가져올 수 있지만

여기서는 화면에 출력된 리스트에서 선택한 댓글의 내용을 가져와 넣어준다.

리스트에서 선택한 댓글의 내용을 가져오기 위해

리스트를 생성할 때 각 댓글을 DIV 테그로 생성하고, 댓글번호를 이용하여 이 DIV 테그의 ID("reply"+reno)를 부여하였다.

즉, document.getElementById("reply"+reno)로 사용자가 수정하고자 하는 댓글의 내용을 가져와

입력창의 입력박스에 넣어주는 것이다 (form.rememo.value = reply.innerText;).

댓글 수정 상태에서 취소나 저장을 하지 않고 다른 글을 수정하려고 할 때,

현재 입력하던 내용을 취소하기 위해, 현재 입력하는 댓글 번호를 저장해서 가지고 있어야 한다.

updateReno는 현재 입력하는 댓글 번호로

현재 입력하던 내용을 취소하고 이전 내용을 화면에 출력하는 데 이용한다 (oldReno.innerText = updateRememo).

입력 창을 감추는 함수(fn_replyUpdateCancel)는

수정하던 댓글 내용(updateReno)를 취소하고 입력창(replyDiv)을 화면에서 보이지 않게 처리한다 (display="none”).

그리고 부모를 document.body로 바꾸어 준다.

현재 있는 위치에는 기존 댓글의 내용이 출력되어야 하기 때문에 다른 곳으로 옮겨 주는 것이다.


수정 후 저장 버튼을 누르면 입력한 내용을 서버로 전송(submit)하고,

서버에서는 내용을 데이터베이스에 저장한 후

다시 게시판 글 읽기로 돌아가("redirect:/board5Read?brdno=") 수정된 댓글이 보이게 된다.


이상의 내용에서 자바 스트립트가 조금 복잡해 보일 수 있는데

기본 개념은 입력창을 적절한 위치에 보여주고 숨기는 것이니 잘 익혀두길 바라고

여기서는 자바 스트립트로만 구성했지만

실제로는 JQuery를 이용하는 것이 조금 더 깔끔하고 쉬울 수 있다.

직접 JQuery로 변환해 보는 것도 좋을 것이고 차후에 변환할 예정이다.


'Java > 게시판 5: 댓글' 카테고리의 다른 글

1. 댓글 시작하기  (1) 2016.05.15
2. 댓글 쓰기  (2) 2016.05.15
3. 댓글 리스트 / 삭제  (0) 2016.05.15

PMD는 정적인 소스코드 분석 도구로

자세한 설치와 사용법은 한국인터넷진흥원에서 제공하는

"공개SW를 활용한 소프트웨어 개발보안 검증가이드"의 "4장 PMD 사용방법"을 따라 한 후 다음 내용을 읽기 바란다.


게시판 예제를 대상으로 PMD를 실행하면 다음과 같은 결과를 얻게 된다.

화면 하단의 "Violations Overview"에서 오류를 두번 클릭하면 해당 오류 코드로 이동한다.

게시판에서 AvoidCatchingGenericException오류가 발견되었다.

이 오류는 일반적인 예외처리(Exception)을 하지 말라는 것으로

TransactionException 등과 같이 구체적으로 작성하면 된다.


예외 처리에 대한 자세한 설명은 검색해 보거나 이 블로그를 참고하기 바라고

위 결과와 관련하여 한가지를 더 처리한다.

board4.xml의 게시판 글쓰기 처리를 하는 SQL인 insertBoard4에서 사용하는 필드명을 틀리게 작성한다.

여기에서는 BRDTITLE1으로 지정했다.

    <insert id="insertBoard4" parameterType="gu.board4.boardVO" >
           <selectKey resultType="String" keyProperty="brdno" order="BEFORE">
            SELECT IFNULL(MAX(BRDNO),0)+1 FROM TBL_BOARD
        </selectKey>
   
        INSERT INTO TBL_BOARD(BRDNO, BRDTITLE1, BRDWRITER, BRDMEMO, BRDDATE, BRDHIT, BRDDELETEFLAG)
        VALUES (#{brdno}, #{brdtitle}, #{brdwriter}, #{brdmemo}, NOW(), 0, 'N' )
    </insert>

board4.xml

웹 브라우저에서 게시글을 작성한후 저장하면(http://localhost:8080/board/board4Save) 다음과 같은 오류가 발생한다.

그림에 나타난 것과 같이 사용된 SQL문과 경로 정보등이 사용자에게 노출되어 보안에 문제를 야기하게 된다.

따라서 PMD에서는 잡히지 않았지만 예외 처리를 바꿔야 한다.


흔히 사용되지만 다음과 같은 코드는 사용하지 않는 것이 좋다.

try {
    프로그램 코드
} catch(Exception e) {
    e.printStackTrace();
}

printStackTrace대신에 System.out.println(e), throw e 등도 사용하지 않는 것이 좋다.

예제에 사용하지 않았지만

이러한 오류를 오류 메시지를 통한 정보노출이라고 하여 PMD에서는 AvoidPrintStackTrace로 설정하여 오류로 출력해 준다.


즉, 앞서 PMD에서 지적된 Avoid catching generic exceptions과 같이 정리하면

다음과 같이 구체적인 예외 처리를 하고 메세지는 직접 출력하는 것이 좋다.

try {
    프로그램 코드
} catch (BadSqlGrammarException ex) {
    System.out.println("잘못된 SQL 문 사용"+ ex.toString());
}

SQL문을 틀리게 작성했기 때문에 BadSqlGrammarException으로 구체적으로 명시하고

오류메세지를 직접 출력한다.

board4Svc.java의 insertBoard 함수에서 위와 같이 수정하고 실행하면

로그에는 오류가 출력되지만 웹 사이트에서는 오류 없이 리스트로 넘어간다.

(사용자에게 글 저장이 안된다는 연락을 받을 수 있다.)


정리하면 다음과 같이 사용하는 것이 좋다.

BadSqlGrammarException는 일부러 발생시킨 오류이기 때문에 TransactionException으로 처리한다.

아니면 try 문을 사용하지 않고 처리해도 된다.

public void insertBoard(BoardVO param, List<FileVO> filelist, String[] fileno)  throws Exception {
       
        DefaultTransactionDefinition def = new DefaultTransactionDefinition();
        def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
        TransactionStatus status = txManager.getTransaction(def);
       
        try {
            ~~ 생략 ~~
            txManager.commit(status);
        } catch (TransactionException ex) {
            txManager.rollback(status);
            System.out.println("데이터 저장 오류: " + ex.toString());
        }           
    }

Board41Svc.java

오류로 잡히지 않았지만 모든 메소드에  throws Exception(위 코드의 굵은 글자) 가 사용되고 있다.

Java 관련 코드에서 일반적으로 사용하는 것이지만 제거하는 것이 좋다.

앞서 언급된 일반적인 예외처리는 지양하는 것이 좋고, 

예외 처리를 Exception으로 던지고 마는 것이 아니라

try문으로 보다 구체적으로 처리하는 것이 추천되기 때문이다.

따라서 Board41Ctr.java와 Board41Svc.java의 throws Exception를 모두 제거하는 것이 좋다.

ex.toString()도 가급적 사용하지 않는 것이 좋지만

개발시 정확한 오류 메시지를 확인하기 위해 사용하였다.


언급한 예외 처리는 Eclipse에서 기본적으로 생성해 주는 것으로 무심코 넘기는 경우가 많은 데,

최근 공공기관, 대기업 등에서 보안에 대한 관심이 높아지면서

상용 도구를 이용하여 이상의 내용보다 더 많은 내용을 점검하고 있다.

따라서 공개 S/W를 이용하여 이러한 사항들을 미리 처리하는 것이 좋을 것이다.


마지막으로

이러한 조치를 다한 후에 web.xml에서 에러 페이지 처리를 해줘야 한다.

설정 방법은 검색해 보거나 다음 블로그를 참고하면 된다.

http://artrix.tistory.com/383

http://hyeonstorage.tistory.com/98


이러한 조치를 통해 다음 그림과 같이 사용자에게 불필요한 정보가 노출되지 않도록 해야 된다.

다음과 같이 web.xml에서 Exception 오류에 대한 오류 웹 페이지 지정을 처리를 해주면 되고

404, 500등의 오류도 처리해 주는 것이 좋다.

    <!-- error 페이지 -->
    <error-page>
        <exception-type>java.lang.Exception</exception-type>
        <location>/WEB-INF/jsp/common/error.jsp</location>
    </error-page>

    <error-page>
        <error-code>404</error-code>
        <location>/WEB-INF/jsp/common/error404.jsp</location>
    </error-page>

board\src\main\webapp\WEB-INF\web.xml

이상의 내용은 사이트 품질과도 관련되지만

정보 노출의 의미에서는 웹 사이트 보안과도 관련이 있는 내용으로 잘 숙지해서 처리해야 한다.


'Java > 게시판 기타: 품질 등' 카테고리의 다른 글

1. 프로그램 작성 외의 것들  (1) 2016.04.24
2. CheckStyle I - 설치  (0) 2016.04.23
3. CheckStyle II  (0) 2016.04.23
4. FindBugs  (0) 2016.04.23

자세한 사용법은 검색해서 찾아보길 바라고

“개발자가 디자인(CSS)을 알아야 하는 이유”와 관련하여 간단한 사항을 정리한다.

개발자들은 웹 브라우저에서 F12키를 눌러 자바스크립트 디버깅을 많이 쓰고

DOM 탐색기에 대해서는 무심코 넘어가는 경우가 많다.

앞서 언급한 바와 같이 디자인(CSS)는 개발하기 쉽게 해주는 한 방법이 되고

웹 개발에서는 동적으로 HTML 생성을 많이 한다.

제대로 생성되는지, 안 될 경우 쉽게 이유를 파악하고 처리하는 방법을 제공하는 것이 DOM 탐색기이다.


먼저 calendar5.html을 다운받아 실행한다.


이 상태에서 F12키를 누른다.

왼쪽에 보이는 HTML 트리가 DOM 탐색기이고

오른쪽에 보이는 것이 해당 DOM (HTML 태그)에 적용된 스타일(CSS)이 나오게 된다.

HTML은 트리 구조의 계층형으로 구성되는데

태그 옆의 삼각형(▷)을 눌러서 하위(자식) 태그를 볼 수 있다.

다음 그림은 DOM 탐색기에서 1(<div>1</div>)을 선택해서 웹 브라우저에서 1이 선택된 것을 볼 수 있다.

그림 상단의 풍선도움말에 나오듯 옵션이 그렇게 선택되어 있는 상태이다.

왼쪽 옆의 “요소선택”을 하면 웹 브라우저에서 마우스로 선택한 태그가 위 그림처럼 DOM 탐색기에 나타난다.

즉 앞서의 옵션은 DOM 탐색기에서 선택하면 웹브라우저에서 해당하는 태그가

요소 선택은 웹 브라우저에서 태그를 선택하면 DOM 탐색기가 선택되는 방식이다.

다음 그림처럼 요소 선택은 웹 브라우저에서 해당 태그를 선택하고

마우스 오른쪽 버튼을 눌러서 나타나는 컨텍스트 메뉴에서도 실행할 수 있다.


이제 이글의 본론을 이야기 한다.

다음 그림과 같이 태그를 선택하면 DOM 탐색기 오른쪽에 스타일 표시 창에 현재 사용중인 CSS 스타일(Class)이나 직접 입력한 인라인 스타일이 나타난다.

여기서 개발자가 값을 입력해 결과를 바로 확인할 수 있고

잘 모르는 CSS 속성이나 값에 대한 도움을 받을 수 있다.


테스트로 달력의 숫자 정렬을 중앙에서 오른쪽으로 바꾸어 보았다.

CSS 클래스가 calendar 하위에 있는 div (#calendar > div)에 일률적으로 부여되었기 때문에 하나만 수정해도 전체에 적용이 된다.

text-align의 값을 right로 바꾸어 주면 화면에 적용되는 것을 바로 알 수 있다.

이렇게 테스트해 보고 코드를 수정해 주면 된다.


이외에도 그림과 같이 숨겨진 값(hidden 태그)을 확인할 때도 유용하게 사용할 수 있다.


개인적인 경험으로

자바스크립트나 JSP에서 동적으로 HTML을 생성했는데

디자인이 틀어지거나 원하는 데로 되지 않는 경우 이 방법으로 쉽게 원인을 찾고 해결할 수 있었다.

익혀두면 웹 개발에서는 많은 도움이 되니 좀 더 자세한 내용을 찾아보길 바란다.




이 페이지에서는 동일한 웹 페이지를 개발할 때 

개발 언어(JavaScript)만 가지고 할 때와 CSS를 같이 사용할 때의 코드를 비교하여 장단점을 정리하였다.

개발 언어는 예제를 간단하게 구현하기 위해 JavaScript (JS)를 사용하였지만

Java 등 다른 언어를 사용했을 때도 동일하다.


이 예제를 이해하기 위해 간단한 달력 만들기를 할 것이고

예제를 만들면서 개발에 대한 이해도 향상시키기 위해 다음과 같이 단계별로 구성하였다.

  1. JS 에서 HTML Table 태그 생성하는 예제
  2. 해당 월의 모든 날짜를 가지고 오는 예제
  3. 1과 2를 섞어서 JS로 만든 간단한 일자 리스트
  4. 3을 보강하여 달력 모양 만들기
  5. 4의 코드를 CSS와 같이 사용하여 만든 달력


먼저, 몇 가지 JS의 코드를 이해해야 한다.

Document 클래스에 있는 

getElementById는 파라메터로 넘겨진 ID에 대한 HTML 태그를 가지고 오는 것이고

createElement는 주어진 파라메터(HTML 태그)를 생성하여 반환한다.

태그를 생성한 후 에는 appendChild로 부모를 지정해 줘야 화면에 보인다.


다음 코드는 달력을 만들기 위한 디자인 코드이다.

즉, 위의 코드는 세로 개수(7)만큼 반복해서 테이블의 행(TR) 태그를 만들고

가로 개수(5)만큼 반복해서 행 안의 (TD) 태그를 생성한다. 

동적으로 테이블 태그를 생성한다.

window.onload = function() {
    var calendar = document.getElementById("calendar");
    var table = document.createElement( "table");
    table.border = "1px";   
    table.width = "100px";   
    for (var i=0; i<5; i++) {
        var tr = document.createElement( "tr");
        table.appendChild(tr);
        for (var j=0; j<5; j++) {
            var td=document.createElement( "td");
            td.innerHTML ="<br/>"
            tr.appendChild(td);
        }
    }
    calendar.appendChild(table);
};   

다운로드: calendar1.html

실행하면 다음 그림과 같이 7 * 5로 구성된 테이블(Table) 태그가 생성된다.

다음 코드는 달력을 만들기 위해 날짜를 생성하는 코드이다.

달력은 매월 1일부터 마지막(28, 29, 10, 31)일까지 하루씩 반복하여 출력하는 것이다.

매월 1일(sdate)은 Date 클래스로 현재 날짜를 읽어와 일(day)을 1로 설정하면 된다 (setDate(1)).

마지막 날짜(edate)는 현재 월의 다음달 (edate.getMonth()+1)을 구하여 일자를 1로 설정하면 된다.

마지막 날짜는 다음달 1일인데

반복하는 일자 값을 다음달 1일보다 작게(<) 하면 되기 때문이다 (sdate < edate).

인터넷의 많은 자료가

옛날부터 전해오는 윤달 계산 방식으로 구현되어 있는데,

이 방식은 코드가 복잡하기 때문에

개발언어에서 제공하는 함수를 이용해서 시작일(sdate)과 종료일(edate)을 구하는 간단한 방식을 이용했다.

window.onload = function() {
    var sdate = new Date();
    var edate = new Date();
    sdate.setDate(1);
    edate.setMonth(edate.getMonth()+1);
    edate.setDate(1);
    while (sdate < edate) {
        document.write(sdate + "<br/>");
        sdate.setDate(sdate.getDate()+1);
    }
};   

다운로드: calendar2.html

실행하면 다음 그림과 같이 4월 1일부터 30일까지가 리스트로 출력된다.


첫 번째 코드와 두 번째 코드를 합쳐서 다음 코드를 작성한다.

이 코드는 그림과 같이 모든 날짜가 한 줄에 출력된다.

window.onload = function() {
    var sdate = new Date();
    var edate = new Date();
    sdate.setDate(1);
    edate.setMonth(edate.getMonth()+1);
    edate.setDate(1);

    var calendar = document.getElementById("calendar");
    var table = document.createElement( "table");
    calendar.appendChild(table);
    table.border = "1px";   
    table.width = "100px";   
    var tr = document.createElement( "tr");
    table.appendChild(tr);

    while (sdate < edate ) {
        var td=document.createElement( "td");
        td.innerHTML = sdate.getDate();
        tr.appendChild(td);
        sdate.setDate(sdate.getDate()+1);
    }
};   

다운로드: calendar3.html

실행 결과 다음 그림과 같이 4월의 일자들이 테이블 각 셀에 들어가서 나열되었다.


이 코드에 매주 토요일에 새로운 행(tr)이 만들어 지게 하는 코드를 넣어주면 된다.

getDay함수는 각 날짜의 요일(0~6)을 반환하는 함수로 

일요일은 0을, 토요일은 6을 반환한다.

따라서, 일요일부터 시작하기 때문에 getDay로 반환된 값이 0이면 새로운 행(TR)에 데이터를 출력한다.


조금 더 달력스럽게 보이기 위해 1일의 요일을 맞춰줘야 한다.

매월의 시작일이 무슨 요일일지 찾아서 그 개수만큼 공백을 넣어줘야 달력처럼 보인다.

변수의 값이 1일 일 때 getDay로 요일(0~6)을 파악하고, 요일 개수만큼 열(TD)을 생성하면

요일을 맞춰서 보여주게 된다.

window.onload = function() {
    var sdate = new Date();
    var edate = new Date();
    sdate.setDate(1);
    edate.setMonth(edate.getMonth()+1);
    edate.setDate(1);

    var calendar = document.getElementById("calendar");
    var table = document.createElement( "table");
    calendar.appendChild(table);
    table.border = "1px";   
    var tr = document.createElement( "tr");
    table.appendChild(tr);

    var preColumn = sdate.getDay();
    for (var i=0; i < preColumn; i++) {
        var td=document.createElement( "td");
        td.innerHTML = "<br/>";
        td.width="20px";
        tr.appendChild(td);
    }
   
    while (sdate < edate ) {
        var td=document.createElement( "td");
        td.innerHTML = sdate.getDate();
        td.width="20px";
        if (sdate.getDay()===0) {
            var tr = document.createElement( "tr");
            table.appendChild(tr);
        }
        tr.appendChild(td);
        sdate.setDate(sdate.getDate()+1);
    }
   
};   

다운로드:calendar4.html

다음 그림과 같이 그럴듯한 달력이 완성되고

제법 많은 코드가 생성된 것을 알 수 있다.



마지막으로 CSS를 사용한 다음 코드를 보면 코드 양이 다른 것을 확인할 수 있다.

<style>
    #calendar > div{
        width: 20px;
        border: 1px solid;
        display:inline-block;
        margin-top:-1;
        margin-left:-1;
        text-align:center;
    }
</style>
<script>
window.onload = function() {
    var sdate = new Date();
    var edate = new Date();
    sdate.setDate(1);
    edate.setMonth(edate.getMonth()+1);
    edate.setDate(1);

    var calendar = document.getElementById("calendar");
    var preColumn = sdate.getDay();
    for (var i=0; i < sdate.getDay(); i++) {
        var div=document.createElement( "div");
        div.innerHTML = "<br/>";
        calendar.appendChild(div);
    }
   
    while (sdate < edate ) {
        var div=document.createElement( "div");
        calendar.appendChild(div);
        div.innerHTML = sdate.getDate();
        sdate.setDate(sdate.getDate()+1);
    }
};
   
</script>   

다운로드: calendar5.html

DIV를 동적으로 생성해서 날짜 값을 넣어준 것이 전부이다.

실행 결과는 그림과 같이 JS만 사용했을 때랑 동일하다.

코드에 IF 문을 사용하지 않는다.

(개인적으로 프로그램을 쉽게 짜기 위해 IF 문 사용을 자제하는 걸 선호한다)

이유는 전체를 감싸는 DIV(calendar)의 크기를 150px로 주고

하위의 날짜 DIV의 크기를 20px로 줘서

7번째 (140px)까지 채우고 8번째가 되면 다음라인으로 배치되는 특성을 이용 한 것이다.

JS에서 처리 하지 않았던 글자의 중앙정렬(text-align)도 추가했다.

배경색등 더 추가해도 CSS처리하기 때문에 JS 코드에 변화는 없다.


이외에도 CSS를 이용하여 보다 쉽게 문자열 자르기등의 기능을 이용할 수 있다.


이렇게 처리하는 것이 중요한 이유는

1. 코드가 간단해 진다는 것이다. 

   개발언어에서 모든 것을 처리하면 당연히 양이 많을 수 밖에 없다.


2. 코드와 디자인을 분리하면 디자인 부분을 남(디자이너 등)에게 맡길 수 있다는 것이다.

    코드와 디자인 부분이 같이 있으면 누가 처리할 것 인지 하는 문제와 더불어

    개발자가 하면 디자인 부분의 누수가 생기고

    디자이너가 하면(?) 버그를 양산 할 수도 있다.

    그래서 중간 영역의 작업자가 있지만 쉬운 일은 아니다.


Spring이나 Struts등 Java나 다른 개발 언어를 사용하여 만드는 경우도 위와 동일하다.

IF 문 처리 부분에서 더 복잡한 코드로 처리되는 데 CSS로 처리하면 깔끔하게 구현할 수 있다.

간단하고 깔끔하게 구현되어야

차후에 수정하거나 다른 사람과의 협업 등에 편리하다.







프로그램을 개발하다 보면 여러 가지 도구들이 필요하다.

여러 사람이 같이 작업하기 때문에 코딩규칙을 정하고 확인하게 된다 (CheckStyle).

사람이 하는 일이라 잠재적인 결함이 발생할 수 있다 (FindBugs).

웹 페이지의 접근성을 진단하는 Open WAX (Open Web Accesiblilty eXtension)도 필요하다.

개발이 완료된 후에는 웹 사이트의 성능을 확인해야 실제 서비스를 제공할 때 문제를 최소화 할 수 있다 (JMeter). 

또, 악의적인 접근에 대한 보안 테스트도 필요하다 (OWASP TOP 10).


보안 도구인 Find Security Bugs는 OWASP TOP 10과 CWE를 커버하는 78개의 버그패턴을 탐지할 수 있다고 한다.

자바 소스 코드를 분석하여 불필요한 부분을 찾고 성능을 높이도록 도와주는 도구인 PMD도 있다.

이와 관련된 설치및 자세한 사용법은 한국인터넷진흥원 사이트에서 제공한다.

이외의 소프트웨어 개발보안가이드, 모바일 서비스 보안 가이드등도 제공하니 읽어보면 많은 도움이 될 것이다.


이러한 항목에 대해서 차후에 천천히 정리하려고 했는데

얼마 전 어떤 분의 지적이 있어 

개발 중간에 필요한 CheckStyle과 FindBugs를 먼저 정리했다.


이외에도 품질 검증과 관련된 다양한 도구는 공개 SW포털(OSS) 등에서 확인할 수 있다.


'Java > 게시판 기타: 품질 등' 카테고리의 다른 글

5. PMD와 예외처리(Exception)  (2) 2016.05.07
2. CheckStyle I - 설치  (0) 2016.04.23
3. CheckStyle II  (0) 2016.04.23
4. FindBugs  (0) 2016.04.23

본 내용은 (주)다모넷 김종호 차장이 인터넷 자료를 토대로 작성한 사내 문서에서 발췌한 것이다.




- Checkstyle는 Java의 소스코드(.java파일)의 기술형식 코딩규약에 준하고 있는지를 체크하는 오픈 소스의 정적 해석 툴입니다.

- 정적 해석(Static program analysis):  실제 실행 없이 컴퓨터 소프트웨어를 분석하는 것을 말하는 것으로, 자동화된 툴을 사용한 분석, 또는 코드 검토 등의 활동을 의미합니다.


ㄱ. 소프트웨어 설치

- 이클립스에서 Software 설치 창으로 이동한다.

- 이클립스 실행 > Help > Install New Software


ㄴ. 업데이트 사이트 주소추가

- 주소 명: http://eclipse-cs.sf.net/update/


ㄷ. 설치 플러그인 선택 - Checkstyle


ㄹ. 설치과정 확인

Eclipse가 재시작되면 설치가 완료된 것이다


Eclipse 메뉴에서 Window > Show View > Other를 선택한다.

위 그림과 같이 Checkstyle > Checkstyle violations를 선택하고 OK한다.

Eclipse 하단에 Checkstyle violations 탭이 추가된 것을 확인할 수 있다.





'Java > 게시판 기타: 품질 등' 카테고리의 다른 글

5. PMD와 예외처리(Exception)  (2) 2016.05.07
1. 프로그램 작성 외의 것들  (1) 2016.04.24
3. CheckStyle II  (0) 2016.04.23
4. FindBugs  (0) 2016.04.23

본 게시판 예제의 프로젝트를 선택하고 마우스 오른쪽 버튼을 눌러 Properties를 실행한다.

Checkstyle에서 "Checkstyle active for this project"를 체크하고 OK를 선택한다.


다음 그림과 같이 규칙에 어긋난 내용들이 나타나게 된다.

먼저 하단의 "Checkstyle violations" 뷰를 보면 프로젝트의 오류 리스트들이 종류별 정리되어 나타난다.

이 규칙은 위 그림에서 "Google Checks"을 선택했기 때문에 나오는 것으로 상세한 규칙은 구글 사이트번역 자료를 확인해 보길 바란다.


위 오류를 해결하는 방법은 2가지가 있다.

- 첫 번째 방법은 오류대로 수정하는 것이고,

- 두 번째 방법은 규칙을 수정하는 것이다.


규칙을 수정하는 이유는 현재 사용한 규칙이 구글의 방식이고

다소 타이트하게 구성되었기 때문에 각자에 맞게끔 수정해서 사용하는 것이 좋다.

개인적으로 예제로 사용된 구글 규칙은 Java 어플리케이션 규칙으로

웹일 경우는 다소 다르게 적용하는 게 좋을 것 같다.

Java 웹도 클래스 등을 사용하고 상속의 개념을 이용하지만 약하게 사용되고

특히 Spring은 클래스 개념이 조금 무시되기도 한다

(Spring은 다른 패키지 경로에 동일한 클래스가 있으면 오류 발생).


오류 수정을 위해
- 현재까지 진행된 보드(board1~4)를 수정하면 제공된 예제가 모두 정상이 되기에

  board4를 복사해서 board41로 만든다.

  SQL, JSP는 제외하고 Java 파일만 복사해서 수정해 본다.


- 규칙도 구글 원본을 수정하기 보다는 복사해서 별도의 규칙 파일을 만들어서 사용한다.


먼저, board4를 복사해서 board41로 만들고 클래스도 동일하게 바꾸어 준다.

다음으로 Eclipse의 windows > Preferences 메뉴를 실행한다.

Google Chceks를 선택하고 Copy 버튼을 눌러서 복사한다.


새로운 규칙 이름을 My Check로 입력하고 OK한다.


다음으로 프로젝트(board)를 선택하고 마우스 오른쪽 메뉴를 눌러서 컨텍스트 메뉴를 실행한다.

메뉴에서 Properties를 실행한후 왼쪽 트리에서 Checkstyle을 선택한다.

화면 중앙의 콤보 박스(Simple)에서 My Checks를 선택하고 OK 한다.

위 그림에서 오른쪽에 있는 Configure 버튼을 기억해야 한다.


Checkstyle violations 뷰에서 Marker count 컬럼명을 클릭하여 오류가 많은 순으로 정렬한다.


오류의 수는 진행 상태에 따라 개수가 바뀔 수 있다.


1. Line contains a tab character가 557회 발생했다.

탭(Tab) 키 사용을 금지하는 것으로 리스트에서 해당 항목을 더블 클릭한다.

831개의 오류가 난 파일들이 나오게 된다. 

확인을 위해 앞서 만든 board41Ctr.java를 찾아서 다시 더블 클릭하면 다음 그림과 같은 화면이 나온다 (아무 파일을 해도 상관없다).

소스 코드 앞에 돋보기에 마우스를 대면 오류를 확인할 수 있다.

Eclipse의 바꾸기(Repalce)를 이용하여 탭을 공백(Space) 4개로 바꾸어 주면 돋보기들이 사라진다.


board41Svc 도 같은 방식으로 수정해 준다.

남는 돋보기는 다른 오류이니 넘어가도 된다.

앞서 오류가 난 39라인의 돋보기를 보면 오류명이 바뀌어 있다.

Checkstyle violations 뷰에서 board41Ctr.java 파일이 사라지고 없다.

탭키는 자주 사용되는 것으로 탭키를 누르면 공백으로 바꾸어 주는 것이 좋다.

구글에서 "eclipse tab to space"로 검색해서 방법을 익혀두면 좋을 것이다.


2. ‘X’ have incorrect indentation level X, expected level should be X가 467회 발생했다.

더블 클릭해서 상세 정보를 보면 들여쓰기 오류인 것을 알수 있다.

2번째(Level 2)에 있어야 하는데 4번째(Level 4)에 있다는 의미로 게시판 예제는 4개씩 들여썻고,

구글은 2칸씩 들여쓰기하고 있다.

프로젝트(board)를 선택하고 마우스 오른쪽 메뉴를 눌러서 컨텍스트 메뉴를 실행한다.

Properties > Checkstyle를 선택하고 Configure 버튼을 클릭하여 다음 화면을 실행한다.

왼쪽 트리에서 Miscellaneous를 선택하고 Indentation의 체크를 해제한뒤 OK 한다.

‘X’ have incorrect indentation level X, expected level should be X뿐 아니라 

‘X’ child have incorrect indentation level X, expected level should be X (353회)도 사라지고 없다.

둘다 들여쓰기 규칙을 의미하는 것으로 위 설정으로 해당 규칙 적용이 되지 않아서 사라졌다.


3. Import statement for 'X' is in the wrong order. Should be in the 'X' group, expecting not assigned imports on this line. (65회)

이것은 Java의 import에 대한 규칙으로 구글 명명 규칙 번역 자료에 상세하게 나와 있다.

이 규칙도 다음 그림과 같이 Properties > Checkstyle | Configure > Import에서 "Custom Import Order"의 체그를 해제한다.


4. Missing a Javadoc comment가 29회 발생했다.

주석에 대한 것으로 현재는 //로 되어 있는 것을 그림과 같이 /* */로 작성해야 한다.

다만 지켜야 할 것이 시작시 /** 이고 문장은 반드시 점(.)으로 끝나야 한다.

이 주석들은 모아져 Javadoc(API 문서)으로 생성되는데 생성 방식은 구글링 해보길 바란다.

개인적으로 웹 프로그래밍에 Javadoc(API 문서)이 필요한 지와 사용여부에 의문이 있지만

주석은 꼭 필요한 것이라 함수의 파라메터에 대한 설명등 보다 많은 주석을 작성하는 것이 좋다.


5. Name 'X' must match pattern 'X'가 19회 발생했다.

상세 화면에서는 Type name 'board41Ctr' must match pattern '^[A-Z][a-zA-Z0-9]*$'.로 나온다.

이것은 정규식을 사용한 것으로 클래스명의 첫 글자를 대문자로 하라는 것이다.

board41Ctr, board41Src, boardVO를 Board41Ctr, Board41Src, BoardVO로 바꾸어 준다.

이것은 Java의 기본 명명 규칙으로 클래스명은 대문자로 시작하고

인스턴스는 소문자로 시작해서 둘을 구분짓는 것이다.

상 세 정보에서 이외에도Local variable name 'p' must match pattern '^[a-z][a-z0-9][a-zA-Z0-9]*$', Parameter name 'Filename' must match pattern '^[a-z][a-z0-9][a-zA-Z0-9]*$'. 가 있다.

해당 코드에서 돋보기를 보면 더 많은 오류가 동시에 발생하는데

이 오류는 변수명이 너무 짧고 파리메타의 변수명은 소문자로 시작해야 한다는 것이다.

 board41Ctr, board41Src, boardVO만 수정하고 넘어간다.

다른 파일 코드를 수정하면 오류가 발생하기 때문에 전체적으로 수정해야 한다.


6. Abbreviation in name 'X' must contain no more than '1' capital letters가 16회 발생했다.

이것은 변수 이름에 대문자가 1개 이상이 사용되었다는 것이다.

Properties > Checkstyle | Configure 에서 "Naming Conventions"에 있는 "Abbreviation As Word In Name"의 체크를 해제해서

명명 규칙 적용을 해제한다.


7. 'X' should be separated from previous statement.가 13회 발생했다.

상세 정보를 보면 'METHOD_DEF' should be separated from previous statement와

',' should be separated from previous statement. 가 있다.

'METHOD_DEF' should be separated from previous statement은 앞 문장과 한 라인을 띄우라는 의미이다.

다음 그림의 27라인에서 엔터키를 치고 저장하면 돋보기가 사라진다.

',' should be separated from previous statement.는 콤마(,) 다음은 다음 라인에서 시작하라는 의미이다.

돋보기에 확인하면 Each variable declaration must be in its own statement라는 문장도 같이 나온다.

Checkstyle violations뷰에 Each variable declaration must be in its own statement는 5회 발생했다.

이것은 다음 코드처럼 각 변수를 콤마가 아닌 개별 선언하라는 의미이다.

public class boardVO {

    private String brdno, brdtitle, brdwriter, brdmemo, brddate, brdhit, brddeleteflag
                 , filecnt;

-----------------------------

public class boardVO {
    private String brdno;
    private String brdtitle;
    private String brdwriter;
    private String brdmemo;
    private String brddate;
    private String brdhit;
    private String brddeleteflag;
    private String filecnt;

개인적으로 오류가 난 코드를 선호하여 명명 규칙을 제거할 수도 있는데

위 코드로 수정하였다.

개인적인 코드 작성 원칙이 가급적 많은 코드를 한 화면에서 본다는 것이다.

많은 코드가 한 눈에 보여야 앞뒤 흐름를 파악하여 실제 버그를 빠르고 쉽게 해결한 경험때문이다.

더우기 같은 코드인데 앞뒤 순서에 따라 성능 향상등의 이점을 얻기도 하기 때문이다.

하지만 수정된 코드가 원칙처럼 사용되고 변수 선언 뒤에 //로 해당 변수의 설명을 넣는 것이 좋은 코드 방법이다.

개인적으로는 위 VO의 변수명, 테이블 필드명등의 이름을 동일하게 부여한다.

직관적으로 이해하게 하여 이러한 설명을 빼고 작성한다.


8. 'X' is not preceded with whitespace가 13회 발생했다.

더블 클릭해서 상세화면을 실행한다.

다음 그림과 같이 board41Ctr.java를 찾아서 다시 더블 클릭하면 오류가 발생한 코드를 볼 수 있다.

상세 메세지와 코드로 != 앞뒤로 공백이 없는 것을 확인할 수 있다.

공백을 넣어 주면 오류가 사라진다.

10회 발생한 'X' is not followed by whitespace도 같은 오류라 위 오류 수정에 의해 해제 되기도 한다.

안 될 경우 상세화면에서 해당 코드를 찾아서 공백 처리하면 된다.


9. 'X' construct must use '{}'s가 8회 발생했다.

아래 코드와 같이 블럭으로 {}를 넣어 주면 된다.

            if (param.getBrdno() == null || "".equals(param.getBrdno()))
                 sqlSession.insert("insertBoard4", param);
            else sqlSession.update("updateBoard4", param);


            if (param.getBrdno() == null || "".equals(param.getBrdno())) {
                 sqlSession.insert("insertBoard4", param);
            } else {
                sqlSession.update("updateBoard4", param);
            }


10. Line is longer than X characters (found X) 가 3회 발견되었다.

한 행의 코드 수가 100자를 넘겼다는 의미이다.

다음 그림과 같이 Maximum Line Length를 해제한다.


11. First sentence of Javadoc is incomplete (period is missing) or not present이 3회 발생했다.

이것은 Javadoc에서 언급한 것으로 문장을 마침표(.)로 끝내라는 것이다.


2가지가 더 있지만 모두 앞서 언급한 것과 같이 처리하면 된다.

board41Ctr.java, board41Src.java, boardVO.java의 코드를 보면 돋보기가 모두 사라진 것을 확인 할 수 있다.

board41Src.java에 노랗게 경고 표시가 되어 있는 것이 있다.

이 것은 HashMap의 세부 타일을 표시하면 좋다는 것으로 다음과 같이 수정하면

코드 편집창에 나타난 경고들이 모두 사라진다.

            HashMap fparam = new HashMap();
            fparam.put("fileno", fileno);

            HashMap<String, String[]> fparam = new HashMap<String, String[]>();


이상으로 명명 규칙등과 관련된 Checkstyle 사용을 살펴 봤다.

이 외에도 더 많은 규칙이 있고 추가도 할 수 있다.

각자에 맞추어 선택하면 될 것이다.





'Java > 게시판 기타: 품질 등' 카테고리의 다른 글

5. PMD와 예외처리(Exception)  (2) 2016.05.07
1. 프로그램 작성 외의 것들  (1) 2016.04.24
2. CheckStyle I - 설치  (0) 2016.04.23
4. FindBugs  (0) 2016.04.23

+ Recent posts