本文包括以下两个部分:
1. Struts2的基本配置和通用功能。
2. Struts2的核心功能:数据接收,数据共享,类型转换,上传下载。
一、Struts2的基本配置和通用功能
1.1 Struts2中action类的三种写法
1.1.1 第一种写法:action类不实现任何接口,不继承任何类。
- package edu.scut.a_action;
- public class UserAction1 {
- public String login(){
- System.out.println("执行了UserAction1!");
- return "success";
- }
- }
1.1.2 第二种写法:action类实现Action接口。
优点:a. 为action类提供了一个默认的execute方法;
b. 为action类提供了常用的视图标记字符串,例如:SUCCESS、ERROR、INPUT、NONE、LOGIN。
- package edu.scut.a_action;
- import com.opensymphony.xwork2.Action;
-
- public class UserAction2 implements Action{
-
- @Override
- public String execute() throws Exception {
- System.out.println("执行了UserAction2!");
- return SUCCESS;
- }
-
- }
1.1.3 第三种写法:action类继承ActionSupport类(常用方法)。
优点:a. 为action类提供了Action接口的默认实现,默认跳转到SUCESS;
b. 为action类提供了常用的视图标记字符串,例如:SUCCESS、ERROR、INPUT、NONE、LOGIN。
c. 为action类额外提供了数据表单验证以及国际化等功能。
- package edu.scut.a_action;
- import com.opensymphony.xwork2.ActionSupport;
-
- public class UserAction3 extends ActionSupport{
- public String login(){
- System.out.println("执行了UserAction3!");
- return SUCCESS;
- }
- }
1.2 Struts2的常量配置
Struts2的常量配置文件在struts2-core-2.3.4.1.jar当中,查找路径为: /org/apache/struts2/default.properties(这是Struts2的默认常量配置文件!)
1.2.1 常用的常量配置:
a. struts.i18n.encoding. 请求参数的编码,相当于servlet中的request.setCharacterEncoding("utf-8")。
b. struts.multipart.parser. 文件上传使用的组件,默认为jakarta。
c. struts.multipart.saveDir. 文件上传时使用的临时目录,默认为windows的临时目录。
d. struts.multipart.maxSize. 文件上传时最大的文件大小,默认为2MB。
e. struts.action.extension. action访问的后缀名, 默认为 action。
f. struts.enable.DynamicMethodInvocation. 动态方法调用,默认为true,一般只在开发调试阶段使 用,建议项目上线时关闭此功能。
g. struts.ui.theme. struts2的UI的主题,默认为 xhtml。
1.2.2 Struts2的常量配置可以修改,在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="true"></constant>
-
- <constant name="struts.i18n.encoding" value="utf-8"></constant>
-
- <constant name="struts.action.extension" value="action"></constant>
-
- <package name="constant" extends="struts-default" namespace="/constant">
- <action name="user_*" class="edu.scut.b_constant.UserAction" method="{1}">
- <result>/index.jsp</result>
- </action>
- </package>
- </struts>
1.3 action的全局视图和默认视图
1.3.1 全局视图
作用:在当前package下面的所有action都可以共享这个视图。
注意:如果在action中配置了同名的视图则会覆盖全局视图。
- <?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="constant" extends="struts-default" namespace="/constant">
-
- <global-results>
- <result>/index.jsp</result>
- </global-results>
-
- <action name="user_*" class="edu.scut.b_constant.UserAction" method="{1}">
- <result>/index.jsp</result>
- </action>
- </package>
- </struts>
1.3.2 默认视图
注意:通常使用action的默认配置可以进行WEB-INF目录下的页面跳转,如下代码中的第2个action。
- <?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="constant" extends="struts-default" namespace="/constant">
-
- <global-results>
- <result>/index.jsp</result>
- </global-results>
-
- <action name="book" class="edu.scut.b_constant.BookAction" method="add">
- </action>
-
- <action name="types">
- <result>/WEB-INF/user.jsp</result>
- </action>
- </package>
- </struts>
1.4 注入action属性
作用:action的参数可以通过struts.xml文件设置到action中。
Example
需求:将c:/f.jpg图片复制到/c:targetFile/路径下。
注入属性的步骤:
a. 在对应action的配置中进行配置。
- <?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="property" extends="struts-default" namespace="/property">
- <action name="book" class="edu.scut.c_property.BookAction" method="addBook">
- <param name="serverPath">/c:targetFile/</param>
- <result name="success" >/index.jsp</result>
- </action>
- </package>
- </struts>
b. 在对应的action类中提供一个同名的setter方法。
- package edu.scut.c_property;
-
- import java.io.File;
- import java.io.FileInputStream;
- import java.io.FileNotFoundException;
- import org.apache.commons.io.FileUtils;
- import com.opensymphony.xwork2.ActionSupport;
-
- public class BookAction extends ActionSupport {
-
- private String serverPath;
- public void setServerPath(String serverPath) {
- this.serverPath = serverPath;
- }
-
- public String addBook() throws Exception{
-
- File file = new File("c:/f.jpg");
- FileInputStream fis = new FileInputStream(file);
-
-
- FileUtils.copyInputStreamToFile(fis, new File(serverPath+file.getName()));
- return SUCCESS;
- }
- }
二、Struts2的核心功能
2.1 页面请求参数的三种接收方式
在Struts2框架中,有关于接参数的拦截器:com.opensymphony.xwork2.interceptor.PrepareInterceptor 。其作用是:把表单用户填写的数据接收过来,然后通过Action的setter方法赋值给Action类。因此,使用Struts2框架时,访问action,一般都要经过这个拦截器。
2.1.1 第一种方式:基本类型数据的接收
优点:参数数量少的时候比较简单使用。
缺点:如果参数数量多的时候,必须每个参数在Action类中提供setter方法逐个接收。
表单代码:
- <form action="${pageContext.request.contextPath }/constant/user_login.action" method="post">
- 用户名:<input type="text" name="name"><br>
- 密码:<input type="password" name="password"><br>
- <input type="submit" value="登录">
- </form>
Action代码:
- package edu.scut.d_param;
-
- import com.opensymphony.xwork2.ActionSupport;
-
- public class UserAction1 extends ActionSupport {
- private String name;
- private String password;
- public void setName(String name) {
- this.name = name;
- }
- public void setPassword(String password) {
- this.password = password;
- }
-
-
- public String reg(){
- System.out.println("执行了注册方法!");
- System.out.println(name);
- System.out.println(password);
- return SUCCESS;
- }
- }
2.1.2 第二种方式:JavaBan类型数据的接收
注意:在action类中必须同时提供getter和setter方法。
优点:a. 参数多的时候更方便地接收。
b. 可以接收多个不同的表单(即封装多个不同的对象)。
缺点:需要修改表单的name属性值。name属性的值都要写成(实体类名.属性名)的形式。
表单代码:
- <form action="${pageContext.request.contextPath }/constant/user_login.action" method="post">
- 用户名:<input type="text" name="user.name"><br>
- 密码:<input type="password" name="user.password"><br>
- <input type="submit" value="登录">
- </form>
User类代码:
- package edu.scut.d_param;
- import java.util.Arrays;
-
- public class User {
- private String name;
- private String password;
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public String getPassword() {
- return password;
- }
- public void setPassword(String password) {
- this.password = password;
- }
-
- @Override
- public String toString() {
- return "User [name=" + name + ", password=" + password + "]";
- }
- }
Action代码:
- package edu.scut.d_param;
- import com.opensymphony.xwork2.ActionSupport;
-
- public class UserAction2 extends ActionSupport {
- private User user;
-
- public User getUser() {
- return user;
- }
- public void setUser(User user) {
- this.user = user;
- }
-
-
- public String reg(){
- System.out.println("执行了注册方法!");
- System.out.println(user);
- return SUCCESS;
- }
- }
2.1.3 第三种方式:模型驱动的方法,action类实现ModelDriven接口
注意:
a. Action类实现ModelDriven接口。
b. 实现getModel()方法。
c. 在Action类声明一个对象的成员变量在getModel方法中去接收表单的数据。
d. 一定要给对象初始化(private User user=new User())。
优点:a. 参数多的时候更方便地接收。
b. 不用修改表单。
缺点:只能接收一个表单(只能封装一个对象)。
表单代码:
- <form action="${pageContext.request.contextPath }/constant/user_login.action" method="post">
- 用户名:<input type="text" name="name"><br>
- 密码:<input type="password" name="password"><br>
- <input type="submit" value="登录">
- </form>
User类代码:
- package edu.scut.d_param;
- import java.util.Arrays;
- public class User {
- private String name;
- private String password;
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public String getPassword() {
- return password;
- }
- public void setPassword(String password) {
- this.password = password;
- }
- @Override
- public String toString() {
- return "User [name=" + name + ", password=" + password + "]";
- }
- }
Action代码:
- package edu.scut.d_param;
- import com.opensymphony.xwork2.ActionSupport;
- import com.opensymphony.xwork2.ModelDriven;
-
- public class UserAction3 extends ActionSupport<span style="color:#FF0000;"> implements ModelDriven<User> </span>{
- private User user= new User();
-
- @Override
- public User getModel() {
- return user;
- }
-
-
- public String reg(){
- System.out.println("执行了UserAction的注册方法!");
- System.out.println(user);
- return SUCCESS;
- }
- }
2.2 数据共享的三种方式
2.2.1 第一种方式:使用原生的servlet的api进行域对象共享
优点:
a. 可以使用servlet中的类。
b. 可以通过原生的request对象获取用户的浏览器的信息。
缺点:
依赖了servlet的api,而strut2框架并不建议使用servlet的api。
Book实体类代码:
- package edu.scut.e_data;
- import java.io.Serializable;
- public class Book implements Serializable {
- private String name;
- private double price;
- public Book() {
- super();
- }
- public Book(String name, double price) {
- super();
- this.name = name;
- this.price = price;
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public double getPrice() {
- return price;
- }
- public void setPrice(double price) {
- this.price = price;
- }
- }
Action代码:
- package edu.scut.e_data;
-
- import java.util.ArrayList;
- import java.util.List;
- import javax.servlet.ServletContext;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpSession;
- import org.apache.struts2.ServletActionContext;
- import com.opensymphony.xwork2.ActionSupport;
-
-
- public class BookAction1 extends ActionSupport{
- public String list(){
- List<Book> books = new ArrayList<Book>();
- for(int i=0; i<5; i++){
- books.add(new Book("java编程思想"+i,50+i*5));
- }
-
-
-
- HttpServletRequest request = ServletActionContext.getRequest();
- request.setAttribute("r_books", books);
-
-
- HttpSession session = request.getSession();
- session.setAttribute("s_books", books);
-
-
- ServletContext context = ServletActionContext.getServletContext();
- context.setAttribute("c_books", books);
-
- return SUCCESS;
- }
- }
2.2.2 第二种方式:使用struts2提供的三个Map集合对象来共享数据
RequestMap: 封装了HttpServletRequest对象
SessionMap :封装了HttpSession对象
ApplicationMap: 封装了ServletContext对象
优点:
a. 不依赖于servlet的api,可以更加方便地去测试action类。
b. 给jsp页面共享更多的数据。
缺点:
Action类中的每个方法都必须重新获取Map集合才能共享数据。
Action代码:
- package edu.scut.e_data;
-
- import java.util.ArrayList;
- import java.util.List;
- import java.util.Map;
- import com.opensymphony.xwork2.ActionContext;
- import com.opensymphony.xwork2.ActionSupport;
-
-
- public class BookAction2 extends ActionSupport {
- public String list(){
-
- List<Book> books = new ArrayList<Book>();
- for(int i = 0 ; i<5; i++){
- books.add(new Book("计算机网络"+i,50+i*5));
- }
-
-
- ActionContext ac = ActionContext.getContext();
-
-
- Map rmap = (Map)ac.get("request");
- rmap.put("r_books", books);
-
-
- Map smap = ac.getSession();
- smap.put("s_books", books);
-
-
- Map cmap = ac.getApplication();
- cmap.put("c_books", books);
-
- return SUCCESS;
- }
- }
2.2.3 第三种方式:采用全局的方法获取Map集合共享数据
分别实现三个接口:RequestAware,SessionAware, ApplicationAware
优点:
a. 不依赖servlet的api。
b. 可以在Action的任何方法去使用Map集合共享数据。
Action代码:
BaseAction
- package edu.scut.e_data;
-
- import java.util.Map;
- import org.apache.struts2.interceptor.ApplicationAware;
- import org.apache.struts2.interceptor.RequestAware;
- import org.apache.struts2.interceptor.SessionAware;
- import com.opensymphony.xwork2.ActionSupport;
-
- public class BaseAction extends ActionSupport implements RequestAware,SessionAware,ApplicationAware {
- protected Map requestMap = null;
- protected Map sessionMap = null;
- protected Map applicationMap = null;
-
- public void setRequest(Map<String,Object> request) {
- this.requestMap = request;
- }
- public void setSession(Map<String,Object> session) {
- this.sessionMap = session;
- }
- public void setApplication(Map<String,Object> application) {
- this.applicationMap = application;
- }
- }
Action
- package edu.scut.e_data;
-
- import java.util.ArrayList;
- import java.util.List;
- import java.util.Map;
- import javax.faces.application.Application;
- import org.apache.struts2.interceptor.ApplicationAware;
- import org.apache.struts2.interceptor.RequestAware;
- import org.apache.struts2.interceptor.SessionAware;
- import com.opensymphony.xwork2.ActionSupport;
- import com.sun.faces.context.ApplicationMap;
-
- public class BookAction3 extends BaseAction {
- public String list(){
-
- List<Book> books = new ArrayList<Book>();
- for(int i=0; i<5; i++){
- books.add(new Book("计算机组成原理"+i,50+i*5));
- }
-
-
-
- requestMap.put("r_books", books);
-
-
- sessionMap.put("s_books", books);
-
-
- applicationMap.put("c_books", books);
-
- return SUCCESS;
- }
- }
2.3 数据类型转换
Struts2内置的参数拦截器可以把表单字符串(String)类型自动转换对应的其他类型。
例如:将表单传过来的String类型转换成double,int,float,short,Java.util.Date。
但是表单输入的内容必须按照Struts框架能够识别的格式输入(日期类型默认只支持短日期类型,即yyyy-MM-dd)。
如果需要扩展Struts2的转换类型,可以自定义类型转换器。
2.3.1 开发自定义类型转换器步骤
a. 编写java类,继承StrutsTypeConverter类。
- package edu.scut.c_convert;
-
- import java.text.ParseException;
- import java.text.SimpleDateFormat;
- import java.util.Date;
- import java.util.Map;
- import org.apache.struts2.util.StrutsTypeConverter;
-
- public class MyDateConverter extends StrutsTypeConverter {
-
- SimpleDateFormat[] sdf = new SimpleDateFormat[]{
- new SimpleDateFormat("yyyy/MM/dd"),
- new SimpleDateFormat("yyyy-MM-dd"),
- new SimpleDateFormat("yyyy.MM.dd"),
- new SimpleDateFormat("yyyy#MM#dd")
- };
-
- @Override
- public Object convertFromString(Map context, String[] values, Class toClass) {
-
- String dateString = values[0];
-
-
-
-
-
-
-
-
-
-
- for(SimpleDateFormat s : sdf){
- try {
- Date date = s.parse(dateString);
- return date;
- } catch (ParseException e) {
-
- continue;
- }
- }
- return null;
- }
-
-
-
-
- @Override
- public String convertToString(Map context, Object o) {
- return null;
- }
- }
b. 绑定类型转换器。
局部绑定:只能绑定一个Action
规则:在需要绑定类型转换器的Action同目录下建立properties文件:Action的名称-conversion.properties。
内容:属性名称=gz.itcast.c_convert.MyDateConverter。
例如:BookAction-conversion.properties。
- publishtime=edu.scut.c_convert.MyDateConverter
全局绑定:可以绑定项目中的全部Action
规则:在src目录下创建xwork-conversion.properties文件。
内容:java.util.Date=gz.itcast.c_convert.MyDateConverter。
- java.util.Date=edu.scut.c_convert.MyDateConverter
2.3.2 三种不同接参方式的绑定规则
a. 基本数据类型接收参数
绑定类型转换器:在Action的同目录下建立 Action的名称-conversion.properties。
内容:属性名称=gz.itcast.c_convert.MyDateConverter。
b. javabean类型接收参数
绑定类型转换器:在Action的同目录下建立Action的名称-conversion.properties。
内容:book.publishtime=gz.itcast.c_convert.MyDateConverter。(注意是实体类名.属性名)
c. 模型驱动接收参数
绑定类型转换器:在模型对象的同目录下建立模型的对象名称-conversion.properties。(注意是模型的对象名称,Book-conversion.properties。而不是BookAction-conversion.properties)
2.4 文件的上传与下载
2.4.1 文件上传
a. 文件上传的三个必要条件:
- form表单,type="File"
- post提交方式
- form的enctype="multipart/form-data"
b. action类,其中包含单文件上传和多文件上传,两种方式都是通过setter方法接收表单上传的文件。多文件上传时,将接受的文件内容,名称,类型用集合封装。
- package edu.scut.b_upload_down;
-
- import java.io.File;
- import java.io.IOException;
- import java.util.List;
- import org.apache.commons.io.FileUtils;
- import com.opensymphony.xwork2.ActionSupport;
- import com.sun.org.apache.xml.internal.resolver.helpers.FileURL;
-
- public class UploadAction extends ActionSupport{
-
- private String name;
- public void setName(String name) {
- this.name = name;
- }
-
-
-
- private File attach;
-
- private String attachFileName;
-
- private String attachContentType;
- public void setAttach(File attach) {
- this.attach = attach;
- }
- public void setAttachFileName(String attachFileName) {
- this.attachFileName = attachFileName;
- }
- public void setAttachContentType(String attachContentType) {
- this.attachContentType = attachContentType;
- }
-
-
- private String serverPath;
- public void setServerPath(String serverPath) {
- this.serverPath = serverPath;
- }
-
-
- public String upload1() throws Exception{
-
- System.out.println("用户名:"+name);
- System.out.println("文件名:"+attachFileName);
- System.out.println("文件类型:"+attachContentType);
- System.out.println("文件大小:"+attach.length());
-
- FileUtils.copyFile(attach, new File(serverPath+attachFileName));
- return SUCCESS;
- }
-
-
-
- private List<File> img;
-
- private List<String> imgFileName;
-
- private List<String> imgContentType;
- public void setImg(List<File> img) {
- this.img = img;
- }
- public void setImgFileName(List<String> imgFileName) {
- this.imgFileName = imgFileName;
- }
- public void setImgContentType(List<String> imgContentType) {
- this.imgContentType = imgContentType;
- }
-
-
- public String upload2() throws Exception{
-
- System.out.println("用户名:"+name);
- if(img!=null){
- for (int i = 0; i < img.size(); i++) {
-
- System.out.println("文件名:"+imgFileName);
- System.out.println("文件类型:"+imgContentType);
- System.out.println("文件大小:"+img.get(i).length());
-
- FileUtils.copyFile(img.get(i), new File(serverPath+(imgFileName.get(i))));
- }
- return SUCCESS;
- }
- return INPUT;
- }
- }
struts.xml配置
- <span style="color:#000000;"><?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="upload" extends="struts-default" namespace="/upload">
- <action name="upload_*" class="edu.scut.b_upload_down.UploadAction" method="{1}">
-
- <param name="serverPath" >/c:targetFiles/</param>
-
- <result >/success.jsp</result>
-
- <result name="input">/fail.jsp</result>
- </action>
- </package>
- </struts>
注意:
INPUT 名称的result是struts2内置的处理错误的视图,struts2框架在文件上传时超过大小,类型转换时转换错误,表单数据验证错误时都会指向到INPUT的视图。
2.4.2 文件下载
Struts框架对文件的下载进行了简化。关键点:需要一个名称为steam的视图。
a. 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="downLoad" extends="struts-default" namespace="/downLoad">
- <action name="down_*" class="edu.scut.b_upload_down.DownAction" method="{1}">
-
- <result type="stream">
-
-
- <param name="contentType">application/octet-stream</param>
-
-
- <param name="contentDisposition">attachment;filename=${fileName}</param>
-
- <param name="inputName">fileContent</param>
-
- <param name="bufferSize">512</param>
- </result>
- </action>
- </package>
- </struts>
b. action类
- package edu.scut.b_upload_down;
-
- import java.io.File;
- import java.io.FileInputStream;
- import java.io.FileNotFoundException;
- import java.io.InputStream;
- import java.io.UnsupportedEncodingException;
- import java.net.URLEncoder;
- import org.apache.struts2.ServletActionContext;
- import com.opensymphony.xwork2.ActionSupport;
-
- public class DownAction extends ActionSupport {
-
- File file = null;
-
-
- private String fileName;
- public String getFileName() throws Exception {
-
- return URLEncoder.encode(fileName,"utf-8");
- }
-
-
- public InputStream getFileContent() throws Exception {
- return new FileInputStream(file);
- }
-
-
- public String down(){
-
- file = new File(ServletActionContext.getServletContext().getRealPath("/download/f.jpg"));
- fileName = file.getName();
- return SUCCESS;
- }
- }