一、国际化概念(了解)
1、什么是国际化
软件
的国际化:软件开发时,要使它能同时应对世界不同地区和国家的访问,并针对不同地区和国家的访问,提供相应的、符合来访者阅读习惯的页面或数据。
2、什么需要国际化
程序:需要国际化。
输入的数据:是什么样的就是什么样的。
比如:
- 用户注册的表单,有用户名,密码这5个汉字,在zh_CN语言环境,显示的就是用户名和密码。但是在en_US语言环境,显示的就应该是username和password。这就是
程序
。 - 用户名输入的是【张三】,密码输入的是【test】,那无论在什么语言环境都应该是是【张三】和【test】。这就是
数据
。
3、固定文本的国际化
例如:消息提示、错误提示和菜单,导航栏等等固定文本。
步骤:
3.1、创建一个消息资源包
一个资源包由多个文件组成,这些文件名都有命名规范:主要文件名_语言代码_国家代码.properties
。
语言代码:由iso规定的。国家代码:由iso规定的。
当文件只有 主要文件名.properties
时,表明它是 默认资源包
。浏览器会根据不同的语言环境找对应语言环境的资源包,当没有找到时,找默认的。
每个资源包的内容都由 相同的key
和 对应语言环境的value
组成。
比如:
message_zh_CN.properties
、 message_zh_HK.properties
、message_en_US.properties
3.2、读取资源包中的内容
国际化的小测试,如下图所示:
![](https://i-blog.csdnimg.cn/blog_migrate/db9bcf9b85b238d10c3d67a14ac03d45.png)
jsp中使用国际化:
配置文件
message_zh_CN.properties
和
message_en_US.properties
的书写:
![](https://i-blog.csdnimg.cn/blog_migrate/83bf9b49661bbebed17de35c50cb6dca.png)
login.jsp文件:
![](https://i-blog.csdnimg.cn/blog_migrate/02a880dfe1d42b42a9189e84338df844.png)
效果如下图所示:
![](https://i-blog.csdnimg.cn/blog_migrate/466d49ef8d6cd0516f6509e78721c35b.png)
![](https://i-blog.csdnimg.cn/blog_migrate/692777592a1b288effc9f0f0fc44e52b.png)
但是呢?
login.jsp中不允许出现下面的java代码块(jsp2.0以后的规定),需要用jsp的标签来替代。
使用jstl的fmt标签,如下图所示:
<% // java代码块
Locale locale = request.getLocale();
ResourceBundle bundle = ResourceBundle.getBundle("com.itheima.resource.message",locale);
%>
![](https://i-blog.csdnimg.cn/blog_migrate/10b1e7889c7d36f8f2d43e0688200520.png)
二、Struts2中的国际化(了解)
1、Struts2中使用国际化的前提
首先,我们要知道,在Struts2中,所有的消息提示都是基于国际化的。
其次,要想在Struts2中使用国际化,动作类必须 继承ActionSupport类
。
2、Struts2中使用国际化
2.1、配置资源包
a、配置全局范围的资源包
![](https://i-blog.csdnimg.cn/blog_migrate/734642fb275e3d27769b848e01d8bc1d.png)
![](https://i-blog.csdnimg.cn/blog_migrate/e4318062dcd185f5f9c852262e0fe9d3.png)
b、配置包范围的资源包
该方式直接新建包范围的资源包,添加配置文件即可,不需要在 struts.xml 中进行配置。
资源包名称命名规范:
package_语言代码_国家代码.properties(固定的写法)
。以此种命名方式的资源包能
被该包及其子包中的动作类访问
。
访问优先级:包范围的资源包高于全局范围的资源包。
![](https://i-blog.csdnimg.cn/blog_migrate/9257beb30c3ce0e40eaf6532911d97e8.png)
c、配置局部消息资源包(只为动作类来使用的)
该方式直接新建动作类范围的配置文件即可,也不需要在 struts.xml 中进行配置。
资源包名称命名规范:
动作类名称_语言代码_国家代码.properties
。以此种命名方式的资源包,只为动作类服务。
访问优先级:优先级最高(就近原则)。
![](https://i-blog.csdnimg.cn/blog_migrate/22b55e669385270e2a8c744698184fef.png)
2.2、读取资源包的内容
a、在动作类中的读取资源包内容(实际开发中几乎从来不用,学习时为了演示而已)
![](https://i-blog.csdnimg.cn/blog_migrate/266323278fe5b23cc42ff517fd02fff6.png)
b、在页面中读取资源包内容
![](https://i-blog.csdnimg.cn/blog_migrate/6503b4d5aa01e9fafda9ade2a0166ab3.png)
Struts2中资源包的搜索顺序,如下图所示:
所在位置:
/struts-2.3.15.3-all/struts-2.3.15.3/docs/WW/docs/localization.html
![](https://i-blog.csdnimg.cn/blog_migrate/6e48715b781cf7759d63d216eef0274b.png)
三、Struts2中的拦截器(特别重要)
1、拦截器的重要性
Struts2中的很多功能都是由拦截器完成的。
比如:servletConfig、staticParam、params、modelDriven等等。
是 AOP编程思想
的一种 应用
形式。
2、拦截器的执行时机
执行动作方法之前,正序执行拦截器。
执行结果视图之后,倒序执行拦截器。
如下图所示:
![](https://i-blog.csdnimg.cn/blog_migrate/5653725cfe639c359eb6b0ef6599eb17.png)
3、自定义拦截器
3.1、拦截器的类视图结构(最终版本):
![](https://i-blog.csdnimg.cn/blog_migrate/4cf9b9f3443c2c89fe45f5370ff3b25f.png)
3.2、编写自定义拦截器步骤:
a、编写一个普通类,
继承AbstractInterceptor类
或者
实现Interceptor接口
。重写其抽象的intercept方法。
![](https://i-blog.csdnimg.cn/blog_migrate/18faa209d362ec319514b05bea26c28f.png)
b、在struts.xml中配置拦截器,注意拦截器必须先声明、再使用。
![](https://i-blog.csdnimg.cn/blog_migrate/65bad9dc992c04ee34121f422efbbd3b.png)
效果图如下:
![](https://i-blog.csdnimg.cn/blog_migrate/f2083414b4dd6a8ac9740062c639c1f1.png)
这时。拦截器干活啦,拦截成功,哈哈,该我想干什么就干什么啦!(坏笑)
3.3、拦截器的执行顺序
拦截器 --> 动作方法 --> 结果视图 --> 拦截器 --> 浏览器响应页面,如下图所示:
![](https://i-blog.csdnimg.cn/blog_migrate/1328483791f5a699a0330589b9168de9.png)
3.4、多个拦截器的执行顺序
当有多个拦截器的时候,是由使用顺序决定执行顺序,与声明顺序无关。
![](https://i-blog.csdnimg.cn/blog_migrate/d9cf8bbecba4e4eb2ee0f4cda8ee779c.png)
3.5、intercept方法的返回值是逻辑结果视图的值。打印下该方法的返回值即可,就不放图啦!
4、拦截器的应用
4.1、检查登录的拦截器案例
配置文件struts.xml:
![](https://i-blog.csdnimg.cn/blog_migrate/41691742c490a71fcd6954df13028156.png)
动作类:
![](https://i-blog.csdnimg.cn/blog_migrate/eee4cc174ed39637816fbd30d9c90c9d.png)
拦截器:
![](https://i-blog.csdnimg.cn/blog_migrate/40e2c93f2af192211e3855a86aa87c8b.png)
页面:
![](https://i-blog.csdnimg.cn/blog_migrate/48c230d9e115e73a7a9ffbc317ec2ab0.png)
4.2、案例中的问题
问题:由于我们写了自己的拦截器,默认的拦截器不起作用了。
解决办法:
a、把默认拦截器也加入到配置文件中
![](https://i-blog.csdnimg.cn/blog_migrate/19a8542d345835c350266b16d29116d2.png)
b、a中暴露的问题:当有多个拦截器时,需要改写的地方非常多。
解决办法:
抽取公共的包,把全局配置放入公共包中
。
![](https://i-blog.csdnimg.cn/blog_migrate/d2ecde1d2cb288ad9ca2de967b56f983.png)
c、b中的问题:还要再每个动作方法中引入拦截器。能不能不写呢?
思路:我们在设置【开发模式】时,覆盖掉了一个default.properties中的常量,那我们能不能把struts-default.xml中的默认拦截器栈的设置给覆盖掉呢?答案是可以的。
![](https://i-blog.csdnimg.cn/blog_migrate/00d5d76894e1d4b448452a1a67adf70d.png)
![](https://i-blog.csdnimg.cn/blog_migrate/cb2ef7b15c25ec7516c34bb5de53df3a.png)
d、c中出现的问题:当我们重新定义了默认的拦截器栈,这时候三个动作login、showMain和showOther都将被检查登录的拦截器拦截。
解决办法:需要通过
AbstractInterceptor类的子类
入手,通过查看发现,该类还有一个抽象的子类:
MethodFilterInterceptor
,它里面提供了两个属性:
excludeMethods
和
includeMethods
。
excludeMethods:表示那些方法不需要拦截
includeMethods:表示哪些方法需要拦截
可以配置多个动作方法,使用,进行分割。
如下图所示:
![](https://i-blog.csdnimg.cn/blog_migrate/fa0a20bf44770d3c07e8b6f10d5adebb.png)
所以我们在自定义拦截器时,还可以
继承MethodFilterInterceptor
并且
重写doIntercept方法
。这种方式更好!
![](https://i-blog.csdnimg.cn/blog_migrate/f758f9109e84ea84b0299d5d0ab95bbb.png)
并且在struts的配置文件中,配置需要拦截哪些方法,和需要放过哪些方法。如下图所示:
![](https://i-blog.csdnimg.cn/blog_migrate/021ae64e33d879f86a1643a560675c1c.png)
e、d中遗留的问题:我们在声明时配置了哪些方法需要拦截,哪些方法不需要拦截。但是在没有写动作类和动作方法之前,不确定方法名叫什么。
解决办法:哪个动作方法需要使用拦截器,我就给它注入参数。
![](https://i-blog.csdnimg.cn/blog_migrate/82b1c88bd41657c6e171dc5633eb9901.png)
四、文件的上传(拦截器)和下载(stream结果类型)(需要练一遍)
1、文件上传
必要前提:
a. 表单form的请求方式method必须是post。
b. enctype取值必须是multipart/form-data。
c. 提供一个文件选择域。
![](https://i-blog.csdnimg.cn/blog_migrate/f5698e58b5749180539259dd2f5915e4.png)
动作类:
![](https://i-blog.csdnimg.cn/blog_migrate/3e6057b08f2b0fcaeda4d0a271560c8c.png)
效果如下图所示:
![](https://i-blog.csdnimg.cn/blog_migrate/bf7a70e238afdb6c0f4ecb54a1054a3f.png)
2、文件上传的配置
2.1、文件上传大小限制(默认大小是2MB)
如果上传文件超过了默认大小,upload拦截器会转向一个input的逻辑视图。如下图所示:
![](https://i-blog.csdnimg.cn/blog_migrate/fc1092901f257c422c132cff1e383f53.png)
按照input的逻辑视图提示,增加结果视图,和增加显示动作错误提示,再次上传,得到新的页面结果视图,如下图所示:
![](https://i-blog.csdnimg.cn/blog_migrate/0ef584b94c74ad6fa8c835e350fa4f74.png)
![](https://i-blog.csdnimg.cn/blog_migrate/b7c853137114ee9d1ba57f658fe2b5b5.png)
a、改变上传文件大小限制:
思路1:在struts.xml中改变default.properties文件中的常量。
![](https://i-blog.csdnimg.cn/blog_migrate/7e2abb8ee4ccce7525bd9f2cddb97198.png)
思路2:给Struts2默认的拦截器栈中的fileUpload拦截器注入参数:(行不通)
![](https://i-blog.csdnimg.cn/blog_migrate/0ba9cb59bfb0cb0aec4df9aa1c02331a.png)
2.2、限制文件上传的类型
a、通过限制上传文件的扩展名
思路:给Struts2默认的拦截器栈中的fileUpload拦截器注入参数:
![](https://i-blog.csdnimg.cn/blog_migrate/770f5cd54ae2efccecd7794641c6457d.png)
当上传非限定扩展名时,有如下错误提示:
![](https://i-blog.csdnimg.cn/blog_migrate/3cb9d32e8a035817e9b6bff9a74af0f4.png)
b、通过限制上传文件的MIME类型
![](https://i-blog.csdnimg.cn/blog_migrate/ec6710d763878f7c350d3d3d7971c170.png)
当上传非限定MIME类型时,有如下错误提示
![](https://i-blog.csdnimg.cn/blog_migrate/e72ad162d26da457306b5697efd17d85.png)
3、出错后的错误信息中文提示(Struts2中的所有文本提示都是基于国际化的)
默认信息提示在:项目目录下\Web App Library\struts2-core.jar\org.apache.struts2\struts-message.properties
![](https://i-blog.csdnimg.cn/blog_migrate/07f7d4042da9655efd86ad2f30dca0bb.png)
解决办法:用国际化消息资源包,把对应的key取值改为中文即可。
常用的key值,配置如下:
![](https://i-blog.csdnimg.cn/blog_migrate/063421b0237c00aab520388d2b03aeec.png)
修改显示错误的资源文件的信息,如下图所示:
![](https://i-blog.csdnimg.cn/blog_migrate/8f4b20ca9f630ea71a2818d048e16e7f.png)
效果如下图所示:
![](https://i-blog.csdnimg.cn/blog_migrate/71c253d0c9d7d7b35e2b484893b6151f.png)
4、多文件上传
jsp页面:
![](https://i-blog.csdnimg.cn/blog_migrate/3037b44ed7b21fed873bc11ea483de7c.png)
配置文件struts.xml:
![](https://i-blog.csdnimg.cn/blog_migrate/27ed9340b68d6a34918b395baf000dc4.png)
动作类:
![](https://i-blog.csdnimg.cn/blog_migrate/7b4cb0f0b93552be669d92984f7c779e.png)
运行结果:没有问题,就不上图啦!
5、文件下载:其实就是一种结果类型(Stream)
动作类:
![](https://i-blog.csdnimg.cn/blog_migrate/e2388b8a9a10b7447f3c357aa911e2d5.png)
配置文件:
![](https://i-blog.csdnimg.cn/blog_migrate/1cf339d52fc42ce4e86b7371cb790251.png)
运行结果:没有问题,就不上图啦!
问题:文件名不能在配置文件中写死,需要根据实际情况获取。
解决办法:
动作类:
五、OGNL简介(非常重要)
1、什么是OGNL?
OGNL是 Object Graphic Navigation Language
(对象图导航
语言)的缩写,它是一个单独的开源项目。 Struts2框架使用OGNL作为默认的 表达式语言
。
2、OGNL的功能
前提:OGNL是struts2整合的一个 开源项目
,所以在struts2中,要想使用OGNL表达式,必须使用 Struts2标签库
。
2.1、支持普通方法的调用
(EL表达式只能调用静态方法,详解见此链接:https://www.cnblogs.com/chenmingjun/p/9243454.html)
2.2、访问静态成员(静态属性,静态方法)
如下图所示:
![](https://i-blog.csdnimg.cn/blog_migrate/2e2b659e9f637b9aac7f2598d252fca2.png)
![](https://i-blog.csdnimg.cn/blog_migrate/7c6f01d6644076ac7ec0c59d19a17213.png)
![](https://i-blog.csdnimg.cn/blog_migrate/c0418bad20bd091d93d3b5726d77fb70.png)
2.3、操作集合对象
a、创建List对象:
b、创建Map对象:
![](https://i-blog.csdnimg.cn/blog_migrate/2471c4317213a0342aa0aba3430d4399.png)
![](https://i-blog.csdnimg.cn/blog_migrate/56dff877479a0a48179bf83ccaf4622e.png)
2.4、OGNL改写文件下载文件名的问题
动作类:
![](https://i-blog.csdnimg.cn/blog_migrate/17a0bd75eb0f1358be6611c6896eae8e.png)
struts.xml配置文件:
![](https://i-blog.csdnimg.cn/blog_migrate/6f559e5eea66601d69a2a824f4bf7174.png)
六、context Map(非常重要)
1、动作类的生命周期
明确:动作类是多例的,每次动作访问,动作类都会实例化。所以是线程安全的
。与Struts1的区别是,struts1的动作类是单例的。
2、请求动作的数据存放
问题:
每次请求时,都会产生一些请求数据,这些数据存放到哪里去了?
明确:
在每次动作执行前,核心控制器StrutsPrepareAndExecuteFilter
都会创建一个 ActionContext
和 ValueStack对象
。且每次动作访问都会创建。
这两个对象存储了整个动作访问期间用到的数据
。并且把数据绑定到了 线程局部变量(ThreadLocal)
上了。所以是线程安全的。
![](https://i-blog.csdnimg.cn/blog_migrate/d03adcb41d56cf877943708173082f3d.png)
![](https://i-blog.csdnimg.cn/blog_migrate/cb17d5648647be461c5e484024007376.png)
3、context Map:存储数据
Struts2的官方文档对context Map的说明:
![](https://i-blog.csdnimg.cn/blog_migrate/e2447ab549bab203549e0796ddb61158.png)
![](https://i-blog.csdnimg.cn/blog_migrate/f377b61a463a918563b37c666a42dd05.png)
注意:
除了value stack之外,全是map,而context Map也是一个map。其实就是Map中又封装的Map。
注意:只是像其封装数据的结构而已
,把结果集封装成一个Map,Map里面又是一个Map,大Map的key是主键,大Map的value是一个小Map,是一条记录)
在页面上使用
<s:debug/>
![](https://i-blog.csdnimg.cn/blog_migrate/262538102b8691ad0eecb51499300181.png)
效果如下图所示:
![](https://i-blog.csdnimg.cn/blog_migrate/b1b92b33188805751dcd544b66032033.png)
![](https://i-blog.csdnimg.cn/blog_migrate/56432314e3017d62e74b37031c1bd3c8.png)
测试存入数据:
![](https://i-blog.csdnimg.cn/blog_migrate/8b48c84b2e8205ca701d9c60bc3784cc.png)
![](https://i-blog.csdnimg.cn/blog_migrate/6e879720317a01032683e88e47237e8c.png)
未完待续,欲知后事如何,且听下回分解…
我的博客园地址: http://www.cnblogs.com/chenmingjun
我的蚂蚁笔记博客地址: http://blog.leanote.com/chenmingjun
Copyright ©2018 黑泽明军
【转载文章务必保留出处和署名,谢谢!】