XJawa. The Ajax Software Saloon


当前位置: 首页 7wxAop开发框架 教程

 目前:0 鲜花 0 牛粪   我要: 献鲜花  扔牛粪
 2、极端体验:初学者10分钟实现完整的单表增删改查功能
 【关闭】 
本站发布时间:2008年05月06日 09:10

概述:对于数据库应用来说,单表的增删改查功能可以揭示应用框架对业务系统开发的基本支持。7wxAop中实现这一功能非常简单,所有代码都可由系统工具生成,而且代码量很小,易于阅读分析。

下面的例子,后台程序都要访问数据库。在7wxAop中,绝大部分的业务过程(Action)都是通过AutoSQL实现的,AutoSQL类似于iBatis,与iBatis一样用SQL表示持久接口,用SQL中的占位符号表示持久接口的输入参数;不同的是AutoSQL中输入参数充分考虑了Web开发下的实际情况,同时,还在SQL中指定了符合Ajax要求的标准数据输出。一个或多个AutoSQL够成AutoAction,形式上AutoAction类似于存储过程,但输入输出方式都是以Web下的Ajax开发为基础开发,所以用于Ajax应用时,可实现最简洁的代码。

我们现在实验如何在10分钟内,从建表开始,开发一个完整的单数据表应用--图书管理,该应用含图书的增、删、改、查(可翻页、单击表头排序的列表)、表单输入校验等功能。

在7wxAop中,数据库应用程序前后端的基本代码都可以在系统工具DBView中生成。实际上,无需任何代码,DBView本身就可以实现任意数据库、任意数据表的增删改查功能;但在实际应用中,我们需要生成代码,以便程序员后期定制不同的功能。

 
 注意

 代码生成器最近更新,早于 07-04-16 19:00 下载xjawa.zip的用户,需下载更新以下文件:
 {xjawa}/www/commonjs/sys_list.js
 {xjawa}/www/system/dbview/createlist.html (按右键另存为)
 {xjawa}/www/system/dbview/createform.html (按右键另存为)
       

1、建表

