目前分類:JAVA - Struts2 (16)

瀏覽方式: 標題列表 簡短摘要

使用 EasyUI 的 Datagrid 選擇到一筆記錄後,將這一筆完整的資料要送到後端 Java 接收,可以先轉換成 JSON 的格式再後送。

UI 的圖示如下,可以用 FireBug 去查看 JavaScript 裡的資料

datagrid

 

作法如下:

HTML 的 Java Script Code:

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<%@    taglib prefix="i" uri="/esayui-tags" %>

<i:html title="easyui-datagrid & EasyUI Demo" >

<div class="col-sm-1"></div>
<div class="col-sm-10">
<i:form id="fmEmpIDLogin" action="Login"  method="post" isExtraPara="false">
                
                    <input name="reqCode" value="" type="hidden" />

    <table id="dg" class="easyui-datagrid" title="CheckBox Selection on DataGrid" style="width:100%;height:400px;padding:10px;"
            data-options="url:'Login_multiEmpID?reqCode=EmpIDList',method:'get',rownumbers:true,pagination:true,singleSelect:true,toolbar: '#tb'">
        <thead>
            <tr>
                <th data-options="field:'ck',checkbox:true"></th>
                <th data-options="field:'empId',sortable:true"> <s:property value="getText('display.sc004.empid')"/> </th>
                <th data-options="field:'realName',sortable:true"> <s:property value="getText('display.sc004.alternatename')"/> </th>
                <th data-options="field:'companyName',sortable:true"> <s:property value="getText('display.sc006.name')"/> </th>
                <th data-options="field:'deptName',sortable:true"> <s:property value="getText('display.sc007.name')"/> </th>
                <th data-options="field:'deptsManagerId',hidden:true">MANAGER_ID</th>
                <th data-options="field:'userId',hidden:true">USER_ID</th>
            </tr>
        </thead>
    </table>

    <div id="tb" style="height:auto">
        <a href="javascript:void(0)" class="easyui-linkbutton" data-options="iconCls:'icon-add',plain:true" onclick="submitForm()">Submit</a>
    </div>

</i:form>
</div>
<div class="col-sm-1"></div>
</i:html>

<script type="text/javascript">
    function submitForm(){
        $("#fmEmpIDLogin input[name='reqCode']").val("empIdLogin");
        var rowData = $('#dg').datagrid('getSelected');
        var cellRow = $("<input>").attr("type", "hidden").attr("name", "cellRow").val(JSON.stringify(rowData));
        $('#fmEmpIDLogin').append($(cellRow));
        $('#fmEmpIDLogin').submit();       
    }    
</script>

 

Java Code: 利用 String[] cellRow 接收,並用 Gson().fromJson(cellRow[0], Map.class); 作轉換即可

public class LoginAction extends BaseSupport {
    
    private String[] cellRow;    

    public String empIdLogin() throws Exception {
        String loginResult=SUCCESS;
        Userinfo userInfo = null;
        logger.debug(cellRow[0]);
        Map<String,Object> result = new Gson().fromJson(cellRow[0], Map.class);
        
        String userEmpID = result.get("empId") == null ? "" : result.get("empId").toString();
        
        return loginResult;
    }
        

    public String[] getCellRow() {
        return cellRow;
    }

    public void setCellRow(String[] cellRow) {
        this.cellRow = cellRow;
    }

}
文章標籤

MIS 發表在 痞客邦 留言(0) 人氣()

上次介紹 Spring Quartz Job Schedule Simple Example 工作排程器 ,現在再來使用 Spring 原生的 Task Execution and Scheduling,首先來瞭解一下 @Scheduled annotation 的意思

This annotation is used for task scheduling. The trigger information needs to be provided along with this annotation. You can use the properties fixedDelay/fixedRate/cron to provide the triggering information.

1. fixedRate: makes Spring run the task on periodic intervals even if the last invocation may be still running. 固定時間執行,不管上一次是否結束
2. fixedDelay: specifically controls the next execution time when the last execution finishes. 上一次執行結束後,再依設定的固定時間執行
3. cron: is a feature originating from Unix cron utility and has various options based on your requirements. BJ4(就不解釋了)

 

方法 1) Task scheduling using fixed delay attribute in @Scheduled annotation

Step 01: 設定 applicationContext.xml,將 task 選取

applicationContext  

<?xml version="1.0" encoding="UTF-8"?>
<beans 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:cache="http://www.springframework.org/schema/cache"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:jpa="http://www.springframework.org/schema/data/jpa"
    xmlns:jee="http://www.springframework.org/schema/jee"
    xmlns:task="http://www.springframework.org/schema/task"
    xsi:schemaLocation="http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd
        http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.2.xsd
        http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.2.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa-1.8.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">

    <!-- Spring Task using Annotation-->
    <task:annotation-driven/>
    <bean id="SpringTask-Annotation" class="com.mis.demo.SpringTaskAnnotationDemo"/>
    

</beans>   

 

Step 02: 建立 SpringTaskAnnotationDemo.java

package com.mis.demo;

import java.util.Date;
import org.springframework.scheduling.annotation.Scheduled;
public class SpringTaskAnnotationDemo {
    @Scheduled(fixedDelay = 5000)
    //@Scheduled(fixedRate = 5000)
    public void demoServiceMethod()
    {
        System.out.println("Method executed at every 5 seconds. Current time is :: "+ new Date());
    }
}

這樣就可以運作了,簡單吧 !!

 

方法 2) Task scheduling using cron expression in @Scheduled annotation

Step 01: 在 applicationContext.xml 設定 class 的 task:scheduled 執行方法,所以在 SpringTaskExecutorDemo.java 的執行 method 為 execute。

    <!-- Spring Task Using cron -->
    <bean id="SpringTask-Cron" class="com.mis.demo.SpringTaskExecutorDemo"/>
    <task:scheduled-tasks>
        <task:scheduled ref="SpringTask-Cron" method="execute" cron="*/5 * * * * ?"/>
    </task:scheduled-tasks>

 

Step 02:  建立 SpringTaskExecutorDemo.java

package com.mis.demo;

import java.util.Calendar;


public class SpringTaskExecutorDemo {
    public void execute () {
        System.out.println("SpringTaskExecutorDemo: Run at " + Calendar.getInstance().getTimeInMillis() );
    }
}

 

這樣就可以運作了,也很簡單吧 !!

 

 

 

 

參考:

http://howtodoinjava.com/spring/spring-core/4-ways-to-schedule-tasks-in-spring-3-scheduled-example/

http://jimwayne.blogspot.tw/2014/04/spring-framework.html

http://docs.spring.io/spring/docs/current/spring-framework-reference/html/scheduling.html

MIS 發表在 痞客邦 留言(0) 人氣()

Struts 2 Customize Theme & Freemarker Template 客制佈景與模板 說明了Struts2 的 tags 是可以自行客制成自已想要的佈景,現在來說明如何使用 FreeMarker 來制作 Struts2 屬於自已建作的 tag libs.

工具:

eclipse : Version: Mars Release (4.5.0) Build id: 20150621-1200

pom.xml:

struts2-core: 2.5.8

struts-annotations: 1.0.5 (不可以用 1.0.6 會出現 tlibVersion Missing 的錯誤)

commons-logging: 1.2

jsp-api : 2.2

javax.servlet-api : 4.0.1

 

Step 01:  建立一個空的 maven project

tag_01

tag_02

 

Step 02: 建立客制的 class: HtmlTag.java 在 package com.easyui.struts2.views.jsp.ui 下

package com.easyui.struts2.views.jsp.ui;

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

import org.apache.struts2.components.Component;
import org.apache.struts2.views.jsp.ui.AbstractClosingTag;

import com.easyui.struts2.components.Html;
import com.opensymphony.xwork2.util.ValueStack;

public class HtmlTag extends AbstractClosingTag {

    @Override
    public Component getBean(ValueStack stack, HttpServletRequest req, HttpServletResponse res) {
        
        return new Html(stack, req, res);
    }

}

 

Step 03 : 建立客制的 class: Html.java 在 package com.easyui.struts2.components , 此檔主要是要產生 .tld 的標籤描述檔, 以及告訴 freemarker 要讀取那一個 ftl , 此範例是要有 html.ftl 與 html-close.ftl 這兩個檔案.

package com.easyui.struts2.components;

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

import org.apache.struts2.components.ClosingUIBean;
import org.apache.struts2.views.annotations.StrutsTag;

import com.opensymphony.xwork2.util.ValueStack;

@StrutsTag(
        name="html",
        tldTagClass="com.easyui.struts2.views.jsp.ui.HtmlTag",
        description="建立一個空的 HTML 結構",
        allowDynamicAttributes=true)
public class Html extends ClosingUIBean {

    public Html(ValueStack stack, HttpServletRequest request, HttpServletResponse response) {
        super(stack, request, response);
        
    }

    @Override
    public String getDefaultOpenTemplate() {        
        return "html";
    }

    @Override
    protected String getDefaultTemplate() {        
        return "html-close";
    }

}

註:

1. 在 pom.xml 中需加入 struts-annotations: 1.0.5 才可以使用 annotations 描述

2. @StrutsTag: annotation for marking a Struts tag
3. @StrutsTagAttribute: annotation for marking an attribute of a Struts tag

 

Step 04: 建立此 tags (標籤) 的 templates & theme

1. 建立 package: template.easyui 並撰寫 html.ftl 與 html-close.ftl

2. 建立 空的 package: template.easyui.html 用來存放 Tobago plugin 自動產生的相關樣版檔案

html.ftl 檔

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>${parameters.title}</title>  
</head>
<body>

 

html-close.ftl 檔


</body>
</html>

 

Step 05: 用 Tobago plugin  建立 TLD file 及使用 Maven 產生這個 taglib 的 jar 檔

請看附註二

 

Step 06: 佈署 (Deploy taglib in your Web application) , 將這個 taglib 的 jar 檔放在 WEB-INF/lib 下

記得要在 struts.xml 裡加入 <constant name="struts.ui.theme" value="easyui"/> , 這樣才會去讀取 JAR 檔 template.easyui 裡的 ftl 檔案

 

Step 07: JSP 裡使用客製的 tag libs

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<%@ taglib prefix="i" uri="/esayui-tags" %>

<i:html title="Basic Layout - jQuery EasyUI Demo">

hi easyui-tags

    <s:form action="Login">
        <s:textfield key="username"/>
        <s:password key="password" />
        <s:submit/>
    </s:form>


</i:html>

 

附註:

一、 Struts2 taglibs Introduction

Few words about the elements of the Struts2 UI component framework should help to understand better the scenario.

JSP Tag: implementation of the JSP tag (e.g TextFieldTag). Notice Struts2 has also Velocity and FreeMarker tags

UI Component: actual implementation of the behavior of the component (e.g TextField)

Template: FreeMarker template which renders the html markup (e.g. <input type=”text”….)

Theme: collection of templates (e.g. simple or ajax)

 

二、整個專案結構如下

tag_03  

註:

1. 在 pom.xml 中需加入 tobago 描述, 才會自動產生目錄: src/main/resources/META-INF 的 easyui-tags.tld 描述檔及 package: template.easyui.html 裡的 html.html

2. 目前 的編譯器 complier 需用 JDK 1.7.x 版才會成功,   JDK1.8.x 會無法產生 easyui-tags.tld 描述檔 及相關的樣版檔

tag_04  

3. Tobago plugin 在 pom.xml 的設定如下:

