일반적으로는 1개의 DB만 연결하지만

2개의 DB에서 조회라도 하는 경우가 생겼을 때

요것들만 손대주면 가뿐할 듯 하다.

 

전자정부프레임워크, iBatis를 사용한 경우이다.

Spring, MyBatis도 그리 다르지 않으니... 양해를... 쿨럭;;;

 

 

1. xxx-datasource.xml

 

DB-A에 대한 선언
<bean id="dataSource1" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
    <property name="driverClassName" value="JdbcDriverClass정보"/>
    <property name="url" value="접속정보" />
    <property name="username" value="접속ID"/>
    <property name="password" value="접속Password"/>
</bean>


DB-B에 대한 선언
<bean id="dataSource2" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
    <property name="driverClassName" value="JdbcDriverClass정보"/>
    <property name="url" value="접속정보" />
    <property name="username" value="접속ID"/>
    <property name="password" value="접속Password"/>
</bean>

 

 

2. xxx-sqlMap.xml

 

DB-A에 대한 선언
<bean id="sqlMapClient1" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
    <property name="configLocation" value="classpath:/egovframework/sqlmap/sql-map-config1.xml"/>
    <property name="dataSource" ref="dataSource1"/>
</bean>


DB-B에 대한 선언
<bean id="sqlMapClient2" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
    <property name="configLocation" value="classpath:/egovframework/sqlmap/sql-map-config2.xml"/>
    <property name="dataSource" ref="dataSource2"/>
</bean>

1개 DB로 사용할 때 정의했었던 파일들이

   모두 2개씩 필요하다.

 

※ sql-map-config.xml 파일은 사용할 SQL들이 들어있는 xml파일들을 기술하는 파일이다.

※ sql-map-config.xml이나 SQL들이 들어있는 xml파일들은

   DB를 1개 사용할 때처럼 해당 DB 기준으로 편하게 사용하면 된다.

 

 

 

DB-A에 대한 DAO 정의

: 전자정부프레임워크에서는 기본으로 dataSource를 사용하도록 되어있으니

  별다른 처리를 하지 않아도 된다.

  (dataSource id 와 sqlMapClient id를 변경하지 않았을 경우)

: 결론은, 별도로 손을 대지 않아도 된다는...;;;

3.1. xxxDAO1.java

 

@Repository("xxxDAO1")
public class xxxDAO1 extends EgovAbstractDAO {

    ....
}

 

 

DB-B에 대한 DAO 정의 (※중요)

3.2. xxxDAO2.java

 

@Repository("xxxDAO2")
public class xxxDAO2 extends EgovAbstractDAO {

 

    @Resource(name = "sqlMapClient2")  중요
                                                          DB-B용으로 정의한 sqlMapClient를 셋팅하라는 의미.

    public void setSuperSqlMapClient( SqlMapClient sqlMapClient ) {
        super.setSqlMapClient( sqlMapClient );
    }

 

    ....
}

 

 

4. DAO를 사용하는 Class에서는

   필요한 DAO에 대한 정의만 하면 된다.

 

    @Resource(name = "xxxDAO1")
    private xxxDAO1 xxxDAO1;

 

    @Resource(name = "xxxDAO2")
    private xxxDAO2 xxxDAO2;

 

 

준비는 끝.

이제 사용하면 된다는...

아니라면, Spring 기본을 좀 더 파야할 듯...^^;

 

 

  1. 초보 2020.04.13 15:21

    sql-map-config2.xml 은 없어도 괜찮은 건가요? 아니면 sql-map-config.xml을 카피해서 이름만 2를 붙이면 될까요?

  2. noname 2022.02.20 16:30

    감사합니다.

mapping path

특정 경로만 지정할 경우를 제외하고

모든 요청 경로에 적용하려고 한다면...

 

반드시

<mvc:mapping path="/**"/>

요롷게 설정해야 한다.

 

 

 <mvc:interceptors>
    <mvc:interceptor>
        <mvc:mapping path="/**"/>
        <bean class="..."/>
    </mvc:interceptor>
 </mvc:interceptors>

 

 

 

 

<mvc:mapping path="/*"/>

요롷게 하나만 설정한 경우

 

"/경로1" 로 들어오는 요청은 적용되지만,

 

"/경로1/경로2" 로 들어오는 요청은 적용되지 않는다...;;;

 

 

권한에 따른 처리를 하는 경우에

소 잃고 외양간 고치는 수가 생기니...

기본적이지만,

특히 주의해야 하니...

 

 

Controller에서

redirect시 Attribute 전달하는 것은 GET방식이 수월하나

POST방식으로 전달하고자 할 때...

 

Spring MVC 3.1 이상에서 가능한...

 

public String xxx( xxVO xxxVO, ..., RedirectAttributes redirectAttributes ) throws Exception {

   ...

   redirectAttributes.addFlashAttribute( "yyyVO", yyyVO );

   return "redirect:/xxx.do";

}

 

 

@ResponseBody Annotation을 사용하게 되면

