BaseMapForm:一个高度灵巧实用的ActionForm

来源:互联网 发布:齿轮制作软件 编辑:程序博客网 时间:2024/04/29 16:11
BaseMapForm:一个高度灵巧实用的ActionForm
2007-3-7
 
BaseMapForm是PVO扩展包cn.hkm.web中一个重要的ActionForm。由于在BaseMapForm中增加了一个Map record属性,和若干个辅助属性,使得它可以完成必须由ActionForm承担的绝大多数、甚至是全部的任务。从而,使Struts的应用变得十分轻松。它的灵活性是十分惊人的,给用户带来的开发效率同样是十分惊人的。
 
一、在Struts中配置BaseMapForm
以下是直接使用BaseMapForm,在Struts的配置文件中(注:Jbuilder中默认的配置文件是WEB-INF/struts-config.xml),类似以下配置:
<struts-config>
 <form-beans>
    <form-bean name="mapForm" type="cn.hkm.web.BaseMapForm" />
 </form-beans>
 <action-mappings>
    <action name="mapForm" parameter="method" path="/menuAction" scope="session" type="mypvo.web.MenuAction">
      <forward name="index" path="/index.jsp" />
      <forward name="userlogin" path="/userlogin.jsp" />
    </action>
 </action-mappings>
</struts-config>
 
二、BaseMapForm表单的设计
为了能充分发挥PVO的作用,建议使用BaseMapForm,可直接使用,也可根据需要继承使用,若继承使用,请一定要覆写(overriding)reset方法,并在reset方法中调用super.reset(actionMapping,servletRequest)方法。在JSP中,按照以下方式建立表单:
用属性id代表数据库表中的主键,用属性f1、f2、f3、f4、f5来代表上传文件,用record.字段名代表其它字段,其它属性可有可无,如sign、which、mainid、subid可用来作为辅助标识。
 
JSP中BaseMapForm表单设计范例:
<html:form action="/a.do?method=abc" method="post" enctype="multipart/form-data">       <html:hidden property="id"/>
<li>姓名: <html:text property="record.name"/></li>
<li>单位:<html:text property="record.unit"/></li>
<li>地址:<html:text property="record.address"/></li>
<li>照片:<html:file property="f1"/></li>
<li><html:submit>提交</html:submit></li>
</html:form>
 
上传表单后,在Action的方法中,若想获取Map m=mapForm.getRecord();请一定先调用mapForm.reset(actionMapping, servletRequest);这个方法的作用是,将表单中record.字段名格式的域值全部提取并保存到Map record的属性中。此外,在BaseMapForm中提供了一组与表单上传数据处理相关的实用方法:
1.         一组字符串格式验证方法,默认正则表达式为”[a-zA-Z0-9]+”,只允许字母和数字
2.         一组将上传文件相关信息保存到record属性的方法,以便于保存到数据库
3.         一组将上传文件保存到文件夹的方法
4.         一组时间查询方法
使用过Struts的用户都知道,通常定义一个普通的ActionForm表单,需要对应数据库表的字段,来添加属性,如果一个表有数十个字段,就要有数十个对应的属性。这样使用表单是比较繁重的苦差事。而动态ActionForm表单,听上去让人激动,用起来却让人心烦,它如同O/R工具中的动态属性一样,每添加一个动态属性,就必须在XML文件中定义一个,实际上比使用普通ActionForm表单还烦人。
而使用BaseMapForm则完全轻松自如,因为,使用它,已经不需要根据数据库表,在ActionForm中来定义一个个对应的属性了,而是直接在JSP页面的表单中根据数据库表的需要随时添加,只要用一个record属性就能满足所有字段的需要。只要用record.字段1名、record.字段2名、record.字段3名….的方式进行,也不需要在XML文件中定义一个个动态属性。它的灵活性是惊人的,如果数据库中的字段名改了,只要在JSP页面上修改为record.字段新名。而不需要修改这个BaseMapForm文件。即使在数据库表中任意添加或删除了新的字段,也不需要修改BaseMapForm文件,只要在JSP页面表单中添加或删除record.字段即可。甚至在不少情况下都不需要修改Action中方法的业务代码。由此可见,PVO不仅大大简化了JDBC的编程,而且也大大简化了Struts中ActionForm的使用,它的灵活性和实用性要比O/R工具好的多。
 
三、BaseMapForm中数据的提取
表单都要提交给Action的某个方法后,请按以下方式提取表单中的数据。如:
BaseMapForm form=(BaseMapForm) actionForm;
form.reset(actionMapping,servletRequest);
如果上传了图片,并希望将图片保存到数据库中,则:
FormFile f=form.getF1();
form.putBinary("content", f);
form.putContentType("contenttype", f);
form.putFileName("filename", f);….
Map m=form.getRecord();//提取Map record属性值
 
