一、自定义一个结果类型
1.编写一个类,实现com.opensymphony.xwork2.Result接口。
例子 :输出验证码在方法中可以通过ServletAPI请求request response完成功能
//自定义的结果视图类型 输出一副验证码图像
public class CaptchaResult implements Result {
<span style="color:#3366ff;">//图片的宽高 这里给了set方法 在struts.xml配置文件里面就可以注入属性了</span>
private int width = 80;
private int height = 25;
public int getWidth() {
return width;
}
public void setWidth(int width) {
this.width = width;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
public void execute(ActionInvocation arg0) throws Exception {
// 自定义结果需要response 这里通过ServletActionContext获取
HttpServletResponse response = ServletActionContext.getResponse();
// 产生由4位数字构成的验证码
int length = 4;
String valcode = "";
Random rd = new Random();
for (int i = 0; i < length; i++)
valcode += rd.nextInt(10);
BufferedImage img = new BufferedImage(width, height,
BufferedImage.TYPE_INT_RGB);
// 获取一个Graphics
Graphics g = img.getGraphics();
// 填充背景色
g.setColor(Color.WHITE);
g.fillRect(1000, 1000, width, height);
// 填充干扰线200
for (int i = 0; i < 5000; i++) {
g.setColor(new Color(rd.nextInt(100) + 155, rd.nextInt(100) + 155,
rd.nextInt(100) + 155));
g.drawLine(rd.nextInt(width), rd.nextInt(height),
rd.nextInt(width), rd.nextInt(height));
}
// 绘制边框
g.setColor(Color.GRAY);
g.drawRect(0, 0, width - 1, height - 1);
// 绘制验证码
Font[] fonts = { new Font("隶书", Font.BOLD, 18),
new Font("楷体", Font.BOLD, 18), new Font("宋体", Font.BOLD, 18),
new Font("幼圆", Font.BOLD, 18) };
for (int i = 0; i < length; i++) {
g.setColor(new Color(rd.nextInt(150), rd.nextInt(150), rd
.nextInt(150)));
g.setFont(fonts[rd.nextInt(fonts.length)]);
g.drawString(valcode.charAt(i) + "", width / valcode.length() * i
+ 2, 18);
}
// 输出图像
g.dispose();
ImageIO.write(img, "jpeg", response.getOutputStream());
}
2.在struts.xml中声明自定义结果类型
<package name="<span style="color:#3333ff;">mystruts-default</span>" extends="struts-default">
<!-- 声明结果类型 -->
<result-types>
<result-type name="captcha" class="com.test.result.CaptchaResult"></result-type>
</result-types>
</package>
3.使用 如果自定义结果视图大家都要用时 就可以这样 继承的是声明的包
<package name="p1" extends="<span style="color:#3333ff;">mystruts-default</span>">
<action name="captcha">
<result name="success" type="captcha">
<span style="color:#ff0000;"> <!-- 注入参数 验证动作里面已有宽高的set方法 -- captcharesult.setheight() 这样></span>
<span style="color:#3333ff;"> <param name="height">100</param>
<param name="width">100</param> </span>
</result>
</action>
</package>
二、Action接收请求参数
作为MVC框架 必须要负责解析HTTP请求的参数 然后封装到javaBean Struts2提供了非常强大的类型转换机制用于请求数据到model对象的封装
(一)封装请求参数有三种方式 常用第二或三种
1.方式一、用动作类作为模型对象 直接封装请求的参数
注:静态参数注入是由一个名字为staticParams拦截器完成的。
a. 首先一个模型 set get略了 请求来的参数可以在execute里处理
public class Person extends ActionSupport {
private String username;
private String password;
private String nickname;
public String execute() throws Exception {
System.out.println("username:"+username+"password:"+password+"nickname:"+nickname);
return SUCCESS;
}
}
b、注入动态(用户输入)参数
jsp:
编写原则:表单的输入域的名称和动作类中的属性名(getter和setter)保持一致。
<form action="${pageContext.request.contextPath}/act1" method="post">
用户名:<input type="text" name="username"/><br/>
密码:<input type="password" name="password"/><br/>
呢称:<input type="text" name="nickname"/><br/>
<input type="submit" value="注册">
</form>
c、注入静态参数 如果用户没有输入呢称的值 就是自己静态注入的游客
<action name="act1" class="com.test.action.Person">
<span style="color:#3333ff;"> <!-- 这里注入参数 相当于Person.setNickname("游客") --></span>
<param name="nickname">游客</param>
</action>
2、方式二 动作类和模型对象分离
a. Student模型
public class Student extends ActionSupport {
private String username;
private String password;
private String nickname;
b.动作
public class StudentAction {
private Student student=new Student();
public Student getStudent() {
return student;
}
public void setStudent(Student student) {
this.student = student;
}
public String save() {<span style="color:#3333ff;">
//在实际操作中这里就可以实现以下功能
// 把表单数据封装到模型对象中
// 调用Service把Student的数据保存到数据库中
</span> System.out.println(student.getUsername() + student.getPassword()
+ student.getNickname());
return "none";
}
}
c、struts.xml的配置
<action name="act2" class="com.test.action.StudentAction" method="save"></action>
d、jsp
重要的是name名 是模型的属性 相当于 student.setusername
<span style="color:#3333ff;"> </span><form action="${pageContext.request.contextPath}/act2" method="post">
用户名:<input type="text" name="<span style="color:#ff0000;">student.username</span>"/><br/>
密码:<input type="text" name="student.password"/><br/>
呢称:<input type="text" name="student.nickname"/><br/>
<input type="submit" value="注册"/>
</form>
总结:框架会探测student这个模型是否为空 如果为空 注入他的实例 分别调用对象的属性 注入值 会调用3次getStudent 来分别注入值
3、(模型和动作分开) 模型驱动 动作类要实现 ModelDriven
a.模型
public class Customer {
private String username;
private String password;
private String nickname;
b、动作类
public class CustmomerAction implements ModelDriven<Customer> {
private Customer customer = new Customer();// 模型一定要new出来
public Customer getCustomer() {
return customer;
}
public void setCustomer(Customer customer) {
this.customer = customer;
}
public String save() {
System.out.println(customer);
return "success";
}
// 调用动作方法前,框架会先调用这个方法
// 这个方法不会实例化customer
public Customer getModel() {
return customer;
}
c、jsp
<form action="${pageContext.request.contextPath}/act3" method="post">
用户名:<input type="text" name="username"/><br/>
密码:<input type="password" name="password"/><br/>
呢称:<input type="text" name="nickname"/>
<input type="submit" value="注册"/>
注:实际上是一个名字为modelDriven拦截器完成的。该拦截器会在调用动作方法前,调用getModel(),得到模型对象,他接着把该模型对象压到了值栈的栈顶。表单的username的值,框架就会调用栈顶对象的setUsername方法。
关键点:实现ModelDriven接口;模型对象要自己实例化;
(二)封装集合或者map(实际开发很少用的)
封装list
name的[]就是代表存在一个集合里
封装map
三、类型转换(开发中几乎不用的 struts自带有 需要理解)
两种情况 1.用户输入的都是字符串 2.显示出的都是字符串
类型转换一般用于 String转换其他类型(用于存储) 其他类型转换String(用于显示)
Struts2类型转换的继承体系
1.自定义类型转换器
a、编写一个类 继承strutsTypeConverter
//自定义类型转换器:
//String--->java.util.Date MM/dd/yyyy
//java.util.Date----->String MM/dd/yyyy
public class MyConvertor extends StrutsTypeConverter {
// 自己定义date格式
private DateFormat df = new SimpleDateFormat("MM/dd/yyyy");
// string----------------------->java.util.Date MM/dd/yyyy 字符串转date
// values:用户输入的值
// toClass:目标类型
public Object convertFromString(Map context, String[] values, Class toClass) {
if (toClass == Date.class) {//判断请求的值是否date
if (values != null && values.length > 0) {
String sdate = values[0];
try {
return df.parse(sdate);
} catch (ParseException e) {
throw new RuntimeException(e);
}
}
}
return null;
}
// java.util.Date--------------->String
public String convertToString(Map context, Object o) {
if(o instanceof Date){
Date d =(Date)o;
return df.format(d);
}
return null;
}<span style="color:#3333ff;">
</span>
b、注册类型转换器 类型转换器分2种
b1、局部转换器 给某个动作用的
在动作类所在包下 创建一个 动作类名-conversion-properties的配置文件
指定birthday这个属性转换
b2、全局类型转换器:给所有动作用 在构建路径 src目录下建立名称为xwork-conversion.properties的配置文件,按照自己的目标类型进行转换器的配置
2、转换失败的时的回显和错误提示
前提是 动作类需要继承ActionSupport类
出现转换失败时,由一个名字为conversionError拦截器负责处理的。会把错误信息封装起来,并且转向一个叫做input的逻辑视图(用于回显数据)。
更改默认的提示错误
a、在动作类中建立一个 动作类名-properties的配置文件内容如下
四、数据校验(开发经常写)
校验分种 客户端校验:javaScript完成
服务器端校验:代码
实际开发 是2种校验都需要写
前提:动作类需要继承ActionSupport 验证是由Validation(声明式校验)、workflow(错误提示)完成的
a、编程式校验:动作类中写代码
a.1针对动作类中的所有动作方法进行校验 在动作类中,覆盖掉validate方法
a.2针对动作类中的指定方法进行校验 有2种方式
方式一:比较麻烦
方式二:使用注解,简单
b、声明式校验(推荐):写配置文件
把校验规则和消息提示放到配置文件中。
b.1针对动作类所有方法进行校验
在动作列类所在的包中,建立名字为 动作类名-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>
<!-- 方式一: 给一个字段指定多个验证器 type是框架提供的验证器
<field name="name">
<field-validator type="requiredstring">
<message>名字不能为空</message>
</field-validator>
</field>
-->
<!-- 方式二 验证器验证字段 还可以验证非字段的验证 -->
<validator type="requiredstring">
<param name="fieldName">age</param>
<message>年龄不能为空</message>
</validator>
</validators>
b2、针对指定方法进行效验
方式一 用 @skipValidation 注解
方式二 比较麻烦
在动作类的包下新建 动作类名-动作别名(就是struts.xml配置文件 Action动作给方法配的name名-validation.xml 写法跟针对所有方法一样
Struts2框架提供的内置验证器 可以参考Struts2解压出来的xwork.jar包下的
xwork-core-2.3.15.3.jar\com\opensymphony\xwork2\validator\validators\default.xml
例子 验证信息记住:不是字段验证 比如 验证2次密码是否一样 这种需要使用 struts标签 的 actionError
配置文件
<?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-validator type="regex">
<param name="regex">
<![CDATA[[a-zA-Z]{3,8}]]>
</param>
<message>名字必须由3~8位字母组成</message>
</field-validator>
</field>
<field name="password">
<field-validator type="requiredstring">
<message>密码不能为空</message>
</field-validator>
<field-validator type="strong">
<message>密码必须由至少一个大写和小写和数字组成</message>
</field-validator>
</field>
<!-- 非字段验证:要使用s:actionError显示错误 -->
<validator type="expression">
<param name="expression">
repassword==password
</param>
<message>两次密码必须一致</message>
</validator>
<field name="email">
<field-validator type="email">
<message>输入正确的邮箱</message>
</field-validator>
</field>
<field name="birthday">
<field-validator type="date">
<param name="min">2000-01-01</param>
<param name="max">2010-12-31</param>
<message>请输入正确的日期</message>
</field-validator>
</field>
<field name="netaddress">
<field-validator type="url">
<message>请输入正确的地址:协议_主机_资源地址</message>
</field-validator>
</field>
</validators>
jsp:
<!-- 非字段验证:要使用s:actionError显示错误 -->
<s:actionerror/>
<s:form action="act3">
<s:textfield name="username" label="用户名"></s:textfield>
<s:textfield name="password" label="密码"></s:textfield>
<s:textfield name="repassword" label="重复密码"></s:textfield>
<s:textfield name="email" label="邮箱"></s:textfield>
<s:textfield name="birthday" label="出生日期(MM/dd/yyyy)"></s:textfield>
<s:textfield name="netaddress" label="地址"></s:textfield>
<s:submit value="注册"></s:submit>
</s:form>
自定义声明式校验
a.编写一个类,继承FieldValidatorSupport 定义一个基于字段的验证器
import org.apache.commons.lang3.StringUtils;
import com.opensymphony.xwork2.validator.ValidationException;
import com.opensymphony.xwork2.validator.validators.FieldValidatorSupport;
//验证密码强度
public class StrongPasswordValidator extends FieldValidatorSupport {
// object:实际上就是动作类
public void validate(Object object) throws ValidationException {
String fieldName = getFieldName();// 得到要验证的字段名
String fieldValue = (String) getFieldValue(fieldName, object);
if (StringUtils.isNotEmpty(fieldValue)) {
// 有值时再做强度验证
if (!isPasswordStrong(fieldValue)) {
// 不满足条件就添加回显信息
addFieldError(fieldName, object);
}
}
}
private static final String GROUP1 = "abcdefghijklmnopqrstuvwxyz";
private static final String GROUP2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
private static final String GROUP3 = "0123456789";
protected boolean isPasswordStrong(String password) {
boolean ok1 = false;// 有一个小写字母就为true
boolean ok2 = false;// 有一个大写字母就为true
boolean ok3 = false;// 有一个数字就为true
int length = password.length();
for (int i = 0; i < length; i++) {
if (ok1 && ok2 && ok3)
break;
String character = password.substring(i, i + 1);
if (GROUP1.contains(character)) {
ok1 = true;
continue;
}
if (GROUP2.contains(character)) {
ok2 = true;
continue;
}
if (GROUP3.contains(character)) {
ok3 = true;
continue;
}
}
return ok1 && ok2 && ok3;
}
}
在src下建立一个validation.xml的配置文件 写法
可以参考Struts2解压出来的xwork.jar包下的
xwork-core-2.3.15.3.jar\com\opensymphony\xwork2\validator\validators\default.xml
<?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>
<validator name="strong" class="com.test.validation.StrongPasswordValidator"></validator>
</validators>
然后就可以直接在验证中使用了