`
walle1027
  • 浏览: 22990 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

web应用的表单查询

 
阅读更多

      在开发web应用程序中,表单查询是一个非常常见的功能,但是需求五花八门,各种各样,更重要的是,后端的SQL/hql要根据页面的输入动态变化。常常形成一个庞大的拼sql的方法,并且各个方法都不一样,为开发,维护带来了不少困难。本人在总结了常用需求的基础上,再结合SSH,想出一个比较通用的方案,以此抛砖引玉。

     实现的思路是这样的,根据页面输入,自动将页面输入转化成一组查询条件,数据访问层再根据这些查询条件自动组装SQL/hql。这个是查询条件类。

import java.io.Serializable;

/**
 * 表单上的查询条件封装类
 * 封装表单的查询条件
 *
 * @auther: XXX
 * Date: 11-4-22
 * Time: 下午2:16
 * @version: 1.0
 */
public class QueryCondition implements Serializable {
    /**
     * 查询主实体名称
     */
    private String enityName;
    /**
     * 实体对应的属性名称
     */
    private String propertyName;
    /**
     * 实体对应的属性类型
     */
    private String propertyType;
    /**
     * 查询关系符号
     */
    private Operator operator;
    /**
     * like查询时候的匹配模式
     */
    private MatchMode matchMode;
    /**
     * 条件的值
     */
    private String value;
    /**
     * 输入的第二个值
     */
    private String value2;
    /**
     * 多个值
     */
    private String[] multipleValue;

    public MatchMode getMatchMode() {
        return matchMode;
    }

    public void setMatchMode(MatchMode matchMode) {
        this.matchMode = matchMode;
    }

    public String getEnityName() {
        return enityName;
    }

    public void setEnityName(String enityName) {
        this.enityName = enityName;
    }

    public String getPropertyName() {
        return propertyName;
    }

    public void setPropertyName(String propertyName) {
        this.propertyName = propertyName;
    }

    public String getPropertyType() {
        return propertyType;
    }

    public void setPropertyType(String propertyType) {
        this.propertyType = propertyType;
    }

    public Operator getOperator() {
        return operator;
    }

    public void setOperator(Operator operator) {
        this.operator = operator;
    }

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }

    public String getValue2() {
        return value2;
    }

    public void setValue2(String value2) {
        this.value2 = value2;
    }

    public String[] getMultipleValue() {
        return multipleValue;
    }

    public void setMultipleValue(String[] multipleValue) {
        this.multipleValue = multipleValue;
    }
}

    这个是oprator类,包含了常用的操作符

/**
 * 关系操作符号
 *
 * @author XX
 * @version 1.0
 */
public enum Operator {

	LIKE,    // Like

	LT,     // 小于

	GT,    // 大于

	LE, // 小于等于

	GE,  // 大于等于

	NE,   // 不等于

	IN,    // IN

	BETWEEN, //between

	EQ        //等于
}

   MathcMode 匹配模式类,模仿hibernate

 

/**
 * @auther: XXX
 * Date: 11-4-27
 * Time: 下午4:40
 * @version: 1.0
 */
public enum MatchMode {
	//精确匹配
	EXACT,
	BEFORE,//前匹配
	AFTER, //后匹配
	ANYWHERE //任意匹配
}

   根据查询条件构造criteria

/**
	 * 根据查询条件组件 QueryBuilder
	 * QueryBuilder 的用法请参考hibernate源代码
	 *
	 * @param conditions 查询条件
	 * @return
	 */
	protected Criteria buildCritria(final List<QueryCondition> conditions) {
		if (conditions != null && conditions.size() > 0) {
			Criteria criteria = getSession().createCriteria(entityClass);
			ClassMetadata metadata = getSessionFactory().getClassMetadata(entityClass);
			for (QueryCondition qc : conditions) {
				if (qc == null) continue;
				Type type = metadata.getPropertyType(qc.getPropertyName());
				switch (qc.getOperator()) {
					case LIKE:
						if (StringUtils.isNotEmpty(qc.getValue())) {

							switch (qc.getMatchMode()) {
								case EXACT:
									criteria.add(Restrictions.like(qc.getPropertyName(), qc.getValue(), MatchMode.EXACT));
									break;
								case AFTER:
									criteria.add(Restrictions.like(qc.getPropertyName(), qc.getValue(), MatchMode.END));
									break;
								case BEFORE:
									criteria.add(Restrictions.like(qc.getPropertyName(), qc.getValue(), MatchMode.START));
									break;
								case ANYWHERE:
									criteria.add(Restrictions.like(qc.getPropertyName(), qc.getValue(), MatchMode.ANYWHERE));
									break;
								default:
									criteria.add(Restrictions.like(qc.getPropertyName(), qc.getValue(), MatchMode.ANYWHERE));
									break;
							}

						}
						break;
					case LT:
						if (StringUtils.isNotEmpty(qc.getValue())) {
							Object value = stringToObject(qc.getValue(), type);
							criteria.add(Restrictions.lt(qc.getPropertyName(), value));
						}
						break;
					case GT:
						if (StringUtils.isNotEmpty(qc.getValue())) {
							Object value = stringToObject(qc.getValue(), type);
							criteria.add(Restrictions.gt(qc.getPropertyName(), value));
						}
						break;
					case LE:
						if (StringUtils.isNotEmpty(qc.getValue())) {
							Object value = stringToObject(qc.getValue(), type);
							criteria.add(Restrictions.le(qc.getPropertyName(), value));
						}
						break;
					case GE:
						if (StringUtils.isNotEmpty(qc.getValue())) {
							Object value = stringToObject(qc.getValue(), type);
							criteria.add(Restrictions.ge(qc.getPropertyName(), value));
						}
						break;
					case NE:
						if (StringUtils.isNotEmpty(qc.getValue())) {
							Object value = stringToObject(qc.getValue(), type);
							criteria.add(Restrictions.ne(qc.getPropertyName(), value));
						}
						break;
					case IN:
						if (qc.getMultipleValue() != null && qc.getMultipleValue().length > 0) {
							Object[] values = new Object[qc.getMultipleValue().length];
							for (int i = 0; i < qc.getMultipleValue().length; i++) {
								values[i] = stringToObject(qc.getMultipleValue()[i], type);
							}
							criteria.add(Restrictions.in(qc.getPropertyName(), values));
						}
						break;
					case BETWEEN:
						if (StringUtils.isNotEmpty(qc.getValue()) || StringUtils.isNotEmpty(qc.getValue2())) {
							criteria.add(Restrictions.between(qc.getPropertyName(), qc.getValue(), qc.getValue2()));
						}
						break;
					default:
						if (StringUtils.isNotEmpty(qc.getValue())) {
							Object value = stringToObject(qc.getValue(), type);
							criteria.add(Restrictions.eq(qc.getPropertyName(), value));
						}
						break;
				}
			}
			return criteria;
		}
		return null;
	}

    根据查询条件构造hql

 

/**
	 * 根据查询条件组件 QueryBuilder
	 * QueryBuilder 的用法请参考hibernate源代码
	 *
	 * @param conditions 查询条件
	 * @return
	 */
	protected QueryBuilder buildQuery(final List<QueryCondition> conditions) {
		if (conditions != null && conditions.size() > 0) {
			String entityName = entityClass.getSimpleName();
			QueryBuilder queryBuilder = new QueryBuilder(entityName, StringUtils.uncapitalize(entityName));
			ClassMetadata metadata = getSessionFactory().getClassMetadata(entityClass);
			Parameters parameters = queryBuilder.getRootParameters();
			for (QueryCondition qc : conditions) {
				if (qc == null) continue;
				Type type = metadata.getPropertyType(qc.getPropertyName());
				switch (qc.getOperator()) {
					case LIKE:
						if (StringUtils.isNotEmpty(qc.getValue())) {
							String value = qc.getValue();
							switch (qc.getMatchMode()) {
								case EXACT:
									break;
								case BEFORE:
									value = "%" + value;
									break;
								case AFTER:
									value = value + "%";
									break;
								case ANYWHERE:
									value = "%" + value + "%";
									break;
								default:
									value = "%" + value + "%";
									break;
							}
							parameters.addWhereWithParam(qc.getPropertyName(), "like", value);
						}
						break;
					case LT:
						if (StringUtils.isNotEmpty(qc.getValue())) {
							Object value = stringToObject(qc.getValue(), type);
							parameters.addWhereWithParam(qc.getPropertyName(), "<", value);
						}
						break;
					case GT:
						if (StringUtils.isNotEmpty(qc.getValue())) {
							Object value = stringToObject(qc.getValue(), type);
							parameters.addWhereWithParam(qc.getPropertyName(), ">", value);
						}
						break;
					case LE:
						if (StringUtils.isNotEmpty(qc.getValue())) {
							Object value = stringToObject(qc.getValue(), type);
							parameters.addWhereWithParam(qc.getPropertyName(), "<=", value);
						}
						break;
					case GE:
						if (StringUtils.isNotEmpty(qc.getValue())) {
							Object value = stringToObject(qc.getValue(), type);
							parameters.addWhereWithParam(qc.getPropertyName(), ">=", value);
						}
						break;
					case NE:
						if (StringUtils.isNotEmpty(qc.getValue())) {
							Object value = stringToObject(qc.getValue(), type);
							parameters.addWhereWithParam(qc.getPropertyName(), "!=", value);
						}
						break;
					case IN:
						if (qc.getMultipleValue() != null && qc.getMultipleValue().length > 0) {
							Object[] values = new Object[qc.getMultipleValue().length];
							for (int i = 0; i < qc.getMultipleValue().length; i++) {
								values[i] = stringToObject(qc.getMultipleValue()[i], type);
							}
							parameters.addWhereWithParams(qc.getPropertyName(), "in (", values, ")");
						}
						break;
					case BETWEEN:
						if (StringUtils.isNotEmpty(qc.getValue()) && StringUtils.isEmpty(qc.getValue2())) {
							Object minValue = stringToObject(qc.getValue(), type);
							parameters.addWhereWithParam(qc.getPropertyName(), ">=", minValue);
						} else if (StringUtils.isEmpty(qc.getValue()) && StringUtils.isNotEmpty(qc.getValue2())) {
							Object maxValue = stringToObject(qc.getValue(), type);
							parameters.addWhereWithParam(qc.getPropertyName(), "<=", maxValue);
						} else if (StringUtils.isNotEmpty(qc.getValue()) && StringUtils.isNotEmpty(qc.getValue2())) {
							Object minValue = stringToObject(qc.getValue(), type);
							Object maxValue = stringToObject(qc.getValue2(), type);
							parameters.addWhereWithParam(qc.getPropertyName(), ">=", minValue);
							parameters.addWhereWithParam(qc.getPropertyName(), "<=", maxValue);
						}
						break;
					default:
						if (StringUtils.isNotEmpty(qc.getValue())) {
							Object value = stringToObject(qc.getValue(), type);
							parameters.addWhereWithParam(qc.getPropertyName(), "=", value);
						}
						break;
				}
			}
			return queryBuilder;
		}
		return null;
	}

    由于从前端传来的参数都是String型的,所以需要把String型的数据进行数据类型转换。这里借助了hibernate的实现。

       /**
	 * 从字符串到java对象的转换
	 *
	 * @param value 值
	 * @param type  类型
	 * @return
	 */
	protected Object stringToObject(String value, Type type) {
		Object ret = null;
		if (type instanceof TimestampType) {
			SimpleDateFormat sdf = new SimpleDateFormat();
			if (value.length() > 10) {
				sdf.applyPattern("yyyy-MM-dd HH:mm:ss");
			} else {
				sdf.applyPattern("yyyy-MM-dd");
			}
			try {
				ret = sdf.parse(value);
			} catch (ParseException e) {
				e.printStackTrace();
			}
		} else if (type instanceof AbstractStandardBasicType) {
			ret = ((AbstractStandardBasicType) type).fromString(value);
		}
		return ret;
	}

   调用方法执行 

    /**
	 * 根据条件自动查询
	 *
	 * @param conditions 查询条件
	 * @return
	 */
	public final List<T> findByCondition(final List<QueryCondition> conditions) {
		Criteria criteria = buildCritria(conditions);
		if (criteria != null) {
                       //增加自定义的其他查询条件
			addCustomCriterion(criteria);
			return criteria.list();
		}
		return null;
	}

    为了能将页面上输入值变成查询条件的List,结合了struts2的自动封装数据的特性,在html中只要这样写,就可以自动将输入项目组装成查询条件的List

<td width="9%" class="right">
			用户编号<@splitor/>
</td>
<td width="18%">
	<input type="hidden" name="condition[0].propertyName" value="userCode"/>
	<select id="__select_userCode" name="condition[0].operator" dojoType="dijit.form.Select">
		<option value="LIKE">模糊查询</option>
		<option value="EQ">相等</option>
		<option value="LT">小于</option>
		<option value="GT">大于</option>
		<option value="LE">小于等于</option>
		<option value="GE">大于等于</option>
		<option value="NE">不等于</option>
		<option value="IN">等于多个</option>
		<option value="BETWEEN">范围</option>
	</select>
	<input type="hidden" name="condition[0].matchMode" value="BEFORE"/>
	<input dojoType="dijit.form.TextBox" name="condition[0].value" id="userCode"/>
</td>
<td width="9%" class="right">
			名称<@splitor/>
</td>
<td width="18%">
	<input type="hidden" name="condition[1].propertyName" value="userName"/>
	<select id="__select_userName" name="condition[1].operator" dojoType="dijit.form.Select">
		<option value="LIKE">模糊查询</option>
		<option value="EQ">相等</option>
		<option value="LT">小于</option>
		<option value="GT">大于</option>
		<option value="LE">小于等于</option>
		<option value="GE">大于等于</option>
		<option value="NE">不等于</option>
		<option value="IN">等于多个</option>
		<option value="BETWEEN">范围</option>
	</select>
	<input type="hidden" name="condition[1].matchMode" value="ANYWHERE"/>
	<input dojoType="dijit.form.TextBox" name="condition[1].value" id="userName"/>
</td>

   只要在Action或者Model中定义这样的一个属性,就可以完成自动转换。

/**
 * 查询条件
 */
protected List<QueryCondition> condition;

 当页面提交或者ajax请求时,会自动将上面的输入变成condition,只要将condition传入上述的方法内,就会自动组装查询条件。

 为了让页面书写简单,将上面的输入项目写成一个宏吧,这样使用更方便。

<#--
|查询条件
| property 属性名 必须输入的参数
| index    顺序号 可选参数,但是要保证它不重复
| id       每个输入项的Id,可选参数,但是在使用dojo的情况下,要保证它不重复
| type     输入框的类型,这个类型是指的dojo的类型。
|            大体来说分为,文本,下拉单,日期输入框,数字输入框 ,复选框,单选框 这几种
-->
<#macro seniorQuery property index=0 id="id" type="text">
<label for="${id}"><@s.text name="${property}"/>:</label>
<input type="hidden" name="condition[${index}].propertyName" value="${property}"/>
<select id="__select_${id}" name="condition[${index}].operator" dojoType="dijit.form.Select">
	<option value="LIKE">模糊查询</option>
	<option value="EQ">相等</option>
	<option value="LT">小于</option>
	<option value="GT">大于</option>
	<option value="LE">小于等于</option>
	<option value="GE">大于等于</option>
	<option value="NE">不等于</option>
	<option value="IN">等于多个</option>
	<option value="BETWEEN">范围</option>
</select> &nbsp;
<#--根据类型决定输入控件的类型-->
	<#local controlType = "dijit.form.TextBox">
	<#if type=="number">
		<#local controlType="dijit.form.NumberTextBox">
		<#elseif type="date">
			<#local controlType="dijit.form.DateTextBox">
		<#elseif type="combo">
			<#local controlType="dojo.form.ComboBox">
		<#elseif type="checkbox">
			<#local controlType="dojo.form.CheckBox">
		<#elseif type="radio">
			<#local controlType="dojo.form.Radio">
	</#if>
<input id="${id}" name="condition[${index}].value" dojoType="${controlType}"/>
<script type="text/javascript">
	dojo.ready(function() {
		dojo.connect(dijit.byId("__select_${id}"), "onChange", function() {
			var operator = dijit.byId("__select_${id}").value;
			if (operator == "BETWEEN") {
				var newObj = new ${controlType}({
					id:"${id}Max",
					name:"condition[${index}].value2"});
				newObj.placeAt(dijit.byId("${id}").domNode, "after");
			} else {
				if (typeof(dijit.byId("${id}Max")) != "undefined") {
					dijit.byId("${id}Max").destroy();
				}
			}
		});
	})
</script>
</#macro>

 这样使用起来更方便,你的查询方法会更容易维护,因为所有 表单的查询条件,都被自动创建为criteria了,额外的关联你可以在addCustomCriterion(criteria);里面实现,这个方法是空方法,你只要新建一个子类,重写此方法就可以了。

 

当然你可以扩展这些宏,或者这些方法。

 

 

 

1
2
分享到:
评论

相关推荐

    web表单及查询

    在传统的Web应用中,当用户在表单中输入查询条件或翻页时,页面会通过HTTP请求发送到服务器,服务器处理请求,然后返回新的HTML页面。这种方式效率较低,因为每次交互都需要完整页面的刷新。然而,通过前端分页和...

    应用Web应聘表单

    在Web开发领域,创建一个应用应聘表单是常见的任务,尤其在招聘流程自动化的过程中。"应用Web应聘表单"是一个用于收集求职者信息的在线平台,它具备信息验证功能、日期选择器以及二级省市联动菜单,以确保提交的数据...

    基于Infopath实现WEB动态表单

    Infopath是一个由微软开发的信息收集工具,主要用于设计、发布和管理XML表单,它允许用户无需编程就可以创建复杂的表单,并且能够将这些表单部署为基于Web的应用程序。Infopath表单通常在Microsoft Office InfoPath ...

    使用表单构建Web页面

    通过理解两者之间的转换机制和Domino Designer的特性,开发者可以创建出满足不同需求的Web应用程序,同时确保数据的准确性和用户界面的友好性。在实际开发过程中,不断探索和实践这些知识点,将有助于提升Web应用的...

    移动 web应用程序 组建

    移动Web应用程序组建是针对ASP.NET框架的一个重要工具集,它专为在移动设备上构建高效、响应式的Web应用而设计。这些组件和技术使得开发者能够利用ASP.NET的优势,为智能手机和平板电脑等移动设备提供优化的用户体验...

    c#+web应用程序入门经典.pdf

    但是,根据标题、描述和标签,可以推测本书的内容涉及C#语言和Web应用程序的入门知识。 C#是一种面向对象的编程语言,它是微软公司推出的一种高级编程语言,主要运行于.NET框架之上。C#具备了现代编程语言所需的...

    Web表单高级技巧

    总之,掌握Web表单的高级技巧对于提升Web应用程序的质量和用户满意度至关重要。通过优化表单设计、高效处理表单数据以及利用ASP.NET的特性,我们可以创建更加智能和用户友好的Web表单。不断学习和实践,才能在这个...

    C#web开发者指南教程PDF(含源代码),很适合入门学习C#web制作web应用程序。附带源代码。

    《C# Web开发者指南教程》是一本专门为初学者设计的教育资源,旨在帮助读者掌握使用C#语言进行Web应用程序开发的基本技能。这本书包含了丰富的理论知识和实际操作指导,结合了源代码,使得学习过程更具实践性。 C#...

    WEB表单设计学习总结.docx

    在 WEB 应用程序中,表单是必不可少的一部分,例如注册、登录、支付等,它们直接影响着用户体验和网站的整体性能。然而,填写表单通常是件麻烦的事情,人们总是希望快速完成表单,以便继续下一步的操作。因此,设计...

    Web表单设计 创建高可用性的网页表单 英文版

    总而言之,Web表单设计对于网站和应用程序来说至关重要,因为它们直接涉及到用户交互和数据收集的过程。一个设计良好的表单可以提高用户体验,促进信息的有效获取,并且有助于提升网站的整体可用性。本书通过深入...

    自定义表单web工程

    通过这个自定义表单Web工程,我们可以学习到如何结合Java后端技术和前端技术来实现一个完整的Web应用,理解服务器与浏览器之间的通信过程,以及如何利用现有的开发工具和框架提高开发效率。同时,对于想要深入学习...

    《Java Web应用开发实用教程》练习答案.docx

    Java Web 应用开发实用教程习题答案 本资源总结了《Java Web 应用开发实用教程》的习题答案,涵盖了 HTML、Java Web 开发、JSP、Tomcat 等方面的知识点。 一、HTML 基础知识 1. HTML 中超链接标记为 `和&lt;/a&gt;` 2. ...

    Flask Web开发:基于Python的Web应用开发实战

    **Flask Web开发:基于Python的Web应用开发实战** Flask是Python编程语言中的一个轻量级Web应用程序框架,以其简洁、灵活的特性受到了开发者们的广泛欢迎。它遵循"微框架"理念,允许开发者自由选择如何组织项目和...

    PHP Web应用开发教程.rar

    通过本教程的学习,你将具备开发动态、功能丰富的Web应用的能力,同时也能为进阶学习如框架、前端技术、服务器优化等打下坚实的基础。在实践中不断探索和积累经验,你将成为一名出色的PHP开发者。

    Flask Web应用开发实战.pdf

    《Flask Web应用开发实战》是一本专注于使用Python的轻量级Web框架Flask进行Web应用开发的专业书籍。Flask以其简洁、灵活的特性,在Python Web开发领域深受开发者喜爱。这本书详细介绍了如何利用Flask构建功能完备的...

    学习《Flask Web开发:基于Python的Web应用开发实战》分享.zip

    《Flask Web开发:基于Python的Web应用开发实战》是一本深入浅出的教程,旨在帮助读者掌握使用Python的Flask框架构建Web应用程序的技术。Flask是一个轻量级的Web服务器网关接口(WSGI)Web应用框架,以其灵活性、...

    Web 应用程序框架组件参考指南

    根据给定的文件信息,我们可以深入探讨Web应用程序框架组件及其在构建现代Web应用中的关键作用。这份《Web应用程序框架组件参考指南》不仅是一份技术文档,更是开发人员理解和掌握Web应用构建基石的重要资料。 ### ...

    Java Web应用客户端编程

    1. **表单验证**:在Web应用中,用户输入的数据需要进行验证,以确保其有效性和安全性。这通常通过JavaScript或jQuery实现,例如检查电子邮件格式、手机号码合法性等。同时,后台也可以通过Servlet或JSP进行二次验证...

    Java Web应用开发项目教程(附电子教案,程序源代码,习题答案)

    《Java Web应用开发项目教程》是一本以实践为导向的教程,旨在帮助读者深入理解并掌握Java Web开发技术。教程通过完整的案例,采用模块化的教学方式,将复杂的Web应用开发过程分解为可操作的步骤,逐步引导学习者...

Global site tag (gtag.js) - Google Analytics