java EE开发之Struts2第二章:参数传递(1)

  struts2的一个重要的使用就是参数的传递,既jsp页面的参数值怎么样传递到action中进行业务的处理。
一,Action访问Servlet API

方式一: 在Action 中解耦合方式 间接访问 Servlet API ——— 使用 ActionContext 对象
在struts2 中 Action API 已经与 Servlet API 解耦合 (没有依赖关系 )
* Servlet API 常见操作 : 表单提交请求参数获取,向request、session、application三个范围存取数据

actionContext = ActionContext.getContext();
1)actionContext.getParameters(); 获得所有请求参数Map集合 相当request.getParameter
Map();
2) actionContext.put(“company”, “凯舟教育”); / actionContext.get(“company”) 对request范围存取数据
3) actionContext.getSession(); 获得session数据Map,对Session范围存取数据不是servletApi
4) actionContext.getApplication(); 获得ServletContext数据Map,对应用访问存取数据

方式二、 使用接口注入的方式,操作Servlet API (耦合)
ServletContextAware : 注入ServletContext对象
ServletRequestAware :注入 request对象
ServletResponseAware : 注入response对象

  • 程序要使用哪个Servlet的对象,实现对应接口

方式三、 在Action中直接通过 ServletActionContext 获得Servlet API
ServletActionContext.getRequest() : 获得request对象 (session)
ServletActionContext.getResponse() : 获得response 对象
ServletActionContext.getServletContext() : 获得ServletContext对象
* 静态方法没有线程问题,ThreadLocal

二 .Action处理请求参数

struts2 和 MVC 定义关系
StrutsPrepareAndExecuteFilter : 控制器
JSP : 视图
Action : 可以作为模型,也可以是控制器

struts2 Action 接受请求参数 :属性驱动 和 模型驱动
【1.Action处理请求参数三种方式】

第一种 :Action 本身作为model对象,通过成员setter封装 (属性驱动 )
页面:
用户名 <input type="text" name="username" /> <br/>
Action :

    public class RegistAction1 extends ActionSupport {
            private String username;
            public void setUsername(String username) {
                this.username = username;
            }
        }

问题一: Action封装数据,会不会有线程问题 ?
答:struts2 Action 是多实例 ,为了在Action封装数据 (struts1 Action 是单例的 )
问题二: 在使用第一种数据封装方式,数据封装到Action属性中,不可能将Action对象传递给 业务层
答:需要再定义单独JavaBean ,将Action属性封装到 JavaBean

第二种 :创建独立model对象,页面通过ognl表达式封装 (属性驱动)
页面:

用户名:<input type="text" name="user.username" /> <br/>  ----- 基于OGNL表达式的写法

Action:

public class RegistAction2 extends ActionSupport {
    private User user;
    public void setUser(User user) {
        this.user = user;
    }

    public User getUser() {
        return user;
    }
}

问题: 谁来完成的参数封装
答:通过下面的拦截器

<interceptor name="params" class="com.opensymphony.xwork2.interceptor.ParametersInterceptor"/>

第三种 :使用ModelDriven接口,对请求数据进行封装 (模型驱动 ) —– 主流
页面:

用户名  <input type="text" name="username" /> <br/>  

Action :

public class RegistAction3 extends ActionSupport implements ModelDriven<User> {
    private User user = new User(); // 必须手动实例化
    public User getModel() {
        return user;
    }
}

优点: 解决了属性驱动存在的问题
缺点: 一次只能封装一个model对象.
另外 struts2 有很多围绕模型驱动的特性
<interceptor name="modelDriven" class="com.opensymphony.xwork2.interceptor.ModelDrivenInterceptor"/> 为模型驱动提供了更多特性
对比第二种、第三种 : 第三种只能在Action中指定一个model对象,第二种可以在Action中定义多个model对象

<input type="text" name="user.username" /> 
    <input type="text" name="product.info" />

三,封装数据到Collection和Map

1) 封装数据到Collection 对象
页面:

username1:<input type="text" name="users[0].username"><br>
        password1:<input type="password" name="users[0].password"><br>

        username2:<input type="text" name="users[1].username"><br>
        password2:<input type="password" name="users[1].password"><br>

Action :

public class UserAction extends ActionSupport {
    private List<User> users;

    public List<User> getProducts() {
        return users;
    }

    public void setProducts(List<User>  users) {
        this.users= users;
    }
}

2) 封装数据到Map 对象
页面:

产品名称 <input type="text" name="map['one'].name" /><br/>  =======  one是map的键值

Action :

public class ProductAction2 extends ActionSupport {
    private Map<String, Product> map;

    public Map<String, Product> getMap() {
        return map;
    }

    public void setMap(Map<String, Product> map) {
        this.map = map;
    }
}   

四, 请求参数的转换

1、 struts2 内部提供大量类型转换器,用来完成数据类型转换问题
boolean 和 Boolean
char和 Character
int 和 Integer
long 和 Long
float 和 Float
double 和 Double
Date 可以接收 yyyy-MM-dd格式字符串
数组 可以将多个同名参数,转换到数组中
集合 支持将数据保存到 List 或者 Map 集合

