struts2+jfreechart整合

struts2 + jfreechart整合:
1、配置环境:
 在struts2中,默认的struts-default.xml中,并没有包含chart的result-type,它是插件的形式使用的。
 把 struts2的解压包的lib里找到struts2-jfreechart-plugin-2.1.8.1.jar,拷贝到你的项目的 classpath里,
 因为这个插件里的文件struts-plugin.xml里有一个chart的result-type。内容如下:

	<package name="jfreechart-default" extends="struts-default">
       	<result-types>
    		<result-type name="chart" class="org.apache.struts2.dispatcher.ChartResult">
    			<param name="height">150</param>
    			<param name="width">200</param>
    		</result-type>
    	</result-types>
    </package>

 

 

 同时把jfreechart的库文件jfreechart-1.0.13.jar和jcommon-1.0.16.jar拷贝到你的项目的 classpath里。

 

2、修改web.xml,增加下面的struts2的配置:

	<filter>
		<filter-name>struts2</filter-name>
		<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
		<init-param>
			<param-name>struts.i18n.encoding</param-name>
			<param-value>UTF-8</param-value>
		</init-param>
	</filter>

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

 

 

3、在src目录下增加新建一个struts.xml配置文件,其主要内容如下:

	<!--
		关于extends继承jfreechart-default这点请大家注意
		因为在struts-default这个包里并没有result-type为chart的 chart
		定义在前面我们导入的struts2-jfreechart-plugin-2.1.8.jar 下面的struts-plugin.xml文件中
	-->
	<package name="jfreechart" extends="jfreechart-default">
		<action name="jfreechart" class="org.usc.actions.JfreeChartAction">
			<result name="success" type="chart">
				<param name="width">600</param>
				<param name="height">400</param>
			</result>
		</action>
	</package>

 

 

4、写测试页面:

	<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
	<%
	String path = request.getContextPath();
	String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
	%>
	<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
	<html>
	  <head>
		<base href="<%=basePath%>">
		<title>jfreechart</title>
	  </head>
	  <body>
		 <img alt="jfreechart" src="jfreechart.action"/>
	  </body>
	</html>

 

 

5、在你的action代码里,返回一个JFreeChart对象即可:

	/**
	 * File   : JfreeChartAction.java
	 * Author : zqding
	 * Date   : 2010-7-27
	 * Version:
	 * Desc   : 	
	 */
	package org.usc.actions;

	import org.jfree.chart.ChartFactory;
	import org.jfree.chart.JFreeChart;
	import org.jfree.data.general.DefaultPieDataset;

	import com.opensymphony.xwork2.ActionSupport;

	public class JfreeChartAction extends ActionSupport {
		/**
		 * 定义JFreeChart对象 大家请注意在这里JFreeChart对象名只能为chart 
		 * 不能是别的, 关于这点大家可以上struts2网站上面查看一下
		 * http://struts.apache.org/2.x/docs/jfreechart-plugin.html
		 */
		private JFreeChart chart;
		
		public JFreeChart getChart() {
			return chart;
		}

		public void setChart(JFreeChart chart) {
			this.chart = chart;
		}

		@Override
		public String execute() throws Exception {
			 //设置数据
			DefaultPieDataset data = new DefaultPieDataset();
			data.setValue("Java", new Double(43.2));
			data.setValue("Visual Basic", new Double(1.0));
			data.setValue("C/C++", new Double(17.5)); 
			data.setValue("Android", new Double(60.0));
			//设置字体及生成的图片格式设置略,请参照API文档
			//生成JFreeChart对象
			chart = ChartFactory.createPieChart("Programme Language", data, true,true, false);
			return SUCCESS;
		}
	}

 

 6、发布到应用服务器,进行测试。
 http://localhost:9090/SSHDemo/jfreechart.jsp
 如下图:

jfreechart

Struts1.x系列教程(18):使用DispatchAction类调用多个Action方法

本文为原创,如需转载,请注明作者和出处,谢谢!

上一篇:Struts1.x系列教程(17):使用IncludeAction和ForwardAction类包含和转入Web资源

在使用Struts动作时,每一个Action都需要编写一个类,并且要在struts-config.xml进行配置。这对于一个拥有很多ActionWeb程序来说,工作量是非常大的。为此,Struts提供了DispatchAction类,这个类允许将一个Action作为一个方法来调用。在Web浏览器中通过请求参数来指定要调用的动作。
虽然
DispatchAction类是一个抽象类,但其中却没有一个抽象方法。因此,DisplatchAction的子类不用实现任何DisplatchAction类中的方法。但如果要处理Action代码,就必须根据相应的Action来编写Action方法。一个Action方法除了方法名和execute方法不一样外,其他的都和execute方法完全一样。但编写Action方法时要注意,Action方法名必须和用于指定动作的请求参数值一致(大小写也必须一致)。在下面的例子中演示了通过DispatchAction类实现方法和Action的对应。在这个例子中,有三个方法:frenunspecificed。其中fren是两个Action方法,分别用于将当前页面转发到法文和英文页面,而当用于指定Action的请求参数不存在时,则调用unspecificed方法(在这个方法中将当前页面转发到中文页面)。在这个程序中使用的用于指定Action的请求参数为language(读者可以指定自己的请求参数)。
<samples工程目录>\src\action目录建立一个MyDispatchAction.java文件,代码如下:

<!–<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
–>packageaction;

importjavax.servlet.RequestDispatcher;
importjavax.servlet.http.*;
importorg.apache.struts.action.*;
importorg.apache.struts.actions.*;

publicclassMyDispatchActionextendsDispatchAction
{
//forward到法文页面
publicActionForwardfr(ActionMappingmapping,ActionFormform,
HttpServletRequestrequest,HttpServletResponseresponse)
{
try
{
RequestDispatcherrd
=request.getRequestDispatcher(/newGlobal.jsp language=fr);
rd.forward(request,response);
}
catch(Exceptione)
{
}
returnnull;
}
//forward到英文页面
publicActionForwarden(ActionMappingmapping,ActionFormform,
HttpServletRequestrequest,HttpServletResponseresponse)
{
try
{
RequestDispatcherrd
=request.getRequestDispatcher(/newGlobal.jsp language=en);
rd.forward(request,response);
}
catch(Exceptione)
{
}
returnnull;
}
//在未使用language=fr和language=en作为访问参数的情况时调用这个方法
protectedActionForwardunspecified(ActionMappingmapping,ActionFormform,
HttpServletRequestrequest,HttpServletResponseresponse)
throwsException
{
try
{
//forward到中文页面
RequestDispatcherrd=request.getRequestDispatcher(/newGlobal.jsp language=zh);
rd.forward(request,response);
}
catch(Exceptione)
{
}
returnnull;
}
}

struts-config.xml文件中加入如下的配置代码来配置MyDispatchAction

<!–<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
–><actionpath=”/locale”type=”action.MyDispatchAction”parameter=”language”/>

其中parameter参数表示用于指定Action的请求参数名。

在启动Tomcat后,可通过如下的URL进行测试:

显示英文页面:

http://localhost:8080/samples/locale.do language=en

显示法文页面:

http://localhost:8080/samples/locale.do language=fr

显示中文页面(默认页面):

http://localhost:8080/samples/locale.do

