• Home
  • About
    • Young's Github Pages photo

      一日不作一日不食

    • About
    • Github
  • Posts
    • All Posts
    • All Tags
  • Projects

Java EE 정리 17

21 Mar 2019

Reading time ~8 minutes

Java EE 정리 17 - 일정관리 만들기(2)


일정관리 만들기(2)

  • 진행중인 프로젝트 패키지
  • Java Calendar는 없는 날짜가 입력되면 다음달 1일이 된다.
    • 3월 31일로 날짜를 변경한 경우
    • 4월로 이동하면 31이 존재하지 않기 때문에 5월달로 이동해버린다.
...
      int nowYear = 0;
      int nowMonth = 0;
      int nowDay = cal.get(Calendar.DAY_OF_MONTH);
      String paramMon = request.getParameter("param_month");
      // 요청했을 때 해당 달에 없는 일이 존재한다면
      // 다음 달 1일로 설정되기 때문에 모든 달에 존재하는 날짜로 일을  설정
      cal.set(Calendar.DAY_OF_MONTH, 1);
...

01

  • 글작성 jsp 끼워넣기
<!-- diary.jsp -->
...
      #diaryContent {
            position: relative;
      }
      #diaryJob {
            position: absolute; top: 10px; left: 160px;
      }
      #writeFrm {
            background-color: #FFFFFF;
            border:1px solid #333;
            box-shadow: 5px 5px 5px #333;
            padding: 10px;
      }
...
</table>
...
<div id="diaryJob">
    <c:import url="write_form.jsp"></c:import>
</div>
<!-- write_form.jsp -->
<%@page import="java.util.Date"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
    
<div id="writeFrm">
<form action="write_process" method="post">
<table id="writeTab">
      <tr>
            <th colspan="2"><span>이벤트 작성</span></th>
      </tr>
      <tr>
            <td style="width:80px;">제목</td>
            <td style="width:400px">
                  <input type="text" name="subject" class="inputBox"
                        style="width:350px;"/>
            </td>
      </tr>
      <tr>
            <td style="width:80px;">내용</td>
            <td style="width:400px">
                  <textarea name="content" id="summernote"></textarea>
            </td>
      </tr>
      <tr>
            <td style="width:80px;">이벤트 일</td>
            <td style="width:400px">
                  <input type="text" name="e_year" class="inputBox"
                        style="width:40px;" readonly="readonly"/>-
                  <input type="text" name="e_month" class="inputBox"
                        style="width:20px;" readonly="readonly"/>-
                  <input type="text" name="e_day" class="inputBox"
                        style="width:20px;" readonly="readonly"/>
            </td>
      </tr>
      <tr>
            <td style="width:80px;">작성자</td>
            <td style="width:400px">
                  <input type="text" name="writer" class="inputBox"
                        style="width:120px;"/>
            </td>
      </tr>
      <tr>
            <td style="width:80px;">비밀번호</td>
            <td style="width:400px">
                  <input type="password" name="writer" class="inputBox"
                        style="width:200px;"/>
            </td>
      </tr>
      <tr>
            <td style="width:80px;">작성일</td>
            <td style="width:400px">
                  <fmt:formatDate value="<%= new Date() %>"  pattern="yyyy-MM-dd a EEEE HH:mm"/>
            </td>
      </tr>
      <tr>
            <td style="width:80px;">작성IP</td>
            <td style="width:400px">
                  <%= request.getRemoteAddr() %>
            </td>
      </tr>
      <tr>
            <td colspan="2" align="center">
                  <input type="button" value="이벤트 작성" class="btn"  id="btnWrite"/>
                  <input type="button" value="닫기" class="btn"  id="btnWriteClose"/>
            </td>
      </tr>
</table>
</form>
</div>

02

  • summernote 적용을 위해 diary.jsp에 스크립트 추가
<!-- diary.jsp -->
...
<!-- summernote 관련 library 시작 -->
<link href="../common/summernote/bootstrap.css" rel="stylesheet">
<script  src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
<script src="../common/summernote/bootstrap.js"></script>
<link href="../common/summernote/summernote-lite.css" rel="stylesheet">
<script src="../common/summernote/summernote-lite.js"></script>
<!-- include summernote-ko-KR -->
<script src="../common/summernote/lang/summernote-ko-KR.js"></script>
<script type="text/javascript">
      $(document).ready(function() {
        $('#summernote').summernote({
      placeholder: '이벤트를 작성해주세요',
      tabsize: 2,
      height: 100,
      width: 380,
      lang: 'ko-KR'
    });
      });