在Eclipse中启动MiniServer后,打开后台管理界面(http://localhost/admin/),进DBView,左边导航树显示的是系统默认业务数据库WebApp的表和视图,点〈Execute SQL〉,右边出现SQL执行控制台界面:

在SQL输入框中,粘贴入以下建表代码:

 CREATE TABLE book(
     ID BIGINT NOT NULL,
     TITLE VARCHAR(40) NOT NULL,
     AUTHOR VARCHAR(10) ,
     PUBLISHER VARCHAR(20),
     PUBLISHDATE DATE,
     CONTENT VARCHAR(1000),
     PRICE DECIMAL(4,2) NOT NULL,
     NUMBER INT NOT NULL,
     PRIMARY KEY(ID)
);

按<Run>,执行建表操作。然后按左侧导航界面上的刷新图标,在Tables列表中就可以看到新建的BOOK表,点击BOOK,右侧出现该表的元数据定义Definition页及数据Data页,在Data页中,我们可以直接增删改查,但我们现在要产生自己的代码。

 

2、产生后台代码

在Definition页,按<AutoSQL>按钮可以产生后台程序代码AutoAction及AutoSQL:

按〈Action Servlet Template〉,进入Action Servlet Template对话框,我们可以产生一个7wxAop应用(即WebActions 子类,如HelloWorld教程中的aop.Test类)的代码模板,由于我们打算这个例子与HelloWorld例子共用WebActions子类aop.Test,因此不用复制整个模板,只需把其中的方法defineAutoActions() 复制并插入到aop.Test即可。然后,我们退出Action Servlet Template对话框,从上图界面中复制“Normal SQL”之上的所有行,插入到defineAutoActions() 方法的actions变量赋值语句中,最后形成的aop.Test代码为:

package aop;

import org.xjawa.system.WebActions;
import javax.servlet.http.HttpServletRequest;

public class Test extends WebActions {
  
  public String[][] defineAutoActions() throws Exception {
    String[][] actions = 
//        取 BOOK 列表
        {"@getBooks","",
          "books(start,len):=SELECT_NOMETA ID,TITLE,AUTHOR,PUBLISHER,PUBLISHDATE,CONTENT,PRICE,NUMBER"
            +" FROM BOOK where {_where} order by {_orderby}",
        },

//        取一条 BOOK 
        {"@getBook","",
          "book:=SELECT ID,TITLE,AUTHOR,PUBLISHER,PUBLISHDATE,CONTENT,PRICE,NUMBER"
            +" FROM BOOK"
            +" WHERE ID={_id}",
        },


//        插入一条 BOOK
        {"@addBook","",
          "INSERT INTO BOOK "
            +"(ID,TITLE,AUTHOR,PUBLISHER,PUBLISHDATE,CONTENT,PRICE,NUMBER) VALUES"
            +"({fieldmax(SELECT MAX(ID) FROM BOOK)_id},'{_title}','{_author}','{_publisher}','{_publishdate(NULL)}','{_content}',{_price},{_number})",
            "id:=requestvalue_id",
        },


//        更新一条 BOOK
        {"@updateBook","",
          "UPDATE BOOK SET "
            +"TITLE='{_title}'"
            +",AUTHOR='{_author}'"
            +",PUBLISHER='{_publisher}'"
            +",PUBLISHDATE='{_publishdate(NULL)}'"
            +",CONTENT='{_content}'"
            +",PRICE={_price}"
            +",NUMBER={_number}"
            +" WHERE ID={_id}",
        },


//        删除一条 BOOK
        {"@delBook","",
          "DELETE FROM BOOK "
            +" WHERE ID IN ({array_id})",
        },
    };
    
    return actions;
  }
  
  public void _helloServer(HttpServletRequest request)throws Exception {
    sendPrimary(request,"info","Hello, " + request.getParameter("myname")
        "! This's Aop Server :" + request.getServerName());
  }

  
}

这就是本例子的唯一的后台代码,含5个AutoAction,没有XML,也没有业务Bean、DAO、实体Bean等等繁琐的东西。

后端代码完成后,停止MiniServer并重新启动。

 

3、产生前端代码

 
 注意

 7wxAop框架前后台都基于unicode设计,因此前台代码(html,js,jsp)必须存储为utf-8文件格式,否则显示可能出现乱码。
       

列表页生成:在BOOK表的Definition页,按<ListView>按钮进入ListView生成界面,顶部的代码生成选项我们分别选择:

 

