// Controller 어노테이션이 있는 클래스에 한해서 예외 처리를  진행해주는 어노테이션 

 

@ExceptionHandler({NullPointerException.class, NumberFormatException.class})
public String errorHandler() {
return "redirect:/home.kh";
}

 

그래서 뭐 service나 store 클래스에서 안됨.....

try~catch를 대행하는 내용...

@ExceptionHandler 뒤에 예외처리되는 클래스 내용을 쓰면됩.

	// Controller 어노테이션이 있는 클래스에 한해서 예외 처리를  진행해주는 어노테이션 
	@ExceptionHandler({NullPointerException.class, NumberFormatException.class, SQLException.class})
	public String errorHandler() {
		return "redirect:/home.kh";
	}

'SPRING' 카테고리의 다른 글

LOG4j 등록  (0) 2022.10.11
AOP를 이용한 트랜젝션  (0) 2022.10.11
AOP 심화 : 메소드 실행시간  (0) 2022.10.07
AOP 배우기  (0) 2022.10.07
220916 스프링 게시판_댓글 8-2 댓글리스트출력  (0) 2022.09.16

시간 확인하는데 필요한 메소드들...참고만 한다...... 참고로 index.html 에 뭘 넣지는 않았음...

package com.kh.junspring.common;

import org.aspectj.lang.ProceedingJoinPoint;
import org.springframework.util.StopWatch;

public class AroundLog {
	public Object aroundLogs(ProceedingJoinPoint pp) throws Throwable {
		//ProceedingJoinPoint는 JoinPoint를 상속받아 구현된 인터페이스
		//ProceedingJoinPointfmf 사용하는 이유는 advice가 실행되는 시점을 프로그램밍 하기위해
		
		StopWatch stopWatch = new StopWatch();
		//start
		stopWatch.start();
		Object obj=pp.proceed(); //pointCut가 실행되는 시점을 잡는 것임
		//stop 
		stopWatch.stop();
		//메소드가 실행되는 시간 출력
		String methodName=pp.getSignature().getName();
		System.out.println(methodName +"()메소드 수행에 걸린시간 : "
				+ stopWatch.getTotalTimeMillis()+"(ms)");
		return obj;		//aroundLogs는 object을 리턴해야지 된다고 하지만 void도 상관없을듯
	}

}

root-context.xml에 추가

	<!--AOP XML -->
	<bean id="log" class="com.kh.junspring.common.LogAdvice"></bean> 
	<bean id="aroundLog" class="com.kh.junspring.common.AroundLog"></bean>
	<aop:config>
		<aop:pointcut expression="execution(* com.kh.junspring..*Impl.*(..))" id="allPointCut"/>
		<aop:aspect ref="log">
			<aop:before method="printLog" pointcut-ref="allPointCut"/>
			<aop:after method="printAfterLog" pointcut-ref="allPointCut"/>
		</aop:aspect>
		<aop:aspect ref="aroundLog">
			<aop:around method="aroundLogs" pointcut-ref="allPointCut"/>			
		</aop:aspect>
	</aop:config>

 

결과...

"execution(* com.kh.junspring..*Impl.*(..)) 의미는 무엇일까?

*포인트 컷 표현식, 범위로 PointCut를 설정할 수 있음..

* 리턴형, 패키지명, 클래스명, 메소드명(매개변수) 이렇게 표시되는 것이다.

1. * org.kh.com.member.model.service.*.*(..)

모든 리턴형이며 service패키지에 있는 모든 클래스 및 모든 메소드(매개변수 0개이상)

2. * org.kh.com.member.model.service..*.*(..)

service패키지의 하위 패키지까지 포함 모든 클래스 및 모든 메소드(매개변수 0개이상)

3. * org.kh.com.member.model.service.*.*()

service패키지만의 모든 클래스+메소드(매개변수가 없는 것만)

4.* org.kh.com.member.model.service..*.*(*)

모든리턴형의 service 하위패지키까지 모든 클래스+메소드( 매개변수 한개만)

5. * org.kh.com.member.model.service..*.*(Integer,..)

모든리턴형의 service 하위패지키까지 모든 클래스+메소드( 1번째파라미터는 정수+매개 변수0개이상)

6. int org.kh.member.service..*.*(integer, ..)

int리턴형의 service 하위패지키까지 모든 클래스 + 메소드(1번째파라미터는 정수+매개 변수0개이상)

7 int org.kh.member.service..*Impl.*(..)