虽然上面的代码可以很好地调用相应的Action方法,但在一些情况时,如请求参数language指定的Action方法不存在时,就会抛出异常。那么如果我们想在非正常情况下都调用默认的处理Action动作的方法(也就是unspecificed方法)该怎么办呢?

实现上,实现这个功能也非常简单,只要我们知道在什么条件下调用unspecified方法,然后在非正常情况下,都将条件设为调用unspecified方法的条件就可实现这个功能。在查看DispatchAction类的源代码后,可找到如下的代码片段:

<!–<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
–>if(name==null)//name表示Action方法名
{
returnthis.unspecified(mapping,form,request,response);
}

从上面的代码可知,只有当namenull时才会调用unspecified方法。这个name值实际上也就是language参数的值。也就是说,只有当language参数不存在时,name才会为null。如果在language的参数值所指的Action方法不存在时或者name为空串的情况下都将name设为null,那么就可以达到我们的目的。

DispatchAction类中有一个dispatchMethod方法,可以在这个方法中处理请求参数值为空串(也就是当“language=”时将方法名设为null)和Action方法未找到的情况。在Action类中有两个特殊方法:executeperform。如果调用了这两个方法,将会出现递归调用的情况。因此,在调用这两个方法时也需要将方法名设为null。这个工作可以在DispatchAction类的getMethodName方法中实现。为了完成这个功能,需要将上面的代码放到MyDispatchAction类中。

<!–<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
–>protectedActionForwarddispatchMethod(ActionMappingmapping,
ActionFormform,HttpServletRequestrequest,
HttpServletResponseresponse,Stringname)
throwsException
{
ActionForwardaf
=null;
//在language参数值为空串的情况下,将方法名赋为null
if(name!=null)//name表示Action方法名,也是language的参数值
if(name.equals(“”))
name
=null;
try
{
af
=super.dispatchMethod(mapping,form,request,response,name);
}
catch(NoSuchMethodExceptione)//处理Action方法未找到的情况
{
//在language的参数值没有对应的Action方法时,将方法名赋为null
name=null;
af
=super.dispatchMethod(mapping,form,request,response,name);
}
returnaf;
}
//当language的参数值为execute或perfore时,必须将方法名赋为null,否则会出现递归调用
protectedStringgetMethodName(ActionMappingmapping,ActionFormform,
HttpServletRequestrequest,HttpServletResponseresponse,
Stringparameter)
throwsException
{
StringmethodName
=super.getMethodName(mapping,form,request,response,parameter);
if(execute.equals(methodName)||perform.equals(methodName))
returnnull;//如果访问的是execute和perform,直接将方法名设为null
returnmethodName;
}

现在我们可以用任何请求参数来访问locale动作,只要未找到Action方法,就会调用默认的unspecified方法。读者可以使用如下的URL来实验一下:

http://localhost:8080/samples/locale.do language=

http://localhost:8080/samples/locale.do language=unknown

下一篇:Struts1.x系列教程(19):LookupDispatchAction类处理一个form多个submit

国内最棒的Google Android技术社区(eoeandroid),欢迎访问!

《银河系列原创教程》发布

《Java Web开发速学宝典》出版,欢迎定购

Struts1.x系列教程(16):使用LocaleAction类实现国际化的Web程序

本文为原创,如需转载,请注明作者和出处,谢谢!

上一篇:Struts1.x系列教程(15):使用DownloadAction类统计文件下载次数

我们曾经在《Struts1.x系列教程(13):国际化》一文中讲过如何通过编程的方式实现多语言的Web页面。在本文中,我们会介绍另外一种实现多语言Web页面的方法。这种方式与《Struts1.x系列教程(13):国际化》一文中所介绍的方法的区别就是无需编写一行代码就可以完成多语言的设置。

Struts提供了一个LocaleAction类来做这个工作。LocaleAction类是一个final动作类,因此,LocaleAction类不能被继承。我们可按着如下两步来使用LocaleAction类进行多语言设置:
1.
配置一个动态Form(当然,也可以使用ActionForm的子类,但为了方便,建议使用动态Form)。这个动态Form至少得有一个表示语言的language属性(如zhfrenjp等)。我们还可以加一个表示国家或地区的country属性(USCNTW)

2.使用<action>元素配置一个Struts动作。这个Struts动作的type属性值是org.apache.struts.actions.LocaleActionname属性值就是在第1步配置的动作Formname属性值。而且在<action>元素中必须有一个名为“success”的<forward>元素。如果语言设置成功,页面就会forward到“success”所指向的页面。

下面我们来举一个使用LocaleAction动作类设置语言的例子,代码如下:

<!–<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
–>
<form-beans>

<form-beanname=”EnglishForm”type=”org.apache.struts.action.DynaActionForm”>
<form-propertyname=”language”type=”java.lang.String”initial=”en”/>
<form-propertyname=”country”type=”java.lang.String”initial=”US”/>
</form-bean>
<form-beanname=”ChineseForm”type=”org.apache.struts.action.DynaActionForm”>
<form-propertyname=”language”type=”java.lang.String”initial=”zh”/>
</form-bean>
</form-beans>

<action-mappings>

<actionname=”EnglishForm”path=”/en”type=”org.apache.struts.actions.LocaleAction”>
<forwardname=”success”path=”/global.jsp”/>
</action>
<actionname=”ChineseForm”path=”/zh”type=”org.apache.struts.actions.LocaleAction”>
<forwardname=”success”path=”/global.jsp”/>
</action>
</action-mappings>

在上面的例子中,使用了在《Struts1.x系列教程(13):国际化》一文中建立的global.jsp文件。在启动Tomcat后,分别在IE中输入如下的URL,可以得到中文和英文的Web页面。

中文页面:http://localhost:8080/samples/zh.do

英文页面:http://localhost:8080/samples/en.do

下一篇:Struts1.x系列教程(17):使用IncludeAction和ForwardAction类包含和转入Web资源

国内最棒的Google Android技术社区(eoeandroid),欢迎访问!

《银河系列原创教程》发布

《Java Web开发速学宝典》出版,欢迎定购

Struts1.x系列教程(15):使用DownloadAction类统计文件下载次数

本文为原创,如需转载,请注明作者和出处,谢谢!

上一篇:Struts1.x系列教程(14):动态Form

除了标准的
org.apache.struts.action.Action类外,在Struts中还提供了另外7Action类来完成特殊的工作。本文及后面的文章中将介绍这些Action类的用法。

一、DownloadAction类简介

可能有时需要在Web程序中加入下载功能。如果要下载的是静态文件,可以直接交给Web服务器处理,但如果要对下载的文件做额外的功能,如统计文件的下载次数。就需要在下载文件之前先要调用相应的程序进行处理。
虽然我们可以直接在
Action子类中来处理下载文件,但是如果这样的程序比较多时,就会写很多重复的代码。为了简化这个工作。Struts提供了一个新的Action类:DownloadAction。所有继承了DownloadAction类的Struts动作都可以非常容易地完成下载文件的工作。
DownloadAction类有一个抽象方法getStreamInfo。这个方法的定义如下:

<!–<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
–>protectedabstractStreamInfogetStreamInfo(ActionMappingmapping,
ActionFormform,HttpServletRequestrequest,
HttpServletResponseresponse)
throwsException;


getStreamInfo方法返回一个StreamInfo对象。StreamInfo接口是DownloadAction类的一个内部接口,这个接口的定义如下:

