目录:
引言 -- 参数基础
1. 结构(Structural)过滤器--FilterList
2.列值过滤器--SingleColumnValueFilter
2.1.第一种构造函数情况 -- 比较的关键字是字符数组
2.2.第二种构造函数情况 -- 比较的关键字是比较器ByteArrayComparable
3.键值元数据
3.1. 基于列族过滤数据的FamilyFilter
3.2. 基于限定符Qualifier(列)过滤数据的QualifierFilter
3.3. 基于列名(即Qualifier)前缀过滤数据的ColumnPrefixFilter
3.4. 基于多个列名(即Qualifier)前缀过滤数据的MultipleColumnPrefixFilter
3.5. 基于列范围(不是行范围)过滤数据ColumnRangeFilter
4. RowKey
5. PageFilter
6. SkipFilter
7. Utility--FirstKeyOnlyFilter
8. 取得查询结果
引言 -- 参数基础
有两个参数类在各类Filter中经常出现,统一介绍下:
(1)比较运算符 CompareFilter.CompareOp
比较运算符用于定义比较关系,可以有以下几类值供选择:
- EQUAL 相等
- GREATER 大于
- GREATER_OR_EQUAL 大于等于
- LESS 小于
- LESS_OR_EQUAL 小于等于
- NOT_EQUAL 不等于
(2)比较器 ByteArrayComparable
通过比较器可以实现多样化目标匹配效果,比较器有以下子类可以使用:
- BinaryComparator 匹配完整字节数组
- BinaryPrefixComparator 匹配字节数组前缀
- BitComparator
- NullComparator
- RegexStringComparator 正则表达式匹配
- SubstringComparator 子串匹配
1. 结构(Structural)过滤器--FilterList
FilterList 代表一个过滤器链,它可以包含一组即将应用于目标数据集的过滤器,过滤器间具有“与” FilterList.Operator.MUST_PASS_ALL 和“或” FilterList.Operator.MUST_PASS_ONE 关系。
官网实例代码,两个“或”关系的过滤器的写法:
FilterList list = new FilterList(FilterList.Operator.MUST_PASS_ONE); //数据只要满足一组过滤器中的一个就可以
SingleColumnValueFilter filter1 = new SingleColumnValueFilter(
cf,
column,
CompareOp.EQUAL,
Bytes.toBytes("my value")
);
list.add(filter1);
SingleColumnValueFilter filter2 = new SingleColumnValueFilter(
cf,
column,
CompareOp.EQUAL,
Bytes.toBytes("my other value")
);
list.add(filter2);
Scan scan = new Scan();
scan.setFilter(list);
2. 列值过滤器--SingleColumnValueFilter
SingleColumnValueFilter 用于测试列值相等 (CompareOp.EQUAL ), 不等 (CompareOp.NOT_EQUAL),或单侧范围 (e.g., CompareOp.GREATER)。
构造函数:
(1)比较的关键字是一个字符数组
SingleColumnValueFilter(byte[] family, byte[] qualifier, CompareFilter.CompareOp compareOp, byte[] value)
(2)比较的关键字是一个比较器(比较器下一小节做介绍)
SingleColumnValueFilter(byte[] family, byte[] qualifier, CompareFilter.CompareOp compareOp, ByteArrayComparable comparator)
2.1.第一种构造函数情况 -- 比较的关键字是字符数组
官网示例代码,检查列值和字符串'my value' 相等:
SingleColumnValueFilter filter = new SingleColumnValueFilter(
cf,
column,
CompareOp.EQUAL,
Bytes.toBytes("my value")
);
scan.setFilter(filter);
个人实测代码:
HTable table = HBaseDAO.getHTable("mypatents");
FilterList filterList = new FilterList(FilterList.Operator.MUST_PASS_ALL);
SingleColumnValueFilter filter = new SingleColumnValueFilter(
Bytes.toBytes("patentinfo"),
Bytes.toBytes("CREATE_TIME"),
CompareOp.EQUAL,
Bytes.toBytes("2016-06-07")
);
filterList.addFilter(filter);
Scan scan = new Scan();
scan.setFilter(filterList);
ResultScanner rs = table.getScanner(scan);
for (Result r : rs) {
System.out.println("Scan: " + r);
}
table.close();
注意:还是大写问题,HBase的列名必须大写!
2.2.第二种构造函数情况 -- 比较的关键字是比较器ByteArrayComparable
该章节主要是针对SingleColumnValueFilter的第二种构造函数使用情况做了一些举例:
(1)支持值比较的正则表达式 -- RegexStringComparator
官网示例代码:
RegexStringComparator comp = new RegexStringComparator("my."); //任意以my打头的值
SingleColumnValueFilter filter = new SingleColumnValueFilter(
cf,
column,
CompareOp.EQUAL,
comp
);
scan.setFilter(filter);
个人实测代码:
HTable table = HBaseDAO.getHTable("mypatents");
FilterList filterList = new FilterList(FilterList.Operator.MUST_PASS_ALL);
RegexStringComparator comp = new RegexStringComparator("2016-06-1.");
SingleColumnValueFilter filter = new SingleColumnValueFilter(
Bytes.toBytes("patentinfo"),
Bytes.toBytes("CREATE_TIME"),
CompareOp.EQUAL,
comp
);
filterList.addFilter(filter);
Scan scan = new Scan();
scan.setFilter(filterList);
ResultScanner rs = table.getScanner(scan);
for (Result r : rs) {
System.out.println("Scan: " + r);
}
table.close();
(2)检测一个子串是否存在于值中(大小写不敏感) -- SubstringComparator
官网示例代码:
SubstringComparator comp = new SubstringComparator("y val"); // looking for 'my value'
SingleColumnValueFilter filter = new SingleColumnValueFilter(
cf,
column,
CompareOp.EQUAL,
comp
);
scan.setFilter(filter);
个人实测代码:
HTable table = HBaseDAO.getHTable("147patents");
FilterList filterList = new FilterList(FilterList.Operator.MUST_PASS_ALL);
// RegexStringComparator comp = new RegexStringComparator("2016-06-1.");
SubstringComparator comp = new SubstringComparator("2016-06-1");
SingleColumnValueFilter filter = new SingleColumnValueFilter(
Bytes.toBytes("patentinfo"),
Bytes.toBytes("CREATE_TIME"),
CompareOp.EQUAL,
comp
);
filterList.addFilter(filter);
Scan scan = new Scan();
scan.setFilter(filterList);
ResultScanner rs = table.getScanner(scan);
for (Result r : rs) {
System.out.println("Scan: " + r);
}
table.close();
(3)BinaryComparator
二进制比较器,用得较少,有需要请自行查阅官网:http://hbase.apache.org/apidocs/org/apache/hadoop/hbase/filter/BinaryComparator.html
(4)BinaryPrefixComparator
二进制前缀比较器,用得较少,有需要请自行查阅官网:http://hbase.apache.org/apidocs/org/apache/hadoop/hbase/filter/BinaryPrefixComparator.html
3. 键值元数据
由于HBase 采用键值对保存内部数据,键值元数据过滤器评估一行的键(ColumnFamily:Qualifiers)是否存在 , 对应前节所述值的情况。
3.1. 基于列族过滤数据的FamilyFilter
构造函数:
FamilyFilter(CompareFilter.CompareOp familyCompareOp, ByteArrayComparable familyComparator)
个人实测代码:
HTable table = HBaseDAO.getHTable("mypatents");
/**
* FamilyFilter构造函数中第二个参数是ByteArrayComparable类型
* ByteArrayComparable类参见“引言-参数基础”章节
* 下面仅以最可能用到的BinaryComparator、BinaryPrefixComparator举例:
*/
FamilyFilter ff = new FamilyFilter(
CompareFilter.CompareOp.EQUAL ,
new BinaryComparator(Bytes.toBytes("pat")) //表中不存在pat列族,过滤结果为空
);
FamilyFilter ff1 = new FamilyFilter(
CompareFilter.CompareOp.EQUAL ,
new BinaryPrefixComparator(Bytes.toBytes("pat")) //表中存在以pat打头的列族patentinfo,过滤结果为该列族所有行
);
Scan scan = new Scan();
scan.setFilter(ff1);
ResultScanner rs = table.getScanner(scan);
注意:
- 如果希望查找的是一个已知的列族,则使用 scan.addFamily(family) 比使用过滤器效率更高;
- 由于目前HBase对多列族支持不完善,所以该过滤器目前用途不大。
3.2. 基于限定符Qualifier(列)过滤数据的QualifierFilter
构造函数:
QualifierFilter(CompareFilter.CompareOp op, ByteArrayComparable qualifierComparator)
个人实测代码:
HTable table = HBaseDAO.getHTable("mypatents");
/**
* QualifierFilter构造函数中第二个参数是ByteArrayComparable类型
* ByteArrayComparable类有以下子类可以使用:
* *******************************************
* BinaryComparator 匹配完整字节数组,
* BinaryPrefixComparator 匹配开始的部分字节数组,
* BitComparator,
* NullComparator,
* RegexStringComparator, 正则表达式匹配
* SubstringComparator
* *******************************************
* 下面仅以最可能用到的BinaryComparator、BinaryPrefixComparator举例:
*/
QualifierFilter ff = new QualifierFilter(
CompareFilter.CompareOp.EQUAL ,
new BinaryComparator(Bytes.toBytes("belong")) //表中不存在belong列,过滤结果为空
);
QualifierFilter ff1 = new QualifierFilter(
CompareFilter.CompareOp.EQUAL ,
new BinaryPrefixComparator(Bytes.toBytes("BELONG")) //表中存在以BELONG打头的列BELONG_SITE,过滤结果为所有行的该列数据
);
Scan scan = new Scan();
scan.setFilter(ff1);
ResultScanner rs = table.getScanner(scan); 说明:
- 一旦涉及到列(Qualifier),HBase就只认大写字母了!
- 该过滤器应该比FamilyFilter更常用!
3.3. 基于列名(即Qualifier)前缀过滤数据的ColumnPrefixFilter ( 该功能用QualifierFilter也能实现 )
构造函数:
ColumnPrefixFilter(byte[] prefix)
注意:
一个列名是可以出现在多个列族中的,该过滤器将返回所有列族中匹配的列。
官网示例代码,查找所有"abc"打头的列:
HTableInterface t = ...;
byte[] row = ...;
byte[] family = ...;
byte[] prefix = Bytes.toBytes("abc");
Scan scan = new Scan(row, row); // (optional) limit to one row
scan.addFamily(family); // (optional) limit to one family
Filter f = new ColumnPrefixFilter(prefix);
scan.setFilter(f);
scan.setBatch(10); // set this if there could be many columns returned
ResultScanner rs = t.getScanner(scan);
for (Result r = rs.next(); r != null; r = rs.next()) {
for (KeyValue kv : r.raw()) {
// each kv represents a column
}
}
rs.close();
个人实测代码:
HTable table = HBaseDAO.getHTable("mypatents");
//返回所有行中以BELONG打头的列的数据
ColumnPrefixFilter ff1 = new ColumnPrefixFilter(Bytes.toBytes("BELONG"));
Scan scan = new Scan();
scan.setFilter(ff1);
ResultScanner rs = table.getScanner(scan); 3.4. 基于多个列名(即Qualifier)前缀过滤数据的MultipleColumnPrefixFilter
说明:
MultipleColumnPrefixFilter 和 ColumnPrefixFilter 行为差不多,但可以指定多个前缀。
官方示例代码,查找所有"abc"或"xyz"打头的列:
HTableInterface t = ...;
byte[] row = ...;
byte[] family = ...;
byte[][] prefixes = new byte[][] {Bytes.toBytes("abc"), Bytes.toBytes("xyz")};
Scan scan = new Scan(row, row); // (optional) limit to one row
scan.addFamily(family); // (optional) limit to one family
Filter f = new MultipleColumnPrefixFilter(prefixes);
scan.setFilter(f);
scan.setBatch(10); // set this if there could be many columns returned
ResultScanner rs = t.getScanner(scan);
for (Result r = rs.next(); r != null; r = rs.next()) {
for (KeyValue kv : r.raw()) {
// each kv represents a column
}
}
rs.close();
个人实测代码:
HTable table = HBaseDAO.getHTable("mypatents");
byte[][] prefixes = new byte[][] {Bytes.toBytes("BELONG"), Bytes.toBytes("CREATE")};
//返回所有行中以BELONG或者CREATE打头的列的数据
MultipleColumnPrefixFilter ff = new MultipleColumnPrefixFilter(prefixes);
Scan scan = new Scan();
scan.setFilter(ff);
ResultScanner rs = table.getScanner(scan); 3.5. 基于列范围(不是行范围)过滤数据ColumnRangeFilter
说明:
- 可用于获得一个范围的列,例如,如果你的一行中有百万个列,但是你只希望查看列名为bbbb到dddd的范围
- 该方法从 HBase 0.92 版本开始引入
- 一个列名是可以出现在多个列族中的,该过滤器将返回所有列族中匹配的列
构造函数:
ColumnRangeFilter(byte[] minColumn, boolean minColumnInclusive, byte[] maxColumn, boolean maxColumnInclusive)
参数解释:
- minColumn - 列范围的最小值,如果为空,则没有下限;
- minColumnInclusive - 列范围是否包含minColumn ;
- maxColumn - 列范围最大值,如果为空,则没有上限;
- maxColumnInclusive - 列范围是否包含maxColumn 。
官网示例代码,查找列名在"bbbb"到"dddd"范围的数据:
HTableInterface t = ...;
byte[] row = ...;
byte[] family = ...;
byte[] startColumn = Bytes.toBytes("bbbb");
byte[] endColumn = Bytes.toBytes("bbdd");
Scan scan = new Scan(row, row); // (optional) limit to one row
scan.addFamily(family); // (optional) limit to one family
Filter f = new ColumnRangeFilter(startColumn, true, endColumn, true);
scan.setFilter(f);
scan.setBatch(10); // set this if there could be many columns returned
ResultScanner rs = t.getScanner(scan);
for (Result r = rs.next(); r != null; r = rs.next()) {
for (KeyValue kv : r.raw()) {
// each kv represents a column
}
}
rs.close();
个人实测代码:
HTable table = HBaseDAO.getHTable("mypatents");
byte[] startColumn = Bytes.toBytes("C");
byte[] endColumn = Bytes.toBytes("D");
//返回所有列中从C到D打头的范围的数据,实际返回类似CREATOR、CREATE_TIME、CHANNEL_CODE等列的数据
ColumnRangeFilter ff = new ColumnRangeFilter(startColumn, true, endColumn, true);
Scan scan = new Scan();
scan.setFilter(ff);
ResultScanner rs = table.getScanner(scan);
4. RowKey
当需要根据行键特征查找一个范围的行数据时,使用Scan的startRow和stopRow会更高效,但是,startRow和stopRow只能匹配行键的开始字符,而不能匹配中间包含的字符:
byte[] startColumn = Bytes.toBytes("aaa");
byte[] endColumn = Bytes.toBytes("bbb");
Scan scan = new Scan(startColumn,endColumn);
当需要针对行键进行更复杂的过滤时,可以使用RowFilter:
构造函数:
RowFilter(CompareFilter.CompareOp rowCompareOp, ByteArrayComparable rowComparator)
参数解释参见“引言-参数基础”章节。
个人实测代码:
HTable table = HBaseDAO.getHTable("147patents");
/**
* rowkey格式为:创建日期_发布日期_ID_TITLE
* 目标:查找 发布日期 为 2013-07-16 的数据
*/
RowFilter rf = new RowFilter(
CompareFilter.CompareOp.EQUAL ,
new SubstringComparator("_2016-05-16_")
);
Scan scan = new Scan();
scan.setFilter(rf);
ResultScanner rs = table.getScanner(scan); 注意:
测试过程中尝试通过组合使用两个RowFilter(CompareFilter.CompareOp参数分别为GREATER_OR_EQUAL和LESS_OR_EQUAL),和SubstringComparator,过滤找出指定发布时间范围内的数据,但结果比较意外,不是预想的数据,估计比较运算符GREATER_OR_EQUAL和LESS_OR_EQUAL和比较器SubstringComparator组合使用效果不太好,慎用。
5.PageFilter
指定页面行数,返回对应行数的结果集。
需要注意的是,该过滤器并不能保证返回的结果行数小于等于指定的页面行数,因为过滤器是分别作用到各个region server的,它只能保证当前region返回的结果行数不超过指定页面行数。
构造函数:
PageFilter(long pageSize)
实测代码(从“2013-07-26”行开始,取5行):
Scan scan = new Scan();
scan.setStartRow(Bytes.toBytes("2016-05-26"));
PageFilter pf = new PageFilter(5L);
scan.setFilter(pf);
ResultScanner rs = table.getScanner(scan);
for (Result r : rs) {
for (Cell cell : r.rawCells()) {
System.out.println("Rowkey : " + Bytes.toString(r.getRow())
+ " Familiy:Quilifier : "
+ Bytes.toString(CellUtil.cloneQualifier(cell))
+ " Value : "
+ Bytes.toString(CellUtil.cloneValue(cell))
+ " Time : " + cell.getTimestamp());
}
} 注意:
由于该过滤器并不能保证返回的结果行数小于等于指定的页面行数,所以更好的返回指定行数的办法是ResultScanner.next(int nbRows) ,即:
ResultScanner rs = table.getScanner(scan);
for (Result r : rs.next(5)) {
for (Cell cell : r.rawCells()) {
System.out.println("Rowkey : " + Bytes.toString(r.getRow())
+ " Familiy:Quilifier : "
+ Bytes.toString(CellUtil.cloneQualifier(cell))
+ " Value : "
+ Bytes.toString(CellUtil.cloneValue(cell))
+ " Time : " + cell.getTimestamp());
}
} 6.SkipFilter
根据整行中的每个列来做过滤,只要存在一列不满足条件,整行都被过滤掉。
例如,如果一行中的所有列代表的是不同物品的重量,则真实场景下这些数值都必须大于零,我们希望将那些包含任意列值为0的行都过滤掉。
在这个情况下,我们结合ValueFilter和SkipFilter共同实现该目的:
scan.setFilter(new SkipFilter(new ValueFilter(CompareOp.NOT_EQUAL,new BinaryComparator(Bytes.toBytes(0))));
构造函数:
SkipFilter(Filter filter)
个人实测代码:
目前的数据:
hbase(main):009:0> scan 'rd_ns:itable'
ROW COLUMN+CELL
100001 column=info:address, timestamp=1455417403438, value=anywhere
100001 column=info:age, timestamp=1455417403438, value=24
100001 column=info:name, timestamp=1455417403438, value=zhangtao
100002 column=info:address, timestamp=1455417426693, value=shangdi
100002 column=info:age, timestamp=1455417426693, value=28
100002 column=info:name, timestamp=1455417426693, value=shichao
100003 column=info:address, timestamp=1455494141522, value=huilongguan
100003 column=info:age, timestamp=1455494999631, value=29
100003 column=info:name, timestamp=1455494141522, value=liyang
3 row(s) in 0.0190 seconds
执行以下代码:
Configuration conf = HBaseConfiguration.create();
HTable table = new HTable(conf, "rd_ns:itable");
Scan scan = new Scan();
scan.setFilter(new SkipFilter(new ValueFilter(CompareOp.NOT_EQUAL,
new BinaryComparator(Bytes.toBytes("28")))));
ResultScanner rs = table.getScanner(scan);
for (Result r : rs) {
for (Cell cell : r.rawCells()) {
System.out.println("Rowkey : " + Bytes.toString(r.getRow())
+ " Familiy:Quilifier : "
+ Bytes.toString(CellUtil.cloneQualifier(cell))
+ " Value : "
+ Bytes.toString(CellUtil.cloneValue(cell))
+ " Time : " + cell.getTimestamp());
}
}
table.close(); 输出结果(整个100002行被过滤掉了):
Rowkey : 100001 Familiy:Quilifier : address Value : anywhere Time : 1455417403438
Rowkey : 100001 Familiy:Quilifier : age Value : 24 Time : 1455417403438
Rowkey : 100001 Familiy:Quilifier : name Value : zhangtao Time : 1455417403438
Rowkey : 100003 Familiy:Quilifier : address Value : huilongguan Time : 1405494141522
Rowkey : 100003 Familiy:Quilifier : age Value : 29 Time : 1455494999631
Rowkey : 100003 Familiy:Quilifier : name Value : liyang Time : 1455494141522 7. Utility--FirstKeyOnlyFilter
该过滤器仅仅返回每一行中的第一个cell的值,可以用于高效的执行行数统计操作。
估计实战意义不大。
构造函数:
public FirstKeyOnlyFilter()
个人实测代码:
HTable table = HBaseDAO.getHTable("mypatents");
FirstKeyOnlyFilter fkof = new FirstKeyOnlyFilter();
Scan scan = new Scan();
scan.setFilter(fkof);
ResultScanner rs = table.getScanner(scan); 8. 取得查询结果
无论是官网的Ref Guide还是网上流传的大部分博客中,输出查询结果的代码都是:
for (Result r = rs.next(); r != null; r = rs.next()) {
for (KeyValue kv : r.raw()) {
// each kv represents a column
}
}
但查看最新的API可知Result实例的raw()方法已经不建议使用了:
raw() Deprecated. as of 0.96, use rawCells()
0.96以后版本正确的获取结果代码如下:
for (Result r : rs) {
for (Cell cell : r.rawCells()) {
System.out.println(
"Rowkey : "+Bytes.toString(r.getRow())+
"Familiy:Quilifier : "+Bytes.toString(CellUtil.cloneQualifier(cell))+
"Value : "+Bytes.toString(CellUtil.cloneValue(cell))
);
}
}
相关推荐
本文将深入解析J2EE过滤器Filter的使用方法,并通过实例来阐述其工作原理。 过滤器在J2EE环境中扮演着预处理和后处理的角色,它可以拦截进入和离开Web应用程序的请求和响应,对数据进行处理或验证,从而提供诸如...
【Java Filter 过滤器详解】 Java Filter,也称为过滤器,是Servlet技术中的核心组件,主要用于在HTTP请求到达目标Servlet或资源之前以及响应返回给客户端之前进行拦截和处理。通过Filter,开发者能够实现诸如权限...
实例代码展示了如何在Vue应用中定义全局过滤器和本地过滤器,以及如何将过滤器应用于数据绑定表达式中。从实例中可以看出,过滤器在处理需要特定格式化的文本时非常有用,比如日期格式化。 在具体实现上,全局过滤...
2. 在模块上添加过滤器,通过`filter`方法指定过滤器的名称和处理函数: ```javascript myAppModule.filter("reverse", function() { return function(input, uppercase) { // 过滤器逻辑 }; }); ``` 在这个...
2. 创建Zend_Filter_StringToLower过滤器实例: ```php $filter = new Zend_Filter_StringToLower; ``` 3. 定义需要过滤的字符串,并应用filter()方法进行过滤: ```php $temp1 = "ABCDefGH"; $temp2 = "我爱NanJing...
### AngularJS 过滤器(Filter) AngularJS的过滤器是用来对数据进行格式化的一种工具,它可以在表达式或指令中使用。过滤器的使用非常简单,只需要通过管道符号(|)后跟过滤器的名称即可。例如,我们想要对一个名...
**JSP过滤器详解与项目实例** 在Java Web开发中,JSP(JavaServer Pages)是用于创建动态网页的一种技术,而过滤器(Filter)则是Servlet API中的一部分,用于处理HTTP请求和响应,提供了一种预处理和后处理请求的...
Angularjs过滤器是 angularjs非常...有朝一日,你可能需要使用自定义过滤器,所以下面这篇文章主要给大家介绍了Angular.Js中过滤器filter与自定义过滤器filter的相关资料,需要的朋友可以参考借鉴,下面来一起看看吧。
Vue.js 的过滤器(Filter)是用于数据转换的一种强大工具,它允许我们在模板中对数据进行处理,以呈现更符合需求的显示效果。过滤器通常用于格式化数据,如日期格式化、字符串首字母大写等。Vue.js 提供了内置的过滤...
过滤器的原理解析,以及使用代码实例
### Vue-cli 3 全局过滤器的实例代码详解知识点 #### Vue-cli 3 项目结构 Vue-cli 3 是一个基于 Vue.js 进行快速开发的完整系统。它提供了一个官方的命令行界面(CLI),用于快速搭建项目脚手架。项目结构在 vue-cli ...
在代码中,过滤器通过 `Vue.filter` 方法定义。这个方法接受两个参数:过滤器名称和过滤器函数。过滤器函数有三个参数,第一个是需要被格式化的值(在这个例子中是字符串),第二个是限制的长度,第三个是后缀。函数...
### Servlet配置过滤器Filter知识点详解 #### 一、概述 在Java Web开发中,`Servlet`过滤器(`Filter`)是一种重要的技术组件,它可以在请求到达目标资源(如Servlet或JSP页面)之前或者响应返回客户端之前进行...
### Struts2配置过滤器详解 #### 一、概述 Struts2是基于MVC模式的一个开源框架,它能够帮助开发者构建出结构清晰且易于维护的Web应用。在实际开发过程中,为了实现某些功能(例如用户认证、权限控制等),往往...
在Asp.Net MVC3中,过滤器(Filter)是一种强大的工具,用于实现面向切面编程(AOP),特别是在处理重复性的任务,如身份验证、日志记录、异常处理和行为拦截等方面。MVC框架提供了内置的Filter机制,使得开发者无需...