</script>
<!-- summernote 관련 library 끝 -->
</head>
...

03

  • 이제 pageFlag Parameter에 따라 jsp를 include 처리
<!-- diary.jsp -->
...
<div id="diaryJob">
      <c:if test="${ not empty param.pageFlag }">
            <c:import url="${ param.pageFlag }.jsp"></c:import>
      </c:if>
</div>
...
<!-- diary.jsp -->
...
<!-- 날짜를 선택하면 글쓰기 jsp가 뜨도록 param 설정 -->
<!-- param_year, param_month, param_date를 같이 전달, 다른 달에서 글쓰기 해도 화면 유지 -->
<td class="diaryTd ${ todayClass }">
      <a href="diary.jsp?param_year=${ nowYear }&param_month=${ nowMonth }&param_date=<%= tempDay %>&pageFlag=write_form">
      <span class="${ dayClass }">
            <%= tempDay %>
      </span>
      </a>
</td>
...
<!-- write_form.jsp -->
...
<td style="width:80px;">이벤트 일</td>
<td style="width:400px">
      <input type="text" name="e_year" class="inputBox"
            style="width:40px;" readonly="readonly" value="${  param.param_year }"/>-
      <input type="text" name="e_month" class="inputBox"
            style="width:20px;" readonly="readonly" value="${  param.param_month }"/>-
      <input type="text" name="e_day" class="inputBox"
            style="width:20px;" readonly="readonly" value="${  param.param_day }"/>
</td>
...

04

  • CSS 수정
    • th들 가운데정렬
    • 이벤트작성 가운데 크게
    • X버튼 우측상단에 붙이기
<th colspan="2" style="text-align: center;">
      <span style="font-size: 20px;">이벤트 작성</span>
      <span style="float:right; padding:5px;">
            <img src="images/btn_close.png"/>
      </span>
</th>

05

  • 다른 달에서 글쓰기 창 띄웠다가 닫는 순간 3월달로 돌아온는 문제 해결
// diary.jsp
$(document).ready(function() {
      $("#btnCloseFrm").click(function() {
            // location.href="diary.jsp?param_year=${ param.param_year  }&param_month=${ param.param_month }"; 또는

            // 히든을 갖고 submit
            $("[name='param_year']").val(${ param.param_year });
            $("[name='param_month']").val(${ param.param_month });
            $("[name='diaryFrm']").submit();
      });
});
  • 기존에 있던 moveMonth를 사용해도 종료처리가 가능
function moveMonth(month,year) {
      $("[name='param_year']").val(year);
      $("[name='param_month']").val(month);
      $("[name='diaryFrm']").submit();
}

$(document).ready(function() {
      $("#btnCloseFrm").click(function() {
            // 엑스버튼 눌렀을 때 글쓰는 창 닫기
            moveMonth("${ param.param_month }","${ param.param_year }");
      });
      $("#btnWriteClose").click(function() {
            // 닫기 버튼 눌렀을 때 글쓰는 창 닫기
            moveMonth("${ param.param_month }", "${ param.param_year  }");
      });
})
  • 글작성 처리
    • 제목, 내용, 작성자, 비밀번호에 id부여 후 검증 수행 후 요청처리
// 글 작성 처리, diary.jsp
$("#btnWrite").click(function() {
      if($("#subject").val() == "") {
            alert("이벤트 제목은 필수입력 항목입니다.")
            $("#subject").focus();
            return;
      }
      
      if($("#summernote").val() == "") {
            alert("이벤트 내용은 필수입력 항목입니다.");
            return;
      }
      
      if($("#writer").val() == "") {
            alert("작성자는 필수입력 항목입니다.");
            $("#writer").focus();
            return;
      }
      if($("#pass").val() == "") {
            alert("비밀번호는 필수입력 항목입니다.");
            $("#pass").focus();
            return;
      }
      
      $("[name='writeFrm']").submit(); // 검증 후 submit
});
  • 날짜 이동한 후 submit했을 때도 날짜 상태가 유지처리
