第一节 Struts2表单验证
1.1 服务端Action验证的两种方式
第一种
-
struts2自带表单字段的验证
- 第一种:重写validate方法,如果数据不对,可以往FieldError添加字段错误信息
- 注意:
- 1.表单一定要用struts的标签:s:form/s:textfield
- 2.addFieldError里的key,是表单的name的值(否则报错)
- 3.validate对于Action来说是全局,也就是对action的所有方法都会拦截验证
- 4.在不需要验证的action方法上,可以声明一个注解@SkipValidation,忽略校验
- 第一种:重写validate方法,如果数据不对,可以往FieldError添加字段错误信息
-
UserAction.java
package com.it.web.action;
import com.it.model.User;
import org.apache.commons.lang3.StringUtils;
import org.apache.struts2.interceptor.validation.SkipValidation;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;
public class UserAction extends ActionSupport implements ModelDriven<User> {
private User user = new User();
@Override
public User getModel() {
return user;
}
@Override
public void validate() {
//判断用户名是否为空
//if(username == null && "".equals(username))
if(StringUtils.isEmpty(user.getUsername())){
addFieldError("username", "用户名不能为空");
}
//判断密码是否为空
if(StringUtils.isEmpty(user.getPassword())){
addFieldError("password", "密码不能为空");
}
}
public String register(){
//com.opensymphony.xwork2.validator.validators.RequiredStringValidator
System.out.println("register方法....");
System.out.println(user);
return NONE;
}
/**
* 返回一个列表
* @return
*/
//@SkipValidation
public String list(){
return "list";
}
}
validate对于Action来说是全局,也就是action的所有方法都会拦截验证,执行list测试方法(如果不使用注解@SkipValidation),直接访问list,会报错,无法访问到userlist.jsp页面,因为validate验证方法全局性,所有方法都会被它验证。
- register.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="/struts-tags" prefix="s"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<s:head></s:head>
</head>
<body>
<hr>
<!-- struts表单的特点
1.action不需要写项目名,会自动加
2.会给表单里面的内容放在table中,并加上样式
3.struts的表单项必须要有name
-->
Struts的Form标签<br>
<%-- <s:fielderror></s:fielderror> --%>
<s:form action="/user/register.action">
<!--
requiredLabel:代表必填项目
requiredPosition:必填*号位置
showPassword:回显时,密码还在
-->
<s:textfield name="username" label="用户名" requiredLabel="true" requiredPosition="left"></s:textfield>
<s:password name="password" label="密码" showPassword="true"></s:password>
<s:textfield name="birthday" label="生日"></s:textfield>
<%-- <s:checkbox name="hobby" label="写代码" value="写代码"></s:checkbox>
<s:checkbox name="hobby" label="泡妞" value="泡妞"></s:checkbox>
<s:checkbox name="hobby" label="买房" value="买房"></s:checkbox> --%>
<!-- list使用的OGNL表达式 -->
<s:checkboxlist list="#{
'写代码':'写代码','泡妞':'泡妞','买房':'买房'}" label="爱好" name="hobby"></s:checkboxlist>
<s:radio list="#{
'true':'已婚','false':'未婚'}" name="married" label="是否已婚"></s:radio>
<s:submit value="注册"></s:submit>
</s:form>
</body>
</html>
- struts.xml
<?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"></constant>
<!-- 设置参数 -->
<package name="p1" extends="struts-default">
<action name="register" class="com.it.web.action.UserAction" method="register">
<!-- input:回显,出现错误后,显示哪个界面 -->
<result name="input">/register.jsp</result>
</action>
<action name="list" class="com.it.web.action.UserAction" method="list">
<result name="list">/userlist.jsp</result>
</action>
</package>
</struts>
- userlist.jsp:测试方法,随便写一句话
- 效果
第二种
-
第二种:写一个方法,格式:validate+方法名(第一个字母大写【如:validateRegister】
-
注意:只针对方法有效,它是一个局部字段校验
-
UserAction.java中修改部分代码,去掉此方法的@Override,否则报错,因为validateRegister不是ActionSupport中的方法
public void validateRegister() {
//判断用户名是否为空
//if(username == null && "".equals(username))
if(StringUtils.isEmpty(user.getUsername())){
addFieldError("username", "用户名不能为空");
}
//判断密码是否为空
if(StringUtils.isEmpty(user.getPassword())){
addFieldError("password", "密码不能为空");
}
}
validateRegister只针对方法有效,它是一个局部字段校验,此时不使用注解@SkipValidation,直接访问list,也能访问得到
1.2 xml声明式验证
全局式声明方式
- 在action包中声明UserAction-validation.xml文件
- 这种方式配置是全局配置,所有action的方法都会拦截验证
- 如果其它方法不想验证,可配置@SkipValidation注解
- dtd约束可以在xwork-core的jar包中找
xml方式配置的文件名前缀要与Action类名一致
- UserAction-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">
<!--dtd在xwork-core-2.3.33.jar中可以找到-->
<validators>
<!-- 第一种校验字段方式 :field-->
<field name="username">
<field-validator type="requiredstring">
<param name="fieldName">username</param>
<message>用户名不能为空-xml</message>
</field-validator>
</field>
<!-- 第二种校验字段方式 :validator更简便-->
<validator type="requiredstring">
<param name="fieldName">password</param>
<message>密码不能为空-xml</message>
</validator>
</validators>
- 效果
全局声明方式,所有action的方法都会拦截验证,此时访问list无法访问到
局部声明方式
- 在action包中声明UserAction-register-validation.xml文件
声明方式 【Action类名-方法名-validation.xml】 - xml内容与上面的一样
此时再访问list,可以访问到
因为此时UserAction-register-validation.xml只验证它的register方法
其它
- struts默认有很多种验证器类型,声明在default.xml中
- 注意default.xml的位置
validators里有很多struts的默认验证配置
default.xml的位置:如下图
例如:密码不能大于6位的配置
<validator type="stringlength">
<param name="fieldName">password</param>
<param name="maxLength">6</param>
<message>密码不能大于6位</message>
</validator>
1.3 验证器综合案例
add.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="/struts-tags" prefix="s"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<s:head></s:head>
</head>
<body>
<hr>
<s:debug></s:debug><%--debug模式,能看到更多的错误信息--%>
添加学生
<s:actionerror/><%--拿到actionError里的 密码不一致 信息--%>
<s:form action="/stu/add.action">
<s:textfield name="username" label="用户名"/>
<s:textfield name="age" label="年龄"/>
<s:textfield name="email" label="邮箱"/>
<%-- <s:password name="password" label="密码"/> --%>
<s:textfield name="password" label="密码"/>
<s:textfield name="repassword" label="确认密码"/>
<s:textfield name="score" label="成绩"/>
<s:textfield name="url" label="个人主页"/>
<s:radio list="{
'男','女'}" name="gender" label="性别"></s:radio>
<s:submit value="提交"/>
</s:form>
</body>
</html>
Student.java
package com.it.model;
public class Student {
private String username;//不能为空,去空字符串
private int age;//18~100
private String email;//正确邮箱格式
private String password;//3~8
private String repassword;//与密码一至
private int score;//必须是自然数
private String url;//必须是一个路径 http://
private String gender;//性别,只有男和女
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;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getRepassword() {
return repassword;
}
public void setRepassword(String repassword) {
this.repassword = repassword;
}
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
@Override
public String toString() {
return "Student [username=" + username + ", age=" + age + ", email=" + email + ", password=" + password
+ ", repassword=" + repassword + ", score=" + score + ", url=" + url + ", gender=" + gender + "]";
}
}
StudentAction.java
package com.it.web.action;
import com.it.model.Student;
import com.it.model.User;
import com.it.service.IUserService;
import com.it.service.impl.UserServiceImpl;
import org.apache.commons.lang3.StringUtils;
import org.apache.struts2.interceptor.validation.SkipValidation;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;
public class StudentAction extends ActionSupport implements ModelDriven<Student> {
private Student stu = new Student();
@Override
public Student getModel() {
// TODO Auto-generated method stub
return stu;
}
public String add(){
//com.opensymphony.xwork2.validator.validators.RequiredFieldValidator
//com.opensymphony.xwork2.validator.validators.RequiredStringValidator
//com.opensymphony.xwork2.validator.validators.IntRangeFieldValidator
//com.opensymphony.xwork2.validator.validators.StringLengthFieldValidator
//com.opensymphony.xwork2.validator.validators.ExpressionValidator
//com.opensymphony.xwork2.validator.validators.RegexFieldValidator
System.out.println(stu);
return NONE;
}
}
struts.xml
<package name="p2" extends="struts-default" namespace="/stu">
<action name="add" class="com.it.web.action.StudentAction" method="add">
<result name="input">/add.jsp</result>
</action>
</package>
StudentAction-add-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>
<!--
1. private String username;//不能为空,去空字符串
requiredstring 比 required 好一点,会自动去除空格
-->
<validator type="requiredstring">
<param name="fieldName">username</param>
<message>用户名不能为空</message>
</validator>
<!--2.private int age;//18~100
1.表单的类型,会根据模型的属性类型去校验
-->
<validator type="int">
<param name="fieldName">age</param>
<param name="min">18</param>
<param name="max">100</param>
<message>年龄必须在18~100</message>
</validator>
<!-- 3.private String email;//正确邮箱格式-->
<validator type="requiredstring">
<param name="fieldName">email</param>
<message>邮箱不能为空</message>
</validator>
<validator type="email">
<param name="fieldName">email</param>
<message>邮箱格式不正确【如:[email protected]】</message>
</validator>
<!--4. private String password;//3~8 -->
<validator type="requiredstring">
<param name="fieldName">password</param>
<message>密码不能为空</message>
</validator>
<validator type="stringlength">
<param name="fieldName">password</param>
<param name="minLength">3</param>
<param name="maxLength">8</param>
<message>密码长度为3~8</message>
</validator>
<!-- 5.private String repassword;//与密码一至 -->
<validator type="expression">
<param name="expression">
<![CDATA[ password == repassword]]>
</param>
<message>密码不一致</message>
</validator>
<!-- 6.private int score;//必须是自然数
regex :正则
-->
<validator type="regex">
<param name="fieldName">score</param>
<param name="regexExpression">\d+</param>
<message>分数必须为数字</message>
</validator>
<!-- private String url;//必须是一个路径 http:// -->
<validator type="url">
<param name="fieldName">url</param>
<message>URL格式不合法,以 http://开头</message>
</validator>
<!-- private String gender;//性别必填,只有男和女 -->
<validator type="required">
<param name="fieldName">gender</param>
<message>性别必选</message>
</validator>
</validators>
效果:
第二节 Struts2的国际化
2.1 什么是国际化
- 软件的国际化:软件开发时要使它能同时应对世界不同地区和国家的访问,并针对不同地区和国家的访问,提供相应的、符合来访者阅读习惯的页面或数据
2.2 国际化使用的场景
- 苹果中文网:https://www.apple.com/cn.
- 苹果英文网:https://www.apple.com.
- 苹果香港网:https://www.apple.com/hk.
- 苹果日本网:https://www.apple.com/jp.
2.3 固定文本的国际化
- 例如:消息提示,错误提示和菜单,导航栏等等固定文本。
第一步:创建一个消息资源包
- 一个资源包由多个文件组成,这些文件名都有命名规范:主要文件名_语言代码_国家代码.properties
- 语言代码和国家代码:由iso规定的。
- 当文件只有主要文件名.properties时,表明它是默认资源包。浏览器会根据不同的语言环境找对应语言环境的资源包。
- 当没有时,找默认的。
- 每个资源包的内容都由相同的key和对应语言环境的value组成。
- 例如:
- message_zh_CN.properties(zh代表语言代码中文,CN国家代码中国)
- message_zh_HK.properties(zh中文,HK香港)
- message_en_US.properties(en英文,US美国)
第二步:读取资源包中的内容
- Java提供ResourceBundle类可以读取资源包的国际化配置文件
- I18NTest.java
package com.it.test;
import java.util.Locale;
import java.util.ResourceBundle;
import org.junit.Test;
public class I18NTest {
@Test
public void test1(){
//读取国际化资源数据
//使用ResourceBundle读取数据
//baseName=包名+文件名
//默认读取是中文
//ResourceBundle rb = ResourceBundle.getBundle("resources.message");
//指定读取某个国家国际化数据
//ResourceBundle rb = ResourceBundle.getBundle("resources.message", Locale.US);
ResourceBundle rb = ResourceBundle.getBundle("resources.message", Locale.CHINA);
System.out.println(rb.getString("login.username"));
System.out.println(rb.getString("login.password"));
System.out.println(rb.getString("login.submit"));
}
}
- 测试效果
第三步:JSP中使用国际化
- 本质还是java实现
- login.jsp
<%@page import="java.util.ResourceBundle"%>
<%@page import="java.util.Locale"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<hr>
<%
Locale local = Locale.getDefault();//获取到一个默认的国家语言
ResourceBundle rb = ResourceBundle.getBundle("resources.message", local);<%-- <%=local.US %> --%>
%>
<%=local %><%-- <%=local.US %> --%>
<form action="${pageContext.request.contextPath}/login.action">
<%=rb.getString("login.username")%><input type="text" name="username"><br>
<%=rb.getString("login.password")%><input type="password" name="password"><br>
<input type="submit" value="<%=rb.getString("login.submit")%>">
</form>
</body>
</html>
- zh_CN默认中文格式
- en_US
第四步:使用jstl标签来国际化
- JSP标准标签库(JSTL)是一个JSP标签集合,它封装了JSP应用的通用核心功能。
- JSTL支持通用的、结构化的任务,比如迭代,条件判断,XML文档操作,国际化标签,SQL标签。
- 除了这些,它还提供了一个框架来使用集成JSTL的自定义标签。
- 首先需要在项目中导入两个jar包
- Jsp中代码截图如下
2.4 Struts提供的国际化
- 前面的国际化与struts无关
第一步:配置资源包
- 配置全局的资源包
- 在struts.xml中配置
<!-- 开发模式 -->
<constant name="struts.devMode" value="true"></constant>
<!-- 配置全局的国际化 -->
<constant name="struts.custom.i18n.resources" value="resources.message"/>
-
代码同上
-
login2.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="/struts-tags" prefix="s"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<hr>
<form action="${pageContext.request.contextPath}/login.action">
<s:text name="login.username"/> <input type="text" name="username"><br>
<s:text name="login.password"/><input type="password" name="password"><br>
<input type="submit" value="<s:text name="login.submit"/>">
</form>
</body>
</html>
- 效果:
- 在IE浏览器设置语言首选项后刷新浏览器
- 配置包范围的资源包
-
资源包名称命名规范:package_语言代码_国家代码.properties(固定的)。以此种命名方式的资源包能被该包及其子包中的动作类访问。
-
优先级:高于全局消息资源包
-
写一个UserAction.java
package com.it.web.action;
import com.opensymphony.xwork2.ActionSupport;
public class UserAction extends ActionSupport{
public String login(){
//com.opensymphony.xwork2.interceptor.ModelDrivenInterceptor
//读取资源包数据-读取资源顺序【局部-包级别-全局】
System.out.println(getText("login.username"));
System.out.println(getText("login.password"));
System.out.println(getText("login.submit"));
return NONE;
}
}
- 在struts.xml中配置
<!-- 开发模式 -->
<constant name="struts.devMode" value="true"></constant>
<!-- 配置全局的国际化 -->
<constant name="struts.custom.i18n.resources" value="resources.message"/>
<package name="p1" extends="struts-default">
<action name="login" class="com.it.web.action.UserAction" method="login">
</action>
</package>
- 访问路径:http://localhost:8080/day04_struts2_demo3/login
- 效果:
- 局部消息资源包
- 资源包名称命名规范:动作类名称_语言代码_国家代码.properties。以此种命名方式的资源包,只为动作类服务。
- 优先级最高(就近原则)。
- Struts2中资源包的搜索顺序:
第二步:读取资源包内容
- jsp读取资源包内容
- 使用struts的标签s:text获取国际化内容,上面的jsp代码中已使用
- Action读取资源包内容
- 使用ActionSupport的getText方法,可以读取到资源包的内容
- 也就是说这个Action一定要继承ActionSupport
- 这种在实际开发中几乎不用
- 自由指定读取资源包
- 在jsp页面可以使用s:i18n标签指向读取的国际资源包文件
- 修改后的login2.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="/struts-tags" prefix="s"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<hr>
<form action="${pageContext.request.contextPath}/login.action">
<s:i18n name="com.it.web.package">
<s:text name="login.username"/> <input type="text" name="username"><br>
<s:text name="login.password"/><input type="password" name="password"><br>
<input type="submit" value="<s:text name="login.submit"/>">
</s:i18n>
</form>
</body>
</html>
- 效果:指定访问包范围内资源文件