TIL/academy

국비 TIL(Today I Learned) 20220825 AOP(Aspect Oriented Programming) : 관점지향 프로그래밍

토희 2022. 8. 25. 15:37
728x90

오늘의 요약!!!!!!!!!

오전만에 수업이 끝남 그리고 CRUD 게시판 만드는거 실습

  • AOP
  • AOP
  • AOP

하루에 요약을 3개씩 쓸라고 했느데 쓸말이 없다.....

 

 

 

 

 

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

=> 프로그램이 실행되는 처리 과정을 바라보는 시점에 따라 분할하여 인식하는것, 해당 시점에 추가적 구현을 하는것

 

Advice: 관점 지점 (아래 사진의 검정색, 쪼갠 시점)

Joinpoint: 진행중인 흐름 (아래 사진의 주황색 부분)

pointcut: 적용 대상

 

 

 

로그인 했느냐 안했느냐에 따라(필터) 어디로 가고 하는거, 

이런 필터를 매번 거는게 번거로움, 또 하나 문제점이 비교대상의 세션유형이 바뀌면 해당하는 곳을 다 바꿔줘야함

이 시점에 뭐 했으면 좋겠다 하고 한번구현하면 나머지 쪽에 다 적용된데

 

이런 부분

 

설정과 관련된 부분

경로
예전에는 이렇게 썼다. 지금은 안 써서 주석처리해놓으심

 

요즘에는

https://araikuma.tistory.com/309

 

[Spring] AspectJ 이용

AOP를 실현하는 것으로, Java에서는 "AspectJ"라는 라이브러리가 널리 사용되고 있다. Spring AOP에서이 AspectJ를 이용한 AOP 처리에 대해 설명한다. AspectJ와 pom.xml 수정 AOP에 대해 조사해 보면, 아마 "Aspe..

araikuma.tistory.com

AspectJ에 대한 설정이 pom.xml에 있음!

 

다시 AOPComponent

생각해보니, 서버 실행될때, 콘솔창이 testAOP() 뜨는 거 많이 봄!!!

 

 

AOPComponent.java

package com.spring.sample.common.component;

import javax.servlet.http.HttpServletRequest;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.servlet.ModelAndView;

@Aspect // AOP용 클래스
@Component // 객체 생성
@EnableAspectJAutoProxy // AspectJ 기능 활성화
public class AOPComponent {
	// Pointcut -> 적용범위
	// @Pointcut(범위설정)
	/*
	 * 범위 
	 * execution -> include필터 나 포함할래
	 * !execution -> exclude필터 나 포함 안할래 
	 * * -> 모든것
	 * *(..) -> 모든 메소드 
	 * .. -> 모든 경로
	 *  &&, || -> 필터 추가
	 *  
	 *  execution(접근권환 반환타입 범위): 접근권한의 경우 필수가 아님
	 */
	
	// com.spring.sample.. 밑에 있는 모든 경로(..)에서 HomeController를 찾고, 모든 메서드인데, 인자도 상관없어
	@Pointcut("execution(* com.spring.sample..HomeController.*(..))")
	public void testAOP() { // 내용이 없어서 void로 하면 되고, pointcut의 이름과 같은 역활
	}

	// ProceedingJoinPoint -> 대상 적용 이벤트 필터, 진행중인 현재상태
	/*
	 * Advice
	 * @Before -> 메소드 실행 전
	 * 
	 * @After -> 메소드 실행 후
	 * 
	 * @After-returning -> 메소드 정상실행 후
	 * 
	 * @After-throwing -> 메소드 예외 발생 후
	 * 
	 * @Around -> 모든 동작시점
	 */
	@Around("testAOP()") //"execution(* com.spring.sample..HomeController.*(..))" 한테서  @Around 모든 동작 시점에 체크해볼래
	public ModelAndView testAOP(ProceedingJoinPoint joinPoint) throws Throwable {
		ModelAndView mav = new ModelAndView();

		// Request 객체 취득
		// RequestContextHolder 
		HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes())
				.getRequest();

		mav = (ModelAndView) joinPoint.proceed(); // 기존 이벤트 처리 행위를 이어서 진행

		System.out.println("------- testAOP 실행됨 ------");

		return mav;
	}
}

 

