오라클자바커뮤니티에서 설립한 오엔제이프로그래밍 실무교육센터
(오라클SQL, 튜닝, 힌트,자바프레임워크, 안드로이드, 아이폰, 닷넷 실무전문 강의)
Action은 params 인터셉터와 setter로 사용자가 넘기는 요청 파라미터의 값을 받는다.
우선 기본적인 예제를 만들어 보는데...
- 사용자는 사용자 정보를 웹화면을 통해 입력 후 Submit 버튼을 클릭하여 UserAction을 호출한다.
- UserAction의 execute 메소드에서 UserInfo Object를 생성하고 사용자정보 저장하기 위해 UserDAO의 save 메소드를 호출한다.
- execute가 SUCCESS or ERROR를 리턴한다.
UserDAO의 save 메소드에서는 인자로 UserInfo Type을 받으므로 Action에서 USerInfo 객체를 생성하고 form에서 넘기는 값들을 setter를 이용하여 세팅해 주어야 한다. 만약 파라미터가 많다면 이작업은 아주 지루한 작업이 될 수 있는 데...
우선 아래 순서대로 위에서 이야기 한 예제를 만들어 보자.
1. 이클립스에서 struts2_userinput 이라는 Tomcat Project를 만든다.
2. struts2 사용하기 위해 필요한 jar 파일을 WEB-INF/lib에 넣은 후 라이브러리에 추가한다.
(struts-2.0.14\lib에 포함되어 있다)
- struts2-core-2.0.14.jar
- xwork-2.0.7.jar
- ognl-2.6.11.jar
- freemarker-2.3.8.jar
3. Jakarta Commons Loggin을 이용하기 위한 jar 파일을 추가한다.
(struts-2.0.14\lib에 포함되어 있다)
- commons-logging-1.0.4.jar
4. UserInfo.java파일을 작성
package login.model;
public class UserInfo {
private String name;
private String addr;
private String tel;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddr() {
return addr;
}
public void setAddr(String addr) {
this.addr = addr;
}
public String getTel() {
return tel;
}
public void setTel(String tel) {
this.tel = tel;
}
}
5. UserDAO.java 작성
package login.dao;
import login.model.UserInfo;
public class UserDAO {
public boolean save(UserInfo userInfo) {
//DB연결 후 넘어오는 사용자 정보 저장 후 true 리턴
//본 예제에서는 true를 리턴
return true;
}
}
6. UserAction.java 작성
package login.action;
import login.dao.UserDAO;
import login.model.UserInfo;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.opensymphony.xwork2.Action;
public class UserAction implements Action {
private String name;
private String addr;
private String tel;
Log log = LogFactory.getLog(UserAction.class);
public String execute() throws Exception {
log.info(">>>>> execute ");
//UserInfo 객체 생성
UserInfo userInfo = new UserInfo();
userInfo.setName(name);
userInfo.setAddr(addr);
userInfo.setTel(tel);
log.info(">>>>> userInfo Object Create...");
//사용자정보 입력위해 DAO 호출
UserDAO loginDao =new UserDAO();
if (loginDao.save(userInfo)) {
return SUCCESS;
}
else {
return ERROR;
}
}
}
7. struts2_userinput 아래에 다음 3개의 JSP 파일을 작성한다.
[form1.jsp]
<%@ page pageEncoding="euc-kr" %>
<html>
<body>
<form action="user.action">
이름 : <input type="text" name="name"/><br>
주소 : <input type="text" name="addr"/><br>
전화번호 : <input type="text" name="tel"/>
<input type="submit"/>
</form>
</body>
</html>
[save_ok.jsp]
SAVE OK!!
[error.jsp]
ERROR!!
8. WEB-INF아래 web.xml 작성
<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_9" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<display-name>Struts2</display-name>
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
9. WEB-INF/src 아래 struts.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="struts2" extends="struts-default">
<action name="user" class="login.action.UserAction">
<result>/save_ok.jsp</result>
<result name="error">/error.jsp</result>
</action>
</package>
</struts>
이번에는 도메인 오브젝트를 사용하여 위 문제를 해결해 보자.
1. UserAction을 개선한 UserAction2.java 파일을 만든다.
package login.action;
import login.dao.UserDAO;
import login.model.UserInfo;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.opensymphony.xwork2.Action;
public class UserAction2 implements Action {
UserInfo userInfo ;
Log log = LogFactory.getLog(UserAction.class);
public String execute() throws Exception {
log.info(">>>>> execute ");
//UserInfo 객체 생성
UserInfo userInfo = new UserInfo();
log.info(">>>>> userInfo Object Create...");
//사용자정보 입력위해 DAO 호출
UserDAO loginDao =new UserDAO();
if (loginDao.save(userInfo)) {
return SUCCESS;
}
else {
return ERROR;
}
}
//UserInfo를 위한 getter, setter
public UserInfo getUserInfo() {
return userInfo;
}
public void setUserInfo(UserInfo userInfo) {
this.userInfo = userInfo;
}
}
2. Action을 호출하기 위한 form2.jsp를 작성한다.
<%@ page pageEncoding="euc-kr" %>
<html>
<body>
<form action="user.action">
이름 : <input type="text" name="userInfo.name"/><br>
주소 : <input type="text" name="userInfo.addr"/><br>
전화번호 : <input type="text" name="userInfo.tel"/>
<input type="submit"/>
</form>
</body>
</html>
실행하여 결과를 확인하자.
크게 두 군데 달라 졌는데.. Action에서 UserInfo를 생성한 후 setXXX하는 부분이 생략되었고...
대신 UserInfo 객체를 위한 getter, setter가 추가 되었으며 JSP파일에서 name부분에 userInfo.을 앞에 붙여 요청파라미터를 넘긴다는 것이다.
form에서 userInfo.XXX 형태로 액션에 넘어오면 params 인터셉터는 액션의 getUserInfo를 호출하여 인스턴스가 생성되어 있는지 있으면 재활용하며 없다면 인스턴스를 생성하고 생성한 인스턴스를 setUserInfo를 호출하여 액션에 세팅한다. 그런다음 getUserInfo().setName(), getUserInfo().setAddr(), getUserInfo().setTel()을 차례로 호출하여 요청파라미터를 도메인 오브젝트에 세팅한다.
위 Action을 보면 어디에서도 UserInfo 객체를 생성하지는 않으며 params 인터셉터에서 생성을 하는데 이 생성된 인스턴스는 setUserInfo() 메소드로 액션에 생성되므로 액션에는 도메인 오브젝트의 getter 뿐아니라 setter가 반드시 필요한 것이다.
물론 Action 다음과 같이 만든다면 setter는 필요 없게 된다.
public class UserAction2 implements Action {
UserInfo userInfo = new UserInfo();
....
}
첫번째 방법보다는 개선된 부분이 있지만 form에서 userInfo.을 앞에 붙여 쓴다는 것은 여전히 불만이다.
이번에는 가장 진보된 형태의 ModelDriven 인터페이스를 구현하여 사용자의 요청 파라미터를 처리해 보자.
1. struts.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="struts2" extends="struts-default">
<action name="user" class="login.action.UserAction3">
<interceptor-ref name="prepare"/>
<interceptor-ref name="modelDriven/>
<interceptor-ref name="params"/>
<result>/save_ok.jsp</result>
<result name="error">/error.jsp</result>
</action>
</package>
</struts>
2. UserAction3.java
package login.action;
import login.dao.UserDAO;
import login.model.UserInfo;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.opensymphony.xwork2.Action;
import com.opensymphony.xwork2.ModelDriven;
import com.opensymphony.xwork2.Preparable;
public class UserAction3 implements Action, Preparable, ModelDriven {
UserInfo userInfo ;
Log log = LogFactory.getLog(UserAction.class);
public String execute() throws Exception {
log.info(">>>>> execute ");
//UserInfo 객체 생성, prepare에서 했다...
//UserInfo userInfo = new UserInfo();
log.info(">>>>> userInfo Object Create...");
//사용자정보 입력위해 DAO 호출
UserDAO loginDao =new UserDAO();
if (loginDao.save(userInfo)) {
return SUCCESS;
}
else {
return ERROR;
}
}
//UserInfo를 위한 getter, setter
public UserInfo getUserInfo() {
return userInfo;
}
//Preparable Interface의 prepare() 구현
public void prepare() throws Exception {
userInfo = new UserInfo();
}
//ModelDriven의 getModel() 구현
public Object getModel() {
return userInfo;
}
}
실행하여 결과를 확인하자!!
2가지 달라진 것이 있는데 prepare, modelDriven이라는 인터셉터를 붙였으며 액션에서 Preparable, ModelDriven 인터페이스를 구현했다. 좀더 자세히 설명하자면 params 인터셉터는 액션의 프로퍼티를 채우는 것이 아니라 ValueStack 상단에 있는 오브젝트 부터 프로퍼티를 채운다. ValueStack은 일종의 스택인데 일반적인 스택처럼 스택의 상단에 오브젝트를 넣고 꺼내는 것이 아니라스택 상단 오브젝트의 프로퍼티를 세팅하고 읽는 스택이다. Struts2에서는 액션 인스턴스를 ValueStack의 최 상단에 넣는다. 따라서 params 인터셉터를 붙이면 액션의 프로퍼티가 세팅 되는 것이다.
modelDriven 인터셉터는 ModelDriven 인터페이스를 구현한 액션에서 getModel() 메소드를 실행해서 리턴받은 모델 오브젝트를 ValueStack의 최 상단에 올린다. (액션 보다 위에...) 따라서 modelDriven 인터셉터를 먼저 붙이고 params 인터셉터를 붙이면 요청파라미터들은 모델 오브젝트의 프로퍼티로 세팅 되는 것이다.
prepare 인터셉터는 Preparable 인터페이스를 구현한 액션에서 prepare() 메소드를 호출한다. 모델 오브젝트를 초기화 하기 위해 되는 것으로 항상 modelDriven 인터셉터보다 먼저 붙여야 한다.
댓글 없음:
댓글 쓰기