전자정부프레임워크 transaction 및 예외처리 방법
어제 예외처리 부분에 많은 문제점이 있었다 따라서 해당 부분을 수정해서 공유하도록 한다.
- transaction 부분
spring에서 transaction 은 여러종류가 있었습니다. 알아보니
JPA, JTA, 그리고 전자정부에서 해주는 JDBC에서 처리
그리고 전역적인지 선언적인지 하는 방법도 있었는데
이번에는 전역적인 방법이고 전자정부에서 default로 주는 그런 transaction 방법을 공유드립니다.
egovframwork.spring.com
context-transaction.xml 생성 후
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
<?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:aop=”http://www.springframework.org/schema/aop”
xmlns:tx=”http://www.springframework.org/schema/tx”
xsi:schemaLocation=”http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<bean id=”txManager” class=”org.springframework.jdbc.datasource.DataSourceTransactionManager”>
<property name=”dataSource” ref=”egov.dataSource”/>
</bean>
<tx:advice id=”txAdvice” transaction-manager=”txManager”>
<tx:method name=”insert*“ propagation=”REQUIRED” rollback-for=”Exception”/>
<tx:method name=”update*“ propagation=”REQUIRED” rollback-for=”Exception”/>
<tx:method name=”delete*“ propagation=”REQUIRED” rollback-for=”Exception”/>
</tx:attributes>
</tx:advice>
<aop:pointcut id=”txRequired”
expression=”execution( egovframework.com..Impl.*(..)) or
execution( mngwserc.com..Impl.*(..))”/>
<aop:advisor advice-ref=”txAdvice” pointcut-ref=”txRequired” />
</aop:config>
</beans>
와 같이 설정했습니다.
transaction 설정 부분은
http://snoopy81.tistory.com/332
블로그 참조 부탁 드립니다.
하여 위의 내용을 정리해보자면
try{}catch 문 안에서 UnknownErrorException 발생시에 앞전에 있었던 db 내용을 롤백 시키겠다는 겁니다.
UnknownErrorException <– 은 제가 따로 만들어놓은 예외 Exception 입니다.
이유는 view페이지로 이동 후 meassage를 보여주기 위한 것입니다.
- 위의 내용을 바탕으로 *ServiceImpl.class 에서의 예외처리 방법.
전일 말씀드렸던 파일 용량 초과 부분과 더불어 위에 소개했던 transaction 부분 처리까지 하여 공유 드릴려고 합니다.
일단 제가만든 설문조사 쪽 정보 입력 부분 입니다.
전일 말씀드렸던 서비스단 처리 부분을 다시 리턴 타입이 없는 void로 변경 한 뒤
예외사항 처리를 Exception으로 관리하도록 변경하였습니다.
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
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
public void insertSurveyInfo(final MultipartHttpServletRequest multiRequest, ModelMap modelMap) throws Exception{
//로직 처리는 이곳에서 한다.
SurveyVO param = new SurveyVO(); // 인서트에 사용될 VO를 선언해준다.
try{
//첨부파일 업로드
final Map<String, MultipartFile> files = multiRequest.getFileMap();
if(!files.isEmpty()){
List
String attach_file_id = null;
int limitFileSize = Integer.parseInt(EgovProperties.getProperty(“Globals.SurveyImageSize”));
atchFileId = fileUtil.parseFileInf(files, ””, 0, ””, ”Globals.fileStorePath”, ”attfile”, limitFileSize); // 파일 아이디
if(atchFileId.size() > 0)
{
attach_file_id = fileMngService.insertFileInfs(atchFileId);
}
if(atchFileId.size()==0){
throw new FileSizeExceedException(“파일 용량 초과”);
}
if(attach_file_id != null){
FileVO vo = new FileVO();
vo.setFileCn(param.getFILE_CN());
// FILE_CN 대체 텍스트 업데이트 실시.
fileDAO.updateImageFileCn(vo); // 대체 텍스트 업데이트
}
}
param.setSC_IDX(SC_IDX.getNextIntegerId()); // MASTER ID 값 셋팅
//param.setSC_IDX(1); // 예외를 발생하기 위한 idx 값 셋MASTER ID 값 셋팅
param.setTITLE(EgovStringUtil.nullConvert(multiRequest.getParameter(“TITLE”)));
param.setSTARTDATE(EgovStringUtil.nullConvert(multiRequest.getParameter(“STARTDATE”)));
param.setENDDATE(EgovStringUtil.nullConvert(multiRequest.getParameter(“ENDDATE”)));
param.setPURPOSE(EgovStringUtil.nullConvert(multiRequest.getParameter(“PURPOSE”)));
param.setUSEUSERINFO(EgovStringUtil.nullConvert(multiRequest.getParameter(“USEUSERINFO”)));
param.setDUPLICATE(EgovStringUtil.nullConvert(multiRequest.getParameter(“DUPLICATE”)));
param.setJOBS(EgovStringUtil.nullConvert(multiRequest.getParameter(“JOBS”)));
param.setSTOP_YN(EgovStringUtil.nullConvert(multiRequest.getParameter(“STOP_YN”)));
param.setALWAYS_YN(EgovStringUtil.nullConvert(multiRequest.getParameter(“ALWAYS_YN”)));
param.setSHOW_YN(EgovStringUtil.nullConvert(multiRequest.getParameter(“SHOW_YN”)));
param.setFILE_CN(EgovStringUtil.nullConvert(multiRequest.getParameter(“FILE_CN”)));
param.setATCH_FILE_ID(EgovStringUtil.nullConvert(multiRequest.getParameter(“ATCH_FILE_ID”)));
// 사용자 정보
HttpSession session = multiRequest.getSession(false);
if(session != null){
LoginVO user = (LoginVO)session.getAttribute(“loginVO”);
param.setREGIP(user.getIp());
param.setREGNAME(user.getName());
param.setREGID(user.getId());
}
// 문제 처리 부분
/*
* 로직 처리는 해당 사항과 같다.
* question (질문 내용은 같은 이름으로 해서 파라미터로 넘어온다.
* 즉 해당 question 갯수가 문제 갯수가 될 수 있다.
* 그리고 해당 문제에 대한 보기 값은
* EXAMPLE_(갯수-1) 한 것이 해당 문제에 대한 보기들이다
* ex) 1번 문제 보기
* => EXAMPLE_0
* 해당 값을 getParameterValues 로 받아서 vo에 1번부터 10번 사이로 담아줄 것이다.
* 단! type 값이 객관식일 경우만!
* 주관식은 QUESTION만 받아준다.
<option value=”R”>객관식(단일선택)</option>
<option value=”C”>객관식(다중선택)</option>
<option value=”T”>주관식(필수입력)</option>
<option value=”E”>객관식(공란허용)</option>
*/
String [] question = multiRequest.getParameterValues(“QUESTION”);
String [] type = multiRequest.getParameterValues(“TYPE”);
String [] example = null;
dao.insertSurveyInfo(param); // 설문 정보 입력
if(1==1){
throw new UnknownErrorException(“강제 예외 Exception 처리”);
}
if(question != null){
// insert 마스터 정보 등록
for(int i = 0; i < question.length ; i++){
param.setSQ_IDX(SQ_IDX.getNextIntegerId()); // 질문 ID값 셋팅
param.setTYPE(type[i]); // 질문 타입
param.setQUESTION(question[i]); // 질의 내용
param.setQUESTIONORDER(i); // 질문 order 값
param.setMAX(0); // 기본 0 셋팅
param.setInitExample(); // 문제 초기화
if(type[i].equals(“R”)){ // 객관식(단일선택)EXAMPLE_2
example = multiRequest.getParameterValues(“EXAMPLE_“+i);
if(example != null){
param.setMAX(example.length); // 문제 갯수 셋팅
for(int j=0; j< example.length; j++){
param.setExample(j, example[j]);
}
}
}
if(type[i].equals(“C”)){ // 객관식(다중선택)
example = multiRequest.getParameterValues(“EXAMPLE_“+i);
if(example != null){
param.setMAX(example.length); // 문제 갯수 셋팅
for(int j=0; j< example.length; j++){
param.setExample(j, example[j]);
}
}
}
// insert 질문 등록
dao.insertSurveyQuestionInfo(param);
}
}
}
catch(FileSizeExceedException fe ){
System.out.println(fe.getMessage());
throw new FileSizeExceedException(“파일 용량초과~!”);
}
catch(Exception e){
e.printStackTrace();
//throw new Exception(“server Error!!”);
throw new UnknownErrorException(“server Error!”);
}
}
해당 메소드를 보시면
-
설문조사 정보 입력.
-
설문조사 문항 정보 입력.
으로 나뉘어집니다.
- 첫번째로 파일 용량 초과에 대한 예외처리 부분
하단에 catch문을 보시면
1
2
3
4
5
6
7
8
9
catch(FileSizeExceedException fe ){
System.out.println(fe.getMessage());
throw new FileSizeExceedException(“파일 용량초과~!”);
}
catch(Exception e){
e.printStackTrace();
//throw new Exception(“server Error!!”);
throw new UnknownErrorException(“server Error!”);
}
**
FileSizeExceedException -> 파일 용량 초과시 Exception 발생 한 뒤에
throw new FileSizeExceedException 떠러트려서
dispatcher-servlet에 선언한 Exception쪽으로 보내버렸습니다(?)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<bean class=”org.springframework.web.servlet.handler.SimpleMappingExceptionResolver”>
<property name=”exceptionMappings”>
<prop key=”java.io.FileNotFoundException”>error/filenotfound</prop>
<prop key=”egovframework.rte.fdl.cmmn.exception.EgovBizException”>egovframework/com/cmm/error/egovBizException</prop>
<prop key=”org.springframework.web.HttpSessionRequiredException”>egovframework/com/uat/uia/EgovLoginUsr</prop>
<prop key=”egovframework.com.cmm.exception.NotPermitException”>error/notpermit</prop>
<prop key=”egovframework.com.cmm.exception.UnknownErrorException”>error/unknown</prop>
<prop key=”egovframework.com.cmm.exception.FileSizeExceedException”>error/filesizeexceed</prop>
</props>
</property>
</bean>
(위는 dispatcher-servlet 쪽 설정임)
jsp 밑으로 하여 error/filesizeexceed.jsp 페이지에서 초과되었다는 alert과 함께 history.back처리하였습니다.
두번째 server 밑 db error 발생시 예외처리
위에 보여드린 insertSurveyInfo 메소드 내용을 보시면
dao.insertSurveyInfo(param); 설문조사 정보 입력 후
1
2
3
if(1==1){
throw new UnknownErrorException(“강제 예외 Exception 처리”);
}
**
강제로 예외를 발생시켜 catch문에 걸리도록 변경하였습니다.
이유는 강제로 예외 발생 시킨 뒤 트렌젝션을 잘하는지 확인하려 걸었습니다.
catch문을 보니
1
2
3
4
5
6
7
8
9
catch(FileSizeExceedException fe ){
System.out.println(fe.getMessage());
throw new FileSizeExceedException(“파일 용량초과~!”);
}
catch(Exception e){
e.printStackTrace();
//throw new Exception(“server Error!!”);
throw new UnknownErrorException(“server Error!”);
}
위와 같이 선언했습니다
Exception 종류중에 fileSizeE.. 익셉션을 먼저 잡고 그 뒤에
Exception 을 잡는데 여기서 Exception은 모든 종류의 예외를 잡겠다는 내용 입니다.
db에서 Error 발생되면 RuntimeException이 발생되고
서버에러 발생하면 그에 따른 여러 Exception이 존재하겠지만,
RuntimeException 과 server에서 발생하는 Error를 동시에 잡겠다는 의미로 해석하시면 됩니다.
그리고 Exception 안에서 UnkownErrorException 이라고 제가 정의해둔 Exception을 발생시켜
메시지 처리 후 history.back 시켜서 다시 작성 페이지로 이동되도록 하였습니다.
이렇게해서 어제 팀장님과 이야기 나누었던 내용을 정리하게 된듯(?) 합니다.