https://engkimbs.tistory.com/746

 

[Spring] 스프링 AOP (Spring AOP) 총정리 : 개념, 프록시 기반 AOP, @AOP

| 스프링 AOP ( Aspect Oriented Programming ) AOP는 Aspect Oriented Programming의 약자로 관점 지향 프로그래밍이라고 불린다. 관점 지향은 쉽게 말해 어떤 로직을 기준으로 핵심적인 관점, 부가적인 관점으..

engkimbs.tistory.com

https://sjh836.tistory.com/157

 

Spring AOP (개념, 용어, 원리, 포인트컷 표현식, JoinPoint API)

1. AOP란? Aspect Oriented Programming 의 약자로 관점지향 프로그래밍이라고 부른다. IoC가 낮은 결합도와 관련된 것이라면 AOP 는 높은 응집도와 관련되어 있다. 서비스들의 비즈니스 메소드들은 복잡한

sjh836.tistory.com

 

 

 

pointcut 추가

 

근디 우리는 지금 리스트랑 디테일은 로그인 안해도 볼수 있게 해야하기 때문에

그냥

포인트컷 잡을때 범위를 어떻게 찾을지 생각해야함

 

 

pointcut atAOP() 추가

 

AOPComponent.java

atAOP 추가 이후 전체코드

package com.spring.sample.common.component;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.servlet.ModelAndView;

@Aspect // AOP용 클래스
@Component // 객체 생성
@EnableAspectJAutoProxy // AspectJ 기능 활성화
public class AOPComponent {
	// Pointcut -> 적용범위
	// @Pointcut(범위설정)
	/*
	 * 범위 execution -> include필터 나 포함할래 
	 * !execution -> exclude필터 나 포함 안할래 
	 * * -> 모든것
	 * *(..) -> 모든 메소드 
	 * .. -> 모든 경로 
	 * &&, || -> 필터 추가
	 * 
	 * execution(접근권환 반환타입 범위): 접근권한의 경우 필수가 아님
	 */

	// com.spring.sample.. 밑에 있는 모든 경로(..)에서 HomeController를 찾고, 모든 메서드인데, 인자도 상관없어
	@Pointcut("execution(* com.spring.sample..HomeController.*(..))")
	public void testAOP() { // 내용이 없어서 void로 하면 되고, pointcut의 이름과 같은 역활
	}

	// ProceedingJoinPoint -> 대상 적용 이벤트 필터, 진행중인 현재상태
	/*
	 * Advice
	 * 
	 * @Before -> 메소드 실행 전
	 * 
	 * @After -> 메소드 실행 후
	 * 
	 * @After-returning -> 메소드 정상실행 후
	 * 
	 * @After-throwing -> 메소드 예외 발생 후
	 * 
	 * @Around -> 모든 동작시점
	 */
	@Around("testAOP()") // "execution(* com.spring.sample..HomeController.*(..))" 한테서 @Around 모든 동작 시점에
							// 체크해볼래
	public ModelAndView testAOP(ProceedingJoinPoint joinPoint) throws Throwable {
		ModelAndView mav = new ModelAndView();

		// Request 객체 취득
		HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes())
				.getRequest();

		mav = (ModelAndView) joinPoint.proceed(); // 기존 이벤트 처리 행위를 이어서 진행

		System.out.println("------- testAOP 실행됨 ------");

		return mav;
	}

	// pointcut 여러개 써도됨
	// 이렇게 했을때 AJAX를 문제, Ajax는 결국 string을 돌려주는데 우리는 지금 ModelAndView로 돌려주게 해놨기 때문에 따로
	// 처리해야함
	@Pointcut("execution(* com.spring.sample..Controller.ATController.*Insert(..))"
			+ "|| execution(* com.spring.sample..Controller.ATController.*Update(..))")
	public void atAOP() {
	}

	@Around("atAOP()") // atAOP()를 가져와서 써
	public ModelAndView atAOP(ProceedingJoinPoint joinPoint) throws Throwable {
		ModelAndView mav = new ModelAndView();

		// Request 객체 취득
		HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes())
				.getRequest();

		HttpSession session = request.getSession();

		if (session.getAttribute("sMemNm") != null && session.getAttribute("sMemNm") != "") { // 로그인 중인 경우
			mav = (ModelAndView) joinPoint.proceed(); // 기존 이벤트 처리 행위를 이어서 진행
		} else { // 비 로그인의 경우
			mav.setViewName("redirect:testALogin");
		}
		return mav;
	}

}