四、将数据保存到数据库
String id=form.getId();//或通过request获取
if ("".equals(id)) //新建
        id = pvo.insertKey("表名", "表的主键名").toString();
pvo.updateARecord("表名", m, "where 表的主键=" + id);//保存记录
 
五、用BaseMapForm将上传文件保存到文件夹
如果上传了文件,希望将文件保存到文件夹,则按以下方式进行:
BaseMapForm form=(BaseMapForm) actionForm;
form.reset(actionMapping,servletRequest);
FormFile f=form.getF1();
form.saveFile(f,"用户自定义文件夹");
不可省略reset()调用,BaseMapForm通过该方法获取上下文真实路径,并设定了一个默认的上传文件目录/upload,最终文件将被保存在“上下文真实路径/upload/用户自定义文件夹/”下面。用户可自定义文件夹、保存的文件名、文件大小、允许上传的文件类型,更多请阅读PVO的文档资料。
 
六、新建记录前的表单数据的初始化
用BaseMapForm表单新建记录,通常可以按以下方式进行:
1、 设置属性id,form.setId("");
2、 设置属性record,form.setRecord(new HashMap());//可根据需要是否保留原值
 
七、修改记录前的表单数据的初始化
用BaseMapForm表单修改记录,其数据初始化的准备工作十分轻松,而用其它方式可能是一件很很繁重的事。通常可以按以下方式进行:
1、 查询该记录
2、 设置属性id
3、 设置属性record
例:
Map m = pvo.getARecord(…);
form.setId(id);//这个id是这条记录的主键值
form.setRecord(m);
 
以上只是简单介绍了BaseMapForm的作用和使用,更详细的应用可参见本篇文章后的附件。也可登录“HashMap关系数据映射技术网站www.aisun.cn)”查阅更多信息。
 
本篇文章后,附加了 “HashMap关系数据映射技术网站www.aisun.cn”中一个完整的用户注册信息管理子系统。涵盖了用户登录、注册前用户名查询、注册新用户、修改用户信息的全部操作。代码中,与数据库数据存取相关的操作均很短,大多数与验证、用户提示信息相关。有兴趣的读者,在你自己的电脑上试一试。
 
参考著作
《精通Struts:基于MVC的Java Web 设计与开发》(孙卫琴 编著 电子工业出版社)
 
 
 
说明:本站将尽力推出具有实际应用价值的范例
附件:本站实际使用的用户注册登录管理系统
 
以下是用户注册信息表
create table userinfo(
userinfo_id bigint primary key,
username varchar(50),
password varchar(50),
name varchar(32),
appellative varchar(32),
unit varchar(32),
tel varchar(16),
mob varchar(16),
qq varchar(16),
email varchar(50),
ip varchar(16),
addressdetail varchar(64),
freeze varchar(1) default 0,
point int default 0
)
 
以下是完整的userinfo.jsp文件,实际效果请观察本站的“注册新用户|修改用户信息”。这个文件中有两个表单。第一个表单用于查询一个用户名是否存在,若不存在,则将这个用户名加载到注册表单,供用户使用。
注册表单,集新建用户信息和修改用户信息于一身,以BaseMapForm中的属性id是否为零长度字符串作为判断标识。这个页面文件稍长的原因是,注册前对表单中的数据进行了检测。
 
 
<%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic" %>
<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
<%@ taglib uri="/WEB-INF/pvotag.tld" prefix="pvo" %>
<%@ page contentType="text/html; charset=GBK" %>
<%@ page import="cn.hkm.sql.*,cn.hkm.web.*,mypvo.web.*,java.util.*" %>
<html>
<head>
<title>
HashMap关系数据映射技术__用户信息录入[注册与修改]
</title>
<link href="<%=request.getContextPath() %>/aisun.css" rel="stylesheet" type="text/css" />
 
<script language="JavaScript" type="text/javascript">
 
