Struts框架详解第二课
1. 封装请求参数到正文中
1.1 静态参数封装
静态参数封装是指在struts.xml配置文件中,给动作类注入值,调用的是setter方法,动作类中要有相应的setter方法。它是由一个staticParams的拦截器完成注入的。
动作类:
|
public class UserAction extends ActionSupport { private String username; private int age; public String addUser(){ System.out.println("username="+username+",age="+age); return SUCCESS; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } } |
Struts.xml文件
|
<package name="user" extends="struts-default"> <action name="addUser" class="com.mangocity.web.action.UserAction" method="addUser"> <param name="username">tom</param> <param name="age">18</param> <result name="success">/success.jsp</result> </action> </package> |
1.2 动态参数封装
动态参数封装是开发中用到的,通过用户的表单封装请求正文参数,动态参数封装的三种方式:
第一种:动作类作为实体模型,这种方式是由params拦截器完成注入的。
动作类:
|
public class UserAction extends ActionSupport { private String username; private int age; public String register(){ System.out.println("username="+username+",age="+age); return SUCCESS; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } } |
页面:表单中的字段名和动作类的属性一致
|
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>用户注册页面</title> </head> <body> <form action="${pageContext.request.contextPath }/register.shtml" method="post"> 用户名:<input type="text" name="username"/> 密码:<input type="password" name="password"/> <input type="submit" value="登陆"/> </form> </body> </html> |
第二种:动作类和实体模型分开
实体模型:
|
public class User implements Serializable{ private String username; private String password; public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } } |
动作类:
|
public class UserAction extends ActionSupport { private User user; public String register(){ System.out.println("username="+user.getUsername()+",password="+user.getPassword()); return SUCCESS; } public User getUser() { return user; } public void setUser(User user) { this.user = user; } } |
Jsp页面:
|
<body> <form action="${pageContext.request.contextPath }/register.shtml" method="post"> 用户名:<input type="text" name="user.username"/><br> 密码:<input type="password" name="user.password"/><br> <input type="submit" value="登陆"/> </form> </body> |
第三种:模型驱动
动作类继承ModelDriven接口,模型对象必须要实例化,这是页面中表单的字段名就可以简写了。是由modelDriven拦截器注入的。
动作类:
|
public class UserAction extends ActionSupport implements ModelDriven<User>{ private User user=new User(); public String register(){ System.out.println("username="+user.getUsername()+",password="+user.getPassword()); return SUCCESS; } public User getUser() { return user; } public void setUser(User user) { this.user = user; } public User getModel() { return user; } } |
Jsp页面:
|
<body> <form action="${pageContext.request.contextPath }/register.shtml" method="post"> 用户名:<input type="text" name="username"/><br> 密码:<input type="password" name="password"/><br> <input type="submit" value="登陆"/> </form> </body> |
2. 数据类型转换
2.1 实际开发中用户通过浏览器输入的数据及展示在浏览器页面的数据都是String或者是String[],而在服务器端需要各种类型的数据,所以就需要进行数据类型的转换,struts2提供的常用类型转换:
a. 基本数据类型自动转换
b. 日期类型:默认按照本地日期格式转换
c. 字符串数组:默认用逗号+空格,连接成一个字符串
2.2 自定义类型转换器
2.2.1 struts2中的类型转换器结构
2.2.2 编写类型转换器(编写一个类继承StrutsTypeConvert,实现抽象方法)
日期类型转换器:
|
public class MyConverter extends StrutsTypeConverter {
private SimpleDateFormat format=new SimpleDateFormat("MM/dd/yyyy"); @Override public Object convertFromString(Map arg0, String[] values, Class clazz) { if(values==null || values.length==0){ return null; } if(clazz!=Date.class){ return null; } String value=values[0]; Date date=null; try { date = format.parse(value); } catch (ParseException e) { e.printStackTrace(); } return date; }
@Override public String convertToString(Map arg0, Object obj) { if(obj instanceof Date){ return format.format(obj); } return null; } } |
2.2.3 注册类型转换器
2.2.3.1 局部类型转换器:只能指定javabean中的属性用
按照属性来注册,在属性所属的javabean包下建立一个properties文件,文件名为:javabean名称-conversion.properties.
要转换的属性名=转换器类型全名
|
birthday=com.mangocity.web.converter.MyConverter |
2.2.3.2 全局类型转换器,按照要转换的数据类型来注册
在src下建立一个固定名称xwork-conversion.properties的属性文件
|
java.util.Date=com.mangocity.web.converter.MyConverter |
2.2.4 类型转换失败后的处理
当类型转换失败后,页面提示:
没有input视图,解决方法就是配置回显示图,提交表单数据失败后,应该再回到提交数据的页面:
|
<package name="user" extends="struts-default"> <action name="register" class="com.mangocity.web.action.UserAction" method="register"> <result name="success">/success.jsp</result> <result name="input">/login.jsp</result> </action> </package> |
但是这个时候用户填写的表单数据没有了,解决方法是用strtus2的标签库,不仅可以回显数据,还可以提示错误消息。
|
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <%@ taglib uri="/struts-tags" prefix="s" %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>用户注册页面</title> <s:head/> </head>
<body> <!-- 显示错误提示 --> <s:fielderror></s:fielderror><!--字段错误 --> <s:actionerror/><!-- 动作错误 --> <s:form action="register"> <s:textfield name="username" label="用户名" requiredLabel="true" requiredPosition=""></s:textfield> <s:password name="password" label="密码" showPassword="true"></s:password> <s:textfield name="birthday" label="生日"></s:textfield> <s:submit value="注册"></s:submit> </s:form> </body> </html> |
错误提示信息是英文的,怎样转成中文,用struts2的国际化。
在属性所在类的包下建立一个与类同名的属性文件:
|
invalid.fieldvalue.birthday=\u8BF7\u8F93\u5165\u6B63\u786E\u7684\u65E5\u671F\u683C\u5F0Fmm/dd/yyyy |
回显如下:
3. 数据验证
3.1 数据验证的方式:
客户端验证:javascript
服务端验证:逻辑验证,必须的,不能省
3.2 struts的服务端验证
3.2.1 编程式验证
前提:动作类必须继承ActionSupport.
3.2.1.1 针对动作类中的所有方法进行验证
在动作类中重写publicvoid validate()方法
|
@Override public void validate(){ if(StringUtils.isBlank(user.getUsername())){ addFieldError("username", "请输入用户名"); } } |
这种方法最大的缺陷就是动作类中的所有方法都会进行验证,当某个方法不需要的参数属性也被验证时就会报错,针对这个问题的解决办法:
第一种 给不需要验证的动作方法添加一个@SkipValidation注解
|
@SkipValidation public String showMain(){ return SUCCESS; } |
第二种 validate方法遵守书写规范:validate+要验证的动作方法名称,注意要验证的动作方法首字母要大写。
|
public void validateRegister(){ if(StringUtils.isBlank(user.getUsername())){ addFieldError("username", "请输入用户名"); } } |
3.2.2 声明式验证
通过编写验证规则的xml文件,需要验证时,编写xml文件,解决了硬编码的问题。
3.2.2.1 针对动作类中的所有动作进行验证:在动作类所在的包中,建立一个ActionClassName-validation.xml的文件:
|
<?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> <!--要验证的字段:name取值和form表单一致 --> <field name="username"> <!-- 指定验证器 :requiredstring是内置验证器,默认会去掉首尾空格,验证null和""--> <field-validator type="requiredstring"> <!--提示信息 --> <message>用户名不能为空</message> </field-validator> </field> </validators> |
3.2.2.2 针对动作类中某个动作进行验证,在动作类所在包建立一个xml文件,文件名为:ActionClassName-ActionName-validation.xml
|
<!-- 另一种配置方式 --> <validator type="requiredstring"> <param name="fieldname">username</param> <message>没有用户名</message> </validator> |
3.2.3 常用验证器示例
|
<?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="username"> <field-validator type="requiredstring"> <message>请输入用户名</message> </field-validator> </field> <field name="age"> <field-validator type="int"> <param name="min">18</param> <param name="max">100</param> <message>年龄必须介于${min}-${max}之间</message> </field-validator> </field> <field name="gender"> <field-validator type="required"> <message>请选择性别</message> </field-validator> </field> <field name="email"> <field-validator type="email"> <message>请输入正确的邮箱格式</message> </field-validator> </field> <field name="password"> <field-validator type="requiredstring"> <message>请输入密码</message> </field-validator> <field-validator type="stringlength"> <param name="minlength">3</param> <param name="maxlength">8</param> <message>密码长度必须是${minlength}~${maxlength}之间</message> </field-validator> </field> <validator type="expression"> <param name="expression"> <![CDATA[ password==repassword ]]> </param> <message>两次密码必须一致</message> </validator> <field name="score"> <field-validator type="regex"> <param name="regrx"> <![CDATA[ \d+ ]]> </param> <message>成绩必须是自然数</message> </field-validator> </field> <field name="url"> <field-validator type="url"> <message>请输入正确的url地址</message> </field-validator> </field> </validators> |
4. 国际化
4.1 国际化的概念
软件的国际化:软件开发时,要使它能同时应对世界不同地区和国家的访问,并针对不同地区和国家的访问,提供相应的、符合来访者阅读习惯的页面或数据
4.2 固定文本的国际化示例
4.2.1 创建一个消息资源包
一个资源包由多个文件组成,这些文件名都有命名规范:主文件名_语言代码_国家代码.properties.语言代码和国家代码由iso规定的。
当文件只有主文件名.propeties时,表明它是默认资源包,浏览器会根据不同的语言环境找对应语言环境的资源包,当没有时,找默认的。
4.2.2 java类中读取资源包中的内容
|
@Test public void test1(){ ResourceBundle bundle=ResourceBundle.getBundle("com.mangocity.resource.message"); String value=bundle.getString("key"); System.out.println(value);//会取message_zh_CN里面的key }
@Test public static void test2(){ ResourceBundle bundle=ResourceBundle.getBundle("com.mangocity.resource.message",Locale.US); String value=bundle.getString("key"); System.out.println(value);//会取message_en_US.properties里面的key } |
4.2.3 jsp页面读取资源包中的内容
|
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <% Locale locale=request.getLocale(); ResourceBundle bundle=ResourceBundle.getBundle("com.mangocity.resource.message",locale); %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title><%=bundle.getString("jsp.login.title")%></title> </head>
<body> <form action=""> <%=bundle.getString("jsp.login.username") %><input type="text"><br> <%=bundle.getString("jsp.login.password") %><input type="text"><br> <input type="submit" value="<%=bundle.getString("jsp.login.submit") %>"> </form> </body> </html> |
4.3 struts2中的国际化
4.3.1 Struts2中使用国际化的前提
要想在struts2中使用国际化,动作类必须继承ActionSupport
4.3.2 struts2中使用国际化的步骤
4.3.2.1 配置资源包
a. 配置全局资源包
|
<!-- struts.xml中配置全局资源包的位置 --> <constant name="struts.custom.i18n.resources" value="com.mangocity.resources.message"/> |
b. 配置包范围的资源包
资源包命名规范:package_语言代码_国家代码.properties.以此种命名方式的资源包能被该包及其子包中的动作类访问。
c. 局部消息资源包(只为动作类来使用的)
资源包命名规范:动作类名称_语言代码_国家代码.properties,以此种命名方式的资源包,只为动作类服务。
4.3.2.2 struts2中资源包的搜索顺序
1. ActionClass.properties
2. Interface.properties
3. BaseClass.properties
4. ModelDriven’s model
5. Package.properties
6. Search up the i18n message keyhierarchy itself
7. Global resource properties
4.3.2.3 读取资源包的内容
a. 动作类中的读取方式
|
public class Demo1Action extends ActionSupport{ public String execute(){ String value=getText("key"); System.out.println(value); return SUCCESS; } } |
b. 在jsp页面中读取资源包中的内容
|
使用struts标签,会按照顺序搜资源包的内容 <s:text name=”key”/> |
C. 自由指定读取资源包
|
<s:i18n name=”com.mangocity.resource.message/> <s:text name=”key:/> |