posts - 78, comments - 34, trackbacks - 0, articles - 1
  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

2009-12-21传智播客——Struts1

Posted on 2009-12-22 20:24 長城 阅读(464) 评论(0)  编辑  收藏

         今天是Struts1的第二天,明天是最后一天。看我这么说,多少感觉Struts1有点烦。因为总是使用配置文件,不用怎么写代码,一个强大的表单校验功能就完成了。其实我们一直专注于代码的重用,减少重复工作所带来的枯燥与麻烦,从这个角度上想,Struts是相当好的!

         下面我们来看一下今天的重点内容:

一、复杂验证

         什么是复杂验证?相比昨天的简单验证(ActionForm)复杂在哪里呢?其一点也不复杂,一说便知。昨天的简单验证是对浏览器提交的Form表单信息的验证,比如用户注册时输入的用户名、密码、生日、邮箱等信息是否合法。而复杂验证,就是对业务逻辑的验证,比如在Action中调用业务逻辑的DAO,验证用户的登录信息是否有效。

         例如,在昨天的练习中添加一个用户登陆页面“login.jsp”,添加一个处理用户登陆的ActionLoginAction”(其实它可以与昨天的用户注册Action放到一起,后边再介绍),再添加一个用户DAOUserDao”。

login.jsp 下面为主体部分:

<body>

    <table align="center">

       <html:form action="${pageContext.request.contextPath }/lgoin.do">

           <tr>

              <td>用户名:</td>

              <td><html:text property="username" /></td>

           </tr>

           <tr>

              <td>密码:</td><td><html:password property="password"/></td>

           </tr>

           <tr>

              <td colspan="2"><html:submit value="登陆"/></td>

           </tr>

       </html:form>

    </table>

</body>

发现“<html:xxx…/>”没有?这是Struts常用的Html标签,下面会有介绍!

LoginAction.java,下面为主体部分

public class LoginAction extends Action {

    @Override

    public ActionForward execute(ActionMapping mapping, ActionForm form,

           HttpServletRequest request, HttpServletResponse response)

           throws Exception {

       // 获取用户提交的信息

       String username = request.getParameter("username");

       String password = request.getParameter("passowrd");

       // 调用UserDao查找用户

       UserDao ud = new UserDao();

       User user = ud.find(username, password);

       // 根据查找结果返回对应信息

       if(user == null){

           // 创建错误信息,也可以使用ActionErrors

           ActionMessages errors = new ActionMessages();

           ActionMessage message = new ActionMessage("errors.login.worng");

           errors.add("loginwrong", message);

           // 将信息保存到requestsession中。

           this.saveErrors(request, errors);

           // 跳转到错误页面

           return mapping.getInputForward();

       }  

       return mapping.findForward("success");

    }

}

其中的UserDao就不用列出来了,因为以前做的很多地方都有提到它。

登陆成功,直接跳转到昨天添加的“success.jsp”页面,显示欢迎信息。如果失败,则跳转回登陆页面,并使用“<html:errors/>”显示其错误信息。在此就不列出了。

注意一定要在struts-config.xml中配置这个新添加的LoginAction,具体信息如下:

<action path="/lgoin"

       type="cn.itcast.cc.actions.LoginAction"

       input="/login.jsp">

       <forward name="success" path="/success.jsp"></forward>

</action>

         昨天落下了一个知识点,信息资源文件。有没有发现,昨天的代码和今天的代码中有类似“ActionMessage("errors.login.worng")”的内容,其中的“"errors.login.worng"”是属性文件的key。这个属性文件是通过struts-config.xml配置的:

<message-resources parameter="MessageResources"></message-resources>

 

         Struts框架根据i18n的文件名称要求,自动加载配置文件,所有的提示信息都可以在这里设置。

         Ok,上边就是一个复杂验证的简单示例。至于到底有多复杂,视业务逻辑的复杂度而定。

 