function checkdata() {
 var txt;
 <logic:equal value="default" name="userinfo_m" property="username">
 txt=document.getElementById("username").value;
 if(txt.length==0||txt==null||txt==""){
    alert("请先输入一个用户名.");
    document.getElementById("username").select();
    return false;
 }
 </logic:equal>
 
 txt=document.getElementById("password").value;
 if(txt==null||txt.length<4||txt.length>50){
    alert("密码长度应大于3,小于50");
    document.getElementById("password").select();
    return false;
 }
 
 var pwd2=document.getElementById("password2").value;
 if(txt!=pwd2){
    alert("验证密码有误,请重新输入密码,并记住密码.");
    document.getElementById("password").select();
    return false;
 }
 
 txt=document.getElementById("name").value;
 if(txt.length>0){
    if(txt.length>16){
      alert("姓名小于16个汉字.");
      document.getElementById("name").select();
      return false;
    }
 }
 
 txt=document.getElementById("tel").value;
 if(txt.length>0){
    if(txt.length<7||txt.length>16){
      alert("电话长度应大于6,小于16字符");
      document.getElementById("tel").select();
      return false;
    }
 }
 
 txt=document.getElementById("mob").value;
 if(txt.length>0){
    if(txt.search("^-?//d+$")!=0) {
      alert("请输入整数");
      document.getElementById("mob").select();
      return false;
    }
    if(txt.length<11||txt.length>13){
      alert("手机号码是否有误,请重输.");
      document.getElementById("mob").select();
      return false;
    }
 }
 
 txt=document.getElementById("qq").value;
 if(txt.length>0){
    if(txt.length>16){
      alert("QQ号小于16");
      document.getElementById("qq").select();
      return false;
    }
    if(txt.search("^//d+(//.//d+)*$")!=0) {
      alert("请输入数字");
      document.getElementById("qq").select();
      return false;
    }
 }
 
 txt=document.getElementById("email").value;
 
 if(txt.length>0){
    if(txt.length>50){
      alert("信箱小于50字符.");
      document.getElementById("email").select();
      return false;
    }
    if(txt.search("^//w+([-+.]//w+)*@//w+([-.]//w+)*//.//w+([-.]//w+)*$")!=0) {
      alert("请输入正确的电子信箱");
      document.getElementById("email").select();
      return false;
    }
 }
 
 txt=document.getElementById("addressdetail").value;
 if(txt.length>0){
    if(txt.length>32){
      alert("地址应小于32个汉字.");
      document.getElementById("addressdetail").select();
      return false;
    }
 }
 
 document.getElementById("userinfo").submit();
}
 
</script>
 
</head>
 
<body bgcolor="#ffffff">
 
 <%//用户信息表 开始%>
 <div class="asC_login">
 
    <h3>用户注册信息,打*号者必填</h3>
 
    <logic:equal value="default" name="userinfo_m" property="username">
      <ul>
        <html:form action="/menuAction.do?method=userQuery" method="post" enctype="multipart/form-data">
          <li>
            <span class="A">用户名</span>
            <span class="B"><html:text property="record.username" styleId="username"/></span>
            <span class="C">提示:请在此输入一个用户名,查询是否存在.</span>
          </li>
          <li>
            <span class="A"></span>
            <span class="B"><html:submit>提交</html:submit></span>
            <span class="C"></span>
          </li>
        </html:form>
      </ul>
    </logic:equal>
 
    <ul class="login">
      <html:form styleId="userinfo" action="/menuAction.do?method=userBase" method="post" enctype="multipart/form-data" >
        <html:hidden property="id"/>
        <html:hidden property="sign"/>
        <li>
          <span class="A">*用户名</span>
          <span class="B">
            <span style="height:22px;line-height:22px;width:96%;vertical-align: middle;background:#008899;color:#ffffff;"><bean:write name="mapForm" property="record.username"/></span>
            <html:hidden property="record.username"/>
          </span>
          <span class="C"></span>
        </li>
        <li>
          <span class="A">*密码</span>
          <span class="B"><html:password property="record.password" styleId="password"/></span>
          <span class="C"></span>
        </li>
        <li>
          <span class="A">再输一遍密码</span>
          <span class="B"><input type="password" name="password2" id="password2" /></span>
          <span class="C"></span>
        </li>
        <li>
          <span class="A">姓名</span>
          <span class="B">
            <logic:notEqual value="default" name="userinfo_m" property="username">
              <html:hidden property="record.name" styleId="name"/>
              <span style="height:22px;line-height:22px;width:96%;vertical-align: middle;background:#008899;color:#ffffff;"><bean:write name="userinfo_m" property="name"/></span>
            </logic:notEqual>
            <logic:equal value="default" name="userinfo_m" property="username">
              <html:text property="record.name" styleId="name"/>
            </logic:equal>
          </span>
          <span class="C"></span>
        </li>
        <li>
          <span class="A">单位</span>
          <span class="B"><html:text property="record.unit" styleId="unit"/></span>
          <span class="C"></span>
        </li>
        <li>
          <span class="A">电话</span>
          <span class="B"><html:text property="record.tel" styleId="tel"/></span>
          <span class="C"></span>
        </li>
        <li>
          <span class="A">手机</span>
          <span class="B"><html:text property="record.mob" styleId="mob"/></span>
          <span class="C"></span>
        </li>
        <li>
          <span class="A">Qq号码</span>
          <span class="B"><html:text property="record.qq" styleId="qq"/></span>
          <span class="C"></span>
        </li>
        <li>
          <span class="A">邮箱</span>
          <span class="B"><html:text property="record.email" styleId="email"/></span>
          <span class="C"></span>
        </li>
        <li>
          <span class="A">地址</span>
          <span class="B"><html:text property="record.addressdetail" styleId="addressdetail"/></span>
          <span class="C"></span>
        </li>
        <li>
          <span class="A"></span>
          <span class="B">
            <html:reset style="width:48%;height:22px;">重设</html:reset>
            <html:button property="" style="width:48%;height:22px;margin:0px;" onclick="checkdata();">提交</html:button>
          </span>
          <span class="C"></span>
        </li>
      </html:form>
    </ul>
 
 </div>
 <%//用户信息表 结束%>
 