aop건 이후

ATController의 insert부분

기존
변경

 

 

실행결과

ATinsert, ATUpdate에 들어갈려고 하면

로그인 페이지로 가버림

 

ATController.java

package com.spring.sample.web.testa.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.web.bind.annotation.PathVariable;
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 com.fasterxml.jackson.databind.ObjectMapper;
import com.spring.sample.common.service.IPagingService;
import com.spring.sample.web.testa.dao.IACDao;

@Controller
public class ATController {
	@Autowired
	public IACDao iACDao;

	@Autowired
	public IPagingService ips;

	@RequestMapping(value = "/ATList")
	public ModelAndView ATList(@RequestParam HashMap<String, String> params, ModelAndView mav) {

		// 비동기가 되면 일단 아무것도 처음에 셋팅 X,
		// 페이지만 셋팅
		int page = 1;

		if (params.get("page") != null && params.get("page") != "") {
			page = Integer.parseInt(params.get("page"));
		}

		mav.addObject("page", page);
		mav.setViewName("testa/T/list");

		return mav;
	}

	@RequestMapping(value = "/ATListAjax", method = RequestMethod.POST, produces = "text/json;charset=UTF-8")
	@ResponseBody
	public String ATListAjax(@RequestParam HashMap<String, String> params) throws Throwable {
		ObjectMapper mapper = new ObjectMapper();
		Map<String, Object> model = new HashMap<String, Object>();

		// 페이지 받아오게 되어있음
		int cnt = iACDao.getInt("T.getTCnt", params);

		HashMap<String, Integer> pd = ips.getPagingData(Integer.parseInt(params.get("page")), cnt, 10, 5);

		params.put("start", Integer.toString(pd.get("start")));
		params.put("end", Integer.toString(pd.get("end")));

		List<HashMap<String, String>> list = iACDao.getList("T.getTList", params);

		model.put("list", list);
		model.put("pd", pd);

		return mapper.writeValueAsString(model);
	}

	@RequestMapping(value = "/ATInsert")
	public ModelAndView aTInsert(ModelAndView mav) {

		mav.setViewName("testa/T/insert");

		return mav;
	}

	@RequestMapping(value = "/ATAction/{gbn}", method = RequestMethod.POST, produces = "text/json;charset=UTF-8")
	@ResponseBody
	public String ATAction(@PathVariable String gbn, @RequestParam HashMap<String, String> params) throws Throwable {
		ObjectMapper mapper = new ObjectMapper();
		Map<String, Object> model = new HashMap<String, Object>();

		int cnt = 0;

		try {
			switch (gbn) {
			case "insert":
				cnt = iACDao.insert("T.insertT", params);
				break;
			case "update":
				cnt = iACDao.update("T.updateT", params);
				break;
			case "delete":
				cnt = iACDao.update("T.deleteT", params);
				break;
			}

			if (cnt > 0) {
				model.put("msg", "success");
			} else {
				model.put("msg", "fail");
			}
		} catch (Exception e) {
			e.printStackTrace();
			model.put("msg", "error");
		}

		return mapper.writeValueAsString(model);
	}

	// 가져오고 변경되는게 없기 때문에 비동기 처리로 안되도 됨
	@RequestMapping(value = "/ATDetail")
	public ModelAndView aTDetail(@RequestParam HashMap<String, String> params, ModelAndView mav) throws Throwable {
		// 글번호 안 넘어왔을때 처리
		if (params.get("no") != null && params.get("no") != "") {
			// 조회수
			iACDao.update("T.updateTHit", params);
			HashMap<String, String> data = iACDao.getMap("T.getT", params);

			mav.addObject("data", data);

			mav.setViewName("testa/T/detail");
		} else {
			mav.setViewName("redirect:ATList");
		}

		return mav;
	}

