知识导入
xml解析
dom4j解析
反射
有完整类名,并且含有空参构造函数,如何创建出对象?
//使用反射创建对象
Class clazz = Class.forName("xxx");
clazz.newInstance();
filter过滤器
- 过滤来自浏览器发送的请求.在请求到达访问资源之前.会先经过过滤器.
- 可以完成批处理. 还可以根据filterChain来决定是否放行.
- 也可以使用请求转发,或重定向,不让请求到目标路径.
自己定义一个struts-Mini
Struts2基础
框架相关
- 什么是框架?
微观:由一个一个类构成的包,包再构成框架
宏观:半成品的项目,我们需要执行什么业务时,为框架填写业务逻辑即可 - 三大框架:SSH=>Struts,Spring,Hibernate
Struts的版本:
Struts1(已经淘汰)
Struts2(我们要学的)也叫xwork。 - 三大框架的作用?
简化我们的开发,降低开发成本,提高开发效率
Struts=> WEB层框架:
优势:
1.不用侵入性比较高的Servlet.可以直接写普通java类作为处理请求逻辑的处理类.这样更易于测试.
2.整合了一些之前需要手动来做的功能. 后台验证,表单回显,自动将表单参数封装,防止表单重复提交,如果不够用我们还可以扩展框架的功能.
Struts2的HelloWorld
1 | //--------------------------------- |
struts2的架构
struts2的架构图解
struts2中的6个配置文件
- default.properties :用于配置struts 常量。例如:编码
- struts-default.xml :struts提供的默认核心配置文件,struts大部分功能都在此配置文件中。
- struts-plugin.xml : struts插件核心配置文件,struts整合其他框架或工具。
- 以上三个文件,用户自己不进行修改。
- struts.xml :用户自定义核心配置文件。
struts.xml 可以配置所有内容,包括:常量,如:
< constant name=”struts.i18n.encoding” value=”GBK”> < /constant> //配置编码 - struts.properties : 用于自定义struts常量配置文件。一般不使用。
- web.xml :也可以配置struts常量
@@@注意:如果配置常量,所有的配置文件存在优先级,编号越大优先级越高。
常见的struts常量
- 用于配置项目编码//struts.i18n.encoding=UTF-8
- struts整合spring需要配置,默认注释掉了//struts.objectFactory = spring
- struts默认使用文件上传解析工具:apache-commons-fileupload
struts.multipart.parser=jakarta - 临时文件保存位置//struts.multipart.saveDir=
- 上传文件最大大小,默认值:2M,单位字节//struts.multipart.maxSize
- 用于设置action请求路径扩展名。默认:action或空。多个值使用逗号分隔//struts.action.extension=action,,
例如:/hello/userAction 或 /hello/userAction.action - 确定是否使用动态方法调用。默认关闭的。//struts.enable.DynamicMethodInvocation = false
- 设置开发模式,默认关闭。如果设置true:将提供更多提示信息,自动加载文件。//struts.devMode = false
- 自动重新加载国际化资源文件//struts.i18n.reload = true
- 自动冲洗加载xml配置文件。例如:struts.xml。但不会自动加载action类。//struts.configuration.xml.reload = true
- 设置struts标签主题,默认值:xhtml。取值:simple。//struts.ui.theme=xhtml
//开发中常用simple。xhtml存在默认布局,开发中布局使用美工提供页面,布局自定义。
struts.xml详解
< constant> 用于配置struts常量
—name:struts提供固定常量名称。此名称从 default.properties文件获得
—value:常量值
例如:<constant name=”struts.devMode” value=”true”> </constant><package> struts用于管理所有action类
—name:给当前包进行唯一命名,必填项。用于其他包继承的。
例如:struts-default.xml//<package name=”struts-default” abstract=”true”> //将struts已经完成的功能,作为一个包存在。名称是固定值struts-default。
—namespace:action访问路径前缀。
例如:”/“
“/hello”
“/a/b/c”
“”
—extends:用于继承其他包的。
例如:<package extends=”struts-default”> 当前action继承struts已经完成功能。
—abstract:是否抽象,如果设置为true,表示没有具体action实现功能。(了解)<action> 用于配置action类(请求处理类)
—name:action名称,用于在请求路径进行访问
—class:action类全限定类名
—method:用于确定action类中需要执行的方法,默认值:execute<result> 用于配置结果集
—name:用于确定action类中,方法的返回值
—text:标签体用于设置jsp路径
—type:结果集类型
— dispatcher:请求转发,从一个action到jsp页面,默认值。
— redirect:重定向到jsp页面
— redirectAction:重定向到另一个action
— stream:以流的方法发送浏览器,用于文件下载。
— chain:链,在一次请求中,从一个action到另一个action<result-types> 用于配置结果集类型的,一般不用,但需要看的懂。
<interceptors> 用于配置拦截器
— <interceptor> 用于注册拦截器的
—<interceptor-stack> 拦截器栈,将已经注册的拦截器组合在一起,形成一个栈。
例如:<interceptor-stack name=”defaultStack”> 声明一个拦截器栈,名称是:defaultStack<default-interceptor-ref> 用于确定当前默认拦截器的
例如:<default-interceptor-ref name=”defaultStack”/> 将“defaultStack”拦截器栈,声明默认拦截器栈<default-action-ref> 如果访问的action不存在,默认执行的aciton。
例如:/a/b/c/d/oneAction 此aciton没有配置,默认情况返回action找不到
!!!如果配置<default-action-ref> 如果存在404时,不显示action找不到,而是指定action<default-class-ref > 用于配置 默认action实现类
例如:<default-class-ref class=”com.opensymphony.xwork2.ActionSupport” />
!!!如果编写配置文件时没有声明class属性,及<action name=””> 将执行ActionSupport类。<include> 将多个struts配置文件组合成一个。
struts.xml 入口配置文件,大家共用的。用于存放通用模块。
<include file=”struts-user.xml” />
<include file=”struts-book.xml” />
提供子配置文件
struts-user.xml
struts-book.xml
action访问
动态方法调用
格式: action名称!方法名称.action
例如:bookAction!add.action
1 | <!-------- jsp文件配置action入口 ----------> |
通配符
<action name="userAction">
, action.name可以使用通配符星号(*),在action.class、aciton.method、result.name 处可以使用{n}方式匹配星号。
例如:
userAction_*
将可以通过{1}方法获得第一个星号匹配到内容。
请求路径/userAction_add
,
<action name="userAction_*" method="{1}">
{1} 匹配的内容是add,将执行add方法userAction_*_*
{1} 匹配第一个星;{2}匹配第二星
请求路径/userAction_add_success
,
<action name="userAction_*_*" method="{1}"><resutl name="{2}">
{1}匹配add方法,{2}匹配返回值的名称success*_*_*
将采用多个分别描述不同的内容,一次{1}{2}{3}获得
请求路径/UserAction_add_success
<action name="*_*_*" class="cn.itcast.action.{1}" method="{2}"> <result name="{3}">/pages/{3}.jsp
1 | <!-- 案例3:通配符 --> |
action访问路径
当默认访问一个action时,package.namespace = /a/b/c
- 优先从”/a/b/c”namespace获得相应的aciton,
- 如果没有获得,将从”/a/b”中获得
- 如果没有获得,将从”/a”中获得
- 如果没有获得,将从”/“中获得
- 如果没有获得,将从””中获得
Action类与servlet API
Action类
实现方法
POJO类
实现Action接口
规范接口,将success (表示成功了),none(没有返回值。相当方法void。没有返回值表示没有result,常用与ajax操作。使用response发送数据),error(服务器异常),input(表示用户输入错误),login(表示需要权限)等字符串封装成相应的常量继承ActionSupport类
ActionSupport类已经默认实现了Action(规范接口),Validateable(数据校验),ValidationAware(错误信息),TextPrivider(国际化)等接口
方法定义
1 | public String execute() throws Exception{ |
- 必须是public
- 建议有返回值,类型必须String
- 方法名称自定义
- 没有参数
- 需要throw Exception
- 非静态的
注意:可以没有返回值,一般情况都有,可以使用return “none” 表示没有返回。
Struts.xml中struts-default包中的默认配置
如果不手动配置Action 默认Action如下配置:
<default-class-ref class="com.opensymphony.xwork2.ActionSupport" />
如果不配置结果的type属性,默认type属性如下配置:
<result-type name="dispatcher" class="org.apache.struts2.dispatcher.ServletDispatcherResult" default="true"/>
访问Servlet api
完全解耦,但只能操作作用域
- 不使用曾经学习过的servlet知识,可以去操作三个作用域
- ActionContext 工具类,action上下文对象
获得实例:ActionContext.getContext()
-api:
ac.put(key,value) , 相当于操作request作用域。request.setAttribute(“key”,value)
ac.getSession().put(key,value) ,相当于操作session作用域。session.setAttribute(“key”,value)
ac.getApplication().put(key,value) ,相当于操作application作用域。servletContext.setAtt…
1 |
|
操作servlet对象
ServletActionContext 工具类,获得需要servlet对象
1 | -api: |
通过实现接口,struts注入
- 需要实现指定的接口,此接口都提供setter,struts在执行action方法之前,将调用setter方法进行赋值。
ServletRequestAware //获得HttpServletRequest对象
ServletResponseAware //获得HttpServletResponse对象
ServletContextAware// 获得ServletContext对象1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18public class Demo5Action3 extends ActionSupport implements ServletRequestAware , ServletResponseAware ,ServletContextAware{
private HttpServletRequest request;
private HttpServletResponse response;
private ServletContext servletContext;
private HttpSession session;
public void setServletRequest(HttpServletRequest request) {
this.session = request.getSession();
this.request = request;
}
public void setServletResponse(HttpServletResponse response) {
this.response = response;
}
public void setServletContext(ServletContext context) {
this.servletContext = context;
}
结果集与参数控制
结果集类型 Result
1 | <!-- 案例 6.1 :结果集类型,重定向jsp --> |
封装请求参数
- 属性封装
- 只要在Action中提供与参数对应的set方法即可自动封装
- 自动类型封装
- struts会自动转换8大基本数据类型和对应包装类.以及Date类型,其中date类型对数据提交格式有要求: yyyy-MM-dd
- 容器数据封装
- 容器:数组、List、Set、Map等
1 | <!-- Jsp表单 --> |
1 | //Action类 |
类型转换
默认支持类型转换
字符串 与 指定类型 之间转换
字符串 转成 指定类型:表单提交,浏览器发送服务器
指定类型 转成 字符串:标签回显,服务器发送浏览器指定类型
8个基本类型、以及包装类
时间 Date,字符串有格式要求:yyyy-MM-dd 或 yyyy-MM-dd HH:mm:ss
数组、List、Map
自定义类型转换器
实现类
- 方案1:实现接口:TypeConverter,有一个方法,但参数过多。
- 方案2:继承默认实现类:DefaultTypeConverter 。提供简洁方法convertValue(Object , Class)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21convertValue(Object value , Class toType)
#1 表单提交,浏览器发送到服务器。浏览器发送的肯定字符串String,需要转换成指定的类型。例如Date类型
-参数1:value,表示浏览器发送的数据。类型是String[] ,底层使用request.getParameterValues("...")
-参数2:toType,表示需要转换的类型,java.uilt.Date类型
具体操作
// 如果toType是 Date类型,表示希望将 字符串转成 时间
if(toType == java.util.Date.class){
//获得数据
String[] params = (String[])value;
//转成成时间
}
#2 标签回显,服务器发送 浏览器,类型之前已经从字符串转成时间,现在希望将时间再转换成 字符串。
-参数1:value,表示服务器已经转成好的时间。类型Date。
-参数2:toType,表示需要转换的类型,String类型
具体操作
if(toType == String.class){
// 将数据强转时间
Date date = (Date)value;
// 格式化
}
注册转换器
- 局部转换器:只对当前Action类有效。
–限制:只能对action类的属性进行转化,不能对javabean中属性转换 - 全局转换器:对所有的Action类有效。
注意:自定义转换器很少使用,一般情况使用默认就可以。多读
局部转换器的创建
–位置:Action类同包
–名称:action类的类名-conversion.properties
–内容:属性=转换器//如birthday=cn.itcast.XXXCoverter全局转换器的创建
–位置:src
–名称:xwork-conversion.properties
–内容:需要转换的类=转换器//如java.util.Data=cn.itcast.XXXConveter
1 | //-----转换器实现----- |
自定义错误信息
我们发现Struts2打印的类型转换错误信息是英文的,这说明我们需要自定义错误信息。自定义错误信息需要在Action所在目录下创建ActionName.properties文件(与Action同名的properties文件),然后在该文件中给出:invalid.fieldvalue.属性名=错误信息,其中invalid.fieldvalue是固定的。(注:若已使用前端校验,可不必配置此项)
例如:invalid.fieldvalue.person=无法将请求参数转换成Person类型!
校验器与拦截器
校验
数据校验
校验分类
-浏览器端校验:javaScript,但不安全
-服务器端校验:struts校验struts校验
- 手动校验:编写代码,适用于需要与数据库交互
- xml校验:编写配置文件,通用校验,逻辑简单。如:不能为空,长度为10等
手动校验
若需要手动校验,必须实现接口:validateable,它提供了一个方法validate()
校验action中的所有方法
–实现接口,并实现validate()方法校验action中的单个方法
-实现接口并编写方法 validate方法() , 此处“方法”表示执行的方法名称,首字母大写。
—-例如:add() 执行前需要校验,必须编写 validateAdd()
注意:先执行“单个方法”校验,再执行“所有方法”校验
- 提供错误提示,阻止目标方法的执行
–this.addFieldError("", "")
给指定的字段设置提示信息,<s:fielderror>
jsp显示错误
–this.addActionMessage(aMessage)
action提示提示信息,<s:actionmessage/>
jsp显示错误
–this.addActionError(anErrorMessage)
action错误,<s:actionerror/>
jsp显示错误
xml校验
- 单个方法校验
–位置:action类同包
–名称:actionClass-actionName-validation.xml
actionClass :表示action类名
actionName:表示action访问名称,及
validation.xml :固定后缀
–内容:xml必须提供约束(DTD、schema[命名空间])
dtd文件位置:xwork-core-2.3.15.3.jar!/xwork-validator-1.0.3.dtd
dtd文件内容:
1 |
所有方法校验
–位置:action类同包
–名称:actionClass-validation.xml
–内容:同上struts提供的校验器
–校验配置文件:xwork-core-2.3.15.3.jar!/com/opensymphony/xwork2/validator/validators/default.xml
输入校验
什么是输入校验?
在Action封装了请求参数后,还需要对其进行校验。例如name不能为空,age只能在18~60之间等等!我们一定要搞清楚,输入校验是在类型转换成功之后,才可能执行的。
校验分类:
–JavaScript客户端校验(改善用户体验);
– 服务器端校验(保证安全性),即使用Struts2输入校验。Struts2输入校验的分类
编程式校验;
配置校验:
XML配置校验(了解);
编程式的输入校验
覆盖ActionSupport类的validate()方法,在这个方法中完成对参数的校验。validate()方法会在参数封装之后,在execute()方法之前执行。如果validate()方法中向fieldError中添加了错误信息,那么就不会再执行execute()方法,而是跳转到input结果码对应的页面。
1 | //---jsp文件中--- |
在validate方法中
- 使用addFieldError(fieldName, errorMessage)方法存入字段的错误信息.
- 使用addActionError(anErrorMessage)方法存入action的错误信息
- 使用addActionMessage(aMessage)方法存入action提示信息
在页面
- 使用<s:fielderror fieldName=”xxx” />取出字段的错误信息
- 使用<s:actionerror/>取出action的错误信息
- 使用<s:actionmessage/>取出action提示信息
- 当然如果你的页面使用了struts2提供的表单标签.表单标签会自动显示字段的错误信息
xml配置方式校验(了解)
使用XML配置方式是先把常用的校验规则写好,然后在XML配置中指定要使用的校验规则。当然Struts2已经帮我们写好了很多的校验规则。我们只需要指在XML文档中配置当前的请求处理方法需要哪些校验规则。
校验要求
要使用XML配置方式校验,你的Action类必须实现Validateable接口。ActionSupport类已经实现了Validateable接口,所以我们通常是直接继承ActionSupport类。
为属性提供getXXX()和setXXX()方法!代码校验是在Action本类中来完成校验,这说明我们可以直接使用本类的private属性,但如果使用XML配置方式校验,这需要使用校验框架的代码来完成校验工作,那么校验框架需要调用Action的getXXX()方法来获取被校验的属性,所以一定要为被校验的属性提供getXXX()方法。
校验文件的创建
- 校验文件的命名必须为:ActionName-validation.xml。例如LoginAction的校验文件命名为:LoginAction-validation.xml。
- 校验文件的路径:必须与Action在同包下。
- 校验文件的DTD:在xwork-core-x.x.x.jar中找到xwork-validator-x.x.x.dtd,打开它,内部会有一段DTD,我们把它copy过来,放到我们的校验文件中。校验文件的元素结果如下:
1 |
|
struts2提供的校验规则(即上文提到的default.xml):
1 |
|
上面文件中每个<validator>
元素都是一个校验规则,校验规则对应一些已经写好的方法,他们有校验属性非空的规则,有校验字符串属性长度的规则,有校验int属性范围的规则等等。通常我们不需要自己来编写校验规范,因为上面的校验规则已经足够了。
每个规则都有自己的名字,校验文件中<field-validator>
的type就是用来指定校验规则的名称。例如下面的代码是对username属性的非空校验:
1 | <validators> |
常用的校验规则
1 | required:当属性为null时校验失败; |
校验进阶
跳过指定的校验方法
如果想跳过某个Action方法的校验,在不需要校验的Action方法上加入@SkipValidation
我们都知道,一个Action中可以存在多个请求处理方法,不同的请求处理方法应该有不同的校验逻辑,所以我们应该为每个请求处理方法提供自己独有的校验方法。而validate()方法是所有请求处理方法公共的校验方法。
指定校验某个方法
- public的,没有返回值,没有参数(public void xxx());
- 方法名称前缀为validate(public void validateXxx());
- 方法名后缀必须与请求处理方法名相同,例如请求处理方法为login(),那么它的私有校验方法为:public validateLogin()。
注意,私有校验方法会在公共校验方法(validate())之前被调用。如果你要为execute()提供私有校验方法,那么这个方法名为validateExecute()。
1 | public class Demo2Action extends ActionSupport { |
拦截器
struts提供拦截器,对action类进行增强的。struts已经实现多个拦截器,完成不同的功能。
例如:文件上传、数据校验、类型转换、参数封装等
默认拦截器栈
struts-default.xml提供struts所有拦截器,也提供默认拦截器栈
<default-interceptor-ref name="defaultStack"/>
所有的action默认使用那个拦截器栈`<interceptor-stack name="defaultStack"> `声明一个拦截器栈,名称为“defaultStack”,通常称为:默认拦截器栈
1 | <interceptor-stack name="defaultStack"> |
关于workflow拦截器的补充:
1 | //方法2:实现ValidationWorkflowAware接口 |
自定义拦截器
实现接口:com.opensymphony.xwork2.interceptor.Interceptor
1
2
3
4
5
6
7
8
9//初始化方法
public void init() { }
//拦截方法
public abstract String intercept(ActionInvocation invocation) throws Exception{
invocation.getAction() 获得当前action类实例
invacation.invoke() 放行
}
//销毁方法
public void destroy() { }继承父类:com.opensymphony.xwork2.interceptor.MethodFilterInterceptor
在使用自定义拦截器,可以对指定的方法进行操作(哪些方法不拦截,哪些必须拦截)
设置属性includeMethods,确定哪些方法进行拦截
设置属性excludeMethods,确定哪些方法不进行拦截<default-interceptor-ref name="xxx">
将指定的拦截器,声明成默认的。
注意:如果使用自定义xxx,“defaultStack”将被覆盖。
注意:拦截器只拦截action类,不拦截jsp文件。
使用拦截器进行表单参数校验
校验流程:
Validation拦截器负责判断Action是否实现Validateable接口.如果实现就调用validate方法.
workflow拦截器判断Action是否实现ValidationAware接口. 如果实现就会判断Action中是否包含错误信息.如果包含错误信息, 停止拦截器递归调用,返回结果到名为input的结果页面中.编程式校验
实现Validateable接口.接口中只有一个方法validate方法.我们可以在该方法中添加错误信息.
添加错误信息需要实现ValidationAware接口.该接口中有一些判断是否含有错误消息.获得错误消息.添加错误消息的方法.
拦截器的注册
注册拦截器一共分为两步:
- 在package中声明拦截器
- 在action中引用拦截器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26<package name="s8" namespace="/" extends="struts-default">
<interceptors>
<!--
在<aciton>元素中引用拦截器的顺序决定了拦截器的执行顺序,
例中会先执行defaultStack中的所有拦截器,再执行MyInterceptor拦截器
-->
<interceptor name="MyInterceptor" class="cn.itcast.interceptor.MyInterceptor" />
<interceptor-stack name="myStack">
<interceptor-ref name="defaultStack" />
<!--
struts2中,一旦为Action指定了拦截器,那么就不会再为这个Action执行默认拦截器了
以我们需要在这个<action>元素中再引用defaultStack拦截器栈。
-->
<interceptor-ref name="MyInterceptor" />
</interceptor-stack>
</interceptors>
<default-interceptor-ref name="myStack" />
<action name="LoginAction">
<result>/index.jsp</result>
<result name="input">/login.jsp</result>
<!--若没有将创建的拦截器指定为默认拦截器,需要加入以下语句:
<interceptor-ref name="defaultStack" />
<interceptor-ref name="MyInterceptor" />
-->
</action>
</package>
OGNL与struts标签
#未完待续