Controller에서 return "json결과"; 하는 경우

json으로 "json결과" 라는 String 을 받게된다.

 

Y/N 식의 단발성 DATA라면 관계 없지만

여러개의 결과값을 받고자 한다면

Map식의 결과를 받는 것이 좋다.

 

이럴 때 사용할 수 있는 방법이다.

 

 

* xxHTML.jsp 의 경우

 

$.ajax( {
    type : "post",
    url : "/xxProc.do",
    data : $("#formid").serialize(),
    dataType : "json",
    success : function( data ) {
        if( "Y" == data.result ) {
            alert( data.message );
        }
    }
} );

 

* xxController.java 의 경우

 

@Controller
public class xxController {

   @RequestMapping( value = "/xxProc.do" )
   public ModelAndView xxProc( xxVO xxxVO, ModelMap model ) throws Exception {
      model.put( "result", "Y" );

      model.put( "message", "OK" );

   return new ModelAndView( "jsonV", model );

}

 

 

이렇게 처리하기 위해 기본 설정이 필요하다.

 

* web.xml

  <servlet>
    <servlet-name>action</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>/WEB-INF/config/dispatcher-servlet.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>

 

* dispatcher-servlet.xml

<bean id="beanNameResolver" class="org.springframework.web.servlet.view.BeanNameViewResolver" p:order="0" />

<bean id="jsonV" class="org.springframework.web.servlet.view.json.MappingJackson2JsonView">

   <property name="contentType" value="application/json;charset=UTF-8"></property>

</bean>

 

* pom.xml

  <dependency>
   <groupId>com.fasterxml.jackson.core</groupId>
   <artifactId>jackson-databind</artifactId>
   <version>2.5.1</version>
  </dependency>

 

  1. 익명 2017.01.03 21:25

    비밀댓글입니다

    • 행이™ 2017.01.09 18:57 신고

      원래 $.ajax를 쓰면 안움직이긴한데요.
      정상적으로 호출이 되었는지는
      호출하려는 해당 method에 print를 쓰셔서 확인하시거나
      명확하게 return을 받은 값을 alert 해보심이 정확하겠죠?

  2. 알 수 없는 사용자 2017.06.06 22:04

    고맙습니다.

참고 : egovframework:파일관리 - File Manage 서비스 -

http://www.egovframe.go.kr/wiki/doku.php?id=egovframework:%ED%8C%8C%EC%9D%BC%EA%B4%80%EB%A6%AC

 

참고 : egovframework:rte:fdl:file_upload - File Upload 서비스 -

http://www.egovframe.go.kr/wiki/doku.php?id=egovframework:rte:fdl:file_upload

 

 

eGovFrame 3.2

eGovFrame Web Project 에서

org.springframework.web.multipart.MultipartHttpServletRequest 를 이용한

다중 파일 업로드를 처리하기 위해서 아래 설정이 필요하다.

 

1. \workspace\ProjectName\src\main\resources\egovframework\spring\context-common.xml 

 <bean id="spring.RegularCommonsMultipartResolver"
  class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    <property name="maxUploadSize" value="100000000" />
    <property name="maxInMemorySize" value="100000000" />
 </bean>

 

2. \workspace\ProjectName\pom.xml

 <dependencies> 에 아래 추가

      ...

    <dependency>
        <groupId>commons-fileupload</groupId>
        <artifactId>commons-fileupload</artifactId>
        <version>1.2.2</version>
    </dependency>
    <dependency>
        <groupId>commons-io</groupId>
        <artifactId>commons-io</artifactId>
        <version>2.0.1</version>
    </dependency>
 </dependencies>

 

3. xxxController.java 

 @RequestMapping(value = "/xxx.do")
 public String xxx( MultipartHttpServletRequest request ) throws Exception {

     MultipartFile file1 = request.getFile( "file1" );

     File savefile1 = new File( "savepath", "filename" );

     file1.transferTo( savefile );

     ....
 }

 

4. xxx.jsp 

 <form id="frmxxx" action="/xxx.do" method="post" enctype="multipart/form-data">

      <input type="file" name="file1" />

      <input type="file" name="file2" />

 </form>

 

 

'plming > Java - Spring' 카테고리의 다른 글

redirect시 POST방식 Attribute 전달하기  (0) 2016.03.15
ajax @ResponseBody없이 json 처리  (3) 2016.03.08
전자정부프레임워크(egov) 파일업로드  (1) 2015.10.06
Excel Upload  (1) 2010.12.20
ORM (Object Relation Mapping)  (0) 2010.09.12
Spring MVC - 에러 처리 전략  (0) 2010.09.11
  1. Mr.mandu 2016.12.21 14:47 신고