<!--write_form.jsp -->
...
<div id="writeFrm">
<form action="diary.jsp" method="post" name="writeFrm">
    <!-- post방식이므로 쿼리스트링에 pageFlag 파라미터를 전송 못함!! -->
    <!-- 히든으로 해결 -->
    <input type="hidden" name="pageFlag" value="write_process"/>
    <input type="hidden" name="param_year" value="${ param.param_year }"/>
    <input type="hidden" name="param_month" value="${ param.param_month }"/>
...
  • useBean, setProperty를 이용 insert할 값들을 VO에 넣는다.
<!-- write_process.jsp -->
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%
      // request.setCharacterEncoding("UTF-8"); // POST 한글처리
      // 근데 여기서 하면 body태그 밑에서 include, 한글화가 안된다.
      // 따라서 diary.jsp 맨 위에서 적용 시켜줘야 함.
%>
<jsp:useBean id="dvo" class="kr.co.sist.vo.DiaryVO" scope="page" />
<jsp:setProperty name="dvo" property="*"/>
<jsp:setProperty name="dvo" property="ip" value="<%=  request.getRemoteAddr() %>"/>

<%
      dvo.setPass(ShaUtil.shaEncoding(dvo.getPass())); // 암호화
%>
  • DBCP 사용 설정
    • Severs/…/server.xml에서 설정
...
<Context docBase="jsp_prj" path="/jsp_prj" reloadable="true"  source="org.eclipse.jst.jee.server:jsp_prj"/>
      <Resource auth="Container"  driverClassName="oracle.jdbc.OracleDriver"
            maxIdle="10" maxTotal="20" maxWaitMillis="-1"
            name="jdbc/jsp_dbcp" password="tiger"  type="javax.sql.DataSource"
            url="jdbc:oracle:thin:@127.0.0.1:1521:orcl"  username="scott"/>
</Context>
</Host>
...
  • DiaryDAO에서 DBCP를 이용 Connection을 얻는 getConn과 새로운 글을 넣는 insertEvent메소드를 만듦
// DiaryDAO
...
private Connection getConn() throws SQLException {
      Connection con = null;
      
      try {
            // 1. JNDI 사용 객체 생성
            Context ctx = new InitialContext();
            
            // 2. DBCP에 저장된 DataSource 얻기
            DataSource ds =  (DataSource)ctx.lookup("java:comp/env/jdbc/jsp_dbcp");
            
            // 3. Connection 얻기
            con = ds.getConnection();
      
      } catch (NamingException e) {
            e.printStackTrace();
      }
      
      return con;
}
...
public void insertEvent(DiaryVO dvo) throws SQLException{
      
      Connection con = null;
      PreparedStatement pstmt = null;
      
      try {
            con = getConn();
            
            StringBuilder insertEvent = new StringBuilder();
            
            insertEvent
            .append(" INSERT INTO  diary(NUM,WRITER,SUBJECT,CONTENT,E_YEAR,E_MONTH,E_DATE,PASS,IP) ")
            .append(" VALUES (seq_diary.nextval,?,?,?,?,?,?,?,?) ");
            
            pstmt = con.prepareStatement(insertEvent.toString());
            pstmt.setString(1, dvo.getWriter());
            pstmt.setString(2, dvo.getSubject());
            pstmt.setString(3, dvo.getContent());
            pstmt.setString(4, dvo.getE_year());
            pstmt.setString(5, dvo.getE_month());
            pstmt.setString(6, dvo.getE_date());
            pstmt.setString(7, dvo.getPass());
            pstmt.setString(8, dvo.getIp());
            
            pstmt.executeUpdate();
            
      } finally {
            if (pstmt != null) { pstmt.close(); }
            if (con != null) { con.close(); }
      }
}
  • write_process.jsp에서 새글 등록처리
<script type="text/javascript">
// scriptlet 사이에 쓰이는 내용은 JS코드가 됨
<%
      dvo.setPass(ShaUtil.shaEncoding(dvo.getPass())); // 암호화
      
      DiaryDAO d_dao = DiaryDAO.getInstance();
      
      try {
            d_dao.insertEvent(dvo);
            %>
            alert("이벤트가 정상적으로 등록 되었습니다.");
            <%
      } catch (SQLException se) {
            // _jspService에서 컴파일 예외를 처리해주지만 우리가  직접하는게 더 좋다
            se.printStackTrace();
            %>
            alert("이벤트가 정상적으로 등록되지 않았습니다.");
            <%
      }