<plugin>
    <groupId>org.apache.myfaces.tobago</groupId>
    <artifactId>maven-apt-plugin</artifactId>                            
    <configuration>
        <A>
                   uri=/esayui-tags,tlibVersion=${project.version},jspVersion=2.0,shortName=easyui,displayName="EasyUI Tags",
                   outFile=${basedir}/src/main/resources/META-INF/${project.artifactId}.tld,
                   description="EasyUI Tags",
                   outTemplatesDir=${basedir}/src/main/java/template/easyui/html                
        </A>
        <resourceTargetPath>target</resourceTargetPath>
        <fork>false</fork>
        <force>true</force>
        <nocompile>true</nocompile>
        <showWarnings>true</showWarnings>
        <factory>
            org.apache.struts.annotations.taglib.apt.TLDAnnotationProcessorFactory
        </factory>
        <target>1.5</target>
        <includes>
            <include>**/*.java</include>
        </includes>
    </configuration>
    <executions>
        <execution>
            <phase>compile</phase>
            <goals>
                <goal>execute</goal>
            </goals>
        </execution>
    </executions>
</plugin>

 


 三、 完整的 pom.xml 檔

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.gu.apps</groupId>
  <artifactId>easyui-tags</artifactId>
  <version>1.0-SNAPSHOT</version>
  <name>easyui-tags</name>
  <dependencies>
      <dependency>
          <groupId>org.apache.struts</groupId>
          <artifactId>struts2-core</artifactId>
          <version>2.3.24.1</version>
      </dependency>
      <dependency>
          <groupId>org.apache.struts</groupId>
          <artifactId>struts-annotations</artifactId>
          <version>1.0.5</version>
      </dependency>
      <dependency>
          <groupId>commons-logging</groupId>
          <artifactId>commons-logging</artifactId>
          <version>1.2</version>
      </dependency>
      <dependency>
          <groupId>javax.servlet.jsp</groupId>
          <artifactId>jsp-api</artifactId>
          <version>2.1</version>
      </dependency>
      <dependency>
          <groupId>javax.servlet</groupId>
          <artifactId>javax.servlet-api</artifactId>
          <version>3.1.0</version>
      </dependency>
  </dependencies>
  <properties>
      <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>
 
  <build>
      <plugins>
        <plugin>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.1</version>
            <configuration>
                <encoding>UTF-8</encoding>
                <source>1.5</source>
                <target>1.5</target>
            </configuration>
        </plugin>
        <plugin>
            <groupId>org.apache.myfaces.tobago</groupId>
            <artifactId>maven-apt-plugin</artifactId>                            
            <configuration>
                <A>
                       uri=/esayui-tags,tlibVersion=${project.version},jspVersion=2.0,shortName=easyui,displayName="EasyUI Tags",
                       outFile=${basedir}/src/main/resources/META-INF/${project.artifactId}.tld,
                       description="EasyUI Tags",
                       outTemplatesDir=${basedir}/src/main/java/template/easyui/html                
                </A>
                <resourceTargetPath>target</resourceTargetPath>
                <fork>false</fork>
                <force>true</force>
                <nocompile>true</nocompile>
                <showWarnings>true</showWarnings>
                <factory>
                    org.apache.struts.annotations.taglib.apt.TLDAnnotationProcessorFactory
                </factory>
                <target>1.5</target>
                <includes>
                    <include>**/*.java</include>
                </includes>
            </configuration>
            <executions>
                <execution>
                    <phase>compile</phase>
                    <goals>
                        <goal>execute</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>        
      </plugins>
    <resources>
           <resource>
               <directory>src/main/java</directory>
            <excludes>
                <exclude>**/*.java</exclude>
            </excludes>               
           </resource>
           <resource>
               <directory>src/main/resources</directory>
           </resource>          
       </resources>    
      <finalName>easyui-tags</finalName>
      <defaultGoal>install</defaultGoal>
  </build>
</project>

 

 

參考:

https://bodez.wordpress.com/2009/03/13/customising-struts2-jsp-tags/

文章標籤

MIS 發表在 痞客邦 留言(0) 人氣()

Struts 2 使用 FreeMarker 來作模板(Template) ,預設的模板是 xhtml (可以解開 struts2-core-2.3.x.x.jar 取得),若要客制佈景(Theme)與模板(Template),需要下列幾個步驟。

預計想要達成的效果有

1. Freemarker Template 中可以使用 Struts 的 tag

2. Customize Theme 客製顏色佈景

 

一、Freemarker Template 中可以使用 Struts 的 tag 實作步驟:

Step 01:  解壓 struts2-core-2.3.x.x.jar 取得 struts-tags.tld 並放在專案(project)的 WEB-INF 下,整個專案目錄如下

struts2-freemarker  

 

Step 02: 修改 web.xml  ,加入 JspSupportServlet 配置

<?xml version="1.0" encoding="UTF-8"?>
<web-app id="struts_blank" version="2.4"
         xmlns="http://java.sun.com/xml/ns/j2ee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
  <display-name>Struts Blank-MIS</display-name>

  <filter>
    <filter-name>struts2</filter-name>
    <filter-class>
      org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter
    </filter-class>
  </filter>

  <filter-mapping>
    <filter-name>struts2</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>

    <servlet>  
        <servlet-name>JspSupportServlet</servlet-name>  
        <servlet-class>org.apache.struts2.views.JspSupportServlet</servlet-class>  
              <!--配置JspSupportServlet啟動-->  
        <load-on-startup>1</load-on-startup>  
    </servlet>  

  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
  </welcome-file-list>
</web-app>

Step 03: 在 Freemarker Template 頁面,加入要使明的 taglib,這樣就可以在 template: fmLogin.ftl 中使用 struts2 內建的 tag 標籤,例:<@s.form action="Login.action">

<#assign s=JspTaglibs["/WEB-INF/struts-tags.tld"] />  
<html>  
<head>  
<title>登錄頁面</title>

<style type="text/css">
    .errorsBg{
        background-color:#fdd;
        color:red;    
        border: 1px solid;
    }
    
    .errorMessage{
        padding:0px 8px;
    }
    
    table{
        border-spacing: 4px;
    }
    td{
        padding:4px;
    }
</style>

</head>  
<body>  
    請輸入用戶名和密碼來登錄<br>  
    <@s.form action="Login.action">  
        <@s.textfield name="username" label="用戶名"/>  
        <@s.textfield name="password" label="密碼"/>  
        <@s.submit value="提交"/>  
    </@s.form>  
</body>  
</html>

 

二、 Customize Theme 客製顏色佈景,客制佈景以 polinwei 為例

Step 01: 建立 package: src/main/java/template/polinwei ,解壓 struts2-core-2.3.x.x.jar 取得 lib\struts2-core-2.3.24.1\template 下目錄 xhtml 的所有檔案放入此 polinwei 目錄下。

struts2-customize-theme  

Step 02: 在 struts.xml 定義要使用的 theme: struts.ui.theme 與 template 目錄: struts.ui.templateDir

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
        "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
        "http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>
    <constant name="struts.enable.DynamicMethodInvocation" value="false"/>
    <constant name="struts.devMode" value="true"/>

    <constant name="struts.ui.theme" value="polinwei" />
    <constant name="struts.ui.templateDir" value="template" />   

    <package name="demo" namespace="/demo" extends="struts-default">
        <action name="Login" class="com.demo.FMTestAction">
            <result name="input" type="freemarker">/WEB-INF/demo/fmLogin.ftl</result>
            <result name="success" type="freemarker">/WEB-INF/demo/fmLoginSuccess.ftl</result>
        </action>

    </package>

    <!-- Add addition packages and configuration here. -->

</struts>

 

Step 03: 開始客制佈景

a. Create a new error-message.ftl file to display the error message.

error-message.ftl

<#--
        Only show message if errors are available.
        This will be done if ActionSupport is used.
-->
<#assign hasFieldErrors = parameters.name?? && fieldErrors?? && fieldErrors[parameters.name]??/>
<#if hasFieldErrors>
<#list fieldErrors[parameters.name] as error>
   <span class="errorMessage" errorFor="${parameters.id}">${error?html}</span><#t/>
</#list>
</#if>

 

b. Modify the controlheader.ftl by adding a new “errorsBg” class to “td” tag if errors exists.

controlheader.ftl

<#include "/${parameters.templateDir}/polinwei/controlheader-core.ftl" />
    <td
<#if hasFieldErrors>
    class="errorsBg" <#t/>
</#if>
<#if parameters.align??>
    align="${parameters.align?html}"<#t/>
</#if>
><#t/>

 

c. Modify the controlheader-core.ftl by delete many unnecessary tags and add a new “errorsBg” class to “td” tag if errors exists.

controlheader-core.ftl

<#--
        Only show message if errors are available.
        This will be done if ActionSupport is used.
-->
<#assign hasFieldErrors = parameters.name?? && fieldErrors?? && fieldErrors[parameters.name]??/>
<#--
        if the label position is top,
        then give the label its own row in the table
-->
<tr>

<td class="tdLabel <#t/>
<#--
<#if hasFieldErrors>
errorsBg"<#t/>
</#if>
-->
><#rt/>

<#if parameters.label??>
    <label <#t/>
<#if parameters.id??>
        for="${parameters.id?html}" <#t/>
</#if>
<#if hasFieldErrors>
        class="errorLabel"<#t/>
<#else>
        class="label"<#t/>
</#if>
 ><#t/>

<#if parameters.required?default(false) && parameters.requiredposition?default("right") != 'right'>
    <span class="required">*</span><#t/>
</#if>
${parameters.label?html}<#t/>
<#if parameters.required?default(false) && parameters.requiredposition?default("right") == 'right'>
        <span class="required">*</span><#t/>
</#if>

</label><#t/>
</#if>

</td><#lt/>

 

d. Modify the text.ftl & password.ftl by adding a new template file “error-message.ftl” after the “simple/text.ftl“.

text.ftl

<#include "/${parameters.templateDir}/${parameters.theme}/controlheader.ftl" />
<#include "/${parameters.templateDir}/simple/text.ftl" />
<#include "/${parameters.templateDir}/polinwei/error-message.ftl" />
<#include "/${parameters.templateDir}/xhtml/controlfooter.ftl" />

password.ftl

<#include "/${parameters.templateDir}/${parameters.theme}/controlheader.ftl" />
<#include "/${parameters.templateDir}/simple/password.ftl" />
<#include "/${parameters.templateDir}/polinwei/error-message.ftl" />
<#include "/${parameters.templateDir}/xhtml/controlfooter.ftl" />

 

 

e. Put the CSS in your view page to format the error message.

<#assign s=JspTaglibs["/WEB-INF/struts-tags.tld"] />  
<html>  
<head>  
<title>登錄頁面</title>

<style type="text/css">
    .errorsBg{
        background-color:#fdd;
        color:red;    
        border: 1px solid;
    }
    
    .errorMessage{
        padding:0px 8px;
    }
    
    table{
        border-spacing: 4px;
    }
    td{
        padding:4px;
    }
</style>

</head>  
<body>  
    請輸入用戶名和密碼來登錄<br>  
    <@s.form action="Login.action">  
        <@s.textfield name="username" label="用戶名"/>  
        <@s.textfield name="password" label="密碼"/>  
        <@s.submit value="提交"/>  
    </@s.form>  
</body>  
</html> 

 

這樣就可以有自已客制的佈景了.

 

參考:

http://www.mkyong.com/struts2/working-with-struts-2-theme-template/

 

文章標籤

MIS 發表在 痞客邦 留言(0) 人氣()

From: Polin Wei

經實作測試,可以正常運作。故記錄之.....

環境:

struts2: 2.3.16.3

freemarker: 2.3.19

Bootstrap: 3.2.0

commons-fileupload: 1.3.1

commons-io:2.4

jQuery-File-Upload: 9.10.0

 

上傳前劃面

 upload-1.png  

上傳後劃面

upload2.png

 

Struts2 結合 jQuery-File-Upload 的實作如下:

step 01: pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.gu</groupId>
  <artifactId>GUSSH</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>war</packaging>
  <name>gussh</name>
  <dependencies>
          <dependency>
              <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.16</version>
          </dependency>
          <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jsp-api</artifactId>
            <version>2.0</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>com.google.code.gson</groupId>
            <artifactId>gson</artifactId>
            <version>2.3</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>4.1.1.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>4.1.1.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>4.1.1.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-orm</artifactId>
            <version>4.1.1.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
            <version>4.1.1.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>4.1.1.RELEASE</version>
        </dependency>
        
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>4.1.1.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-core</artifactId>
            <version>4.2.15.Final</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-entitymanager</artifactId>
            <version>4.2.15.Final</version>
        </dependency>
        
        <dependency>
            <groupId>commons-codec</groupId>
            <artifactId>commons-codec</artifactId>
            <version>1.3</version>
        </dependency>
        
        <dependency>
            <groupId>org.apache.struts</groupId>
            <artifactId>struts2-core</artifactId>
            <version>2.3.16.3</version>
        </dependency>
        <dependency>
            <groupId>org.apache.struts</groupId>
            <artifactId>struts2-spring-plugin</artifactId>
            <version>2.3.16.3</version>
        </dependency>
        <dependency>
            <groupId>org.apache.struts</groupId>
            <artifactId>struts2-json-plugin</artifactId>
            <version>2.3.16.3</version>
        </dependency>
        <dependency>
            <groupId>org.apache.struts</groupId>
            <artifactId>struts2-config-browser-plugin</artifactId>
            <version>2.3.16.3</version>
        </dependency>
        <dependency>
            <groupId>commons-beanutils</groupId>
            <artifactId>commons-beanutils</artifactId>
            <version>1.8.0</version>
        </dependency>
        <dependency>
            <groupId>commons-lang</groupId>
            <artifactId>commons-lang</artifactId>
            <version>2.6</version>
        </dependency>
        <dependency>
            <groupId>commons-digester</groupId>
            <artifactId>commons-digester</artifactId>
            <version>1.7</version>
        </dependency>
        <dependency>
            <groupId>commons-httpclient</groupId>
            <artifactId>commons-httpclient</artifactId>
            <version>3.1</version>
        </dependency>
        <dependency>
            <groupId>com.thoughtworks.xstream</groupId>
            <artifactId>xstream</artifactId>
            <version>1.3.1</version>
        </dependency>
        <dependency>
            <groupId>p6spy</groupId>
            <artifactId>p6spy</artifactId>
            <version>1.3</version>
        </dependency>
        
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi</artifactId>
            <version>3.0.1-FINAL</version>
        </dependency>
        <dependency>
            <groupId>quartz</groupId>
            <artifactId>quartz</artifactId>
            <version>1.5.2</version>
        </dependency>
        
        <dependency>
            <groupId>stax</groupId>
            <artifactId>stax</artifactId>
            <version>1.2.0</version>
        </dependency>
        <dependency>
            <groupId>com.sun.xml</groupId>
            <artifactId>saaj-impl</artifactId>
            <version>1.3</version>
        </dependency>
        <dependency>
            <groupId>javax.activation</groupId>
            <artifactId>activation</artifactId>
            <version>1.1</version>
        </dependency>
        <dependency>
            <groupId>com.sun.xml.stream</groupId>
            <artifactId>sjsxp</artifactId>
            <version>1.0.1</version>
        </dependency>
        
        <dependency>
            <groupId>taglibs</groupId>
            <artifactId>standard</artifactId>
            <version>1.1.2</version>
        </dependency>
        <dependency>
            <groupId>wsdl4j</groupId>
            <artifactId>wsdl4j</artifactId>
            <version>1.5.1</version>
        </dependency>
        <dependency>
            <groupId>oro</groupId>
            <artifactId>oro</artifactId>
            <version>2.0.8</version>
        </dependency>
        <dependency>
            <groupId>jasperreports</groupId>
            <artifactId>jasperreports</artifactId>
            <version>1.3.4</version>
        </dependency>
        <dependency>
            <groupId>jfree</groupId>
            <artifactId>jfreechart</artifactId>
            <version>1.0.9</version>
        </dependency>
        <dependency>
            <groupId>jfree</groupId>
            <artifactId>jfreechart-experimental</artifactId>
            <version>1.0.9</version>
        </dependency>
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>itext-asian</artifactId>
            <version>5.2.0</version>
        </dependency>
        
        <dependency>
            <groupId>net.sf.json-lib</groupId>
            <artifactId>json-lib</artifactId>
            <version>2.4</version>
            <classifier>jdk15</classifier>
        </dependency>
        
        <dependency>
            <groupId>net.sf.barcode4j</groupId>
            <artifactId>barcode4j</artifactId>
            <version>2.0</version>
        </dependency>
        <dependency>
            <groupId>net.sf.morph</groupId>
            <artifactId>morph</artifactId>
            <version>1.1.1</version>
        </dependency>
        <dependency>
            <groupId>commons-beanutils</groupId>
            <artifactId>commons-beanutils-bean-collections</artifactId>
            <version>1.7.0</version>
        </dependency>
        <dependency>
            <groupId>dom4j</groupId>
            <artifactId>dom4j</artifactId>
            <version>1.6.1</version>
        </dependency>
        <dependency>
            <groupId>aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
            <version>1.5.3</version>
        </dependency>
        <dependency>
            <groupId>axis</groupId>
            <artifactId>axis</artifactId>
            <version>1.4</version>
        </dependency>
        
        <dependency>
            <groupId>com.keypoint</groupId>
            <artifactId>png-encoder</artifactId>
            <version>1.5</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.6.1</version>
        </dependency>
        <dependency>
            <groupId>commons-dbcp</groupId>
            <artifactId>commons-dbcp</artifactId>
            <version>1.2.2</version>
        </dependency>
        <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib-nodep</artifactId>
            <version>2.1_3</version>
        </dependency>
        <dependency>
            <groupId>javax.annotation</groupId>
            <artifactId>jsr250-api</artifactId>
            <version>1.0</version>
        </dependency>
        <dependency>
            <groupId>net.sf.ehcache</groupId>
            <artifactId>ehcache</artifactId>
            <version>1.3.0</version>
        </dependency>
        <dependency>
            <groupId>javax.transaction</groupId>
            <artifactId>jta</artifactId>
            <version>1.1</version>
        </dependency>
        <dependency>
            <groupId>com.sun.mail</groupId>
            <artifactId>javax.mail</artifactId>
            <version>1.5.2</version>
        </dependency>
        <dependency>
            <groupId>net.sourceforge.jexcelapi</groupId>
            <artifactId>jxl</artifactId>
            <version>2.6</version>
        </dependency>
        <dependency>
            <groupId>commons-javaflow</groupId>
            <artifactId>commons-javaflow</artifactId>
            <version>20060411</version>
            <scope>system</scope>
            <systemPath>${project.basedir}/src/main/webapp/WEB-INF/lib/commons-javaflow-20060411.jar</systemPath>
        </dependency>

        <dependency>
            <groupId>net.sourceforge.barbecue</groupId>
            <artifactId>barbecue</artifactId>
            <version>1.1</version>
            <scope>system</scope>
            <systemPath>${project.basedir}/src/main/webapp/WEB-INF/lib/barbecue-1.1.jar</systemPath>
        </dependency>

        <dependency>
            <groupId>lotus.sametime</groupId>
            <artifactId>STComm</artifactId>
            <version>1.0</version>
            <scope>system</scope>
            <systemPath>${project.basedir}/src/main/webapp/WEB-INF/lib/STComm.jar</systemPath>
        </dependency>

        <dependency>
            <groupId>lotus.sametime</groupId>
            <artifactId>NCSO</artifactId>
            <version>1.0</version>
            <scope>system</scope>
            <systemPath>${project.basedir}/src/main/webapp/WEB-INF/lib/NCSO.jar</systemPath>
        </dependency>

        <dependency>
            <groupId>lotus.sametime</groupId>
            <artifactId>CommRes</artifactId>
            <version>1.0</version>
            <scope>system</scope>
            <systemPath>${project.basedir}/src/main/webapp/WEB-INF/lib/CommRes.jar</systemPath>
        </dependency>

        <dependency>
            <groupId>com.wnjsoft.dlp</groupId>
            <artifactId>ds-orgimport</artifactId>
            <version>1.0</version>
            <scope>system</scope>
            <systemPath>${project.basedir}/src/main/webapp/WEB-INF/lib/ds-orgimport.jar</systemPath>
        </dependency>

        <dependency>
            <groupId>com.wnjsoft.dlp</groupId>
            <artifactId>ds-userimport</artifactId>
            <version>1.0</version>
            <scope>system</scope>
            <systemPath>${project.basedir}/src/main/webapp/WEB-INF/lib/ds-userimport.jar</systemPath>
        </dependency>

        <dependency>
            <groupId>com.ds.globeunion.wfclient</groupId>
            <artifactId>ds-wf-client</artifactId>
            <version>1.0</version>
            <scope>system</scope>
            <systemPath>${project.basedir}/src/main/webapp/WEB-INF/lib/ds-wf-client.jar</systemPath>
        </dependency>
        <dependency>
            <groupId>jasperreports</groupId>
            <artifactId>ireport</artifactId>
            <version>2.0.0</version>
            <scope>system</scope>
            <systemPath>${project.basedir}/src/main/webapp/WEB-INF/lib/iReport.jar</systemPath>
        </dependency>
        <dependency>
            <groupId>com.oracle</groupId>
            <artifactId>ojdbc14</artifactId>
            <version>10.2.0.3.0</version>
            <scope>system</scope>
            <systemPath>${project.basedir}/src/main/webapp/WEB-INF/lib/ojdbc14.jar</systemPath>
        </dependency>
        <dependency>
            <groupId>com.oracle</groupId>
            <artifactId>ojdbc14_g</artifactId>
            <version>10.2.0.3.0</version>
            <scope>system</scope>
            <systemPath>${project.basedir}/src/main/webapp/WEB-INF/lib/ojdbc14_g.jar</systemPath>
        </dependency>
        <dependency>
            <groupId>com.sun.xml</groupId>
            <artifactId>saaj-coms</artifactId>
            <version>1.0</version>
            <scope>system</scope>
            <systemPath>${project.basedir}/src/main/webapp/WEB-INF/lib/saaj-coms.jar</systemPath>
        </dependency>
        <dependency>
            <groupId>com.gu.apps</groupId>
            <artifactId>gu-taglibs</artifactId>
            <version>1.0.0</version>
            <scope>system</scope>
            <systemPath>${project.basedir}/src/main/webapp/WEB-INF/lib/gu-taglibs-1.0.0.jar</systemPath>
        </dependency>
        <dependency>
            <groupId>javax.sql</groupId>
            <artifactId>jdbc-stdext</artifactId>
            <version>2.0</version>
            <scope>system</scope>
            <systemPath>${project.basedir}/src/main/webapp/WEB-INF/lib/jdbc2_0-stdext.jar</systemPath>
        </dependency>
        <dependency>
            <groupId>com.jgeppert.struts2.bootstrap</groupId>
            <artifactId>struts2-bootstrap-plugin</artifactId>
            <version>2.0.0</version>
        </dependency>
        <dependency>
            <groupId>com.jgeppert.struts2.jquery</groupId>
            <artifactId>struts2-jquery-plugin</artifactId>
            <version>3.7.1</version>
        </dependency>
        <dependency>
            <groupId>com.ckeditor</groupId>
            <artifactId>ckeditor-java-core</artifactId>
            <version>3.5.3</version>
        </dependency>
        <dependency>
            <groupId>commons-fileupload</groupId>
            <artifactId>commons-fileupload</artifactId>
            <version>1.3.1</version>
        </dependency>
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.4</version>
        </dependency>
  </dependencies>
</project>

 

step 02: struts.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
    "http://struts.apache.org/dtds/struts-2.3.dtd">
      
<struts>

     <!-- devMode is helpful when you want some extra logs for debugging -->
     <constant name="struts.devMode" value="false" />
     <constant name="struts.i18n.encoding" value="UTF-8" />
     <!-- Global message resource;
         Otherwise you will have seperate message resource for each Action
     -->
     <constant name="struts.custom.i18n.resources" value="com.gussh.sc.messages.messages" />
     <constant name="struts.enable.DynamicMethodInvocation" value="true" />
     <constant name="struts.multipart.maxSize" value="1048576000" />
             
     <package name="gussh-default" namespace="/" extends="struts-default,json-default">
     
       <interceptors>
            <interceptor name="authInterceptor" class="com.gussh.AuthInterceptor"></interceptor>
            
               <interceptor-stack name="gussh-stack">
                <interceptor-ref name="fileUpload">
                    <param name="maximumSize">104857600</param>
                </interceptor-ref>
                <interceptor-ref name="authInterceptor" />                    
                <interceptor-ref name="defaultStack"/>
               </interceptor-stack> 
               
       </interceptors>
       <default-interceptor-ref name="gussh-stack"/>
       <default-action-ref name="UnderConstruction"/>
                       
       <global-results>
          <result name="json-output">/gussh/common/json-output.jsp</result>
          <result name="error">/error.jsp</result>
        </global-results>
         
        <global-exception-mappings>
            <exception-mapping exception="java.lang.Exception" result="error"/>            
        </global-exception-mappings>
        
       <action name="UnderConstruction">
           <result>/templates/SSO/GUSSO.jsp</result>
       </action>        
 
        <action name="FileOutput" class="com.gussh.common.utils.FileOutput" >              
            <result name="success" type="stream">
                <param name="contentType">application/octet-stream;charset=ISO8859-1</param>
                <param name="inputName">inputStream</param>
                <!-- 使用經過轉碼的檔名作為下載檔案名,downloadFileName屬性  對應action類中的方法 getDownloadFileName() -->  
                <param name="contentDisposition">attachment;filename="${downloadFileName}"</param>
                <param name="bufferSize">4096</param>                
            </result>  
        </action>        
            
     </package>
    
     <!-- Add addition packages and configuration here. -->
      
</struts>

 

Step03: jsp 頁面

<s:form cssClass="fileupload" name="UsersTagAction" action="UsersTagAction" enctype="multipart/form-data">

...

...

<div class="row fileupload-buttonbar">
    <div class="col-lg-7">
        <!-- The fileinput-button span is used to style the file input field as button -->
        <span class="btn btn-success btn-sm fileinput-button">
            <i class="glyphicon glyphicon-plus" style="font-size: 14px"></i>
            <span><s:text name="common.upload.select" /></span>
            <input type="file" name="file" multiple>                    
        </span>           
        <button type="submit" class="btn btn-primary btn-sm start">
            <i class="glyphicon glyphicon-upload" style="font-size: 14px"></i>
            <span><s:text name="common.upload" /></span>
        </button>
        <button type="reset" class="btn btn-warning btn-sm cancel">
            <i class="glyphicon glyphicon-ban-circle" style="font-size: 14px"></i>
            <span><s:text name="common.upload.cancel" /></span>
        </button>
        <button type="button" class="btn btn-danger btn-sm delete">
            <i class="glyphicon glyphicon-trash" style="font-size: 14px"></i>
            <span><s:text name="common.btn.delete" /></span>
        </button>
        <input type="checkbox" class="toggle">
        <!-- The global file processing state -->
        <span class="fileupload-process"></span>
    </div>
</div>
<!-- The table listing the files available for upload/download -->
<table role="presentation" class="table table-striped"><tbody class="files"></tbody></table>

 

...</s:form>

 

step 04: freemarker(ftl) 頁面, 放在 html 最下面, 以便所有頁面共用

<!-- The template to display files available for upload -->
<script id="template-upload" type="text/x-tmpl">
{% for (var i=0, file; file=o.files[i]; i++) { %}
    <tr class="template-upload fade">
        <td>
            <span class="preview"></span>
        </td>
        <td>
            <p class="name">{%=file.name%}</p>
            <strong class="error text-danger"></strong>
        </td>
        <td class="title"><input name="fileDescription" placeholder="File Description"></td>    
        <td>
            <p class="size">Processing...</p>
            <div class="progress progress-striped active" role="progressbar" aria-valuemin="0" aria-valuemax="100" aria-valuenow="0"><div class="progress-bar progress-bar-success" style="width:0%;"></div></div>
        </td>
        <td>
            {% if (!i && !o.options.autoUpload) { %}
                <button class="btn btn-primary btn-sm start" disabled>
                    <i class="glyphicon glyphicon-upload" style="font-size: 14px"></i>
                    <span style="font-size: 12px">${action.getText('common.upload.select')}</span>
                </button>
            {% } %}
            {% if (!i) { %}
                <button class="btn btn-warning btn-sm cancel">
                    <i class="glyphicon glyphicon-ban-circle" style="font-size: 14px"></i>
                    <span style="font-size: 12px">${action.getText('common.upload.cancel')}</span>
                </button>
            {% } %}
        </td>
    </tr>
{% } %}
</script>
<!-- The template to display files available for download -->
<script id="template-download" type="text/x-tmpl">
{% for (var i=0, file; file=o.files[i]; i++) { %}
    <tr class="template-download fade">
        <td>
            <span class="preview">
                {% if (file.thumbnailUrl) { %}
                    <a href="{%=file.url%}" title="{%=file.name%}" download="{%=file.name%}" data-gallery><img src="{%=file.thumbnailUrl%}"></a>
                {% } %}
            </span>
        </td>
        <td>
            <p class="name">                
                {% if (file.url) { %}
                    <a href="{%=file.url%}" title="{%=file.name%}" download="{%=file.name%}" {%=file.thumbnailUrl?'data-gallery':''%}><img src="${request.contextPath}/webTemplate/themes/gussh/images/Download-icon.png"/>{%=file.name%}</a>
                {% } else { %}
                    <span>{%=file.name%}</span>
                {% } %}
            </p>
            {% if (file.error) { %}
                <div><span class="label label-danger">Error</span> {%=file.error%}</div>
            {% } %}
        </td>
        <td>
            <span class="size">{%=o.formatFileSize(file.size)%}</span>
        </td>
        <td>
            {% if (file.deleteUrl) { %}
                <button class="btn btn-danger btn-sm delete" data-type="{%=file.deleteType%}" data-url="{%=file.deleteUrl%}"{% if (file.deleteWithCredentials) { %} data-xhr-fields='{"withCredentials":true}'{% } %}>
                    <i class="glyphicon glyphicon-trash" style="font-size: 12px"></i>
                    <span>${action.getText('common.btn.delete')}</span>
                </button>
                <input type="checkbox" name="delete" value="1" class="toggle">
            {% } else { %}
                <button class="btn btn-warning btn-sm cancel">
                    <i class="glyphicon glyphicon-ban-circle" style="font-size: 12px"></i>
                    <span>${action.getText('common.upload.cancel')}</span>
                </button>
            {% } %}
        </td>
    </tr>
{% } %}
</script>
    
</body>
</html>

 

Step 05: 處理 file upload 的 class

package com.gussh;


import java.lang.reflect.Method;
import java.util.Locale;
import java.util.Map;
import java.util.regex.Pattern;

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

import org.apache.log4j.Logger;
import org.apache.struts2.ServletActionContext;
import org.apache.struts2.dispatcher.mapper.ActionMapping;

import com.gussh.common.utils.BA_TOOLS;
import com.gussh.common.utils.BA_Validate;
import com.gussh.sc.model.UserInfo;
import com.gussh.spfs.SPFS_TOOLS;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.Preparable;
import com.opensymphony.xwork2.validator.annotations.DateRangeFieldValidator;
import com.opensymphony.xwork2.validator.validators.EmailValidator;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

public class BaseSupport extends ActionSupport implements Preparable {
    
    Logger logger = Logger.getLogger(BaseSupport.class);
    private static final long serialVersionUID = 1L;
    
    // 網頁會使用的 request, response, session
    public HttpServletRequest request = ServletActionContext.getRequest();
    public HttpServletResponse response = ServletActionContext.getResponse();
    public Map<String, Object> session = ActionContext.getContext().getSession();


    //處理檔案上傳, 因 jQuery-File-Upload 一次處理一個檔案上傳, 所以不需使用 MultipleFileUploadUsingListAction
    protected File file ;
    protected String fileFileName ;
    protected String fileContentType ;
    protected String fileDescription ;
    
    @Resource(name="BA_TOOLS")
    protected BA_TOOLS baTools;    
    
    public BaseSupport() {
        // TODO Auto-generated constructor stub
    }

    public void prepare() throws Exception {
        // TODO Auto-generated constructor stub
        
    }    


    @Override
    public String execute() throws Exception {
        String reqCode="fileUpload";
            String reqResult="";
            reqResult=doReqCode(reqCode);        
        return reqResult;
    }

    public String fileUpload() {
        String filePath="/upload/";
        try {
            baTools.uploadFileToServer(response, filePath, file, fileFileName, fileContentType, fileDescription);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return super.fileUpload();
    }


    //執行其它自定的 reqCode Function
    public String doReqCode(String reqCode) {
        reqResult=INPUT;
        boolean result = false;
        Method[] methods = this.getClass().getMethods();
        for (int i = 0; i < methods.length; i++) {
            Method method = methods[i];
            if (reqCode.equals(method.getName())) {
                try {
                    reqResult=method.invoke(this).toString();
                    result=true;
                } catch (Exception e) {
                    this.addActionError(reqCode+": "+  getText("msg.system.methodExecuteError"));
                    logger.info(e);                
                }
            }
        }
        if (!result){
            this.addActionError(reqCode+": "+  getText("msg.system.methodNotFound"));
        }
        
        return reqResult;
    }


    //處理檔案上傳
    public File getFile() {
        return file;
    }

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

    public String getFileFileName() {
        return fileFileName;
    }

    public void setFileFileName(String fileFileName) {
        this.fileFileName = fileFileName;
    }

    public String getFileContentType() {
        return fileContentType;
    }

    public void setFileContentType(String fileContentType) {
        this.fileContentType = fileContentType;
    }

    public String getFileDescription() {
        return fileDescription;
    }

    public void setFileDescription(String fileDescription) {
        this.fileDescription = fileDescription;
    }
    
}

 

Step 06: 公共程式的 class: BA_TOOLS

@Service
@Component("BA_TOOLS")
public class BA_TOOLS extends BaseDataSource {

    static Logger loger = Logger.getLogger(BA_TOOLS.class.getName());
    
    private static final ActionSupport actionSupport = new ActionSupport();
    
    /**
     * 上傳檔案到主機上,並且變更原始檔名為 new Date().getTime() + extension
     * @param filePath 檔案路徑
     * @param file     上傳的實體檔案來源
     * @param fileFileName 上傳的實體檔案檔名
     * @param fileContentType 上傳的實體檔案型態
     * @param fileDescription 上傳的實體檔案說明
     * @return
     * @throws IOException
     */
    public String uploadFileToServer(HttpServletResponse response,String filePath, File file, String fileFileName, String fileContentType, String fileDescription) throws IOException{
        
        String saveFileName = "";
        String showFileDescript = fileDescription.isEmpty()?fileFileName:fileDescription;
        String uploadFileGson="";
        InputStream is = null;
        OutputStream os = null;
        int BUFFER_SIZE = 8 * 1024;
        int fileSize=0;
        
        
        Gson gson = new GsonBuilder().enableComplexMapKeySerialization().create();
        Map<String,Object> rowAttribute = new HashMap<String,Object>();
        List<Map<String,Object>> fileAttribute = new ArrayList<Map<String,Object>>();
        Map<String,Object> itemCategory = new HashMap<String,Object>();
        
        String osName = System.getProperty("os.name");
        if (!osName.equals("Linux")) {
            filePath = "C:" + filePath;
        }
        try{
            //檢查是否有此Folder:filePath, 若無則建立
            File filePathIsFolder = new File(filePath);
            if (!filePathIsFolder.isDirectory())
                filePathIsFolder.mkdirs();
            //取得上傳檔案的附檔名
            String extension = "";
            if (fileFileName.indexOf('.') > -1){
                String[] tmp = fileFileName.split("\\.");
                extension = "." + tmp[tmp.length - 1];
            }
            saveFileName = new Date().getTime() + extension;
            
            //開始將檔案讀出並寫入主機            
            is = new FileInputStream(file);
            fileSize=is.available();
            File destFile = new File(filePath, saveFileName);
            os = new FileOutputStream(destFile);
            byte[] buffer = new byte[BUFFER_SIZE];
            while(is.read(buffer)>0){
                os.write(buffer);
            }
            is.close();
            os.close();
            
            //組成 jquery-file-upload 需要的 gson 格式
            itemCategory.put("name", showFileDescript);
            itemCategory.put("size", fileSize);
            itemCategory.put("type", fileContentType);
            itemCategory.put("url", "FileOutput?name="+saveFileName);
            itemCategory.put("deleteUrl", "Index?reqCode=fileDelete&fileFileName="+saveFileName);
            itemCategory.put("deleteType", "POST");
            fileAttribute.add(itemCategory);
            rowAttribute.put("files", fileAttribute);
            
            
        } catch (Exception e) {
            e.printStackTrace();
        } finally{
            if (null!=is){
                is.close();
            }
            if (null!=os){
                os.close();
            }
        }
        //產生 gson 字串
        uploadFileGson=gson.toJson(rowAttribute);
        //回傳 gson 至前端
        gsonOutput(response,uploadFileGson);
        
        return saveFileName;
    }
    
    /**
     * 在前端產生 Gson String
     * @param response
     * @param gsonString
     */
    public void gsonOutput(HttpServletResponse response, String gsonString){
        PrintWriter writer=null;
        response.setContentType("text/html;charset=UTF-8");
        try {
            writer = response.getWriter();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        writer.print(gsonString);
        writer.flush();
        writer.close();        
    }
}       

 

