목차 >> Excel 
+- Excel Export  
+- Excel Import

15 장 Excel

이번 장의 목적은 Glue Framework 기반으로 하여 Excel Export, Import 기능을 설명하는데 있다. 이번 장의 범위는 일반적인 Excel 형태에 대해서는 Template 형태로 기능을 지원하며 Site 별 필요한 추가 기능에 대해서는 개발 방법에 대한 가이드를 제공하는 것으로 한다.

Excel Export

Database에서 조회한 Data를 Excel로 Export하기 위해서는 View 객체를 정의하여 구현 가능하다. Glue Framework에서는 아래 3가지의 View Template를 제공한다

그림 : Excel Export
Excel Export

GlueExcelInfo

Excel Export를 위한 정보를 Set하는 Activity Class이다

GlueXMLViewController

Excel Import / Export를 위한 Controller로서 Excel 외 다양한 View에 대해서도 Control 할 수 있다. 기본적으로 GlueSimpleController와 동일하나 Request Parameter [viewname] 값에 해당하는 ModelAndView를 XML로부터 참조하여 View를 만든다.

excel-views.xml

Excel Export를 위한 ModelAndView를 정의한 XML 파일이다. 이 xml에서는 Excel Export방식을 지정할 수 있으며 아래와 같이 3가지 Tempate을 제공한다

  1. GluePOIExcelView : POI의 HSSF와 XSSF을 구현하여 Excel 2007이전 / 이후 버전을 모두 지원. Glue 라이브러리에 포함될 경우 라이센스 문제가 발생할 가능성이 있으므로 Sample로 공개
  2. GlueJExcelView : AbstractJExcelView를 확장하여 구현하였으며 Excel 2003 이전 버전에 대해서만 지원 가능하다. 성능상으로 GluePOIExcelView보다 빠르다.
  3. HtmlExcelView - 구현 예정 : Html로 디자인한 화면과 JSTL을 이용하여 Template으로 Excel 디자인 및 Format을 다양하게 구현할 수 있다.

Excel Import

Database로 Data를 Insert 또는 Update하기 위해 지정한 Excel을 파싱하여 GlueContext에 ListMap<String, Object>형태로 저장하는 기능을 제공한다.

그림 : Excel Import
Excel Import

GlueXMLViewController

화면의 [multipart/form-data] Data에 대해 MultipartRequest 객체를 생성한 후 Excel 파일을 파싱(Map의 List로 변환)하여 GlueContext에 저장한다.
저장하는 Key는 [sheet명]이다.
예를 들어 Sheet명이 emp인 경우 emp sheet의 Data를 ListMap<String, Object>형태로 변환하여 [emp]를 Key로 GlueContext에 저장한다.

Glue Service

Glue AD 작성 시 GlueJDBCUpdate, GlueJDBCInsert, GlueJDBCDelete Activity를 사용하여 Import한 Data를 DB로 Update, Insert, Delete가 가능하다.
Property 작성 방법 : Property [chk-name]은 삭제하고 [list-key]에 Excel sheet명을 입력.

Glue 환경 설정

Glue Framework 4.0 패키지에 포함된 설정파일을 기준으로 작성하였다

  • web.xml

    기본적인 Glue Framework 4.x 버전에서 사용하는 web.xml과 크게 다른 점은 없으며 Excel Control을 위해 아래와 같은 DispatcherServlet 추가한다. url-pattern를 이용해 *.excel 으로 URL 를 분리한다.

    <servlet>
        <servlet-name>excel</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>excel</servlet-name>
        <url-pattern>*.excel</url-pattern>
    </servlet-mapping>
    
  • servlet-name-servlet.xml

    web.xml 에 servlet-name을 excel로 정의 했다면, excel-servlet.xml 을 아래와 같이 구성한다.
    urlMapping 빈의 mappings property에는 Excel을 Upload, Download하기 위한 URL과 담당하는 Controller명을 지정한다.
    InternalResourceViewResolver를 통해 XML 파일에 해당 View가 존재하지 않는 경우 JSP 파일을 찾는다

    <bean id="simpleUrlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
        <property name="mappings">
            <value>
                /**/excelUpload.excel=glueXMLViewController
                /**/excelDownload.excel=glueXMLViewController
            </value>
        </property>
    </bean>
    <!-- Excel Upload, Download Controller -->
    <bean id="glueXMLViewController" class="com.poscoict.glueframework.web.control.spring.GlueXMLViewController" />
    <!-- Excel View -->
    <bean class="org.springframework.web.servlet.view.XmlViewResolver">
        <property name="location">
            <value>/WEB-INF/excel-views.xml</value>
        </property>
        <property name="order" value="0" />
    </bean>
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/excel/" />
        <property name="suffix" value=".jsp" />
    </bean>
    
  • /WEB-INF/excel-views.xml

    XMLViewResolver의 location property에 정의된 파일은 다음과 같이 구성한다.

    <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.springframework.org/schema/beans 
                            http://www.springframework.org/schema/beans/spring-beans-3.2.xsd">
        <!-- Generic View for excel included 2007 higher -->
        <bean id="GluePOIExcelView" class="sample.web.control.spring.view.GluePOIExcelView"/>
        <!-- Generic View for JExcel(JXL) -->
        <bean id="GlueJExcelView" class="com.poscoict.glueframework.web.control.spring.view.GlueJExcelView"/>
    </beans>
    

    bean id는 화면에서는 사용할 Model명을 정의한다.

