Java-Struts学习笔记之拦截器、文件上传下载、xml、json
文件结构
Struts2应用的分层体系架构 要点:
1.将处理逻辑放到service里,如Action层不准许出现在sql语句,session、request不允许传到service层去。
示例:
LoginAction.java
package com.struts2.struts2;
……该导入的包……
public class LoginAction extends ActionSupport
{
private String username;
private String password;
private int age;
private Date date;
private LoginService loginService = new LoginServiceImpl();
……Set与get方法……
public String execute() throws Exception
{ //业务逻辑不写到Action里
// if(!"hello".equals(username))
// {
// throw new UsernameException("username invalid");
// }
// if(!"world".equals(password))
// {
// throw new PasswordException("password invalid");
// }
// return SUCCESS;
//利用ServletActionContext,获得HttpServletRequest请求
HttpServletRequest request = ServletActionContext.getRequest();
HttpSession session = request.getSession();
session.setAttribute("hello", "helloworld");
ActionContext actionContext = ActionContext.getContext();
Map<String, Object> map = actionContext.getSession(); //获取session
Object object = map.get("hello"); //打印出session的信息
System.out.println(object);
if(this.loginService.isLogin(username, password))
{
return SUCCESS;
}
return INPUT;
}
………………
}
LoginService.java
package com.struts2.service;
public interface LoginService
{
public boolean isLogin(String username, String password);
}
LoginServiceImpl.java
package com.struts2.service.impl;
import com.struts2.service.LoginService;
public class LoginServiceImpl implements LoginService
{
public boolean isLogin(String username, String password)
{
if("hello".equals(username) && "world".equals(password))
{
return true;
}
return false;
}
}
编辑struts2.xml文件
…………
<action name="login" class="com.struts2.struts2.LoginAction">
<result name="success" type="dispatcher">/result.jsp</result>
<result name="input">/login.jsp</result>
</action>
…………
Struts2的模型驱动(model driven)
要点:
1.属性驱动(propertity driven)与模型驱动的区别:之前的都是属性驱动,属性驱动与模型驱动的处理方式差不多,但它们导致的结果却不同,属性驱动是在接收的请求后,将对象里的值一个一个的 set 好,此时并没有new 出一个整的对象。而模型驱动是在接收到用户提交表单请求后,就将对象创建好了,并把对象的值也设定好了,可以直接拿对象来用了。
2.实现了ModelDriven接口的Action的执行过程
1).首先调用getModel()方法,返回一个person对象
2).模型查找提交过来的表单中有没有username、password等属性名是否匹配,如果匹配,则将对应的值自动设置到对象中,放到模型当中。
3).当在结果页面,以request.getAttribute()或requestScope取值时,同样通过Action从模型当中取值。
属性驱动与模型驱动的比较
1)属性驱动灵活,准确;模型驱动不灵活,因为很多时候,页面所提交过来的参数并不属于模型中的属性,也就是说页面所提交过来的参数与模型中的属性并不一致,这是很常见的情况。
2)模型驱动更加符合面向对象的编程风格,使得我们获得的是对象而不是一个个离散的值。
小结:推荐使用属性驱动编写 Action。
Preparable接口的作用是让 Action完成一些初始化工作,这些初始化工作是放在 Preparable接口的prepare方法中完成的,该方法会在execute方法执行之前得到调用。
示例:
Person.java
package com.struts2.bean;
import java.util.Date;
public class Person
{
private String username;
private String password;
private int age;
private Date date;
……get、set方法……
}
LoginAction2.java
package com.struts2.struts2;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;
import com.opensymphony.xwork2.Preparable;
import com.struts2.bean.Person;
public class LoginAction2 extends ActionSupport implements ModelDriven<Person>, Preparable
{ //模型驱动
private Person person = new Person();
//1.首先调用getModel()方法,返回一个person对象
//2.模型查找提交过来的表单中有没有username、password等属性值,如果有,则模型自动设置到对象中
public Person getModel()
{
System.out.println("getModel invoked!");
return person; //返回生成的person
}
//调用这个方法让action准备自身
public void prepare() throws Exception
{
System.out.println("prepare invoked!!");
}
public String execute() throws Exception
{
System.out.println("execute invoked!");
//System.out.println(person.getUsername());
return SUCCESS;
}
}
struts.xml
向struts.xml文件中,添加一个action,如下:
<action name="login2" class="com.struts2.struts2.LoginAction2">
<result name="success">/result.jsp</result>
</action>
login.jsp
…………
<form action="login2.action">
username: <input type="text" name="username"><br>
password: <input type="password" name="password"><br>
age: <input type="text" name="age"><br>
date: <input type="text" name="date"><br>
<input type="submit" value="submit">
</form>
…………
result.jsp
…………
<body>
username: ${requestScope.username }<br><!-- requestScope相当于request.getAttribute() -->
password: ${requestScope.password }<br>
age: ${requestScope.age }<br>
date: ${requestScope.date }<br>
session: ${sessionScope.hello }<!-- 取得通过ServletActionContext方式获取的session -->
</body>
…………
服务器端代码的单元测试
要点:
服务器端代码的单元测试有两种模式
1) 容器内测试(Jetty)
2) Mock 测试 ( 继承 HttpServletRequest 、 HttpSession 、HttpServletResponse等Servlet API) 。
防止表单重复提交
要点:
1. 采取请求转发的方式完成表单内容的添加会造成内容的重复插入。采取重定向的方式实现数据的添加不会导致数据的重复插入(即:重定向到一个list查询Action)。
2. 因为struts.xml文件中<package name="struts2" extends="struts-default">,所以继续了struts-default中的结果类型。
防止表单重复提交的两种方式
1) 通过重定向
2) 通过Session Token(Session令牌):当客户端请求页面时,服务器会通过token标签生成一个随机数,并且将该随机数放置到 session当中,然后将该随机数发向户端;如果客户第一次提交,那么会将该随机数发往服务器端,服务器会接收到该随机数并且与 session 中所保存的随机数进行比较,这时两者的值是相同的,服务器认为是第一次提交,并且将更新服务器端的这个随机数值;如果此时再次重复提交,那么客户端发向服务器端的随机数还是之前的那个,而服务器端的随机数则已经发生了变化,两者不同,服务器就认为这是重复提交,进而转向invalid.token所指向的结果页面。
Struts-default.xml中定义的结果类型
打开struts2-core-2.2.1.1.jar下的struts-default.xml文件,其中定义了的结果类型,如下:
<package name="struts-default" abstract="true">
<result-types>
<result-type name="chain" class="com.opensymphony.xwork2.ActionChainResult"/>
<result-type name="dispatcher" class="org.apache.struts2.dispatcher.ServletDispatcherResult" default="true"/>
<result-type name="freemarker" class="org.apache.struts2.views.freemarker.FreemarkerResult"/>
<result-type name="httpheader" class="org.apache.struts2.dispatcher.HttpHeaderResult"/>
<result-type name="redirect" class="org.apache.struts2.dispatcher.ServletRedirectResult"/>
<result-type name="redirectAction" class="org.apache.struts2.dispatcher.ServletActionRedirectResult"/>
<result-type name="stream" class="org.apache.struts2.dispatcher.StreamResult"/>
<result-type name="velocity" class="org.apache.struts2.dispatcher.VelocityResult"/>
<result-type name="xslt" class="org.apache.struts2.views.xslt.XSLTResult"/>
<result-type name="plainText" class="org.apache.struts2.dispatcher.PlainTextResult" />
</result-types>
………………
页面重定向与请求转发的设定
在struts.xml文件中,设置Action中的result元素的type属性即可,如下:
<action name="login" class="com.struts2.struts2.LoginAction">
<!--
<result name="success" type="dispatcher">/result.jsp</result>
-->
<result name="success" type="redirect">/result.jsp</result>
<result name="input">/login.jsp</result>
</action>
重定向到Action (redirectAction)
action1.jsp
…………
<body>
<form action="action1.action">
username: <input type="text" name="username"><br>
password: <input type="password" name="password"><br>
<input type="submit" value="submit">
</form>
</body>
…………
action2.jsp
…………
<body>
username: <s:property value="username"/><br>
password: <s:property value="password"/><br>
usernameAndPassword: <s:property value="usernameAndPassword"/>
</body>
…………
Action1.java
package com.struts2.struts2;
import com.opensymphony.xwork2.ActionSupport;
public class Action1 extends ActionSupport
{
private String username;
private String password;
private String usernameAndPassword;
……set、get方法……
@Override
public String execute() throws Exception
{
this.usernameAndPassword = this.username + this.password;
return SUCCESS;
}
}
Action2.java
package com.struts2.struts2;
import com.opensymphony.xwork2.ActionSupport;
public class Action2 extends ActionSupport
{
private String username;
private String password;
private String usernameAndPassword;
………get、set方法………
@Override
public String execute() throws Exception
{
return SUCCESS;
}
}
struts.xml
…………
<action name="action1" class="com.struts2.struts2.Action1">
<result name="success" type="redirectAction">
<!--如果不传参数,可把action2直接写到result的text域中 -->
<param name="actionName">action2</param>
<param name="username">${username}</param><!-- 获取Action1的成员变量 -->
<param name="password">${password}</param>
<param name="usernameAndPassword">${usernameAndPassword}</param>
</result>
</action>
<action name="action2" class="com.struts2.struts2.Action2">
<result name="success">/action2.jsp</result>
</action>
…………
chain结果类型(Action之间的请求转发)
要点:直接修改struts.xml文件中的action的result的type属性的值为 chain ,如下:
…………
<action name="action1" class="com.vvvv.struts2.Action1">
<result name="success" type=chain">
<!--如果不传参数,可把action2直接写到result的text域中 -->
<param name="actionName">action2</param>
<param name="username">${username}</param><!-- 获取Action1的成员变量 -->
<param name="password">${password}</param>
<param name="usernameAndPassword">${usernameAndPassword}</param>
</result>
…………
运行可以发现,这种方式不是以重定向的形式转发,且action2.jsp页面拿不到usernameAndPassword的信息。因为由Action1转发到到Action2,是在服务器内部进行了,是在一个客户端页面(action1.jsp)请求范围内,而请求中只包含username、password两个参数。所以拿不到usernameAndPassword的值。
Struts2 Session Token机制
token.jsp
…………
<body>
<s:form action="token.action" theme="simple">
username: <s:textfield name="username"></s:textfield><br>
password: <s:password name="password"></s:password><br>
<s:token></s:token>
<s:submit value="submit"></s:submit>
</s:form>
</body>
…………
TokenAction.java
package com.struts2.struts2;
import com.opensymphony.xwork2.ActionSupport;
public class TokenAction extends ActionSupport
{
private String username;
private String password;
……get、set方法……
@Override
public String execute() throws Exception
{
return SUCCESS;
}
}
tokenSuccess.jsp
…………
<body>
username: <s:property value="username"/><br>
password: <s:property value="password"/>
</body>
…………
tokenFail.jsp
…………
<body>
不要重复提交表单
</body>
…………
struts.xml
…………
<action name="token" class="com.struts2.struts2.TokenAction">
<result name="success">/tokenSuccess.jsp</result>
<result name="invalid.token">/tokenFail.jsp</result>
<interceptor-ref name="token"></interceptor-ref>
<interceptor-ref name="defaultStack"></interceptor-ref>
</action>
…………
struts2拦截器
要点:
拦截器(Interceptor) :拦截器是Struts2的核心,Struts2的众多功能都是通过拦截器来实现的;
拦截器在服务器被启动时,被初始化,调用init方法;
拦截器的配置
1)编写实现Interceptor 接口的类。
2)在struts.xml 文件中定义拦截器。
3)在action中使用拦截器
首先编写拦截器类(TheInterceptor1)
package com.struts2.interceptor;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.Interceptor;
public class TheInterceptor1 implements Interceptor
{
private String test;
public String getTest()
{
return test;
}
public void setTest(String test)
{
System.out.println("setTest invoked!"); //set方法先于init方法执行
this.test = test;
}
public void destroy()
{
}
public void init()
{
System.out.println("init invoked!");
System.out.println("test: " + this.test);
}
//服务器永远不会去执行挂截器,只不过是在执行拦截器之前,执行一个invoke方法
public String intercept(ActionInvocation invocation) throws Exception
{
System.out.println("before");
String result = invocation.invoke();
System.out.println("after");
return result;
}
}
struts.xml
<struts>
<package name="struts2" extends="struts-default">
<interceptors>
<interceptor name="theInterceptor1" class="com.vvvv.interceptor.TheInterceptor1">
<param name="test">vvvv</param>
</interceptor>
</interceptors>
………………
<action name="token" class="com.struts2.struts2.TokenAction">
<result name="success">/tokenSuccess.jsp</result>
<result name="invalid.token">/tokenFail.jsp</result>
<interceptor-ref name="token"></interceptor-ref>
<interceptor-ref name="defaultStack"></interceptor-ref>
</action>
</package>
</struts>
一旦定义了自己的拦截器,将其配置到 action上后,我们需要在action的最后加上默认的拦截器栈:defaultStack。
示例2
项目源包 : struts2sd
要点:
- 定义拦截器时可以直接继承AbstractInterceptor 抽象类(该类实现了 Interceptor 接口,并且对 init 和 destroy 方法进行了空实现) ,然后实现其抽象方法 intercept即可;
- 方法过滤拦截器(可以对指定方法进行拦截的拦截器);
- 在方法过滤拦截器中,如果既没有指定 includeMethods 参数,也没有指定execludeMethods 参数,那么所有的方法都会被拦截,也就是说所有的方法都被认为是 includeMethods 的;如果仅仅指定了 includeMethods,那么只会拦截 includeMethods 中的方法,没有包含在includeMethods 中的方法就不会被拦截。
TheInterceptor2.java
package com.vvvv.interceptor;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
public class TheInterceptor2 extends AbstractInterceptor
{
@Override
public String intercept(ActionInvocation invocation) throws Exception
{
System.out.println("interceptor before...");
System.out.println("interceptor2: " + invocation.getAction().getClass());
String result = invocation.invoke();
System.out.println("interceptor after...");
return result;
}
}
struts.xml
…………
<interceptors>
<interceptor name="theInterceptor1" class="com.vvvv.interceptor.TheInterceptor1">
<param name="test">vvvv</param>
</interceptor>
<interceptor name="theInterceptor2" class="com.vvvv.interceptor.TheInterceptor2">
</interceptor>
<interceptor name="theInterceptor3" class="com.vvvv.interceptor.TheInterceptor3">
</interceptor>
<interceptor name="loginInterceptor" class="com.vvvv.interceptor.LoginInterceptor">
</interceptor>
</interceptors>
…………
<action name="action1" class="com.vvvv.struts2.Action1" method="myExecute">
<result name="success" type="chain">
<param name="actionName">action2</param>
<param name="username">${username}</param>
<param name="password">${password}</param>
<param name="usernameAndPassword">${usernameAndPassword}</param>
</result>
<interceptor-ref name="theInterceptor1"></interceptor-ref>
<interceptor-ref name="theInterceptor2"></interceptor-ref>
<!-- 方法过滤拦截器 -->
<interceptor-ref name="theInterceptor3">
<param name="includeMethods">execute, myExecute</param>
<!-- 不包含以下拦截器,使其不执行 --><!--
<param name="excludeMethods">myExecute</param>
-->
</interceptor-ref>
<interceptor-ref name="defaultStack"></interceptor-ref>
</action>
…………
TheInterceptor3
package com.vvvv.interceptor;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.MethodFilterInterceptor;
import com.vvvv.listener.TheListener;
public class TheInterceptor3 extends MethodFilterInterceptor
{
@Override
protected String doIntercept(ActionInvocation invocation) throws Exception
{
invocation.addPreResultListener(new TheListener());
System.out.println("before interceptor3");
String result = invocation.invoke();
System.out.println("after interceptor3");
return result;
}
}
示例3 struts.xml
<interceptors>
<interceptor name="theInterceptor1" class="com.vvvv.interceptor.TheInterceptor1">
<param name="test">vvvv</param>
</interceptor>
<interceptor name="theInterceptor2" class="com.vvvv.interceptor.TheInterceptor2">
</interceptor>
<interceptor name="theInterceptor3" class="com.vvvv.interceptor.TheInterceptor3">
</interceptor>
<!-- 配置login拦截器 -->
<interceptor name="loginInterceptor" class="com.vvvv.interceptor.LoginInterceptor">
</interceptor>
<interceptor-stack name="myDefaultInterceptorStack">
<interceptor-ref name="loginInterceptor"></interceptor-ref>
<interceptor-ref name="defaultStack"></interceptor-ref>
</interceptor-stack>
</interceptors>
<default-interceptor-ref name="myDefaultInterceptorStack"></default-interceptor-ref>
<global-results>
<result name="usernameInvalid">/usernameInvalid.jsp</result>
<result name="passwordInvalid">/passwordInvalid.jsp</result>
<result name="login">/error.jsp</result>
</global-results>
<global-exception-mappings>
<exception-mapping result="usernameInvalid" exception="com.vvvv.exception.UsernameException"></exception-mapping>
<exception-mapping result="passwordInvalid" exception="com.vvvv.exception.PasswordException"></exception-mapping>
</global-exception-mappings>
<action name="login" class="com.vvvv.struts2.LoginAction">
<result name="success" type="dispatcher">/result.jsp</result>
<result name="input">/login.jsp</result>
</action>
<action name="login2" class="com.vvvv.struts2.LoginAction2">
<result name="success">/result.jsp</result>
</action>
<action name="userAction" class="com.vvvv.struts2.UserAction">
<result name="success">/output.jsp</result>
</action>
<action name="userAction2" class="com.vvvv.struts2.UserAction2">
<result name="success">/output.jsp</result>
</action>
<action name="register" class="com.vvvv.struts2.RegisterAction" method="myExecute">
<result name="success">/registerResult.jsp</result>
<result name="input">/register.jsp</result>
</action>
<action name="action1" class="com.vvvv.struts2.Action1" method="myExecute">
<result name="success" type="chain">
<param name="actionName">action2</param>
<param name="username">${username}</param>
<param name="password">${password}</param>
<param name="usernameAndPassword">${usernameAndPassword}</param>
</result>
…………
LoginInterceptor.java
package com.vvvv.interceptor;
import java.util.Map;
import com.opensymphony.xwork2.Action;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
import com.vvvv.struts2.LoginAction;
public class LoginInterceptor extends AbstractInterceptor
{
@Override
@SuppressWarnings("unchecked")
public String intercept(ActionInvocation invocation) throws Exception
{
if(LoginAction.class == invocation.getAction().getClass())
{
return invocation.invoke();
}
Map map = invocation.getInvocationContext().getSession();
if(null == map.get("userInfo"))
{
return Action.LOGIN;
}
return invocation.invoke();
}
}
同时,也可以在一个Struts.xml中有多个package ,例如,可以将前台的Action放到一个package里,将后台的一个package放到另一个包里面。
也可以将配置文件拆分开来,写到多个配置文件中,例如:
<struts>
<include file="xxx.xml"></include>
…………
struts-2.3.1-all.zip\struts-2.3.1\apps\struts2-mailreader.war\WEB-INF\src\java\struts.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<constant name="struts.action.extension" value="do" />
<constant name="struts.devMode" value="false" />
<constant name="struts.enable.DynamicMethodInvocation" value="false" />
<include file="mailreader-default.xml"/>
<include file="mailreader-support.xml"/>
</struts>
struts命名空间
- package 元素的 abstract 属性表示该包是抽象的,不能直接使用,需要由子包继承才可以使用。struts-default 这个 package 就是abstract的,因此需要我们继承这个包来使用。
- package元素的 namespace属性起到命名空间分割的作用。 通常将namespace的属性值定义成页面所在的目录名。
配置struts.xml
…………
<package name="hello" extends="struts-default" namespace="/theNamespace">
<action name="namespaceAction" class="com.vvvv.struts2.NamespaceAction">
<result name="success">output.jsp</result>
</action>
</package>
…………
NamespaceAction(命名空间)
package com.vvvv.struts2;
import com.opensymphony.xwork2.ActionSupport;
public class NamespaceAction extends ActionSupport
{
@Override
public String execute() throws Exception
{
return SUCCESS;
}
}
实现文件上传
要点:
1. 进行文件上传时,必须将表单的 method属性设为post,将enctype属性设为multipart/form-data。
2. Struts2在进行文件上传操作时,实际上是通过两个步骤实现的:
1)首先将客户端上传的文件保存到struts.multipart.saveDir键所指定的目录中,如果该键所对应的目录不存在,那么就保存到javax.servlet.context.tempdir 环境变量所指定的目录中。
2)Action中所定义的File类型的成员变量file实际上指向的是临时目录中的临时文件,然后在服务器端通过 IO的方式将临时文件写入到指定的服务器端目录中。
示例1 fileUpload.jsp
<form action="fileUpload.action" method="post" enctype="multipart/form-data">
username: <input type="text" name="username"><br>
file: <input type="file" name="file"><br>
<input type="submit" value="submit">
</form>
fileUploadResult.jsp
<body>
username: <s:property value="username"/><br>
name:<s:property value="fileFileName"/>
<br>
type:<s:property value="fileContentType"/>
</body>
通过servlet实现对文件的上传
UploadServlet.java
package com.vvvv.servlet;
import java.io.File;
import java.io.IOException;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
public class UploadServlet extends HttpServlet
{
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
//DiskFileItemFactory创建在内存中保存内容的FileItem实例
DiskFileItemFactory factory = new DiskFileItemFactory();
//得到真实绝对路径
String path = req.getRealPath("/upload");
//把工厂的仓库设置为真实路径
factory.setRepository(new File(path));
//设置阀值
factory.setSizeThreshold(1024 * 1024);
//创建ServletFileUpload实例
ServletFileUpload upload = new ServletFileUpload(factory);
try
{
//解析HttpServletRequest到List到中
List<FileItem> list = (List<FileItem>)upload.parseRequest(req);
for(FileItem item : list)
{
//获得表单字段的名字
String name = item.getFieldName();
//判断是否是表单字段
//如果是普通文本域返回true; 如果不是普通文本域返回false.
if(item.isFormField())
{
//获得表单字段的值
String value = item.getString();
System.out.println(name + "=" + value);
req.setAttribute(name, value);
}
else
{
String value = item.getName();
int start = value.lastIndexOf("\\");
String fileName = value.substring(start + 1);
req.setAttribute(name, fileName);
item.write(new File(path, fileName));
// OutputStream os = new FileOutputStream(new File(path, fileName));
// InputStream is = item.getInputStream();
// byte[] buffer = new byte[400];
// int length = 0;
// while((length = is.read(buffer)) != -1)
// {
// os.write(buffer, 0, length);
// }
// is.close();
// os.close();
}
}
}
catch(Exception ex)
{
ex.printStackTrace();
}
req.getRequestDispatcher("fileUploadResult.jsp").forward(req, resp);
}
}
Struts2的配置文件
WEB-INF/lib/struts2-core-2.2.1.1.jar/org.apache.struts2/default.properties
…………
### This can be used to set your default locale and encoding scheme
# struts.locale=en_US
struts.i18n.encoding=UTF-8 //指定了国际化的默认编码格式
### 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
…………
### Used by the DefaultActionMapper
### You may provide a comma separated list, e.g. struts.action.extension=action,jnlp,do
### The blank extension allows you to match directory listings as well as pure action names
### without interfering with static resources.
struts.action.extension=action,, //指定了表单提交的文件的后缀名
…………
单个文件上传
fileUpload.jsp
…………
<form action="fileUpload.action" method="post" enctype="multipart/form-data">
username: <input type="text" name="username"><br>
file: <input type="file" name="file"><br>
<input type="submit" value="submit">
</form>
…………
fileUploadResult.jsp
…………
<body>
username: <s:property value="username"/><br>
name:<s:property value="fileFileName"/>
<br>
type:<s:property value="fileContentType"/>
</body>
…………
UploadAction.java
package com.vvvv.struts2;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import org.apache.struts2.ServletActionContext;
import com.opensymphony.xwork2.ActionSupport;
public class UploadAction extends ActionSupport
{
private String username;
private File file;
private String fileFileName;
private String fileContentType;
…………set、get方法…………
@Override
public String execute() throws Exception
{
//文件上传的步骤是:先将上传的文件缓存在struts.multipart.saveDir=xxx指定的目录下,
//然后从xxx目录下,通过输出流将文件上传到服务器指定的目录("/upload")
String root = ServletActionContext.getRequest().getRealPath("/upload");
InputStream is = new FileInputStream(file);
System.out.println("path: " + file.getAbsolutePath());
System.out.println("file: " + file.getName());
System.out.println("fileFileName: " + fileFileName);
File destFile = new File(root, fileFileName);
OutputStream os = new FileOutputStream(destFile);
byte[] buffer = new byte[400];
int length = 0;
while(-1 != (length = is.read(buffer)))
{
os.write(buffer, 0, length);
Thread.sleep(1000);
}
is.close();
os.close();
return SUCCESS;
}
}
struts.properties
#定义文件的拓展名
struts.action.extension=action
#指定上传文件的缓存目录
struts.multipart.saveDir=c:/vvvv
#限定上传文件的最大大小
struts.multipart.maxSize=1048576000
注:限定上传文件的大小等也可以在struts.xml文件中配置,如下:
<struts><!-- 限定2M -->
<constant name="struts.multipart.maxSize" value="5242880"></constant>
…………
</struts>
多个文件上传 fileUpload2.jsp
<form action="fileUpload2.action" method="post" enctype="multipart/form-data">
username: <input type="text" name="username"><br>
file: <input type="file" name="file"><br>
file2: <input type="file" name="file"><br>
file3: <input type="file" name="file"><br>
<input type="submit" value="submit">
</form>
fileUploadResult2.jsp
<body>
username: <s:property value="username"/><br>
<s:iterator value="fileFileName" id="f">
file: <s:property value="#f.toUpperCase()"/><br><!-- ognl表达示 -->
</s:iterator>
</body>
UploadAction2.java
package com.vvvv.struts2;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
import org.apache.struts2.ServletActionContext;
import com.opensymphony.xwork2.ActionSupport;
public class UploadAction2 extends ActionSupport
{
private String username;
private List<File> file;
private List<String> fileFileName;
private List<String> fileContentType;
…………set、get方法…………
@Override
public String execute() throws Exception
{
for(int i = 0; i < file.size(); i++)
{
InputStream is = new FileInputStream(file.get(i));
String root = ServletActionContext.getRequest().getRealPath("/upload");
File destFile = new File(root, fileFileName.get(i));
OutputStream os = new FileOutputStream(destFile);
byte[] buffer = new byte[400];
int length = 0;
while(-1 != (length = is.read(buffer)))
{
os.write(buffer, 0, length);
}
is.close();
os.close();
}
return SUCCESS;
}
}
struts2文件下载
struts.xml
<package>
<!--…………-->
<action name="fileUpload2" class="com.vvvv.struts2.UploadAction2">
<result name="success">/fileUploadResult2.jsp</result>
</action>
<action name="downloadFile2" class="com.vvvv.struts2.DownloadAction2">
<result type="stream"><!-- 动态的获得文件的名字 -->
<param name="contentDisposition">attachment;filename=${filename}</param>
<param name="inputName">downloadFile</param>
</result>
</action>
</package>
downloadFile.jsp
<body>
<a href="downloadFile2.action?number=1">下载文件</a>
</body>
downloadAction2.java
package com.vvvv.struts2;
import java.io.InputStream;
import org.apache.struts2.ServletActionContext;
import com.opensymphony.xwork2.ActionSupport;
public class DownloadAction2 extends ActionSupport
{
private int number;
private String filename;
…………get、set方法…………
public InputStream getDownloadFile()
{
try
{
if (1 == number)
{
//动态的修改文件的名字
this.filename = "中文.txt";
//转码
this.filename = new String(this.filename.getBytes("gbk"),
"8859_1");
return ServletActionContext.getServletContext()
.getResourceAsStream("/upload/中文.txt");
}
else
{
this.filename = "CaptureSprite.exe";
return ServletActionContext.getServletContext()
.getResourceAsStream("/upload/CaptureSprite.exe");
}
}
catch (Exception ex)
{
}
return null;
}
@Override
public String execute() throws Exception
{
return SUCCESS;
}
}
基于注解的配置
要点
在项目中引入名为:struts2-convention-plugin-2.2.1.1.jar的jar 包,并删除掉struts.xml
打开struts2-convention-plugi-xxx.jar的结构如下:
编辑LoginAction.java,
package com.vvvv.struts2;
@ParentPackage("struts-default")
@Action(value = "login", results = {
@Result(name = "success", location = "/login.jsp"),
@Result(name = "input", location = "/login.jsp") })
//@InterceptorRef("defaultStack")
//@InterceptorRefs({@InterceptorRef(""), @InterceptorRef("")})
//@ExceptionMappings({@ExceptionMapping(),@E.....})
public class LoginAction extends ActionSupport
{
private String username;
private String password;
private int age;
private Date date;
private LoginService loginService = new LoginServi
…………
}
Struts2异步处理xml
项目文件结构
要点: 向项目中导入dom4j.jar包
GetXMLAction.java
package com.vvvv.action.xml;
…………get、set方法…………
public class GetXMLAction extends ActionSupport
{
private String name;
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
@Override
public String execute() throws Exception
{
//zhang san
People people1 = new People();
people1.setId(1);
people1.setName("zhangsan");
people1.setAge(30);
people1.setAddress("beijing");
People people2 = new People();
people2.setId(2);
people2.setName("lisi");
people2.setAge(50);
people2.setAddress("tianjin");
//创建文档对象
Document document = DocumentHelper.createDocument();
//创建根元素
Element rootElement = document.addElement("persons");
rootElement.addComment("This is comment!!");
Element e = rootElement.addElement("person");
Element idElement = e.addElement("id");
Element nameElement = e.addElement("name");
Element ageElement = e.addElement("age");
Element addressElement = e.addElement("address");
if("zhangsan".equals(name))
{
idElement.setText(people1.getId() + "");
nameElement.setText(people1.getName());
ageElement.setText(people1.getAge() + "");
addressElement.setText(people1.getAddress());
}
else{
idElement.setText(people2.getId() + "");
nameElement.setText(people2.getName());
ageElement.setText(people2.getAge() + "");
addressElement.setText(people2.getAddress());
}
//创建ajax响应
HttpServletResponse response = ServletActionContext.getResponse();
response.setContentType("text/xml; charset=utf-8");
response.setHeader("cache-control", "no-cache");
PrintWriter out = response.getWriter();
OutputFormat format = OutputFormat.createPrettyPrint();
format.setEncoding("utf-8");
XMLWriter writer = new XMLWriter(out, format);
writer.write(document);
out.flush();
out.close();
return null;
}
}
People.java
package com.vvvv.action.xml;
public class People
{
private int id;
private String name;
private int age;
private String address;
…………get、set方法…………
}
Struts2异步处理Json
要点
向项目中导入Json插件,struts2-json-plugin-xxx.jar
getJson.jsp
<script type="text/javascript" src="scripts/jquery-1.4.4.js"></script>
<script type="text/javascript">
$(function()
{
$("#button1").click(function()
{
$.post("getJsonAction2.action",{name: $("#name").val()},
function(returnedData, status)
{
var people = returnedData;
var id = people.id;
var name = people.name;
var age = people.myAge;
var address = people.address;
var html = "<table width='60%' border='1' align='center'><tr><th>id</th><th>name</th><th>age</th><th>address</th><tr align='center'><td>" + id + "</td><td>" + name + "</td><td>" + age + "</td><td>" + address + "</td></tr></table>";
$("#theBody table:eq(0)").remove();
$("#theBody").append(html);
});
});
});
</script>
</head>
<body id="theBody">
<select id="name">
<option value="zhangsan">zhangsan</option>
<option value="lisi">lisi</option>
</select>
<input type="button" value="get json content from server" id="button1">
</body>
GetJsonAction.java
package com.vvvv.action.json;
…………get、set方法…………
public class GetJsonAction extends ActionSupport
{
private String name;
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
@Override
public String execute() throws Exception
{
People people = new People();
people.setId(1);
people.setName(name);
people.setAge(30);
people.setAddress("beijing");
Gson gson = new Gson();
String result = gson.toJson(people);
HttpServletResponse response = ServletActionContext.getResponse();
response.setContentType("application/json; charset=utf-8");
response.setHeader("cache-control", "no-cache");
PrintWriter out = response.getWriter();
out.print(result);
out.flush();
out.close();
return null;
}
}
GetJsonAction2.java(利用struts2的插件)
package com.vvvv.action.json;
public class GetJsonAction2 extends ActionSupport
{
private String name;
private int id;
private int age;
private String address;
…………get、set方法…………
@Override
public String execute() throws Exception
{
this.id = 1;
this.age = 30;
this.address = "beijing";
return SUCCESS;
}
}
注:本文档参考张龙老师的struts2教程