Step 07: 檔案下載的 class: FileOutput

package com.gussh.common.utils;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;

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

import org.apache.log4j.Logger;
import org.apache.struts2.ServletActionContext;

import com.opensymphony.xwork2.ActionSupport;

public class FileOutput extends ActionSupport {
    
    static Logger logger = Logger.getLogger(FileOutput.class);
    
    @Resource(name="BA_TOOLS")
    protected BA_TOOLS baTools;
    public HttpServletRequest request = ServletActionContext.getRequest();
    public HttpServletResponse response = ServletActionContext.getResponse();
    
    private InputStream inputStream ;
    private String name;    
    
    public InputStream getInputStream() {        
        
        String filenamedownload = "";
        String filePath="/upload/";        
        String osName = System.getProperty("os.name");
        
        if (!osName.equals("Linux")) {
            filePath = "C:" + filePath;
        }
        
        filenamedownload = filePath+ "/" + this.getName();
        
         try{
             File file = new File(filenamedownload);
             if(file.length()>0)
                 inputStream = new FileInputStream(filenamedownload);
             else
                 inputStream = new ByteArrayInputStream("No Files".getBytes());
         }catch(Exception e){
             e.printStackTrace();
         }
        
        
         //return ServletActionContext.getServletContext().getResourceAsStream(filenamedownload);
         return inputStream;
    }
    