%>
</script>
  • JavaScript에서 alert은 코드 브레이커(정지) 기능을 한다.
    • onload 처리를 해서 HTML을 모두 그린 뒤 JavaScript가 동작하도록 변경
<script type="text/javascript">
window.onload = function() { 
//또는 jQuery로 $(window).load(function(){ ... });
<%
      dvo.setPass(ShaUtil.shaEncoding(dvo.getPass())); // 암호화
      
      DiaryDAO d_dao = DiaryDAO.getInstance();
      
      try {
            d_dao.insertEvent(dvo);
            %>
            alert("이벤트가 정상적으로 등록 되었습니다.");
            <%
      } catch (SQLException se) {
            // _jspService에서 컴파일 예외를 처리해주지만 우리가  직접하는게 더 좋다
            se.printStackTrace();
            %>
            alert("이벤트가 정상적으로 등록되지 않았습니다.");
            <%
      }
%>
}
</script>

06

  • 글 등록 후 새로고침으로 발생하는 중복등록 막기
    • session을 사용해서 막는다.

07

  • session으로 새로고침 재등록을 막는다.
    • writeFlag란 session 속성을 만들고 boolean형 값을 저장
    • writeFlag속성값이 null이 아니고 false라면 글쓰기 수행
      • null이거나 true(이미 쓴 상태)라면 글쓰기를 수행하지 않는다.
<!-- write_form.jsp -->
<%    // 글 쓰기 전, false로 writeFlag 세션속성 값 설정
      session.setAttribute("writeFlag",false);
%>    
<!-- write_process.jsp -->
<%
      // 새로고침(F5)로 중복 실행 방지 세션
      Boolean flag = (Boolean)session.getAttribute("writeFlag");
      
      if (flag != null && !flag) {
            dvo.setPass(ShaUtil.shaEncoding(dvo.getPass())); // 암호화
            
            DiaryDAO d_dao = DiaryDAO.getInstance();
            
            try {
                  d_dao.insertEvent(dvo);
                  %>
                  alert("이벤트가 정상적으로 등록 되었습니다.");
                  <%
                  session.setAttribute("writeFlag", true); // 읽음처리
            } catch (SQLException se) {
                  // _jspService에서 컴파일 예외를 처리해주지만 우리가  직접하는게 더 좋다
                  se.printStackTrace();
                  %>
                  alert("이벤트가 정상적으로 등록되지 않았습니다.");
                  <%
            }
      }
%>
  • 달력에 이벤트가 존재하는지 표시 * DiaryDAO에서 selectMonthEvent 메소드를 만듦
