톰캣 try increasing the timeout in the server editor -> 컴파일이 오래 진행되지 않으면 뜨는 오류. ----> 너무 많은 파일들이 한 서버에 동기화되어있을 때 생긴다
실제로 서버를 확인해보니 이제껏 실행했던 예제가 다 들어있었음.. 이러니까 느리지 다 없애니까 5초 내에 실행 쌉가능! 앞으로 같은 실수는 하지 않겠음

** 트랜잭션 기능 추가 예제 <springsboard>

체크할 부분
root-context.xml : 트랜잭션 매니저 설정 (트랜잭션 처리 위한 객체 생성)
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
   <property name="dataSource" ref="dataSource"/>
</bean>

- dao class @Transactional - 정상처리시 커밋, 문제 발생시 롤백 처리
@Transactional
public void insertBoard(BoardBean b) throws Exception {
// getSession();
   sqlSession.insert("Test.board_insert", b);
// sqlsession.commit();
}


** 검색, 페이지 블록 처리 + insert 방식 변경 <board1>

PK num, 답글 ref에 시퀀스를 사용하지 않는 경우 -> max()로 최대값을 구해 +1시켜 집어넣는 방식...

+) root-context.xml
<context:property-placeholder location="classpath:jdbc.properties" />
----properties 파일의 property 변수들 받아와서 아래에 적용하는 방식 사용
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
destroy-method="close">
  <property name="driverClass" value="${jdbc.driverClassName}" />
  <property name="jdbcUrl" value="${jdbc.url}" />
  <property name="user" value="${jdbc.username}" />
  <property name="password" value="${jdbc.password}" />
  <property name="maxPoolSize" value="${jdbc.maxPoolSize}" />
</bean>

* board.java (DTO)
기존 글작성/출력에 관련된 필드 외에 페이지(startRow, endRow), 검색(search, keyword) 필드를 추가해 사용

* controller.java
@RequestMapping("list.do") // 전체 목록, 검색 목록
public String list(String pageNum, Board board, Model model) {
   final int rowPerPage = 10; // 화면에 출력할 데이터 갯수
   if (pageNum == null || pageNum.equals("")) {
      pageNum = "1";
   }
   int currentPage = Integer.parseInt(pageNum); // 현재 페이지 번호

   // int total = bs.getTotal();
   int total = bs.getTotal(board);
// 검색 데이터 갯수 - count(*) : 카운트할 때 검색 필드에 값이 없다면 전체 갯수를 출력, 검색값이 있다면 where 조건 추가해 출력
// 자세한 설명은 2번으로~

   int startRow = (currentPage - 1) * rowPerPage + 1;
   int endRow = startRow + rowPerPage - 1;

   PagingPgm pp = new PagingPgm(total, rowPerPage, currentPage);   //페이지 블록 ---- 1번으로!
   board.setStartRow(startRow);
   board.setEndRow(endRow);
   // List<Board> list = bs.list(startRow, endRow);
   int no = total - startRow + 1;   // 화면 출력 번호
   List<Board> list = bs.list(board);               //목록(전체or검색) 출력 ---- 2번으로!

   model.addAttribute("list", list);
   model.addAttribute("no", no);
   model.addAttribute("pp", pp);
   // 검색
   model.addAttribute("search", board.getSearch());
   model.addAttribute("keyword", board.getKeyword());

   return "list";
}


1. 페이지 블록 처리 - PagingPgm.java
전용 service class를 따로 생성해 그 안에서 처리
필드
private int total;    // 데이터 갯수
private int rowPerPage;    // 화면에 출력할 데이터 갯수
private int pagePerBlk = 10;    // 블럭당 페이지 갯수 (1개의 블럭당 10개의 페이지)
private int currentPage;    // 현재 페이지 번호
private int startPage;    // 각 블럭의 시작 페이지
private int endPage;   // 각 블럭의 끝 페이지
private int totalPage;    // 총 페이지 수

public PagingPgm(int total, int rowPerPage, int currentPage) {
   this.total = total;
   this.rowPerPage = rowPerPage;
   this.currentPage = currentPage;
//생성자 매개변수로 값을 받아 아래에서 다른 필드값도 초기화함

   totalPage = (int) Math.ceil((double) total / rowPerPage);
   startPage = currentPage - (currentPage - 1) % pagePerBlk;  // 1,  11, 21...
   endPage = startPage + pagePerBlk - 1;   // 10, 20, 30...
   if (endPage > totalPage)
   endPage = totalPage;
}


2. 목록(전체or검색) 출력 - board.xml
: mapper class에서 <where> <if>를 이용해 유연한 select가 가능하도록 함 (검색 데이터 갯수 출력에도 사용)
<select id="list" parameterType="board" resultMap="boardResult">
   select * from (select a.*,rowNum rn from (
      select * from board
   <where>   //조건에 부합할 때만 where 조건문이 추가됨, 없을 시 조건 없이 전체 select
      <if test="keyword != null and search!='subcon'">  //board DTO에서 키워드 값과 항목이 있는 경우 (단, 제목+내용 제외)
         ${search} like '%'||#{keyword}||'%'
      </if>
      <if test="keyword != null and search=='subcon'">  //board DTO에 키워드 값이 있고 항목이 '제목+내용'인 경우
         subject like '%'||#{keyword}||'%' or     <----- % 사이에 || 들어가는 거 확인!!!!

         content like '%'||#{keyword}||'%'
      </if>
   </where>
      order by ref desc,re_step) a )
      where rn between #{startRow} and #{endRow}   //board DTO에 추가되어있는 페이지 필드
</select>


* list.jsp