    public String execute() throws Exception {    
        return "success";
    }

    public String getDownloadFileName() {   
          
        String downFileName = name;  
        try {  
            downFileName = new String(downFileName.getBytes(), "ISO8859-1");
        } catch (UnsupportedEncodingException e) {  
            e.printStackTrace();  
        }  
        return downFileName;   
 
    }    
    
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }       
    
}

 

Step 08: file upload 的 javascript

$(document).ready(function () {
    
    // Initialize the jQuery File Upload widget:
    $('.fileupload').each(function (e, data) {    
        $(this).fileupload({
            dropZone: $(this)            
        });        
        $('#reqCode').val('fileUpload');
    });
    
    /*處理每一個檔案上傳前, 加入單一 fileDescription 的值*/
    $('.fileupload').bind('fileuploadsubmit', function (e, data) {
       
        // 剔除欄位:fileDescription 後, 取得所有要上傳的值
        var allInputs = $( ":input[name!='fileDescription']"  );
        // 抓取 id="template-upload" 裡新增加單一的 input 欄位: fileDescription
        var fileUploadInputs = data.context.find(':input');
        // 兩個 array 再 merge , 就是所有欄位要上傳的所有值
        var inputs = $.merge(allInputs,fileUploadInputs);
        
        if (inputs.filter(function () {
                return !this.value && $(this).prop('required');
            }).first().focus().length) {
            data.context.find('button').prop('disabled', false);
            return false;
        }
        // 上傳的欄位值需要序列化, 才會逐一上傳
        data.formData = inputs.serializeArray();
    });

});

 

