먼저 답을 말하자면 별도 설치할 필요는 없습니다.

정확히는 해당 드라이버 jar 파일만 있으면 별도로 설치 할 필요는 없습니다.

 

DBMS 접속 시 사용되는 방식은 Thin 방식과 OCI 방식이 존재합니다. 

 

 

THIN 방식이라고 말하면 생소할 수 있는데 아래 예시처럼 Java 개발시 사용되는 문법의 경우 해당됩니다.

 

String driver = "oracle.jdbc.driver.OracleDriver";
String url = "jdbc:oracle:thin:@111.111.111.1:1521:dbsid";
.....
...
.

 

THIN방식은 순수하게 자바 패키지(클래스들)만으로 바로 DB와 연결하므로 범용성이 높습니다.

( OCI 방식은 플렛폼에 영향을 많이 받는데 비해.. )

상대적으로 OCI보다 속도가 느리긴 하지만 크게 느껴지는 정도는 아닙니다.(수행되는 작업에 따라 다를 수 있음)

 

 

다만 오라클클라이언트를 설치하게 되면 SQL*PLUS 같은 프로그램이 설치되기 때문에 필요할 수 있습니다. 

 

하지만 별도로 DB 접속을 하게되는 토트, 오렌지 등에서는 Oracle Clinet 설치가 필요합니다.

 

 

 

1. 개요

- iReport란?

iReportJasperReports 라이브러리를 통해 모든 종류의 Java 응용에 사용할 수 있고, 복잡한 보고서를 생성하는 오픈 소스 프로그램이다. 이 iReport는 100% Java로 구현됐으며, GNU (General Public License)에서 소스 코드를 배포한다.

 

iReport는 그래픽 인터페이스를 통해 어떤 종류의 복잡한 보고서도 간단하고 빠르게 생성할 수 있고, JasperReportsXML 문법을 공들여 배우지 않아도 개발 시간을 단축해 개발자에게 큰 도움을 준다.

 

즉,  iReportJasperReports를 위한 Reports Design Tool이라고 할 수 있다.

 