<!–<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
–>publicstaticinterfaceStreamInfo
{
publicabstractStringgetContentType();
publicabstractInputStreamgetInputStream()throwsIOException;
}

从上面的代码可以看出,StreamInfo接口有两个方法。其中getInputStream方法返回了服务端要下载的文件的InputStream对象。getContenttType方法返回了HTTP响应消息头字段Content-Type的信息。在getStreamInfo方法中只要返回了实现这两个方法的StreamInfo对象,就可以自动完成下载工作。
为了方便起见,DownloadAction类中还提供了两个实现StreamInfo的内类:FileStreamInfo和ResourceStreamInfo。这两个类的构造方法的定义如下:

<!–<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
–>publicFileStreamInfo(StringcontentType,Filefile);
publicResourceStreamInfo(StringcontentType,ServletContextcontext,Stringpath);

我们可以使用FileStreamInfo类来下载静态的文件。如果要下载的文件在Web根目录,可以使用ResourceStreamInfo类。其中path参数表示文件相对于Web根目录的路径,必须以“/”开头,表示从Web根目录开始。

二、实例:统计文件的下载次数

在本节中将使用DownloadAction类实现一个统计文件下载次数的Web程序。这个程序的基本原理是当一个文件下载完成后,加这个文件在数据库中的下载次数加1,如果某个文件是第一次下载,则在数据库中添加一条新记录,下载次数为1

为了实现这个Web程序,需要如下几步:
【第1步】建立用于保存文件下载次数的数据表

在本例中我们使用名为struts数据库,并且在struts数据库中建立一个t_dcount表,代码如下:

<!–<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
–>CREATETABLEstruts.t_dcount(
id
INTNOTNULL,
countINTNOTNULL,
filename
VARCHAR(256)NOTNULL,
PRIMARYKEY(id)
)ENGINE
=InnoDBDEFAULTCHARSET=gbk;

【第2步】编写Struts动作类

这个Struts动作类负责完成文件的下载工作。如果在访问Struts动作类时不加file参数,会将指定目录下的所有文件(不包括隐藏文件)和已经下载的次数发送到客户端浏览器。如果通过file参数指定了下载文件,这个Struts动作就会下载这个文件。
在<samples工程目录>\src\action目录中建立一个FileDownloadAction.java文件,代码如下:

<!–<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
–>packagechapter6.action;

importjavax.servlet.http.*;
importorg.apache.struts.action.*;
importorg.apache.struts.actions.*;
importjava.io.*;
importjava.sql.*;

publicclassFileDownloadActionextendsDownloadAction
{
privateConnectionconn;
privateStringpath;
privateStringfilename;

//获得了Connection对象
privatevoidopenConnection()throwsException
{
if(conn==null)
{
Class.forName(
com.mysql.jdbc.Driver);
conn
=DriverManager.getConnection(
jdbc:mysql://localhost/struts characterEncoding=GBK,
root,1234);
}
}
//获得某个文件的下载次数,其中id是文件名的hashcode
privateintgetDownloadCount(intid)throwsException
{
openConnection();
PreparedStatementpstmt
=conn
.prepareStatement(
SELECTcountFROMt_dcountWHEREid=+String.valueOf(id));
ResultSetrs
=pstmt.executeQuery();
while(rs.next())
{
returnrs.getInt(1);
}
return0;
}
//在文件完成下载后,将该文件的下载次数加1
privatevoidincDownloadCount()throwsException
{
openConnection();
intid=filename.hashCode();
PreparedStatementpstmt
=conn
.prepareStatement(
UPDATEt_dcountSETcount=count+1WHEREid=
+String.valueOf(id));
if(pstmt.executeUpdate()==0)
{
pstmt.executeUpdate(
INSERTINTOt_dcount(id,count,filename)values(
+String.valueOf(id)+,1,’+filename+‘));
}
}

//下载文件时调用getStreamInfo方法
protectedStreamInfogetStreamInfo(ActionMappingmapping,ActionFormform,
HttpServletRequestrequest,HttpServletResponseresponse)
throwsException
{
finalFileInputStreamfis=newFileInputStream(path+filename);
finalStringcontentType=application/file;
//建议设置content-disposition响应信息头,否则Web浏览器在下载文件时
//无法在保存文件对话框中显示正确的文件名
response.setHeader(content-disposition,attachment;filename=
+filename);
incDownloadCount();
returnnewDownloadAction.StreamInfo()//使用隐式的方法实现了StreamInfo接口
{
publicStringgetContentType()
{

returncontentType;
}
publicInputStreamgetInputStream()throwsIOException
{
returnfis;
}
};
}
//如果Struts动作不加file请求参数,则通过execute方法将指定目录中文件列表输出到客户端
publicActionForwardexecute(ActionMappingmapping,ActionFormform,
HttpServletRequestrequest,HttpServletResponseresponse)
throwsException
{
path
=this.getServlet().getInitParameter(downloadPath);
filename
=request.getParameter(file);
if(filename==null)
{
Filefile
=newFile(path);
File[]files
=file.listFiles();
response.setCharacterEncoding(
GBK);
PrintWriterout
=response.getWriter();

out.println(<ul>);
for(Filef:files)//开始向客户端浏览器输出文件列表
{

if(f.isFile()&&!f.isHidden())
{
out.println(
<li><ahref=’+request.getContextPath()+mapping.getPath()
+.do file=+f.getName()+‘>+f.getName()
+</a>&nbsp;&nbsp;<fontcolor=’blue’>下载次数:
+String.valueOf(getDownloadCount(f.getName().hashCode()))
+</color></li>);
}
}
out.println(
</ul>);
returnnull;
}
else
{
//当file参数存在时,则调用DownloadAction中的execute方法
//实际上,在DownloadAction类中的execute方法调用了getStreamInfo方法
//这条语句就相当于调用了getStreamInfo方法
returnsuper.execute(mapping,form,request,response);
}
}
}

【第3步】配置Struts动作类

在struts-config.xml文件中的<action-mappings>标签中加入了如下内容:

<!–<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
–><actionpath=”/download”scope=”request”type=”action.FileDownloadAction”/>

【第4步】配置下载路径

在web.xml中找到一个叫action的Servlet,并在<servlet>标签中添加如下内容:

<!–<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
–> <init-param>
<param-name>downloadPath</param-name>
<param-value>D:\download\</param-value>
</init-param>

读取可以设置自已的下载目录,但下载目录必须以“”结尾。
启动Tomcat后,在IE中输入如下的URL来测试程序:

http://localhost:8080/samples/download.do


下一篇:Struts1.x系列教程(16):使用LocaleAction类实现国际化的Web程序

国内最棒的Google Android技术社区(eoeandroid),欢迎访问!

《银河系列原创教程》发布

《Java Web开发速学宝典》出版,欢迎定购

Struts2教程8:拦截器概述

本文为原创,如需转载,请注明作者和出处,谢谢!

上一篇:Struts2教程7:上传任意多个文件

Struts2的拦截器和Servlet过滤器类似。在执行Actionexecute方法之前,Struts2会首先执行在struts.xml中引用的拦截器,在执行完所有引用的拦截器的intercept方法后,会执行Actionexecute方法。

Struts2拦截器类必须从com.opensymphony.xwork2.interceptor.Interceptor接口继承,在Intercepter接口中有如下三个方法需要实现:
<!–<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
–>

<!–<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
–>voiddestroy();
voidinit();
Stringintercept(ActionInvocationinvocation)
throwsException;