Sample 화면

다음 ActivityDiagram는 아래 3가지 Case를 다루고 있다.

  1. download : 사원 및 부서 테이블을 조회한 후 Excel Export를 위한 정보를 Set하는 Activity로 구성된 Case
  2. download2 : 사원 및 부서 테이블 조회만 수행하며 Excel Export를 위한 정보는 화면(JSP)에서 받는 Case
  3. upload : Upload된 Excel Data로 Update하는 Case
    그림 : excel-service.xml
    excel-service.xml

    아래는 Download를 위한 JSP 페이지의 일부이다. viewname으로 GluePOIExcelView를 지정하여 POI Library를 이용하여 Excel을 Generate하며GlueJExcelView 나 개발자가 직접 구현한 view명을 지정하여 사용할 수 있다.

    <form name="downloadForm" action="./excelDownload.excel" method="post">
    <input type="hidden" name="ServiceName" value="excel-service">
    <input type="hidden" name="download" value="1">
    <input type="hidden" name="viewname" value="GluePOIExcelView">
    <input type="text" name="deptno" value="20">
    <input type="submit" name="Excel Download">
    </form>
    

    GlueExcelInfo Activity 에는 Excel을 생성하기 위한 부가 정보를 입력한다. 작성예는 아래와 같고 자세한 사용법은 GlueExcelInfo JavaDoc을 참고한다

    <activity name="Excel Export Setup" class="com.poscoict.glueframework.biz.activity.GlueExcelInfo">
        <transition name="success" value="end" />
        <property name="sheet-name" value="사원정보,부서정보" />
        <property name="dept-column-width" value="80,120" />
        <property name="dept-column-id" value="DEPTNO,DNAME" />
        <property name="sheet-id" value="emp,dept" />
        <property name="dept-column-name" value="부서번호,부서명" />
    </activity>
    

    아래는 Excel Import를 위한 JSP페이지의 일부이다. forwardname으로는 glue 수행 후 jsp 페이지명을 지정할 수 있다.

    <form name="uploadForm" action="./excelUpload.excel" method="post" onSubmit="return goUploadExcel();" encType="multipart/form-data">
    <input type="file" name="excelFileName" />
    <input type="hidden" name="ServiceName" value="excel-service">
    <input type="hidden" name="upload" value="1">
    <input type="hidden" name="forwardname" value="excelUpload">
    <input type="submit" ></button>
    </form>
    

    Excel Import와 관련 파싱된 Excel은 GlueContext에 저장되며 Reusable Activity를 활용하여 수정, 삭제, 등록이 가능하다. 아래는 그 예이다.

    <activity name="부서수정" class="com.poscoict.glueframework.biz.activity.GlueJdbcModify">
        <transition name="success" value="end" />
        <property name="result-key" value="dept.update_resultList" />
        <property name="param-bindings" value="DNAME=DNAME|DEPTNO=DEPTNO" />
        <property name="sql-key" value="dept.update" />
        <property name="dao" value="test-dao" />
        <property name="list-key" value="부서정보" />
    </activity>
    

Custumizing

Glue에서 제공하는 View Class는 일반적인 Case에 대해 제공하며 각 Site별 추가 요구사항이 존재하는 경우 별도의 Excel View를 만들도록 한다.

POI용 View 제작

POI API에서 CellStyle을 생성하기 위해서는 workbook이 필요하기 때문에 아래와 같이 View Class의 getExcelStyle()을 재정의하도록 한다. 아래는 숫자 타입의 Cell에 대해 왼쪽 정렬하는 샘플 소스이다.

public class LeftAlignExcelView extends GluePOIExcelView {
    . . . .
    protected ExcelStyle getExcelStyle(Workbook workbook){
        ExcelStyle excelStyle = new ExcelStyle(workbook);
        // excel style을 수정하는 로직
        CellStyle bigDecimalCellStyle =excelStyle.getBigDecimalCellStyle();
        bigDecimalCellStyle.setAlign(CellStyle.ALIGN_LEFT);
        . . . . .
        return excelStyle;
    }
}

JExcel View 제작

GlueJExcelView에서는 GlueContext에서 [excel-style]로 지정된 객체를 Excel Style로 사용 가능하다. 따라서 Excel Style을 변경하고자 한다면 JExcelFormat Class를 확장하여 Customizing 후 Activity Diagram에서 GlueContext에 [excel-style]를 Key로 저장하면 된다.

public class JExcelFormat {
    WritableCellFormat headerCellFormat;      // 
    WritableCellFormat bigDecimalCellFormat;
    WritableCellFormat timestampCellFormat;
    WritableCellFormat stringCellFormat;
    String dateFormat = "yyyy-mm-dd";
    . . . . 
}

와 같이 정의된 JExcelFormat을 상속받아

public class MyExcelFormat extends JExcelFormat {
    public void setHeaderCellFormat(WritableCellFormat headerCellFormat) {
        this.headerCellFormat = headerCellFormat;
        this.headerCellFormat.setBorder(Border.ALL, BorderLineStyle.THICK);
        . . . .
    }
    . . . . 
}

와 같이 원하는 부분을 수정한다.