다운로드 서비스는 아래 사이트에서 이용할 수 있다.(무료

https://sourceforge.net/projects/ireport/

 

iReport-Designer for JasperReports

Download iReport-Designer for JasperReports for free. NOTE: iReport/Jaspersoft Studio Support Announcement: As of version 5.5.0, Jaspersoft Studio will be the official design client for JasperReports. iReport will remain as a supported product in maintenan

sourceforge.net

 

2. iReport 설치 및 실행

    a. 다운로드한 파일을 압축을 해제 

    b. 압축을 해제 한 디렉터리 하위의 bin 폴더의 ireport.exe 파일을 실행

 

 

3. iReport UI 설명

[iReport UI Layout

4. iReport 환경설정

    4-1. Class path 설정

        Tools의 Options window를 오픈하여 아래 그림과 같이 설정합니다. 

    

    4-2. Compile 경로 설정

        iReport는 컴파일된 .jasper 파일을 사용하여 서비스가 제공됩니다. 따라서 Complie path를 설정하여 서비스되는

        시스템에 자동으로 저장될 수 있도록 설정하는 편이 업무에 도움이 됩니다.

컴파일 된 jasper파일 경로 설정

    4-3. Database 연동

        iReport는 DB와 직접 통신하여 데이터를 질의하고 출력 할 수 있습니다. 해당 기능을 사용하기 위해서 먼저 JDBC

        연결 설정을 수행합니다.

 

이상으로 iReport 설정 방법을 알아보았습니다. 

 

Exception sending context initialized event to listener instance of class org.springframework.web.context.ContextLoaderListener

 

 

톰켓 실행할때 해당 오류를 만날 수 있습니다. 

 

이유는 간단합니다. 라이브러리에 runtime 라이브러리가 추가되지 않아서 발생한 Exception 입니다.

 

 

 

 

 

 

 

일반적으로 이미지 타입이 RGB가 아닌 CMYK인 경우 


ImageIO.read() 를 이용하여 읽을 경우  Unsupported Image Type 가 발생한다.


일반적으로 CMYK타입 이미지는  ImageIO 로 read 하기 불가능하다




ImageIO.read(file); 를 이용해서 Exception이 발생할 경우 컨버터를 이용하여 처리하는 방식을 이용하여 오류를 줄일 수 있다. 



converter_Lib.zip



converter_Lib.zip의 icc 파일은 Cmyk2RgbConverter와 동일한 경로에 위치하면 된다. 



< Cmyk2RgbConverter.java >


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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
public class Cmyk2RgbConverter {
 
    public static final int TYPE_RGB = 1;
    public static final int TYPE_CMYK = 2;
    public static final int TYPE_YCCK = 3;
 
    private static int colorTp = TYPE_RGB;
    private static boolean markerFlag = false;
 
 
 
    public static BufferedImage readImage(File file) throws IOException, ImageReadException {
        colorTp = TYPE_RGB;
        markerFlag = false;
 
        ImageInputStream stream = ImageIO.createImageInputStream(file);
        Iterator < itor_imgReader > iter = ImageIO.getitor_imgReaders(stream);
        while (iter.hasNext()) {
            itor_imgReader reader = iter.next();
            reader.setInput(stream);
 
            BufferedImage image;
 
            ICC_pf pf = null;
            try {
                image = reader.read(0);
                
                reader.reset();
            } catch (IIOException e) {
                colorTp = TYPE_CMYK;
                checkMarker(file);
                pf = Sanselan.getICCpf(file);
                Writablewr wr = (Writablewr) reader.readwr(0null);
 
                
                reader.reset();
 
                if (colorTp == TYPE_YCCK) {
                    convertYcck2Cmyk(wr);
                }
 
                if (markerFlag) {
                    convInvColors(wr);
                }
                image = convertCmykToRgb(wr, pf);
                image.flush();
            } finally {
                stream.close(); 
            }
 
            return image;
        }
 
        return null;
    }
 
    public static void checkMarker(File file) throws IOException, ImageReadException {
        JpegImageParser parser = new JpegImageParser();
        ByteSource byteSource = new ByteSourceFile(file);
        @SuppressWarnings("rawtypes")
        ArrayList segments = parser.readSegments(byteSource, new int[] {
            0xffee
        }, true);
        if (segments != null && segments.size() >= 1) {
            UnknownSegment app14Segment = (UnknownSegment) segments.get(0);
            byte[] data = app14Segment.bytes;
            if (data.length >= 12 && data[0== 'A' && data[1== 'd' && data[2== 'o' && data[3== 'b' && data[4== 'e') {
                markerFlag = true;
                int transform = app14Segment.bytes[11& 0xff;
                if (transform == 2)
                    colorTp = TYPE_YCCK;
            }
        }
    }
 
    public static void convertYcck2Cmyk(Writablewr wr) {
        int height = wr.getHeight();
        int width = wr.getWidth();
        int stride = width * 4;
        int[] rowData = new int[stride];
        for (int h = 0; h < height; h++) {
            wr.getPixels(0, h, width, 1, rowData);
 
            for (int x = 0; x < stride; x += 4) {
                int y = rowData[x];
                int cb = rowData[x + 1];
                int cr = rowData[x + 2];
 
                int c = (int)(y + 1.402 * cr - 178.956);
                int m = (int)(y - 0.34414 * cb - 0.71414 * cr + 135.95984);
                y = (int)(y + 1.772 * cb - 226.316);
 
                if (c < 0)
                    c = 0;
                else if (c > 255)
                    c = 255;
                if (m < 0)
                    m = 0;
                else if (m > 255)
                    m = 255;
                if (y < 0)
                    y = 0;
                else if (y > 255)
                    y = 255;
 
                rowData[x] = 255 - c;
                rowData[x + 1= 255 - m;
                rowData[x + 2= 255 - y;
            }
 
            wr.setPixels(0, h, width, 1, rowData);
        }
    }
 
    public static void convInvColors(Writablewr wr) {
        int height = wr.getHeight();
        int width = wr.getWidth();
        int stride = width * 4;
        int[] rowData = new int[stride];
        for (int h = 0; h < height; h++) {
            wr.getPixels(0, h, width, 1, rowData);
            for (int x = 0; x < stride; x++)
                rowData[x] = 255 - rowData[x];
            wr.setPixels(0, h, width, 1, rowData);
        }
    }
 
    public static BufferedImage convertCmykToRgb(wr cmykwr, ICC_pf cmykpf) throws IOException {
 
        if (cmykpf == null) {
            cmykpf = ICC_pf.getInstance(CMYKConverter.class.getResourceAsStream("ISOcoated_v2_300_eci.icc"));
        }
 
        ICC_ColorSpace cmykCS = new ICC_ColorSpace(cmykpf);
        BufferedImage rgbImage = new BufferedImage(cmykwr.getWidth(), cmykwr.getHeight(), BufferedImage.TYPE_INT_RGB);
        Writablewr rgbwr = rgbImage.getwr();
        ColorSpace rgbCS = rgbImage.getColorModel().getColorSpace();
        ColorConvertOp cmykToRgb = new ColorConvertOp(cmykCS, rgbCS, null);
        cmykToRgb.filter(cmykwr, rgbwr);
        return rgbImage;
    }
 
    public static void intToBigEndian(int value, byte[] array, int index) {
        array[index] = (byte)(value >> 24);
        array[index + 1= (byte)(value >> 16);
        array[index + 2= (byte)(value >> 8);
        array[index + 3= (byte)(value);
    }
 
}
 
cs



일반적으로 Database Connection을 가져오지 못하면 Cannot create PoolableConnectionFactory  Exception이 발생한다.


그리고 쿼리작성 문법에 오류가 나면 (ORA-00923: FROM 키워드가 필요한 위치에 없습니다.) 등의 오류가 발생한다.


근데 DB에 연결도 못했는데 문법오류가 나는 경우가 있다.


물론 연결 접속정보나 이런것들 방화벽 다 확인해보았지만 모두다 정상인 상태이다.


org.apache.commons.dbcp.SQLNestedException: Cannot create PoolableConnectionFactory (ORA-00923: FROM 키워드가 필요한 위치에 없습니다.)


이경우는 Spring Framework의 설정부분 중 validationQuery를 확인해 보아야한다. 


환경설정을 할 때 DB 종류가 바뀌는 경우 접하는 경우가 대부분이다.


1
2
3
4
5
6
7
8
 
 
// HashSet과 LinkedHashSet의 차이는 중복이 제거 될 때 HashSet은 기존 리스트의 구성요서의 순서가 지켜지지 않는다 
 
List<String> uniqueItems = new ArrayList<String>(new HashSet<String>(returnitems));
 
 
List<String> uniqueItems = new ArrayList<String>(new LinkedHashSet<String>(returnitems));
cs


 

List에 내용물이 String이나 int가 아닌 경우 정렬

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
 
ArrayList<HashMap<StringString>> items = new ArrayList<HashMap<StringString>>();
 
 
Collections.sort(items, new Comparator<HashMap<StringString>>() {
            @Override
            public int compare(HashMap<StringString> first, HashMap<StringString> second) {
                
                int firstValue = Integer.valueOf(first.get("ORDER_BY"));
                int secondValue = Integer.valueOf(second.get("ORDER_BY"));
 
                if (firstValue > secondValue) {
                    return -1;
                } else if (firstValue < secondValue) {
                    return 1;
                } else /* if (firstValue == secondValue) */ {
                    return 0;
                }
                
            }
        });
cs

 

 

물론 비교를 compareTo로 해도 되긴하는데 내경 우에는 700 60 500의 값이 비교될 때 

 

60이 500보다 우선순위로 정렬되는 기이현상으로 인하여 

 

if else if로 구현하였음

※ Spring Frame Work 3.2 기준 실제 사용 했던 Servlet.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
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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
<?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:context="http://www.springframework.org/schema/context"
    xmlns:jee="http://www.springframework.org/schema/jee" 
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:mvc="http://www.springframework.org/schema/mvc" 
    xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:util="http://www.springframework.org/schema/util" 
    xmlns:task="http://www.springframework.org/schema/task" 
    xsi:schemaLocation="http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.2.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
        http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd 
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
        http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.2.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd
        http://www.springframework.org/schema/task
        http://www.springframework.org/schema/task/spring-task-3.2.xsd">
        
 
 
 
    <!-- The controllers are autodetected POJOs labeled with the @Controller, @Service, @Component annotation. -->
    <!-- @Controller, @Service, @Component annotation 아래의 package를 스켄하여 @Autowired 
        어노테이션을 이용하여 해당하는 엔티티 및 서비스를 맵핑한다. -->
    <!-- <context:component-scan base-package="com.isource.web.controller, com.isource.domain.service, 
        com.isource.web.validator, com.isource.web.security"/> -->
        
        
        
        
    
    <context:component-scan base-package="com.myPackage.web" />
    <mvc:resources location="/WEB-INF/resources/" mapping="/resources/**" />
 
 
    <context:annotation-config></context:annotation-config>
<!--     <task:executor id="taskExecutor" pool-size="5"/>
    <task:annotation-driven executor="taskExecutor"/> -->
    
    
 
    <!-- Annotation 기반 트랜잭션 설정 -->
    <tx:annotation-driven transaction-manager="oracleTransactionManager" />
 
    <!-- 트랜잭션 매니저 -->
    <bean id="oracleTransactionManager"
        class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource" />
    </bean>
 
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="configLocation" value="classpath:/mybatis/mybatisConfig.xml" />
        <property name="mapperLocations" value="classpath:/mybatis/sql/**/*.xml" />
    </bean>
 
    <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
        <constructor-arg index="0" ref="sqlSessionFactory" />
    </bean>
    <bean id="sqlBatchSession" class="org.mybatis.spring.SqlSessionTemplate">
        <constructor-arg index="0" ref="sqlSessionFactory" />
        <constructor-arg index="1" value="BATCH" />
    </bean>
 
    <bean id="anotherTransactionManager"
        class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="anotherDataSource" />
    </bean>
 
    <bean id="anotherSqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="anotherDataSource" />
        <property name="configLocation" value="classpath:/mybatis/mybatisConfig_another.xml" />
        <property name="mapperLocations" value="classpath:/mybatis/sql_another/**/*.xml" />
    </bean>
 
    <bean id="anotherSqlSession" class="org.mybatis.spring.SqlSessionTemplate">
        <constructor-arg index="0" ref="anotherSqlSessionFactory" />
    </bean>
    
    <bean id="anotherBatchSqlSession" class="org.mybatis.spring.SqlSessionTemplate">
        <constructor-arg index="0" ref="anotherSqlSessionFactory" />
        <constructor-arg index="1" value="BATCH" />
    </bean>
 
    <!-- Validation 활성화(validator="validator"), conversionService 활성화, 메세지 컨버터 
        등록 (JSON을 바꿔주는부분) -->
    <mvc:annotation-driven conversion-service="conversionService">
        <mvc:message-converters>
            <bean
                class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
                <property name="objectMapper">
                    <bean class="com.myPackage.web.converter.CustomObjectMapper" />
                </property>
            </bean>
            <bean class="org.springframework.http.converter.StringHttpMessageConverter">
                <property name="supportedMediaTypes">
                    <list>
                        <value>text/html;charset=UTF-8</value>
                    </list>
                </property>
            </bean>
        </mvc:message-converters>
    </mvc:annotation-driven>
 
    <mvc:interceptors>
        <mvc:interceptor>
            <mvc:mapping path="/**" />
            <mvc:exclude-mapping path="/login**" />
            <mvc:exclude-mapping path="/login*" />
            <mvc:exclude-mapping path="/loginform**" />
            <mvc:exclude-mapping path="/resources/**" />
            <mvc:exclude-mapping path="/*.ico" />
            <bean class="com.isource.web.controller.IsourceInterceptor" />
        </mvc:interceptor>
 
        <bean id="localeChangeInterceptor"
            class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor">
            <property name="paramName" value="convertLocale" />
        </bean>
    </mvc:interceptors>
    
    
    <bean id="localeResolver"
        class="org.springframework.web.servlet.i18n.SessionLocaleResolver">
        <property name="defaultLocale" value="ko" />
    </bean>
    
 
    <!-- Configure the multipart resolver -->
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
            <!-- one of the properties available; the maximum file size in bytes about 
            10MB -->
        <property name="maxUploadSize" value="10000000" />
    </bean>
    <alias name="multipartResolver" alias="multipartResolver" />
 
    <!-- Configure the file upload directory -->
    <!-- <bean id="uploadDirResource" class="org.springframework.core.io.FileSystemResource"> 
        <constructor-arg> <value>C:/myPackage/upload/</value> </constructor-arg> </bean> -->
 
    <!-- tiles 2에서 전부처리되어 주석처리됨. <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" p:order="2" p:prefix="/WEB-INF/views/" p:suffix=".jsp"/> -->
 
    <bean id="tilesViewResolver" class="org.springframework.web.servlet.view.UrlBasedViewResolver" p:order="1" p:viewClass="org.springframework.web.servlet.view.tiles2.TilesView" />
    <bean class="org.springframework.web.servlet.view.tiles2.TilesConfigurer" id="tilesConfigurer">
        <property name="definitions">
            <list>
                <value>/WEB-INF/tiles/tiles-def.xml</value>
            </list>
        </property>
    </bean>
 
    <!-- @Valid 에서 스프링의 Message.properties를 사용하기 위해 추기 -->
    <bean id="validator"
        class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
        <property name="validationMessageSource" ref="messageSource" />
    </bean>
 
    <!-- Message -->
    <bean id="messageSource"
        class="com.myPackage.extendz.IscReloadableResourceBundleMessageSource">
        <!-- class="org.springframework.context.support.ReloadableResourceBundleMessageSource"> -->
        <property name="defaultEncoding" value="UTF-8" />
        <property name="basenames">
            <list>
                <value>classpath:/messages/messages</value>
                <value>classpath:/messages/buttons</value>
                <value>classpath:/messages/labels</value>
            </list>
        </property>
    </bean>
 
    <!-- Exception 처리 -->
    <bean
        class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver">
        <property name="order" value="1" />
    </bean>
    
    
    <bean
        class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
        <property name="order" value="2" />
        <property name="defaultErrorView" value="/common/error500" />
        <!--.main 은 타일즈 standalone layout 적용 -->
    </bean>
 
 
    <!-- Conversion Service 기본 포멧터 사용 -->
    <bean id="conversionService"
        class="org.springframework.format.support.FormattingConversionServiceFactoryBean" />
 
    <bean id="logDataSource_pos" class="net.sf.log4jdbc.Log4jdbcProxyDataSource">
        <constructor-arg ref="dataSource" />
        <property name="logFormatter">
            <bean class="net.sf.log4jdbc.tools.Log4JdbcCustomFormatter">
                <property name="loggingType" value="MULTI_LINE" />
                <property name="sqlPrefix" value="SQL=>" />
            </bean>
        </property>
    </bean>
 
 
    <!-- Quartz -->
    <bean id="batchService" class="com.myPackage.schedule.quartz.job.service.BatchService" />
    <bean id="sapJcoTransfer" class="com.myPackage.schedule.quartz.job.transfer.SapJcoTransfer" />
    <bean id="procedureTransfer" class="com.myPackage.schedule.quartz.job.transfer.ProcedureTransfer" />
    
 
     <bean name="isourceJob" class="org.springframework.scheduling.quartz.JobDetailFactoryBean" p:jobClass="com.isource.schedule.quartz.job.IsourceQuartzJobBean" p:durability="true">
        <property name="jobDataAsMap">
            <map>
                <entry key="batchService" value-ref="batchService" />
            </map>
        </property>
    </bean>
 
    <!-- <bean id="cronTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerBean" p:jobDetail-ref="isourceJob" p:startDelay="0" p:cronExpression="0/10 * * * * ?" /> -->
    
    <bean id="SimpleTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerFactoryBean">
        <property name="jobDetail" ref="isourceJob" />
        <property name="startDelay" value="0" />
        <property name="repeatInterval" value="604800000" /
    </bean>
    
          
          
          
          
    <bean id="schedulerFactoryBean" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
        <property name="triggers">
            <list>
                <ref bean="SimpleTrigger" />
            </list>
        </property>
    </bean>
    <bean class="com.myPackage.common.util.ApplicationContextAwareExtends"/>
    
    
    
    <bean class="com.myPackage.common.helper.mail.MailSendWorker">
        <constructor-arg>
            <ref bean="naverMailSender" />
        </constructor-arg>
    </bean>
    
    <!-- Gmail setting -->
    <bean name="gmailMailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl"
            p:password="input your password"
            p:host="smtp.gmail.com"
            p:port="587"
            p:protocol="smtp"
            p:username="input your account"
            p:defaultEncoding="utf-8">
        <property name="javaMailProperties">
            <props>
                <prop key="mail.smtp.ssl.enable">false</prop>
                <prop key="mail.smtp.starttls.enable">true</prop>
                <prop key="mail.smtp.ssl.trust">*</prop>
                <prop key="mail.smtp.port">587</prop><!-- mail.smtp.ssl.enable true인 경우 주석처리후 사용 -->
                <prop key="mail.smtp.auth">true</prop>
                <prop key="mail.debug">true</prop>
            </props>
        </property>
    </bean>
    
    <!-- naver setting -->
    <bean name="naverMailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl"
            p:password="input your password" 
            p:host="smtp.naver.com"
            p:port="465"
            p:protocol="smtps" 
            p:username="input your account"
            p:defaultEncoding="utf-8">
        <property name="javaMailProperties">
            <props>
                <prop key="mail.smtp.starttls.enable">true</prop>
                <prop key="mail.smtp.auth">true</prop>
                <prop key="mail.smtp.ssl.enable">true</prop>
                <prop key="mail.smtps.ssl.checkserveridentity">true</prop>
                <prop key="mail.smtps.ssl.trust">*</prop>
                <prop key="mail.debug">false</prop>
            </props>
        </property>
    </bean>
    
    <!-- Local Stmp setting -->
    <bean name="customMailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl"
            p:host="smtp.mailplug.co.kr"
            p:protocol="SSL"
            p:defaultEncoding="utf-8">
        <property name="javaMailProperties">
            <props>
                <prop key="mail.smtp.port">465</prop>
                <prop key="mail.smtp.starttls.enable">false</prop>
                <prop key="mail.smtp.ssl.enable">true</prop>
                <prop key="mail.smtp.ssl.trust">*</prop>
                <prop key="mail.smtp.auth">true</prop>
                <prop key="mail.debug">true</prop>
            </props>
        </property>
        <!-- <property name="username" value="customSTMPUser"/>
        <property name="password" value="customSTMPPassword"/> -->
 
    </bean>
    
 
</beans>
 
cs


 

selectkey를 사용하여 키를 생성하면서 CUD 작업을 진행할 경우 생성한 key를 가져오지 못하는 경우가 있습니다. 

 

이 경우 간단한 이유인데요 보통 개발하실 때 복사하기 붙여 넣기만 하다가 해당 기능의 각 속성들의 기능을 잘 파악하지 못하여 발생하는 문제입니다. 

 

 

<insert id="queryId" parameterType="java.util.Map">
<selectKey keyProperty="id" resultType="java.lang.String">

 

SELECT #{CUODE} ||#{DIE}|| #{I11TH} FROM DUAL

 

</selectKey>

 

MERGE INTO MY_TABLE SM
USING (SELECT #{id} SALES_NO
,#{AA} AA
,#{BB} BB
,#{CC} CC
FROM DUAL) MG
ON
......
....
..

</insert>

 

 

 
위 의 소스의 경우 id 값을 가지고 오지못하고 해당 값이 Not Null 이라면 오라클 익셉션이 발생합니다.
selectkey의 각 속성값을 살펴보면 다음과 같습니다.
 
Attribute Description
keyProperty The target property where the result of the 
selectKey statement should be set.
Can be a comma separated list of property names if multiple generated columns are expected.
keyColumn The column name(s) in the returned result set that match the properties.
Can be a comma separated list of column names if multiple generated columns are expected.
resultType The type of the result. MyBatis can usually figure this out, but it doesn't hurt to add it to be sure.
MyBatis allows any simple type to be used as the key, including Strings.
If you are expecting multiple generated columns, then you can use an Object that contains
the expected properties, or a Map.
order This can be set to BEFORE or AFTER.
If set to BEFORE, then it will select the key first, set the keyProperty and then execute
the insert statement. If set to AFTER, it runs the insert statement and
then the selectKey statement – which is common with databases like Oracle
that may have embedded sequence calls inside of insert statements.
statementType Same as above, MyBatis supports STATEMENTPREPARED and CALLABLE statement types
that map to StatementPreparedStatementand CallableStatement respectively
 
 
 
해당 문제를 해결하기 위해서 확인해야 할 것은 order 속성입니다. 
ORDER 속성은 BEFORE 와 AFTER를 선택할 수 있는데 해당 속성을 정의하지 않을경우 기본값이 AFTER입니다. 
BEFORE는 INSERT 문을 실행하기전 selectkey 구문을 수행하고 AFTER는 INSERT문을 수행한 후 selectkey가 수행됩니다. 
 
즉 올바른 동작을 위해서는 아래 예제와 같이 코드가 작성되어야 합니다. 

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<insert id="queryId" parameterType="java.util.Map">
        <selectKey keyProperty="id" resultType="java.lang.String" order="BEFORE">
        SELECT #{ASDFAS} ||#{SDF}|| #{INVASDFONTH} FROM DUAL
        </selectKey>
        MERGE INTO MY_TABLE SM
        USING (SELECT #{id} SALES_NO
                     ,#{AA} AA
                     ,#{BB} BB
                     ,#{CC} CC
                 FROM DUAL) MG 
           ON
        ......
        ....
        ..
<insert>
cs

 

Mybatis를 이용하여 프로젝트 진행 시 아래와 같은 Exception이 발생하는 경우가 있습니다. 



java.sql.SQLException: 허용되지 않은 작업



이 경우는 sqlSession 객체가 배치타입으로 설정되어 있어서 프로시저를 호출 할 수 없는 경우입니다. 


mybatis의 배치 관련 설정하는 곳은 대표적으로 두군대를 볼 수 있습니다. 


각 설정 파일은 환경에 따라 파일명이 상이 할 수 있으므로 아래와 같이 설명하도록 하겠습니다. 


1. 스프링 설정 xml 

  <bean id="sqlBatchSession" class="org.mybatis.spring.SqlSessionTemplate">

<constructor-arg index="0" ref="sqlSessionFactory" />

<constructor-arg index="1" value="BATCH" />

</bean> 



붉은색 항목이 존재할 경우 모든 DB관련 작업은 배치 형태로 수행하게 됩니다. (ibatis의 executeBatch 와 동일)  

해당 부분을 삭제 하면 정상적으로 프로시저 호출이 가능합니다. 


2. mybatis 설정 xml 

  <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">

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

<property name="configLocation" value="classpath:/mybatis/mybatisConfig.xml" />

<property name="mapperLocations" value="classpath:/mybatis/sql/**/*.xml" />

</bean> 


붉은색 부분에 설정한 Mybatis 설정파일의 내용을 확인해 볼 필요가 있습니다. 


<?xml version="1.0" encoding="UTF-8" ?>

<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "HTTP://mybatis.org/dtd/mybatis-3-config.dtd">


<configuration>

<settings>

<setting name="cacheEnabled" value="true" />

<setting name="jdbcTypeForNull" value="VARCHAR"/>

<setting name="defaultExecutorType" value="BATCH"/>

</settings>

<!-- Type aliases -->

<typeAliases />


<!-- Mappers -->

<mappers />

</configuration> 


붉은색으로 표시된 설정항목이 존재할 경우 스프링 설정.xml에서 <constructor-arg index="1" value="BATCH" /> 가 없더라도 배치형태로 수행 하게 됩니다. 


sqlSession 객체를 일반 형태와 배치형태로 두개의 빈을 등록해 사용하길 권장드립니다. 


당연히 배치관련 옵션은 스프링설정.xml에서 배치형태로 설정하시고 Mybatis설정 파일에서는 해당 설정값을 제거 하시고 사용하시는걸 추천드립니다. 



스프링설정.xml에서 관리하는 내용의 예제 소스

<bean id="oracleTransactionManager"

class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

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

</bean>


<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">

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

<property name="configLocation" value="classpath:/mybatis/mybatisConfig.xml" />

<property name="mapperLocations" value="classpath:/mybatis/sql/**/*.xml" />

</bean>


<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">

<constructor-arg index="0" ref="sqlSessionFactory" />

</bean>

<bean id="sqlBatchSession" class="org.mybatis.spring.SqlSessionTemplate">

<constructor-arg index="0" ref="sqlSessionFactory" />

<constructor-arg index="1" value="BATCH" />

</bean>




+ Recent posts