大致的作業如上.

 

參考網址:

Setting formData on upload start for each individual file upload

https://struts.apache.org/docs/file-upload.html

 

 

文章標籤

MIS 發表在 痞客邦 留言(0) 人氣()

在 Struts2 的異常處理有兩種,一種是程式撰寫的邏輯出錯,另一種是找不到 action Name : There is no Action mapped for namespace...,避免系統出錯的改善作法如下:

 

程式撰寫的邏輯出錯:

在 Struts.xml 內加入

<global-results>
    <result name="error">/error.jsp</result>
</global-results>

<global-exception-mappings>
    <exception-mapping exception="java.lang.Exception" result="error"/>            
</global-exception-mappings>

建立 error.jp 檔案

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>An unexpected error has occurred</title>
</head>
<body>

    <h3>The application has malfunctioned(該應用程序出現錯誤)</h3>

    <p>Please contact technical support with the following information(請聯繫資訊單位並提供以下信息):</p>

    <h4>
        Exception Name:<s:property value="exception" />
    </h4>

    <h4>
        Exception Details:<s:property value="exceptionStack" />
    </h4>

</body>
</html>

 

一種是找不到 action Name:

有兩個方法可以解決

第一種是方法利用 default-action-ref:

在 Struts.xml 內加入

<default-action-ref name="UnderConstruction"/>

<action name="UnderConstruction">
   <result>/UnderConstruction.jsp</result>
</action>

建立 UnderConstruction.jp 檔案

<%@ page language="java" contentType="text/html; charset=UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<%@page import="org.apache.struts2.ServletActionContext"%>
<%@page import="com.opensymphony.xwork2.ActionContext"%>
<%@page import="java.util.*"%>
<%@page import="java.net.*"%>
<%@page import="java.text.MessageFormat"%>
<%@page import="com.gussh.common.utils.*"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>

<%

String username = (String)session.getAttribute("USERNAME");
String password = (String)session.getAttribute("PASSWORD");
String language = (String)request.getSession().getAttribute("loginLanguage");
String progModule = (String)session.getAttribute("progModule");
String actionName= "";
String actionURL= "";


ActionContext actionContext = ServletActionContext.getContext();
actionName = actionContext.getName();

actionURL="http://polinwei.blogspot.tw/login.do";

    
    
%>
<body>

<%if(username != null){%>
    <form name="ssoForm" action="<%=actionURL %>" target='_blank'>
    <input type="hidden" name="username" value="<%=username %>" />
    <input type="hidden" name="password" value="<%=password %>"  />
    <input type="hidden" name="language" value="<%=language %>"  />       
    </form>
    <script type="text/javascript">
    var formObj=document.ssoForm;
    formObj.method='post';
    formObj.submit();
    document.location.href="<%=request.getContextPath()%>/Index?reqCode=moduleSelect&progModule=<%=progModule%>"
    </script>
<% }else{ %>
    <script type="text/javascript">
        window.opener.top.document.location.href="<%=actionURL %>";
        window.opener=null;
        window.open("","_self");
        window.close();
    </script>
<% }%>
</body>
</html>

 

第二種作法則是利用 unknown-handler-stack:

在 Struts.xml 內加入

<struts>
.
.    
   <!-- 使用bean 定義一個UnknownHandler -->  
     <bean type="com.opensymphony.xwork2.UnknownHandler" name="myHandler" class="com.sc.actions.UnderConstructionAction" />
    
   <package name="default" namespace="/" extends="struts-default">
   .
   .
   </package>    
   <!-- Add addition packages and configuration here. -->

     
    <!-- 定義本系統的 UnknownHandler -->        
    <unknown-handler-stack>
       <unknown-handler-ref name="myHandler" />
    </unknown-handler-stack>      
</struts>   

 

class="com.sc.actions.UnderConstructionAction"

package com.gussh.sc.actions;

import java.util.Map;

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

import org.apache.struts2.ServletActionContext;
import org.apache.struts2.dispatcher.ServletDispatcherResult;

import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.Result;
import com.opensymphony.xwork2.UnknownHandler;
import com.opensymphony.xwork2.XWorkException;
import com.opensymphony.xwork2.config.entities.ActionConfig;


public class UnderConstructionAction implements UnknownHandler {
    // 網頁會使用的 request, response, session
    public HttpServletRequest request = ServletActionContext.getRequest();
    public HttpServletResponse response = ServletActionContext.getResponse();
    public Map<String, Object> session = ActionContext.getContext().getSession();
   
    public ActionConfig handleUnknownAction(String namespace, String actionName)
            throws XWorkException {        

        ActionConfig actionConfig = null;
        request.setAttribute("actionName",actionName);    
        
        return actionConfig;

    }

    public Result handleUnknownResult(ActionContext actionContext,
            String actionName, ActionConfig actionConfig, String resultCode)
            throws XWorkException {
        actionContext.put("action", actionName);  
        actionContext.put("result", resultCode);
        request.setAttribute("actionName",actionName);
        return new ServletDispatcherResult("/templates/SSO/GUSSO.jsp");
    }

    public Object handleUnknownActionMethod(Object action, String methodName)
            throws NoSuchMethodException {
        // TODO Auto-generated method stub
        return null;
    }

}

 

 

參考:

https://struts.apache.org/docs/unknown-handlers.html

https://struts.apache.org/docs/exception-configuration.html

http://terryjs.iteye.com/blog/777999

文章標籤

MIS 發表在 痞客邦 留言(0) 人氣()

在 freemark 的頁面要嵌入 action 及 參數( Parameters) 有兩種方式

1. 使用 struts2 tag: action

<img width='100px' src='
    <@s.action name="Picout" executeResult="success">  
           <@s.param name="name">${Session.userInfo['PHOTO_PATH']}</@s.param>  
    </@s.action>  
'/>

 

2. 使用 struts2 tag: url

<img width='100px' src='<@s.url action="Picout"><@s.param name="name">${Session.userInfo['PHOTO_PATH']}</@s.param></@s.url>' />

 

個人建議使用第2種方法較為方便

參考: http://www.mkyong.com/struts2/struts-2-url-tag-example/

struts2:在freemarker頁面取得 Application Cookie Request Session parameter

文章標籤

MIS 發表在 痞客邦 留言(0) 人氣()

Struts 2 對於 Interceptor 攔截器的基本概念與實作 的瞭解後,我們現在來作一下 Interceptor 在 Struts 2 上的基本運用。

首先建立一個 class : com.test.interceptor.MyInterceptor 並且 implements Interceptor,這個 Interceptor 是個 Interface,所以需要實作三個 method:init()、destroy()、intercept(ActionInvocation invocation),其中只有 intercept(ActionInvocation invocation) 需要回傳一個 String 的值,可以利用  invocation.invoke(); 來讓系統自已跳到預設的下一個 Action method。

 

package com.test.interceptor;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.Interceptor;

public class MyInterceptor implements Interceptor {

    @Override
    public void destroy() {
        System.out.println("MyInterceptor destroy()");

    }

    @Override
    public void init() {
        System.out.println("MyInterceptor Init()");
        
    }

    @Override
    public String intercept(ActionInvocation invocation) throws Exception {
        System.out.println("MyInterceptor:"+invocation.invoke());
        
        return invocation.invoke();
    }

}

 

再來對 struts.xml 加入自建的 interceptor,在 <interceptors>...</interceptors> 中是定義我們自建的 Interceptor ,讓 Struts 知道有這一個 Interceptor (攔截器),然後再對要攔截的Action name 作設定。

要注意的是,因為我們的 <package name="test" 是 extends="struts-default" ,而 struts-default.xml (在struts2-core-2.x.x.jar 裡預設的) 的預設 Interceptor (攔截器) 是defaultStack,若沒加入它,則系統會停在我們自建的 Interceptor (攔截器),而不會繼續往下執行 validate() -> execute()...等相關的 method()。

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
        "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
        "http://struts.apache.org/dtds/struts-2.3.dtd">

<struts>

    <package name="test" namespace="/test" extends="struts-default">

        <interceptors>
            <interceptor name="myInterceptor" class="com.test.interceptor.MyInterceptor"></interceptor>       

        </interceptors>

        
        <!-- Spring Testing -->
        <action name="userLogin_*" method="{1}" class="testUserLogin">
            <result name="input">userLogin.jsp</result>
            <result name="success">eip.jsp</result>
       
            <interceptor-ref name="myInterceptor"/>
            <interceptor-ref name="defaultStack"/>
       
        </action>  

        <!-- Add additional "example" package actions here. -->

    </package>
</struts>

 

上面的設定,也可以用 Interceptor Stock 來達成,如下:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
        "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
        "http://struts.apache.org/dtds/struts-2.3.dtd">

