본문 바로가기

Struts2 + iBatis

Interceptor (미)

스트럿츠 2에 도입된 중요한 요소 중에 하나로 Action 객체가 실행하기 전/후에 호출된다.

⋅ 모든 액션 요청(Action Request)에 대해 공통적으로 적용되어야 하는 공통 기능들을 제공하는 모듈
⋅ 인터셉터의 시작은 ActionInvocation 이 담당한다
⋅ 액션 프록시가 ActionInvocation 의 invoke() 메소드를 호출 할 때 인터셉터의 실행이 시작된다.
⋅ 인터셉터의 작업이 끝나면, 또 다시 ActionInvocation 의 invoke() 메소드를 다시 호출
 -> invoke() 에서드는 실행할 추가 인터셉터가 존재하는지 조사
 -> 실행할 인터셉터가 존재한다면, 그 인터셉터의 interceptor() 메소드를 호출하는 식으로 인터셉터 체인을 형성 -> 만약 더 실행 할 인터셉터가 존재하지 않는다면, 액션을 호출한 후 result를 실행

⋅ 스트럿츠2가 자체적으로 기본적인 인터셉터들은 제공하고 있으며, 디폴트 XML(struts-default.xml) 파일에 정의되어 있다.

- 사용자 정의의 interceptor을 넣어버리게 되면 기본적으로 사용하고 있던 interceptor 가 작동이 안됨
- 하나라도 사용자정의 인터셉터를 넣어버리면 인터셉터간의 연결고리가 끊어지기 때문
- 그래서 '그 다음 interceptor를 실행시켜' 하고 명시해줘야함

- interceptor가 여러개면 순차적으로 실행되고 Action을 실행
- 모든 Action에 적용할 수도 있고 부분적으로도 가능

- 내 프로젝트에 필요한 인터셉터를 묶음으로 만들 수 있음 (하나의 묶음안에는 보통 3~5개의 인터셉터들이 들어있을것임)
- 해당 action에서 내가 필요한 묶음만 부르면 됨 (interceptor의 묶음을 stack이라고 부름)
- 내부적으로 만들어놓은 params 같은 인터셉터는 그 명을 바꾸면 안된다.

[대표적인 Struts2에서 제공하는 interceptor들]
⋅ modelDriven : 액션이 ModelDriven 인터페이스를 구현하였다면 getModel() 결과를 ValueStack에 넣어 준다
⋅ params : 요청 파라미터들을 액션에 저장한다.
⋅ prepare : 액션이 Preparable 인터페이스를 구현하였다면 prepare() 메소드를 호출한다.

 

write.jsp
<%@ page contentType="text/html; charset=UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%
	request.setCharacterEncoding("UTF-8"); 
	String cp = request.getContextPath(); 
%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>

<form action="<%=cp %>/inter/save.action" method="post">
이름: <input type="text" name="userName"/><br/>
패스워드: <input type ="text" name="userPwd"/><br/>
<input type="submit" value="전송"/>
</form>

</body>
</html>

 

view.jsp
<%@ page contentType="text/html; charset=UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%
	request.setCharacterEncoding("UTF-8"); 
	String cp = request.getContextPath(); 
%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>

이름: ${userName}<br/>
패스워드: ${userPwd }<br/>

</body>
</html>

 

struts-inter.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">

<struts>
	<package name="inter" extends="default" namespace="/inter">
		
		<!-- Spring에서는 이런식으로 객체 생성 많이함. new로 안하고 -->
		<!-- 인터셉터 객체 생성 -->
		<interceptors>
			<interceptor name="myTimer" class="com.inter.TimerIntercepter"></interceptor>
		</interceptors>
	
		<action name="write">
			<result>/interTest/write.jsp</result>
		</action>
		
		<!-- method의 이름은 건네줄 필요가 없음 execute니깐 알아서 실행되니깐 -->
		<!-- 명시: params 인터셉터 실행시켜 -->
		<action name="save" class="com.inter.TestAction">
			<interceptor-ref name="myTimer"/>
			<interceptor-ref name="params"/>
			<result name="success">/interTest/view.jsp</result>
		</action>
	
	</package>
</struts>

 

 

TestAction.java
package com.inter;

import com.opensymphony.xwork2.ActionSupport;

public class TestAction extends ActionSupport{
	
	
	// dto를 바로 넘기듯이
	// 이렇게 낱개로 .jsp로 넘긴다고 생각하면 됨
	// => 이걸 struts2가 넘겨주고 있는 것임 (struts2의 core에 코딩이 되어있음)
	
