重拾Java EE——Struts 2(3)高级核心一
一、国际化概念(了解)
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://img.haomeiwen.com/i3034232/ea6ad88118c231fe.png)
jsp中使用国际化:
![](https://img.haomeiwen.com/i3034232/a3bfbf79d7258f39.png)
![](https://img.haomeiwen.com/i3034232/e45b36d473f6a972.png)
使用jstl的fmt标签:
![](https://img.haomeiwen.com/i3034232/166eadce818181e5.png)
二、Struts2中的国际化(了解)
1、Struts2中使用国际化的前提
首先,我们要知道,在Struts2中,所有的消息提示都是基于国际化的。
其次,要想在Struts2中使用国际化,动作类必须继承ActionSupport类。
2、Struts2中使用国际化
2.1、配置资源包
a、配置全局资源包
![](https://img.haomeiwen.com/i3034232/b5e08230af164116.png)
b、配置包范围的资源包
![](https://img.haomeiwen.com/i3034232/c61050bf24889481.png)
资源包名称命名规范:package_语言代码_国家代码.properties(固定的)。以此种命名方式的资源包能被该包及其子包中的动作类访问。
优先级:高于全局消息资源包
c、局部消息资源包(只为动作类来使用的)
![](https://img.haomeiwen.com/i3034232/0602a66711e2d6dc.png)
资源包名称命名规范:动作类名称语言代码国家代码.properties。以此种命名方式的资源包,只为动作类服务。
优先级最高(就近原则)。
Struts2中资源包的搜索顺序:
![](https://img.haomeiwen.com/i3034232/6d6f3542498d255e.png)
2.2、读取资源包的内容
a、动作类中的读取方式(实际开发中几乎从来不用)
![](https://img.haomeiwen.com/i3034232/3c029f00738fee37.png)
b、在页面中读取资源包内容
直接访问jsp:
![](https://img.haomeiwen.com/i3034232/991b671e32c26203.png)
![](https://img.haomeiwen.com/i3034232/16d16055cdda6d1d.png)
通过动作类访问jsp
![](https://img.haomeiwen.com/i3034232/7ea993a37791f4d8.png)
c、自由指定读取资源包
![](https://img.haomeiwen.com/i3034232/939b4208a78202df.png)
三、Struts2中的拦截器(特别重要)
1、拦截器的重要性
Struts2中的很多功能都是由拦截器完成的。比如:servletConfig,staticParam,params,modelDriven等等。
是AOP编程思想的一种应用形式。
2、拦截器的执行时机:
![](https://img.haomeiwen.com/i3034232/63b36b1f957ee709.png)
3、自定义拦截器
3.1、拦截器的类试图(初级版本):
![](https://img.haomeiwen.com/i3034232/63168bde4ba25dea.png)
3.2、编写步骤:
a、编写一个类,继承AbstractInterceptor类或者实现Interceptor接口。重写intercept方法。
![](https://img.haomeiwen.com/i3034232/7537ace77e96c73a.png)
b、配置拦截器:注意拦截器必须先声明再使用
![](https://img.haomeiwen.com/i3034232/103958cc00975632.png)
3.3、执行顺序
![](https://img.haomeiwen.com/i3034232/c66e9825f728c9e8.png)
3.4、多个拦截器的执行顺序
![](https://img.haomeiwen.com/i3034232/2d006a5575ca6940.png)
3.5、intercept方法的返回值
![](https://img.haomeiwen.com/i3034232/51bf94508b4167c3.png)
4、拦截器的应用:
4.1、检查登录的拦截器案例
配置文件:
![](https://img.haomeiwen.com/i3034232/e71c926c26f1870f.png)
动作类:
![](https://img.haomeiwen.com/i3034232/badc2d69f9cab2aa.png)
拦截器:
![](https://img.haomeiwen.com/i3034232/8a656c8d3beaafad.png)
页面:
![](https://img.haomeiwen.com/i3034232/ecb4ff7b4ae72769.png)
4.2、案例中的问题
问题:由于我们写了自己的拦截器,默认的拦截器不起作用了。
解决办法:
a、把默认拦截器加入到配置文件中
![](https://img.haomeiwen.com/i3034232/607200c5c8054928.png)
b、a中暴露的问题:当有多个拦截器时,需要改写的地方非常多。
解决办法:抽取公共的包,把全局配置放入公共包中。
![](https://img.haomeiwen.com/i3034232/55a69501e7005148.png)
c、b中的问题:还要再每个动作方法中引入拦截器。能不能不写呢?
思路:我们在设置【开发模式】时,覆盖掉了一个default.properties中的常量,能不能把struts-default.xml中的默认拦截器栈的设置给覆盖掉呢?答案是可以的。
![](https://img.haomeiwen.com/i3034232/7d26911f5de1203f.png)
解决办法:
![](https://img.haomeiwen.com/i3034232/e11ba150be71b25f.png)
d、c中出现的问题:当使用了默认拦截器栈,这时候三个动作login,showIndex和show1Action都将被检查登录的拦截器拦截。
解决办法:
需要通过AbstractInterceptor类的子类入手,通过查看发现,该类还有一个子类是抽象的:
![](https://img.haomeiwen.com/i3034232/63061726f2b95dde.png)
所以我们在自定义拦截器时,还可以继承MethodFilterInterceptor并且重写doIntercept方法。
![](https://img.haomeiwen.com/i3034232/61df58c7c09f4863.png)
并且在struts的配置文件中,配置需要拦截哪些方法,和需要放过哪些方法。
![](https://img.haomeiwen.com/i3034232/d9b48924d79b1d93.png)
e、d中遗留的问题:我们在声明时配置了哪些方法需要拦截,哪些方法不需要拦截。但是在没有写动作类和动作方法之前,不确定方法名叫什么。
解决办法:我们需要在使用拦截器的时候给它注入参数。
![](https://img.haomeiwen.com/i3034232/e16c0a7ff24c351c.png)
4.3、拦截器类视图(全):
![](https://img.haomeiwen.com/i3034232/8d37be1d661a4fd0.png)
四、文件的上传(拦截器)和下载(stream结果类型)
1、文件上传
必要前提:
a.表单method必须是post;
b.enctype取值必须是multipart/form-data;
c.提供文件选择域。
![](https://img.haomeiwen.com/i3034232/2310c758d5b52e80.png)
动作类:
![](https://img.haomeiwen.com/i3034232/4c0b91e70d7bc5c0.png)
2、文件上传的配置
2.1、文件上传大小限制(默认是2MB)
如果上传文件超过了默认大小,upload拦截器会转向一个input的逻辑视图。
![](https://img.haomeiwen.com/i3034232/656710ca873c5637.png)
![](https://img.haomeiwen.com/i3034232/ecec50ea9f809390.png)
![](https://img.haomeiwen.com/i3034232/95e5397854de6ec1.png)
![](https://img.haomeiwen.com/i3034232/e0e56e0a465b55b2.png)
![](https://img.haomeiwen.com/i3034232/10ad8193b8248185.png)
![](https://img.haomeiwen.com/i3034232/3eb2368fa2c57745.png)
a、改变上传文件大小限制:
思路1:给Struts2的拦截器注入参数:(行不通)
![](https://img.haomeiwen.com/i3034232/ef3ce7d66e4e843b.png)
![](https://img.haomeiwen.com/i3034232/fa7348c83f291b12.png)
思路2:在struts.xml中改变default.properties文件中的常量。
![](https://img.haomeiwen.com/i3034232/3cd92488f6ac629d.png)
![](https://img.haomeiwen.com/i3034232/51f1aeb674d1f9d6.png)
2.2、限制文件上传的类型
a、通过限制上传文件的扩展名
思路:给fileUpload拦截器注入参数
![](https://img.haomeiwen.com/i3034232/d839420e8818e5f5.png)
![](https://img.haomeiwen.com/i3034232/12cc2cb64d2e44db.png)
当上传非限定扩展名时:有如下错误提示
![](https://img.haomeiwen.com/i3034232/5388921cf6b76d43.png)
b、通过限制上传文件的MIME类型
![](https://img.haomeiwen.com/i3034232/9fcbc7ee2b87102d.png)
当上传非限定MIME类型时:有如下错误提示
![](https://img.haomeiwen.com/i3034232/e7f72703ee6cc23c.png)
3、出错后的错误信息中文提示(Struts2中的所有文本提示都是基于国际化的)
默认信息提示在:struts2-core.jar\org.apache.struts2\struts-message.properties
![](https://img.haomeiwen.com/i3034232/7414d458741d5c98.png)
解决办法:用国际化消息资源包,把对应的key取值改为中文即可。
常用的key值:
![](https://img.haomeiwen.com/i3034232/be2dcb2a84f4f363.png)
![](https://img.haomeiwen.com/i3034232/860f47b0772619cd.png)
4、多文件上传
jsp页面:
![](https://img.haomeiwen.com/i3034232/35e9790ecd019321.png)
配置文件:
![](https://img.haomeiwen.com/i3034232/fe08116ba59ce95f.png)
动作类:
![](https://img.haomeiwen.com/i3034232/0a12ca4aea162508.png)
运行结果:
![](https://img.haomeiwen.com/i3034232/6237ebfc6a60c004.png)
5、文件下载:其实就是一种结果类型(Stream)
动作类:
![](https://img.haomeiwen.com/i3034232/cc9ac4bd6fc82c1d.png)
配置文件:
![](https://img.haomeiwen.com/i3034232/5749c1daf986e2f8.png)
运行结果:
![](https://img.haomeiwen.com/i3034232/9aaa0000bd3c5af9.png)
问题:文件名不能在配置文件中写死,需要根据实际情况获取。
解决办法:
动作类:
![](https://img.haomeiwen.com/i3034232/650513726ffc46a0.png)
配置文件:
![](https://img.haomeiwen.com/i3034232/5cbbbcbeb6afe13c.png)
运行结果:
![](https://img.haomeiwen.com/i3034232/b03cedc3df5584a7.png)
五、OGNL简介(非常重要)
1、什么是OGNL
OGNL是Object Graphic Navigation Language(对象图导航语言)的缩写,它是一个单独的开源项目。 Struts2框架使用OGNL作为默认的表达式语言。
2、OGNL的功能
前提:OGNL是struts2整合的一个开源项目,所以在struts2中,要想使用OGNL表达式,必须使用Struts2标签库
2.1、支持普通方法的调用
![](https://img.haomeiwen.com/i3034232/42b098abbb693b1c.png)
![](https://img.haomeiwen.com/i3034232/9df564442447d8c9.png)
(EL表达式只能调用静态方法)
2.2、访问静态成员(静态属性,静态方法)
![](https://img.haomeiwen.com/i3034232/3c58f6c219c0c485.png)
![](https://img.haomeiwen.com/i3034232/15149588a44010a8.png)
![](https://img.haomeiwen.com/i3034232/1b736a93ad06f579.png)
OGNL改写文件下载:
![](https://img.haomeiwen.com/i3034232/ef9bffd209f8e3ea.png)
![](https://img.haomeiwen.com/i3034232/143ebe463b452ee5.png)
2.3、操作集合对象
a、创建List对象:
![](https://img.haomeiwen.com/i3034232/7bd18d52b2ab8a6d.png)
![](https://img.haomeiwen.com/i3034232/339c6d5649d53c48.png)
b、创建Map对象:
![](https://img.haomeiwen.com/i3034232/600a1cb88b53a1d9.png)
![](https://img.haomeiwen.com/i3034232/f4af660bd8899ca8.png)
六、contextMap(非常重要)
1、动作类的生命周期
明确:动作类是多例的,每次动作访问,动作类都会实例化。所以是线程安全的。与Struts1的区别是,struts1的动作类是单例的。
2、请求动作的数据存放
问题:
每次请求时,都会产生一些请求数据,这些数据存放到哪里去了?
明确:
在每次动作执行前,核心控制器StrutsPrepareAndExecuteFilter都会创建一个ActionContext和ValueStack对象。且每次动作访问都会创建。
这两个对象存储了整个动作访问期间用到的数据。并且把数据绑定到了线程局部变量(ThreadLocal)上了。所以是线程安全的。
![](https://img.haomeiwen.com/i3034232/f3b23e2d86041b89.png)
![](https://img.haomeiwen.com/i3034232/929528b2e3c5b15f.png)
3、contextMap:存储数据
Struts2的官方文档对contextMap的说明:
![](https://img.haomeiwen.com/i3034232/5ae2459dd3676a39.png)
![](https://img.haomeiwen.com/i3034232/c10db4e4a4bcf654.png)
注意:
除了value stack之外,全是map,而contextMap也是一个map。其实就是Map中又封装的Map。(很像dbutils中KeyedHandler封装数据的结构,只是封装数据的结构)
查看contextMap中的数据:
在页面上使用<s:debug/>
![](https://img.haomeiwen.com/i3034232/08f0ebc102ce4702.png)
![](https://img.haomeiwen.com/i3034232/1a7b185d2e6fc154.png)
测试存入数据:
![](https://img.haomeiwen.com/i3034232/7aa99341ece9b9af.png)
![](https://img.haomeiwen.com/i3034232/a6bfd5afa6dbbe48.png)