二、处理Struts的中文乱码问题

         1.Actionexecute方法中有一个“HttpServletRequest”参数,使用这个参数设置编码格式可不可以?“request.setCharacterEncoding("UTF-8");”。No,如果requestgetParamter方法被调用过,setCharacterEncoding就无效。在什么地方调用了getParamter方法?ActionForm中调用了啊!

         2.编写一个filter,在这学习过滤器时已经介绍了。是一个好的解决办法。

         3.我们不是在1中说了,是ActionForm调用了getParameter方法吗?那就在getParameter之前调用setCharacterEncoding设置编码。ActionForm之前是什么?是ActionSerlvet,嗯,对的。我们需要使用继承重写ActionServlet,并覆盖ActionServletprocess方法,在process方法里设置编码。然后修改web.xmlaction名称的Servlet,使它的类指向我们自定义的ActionServlet

         4.除了通过编写自己的ActionServlet设置request的编码,也可以编写自己的RequestProcessor。什么是RequestProcessorActionServletprocess方法调用了RequestProcessor方法,RequestProcessorActionServlet控制器的核心。所以我们编写自己的RequestProcessor方法,并覆盖它的process方法,在process方法中设置request的编码。完成后,需要在struts-config.xml添加:

<controller processorClass="cn.itcast.cc.servlet.MyRequestProcessor"/>

         上边没什么复杂的,我就不一一实现了!

三、使用Struts处理表单重复提交的问题和StrutsHTML标签

         什么是表单重复提交?概括一下:在一个会话中,重复向服务器提交表单数据!这就是表单重复提交。比如,在当前页面下连续点击提交按钮(但页面一旦被刷新就启动了一个新会话)。

         在以前学习Session时,也有讲过这一问题。这一问题的处理办法:

1.        编写一个JavaScript脚本,当用户点击提交按钮时。使用按钮变灰(禁用),或设置一个标记,用户无法点击,或再次点击时判断这个标记值。来防止用户重复提交表单数据。

2.        在用户向服务器请求信息时,比如请求注册页面时。在服务器生成一个全球唯一标识符码,将标识符码同时保存到Session和页面的隐藏字段中。当用户提交注册信息时,对比Session和隐藏字段中的标识码,如果相同说明是用户第一次提交,此时,将Session中的标记码删除掉。当用户再次提交注册信息时,标识码已经不相同了(因为sesssion中的已经被删除了),所以就拒绝这个重复的请求。

3.        今天我们学习一个新的方便快捷的办法,处理表单重复提交的问题。此处连同strutsHtml标签一同介绍了。

1).我们修改昨天的注册页面的Body体内容为:

<body>

    <table align="center">

       <html:form>

           <tr>

              <td>用户名:</td>

              <td><html:text property="username" /></td>

           </tr>

           <tr>

              <td>密码:</td>

              <td><html:password property="password" /></td>

           </tr>

           <tr>  

              <td>确认密码:</td>

              <td><html:password property="password1" /></td>

           </tr>

           <tr>

              <td>生日:</td>

              <td><html:text property="birthday" "/></td>

           </tr>

           <tr>

              <td><html:submit value="注册"/></td>

              <td><html:reset value="重填"/></td>

           </tr>

       </html:form>

    </table>

</body>

         使用strutsHTML标签有什么好处?

1.        验证表单错误,表单回显。

2.        将表单与ActionForm进行校验,如果出现错误就抛异常。昨天没有使用strutsHTML标签时,是不会抛异常的。

注意:如果表单中存在“<html:checkbox/>”选项,它是不会被回显的,应当使用:<html:multibox property="interesting" value="reading"></html:multibox>

         2).在加载表单之前调用“TokenProcessor.saveToken()”方法,它会自动向表单和Session中添加全球唯一标识符(自动创建表单中的隐藏字段)。比如,我们可以在跳转到JSP页面的Action中添加“TokenProcessor.saveToken()”方法,也可以在JSP页面的表单之前添加““TokenProcessor.saveToken()”方法”。这里我们在JSP页面的表单之前添加:

