Interceptor (拦截器):起到拦截客户端对 Action 请求的做用。html
编写一个类实现 Interceptor 接口或继承 AbstractInterceptor 类。java
package com.zze.interceptor; import com.opensymphony.xwork2.ActionInvocation; import com.opensymphony.xwork2.interceptor.Interceptor; public class Test1Interceptor implements Interceptor { @Override public void destroy() { System.out.println("from Test1Interceptor.destroy"); } @Override public void init() { System.out.println("from Test1Interceptor.init"); } @Override public String intercept(ActionInvocation invocation) throws Exception { System.out.println("from Test1Interceptor.intercept"); return invocation.invoke(); } }
package com.zze.interceptor; import com.opensymphony.xwork2.ActionInvocation; import com.opensymphony.xwork2.interceptor.AbstractInterceptor; public class Test2Interceptor extends AbstractInterceptor { @Override public String intercept(ActionInvocation invocation) throws Exception { System.out.println("Test2Interceptor.intercept"); return invocation.invoke(); } }
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN" "http://struts.apache.org/dtds/struts-2.3.dtd"> <struts> <constant name="struts.devMode" value="true"/> <package name="test" extends="struts-default" namespace="/"> <!--定义拦截器--> <interceptors> <interceptor name="interceptor1" class="com.zze.interceptor.Test1Interceptor"/> <interceptor name="interceptor2" class="com.zze.interceptor.Test2Interceptor"/> </interceptors> <action name="*" class="com.zze.action.{1}Action"> <result>/index.jsp</result> <!--引入拦截器--> <interceptor-ref name="defaultStack"/> <interceptor-ref name="interceptor1"/> <interceptor-ref name="interceptor2"/> </action> </package> </struts>
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN" "http://struts.apache.org/dtds/struts-2.3.dtd"> <struts> <constant name="struts.devMode" value="true"/> <package name="test" extends="struts-default" namespace="/"> <!--定义拦截器--> <interceptors> <interceptor name="interceptor1" class="com.zze.interceptor.Test1Interceptor"/> <interceptor name="interceptor2" class="com.zze.interceptor.Test2Interceptor"/> <!--定义拦截器栈--> <interceptor-stack name="myStack"> <interceptor-ref name="defaultStack"/> <interceptor-ref name="interceptor1"/> <interceptor-ref name="interceptor2"/> </interceptor-stack> </interceptors> <action name="*" class="com.zze.action.{1}Action"> <result>/index.jsp</result> <!--引入拦截器栈--> <interceptor-ref name="myStack"/> </action> </package> </struts>
Struts2 还为咱们提供了一些功能加强的过滤器,咱们只须要继承它简单配置便可,例如:web
package com.zze.interceptor; import com.opensymphony.xwork2.ActionInvocation; import com.opensymphony.xwork2.interceptor.MethodFilterInterceptor; /** * MethodFilterInterceptor 可让咱们很简单的控制要拦截的方法和不需拦截的方法 */ public class TestInterceptor extends MethodFilterInterceptor { @Override protected String doIntercept(ActionInvocation invocation) throws Exception { System.out.println("from TestInterceptor.doIntercept"); return invocation.invoke(); } }
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN" "http://struts.apache.org/dtds/struts-2.3.dtd"> <struts> <constant name="struts.devMode" value="true"/> <package name="test" extends="struts-default" namespace="/"> <!--定义拦截器--> <interceptors> <interceptor name="methodInterceptor" class="com.zze.interceptor.TestInterceptor"/> </interceptors> <action name="*_*" class="com.zze.action.{1}Action" method="{2}"> <result>/index.jsp</result> <interceptor-ref name="methodInterceptor"> <!--配置不拦截的方法名--> <param name="excludeMethods">login,index</param> <!--配置要拦截的方法名--> <param name="includeMethods">home,list</param> </interceptor-ref> </action> </package> </struts>
依旧是从核心过滤器的 doFilter 方法开始:ajax
1 public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { 2 3 HttpServletRequest request = (HttpServletRequest) req; 4 HttpServletResponse response = (HttpServletResponse) res; 5 6 try { 7 // 判断当前请求 URL 是否在不处理范围内 8 if (excludedPatterns != null && prepare.isUrlExcluded(request, excludedPatterns)) { 9 chain.doFilter(request, response); 10 } else { 11 // 设置编码,默认 request.setCharacterEncoding("UTF-8") 12 prepare.setEncodingAndLocale(request, response); 13 // 建立 Action 及建立 ValueStack 值栈 14 prepare.createActionContext(request, response); 15 // 将本次请求相关配置绑定到当前线程 ThreadLocal 16 prepare.assignDispatcherToThread(); 17 // 包装原生 request ,对其进行加强 18 request = prepare.wrapRequest(request); 19 // 找到这次请求对应配置文件 struts.xml 中的映射相关信息,封装到 ActionMapping 实例 20 ActionMapping mapping = prepare.findActionMapping(request, response, true); 21 if (mapping == null) { // 未找到映射信息 22 // 查看这次请求目标是不是静态资源 23 boolean handled = execute.executeStaticResourceRequest(request, response); 24 if (!handled) { 25 chain.doFilter(request, response); 26 } 27 } else {// 找到了映射信息 28 // 执行拦截器及 Action 29 execute.executeAction(request, response, mapping); 30 } 31 } 32 } finally { 33 // 清理请求信息 34 prepare.cleanupRequest(request); 35 } 36 }
进到 29 行的 execute.executeAction 方法:正则表达式
1 public void executeAction(HttpServletRequest request, HttpServletResponse response, ActionMapping mapping) throws ServletException { 2 dispatcher.serviceAction(request, response, mapping); 3 }
继续进到 dispatcher.serviceAction 方法:express
1 public void serviceAction(HttpServletRequest request, HttpServletResponse response, ActionMapping mapping) 2 throws ServletException { 3 4 Map<String, Object> extraContext = createContextMap(request, response, mapping); 5 // 从 request 中获取值栈 6 ValueStack stack = (ValueStack) request.getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY); 7 boolean nullStack = stack == null; 8 if (nullStack) { 9 // 若是从 request 中未获取到值栈,则从 ActionContext 中取出值栈赋值给 stack 10 ActionContext ctx = ActionContext.getContext(); 11 if (ctx != null) { 12 stack = ctx.getValueStack(); 13 } 14 } 15 if (stack != null) { 16 extraContext.put(ActionContext.VALUE_STACK, valueStackFactory.createValueStack(stack)); 17 } 18 19 String timerKey = "Handling request from Dispatcher"; 20 try { 21 UtilTimerStack.push(timerKey); 22 String namespace = mapping.getNamespace(); 23 String name = mapping.getName(); 24 String method = mapping.getMethod(); 25 // 建立 Action 代理对象 26 ActionProxy proxy = getContainer().getInstance(ActionProxyFactory.class).createActionProxy( 27 namespace, name, method, extraContext, true, false); 28 // 将值栈放入 request 29 request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, proxy.getInvocation().getStack()); 30 if (mapping.getResult() != null) { 31 Result result = mapping.getResult(); 32 result.execute(proxy.getInvocation()); 33 } else { 34 // Action 代理开始执行过滤器和 Action 35 proxy.execute(); 36 } 37 38 if (!nullStack) { 39 // 将已存在的值栈放入 Request 40 request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, stack); 41 } 42 } catch (ConfigurationException e) { 43 logConfigurationException(request, e); 44 sendError(request, response, HttpServletResponse.SC_NOT_FOUND, e); 45 } catch (Exception e) { 46 if (handleException || devMode) { 47 sendError(request, response, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e); 48 } else { 49 throw new ServletException(e); 50 } 51 } finally { 52 UtilTimerStack.pop(timerKey); 53 } 54 }
Action 及过滤器的执行在 34 行,查看 proxy.execute 方法:apache
1 public String execute() throws Exception { 2 ActionContext previous = ActionContext.getContext(); 3 ActionContext.setContext(invocation.getInvocationContext()); 4 try { 5 return invocation.invoke(); 6 } finally { 7 if (cleanupContext) 8 ActionContext.setContext(previous); 9 } 10 }
在这里又执行 invocation.invoke 方法:浏览器
1 public String invoke() throws Exception { 2 String profileKey = "invoke: "; 3 try { 4 UtilTimerStack.push(profileKey); 5 6 if (executed) { 7 throw new IllegalStateException("Action has already executed"); 8 } 9 // interceptors 是一个 Iterator (迭代器)对象,存放了全部拦截器的引用 10 if (interceptors.hasNext()) { // 若是存在下一个未迭代的拦截器 11 final InterceptorMapping interceptor = interceptors.next(); // 获取到拦截器 12 String interceptorMsg = "interceptor: " + interceptor.getName(); 13 UtilTimerStack.push(interceptorMsg); 14 try { 15 // 执行拦截器的 intercept 方法 16 resultCode = interceptor.getInterceptor().intercept(DefaultActionInvocation.this); 17 } 18 finally { 19 UtilTimerStack.pop(interceptorMsg); 20 } 21 } else { // 若是不存在下一个未迭代的拦截器 22 // 开始执行 Action 23 resultCode = invokeActionOnly(); 24 } 25 26 if (!executed) { 27 if (preResultListeners != null) { 28 LOG.trace("Executing PreResultListeners for result [#0]", result); 29 30 for (Object preResultListener : preResultListeners) { 31 PreResultListener listener = (PreResultListener) preResultListener; 32 33 String _profileKey = "preResultListener: "; 34 try { 35 UtilTimerStack.push(_profileKey); 36 listener.beforeResult(this, resultCode); 37 } 38 finally { 39 UtilTimerStack.pop(_profileKey); 40 } 41 } 42 } 43 44 if (proxy.getExecuteResult()) { 45 executeResult(); 46 } 47 48 executed = true; 49 } 50 51 return resultCode; 52 } 53 finally { 54 UtilTimerStack.pop(profileKey); 55 } 56 }
重点就在这个方法的 10-24 行了,这里在迭代全部拦截器,而且在 16 行把当前 DefaultActionInvocation 实例做为 invocation 参数传入执行了当前迭代的拦截器的 intercept 方法。而咱们已经知道,拦截器中放行就是经过调用传入的 invocation 参数的 invocation.invoke 方法,即当前 invoke 方法。没错,这是一个递归!!!服务器
Struts2 就是经过递归来迭代调用拦截器,这个递归能维持下去的条件有两个:架构
一、迭代器 interceptors 中还存在未迭代的拦截器。
二、在迭代器的 intercept 方法中必须调用 invocation.invoke 方法。
总结上述,Struts2 的执行流程以下:
客户端向服务器发送一个 Action 请求,首先执行核心过滤器 (StrutsPrepareAndExecuteFilter) 的 doFilter 方法。
在这个方法中,调用了 ExecuteOperations 实例 execute 的 executeAction 方法,而 executeAction 方法中又执行了 Dispatcher 实例 dispatcher 的 serviceAction 方法。
在 serviceAction 中建立了 Action 代理对象 proxy,这个代理对象为 StrutsActionProxy 的实例,接着执行了 Action 代理对象的 execute 方法。
在 execute 方法中又执行了 DefaultActionInvocation 的实例 invocation 的 invoke 方法。
在 invoke 方法中递归迭代执行拦截器,当拦截器迭代完毕,就会执行目标 Action 的目标方法,最后 Struts2 处理 Action 返回的逻辑视图结果,将处理结果交给 response 对象响应给浏览器。
经过上述代码也能够看到,Action 的执行时机是在迭代器正常执行完以后,到这里能够得出结论:
若是在迭代器中未调用 invocation.invoke ,则后续的迭代器不会被执行,且 Action 也不会被执行,这就是 invocation.invoke 放行的原理。
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ taglib prefix="s" uri="/struts-tags" %> <html> <head> <title>标签库测试</title> </head> <body> <s:set var="i" value="3" scope="request"/> <s:if test="#request.i>3"> i>3 </s:if> <s:elseif test="#request.i<3"> i<3 </s:elseif> <s:else> i=3 </s:else> </body> </html>
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ taglib prefix="s" uri="/struts-tags" %> <html> <head> <title>标签库测试</title> </head> <body> <%--当前遍历对象会被放到值栈的root和context中--%> <%--遍历 List--%> <s:iterator var="letter" value="{'a','b','c'}"> <s:property value="letter"></s:property> </s:iterator> <hr> <%--遍历 Map--%> <s:iterator value="#{'a':'1','b':'2','c':'3'}"> key: <s:property value="key"/> value: <s:property value="value"/> <br> </s:iterator> <hr> <%--相似 for 循环--%> <s:iterator var="i" begin="0" end="10" step="2" status="s"> <s:property value="#s.count"/> : <s:property value="i"/> <br> </s:iterator> </body> </html>
<%@ page import="java.util.Date" %> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ taglib prefix="s" uri="/struts-tags" %> <html> <head> <title>标签库测试</title> </head> <body> <% Date date = new Date(); request.setAttribute("date", date); %> <s:date name="#request.date" /> <br> <s:date name="#request.date" format="yyyy年MM月dd日 HH:mm:ss" /> </body> </html>
<%@ page import="java.util.Date" %> <%@ page import="java.util.TreeMap" %> <%@ page import="java.util.HashMap" %> <%@ page import="java.util.Map" %> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ taglib prefix="s" uri="/struts-tags" %> <html> <head> <title>标签库测试</title> </head> <body> <%-- Struts2 默认会表单中标签套上 table 若是不想要 Struts2 提供的样式,可更改默认常量 struts.ui.theme struts.ui.theme 有三个可选值: xhtml : 默认值。 simple : 无样式提供。 ajax : 这个主题里的模板以 xhtml 主题里的模板为基础,但增长了一些ajax功能。 除了更改配置文件中的常量,还能够经过修改 s:form 上的 theme 属性来让主题只对当前表单生效 --%> <% Map<String, String> gender = new HashMap<String, String>(); gender.put("1", "男"); gender.put("2", "女"); request.setAttribute("gender", gender); Map<String, String> address = new HashMap<String, String>(); address.put("hk", "香港"); address.put("jp", "日本"); request.setAttribute("address", address); Map<String, String> hobby = new HashMap<String, String>(); hobby.put("1", "吃饭"); hobby.put("2", "睡觉"); hobby.put("3", "打豆豆"); request.setAttribute("hobby",hobby); %> <s:form namespace="/" action="Test1"> <%--隐藏域--%> <s:hidden name="id"/> <%--文本框--%> <s:textfield name="username" label="用户名"/> <%--密码框--%> <s:password name="password" label="密码"/> <%--单选框--%> <s:radio list="#request.gender" name="gender" label="性别"/> <%--下拉框--%> <s:select list="#request.address" name="address" label="地点"/> <%--多选框--%> <s:checkboxlist list="#request.hobby" name="hobby" label="爱好"/> <%--文本域--%> <s:textarea rows="3" cols="10" value="默认值" label="简介" /> <%--提交按钮--%> <s:submit value="提交"/> </s:form> </body> </html>
package com.zze.action; import com.opensymphony.xwork2.ActionSupport; public class Test1Action extends ActionSupport { private String name; public void setName(String name) { this.name = name; } @Override public String execute() throws Exception { System.out.println("................."); return super.execute(); } /** * 编写一个类,继承 ActionSupport,重写 validate 方法 * 每次请求此 Action 都会先执行 validate 方法 * 若是验证有错误,将错误经过 this.addFieldError 或 this.addActionError 交给 Struts2 * 而后 Struts2 会返回 input 逻辑视图,手动定义好 input 跳转到的页面 * 在页面能够经过 <s:actionerror/> <s:fielderror/> 标签获取到错误信息 */ @Override public void validate() { if(name == null || name.trim().length() == 0){ this.addFieldError("name","用户名不能为空"); } } }
package com.zze.action; import com.opensymphony.xwork2.ActionSupport; public class Test2Action extends ActionSupport { private String name; public void setName(String name) { this.name = name; } public String add() { System.out.println("from add...."); return SUCCESS; } /** * 编写一个类,继承 ActionSupport * 若是要给指定的方法校验,须要按规则定义一个方法: * 校验的方法名要遵循:validate+方法名首字母大写 * 以下,要给 add 方法校验,定义的方法名就为 validateAdd * 而后每次请求这个方法就会限制性校验方法 * 若是验证有错误,将错误经过 this.addFieldError 或 this.addActionError 交给 Struts2 * 而后 Struts2 会返回 input 逻辑视图,手动定义好 input 跳转到的页面 * 在页面能够经过 <s:actionerror/> <s:fielderror/> 标签获取到错误信息 */ public void validateAdd() { System.out.println("from validateAdd..."); } }
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE validators PUBLIC "-//Apache Struts//XWork Validator 1.0.3//EN" "http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd"> <!-- 一、在 Action 所在包下建立一个 xml 文件,名称为 Action类名-validation.xml 如 : 此文件是给名为 Test3Action 的 Action 校验,文件名则为 Test3Action-validation.xml 二、引入 DTD 约束,该约束可在 xwork-core-2.3.37.jar!/xwork-validator-1.0.3.dtd 下找到 --> <validators> <!-- name : 要校验的字段名 注意:须要获取到值才能对字段进行校验,因此在 Action 中要给对应字段提供 get 方法。 --> <field name="name"> <!-- type : Struts2 已经给咱们提供了不少验证器 在 xwork-core-2.3.37.jar!/com/opensymphony/xwork2/validator/validators/default.xml 中能够看到 --> <field-validator type="requiredstring"> <!--返回的错误信息--> <message>用户名不能为空</message> </field-validator> </field> </validators>
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE validators PUBLIC "-//Apache Struts//XWork Validator 1.0.3//EN" "http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd"> <!-- 一、在 Action 所在包下建立一个 xml 文件,名称为 Action类名-方法访问路径-validation.xml 如 : 此文件只给名为 Test4Action 的 Action 下的 add 方法校验, Struts.xml 对应Action 配置为 <action name="*_*" class="com.zze.action.{1}Action" method="{2}"> 文件名则为 Test4Action-Test4_add-validation.xml 二、引入 DTD 约束,该约束可在 xwork-core-2.3.37.jar!/xwork-validator-1.0.3.dtd 下找到 --> <validators> <!-- name : 要校验的字段名 注意:须要获取到值才能对字段进行校验,因此在 Action 中要给对应字段提供 get 方法。 --> <field name="name"> <!-- type : Struts2 已经给咱们提供了不少验证器 在 xwork-core-2.3.37.jar!/com/opensymphony/xwork2/validator/validators/default.xml 中能够看到 --> <field-validator type="stringlength"> <param name="minLength">6</param> <param name="maxLength">12</param> <!--返回的错误信息--> <message>用户名必须在6-12位之间</message> </field-validator> </field> </validators>
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE validators PUBLIC "-//Apache Struts//XWork Validator Definition 1.0//EN" "http://struts.apache.org/dtds/xwork-validator-definition-1.0.dtd"> <validators> <!--必填校验器,要求被校验的属性值不能为 null--> <validator name="required" class="com.opensymphony.xwork2.validator.validators.RequiredFieldValidator"/> <!--必填字符串校验器,要求被校验的属性值不能为 null,而且长度大于 0 ,默认状况下不会对字符串去先后空格--> <validator name="requiredstring" class="com.opensymphony.xwork2.validator.validators.RequiredStringValidator"/> <!--数值校验器,要求被校验的属性值可转 int ,且可指定范围,min 指定最小值,max 指定最大值--> <validator name="int" class="com.opensymphony.xwork2.validator.validators.IntRangeFieldValidator"/> <!--数值校验器,要求被校验的属性值可转 long,且可指定范围,min 指定最小值,max 指定最大值--> <validator name="long" class="com.opensymphony.xwork2.validator.validators.LongRangeFieldValidator"/> <!--数值校验器,要求被校验的属性值可转 short,且可指定范围,min 指定最小值,max 指定最大值--> <validator name="short" class="com.opensymphony.xwork2.validator.validators.ShortRangeFieldValidator"/> <!--数值校验器,要求被校验的属性值可转 double,且可指定范围,min 指定最小值,max 指定最大值--> <validator name="double" class="com.opensymphony.xwork2.validator.validators.DoubleRangeFieldValidator"/> <!--日期校验器,要求被校验的属性值可转 Date,且可指定范围,min 指定最小值,max 指定最大值--> <validator name="date" class="com.opensymphony.xwork2.validator.validators.DateRangeFieldValidator"/> <!--OGNL表达式校验器,它是一个非属性校验器,expression 指定 ognl 表达式,该逻辑表达式基于 ValueStack进行求值,返回 true 时校验经过,不然不经过,该校验器不可用在字段校验器风格的配置中--> <validator name="expression" class="com.opensymphony.xwork2.validator.validators.ExpressionValidator"/> <!--字段OGNL表达式校验器,要求被校验的属性值知足一个 OGNL 表达式,expression 参数指定 OGNL 表达式,该逻辑表达式基于 ValueStack进行求值,返回 true 时校验经过,不然不经过--> <validator name="fieldexpression" class="com.opensymphony.xwork2.validator.validators.FieldExpressionValidator"/> <!--邮件地址校验器,要求若是被校验的属性值非空,则必须是合法的邮件地址--> <validator name="email" class="com.opensymphony.xwork2.validator.validators.EmailValidator"/> <!--网址校验器,要求若是被校验的属性值非空,则必须是合法的 url 地址--> <validator name="url" class="com.opensymphony.xwork2.validator.validators.URLValidator"/> <!--用于校验 Action 中符合类型的属性,它指定一个校验文件用于校验复合类型属性中的属性--> <validator name="visitor" class="com.opensymphony.xwork2.validator.validators.VisitorFieldValidator"/> <!--转换校验器,指定在类型转换失败时,提示的错误消息--> <validator name="conversion" class="com.opensymphony.xwork2.validator.validators.ConversionErrorFieldValidator"/> <!--字符串长度校验器,要求被校验的属性值必须在指定的范围内,不然校验失败,minLength 指定最小长度,maxLength 指定最大长度,trim 指定交验以前是否去除字符串先后空格--> <validator name="stringlength" class="com.opensymphony.xwork2.validator.validators.StringLengthFieldValidator"/> <!--正则表达式校验器,检查被校验的属性值是否匹配一个正则表达式,expression 指定正则表达式,caseSensitive 指定进行正则表达式匹配时,是否区分大小写,默认为 true--> <validator name="regex" class="com.opensymphony.xwork2.validator.validators.RegexFieldValidator"/> <validator name="conditionalvisitor" class="com.opensymphony.xwork2.validator.validators.ConditionalVisitorFieldValidator"/> </validators>
package com.zze.validator; import com.opensymphony.xwork2.validator.ValidationException; import com.opensymphony.xwork2.validator.validators.FieldValidatorSupport; /** * 对指定字段进行过滤 * * 除了继承 FieldValidatorSupport * 还能够继承 ValidatorSupport */ public class AgeValidator extends FieldValidatorSupport { @Override public void validate(Object object) throws ValidationException { // 得到字段名称 String fieldName = this.getFieldName(); Object fieldValue = this.getFieldValue(fieldName, object); if(fieldValue instanceof Integer){ int age = (Integer)fieldValue; if(age<0){ this.addFieldError(fieldName,object); } } } }
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE validators PUBLIC "-//Apache Struts//XWork Validator Definition 1.0//EN" "http://struts.apache.org/dtds/xwork-validator-definition-1.0.dtd"> <!--在 src 下新建 validators.xml --> <validators> <!--注册验证器--> <validator name="ageValidator" class="com.zze.validator.AgeValidator"/> </validators>
一、在类路径下新建 properties 资源文件,文件名为以下格式:
名称_en_uS.properties // 英文 名称_zh_CN.properties // 中文
例如:
name=姓名不能为空
name=name can't be null
二、在 struts.xml 中配置常量:
<constant name="struts.custom.i18n.resources" value="message"/>
三、接下来就能够获取资源文件中国际化后的内容了:
package com.zze.action; import com.opensymphony.xwork2.ActionSupport; public class I18NAction extends ActionSupport { @Override public String execute() throws Exception { String name = getText("name"); System.out.println(name); // 姓名不能为空 return super.execute(); } }
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ taglib prefix="s" uri="/struts-tags" %> <html> <head> <title>国际化测试</title> </head> <body> <s:text name="name"/> </body> </html>
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE validators PUBLIC "-//Apache Struts//XWork Validator 1.0.3//EN" "http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd"> <validators> <field name="name"> <field-validator type="requiredstring"> <!--经过 key 取出国际化文本--> <message key="name"></message> </field-validator> </field> </validators>
一、在 Action 所在的包下建立 properties 资源文件,文件名为以下格式:
Action名_zh_CN.properties // 中文 Action名_en_US.properties // 英文
二、直接在 Action 中使用便可,使用方式同全局一致。
一、在需国际化的包下新建 properties 资源文件,文件名格式以下:
package_zh_CN.properties // 中文 package_en_US.properties // 英文
二、接下来在当前包及子包中都能使用该国际化资源文件。
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ taglib prefix="s" uri="/struts-tags" %> <html> <head> <title>国际化测试</title> </head> <body> <s:i18n name="com/zze/action/package"> <s:text name="msg"/> </s:i18n> </body> </html>
wel=欢迎 {0}
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ taglib prefix="s" uri="/struts-tags" %> <html> <head> <title>国际化测试</title> </head> <body> <s:i18n name="com/zze/action/package"> <s:text name="wel"> <s:param>张三</s:param> </s:text> </s:i18n> </body> </html>
package com.zze.action; import com.opensymphony.xwork2.ActionSupport; public class I18NAction extends ActionSupport { @Override public String execute() throws Exception { String wel = getText("wel", new String[]{"张三"}); System.out.println(wel); // 欢迎 张三 return super.execute(); } }
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN" "http://struts.apache.org/dtds/struts-2.3.dtd"> <struts> <!--限制单次文件上传总大小不可大于 5m--> <constant name="struts.multipart.maxSize" value="5242880"/> <!--配置国际化资源文件名--> <constant name="struts.custom.i18n.resources" value="message"/> <package name="test" extends="struts-default" namespace="/"> <action name="upload" class="com.zze.web.action.FileUploadAction"> <result name="input">/index.jsp</result> <interceptor-ref name="defaultStack"> <!--限制单个文件大小不超过 2m--> <param name="fileUpload.maximumSize">2097152</param> <!--限制文件后缀--> <param name="fileUpload.allowedExtensions">.jpg,.png</param> <!--限制文件的 MIME 类型--> <param name="fileUpload.allowedTypes">image/jpg,image/png</param> </interceptor-ref> </action> </package> </struts>
struts.messages.error.uploading=\u4e0a\u4f20\u9519\u8bef struts.messages.error.file.too.large=\u6587\u4ef6\u592a\u5927 struts.messages.error.content.type.not.allowed=\u8bf7\u9009\u62e9\u56fe\u7247\u6587\u4ef6 struts.messages.error.file.extension.not.allowed=\u8bf7\u9009\u62e9\u002e\u006a\u0070\u0067\u6216\u002e\u0070\u006e\u0067\u7ed3\u5c3e\u7684\u6587\u4ef6
package com.zze.web.action; import com.opensymphony.xwork2.ActionSupport; import org.apache.commons.io.FileUtils; import org.apache.struts2.interceptor.ServletResponseAware; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletResponse; import java.io.File; public class FileUploadAction extends ActionSupport implements ServletResponseAware { /* 为文件上传提供三个属性 : String 表单项 name + FileName : 接收文件名称 File 表单项 name : 接收文件内容 String 表单项 name + ContentType : 上传文件的 ContentType */ private String fileFileName; private File file; private String fileContentType; public void setFileFileName(String fileFileName) { this.fileFileName = fileFileName; } public void setFile(File file) { this.file = file; } public void setFileContentType(String fileContentType) { this.fileContentType = fileContentType; } private ServletResponse response; @Override public String execute() throws Exception { response.setContentType("text/plain;charset=utf8"); String msg = "上传成功"; System.out.println(fileFileName); System.out.println(file); System.out.println(fileContentType); // 存储路径 String fullPath = "D://upload/"+fileFileName; File destFile = new File(fullPath); FileUtils.copyFile(file,destFile); response.getWriter().write(msg); return NONE; } @Override public void setServletResponse(HttpServletResponse response) { this.response = response; } }
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@taglib prefix="s" uri="/struts-tags" %> <html> <head> <title>Struts2 文件上传测试</title> </head> <body> <form action="${pageContext.request.contextPath}/upload" method="post" enctype="multipart/form-data"> <input type="file" name="file"> <input type="submit" value="上传"> <s:actionerror/> <s:fielderror/> </form> </body> </html>