spring 14강 AOP와 트랜잭션 처리 실습
AOP 실습 예제 )
사용자가 메시지를 남기면 포인트 10 증가
메시지를 읽으면 포인트 5 증가
.aop : MessageAdvice.java
.controller.message : MessageController.java / LogAdvice.java (< 로그수집 기능에 대한 내용은 13강 포스팅 참고)
.model.message.dto : UserDTO.java / MessageDTO.java
.model.message.dao : MessageDAO/Impl / PointDAO/Impl
.service.message : MessageService/Impl
pointMapper.xml
AOP 실습용 테이블
AOP와 트랜잭션 쿼리를 활용한 실습
aop실습.sql //다시확인
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | drop table tbl_user cascade constraints; create table tble_user( userid varchar2(50) not null, upw varchar2(50) not null, uname varchar2(100) not null, upoint number default 0, primary key(userid) ); create table tbl_message( mid number not null, --메시지 일련번호(PK) targetid varchar2(50) not null, --받는사람 아이디 sender varchar2(50) not null, --보낸사람 아이디 message varchar2(4000) not null, opendate date, -- 열람 시간 senddate date default sysdate, -- 보낸시간 primary key(mid) ); --시퀀스 생성 create sequence message_seq start with 1 increment by 1; --제약조건 설정 alter table tbl_message add constraint fk_usertarget foreign key (targetid) references tbl_user(userid); alter table tbl_message add constraint fk_usersender foreign key (sender) references tbl_user(userid); --사용자 추가 insert into tbl_user (user_id, upw, uname) values('user00', '0000', 'kim'); insert into tbl_user (user_id, upw, uname) values('user01', '1111', 'park'); insert into tbl_user (user_id, upw, uname) values('user02', '2222', 'woo'); insert into tbl_user (user_id, upw, uname) values('user03', '3333', 'hong'); insert into tbl_user (user_id, upw, uname) values('user04', '4444', 'hwang'); insert into tbl_user (user_id, upw, uname) values('user05', '5555', 'chang'); select * from tbl_user; --user02가 user00에게 메시지를 전송 insert into tbl_message(mid, targetid, sender, message) values(message_seq.nextval, 'user00', 'user02', 'message01'); --user02에게 포인트 10 추가 update tbl_user set upoint=upoint+10 where userid='user02'; select*from tbl_user; --user00의 메시지 박스 조회 select * from tbl_massage where targetid='user00'; update tbl_message set opendate = sysdate where mid =2; select * from tbl_message; --user00에게 포인트 5 추가 update tbl_user set upoint=upoint+5 where iserid='user00'; select * from tbl_user; delete from tbl_message; commit; |
pointMapper.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | <?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"> <!-- mappers/message/pointMapper.xml --> <!-- 다른 mapper와 중복되지 않도록 네임스페이스 기재 --> <mapper namespace="point"> <!-- sqlSession.update("point.updatePoint", map); --> <update id="updatePoint"> update tbl_user set upoint=upoint+#{point} where userid=#{userid} </update> </mapper> | cs |
트랜잭션 처리
트랜잭션 처리 대상 method에 @Transactional 처리를 해준다.
@Transactional이 붙은 메서드는 블럭 안의 모든 코드가 완료되지 않으면 rollback시킨다.
root-context.xml 파일의 네임스페이스의 tx 체크 확인
root-context.xml
1 2 3 4 5 6 7 8 | <!-- 트랜잭션 관련 설정 --> <bean id="transactionManager" //=변수명 class=""는 자료형 class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean> <!-- 트랜잭션 관련 어노테이션을 자동 인식하는 옵션 --> <tx:annotation-driven /> | cs |
id는 변수 명 class는 자료형
property는 해당 클래스의 필드?(변수) , dataSource라는 다른 bean을 참조한다.
tx : 트랜잭션 처리 관련된 태그를 사용할 수 있는 네임스페이스 추가
root-context 상단에
1 2 3 4 5 6 7 8 9 | <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:mybatis-spring="http://mybatis.org/schema/mybatis-spring" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://mybatis.org/schema/mybatis-spring http://mybatis.org/schema/mybatis-spring-1.2.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd"> | cs |
네임스페이스 설정 코드가 자동으로 추가된다.
MessageDAOImpl.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | package com.example.spring02.model.message.dao; import javax.inject.Inject; import org.apache.ibatis.session.SqlSession; import org.springframework.stereotype.Repository; import com.example.spring02.model.message.dto.MessageDTO; import com.example.spring02.model.shop.dao.CartDAO; @Repository //dao bean으로 등록 public class MessageDAOImpl implements MessageDAO { @Inject //의존관계 주입(Dependency Injection, DI) SqlSession sqlSession; @Override public void create(MessageDTO dto) { sqlSession.insert("message.create", dto); } @Override public MessageDTO readMessage(int mid) { return null; } @Override public void updateState(int mid) { } } |
MessageServiceImpl.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | package com.example.spring02.service.message; import javax.inject.Inject; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import com.example.spring02.model.message.dao.MessageDAO; import com.example.spring02.model.message.dao.PointDAO; import com.example.spring02.model.message.dto.MessageDTO; @Service public class MessageServiceImpl implements MessageService { //Inject는 각각 해야 함 @Inject MessageDAO messageDao; @Inject PointDAO pointDao; //트랜잭션 처리 대상 method @Transactional @Override public void addMessage(MessageDTO dto) { //메시지를 테이블에 저장 messageDao.create(dto); //메시지를 보낸 회원에게 10포인트 추가 pointDao.updatePoint(dto.getSender(), 10); } @Override public MessageDTO readMessage(String userid, int mid) { // TODO Auto-generated method stub return null; } } |
@Trancactional 는 메시지를 저장했는데, 포인트 추가에 실패하면 롤백시킴
MessageController.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | package com.example.spring02.controller.message; import javax.inject.Inject; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; 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.RestController; import com.example.spring02.model.message.dto.MessageDTO; import com.example.spring02.service.message.MessageService; @RestController @RequestMapping("messages/*") //공통적인 url mapping public class MessageController { @Inject MessageService messageService; @RequestMapping(value="/", method=RequestMethod.POST) public ResponseEntity<String> addMessage( @RequestBody MessageDTO dto){ ResponseEntity<String> entity=null; try { messageService.addMessage(dto); entity=new ResponseEntity<>("success",HttpStatus.OK); } catch (Exception e) { e.printStackTrace(); entity=new ResponseEntity<>(e.getMessage() ,HttpStatus.BAD_REQUEST); } return entity; } } | cs |
ResponseEntity는 코드를 실행했을때 성공했는지 실패했는지 간단한 메시지와 에러코드를 전달
MessageAdvice.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | package com.example.spring02.aop; import java.util.Arrays; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; @Component // 기타 bean @Aspect // aop bean - 공통 업무를 지원하는 코드 public class MessageAdvice { private static final Logger logger =LoggerFactory.getLogger(MessageAdvice.class); @Before( "execution(* " + " com.example.spring02.service.message" + ".MessageService*.*(..))") public void startLog(JoinPoint jp) { logger.info("핵심 업무 코드의 정보:"+jp.getSignature()); logger.info("method:"+jp.getSignature().getName()); logger.info("매개변수:"+Arrays.toString(jp.getArgs())); } @Around( "execution(* " + " com.example.spring02.service.message" + ".MessageService*.*(..) )") public Object timeLog(ProceedingJoinPoint pjp) throws Throwable { //호출 전(Before) long start=System.currentTimeMillis(); Object result=pjp.proceed(); //호출 후(After) long end=System.currentTimeMillis(); logger.info(pjp.getSignature().getName()+":"+(end-start)); logger.info("================="); return result; } } |
메시지 서비스 실행 전에는 로그수집, 실행 전후에 시간 체크해주는 advice 클래스
MessageService의 모든 클래스(, 모든 파라미터)가 호출될 때 마다(실행 직전에) startLog 메서드 실행
한가지 작업에 로그가 너무 많이 쌓이므로
이전에 만든 logAdvice에 있던 로그 메서드의 @Around는 주석처리 해놓는다.
@After와 @Before는 매개변수로 JoinPoint 변수를,
@Around는 매개변수로 ProceedingJoinPoint 변수를 사용
ARC 추가하기
이번 실습에서는 뷰(view)를 별도로 만들지 않고 Advanced Rest client 확장 프로그램으로만 테스트 수행
Advanced Rest client : 크롬 확장 프로그램
구글 크롬에서 advanced rest client 서칭
ARC 추가하기
https://chrome.google.com/webstore/detail/advanced-rest-client/hgmloofddffdnphfgcellkdfbfbjeloo
입력데이터를 json으로 보내기 위해 사용
( GET과 POST는 HTTP메서드 )
Method : POST
Request URL : http://localhost/spring02/message (실행시 포트번호 있으면 포트까지 그대로 입력)
Body
- Body content type : application/json
- Editor view : Raw unput
String 타입의 json형식 데이터를 보내면
MessageController 메서드 매개변수자리에서 @Requestody가 MessageDTO 타입으로 받아서 매핑시켜준다.
'Spring > study' 카테고리의 다른 글
spring 16강 자바스크립트 난독화, Proguard를 이용한 자바 코드 난독화 (0) | 2019.07.01 |
---|---|
spring 15강 인터셉터(Interceptor) (0) | 2019.06.28 |
spring 13강 AOP의 개요, 로그수집 예제 (0) | 2019.06.27 |
http와 https의 차이점 (0) | 2019.06.27 |
spring 12강 Google Chart, JFree Chart (0) | 2019.06.26 |