	@RequestMapping(value = "/ATUpdate")
	public ModelAndView aTUpdate(@RequestParam HashMap<String, String> params, ModelAndView mav) throws Throwable {
		// 글번호 안 넘어왔을때 처리
		if (params.get("no") != null && params.get("no") != "") {
			HashMap<String, String> data = iACDao.getMap("T.getT", params);

			mav.addObject("data", data);

			mav.setViewName("testa/T/update");
		} else {
			mav.setViewName("redirect:ATList");
		}

		return mav;
	}

}

 

 

 

 

 

내일꺼 미리 셋팅

TBOARD테이블 수정 CATE_NO 컬럼 추가

 

CATE테이블 만듬

CATE 테이블이랑 TBOARD랑 외래키 설정

시퀀스도 추가해줌

 

 

CRUD게시판 만들기 실습(한줄 게시판 느낌으로 만듬, 강사님이랑 같이 한건 아님)

ACateController.java

package com.spring.sample.web.testa.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.web.bind.annotation.PathVariable;
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 com.fasterxml.jackson.databind.ObjectMapper;
import com.spring.sample.common.service.IPagingService;
import com.spring.sample.web.testa.dao.IACDao;

@Controller
public class ACateController {
	@Autowired
	public IACDao dao;

	@Autowired
	public IPagingService ips;

	// DB안 붙으니 예외처리 x
	@RequestMapping(value = "ACOB")
	public ModelAndView aob(ModelAndView mav) {
		mav.setViewName("testa/Cate/cob");

		return mav;
	}

	@RequestMapping(value = "/ACOBAction/{gbn}", method = RequestMethod.POST, produces = "text/json;charset=UTF-8")
	@ResponseBody
	public String AOBAction(@PathVariable String gbn, @RequestParam HashMap<String, String> params) throws Throwable {
		ObjectMapper mapper = new ObjectMapper();
		Map<String, Object> model = new HashMap<String, Object>();

		int cnt = 0;

		try {
			switch (gbn) {
			case "insert":
				cnt = dao.insert("cob.insertOb", params);
				break;
			case "update":
				cnt = dao.update("cob.updateOb", params);
				break;
			case "delete":
				cnt = dao.update("cob.deleteOb", params);
				break;
			}

			if (cnt > 0) {
				model.put("msg", "success");
			} else {
				model.put("msg", "fail");
			}
		} catch (Exception e) {
			e.printStackTrace();
			model.put("msg", "error");
		}

		return mapper.writeValueAsString(model);
	}

	@RequestMapping(value = "/ACOBList", method = RequestMethod.POST, produces = "text/json;charset=UTF-8")
	@ResponseBody
	public String AOBList(@RequestParam HashMap<String, String> params) throws Throwable {
		ObjectMapper mapper = new ObjectMapper();
		Map<String, Object> model = new HashMap<String, Object>();

		// 페이지 받아오게 되어있음
		int cnt = dao.getInt("cob.getObCnt", params);

		HashMap<String, Integer> pd = ips.getPagingData(Integer.parseInt(params.get("page")), cnt, 10, 5);

		params.put("start", Integer.toString(pd.get("start")));
		params.put("end", Integer.toString(pd.get("end")));

		List<HashMap<String, String>> list = dao.getList("cob.getObList", params);

		model.put("list", list);
		model.put("pd", pd);

		return mapper.writeValueAsString(model);
	}
}

 

cob.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<!-- Common CSS -->
<link rel="stylesheet" type="text/css" href="resources/css/common/cmn.css" />
<!-- Popup CSS -->
<link rel="stylesheet" type="text/css" href="resources/css/common/popup.css" />
<style type="text/css">
.wrap{ 
	width: 600px; 
	margin: 0 auto;
}
.mtb{
	margin: 5px;
}
.login{
	vertical-align: baseline;
}
.cateNm{
	width: calc(100% - 22px); 
	height: 40px; 
	border: 1px solid #d7d7d7; 
	resize: none; 
	padding: 10px
}

.update{
	display: none;
}
.con_td{
	font-size: 0
}
.paging_area{
	display: block; 
	position: relative; 
	left: 0;
	margin-bottom: 10px;
}
.search_area{
	text-align: center;
}
body {
	overflow: auto;
}
</style>
<script type="text/javascript" 
		src="resources/script/jquery/jquery-1.12.4.min.js"></script>