<%

    org.apache.struts.util.TokenProcessor.getInstance().saveToken(request);

    %>

         3).启动服务器,访问注册页面。查看注册页面的源代码,发现自动生成了以下部分:

<form name="regForm" method="post" action="/091220StrutsLogin/reg.do;jsessionid=13ADEF2ADC0126D626FBE49EC98F5EFF">

    <div>

       <input type="hidden" name="org.apache.struts.taglib.html.TOKEN" value="cb279a07b286c393c7c1081a49e44313">

    </div>

其中 form 中的namemethodjsessionid<div>中的内容是自动添加的。

Name是表单ActionForm的名字,Sturts使用它与ActionForm进行校验。

Method是表单的提交方式。

Jsessionid当第一次请求注册页面时,或cookie被禁用时。Sturts框架会自动进行URL重写。

<div>中的内容是防止表单重复提交。

         4).在处理注册信息的Action中调用“TokenProcessor.isTokenValid(request)”方法用于判断表单是否重复提交,返回真为第一次提交,返回假为重复提交。然后调用“TokenProcessor.getInstance().resetToken(request);”方法清除seission的防止表单重复提交的信息,从此以后isTokenValid方法返回假。

                  

常用的Struts HTML标签(老佟的):

标签

用途/注解

html

产生一个<html>标签。也包括来自于用户会话中的 language 属性

form

定义一个表单。Action focus 属性是最有用的属性

checkbox

产生一个检查框字段

file

产生一个文件选择输入字段

hidden

产生一个隐藏字段

option

产生一个选择项

options

产生一个选择项列表

password

产生一个口令输入字段

radio

产生一个单选输入字段

select

产生一个选择元素

text

产生一个文本输入字段

textarea

产生一个 html 文本区域元素

image

产生一个图像输入字段

button

产生一个按钮输入字段

cancel

产生一个取消按钮

submit

产生一个提交按钮

reset

产生一个重新设定按钮

errors

显示错误消息

img

产生一个 html img 标签

 

四、使用Strutsvalidator插件进行简单的表单验证

         之前我们使用的是ActionForm进行表单的简单验证,在那里我们需要手动的进行各个字段的合法性验证,这是一个重复的工作,而且十分无聊。Validator插件,就是用于解决这个问题的。

1.struts中引入插件,需要向struts-config.xml文件添加:

<plug-in className="org.apache.struts.validator.ValidatorPlugIn">

        <set-property property="pathnames"

                value="/org/apache/struts/validator/validator-rules.xml,

                             /WEB-INF/validation.xml" />

    </plug-in>

   

其中pathnames属性的两个值:

1)./org/apache/struts/validator/validator-rules.xml”中定义了Validator提供的字段约束。validator-rules.xml文件在struts-core-1.3.8.jarorg.apache. struts.validator包中。

2)./WEB-INF/validation.xml”是Validator的配置文件。

2.如果你知道这个文件内容应该是什么样子。可以到struts包的apps目录下,解压缩struts-cookbook-1.3.8.war,在它的WEB-INF目录下就有一个validation.xml文件。我们向“WEB-INF”目录下添加“validation.xml”文件,并添加内容:

<form-validation>

    <formset>

       <form name="validatorForm">

<!—- 用户名 -->

           <field property="username" depends="minlength">

                <arg key="validator.min" position="0"/>

              <arg key="${var:minlength}" resource="false" position="1"/>             

              <var>

                  <var-name>minlength</var-name>

                  <var-value>6</var-value>

              </var>

           </field>

<!—- 密码 -->

           <field property="password" depends="required,minlength">

              <arg key="validator.password" position="0" />

              <arg key="${var:minlength}" resource="false" position="1" name="minlength"/>

              <var>

                  <var-name>minlength</var-name>

                  <var-value>5</var-value>

              </var>

           </field>

          

           <field property="password2" depends="validwhen">

              <msg name="validwhen" key="validator.validwhen.password2"/>

              <var>

                  <var-name>test</var-name>

                  <var-value>(*this*==password)</var-value>

              </var>

           </field>

