Struts2国际化
1、 国际化原理 ? 什么是国际化 ?
同一款软件 可以为不同用户,提供不同语言界面 —- 国际化软件
需要一个语言资源包(很多properties文件,每个properties文件 针对一个国家或者语言 ,通过java程序根据来访者国家语言,自动读取不同properties文件 )
2、 资源包编写
properties文件命名 : 基本名称语言(小写)国家(大写).properties
例如 :
messages_zh_CN.properties 中国中文
messages_en_US.properties 美国英文
3、 ResourceBundle 根据不同Locale(地域信息),读取不同国家 properties文件
ResourceBundle bundle = ResourceBundle.getBundle(“messages”, Locale.US);
国际化配置
第一种 全局国际化信息文件 (所有Action都可以使用 ) ——- 最常用
* properties文件可以在任何包中
* 需要在struts.xml 中配置全局信息文件位置
struts.xml
<constant name="struts.custom.i18n.resources" value="messages"></constant> messages.properties 在src根目录
<constant name="struts.custom.i18n.resources" value="cn.itcast.resources.messages"></constant>
messages.properties 在 cn.itcast.resources 包
国际化信息
在Action中使用 : this.getText(“msg”);
在jsp中使用 :
在配置文件中(校验xml) :
第二种 Action范围信息文件 (只能在某个Action中使用 )
数据只能在对应Action中使用,在Action类所在包 创建 Action类名.properties ——— 无需配置
第三种 package范围信息文件 (package中所有Action都可以使用 )
数据对包 (包括子包)中的所有Action 都有效 , 在包中创建 package.properties —– 无需配置
第四种 临时信息文件 (主要在jsp中 引入国际化信息 )
在jsp指定读取 哪个properties文件
* 向信息中传递参数 {0} {1} ———— MessageFormat 动态消息文本
this.getText(“required”, new String[] { “用户名” });
Struts2拦截器
拦截器介绍
拦截器 的使用 ,源自Spring AOP(面向切面编程)思想
拦截器 采用 责任链 模式
* 在责任链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链。
* 责任链每一个节点,都可以继续调用下一个节点,也可以阻止流程继续执行
在struts2 中可以定义很多个拦截器,将多个拦截器按照特定顺序 组成拦截器栈 (顺序调用 栈中的每一个拦截器 )
1、 struts2 所有拦截器 都必须实现 Interceptor 接口
2、 AbstractInterceptor 类实现了 Interceptor 接口. 并为 init, destroy 提供了一个空白的实现
所有实际开发中,自定义拦截器 只需要 继承 AbstractInterceptor类, 提供 intercept 方法实现
3、 常用struts2 拦截器
<interceptor-ref name="modelDriven"/> 模型驱动
<interceptor-ref name="fileUpload"/> 文件上传
<interceptor-ref name="params"> 参数解析封装
<interceptor-ref name="conversionError"/> 类型转换错误
<interceptor-ref name="validation"> 请求参数校验
<interceptor-ref name="workflow"> 拦截跳转 input 视图
自定义拦截器案例
案例 : 登陆,对其它Action访问 通过自定义拦截器 进行权限控制
导入jar包 (struts2 jar、c3p0、 dbutils、 mysql驱动)
web.xml
struts.xml
JDBCUtils 工具类
第一步 : 编写index.jsp 提供 图书增删改查 四个功能
编写BookAction ,提供四个业务方法
第二步: 完成登陆功能
第三步 :必须要登陆 才能进行图书管理
使用Filter 进行权限控制 —- 过滤所有web请求 (所有web资源访问)
使用拦截器 进行权限控制 —- 主要拦截对Action访问 (不能拦截JSP)
定义拦截器 继承AbstractInterceptor
配置拦截器
方式一
<!-- 注册拦截器 -->
<interceptors>
<interceptor name="privilege" class="cn.itcast.interceptor.PrivilegeInterceptor"></interceptor>
</interceptors>
<action name="book_*" class="cn.itcast.action.BookAction" method="{1}" >
<!-- 使用拦截器 -->
<!-- 当使用自定义拦截器 后,默认拦截器 就会失效 -->
<interceptor-ref name="defaultStack"></interceptor-ref>
nterceptor-ref name="privilege"></interceptor-ref>
</action>
方式二
<!-- 注册拦截器 -->
<interceptors>
<interceptor name="privilege" class="cn.itcast.interceptor.PrivilegeInterceptor"></interceptor>
<!-- 自定义拦截器栈 -->
<interceptor-stack name="privilegeStack">
<interceptor-ref name="defaultStack"></interceptor-ref>
<interceptor-ref name="privilege"></interceptor-ref>
</interceptor-stack>
</interceptors>
<!-- 设置当前包 所有Action 都使用 自定义拦截器栈 -->
<default-interceptor-ref name="privilegeStack"></default-interceptor-ref>
Struts2文件上传下载
Struts2文件上传
提供 FileUpload 拦截器,用于解析 multipart/form-data 编码格式请求,解析上传文件的内容
fileUpload拦截器 默认在 defaultStack 栈中, 默认会执行的
在Action需要对上传文件内容进行接收
页面:
<input type="file" name="upload" />
Action :
public class UploadAction extends ActionSupport {
// 接收上传内容
// <input type="file" name="upload" />
private File upload; // 这里变量名 和 页面表单元素 name 属性一致
private String uploadContentType;
private String uploadFileName;
}
* 格式 : 上传表单项name属性 + ContentType 、 上传表单项name属性 + FileName
* 为三个对象 提供 setter 方法
通过FileUtils 提供 copyFile 进行文件复制,将上传文件 保存到服务器端
Struts2文件上传问题解决
配置 input 视图 ,作为上传出错后 跳转页面
在文件上传时,如果发生错误 ,fileUpload拦截器 会设置错误信息,workflow拦截器 跳转到 input 视图
struts.multipart.parser=jakarta 定义文件上传,采用 commons-fileupload 技术
* 同时支持 cos 、pell 上传技术 (如果使用其它上传技术,单独下载jar包 )
通过 struts.multipart.maxSize 常量设置文件上传总大小限制
* struts.multipart.maxSize=2097152 默认上传文件总大小 2MB
* 超过文件总大小,跳转input 视图, 通过 回显错误信息
在struts.xml 设置上传总大小
设置上传文件总大小,对所有上传form有效,只想对当前form进行设置,可以设置fileUpload拦截器属性
FileUpload 拦截器有 3 个属性可以设置.
* maximumSize: 上传文件的最大长度(以字节为单位), 默认值为 2 MB
* allowedTypes: 允许上传文件的类型, 各类型之间以逗号分隔
* allowedExtensions: 允许上传文件扩展名, 各扩展名之间以逗号分隔
如果针对fileUpload 进行参数设置,当出错时,在页面通过 回显错误信息
struts-messages.properties 文件里预定义 上传错误信息,通过覆盖对应key 显示中文信息
struts.messages.error.uploading=Error uploading: {0}
struts.messages.error.file.too.large=The file is to large to be uploaded: {0} "{1}" "{2}" {3}
struts.messages.error.content.type.not.allowed=Content-Type not allowed: {0} "{1}" "{2}" {3}
struts.messages.error.file.extension.not.allowed=File extension not allowed: {0} "{1}" "{2}" {3}
修改为
struts.messages.error.uploading=上传错误: {0}
struts.messages.error.file.too.large=上传文件太大: {0} "{1}" "{2}" {3}
struts.messages.error.content.type.not.allowed=上传文件的类型不允许: {0} "{1}" "{2}" {3}
struts.messages.error.file.extension.not.allowed=上传文件的后缀名不允许: {0} "{1}" "{2}" {3}
多文件上传
第一步:在WEB-INF/lib下加入commons-fileupload-1.2.1.jar、commons-io-1.3.2.jar。这两个文件可以从http://commons.apache.org/下载。
第二步:把form表的enctype设置为:“multipart/form-data“,如下:
<form enctype="multipart/form-data" action="${pageContext.request.contextPath}/xxx.action" method="post">
<input type="file" name="uploadImages">
<input type="file" name="uploadImages">
</form>
第三步:在Action类中添加以下属性,属性红色部分对应于表单中文件字段的名称:
public class uploadAction{
private File[] uploadImages;//得到上传的文件
private String[] uploadImagesContentType;//得到文件的类型
private String[] uploadImagesFileName;//得到文件的名称
//这里略省了属性的getter/setter方法
public String saveFiles() throws Exception{
ServletContext sc = ServletActionContext.getServletContext();
String realpath = sc.getRealPath("/uploadfile");
try {
if(uploadImages!=null&&uploadImages.length>0){
for(int i=0;i<uploadImages.length;i++){
File destFile = new File(realpath,uploadImageFileNames[i]);
FileUtils.copyFile(uploadImages[i], destFile);
}
}
} catch (IOException e) {
e.printStackTrace();}return "success";}}
Struts2文件下载
1) struts2 完成文件下载,通过 结果集类型 (Result Type) stream 来完成的
struts-default.xml 定义
2) 使用Stream结果集 完成文件下载
文件下载原理: 服务器读取下载文件内容,通过Response响应流写回, 设置 ContentType、 ContentDisposition 头信息
public class StreamResult extends StrutsResultSupport {
protected String contentType = "text/plain"; // contentType头信息 (下载文件对应 MIME协议规定类型 )
* html --- text/html . txt--- text/plain
protected String contentDisposition = "inline"; // ContentDisposition头信息 (下载文件打开方式 inline浏览器内部打开, attachment 以附件形式打开)
protected String inputName = "inputStream"; // 需要Action中 提供 getInputStream 方法 返回 InputStream 提供下载文件 内容
}
Action 提供 InputStream 返回值 getInputStream 方法 ——- 指定下载文件流
配置 stream 结果集 参数
* 下载附件名乱码问题 , IE和火狐 解决不同
* public String encodeDownloadFilename(String filename, String agent)
throws IOException {
if (agent.contains("Firefox")) { // 火狐浏览器
filename = "=?UTF-8?B?"
+ new BASE64Encoder().encode(filename.getBytes("utf-8"))
+ "?=";
} else { // IE及其他浏览器
filename = URLEncoder.encode(filename, "utf-8");
}
return filename;
}
OGNL表示式使用 和 值栈
OGNL是Object Graphic Navigation Language(对象图导航语言)的缩写,它是一个开源项目。 Struts2框架使用OGNL作为默认的表达式语言。
* xwork 提供 OGNL表达式
* ognl-3.0.5.jar
OGNL 是一种比EL 强大很多倍的语言
OGNL 提供五大类功能
1、支持对象方法调用,如xxx.doSomeSpecial();
2、支持类静态的方法调用和值访问
3、访问OGNL上下文(OGNL context)和ActionContext; (重点 操作ValueStack值栈 )
4、支持赋值操作和表达式串联
5、操作集合对象。
1、 使用OGNL访问 对象方法 和 静态方法
* OGNL 在jsp 结合 struts2 标签库 使用 , 执行 ognl表达式
调用 实例方法 : 对象.方法() —-
调用 静态方法 : @[类全名(包括包路径)]@[方法名] —
* 使用 静态方法调用 必须 设置 struts.ognl.allowStaticMethodAccess=true
2、 访问OGNL上下文(OGNL context)和ActionContext
OGNL上下文(OGNL context) 对象 —– 值栈 ValueStack
问题一 : 什么是值栈 ValueStack ?
ValueStack 是 struts2 提供一个接口,实现类 OgnlValueStack —- 值栈对象 (OGNL是从值栈中获取数据的 )
每个Action实例都有一个ValueStack对象 (一个请求 对应 一个ValueStack对象 )
在其中保存当前Action 对象和其他相关对象 (值栈中 是有Action 引用的 )
Struts 框架把 ValueStack 对象保存在名为 “struts.valueStack” 的请求属性中,request中 (值栈对象 是 request一个属性)
问题二 : 值栈的内部结构 ?
值栈由两部分组成
ObjectStack: Struts 把动作和相关对象压入 ObjectStack 中–List
ContextMap: Struts 把各种各样的映射关系(一些 Map 类型的对象) 压入 ContextMap 中
Struts 会把下面这些映射压入 ContextMap 中
parameters: 该 Map 中包含当前请求的请求参数
request: 该 Map 中包含当前 request 对象中的所有属性
session: 该 Map 中包含当前 session 对象中的所有属性
application:该 Map 中包含当前 application 对象中的所有属性
attr: 该 Map 按如下顺序来检索某个属性: request, session, application
ValueStack中 存在root属性 (CompoundRoot) 、 context 属性 (OgnlContext )
* CompoundRoot 就是ArrayList
* OgnlContext 就是 Map
context 对应Map 引入 root对象
* context中还存在 request、 session、application、 attr、 parameters 对象引用
* OGNL表达式,访问root中数据时 不需要 #, 访问 request、 session、application、 attr、 parameters 对象数据 必须写 #
* 操作值栈 默认指 操作 root 元素
问题三 : 值栈对象的创建 ,ValueStack 和 ActionContext 是什么关系 ?
值栈对象 是请求时 创建的
doFilter中 prepare.createActionContext(request, response);
* 创建ActionContext 对象过程中,创建 值栈对象ValueStack
* ActionContext对象 对 ValueStack对象 有引用的 (在程序中 通过 ActionContext 获得 值栈对象 )
Dispatcher类 serviceAction 方法中 将值栈对象保存到 request范围
request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, proxy.getInvocation().getStack());
问题四 : 如何获得值栈对象
获得值栈对象 有两种方法
ValueStack valueStack = (ValueStack) ServletActionContext.getRequest().getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY);
ValueStack valueStack2 = ActionContext.getContext().getValueStack();
问题五: 向值栈保存数据 (主要针对 root)
两种方式
// 将数据保存root的索引0位置,放置到第一个元素 ArrayList add(0,element);
valueStack.push("itcast");
// 在值栈创建参数map, 将数据保存到map中
valueStack.set("company", "传智播客");
在jsp中 通过 <s:debug /> 查看值栈的内容
问题六: 在JSP中获取值栈的数据
访问root中数据 不需要#
访问 其它对象数据 加 #
通过下标获取root中对象
//取值栈顶对象
直接在root中查找对象属性 (自上而下自动查找)
valueStack:
在OgnlContext中获取数据
request:<s:property value="#request.username"/>
session:<s:property value="#session.username"/>
application:<s:property value="#application.username"/>
attr:<s:property value="#attr.username"/>
parameters:<s:property value="#parameters.cid[0]"/>