<struts>

    <package name="test" namespace="/test" extends="struts-default">

        <interceptors>
            <interceptor name="myInterceptor" class="com.test.interceptor.MyInterceptor"></interceptor>
        
            <interceptor-stack name="testStock">
                <interceptor-ref name="myInterceptor"/>
                <interceptor-ref name="defaultStack"/>
            </interceptor-stack>
        </interceptors>      
        
        <!-- Spring Testing -->
        <action name="userLogin_*" method="{1}" class="testUserLogin">
            <result name="input">userLogin.jsp</result>
            <result name="success">eip.jsp</result>  
            
            <interceptor-ref name=name="testStock">
        </action>  

        <!-- Add additional "example" package actions here. -->

    </package>
</struts>

 

或者是利用 default-interceptor-ref 來對全部的 Action Name 作 Interceptor (攔截器),如下:

 

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
        "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
        "http://struts.apache.org/dtds/struts-2.3.dtd">

<struts>

    <package name="test" namespace="/test" extends="struts-default">

        <interceptors>
            <interceptor name="myInterceptor" class="com.test.interceptor.MyInterceptor"></interceptor>
        
            <interceptor-stack name="testStock">
                <interceptor-ref name="myInterceptor"/>
                <interceptor-ref name="defaultStack"/>
            </interceptor-stack>
        </interceptors>
        <default-interceptor-ref name="testStock"></default-interceptor-ref>
        
        <!-- Spring Testing -->
        <action name="userLogin_*" method="{1}" class="testUserLogin">
            <result name="input">userLogin.jsp</result>
            <result name="success">eip.jsp</result>              
            
        </action>  

        <!-- Add additional "example" package actions here. -->

    </package>
</struts>

 

參考:

http://struts.apache.org/maven/index.html

http://struts.apache.org/maven/xwork-core/apidocs/index.html

文章標籤

MIS 發表在 痞客邦 留言(0) 人氣()

Struts 2 支援 POJO 的程式撰寫,所以可以指定 Action Method 來執行您在 struts.xml 中的設定。

<action name="userLogout" method="logout" class="com.gu.EipLogin">
     <result>eip_home.jsp</result>
</action>

 

在 Action Class : com.gu.EipLogin 的程式段

    public String logout(){
        session.clear();
        System.out.println("logout method");
        return SUCCESS;
    }

 

加入 validate() 的  this.addFieldError(...) 或 this.addActionError(...) 後

    @Override
    public void validate() {
        // TODO Auto-generated method stub
        super.validate();
        boolean isInvalidError = false;
        if (isInvalid(getUserName())){
            this.addFieldError("userName", this.getText("userName.error") );
            isInvalidError = true;
        }
        if (isInvalid(getPassword())){
            this.addFieldError("password", this.getText("password.error") );
            isInvalidError = true;
        }
        if (isInvalidError){
            this.addActionError(getText("errors.general"));
        } else {
            session.put("userName", getUserName());
            session.put("login", true);
        }
    }

 

卻發生了錯誤訊息:

Struts Problem Report

Struts has detected an unhandled exception:

Messages:
  • No result defined for action com.gu.EipLogin and result input

 

原因是 Struts 2 進入 Action 時,會先作 validate() ,沒有錯誤後才會執行後續的 method 如: execute()....等,若有錯誤則返回 <result name="input">...</result>; 所以當要執行指定的 method : logout() 前,發生了錯誤會返回預設的 <result name="input">...</result>,但我們又沒有指定,所以才會發生錯誤。

解決的方法是在 logout 的 method 上加入annotation: @SkipValidation ,指示此 method : logout() 不需作 validate() 即可。

    @SkipValidation
    public String logout(){
        session.clear();
        System.out.println("logout method");
        return SUCCESS;
    }

 

 

文章標籤

MIS 發表在 痞客邦 留言(0) 人氣()

Struts 2 在 struts2-core-2.x.x.jar 的 struts-default.xml 中也設定了許多的 Interceptor 攔截器,Interceptor 攔截器的基本概念大致整理如下:

1. 要有目標對象

2. 攔截器本身,在攔截器本身安插要執行的作業

3. 由 java.lang.reflect.InvocationHandler 來讓 目標對象 與 攔截器 產生關連

4. 由 代理 java.lang.reflect.Proxy 來執行,用來產生動態對象

 

依上面的概念來實作如下:

Step 01: 建立一個 Interface: TargetProvider.java 及實作它: TargetImpl.java

TargetProvider.java

package com.test.interceptor;

public interface TargetProvider {

    public void doExecute();
}

 

TargetImpl.java

package com.test.interceptor;

public class TargetImpl implements TargetProvider {

    @Override
    public void doExecute() {
        // TODO Auto-generated method stub
        System.out.println("do Execute");

    }

}

 

Step 02: 建立Interceptor 攔截器本身:TargetInterceptor.java,並在攔截器本身安撰寫想要執行的作業

package com.test.interceptor;

public class TargetInterceptor {

    public void beforeExecute(){
        System.out.println("before Execute");
    }
    
    public void afterExecute(){
        System.out.println("after Execute");
    }
}

 

由上可以得知,目前 TargetImpl.javaTargetInterceptor.java 並沒有關連

 

Step 03: 建立 java.lang.reflect.InvocationHandler :TargetHandler.java  , 利用 invoke(Object proxy, Method method, Object[] args) 方法讓 TargetImpl.javaTargetInterceptor.java 兩者產生關連

TargetHandler.java

package com.test.interceptor;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class TargetHandler implements InvocationHandler {
    
    private Object object;
    private TargetInterceptor targetInterceptor = new TargetInterceptor();
    
    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        // TODO Auto-generated method stub
        
        Object result = null;
        
        targetInterceptor.beforeExecute();
        
        result = method.invoke(object, args);
        
        targetInterceptor.afterExecute();
        
        return result;
    }
    
    public Object getObject() {
        return object;
    }

    public void setObject(Object object) {
        this.object = object;
    }    

}

 

Step 04: 再透過 java.lang.reflect.Proxy: TargetProxy.java 的代理(Proxy) 動態產生新的 ProxyInstance,來執行攔截器作業

package com.test.interceptor;

import java.lang.reflect.Proxy;

public class TargetProxy {

    public Object getProxy(Object object){
        
        TargetHandler targetHandler = new TargetHandler();
        targetHandler.setObject(object);
        
        return Proxy.newProxyInstance(TargetImpl.class.getClassLoader(), object.getClass().getInterfaces(), targetHandler);
        
    }
}

 

step 05: 最後建立一個 Class: Client.java 來作測試

package com.test.interceptor;

public class Client {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        TargetProvider target = new TargetImpl();
        TargetProxy targetProxy = new TargetProxy();
        
        TargetProvider proxy = (TargetProvider) targetProxy.getProxy(target);
        proxy.doExecute();
    

    }

}

 

執行 Class: Client 的結果如下:

before Execute
do Execute
after Execute

所以可以得知:在目標對象 Object: TargetProvider target ,透過代理 Proxy:  TargetProxy targetProxy 執行時,會動態產生新的 ProxyInstance,並藉由動態產生新的 ProxyInstance 間接讓 InvocationHandlerinvoke() 方法,使得 目標對象 Object: TargetProvider target 與攔截器 Interceptor 攔截器:TargetInterceptor 產生關連 ,因此可以作到我們想要攔截到目標對象時,想要多作的作業。

 

文章標籤

MIS 發表在 痞客邦 留言(1) 人氣()

Struts 2 要與 Spring 結合並不難,因為 Struts 2 本身就已經預留介面,在 struts2-core-2.x.x.jar 裡的 org.apache.struts2.default.properties 有這一段設定

### if specified, the default object factory can be overridden here
### Note: short-hand notation is supported in some cases, such as "spring"
###       Alternatively, you can provide a com.opensymphony.xwork2.ObjectFactory subclass name here
# struts.objectFactory = spring

### specifies the autoWiring logic when using the SpringObjectFactory.
### valid values are: name, type, auto, and constructor (name is the default)
struts.objectFactory.spring.autoWire = name

 

現在來實作一下:

Step 01: 建立一個帳號登入的 userLogin.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<%@ taglib prefix="sj" uri="/struts-jquery-tags" %>
<%@ taglib prefix="sb" uri="/struts-bootstrap-tags" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<html>
<head>
    <!-- 設定 base patch  
    if you want to set a base path for all relative links so that you don't need to repeat
    ${pageContext.request.contextPath} in every relative link, use the <base> tag.
    This way every relative link (i.e. not starting with / or a scheme) will become relative to the <base>.
    -->
    <c:set var="url">${pageContext.request.requestURL}</c:set>
    <base href="${fn:substring(url, 0, fn:length(url) - fn:length(pageContext.request.requestURI))}${pageContext.request.contextPath}/" />    
    <sj:head jqueryui="false"/>
    <sb:head includeScripts="true" includeScriptsValidation="false" includeStyles="true" />    
    
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="keywords" content="struts2, twitter, bootstrap, plugin, showcase" />
    <meta name="description" content="Enable Client Side Validation - Struts2 Bootstrap Plugin" />
    
    <!-- Le HTML5 shim, for IE6-8 support of HTML elements -->
    <!--[if lt IE 9]>
    <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
    <![endif]-->

     <!-- Custom styles for this template
    <link href="css/Cosmo/bootstrap.min.css" rel="stylesheet">
    <link href="css/homepage.css" rel="stylesheet">
    -->
<title>User login</title>
</head>
<body>

<div class="container">
    <div class="row">
        <div class="col-md-6">
            Hi Welcome !!
        </div>
        <div class="col-md-6">

            <h1>歡迎光臨  </h1>
            <p>請輸入您的帳號</p>
            <s:actionmessage theme="bootstrap"/>
            <s:actionerror theme="bootstrap"/>


            <!--            
            <s:fielderror theme="bootstrap"/>

            <s:if test="hasActionErrors()">
               <div class="errors">
                  <s:actionerror/>
               </div>
            </s:if>           
            <s:if test="hasActionMessages()">
               <div class="welcome">
                  <s:actionmessage/>
               </div>
            </s:if>
             -->

            
            <s:form action="userLogin" theme="bootstrap" class="form-signin">
                <s:textfield key="loginName" />                
                <s:password key="password" />
                <s:submit cssClass="btn btn-primary"/>
            </s:form>

        </div>
    </div>

    <footer class="footer">
        <p class="pull-right"><a href="#">Back to top</a></p>        
    </footer>

</div>
<!-- /container -->

</body>
</html>

 

Step 02: 建立對應的 userLogin Action Class: com.gu.test.spring.LoginAction

package com.gu.test.spring;

import com.opensymphony.xwork2.ActionSupport;

public class LoginAction extends ActionSupport {
    private String loginName;
    private String password;
    
    public String getLoginName() {
        return loginName;
    }
    public void setLoginName(String loginName) {
        this.loginName = loginName;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
    
    public String execute() throws Exception {
        if (isInvalid(getLoginName()))
            return INPUT ;
        if(isInvalid(getPassword()))
            return INPUT;  
        
        return SUCCESS;
    }
    
    private boolean isInvalid(String str){
        return ( str==null || str.length()==0 );
    }
    
    @Override
    public void validate() {
        // TODO Auto-generated method stub
        super.validate();
        boolean isInvalidError = false;
        if (isInvalid(getLoginName())){
            this.addFieldError("loginName", this.getText("loginName.error") );
            isInvalidError = true;
        }
        if (isInvalid(getPassword())){
            this.addFieldError("password", this.getText("password.error") );
            isInvalidError = true;
        }
        if (isInvalidError){
            this.addActionError(getText("errors.general"));
        }
        
    }
}

 

Step 03: 利用Maven 來加入 Spring 的 Jar 檔. 可以參考 http://mvnrepository.com/artifact/org.apache.struts/struts2-spring-plugin

<dependency>
    <groupId>org.apache.struts</groupId>
    <artifactId>struts2-spring-plugin</artifactId>
    <version>2.3.16.3</version>
</dependency>

 

Step 04: 配置 Struts & Spring : struts.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
        "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
        "http://struts.apache.org/dtds/struts-2.3.dtd">
        