当程序提示输入后台“应用程序名”时,输入“aop.Test”。在WWW下的7wx文件夹中创建空的books.html文件,将产生的代码复制到该文件中,books.html文件代码如下(注意以utf-8格式保存):

   <HTML>
   <HEAD>
   <TITLE> Book List </TITLE>
   <META NAME="Generator" CONTENT="7WX/AOP Framework">
   <META http-equiv="content-type" content="text/html; charset=utf-8">
   <!-- 导入前端系统库 -->
   <SCRIPT src="/commonjs/7wx.js"></SCRIPT>
   </HEAD>

   <!-- =============== HTML area =======================-->

   <BODY leftmargin=0 topmargin=0>
   <table class=layout cellpadding=0 cellspacing=0>
      <!-- A.功能按钮区 -->
      <tr class=toolbar><td>
         <table cellpadding=0 cellspacing=0 width=100% ><tr>
         <td>
            <button id=buttonAdd onclick="addBook();" >新建</button>
            <button id=buttonMod onclick="modBook();" >修改</button>
            <button id=buttonDel onclick="delBook();" >删除</button>
            <!-- <button id=buttonSearch onclick="Xdialog('searchbook.html');">查找</button> -->
         </td>
         <td align=right>
            <select id=smartSearch onchange="smartSearchChange();">
               <option value="1=1" selected>快速查找</option>
               <!-- <option value="cloumnA=0">1.某条件</option> -->
               <option value="findtitle">2.查找标题</option>
               <!-- <option value="findcolumnA">3.查找某列</option> -->
            </select>
         </td>
         </tr></table>
      </td></tr>
      
      <!-- B.业务数据区:列表 -->
      <tr><td><div class=listviewcontainer>


   <!-- 列表模板开始--------------------------------- -->
   <TABLE id=booklist width=100%  class=clistview>
   <TR align=center class=clistviewhead>
      <TD width=20 nowrap><input type="checkbox" value="全选" onclick="XsetAllTableLinesChecked(booklist,this.checked);"></TD>
      <TD nowrap width=20 style='cursor:hand' onclick="reOrder('ID')" >ID</TD>
      <TD nowrap width=130 style='cursor:hand' onclick="reOrder('TITLE')" >TITLE</TD>
      <TD nowrap width=40 style='cursor:hand' onclick="reOrder('AUTHOR')" >AUTHOR</TD>
      <TD nowrap width=70 style='cursor:hand' onclick="reOrder('PUBLISHER')" >PUBLISHER</TD>
      <TD nowrap width=40 style='cursor:hand' onclick="reOrder('PUBLISHDATE')" >PUBLISHDATE</TD>
      <TD nowrap width=160 style='cursor:hand' onclick="reOrder('CONTENT')" >CONTENT</TD>
      <TD nowrap width=22 style='cursor:hand' onclick="reOrder('PRICE')" >PRICE</TD>
      <TD nowrap width=43 style='cursor:hand' onclick="reOrder('NUMBER')" >NUMBER</TD>
   </TR>
   <TR style='display:none;'>
      <TD><INPUT type=checkbox XobjectID={books_ID} XhelpValue={books_ID}></TD>
      <TD nowrap align='right' style='color:blue;'>{books_ID}</TD>
      <TD nowrap>{books_TITLE}</TD>
      <TD nowrap>{books_AUTHOR}</TD>
      <TD nowrap>{books_PUBLISHER}</TD>
      <TD nowrap>{books_PUBLISHDATE}</TD>
      <TD nowrap>{books_CONTENT}</TD>
      <TD nowrap align='right' style='color:blue;'>{books_PRICE}</TD>
      <TD nowrap align='right' style='color:blue;'>{books_NUMBER}</TD>
   </TR>
