Struts实例的解析,一个例子就懂了好多~

在前面的一篇文章中,使用的是官方例子,这里对其进行一个分析学习。

这个例子是基于Struts2的,和Struts1有区别。

代码的整体结构如下



先从配置文件入手,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.enable.DynamicMethodInvocation" value="false" />
    <constant name="struts.devMode" value="true" />

    <package name="default" namespace="/" extends="struts-default">

        <default-action-ref name="index" />

        <global-results>
            <result name="error">/error.jsp</result>
        </global-results>

        <global-exception-mappings>
            <exception-mapping exception="java.lang.Exception" result="error"/>
        </global-exception-mappings>

        <action name="index">
            <result type="redirectAction">
                <param name="actionName">HelloWorld</param>
                <param name="namespace">/example</param>
            </result>
        </action>
    </package>

    <include file="example.xml"/>

    <!-- Add packages here -->

</struts>

有include的xml文件,example.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
        "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
        "http://struts.apache.org/dtds/struts-2.0.dtd">

<struts>

    <package name="example" namespace="/example" extends="default">

        <action name="HelloWorld" class="example.HelloWorld">
            <result>/example/HelloWorld.jsp</result>
        </action>

        <action name="Login_*" method="{1}" class="example.Login">
            <result name="input">/example/Login.jsp</result>
            <result type="redirectAction">Menu</result>
        </action>

        <action name="*" class="example.ExampleSupport">
            <result>/example/{1}.jsp</result>
        </action>

        <!-- Add actions here -->
    </package>
</struts>

在上面可以看到通配符*,支持通配符

<action name="Login_*" method="{1}" class="example.Login">
            <result name="input">/example/Login.jsp</result>
            <result type="redirectAction">Menu</result>
        </action>

想必:Login_execute, Login_test 等Action名称, 而method="{1}" 中的{1} 应该是 第一个通配符的值, 例如execute, test, 也就是说要执行java 类Login 中的execute,input方法。
实验一下:http://localhost:8080/Struts2Demo/example/Login_execute, 注意namespace 是/example
果然登录界面出现了:


上面的...required是必然出现的,因为检查为false

测试一下 http://localhost:8080/Struts2Demo/example/Login_test


由于没有test方法,所以肯定抛异常,这个异常是自己定义的啦

        <global-results>
            <result name="error">/error.jsp</result>
        </global-results>

这里的error.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java"%>
<%@ taglib prefix="s" uri="/struts-tags"%>

<html>
<head>
<title>Simple jsp page</title>
</head>
<body>
	<h3>Exception:</h3>
	<s:property value="exception" />

	<h3>Stack trace:</h3>
	<pre>
        <s:property value="exceptionStack" />
    </pre>
</body>
</html>

但是,上面的一篇文章中有说ActionForm的,但是在哪里啊,没有找到。

原来,Struts2中有进步的啦。

在Struts1 中,是使用ActionForm 来封装从浏览器中来的数据,每个Action 都需要写一个ActionForm,, 用起来虽然比较麻烦,但是比较清晰。
在Struts2中,我们似乎并没有看到类似的概念,只看到在Action中的一些getter和setter方法,例如class Login 中的username,password