    파일 업로드할때 파일들을 다중으로 선택할 수 있나요?

Excel 97~2003(.xls)에 대한 파일을 처리할 때에는
별도의 서드파트의 라이브러리들이 있었지만,

Excel 2007(.xlsx)을 처리하면서는
Apache POI (http://poi.apache.org/) 를 활용하는 방법도 괜찮을 듯 싶다.

이를 위해 poi-로 시작하는 .jar 파일들을 import 하면 처리할 수 있다.

poi-3.7-20101029.jar
poi-examples-3.7-20101029.jar
poi-ooxml-3.7-20101029.jar
poi-ooxml-schemas-3.7-20101029.jar
poi-scratchpad-3.7-20101029.jar


 <!-- excelUpload.jsp -->

 <script type="text/javascript">
 function goUploadExcel(){
     var uploadForm = document.uploadForm;

     if( uploadForm.file1.value == "" ) {
         alert( "파일을 업로드해주세요." );
         return false;
     } else if( !checkFileType(uploadForm.file1.value) ) {
         alert( "엑셀파일만 업로드 해주세요." );
         return false;
     }

     if( confirm("업로드 하시겠습니까?") ) {
         uploadForm.action = "/excelUpload.do";
         uploadForm.submit();
     }
 }

 function checkFileType( filePath ) {
     var fileFormat = filePath.toLowerCase();

     if( fileFormat.indexOf(".xls") > -1 ) return true;
     else return false;
 }
 </script>


 <form name="uploadForm" action="" method="post" onSubmit="return false;" encType="multipart/form-data">
     <input type="file" name="file1" />
     <button type="button" onclick="goUploadExcel();" onkeypress="this.onclick();"></button>
 </form>



 <!-- action.xml -->
 
 <bean id="excelUploadController" parent="defaultController" class="controller.excelUploadController">
     <property name="methodNameResolver">
         <ref local="excelUploadControllerMethodNameResolver" />
     </property>
 </bean>
 <bean id="excelUploadControllerMethodNameResolver" class="org.springframework.web.servlet.mvc.multiaction.PropertiesMethodNameResolver">
     <property name="mappings">
         <props>
             <prop key="/excelUpload.do">excelUpload</prop>
         </props>
     </property>
 </bean>
 
 <bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
     <property name="mappings">
         <props>
             <prop key="/excelUpload.do">excelUploadController</prop>
         </props>
     </property>
 </bean>


 // excelUploadController.java

 package controller;


 import java.io.File;
 import java.io.FileInputStream;
 import java.io.IOException;

 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;

 import org.apache.poi.hssf.usermodel.HSSFWorkbook;
 import org.apache.poi.ss.usermodel.Cell;
 import org.apache.poi.ss.usermodel.DateUtil;
 import org.apache.poi.ss.usermodel.Row;
 import org.apache.poi.xssf.usermodel.XSSFWorkbook;
 import org.springframework.web.multipart.MultipartFile;
 import org.springframework.web.multipart.MultipartHttpServletRequest;
 import org.springframework.web.servlet.ModelAndView;
 import org.springframework.web.servlet.mvc.multiaction.MultiActionController;


 public class excelUploadController extends MultiActionController {

     public ModelAndView excelUpload( HttpServletRequest request, HttpServletResponse response ) throws Exception {

         try {
             String rootPath = (request.getSession().getServletContext().getRealPath("/")).replace( "\\", "/" );
             String savePath = rootPath + "uploaddir" + File.separator;

             // 파일이 저장된 실제 경로 + 파일명 찾기

             // Apache POI 사용 시
             // Apache POI (http://poi.apache.org/) - the Java API for Microsoft Documents
             MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest)request;
             MultipartFile mFile = multipartRequest.getFile( "file1" );

             if( multipartFile != null && multipartFile.getSize() > 0 ) {
                 String saveFileName = multipartFile.getOriginalFilename();
                 long fileSize = multipartFile.getSize();

                 if( fileSize > 0 && !saveFileName.equals("") ) {
                     saveFileName = savePath + saveFileName;

                     File tempFile = new File(saveFileName);
                     OutputStream outputStream = new FileOutputStream( tempFile );
                     FileCopyUtils.copy( multipartFile.getInputStream(), outputStream );
                     outputStream.close();


             /******************************************************************************
             // oreilly COS 사용 시
             // oreilly COS (http://www.servlets.com/cos/index.html)
             import com.oreilly.servlet.MultipartRequest
             import com.oreilly.servlet.multipart.DefaultFileRenamePolicy

             int sizeLimit = 30 * 1024 * 1024 ; // 용량제한
             String formName = "";
             String fileName = "";
             Vector vFileName = new Vector();
             Vector vFileSize = new Vector();
             String[] aFileName = null;
             String[] aFileSize = null;
             long fileSize = 0;

             MultipartRequest multi = new MultipartRequest(request, savePath, sizeLimit, "euc-kr", new DefaultFileRenamePolicy());
             Enumeration formNames = multi.getFileNames();
             while( formNames.hasMoreElements() ) {
                 formName = (String)formNames.nextElement();
                 fileName = multi.getFilesystemName(formName);

                 if(fileName != null) {   // 파일이 업로드 되면
                     fileSize = multi.getFile(formName).length();
                     vFileName.addElement(fileName);
                     vFileSize.addElement(String.valueOf(fileSize));
                 }
             }
             ******************************************************************************/


                     // Excel 처리
                     // Excel 97~2003(.xls)과 Excel 2007(.xlsx)은 각각 처리해야 한다.
                     if( saveFileName.indexOf(".xlsx") > -1 ) readExcel2007( saveFileName );
                     else if( saveFileName.indexOf(".xls") > -1 ) readExcel( saveFileName );
                 }
             }
         } catch ( Exception ex ) {
             ex.printStackTrace();
         }

         return new ModelAndView( nextPage );
     }


     // Excel 2007(.xlsx) 이상 파일처리
     public void readExcel2007( String excel ) throws IOException {
         // check file
         File file = new File( excel );
         if( !file.exists() || !file.isFile() || !file.canRead() ) {
             throw new IOException( excel );
         }

         // http://poi.apache.org/apidocs/index.html?overview-summary.html
         // http://poi.apache.org/apidocs/org/apache/poi/xssf/usermodel/XSSFWorkbook.html
         XSSFWorkbook wb = new XSSFWorkbook( new FileInputStream(file) );
         try {
             for( int i=0; i<wb.getNumberOfSheets(); i++ ) {
                 for( Row row : wb.getSheetAt(i) ) {
                     for( Cell cell : row ) {
                         switch( cell.getCellType() ) {
                             case XSSFCell.CELL_TYPE_STRING:
                                 cell.getRichStringCellValue().getString();
                                 break;
                             case XSSFCell.CELL_TYPE_NUMERIC:
                                 if( HSSFDateUtil.isCellDateFormatted(cell) ) {
                                     java.util.Date dateValue = cell.getDateCellValue();
                                     Integer year = dateValue.getYear(); // or getYear
                                     if (year != -1) dateFormat.format(dateValue);
                                     else timeFormat.format(dateValue);
                                 }
                                 else {
                                     Double.valueOf( cell.getNumericCellValue() ).intValue();
                                 }
                                 break;
                             case XSSFCell.CELL_TYPE_FORMULA:
                                 cell.getCellFormula();  break;
                             case XSSFCell.CELL_TYPE_BOOLEAN:
                                 cell.getBooleanCellValue();  break;
                             case XSSFCell.CELL_TYPE_ERROR:
                                 cell.getErrorCellString();
                                 cell.getErrorCellValue();  break;
                             case XSSFCell.CELL_TYPE_BLANK: break;
                             default: break;
                         }
                     }
                 }
             }
         } catch( Exception ex ) {
             ex.printStackTrace();
         }
     }


     // Excel 97~2003(.xls) 파일처리
     public void readExcel( String excel ) throws IOException {
         // check file
         File file = new File( excel );
         if( !file.exists() || !file.isFile() || !file.canRead() ) {
             throw new IOException( excel );
         }

         // http://poi.apache.org/apidocs/index.html?overview-summary.html
         // http://poi.apache.org/apidocs/org/apache/poi/hssf/usermodel/HSSFWorkbook.html
         HSSFWorkbook wb = new HSSFWorkbook(new FileInputStream(file));
         try {
             for( int i=0; i<wb.getNumberOfSheets(); i++ ) {
                 for( Row row : wb.getSheetAt(i) ) {
                     for( Cell cell : row ) {
                         switch( cell.getCellType() ) {
                             case HSSFCell.CELL_TYPE_STRING:
                                 cell.getRichStringCellValue().getString();
                                 break;
                             case HSSFCell.CELL_TYPE_NUMERIC:
                                 if( HSSFDateUtil.isCellDateFormatted(cell) ) {
                                     java.util.Date dateValue = cell.getDateCellValue();
                                     Integer year = dateValue.getYear(); // or getYear
                                     if (year != -1) dateFormat.format(dateValue);
                                     else timeFormat.format(dateValue);
                                 }
                                 else {
                                     Double.valueOf( cell.getNumericCellValue() ).intValue();
                                 }
                                 break;
                             case HSSFCell.CELL_TYPE_FORMULA:
                                 cell.getCellFormula();  break;
                             case HSSFCell.CELL_TYPE_BOOLEAN:
                                 cell.getBooleanCellValue();  break;
                             case HSSFCell.CELL_TYPE_ERROR:
                                 cell.getErrorCellValue();  break;
                             case HSSFCell.CELL_TYPE_BLANK: break;
                             default: break;
                         }
                     }
                 }
             }
         } catch( Exception ex ) {
             ex.printStackTrace();
         }
     }

 }



'plming > Java - Spring' 카테고리의 다른 글

ajax @ResponseBody없이 json 처리  (3) 2016.03.08
전자정부프레임워크(egov) 파일업로드  (1) 2015.10.06
Excel Upload  (1) 2010.12.20
ORM (Object Relation Mapping)  (0) 2010.09.12
Spring MVC - 에러 처리 전략  (0) 2010.09.11
Spring MVC - 다국어 지원  (0) 2010.09.05
  1. 조용준 2013.11.27 10:28