<script type="text/javascript" 
src="resources/script/common/popup.js"></script>
<!-- Slimscroll -->
<!-- <script type="text/javascript" src="resources/script/jquery/jquery.slimscroll.js"></script> -->
<script type="text/javascript">
$(document).ready(function () {

	
	reloadList();
	
	
	$("#insertBtn").on("click", function () {
	 		if($.trim($("#cateNm").val()) == ""){
				makeAlert("알림","카테고리를 입력하세요." , function () {
					$("#cateNm").focus();
				});
	 		}	else {
	 				action("insert");
			}
	
		})
		
	// 페이징 클릭시
	$(".paging_area").on("click", "span", function () {
		$("#page").val($(this).attr("page"));
		//기존 값 유지
		$("#searchGbn").val($("#oldGbn").val());
		$("#searchText").val($("#oldText").val());
		
		reloadList();
	})	
		
	// 검색 클릭시
	$("#searchBtn").on("click", function () {
		$("#page").val("1");
		//기존 값 새값으로 변경
		$("#oldGbn").val($("#searchGbn").val());
		$("#oldText").val($("#searchText").val());
		
		reloadList();
	})
	
	// 목록의 삭제버튼 클릭시
	$("tbody").on("click", ".delete_btn", function () {
		var no = $(this).parent().parent().attr("no");
		
		  makePopup({
		         title : "알림",
		         contents : "삭제하시겠습니까?",
		         // draggable : true,
		         buttons : [{
		            name : "삭제",
		            func:function() {
		            	$("#no").val(no);
		            	action("delete");
		            	closePopup(); // 제일 위의 팝업 닫기
		            }
		         }, {
		            name : "취소"
		    }]
		})
	})
	
	// 목록 수정버튼 클릭시
	$("tbody").on("click", ".update_btn", function () {
		var no = $(this).parent().parent().attr("no");
		$("#no").val(no);

		
		//eq(인덱스번호) : 자식들 중 인덱스 몇번째 인지 찾아서 취득
		var con = $(this).parent().parent().children().eq(1).html();
		// 수정 내용 넣기 전 <> 변화
		con = con.replace(/&lt;/gi, "<");
		con = con.replace(/&gt;/gi, ">");
		
		
		$("#cateNm").val(con);
		
		
		// 등록버튼 감추기 + 수정, 취소버튼 나타나기
		$(".insert").hide();
		$(".update").show();
		
		// 작성영역에 포커스
		$("#cateNm").focus();
	})
	
	// 수정 영역의 취소버튼
	$("thead #cancelBtn").on("click", function () {
		// 입력내용 초기화
		$("#no").val("");
		$("#cateNm").val("");
		// 등록버튼 나타나기 + 수정, 취소버튼 감추기
		$(".insert").show();
		$(".update").hide();
	})
	
	// 수정 영역의 수정버튼
	$("thead #updateBtn").on("click", function () {
		action("update");
		console.log("1");
	})
	
})


var msg ={
	"insert" : "등록",
	"update" : "수정",
	"delete" : "삭제",
}

function action(flag) {
	// con의 <를을 웹문자로 변환
	$("#cateNm").val($("#cateNm").val().replace(/</gi, "&lt;"));
	// con의 >를을 웹문자로 변환
	$("#cateNm").val($("#cateNm").val().replace(/>/gi, "&gt;"));
	
	
	// Javascript object에서의 [] : 해당 키값으로 내용을 불러오거나 넣을 수있다. 
	// Java의 Map에서 get, put역활
	console.log(msg[flag]);
	
	var params = $("#actionForm").serialize();
	
	$.ajax({
		url : "ACOBAction/" + flag,
		type : "POST", 
		dataType: "json", 
		data: params, 
		success : function(res) { 
			switch(res.msg){
			case "success" :
				// 내용 초기화
				$("#cateNm").val("");
				$("#no").val("");

				// 목록 재조회
				switch(flag){
				case "insert" :
				case "delete" :
					// 조회 데이터 초기화
					$("#page").val("1");
					$("#searchGbn").val("0");
					$("#searchText").val("");
					$("#oldGbn").val("0");
					$("#oldText").val("");
					break;
				case "update" :
					// 기존값 유지
					$("#searchGbn").val($("#oldGbn").val());
					$("#searchText").val($("#oldText").val());

					// 입력내용 초기화
					$("#no").val("");
					$("#cateNm").val("");
					// 등록버튼 나타나기 + 수정, 취소버튼 감추기
					$(".insert").show();
					$(".update").hide();
					break;
					
			
				}
				reloadList();
				break;
			case "fail" :
				makeAlert("알림" ,  msg[flag] + "에 실패하였습니다.");
				break;
			case "error" :
				makeAlert("알림" , msg[flag] + " 중 문제가 발생하였습니다.");
				break;
			}
		},
		error : function(request, status, error) { 
			console.log(request.responseText); 
		}
	}); //Ajax End
} // action Function End

