1. Action开发、通配符、路径匹配
1) Struts2配置
a) Struts2的Action的几种开发方式
方式一:继承ActionSupport
package com.xp.a_config;import com.opensymphony.xwork2.ActionSupport;public class UserAction extends ActionSupport{ PRivate static final long serialVersionUID = 1L; //action中业务处理方法 public String login() { System.out.println("UserAction.login()"); return "success"; }}如果使用struts2数据校验功能必须继承ActionSupport
方式二:实现Action接口
public class UserAction2 implements Action{ public String login() { System.out.println("UserAction.login()"); return "success"; } @Override public String execute() throws Exception { return null; }}方式三:不继承任何类,不实现任何接口public class UserAction3 { private String userName; public void setUserName(String userName) { this.userName = userName; } public String login() { System.out.println("UserAction3.login"+userName); return "success"; }}1) struts2通配符映射机制
A. 一个Web 应用可能有成百上千个 action 声明. 可以利用 struts 提供的通配符映射机制把多个彼此相似的映射关系简化为一个映射关系
B. 通配符映射规则
a) 若找到多个匹配, 没有通配符的那个将胜出
b) 若指定的动作不存在, Struts 将会尝试把这个 URI 与任何一个包含着通配符* 的动作名及进行匹配
c) 若 Struts 找到的带有通配符的匹配不止一个,最后一个匹配将胜出
d) 被通配符匹配到的 URI 字符串的子串可以用 {1}, {2} 来引用. {1} 匹配第一个子串, {2} 匹配第二个子串…
e) {0} 匹配整个 URI
l 可以匹配零个或多个字符, 但不包括/ 字符. 如果想把 / 字符包括在内, 需要使用 **. 如果需要对某个字符进行转义, 需要使用 /.
2) Struts2路径匹配原则
<struts> <package name="config" namespace="/user" extends="struts-default" abstract="false"> <action name="user_*" class="com.xp.a_config.UserAction" method="{1}"> <result name="{1}">/{1}.jsp</result> </action> </package></struts>访问路径:http://localhost:8080/day29/user/user_loginok
访问路径:http://localhost:8080/day29/user/a/b/user_loginok
访问路径:http://localhost:8080/day29/a/b/user/user_loginno ok
访问路径:http://localhost:8080/day29/user/a/b/user_login
Struts2的Action名称搜索机制
1、获得请求路径的URI,例如url是:
/Struts2_01/hello_a/a/b/helloWorld.action
2、首先查询namespace为/hello_a/a/b的package,
如果存在这个package,则在这个package中查询名字为helloWorld的
action,如果不存在这个package则转步骤3
3、查询namespace为/hello_a/a的package,
如果存在这个package,则在这个package中寻找名字为helloWorld的
action,如果不存在这个package,则转步骤4
4、查询namespace为/hello_a的package,
如果存在这个package,则在这个package中寻找名字为helloWorld的
action,如果仍然不存在这个package,则转步骤5
5、查询默认的namaspace的package
查询名字为helloWorld的action(默认的命名空间为空字符串“/” )
如果还是找不到,页面提示404找不到action的异常。
Tomcat
Localhost: 找到访问哪一台机器
8080: 找到Tomcat
day29: web项目名称
/user/a/b:先看有没有这个名称空间,没找到继续向下
/user/a: 先看有没有这个名称空间,没找到继续向下
/user: 先看有没有这个名称空间,没找到继续向下
/: 默认命名空间,还没找到,报错
1) Struts2路径匹配原则
Struts中默认访问后缀:
Struts1中默认访问后缀是*.doc
Struts1中默认访问后缀是*.action
如何修改默认访问后缀
Struts2的.action访问后缀在哪里定义
Struts-core-2.3.4-1/org.apache.struts/default.properties
自定义后缀修改常量
<constantname="struts.action.extension" value="do"/>
2.struts常量用法
指定默认编码集,作用于HttpServletRequest的setCharacterEncoding方法 和freemarker 、velocity的输出
<constantname="struts.i18n.encoding" value="UTF-8"/>
设置浏览器是否缓存静态内容,默认值为true(生产环境下使用),开发阶段最好关闭
<constantname="struts.serve.static.browserCache" value="false"/>
当struts的配置文件修改后,系统是否自动重新加载该文件,默认值为false(生产环境下使用),开发阶段最好打开
<constantname="struts.configuration.xml.reload" value="true"/>
开发模式下使用,这样可以打印出更详细的错误信息
<constantname="struts.devMode" value="true" />
默认的视图主题
<constantname="struts.ui.theme" value="simple" />
与spring集成时,指定由spring负责action对象的创建
<constantname="struts.objectFactory" value="spring" />
该属性设置Struts 2是否支持动态方法调用,该属性的默认值是true。如果需要关闭动态方法调用,则可设置该属性
为 false
<constantname="struts.enable.DynamicMethodInvocation"value="false"/>
上传文件的大小限制
<constant name="struts.multipart.maxSize"value=“10701096"/>
3.struts2指定多个配置文件
4.struts2动态方法调用
package com.xp.b_config2;public class UserAction { private String userName; public void setUserName(String userName) { this.userName = userName; } // Action中业务处理方法 public String login() { System.out.println("UserAction.login()"); return "success"; } public String register() { System.out.println("register()"); return "success"; }}package com.xp.b_config2;import com.opensymphony.xwork2.ActionSupport;public class TestAction extends ActionSupport { @Override public String execute() throws Exception { System.out.println("TestAction.execute()"); return SUCCESS; }}<?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="config2" namespace="/" extends="struts-default"> <!-- 动态方法调用: http://locahost:8080/struts02/user!login <action name="user" class="com.xp.b_config2.UserAction"> <result name="success">/index.jsp</result> </action> --> <!-- 配置全局跳转视图 --> <global-results> <result name="success">/index.jsp</result> </global-results> <!-- 通配符: http://locahost:8080/struts02/user_login --> <action name="user_*" class="com.xp.b_config2.UserAction" method="{1}"></action> <!-- <action name="test" class="com.xp.b_config2.TestAction" method="execute"> 返回结果标记success对应的页面再当前action中没有配置, 所以会去找全局配置有是否有success标记对应的页面 </action> --> <!-- 配置各项默认值 --> <!-- name 只配置了访问路径名称 class 默认执行的action在struts-default有配置 <default-class-ref class="com.opensymphony.xwork2.ActionSupport" /> method 默认为execute 默认的方法execute返回值为success,对应的页面去全局视图找。 --> <action name="test"></action> <!-- 什么情况不配置class? 即处理的aciton --> <!-- 答案: 当只是需要跳转到WEB-INF下资源的时候。 --> <action name="test2"> <result name="success" type="redirect">/WEB-INF/index.jsp</result> </action> </package></struts>Strust2中Action配置项的默认值
4.数据处理的几种方式
package com.xp.c_data;import java.util.Map;import com.opensymphony.xwork2.ActionContext;import com.opensymphony.xwork2.ActionSupport;/** * 数据处理 */public class DataAction_bak extends ActionSupport { @Override public String execute() throws Exception { /* 1. 请求数据封装; 2. 调用Service处理业务逻辑,拿到结果数据 */ /* 3. 数据保存到域中 */ /* * * // Struts中对数据操作,方式1: 直接拿到ServletApi, 执行操作 * HttpServletRequest request = ServletActionContext.getRequest(); * Httpsession session = request.getSession(); * ServletContext application = ServletActionContext.getServletContext(); * // 操作 * request.setAttribute("request_data", "request_data1"); * session.setAttribute("session_data", "session_data1"); * application.setAttribute("application_data", "application_data1"); */ /* * 【推荐:解耦的方式实现对数据的操作】 * Struts中对数据操作,方式2: 通过ActionContext类 */ ActionContext ac = ActionContext.getContext(); /* * 得到Struts对HttpServletRequest对象进行了封装,封装为一个map * 拿到表示request对象的map */ Map<String, Object> request = ac.getContextMap(); /* 拿到表示session对象的map */ Map<String, Object> session = ac.getSession(); /* 拿到表示servletContext对象的map */ Map<String, Object> application = ac.getApplication(); /* 数据 */ request.put( "request_data", "request_data1_actionContext" ); session.put( "session_data", "session_data1_actionContext" ); application.put( "application_data", "application_data1_actionContext" ); return(SUCCESS); }}package com.xp.c_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;/** * 数据处理, 方式3: 实现接口的方法 */public class DataAction extends ActionSupport implements RequestAware, SessionAware, ApplicationAware { private Map<String, Object> request; private Map<String, Object> session; private Map<String, Object> application; /* struts运行时候,会把代表request的map对象注入 */ @Override public void setRequest( Map<String, Object> request ) { this.request = request; } /* 注入session */ @Override public void setSession( Map<String, Object> session ) { this.session = session; } /* 注入application */ @Override public void setApplication( Map<String, Object> application ) { this.application = application; } @Override public String execute() throws Exception { /* 数据 */ request.put( "request_data", "request_data1_actionAware" ); session.put( "session_data", "session_data1_actionAware" ); application.put( "application_data", "application_data1_actionAware" );/* */ return(SUCCESS); }}<?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="data" namespace="/" extends="struts-default"> <!-- 全局配置 --> <global-results> <result name="success">/data.jsp</result> </global-results> <action name="data" class="com.xp.c_data.DataAction"></action> </package></struts>5.日期类型转换器 Struts2中为什么要类型转换? HTML表单采集数据 提交表单 Action 底层依赖HTTP传递数据,而HTTP协议中 没有 “类型” 的概念. 每一项 表单输入只可能是一个字符串或一个字符串数组。因此在服务器端Action 中 必须把 String 转换为业务需要的特定的数据类型 Struts2中如何传递请求参数给Action? Struts2框架会将表单的参数以同名的方式设置给对应Action的属性中。 该工作主要是由Parameters拦截器做的。而该拦截器中已经自动的实现了 String到基本数据类型之间的转换工作。类似于: Beanutils工具。 案例 1、注册表单(ServletActionContext先获取参数后自动同名设置获取) 2、Action中定义同名属性并提供get和set方法 3、检测是否转换请求数据自动封装实现原理:请求参数拦截器方式一:jsp表单数据填充到action中的属性<%@ 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>My JSP 'index.jsp' starting page</title> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0"> <meta http-equiv="keyWords" content="keyword1,keyword2,keyword3"> <meta http-equiv="description" content="This is my page"> </head> <body> <form action="${pageContext.request.contextPath }/user_register.action" method="post"> 用户名:<input type="text" name="user.name"><br/> 密码:<input type="text" name="user.pwd"><br/> 年龄:<input type="text" name="user.age"><br/> 生日:<input type="text" name="user.birth"><br/> <input type="submit" value="注册"> </form> </body></html>方式二:Jsp表单数据填充到action对象中的属性package com.xp.d_type;import java.util.Date;public class User { // 封装请求数据 private String name; // 必须给set / get可以不用给 private String pwd; private int age; private Date birth; public void setName(String name) { this.name = name; } public void setPwd(String pwd) { this.pwd = pwd; } public void setAge(int age) { this.age = age; } public void setBirth(Date birth) { this.birth = birth; } public String getName() { return name; } public String getPwd() { return pwd; } public int getAge() { return age; } public Date getBirth() { return birth; } }package com.xp.d_type;/** * Struts核心业务: 请求数据自动封装以及类型转换 */public class UserAction { // 对象类型,一定给get方法 private User user; public void setUser(User user) { this.user = user; } public User getUser() { return user; } // 处理注册请求 public String register() { System.out.println(user.getName()); System.out.println(user.getPwd()); System.out.println(user.getAge()); System.out.println(user.getBirth()); return "success"; }}Struts2自定义转换器将格式为yyyy/MM/dd的字符串转换为日期?
Struts2自定义全局类型转换器
l Struts2中如何自定义全局类型转换器?
实现的接口和继承的类都是相同的,本质上就是配置的方式不同。
l 实现
1、自定义转换器继承StrutsTypeConverter
2、重写convertFromString和convertToString方法
3、注册转换器
3.1 在项目src目录下建立以下固定文件
xwork-conversion.properties
3.2 在3.1文件中添加以下数据
需要转换的类类型=转换器类的权限定名
如: java.util.Date= cn.itcast.converter.DateConverter
l 总结
该拦截器负责对错误信息进行拦截器<interceptorname="conversionError“ class="org.apache.struts2.interceptor.StrutsConversionErrorInterceptor"/>package com.xp.d_type;import java.text.DateFormat;import java.text.ParseException;import java.text.SimpleDateFormat;import java.util.Date;import java.util.Map;import org.apache.struts2.util.StrutsTypeConverter;/** * 自定义类型转换器类 */public class MyConverter extends StrutsTypeConverter { /* 新需求: 要求项目中要支持的格式,如: yyyy-MM-dd/yyyyMMdd/yyyy年MM月dd日.. */ /* 先定义项目中支持的转换的格式 */ DateFormat[] df = { new SimpleDateFormat( "yyyy-MM-dd" ), new SimpleDateFormat( "yyyyMMdd" ), new SimpleDateFormat( "yyyy年MM月dd日" ) }; /** * 把String转换为指定的类型 【String To Date】 * @param context * 当前上下文环境 * @param values * jsp表单提交的字符串的值 * @param toClass * 要转换为的目标类型 */ @Override public Object convertFromString( Map context, String[] values, Class toClass ) { /* 判断: 内容不能为空 */ if ( values == null || values.length == 0 ) { return(null); } /* 判断类型必须为Date */ if ( Date.class != toClass ) { return(null); } /* 迭代:转换失败继续下一个格式的转换; 转换成功就直接返回 */ for ( int i = 0; i < df.length; i++ ) { try { return(df[i].parse( values[0] ) ); } catch ( ParseException e ) { continue; } } return(null); } @Override public String convertToString( Map context, Object o ) { return(null); }}<?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="type" namespace="/" extends="struts-default"> <action name="user_*" class="com.xp.d_type.UserAction" method="{1}"> <result name="success">/index.jsp</result> <!-- 当日期类型转换错误的时候,会跳到input视图(struts内部返回) --> <result name="input">/error.jsp</result> </action> </package> </struts>Struts中jsp提交的数据,struts会自动转换为action中属性的类型对于基本数据类型以及日期类型会自动转换日期类型只支持yyyy-MM-dd格式转换器开发步骤Struts2类型转换器(源码分析)
6.文件上传下载
Struts2文件支持
l Struts2直接支持文件上传吗?
支持、默认使用的是fileupload工具。导入struts2包的时候可见。
l 上传表单?
表单属性 enctype = multipart/form-data
表单属性 method =post
输入属性 type = file
l 文件上传拦截器上传文件
<interceptorname="fileUpload" class="org.apache.struts2.interceptor.FileUploadInterceptor"/>
l Struts2默认可以上传的文件大小是2M
Struts2上传方法实现
Struts2文件失败配置
Struts2上传文件大小配置
l 如果上传的文件大于2M,查看控制台错误信息如下org.apache.commons.fileupload.FileUploadBase$SizeLimitExceededException:the request was rejected because its size (77817949) exceeds the configuredmaximum (2097152)
l 异常分析
该异常信息是common-fileupload组件输出的,而非是Struts2框架。
l 设置上传组件的文件大小限制
<!-- 设置最大上传的大小是80M -->
<constantname="struts.multipart.maxSize"value="83886080"></constant>
l Struts2中是使用FileUpload拦截器进行文件上传的
<interceptor name="fileUpload"class="org.apache.struts2.interceptor.FileUploadInterceptor"/>
<interceptor-stack name="defaultStack">
<interceptor-ref name="fileUpload"/> ….
</interceptor-stack>
l FileUploadInterceptor拦截器API
Struts2上传文件错误处理
l FileUploadInterceptor 源码分析
intercept()方法中
StringcontentTypeName = inputName + "ContentType";
StringfileNameName = inputName + "FileName";
而且配置的参数该拦截器调用了相应的set方法
setAllowedExtensions(String)、setAllowedTypes(String)、setMaximumSize(Long)
l 上传错误信息显示
l 上传错误信息分析
错误信息File too large如果显示中文的话会更加的友好!
Struts2多文件上传
package com.xp.e_fileupload;import java.io.File;import org.apache.commons.io.FileUtils;import org.apache.struts2.ServletActionContext;import com.opensymphony.xwork2.ActionSupport;public class FileUpload extends ActionSupport { // 对应表单:<input type="file" name="file1"> private File file1; // 文件名 private String file1FileName; // 文件的类型(MIME) private String file1ContentType; public void setFile1(File file1) { this.file1 = file1; } public void setFile1FileName(String file1FileName) { this.file1FileName = file1FileName; } public void setFile1ContentType(String file1ContentType) { this.file1ContentType = file1ContentType; } @Override public String execute() throws Exception { /******拿到上传的文件,进行处理******/ // 把文件上传到upload目录 // 获取上传的目录路径 String path = ServletActionContext.getServletContext().getRealPath("/upload"); // 创建目标文件对象 File destFile = new File(path,file1FileName); // 把上传的文件,拷贝到目标文件中 FileUtils.copyFile(file1, destFile); return SUCCESS; }}package com.xp.e_fileupload;import java.io.File;import java.io.InputStream;import java.io.UnsupportedEncodingException;import java.net.URLEncoder;import java.util.Map;import org.apache.struts2.ServletActionContext;import com.opensymphony.xwork2.ActionContext;import com.opensymphony.xwork2.ActionSupport;/** * 文件下载 * 1. 显示所有要下载文件的列表 * 2. 文件下载 */public class DownAction extends ActionSupport { /*************1. 显示所有要下载文件的列表*********************/ public String list() throws Exception { //得到upload目录路径 String path = ServletActionContext.getServletContext().getRealPath("/upload"); // 目录对象 File file = new File(path); // 得到所有要下载的文件的文件名 String[] fileNames = file.list(); // 保存 ActionContext ac = ActionContext.getContext(); // 得到代表request的map (第二种方式) Map<String,Object> request= (Map<String, Object>) ac.get("request"); request.put("fileNames", fileNames); return "list"; } /*************2. 文件下载*********************/ // 1. 获取要下载的文件的文件名 private String fileName; public void setFileName(String fileName) { // 处理传入的参数中问题(get提交) try { fileName = new String(fileName.getBytes("ISO8859-1"),"UTF-8"); } catch (UnsupportedEncodingException e) { throw new RuntimeException(e); } // 把处理好的文件名,赋值 this.fileName = fileName; } //2. 下载提交的业务方法 (在struts.xml中配置返回stream) public String down() throws Exception { return "download"; } // 3. 返回文件流的方法 public InputStream getAttrInputStream(){ return ServletActionContext.getServletContext().getResourceAsStream("/upload/" + fileName); } // 4. 下载显示的文件名(浏览器显示的文件名) public String getDownFileName() { // 需要进行中文编码 try { fileName = URLEncoder.encode(fileName, "UTF-8"); } catch (UnsupportedEncodingException e) { throw new RuntimeException(e); } return fileName; }}<?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"> <!-- 注意: action 的名称不能用关键字"fileUpload" --> <action name="fileUploadAction" class="com.xp.e_fileupload.FileUpload"> <!-- 限制运行上传的文件的类型 --> <interceptor-ref name="defaultStack"> <!-- 限制运行的文件的扩展名 --> <param name="fileUpload.allowedExtensions">txt,jpg,jar</param> <!-- 限制运行的类型 【与上面同时使用,取交集】 <param name="fileUpload.allowedTypes">text/plain</param> --> </interceptor-ref> <result name="success">/e/success.jsp</result> <!-- 配置错误视图 --> <result name="input">/e/error.jsp</result> </action> <action name="down_*" class="com.xp.e_fileupload.DownAction" method="{1}"> <!-- 列表展示 --> <result name="list">/e/list.jsp</result> <!-- 下载操作 --> <result name="download" type="stream"> <!-- 运行下载的文件的类型:指定为所有的二进制文件类型 --> <param name="contentType">application/octet-stream</param> <!-- 对应的是Action中属性: 返回流的属性【其实就是getAttrInputStream()】 --> <param name="inputName">attrInputStream</param> <!-- 下载头,包括:浏览器显示的文件名 --> <param name="contentDisposition">attachment;filename=${downFileName}</param> <!-- 缓冲区大小设置 --> <param name="bufferSize">1024</param> </result> </action> </package></struts>
新闻热点
疑难解答