案例: 输入合法年龄和生日可以自动转换
当输入abc 转换为 int类型 age时

    Caused by: java.lang.NoSuchMethodException: com.kz.struts2.demo3.CustomerAction.setAge([Ljava.lang.String;
分析: 输入20 ,转换 int类型20  --- setAge(int) 
      输入abc,转换int 出错 ---- setAge(String) ----- 报错方法不存在异常

五,自定义类型转换器

1) 自定义类型转换器

第一种 实现TypeConverter接口

convertValue(java.util.Map<java.lang.String,java.lang.Object> context, 
            java.lang.Object target, 
            java.lang.String propertyName, 
            java.lang.Class toType) 

第二种 继承 DefaultTypeConverter

convertValue(java.util.Map<java.lang.String,
            java.lang.Object> context, 
            java.lang.Object value,
            java.lang.Class toType) 

第三种 继承 StrutsTypeConverter

convertFromString(java.util.Map context, 
                java.lang.String[] values, 
                java.lang.Class toClass)  --- 请求封装
convertToString(java.util.Map context, java.lang.Object o)   --- 数据回显 

类型转换器 一直都是双向转换
页面提交请求参数,封装到model — 需要转换
model数据 需要在页面 回显 —- 需要转换

2) 以 1990/10/10 为例,自定义日期转换器,完成转换

public Object convertValue(Map<String, Object> context, Object value,
    Class toType) {
    // 根据toType判断 是请求封装 还是 数据回显
    DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd");
    if (toType == Date.class) {
        // 请求参数封装 (value是字符串)
        String[] params = (String[]) value;
        String strVal = params[0]; // 转换为 日期类型
        try {
            return dateFormat.parse(strVal);
        } catch (ParseException e) {
            e.printStackTrace();
        }
    } else {
        // 回显(value是 Date)
        Date date = (Date) value;
        return dateFormat.format(date);
    }

    return null;
}

3) 注册类型转换器
局部注册 : 只对当前Action有效或者model有效(针对属性)
全局注册 : 针对所有Action的日期类型有效 (针对类型 )

具体方法

1.局部–针对于action
配置文件所在位置以及名称: 在Action类所在包 创建Action类名-conversion.properties ,
配置文件书写: 格式 : 属性名称=类型转换器的全类名

2.局部–针对于model
配置文件所在位置以及名称: 在model类所在包 创建model类名-conversion.properties ,
配置文件书写: 格式 : 属性名称=类型转换器的全类名

3.全局
配置文件所在位置以及名称:在src下创建一个xwork-conversion.properties

六,类型转换错误处理

Struts2中的struts-default.xml文件中的defaultStack拦截器栈中18个拦截器中的

通过分析拦截器作用,得知当类型转换出错时,自动跳转input视图 ,在input视图页面中 <s:fieldError/> 显示错误信息
在Action所在包中,创建 ActionName.properties,在局部资源文件中配置提示信息 : invalid.fieldvalue.属性名= 错误信息
注意:
1,如果是自定义类型转换器,出现类型转换问题,要跳转到input视图,在类型转换器中, 必须抛出异常才可以。throw new RuntimeException();
2,action必须继承之ActionSupport (调用里面的addFieldError())

七,请求参数的校验

【1.手工代码校验请求参数】

步骤一: 封装数据
步骤二: 实现 校验Action ,必须继承ActionSupport 类 (查看ActionSupport源码 继承 了validatable validateware接口 具有了校验功能!)
步骤三: 覆盖validate方法,完成对Action的业务方法 数据校验
通过代码逻辑判断参数是否有效,如果参数非法 , this.addFieldError (ActionSupport提供)workflow拦截器 跳转回 input页面
步骤四: 在jsp中 通过 <s:fieldError/> 显示错误信息
validate方法会对Action中所有业务方法进行校验,如果只想校验某一个方法 : validate方法名() ,例如:请求处理方法叫 regist() 校验 的方法名 validateRegist().
原理:

【2.Xml配置方式数据校验】

XML配置方式 数据校验 (企业主流校验)
代码校验 不适用于 大型项目, 流程数据复杂时,开发量和维护量 都会很大
xml配置校验原理 : 将很多校验规则代码已经写好,只需要在xml中定义数据所使用校验规则就可以了
步骤一 :编写jsp
步骤二 :编写Action 必须继承ActionSupport 或者 实现 Validateable 接口
步骤三 :封装请求参数
* 使用xml校验 必须提供get方法
步骤四 :编写校验规则xml文件
在Action所在包 编写 Action类名-validation.xml 对Action所有业务方法进行校验 引入DTD

xwork-core-2.3.7.jar 中 xwork-validator-1.0.3.dtd 
        <!DOCTYPE validators PUBLIC
        "-//Apache Struts//XWork Validator 1.0.3//EN"
        "http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd">

内置校验器定义文件

xwork-core-2.3.7.jar 中 /com/opensymphony/xwork2/validator/validators/default.xml

书写:
1.根元素

<validators>

2.子元素

    <field name="属性名称"></field>

