목차

File Manage 서비스

개요

비즈니스 로직을 처리하면서 필요한 첨부파일등의 처리를 위한 공통 기능을 제공하여, 파일 목록 조회, 파일 다운로드 기능을 공통적으로 사용할 수 있으며 파일 등록 부분은 클라이언트 JavaScript 및 그 활용예시를 제공한다.

본 기능은 전자정부 표준프레임워크 실행환경의 File Upload/Download 기능을 활용하여 구성되어있다.

설명

파일 업로드를 위한 공통기능은 크게 MultipartRequest를 통해서 서버로 전송된 파일을 파싱하여 디스크에 생성하고 해당 정보를 저장하는 EgovFileMngUtil 클래스와 파일정보를 관리하기 위한 EgovFileMngService 서비스로 구성되어있다.(관련소스 부분 참조)

JSP에서 파일 업로드를 처리하는 부분은 Dynamic HTML 기반으로 되어있으며, 해당 기능처리를 위한 Script는 EgovMultiFile.js에 구성되어있다. 이를 각 업로드가 필요한 기능화면에 사용방법에 의거하여 적용하여 기능 구성을 한다.

관련 클래스 다이어그램

클래스다이어그램

관련소스
유형대상소스명비고
Controlleregovframework.com.cmm.web.EgovFileMngController.java파일업로드, 조회를 위한 컨트롤러 클래스
Controlleregovframework.com.cmm.web.EgovFileDownloadController.java파일다운로드를 위한 컨트롤러 클래스
Serviceegovframework.com.cmm.service.EgovFileMngService.java파일관리를 위한 서비스 인터페이스
ServiceImplegovframework.com.cmm.service.impl.EgovFileMngServiceImpl.java파일관리를 위한 서비스 구현 클래스
VOegovframework.com.cmm.service.FileVO.java파일관리를 위한 VO 클래스
DAOegovframework.com.cmm.service.imp.FileManageDAO.java파일정보 관리를 위한 데이터처리 클래스
Componentegovframework.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파일 상세정보를 관리

환경설정

파일 업로드 기능을 활용하기 위하여 필요한 항목 및 그 환경 설정은 다음과 같다.

context-common.xml
    <!-- 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 설정으로 추가해둔다.

context-properties.xml
  <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를 명시하도록 한다.

context-idgen.xml
	<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 명을 준수하는 것을 권장함

File Upload(최초등록)
JSP/Script (File Upload)

파일을 업로드 하기 위하여 해당 화면에서 사용하는 폼은 다음의 형태를 준수해야 한다.

  <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 (File Upload)

업무 비즈니스 처리를 위한 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를 리턴한다.
	}
    .....		
 }
File Select

  1. 해당 업무로직에서 첨부파일이 있는 것이 확인 될 경우 아래의 코드예시처럼 해당 게시물에 등록된 첨부파일 ID를 Parameter로 전송한다.
  2. 파일목록의 조회가 완료되는 경우 새 텍스트 문서.txt [405 byte] 처럼 저장된 파일명과 파일의 크기가 표시된다.
  3. File Select의 경우 파일을 삭제하는 기능버튼은 활성화되지 않으며 파일의 다운로드를 위한 링크만이 존재한다.
   <c:import url="/cmm/fms/selectFileInfs.do" >
     <c:param name="param_atchFileId" value="${result.atchFileId}" />
   </c:import>
 
File Delete

  1. 해당 업무로직에서 첨부파일을 삭제할 필요가 있는 경우 (게시물의 수정등) 사용하며 File Select의 경우와 마찬가지로 등록된 첨부파일 ID를 Parameter로 전송한다.
  2. File Select의 경우와는 반대로 파일 다운로드 링크는 존재하지 않으며 파일 삭제를 위한 삭제버튼이 활성화된다.
   <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>
File Upload(수정등록)

파일을 업로드 하기 위하여 해당 화면에서 사용하는 폼은 다음의 형태를 준수해야 한다.
  <form name="frm" method="post" enctype="multipart/form-data" >
   <input type="hidden" name="posblAtchFileNumber" value="최대등록가능파일숫자" />
   .....
  </form> 
 
JSP/Script (File Upload - 수정등록)

비즈니스 로직 상에서 수정 시점에 파일을 첨부하거나 삭제하는 경우이며, 현재 해당 모듈에서는 파일의 삭제와 저장을 분리하여 별도의 Transaction으로 처리하고 있다. 이 경우에도 최초등록때와 마찬가지로 먼저 EgovMultiFile.js를 사용할 수 있도록 해당 페이지에 등록한다.
  <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버튼을 누르는 경우 파일 객체를 삭제한다.

Controller (File Upload - 수정등록)

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);
	}
}	
......

참고자료