Java实战之01Struts2-03属性封装、类型转换、数据验证
九、封装请求正文到对象中
1、静态参数封装
在struts.xml配置文件中,给动作类注入值。调用的是setter方法。
原因:是由一个staticParams的拦截器完成注入的。
2、动态参数封装:开发时用到的
通过用户的表单封装请求正文参数。
2.1、动作类作为实体模型
实体模型:Entity,对应数据库中表的记录(注意类对应的是表结构,而对象对应的是一条记录)
1 public class Demo1Action extends ActionSupport { 2 3 private String name; 4 private int age; 5 6 public String demo1(){ 7 System.out.println(name); 8 System.out.println(age); 9 return SUCCESS; 10 } 11 12 public String getName() { 13 return name; 14 } 15 public void setName(String name) { 16 this.name = name; 17 } 18 public int getAge() { 19 return age; 20 } 21 public void setAge(int age) { 22 this.age = age; 23 } 24 }
1 <!-- 动态参数封装:使用表单提交数据,第一种方式 --> 2 <action name="action2" class="cn.itcast.web.action.Demo2Action" method="demo2"> 3 <result name="success">/success.jsp</result> 4 </action>
1 <form action="${pageContext.request.contextPath}/action2" method="POST"> 2 用户名:<input type="text" name="name"/><br/> 3 年龄:<input type="text" name="age"><br/> 4 <input type="submit" value="提交"/> 5 </form>
原因:是由params拦截器完成的。
2.2、动作类和实体模型分开
问题:
由于我们没有初始化user对象,默认为null,一调用setUser方法,就空指针异常了。但是框架却封装进去值了。
原因:
通过执行过程:
1 public class Demo3Action extends ActionSupport { 2 3 private User user = new User(); 4 5 public String demo3(){ 6 System.out.println(user.getName()); 7 System.out.println(user.getAge()); 8 return SUCCESS; 9 } 10 11 public User getUser() { 12 System.out.println("getUser"); 13 return user; 14 } 15 public void setUser(User user) { 16 System.out.println("setUser"); 17 this.user = user; 18 } 19 }
2.3、模型驱动:建立动作类和模型分开的前提下(开发中采用的方式)
此处的学习目标:目前先记住怎么写,要想理解,必须等讲完OGNL表达式之后。
1 public class Demo4Action extends ActionSupport implements ModelDriven<User>{ 2 3 private User user = new User(); 4 5 public User getModel() { 6 return user; 7 } 8 9 public String demo4(){ 10 System.out.println(user.getName()); 11 System.out.println(user.getAge()); 12 return SUCCESS; 13 } 14 }
原因:是由modelDriven拦截器和params拦截器配合做的。
十、数据类型的转换(明白原理,实际开发中几乎不用)
1、开发中的情况:
实际开发中用户通过浏览器输入的数据都是String或者String[]。
String/String[]————填充模型(set方法)————>POJO(plain old java object) pojo中有java的数据类型。
POJO————————获取(get方法)————>页面展示:String
2、类型转换情况
写数据:(增,删,改)都是String或String[]数组转换为其他类型。
读数据:(查)其他类型转换为String。
3、Struts2提供的常用类型转换
a.基本数据类型自动转换。
b.日期类型:默认按照本地日期格式转换(yyyy-MM-dd)。
c.字符串数组:默认用逗号+空格,连接成一个字符串。
4、自定义类型转换器(知道)
示例:把日期格式按照 MM/dd/yyyy的格式转换
4.1、Struts2中的类型转换器结构:
4.2、编写类型转换器(编写一个类继承StrutsTypeConverter,实现抽象方法)
1 public class MyTypeConverter extends StrutsTypeConverter { 2 3 private DateFormat format = new SimpleDateFormat("MM/dd/yyyy"); 4 5 public Object convertFromString(Map context, String[] values, Class toClass) { 6 if(values == null || values.length == 0){ 7 return null; 8 } 9 String date = values[0]; 10 if(java.util.Date.class == toClass){ 11 try { 12 return format.parse(date); 13 } catch (ParseException e) { 14 e.printStackTrace(); 15 } 16 } 17 return null; 18 } 19 public String convertToString(Map context, Object o) { 20 if(o instanceof Date){ 21 Date date = (Date)o; 22 return format.format(date); 23 } 24 return null; 25 } 26 }
4.3、注册类型转换器
局部类型转换器:只能指定javabean中的属性用
按照属性来注册。在属性所属的javabean的包下建立一个.properties文件。文件名称:javabean名称-conversion.properties
全局类型转换器:(推荐)
按照要转换的数据类型来注册。
at the top op classpath,建立一个固定名称xwork-conversion.properties的属性文件。
5、转换失败后的处理(需要掌握)
当转换失败后,页面提示:
解决办法:配置回显结果视图
十一、数据验证
用户的输入验证,必须做,且工作量巨大。
1、验证的方式
客户端验证:javascript
服务端验证:逻辑验证(我们的代码)
注意:如果客户端和服务端二选一的话,服务器端的不能省。
实际开发中:客户端+服务端
2、Struts2的服务端验证
2.1、编程式验证
前提:
动作类必须继承ActionSupport
在代码中编写验证规则。
a、针对动作类中的所有动作方法进行验证:
在动作类中覆盖public void validate()方法。
1 public class StudentAction extends ActionSupport implements ModelDriven<Student> { 2 3 private Student student = new Student(); 4 5 public Student getModel() { 6 return student; 7 } 8 public void validate(){ 9 if(StringUtils.isBlank(student.getUsername())){ 10 addFieldError("username", "用户名不能为空"); 11 } 12 } 13 public void validateRegist(){ 14 if(StringUtils.isBlank(student.getUsername())){ 15 addFieldError("username", "用户名不能为空"); 16 } 17 } 18 19 public String regist(){ 20 System.out.println("用户名不能为空"); 21 return SUCCESS; 22 } 23 24 public String update(){ 25 System.out.println("用户名不能为空“); 26 return SUCCESS; 27 } 28 29 @SkipValidation 30 public String findAll(){ 31 return SUCCESS; 32 } 33 }
由此可知,该验证方法会对动作类中的所有动作方法进行验证。
b、针对动作类中的某个动作方法进行验证
针对上面的问题,解决办法1:给不需要验证的动作方法添加一个@SkipValidation注解。
解决办法1和解决办法2的使用时机:需要验证的动作方法少,用解决办法2。需要验证的方法多,用解决方式1。(简单一点:挑少的写)
所有编程式验证的弊端:硬编码。
2.2、声明式验证(推荐)
通过编写验证规则的xml文件。需要验证时,编写xml文件,不要验证,就不写。
优势:解决了2.1编程式验证的弊端
a、针对动作类中的所有动作进行验证:在动作类所在的包中,建立一个ActionClassName-validation.xml的文件,内容如下:
注意:它是针对动作类中的所有动作方法。
b、针对动作类中的某个动作进行验证:在动作类所在的包中建立一个xml文件,名称为ActionClassName-ActionName-validation.xml。内容如下:
2.3、Struts2内置的常用声明式验证器
2.3.1位置:
xwork-core-2.3.15.3.jar\com\opensymphony\xwork2\validator\validator\default.xml
2.3.2、验证器注入参数
例如:我们使用requiredstring,默认是去空格,当我们不想去空格时,就可以给验证器注入参数。
基于字段的:
基于验证器的:
3、常用验证器示例
1 public class Student implements Serializable { 2 3 private String username; 4 private String password; 5 private Date birthday; 6 private String hobby; 7 private boolean married; 8 9 public String getUsername() { 10 return username; 11 } 12 public void setUsername(String username) { 13 this.username = username; 14 } 15 public String getPassword() { 16 return password; 17 } 18 public void setPassword(String password) { 19 this.password = password; 20 } 21 public Date getBirthday() { 22 return birthday; 23 } 24 public void setBirthday(Date birthday) { 25 this.birthday = birthday; 26 } 27 public String getHobby() { 28 return hobby; 29 } 30 public void setHobby(String hobby) { 31 this.hobby = hobby; 32 } 33 public boolean isMarried() { 34 return married; 35 } 36 public void setMarried(boolean married) { 37 this.married = married; 38 } 39 }
1 <body> 2 <s:actionerror/> 3 <s:form action="saveUser"> 4 <s:textfield name="username" label="用户名"/> 5 <s:textfield name="age" label="年龄"/> 6 <s:textfield name="email" label="邮箱"/> 7 <s:textfield name="password" label="密码" /> 8 <s:textfield name="repassword" label="确认密码"/> 9 <s:textfield name="score" label="成绩" /> 10 <s:textfield name="url" label="个人主页"/> 11 <%-- list中的内容: 12 相当于创建一个新的List集合 13 --%> 14 <s:radio list="{'男','女'}" name="gender" label="性别"/> 15 <%-- 16 <input type="radio" name="gender" value="男"/>男 17 <input type="radio" name="gender" value="女"/>女 18 --%> 19 <s:submit value="注册"></s:submit> 20 </s:form> 21 </body>