    <!--加入 Spring -->    
    <constant name="struts.objectFactory" value="spring" />
<struts>
    <package name="test" namespace="/test" extends="struts-default">

        <!-- Spring Testing -->
        <action name="userLogin_*" method="{1}" class="userLogin">
            <result name="input">userLogin.jsp</result>
            <result name="success">eip.jsp</result>
        </action>  

        <!-- Add additional "example" package actions here. -->

    </package>
</struts>

這裡的 class="userLogin" 已轉由 Spring 的介面來接手,因此在 Spring 的 applicationContext.xml 要有 bean id="userLogin" 來承接,並指定 class="com.gu.test.spring.LoginAction"

 

Step 05: 配置 Struts & Spring : applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<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.xsd">

    <bean id="userLogin" class="com.gu.test.spring.LoginAction" scope="prototype"/>
    
</beans>

 

Step 06: 配置 Struts & Spring : web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app id="struts_blank" version="2.4"
         xmlns="http://java.sun.com/xml/ns/j2ee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
  <display-name>Struts Blank</display-name>

<!-- Context Configuration locations for Spring XML files -->
<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>


  <filter>
    <filter-name>struts2</filter-name>
    <filter-class>
      org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter
    </filter-class>
  </filter>

  <filter-mapping>
    <filter-name>struts2</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>

  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
  </welcome-file-list>
    

  <!-- 啟動  Spring Bean Configure the Spring listener -->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>  
 
</web-app>

 

登入 http://localhost:8080/guMIS/test/userLogin_input 測試,這樣就可以運作正常了。

文章標籤

MIS 發表在 痞客邦 留言(0) 人氣()

在這篇文章:Apache 利用 mod_rewrite 做到網址轉換達成SEO優化 說到使用此方法的好處,在 Struts2 中也可以利用 WildcardMappings 來達成 SEO 優化,舉下列例子來說明:

原來:http://localhost:8080/guEBS/guWeb/userChooseLang?lang=chinese

變成:http://localhost:8080/guEBS/guWeb/userChooseLang/chinese

 

Step 1:在 struts.xml 上的設定

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
        "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
        "http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>    
    <constant name="struts.mapper.alwaysSelectFullNamespace" value="false"/>
    <constant name="struts.enable.SlashesInActionNames" value="true"/>
    <constant name="struts.patternMatcher" value="namedVariable"/>        
    
    <package name="guWeb" namespace="/guWeb" extends="struts-default">  

        <action name="userChooseLang/{lang}" class="com.gu.web.GUsetLang">    
            <result>/guWeb/Home.jsp</result>        
        </action>  


    </package>
    <!-- Add addition packages and configuration here. -->
</struts>

 

Step 2:Action Class: com.gu.web.GUsetLang.java

package com.gu.web;

public class GUsetLang extends ActionSupport {