</TABLE>
   <!-- 列表模板结束--------------------------------- -->
      
      </div></td></tr>

      <!-- C.业务数据区:列表翻页控制 -->
      <tr class=pagebar><td>
         <SCRIPT>XinsertPageControl(15)</SCRIPT>
      </td></tr>

   </table>
   </BODY>

   <!-- =============== Script area =======================-->

   <SCRIPT LANGUAGE="JavaScript">
   <!--
   ////////////////=====A.界面初始化=========

   var orderBy = "id";//默认排序
   var searchWhere = "";//查找条件 格式为“ AND (name='test')”
   var smartWhere = "1=1";//默认的快速查找条件

   //界面初始化
   function loadok(){
      XsetAppAndAction("aop.Test","getBooks");//设定应用程序servlet及取列表数据的请求动作名
      loadBooks();//取列表数据
   }

   //快速查找条件改变
   function smartSearchChange(){
      if(smartSearch.value=="findtitle"){ //需额外参数型快速查找
         var title = window.prompt('模糊查找标题,请输入关键字:','');
         if(title!=null)
            smartWhere = "title like '%"+title+"%'";

      //else if(smartSearch.value=="findcolumnA"){ //需额外参数型快速查找
      //   var title = window.prompt('模糊查找columnA,请输入关键字:','');
      //   if(title!=null)
      //      smartWhere = "columnA like '%"+title+"%'";
      
      }else //简单快速查找
         smartWhere = smartSearch.value;

      loadBooks();
   }

   //取数据,初始进入,改变排序,查找、快速查找时调用此函数
   function loadBooks(){
      XnewQuery("&where="+smartWhere + searchWhere + "&orderby="+orderBy,true);//访问后台程序
   }

   //页数据显示,调用loadRoles()或翻页操作,服务器返回数据时,将调用此函数
   function on_getBooks(){
      XfillTableWithArray(booklist,buffer.books);//合成列表显示
      XresetPageCtl(buffer.books_count);//重置翻页控制条
   }

   ////////////////=====B.用户动作响应=========

   //排序列表,在点击表头时调用
   function reOrder(colName){
      orderBy =  (orderBy==colName)? (colName+" DESC") : colName;//按某列排序,再点反序正序切换
      loadBooks();   
   }

   //增加Book
   function addBook(){
      Xdialog1("book.html?id=-1");//调用表单页,id=-1 为新增
   }

   //更新Book
   function modBook(){
      var selectedItems = XgetTableSelectedLines(booklist);//取选中行的id集合
      if(selectedItems.length==0){
         alert('进行该操作只前,请先选择book。');
         return;
      }
      for(var i=0;i<selectedItems.length;i++)
         Xdialog1("book.html?id="+selectedItems[i]);   //调用表单页,id=有效值 为更新
   }

   //删除Book
   function delBook(){
      var url = checkSelectURL(booklist,"id");
      if(url.length>0) 
         if(confirm("确定要删除这些book吗?"))
            callServer("aop.Test",'delBook',url);
   }

   //选择book辅助函数
   function checkSelectURL(tab,para){
      var URL = XgetTableSelectedLinesURL(tab,para);//取选中行的id集合构成的url
      if(URL.length==0) alert('进行该操作之前,请先选择book。');
      return URL;
   }


   ////////////////=====C.对话框或后台动作响应=========

   function onAddBook(){Xrefresh();}//在表单页book.html用于新建时,新建成功后调用
   function onUpdateBook(){Xrefresh();}//在表单页book.html用于更新时,更新成功后调用
   function on_delBook(){Xrefresh();}
   function onSearchBook(where){//在查询页searchbook.html中调用
      searchWhere=where;
      loadBooks();   //按新查询条件载入新数据
   }

   /////////////////======D.显示格式化函数================


   setTimeout('loadok()',1);
   //-->
   </SCRIPT>
   </HTML>
   

 

表单页生成:在BOOK表的Definition页,按<FormView>按钮进入FormView生成界面,顶部的代码生成选项我们分别选择:

输入域排成   

当程序提示输入后台“应用程序名”时,输入“aop.Test”。在WWW下的7wx文件夹中创建空的book.html文件(在7wxAop中,默认表单页文件名为数据表名,列表页文件名为表名的复数形式),将产生的代码复制到该文件中,book.html文件代码如下(注意以utf-8格式保存):

<HTML>
<HEAD>
<TITLE> Book </TITLE>
<META NAME="Generator" CONTENT="7WX/AOP Framework">
<META http-equiv="content-type" content="text/html; charset=utf-8">
<!-- 导入前端系统库 -->
<SCRIPT src="/commonjs/7wx.js"></SCRIPT>
</HEAD>

<!-- =============== HTML area =======================-->

<BODY leftmargin=0 topmargin=0>
<table class=layout cellpadding=0 cellspacing=0>
   <!-- A.标题区 -->
   <tr class=formtitle><td>
      Book属性
   </td></tr>

   <!-- B.表单区 -->
   <tr><td class=formcontainer>

