본문 바로가기

프로그래밍/JAVA & SPRING

[LifeSoft] spring 13강 AOP의 개요, 로그수집 예제

반응형

사. AOP 실습예제

사용자가 메시지를 남기면 포인트 10 증가

메시지를 읽으면 포인트 5 증가

com.example.spring02.aop

                                          MessageAdvice.java

com.example.spring02.controller.message.

                                          MessageController.java

com.example.spring02.model.message.dto

                                          UserDTO.java

                                          MessageDTO.java

com.example.spring02.model.message.dao

                                          MessageDAO.java

                                          MessageDAOImpl.java

                                          PointDAO.java

                                          PointDAOImpl.java                                         

com.example.spring02.service.message

                                          MessageService.java

                                          MessageServiceImpl.java

 

사. AOP 실습용 테이블

AOP와 트랜잭션 처리를 활용한 실습

글쓰기를 하면 포인트 10을 부여

글읽기를 하면 열람시간을 수정하고 포인트 5를 부여

 

drop table tbl_user cascade constraints;

-- 사용자 테이블

create table tbl_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, -- 메시지 일련번호

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;

 

-- 시퀀스.nextval ==> 다음번호

select message_seq.nextval from dual;

 

 

-- 제약 조건 설정

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 (userid, upw, uname) values ('user00', 'user00', 'kim');

insert into tbl_user (userid, upw, uname) values ('user01', 'user01', 'park');

insert into tbl_user (userid, upw, uname) values ('user02', 'user02', 'hong');

insert into tbl_user (userid, upw, uname) values ('user03', 'user03', 'choi');

insert into tbl_user (userid, upw, uname) values ('user04', 'user04', 'lee');

 

select * from tbl_user;

보내는 사람 입장에서

이곳을 tx 처리를 해준다. 하나라도 안되면 롤백해야 한다.

-- user02가 user00에게 메시지 전송

insert into tbl_message (mid, targetid, sender, message)

values (message_seq.nextval, 'user00', 'user02', '첫 메시지.. 안녕.. ');

-- user02가 포인트 10 추가

update tbl_user set upoint = upoint+10 where userid = 'user02';

select * from tbl_user;

 

받는 사람 입장에서

-- user00의 메시지목록 조회

select * from tbl_message where targetid='user00';

-- 메시지를 읽으면 열람시간 저장

update tbl_message set opendate=sysdate where mid=2; (mid는 바뀔 수 있다)

select * from tbl_message;

-- 메시지를 읽으면 포인트 5 추가

update tbl_user set upoint=upoint+5 where userid = 'user00';

select * from tbl_user;

 

delete from tbl_message;

update tbl_user set upoint=0;

commit; -- 지금까지 작업을 웹에서 사용하려면

 

이런 것을 코드로 구현을 해본다.

5) MessageDTO.java

메시지 테이블의 내용을 저장하기 위해 dto의 필드들을 선언했다.

 

public class MessageDTO {

 private int mid;
 private String targetid;
 private String sender;
 private String message;
 private Date opendate;
 private Date senddate;
 
 public int getMid() {
  return mid;
 }
...
}



두번째로 사용자 정보를 저장하기 위한 클래스를 선언한다.

6) UserDTO.java

 

public class UserDTO {
 private String userid;
 private String upw;
 private String uname;
 private int upoint;

public String getUserid() {
  return userid;
 }
...
}



메시지를 전달하는 기능을 만들기 위해 MessageDAO를 만든다.

model.message.dao.MessageDAO.java

 

public interface MessageDAO {
 public void create(MessageDTO dto);
 public MessageDTO readMessage(int mid);
 public void updateState(int mid);
}

 



구현클래스 MessageDAOImpl 를 만든다.

 

@Repository // 현재 클래스를 스프링에서 관리
public class MessageDAOImpl implements MessageDAO {

 @Inject // mybatis로 sql 실행을 하기 위한 객체를 주입(연결)
 SqlSession sqlSession;
 

 @Override
 public void create(MessageDTO dto) {
  sqlSession.insert("message.create", dto);  
 }

 @Override
 public MessageDTO readMessage(int mid) {
  return sqlSession.selectOne("message.read", mid);
 }

 @Override
 public void updateState(int mid) {

 }
}



 

9) messageMapper.xml

 

<mapper namespace="message">

 <insert id="insert">

 insert into tbl_message

 (mid, targetid, sender, message)

 values

 (message_seq.nextval, #{targetid}, #{sender}, #{message})

 </insert>

</mapper>

 

 


10) PointDAO.java , PointDAOImpl.java