    private String lang;
    @Override
    public String execute() throws Exception {
        // TODO Auto-generated method stub
        String sLang = "chinese".equalsIgnoreCase(getLang()) ? "zh-TW" : "en-US" ;        
        session.put("userLang", sLang);
        super.execute();
        setNavMenu("guWeb");
        return SUCCESS;
    }
    public String getLang() {
        return lang;
    }
    public void setLang(String lang) {
        this.lang = lang;
    }

}

 

Step 3:jsp頁面Home.jsp 的測試

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
       <h1>Wild Card Value</h1>
       lang: <s:property value="lang"/>
</body>
</html>

 

但要注意,若常數 <constant name="struts.patternMatcher" value="namedVariable"/> 或 <constant name="struts.patternMatcher" value="regex"/> ,則 <action name="demo_*" method="{1}" class="..."> 會無法正常作業,這設定只能二擇一。在 http://struts.apache.org/release/2.2.x/docs/wildcard-mappings.html 有說明。


Only one PatternMatcher implementation can be used at a time. The two implementations included with Struts 2 are mutually exclusive. You cannot use Wildcards and Named Variable patterns at the same application (if that were required, you'd need to create a custom PatternMatcher implementation).

參考:

http://www.struts2.info/blog/better-urls-with-struts2

http://struts.apache.org/release/2.2.x/docs/wildcard-mappings.html

文章標籤

MIS 發表在 痞客邦 留言(0) 人氣()

Struts 2 仍有多語言的支援,相關的文件可以查看 http://struts.apache.org/release/2.2.x/docs/localization.html ,搜尋的順序是:

  1. ActionClass.properties
  2. Interface.properties (every interface and sub-interface)
  3. BaseClass.properties (all the way to Object.properties)
  4. ModelDriven's model (if implements ModelDriven), for the model object repeat from 1
  5. package.properties (of the directory where class is located and every parent directory all the way to the root directory)
  6. search up the i18n message key hierarchy itself
  7. global resource properties

參考網文 Struts 2 – Resource bundle example 的一張圖可以大致瞭解其搜尋順序

 若 struts.xml 檔內容如下

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
        "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
        "http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>
    <constant name="struts.enable.DynamicMethodInvocation" value="false"/>
    <constant name="struts.devMode" value="true"/>
    <constant name="struts.custom.i18n.resources" value="messages" />  

    <package name="default" namespace="/" extends="struts-default">

        <global-results>
            <result name="error">/error.jsp</result>
        </global-results>

        <global-exception-mappings>
            <exception-mapping exception="java.lang.Exception" result="error"/>
        </global-exception-mappings>
      
        <action name="Login_*" method="{1}" class="com.gu.Login">
            <result name="input">/Login.jsp</result>
        </action>
    </package>
</struts>

而 properties 檔:global.properties & package.properties 擺放的位置如下圖:

struts_properties  

所以在 com.gu 裡的 package.properties 內的值就會優先於 global.properties。而 global-resource 的設定可以參考: http://struts.apache.org/release/2.3.x/docs/how-do-i-set-a-global-resource-bundle.html。但個人覺得最好用的是在 struts.xml 中設定 <constant name="struts.custom.i18n.resources" value="messages" />,然後在message.properties 檔作維護就好。

取得的方法有下列幾個方法:

1. Action class:使用函數 getText("key")

public class Login extends ActionSupport{
        ...
        public void validate(){
                if("".equals(getUsername())){
                        addFieldError("username", getText("username.required"));
                }
        }
}

 

2. property tag: property (屬性)的 tag 用 getText("key") 來取值

<s:property value="getText('username')" />

 

3. text tag:text(文字) 的 tag 用 "name" 的屬性來取值

<s:text name="username" />

 

4. Key attribute:以 "key" 的屬性來取值

<s:textfield key="username" />

 

5. I18n tag :指定檔案取值,例如讀取檔案 com.gu.ebs.package.properties

<s:i18n name="com.gu.ebs.package" >
     <s:text name="username" />
</s:i18n>

 

參考:

http://struts.apache.org/release/2.2.x/docs/localization.html

http://www.mkyong.com/struts2/struts-2-resource-bundle-example/

http://www.mkyong.com/struts2/struts-2-key-attribute-example/

 

文章標籤

MIS 發表在 痞客邦 留言(0) 人氣()

主要目的:如何在 eclipse 利用 maven 建立 struts2 並在 eclipse internal runtime Server: Tomcat 作開發環境測試

平台:

eclipse:
Version: Kepler Service Release 2
Build id: 20140224-0627

maven:Maven Integration for Eclipse (Luna and newer) 1.5

tomcat:apache-tomcat-7.0.52_x64

java:jdk1.7.0_45_x64

jboss:JBoss EAP 6.2.0.GA

 

step01:建立一個 struts2-archetype-blank 的 maven 專案

maven_struts_01.png

 

maven_struts_02.png

可以按一下 Add Archetype,建立一個空的 Struts2 專案,相關欄位資訊可以查:http://struts.apache.org/release/2.2.x/docs/struts-2-blank-archetype.html

maven_struts_03.png  

填入此專案相關的資訊

maven_struts_04.png  

目前的 Struts2 專案: guEBS 架構如下:

maven_struts_05.png

 

Step02:轉換成為 Dynamic Web project

選擇此專案 guEBS 按下滑鼠右鍵,選擇 Properties 裡的 Project Facets ,按下 Covert to faceted form...

 

maven_struts_06.png

先將 java 的版本改為 1.7 ,再將 Dynamic Web project 的 check box 打勾,此時下方會出現 "Further configuration available...",Content directory 原本是 WebContent ,修改為 src/main/webapp

maven_struts_07.png

再到 Deployment AssemblyMaven Dependencies 加入,然後按 Apply -> ok。

maven_struts_071.png  

 

Step03:Deploy to Internal runtime Server:Tomcat 測試

執行 Maven build 時, 應該在 target 目前下會產生 guEBS-1.0.0-SNAPSHOT.war,這個檔直接可以佈署在 JBoss 下執行。

maven_struts_08.png

 

也可以佈署在 eclipse 內的 runtime server,這裡 runtime server 使用的是 apache-tomcat-7.0.52_x64

maven_struts_09.png

 

執行時,會出現下列的錯誤訊息:The method getJspApplicationContext(ServletContext) is undefined for the type JspFactory

Messages:     
Unable to compile class for JSP: An error occurred at line: [42] in the generated java file: [D:\wei_workspace\.metadata\.plugins\org.eclipse.wst.server.core\tmp0\work\Catalina\localhost\guEBS\org\apache\jsp\example\HelloWorld_jsp.java] The method getJspApplicationContext(ServletContext) is undefined for the type JspFactory Stacktrace:

maven_struts_072.png  

The method getJspApplicationContext(ServletContext) is undefined for the type JspFactory 的異常的原因及解決辦法。

原因:這是由於工程的WEB-INF/lib下存在 jsp-api.jar、servlet-api.jar,與Tomcat自帶的jar包衝突造成的。
解決辦法:

從 pom.xml 檔中移除 jsp-api.jar、servlet-api.jar 的 dependency 設定

<!-- 本機 Tomcat 測試時, servlet-api , jsp-api 不要載入
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
            <version>2.4</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jsp-api</artifactId>
            <version>2.0</version>
            <scope>provided</scope>
        </dependency>
-->

 在測試一次,就沒有問題了,但若是佈署在 JBoss EAP 6.2.0.GA 則不需要在 pom.xml 檔的內文中移除 jsp-api.jar、servlet-api.jar 的 dependency 設定。

maven_struts_10.png

注意:若要重新作 maven build 產生 guEBS-1.0.0-SNAPSHOT.war 檔時,jsp-api.jar、servlet-api.jar 的 dependency 設定要加回來,不然會有錯誤訊息。

maven_struts_11.png  

 

參考:

http://struts.apache.org/release/2.2.x/docs/struts-2-maven-archetypes.html

https://wiki.base22.com/display/btg/How+to+create+a+Maven+web+app+and+deploy+to+Tomcat+-+fast

http://www.avajava.com/tutorials/lessons/how-do-i-deploy-a-maven-web-application-to-tomcat.html

http://developer.51cto.com/art/201205/338496.htm

 

文章標籤

MIS 發表在 痞客邦 留言(0) 人氣()

Struts2 的類型轉換方法有分成區域性及全域性兩種,以實例來說明這兩種的差別與設定方法。

實作的過程大致是這樣的:客戶端建立一個 X,Y 字串的輸入input.jsp ,然後經過 struts2 的類型轉換後,再顯示於客戶端 pointConverterResult.jsp

Step 01:建立 struts.xml 檔,內容為

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
    "http://struts.apache.org/dtds/struts-2.3.dtd">

<struts>
    <package name="test" namespace="/test" extends="struts-default">
        
        <action name="Hello" class="com.test.Hello">
            <result name="success">/test/Hello.jsp</result>
        </action>
        <action name="UserLogin_*" method="{1}" class="com.test.UserLoginAction">
            <result name="sign_on">/test/userLogin.jsp</result>
            <result name="input">/test/userLogin2.jsp</result>
            <result name="success">/test/userLoginResult.jsp</result>
        </action>
        
        <action name="PointConverter" class="com.test.PointConverterAction">
            <result name="success">/test/pointConverterResult.jsp</result>
        </action>
    </package>    
    
</struts>

 

Step 02:建立客戶端的輸入劃面 input.jsp & 處理後的的顥示劃面 pointConverterResult.jsp

input.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<%
String path = request.getContextPath();
String basePath = request.getScheme() + "://" + request.getServerName() +":"+ request.getServerPort() + path;
%>

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<base href="<%=basePath%>" >

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Converter Demo</title>
</head>
<body>
point 欄位輸入座標 x,y 取出 x 與 y 值
<s:form name="frm_PointConver" action="PointConverter">
    <s:textfield name="point" label="point"/>
    <s:textfield name="point1" label="point1"/>
    <s:textfield name="age" label="age"/>
    <s:textfield name="username" label="userName" />
    <s:textfield name="date" label="birthday" />
    
    <s:submit/>
</s:form>
</body>
</html>

 

pointConverterResult.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>    
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>point Converter Result</title>
</head>
<body>

Point:<s:property value="point"/> <br>
Point1:<s:property value="point1"/> <br>
age:<s:property value="age"/><br>
username:<s:property value="username"/><br>
birthday:<s:property value="date"/><br>


</body>
</html>

 

Step 03:建立 class:Point 於 package: com.test 下,這個 class 很簡單,只是為了設定/取得 X,Y 軸的值

package com.test;

public class Point {

    private int x,y;

    public int getX() {
        return x;
    }

    public void setX(int x) {
        this.x = x;
    }

    public int getY() {
        return y;
    }

    public void setY(int y) {
        this.y = y;
    }
    
}

 

Step 04:建立一個自定類型轉換的 class: PointConverter 於 package: com.test 下,因為 struts2 的 JAR 檔內有一個 ognl-x.x.x.jar,此 JAR 包含了一個 class:TypeConverter,這個 class 預設有一個 DefaultTypeConverter method,所以可以利用這個 method 來改寫我們自已想要的類型轉換,文檔可以參考:http://commons.apache.org/proper/commons-ognl/apidocs/index.html

package com.test;

import java.util.Date;
import java.util.Map;

import ognl.DefaultTypeConverter;

public class PointConverter extends DefaultTypeConverter {

    @Override
    public Object convertValue(Map context, Object value, Class toType) {
        // TODO Auto-generated method stub
        //return super.convertValue(context, value, toType);
        
        // 從 客戶端 至 伺服器端
        if ( Point.class == toType ){
            Point point = new Point();
            
            String[] str = (String[]) value;
            String[] paramValues = str[0].split(",");
            
            int x = Integer.parseInt(paramValues[0]);
            int y = Integer.parseInt(paramValues[1]);
            
            point.setX(x);
            point.setY(y);
            
            return point;
        }
        

        // 從伺服器端 至 客戶端
        if (String.class == toType){
            Point point = (Point) value;
            
            int x = point.getX();
            int y = point.getY();
            
            String result = "[X:" + x + ",Y:" + y +"]";
            return result;
        }
        
        return null;
        
    }

}

 

Step 05: 依 struts.xml 裡指示,建立一個 Action class:PointConverterAction

package com.test;

import java.util.Date;

import com.opensymphony.xwork2.ActionSupport;

/**
 * @author polin.wei
 *
 */
public class PointConverterAction extends ActionSupport {

    private Point point;
    private Point point1;
    private int age;
    private String username;
    private Date date;
    
    public Point getPoint() {
        return point;
    }
    public void setPoint(Point point) {
        this.point = point;
    }
    
    public Point getPoint1() {
        return point1;
    }
    public void setPoint1(Point point1) {
        this.point1 = point1;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public Date getDate() {
        return date;
    }
    public void setDate(Date date) {
        this.date = date;
    }
    @Override
    public String execute() throws Exception {
        // TODO Auto-generated method stub
        
        return SUCCESS;
    }
    
    
}

 

Step 06:在類型轉換有分成區域性及全域性,若是區域性則在 Action class:PointConverterAction 相同的 package: com.test 下需建立一個檔案 PointConverterAction-conversion.properties (-conversion.properties 是固定的,此檔用來指示 struts2 那一個欄位,[ 如:input.jsp 中的 point 欄位] 在作 setPoint()/getPoint() 前,要先使用此自定義類型 [如: com.test.PointConverter ] 作轉換 );若是全域性:則在 struts.xml 檔案相同目錄下需建立一個檔案:xwork-conversion.properties 來指示 struts2 那一種類型 [如:com.test.Point] 均使用那一個 class [如:com.test.PointConverter ]來作類型轉換。

 

PointConverterAction-conversion.properties 的內容如下:

point=com.test.PointConverter

 

xwork-conversion.properties 的內容如下:

com.test.Point=com.test.PointConverter
文章標籤

MIS 發表在 痞客邦 留言(0) 人氣()

Struts 2 的開發環境設定,所需最低的要求為:

1. Servlet API 2.4
2. JSP API 2.0
3. Java 5

可以在 http://struts.apache.org/downloads.html 此下載所需的 Struts 2 所有開發套件,在此使用 Struts 2.3.15.2 ("best available")。

在此建議的 IDE 介面為 Eclipse IDE for Java and Report Developers Eclipse IDE for Java and Report Developers,下載後解壓於 D:\Progs\eclipse ; WEB Server 可以使用 Apache Tomcat v7.0.42 ,下載後解壓於C:\AppServ\apache-tomcat-7.0.42 ; Java JDK 1.6 或 1.7 版,下載後執行安裝。接下來就直接執行 D:\Progs\eclipse\eclipse.exe 即可啟動 Eclipse IDE 開發環境。

Step 1: 首先要在 Eclipse IDE 開發環境建立一個專案 struts2_test:

struts2-sample-project.png  

整個專案的程式擺放配置如下圖:

struts2-sample.png  

Step 2: 在此專案的 WEB-INF 下建立一個 web.xml 來定義此專案起動時的執行方式

<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_9" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">

    <display-name>Struts Blank</display-name>

    <filter>
        <filter-name>struts2</filter-name>
        <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
    </filter>

    <filter-mapping>
        <filter-name>struts2</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <welcome-file-list>
        <welcome-file>index.html</welcome-file>
    </welcome-file-list>

</web-app>

Step 3: 於Java Source 下建立 Struts 2 Action 的規則檔: struts.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
    "http://struts.apache.org/dtds/struts-2.3.dtd">

<struts>

    <constant name="struts.enable.DynamicMethodInvocation" value="false" />
    <constant name="struts.devMode" value="true" />

    <package name="default" namespace="/" extends="struts-default">

        <default-action-ref name="index" />

        <global-results>
            <result name="error">/error.jsp</result>
        </global-results>

        <global-exception-mappings>
            <exception-mapping exception="java.lang.Exception" result="error"/>
        </global-exception-mappings>

        <action name="index">
            <result type="redirectAction">
                <param name="actionName">HelloWorld</param>
                <param name="namespace">/example</param>
            </result>
        </action>
    </package>
    
    <!-- Add packages here -->    
    <include file="example.xml"/>
    <include file="test.xml"/>
</struts>

注意,可以使用Struts 2.3.15.2 中的 struts2-blank 的專案來作初始設定。這裡建立一個 test 的 package 測試,所以要將 test.xml 檔案含括進來。test.xml 的檔案內容如下:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
    "http://struts.apache.org/dtds/struts-2.3.dtd">

<struts>
    <package name="test" namespace="/test" extends="struts-default">
        
        <action name="Hello" class="com.test.Hello">
            <result name="success">/test/Hello.jsp</result>
        </action>
        <action name="UserLogin_*" method="{1}" class="com.test.UserLoginAction">
            <result name="sign_on">/test/userLogin.jsp</result>
            <result name="input">/test/userLogin2.jsp</result>  => input 是 struts2 的預設值,即是 http://localhost:8080/struts2_test/test/UserLogin_input 會指向 /test/userLogin2.jsp 這個檔案
            <result name="success">/test/userLoginResult.jsp</result>
        </action>
        
    </package>    
    
</struts>

 Step 3:將所需 Struts2 的 JAR 檔放在 WEB-INF/lib 目錄下:

asm-3.3.jar
asm-commons-3.3.jar
asm-tree-3.3.jar
commons-fileupload-1.3.jar
commons-io-2.0.1.jar
commons-lang3-3.1.jar
commons-logging-1.1.3.jar
freemarker-2.3.19.jar
javassist-3.11.0.GA.jar
log4j-1.2.17.jar
ognl-3.0.6.jar
struts2-core-2.3.15.2.jar
xwork-core-2.3.15.2.jar

Step 4: 先建立一個顯示 "Hi Hello Struts 2!!"  的 Hello.jsp 頁面,其中"Hello Struts 2!!"為要取得的message。

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>    
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Hello Struts 2</title>
</head>
<body>
  Hi <s:property value="message" />
</body>
</html>

  Step 5: Hello.jsp 頁面裡要取得 message 的變數,在 test.xml 控制檔中已宣告對應的 class="com.test.Hello" ,所以要建立取得此 message 的方法:getMessage(),檔案為 Hello.java ,package 為 com.test

package com.test;

public class Hello {
    public String getMessage(){
        return "Hello Struts 2!!";
    }
    
    public String execute(){
        return "success";
    }
}

注意:struts2 預設回應的方法為 execute() ,只要填入 return "success" 即可在 Apache Tomcate 中執行 http://localhost:8080/struts2_test/test/Hello 。

 

建立一個使用者登入作業範例:

step 1:建立 userLogin2.jsp

還記得在 test.xml 中我們有一個設定<result name="input">/test/userLogin2.jsp</result>  => input 是 struts2 的預設值,即是 http://localhost:8080/struts2_test/test/UserLogin_input 會指向 /test/userLogin2.jsp 這個檔案,內容如下:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
   
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>User Login Form Using taglib </title>
</head>
<body>

<s:form action="UserLogin">
    <s:textfield key="loginName" />
    <s:password key="password" />
    <s:submit />
</s:form>

</body>
</html>

 Step 2:建立對應的 ActionForm class="com.test.UserLoginAction"

package com.test;

import com.opensymphony.xwork2.ActionSupport;

public class UserLoginAction extends ActionSupport {
    
    private String loginName;
    private String password;
    
    public String getLoginName() {
        return loginName;
    }
    public void setLoginName(String loginName) {
        this.loginName = loginName;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
    
    public String execute() throws Exception {
        if (isInvalid(getLoginName()))
            return INPUT ;
        if(isInvalid(getPassword()))
            return "sign_on";
        
        return SUCCESS; // "success";
    }
    
    private boolean isInvalid(String str){
        return ( str==null || str.length()==0 );
    }
    
    @Override
    public void validate() {
        // TODO Auto-generated method stub
        super.validate();
        if (isInvalid(getLoginName()))
            this.addFieldError("loginName", "Login Name was required");
        
    }
    
}

 Step 3:對輸入欄位加入判斷

在 Struts2 要對欄位加入偵錯判斷的方法有二個,一個是覆寫 validate() 的方法,在此方法裡加入  this.addFieldError("loginName", "Login Name was required"); ,第二種方法為建立一個檔案為 程式名-validation.xml 的檔案,如: UserLoginAction-validation.xml,內容如下:

<!DOCTYPE validators PUBLIC
        "-//Apache Struts//XWork Validator 1.0.2//EN"
        "http://struts.apache.org/dtds/xwork-validator-1.0.2.dtd">

<validators>
    <field name="loginName">
        <field-validator type="requiredstring">
            <message key="requiredstring"/>
        </field-validator>
    </field>
    <field name="password">
        <field-validator type="requiredstring">
            <message key="requiredstring"/>
        </field-validator>
    </field>
</validators>

Step 4:建立多國語言判斷

Struts2 是可以支援多國語言的,但您必需使用 struts-tags 且在輸入欄位的 From 裡使用 key 值,如  <s:textfield key="loginName" /> ,多國語言的檔名為 package.properties ,預設是 US 。內容如下:

password = Password
loginName = Login Name

 PS: Eclipse 的多國語言的編輯器可以從 http://sourceforge.net/projects/eclipse-rbe/ 下載 ResourceBundleEditor_v0.8.0.zip ,解壓後放在 D:\Progs\eclipse\plugins 目錄下,重新起動 Eclipse 就可以了。

 參考:

http://struts.apache.org/release/2.2.x/docs/message-resource-files.html

 

文章標籤

MIS 發表在 痞客邦 留言(0) 人氣()