<!-- 表单模板开始----------------------------- -->
<form id="bookform">
<table border=0 cellpadding=2 cellspacing=0 width=100% class=formalltable>

   <tr>
      <td><input type='hidden' name='id' ></td>
   </tr>
   <tr>
      <td align=right><span id='xcLabel_title'></span>:</td>
      <td><input type='text' name='title' ></td>
   </tr>
   <tr>
      <td align=right><span id='xcLabel_author'></span>:</td>
      <td><input type='text' name='author' ></td>
   </tr>
   <tr>
      <td align=right><span id='xcLabel_publisher'></span>:</td>
      <td><input type='text' name='publisher' ></td>
   </tr>
   <tr>
      <td align=right><span id='xcLabel_publishdate'></span>:</td>
      <td><input type='text' name='publishdate'  readonly>&nbsp;<a onclick='XselectDateFor(bookform.publishdate)' style='cursor:hand'>选择</a></td>
   </tr>
   <tr>
      <td align=right><span id='xcLabel_content'></span>:</td>
      <td><input type='text' name='content' ></td>
   </tr>
   <tr>
      <td align=right><span id='xcLabel_price'></span>:</td>
      <td><input type='text' name='price' ></td>
   </tr>
   <tr>
      <td align=right><span id='xcLabel_number'></span>:</td>
      <td><input type='text' name='number' ></td>
   </tr>

</table>

</form>      
<!-- 表单模板结束----------------------------- -->


<!-- 全部表单区域结束-------------------------- -->
   </td></tr>

   <!-- C.按钮区 -->
   <tr class=buttonbar><td>
   <div id=xeditbar>
      <button onclick="okClick('save');" accesskey="s"> 保存(S) </button> 
      <button id=nextbtn onclick="okClick('saveAndNext');"
         style="display:none;" accesskey="n"> 保存并输入写下一条(N) </button>  
      <button onclick="okClick('saveAndExit');" accesskey="o"> 保存并退出(O) </button>  
      <button onclick="window.close();" accesskey="c"> 取消(C) </button>
   </div>
   <div id=xviewbar style="display:none;">
      <button onclick="window.close();" accesskey="x"> 关闭窗口(X) </button>
   </div>   
   </td></tr>
</table>
</BODY>

<!-- =============== Script area =======================-->

<SCRIPT LANGUAGE="JavaScript">
<!--
////////////////=====A.界面初始化=========
var formForInsert = false;//当前页面表单是否用于新建(否则为更新或查看)

function loadok(){
   var id = XgetPara("id","-1");//取url传递过来的对象键值,-1为新建对象
   formForInsert = id == "-1";
   if(formForInsert){nextbtn.style.display="";}//新建时可“保存并新建下一条”
   
   callServer("aop.Test","getBook", '&id='+id
      + XgetFormDicsURL(bookform));//取对象属性及表的元数据(字段定义)及记录行(更新时),XgetFormDicsURL取表单中的字典信息。

   if(XgetPara("forview")=='1'){//表单仅用于查看
      xviewbar.style.display="";xeditbar.style.display="none";
      
   }
}
function on_getBook(){
   if((!formForInsert) && buffer.book.length==0){
      alert("指定的Book已不存在!可能是另外的用户刚刚删除了该记录。");window.close();return;
   }

   XadjustControlSize();//根据数据库的元数据调整各输入框的显示长短。如手工调整则注释本行
   XnoValidateOnBlur();//焦点离开任意输入框不作输入校验(即不作动态校验)。如需要动态校验特性,则注释本行。
   buffer.book_colLabels=['ID','TITLE','AUTHOR','PUBLISHER','PUBLISHDATE','CONTENT','PRICE','NUMBER'];//各字段的显示名(中文名)。表单整体输入校验时用。

   XinitFormWithData(bookform,"book");//充填表单。新增对象时,只初始化校验信息和输入字典;更新对象时,还充填各字段值
   
   
   if((document.location+"").indexOf("book.html")>0)
      windowResize(460,600);
}

////////////////=====B.用户动作响应=========
var okClickType = null;//保存类型:保存save、保存并输入下一条saveAndNext、保存并退出saveAndExit
function okClick(type){
   okClickType = type;
   if(Xvalidate(bookform)){//系统自动完成的输入校验
      //在此输入个性化的校验   

      var act = formForInsert ? 'addBook' : 'updateBook' ;
      callServer("aop.Test",act,bookform);//提交表单到服务器
   }
}