其中intercept方法是拦截器的核心方法,所有安装的拦截器都会调用之个方法。在Struts2中已经在struts-default.xml中预定义了一些自带的拦截器,如timerparams等。如果在<package>标签中继承struts-default,则当前package就会自动拥有struts-default.xml中的所有配置。代码如下:

<package name=”demo”
extends=”struts-default” > … </package>

struts-default.xml中有一个默认的引用,在默认情况下(也就是<action>中未引用拦截器时)会自动引用一些拦截器。这个默认的拦截器引用如下:

<!–<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
–><default-interceptor-refname=”defaultStack”/>

<interceptor-stackname=”defaultStack”>
<interceptor-refname=”exception”/>
<interceptor-refname=”alias”/>
<interceptor-refname=”servletConfig”/>
<interceptor-refname=”prepare”/>
<interceptor-refname=”i18n”/>
<interceptor-refname=”chain”/>
<interceptor-refname=”debugging”/>
<interceptor-refname=”profiling”/>
<interceptor-refname=”scopedModelDriven”/>
<interceptor-refname=”modelDriven”/>
<interceptor-refname=”fileUpload”/>
<interceptor-refname=”checkbox”/>
<interceptor-refname=”staticParams”/>
<interceptor-refname=”params”>
<paramname=”excludeParams”>dojo\..*</param>
</interceptor-ref>
<interceptor-refname=”conversionError”/>
<interceptor-refname=”validation”>
<paramname=”excludeMethods”>input,back,cancel,browse</param>
</interceptor-ref>
<interceptor-refname=”workflow”>
<paramname=”excludeMethods”>input,back,cancel,browse</param>
</interceptor-ref>
</interceptor-stack>

上面在defaultStack中引用的拦截器都可以在<action>中不经过引用就可以使用(如果在<action>中引用了任何拦截器后,要使用在defaultStack中定义的拦截器,也需要在<action>中重新引用,在后面将详细讲解)。

下面我们来看几个简单的拦截器的使用方法。

一、记录拦截器和execute方法的执行时间(timer)

timerStruts2中最简单的拦截器,这个拦截器对应的类是com.opensymphony.xwork2.interceptor.TimerInterceptor。它的功能是记录execute方法和其他拦截器(在timer后面定义的拦截器)的intercept方法执行的时间总和。如下面的配置代码所示:

<!–<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
–><actionname=”first”class=”action.FirstAction”>
<interceptor-refname=”logger”/>
<interceptor-refname=”timer”/>
</action>

由于在timer后面没有其他的拦截器定义,因此,timer只能记录execute方法的执行时间,在访问first动作时,会在控制台输出类似下面的一条信息:

信息: Executed action [/test/first!execute] took 16 ms.

在使用timer拦截器时,需要commons-logging.jar的支持。将logger引用放到timer的后面,就可以记录logger拦截器的intercept方法和Actionexecute方法的执行时间总和,代码如下:

<!–<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
–><actionname=”first”class=”action.FirstAction”>
<interceptor-refname=”timer”/>
<interceptor-refname=”logger”/>
</action>

大家可以使用如下的Action类来测试一下timer拦截器:

<!–<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
–>packageaction;

importcom.opensymphony.xwork2.ActionSupport;

publicclassFirstActionextendsActionSupport

{
publicStringexecute()throwsException

{
Thread.sleep(1000);//延迟1秒
returnnull;
}

}

如果只记录execute方法的执行时间,一般会输出如下的信息:

信息: Executed action [/test/first!execute] took 1000 ms.

二、通过请求调用Actionsetter方法(params)


当客户端的一个form向服务端提交请求时,如有一个textfield,代码如下:

<!–<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
–><s:formaction=”first”namespace=”/test”>
<s:textfieldname=”name”/>
<s:submit/>
</s:form>

在提交后,Struts2将会自动调用first动作类中的setName方法,并将name文本框中的值通过setName方法的参数传入。实际上,这个操作是由params拦截器完成的,params对应的类是com.opensymphony.xwork2.interceptor.ParametersInterceptor。由于params已经在defaultStack中定义,因此,在未引用拦截器的<action>中是会自动引用params的,如下面的配置代码,在访问first动作时,Struts2是会自动执行相应的setter方法的。

<action name=”first”
class=”action.FirstAction”>


… …

</action>

但如果在<action>中引用了其他的拦截器,就必须再次引用params拦截器,Struts2才能调用相应的setter方法。如下面的配置代码所示:

<!–<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
–><actionname=”first”class=”action.FirstAction”>
<interceptor-refname=”timer”/>
<interceptor-refname=”params”/>
</action>

三、通过配置参数调用Actionsetter方法(static-params)

static-params拦截器可以通过配置<params>标签来调用Action类的相应的setter方法,static-params拦截器对应的类是com.opensymphony.xwork2.interceptor.StaticParametersInterceptor。
下面配置代码演示了如何使用static-params拦截器:

<!–<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
–><actionname=”first”class=”action.FirstAction”>
<interceptor-refname=”timer”/>
<paramname=”who”>比尔</param>
<interceptor-refname=”params”/>
<interceptor-refname=”static-params”/>
</action>

如果first动作使用上面的配置,在访问first动作时,Struts2会自动调用setWho方法将“比尔”作为参数值传入setWho方法。

四、使用拦截器栈

为了能在多个动作中方便地引用同一个或几个拦截器,可以使用拦截器栈将这些拦截器作为一个整体来引用。拦截器栈要在<package>标签中使用<interceptors>和子标签<interceptor-stack>来定义。代码如下:

<!–<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
–><packagename=”demo”extends=”struts-default”>
<interceptors>
<interceptor-stackname=”mystack”>
<interceptor-refname=”timer”/>
<interceptor-refname=”logger”/>
<interceptor-refname=”params”/>
<interceptor-refname=”static-params”/>
</interceptor-stack>
</interceptors>

<actionname=”first”class=”action.FirstAction”>
<paramname=”who”>比尔</param>
<interceptor-refname=”mystack”/>
</action>
</package>

可以象使用拦截器一样使用拦截器栈,如上面代码所示。


下一篇:Struts2教程9:实现自已的拦截器



国内最棒的Google Android技术社区(eoeandroid),欢迎访问!

《银河系列原创教程》发布

《Java Web开发速学宝典》出版,欢迎定购

Struts1.x系列教程(15):使用DownloadAction类统计文件下载次数

本文为原创,如需转载,请注明作者和出处,谢谢!

上一篇:Struts1.x系列教程(14):动态Form

除了标准的
org.apache.struts.action.Action类外,在Struts中还提供了另外7Action类来完成特殊的工作。本文及后面的文章中将介绍这些Action类的用法。

一、DownloadAction类简介

可能有时需要在Web程序中加入下载功能。如果要下载的是静态文件,可以直接交给Web服务器处理,但如果要对下载的文件做额外的功能,如统计文件的下载次数。就需要在下载文件之前先要调用相应的程序进行处理。
虽然我们可以直接在
Action子类中来处理下载文件,但是如果这样的程序比较多时,就会写很多重复的代码。为了简化这个工作。Struts提供了一个新的Action类:DownloadAction。所有继承了DownloadAction类的Struts动作都可以非常容易地完成下载文件的工作。
DownloadAction类有一个抽象方法getStreamInfo。这个方法的定义如下:

<!–<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
–>protectedabstractStreamInfogetStreamInfo(ActionMappingmapping,
ActionFormform,HttpServletRequestrequest,
HttpServletResponseresponse)
throwsException;


getStreamInfo方法返回一个StreamInfo对象。StreamInfo接口是DownloadAction类的一个内部接口,这个接口的定义如下:

<!–<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
–>publicstaticinterfaceStreamInfo
{
publicabstractStringgetContentType();
publicabstractInputStreamgetInputStream()throwsIOException;
}

从上面的代码可以看出,StreamInfo接口有两个方法。其中getInputStream方法返回了服务端要下载的文件的InputStream对象。getContenttType方法返回了HTTP响应消息头字段Content-Type的信息。在getStreamInfo方法中只要返回了实现这两个方法的StreamInfo对象,就可以自动完成下载工作。
为了方便起见,DownloadAction类中还提供了两个实现StreamInfo的内类:FileStreamInfo和ResourceStreamInfo。这两个类的构造方法的定义如下:

<!–<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
–>publicFileStreamInfo(StringcontentType,Filefile);
publicResourceStreamInfo(StringcontentType,ServletContextcontext,Stringpath);

我们可以使用FileStreamInfo类来下载静态的文件。如果要下载的文件在Web根目录,可以使用ResourceStreamInfo类。其中path参数表示文件相对于Web根目录的路径,必须以“/”开头,表示从Web根目录开始。

二、实例:统计文件的下载次数

在本节中将使用DownloadAction类实现一个统计文件下载次数的Web程序。这个程序的基本原理是当一个文件下载完成后,加这个文件在数据库中的下载次数加1,如果某个文件是第一次下载,则在数据库中添加一条新记录,下载次数为1

为了实现这个Web程序,需要如下几步:
【第1步】建立用于保存文件下载次数的数据表

在本例中我们使用名为struts数据库,并且在struts数据库中建立一个t_dcount表,代码如下:

<!–<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
–>CREATETABLEstruts.t_dcount(
id
INTNOTNULL,
countINTNOTNULL,
filename
VARCHAR(256)NOTNULL,
PRIMARYKEY(id)
)ENGINE
=InnoDBDEFAULTCHARSET=gbk;

【第2步】编写Struts动作类

这个Struts动作类负责完成文件的下载工作。如果在访问Struts动作类时不加file参数,会将指定目录下的所有文件(不包括隐藏文件)和已经下载的次数发送到客户端浏览器。如果通过file参数指定了下载文件,这个Struts动作就会下载这个文件。
在<samples工程目录>\src\action目录中建立一个FileDownloadAction.java文件,代码如下:

<!–<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
–>packagechapter6.action;

importjavax.servlet.http.*;
importorg.apache.struts.action.*;
importorg.apache.struts.actions.*;
importjava.io.*;
importjava.sql.*;

publicclassFileDownloadActionextendsDownloadAction
{
privateConnectionconn;
privateStringpath;
privateStringfilename;

//获得了Connection对象
privatevoidopenConnection()throwsException
{
if(conn==null)
{
Class.forName(
com.mysql.jdbc.Driver);
conn
=DriverManager.getConnection(
jdbc:mysql://localhost/struts characterEncoding=GBK,
root,1234);
}
}
//获得某个文件的下载次数,其中id是文件名的hashcode
privateintgetDownloadCount(intid)throwsException
{
openConnection();
PreparedStatementpstmt
=conn
.prepareStatement(
SELECTcountFROMt_dcountWHEREid=+String.valueOf(id));
ResultSetrs
=pstmt.executeQuery();
while(rs.next())
{
returnrs.getInt(1);
}
return0;
}
//在文件完成下载后,将该文件的下载次数加1
privatevoidincDownloadCount()throwsException
{
openConnection();
intid=filename.hashCode();
PreparedStatementpstmt
=conn
.prepareStatement(
UPDATEt_dcountSETcount=count+1WHEREid=
+String.valueOf(id));
if(pstmt.executeUpdate()==0)
{
pstmt.executeUpdate(
INSERTINTOt_dcount(id,count,filename)values(
+String.valueOf(id)+,1,’+filename+‘));
}
}

//下载文件时调用getStreamInfo方法
protectedStreamInfogetStreamInfo(ActionMappingmapping,ActionFormform,
HttpServletRequestrequest,HttpServletResponseresponse)
throwsException
{
finalFileInputStreamfis=newFileInputStream(path+filename);
finalStringcontentType=application/file;
//建议设置content-disposition响应信息头,否则Web浏览器在下载文件时
//无法在保存文件对话框中显示正确的文件名
response.setHeader(content-disposition,attachment;filename=
+filename);
incDownloadCount();
returnnewDownloadAction.StreamInfo()//使用隐式的方法实现了StreamInfo接口
{
publicStringgetContentType()
{

returncontentType;
}
publicInputStreamgetInputStream()throwsIOException
{
returnfis;
}
};
}
//如果Struts动作不加file请求参数,则通过execute方法将指定目录中文件列表输出到客户端
publicActionForwardexecute(ActionMappingmapping,ActionFormform,
HttpServletRequestrequest,HttpServletResponseresponse)
throwsException
{
path
=this.getServlet().getInitParameter(downloadPath);
filename
=request.getParameter(file);
if(filename==null)
{
Filefile
=newFile(path);
File[]files
=file.listFiles();
response.setCharacterEncoding(
GBK);
PrintWriterout
=response.getWriter();

out.println(<ul>);
for(Filef:files)//开始向客户端浏览器输出文件列表
{

if(f.isFile()&&!f.isHidden())
{
out.println(
<li><ahref=’+request.getContextPath()+mapping.getPath()
+.do file=+f.getName()+‘>+f.getName()
+</a>&nbsp;&nbsp;<fontcolor=’blue’>下载次数:
+String.valueOf(getDownloadCount(f.getName().hashCode()))
+</color></li>);
}
}
out.println(
</ul>);
returnnull;
}
else
{
//当file参数存在时,则调用DownloadAction中的execute方法
//实际上,在DownloadAction类中的execute方法调用了getStreamInfo方法
//这条语句就相当于调用了getStreamInfo方法
returnsuper.execute(mapping,form,request,response);
}
}
}

【第3步】配置Struts动作类

在struts-config.xml文件中的<action-mappings>标签中加入了如下内容:

<!–<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
–><actionpath=”/download”scope=”request”type=”action.FileDownloadAction”/>

【第4步】配置下载路径

在web.xml中找到一个叫action的Servlet,并在<servlet>标签中添加如下内容:

<!–<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
–> <init-param>
<param-name>downloadPath</param-name>
<param-value>D:\download\</param-value>
</init-param>

读取可以设置自已的下载目录,但下载目录必须以“”结尾。
启动Tomcat后,在IE中输入如下的URL来测试程序:

http://localhost:8080/samples/download.do


下一篇:Struts1.x系列教程(16):使用LocaleAction类实现国际化的Web程序

国内最棒的Google Android技术社区(eoeandroid),欢迎访问!

《银河系列原创教程》发布

《Java Web开发速学宝典》出版,欢迎定购

Struts2教程10:国际化

本文为原创,如需转载,请注明作者和出处,谢谢!

上一篇:Struts2教程9:实现自已的拦截器

