ajax에서 url로 보낸 데이터를 설정한 매개변수에 저장해주는 어노테이션.
rest방식의 get방식은 url에 parameter를 넣는 데이터전송을 사용하지않음
@GetMapping("/all/{replyBno}")
public ResponseEntity<List<ReplyVO>> readReplies(@PathVariable("replyBno") int replyBno) {
List<ReplyVO> list=replyService.read(replyBno);
return new ResponseEntity<List<ReplyVO>>(list, HttpStatus.OK);
}
자바스크립트에서 url을 read 방식으로 바꿔준다.
var url='replies/all/'+replyBno;
headers : {
'Content-Type':'application/json',
'X-HTTP-Method-Override':'(POST/PUT/DELETE)'
}
post, put, delete는 아무나 url에 접근할 수 없어서 ajax에서 header로 명시해줘야 가능하다
AOP(Aspect Oriented Programming)
관점지향 프로그래밍. 핵심/부가로 기능을 나눠서 관점기준으로 모듈화함.
원래는 흐름대로 A->B->C->a->b->c 수평적 모듈화를 했다면 관점으로 A,a|B,b|C,c 수직적 모듈화하는 것.
흐름을 횡단하는 형식
@Component
: Proxy 객체에 주입(injection)하기 위해 선언한다@Aspect
: Aspect=Advice+Pointcut<!-- AspectJ -->
<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>
beans 속성에 http://www.springframework.org/schema/tx
추가하기
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
http://www.springframework.org/schema/aop
추가하기<beans:beans xmlns="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<aop:aspectj-autoproxy />
추가하기<!-- Annotation 기반의 AOP 기능 사용 -->
<aop:aspectj-autoproxy />
@Pointcut("execution(* edu.spring.ex03.HomeController.home(..))")
public void pcHome() {}
@Around("pcHome()")
public Object homeAdvice(ProceedingJoinPoint jp) {
Object result=null;
LOGGER.info("===== homeAdvice");
try {
LOGGER.info("===== home() 호출 전"); //@Before
result=jp.proceed(); //HomeController.home() 실행
LOGGER.info("===== home() 리턴 후"); //@AfterReturning
} catch (Throwable e) {
//@AfterThrowing
LOGGER.info("===== 예외 발생 : "+e.getMessage());
} finally {
//@After
LOGGER.info("===== finally");
}
return "reply";
}
@Pointcut()
: 간섭할 포인트컷 메소드 위치 지정@Around()
: 포인트컷 메소드를 적용시킴포인트컷으로 home.jsp
경로를 지정하고 home.jsp의 실행 전후에 간섭할 수가 있다
INFO : edu.spring.ex03.aspect.HomeAspect - ===== homeAdvice
INFO : edu.spring.ex03.aspect.HomeAspect - ===== home() 호출 전
INFO : edu.spring.ex03.HomeController - Welcome home! The client locale is ko_KR.
INFO : edu.spring.ex03.aspect.HomeAspect - ===== home() 리턴 후
경로뿐만 아니라 클래스와 메소드의 이름으로 접근할 수 있음
@Before("execution(* edu.spring.ex03.service.CustomerServiceImple.*Customer(..))")
public void beforeAdvice(JoinPoint jp) {
logger.info("===== beforeAdvice");
logger.info("target : "+jp.getTarget()); //return 할 타겟 경로
logger.info("signature : "+jp.getSignature());
}
댓글 테이블에 데이터가 추가되면 게시글 테이블의 댓글수 컬럼의 데이터가 추가된 댓글 수만큼 업데이트되어야한다
update board
set reply_count=reply_count+?
where board_no=?
변수 두개를 하나의 파라미터로 넘겨야하기 때문에 key-value의 map으로 담아보내기
public int updateReplyCount(int amount, int bno) {
Map<String, Integer> args=new HashMap<String, Integer>();
args.put("amount", amount);
args.put("bno", bno);
return sqlSession.update(NAMESPACE+".update_reply_count", args);
}
두 테이블의 동작이 연속적으로 일어나야하는데 그러려면 하나의 클래스가 두개의 테이블에 접근해야함. 이런 역할을 Service
가 한다. DAO는 DB와 1:1매칭이기 때문에 못함
@Autowired
private ReplyDAO replyDAO;
@Autowired
private BoardDAO boardDAO;
@Override
public int create(ReplyVO vo) {
LOGGER.info("create() 호출");
replyDAO.insert(vo);
LOGGER.info("댓글 입력 성공");
boardDAO.updateReplyCount(1, vo.getReplyBno());
LOGGER.info("게시판 댓글 수 수정 성공");
return 1;
}
insert/delete는 무조건 한번에 하나의 데이터만 등록되기 때문에 댓글수 컬럼의 증감폭은 1이다
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="ds"></property>
</bean>
xmlns:tx
사용하기<!-- 트랜잭션 관리를 수행하는 Aspect를 annotation 기반으로 사용 -->
<tx:annotation-driven/>
네트워크 문제로 데이터 이동 시 데이터가 유실되거나 DB에 반영이 제대로 되지않았을 경우 데이터가 불일치하게 된다
예를 들어 위에서 본 댓글수의 경우 댓글 추가는 되었는데 댓글수 추가가 실행되지 않았을 때 데이터가 불일치하게됨
이 경우 rollback(이전상태로 돌려주기)을 해주는 게 바로 트랜잭션.
@Transactional //exception 발생 시 rollback
@Override
public int delete(int replyNo, int replyBno) throws Exception{
LOGGER.info("delete() 호출");
replyDAO.delete(replyNo);
LOGGER.info("댓글 삭제 성공");
boardDAO.updateReplyCount(-1, replyBno);
LOGGER.info("게시판 댓글 수 수정 성공");
return 1;
}
Filter : Application에 등록됨 (프로젝트 전반적)
Interceptor : Spring Context에 등록됨(webapp/WEB-INF/spring 내부)
전체적인 Request, Response에 대한 처리가 필요할 때 사용
ex) 문자 인코딩
세션 및 쿠키 체크 등 HTTP 프로토콜 단위로 처리가 필요할 때 사용
ex) 로그인 세션 체크
비지니스(Service)단계에서 세밀한 조정이 필요할 때 사용
ex) 로깅, 트랜잭션, 예외처리