예외처리 및 스트럿츠 커스텀 태그 예제
오라클자바커뮤니티에서 설립한 오엔제이프로그래밍 실무교육센터
(오라클SQL, 튜닝, 힌트,자바프레임워크, 안드로이드, 아이폰, 닷넷 실무전문 강의)
아래 예제는 모든 예외의 루트인 BaseException두어 예외에 대해 프로그램 내부에서 처리하는 예제 입니다.
JDBC오류에 대해서는 로깅을 이용하여 실제 오류를 확인하며 사용자에게는 아래와 같이 변환 된 오류정보를 반환 합니다.
우선 실행 흐름을 살펴보면 emp.jsp를 실행하면 부서코드를 입력 할 수 있는 창이 나타나는데 여기에서 EMP테이블의 DEPTNO에 해당하는 부서코드(예를 들면 10)를 입력한 후 “EMP LIST”를 클릭하게 되면 EMP TABLE에서 원하는 부서에 해당 하는 사원의 ename, job이 출력되는 예제 입니다.
유심히 볼 부분은 예외를 처리하는 방법과 emplist.jsp에서 EMP 테이블의 데이터를 출력 할 때 <logic:iterate>를 사용하여 반복적으로 자바 빈의 내용을 출력 하는 부분 입니다.
데이터베이스 커넥션 풀은 bitmechanic의 JDBC POOL을 사용 했으며 이 부분에 대한 자세한 사항은 오라클자바의 스트럿츠 강좌 “DB를 사용하여 로그인 하기” 강좌를 참고 하시기 바랍니다.
===============================================================
------------------
1. emp.jsp
------------------
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html"%>
<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean"%>
<html>
<body>
<html:errors/>
<html:form action="/EmpSubmit">
<bean:message key="user.depttitle"/>:<html:text property="deptno" value=""/>
<html:submit value="EMP LIST">
</html:submit>
</html:form>
</body>
</html>
------------------
2. emplist.jsp
------------------
<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean"%>
<%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic"%>
<html>
<head>
<title>Emp User List</title>
</head>
<body>
<h1>Emp User List</h1>
<!-- ================================================ -->
<logic:present name="users">
<table border="1">
<tr>
<th>
<bean:message key="user.ename"/>
</th>
<th>
<bean:message key="user.job" />
</th>
</tr>
<!---------------------------------------------->
<logic:iterate id="user" name="users">
<tr>
<td>
<bean:write name="user" property="ename"/>
</td>
<td>
<bean:write name="user" property="job"/>
</td>
</tr>
</logic:iterate>
<!---------------------------------------------->
</table>
</logic:present>
<!-- =================================================== -->
</body>
</html>
------------------
3. EmpForm.java
------------------
package logic;
import org.apache.struts.action.ActionForm;
public class EmpForm extends ActionForm {
private String deptno=null;
public String getDeptno() {
return deptno;
}
public void setDeptno(String deptno) {
this.deptno = deptno;
}
}
------------------------------
4. DisplayAllUserAction.java
------------------------------
본 예제의 경우 Action을 하나만 간단 하게 관리 하지만 실제 액션이 많이지는 경우 메인 액션을 하나 두고 나머지 액션들이 메인 액션을 상속 받게 하는 구조로 구성 할 수 있습니다. 그러한 경우 아래에서의 예외 처리 부분은 execute 메소드에 두고 execute의 마지막 부분에서 각 하위 액션들이 구현 할 메소드를 호출 하는 형태로 구성을 합니다. 이에 관한 사항은 스트럿츠 강좌 “Struts에서의 예외처리(2)”를 참고 하시기 바랍니다.
package logic;
import org.apache.struts.action.Action;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import logic.BaseException;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionErrors;
import org.apache.struts.action.ActionError;
import java.util.List;
import java.util.Iterator;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* @author 이종철
*/
public class DisplayAllUserAction extends Action {
ActionForward forwardPage = null;
public ActionForward execute(ActionMapping mapping, ActionForm form,HttpServletRequest request, HttpServletResponse response) {
Log log = LogFactory.getLog(DisplayAllUserAction.class);
try {
GetUserDAO user = new GetUserDAO();
List list = user.getUserList(((EmpForm)form).getDeptno());
if (list.size() > 0){
request.setAttribute("users", list);
}
forwardPage = mapping.findForward("usersuccess");
}
catch (BaseException ex){
log.info("BaseException : " +ex);
forwardPage = processExceptions( request, mapping, ex);
}
return forwardPage;
}
protected ActionForward processExceptions( HttpServletRequest request,
ActionMapping mapping,
BaseException ex )
{
ActionErrors errors = new ActionErrors( );
ActionForward forward = null;
//processBaseException(errors, (FieldException) ex);
processBaseException(errors, ex);
// 입력된 리소스와 failure 포워드를 반환 합니다.
String inputStr = mapping.getInput( );
if ( inputStr != null) {
forward = new ActionForward( inputStr );
}
// 예외가 하위 예외를 포함하고 있는지 확인
List exceptions = ex.getExceptions( );
if (exceptions != null && !exceptions.isEmpty() ){
int size = exceptions.size( );
Iterator iter = exceptions.iterator( );
while( iter.hasNext( ) ){
// 모든 하위예외들은 BaseException이어야 합니다.
BaseException subException =(BaseException)iter.next( );
processBaseException(errors, subException);
}
}
// Tell the Struts framework to save the errors into the request
saveErrors( request, errors );
// Return the ActionForward
return forward;
}
protected void processBaseException( ActionErrors errors, BaseException ex)
{
// 추가될 ActionError의 레퍼런스 저장
ActionError newActionError = null;
// 에러 코드는 리소스 번들의 키값
String errorCode = ex.getMessageKey();
/*
* MessageFormat 객체가 사용하는 추가적인 인자가 있다면
* args에 예외를 추가
*/
Object[] args = ex.getMessageArgs( );
// ACtionError 클래스의 인스턴스 생성자
if ( args != null && args.length > 0 ){
// Use the arguments that were provided in the exception
newActionError = new ActionError( errorCode, args );
}
else{
newActionError = new ActionError(errorCode);
}
errors.add(ActionErrors.GLOBAL_ERROR, newActionError );
}
}
------------------------------
5. GetUserDAO.java
------------------------------
package logic;
import java.sql.*;
import com.bitmechanic.sql.*;
import java.util.*;
import logic.BaseException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class GetUserDAO {
private static String LIST_QUERY = "SELECT ename, job from emp where deptno=?";
public List getUserList(String deptno) throws BaseException
{
Connection con = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
List list = null;
Log log = LogFactory.getLog(GetUserDAO.class);
try
{
con = DriverManager.getConnection(ConnectionPoolManager.URL_PREFIX+"wink");
pstmt = con.prepareStatement(LIST_QUERY);
pstmt.setInt(1,java.lang.Integer.parseInt(deptno));
rs = pstmt.executeQuery();
list = new ArrayList(50);
while ( rs.next() )
{
String ename = rs.getString(1);
String job = rs.getString(2);
User user = new User();
user.setEname(ename);
user.setJob(job);
list.add(user);
}
return list;
}
catch (SQLException e1)
{
log.info("SQLException : " + e1);
BaseException b = new BaseException(e1);
b.setMessageKey("jdbc.error");
throw b;
}
finally
{
try
{
if ( rs != null ) rs.close();
if ( pstmt != null ) pstmt.close();
if ( con != null ) con.close();
}
catch ( Exception ignore )
{
}
}
}
}
------------------------------
6. User.java
------------------------------
package logic;
import java.io.Serializable;
public class User implements Serializable {
private String ename=null;
private String job=null;
public String getEname() {
return ename;
}
public String getJob() {
return job;
}
public void setEname(String ename) {
this.ename = ename;
}
public void setJob(String job) {
this.job = job;
}
}
------------------------------
7. BaseException.java
------------------------------
package logic;
import java.util.List;
import java.util.ArrayList;
import java.io.PrintStream;
import java.io.PrintWriter;
/**
* 이 클래스는 애플리케이션 예외의 공통 슈퍼 클래스 입니다.
* 이 클래스와 이 클래스의 서브 클래스는 chained exception 기능을 제공
* chained exception 기능은 원래 문제를 이 클래스나 이 클래스의 서브 클래스로
* 감싸서 다시 실행 할 수 있습니다.
* 이 클래스는 exception을 List로 관리 함으로서 다중 예외 처리가 가능 합니다.
*/
public class BaseException extends Exception{
protected Throwable rootCause = null;
//예외를 여러 개 관리하고 나중에 ActionError를 만들 때도 반영
private List exceptions = new ArrayList( );
private String messageKey = null;
private Object[] messageArgs = null;
public BaseException( ){
super();
}
//생성자
public BaseException( Throwable rootCause ) {
this.rootCause = rootCause;
}
public List getExceptions( ) {
return exceptions;
}
public void addException( BaseException ex ){
exceptions.add( ex );
}
public void setMessageKey( String key ){
this.messageKey = key;
}
public String getMessageKey( ){
return messageKey;
}
//어떤 메시지는 아규먼트가 여러 개 일 수 있습니다.
// 예를들면 나이는 0 ~ 99 사이의 수가 들어와야 합니다.
public void setMessageArgs( Object[] args ){
this.messageArgs = args;
}
public Object[] getMessageArgs( ){
return messageArgs;
}
public void setRootCause(Throwable anException) {
rootCause = anException;
}
public Throwable getRootCause( ) {
return rootCause;
}
public void printStackTrace( ) {
printStackTrace(System.err);
}
public void printStackTrace(PrintStream outStream) {
printStackTrace(new PrintWriter(outStream));
}
public void printStackTrace(PrintWriter writer) {
super.printStackTrace(writer);
if ( getRootCause( ) != null ) {
getRootCause( ).printStackTrace(writer);
}
writer.flush( );
}
}
------------------------------
8. struts-config.xml
------------------------------
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts-config PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 1.1//EN" "http://jakarta.apache.org/struts/dtds/struts-config_1_1.dtd">
<struts-config>
<!-- ============ Form Bean Definitions ======================== -->
<form-beans>
<form-bean name="EmpForm" type="logic.EmpForm">
<form-property name="deptno" type="java.lang.String" />
</form-bean>
</form-beans>
<!-- ========== Global Forward Definitions ================ -->
<global-forwards>
<forward name="usersuccess" path="/logic/emplist.jsp" />
</global-forwards>
<!-- ========== Action Mapping Definitions ================ -->
<action-mappings>
<action
path="/EmpSubmit"
type="logic.DisplayAllUserAction"
name="EmpForm"
validate="false"
input="/logic/emp.jsp"
/>
</action-mappings>
<!-- 아래는 스트러츠 Application에서 사용할 Message Resource들을 설정 -->
<message-resources parameter="resources.application"/>
</struts-config>
------------------------------
9. application.properties
-----------------------------
user.depttitle=DEPTNO
jdbc.error=SAVE FAIL!!!
###############################################3
errors.header=<h3><font color="red">ERROR!</font></h3>
You must correct the following error(s) before proceeding:<UL>
errors.footer=</ul><hr>
------------------------------
10. NewActionServlet.java
------------------------------
package logic;
import javax.servlet.ServletException;
import javax.servlet.ServletConfig;
import org.apache.struts.action.ActionServlet;
//Connection Pool
import com.bitmechanic.sql.*;
public class NewActionServlet extends ActionServlet {
private ConnectionPoolManager cpm;
/*
* poolAias는 커넥션 풀을 별칭(Alias)를 줘서 여러 개의 풀을 이용할 수 있게 해줍니다.
* 이 값을 잘 기억하였다가 LoginDAO.java에서 실제 커넥션을 수립할때 인자로 줘야 합니다.
*/
private String POOL_ALIAS = "wink";
private String JDBC_DRIVER = "oracle.jdbc.driver.OracleDriver"; // driver
private String DB_URL = "jdbc:oracle:thin:@localhost:1521:WINK"; // url
private String DB_USER = "SCOTT"; // id
private String DB_PASSWORD = "TIGER"; // pw
private int REAP_CONN_INTERVAL = 300; // 여기서부터는 bitmechanic 을 위한 환경 설정 값
/* 커넥션 풀에 담을 수 있는 커넥션의 최대 수 */
private int MAX_CONNECTION = 20;
/* idleTimeout은 ConnectionPoolManager가 그 간격으로 수행을
* 하게 되므로 적당한 시간을 설정하면 됩니다.
* (데이터베이스의 불필요한 Open Session 수를 줄일 수 있슴)
*/
private int IDLE_TIMEOUT = 60;
/* checkoutTimeout은 너무 짧게 설정해도 안되는게 정상적인 query 수행시간이 길다면
* 정상적으로 작동하는 query 수행 중에 Connection을 Reaping(제거)해 버리므로
* 최대의 쿼리 수행 시간보다 크게 설정해야 합니다.
* 즉 풀에서 나갔다가 돌아오는 시간의 Timeout 설정
*/
private int CHECKOUT_TIMEOUT = 60;
//Checkout의 최대 수를 지정 합니다
private int MAX_CHECKOUT = 15;
public void init(ServletConfig config) throws ServletException
{
try
{
Class.forName(JDBC_DRIVER);
cpm = new ConnectionPoolManager(REAP_CONN_INTERVAL);
cpm.addAlias(POOL_ALIAS,JDBC_DRIVER,DB_URL,DB_USER,DB_PASSWORD,MAX_CONNECTION,IDLE_TIMEOUT,CHECKOUT_TIMEOUT, MAX_CHECKOUT);
// connection pool 생성 후에 부모 class의 init method 연속 수행
super.init(config);
}
catch ( Exception e1 )
{
e1.printStackTrace();
}
}
}
----------------------
12. web.xml
----------------------
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE web-app
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
<display-name>Welcome to Tomcat</display-name>
<description>
Welcome to Tomcat
</description>
<!-- Struts Tag Library Descriptors -->
<taglib>
<taglib-uri>/WEB-INF/struts-bean.tld</taglib-uri>
<taglib-location>/WEB-INF/struts-bean.tld</taglib-location>
</taglib>
<taglib>
<taglib-uri>/WEB-INF/struts-html.tld</taglib-uri>
<taglib-location>/WEB-INF/struts-html.tld</taglib-location>
</taglib>
<taglib>
<taglib-uri>/WEB-INF/struts-logic.tld</taglib-uri>
<taglib-location>/WEB-INF/struts-logic.tld</taglib-location>
</taglib>
<servlet>
<servlet-name>action</servlet-name>
<servlet-class>logic.NewActionServlet</servlet-class>
<init-param>
<param-name>config</param-name>
<param-value>/WEB-INF/struts-config.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<!-- ActionServlet Mapping ====================================-->
<servlet-mapping>
<servlet-name>action</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
</web-app>
댓글 없음:
댓글 쓰기