我们知道JSP页面是需要转换为servlet的,在转换过程中肯定是要进行编码的。在JSP转换为servlet过程中下面一段代码起到至关重要的作用。
在上面代码中有两个地方存在编码:pageEncoding、contentType的charset。其中pageEncoding是jsp文件本身的编码,而contentType的charset是指服务器发送给客户端时的内容编码。
在前面一篇博客中就提到过(java中文乱码解决之道(四)-----java编码转换过程)jsp在转换为Servlet的过程中是需要经过主要的三次编码转换过程(除去数据库编码转换、页面参数输入编码转换):
第一次:转换为.java文件;
第二次:转换为.class文件;
第三次:业务逻辑处理后输出。
第一阶段
JVM将JSP编译为.jsp文件。在这个过程中pageEncoding就起到作用了,JVM首先会获取pageEncoding的值,如果该值存在则采用它设定的编码来编译,否则则采用file.encoding编码来编译。
第二阶段
JVM将.java文件转换为.class文件。在这个过程就与任何编码的设置都没有关系了,不管JSP采用了什么样的编码格式都将无效。经过这个阶段后.jsp文件就转换成了统一的Unicode格式的.class文件了。
第三阶段
- 后台经过业务逻辑处理后将产生的结果输出到客户端。在这个过程中contentType的charset就发挥了功效。如果设置了charset则浏览器就会使用指定的编码格式进行解码,否则采用默认的ISO-8859-1编码格式进行解码处理。
流程如如下:
本文链接:java中文乱码解决之道(七)-----JSP页面编码过程,转载请注明。
前面已经做了一些准备工作,本篇将介绍查询条件的封装,它是规约模式的一个应用。
规约使用一个对象来封装谓词,我之前已经介绍过它在验证方面的应用,本篇是规约模式在查询方面的应用。
规约的强大之处在于,能够将一堆杂乱无章的条件判断或查询条件封装起来,以一个清晰的概念来表达,并使得这些谓词具备了可复用的能力。
首先在Util.Domains项目的Repositories目录中创建ICriteria接口,这个接口表示一个查询条件,代码如下。
using System.Linq.Expressions;
namespace Util.Domains.Repositories {
/// <summary>
/// 查询条件
/// </summary>
/// <typeparam name="TEntity">实体类型</typeparam>
public interface ICriteria<TEntity> where TEntity : class,IAggregateRoot {
/// <summary>
/// 获取谓词
/// </summary>
Expression<Func<TEntity, bool>> GetPredicate();
}
}
由于我们使用了EF这种ORM框架,查询条件的结果是一个Expression<Func<TEntity, bool>>的谓词表达式。
在Util.Datas项目中,打开Extensions.Query.cs文件,增加以下代码。
/// 过滤
/// </summary>
/// <typeparam name="T">实体类型</typeparam>
/// <param name="source">数据源</param>
/// <param name="criteria">查询条件</param>
public static IQueryable<T> Filter<T>( this IQueryable<T> source, ICriteria<T> criteria ) where T : class,IAggregateRoot {
if ( criteria == null )
return source;
var predicate = criteria.GetPredicate();
if ( predicate == null )
return source;
return source.Where( predicate );
}
我们在IQueryable对象上扩展了一个Filter方法,该方法接收一个查询条件,如果查询条件有效,就使用Where方法添加过滤条件。
基础工作就这么多,下面来看几个范例。
在信息系统中,经常会进行范围查询,比如一个日期段的查询。这看起来是一个简单的需求,初学者一般这样写,t => t.Date >= BeginDate && t.Date <= EndDate,其结果可能是错误的,这是由于从表现层传入的查询条件是可选的,如果客户没有进行输入,结果就是错的。
对于范围查询来讲,还有更多的细节需要思考,比如,起始日期和结束日期都没有输入,或只输入了起始日期或结束日期,也可能客户输入的起始日期比结束日期还大。为了获得健壮性,我们会对查询条件进行各种判断,从而导致杂乱无章的代码。更要命的是,这些代码无法复用,在另一个范围查询的位置,我们必须把之前的代码复制过去进行修改。
一个更好的办法是把范围查询逻辑封装到查询条件对象中,以后需要进行范围查询时,即可随手拈来。
在Util.Datas项目Queries目录中,新建Criterias目录,创建一个查询条件基类CriteriaBase,代码如下。
using System.Linq.Expressions;
using Util.Domains;
using Util.Domains.Repositories;
namespace Util.Datas.Queries.Criterias {
/// <summary>
/// 查询条件
/// </summary>
/// <typeparam name="TEntity">实体类型</typeparam>
public abstract class CriteriaBase<TEntity> : ICriteria<TEntity> where TEntity : class, IAggregateRoot {
/// <summary>
/// 谓词
/// </summary>
protected Expression<Func<TEntity, bool>> Predicate { get; set; }
/// <summary>
/// 获取谓词
/// </summary>
public virtual Expression<Func<TEntity, bool>> GetPredicate() {
return Predicate;
}
}
}
根据数据类型不同,范围查询有很多种类,比如日期范围查询、日期时间范围查询、整数范围查询、浮点数范围查询等。我们需要为范围查询条件创建一个基类SegmentCriteria,代码如下。
using System.Linq.Expressions;
using Util.Domains;
using Util.Lambdas;
namespace Util.Datas.Queries.Criterias {
/// <summary>
/// 段过滤条件
没有评论:
发表评论