	private static final long serialVersionUID = 1L;
	private String userName;
	private String userPwd;
	// 이 변수들도 Struts2의 내부적으론 자동이 아니라 params라는 바구니에 사실 담겨간거임
	// params: 내부적으로 사용하는 변수
	// 자동으로 넘기는 작업도 => interceptor임.
	
	
	public String getUserName() {
		return userName;
	}
	public void setUserName(String userName) {
		this.userName = userName;
	}
	public String getUserPwd() {
		return userPwd;
	}
	public void setUserPwd(String userPwd) {
		this.userPwd = userPwd;
	} 
	
	
	// 당연히 여기다가 이렇게 dto 만들 수 있음.
	// 길어지니깐 항상 dto를 분리시킨거 
	
	// 원래는 1단계. Domain Object 방식 이용해서
	// ( {user.userId} 이렇게 써야함)
	// ModelDriven한테 dto를 맡기면 {userId} 이렇게 쓸 수 있는 거고
	
	// 결론) dto를 지금 Action에다가 넣어놨으므로 
	// 객체 생성하는 prepare()도 필요 없고 ModelDriven도 필요 없음
	
	
	@Override
	public String execute() throws Exception {
		return SUCCESS;
	}
	
}

 

TimerIntercepter.java
package com.inter;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;

public class TimerIntercepter extends AbstractInterceptor{

	private static final long serialVersionUID = 1L;
	
	private static Log log =
			LogFactory.getLog(TimerIntercepter.class);
	//이 class를 실행하다가 만들어지는 로그를 이 log 변수에 담아라

	@Override
	public String intercept(ActionInvocation invocation) throws Exception {
		
		
		// 인터셉터 실행 전 (Action 실행 전에 실행되는 인터셉터)
		long start = System.currentTimeMillis();
		
		String result = invocation.invoke(); // Action 실행해주는 애 
		// 반환값이 success이냐 input이냐
		
		// 인터셉터 실행 후 (Action 갔다가 돌아오는 길에 실행되는 인터셉터)
		long end = System.currentTimeMillis();
		// Action 실행 전에 하는것임 
		// client가 요청 -> 인터셉터(여러개올 수 있음) -> Action
		// Action의 결과는 success, input
		
		
		log.info("실행시간: " + (end-start) + "ms");
		// 로그방식으로 찍어보기
		// System.out.println(); 
		
		return null;
	}
	

}

 

 

Interceptor - Stack으로 묶어서 저장하기

struts.xml - 공통적인 환경세팅 (interceptor도 여기다가 넣음)
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">

<!-- 공통적인 환경세팅을 여기다가 해주면 됨 -->

<struts>
	<package name="default" extends="struts-default" namespace="">
	
		<result-types>
			<result-type name="tiles"
				class="org.apache.struts2.views.tiles.TilesResult" />
		</result-types>
		
		<interceptors>
		
			<interceptor-stack name="myBasicStack">
				<interceptor-ref name="exception"/>
				<interceptor-ref name="servletConfig"/>
				<interceptor-ref name="params"/>
			</interceptor-stack>
			
			<interceptor-stack name="myPrepareParamStack">
				<interceptor-ref name="exception"/>
				<interceptor-ref name="servletConfig"/>
				<interceptor-ref name="prepare"/>
				<interceptor-ref name="modelDriven"/>
				<interceptor-ref name="params"/>
			</interceptor-stack>
			
			<interceptor-stack name="myFileUploadPrepareParamStack">
				<interceptor-ref name="exception"/>
				<interceptor-ref name="servletConfig"/>
				<interceptor-ref name="fileUpload"/>
				<interceptor-ref name="prepare"/>
				<interceptor-ref name="modelDriven"/>
				<interceptor-ref name="params"/>
			</interceptor-stack>
		
		</interceptors>
		
		<default-interceptor-ref name="myBasicStack"/>
		
		
		
		<global-results>
			<result name="error">/exception/error.jsp</result>
		</global-results>
		
	</package>

	<!-- package의 name은 아무의미없음. 중복되지만 않게 주면 됨 -->
	<!-- struts-default : core의 xml파일을 읽어낸 것임 -->
	<!-- 주소창에 /로 오는 모든것 -->

	<include file="struts-temp.xml"/>
	<include file="struts-board.xml"/>

</struts>