国际化的作用就是根据不同国家的用户在访问Web或其他类型的程序时,将各种信息以本地的常用形式显示出来,如界面信息在中国,就会显示中文信息,在以英文为主的国家里,就会显示英文信息。还有就是一些信息的格式,如日期格式等。

从属性文件中获得字符串信息是国际化的基本应用。在Struts2中使用的属性文件就是Java属性文件,扩展名为properties。在Struts2中的属性文件可以有很多默认的位置,Struts2可按如下的顺序(或步骤)来定位属性文件:

1.ActionClass.properties:属性文件名和动作类同名。Struts2会首先查询与当前访问的动作类同名,并且和ActionClass.class在同一个目录下的属性文件。

2.BaseClass.propertiesBaseClass表示动作类的基类。所有动作类都会查找Object.properties文件(因为Object是所有Java类的基类),但要注意的是Object.properties文件可不能放到当前动作类的目录中,由于Objectjava.lang包中,因此,Object.properties要放到jdk包的java”lang目录中。而对于ActionSupport.properties文件,当然也不能放到动作类的当前目录中,由于ActionSupport类中com.opensymphony.xwork2名中,因此,需要将ActionSupport.properties文件放到xwork2.jar包中的com\opensymphony\xwork2目录中,由于放到jar文件中不太方便,因此,可以使一个和当前动作类在一个目录的类先继承ActionSupport,然后所有的动作类都继承于这个类。代码如下:

<!–<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
–>publicclassMyActionSupportextendsActionSupport
{
… …
}
publicclassActionClassextendsMyActionSupport
{
… …
}

这样的话,只要存在一个MyActionSupport.properties,在当前目录下的所有动作类都会读取这个文件。

3.Interface.properties:这类文件和BaseClass.properties类似,Interface表示动作类实现的接口。

4.如果动作类实现了ModelDriven, 那么重复第1步。

5.package.properties:大家要注意。这个文件就叫package.properties。不象InterfaceBaseClass都是泛指。这个文件可以放到当前动作类的包的任何一层目录下。如当前动作类在action.test包中。那么package.properties可以放到action目录中,也可以放到action”test目录中。Struts2会从离动作类最近的位置开始查找package.properties文件。

6.搜索il8n资源信息

7.查找全局资源属性文件

如下面是一个动作类

<!–<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
–>packageaction.test;

importorg.apache.struts2.*;
importcom.opensymphony.xwork2.ActionSupport;

publicclassInternationalizingextendsActionSupport
{
publicStringexecute()throwsException
{
returnforward;
}
}

action\test目录下有一个Internationalizing.properties文件,内容如下:

delete = 删除

save = 保存

我们可以在jsp文件中使用如下几种方法取出资源信息:

<s:propertyvalue=”getText(‘delete’)”/>

<s:text name=”save” />


3.
使用<s:il8n>标签。这个标签可以直接定位属性文件,如abc.propertiesWEB-INF\classes\test目录下,内容和Internationalizing.properties一样,则可以使用如下的代码读取abc.properties的内容:

<!–<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
–><%@taglibprefix=suri=/struts-tags%>
<s:i18nname=”test.abc”>
<s:textname=”save”/>
<s:textname=”delete”/>
</s:i18n>

当然,我们也可以使用全局的属性文件,在WEB-INF”classes目录下建立一个struts.properties文件,内容如下:

struts.custom.i18n.resources=my

WEB-INF\classes目录下建立一个my.properties文件,当Struts2按着上述的顺序没有找到相应的属性文件时,最后就会考虑寻找全局的属性文件,因此,就会找到my.properties

还可以通过属性文件名来让Struts2按着客户端浏览器的语言环境来找符合某种语言的属性文件。如有三个属性文件language.propertieslanguage_en.propertieslanguage_zh.properties。如果客户端的语言是中文,Struts2就会读language_zh.properties,如果是英文,就会读language_en.properties。如果这两个文件的某个不存在,就会读language.properties。读者可通过IE的[工具]->[Internet]->[语言]来测试客户端浏览器的语言,如图1所示:

图1

国内最棒的Google Android技术社区(eoeandroid),欢迎访问!

《银河系列原创教程》发布

《Java Web开发速学宝典》出版,欢迎定购

Struts1.x系列教程(20):使用EventDispatchAction类处理一个form多个submit

本文为原创,如需转载,请注明作者和出处,谢谢!

上一篇:Struts1.x系列教程(19):LookupDispatchAction类处理一个form多个submit

虽然LookupDispatchAction类可以很好地处理拥有多个提交按钮的Form,但是必须要和属性文件相关联,而且还得在getKeyMethodMap方法中进行keyAction方法的映射,使用起来十分不方便。从Struts1.2.9开始,加入了另一个用于处理多个提交动作的EventDispatchAction类。这个类也是DispatchAction的子类,它在使用上要比LookupDispatchAction类容易的多。EventDispatchAction类的基本原理是通过<action>元素的parameter属性指定多个动作,中间用逗号(,)分隔。每个动作实际上就是<html:submit>标签的property属性值。这样EventDispatchAction类就可以根据每个<html:submit>标签的属性值来确定用户按的是哪个提交按钮了。

我们可以按如下三步来使用EventDispatchAction类。

【第1步】实现EventDispatchAction的子类

<samples工程目录>\src\action目录中建立一个MyEventDispatchAction.java文件,代码如下:

<!–<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
–>packageaction;

importjava.io.PrintWriter;
importjavax.servlet.http.*;
importorg.apache.struts.action.*;
importorg.apache.struts.actions.*;

publicclassMyEventDispatchActionextendsEventDispatchAction
{
//处理print动作
publicActionForwardprint(ActionMappingmapping,ActionFormform,
HttpServletRequestrequest,HttpServletResponseresponse)
{
try
{
response.setCharacterEncoding(
GBK);
PrintWriterout
=response.getWriter();
out.println(
打印成功!);
}
catch(Exceptione)
{
}
returnnull;
}
//处理save动作
publicActionForwardsave(ActionMappingmapping,ActionFormform,
HttpServletRequestrequest,HttpServletResponseresponse)
{
try
{
response.setCharacterEncoding(
GBK);
PrintWriterout
=response.getWriter();
out.println(
保存成功!);
}
catch(Exceptione)
{
}
returnnull;
}
}

MyEventDispatchAction类中有两个方法:printsave,分别用来处理property属性值为“print”和“save”的<html:submit>标签提交的请求动作。

【第2步】配置EventDispatchAction

打开struts-config.xml文件,在 <action-mappings>元素中加入如下的内容:

<!–<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
–><actionname=”firstValidatorForm”path=”/event”
type
=”action.MyEventDispatchAction”validate=”false”parameter=”print,save”/>

【第3步】实现有多个提交按钮的JSP页面

Web根目录中建立一个moreSubmit.jsp文件,代码如下:

<!–<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
–><%@pagepageEncoding=”GBK”%>
<%@tagliburi=”http://struts.apache.org/tags-html”prefix=”html”%>
<html>
<head>
<title>多提交演示</title>
</head>
<body>
<html:formaction=”event”>
name:
<html:textproperty=”name”/>&nbsp;&nbsp;<p>
<html:submitproperty=”print”value=”打印”/>
<html:submitproperty=”save”value=”保存”/>
</html:form>
</body>
</html>

在编写moreSubmit.jsp文件时要注意,“打印”和“保存”按钮的property属性必须和<action>动作中的parameter参数值一致。也就是“print”和“save”。
启动Tomcat后,在IE中输入如下的URL来测试程序:

http://localhost:8080/samples/moreSubmit.jsp

为了区别提交请求参数和其他参数,在<html:submit>标签的property属性值还可以有一个后缀“.x”(<action>元素的parameter属性值仍然是“print, save”。如“打印”按钮的代码可以写成如下形式:

<!–<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
–><html:submitproperty=”print.x”value=”打印”/>

下一篇:Struts1.x系列教程(21):使用MappingDispatchAction类调用不同的Action方法

国内最棒的Google Android技术社区(eoeandroid),欢迎访问!

《银河系列原创教程》发布

《Java Web开发速学宝典》出版,欢迎定购

Struts2教程8:拦截器概述

本文为原创,如需转载,请注明作者和出处,谢谢!

上一篇:Struts2教程7:上传任意多个文件

Struts2的拦截器和Servlet过滤器类似。在执行Actionexecute方法之前,Struts2会首先执行在struts.xml中引用的拦截器,在执行完所有引用的拦截器的intercept方法后,会执行Actionexecute方法。

Struts2拦截器类必须从com.opensymphony.xwork2.interceptor.Interceptor接口继承,在Intercepter接口中有如下三个方法需要实现:
<!–<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
–>

<!–<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
–>voiddestroy();
voidinit();
Stringintercept(ActionInvocationinvocation)
throwsException;

其中intercept方法是拦截器的核心方法,所有安装的拦截器都会调用之个方法。在Struts2中已经在struts-default.xml中预定义了一些自带的拦截器,如timerparams等。如果在<package>标签中继承struts-default,则当前package就会自动拥有struts-default.xml中的所有配置。代码如下:

<package name=”demo”
extends=”struts-default” > … </package>

struts-default.xml中有一个默认的引用,在默认情况下(也就是<action>中未引用拦截器时)会自动引用一些拦截器。这个默认的拦截器引用如下:

<!–<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
–><default-interceptor-refname=”defaultStack”/>

<interceptor-stackname=”defaultStack”>
<interceptor-refname=”exception”/>
<interceptor-refname=”alias”/>
<interceptor-refname=”servletConfig”/>
<interceptor-refname=”prepare”/>
<interceptor-refname=”i18n”/>
<interceptor-refname=”chain”/>
<interceptor-refname=”debugging”/>
<interceptor-refname=”profiling”/>
<interceptor-refname=”scopedModelDriven”/>
<interceptor-refname=”modelDriven”/>
<interceptor-refname=”fileUpload”/>
<interceptor-refname=”checkbox”/>
<interceptor-refname=”staticParams”/>
<interceptor-refname=”params”>
<paramname=”excludeParams”>dojo\..*</param>
</interceptor-ref>
<interceptor-refname=”conversionError”/>
<interceptor-refname=”validation”>
<paramname=”excludeMethods”>input,back,cancel,browse</param>
</interceptor-ref>
<interceptor-refname=”workflow”>
<paramname=”excludeMethods”>input,back,cancel,browse</param>
</interceptor-ref>
</interceptor-stack>

上面在defaultStack中引用的拦截器都可以在<action>中不经过引用就可以使用(如果在<action>中引用了任何拦截器后,要使用在defaultStack中定义的拦截器,也需要在<action>中重新引用,在后面将详细讲解)。

下面我们来看几个简单的拦截器的使用方法。

一、记录拦截器和execute方法的执行时间(timer)

timerStruts2中最简单的拦截器,这个拦截器对应的类是com.opensymphony.xwork2.interceptor.TimerInterceptor。它的功能是记录execute方法和其他拦截器(在timer后面定义的拦截器)的intercept方法执行的时间总和。如下面的配置代码所示:

<!–<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
–><actionname=”first”class=”action.FirstAction”>
<interceptor-refname=”logger”/>
<interceptor-refname=”timer”/>
</action>

由于在timer后面没有其他的拦截器定义,因此,timer只能记录execute方法的执行时间,在访问first动作时,会在控制台输出类似下面的一条信息:

信息: Executed action [/test/first!execute] took 16 ms.

在使用timer拦截器时,需要commons-logging.jar的支持。将logger引用放到timer的后面,就可以记录logger拦截器的intercept方法和Actionexecute方法的执行时间总和,代码如下:

<!–<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
–><actionname=”first”class=”action.FirstAction”>
<interceptor-refname=”timer”/>
<interceptor-refname=”logger”/>
</action>

大家可以使用如下的Action类来测试一下timer拦截器:

<!–<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
–>packageaction;

importcom.opensymphony.xwork2.ActionSupport;

publicclassFirstActionextendsActionSupport

{
publicStringexecute()throwsException

{
Thread.sleep(1000);//延迟1秒
returnnull;
}

}

如果只记录execute方法的执行时间,一般会输出如下的信息:

信息: Executed action [/test/first!execute] took 1000 ms.

二、通过请求调用Actionsetter方法(params)


当客户端的一个form向服务端提交请求时,如有一个textfield,代码如下:

<!–<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
–><s:formaction=”first”namespace=”/test”>
<s:textfieldname=”name”/>
<s:submit/>
</s:form>

在提交后,Struts2将会自动调用first动作类中的setName方法,并将name文本框中的值通过setName方法的参数传入。实际上,这个操作是由params拦截器完成的,params对应的类是com.opensymphony.xwork2.interceptor.ParametersInterceptor。由于params已经在defaultStack中定义,因此,在未引用拦截器的<action>中是会自动引用params的,如下面的配置代码,在访问first动作时,Struts2是会自动执行相应的setter方法的。

<action name=”first”
class=”action.FirstAction”>


… …

</action>

但如果在<action>中引用了其他的拦截器,就必须再次引用params拦截器,Struts2才能调用相应的setter方法。如下面的配置代码所示:

<!–<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
–><actionname=”first”class=”action.FirstAction”>
<interceptor-refname=”timer”/>
<interceptor-refname=”params”/>
</action>

三、通过配置参数调用Actionsetter方法(static-params)

static-params拦截器可以通过配置<params>标签来调用Action类的相应的setter方法,static-params拦截器对应的类是com.opensymphony.xwork2.interceptor.StaticParametersInterceptor。
下面配置代码演示了如何使用static-params拦截器:

<!–<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
–><actionname=”first”class=”action.FirstAction”>
<interceptor-refname=”timer”/>
<paramname=”who”>比尔</param>
<interceptor-refname=”params”/>
<interceptor-refname=”static-params”/>
</action>

如果first动作使用上面的配置,在访问first动作时,Struts2会自动调用setWho方法将“比尔”作为参数值传入setWho方法。

四、使用拦截器栈

为了能在多个动作中方便地引用同一个或几个拦截器,可以使用拦截器栈将这些拦截器作为一个整体来引用。拦截器栈要在<package>标签中使用<interceptors>和子标签<interceptor-stack>来定义。代码如下:

<!–<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
–><packagename=”demo”extends=”struts-default”>
<interceptors>
<interceptor-stackname=”mystack”>
<interceptor-refname=”timer”/>
<interceptor-refname=”logger”/>
<interceptor-refname=”params”/>
<interceptor-refname=”static-params”/>
</interceptor-stack>
</interceptors>

<actionname=”first”class=”action.FirstAction”>
<paramname=”who”>比尔</param>
<interceptor-refname=”mystack”/>
</action>
</package>

可以象使用拦截器一样使用拦截器栈,如上面代码所示。


下一篇:Struts2教程9:实现自已的拦截器



国内最棒的Google Android技术社区(eoeandroid),欢迎访问!

《银河系列原创教程》发布

《Java Web开发速学宝典》出版,欢迎定购

Struts2教程7:上传任意多个文件

本文为原创,如需转载,请注明作者和出处,谢谢!

上一篇:Struts2教程6:在Action类中获得HttpServletResponse对象的四种方法


一、上传单个文件

上传文件是很多Web程序都具有的功能。在Struts1.x中已经提供了用于上传文件的组件。而在Struts2中提供了一个更为容易操作的上传文件组件。所不同的是,Struts1.x的上传组件需要一个ActionForm来传递文件,而Struts2的上传组件是一个拦截器(这个拦截器不用配置,是自动装载的)。在本文中先介绍一下如何用struts2上传单个文件,最后介绍一下用struts2上传任意多个文件。

要用Struts2实现上传单个文件的功能非常容易实现,只要使用普通的Action即可。但为了获得一些上传文件的信息,如上传文件名、上传文件类型以及上传文件的Stream对象,就需要按着一定规则来为Action类增加一些gettersetter方法。

Struts2中,用于获得和设置java.io.File对象(Struts2将文件上传到临时路径,并使用java.io.File打开这个临时文件)的方法是getUploadsetUpload。获得和设置文件名的方法是getUploadFileNamesetUploadFileName,获得和设置上传文件内容类型的方法是getUploadContentTypesetUploadContentType。下面是用于上传的动作类的完整代码:

<!–<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
–>packageaction;

importjava.io.*;
importcom.opensymphony.xwork2.ActionSupport;

publicclassUploadActionextendsActionSupport
{
privateFileupload;
privateString uploadFileName;
privateStringuploadContentType;

publicStringgetUploadFileName()
{
return uploadFileName;
}

publicvoidsetUploadFileName(StringfileName)
{
this.uploadFileName=fileName;
}

publicFilegetUpload()
{
returnupload;
}

publicvoidsetUpload(Fileupload)
{
this.upload=upload;
}
publicvoidsetUploadContentType(StringcontentType)
{
this.uploadContentType=contentType;

}

publicStringgetUploadContentType()
{
returnthis.uploadContentType;
}
publicStringexecute()throwsException
{
java.io.InputStreamis
=newjava.io.FileInputStream(upload);
java.io.OutputStreamos
=newjava.io.FileOutputStream(d:\\upload\\+ uploadFileName);
bytebuffer[]=newbyte[8192];
intcount=0;
while((count=is.read(buffer))>0)
{
os.write(buffer,
0,count);
}
os.close();
is.close();
returnSUCCESS;
}
}


execute方法中的实现代码就很简单了,只是从临时文件复制到指定的路径(在这里是d:\upload)中。上传文件的临时目录的默认值是javax.servlet.context.tempdir的值,但可以通过struts.properties(和struts.xml在同一个目录下)的struts.multipart.saveDir属性设置。Struts2上传文件的默认大小限制是2M2097152字节),也可以通过struts.properties文件中的struts.multipart.maxSize修改,如struts.multipart.maxSize=2048 表示一次上传文件的总大小不能超过2K字节。