</body>
</html>
 
 
 
以下是userinfo.jsp文件中使用的样式表
 
/************** .asC_login styles *****************/
 
.asC_login{
margin:0px;
padding:0px;
width:100%;
height:100%;
padding:8px;
margin:1px;
background-color:#f0ffff;
}
 
.asC_login ul{
margin:0px;
margin-top:2px;
list-style-type:none;
}
 
.asC_login li{
overflow:hidden;
padding:0px;
margin:0px 8px;
display:block;
 
height:24px;
line-height:26px;
text-decoration:none;
 
}
 
.asC_login span.A {
padding:1px 0px 1px 4px;
float:left;
width:16%;
text-align:right;
}
.asC_login span.B {
float:left;
padding:1px 0px 1px 8px;
float:left;
width:20%;
font-size: 12px;
}
 
.asC_login span.B input{
width:96%;
height:20px;
}
 
.asC_login span.C{
float:left;
padding:1px 0px 1px 4px;
width:58%;
}
 
 
 
以下是MenuAction.java中完整的用户注册管理部分的几个方法。包括:用户查询、注册新用户、修改用户信息、登录。整个相关方法的代码不足150行,有关数据库操作的部分很短,多数代码是对数据进行严格的检测,为使用者提供友好的提示信息。
 
 
package mypvo.web;
 
import cn.hkm.sql.WhereString;
import javax.servlet.http.HttpSession;
import org.apache.struts.action.ActionForward;
import java.util.Map;
import java.sql.SQLException;
import java.util.HashMap;
import cn.hkm.sql.ProcessVO;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts.action.ActionForm;
import cn.hkm.web.BaseMapForm;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
import org.apache.struts.action.ActionMapping;
 
public class MenuAction extends org.apache.struts.actions.DispatchAction {
 
 /**
   * 用户登录
   * */
 public ActionForward userLogin(ActionMapping actionMapping,
                                 ActionForm actionForm,
                                 HttpServletRequest servletRequest,
                                 HttpServletResponse servletResponse) throws
      SQLException {
    BaseMapForm form = (BaseMapForm) actionForm;
    HttpSession session = servletRequest.getSession(false);
    String username = servletRequest.getParameter("user");
    String password = servletRequest.getParameter("pwd");
    if (!form.isValidStr(username) || !form.isValidStr(password)) { //防止sql注入
      servletRequest.setAttribute("_alt", "含有非法字符,拒绝登录");
      return actionMapping.findForward("index");
    }
    String sql = "select * from userinfo where password like '" + password +
        "' and username like '" + username + "'"; 
    ProcessVO pvo = new ProcessVO(_Con.getCon());
    try {
      List v = pvo.getSomeRecord(sql);
      if (v.size() == 1) {
        session.setAttribute("userinfo_m", v.get(0));
        servletRequest.setAttribute("_alt", "登录成功.");
      }
      else {
        servletRequest.setAttribute("_alt", "登录失败.");
      }
    }
    finally {
      pvo.closeCon();
    }
    session.setAttribute("body", "/mainbody.jsp");
    return actionMapping.findForward("index");
 } 
 
 /**
   * 注册新用户
   * */
 public ActionForward userNew(ActionMapping actionMapping,
                               ActionForm actionForm,
                               HttpServletRequest servletRequest,
                               HttpServletResponse servletResponse) {
    BaseMapForm form = (BaseMapForm) actionForm;
    form.setId(""); //初始化表单中的主键,将主键置空,作为新建记录的标识
    form.setRecord(new HashMap());//清空表单中的其它记录
    HttpSession session = servletRequest.getSession(true);
    session.setAttribute("body", "/userinfo.jsp");
    return actionMapping.findForward("index");
 }
 