<!—- 生日 -->

           <field property="birthday" depends="date">

              <arg key="validator. birthday" />

             

              <var>

                  <var-name>datePattern</var-name>

                  <var-value>yyyy-MM-dd</var-value>

              </var>

           </field>

       </form>

    </formset>

</form-validation>

         1).<form name="validatorForm">”指定ActionForm,这个ActionForm不需要编写自己的validate方法。

         2).一个<filed></filed>设置一个表单中的字段:

.property="username"”指向注册页面“<html:text property="username" />”。

.<arg key="validator.min" position="0"/>key指向配置文件MessageResources.properties中自定义的keyPosition用于替换第1个位置“{0}”,因为在milength约束中有“msg="errors.minlength"”设置,errors.minlengthMessageResources.properties中自定义。

.<arg key="${var:minlength}" resource="false" position="1"/>”,key指向下边的<var>resource="false"为不读取MessageResources.properties文件,替换第2个位置“{1}”。

. <var>”定义一个自己的变量,用于设置字符串的最小长度。

                   .密码部分就不做详解了,但其中“<msg name="validwhen" key="validator.validwhen.password2"/>”用于替换“validwhen”的默认错误信息。

                   .生日部分也不做详解了。

 

五、DispatchAction,同一类请求综合处理

         同学提问了一个好问题,以前在做练习时,每个请求都单独写一个Servlet,现在的Action我们也要这么写吗?当然不是!如果开发一个大工程,有上千个请求,难道要写上千个Action吗?DispatchAction为我们解决了这个问题。

         例,处理用户注册、登陆、更新、删除的这一类请求,我们可以编写一个DispatchAction

import javax.servlet.http.*;

import org.apache.struts.action.*;

import org.apache.struts.actions.DispatchAction;

 

public class TestDispatchAction extends DispatchAction {

    // add处理

    public ActionForward add(ActionMapping mapping, ActionForm form,

           HttpServletRequest request, HttpServletResponse response)

           throws Exception {

       System.out.println("TestDispatchAction.add");

       return mapping.findForward("success");

    }

    // find处理

    public ActionForward find(ActionMapping mapping, ActionForm form,

           HttpServletRequest request, HttpServletResponse response)

           throws Exception {

       System.out.println("TestDispatchAction.find");

       return mapping.findForward("success");

    }

}

         我们需要在struts-config.xml添加如下配置:

<?xml version="1.0" encoding="UTF-8" ?>

<!DOCTYPE struts-config PUBLIC

          "-//Apache Software Foundation//DTD Struts Configuration 1.3//EN"

          "http://struts.apache.org/dtds/struts-config_1_3.dtd">

<struts-config>

    <action-mappings>

       <action path="/action"

           type="cn.itcast.cc.actions.TestDispatchAction"

           parameter="method">

           <forward name="success" path="/WEB-INF/pages/success.jsp" />

       </action>

    </action-mappings>

</struts-config>

         其中的“parameter="method"”,这里的“method”必须与下面的JSP页面中的请求参数名称相同。TestDispatchAction中的方法名称与参数值相同,参数值指向哪个方法,DispacthAction就调用哪个方法。

         JSP页面:

<%@ page language="java" contentType="text/html; charset=UTF-8"

    pageEncoding="UTF-8"%>

<%@ taglib prefix="html" uri="http://struts.apache.org/tags-html"%>

 

<!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>

<html:link action="/action.do?method=add">add</html:link>

<html:link action="/action.do?method=find">find</html:link>

</body>

</html>

         其中的http://struts.apache.org/tags-html在是菜单:widnow->perferences->XML->XML Catalog添加的,它是指向“struts-1.3.8\docs\dtds\struts-config_1_3.dtd”的URI

         嗯,今天结束!看似内容并不多,但要熟练掌握还要多加练习。

         加油!


只有注册用户登录后才能发表评论。


网站导航: