<error-page>
<error-code>400</error-code>
<location>/error/error400</location>
</error-page>
<error-page>
<error-code>404</error-code>
<location>/error/error404</location>
</error-page>
<error-page>
<error-code>500</error-code>
<location>/error/error500</location>
</error-page>
<!-- HTTP 상태 코드를 사용하여 오류 페이지 설정 끝 -->
ErrorController.java
package kr.or.ddit.utils;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class ErrorController {
//요청 URI : /error/error400
@GetMapping("/error/error400")
public String error400() {
//forwarding : jps
return "error/error400";
}
//요청 URI : /error/error404
@GetMapping("/error/error404")
public String error404() {
//forwarding : jps
return "error/error404";
}
//요청 URI : /error/error500
@GetMapping("/error/error500")
public String error500() {
//forwarding : jps
return "error/error500";
}
}
Aspect(애스팩트) : AOP(Aspect Oriented Programming)의 단위가 되는 횡단 관심사 - 횡단 관심사(Cross-Cutting Concern) : 핵심(core) 비즈니스 로직(삼겹살구어먹기, 빵또아의 아이스크림)과 다소 거리가 있지만, 여러 모듈에서 공통적이고 반복적인 처리를 요구하는 내용(불판닦기, 불판교체, 빵또아의 빵) - 횡단 관심사 분리(Separation Of Cross-Cutting Concern) : 횡단 관심사에 해당하는 부분(불판닦기, 불판교체, 빵또아의 빵)을 분리해서 한 곳으로 모으는 것을 의미 - Component : 골뱅이Aspect와 짝궁. component-scan시 "여기 봐주세요"라는 의미 - JoinPoint : 어드바이스가 적용될 수 있는 위치 - Advice(로그 출력 한다) : 어떤 부가기능(불판닦기)을 언제(삼겹살을 굽기 전(Before)에) 사용할지 정의 * 언제? - Before : 조인포인트(createPost()) 전에 실행. (삼겹살을 굽기 직전에) - After : 조인 포인트(createPost())에서 처리가 완료된 후 실행(삽겹살을 굽고 먹은 직후 실행) - Around : 조인 포인트(createPost()) 전후에 실행(삽겹살을 굽기 직전과 먹은 직후 실행) - After Returning : 조인 포인트(createPost())가 정상적으로 종료 후 실행 - After Throwing : 조인 포인트(createPost())에서 예외 발생 시 실행. 예외가 발생안되면 실행 안함
pom.xml
dependencies 안에 추가
<!-- AOP(Aspect Oriented Programming : 관점 지향 프로그래밍) 시작
1) aspectjrt => 이미 있으므로 생략
2) aspectjweaver => 없으므로 의존 관계를 정의
-->
<!-- https://mvnrepository.com/artifact/aspectj/aspectjweaver
1.5.4 -->
<!-- AspectJ RunTime -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${org.aspectj-version}</version>
</dependency>
<!-- AspectJ Weaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>${org.aspectj-version}</version>
</dependency>
<!-- AspectJ Tools -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjtools</artifactId>
<version>${org.aspectj-version}</version>
</dependency>
<!-- AOP(Aspect Oriented Programming : 관점 지향 프로그래밍) 끝 -->
package kr.or.ddit.aop;
import java.util.Arrays;
import org.aopalliance.intercept.Joinpoint;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Component
@Aspect
public class ServiceLoggerAdvice {
@Before("execution(* kr.or.ddit.*..*(..))")
public void startLog(JoinPoint jp) {
log.info("startLog");
//.getSignature() : 어떤 클래스의 어떤 메서드가 실행되었는지 보여줌. 파라미터 타입은 무엇인지 보여줌
// kr.or.ddit.service.BoardService.register(BoardVO)
log.info("startLog : " + jp.getSignature());
//.getArgs() : 전달 된 파라미터 정보를 보여줌
// [BoardVO [boardNo=127,title=개똥이]]
log.info("startLog : " + Arrays.toString(jp.getArgs()));
}
//어드바이스
//조인 포인트(메소드)가 정상적으로 종료한 후에 실행됨. 예외 발생 시 실행 안됨
@AfterReturning("execution(* kr.or.ddit.*..*(..))")
public void logReturning(JoinPoint jp) {
log.info("logReturning");
//.getSignature() : 어떤 클래스의 어떤 메서드가 실행되었는지 보여줌. 파라미터 타입은 무엇인지 보여줌
// kr.or.ddit.service.BoardService.register(BoardVO)
log.info("logReturning : " + jp.getSignature());
}
}
결과 화면2 : startLog 후 작동하며 중간에 에러 발생 시 logReturning이 작동 안 함
@AfterThrowing
ServiceLoggerAdvice.java
하단에 추가
//어드바이스
//조인 포인트(메서드)에서 예외 발생 시 실행. 예외가 발생 안 되면 실행 안 됨
//throwing : 예외 발생 시 메시지가 들어감
@AfterThrowing(pointcut="excution(* kr.or.ddit.*..*(..))", throwing="e")
public void logException(JoinPoint jp, Exception e) {
log.info("logException");
//.getSignature() : 어떤 클래스의 어떤 메서드가 실행되었는지 보여줌. 파라미터 타입은 무엇인지 보여줌
// kr.or.ddit.service.BoardService.register(BoardVO)
log.info("logException : " + jp.getSignature());
//예외 메시지를 보여줌
log.info("logException : " + e);
}
@After
ServiceLoggerAdvice.java
하단에 추가
//어드바이스
//조인 포인트(메서드)를 완료한 후에 실행함. 예외 발생이 되더라도 항상 실행 됨
@After("execution(* kr.or.ddit.*..*(..))")
public void endLog(JoinPoint jp) {
log.info("endLog");
//.getSignature() : 어떤 클래스의 어떤 메서드가 실행되었는지 보여줌. 파라미터 타입은 무엇인지 보여줌
// kr.or.ddit.service.BoardService.register(BoardVO)
log.info("endLog : " + jp.getSignature());
//.getArgs() : 전달 된 파라미터 정보를 보여줌
// [BoardVO [boardNo=127,title=개똥이]]
log.info("endLog : " + Arrays.toString(jp.getArgs()));
}
결과 화면3
@Around 예시
ServiceLoggerAdvice.java
하단에 추가
//ProceedingJoinPoint : around 어드바이스에서 사용함
// 횡단관심사 - 포인트컷 대상 core메소드 - 횡단관심사
// 스프링프레임워크가 컨트롤 하고 있는 비즈니스로직 호출을 가로챔. 책임이 around 어드바이스로 전가됨
// 그래서 비즈니스 메소드에 대한 정보를 around 어드바이스 메소드가 가지고 있어야 하고
// 그 정보를 스프링 컨테이너가 around 어드바이스 메소드로 넘겨주면
// ProceedingJoingPoint 객체로 받아서 around 어드바이스가 컨트롤 시 활용함
@Around("execution(* kr.or.ddit.*..*(..))")
public Object timeLog(ProceedingJoinPoint pjp) throws Throwable{
//메소드 실행 직전 시간 체킹
long startTime = System.currentTimeMillis();
log.info("pjpStart : " + Arrays.toString(pjp.getArgs()));
//메소드 실행
Object result = pjp.proceed();
//메소드 실행 직후 시간 체킹
long endTime = System.currentTimeMillis();
log.info("pjpEnd : " + Arrays.toString(pjp.getArgs()));
//직후 시간 - 직전 시간 => 메소드 실행 시간
log.info(pjp.getSignature().getName() + " : " + (endTime - startTime));
return result;
}
<!-- Mapper 인터페이스 설정
개발자가 직접 DAO를 설정하지 않아도
자동으로 Mapper 인터페이스를 활용하는 객체를 생성하게 됨
.별별. => (중첩된)패키지 하위의 모든 것
-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="kr.or.ddit.**.mapper" />
</bean>
package kr.or.ddit.mapper;
import java.util.List;
import java.util.Map;
import kr.or.ddit.vo.LprodVO;
import kr.or.ddit.vo.ProductVO;
public interface LprodMapper {
//전체 행의 수
public int getTotal();
public int createPost(LprodVO lprodVO);
// 상품 분류 목록
public List<LprodVO> list(Map<String, Object> map);
// 상품 분류 상세
public LprodVO detail(LprodVO lprodVO);
// 상품 분류 수정
public int updatePost(LprodVO lprodVO);
// 상품 분류 삭제
public int deletePost(LprodVO lpordVO);
public int getLprodId();
public int insertProduct(ProductVO productVO);
}
lprod2_SQL.xml
list 부분 수정 및 where 생성
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="lprod">
<!-- LprodVO(lprodId=14, lprodGu=P501, lprodNm=분식류) -->
<insert id="createPost" parameterType="lprodVO">
insert into lprod(lprod_id,lprod_gu,lprod_nm)
values(#{lprodId},#{lprodGu},#{lprodNm})
</insert>
<select id="list" resultType="lprodVO" parameterType="hashMap">
WITH U AS(
SELECT ROW_NUMBER() OVER(ORDER BY LPROD_ID DESC) RNUM
, T.*
FROM
(
SELECT LPROD_ID, LPROD_GU, LPROD_NM
FROM LPROD
WHERE 1 = 1
<include refid="where"></include>
) T
)
SELECT U.*
FROM U
WHERE U.RNUM BETWEEN ((1 * 10)-(10-1)) AND (1 * 10)
</select>
<sql id="where">
AND (LPROD_ID LIKE '%' || #{keyword} || '%'
OR LPROD_GU LIKE '%' || #{keyword} || '%'
OR LPROD_NM LIKE '%' || #{keyword} || '%')
</sql>
<!-- LPROD : 1 -->
<!-- DB영역과 Java의 영역을 서로 매핑하는 역할을 함 -->
<resultMap type="lprodVO" id="lprodMap">
<result property="lprodId" column="LPROD_ID"/>
<result property="lprodGu" column="LPROD_GU"/>
<result property="lprodNm" column="LPROD_NM"/>
<!-- 1:N이기에 collection 사용 -->
<collection property="productVOList" resultMap="productMap"></collection>
</resultMap>
<!-- PRODUCT : N -->
<resultMap type="productVO" id="productMap">
<result property="productId" column="PRODUCT_ID"/>
<result property="pname" column="PNAME"/>
<result property="unitPrice" column="UNIT_PRICE"/>
<result property="description" column="DESCRIPTION"/>
<result property="manufacturer" column="MANUFACTURER"/>
<result property="category" column="CATEGORY"/>
<result property="unitsInStock" column="UNITS_IN_STOCK"/>
<result property="condition" column="CONDITION"/>
<result property="filename" column="FILENAME"/>
<result property="quantity" column="QUANTITY"/>
</resultMap>
<!-- PRODUCT : N -->
<!-- join을 했기에 resultMap을 사용 -->
<select id="detail" parameterType="lprodVO" resultMap="lprodMap">
SELECT A.LPROD_ID, A.LPROD_GU, A.LPROD_NM,
B.PRODUCT_ID, B.PNAME, B.UNIT_PRICE, B.DESCRIPTION, B.MANUFACTURER,
B.CATEGORY, B.UNITS_IN_STOCK, B.CONDITION, B.FILENAME, B.QUANTITY
FROM LPROD A LEFT OUTER JOIN PRODUCT B ON(A.LPROD_GU = SUBSTR(B.PRODUCT_ID,1,4))
WHERE A.LPROD_GU = #{lprodGu}
</select>
<update id="updatePost" parameterType="lprodVO">
UPDATE LPROD
SET LPROD_ID=#{lprodId}, LPROD_NM=#{lprodNm}
WHERE LPROD_GU=#{lprodGu}
</update>
<delete id="deletePost" parameterType="lprodVO">
DELETE FROM LPROD
WHERE LPROD_GU = #{lprodGu}
</delete>
<select id="getLprodId" resultType="Integer">
SELECT MAX(LPROD_ID)+1
FROM LPROD
</select>
<insert id="insertProduct" parameterType="productVO">
INSERT INTO PRODUCT(PRODUCT_ID, PNAME, UNIT_PRICE)
VALUES(#{productId}, #{pname}, #{unitPrice})
</insert>
</mapper>
결과 화면1
페이징 추가
LprodController.java
map.put("currentPage",currentPage) 추가
package kr.or.ddit.controller;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import kr.or.ddit.service.LprodService;
import kr.or.ddit.utils.ArticlePage;
import kr.or.ddit.vo.LprodVO;
import kr.or.ddit.vo.ProductVO;
import lombok.extern.slf4j.Slf4j;
/*
Controller 어노테이션
스프링 프레임워크에게 "이 클래스는 웹 브라우저의 요청(request)를
받아들이는 컨트롤러야" 라고 알려주는 것임.
스프링은 servlet-context.xml의 context:component-scan의 설정에 의해
이 클래스를 자바빈 객체로 등록(메모리에 바인딩).
*/
//스프링 프레임워크에게 "이 클래스는 컨트롤러야"라고 알려주자
@Slf4j
@RequestMapping("/lprod")
@Controller
public class LprodController {
//DI(의존성 주입) / IoC(제어의 역전)
@Autowired
LprodService lprodService;
/*
요청URI : /lprod/list or /lprod/list?currentPage=2 or /lprod/list?currentPage=
요청파라미터 : {keyword=개똥이}
요청방식 : get
*/
@RequestMapping(value="/list", method=RequestMethod.GET)
public ModelAndView list(ModelAndView mav,
@RequestParam(value="currentPage", required=false, defaultValue="1") int currentPage,
@RequestParam(value="keyword",required=false,defaultValue="") String keyword) {
log.info("list에 왔다");
log.info("keyword : " + keyword);
Map<String,Object> map = new HashMap<String,Object>();
map.put("keyword",keyword);
map.put("currentPage",currentPage);
//전체 행의 수
int total = this.lprodService.getTotal();
log.info("list->total : " + total);
//Model(데이터)
//상품분류 목록
List<LprodVO> lprodVOList = this.lprodService.list(map);
log.info("list->lprodVOList : " + lprodVOList);
mav.addObject("articlePage", new ArticlePage<LprodVO>(total, currentPage, 10, lprodVOList, keyword));
//View(jsp)
mav.setViewName("lprod/list");
return mav;
}
}
package kr.or.ddit.mapper;
import java.util.List;
import java.util.Map;
import kr.or.ddit.vo.LprodVO;
import kr.or.ddit.vo.ProductVO;
public interface LprodMapper {
//전체 행의 수
public int getTotal(Map<String, Object> map);
}
lprod2_SQL.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="kr.or.ddit.mapper.LprodMapper">
<sql id="where">
AND (LPROD_ID LIKE '%' || #{keyword} || '%'
OR LPROD_GU LIKE '%' || #{keyword} || '%'
OR LPROD_NM LIKE '%' || #{keyword} || '%')
</sql>
<select id="list" resultType="lprodVO" parameterType="hashMap">
WITH U AS(
SELECT ROW_NUMBER() OVER(ORDER BY LPROD_ID DESC) RNUM
, T.*
FROM
(
SELECT LPROD_ID, LPROD_GU, LPROD_NM
FROM LPROD
WHERE 1 = 1
<include refid="where"></include>
) T
)
SELECT U.*
FROM U
WHERE U.RNUM BETWEEN ((1 * 10)-(10-1)) AND (1 * 10)
</select>
<!-- 전체 행의 수
public int getTotal() -->
<select id="getTotal" parameterType="hashMap" resultType="int">
SELECT COUNT(*)
FROM LPROD
WHERE 1 = 1
<include refid="where"></include>
</select>
</mapper>
결과 화면6 : U7로 검색
페이징 처리 및 비동기로 검색 처리
ArticlePage.java
package kr.or.ddit.utils;
import java.util.List;
public class ArticlePage<T> {
//전체글 수
private int total;
// 현재 페이지 번호
private int currentPage;
// 전체 페이지수
private int totalPages;
// 블록의 시작 페이지 번호 ex) [1][2][3] 에서의 1
private int startPage;
//블록의 종료 페이지 번호 ex) [1][2][3] 에서의 3
private int endPage;
//검색어
private String keyword = "";
//요청URL
private String url = "";
//select 결과 데이터
private List<T> content;
//페이징 처리
private String pagingArea = "";
//생성자(Constructor) : 페이징 정보를 생성
// 753 1 10 select결과10행
public ArticlePage(int total, int currentPage, int size, List<T> content, String keyword) {
//size : 한 화면에 보여질 목록의 행 수
this.total = total; //753
this.currentPage = currentPage; //1
this.content = content;
this.keyword = keyword;
//전체글 수가 0이면?
if(total==0) {
totalPages = 0;//전체 페이지 수
startPage = 0;//블록 시작번호
endPage = 0; //블록 종료번호
}else {//글이 있다면
//전체 페이지 수 = 전체글 수 / 한 화면에 보여질 목록의 행 수
//3 = 31 / 10
totalPages = total / size;//75
//나머지가 있다면, 페이지를 1 증가
if(total % size > 0) {//나머지3
totalPages++;//76
}
//페이지 블록 시작번호를 구하는 공식
// 블록시작번호 = 현재페이지 / 페이지크기 * 페이지크기 + 1
startPage = currentPage / 5 * 5 + 1;//1
//현재페이지 % 페이지크기 => 0일 때 보정
if(currentPage % 5 == 0) {
startPage -= 5;
}
//블록종료번호 = 시작페이지번호 + (페이지크기 - 1)
//[1][2][3][4][5][다음]
endPage = startPage + (5 - 1);//5
//종료페이지번호 > 전체페이지수
if(endPage > totalPages) {
endPage = totalPages;
}
}
pagingArea += "<div class='col-sm-12 col-md-7'>";
pagingArea += "<div class='dataTables_paginate paging_simple_numbers' id='example2_paginate'>";
pagingArea += "<ul class='pagination'>";
pagingArea += "<li class='paginate_button page-item previous ";
if(this.startPage<6) {
pagingArea += "disabled ";
}
pagingArea += "'";
pagingArea += "id='example2_previous'>";
pagingArea += "<a href='"+this.url+"?currentPage="+(this.startPage-5)+"&keyword="+this.keyword+"' aria-controls='example2' data-dt-idx='0' tabindex='0' ";
pagingArea += "class='page-link'>Previous</a></li>";
for(int pNo=this.startPage;pNo<=this.endPage;pNo++) {
pagingArea += "<li class='paginate_button page-item ";
if(this.currentPage == pNo) {
pagingArea += "active";
}
pagingArea += "'>";
pagingArea += "<a href='"+this.url+"?currentPage="+pNo+"&keyword="+this.keyword+"' aria-controls='example2' data-dt-idx='1' tabindex='0' ";
pagingArea += "class='page-link'>"+pNo+"</a>";
pagingArea += "</li>";
}
pagingArea += "<li class='paginate_button page-item next ";
if(this.endPage>=this.totalPages) {
pagingArea += "disabled";
}
pagingArea += "' id='example2_next'><a ";
pagingArea += "href='"+this.url+"?currentPage="+(this.startPage+5)+"&keyword="+this.keyword+"' aria-controls='example2' data-dt-idx='7' ";
pagingArea += "tabindex='0' class='page-link'>Next</a></li>";
pagingArea += "</ul>";
pagingArea += "</div>";
pagingArea += "</div>";
}//end 생성자
public int getTotal() {
return total;
}
public void setTotal(int total) {
this.total = total;
}
public int getCurrentPage() {
return currentPage;
}
public void setCurrentPage(int currentPage) {
this.currentPage = currentPage;
}
public int getTotalPages() {
return totalPages;
}
public void setTotalPages(int totalPages) {
this.totalPages = totalPages;
}
public int getStartPage() {
return startPage;
}
public void setStartPage(int startPage) {
this.startPage = startPage;
}
public int getEndPage() {
return endPage;
}
public void setEndPage(int endPage) {
this.endPage = endPage;
}
public String getKeyword() {
return keyword;
}
public void setKeyword(String keyword) {
this.keyword = keyword;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public List<T> getContent() {
return content;
}
public void setContent(List<T> content) {
this.content = content;
}
//전체 글의 수가 0인가?
public boolean hasNoArticles() {
return this.total == 0;
}
//데이터가 있나?
public boolean hasArticles() {
return this.total > 0;
}
public void setPagingArea(String pagingArea) {
this.pagingArea = pagingArea;
}
//페이징 블록을 자동화
public String getPagingArea() {
return this.pagingArea;
}
}
BookController.java
currentPage추가
package kr.or.ddit.controller;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import kr.or.ddit.service.BookService;
import kr.or.ddit.utils.ArticlePage;
import kr.or.ddit.vo.BookVO;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Controller
public class BookController {
@Autowired
BookService bookService;
/*
요청URI : /list?keyword=알탄 or /list or /list?keyword=
요청파라미터 : keyword=알탄 or 없음
요청방식 : get
required=false : 선택사항. 파라미터가 없어도 무관
*/
@RequestMapping(value="/list", method=RequestMethod.GET)
public ModelAndView list(ModelAndView mav,
@RequestParam(value="currentPage",required=false,defaultValue="1") int currentPage,
@RequestParam(value="keyword",required=false,defaultValue="") String keyword) {
log.info("list에 왔다");
log.info("list->keyword : " + keyword);
//map{"keyword":"알탄"}
Map<String,Object> map = new HashMap<String,Object>();
map.put("keyword", keyword);
map.put("currentPage", currentPage);
//도서 전체 행수
int total = this.bookService.getTotal(map);
log.info("list->total : " + total);
//도서 목록 map{"keyword":"알탄"}
List<BookVO> bookVOList = this.bookService.list(map);
log.info("list->bookVOList : " + bookVOList);
//Model : 데이터
mav.addObject("articlePage", new ArticlePage<BookVO>(total, currentPage, 10, bookVOList, keyword));
//View : jsp
//forwarding : 데이터가 넘어감
mav.setViewName("book/list");
return mav;
}
/*
요청URI : /listAjax
요청파라미터(JSON->String) : {keyword:알탄} or {keyword:""}
요청방식 : post
*/
@ResponseBody
@RequestMapping(value="/listAjax", method=RequestMethod.POST)
public ArticlePage<BookVO> listAjax(@RequestBody Map<String,Object> map) {
log.info("list에 왔다");
log.info("list->map : " + map);
//map{"keyword":"알탄","currentPage":1}
//map.put("keyword", keyword);
int total = this.bookService.getTotal(map);
log.info("listAjax -> total : " + total);
//도서 목록 map{"keyword":"알탄"}
List<BookVO> bookVOList = this.bookService.list(map);
log.info("list->bookVOList : " + bookVOList);
return new ArticlePage(total, Integer.parseInt(map.get("currentPage").toString()), 10, bookVOList, map.get("keyword").toString());
}
}
BookService.java
전체 게시글 조회 추가
package kr.or.ddit.service;
import java.util.List;
import java.util.Map;
import kr.or.ddit.vo.BookVO;
public interface BookService {
public int getTotal(Map<String, Object> map);
}
package kr.or.ddit.dao;
import java.util.List;
import java.util.Map;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import kr.or.ddit.vo.BookVO;
@Repository
public class BookDao {
@Autowired
SqlSessionTemplate sqlSessionTemplate;
//도서 목록
public List<BookVO> list(Map<String, Object> map) {
//.selectList("namespace.id",파라미터)
return this.sqlSessionTemplate.selectList("book.list",map);
}
public int getTotal(Map<String, Object> map) {
return this.sqlSessionTemplate.selectOne("book.getTotal", map);
}
}
book_SQL.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="book">
<sql id="where">
<if test="keyword!=null and keyword!=''">
AND (TITLE LIKE '%' || #{keyword} || '%'
OR CATEGORY LIKE '%' || #{keyword} || '%'
OR PRICE LIKE '%' || #{keyword} || '%')
</if>
</sql>
<!-- 도서 목록
where 1 = 1은 늘 참임.
조건이 2개 이상일 때 WHERE + AND
조건이 1개일 때 WHERE이어야 함.
WHERE(생략)
AND => 오류 발생
==>
WHERE 1 = 1
AND(생략)
AND => 정상
True and True = True
True and False = False
keyword : "알탄" (/list?keyword=알탄)
keyword : "" (/list?keyword=)
-->
<!-- bookVO의 값으로 매핑되게 작업해놓음 -->
<select id="list" resultType="bookVO" parameterType="hashMap">
SELECT T.*
FROM
(
SELECT ROW_NUMBER() OVER(ORDER BY BOOK_ID DESC) RNUM
, BOOK_ID, TITLE, CATEGORY, PRICE, INSERT_DATE
FROM BOOK
WHERE 1=1
<include refid="where"></include>
) T
WHERE T.RNUM BETWEEN ((#{currentPage} * 10) - (10 - 1)) AND (#{currentPage} * 10)
</select>
<!-- 도서 전체 행수 -->
<select id="getTotal" parameterType="hashMap" resultType="int">
SELECT COUNT(*)
FROM BOOK
WHERE 1 = 1
<include refid="where"></include>
</select>
</mapper>