1. 검색폼
<form action="list.do">
   <input type="hidden" name="pageNum" value="1"> 
   <select name="search">   //검색 페이지 출력 시 기존 검색항목/키워드가 그대로 남아있도록 if문으로 처리
      <option value="subject" <c:if test="${search=='subject'}">selected="selected" </c:if>>제목</option>
      <option value="content" <c:if test="${search=='content'}">selected="selected" </c:if>>내용</option>
      <option value="writer" <c:if test="${search=='writer'}">selected="selected" </c:if>>작성자</option>
      <option value="subcon" <c:if test="${search=='subcon'}">selected="selected" </c:if>>제목+내용</option>
   </select> 
   <input type="text" name="keyword" <c:if test="${!empty keyword}">value="${keyword }" </c:if> > 
   <input type="submit" value="확인">
</form>

2. 페이지 블록
   //키워드가 없으면 전체 목록 페이지 출력
<c:if test="${empty keyword}">
   <c:forEach var="i" begin="${pp.startPage}" end="${pp.endPage}">
      <li <c:if test="${pp.currentPage==i}">class="active"</c:if>>
          <a href="list.do?pageNum=${i}">${i}</a></li>
   </c:forEach>

   //키워드가 있으면 검색 목록 페이지 출력
<c:if test="${not empty keyword}">
   <c:forEach var="i" begin="${pp.startPage}" end="${pp.endPage}">
      <li <c:if test="${pp.currentPage==i}">class="active"</c:if>>
          <a href="list.do?pageNum=${i}&search=${search}&keyword=${keyword}">${i}</a></li>
   </c:forEach>



*  insert 방식 변경 : 원글/답글 입력폼을 하나로 사용해서 시퀀스를 사용하지 않는 방식
Controller.java

//원글, 답글 작성폼으로
@RequestMapping("insertForm.do")
public String insertForm(String nm, String pageNum, Model model) {
   int num = 0, ref = 0, re_level = 0, re_step = 0; // 원글 기본 셋팅
   if (nm != null) {      //부모글에서 답변을 눌러 들어오는 경우 부모글의 num=nm 정보가 있음
      num = Integer.parseInt(nm);    //그 값을 num로 지정
      Board board = bs.select(num); // 부모글 정보 구해옴 - 아래 insert.do에서 사용해야 함
      ref = board.getRef();
      re_level = board.getRe_level();
      re_step = board.getRe_step();
   }
   model.addAttribute("num", num);   //어차피 바꿀 건데 왜 필요한가 -> insert.do에서 원글인지 답글인지 판단
   model.addAttribute("ref", ref);
   model.addAttribute("re_level", re_level);
   model.addAttribute("re_step", re_step);
   model.addAttribute("pageNum", pageNum);
   return "insertForm";
}

//글 작성
@RequestMapping("insert.do")
public String insert(Board board, Model model, HttpServletRequest request) {
   int num = board.getNum();
   int number = bs.getMaxNum();   //max()함수를 이용해 컬럼 num의 가장 큰 값+1을 가져옴
   if (num != 0) {   // 답글
      bs.updateRe(board);  //먼저 달린 답글의 순서를 하나씩 뒤로 미는 sql update
      board.setRe_level(board.getRe_level() + 1);  //controller에서 1 증가시켜 셋팅
      board.setRe_step(board.getRe_step() + 1);
   } else { // 원글일 때 ref값만 num과 일치시켜줌
      board.setRef(number);
   }
   board.setNum(number);   //max()+1 값을 num으로 지정
   String ip = request.getRemoteAddr();
   board.setIp(ip);
   int result = bs.insert(board);
   model.addAttribute("result", result);
   return "insert";
}

* board.xml (mapper)
<select id="getMaxNum" resultType="int">
   select nvl(max(num),0) + 1 from board     //시퀀스 대신. 최대값+1의 값을 구해서 넘겨줌
</select>

※ 왜 nvl()을 사용하는가!?????
nvl(max(num),0) ---> max(num)값이 존재하지 않는다면, 그 값을 0으로 치환해준다
즉, 테이블에 아무 값도 존재하지 않는 상태라면 0으로 치환한 뒤 +1을 해서, num=1로 첫 글을 등록할 수 있게 해주는 것!

** 상세페이지 하단에 목록 출력
$(function() {
   $('#list').load('list.do?pageNum=${pageNum} table');
});
--- 페이지 열릴 때 list.do를 로드하고 id=list인 블록에 삽입 (이 때, 원하는 부분만 로드할 수 있음)
끝에 table을 붙여놓으면 ---> list.do에서 table 부분만 가져와서 블록에 삽입하는 것임

<div id="list"></div> <--이 공간에 추가됨

이건 레이아웃 나눠서 고정메뉴를 넣어야 할 때 유용하게 사용할 수 있을 것 같다


* 비밀번호 비교 방식 변경
- Controller.java @RequestMapping("deleteForm.do")
: deleteForm으로 넘어가는 요청이 들어올 때, num에 대한 검색을 진행하고 dto로 값을 받아 view(deleteForm)로 공유함

 

-deleteForm.jsp
<input type="hidden" name="passwd" value="${board.passwd}"> 
<input type="password" name="passwd2" required="required">

: db에서 받아온 비밀번호와 입력받은 비밀번호를 한 form에 input으로 넣어둔 뒤 유효성 검사로 두 값을 서로 비교
function chk() {

  if (frm.passwd.value != frm.passwd2.value)


-Controller.java  @RequestMapping("delete.do")
: 비밀번호 비교하는 과정 없이 바로 요청을 수행할 수 있음!


---> 폼 내부에서 비교하는 방식. 조금 더 효율적으로 사용할 수 있음

+ Recent posts