    엑셀업로드하면 디비에 인설트되는건가요?

ORM이란, 객체형 데이터(Java의 Object)와 관계형 데이터(관계형 데이터베이스의 테이블) 사이에서 개념적으로 일치하지 않는 부분을 해결하기 위하여 이 둘 사이의 데이터를 매핑(Mapping)하는 것.
객체형 데이터와 관계형 데이터의 각 속성들을 매핑할 경우 관계형 데이터를 객체형 데이터처럼 사용하는 것이 가능하다.

ORM 프레임워크는 Jboss 오픈 소스 그룹(http://www.jboss.org)에 포함된 Hibernate (http://www.hibernate.org), iBatis (http://ibatis.apache.org), OJB (http://db.apache.org/ojb) 등 오픈 소스 진영에서 개발되어 많이 사용되고 있다.  JDBC 기반 하에서 개발되던 퍼시스턴스 계층의 대부분을 ORM 프레임워크가 대체할 것이다.


[출처] Spring 프레임워크 워크북

'plming > Java - Spring' 카테고리의 다른 글

전자정부프레임워크(egov) 파일업로드  (1) 2015.10.06
Excel Upload  (1) 2010.12.20
ORM (Object Relation Mapping)  (0) 2010.09.12
Spring MVC - 에러 처리 전략  (0) 2010.09.11
Spring MVC - 다국어 지원  (0) 2010.09.05
Spring MVC - 파일 업로드  (0) 2010.09.03

Controller 내에서 발생하는 에러를 정교하게 처리하기 위해 ExceptionResolver를 이용할 수 있다.

 action-servlet.xml - ExceptionResolver를 설정하는 부분

 <bean id="exceptionResolver" class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
     <property name="exceptionMappings">
         <props>
             <prop key="net.javajigi.user.ExistedUserException">defaultErrorMessage</prop>
             <prop key="net.javajigi.user.UserNotFoundException">defaultErrorMessage</prop>
         </props>
     </property>
     <property name="exceptionAttribute" value="sampleException" />
     <property name="defaultErrorView" value="error" />
 </bean>

Controller 내에서 net.javajigi.user.ExistedUserException 이 발생할 경우 "sampleException" 이름으로 "WEB-INF/jsp/defaultErrorMessage.jsp" 파일에 에러 메시지를 출력하게 된다.  "exceptionAttribute" 속성을 사용하지 않았을 때의 디폴트 값은 "exception" 이다.  "defaultErrorView" 속성은 앞의 "exceptionMappings" 에 정의된 Exception 외의 다른 에러가 발생할 경우 "/WEB-INF/jsp/error.jsp" 에 에러 메시지를 출력(에러 안내문장이 정해진)하도록 설정한 것이다.

 defaultErrorMessage.jsp

 <%@ taglib uri="http://java.sun.com/jstl/core_rt" prefix="c"%>
 <%@ taglib uri="http://java.sun.com/jstl/fmt_rt" prefix="fmt" %>

 <p><span class="fieldError"><c:out value="${sampleException.message}"/></span></p>



입력화면의 입력 값들을 유지한 상태로 에러 메시지를 출력하기 위해서는 Controller에서 Exception을 직접 처리해야 한다.

 import org.springframework.validation.BindException;
 import org.springframework.web.servlet.ModelAndView;
 import org.springframework.web.servlet.mvc.SimpleFormController;

 public class UserFormController extends SimpleFormController {

     public ModelAndView onSubmit(HttpServletRequest request,
             HttpServletResponse response, Object command, BindException errors)
             throws Exception {

             try {
                 userService.addUser(user);
             } catch (ExistedUserException e) {
                 ModelAndView mav = new ModelAndView(getFormView());
                 mav.addObject("user", user);
                 mav.addObject("existedUserException", e);

                 return mav;
             }


 - 에러 메시지를 출력하는 JSP

 <%@ taglib uri="http://java.sun.com/jstl/core_rt" prefix="c"%>
 <%@ taglib uri="http://java.sun.com/jstl/fmt_rt" prefix="fmt" %>
 <%@ taglib uri="http://www.springmodules.org/tags/commons-validator" prefix="v"%>
 <%@ taglib uri="http://www.springframework.org/tags" prefix="spring"%>
 
 <c:if test="${not empty existedUserException }">
 <br/>
 <p><b><fmt:message key="error.message"/></b> :
 <span class="fieldError"><c:out value="${existedUserException.message}"/></span>
 </p>
 </c:if>


[출처] Spring 프레임워크 워크북

'plming > Java - Spring' 카테고리의 다른 글

Excel Upload  (1) 2010.12.20
ORM (Object Relation Mapping)  (0) 2010.09.12
Spring MVC - 에러 처리 전략  (0) 2010.09.11
Spring MVC - 다국어 지원  (0) 2010.09.05
Spring MVC - 파일 업로드  (0) 2010.09.03
Spring MVC - 기타 Controller  (0) 2010.09.02
다국어를 지원하기 위해서 모든 인코딩을 EUC-KR에서 UTF-8로 변경

 web.xml

 <filter>
     <filter-name>Encoding Filter</filter-name>
     <filter-class>net.javajigi.filter.EncodingFilter</filter-class>
     <init-param>
         <param-name>encoding</param-name>
         <param-value>UTF-8</param-value>
     </init-param>
 </filter>


모든 메시지와 이미지 등의 정보를 MessageSource 파일에서 관리함으로써 다국어 지원이 가능하다.

 action-servlet.xml

 <bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
     <property name="basename" value="Messages" />
 </bean>


다른 언어를 추가적으로 서비스할 필요가 발생하면, 같은 키 값을 가지는 MessageSource 파일을 하나 추가하기만 하면된다.

  관리의 편의성을 위하여 MessageSource를 Properties 파일이 아닌 데이터베이스에서 관리하는 경우도 많다.  하지만, JDK에서 제공하는 java.util.ResourceBundle을 이용할 수 없기 때문에 별도의 구현 클래스를 생성해야 하는 단점이 있다.

  java.util.Bundle의 단점은 Properties 파일의 메시지를 초기화 후 캐싱(Caching)을 하고 있기 때문에 메시지가 변경되더라도 애플리케이션을 재시작하기 전까지는 반영이 되지 않는다.  이를 해결하기 위해 ReloadableResourceBundleMessageSource 클래스를 지원한다.

Spring MVC는 접근하는 클라이언트의 Locale 정보를 기준으로 각 언어에 해당하는 MessageSource를 찾는다.  해당 언어에 대한 파일이 없을 경우에는 디폴트로 사용한 Messages.properties 파일에 있는 메시지가 서비스된다.

- Messages.properties : 애플리케이션의 디폴트 언어를 위한 메시지 및 이미지 파일 정보
- Messages_ko.properties : 한글을 위한 메시지 및 이미지 파일 정보
- Messages_en.properties : 영어을 위한 메시지 및 이미지 파일 정보
- Messages_zh.properties : 중국어을 위한 메시지 및 이미지 파일 정보

테스트 하기 위해 Locale 정보/언어를 브라우저에서 변경하면 된다.  IE의 경우, [도구]-[인터넷옵션]의 [일반]탭에서 [언어]를 선택하여 언어 설정을 바꿔주면 된다.  "한국어[ko]"가 제일 위에 올라와 있다. "영어[en]"를 추가하고, 제일 위로 위치하도록 설정하고 브라우저를 새로 시작하면 영어 메시지를 테스트 할 수 있다.




 index.jsp

 <%@page contentType="text/html; charset=utf-8"%>
 <%@ taglib uri="http://java.sun.com/jstl/fmt_rt" prefix="fmt" %>

 <html>
 <head>
 <title><fmt:message key="index.title"/></title>
 <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
 </head>
 <body>

 <div id="welcome">
 <h1><fmt:message key="index.welcome.title"/></h1>

 <fmt:message key="index.welcome.body"/>
 </div>

 </body>
 </html>


JSP 파일에서 메시지를 출력하기 위해 JSTL의 <fmt /> 커스텀 태그를 이용할 수 있다.


Spring MVC는 다국어를 지원하기 위해 여러 종류의 LocalResolver를 가지고 있다.  빈 설정파일에서 정의하지 않을 경우, 디폴트로 AcceptHeaderLocaleResolver가 이용된다. 이외에도 FixedLocaleResolver와 브라우저의 Locale에 따라 해당 언어 서비스를 하는 것이 아닌, 원하는 언어를 선택/서비스할 수 있는 CookieLocaleResolver와 SessionLocaleResolver가 있다.

 import java.util.Locale;
 
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import javax.servlet.http.HttpSession;
 
 import org.springframework.web.bind.RequestUtils;
 import org.springframework.web.servlet.ModelAndView;
 import org.springframework.web.servlet.i18n.SessionLocaleResolver;
 import org.springframework.web.servlet.mvc.Controller;
 
 public class SessionLocaleController implements Controller {
     public static final int KOREA_LOCALE = 1;
     public static final int ENGLISH_LOCALE = 2;
 
     public ModelAndView handleRequest(HttpServletRequest request,
             HttpServletResponse response) throws Exception {
         int localeMode = RequestUtils.getIntParameter(request, "locale", 1);
 
         Locale locale = null;
         if( localeMode == KOREA_LOCALE ){
             locale = Locale.KOREAN;
         } else if( localeMode == ENGLISH_LOCALE ) {
             locale = Locale.ENGLISH;
         } else {
             locale = Locale.KOREAN;
         }
 
         HttpSession session = request.getSession();
         session.setAttribute(SessionLocaleResolver.LOCALE_SESSION_ATTRIBUTE_NAME, locale);
 
         return new ModelAndView("/index");
     }
 }

 action-servlet.xml - SessionLocaleResolver 설정

 <bean id="localeResolver" class="org.springframework.web.servlet.i18n.SessionLocaleResolver" />

 <bean id="/changelocale.do" class="net.javajigi.common.web.SessionLocaleController" />

.../changelocale.do?local=1
.../changelocale.do?local=2

지원해야 하는 언어가 증가하는 부분과 개발이후 변경사항이 발생할 경우의 유지보수 비용의 증가도 줄이는 장점이 있으므로, 초기 빠른 개발 완료를 위해 똑같은 애플리케이션을 언어별로 복사해서 만드는 것보다는 LocaleResolver를 적용하는 것이 낫다.
또한, 다국어를 지원하면서 개발자들이 흔히 간과하는 부분은 이미지를 각 언어별로 관리해야 한다는 것이다.  애플리케이션을 구성하고 있는 이미지에도 글이 포함되어 있기 때문에 이미지의 경로 정보또한 MessageSource에서 관리해야 한다.


[출처] Spring 프레임워크 워크북

1. 파일 업로드를 위한 기본 설정

Spring MVC는 파일 업로드 기능을 지원하기 위하여 Commons 파일 업로드(http://jakarta.apache.org/commons/fileupload)와 COS 파일 업로드(http://www.servlets.com/cos) 라이브러리를 지원하고 있다.

파일 업로드 기능을 구현하기 위해서는 먼저 빈 설정파일에서 MultipartResolver를 정의해야 한다.

 action-servlet.xml - 파일 업로드 기능을 구현하기 위하여 MultipartResolver 정의

 <bean id="multipartResolver"
 class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
     <property name="maxUploadSize">
         <value>10000000</value>
     </property>
     <property name="uploadTempDir" ref="uploadDirResource" />
 </bean>

 <bean id="uploadDirResource" class="org.springframework.core.io.FileSystemResource">
     <constructor-arg>
         <value>D:/Temp/fileupload/temp/</value>
     </constructor-arg>
 </bean>


만약 COS 파일 업로드 라이브러리를 이용하고자 한다면 "org.springframework.web.multipart.cos.CosMultipartResolver"를 이용하면 된다.


2. 가장 간단한 구현 방법 - 첨부 파일의 수가 정적, 동적인 경우 모두 이용 가능

Spring MVC에서 파일 업로드 기능을 구현하기 위하여 가장 쉬운 방법은 HttpServletRequest를 MultipartHttpServletRequest로 캐스팅(Casting)한 다음 첨부된 파일을 직접 얻어내는 방법이다.

 edit.jsp - 파일 업로드 부분

 <form name="boardForm" action="${pageContext.request.contextPath}/board/editBoard.do"
     method="post" enctype="multipart/form-data">

 <input type="file" style="width:400" name="file1"/>
 <input type="file" style="width:400" name="file2"/>
 <input type="file" style="width:400" name="file3"/>

 

 BoardFormController.java - 파일 업로드 부분

 public class BoardFormController extends SimpleFormController {

     private List getBoardFileList(HttpServletRequest request) {
         MultipartHttpServletRequest mpRequest = (MultipartHttpServletRequest) request;
         Iterator fileNameIterator = mpRequest.getFileNames();

         List boardFileList = new ArrayList();
         while (fileNameIterator.hasNext()) {
             MultipartFile multiFile = mpRequest
                     .getFile((String) fileNameIterator.next());

             if (multiFile.getSize() > 0) {
                 BoardFile boardFile = FileUploadUtil.uploadFormFile(multiFile,
                         realUploadPath);
                 boardFileList.add(boardFile);
             }
         }

         return boardFileList;
     }
 }

 

 import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;

 import net.javajigi.board.model.BoardFile;

 import org.springframework.web.multipart.MultipartFile;

 public class FileUploadUtil {

     public static BoardFile uploadFormFile(MultipartFile formFile, String realPath) {
         InputStream stream;

         UUID uuid = UUID.randomUUID();
         String tempFileName = uuid.toString();

         try {
             stream = formFile.getInputStream();

             OutputStream bos = new FileOutputStream(realPath + tempFileName);
             int bytesRead = 0;
             byte[] buffer = new byte[8192];
             while ((bytesRead = stream.read(buffer, 0, 8192)) != -1) {
                 bos.write(buffer, 0, bytesRead);
             }
             bos.close();
             stream.close();

             if (logger.isDebugEnabled()) {
                 logger.debug("The file has been written to \"" + realPath
                         + tempFileName);
             }
         } catch (FileNotFoundException e) {
             e.printStackTrace();
         } catch (IOException e) {
             e.printStackTrace();
         }

         BoardFile boardFile = new BoardFile();
         boardFile.setFileName(formFile.getOriginalFilename());
         boardFile.setFileSize(formFile.getSize());
         boardFile.setContentType(formFile.getContentType());
         boardFile.setTempFileName(tempFileName);

         return boardFile;
     }
 }



3. PropertyEditor를 이용하는 방법 - 첨부 파일의 수가 정적일 경우 사용.

자바빈 규약에는 자바빈에 전달되는 속성의 타입(Type)을 개발자들이 지정하는 것을 가능하도록 하기 위하여 PropertyEditor라는 기능을 지원하고 있다.  Spring MVC의 MultipartResolver를 이용하여 파일을 업로드한 다음 데이터 바인딩(Data Binding)을 이용하여 데이터를 전달할 경우 Command의 속성에 전달되는 데이터의 타입은 MultipartFile이다.  그런데 자료실 게시판에서 첨부 파일 정보를 담당하고 있는 도메인 모델은 BoardFile이다.  따라서 데이터 바인딩 할 때 첨부파일 정보를 MultipartFile에서 BoardFile로 변경해주어야 한다.  이와 같은 작업이 가능하도록 지원하는 것이 자바빈의 PropertyEditor이다.

 public class Board extends BaseObject {
     private BoardFile file1 = null;
     private BoardFile file2 = null;
     private BoardFile file3 = null;

     public BoardFile getFile1() {
         return file1;
     }
     public void setFile1(BoardFile file1) {
         this.file1 = file1;
     }
     ::
 }

 

 BoardFileMultipartPropertyEditor.java - MultipartFile을 BoardFile로 변경해주는 PropertyEditor

 public class BoardFileMultipartPropertyEditor extends PropertyEditorSupport {
     private String realUploadPath;

     public BoardFileMultipartPropertyEditor(String realUploadPath) {
         this.realUploadPath = realUploadPath;
     }

     public void setValue(Object value) {
         if (value instanceof MultipartFile) {
             MultipartFile multipartFile = (MultipartFile) value;

             if (multipartFile.getSize() > 0) {
                 BoardFile boardFile = FileUploadUtil.uploadFormFile(
                         multipartFile, realUploadPath);
                 super.setValue(boardFile);
             } else {
                 super.setValue(null);
             }
         } else {
             super.setValue(value != null ? value.toString().getBytes() : null);
         }
     }
 }

 

 데이터 바인딩을 위하여 BoardFileMultipartPropertyEditor를 이용하는 BoardFormController

 public class BoardFormController extends SimpleFormController {

     protected void initBinder(HttpServletRequest request,
             ServletRequestDataBinder binder) throws Exception {
         binder.registerCustomEditor(BoardFile.class,
                 new BoardFileMultipartPropertyEditor(realUploadPath));

     }

     protected ModelAndView onSubmit(HttpServletRequest request,
             HttpServletResponse response, Object command,
             BindException exception) throws Exception {
         Board board = (Board) command;
         board.addBoardFile(board.getFile1());
         board.addBoardFile(board.getFile2());
         board.addBoardFile(board.getFile3());

         return new ModelAndView(getSuccessView());
     }
 }


  PropertyEditor를 이용할 경우 Command클래스나 Controller가 MultipartFile에 종속될 필요없이 데이터 바인딩만으로 파일업로드 기능을 구현하는 것이 가능하지만, 첨부파일의 수가 동적으로 변경되는 경우에는 사용하기 힘들다는 단점이 있다.

  PropertyEditor는 자바빈의 데이터 바인딩을 처리하기 위하여 유용하게 사용할 수 있는 기능이다.  Spring 프레임워크에서도 이미 많은 PropertyEditor를 제공하고 있다.  PropertyEditor에 관한 자세한 내용은 http://www.springframework.org/docs/reference/validation.html#beans-beans-conversion 문서를 참고하기 바란다.


4. MultipartFile 리스트를 이용하는 방법 - 첨부 파일의 수가 동적일 경우 사용

 edit.jsp - 파일 업로드 기능

 <form name="boardForm" action="${pageContext.request.contextPath}/board/editBoard.do"
     method="post" enctype="multipart/form-data">

 <input type="file" style="width:400" name="file[0]"/>
 <input type="file" style="width:400" name="file[1]"/>
 <input type="file" style="width:400" name="file[2]"/>

 

 public class Board extends BaseObject {
     private List file = null;

     public Board() {
         boardFiles = new ArrayList();
         file = new ArrayList();
     }

     public List getFile() {
         return file;
     }

     public void setFile(List file) {
         this.file = file;
     }
 }

 

 public class BoardFormController extends SimpleFormController {
     protected ModelAndView onSubmit(HttpServletRequest request,
             HttpServletResponse response, Object command,
             BindException exception) throws Exception {
         Board board = (Board) command;
         List fileList = board.getFile();
         Iterator fileIter = fileList.iterator();
         while (fileIter.hasNext()) {
             MultipartFile multiFile = (MultipartFile) fileIter.next();
             if (multiFile.getSize() > 0) {
                 board.addBoardFile(FileUploadUtil.uploadFormFile(multiFile,
                         realUploadPath));
             }
         }

         return new ModelAndView(getSuccessView());
     }
 }


이 방법을 이용할 경우 MultipartFile API와 의존관계에 놓이게 되지만 첨부파일의 수가 동적으로 변경될 경우에는 유용하게 사용할 수 있다.


[출처] http://www.javajigi.net/pages/viewpage.action?pageId=28377096
[출처] Spring 프레임워크 워크북

+ Recent posts