function reloadList() {
	var params = $("#searchForm").serialize();
	$.ajax({
		url : "ACOBList",
		type : "POST", 
		dataType: "json", 
		data: params, 
		success : function(res) { 
			drawList(res.list);
			drawPaging(res.pd);
		},
		error : function(request, status, error) { 
			console.log(request.responseText); 
		}
	}); //Ajax End
}

function drawList(list) {
	var html = "";
	
	for(var data of list){
		html +="<tr no=\"" + data.CATE_NO  + "\">";
		html +="<td>" + data.CATE_NO + "</td>";
		html +="<td>" + data.CATE_NM + "</td>";
		html +="<td>";
			html +="<div class=\"cmn_btn_ml mtb update_btn\">수정</div><br/>";
			html +="<div class=\"cmn_btn_ml mtb delete_btn\">삭제</div>";
		html +="</td>";
		html +="</tr>";
	}
	
	$("tbody").html(html);
}



function drawPaging(pd) {
	var html = "";
	
	html += "<span class=\"page_btn page_first\" page=\"1\">처음</span>";
	// 이전
	if($("#page").val() == "1"){
		html += "<span class=\"page_btn page_prev\" page=\"1\">이전</span>";
	} else{
		// 문자열을 숫자로 바꾸기위해 *1
		html += "<span class=\"page_btn page_prev\" page=\"" + ($("#page").val() *1 - 1) + "\">이전</span>";
	}
	
	for(var i = pd.startP; i <= pd.endP; i++){
		if($("#page").val() * 1 == i){ // 현재 페이지
			html += "<span class=\"page_btn_on\" page=\"" + i + "\">" + i + "</span>";
		} else { // 다른 페이지
			html += "<span class=\"page_btn\" page=\"" + i + "\">" + i + "</span>";
		}
	}
	
	if($("#page").val() *1 == pd.endP){ // 현재페이지가 마지막 페이지라면
		html += "<span class=\"page_btn page_next\" page=\"" +pd.maxP+ "\">다음</span>";
	} else {
		html += "<span class=\"page_btn page_next\" page=\"" + ($("#page").val() *1 + 1) + "\">다음</span>";
	}
	
	html += "<span class=\"page_btn page_last\" page=\"" +pd.maxP+ "\">마지막</span>";
	
	$(".paging_area").html(html);
                                                                     
}

</script>
</head>
<body>
<hr/>
<div class="wrap">
	<div class="board_area">
		<!-- 작성 또는 로그인 -->
		
		<!-- 목록 -->
		<table class="board_table">
			<colgroup>
				<col width="100"> <!-- 번호 -->
				<col width="500"> <!-- 카테고리명 -->
			</colgroup>
			<thead>
						<tr>
							<td colspan="3" class="con_td">
								<form action="#" id="actionForm">
									<input type="hidden" name="no" id="no">
									<textarea class="cateNm" name="cateNm" id="cateNm" placeholder="카테고리명을 입력해주세요"></textarea>
								</form>
							</td>
							<td>
								<div class="insert">
									<div class="cmn_btn_ml" id="insertBtn">등록</div>
								</div> 
								<div class="update">
									<div class="cmn_btn_ml mtb" id="updateBtn">수정</div><br/>
									<div class="cmn_btn_ml mtb" id="cancelBtn">취소</div>
								</div>
							</td>
						</tr>
				<tr>
					<th>번호</th>
					<th>카테고리명</th>
				</tr>
			</thead>
			<tbody>
				
			</tbody>
		</table>
		<!-- 페이징 -->
		<div class="paging_area"></div>
	</div>
	<div class="search_area">
		<!-- 검색어 유지용 -->
		<input type="hidden" id="oldGbn" value="0" />
		<input type="hidden" id="oldText" />
		<form action="#" id="searchForm">
			<input type="hidden" name="page" id="page" value="1" />
			<select name="searchGbn" id="searchGbn">
				<option value="0">번호</option>
				<option value="1">카테고리명</option>
			</select>
			<input type="text" name="searchText" id="searchText"/>
			<div class="cmn_btn_ml" id="searchBtn">검색</div>
		</form>
	</div>
