分享
 
 
 

用Java构造Intranet范例查询系统

王朝java/jsp·作者佚名  2008-05-19
窄屏简体版  字體: |||超大  

一、范例查询

我们的终极目标是一个能够满足所有潜在用户的Intranet。为此,我们必须提高Intranet用户访问数据库的灵活性,一种可能的方案是采用所谓的即席查询(Ad-hoc Query)。

“即席”两个字在这里的含义是“不作特殊准备地,随意、自由地”。即席查询允许用户象数据库管理员一样,自由地访问数据库。也许,最灵活的方式是让用户在Web页面的文本输入框中直接输入SQL命令,然后由应用发送该SQL命令查询数据库。然而,虽然这种方式很灵活,但要实施得好很困难,存在许多问题。

首先,这种方式不安全。如果不对用户进行大量的培训,不在应用中对用户输入的SQL命令进行严格的检验,用户可能有意无意地破坏系统运行。另外,即使进行了培训,要求用户总是能够构造出高效的SQL查询也不切实际。

然而,这些问题并不能完全阻碍我们构造出有效的Intranet即席查询系统。一般地,Intranet内的用户比网络之外的用户可信度高。为此,我们可以采用灵活性稍差但仍不失高效的方案――范例查询(Query-By-Example,QBE)。范例查询的使用简单、灵活,不需要对用户进行大量的培训,同时它也比直接使用SQL的方式更安全。

在范例查询系统中,我们提供给用户的界面与数据库结构之间有着密切的对应关系。每一个查询项目有一个相应的用户界面控件。例如,假设有一个雇员信息数据库,我们用一个列表框允许用户选择雇员所在的部门,用一个文本框允许用户输入薪金范围限制查询结果。

二、数据库抽象

对于一些程序员来说,数据库操作有时就象是一堆散乱的连接字符串、SQL命令和结果集。Java的面向对象特色可以让数据源具有更好的可管理性。接下来我们将用Java技术构造一个浏览器界面的QBE系统。这个系统以几个核心类为基础,核心类允许JSP页面在更高的层次上操作数据库,避免大量地编写底层SQL代码。

数据库最基本的元素之一是表。在数据库中,表是数据记录的容器,比如用来容纳雇员名字和薪水信息。下面的DBTable类描述的就是数据库里面的表。DBTable类的公用方法负责处理最底层的细节。比如,addChildTable方法用来建立表的父-子关系,addConstraint方法用来过滤表的输出。

【Listing 1:DBTable.java,描述数据库的表】

import java.util.*;

public class DBTable {

String pkey;

// 主键

String name;

// 表的名字

Vector columns;

// 结果集包含的列

Hashtable col_desc; // 各个列的描述

Vector children;

// 子表

Vector constraints; // 所有约束

/* 创建一个新的、未经初始化的表*/

protected DBTable() {

columns

= new Vector();

children

= new Vector();

constraints = new Vector();

col_desc = new Hashtable();

}

/* 创建一个新的表,指定名字和主键*/

public DBTable(String name, String pkey) {

this();

this.name = name;

this.pkey = pkey;

}

/* 返回主键 */

public String getPrimaryKey() {

return pkey;

}

/* 创建一个新的约束,设置它的值,

* 并把它加入表的约束列表

*/

public void addConstraint(String column,

int op,

String value) {

Constraint c = new Constraint();

c.column = column;

c.op

= op;

c.value

= value;

constraints.add(c);

}

/* 把结果集限制为单个记录的简便方法 */

public void constrainByPrimaryKey(String value) {

addConstraint(pkey, Constraint.EQ, "'" + value + "'");

}

/* 添加一个列 */

public void addColumn(String column,

String description) {

columns.add(column);

col_desc.put(column, description);

}

/* 添加一个子表,通过外键建立关系 */

public void addChildTable(DBTable table, String fkey) {

children.add(table);

addConstraint(this.pkey, Constraint.EQ,

table.name + "." + fkey);

}

/* 搜索当前表以及(递归地搜索)所有子表,

* 寻找指定的列,返回该列的描述 */

public String findColumnDescription(String column) {

String result = (String) col_desc.get(column);

if (result != null) { // 已经找到指定的列

return result;

} else {

// 在所有子表中搜索该列

Enumeration e = children.elements();

while (e.hasMoreElements()) {

DBTable child = (DBTable) e.nextElement();

result = child.findColumnDescription(column);

if (result != null) { // 已经找到!

return result;

}

}

return null; // 在所有表中都无法找到指定的列

}

}

/* 搜索当前表以及(递归地搜索)所有子表,

* 检查指定的列是否是一个主键 */

public boolean isPrimaryKey(String column) {

if (pkey.equals(column)) { // 已经找到指定的列

return true;

} else {

// 搜索所有子表

Enumeration e = children.elements();

while (e.hasMoreElements()) {

DBTable child = (DBTable) e.nextElement();

if (child.isPrimaryKey(column)) { // 已经找到!

return true;

}

}

return false;

}

}

}

单独的DBTable类其实没有什么实际用途,它只是一种抽象的描述,既没有建立底层的数据库连接,也没有任何SQL命令。为发挥DBTable类的作用,我们必须定义一个DBTable类的子类,在子类中利用DBTable类定义的方法访问数据库服务器。

下面就是DBTable类的子类SQLDBTable.java:

【Listing 2:SQLDBTable,扩展DBTable提供SQL和JDBC支持】

import java.sql.*;

import java.util.*;

public class SQLDBTable extends DBTable {

/* 构造函数 */

public SQLDBTable(String name, String pkey) {

super(name, pkey);

}

/* 生成一个SQL命令 */

public String generateSQL() {

/* 获得SQL命令中出现的所有表的一个清单 */

Vector tables = new Vector();

findTables(tables);

/* 获得所有列的一个清单 */

Vector columns = new Vector();

findColumns(columns);

/* 获得必须在WHERE子句中出现的所有约束

* 的一个清单

*/

Vector where = new Vector();

findConstraints(where);

/* 创建一个容纳SQL命令的StringBuffer */

StringBuffer sql = new StringBuffer("SELECT ");

sql.append(delimitedList(", ", columns.elements()));

sql.append(" FROM ");

sql.append(delimitedList(", ", tables.elements()));

if (where.size() 0) {

sql.append(" WHERE ");

sql.append(delimitedList(" AND ", where.elements()));

}

return sql.toString();

}

/* 利用一个JDBC连接提取结果记录,

* 注意:调用者必须关闭结果集的

* Statement对象

*/

public ResultSet fetchRows(Connection conn)

throws Exception

{

String sql = generateSQL();

/* 创建Statement(可能抛出SQLExeception异常)*/

Statement stmt = conn.createStatement();

/* 返回结果集 */

return stmt.executeQuery(sql);

}

/* 这是一个从主键以外的各个列获取数据的简便

* 方法。它在下列情形下使用:当你不想让用户看到主键时。

*关于使用该方法的例子,请参见HtmlSelectListMaker.java。

*/

public Enumeration getDisplayData(ResultSet rs) throws SQLException

{

ResultSetMetaData rmd = rs.getMetaData();

Vector result = new Vector();

for(int i = 0; i < rmd.getColumnCount(); i++) {

String column = rmd.getColumnName(i + 1);

if (isPrimaryKey(column)) {

continue;

}

result.addElement( rs.getString(column) );

}

return result.elements();

}

/* 该方法生成带分界符的列表,仅供内部使用。

* 用来为SQL命令生成空格或逗号分隔的列表。

*/

private String delimitedList(String delim, Enumeration e)

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有