int리턴형의 service 하위패지키까지 모든 Impl 클래스 +모든메소드(매개변수 0개이상)

 

<aop:befor> 메소드 실행 전에 적용되는 어드바이스를 정의
<aop:around> 메소드 호출 이전, 이후, 예외 발생 등 모든 시점에 적용가능한 어드바이스를 정의
<aop:after> 메소드가 정상적으로 실행되는지 또는 예외를 발생시키는지 여부에 상관없는 어드바이스를 정의
<aop:after-returning> 메소드가 정상적으로 실행된 후에 적용되는 어드바이스를 정의
<aop:after-throwing> 메소드가 예외를 발생시킬때 적용되는 어드바이스를 정의
Try-catch 블록에서 catch블록과 비슷함

<aop:around method="aroundLogs" pointcut-ref="allPointCut"/> 은

어드바이스Advice 를 정의하는 태그이고 이런의미이다.

 

'SPRING' 카테고리의 다른 글

AOP를 이용한 트랜젝션  (0) 2022.10.11
예외처리 어노테이션  (0) 2022.10.07
AOP 배우기  (0) 2022.10.07
220916 스프링 게시판_댓글 8-2 댓글리스트출력  (0) 2022.09.16
220916 스프링 게시판_댓글 8-1 댓글올리기  (1) 2022.09.16

AOP(Aspect Oriented Programming)  관계지향 프로그래밍

소스 코드의 중복을 줄이고, 필요할 때마다 가져다 쓰는 객체화 기술

즉 공통되는 부분을 따로 빼내어 필요한 시점에 해당 코드를  추가해주는 기술을 AOP라고 함

공통되는 부분을 따로 빼내서 만든 클래스를 Advice 라고하는데 메소드이기도 하다.

객채 생성, 메소드 호출, 예외발생시점등 작업이 시작되는 시점을 Joinpoint

공통 코드를 끼워 넣는 작업을 Weaving