</div>
</body>
</html>

 

Cate_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="cob">
	<insert id="insertOb" parameterType="hashmap">
		INSERT INTO CATE(CATE_NO, CATE_NM) VALUES (CATE_SEQ.NEXTVAL, #{cateNm})
	</insert>
	<update id="updateOb" parameterType="hashmap">
		UPDATE CATE SET CATE_NM = #{cateNm}
		WHERE CATE_NO = #{no}
	</update>
	<update id="deleteOb" parameterType="hashmap">
		UPDATE CATE SET DEL = 0
		WHERE CATE_NO = #{no}
	</update>
	<select id="getObCnt" parameterType="hashmap" resultType="Integer">
		SELECT COUNT(*) AS CNT
			FROM CATE
		WHERE DEL = 1
		<if test="searchText != null and searchText != ''">
			<choose>
			 	<when test="searchGbn eq 0">
			 			AND CATE_NO = #{searchText} 
			 	</when>
				<when test="searchGbn eq 1">
			 			AND CATE_NM LIKE '%' || #{searchText} || '%'
			 	</when>
			</choose>
		</if>
	</select>
	<select id="getObList" parameterType="hashmap" resultType="hashmap">
		SELECT S.CATE_NO, S.CATE_NM
		FROM(SELECT CATE_NO, CATE_NM, 
		ROW_NUMBER() OVER(ORDER BY CATE_NO DESC, CATE_NM DESC) AS RNK
		FROM CATE
		 WHERE DEL = 1
	      <if test="searchText != null and searchText != ''">
				<choose>
				 	<when test="searchGbn eq 0">
				 			AND CATE_NO = #{searchText} 
				 	</when>
					<when test="searchGbn eq 1">

				 			AND CATE_NM LIKE '%' || #{searchText} || '%'
				 	</when>
				</choose>
			</if>
	      ) S
		WHERE S.RNK BETWEEN #{start} AND #{end}
	</select>
</mapper>

 

결과화면

등록, 수정, 삭제, 검색, 페이징 다 잘 됨!

 

 


개인적으로 패스트캠퍼스의 강의 들음

 

AOP

공통 코드의 분리

 

 

하나의 메서드의 두개의 관심사

메서드의 핵심기능, 부가기능이 있어

메서드들이 부가기능을 공통적으로 가지고 있어 => 분리

 

 

분리

1. 관심사

2. 변하는것, 변하지 않는것

3. 공통코드

 

분리하고 myAdvice 클래스에서 reflection API 통해서 호출하면, 더 변경에 유리한 코드가 됨

 

reflection API

https://tecoble.techcourse.co.kr/post/2020-07-16-reflection-api/

 

Reflection API 간단히 알아보자.

Spring Framework를 학습하다 보면 Java Reflection API를 자주 접하게 된다. 하지만 Reflection API…

tecoble.techcourse.co.kr

 

강의에서는 reflection API사용했구, 우리는 AspectJ 라이브러리 했고,

 

뭔가 aop제외하는것도 다름

AspectJ 에서는 !~~~ 이렇게, 강의에서는 pattern으로 정의해서 사용

 

 

 

https://sabarada.tistory.com/97

 

[Spring] Spring AOP - 원리편

안녕하세요. 오늘은 Spring AOP의 3번째 시간으로 마지막 시간입니다. 오늘은 AOP가 Spring 내부에서 구현되는 원리에 대해서 한번 알아보는 시간을 가져보도록 하겠습니다. AOP를 사용하는 방법 및 기

sabarada.tistory.com

 

728x90