1、使用Filter做为控制器
1.1 好处
使用一个过滤器作为控制器,可以方便的在应用程序中对所有资源进行访问
1.2 Servlet VS Filter
Servlet可以做的Filter都可以完成
Filter可以拦截资源
Filter中含有FilterChain
2、Struts2概述(WebWork)
2.1 概述
- Struts2 是一个用来开发MVC应用程序的框架,它提供了Web应用程序开发过程中的一些常见问题的解决方案
- 如下方案:
对来自用户的输入数据进行合法性验证
统一的布局
可扩展性
国际化和本地化
支持Ajax
表单的重复提交
文件的上传和下载
2.2 特点
Strtus2使用一个过滤器作为控制器
Struts2的Html表单将被直接映射到一个 POJO
Struts2的验证逻辑编写在Action中
Struts2中的任何一个POJO都可以是一个Action类
Struts2在页面中使用OGNL来显示各种对象模型,可以不再使用EL和JSTL
2.3 mac环境下idea中的struts2项目搭建
- 创建普通的maven环境下web-app项目
- 引入jar包
<dependency>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-core</artifactId>
<version>2.5.22</version>
</dependency>
- 在web.xml中配置struts2
<display-name>Archetype Created Web Application</display-name>
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/'*'</url-pattern>
</filter-mapping>
- 在当前web应用下添加struts2的配置文件
<struts>
<package name="helloWorld" extends="struts-default" namespace="/">
<!--
配置一个action,一个struts2的请求就是一个action
-->
<action name="project-input">
<result>/WEB-INF/error/input.jsp</result>
</action>
<action name="error" class="CpuInfo" method="save">
<result name="error">/WEB-INF/error/error.jsp</result>
</action>
</package>
</struts>
- 页面内容
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<base href="http://localhost:8080/">
</head>
<body>
<h2>FilterAsControl-index</h2>
<a href="project-input.action" >project-input</a>
</body>
</html>
- 目录结果
- 此时会遇到以下问题
- 解决方法
可参照次链接解决以上问题!!!
- 成功显示
2.4 Struts2中可以应答哪些请求
- 默认的配置文件中
以.action结尾或者空结尾
- 在struts.xml中可以在package前配置constant
<constant name="struts.action.extension" value="action,do,"></constant>
3、Struts2详解
3.1 在Action中访问web资源
- 什么是web资源?
HttpServletRequest,HttpSession,ServletContext等原生的Servlet API
- 如何访问
(1)和Servlet API解耦的方式:只能访问有限的Servlet API对象,且只能访问其有限的方法(读取请求的参数,读取域对象的属性,使session失效)
使用 ActionContext
实现XxxAware接口
(2)和Servlet API耦合的方式:可以访问更多的Servlet API对象,且可以调用其原生的方法
使用ServletActionContext
实现ServletXxxAware接口
- 使用ActionContext访问web资源
/**
* java 代码
*/
public class ActionContextTest {
public String execute(){
// 1. 获取ActionContext
ActionContext actionContext = ActionContext.getContext();
// 2. 获取Application对应的map,并向其添加一个属性
Map<String ,Object> mapApplication = actionContext.getApplication();
// 设置属性
mapApplication.put("applicationKey", "applicationKeyValue");
// 获取属性
Object date = mapApplication.get("date");
// System.out.println("获取属性 date: " + new SimpleDateFormat("yyyy-MM-dd HH-mm-ss").format((Date) date));
System.out.println("获取属性 date: " + date);
// 3. session
Map<String ,Object> mapSession = actionContext.getSession();
// 4. request
Map<String ,Object> mapRequest = (Map<String ,Object>)actionContext.get("request");
// 5. 获取请求参数所对应的map,并获取指定的参数值
HttpParameters mapParam = actionContext.getParameters();
System.out.println(mapParam.get("name"));
return "success";
}
}
/**
* jsp 页面
*/
<body>
<h2>StrutsHelloWorld-actionContext</h2>
applicationKey : ${applicationScope.applicationKey}
<%
if (application.getAttribute("date") == null)
application.setAttribute("date" ,new Date());
%>
</body>
- 实现XxxAware接口访问web资源
/**
* java代码
*/
public class AwareActionTest implements ApplicationAware, RequestAware, SessionAware, ParameterAware {
public String execute(){
// 1. application
application.put("applicationKey","applicationKeyValue");
System.out.println(application.get("date"));
// 2. session
session.put("sessionKey","sessionKeyValue");
// 3. request
request.put("requestKey", "requestKeyValue");
// 4. param 只读不能写
param.put("paramKey", new String[]{"pa1", "pa2"});
System.out.println("name : " + param.get("name")[0]);
System.out.println("age : " + param.get("age")[0]);
return "success";
}
private Map<String, Object> application;
private Map<String, String[]> param;
private Map<String, Object> request;
private Map<String, Object> session;
@Override
public void setApplication(Map<String, Object> application) {
this.application = application;
}
@Override
public void setParameters(Map<String, String[]> param) {
this.param = param;
}
@Override
public void setRequest(Map<String, Object> request) {
this.request = request;
}
@Override
public void setSession(Map<String, Object> session) {
this.session = session;
}
}
/**
* jsp页面
*/
<body>
<h2>StrutsHelloWorld-awareAction</h2>
applicationKey : ${applicationScope.applicationKey}
<hr />
<%
if (application.getAttribute("date") == null)
application.setAttribute("date" ,new Date());
%>
sessionKey : ${ sessionScope.sessionKey }
<hr />
requestKey : ${ requestScope.requestKey }
<hr />
paramKey : ${ paramValues.paramKey }
</body>
- 使用ServletActionContext和实现ServletXxxAware接口访问web资源
/**
* 使用ServletActionContext
*/
public class ServletActionContextTest {
public String execute(){
HttpServletRequest request = ServletActionContext.getRequest();
HttpSession session = request.getSession();
ServletContext servletContext = ServletActionContext.getServletContext();
System.out.println(session.getAttribute("date"));
System.out.println("execute ---- ");
return "success";
}
}
/**
* 实现ServletXxxAware接口
*/
public class ServletActionAwareTest implements ServletRequestAware , ServletContextAware, ServletResponseAware {
public String execute(){
return "success";
}
@Override
public void setServletRequest(HttpServletRequest httpServletRequest) {
System.out.println("httpServletRequest --- ");
}
@Override
public void setServletResponse(HttpServletResponse httpServletResponse) {
System.out.println("httpServletResponse --- ");
}
@Override
public void setServletContext(ServletContext servletContext) {
System.out.println("servletContext --- ");
}
}
3.2 ActionSupport(默认的Action类)
- 在struts.xml中没有配置 类时,默认为ActionSupport类
<action name="testActionSupport">
<result>/WEB-INF/error/testActionSupport.jsp</result>
</action>
- 在手工完成字段验证,显示错误消息,国际化等的情况下,推荐继承ActionSupport
3.3 result
- result概述
(1)action的字节点
(2)代表action方法执行后,可能要去的一个目的地
(3)一个action节点可以配置多个result子节点
(4)result的name属性值对应着action方法可能有的一个返回值
(5)result的type表示结果的响应类型
- result的type属性
其属性值在struts-default包的result-types节点的name属性中定义
(1)dispatcher
(2)redirect
(3)redirectAction:重定向到一个action
(4)chain:转发到一个Action
<action name="testResult" class="project3.TestResult">
<result name="fail">/WEB-INF/testResult/fail.jsp</result>
<result name="login">/WEB-INF/testResult/login.jsp</result>
<result name="error">/WEB-INF/testResult/error.jsp</result>
<!-- <result name="success" type="redirectAction">-->
<!-- <param name="actionName">testAction</param>-->
<!-- <param name="namespace">/atguigu</param>-->
<!-- </result>-->
<result type="redirect" name="success" >/atguigu/testAction.do</result>
</action>
</package>
<package name="testPackage" namespace="/atguigu" extends="struts-default">
<action name="testAction" class="project3.TestAction">
<result>/WEB-INF/testResult/success.jsp</result>
</action>
</package>
3.4 通配符映射
- 什么是通配符映射
一个web应用可能有成百上千个action声明,可以利用struts提供的 通配符映射机制 把多个彼此相似的映射关系简化为一个映射关系
若找不到多个匹配,没有通配符的那个将胜出
- 使用通配符映射
<action name="userAction-*" class="project3.UserAction" method="{1}">
<result name="{1}-success">/WEB-INF/testResult/success.jsp</result>
</action>
- 出现无法匹配的问题:
在struts2.5中为了限制通配符方法的使用,增加了strict-method-invocation属性。struts2.3及之前的版本没有设置,所以可以直接调用。而struts2.5中strict-method-invocation属性值默认为true,故出现了无法映射的问题。
- 解决方案
在使用了通配符的package上添加strict-method-invocation="false"属性
3.5 动态方法调用
- 用途
通过url动态调用Action中的方法
- 使用 动态方法调用 前
<action name="user-action-success" class="project3.UserAction" method="success">
<result name="success-success">/WEB-INF/testResult/success.jsp</result>
</action>
- 使用 动态方法调用 后
<action name="autoAction" class="project3.UserAction2">
<result>/WEB-INF/testResult/success.jsp</result>
</action>
- 使用步骤:
(1)打开允许动态方法调用的开关
<constant name="struts.enable.DynamicMethodInvocation" value="true" />
(2)写代码
<action name="autoAction" class="project3.UserAction2" method="success">
<result>/WEB-INF/testResult/success.jsp</result>
</action>
http://localhost:8080/autoAction!error.do?num=4
- 不推荐使用
4、 OGNL
4.1 OGNL的作用
在jsp页面上可以利用OGNL(对象-图导航语言)访问到值栈里的对象属性
若希望访问值栈中ContextMap中的数据,需要给OGNl表达式加上一个前缀字符#,如果没有前缀字符#,索引将在ObjectStack里进行
4.2 值栈
- valueStack
(1)ObjectStack:将action和相关对象压入ObjectStack中
(2)ContextStack:把各种个样的映射关系压入,实际上就是对ActionContext的操作(request、session…)
4.3 property
Struts2利用s:property标签和OGNL表达式来读取值栈中的属性值
(1)对象栈:对象栈中的某一个对象的属性值
(2)Map栈:request,session,application的一个属性值或一个 请求参数的值
4.4 读取对象栈中的属性
- 读取方式
object.propertyName
[0].propertyName:从第几个栈顶对象开始搜索
propertyName:若从栈顶开始搜索,则可以省略下标部分
- 实现方式
username : <input type="text" name="username" value="${username}"><br />
username : <s:property value="username" /> <br />
username : <s:property value="[0].username" /> <br />
username : <s:property value="[1].username" /> <br />
public class CpuInfo {
private String username;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
@Override
public String toString() {
return "project2.CpuInfo{" +
"username='" + username + '\'' +
'}';
}
public String save(){
// 获取值栈
ValueStack valueStack = ActionContext.getContext().getValueStack();
OgnlTest ognlTest = new OgnlTest();
ognlTest.setUsername("里斯");
// 压入值栈的栈顶
valueStack.push(ognlTest);
System.out.println("save : " + this);
return "error";
}
}
public class OgnlTest {
private String username;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
}
输出结果
4.5 读取Map栈中的值
- 读取方式:
#object.propertyName
#object.property.propertyName
- 读取顺序
request、session、application
- 实现方式
<%
String [] name = new String[] {"aa","bb","cc"};
request.setAttribute("name", name);
%>
name[1]:<s:property value="#request.name[1]" /> <br />
4.6. OGNL调用字段和方法
- 调用
任何一个Java类中的静态字段或者方法
被压入到ValueStack栈的对象上的公共字段和方法
- 调用一个Java类中的静态字段或者方法
(1)调用静态方法时要打开开关
<constant name="struts.ognl.allowStaticMethodAccess" value="true" />
- 调用方法
<%--使用OGNL调用 静态字段和方法--%>
<s:property value="@java.lang.Math@PI" /><br />
<s:property value="@java.lang.Math@cos(0)" /><br />
4.7 OGNL访问数组类型的属性(attr)
<%
String [] name = new String[] {"aa","bb","cc"};
request.setAttribute("name", name);
%>
name[1]:<s:property value="#request.name[1]" /> <br />
length:<s:property value="#attr.name.length" /><br />
name[2]:<s:property value="#attr.name[2]" /><br />
4.8 OGNL访问List类型属性的值
与数组类型相似
4.9 OGNL访问Map类型属性的值
5、Struts2声明式的异常处理
5.1 exception-mapping元素
配置当前action的声明式异常
<exception-mapping exception="java.lang.ArithmeticException" result="input" />
<%@ taglib prefix="s" uri="/struts-tags" %>
<s:debug ></s:debug>
5.2 实现方式
public class CpuInfo {
private String username;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
@Override
public String toString() {
return "project2.CpuInfo{" +
"username='" + username + '\'' +
'}';
}
public String save(){
int i = 10/ 0; // 异常信息
// 获取值栈
ValueStack valueStack = ActionContext.getContext().getValueStack();
OgnlTest ognlTest = new OgnlTest();
ognlTest.setUsername("里斯");
// 压入值栈的栈顶
valueStack.push(ognlTest);
System.out.println("save : " + this);
return "error";
}
}
<action name="error" class="project2.CpuInfo" method="save">
<exception-mapping exception="java.lang.ArithmeticException" result="input" />
<result name="input">/WEB-INF/error/input.jsp</result>
<result name="error">/WEB-INF/error/error.jsp</result>
</action>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
<base href="http://localhost:8080/">
</head>
<body>
<h2>StrutsHelloWorld-input</h2>
<br />
s:debug:<s:debug ></s:debug><br />
s:exceptionStack:<s:property value="exceptionStack" />
s:exception:<s:property value="exception" />
<br />
<form method="post" action="error.action">
username : <input type="text" name="username"><br />
<input type="submit" value="提交-error">
</form>
</body>
</html>
5.3 全局的Exception捕获配置
<package name="helloWorld" extends="struts-default" namespace="/" strict-method-invocation="false">
<global-results>
<result name="input">/WEB-INF/error/input.jsp</result>
</global-results>
<global-exception-mappings>
<exception-mapping exception="java.lang.ArithmeticException" result="input" />
</global-exception-mappings>
</package>
6、通用标签
6.1 property标签
用来输出一个值栈属性的值
6.2 url标签
用来动态的创建一个url
<s:url value="/urlValue" var="url" >
<s:param value="1001" name=" urlValueName" />
</s:url>
${ url }<br />
<s:url value="/urlValue" var="url1" >
<%-- 对于value值会自动进行OGNL解析 若不希望进行解析,则需要用单引号--%>
<s:param value="urlValueName" name=" urlValueName" />
</s:url>
${ url1 } <br />
<s:url value="/urlValue2" var="url2" >
<%-- 对于value值会自动进行OGNL解析 若不希望进行解析,则需要用单引号--%>
<s:param value="'abcdd'" name=" urlValueName" />
</s:url>
${ url2 }<br />
<s:url var="url3" namespace="/testtest" method="save" action="actionTest" />
${ url3 }
输出结果:
/urlValue?+urlValueName=1001
/urlValue?+urlValueName=
/urlValue2?+urlValueName=abcdd
/testtest/actionTest!save.action
6.3 set标签
- 作用
ValueStack值栈中的ContextMap值栈
Map类型的session对象
Map类型的application对象
Map类型的request对象
Map类型的page对象
- 用法
<s:set name ="sessionname" scope="session" value="test" /><br />
sessionScope.session : ${sessionScope.sessionname}
6.4 push标签
- 作用:
push标签的功能和set标签类似
push标签将把一个对象压入valueStack而不是压入ContextMap
push标签起始时把一个对象压入栈,标签结束时,将对象弹出栈
- 实现:
<%
CpuInfo cpuInfo = new CpuInfo();
cpuInfo.setUsername("lisa");
request.setAttribute("cpuInfo", cpuInfo);
%>
<s:push value="#request.cpuInfo">
username : ${username}
</s:push>
输出内容:
username : lisa
6.5 if、else、elseif标签
- 作用
用于进行条件测试
- 实现
<%
int num = 100;
session.setAttribute("num", num);
%>
<s:if test="#session.num = 100">
等于100
</s:if>
<s:elseif test="#session.num < 100">
小于100
</s:elseif>
输出结果
lisa 等于100
6.6 Iterator标签
- 作用:
iterator标签可以用来遍历一个数组、collection、map
并把这个可遍历对象中的每一个元素一次压入或者弹出ValueStack栈
- 实现:
<s:iterator value="#session.persons" >
${name} - > ${age}
</s:iterator>
6.7 Sort标签
- 作用:
对一个可遍历对象里的元素进行排序
- 实现:
<%
List<CpuInfo> persons = new ArrayList<CpuInfo>();
CpuInfo cpuInfo1 = new CpuInfo();
cpuInfo1.setUsername("sss");
persons.add(cpuInfo1);
CpuInfo cpuInfo2 = new CpuInfo();
cpuInfo2.setUsername("aaa");
persons.add(cpuInfo2);
CpuInfo cpuInfo3 = new CpuInfo();
cpuInfo3.setUsername("mmm");
persons.add(cpuInfo3);
CpuInfo cpuInfo4 = new CpuInfo();
cpuInfo4.setUsername("222");
persons.add(cpuInfo4);
request.setAttribute("cpuInfo1", persons);
Comparator comparator = new ComparatorTest();
request.setAttribute("comparator", comparator);
%>
<s:sort comparator="#request.comparator" source="#request.cpuInfo1" var="cpuInfo" />
<s:iterator value="#attr.cpuInfo">
username : ${username}
</s:iterator>
public class ComparatorTest implements Comparator<CpuInfo> {
@Override
public int compare(CpuInfo o1, CpuInfo o2) {
return o1.getUsername().compareTo(o2.getUsername());
}
}
6.8 date标签
- 作用:
对date进行排版
- 实现:
<s:date name="#session.date" format="yyyy-MM-dd" var="date2" />
${date2}
6.9 a标签
- 作用:
a标签将呈现一个HTML链接
6.10 表单标签
- 概念
表单标签将在HTML文档里被呈现为一个表单元素
- 优点
表单回显
对页面进行布局和排版
- 赋值
标签的属性可以背赋值为一个静态的值或一个OGNL表达式
使用OGNL表达式并把它用%{}括起来,这个表达式将会被求值
- 实现
<body>
<h2>StrutsHelloWorld-form</h2>
<s:form action="save.action" >
<s:hidden name="id" />
<s:textfield name="username" label="username" />
<s:password name="password" label="password" />
<s:textarea name="desc" label="desc" />
<s:submit />
</s:form>
</body>
- 特点
使用和HTML的form的标签差不多
Struts2的form标签会生成一个table,以进行自动的排版
可以对表单提交的值进行回显
- 其他标签
checkbox复选框
radio、select、checkboxlist等标签(list,listKey,listValue)
select
optiongroup
checkboxlist
- 主题
- 概述
为了让所有的UI标签能够产生同样的视觉效果而归集到一起的一组模版,即风格相近的模版被打包为一个主题
- 包含主题
- simple
- xhtml
- css
- ajax
- 使用方式
- 利用标签theme属性添加
<s:hidden name="id" theme="simple" />
- 域标签添加
<%
request.setAttribute("theme" , "simple");
%>
- struts.xml中全局修改
<constant name="struts.ui.theme" value="simple" />
7、Struts2的运行流程
7.1 ActionProxy
是Action的一个代理类,也就是说Action的调用就是通过ActionProxy实现的,其实就是调用了ActionProxy.execute()方法,而该方法又调用了ActionInvocation.invoke()方法
7.2 ActionInvocation
是Action的调用者,其在Action的执行过程中,负责Interceptor、action和Result等一系列元素的调度
7.3 params拦截器
Parameters拦截器将把表单字段映射到ValueStack栈的栈顶对象的各个属性中。如果某个字段在模型里没有匹配的属性,Param拦截器将尝试ValueStack栈中的下个对象
7.4 ModelDriven
- 概述
如果Action类ModelDriven接口,该拦截器将把ModelDriven接口的getModel()方法返回的对象置于栈顶
- 实现
- 实现接口ModelDriven
- 重写接口的方法:getModel(){}
@Override
public Employee getModel(){
employee = new Employee();
return employee;
}
- 运行流程
- (1)ModelDrivenInterceptor - > intercept
public String intercept(ActionInvocation invocation) throws Exception {
// 获取Action对象- Employee
Object action = invocation.getAction();
// 判断是否为ModelDriven的实例
if (action instanceof ModelDriven) {
// 强转
ModelDriven modelDriven = (ModelDriven)action;
// 获取值栈
ValueStack stack = invocation.getStack();
// 调用EmployeeAction中实现的 getModel() 方法
Object model = modelDriven.getModel();
if (model != null) {
// 将getModel()的返回值赋值
stack.push(model);
}
if (this.refreshModelBeforeResult) {
invocation.addPreResultListener(new ModelDrivenInterceptor.RefreshModelBeforeResult(modelDriven, model));
}
}
return invocation.invoke();
}
- (2)ParametersInterceptor - > intercept(把请求的参数赋值给栈顶对象对应的属性,若栈顶对象没有对应的属性,则查询值栈中下一个对象对应的属性。)
- (3)注意
@Override
public Employee getModel(){
employee = new Employee();
return employee;
}
/**
* 不可以用此方法实现
*/
@Override
public Employee getModel(){
return new Employee();
}
7.5 paramsPrepareParamsStack拦截器
- 实现
<package name="testPackage" namespace="/atguigu" extends="struts-default">
<default-interceptor-ref name="paramsPrepareParamsStack" />
<action name="testAction" class="project3.TestAction">
<result>/WEB-INF/testResult/success.jsp</result>
</action>
</package>
- 流程
params -> modelDriven -> params
7.6 Preparable拦截器
- 概述
Struts2.0中的modelDriven拦截器负责把Action类以外的一个对象压入到值栈栈顶
而prepare拦截器负责准备为getModel()方法准备model
8、类型转换
8.1 概述
从一个HTML表单到一个Action对象,类型转换是从字符串到非字符串
在Struts2中,把请求参数映射到action属性的工作由Parameters拦截器负责,他是默认的defaultStack拦截器中的一员。parameters拦截器可以自动完成字符串和基本数据类型之间的转换
8.2 类型转换错误
- 如果类型转换失败:
- 若Action类没有实现ValidationAware接口:Struts在遇到类型转换错误时仍会继续调用Action方法
- 若实现了ValidationAware接口,Struts在遇到类型转换错误时将不会继续调用其Action方法(抛异常)
- 实现ValidationAware接口,定制输出内容
- 在同一文件夹下 创建 ActionClassName.properties文件
- 添加键值对:invalid.fieldvalue.fieldName=xxx
- 在simple主题下的显示
- (1)在值栈中有fieldErrors字段,显示错误属性
${fieldErrors.age[0]}
- (2)使用标签显示
<s:fielderror fieldName="fieldname" />
8.3 定制类型转换
- 概述
- 为什么使用自定义类型的转换器?
因为Struts不能自动完成字符串到引用类型的转换
- 实现
- (1)必须实现ognl.TypeConverter接口,对于这个接口的某种具体实现做扩展
- (2)StrutsTypeConverter类
- (3)配置类型转换器
基于字段的配置:在字段所在的Model(可能是Action,可能是一个JavaBean)的包下,新建一个ModelClassName-conversion.properts
在该文件中输入键值对:fieldName=类型转换器的全类名
第一次使用该类型转换器时,创建该实例
类型转换器是单实例的
在src下新建xwork-conversion.properties,键入带转换的类型=类型转换的全类名
在当前Struts2应用被加载时创建实例
- 类型转换与复杂属性配合使用
- Struts2表单标签的name值可以被赋值为属性的属性:name = mgr.name
- 属性的属性也可以使用基于类型的转换器
- 类型转换与集合配合使用
9、Struts国际化
9.1 概述:
- 国际化:把在无需修改源代码即可让开发出来的应用程序能够支持多种语言和数据格式称为国际化
- 本地化:指让一个具备国际化支持的应用程序支持某个特定的地区
- Struts2国际化是建立在Java国际化基础上的
- Struts2国际化是建立在Java国际化基础之上的:
为不同国家/语言提供对应的消息资源文件
9.2 配置国际化资源文件
9.3 使用超链接实现动态加载国际化资源文件
10、Struts2的运行流程
11、Struts2的输入验证
11.1 概述
- 一个健壮的web应用程序必须确保用户输入是合法的、有效的。
- 两种验证方式:
- 基于XWork Validation Framework的声明式验证(其中有内建的验证程序,使用这些验证程序不需要变成,只要在一个XML中对验证程序应该如何工作作出声明即可)
- 编程式验证:通过编写代码来验证用户输入
11.2 基于XWork Validation Framework的声明式验证
-
哪些字段需要验证
-
使用什么验证规则
-
如果验证失败需要吧什么样的错误信息发送到浏览器端
-
配置验证规则
-
注意:
- 如果使用的是非simple主题,则自动显示错误信息
- 如果使用的是simple主题,则需要自己打印
/**
* 第一种方式
*/
<s:fielderror fieldName="age" />
/**
* 第二种方式 el表达式(OGNL)
*/
${fieldErrors.age[0]}
/**
* 第三种方式 国际化
*/
- 若一个Action可以应答多个Action请求,多个Action使用不同的验证规则,则需要使用别名
11.3 声明式验证的原理
- Struts2默认的拦截器中提供了一个validation拦截器
- 每个具体的验证规则都会对应具体的一个验证器,有一个配置文件将验证规则名称和验证器联系在一起,而实际上验证的是那个验证器
11.4 Struts2 的内建验证程序
- 设置短路验证