/*
 * $Id: Login.java 471756 2006-11-06 15:01:43Z husted $
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package example;

public class Login extends ExampleSupport {

    public String execute() throws Exception {

        if (isInvalid(getUsername())) return INPUT;

        if (isInvalid(getPassword())) return INPUT;

        return SUCCESS;
    }

    private boolean isInvalid(String value) {
        return (value == null || value.length() == 0);
    }

    private String username;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    private String password;

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

}

在Login.jsp中,肯定有与其相对应的类似javabean的东西

<s:form action="Login">
    <s:textfield key="username"/>  <--- 肯定是和class Login 中的username 绑定
    <s:password key="password" />  <--- 肯定是和class Login 中的password 绑定
    <s:submit/>
</s:form>
我们在setUsername和setPassword中,可以加入一些System.out函数,来看一下何时调用。

在Struts2中, Form 和 Action是混到一起了,Action中可以有实例变量,并且可以被框架自动赋值(当然是通过setter方法),至于通过getter暴露出的属性值,在jsp中可以引用。
既然Action中有实例变量,那就意味着Struts2会为每一个http request 创建一个新的Action实例(Struts1不是这样的),所以你不用担心线程安全问题。


为什么要混合ActionForm和Action?

为每个Action开发一个ActionForm确实是一件不那么Happy的事情,需要额外的工作建立一个额外ActionForm的类, 并且这个类只能用在相关的Action上。
Struts2 则把Action和ActionForm合并为一了, 咋一看感觉比较乱,但用起来就会发现,确实是极大的减少了开发量,通过简单的getter/setter就能获取界面上的数据。
虽然在设计上看起来不够优雅和完美,但实用性十足,这就够了。
对于那些追求完美的同学, 我相信struts2 还是能支持ActionForm 的。


如何做输入验证?

就是简单的一个xml文件中验证的啦,在Login_validator.xml文件中,

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

<validators>
    <field name="username">
        <field-validator type="requiredstring">
            <message key="requiredstring"/>
        </field-validator>
    </field>
    <field name="password">
        <field-validator type="requiredstring">
            <message key="requiredstring"/>
        </field-validator>
    </field>
</validators>

1. 有两个field,肯定是验证两个的啦。

2. 然后,field-validator的type是requiredstring,就是说需要字符串类型的啦,也不想要null

3. 如果失败,需要message,这里的massage是key=。。。所以,一定是个键值,在resource中有定义的。

4. 估计也是根据名字来进行统配的。<ActionName>_validator.xml,所以是和Action相配的,需要在同一个package下面。

HelloWorld.message= Struts is up and running ...
requiredstring = ${getText(fieldName)} is required.
password = password
username = username
Missing.message =  This feature is under construction. Please try again in the next interation.
上面就是有个requiredstring的键值,
${getText(fieldName)} is required
其中,

fieldName 应该就是当前要验证的filed的名称,例如"username", "password"
而getText() 应该是struts2提供的方法,估计是为了多语言处理的,如果当前的field 是"username" , 那么 getText(“username”) 在这个例子中就是“User Name”.


错误信息怎么显示?

验证失败,肯定要在jsp 中输入错误信息,这一点Struts2的tag library已经给我们封装好了, 当然是高度封装:

<%@ page contentType="text/html; charset=UTF-8" %>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
    <title>Sign On</title>
</head>

<body>
<s:form action="Login">
    <s:textfield key="username"/>
    <s:password key="password" />
    <s:submit/>
</s:form>
</body>
</html>
如果username 或者password没有输入, struts2就会在每一个输入域的上方显示错误消息。
注意 <s:textfield key="username"/> 用的是key = xxx , 你可以试一下 name=xxxx, 就可以发现 其中的奥秘:
使用key =xxx , 最终的html中既有label ,又有input field, 使用name=xxx,只会输出 input filed ,需要自己来写label 了。

我只能通过xml文件类配置输入验证吗

当然不是,这个例子中就有的啦。

重写方法validate。

观察一下Login这个类, 它最终扩展了ActionSupport ,这个类有很多和验证相关的方法,例如addFieldError (),validate()等等,我们尝试一下在class Login中覆盖validate方法:

public void validate(){
    	if(!"andy".equals(getUsername())){
    		addFieldError("username",getText("user.incorrect"));
    	}
    	if(!"pass4andy".equals(getPassword())){
    		addFieldError("password",getText("password.incorrect"));
    	}
    }

当然要记得在package.properties 新添加两个message 

user.incorrect=User name is not correct

password.incorrect=Password is not correct


当然,这里可以去查调用其它的,比如来查数据库的啦。


后记

部分参考 http://www.myexception.cn/program/1434295.html

谢谢




©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页