// DiaryDAO
public MonthVO[][] selectMonthEvent(String year, String month) throws  SQLException {
      MonthVO[][] mvo = new MonthVO[31][];
      
      Connection con = null;
      PreparedStatement pstmt = null;
      ResultSet rs = null;
      
      try {
            con = getConn();
            
            StringBuilder selectMonthData = new StringBuilder();
            
            selectMonthData
            .append(" SELECT num, subject ")
            .append(" FROM diary ")
            .append(" WHERE e_year=? and e_month=? and e_date=? ");
            
            MonthVO temp = null;
            // DB에 두번 접속하지 않기 위해 정보를 담을 List
            List<MonthVO> list = new ArrayList<MonthVO>();
            
            pstmt = con.prepareStatement(selectMonthData.toString());
            pstmt.setString(1, year);
            pstmt.setString(2, month);
            for(int i=1; i<32; i++) { // 해당 년월의 1일부터 31일까지 쿼리 수행
                  pstmt.setString(3, String.valueOf(i));
                  rs = pstmt.executeQuery();
                  
                  int idx = 0;
                  while(rs.next()) { // 실행 결과가 존재한다면
                        // 해당 일자의 글이 존재하므로 글의 값을  저장한다.
                        list.add(new MonthVO(rs.getInt("num"),  
                              rs.getString("subject")));
                  }
                  rs.close();
                  if (list.size() != 0) {
                        // 글을 저장할 배열 생성
                        MonthVO[] mvoArr = new MonthVO[list.size()];
                        // 리스트에 존재하는 값을 일차원 배열에 복사
                        list.toArray(mvoArr);
                        // 일차원 배열의 값을 가변배열의 i행에 추가
                        mvo[i-1] = mvoArr;
                  }
                  list.clear(); // 리스트 초기화
            }
      } finally {
            if (rs != null) { rs.close(); }
            if (pstmt != null) { pstmt.close(); }
            if (con != null) { con.close(); }
      }
      
      return mvo;
}
<!-- diary.jsp -->
...
<%
      String dayClass="";
      String todayClass=""; // 요일별 색
      
      // 요청되는 년,월의 모든 이벤트를 조회
      DiaryDAO d_dao = DiaryDAO.getInstance();
      
    
      try {
            // 해당 년월에 이벤트 정보를 담는 가변배열
            MonthVO[][] monthEvtData = d_dao.selectMonthEvent(
                        String.valueOf(nowYear),  String.valueOf(nowMonth));
            MonthVO[] dayEvt = null; // 해당 일에 글이 존재한다면 저장할  배열
            
      ...
      <td class="diaryTd ${ todayClass }">
            <%
                  dayEvt = monthEvtData[tempDay-1];
            %>
            <div>
            <a href="diary.jsp?param_year=${ nowYear }&param_month=${ nowMonth }&param_day=<%= tempDay  %>&pageFlag=write_form">
                  <span class="${ dayClass }">
                        <%= tempDay %>
                  </span>
            </a>
            </div>
            <div>
            <%
                  if (dayEvt != null) {
                        for(int i=0; i<dayEvt.length; i++) {
                        %>
                              <img src="images/evtflag.png" 
                                    title="<%=dayEvt[i].getSubject()%>"/>
                        <%
                        }
                  }
            %>
            </div>
      </td>
      ...  
      } catch (SQLException se) { // SQLException 예외처리
            se.printStackTrace();
%>
<tr>
      <td colspan="7" style="text-align:center; height:400px;">
            <img src="images/construction.jpg" title="죄송합니다."/>
      </td>
</tr>
<%
      }
%>

08

  • 이벤트를 등록하고 페이지를 갱신
<!-- write_process.jsp -->
...
alert("이벤트가 정상적으로 등록 되었습니다.");
location.href="diary.jsp?param_year=${ param.param_year }&param_month=${ param.param_month }";
...
  • 이벤트 제목이 20자 이상이면 …으로 대체
String tempSubject = "";
...
<%
      if (dayEvt != null) {
            for(int i=0; i<dayEvt.length; i++) {
                  tempSubject = dayEvt[i].getSubject();
                  if (tempSubject.length() > 21) {
                        tempSubject = tempSubject.substring(0,20)+"...";
                  }
            %>
                  <img src="images/evtflag.png"  title="<%=tempSubject%>"/>
            <%
            }
      }
%>

09

  • 이벤트를 5개 이상 등록 막기
<!-- diary.jsp -->
<script type="text/javascript">
      ...
      function writeEvt(year, month, date, pageFlag, evtCnt) {
            
            if(evtCnt > 4) {
                  alert("하루에 작성 가능한 이벤트의 수는 5개 입니다.");
                  return;
            }

            $("[name='param_year']").val(year);
            $("[name='param_month']").val(month);
            $("[name='param_date']").val(date);
            $("[name='pageFlag']").val(pageFlag);
            $("[name='diaryFrm']").submit();
      }
</script>
...
<form action="diary.jsp" name="diaryFrm" method="post" >
      <input type="hidden" name="param_month"/>
      <input type="hidden" name="param_year"/>
      <input type="hidden" name="param_date"/>
      <input type="hidden" name="pageFlag"/>
</form>
...
int evtCnt = 0; // 이벤트 건수를 제한하기 위한 변수
...
<div><a href="#void" onclick="writeEvt(${ nowYear },${ nowMonth },<%=  tempDay %>,'write_form',<%=evtCnt%>)"><span class="${ dayClass }">
      <%= tempDay %></span>
</a>

10



Java EEJSP