Advice를 어디에 적용할지 결정하는 포인트컷(PointCut : JoinPoint 집합)을 합친것을 Aspect(에스펙트

부가기능을 독립적인 요소로 분리한 아스펙트는 런타임 시에 필요한 위치에 동적으로 참여가능함

Advice를 삽입할 대상객체 TargetObject

대상 객체에 Advice가 적용된 후 생성되는 객체 Proxy

Aspect 개념 그림
Proxy개념 그림
부가기능 클래스를 메소드해서 처리 하는것아닐까?

Spring AOP는 메소드 조인포인트만 지원: 동적 프록시 기반으로 지원하여 핵심기능(대상객체)의 메소드가 호출되는 런타임 시점에만 부가기능(어드바이스)를 적용할수 있다.  ///물론 AspectJ는 고급이라 다양하게 할수 있다고 함

AOP설정...

먼저 fom.xml 에 의존성 추가.

<!-- AspectJ Weaver -->
	<!-- weaver는 AOP에서 advice를 핵심 기능에 적용하는 설정 파일이다 -->
	<dependency>
		<groupId>org.aspectj</groupId>
		<artifactId>aspectjweaver</artifactId>
		<version>${org.aspectj-version}</version>
	</dependency>

 servlet-context.xml에 키워 주기.

xmlns:aop="http://www.springframework.org/schema/aop"  1.

하단에 http://www.springframework.org/schema/aop   2.
http://www.springframework.org/schema/aop/spring-aop-4.3.xsd"> 3. 넣기...

빈안에 <aop:aspectj-autoproxy></aop:aspectj-autoproxy> 프록시 작업한다고 신고함.

advice 클래스 만든다......

common 패키지만들고...LogAdvice 클래스만들어서 메소드 printLog()생성

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

root-context.xml. 에도 동일하게 1,2,3 넣기

하단에 프록시 작업한다고 신고하기

<!--AOP XML -->
<bean id="log" class="com.kh.junspring.common.LogAdvice"></bean>
<aop:config>
<aop:pointcut expression="execution(* com.kh.junspring..*Impl.*(..))" id="allPointCut"/>

// Impl 로 끝나는 클래스의 런타임시에 작동하라는 것이다.
<aop:aspect ref="log">
<aop:before method="printLog" pointcut-ref="allPointCut"/>

// Impl 클래스의 printLog의 메소드를 동작시킨다는 것이다.
</aop:aspect>
</aop:config>

 

원래는 해당파일의 Namespaces탭이 나와야 하는데 안 나와서 수기작성했다....

이렇게 자동으로 된다.

 

 

상세페이지에 댓글 리스트 자리 만들고....

상세페이지 controller에 댓글 리스트 부분만들고

@RequestMapping(value = "/board/detail.kh", method = RequestMethod.GET)
	public ModelAndView boardDetailView(ModelAndView mv, @RequestParam("boardNo") Integer boardNo
			, @RequestParam(value = "page", required = false) Integer page
			, HttpSession session) { // 커리스트링으로 앞단에서 넘어왔기때문에 받아줄 객체/ int롤 받으면 null체크 안되서 integer로 받은것임
		try {
			Board board = bService.printOneByNo(boardNo);
			List<Reply>rList=bService.printAllReply(boardNo); 
			// 게시글 상세조회를 할때 댓글리스트까지 가져오는 것
			session.setAttribute("boardNo", board.getBoardNo());			
			// 세션에 boardNo를 저장-> 삭제하기 위해서			
			mv.addObject("rList", rList);//reply list를 전달함
			mv.addObject("board", board);
			mv.addObject("page", page);
			mv.setViewName("board/detailView");

		} catch (Exception e) {
			mv.addObject("msg", e.toString());
			mv.setViewName("/common/errorPage");

		}

		return mv;
	}

List<Reply>rList=bService.printAllReply(boardNo);

리스트로 받아와야 한다........boardNo는 이미 있으니깐 다시 애용^^

mv.addObject("rList", rList);//reply list를 전달함

받아온 댓글리스트를  다시 상세페이지에 같이 전송

 

그다음 service와 store의 과정은 같다.

 

<resultMap type="Reply" id="ReplyResultMap">
	   <id     property="replyNo"         column="REPLY_NO"/>
	   <result property="replyNo"      column="REPLY_NO"/>
	   <result property="refBoardNo"      column="REF_BOARD_NO"/>
	   <result property="replyContents"   column="REPLY_CONTENTS"/>
	   <result property="replyWriter"     column="REPLY_WRITER"/>
	   <result property="rCreateDate"   column="R_CREATE_DATE"/>
	   <result property="rUpdateDate" column="R_UPDATE_DATE"/>
	   <result property="rStatus"   column="R_UPDATE_DATE"/>
	</resultMap>

매핑주의사항....select와 별칭!!

selete할때 resultMap이 있어야 하니깐 위에 하나더 추가한다...근데 여기서 type="Reply" 은 놓쳤는데 저렇게 짧게 쓸수있는건 전에 했던  Mybatis-config. 매핑의 별칭 때문인거였다.....놓치지 말라구!!

<typeAliases>
		<typeAlias type="com.kh.junspring.member.domain.Member" alias="Member"/>
		<typeAlias type="com.kh.junspring.board.domain.Board" alias="Board"/>
		<typeAlias type="com.kh.junspring.board.domain.Reply" alias="Reply"/>
	</typeAliases>

 

상세페이지에서 댓글 리스트 출력 forEach

<!-- 댓글 목록  -->
	<table align="center" width="500" border="1">
		<c:forEach items="${rList }" var="reply">
		<tr>
			<td width="100">${reply.replyWriter }</td>
			<td>${reply.replyContents }</td>
			<td>${reply.rUpdateDate }</td>
			<td>
				<a href="#"  onclick="modifyReply();">수정</a>
				<a href="#">삭제</a>
			</td>
		</tr>
		<tr id="remo" style="display:none;">
			<td colspan="3"><input type="text" size="50" value="${reply.replyContents }"></td>
			<td><button>수정</button></td>
		</tr>
		</c:forEach>	
	</table>

<c:forEach items="${rList }" var="reply">

맨날 새로운 for each문.....어쩐단 말이냐....ㅠㅠ

수정과 삭제는 다음주로....

상세 페이지에서 댓글 입력부분을 만들고

	<form action="/board/addReply.kh" method="post">	
		<input type="hidden" name="refBoardNo" value="${board.boardNo }">
		<input type="hidden" name="page" value="${page }">
		<table>
		 <tr>
		 	<textarea rows="3" cols="55"  name="replyContents"></textarea>
		 </tr>
		 <tr>
		 	<button>등록하기</button>
		 </tr>
		</table>
	</form>

<input type="hidden" name="refBoardNo" value="${board.boardNo }">
<input type="hidden" name="page" value="${page }">

상세페이지의 해당 게시글 no와  받아왔던 목록을 보내주기 위해서.

댓글 클래스 생성

db생성

CREATE TABLE REPLY_TBL(
    REPLY_NO NUMBER PRIMARY KEY,
    REF_BOARD_NO NUMBER NOT NULL,
    REPLY_CONTENTS VARCHAR2(500) NOT NULL,
    REPLY_WRITER VARCHAR2(30) NOT NULL,
    R_CREATE_DATE DATE DEFAULT SYSDATE,
    R_UPDATE_DATE DATE DEFAULT SYSDATE,
    R_STATUS VARCHAR2(2) DEFAULT 'Y'    
);

CREATE SEQUENCE SEQ_REPLY_NO;

테이블 만들고. 댓글의 시퀀스도 만들어 준다.

 

controller에 댓글 입력부분 만들기.

 

	@RequestMapping(value="/board/addReply.kh", method=RequestMethod.POST)
	public ModelAndView addBoardReply(
			ModelAndView mv
			, @ModelAttribute Reply reply
			,HttpSession session
			, @RequestParam(value = "page", required = false) int page) {
		//INSERT INTO REPLY_TBL VALUES(#{replyNo}=시퀀스,#{refBoardNo},#{replyContents},#{replyWriter},DEFAULT,DEFAULT,DEFAULT
		Member member=(Member)session.getAttribute("loginUser");
		String replyWriter=member.getMemberId();
		
		reply.setReplyWriter(replyWriter);
		int result=bService.registerReply(reply);
		if(result>0) {
			mv.setViewName("redirect:/board/detail.kh?boardNo="+reply.getRefBoardNo()); //+"&page="page
		}
		mv.addObject("page",page);
		return mv;
			
	}

session의 기록된 로그인 정보 가져오는것.......잊으면안됨...로그인정보는 어디서든 쓰이니깐..

가져올때 페이지가져야와 리스트 간다...

mv.setViewName("redirect:/board/detail.kh?boardNo="+reply.getRefBoardNo()); //+"&page="page
}
mv.addObject("page",page);

