비즈니스 로직을 처리하면서 필요한 첨부파일등의 처리를 위한 공통 기능을 제공하여, 파일 목록 조회, 파일 다운로드 기능을 공통적으로 사용할 수 있으며 파일 등록 부분은 클라이언트 JavaScript 및 그 활용예시를 제공한다.
본 기능은 전자정부 표준프레임워크 실행환경의 File Upload/Download 기능을 활용하여 구성되어있다.
파일 업로드를 위한 공통기능은 크게 MultipartRequest를 통해서 서버로 전송된 파일을 파싱하여 디스크에 생성하고 해당 정보를 저장하는 EgovFileMngUtil 클래스와 파일정보를 관리하기 위한 EgovFileMngService 서비스로 구성되어있다.(관련소스 부분 참조)
JSP에서 파일 업로드를 처리하는 부분은 Dynamic HTML 기반으로 되어있으며, 해당 기능처리를 위한 Script는 EgovMultiFile.js에 구성되어있다. 이를 각 업로드가 필요한 기능화면에 사용방법에 의거하여 적용하여 기능 구성을 한다.
유형 | 대상소스명 | 비고 |
---|---|---|
Controller | egovframework.com.cmm.web.EgovFileMngController.java | 파일업로드, 조회를 위한 컨트롤러 클래스 |
Controller | egovframework.com.cmm.web.EgovFileDownloadController.java | 파일다운로드를 위한 컨트롤러 클래스 |
Service | egovframework.com.cmm.service.EgovFileMngService.java | 파일관리를 위한 서비스 인터페이스 |
ServiceImpl | egovframework.com.cmm.service.impl.EgovFileMngServiceImpl.java | 파일관리를 위한 서비스 구현 클래스 |
VO | egovframework.com.cmm.service.FileVO.java | 파일관리를 위한 VO 클래스 |
DAO | egovframework.com.cmm.service.imp.FileManageDAO.java | 파일정보 관리를 위한 데이터처리 클래스 |
Component | egovframework.com.cmm.service.EgovFileMngUtil.java | 파일생성 및 파일정보의 DB저장을 위한 Util 클래스 |
JSP | /WEB-INF/jsp/egovframework/cmm/fms/EgovFileList.jsp | 파일목록 조회 및 다운로드 처리를 위한 목록조회 페이지 |
js | /js/egovframework/cmm/fms/EgovMultiFile.js | 파일업로드 처리를 위한 Javascript 파일 |
테이블명 | 테이블명(영문) | 비고 |
---|---|---|
파일정보 | COMTNFILE | 파일 헤더정보를 관리 |
파일상세정보 | COMTNFILEDETAIL | 파일 상세정보를 관리 |
파일 업로드 기능을 활용하기 위하여 필요한 항목 및 그 환경 설정은 다음과 같다.
<!-- MULTIPART RESOLVERS --> <!-- regular spring resolver --> <bean id="spring.RegularCommonsMultipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <property name="maxUploadSize" value="100000000" /> <property name="maxInMemorySize" value="100000000" /> </bean> <!-- custom multi file resolver --> <bean id="local.MultiCommonsMultipartResolver" class="egovframework.com.cmm.web.EgovMultipartResolver"> <property name="maxUploadSize" value="100000000" /> <property name="maxInMemorySize" value="100000000" /> </bean>
본 공통기능에서는 다중파일 업로드 처리를 하기 때문에 그를 위해서 egovframework.com.cmm.web.EgovMultipartResolver 클래스를 MultiCommonsMultipartResolver로서 등록해야 하며 필요시 maxUploadSize, maxInMemorySize의 값을 변경해서 업로드 가능한 최대 파일 크기를 지정한다. ※ spring.RegularCommonsMultipartResolver는 Default 설정으로 추가해둔다.
<bean name="propertiesService" class="egovframework.rte.fdl.property.impl.EgovPropertyServiceImpl" destroy-method="destroy"> <property name="properties"> <map> <entry key="pageUnit" value="10"/> <entry key="pageSize" value="10"/> <entry key="Globals.fileStorePath" value="/product/jeus/egovProps/upload/"/> </map> </property> </bean>
Globals.fileStorePath의 값은 실제 파일이 저장될 수 있는 물리적인 디렉토리 위치를 지정하며 지정시 주소의 가장 뒷 부분에 해당 운영체제에 맞는 File.seperator를 명시하도록 한다.
<bean name="egovFileIdGnrService" class="egovframework.rte.fdl.idgnr.impl.EgovTableIdGnrService" destroy-method="destroy"> <property name="dataSource" ref="dataSource" /> <property name="strategy" ref="fileStrategy" /> <property name="blockSize" value="10"/> <property name="table" value="COMTECOPSEQ"/> <property name="tableName" value="FILE_ID"/> </bean> <bean name="fileStrategy" class="egovframework.rte.fdl.idgnr.impl.strategy.EgovIdGnrStrategyImpl"> <property name="prefix" value="FILE_" /> <property name="cipers" value="15" /> <property name="fillChar" value="0" /> </bean>
CREATE TABLE COMTECOPSEQ ( table_name varchar(16) NOT NULL, next_id DECIMAL(30) NOT NULL, PRIMARY KEY (table_name)); INSERT INTO COMTECOPSEQ VALUES('FILE_ID','0');
상기 설정이 모두 완료된 경우 파일 관리를 사용할 비즈니스 로직에 맞춰서 다음의 4가지 경우에 따른 추가적인 코딩작업을 수행한다.
파일 조회 및 파일 삭제처리를 위한 EgovFileList.jsp에서 사용하는 Javascript의 경우 Form 명을 frm으로 사용하고 있음. 별도의 작업을 줄이기 위해서 해당 Form 명을 준수하는 것을 권장함
파일을 업로드 하기 위하여 해당 화면에서 사용하는 폼은 다음의 형태를 준수해야 한다.
<form name="frm" method="post" enctype="multipart/form-data" > <input type="hidden" name="posblAtchFileNumber" value="최대등록가능파일숫자" /> ..... </form>
파일을 등록하기 위하여 먼저 EgovMultiFile.js를 사용할 수 있도록 해당 페이지에 등록한다.
<script type="text/javascript" src="<c:url value='/js/egovframework/cmm/fms/EgovMultiFile.js'/>" ></script>
스크립트에서 사용할 파일객체 및 그 파일객체를 쌓아둘 위치를 지정할 수 있도록 다음의 HTML 코드 및 스크립트를 삽입한다.
<table width="680px" cellspacing="0" cellpadding="0" border="0" align="center" class="UseTable"> <tr> <td><input name="file_1" id="egovComFileUploader" type="file" /></td> </tr> <tr> <td> <div id="egovComFileList"></div> </td> </tr> </table>
HTML 코드가 끝나는 위치에 스크립트를 추가해야 하며, 아래의 코드예시에서 document.frm.posblAtchFileNumber.value 값은 업로드가 가능한 최대 파일의 숫자를 form에 담아두기 위한 용도이므로 실제 사용하지 않는 필드라고 해도 추가를 해둬야 한다. 해당 값이 없을 경우에 기본값은 3개이나 필요시 변경이 가능하다.
<script type="text/javascript"> var maxFileNum = document.frm.posblAtchFileNumber.value; if(maxFileNum==null || maxFileNum==""){ maxFileNum = 3; } var multi_selector = new MultiSelector( document.getElementById( 'egovComFileList' ), maxFileNum ); multi_selector.addElement( document.getElementById( 'egovComFileUploader' ) ); </script>
스크립트와 HTML코드를 모두 작성하고 업무화면을 호출하는 경우 아래와 같은 화면을 확인할 수 있다. 최대 파일수치까지 등록되면 파일찾기 버튼은 비활성화되며 Delete버튼을 누르는 경우 파일 객체를 삭제한다.
업무 비즈니스 처리를 위한 Controller에서는 메서드에서 MultipartHttpServletRequest를 받을 수 있도록 입력항목으로 추가하고 해당 파일요청을 처리하기 위한
import egovframework.com.cmm.service.EgovFileMngService; import egovframework.com.cmm.service.EgovFileMngUtil; @Resource(name="EgovFileMngService") private EgovFileMngService fileMngService; @Resource(name="EgovFileMngUtil") private EgovFileMngUtil fileUtil; public String insertBoardArticle( final MultipartHttpServletRequest multiRequest, @ModelAttribute("searchVO") BoardVO boardVO, @ModelAttribute("board") Board board, SessionVO sessionVO, ModelMap model, SessionStatus status) throws Exception{ List<FileVO> _result = null; String _atchFileId = ""; final Map<String, MultipartFile> files = multiRequest.getFileMap(); if(!files.isEmpty()){ _result = fileUtil.parseFileInf(files, "BBS_", 0, "", ""); _atchFileId = fileMngService.insertFileInfs(_result); //파일이 생성되고나면 생성된 첨부파일 ID를 리턴한다. } ..... }
<c:import url="/cmm/fms/selectFileInfs.do" > <c:param name="param_atchFileId" value="${result.atchFileId}" /> </c:import>
<c:import url="/cmm/fms/selectFileInfsForUpdate.do" > <c:param name="param_atchFileId" value="${result.atchFileId}" /> </c:import>
<code html> <form name="frm" method="post"> <input type="hidden" name="returnUrl" value="<c:url value='/cop/bbs/forUpdateBoardArticle.do'/>"/> </form> </code>
<form name="frm" method="post" enctype="multipart/form-data" > <input type="hidden" name="posblAtchFileNumber" value="최대등록가능파일숫자" /> ..... </form>
<script type="text/javascript" src="<c:url value='/js/egovframework/cmm/fms/EgovMultiFile.js'/>" ></script>
앞서 이야기한바와 같이 수정 시점에서는 기존에 등록된 파일을 삭제하거나 신규로 등록하는 형태로 진행되므로 신규로 파일을 입력할 수 있는 부분과 파일을 삭제하는 부분을 모두 한 업무화면에 표현해야 한다. 파일 목록을 조회하고 삭제하는 부분은 기존의 파일 삭제때와 마찬가지로 처리하며 파일을 쌓는 부분은 아래와 같은 HTML 코드를 준비한다.
<div id="file_upload_posbl" style="display:none;" > <table width="680px" cellspacing="0" cellpadding="0" border="0" align="center" class="UseTable"> <tr> <td><input name="file_1" id="egovComFileUploader" type="file" /></td> </tr> <tr> <td> <div id="egovComFileList"></div> </td> </tr> </table> </div> <div id="file_upload_imposbl" style="display:none;" > <table width="680px" cellspacing="0" cellpadding="0" border="0" align="center" class="UseTable"> <tr> <td><spring:message code="common.imposbl.fileupload" /></td> </tr> </table> </div>
DIV를 file_upload_posbl, file_upload_imposbl로 나눠둔 것은 메시지 처리등을 위한 부분이며 개선의 여지가 있다.
HTML 코드가 끝나는 위치에 스크립트를 추가해야 하며, 아래의 코드예시에서 document.frm.posblAtchFileNumber.value 값은 업로드가 가능한 최대 파일의 숫자를 form에 담아두기 위한 용도이므로 실제 사용하지 않는 필드라고 해도 추가를 해둬야 한다. 파일 등록때와 마찬가지로 파일 업로드 기능에서 사용하는 Form명은 frm이다.
<script type="text/javascript"> var existFileNum = document.frm.fileListCnt.value; // 이 값은 File List를 조회하는 부분에 담겨온다. var maxFileNum = document.frm.posblAtchFileNumber.value; // 각 비즈니스 로직에서는 해당하는 폼 값에 첨부가능한 최대파일 숫자를 세팅해둬야 함 var uploadableFileNum = maxFileNum - existFileNum; // 최대등록가능한 파일숫자에서 기존에 등록된 숫자를 뺀다. if(uploadableFileNum<0) { uploadableFileNum = 0; } if(uploadableFileNum != 0){ fn_egov_check_file('Y'); var multi_selector = new MultiSelector( document.getElementById( 'egovComFileList' ), uploadableFileNum ); multi_selector.addElement( document.getElementById( 'egovComFileUploader' ) ); }else{ fn_egov_check_file('N'); } </script>
스크립트와 HTML코드를 모두 작성하고 업무화면을 호출하는 경우 아래와 같은 화면을 확인할 수 있다. 최대 파일수치까지 등록되면 파일찾기 버튼은 비활성화되며 Delete버튼을 누르는 경우 파일 객체를 삭제한다.
import egovframework.com.cmm.service.EgovFileMngService; import egovframework.com.cmm.service.EgovFileMngUtil; @Resource(name="EgovFileMngService") private EgovFileMngService fileMngService; @Resource(name="EgovFileMngUtil") private EgovFileMngUtil fileUtil; public String updateBoardArticle( final MultipartHttpServletRequest multiRequest, @ModelAttribute("searchVO") BoardVO boardVO, @ModelAttribute("board") Board board, SessionVO sessionVO, ModelMap model, SessionStatus status) throws Exception{ String _atchFileId = boardVO.getAtchFileId();/ 해당 업무기능에 따라서 수정되는 기능의 파일 ID를 불러온다. final Map<String, MultipartFile> files = multiRequest.getFileMap(); if(!files.isEmpty()){ if("".equals(_atchFileId)){ List<FileVO> _result = fileUtil.parseFileInf(files, "BBS_", 0, _atchFileId, ""); _atchFileId = fileMngService.insertFileInfs(_result); // 기존에 첨부파일 ID가 없다. board.setAtchFileId(_atchFileId); // 관련 비즈니스 규칙에 따라서 생성된 첨부파일 ID 정보를 세팅한다. }else{ FileVO fvo = new FileVO(); fvo.setAtchFileId(_atchFileId); // 최종 파일 순번을 획득하기 위하여 VO에 현재 첨부파일 ID를 세팅한다. int _cnt = fileMngService.getMaxFileSN(fvo); // 해당 첨부파일 ID에 속하는 최종 파일 순번을 획득한다. List<FileVO> _result = fileUtil.parseFileInf(files, "BBS_", _cnt, _atchFileId, ""); fileMngService.updateFileInfs(_result); } } ......