톰캣 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")
: 비밀번호 비교하는 과정 없이 바로 요청을 수행할 수 있음!
---> 폼 내부에서 비교하는 방식. 조금 더 효율적으로 사용할 수 있음
'수업 > 정리' 카테고리의 다른 글
220509 Springboot1 - 프로젝트 생성, 실행 (0) | 2022.05.09 |
---|---|
220506 Spring-11 댓글★★★ (0) | 2022.05.07 |
220503 Spring-9 실습: 회원관리, 게시판관리 (0) | 2022.05.03 |
220502 Spring-8 메일 인증, 파일 업로드 (0) | 2022.05.02 |
220429 Spring-7 MVC구현2 목록, 상세, 수정, 삭제 (0) | 2022.04.29 |