////////////////=====C.对话框或后台动作响应=========

function on_updateBook(){
   if(opener!=null  && typeof(opener.onUpdateBook)!='undefiend')opener.onUpdateBook();
   doNext();
}
function on_addBook(){
   if(opener!=null  && typeof(opener.onAddBook)!='undefiend')opener.onAddBook();
   doNext();
}
function doNext(){
   if(okClickType=="saveAndNext"){
      window.document.location = window.document.location;
   }else if(okClickType=="save"){
      if(formForInsert){//新建
         if(typeof(buffer.id)=='undefined'){alert("后端开发者:程序错误,未返回新记录的主键值。");return;}
         bookform.id.value = buffer.id;//回填主键
         bookform.id.readOnly = true;
         formForInsert = false;//转为更新状态
         
      }
   }else  //保存并退出saveAndExit
      window.close();
}

////////////////=====D.自定义的输入校验及显示格式化函数=========
function shortDate(inStr){return inStr.substring(0,10);}

setTimeout('loadok()',1);
//-->
</SCRIPT>
</HTML>

OK,所有前端代码都生成了,就两个文件books.html、book.html。不用任何JSP、XML以及配置文件。

 

4、运行新程序

在浏览器中访问:http://localhost/7wx/books.html ,出现一个图书列表界面:

这个列表页有以下特性:点击表头可按该列排序,可多选或全选数据行,翻页浏览

该页中按〈新建〉或〈修改〉按钮,就可以打开表单进行图书新增或修改:

这个表单默认有以下特性:带输入校验,包括非空检查,串长度检查,输入数据类型和精度检查;输入域中按<TAB>键或回车可以移到下一个输入域,日期域的选择

在本例中,我们并未手工编写任何代码,DBView基于数据库表BOOK的元信息,生成了Test.java、books.html、book.html三个代码文件,完全具备了我们要求的单表增删改查功能。下一节中,我们将通读这三个代码文件,并对程序进行改进。


阅读次数(今天):2379()   打印】 【关闭

 最新评论
2008-06-20 18:44:40   admin   IP:202.43.146.*
to javaboy:

DBView可产生父子表的增、删、修改代码,目前没有教程例子。

to 匿名:

在Studio的DataSource And JDBC 节点下配置数据源。

2008-06-20 14:10:03   匿名   IP:116.24.222.*
怎么连接数据库啊,比如mysql?

2008-06-19 15:15:13   javaboy   IP:220.173.107.*
有没有多表关联增、删、修改、查找的例子?

2008-06-18 13:29:12   admin   IP:202.43.146.*
查一下lib下的tools.jar的版本。

http://www.xjawa.org/content/bbs/article.page?id=195&keyword=tools.jar

2008-06-18 00:48:02   匿名   IP:116.230.4.*
Jetty是不是太老了啊?jdk1.5.0_11报错

2008-05-04 17:05:54   小凫   IP:124.16.138.*
啥时候出下一章,学习资源太少了。最好讲讲高级应用!

2007-10-24 08:10:48   desu   IP:218.83.108.*
studing ... ...

2007-08-29 20:55:38   匿名   IP:222.70.149.*
为什么没有下一篇呢?

2007-06-26 11:13:11   hnbk   IP:219.133.154.*
good ths

共有 9 条评论

 发表评论
网名:  (不填则为匿名发布)   验证码:  必须输入
评论:
· 请尊重网上道德,遵守中华人民共和国的各项有关法律法规
· 承担一切因您的行为而直接或间接导致的民事或刑事法律责任
· 本站留言板管理人员有权保留或删除其管辖留言中的任意内容
· 您在本站留言板发表的作品,本站有权在网站内转载或引用
· 参与本留言即表明您已经阅读并接受上述条款