下面的代码是上传文件的JSP页面代码

<!–<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
–><%@pagelanguage=javaimport=java.util.*pageEncoding=GBK%>
<%@taglibprefix=suri=/struts-tags%>

<html>
<head>
<title>上传单个文件</title>
</head>

<body>
<s:formaction=”upload”namespace=”/test”
enctype
=”multipart/form-data”>
<s:filename=”upload”label=”输入要上传的文件名”/>
<s:submitvalue=”上传”/>
</s:form>

</body>
</html>


也可以在success.jsp页中通过<s:property>获得文件的属性文件名和文件内容类型),代码如下

<s:property
value=”uploadFileName”/>

二、上传任意多个文件

Struts2中,上传任意多个文件也非常容易实现。首先,要想上传任意多个文件,需要在客户端使用DOM技术生成任意多个<input type=”file” />标签。name属性值都相同。代码如下:

<!–<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
–><html>
<head>
<scriptlanguage=”javascript”>

functionaddComponent()
{
varuploadHTML=document.createElement(<inputtype=’file’name=’upload’/>);
document.getElementById(
files).appendChild(uploadHTML);
uploadHTML
=document.createElement(<p/>);
document.getElementById(
files).appendChild(uploadHTML);
}
</script>
</head>
<body>
<inputtype=”button”onclick=”addComponent();”value=”添加文件”/>
<br/>
<formonsubmit=”returntrue;”action=”/struts2/test/upload.action”
method
=”post”enctype=”multipart/form-data”>
<spanid=”files”><inputtype=’file’name=’upload’/>
<p/>
</span>
<inputtype=”submit”value=”上传”/>
</form>
</body>

</html>

上面的javascript代码可以生成任意多个<input type=’file’>标签,name的值都为file(要注意的是,上面的javascript代码只适合于IE浏览器,firefox等其他浏览器需要使用他的代码)。至于Action类,和上传单个文件的Action类基本一至,只需要将三个属性的类型改为List即可。代码如下:

<!–<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
–>packageaction;

importjava.io.*;
importcom.opensymphony.xwork2.ActionSupport;

publicclassUploadMoreActionextendsActionSupport
{
privatejava.util.List<File>uploads;
privatejava.util.List<String> uploadsFileName;
privatejava.util.List<String>uploadsContentType;

publicjava.util.List<String>getUploadsFileName()
{
return uploadFileName;
}
publicvoidsetUploadFileName(java.util.List<String>fileNames)
{
this.uploadFileName =fileNames;
}
publicjava.util.List<File>getUploads()
{
returnuploads;
}

publicvoidsetUploads(java.util.List<File>uploads)
{
this.uploads=uploads;
}

publicvoidsetUploadsContentType(java.util.List<String>contentTypes)
{
this.uploadsContentType =contentTypes;

}

publicjava.util.List<String>getUploadsContentType()
{
returnthis.uploadsContentType;
}

publicStringexecute()throwsException
{
if(uploads!=null)
{
inti=0;
for(;i<uploads.size();i++)
{
java.io.InputStreamis
=newjava.io.FileInputStream(uploads.get(i));
java.io.OutputStreamos
=newjava.io.FileOutputStream(
d:\\upload\\+ uploadsFileName.get(i));
bytebuffer[]=newbyte[8192];
intcount=0;
while((count=is.read(buffer))>0)
{
os.write(buffer,
0,count);
}
os.close();
is.close();
}
}
returnSUCCESS;
}
}

execute方法中,只是对List对象进行枚举,在循环中的代码和上传单个文件时的代码基本相同。如果读者使用过struts1.x的上传组件,是不是感觉Struts2的上传功能更容易实现呢?Struts1.x中上传多个文件时,可是需要建立带索引的属性的。而在Struts2中,就是这么简单就搞定了。1是上传任意多个文件的界面。

1

在本文中给出了用Struts2上传任意多个文件的一个方法,如果哪位读者有更好的方法,请跟贴!

下一篇:Struts2教程8:拦截器概述

国内最棒的Google Android技术社区(eoeandroid),欢迎访问!

《银河系列原创教程》发布

《Java Web开发速学宝典》出版,欢迎定购