메시지 저장후에 포인트 부여하는 기능을 만든다.

 

public interface PointDAO {

 public void updatePoint(String userid, int point);

}

 

 

@Repository

public class PointDAOImpl implements PointDAO {

 @Inject // sql 실행을 위한 sql 세션 주입받음

 SqlSession SqlSession;

 @Override

 public void updatePoint(String userid, int point) {

  Map<String, Object> map = new HashMap<>();

  map.put("userid", userid);

  map.put("point", point);

  SqlSession.update("point.updatePoint", map);

 }
}



13) MessageService.java

 

public interface MessageService {

 public void create(MessageDTO dto);

 public MessageDTO readMessage(String userid, int mid);

}

 

 


MessageServiceImpl.java을 만들때 생각해야 할 것이 있다.

14) MessageServiceImpl.java

트랜잭션 처리 (거래처리 단위)

 

트랜잭션이 완료되지 않은 상태에서 에러가 발생할 경우 데이터에 오류가 발생함.

예를 들어 메시지는 전달되나 포인트는 안올라가는 문제가 발생할 수 있음.

 

실습하기 전에 root-context.xml 파일의 namespace 탭의 tx 체크 확하고

트랜잭션 관련 설정을 한다.

 

<!-- 트랜잭션 관련 설정을 하는 bean을 등록 -->

 <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

  <property name="dataSource" ref="dataSource" />

 </bean>

 <!-- 트랜잭션 관련 어노테이션을 자동 인식하는 옵션 -->

 <tx:annotation-driven/>



트랜잭션 관련 bean 설정 추가 (addMessage()에 @Transactioal 추가)

MessageServiceImpl.java에 추가한다.

 

15) controller.message.MessageController.java

jsp페이지를 만들지 않고

tool을 이용해서 처리한다.

입력데이터도 json

출력데이터도 json으로 받는다.

메소드 addMessage( @RequestBody MessageDTO dto )를 보면

@RequestBody 를 쓰면 데이터를 json형식으로 받겠다는 거다.

json은 String인데 그것을 MessageDTO타입으로 바꾸겠다.

 

 

//@RestController(@Controller + @ResponseBody)

@Controller
@RequestMapping("/messages/*")
public class MessageController {

 @Inject
 MessageService service;

 // ResponseEntity: Http Status Code(http 상태코드) + 데이터 전달
 // @RequestBody : 클라이언트  => 서버(json 데이터가 입력될 때)
 // @ResponseBody : 서버 => 클라이언트(json)
 @ResponseBody
 @RequestMapping(value="/", method=RequestMethod.POST)
 public ResponseEntity<String> addMessage(@RequestBody MessageDTO dto ) {

  ResponseEntity<String> entity = null;
   
  try {

   service.create(dto);

   // new ResponseEntity<자료형>(리턴값, http status code)
   // 이 라인은 위의 메시지 작성이 성공했을 때(+트랜잭션까지 끝났다) 실행된다.

   entity = new ResponseEntity<>("success", HttpStatus.OK);

  } catch (Exception e) {

   e.printStackTrace();

   entity = new ResponseEntity<>(e.getMessage(), HttpStatus.BAD_REQUEST);

  }

  return entity;

 }
}



16) MessagAdvice.java

그럼 Message 관련서비스를 aop를 이용해서

서비스쪽에 AOP설정을 해서

전후 처리를 해보겠다.

 

@Component
@Aspect
public class MessagAdvice {

 private static final Logger logger = LoggerFactory.getLogger(MessagAdvice.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 {

  long start = System.currentTimeMillis();
  Object result = pjp.proceed();
  long end = System.currentTimeMillis();
  logger.info(pjp.getSignature().getName()+":"+(end-start));

  logger.info("===================================");

  return result;

 }



일단 LogAdvice의 @Around를 주석처리한다.

 

(실습방법)

이번 실습에서는 뷰(view)를 별도로 만들지 않고 Advanced REST client 확장 프로그램으로만 테스트를 수행한다. (구글에서 검색해서 찾는다)

 

입력데이터를 json으로 보내기 위해 사용

put: 전체 수정

delete : 삭제

patch : 일부분 수정

 

method : POST

Request URL : http://localhost/spring02/messages/

Body

  Body content type : application/json

  Editor view : Raw input

 

 

 

method : POST

Request URL : http://localhost/spring02/messages/

Body > Body content type > application/json

           Editor view > Raw input

{

"targetid" : "user01",

"sender" : "user02",

"message" : "Good morning"

}