@kate这里的属性名称 由谁决定?
如果属性驱动:jsp页面的name值 例如:user.uname
jsp中:<input name=”user.uname”/>
action中:private Users user;
如果模型驱动:jsp页面的name值 例如:uname
jsp中:<input name=”uname”/>
action中:private Users user;

3.<field>子元素
<field-validator type="校验器"> 这个是指定校验器
问题:校验器有哪些? 看下面

4.子元素

<message>错误信息</message>

5.<field-validator>子元素

<param name=""></param>

用于指定校验器中的参数.

步骤五 :获取校验错误信息

<s:fielderror/>

内建校验器—-查看校验器类的源码 属性就是我们要配的参数

required (必填校验器,要求被校验的属性值不能为null)
requiredstring (必填字符串校验器,要求被校验的属性值不能为null,并且长度大于0,默认情况下会对字符串去前后空格 也可以配置<param name=”trim”>false</param>)
stringlength (字符串长度校验器,要求被校验的属性值必须在指定的范围内,否则校验失败,minLength参数指定最小长度,maxLength参数指定最大长度,trim参数指定校验field之前是否去除字符串前后的空格)
regex (正则表达式校验器,检查被校验的属性值是否匹配一个正则表达式,expression参数指定正则表达式,caseSensitive参数指定进行正则表达式匹配时,是否区分大小写,默认值为true)
int(整数校验器,要求field的整数值必须在指定范围内,min指定最小值,max指定最大值)
double(双精度浮点数校验器,要求field的双精度浮点数必须在指定范围内,min指定最小值,max指定最大值)
fieldexpression (字段OGNL表达式校验器,要求field满足一个ognl表达式,expression参数指定ognl表达式,该逻辑表达式基于ValueStack进行求值,返回true时校验通过,否则不通过)
email(邮件地址校验器,要求如果被校验的属性值非空,则必须是合法的邮件地址)
url(网址校验器,要求如果被校验的属性值非空,则必须是合法的url地址)
date(日期校验器,要求field的日期值必须在指定范围内,min指定最小值,max指定最大值)

案例
required 必填校验器

<field-validator type="required">
       <message>性别不能为空!</message>
</field-validator>

requiredstring 必填字符串校验器

<field-validator type="requiredstring">
       <param name="trim">true</param>
       <message>用户名不能为空!</message>
</field-validator>

stringlength:字符串长度校验器

<field-validator type="stringlength">
    <param name="maxLength">10</param>
    <param name="minLength">2</param>
    <param name="trim">true</param>
    <message><![CDATA[产品名称应在2-10个字符之间]]></message>
</field-validator>

NOTE:要配合非空校验器一起使用

int:整数校验器

<field-validator type="int">
    <param name="min">1</param>
    <param name="max">150</param>
    <message>年龄必须在1-150之间</message>
</field-validator>

date: 日期校验器

<field-validator type="date">
    <param name="min">1900-01-01</param>
    <param name="max">2050-02-21</param>
    <message>生日必须在${min}到${max}之间</message>
</field-validator>

url: 网络路径校验器

<field-validator type="url">
    <message>凯舟教育的主页地址必须是一个有效网址</message>
</field-validator>

email:邮件地址校验器

<field-validator type="email">
    <message>电子邮件地址无效</message>
</field-validator>

regex:正则表达式校验器

<field-validator type="regex">
     <param name="regexExpression"><![CDATA[^13\d{9}$]]></param>
     <message>手机号格式不正确!</message>
</field-validator>

fieldexpression : 字段表达式校验

<field-validator type="fieldexpression">
       <param name="expression"><![CDATA[(password==repassword)]]></param>
       <message>两次密码输入不一致</message>
</field-validator>

如何对指定的方法校验 ?

格式 Action类名-ActionName(元素name属性)-validation.xml
例如 : 校验AddCustomerAction中execute方法 配置 <action name="addcustomer" .../> 校验文件名字:
AddCusotmerAction-addcustomer-validation.xml

<action name="regist" class="com.kz.action.UserAction" method="regist">
    <result name="input">/regist.jsp</result>
</action>

配置UserAction-regist.validation.xml 只会校验 regist方法

<action name="login" class="com.kz.action.UserAction" method="login">
    <result name="input">/regist.jsp</result>
</action>

配置UserAction-login.validation.xml 只会校验 login方法

【3 .自定义校验规则】

步骤一: 自定义校验器 必须实现 Validator 接口
通常自定义校验器 继承 ValidatorSupport 和 FieldValidatorSupport
* ValidatorSupport 针对不是一个输入字段 (两个密码一致)
* FieldValidatorSupport 针对是一个输入字段 (用户名非空)
步骤二: 注册校验器
在工程的src下新建validators.xml文件
引入 xwork-core-2.3.7.jar 中 xwork-validator-config-1.0.dtd
步骤三 :使用校验器
在Action所有包 创建Action类名-validation.xml

实际开发中很少用到自定义校验器 因为有正则表达式可以做任何校验

发布了26 篇原创文章 · 获赞 13 · 访问量 7017

猜你喜欢

转载自blog.csdn.net/womeia331416/article/details/78341269