X-internet파일처리
From JCFWiKi
Copyright © 2007 Daewoo Information Systems Co., Ltd. |
|
여기서는 x-internet 기반으로 파일을 DB에 BLOB 형태로 관리할 때 사용되는 기술과 사용하는 방법에 대해서 설명합니다. |
목차 |
[편집] Miplatform에서 파일 업로드 처리
Copyright © 2007 Daewoo Information Systems Co., Ltd. |
Miplatform과 JCF를 연동하여 파일 업로드를 처리하기 위해서 다음과 같은 단계를 통해 구현할 수 있다. 아래의 처리방법은 위에 제시된 환경정보에 따라 약간의 변동사항이 발생할 수 있다. 따라서 구현 이전에 환경정보를 필수적으로 확인하는 것이 중요하다.
* 파일 업로드 처리방법 1. Client tier (Miplatform) 구현 및 설정 2. BLOB 데이터 처리를 위한 Model 구성 3. Action 및 struts*.xml 구성 4. Service, Dao 그리고 applicationContext*.xml 구성 5. SqlMap 구성 6. 테스트 및 실행
[편집] Client tier (Miplatform) 구현 및 설정
Miplatform에서 DB에 파일을 BLOB 형태로 업로드하고 저장된 파일을 조회하여 image 컴포넌트에 출력해 주는 JCF 기반의 프로그램를 구현할 것이다. 우선 화면을 구성하고 파일을 처리하기 위해 컴포넌트와 데이터셋을 다음과 같이 설정한다.
[편집] 컴포넌트, 데이터셋 설정
1.이미지파일이 들어가는 DATESET의 column의 type을 BLOB으로 지정한다.
<Dataset DataSetType="Dataset" Id="DS_DEPT"> <Contents> <colinfo id="deptCode" size="50" type="STRING"/> <colinfo id="deptName" size="50" type="STRING"/> <colinfo id="maxCnt" size="10" type="INT"/> <colinfo id="univ" size="50" type="STRING"/> <colinfo id="fileName" size="100" type="STRING"/> <colinfo encrypt="base64" id="proImage" size="256" type="BLOB"/> </Contents> </Dataset>
2. 이미지를 화면에 삽입하고 ,propertis를 다음과 같이 지정한다.
(1) 이미지 컴포넌트를 화면에 삽입한다. 예) Image Component : 이미지 컴포넌트를 폼에 Drag & Drop으로 가져온다.
(2) 삽입된 이미지 컴포넌트에 해당되는 Dateset을 바인딩한다. 예) BindDataset = DS_DEPT (BLOB형의 파일처리를 위한 데이터셋)
(3) 삽입된 이미지 컴포넌트에 해당되는 Dateset의 Column을 바인딩한다. 예) Column = PROIMAGE (BLOB으로 지정된 데이터셋의 컬럼명)
(4) 이미지의 크기를 autofited 하고 싶다면 FileType을 STRETCH으로 지정한다. 예) FillType = STRETCH
(5) 여기서는 버튼으로 이미지를 삽입하지만, 이미지 컴포넌트를 클릭하며 이미지를 삽입하고 싶다면 Static을 false로 지정한다.
예) Static = False (이미지 컴포넌트에 function을 적용하여 다이나믹한 액션을 부여할 경우에 False로 설정)
3. 파일업로드에 대한 컴포넌트를 화면에 삽입한다.
(1) 파일 업로드를 위해 로컬에 있는 파일을 선택할 수 있는 팝업 창을 제공하는 File Dialog 컴포넌트를 폼에 가져온다. (2) File Dialog를 통해 선택된 로컬 파일을 임시도 저장하기 위한 File 컴포넌트를 폼에 가져온다. (3) 파일을 데이터셋에 지정된 BLOB 형태로 서버의 Action에 전달하기 위한 액션버튼을 구성한다.
[편집] 파일 업로드 화면 스크립트 작성
파일 업로드를 위해 화면에서 두 가지 이벤트를 제공한다.
#파일첨부버튼 클릭 시 파일 다이얼로그 박스가 출력되어 파일 업로드가 가능하도록 한다. #이미지 컴포넌트 클릭 시 파일 다이어로그 박스가 출력되어 파일 업로드가 가능하고록 한다.
- 다음과 같이 스크립트를 작성하고, 파일첨부버튼과 이미지 컴포넌트에 OnClick 이벤트로 지정한다.
//============================================================================== // 파일처리 //============================================================================= //파일 경로와 이름을 받아오는 변수 var u_totFile; function BtnFile_OnClick(obj,nX,nY) { //파일을 첩부하는 팝업창(ProFileDialog) OPEN ProFileDialog.Type = "OPEN"; if(ProFileDialog.Open()) { //u_totFile에 파일 경로와 이름을 받아옴 u_totFile = ProFileDialog.FilePath + "\\" + ProFileDialog.FileName; alert(u_totFile); //파일을 임시로 저장하는 메소드 호출 fileTempSave(); } else { //첨부된 파일이 없다면 alert alert("사진파일을 가져오지 않았습니다."); } } function fileTempSave() { //file 컴포넌트(ProFile)에 파일 이름과 경로를 받아옴, ProFile.FileName = u_totFile; //파일 다운로드를 위해 파일명을 DB에 저장 alert(ProFile.FileName); var strFileNameArr = split(ProFile.FileName, "\\" ,"webstyle"); alert(strFileNameArr[strFileNameArr.length()-1]); DS_DEPT.SetColumn(DS_DEPT.row, "fileName", strFileNameArr[strFileNameArr.length()-1]); //File 컴포넌트에 FileName Propery로 지정된 파일을 Open //여기서 'r'을 읽기가능하다는 뜻이고, //'b'는 binary파일로 변환한다는 뜻이다. ProFile.Open("rb"); //그림 파일 확장자 validation var strArr =split(ProFile.FileName, "." ,"webstyle"); //그림 파일 확장자가 jpg, jpeg, gif 중 하나일 경우 if(strArr[strArr.length()-1] == "jpg" || strArr[strArr.length()-1] == "jpeg" || strArr[strArr.length()-1] == "gif") { alert("파일의 확장자는" + strArr[strArr.length()-1] +"입니다."); //b_read라는 변수에 binary파일로 변환한 값을 저장 b_read = ProFile.ReadBinary(); //alert(DS_DEPT.row); //해당DATASET의 proImage 에 b_read 를 넘긴다. DS_DEPT.SetColumn(DS_DEPT.row, "proImage", b_read); //open한 파일 컴포넌트를 닫는다. ProFile.Close(); // alert(b_read); } else //그림 파일 확장자가 jpg, jpeg, gif 중 하나가 아닐 경우 alert(strArr[strArr.length()-1] + " 파일은 올릴 수 없습니다."); } function Div_Input_proImage_OnClick(obj,nX,nY) { //파일 첩부하는 팝업창을 열다. ProFileDialog.Type = "OPEN"; if(ProFileDialog.Open()) { // u_totFile에 파일 경로와 이름을 받아옴 u_totFile = ProFileDialog.FilePath + "\\" + ProFileDialog.FileName; // alert(u_totFile); //파일을 임시로 저장하는 메소드 호출 fileTempSave(); } else { //첨보된 파일이 없다면 alert alert("사진파일을 가져오지 않았습니다."); } }
[편집] 파일 업로드를 위한 저장 화면 스크립트 작성
위의 화면 스크립트를 통해 파일 업로드를 위한 BLOB 데이터바인딩이 데이터셋에 반영되면 아래의 저장 화면 스크립트를 통해 서버측 Struts2 Action에 저장을 요청하게 된다.
//============================================================================== // 저장 //============================================================================= function BtnSave_OnClick(obj) { Transaction("save", "http://(호스트명:포트)/file/dept/saveDepts.action", "DS_DEPT=DS_DEPT:u", "", "", "trancallback"); }
[편집] StartXML을 JSP로 변환(Samples_ci_main.xml -> Samples_ci_main.jsp로 변환)
주소의 변경 없이 임의의 context path에서도 파일 업로드 프로그램이 실행될 수 있도록 설정하기 위해서 다음과 같은 java scriptlet을 StartXML의 상단에 삽입하고 파일 확장자를 xml에서 jsp로 변경한다.
<%@page contentType="text/xml; charset=utf-8" language="java" import="java.net.*" %><% String baseurl = ""; String scheme = request.getScheme(); String host = request.getServerName(); int port = request.getServerPort(); String path = request.getContextPath(); try { baseurl = new URI(scheme,null,host,port,path,null,null).toString(); } catch (URISyntaxException e) { e.printStackTrace(); } %><?xml version="1.0" encoding="euc-kr"?> ......
파일 업로드 샘플의 초기 로딩 시 jsp로 설정한 StartXML이 로딩될 수 있도록 index_start.jsp와 install_lite_320U.jsp 파일을 다음과 같이 수정한다.
우선 request에서 주소를 가져오고, 가져온 주소를 baseurl에 저장하여 실제로 주소가 필요한 소스파일에서 <%=baseurl%>의 형태로 다이나믹한 주소를 제공하게 된다.
- index_start.jsp
<%@page contentType="text/html; charset=utf-8" language="java" import="java.net.*" %> <% String baseurl = ""; String scheme = request.getScheme(); String host = request.getServerName(); int port = request.getServerPort(); String path = request.getContextPath(); try { baseurl = new URI(scheme,null,host,port,path,null,null).toString(); } catch (URISyntaxException e) { e.printStackTrace(); } %> <HTML> <html> <head> ...... <script language="javascript"> function fn_start() { /*alert(Check_Module()); alert("1");*/ if ( Check_Module() == "true" ) { MiInstallCtrl.Key = "DAEWOO1"; MiInstallCtrl.Version = "3.2"; MiInstallCtrl.Width = "1024"; MiInstallCtrl.Height = "768"; MiInstallCtrl.DeviceType = "Win32U"; MiInstallCtrl.Launch = true; MiInstallCtrl.UpdateURL = "http://scm.dev.daewoobrenic.co.kr/install320U/update_cfg.xml"; var Bcnt = MiInstallCtrl.ExistVersionUpCnt(); if ( Bcnt ){window.location = "<%=baseurl%>/install_lite_320U.jsp";} else {MiInstallCtrl.StartXml = "<%=baseurl%>/commonXML/Samples_ci_main.jsp";MiInstallCtrl.Width = 1024;MiInstallCtrl.Height = 768; MiInstallCtrl.Run(); opener=window; window.open('about:blank','_self').close(); } }else { alert("Cab파일 설치 오류 TobeSoft Col.,,Ltd.에서 배포하는 Miplatform ActiveX가 필요합니다."); } } </script> </head> <body onload="fn_start()"> <OBJECT ID="MiInstallCtrl" CLASSID="clsid:1A000B1F-B285-4fbf-B3CD-B50845003EBA" codebase="http://scm.dev.daewoobrenic.co.kr/install320U/MiPlatform_Updater320_20070809_1500.cab#version=2007,7,27,1" width=0 height=0 VIEWASTEXT> <param name="KEY" value="DAEWOO1"> <param name="VERSION" value="3.2"> <param name="DeviceType" value="Win32U"> </OBJECT> </body>
</html>
- install_lite_320U.jsp
<%@page contentType="text/html; charset=utf-8" language="java" import="java.net.*" %> <% String baseurl = ""; String scheme = request.getScheme(); String host = request.getServerName(); int port = request.getServerPort(); String path = request.getContextPath(); try { baseurl = new URI(scheme,null,host,port,path,null,null).toString(); } catch (URISyntaxException e) { e.printStackTrace(); } %> <html> <head> <meta http-equiv=Content-type content="text/html; charset=euc-kr"> ...... <SCRIPT language=JavaScript for=MiInstallCtrl event=OnEndDownLoad(VersionFileName,DownFileName,Type,TotalCnt,CurIndex)> { // alert("OnEndDownLoad : " + Type); if ( Type == 1 ) //EVENTCONFIG { TotalVersionFileCnt = TotalCnt; for ( var i = pg_cell_At ; i < progress.length ; i++ ) progress_update(progress,i); for ( var j = pg1_cell_At ; j < progress1.length ; j++ ) progress_update(progress1,j); if ( prc_msg != "" && prc_msg != null && prc_msg != "undefined" ) prc_msg.innerHTML = " 설치 완료"; MiInstallCtrl.Key = "DAEWOO1"; MiInstallCtrl.Version = "3.2"; MiInstallCtrl.Width = "1024"; MiInstallCtrl.Height = "768"; MiInstallCtrl.DeviceType = "Win32U"; MiInstallCtrl.Launch = true; MiInstallCtrl.ComponentPath = "%UserApp%TobeSoft\\ucups\\components"; MiInstallCtrl.StartXml = "<%=baseurl%>/DISODC_UI/Samples_ci_main.xml"; MiInstallCtrl.Run(); opener=window; self.close(); } else if ( Type == 2 ) //EVENTGETVERSIONCNT { if ( TotalCnt == CurIndex ){ for ( var i = pg1_cell_At ; i < progress1.length ; i++ ) progress_update(progress1,i); } else { if ( CurIndex > 1 ) { var before_At = pg_cell_At; pg_cell_At += parseInt( ( ( (CurIndex - 1)/TotalVersionFileCnt ) * progress.length ) - before_At ); for ( var i = before_At ; i < pg_cell_At ; i++ ) progress_update(progress,i); } pg1_cell_At = 0; var tpos = DownFileName.lastIndexOf("/") + 1; var Fname = DownFileName.substr(tpos,DownFileName.length - tpos); item_nm.innerHTML = " " + Fname; } } ...... </body> </html>
[편집] BLOB 데이터 처리를 위한 Model 구성
화면에서 넘어온 데이터셋에 담긴 데이터를 서버측 Action에서 받아 맵핑하기 위한 모델은 다음과 같이 구성하였다. BLOB 데이터는 Model에서 byte[]로 받으면 되고 파일 다운로드를 위해 파일명을 별도로 저장하는 것이 필요하다.
package com.dept.model; public class Dept { private String deptCode; private String deptName; private String maxCnt; private String univ; private String rowStatus; //file infoprivate String fileName;private byte[] proImage;///////////////////Getter/Setter///////////////////////////////////////// public byte[] getProImage() { return proImage; } public void setProImage(byte[] proImage) { this.proImage = proImage; } public String getDeptCode() { return deptCode; } public void setDeptCode(String deptCode) { this.deptCode = deptCode; } public String getDeptName() { return deptName; } public void setDeptName(String deptName) { this.deptName = deptName; } public String getMaxCnt() { return maxCnt; } public void setMaxCnt(String maxCnt) { this.maxCnt = maxCnt; } public String getUniv() { return univ; } public void setUniv(String univ) { this.univ = univ; } public String getRowStatus() { return rowStatus; } public void setRowStatus(String rowStatus) { this.rowStatus = rowStatus; } public String getFileName() { return fileName; } public void setFileName(String fileName) { this.fileName = fileName; }
}
[편집] Action 및 struts*.xml 구성
DeptAction은 위에서 구성된 화면과 Struts2 기반으로 http 기반의 xml 통신을 한다. JCF가 제공하는 MiRequest, MiResponse 클래스의 메소드를 통해 클라이언트에서 전송된 BLOB을 포함한 Dataset을 서버의 Model에 맵핑하여 Service, Dao를 통해 DB의 DEPT 테이블에 데이터를 저장한다.
- struts-dept.xml
Miplatform에서 요청한 파일 업로드를 Struts2 기반으로 처리하기 위해서 다음과 같이 설정한다.
<?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="/dept" extends="struts-default" namespace="/dept"> <action name="findDepts" class="com.dept.action.DeptAction" method="findDepts" /> <action name="saveDepts" class="com.dept.action.DeptAction" method="saveDepts" /> </package> </struts>
- DeptAction
Struts2를 통해 전달된 데이터는 DeptAction에서 MiRequest, MiResponse 클래스를 통해 Dept Model에 저장되고 서버측 Service, Dao에 전달된다.
package com.dept.action; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import com.daewoobrenic.jcf.ui.miplatform.MiRequest; import com.daewoobrenic.jcf.ui.miplatform.MiResponse; import com.daewoobrenic.jcf.web.struts2.action.BaseAction; import com.dept.model.Dept; import com.dept.service.DeptService; public class DeptAction extends BaseAction { private DeptService deptService; // //////////////////////////////////////////////////////////////////////////// // /////////////////////////// Miplatform // //////////////////////////////////////////////////////////////////////////// /** * Dept 조회 */ public void findDepts() { List deptList = null; deptList = deptService.findDepts(); HashMap dataSetMap = new HashMap(); dataSetMap.put("DS_DEPT", deptList); MiResponse res = new MiResponse(getResponse()); res.send(dataSetMap); } /** * Dept 저장 */ public void saveDepts() { MiRequest req = new MiRequest(getRequest()); List deptList = null; deptList = req.extractObjectList(Dept.class.getCanonicalName(), "DS_DEPT"); deptService.saveDepts(deptList); MiResponse res = new MiResponse(getResponse()); res.success(); } // //////////////////////////////////////////////////////////////////////////// // /////////////////////////// getter / setter // //////////////////////////////////////////////////////////////////////////// public DeptService getDeptService() { return deptService; } public void setDeptService(DeptService deptService) { this.deptService = deptService; } }
[편집] Service, Dao 그리고 applicationContext*.xml 구성
Oralce Blob 데이터를 사용하기 위해서는 다음 JCF 3.0 매뉴얼을 참고하기 바란다. CLOB/BLOB 사용하기
- DeptService 인터페이스
DeptService에서는 Dept 정보를 조회하고 변경된 내용(입력, 수정, 삭제)에 대하여 저장할 수 있는 인터페이스 메소드를 제공한다.
package com.dept.service; import java.util.List; import com.dept.dao.DeptDao; import com.dept.model.Dept; public interface DeptService { public abstract List findDepts(); public abstract void saveDepts(List deptList); }
- DeptService 구현 클래스
위의 인터페이스에서 지정한 메소드를 구현한다. 특별히 저장하는 메소드에서는 Miplatform이 제공하는 rowStatus에 따라 입력, 수정, 삭제가 선별적으로 수행된다.
package com.dept.service; import java.util.List; import jcf.exception.BusinessException; import com.Constant; import com.dept.dao.DeptDao; import com.dept.model.Dept; public class DeptServiceImpl implements DeptService { private DeptDao deptDao; ////////////////////////////////////////////////////////////////////////////// ///////////////////////////// Business Method /////////////////////////////// ////////////////////////////////////////////////////////////////////////////// /* (non-Javadoc) * @see com.dept.service.DeptService#findDepts() */ public List findDepts(){ return deptDao.findDepts(); } /* (non-Javadoc) * @see com.dept.service.DeptService#saveDepts(java.util.List) */ public void saveDepts(List deptList) { Dept dept = null; for (int i = 0; i < deptList.size(); i++) { dept = (Dept) deptList.get(i); // System.out.println(term.getRowStatus()); if(Constant.CODE_STATUS_INSERT.equalsIgnoreCase(dept.getRowStatus())) deptDao.insertDept(dept); else if(Constant.CODE_STATUS_UPDATE.equalsIgnoreCase(dept.getRowStatus())) deptDao.updateDept(dept); else if(Constant.CODE_STATUS_DELETE.equalsIgnoreCase(dept.getRowStatus())) deptDao.deleteDept(dept.getDeptCode()); else throw new BusinessException("Row Status" + dept.getRowStatus() + " is not appropriate."); } } ////////////////////////////////////////////////////////////////////////////// ///////////////////////////// getter / setter /////////////////////////////// ////////////////////////////////////////////////////////////////////////////// /* (non-Javadoc) * @see com.dept.service.DeptService#getDeptDao() */ public DeptDao getDeptDao() { return deptDao; } /* (non-Javadoc) * @see com.dept.service.DeptService#setDeptDao(com.dept.dao.DeptDao) */ public void setDeptDao(DeptDao deptDao) { this.deptDao = deptDao; } }
- applicationContext-dept.xml
Dept 서비스를 제공하기 위해 WAS 로딩 시 Spring에 로딩되어야 하는 Bean을 설정한다.
<?xml version="1.0" encoding="UTF-8"?> <beans default-autowire="no" default-lazy-init="false" default-dependency-check="none" 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" xmlns:jee="http://www.springframework.org/schema/jee" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.0.xsd"> <bean name="deptService" class="com.dept.service.DeptServiceImpl"> <property name="deptDao" ref="deptDao" /> </bean> <bean name="deptDao" class="com.dept.dao.DeptDaoImpl"> <property name="sqlMapClient" ref="sqlMapClient" /> </bean> </beans>
- DeptDao 인터페이스
입력, 수정, 삭제 및 리스트 조회에 대한 인터페이스 메소드를 제공한다.
package com.dept.dao; import java.util.List; import com.dept.model.Dept; public interface DeptDao { public abstract List findDepts(); public abstract void insertDept(Dept dept); public abstract void updateDept(Dept dept); public abstract void deleteDept(String deptCode); }
- DeptDao 구현 클래스
입력, 수정, 삭제 및 리스트 조회에 대한 메소드를 구현한다.
package com.dept.dao; import java.util.List; import jcf.dao.sqlmap.BaseSqlMapClientDAO; import com.dept.model.Dept; public class DeptDaoImpl extends BaseSqlMapClientDAO implements DeptDao{ public List findDepts() { return executeQueryForList("dept.findDepts", null); } public void insertDept(Dept dept) { executeUpdate("dept.insertDept", dept); } public void updateDept(Dept dept) { executeUpdate("dept.updateDept", dept); } public void deleteDept(String deptCode) { executeUpdate("dept.deleteDept", deptCode); } }
[편집] SqlMap 구성
- Dept.xml
DEPT 테이블에 대한 입력,수정,삭제,리스트조회에 대한 쿼리문장을 작성한다.
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <!DOCTYPE sqlMap PUBLIC "-//iBATIS.com//DTD SQL Map 2.0//EN" "http://www.ibatis.com/dtd/sql-map-2.dtd"> <sqlMap namespace="dept"> <!-- ibatis cache를 dept namespace에 적용하여 조회를 성능을 향상시킨다.--> <cacheModel type="LRU" id="dept-cache"> <flushInterval hours="24"/> <flushOnExecute statement="dept.insertDept"/> <flushOnExecute statement="dept.updateDept"/> <flushOnExecute statement="dept.deleteDept"/> </cacheModel> <typeAlias alias="dept" type="com.dept.model.Dept" /> <resultMap class="dept" id="resultMap-dept"> <result property="deptCode" column="dept_cd" /> <result property="deptName" column="dept_name" /> <result property="maxCnt" column="max_cnt" /> <result property="univ" column="univ" /> <result property="fileName" column="file_name" /> <result property="proImage" column="proimage" /> </resultMap> <!-- ========================================== Statements ========================================== --> <!-- Dept 조회--> <statement id="findDepts" parameterClass="string" resultMap="resultMap-dept" cacheModel="dept-cache"> <![CDATA[ SELECT dept_cd, dept_name, max_cnt, univ, file_name, proimage FROM DEPT ]]> </statement> <!-- Dept 입력--> <statement id="insertDept" parameterClass="dept" cacheModel="dept-cache"> <![CDATA[ INSERT INTO DEPT(dept_cd, dept_name, max_cnt, univ, file_name, proimage) VALUES(#deptCode#, #deptName#, #maxCnt#, #univ#, #fileName#, #proImage#) ]]> </statement> <!-- Dept 수정--> <statement id="updateDept" parameterClass="dept" cacheModel="dept-cache"> <![CDATA[ UPDATE DEPT SET dept_name = #deptName#, max_cnt = #maxCnt#, univ = #univ#, proimage = #proImage#, file_name = #fileName# WHERE dept_cd = #deptCode# ]]> </statement> <!-- Dept 삭제--> <statement id="deleteDept" parameterClass="string" cacheModel="dept-cache"> <![CDATA[ DELETE FROM DEPT WHERE dept_cd = #deptCode# ]]> </statement> </sqlMap>
- sqlmap-config.xml
ibats 프레임워크에서 해당 sqlmap을 인지할 수 있도록 Dept.xml slqmap에 대한 리소스를 다음과 같이 등록한다.
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <!DOCTYPE sqlMapConfig PUBLIC "-//iBATIS.com//DTD SQL Map Config 2.0//EN" "http://www.ibatis.com/dtd/sql-map-config-2.dtd"> <sqlMapConfig> <!--settings cacheModelsEnabled="true" /--> <settings cacheModelsEnabled="true" enhancementEnabled="true" lazyLoadingEnabled="true" maxRequests="32" maxSessions="10" maxTransactions="5" useStatementNamespaces="true" /> <!-- ========== CLOB/BLOB Handler Setting ============= --> <typeHandler callback="org.springframework.orm.ibatis.support.ClobStringTypeHandler" jdbcType="CLOB" javaType="java.lang.String" /> <typeHandler callback="org.springframework.orm.ibatis.support.BlobByteArrayTypeHandler" jdbcType="BLOB" javaType="[B" /> <!-- ==========Framework Configuration Section============= --><sqlMap resource="com/dept/dao/sqlmap/Dept.xml" /></sqlMapConfig>
[편집] 테스트 및 실행
- Tomcat 프로젝트로 등록하고 context path(/file로 등록)를 지정하면 tomcat 환경에서 구동할 수 있게 된다.
- Tomcat을 구동시키면 file.xml에 대한 context가 로딩되는 것을 콘솔창에서 로그로 확인할 수 있다.
- Tomcat 로딩이 완료되면 IE 웹브라우저를 실행시키고 주소입력줄에 http://localhost:8080/file로 입력하고 엔터를 누른다.
- 다음과 같은 Miplatform 화면이 출력되는 것을 확인할 수 있다.
- 상단에 있는 조회버튼을 클릭하면 Dept 리스트가 다음과 같이 조회된다.
- 추가버튼을 클릭하면 그리드에 행이 추가되다.
- 추가된 행에 데이터를 입력하고 학과장사진첨부하기버튼을 클릭하거나 이미지를 클릭하면 파일선택창이 출력된다
- 파일선택창에서 사진을 선택하여 저장버튼을 누르면 서버와 통신하여 DB에 Dept 데이터와 사진파일의 BLOB 데이터가 저장된다.