page정보를 2가지 준비해 봤는데 일단 이것저것 해봐야 한다. 아직 되는지 안되는지 모르겠다.

매핑하여 db저장...

<!--여기서 부터는 댓글입니다.  -->
	<insert id="insertReply">
		INSERT INTO REPLY_TBL 
		VALUES(SEQ_REPLY_NO.NEXTVAL, #{refBoardNo}, #{replyContents}, #{replyWriter}, DEFAULT,DEFAULT,DEFAULT)
	</insert>

여까지 뭐....^^

 

 

먼저 수정할때부터 현재 페이지를 가지고 가야한다

 

<td><a href="/board/detail.kh?boardNo=${board.boardNo}&page=${currentPage }">${board.boardTitle }</a></td>
	@RequestMapping(value = "/board/detail.kh", method = RequestMethod.GET)
	public ModelAndView boardDetailView(ModelAndView mv, @RequestParam("boardNo") Integer boardNo
			, @RequestParam(value = "page", required = false) Integer page
			, HttpSession session) { // 커리스트링으로 앞단에서 넘어왔기때문에 받아줄 객체/ int롤 받으면 null체크 안되서 integer로 받은것임
		try {
			Board board = bService.printOneByNo(boardNo);
			session.setAttribute("boardNo", board.getBoardNo());
			// 세션에 boardNo를 저장-> 삭제하기 위해서
			mv.addObject("board", board);
			mv.addObject("page", page);

a태그 전송할때 값을 보내준다.

page=${currentPage }"

심플하다.

 

 @RequestParam(value = "page", required = false) Integer page

이걸로 받아서

mv.addObject("page", page);

로  수정페이지로 값을 전달한것임.

 

<a href="#" onclick="boardRemove(${page});">삭제하기</a> 
<a href="/home.kh">홈으로</a>
	<script>
		function boardRemove(page) {
			event.preventDefault();// 하이퍼 링크 이동 방지
			if(confirm("게시물을 정말 삭제하시겠습니까?")){
				location.href="/board/remove.kh?page="+page;
			}			
		}
	</script>

상세페이지에 목록 다 하고 마지막 삭제하기 정말할때 페이지 값을 함수로 해서 다시 보내준다.

public String boardRemove(HttpSession session, Model model,
			@RequestParam("page") Integer page) {
		// 삭제만 하니깐..ModelAndView가아니라 그냥 String 반환에 model연결함

		try {
			int boardNo = (int) session.getAttribute("boardNo");
			int result = bService.removeOnebyNo(boardNo);
			if (result > 0) {
				session.removeAttribute("boardNo");
				// 성공해서 삭제되었으니깐 세션에서 정보를 삭제해야함
			}
			//model.addAttribute("page", page);
			return "redirect:/board/list.kh?page="+page; 
			
		} catch (Exception e) {
			model.addAttribute("msg",e.toString());
			return "common/errorPage";

		}
	}

@RequestParam("page") Integer page)  함수로 받으니깐 표현이 조매 다름...

삭제 후 다시 mv로 리스트 조회로 보낼때 다시 페이지를 보낸다.

삭제가 되었다......

public ModelAndView boardModify(@ModelAttribute Board board, ModelAndView mv,
			@RequestParam(value = "reloadFile", required = false) MultipartFile reloadFile // 위에서 upload였는데 여기선
			,@RequestParam("page")Integer page																				// reloadFile로 변경
			, HttpServletRequest request) {
		try {
			String boardFilename = reloadFile.getOriginalFilename();
			if (reloadFile != null && !boardFilename.equals("")) {
				// 파일 이 있거나, 파일명이 있을때
				// 수정방법 = 1, 대체 2, 삭제 후 저장 ==>삭제후 저장이 오히려 편함
				// 파일 경로를 알아야 한다. 리케스트 필요 httpHttpServletRequest request
				// 파일 삭제
				String root = request.getSession().getServletContext().getRealPath("resources");
				String savedPath = root + "\\buploadFiles";
				// 파일이름을 갖고 오고자 db로 갈필요는 없음. 이 jsp에 board 자료가 있음

				File file = new File(savedPath + "\\" + board.getBoardFileRename());// file.io
				if (file.exists()) { // 파일이 정말 있는지 확인
					file.delete(); // 파일 지움
				}
				// 삭제 했으니깐 다시 저장
				SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
				String boardFileRename = sdf.format(new Date(System.currentTimeMillis())) + "."
						+ boardFilename.substring(boardFilename.lastIndexOf(".") + 1);
				// substring 때문에 1을 더한것임
				// lastIndexOf(".")은 파일.뒤의 확장자 구하는 것이다.
				String boardFilepath = savedPath + "\\" + boardFileRename;
				reloadFile.transferTo(new File(boardFilepath));

				board.setBoardFilename(boardFilename);
				board.setBoardFileRename(boardFileRename);
				board.setBoardFilepath(boardFilepath);
			}
			int result = bService.modifyBoard(board);
			mv.setViewName("redirect:/board/list.kh?page="+page);

수정할때는 약간다르다.....

,@RequestParam("page")Integer page

mv.setViewName("redirect:/board/list.kh?page="+page);// 이건 전송방식이 조금 다르지만 응용이다.

 

<h1 align="center">${board.boardNo }번 게시글 수정하기</h1>
	<br><br>
	<form action="/board/modify.kh" method="post" enctype="multipart/form-data">
		<input type="hidden" name="page" value="${page }">
		<input type="hidden" name="boardNo" value="${board.boardNo }">
		<input type="hidden" name="boardFilename" value="${board.boardFilename }"> 
		<input type="hidden" name="boardFileRename" value="${board.boardFileRename }">

순서를 바꿔서 기재했으나...

수정페이지에서 현재페이지를 받는 것임.....input으로 전달한다.

<input type="hidden" name="page" value="${page }">

이런식으로 수정과 관련후 List 돌아가는 mv들에게 모두수정을 하면....잘된다.^^

일단 샘은 너무 수월하게 설명하시고 한번에 진행되기도 했다.

오타와의 전면전...절대 오타내면 안됨!!!!!@@@@@ 눈 빠진다!!!!

<tr>
					<td> * 우편번호</td>
					<td>
						<input type="text" name="post" class="postcodify_postcode5" >
						<button type="button" id="postcodify_search_button">검색</button>
					</td>
				</tr>
					<tr>
					<td> * 도로명주소</td>
					<td>
						<input type="text" name="address1" class="postcodify_address" >
					</td>
				</tr>
					<tr>
					<td> * 상세주소</td>
					<td>
						<input type="text" name="address2" class="postcodify_address" >
					</td>
				</tr>

클래스명 있는그대로 써야한다. 틀리면 안됨.

아이디는 상관없음.

 

<!-- 주소api를 쓰기 위한 스크립트 -->
<script src="//ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
<script src="//d1p7wdleee1q2z.cloudfront.net/post/search.min.js"></script>
				
<script>		
		/* 주소api구간 */
		$("#postcodify_search_button").postcodifyPopUp();

</script>

스크립트 넣어야지~~~~

 

public ModelAndView memberJoin(  //스프링에서 모델과 뷰를 합쳐좋은 클래스이다.
			@ModelAttribute Member member
		//  @ModelAttribute하나로 하단 @RequestParam 의 변수 값 받는 것을 모두 퉁칠수 있다. 대신에 input에 name과 변수명이 동일해야함. 아주 중요
			//명칭이 다르면 Member 객체에서 그 값은 안들어감...
//			@RequestParam("memberId") String memberId  //form의 input의 name값 // 틀리면 안됨
//			, @RequestParam("memberPwd") String memberPwd
//			,  @RequestParam("memberName") String memberName
//			,  @RequestParam("memberEmail") String memberEmail
//			,  @RequestParam("memberPhone") String memberPhone
			,  @RequestParam("post") String post
			,  @RequestParam("address1") String address1
			,  @RequestParam("address2") String address2
//			, Model model
			, ModelAndView mv){
		//request.setCharacherEncoding("utf-8");  할수도 있으나 그럼 매번 사용해줘야 함으로 필터로 진행하기로 함.
		
	try {	
//		Member member=new Member(memberId,memberPwd, memberName, memberEmail,memberPhone, post+","+memberAddress);
// 	    @ModelAttribute("") 덕분에 위에것을 다래 것으로 간단히 기재하면 된다.
		member.setMemberAddr(post+","+address1+"/"+address2);

controller 에 param값 불러온것을 또 한가지로 합친다.... 샘은 ,로 했는데 나중에 수정시 불러오기 있을것 같아...한번더 체크

			<tr>
					<td> * 우편번호</td>
					<td>
						<input type="text" name="post"  value="${addrInfos[0] }">
				
					</td>
				</tr>
	
				<tr>
					<td> * 주소</td>
					<td>
						<input type="text" name="address1" value="${addrInfos[1]}">
					</td>
				</tr>
				<tr>
					<td> * 주소</td>
					<td>
						<input type="text" name="address2" value="${addrInfos[2]}">
					</td>
				</tr>

수정페이지에서 값과 이름을 수정하였다.

 

상세보기 하고 다시 리스트 갈때 보던 화면으로 넘어가기 배운다.

<td><a href="/board/detail.kh?boardNo=${board.boardNo}&page=${currentPage }">${board.boardTitle }</a></td>

넘어갈때 검색할 no번호 옆에다가 현재페이지 정보도 같이 보낸다.

///board/list.kh?page=${currentPage } 현재 페이지를 화면에서 가져올때 받는 부분
		List<Board> bList = bService.printAllBoard(currentPage, limit); //
		if (!bList.isEmpty()) {
			mv.addObject("urlVal","list");//전체 리스트 출력할때 페이지란 것
			mv.addObject("currentPage", currentPage);
			mv.addObject("maxPage", maxPage);
			mv.addObject("startNavi", startNavi);
			mv.addObject("endNavi", endNavi);
			mv.addObject("bList", bList);
		}
		mv.setViewName("board/listView");
		return mv;

mv.addObject("urlVal","list");//전체 리스트 출력할때 페이지란 것
mv.addObject("currentPage", currentPage); ///보내준 정보를 사용하는 것

controller에서 리스트 출력할때 화면에 페이지 관련  주문을 urlVal로 했다.

	//검색값이 있을때와 없을때를 if문으로 구별했다.
				mv.addObject("urlVal","search");
				// 화면 페이지 진행할대 search값이라고 전달한다.
				mv.addObject("searchCondition", searchCondition);
				mv.addObject("searchValue", searchValue);
				//써치 조건에 대한 값의 페이지 구성여부도 알려준다.
				mv.addObject("maxPage", maxPage);
				mv.addObject("currentPage", currentPage);
				mv.addObject("startNavi", startNavi);
				mv.addObject("endNavi", endNavi);
				mv.setViewName("board/listView");

여기는 검색 controller부분이다.....이렇게 각마다 페이지 구성을 해줄수 있을듯하다.

	<c:if test="${startNavi !=1}">
						<a href="/board/{urlVal}.kh?page=${startNavi - 1 }">[이전]</a>
						<!--이전페이지가 0부터 계산되는 것을 막으려고..  -->
					</c:if>
						<c:forEach var="p" begin="${startNavi }" end="${endNavi }">
						<!--현재페이지 일경우 진한게 표시하기.  -->
							<c:if test="${currentPage eq p }">
								<b>${p }</b>
							</c:if>
							
							<c:if test="${currentPage ne p }">
								<a href="/board/${urlVal }.kh?page=${p }&searchCondition=${searchCondition}&searchValue=${searchValue}">
								${p }</a>
							</c:if>					
						</c:forEach>
					
					<c:if test="${maxPage > currentPage }">
						<a href="/board/${urlVal }.kh?page=${endNavi+1 }">[다음]</a>
					</c:if>

 

<a href="/board/${urlVal }.kh?page=${p }&searchCondition=${searchCondition}&searchValue=${searchValue}"

a태그 href주소부분을 보면 변경처리 확인된다. 저기서 mv에서 값을 받아오는 것을 쓰는것이다.

html주소 라인을 보면 정보가 확인된다.

jsp 화면에 if문을 넣는다.

<c:if test="${empty BList }">
		<c:forEach items="${bList }" var="board" varStatus="i">
			<tr>
				<td>${i.count }</td>
				<td><a href="/board/detail.kh?boardNo=${board.boardNo}">${board.boardTitle }</a></td>
				<td>${board.boardWriter }</td>
				<td>${board.bCreateDate }</td>				
				<td>${board.boardCount }</td>
				<td>${board.boardFilename }</td>
				<td>
					<c:if test="${!empty board.boardFilename }">
						O
					</c:if>
					<c:if test="${empty board.boardFilename }">
						X
					</c:if>
				</td>
			</tr>
		</c:forEach>
			<tr align="center" height="20">			
				<td colspan="7">
					<c:if test="${startNavi !=1}">
						<a href="/board/list.kh?page=${startNavi - 1 }">[이전]</a>
						<!--이전페이지가 0부터 계산되는 것을 막으려고..  -->
					</c:if>
						<c:forEach var="p" begin="${startNavi }" end="${endNavi }">
						<!--현재페이지 일경우 진한게 표시하기.  -->
							<c:if test="${currentPage eq p }">
								<b>${p }</b>
							</c:if>
							
							<c:if test="${currentPage ne p }">
								<a href="/board/list.kh?page=${p }">${p }</a>
							</c:if>					
						</c:forEach>
					<c:if test="${maxPage-1 > currentPage }">
						<a href="/board/list.kh?page=${endNavi+1 }">[다음]</a>
						<%-- <a href="/board/list.kh?page=${currentPage+5 }">[다음]</a>--%>
					</c:if>		
				</td>				
			</tr>
	
		</c:if>
		<!-- 검색list값이 없을경우  -->
		<c:if test="${!empty BList }">
			<tr>
				<td colspan="7" align="center">데이터가 존재하지 않습니다.</td>
			</tr>
		</c:if>

페이징안쪽으로 if와 else에 해당하는 구문을 넣는다.

 

try {
			List<Board> bList = bService.printAllByValue(searchCondition, searchValue,currentPage, limit);
			if (!bList.isEmpty()) {
				mv.addObject("bList", bList);
			}else {
				mv.addObject("bList", null);
			}
				mv.addObject("maxPage", maxPage);
				mv.addObject("currentPage", currentPage);
				mv.addObject("startNavi", startNavi);
				mv.addObject("endNavi", endNavi);
				mv.setViewName("board/listView");

controller에도 리스트를 줄지 null을 전달할지 작성해준다.

<select name="searchCondition">
			 			<option value="all">전체</option>
			 			<option value="writer">작성자</option>
			 			<option value="title" selected>제목</option>
			 			<option value="contents">내용</option>
			 		</select>

option 에 기본값은 selected를 주면 된다....전체를 기본값줄려면 전체 칸으로 옮겨 주면 된다.

<form action="/board/search.kh" method="get">
		<select name="searchCondition">
			<option value="all" <c:if test=" test="${searchCondition eq 'all' }">selected</c:if>전체</option>
			<option value="writer">작성자</option>
			<option value="title">제목</option>
			<option value="contents">내용</option>
		</select>
		<input type="text" name="searchValue" value="${searchValue }>
		<button type="submit" value="검색">검색</button>
</form>

검색칸에 내가 진행한 데이터가 남아 있게 할때...

option 칸마다 if문을 넣으면 된다.

조건문으로 DB를 검색해야한다....

<form action="/board/search.kh" method="get">
			 		<select name="searchCondition">
			 			<option value="all">전체</option>
			 			<option value="writer">작성자</option>
			 			<option value="title">제목</option>
			 			<option value="contents">내용</option>
			 		</select>
			 		<input type="text" name="searchValue">
			 		<button type="submit" value="검색">검색</button>
			 	</form>

먼저lselct값의 분류 값과 input에서  입력값을 같이 매핑시 전달해야하는데

클래스를 계속만들면 복잡하니깐 hashMap을 사용해서 한번에 그냥 전달했다....

그다음 조건문!

STORELOGIC에서 먼저 했다.물론controller에서 해도 된다.

	@Override
	public List<Board> selectAllByValue(SqlSessionTemplate session, String searchCondition, String searchValue,int currentPage, int limit) {
		int offset=(currentPage-1)*limit;
		RowBounds rowBounds = new RowBounds(offset, limit);
		HashMap<String, String > paramMap=new HashMap<String, String>();
		//검색시 데이터가 2개인데 같이 전송할수가 없다.
		//해시맵을 사용해 2개를 한개로 묶는다. 아니면 클래스 사용해서 진행해야함 mybatis에서 했음
		paramMap.put("searchCondition",searchCondition);
		paramMap.put("searchValue",searchValue);
		String mapping=null;
		 switch(searchCondition){
		 case "writer":
			mapping="BoardMapper.selectAllByWriter";
			break;
		 case "title":
			 mapping="BoardMapper.selectAllByTitle";
				break;
		 case "contents":
				mapping="BoardMapper.selectAllByContents";
				break;
			default:
				mapping="BoardMapper.selectAllByContents";
				break;
			 
		}
		
		List<Board> bList=session.selectList(mapping, paramMap,rowBounds);
		return bList;
	}

2번째는 매핑이다. 조건문을 하고 나니 출력할 데이터의 페이징이 문제가 되었다.

			<select id="selectAllByValue" resultMap="boardResultMap">
SELECT * FROM BOARD_TBL
<where>
<if test="searchCondition.toString() == 'title'"> BOARD_TITLE LIKE '%'||#{searchValue}||'%' </if>
<if test="searchCondition.toString() == 'contents'"> BOARD_CONTENTS LIKE '%'||#{searchValue}||'%' </if>
<if test="searchCondition.toString() == 'writer'"> BOARD_WRITER LIKE '%'||#{searchValue}||'%' </if>
<if test="searchCondition.toString() == 'all'"> BOARD_TITLE LIKE '%'||#{searchValue}||'%' OR BOARD_CONTENTS LIKE '%'||#{searchValue}||'%' OR BOARD_WRITER LIKE '%'||#{searchValue}||'%' </if>
AND B_STATUS = 'Y'
</where>
</select>

반영한 controller

	@RequestMapping(value = "/board/search.kh", method = RequestMethod.GET)
	public ModelAndView boardSearchList(ModelAndView mv
			, @RequestParam("searchCondition") String searchCondition // select
			, @RequestParam("searchValue") String searchValue  // input
			, @RequestParam(value = "page", required = false) Integer page) {


		int currentPage = (page != null) ? page : 1;		
		int totalCount = bService.getTotalCount(searchCondition, searchValue); 
        // 분류전체게시물의 갯수가 필요함.
		int limit = 10; // 한페이지당 보여주고 싶은 게시물의 갯수 //이것은 프론트에서 Param에서 받아올수 있다.
		int naviLimit = 5; // 몇개의 페이지씩 표기할것인가.....[이전]1 2 3 4 5[다음]
		int maxPage;
		int startNavi;
		int endNavi;
		// 23/5 = 4.8+0.9=5(.7)=5 페이지 갯수구하는 것 무조건 올림해야한다.
		maxPage = (int) ((double) totalCount / limit + 0.9);
		startNavi = ((int) ((double) currentPage / naviLimit + 0.9) - 1) * naviLimit + 1;
		endNavi = startNavi + naviLimit - 1; // 처음과 끝만 알면 나머지는 FOR문이 한다.
		if (maxPage < endNavi) {
			endNavi = maxPage;
		}
        //페이징 부분
		try {
			List<Board> bList = bService.printAllByValue(searchCondition, searchValue,currentPage, limit);
			if (!bList.isEmpty()) {
				mv.addObject("bList", bList);
				mv.addObject("maxPage", maxPage);
				mv.addObject("currentPage", currentPage);
				mv.addObject("startNavi", startNavi);
				mv.addObject("endNavi", endNavi);
				mv.setViewName("board/listView");
			}
		} catch (Exception e) {
			mv.addObject("msg", e.toString()).setViewName("common/errorPage");
		}
		return mv;
	}

 

 

+ Recent posts