 /**
   * 查询一个用户名是否存在,若不存在,则将此用户名提交给用户注册使用
   * */
 public ActionForward userQuery(ActionMapping actionMapping,
                                 ActionForm actionForm,
                                 HttpServletRequest servletRequest,
                                 HttpServletResponse servletResponse) throws
      SQLException {
    BaseMapForm mapForm = (BaseMapForm) actionForm;
    String username = servletRequest.getParameter("record.username");
    if (!mapForm.isValidStr(username, "[a-zA-Z0-9]+", 4, 50)) { //有利于防止sql注入
      servletRequest.setAttribute("_alt", "用户名中不能含有_?*空格等非常规字符,且长度大于等于4小于等于50");
      return actionMapping.findForward("index");
    }
    String sql = "select username from userinfo where username like '" +
        username + "'";
    ProcessVO pvo = new ProcessVO(_Con.getCon());
    try {
      List v = pvo.getSomeRecord(sql);
      if (v.size() == 0) {
        Map userinfo_m = new HashMap();
        userinfo_m.put("username", username);
        mapForm.setRecord(userinfo_m); //保存查询结果,供用户使用
        servletRequest.setAttribute("_alt", "你可以使用该帐号.");
      }
      else {
        servletRequest.setAttribute("_alt", "该用户已存在.");
      }
    }
    finally {
      pvo.closeCon();
    }
    return actionMapping.findForward("index");
 } 
 
 /**注册或修改用户信息*/
 public ActionForward userBase(ActionMapping actionMapping,
                                ActionForm actionForm,
                                HttpServletRequest servletRequest,
                                HttpServletResponse servletResponse) throws
      SQLException {
    HttpSession session = servletRequest.getSession(false);
    BaseMapForm mapForm = (BaseMapForm) actionForm;
    String username = servletRequest.getParameter("record.username");
    String password = servletRequest.getParameter("record.password");
    if (!mapForm.isValidStr(username, "[a-zA-Z0-9]+", 4, 50) ||
        !mapForm.isValidStr(password, "[a-zA-Z0-9]+", 4, 50)) { //有利于防止sql注入,
      servletRequest.setAttribute("_alt",
                                  "用户名或密码中不能含有_?*空格等非常规字符,且长度大于等于4小于等于50");
      return actionMapping.findForward("index");
    }
    String id = servletRequest.getParameter("id");
    mapForm.reset(actionMapping, servletRequest);
    Map m = mapForm.getRecord();
    ProcessVO pvo = new ProcessVO(_Con.getCon());
    try {
      pvo.setAutoCommit(false);
      if ("".equals(id)) //新建
        id = pvo.insertKey("userinfo", "userinfo_id").toString();
      pvo.updateARecord("userinfo", m, "where userinfo_id=" + id);//新建或修改用户信息
      String sql = "select * from userinfo where userinfo_id=" + id;
      Map _m = pvo.getARecord(sql);
      pvo.commit();
      mapForm.setId(id); //确保数据存贮后,保存表单中用户,主关键字段信息,防止新建
      session.setAttribute("userinfo_m", _m);
      servletRequest.setAttribute("_alt", "注册或修改成功.");
    }
    catch (SQLException ex) {
      pvo.rollback();
      ex.printStackTrace();
      servletRequest.setAttribute("_alt", "注册或修改失败.");
      return actionMapping.findForward("index");
    }
    finally {
      pvo.closeCon();
    }
    return actionMapping.findForward("index");
 } 
 
 /**
   * 为编辑用户信息准备数据
   * */
 public ActionForward userEdit(ActionMapping actionMapping,
                                ActionForm actionForm,
                                HttpServletRequest servletRequest,
                                HttpServletResponse servletResponse) {
    BaseMapForm form = (BaseMapForm) actionForm;
    HttpSession session = servletRequest.getSession(true);
    session.setAttribute("body", "/userinfo.jsp");
    Map m = (Map) session.getAttribute("userinfo_m"); //获取已存贮的用户信息,这个Map变量在整个会中存在,初次访问本站时创建了一个默认的用户,是本站用来判断哪个用户的依据。
    String username = (String) m.get("username");
    Long ID = (Long) m.get("userinfo_id");
    if (!"default".equals(username)) {
      Map _m = new HashMap(); //建议用新的Map对象存贮到表单中,以防止在JavaBean中修改保存在原来userinfo_m中的数据
      _m.putAll(m);
      form.setRecord(_m); //初始化表单数据
      form.setId(ID.toString()); //初始化表单中的主键
    }
    return actionMapping.findForward("index");
 }
 
}