??xml version="1.0" encoding="utf-8" standalone="yes"?>
]]>
看看Hibernate Validator 是怎么做的?一见到?怿你就会说: Oh God, q就是我需要的.
M获得Matrix授权的网站,转蝲请保留以下作者信息和链接Q?/span>
作者:icess(作者的blog:http://blog.matrix.org.cn/page/icess)
关键字:Hibernate Validator
用Annotations l类或者类的属性加上约?constraint),在运行期查属性值是很优雅的.Hibernate Validator是q样的一个框?该框架是十分Ҏ?像参考文中宣称的那?,几乎没有什么学习曲U?Validator 是一个验证框?不需要和Hibernate的其他部分绑定就可以使用,只要在你的项目中dHibernate-annotations.jar库就可以?那么下面p我们看看怎么使用?
Person.java c?/font>
/*
* Created on 2006-1-12 Person.java
* @author
*/
package
test.annotation.validator;
import
org.hibernate.validator.Length;
import
org.hibernate.validator.Min;
import
org.hibernate.validator.Valid;
//@Serializability //试自定义约?/font>
public class
Person {
private
String name;
private int
age;
private
Address address;
public
Person() {}
@Valid //注意此处
public
Address getAddress() {
return
address;
}
public void
setAddress(Address address) {
this
.address = address;
}
@Min(value =
1
)
public int
getAge() {
return
age;
}
public void
setAge(
int
age) {
this
.age = age;
}
@Length(min =
4
)
public
String getName() {
return
name;
}
public void
setName(String name) {
this
.name = name;
}
}
Address.java c?/font>
/*
* Created on 2006-1-12 Address.java
* @author
*/
package
test.annotation.validator;
import
org.hibernate.validator.Length;
import
org.hibernate.validator.Max;
import
org.hibernate.validator.Min;
public class
Address {
private
String street;
private int
num;
public
Address() {}
@Min(value =
1
)
@Max(value =
100
)
public int
getNum() {
return
num;
}
public void
setNum(
int
num) {
this
.num = num;
}
@Length(min =
3
,max =
8
)
public
String getStreet() {
return
street;
}
public void
setStreet(String street) {
this
.street = street;
}
}
上面是两个用 Validator Annotations 注释?c? 每个属性都?U束限制? 下面看看试的类?
TestValidator.java c?/code>
/*
* Created on 2006-1-12
* @author icerain
*/
package
test.annotation.validator;
import
org.hibernate.validator.ClassValidator;
import
org.hibernate.validator.InvalidValue;
public class
TestValidator {
public void
test() {
Address add =
new
Address();
add.setNum(
0
);
add.setStreet(
"1"
);
Person p =
new
Person();
p.setAddress(add);
p.setAge(
0
);
p.setName(
"ice"
);
/******************Test validator ********/
// 注意该处只验证了Person Z说明 @Valid 注释的?/font>
ClassValidator<Person> classValidator =
new
ClassValidator<Person> (Person.
class
);
InvalidValue[] validMessages = classValidator.getInvalidValues(p);
for
(InvalidValue value : validMessages) {
System.out.println(
"InvalidValue 的长度是:"
+ validMessages.length
+
" . 验证消息? "
+ value.getMessage()
+
" . PropertyPath ?"
+ value.getPropertyPath()
+
" .\n\t PropertyName ? "
+value.getPropertyName()
+
"Value ? "
+ value.getValue()
+
" Bean ? "
+ value.getBean()
+
"\n\t BeanClass ?"
+ value.getBeanClass());
}
}
public static void
main(String[] args) {
new
TestValidator().test();
}
}
E序的输出如? InvalidValue 的长度是:4 . 验证消息? 必须大于{于 1 . PropertyPath ?age . PropertyName ? age. Value ? 0 Bean ? test.annotation.validator.Person@dd87b2 BeanClass ?class test.annotation.validator.Person InvalidValue 的长度是:4 . 验证消息? 长度必须介于 4 ?2147483647 之间 . PropertyPath ?name . PropertyName ? name. Value ? ice Bean ? test.annotation.validator.Person@dd87b2 BeanClass ?class test.annotation.validator.Person InvalidValue 的长度是:4 . 验证消息? 必须大于{于 1 . PropertyPath ?address.num . PropertyName ? num. Value ? 0 Bean ? test.annotation.validator.Address@197d257 BeanClass ?class test.annotation.validator.Address InvalidValue 的长度是:4 . 验证消息? 长度必须介于 3 ?8 之间 . PropertyPath ?address.street . PropertyName ? street. Value ? 1 Bean ? test.annotation.validator.Address@197d257 BeanClass ?class test.annotation.validator.Address 可以看出不满约束的值都被指Z. 同时该句: 我们只验证了 Person. 在Person里面的Address的属?׃?code style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New',Courier">@Valid Annotations 所?Address的相兛_性也被机联验证了 . InvalidValue 的长度是:2 . 验证消息? 必须大于{于 1 . PropertyPath ?age . PropertyName ? age. Value ? 0 Bean ? test.annotation.validator.Person@18fef3d BeanClass ?class test.annotation.validator.Person InvalidValue 的长度是:2 . 验证消息? 长度必须介于 4 ?2147483647 之间 . PropertyPath ?name . PropertyName ? name. Value ? ice Bean ? test.annotation.validator.Person@18fef3d BeanClass ?class test.annotation.validator.PersonClassValidator<Person> classValidator = new ClassValidator<Person> (Person.class);
如果 ?/span>
@Valid Annotations L,l果如下:
可以看出 没有验证 Address.
当然?,你还可以只验证一个属?, 没有必要验证整个c?只需要在调用
classValidator.getInvalidValues(p,"age")Ҏ?加上你要验证的属性就可以?如我们只想验证age 属?把代码改为如下所C?
InvalidValue[] validMessages = classValidator.getInvalidValues(p,"age"); /
/只验证age 属?/font>
q行l果如下:
InvalidValue 的长度是:1 . 验证消息? 必须大于{于 1 . PropertyPath ?age .
PropertyName ? age. Value ? 0 Bean ? test.annotation.validator.Person@1457cb
BeanClass ?class test.annotation.validator.Person
只是验证?age 属?
怎么?,很简单吧. 关于 Hibernate Validator 内徏的验证Annotations 大家可以看看 API 或?参考文?中文版我正在译?误问我?Blog 获得最C?.
如果你要写自qU束?, 你不用担?,q也是很Ҏ?
MU束有两部分l成: [U束描述W?x释]the constraint descriptor (the annotation) 和[U束validator ?实现c] the constraint validator (the implementation class).下面我们扩展Hibernate Test suit 中的一个Test 来讲解一?
首先: 要声明一?/span>
constraint descriptor .如下:
package
test.annotation.validator;
import
java.lang.annotation.Documented;
import static
java.lang.annotation.ElementType.TYPE;
import static
java.lang.annotation.ElementType.FIELD;
import static
java.lang.annotation.ElementType.METHOD;
import
java.lang.annotation.Retention;
import static
java.lang.annotation.RetentionPolicy.RUNTIME;
import
java.lang.annotation.Target;
import
org.hibernate.validator.ValidatorClass;
/**
* Dummy sample of a bean-level validation annotation
*
*
@author
Emmanuel Bernard
*/
@ValidatorClass(SerializabilityValidator.
class
)
@Target({METHOD,FIELD,TYPE})
@Retention(RUNTIME)
@Documented
public
@interface Serializability {
int
num()
default
11
;
String message()
default
"bean must be serialiable"
;
}
@ValidatorClass(SerializabilityValidator.
class
) 指出?
constraint validator c?
@Target({METHOD,FIELD,TYPE})
@Retention(RUNTIME)
@Documented
q几个我׃用解释了?
Serializability 里面声明了一?message 昄U束的提CZ? num 只是Z说明一个方?在这里面没有实际用途用 .
然后是 实现一?/span>
constraint validator c?该类要实?/span>Validator<ConstraintAnnotation>.q里?/span>SerializabilityValidator.java 如下:
//$Id: SerializabilityValidator.java,v 1.3 2005/11/17 18:12:11 epbernard Exp $
constraint descriptor 里面的属?如上面我们声明的 num
package
test.annotation.validator;
import
java.io.Serializable;
import
org.hibernate.validator.Validator;
/**
* Sample of a bean-level validator
*
*
@author
Emmanuel Bernard
*/
public class
SerializabilityValidator
implements
Validator<Serializability>, Serializable {
public boolean
isValid(Object value) {
//q里只是Validator 里面?实现验证规则?Ҏ. value 是要验证的?
System.out.println(
"IN SerializabilityValidator isValid:"
+value.getClass()+
": "
+value.toString());
return
value instanceof Serializable;
}
public void initialize(Serializability parameters) {
// 在这里可?取得
System.out.println(
"IN SerializabilityValidator: parameters:"
+ parameters.num() );
}
}
然后在你的类中应用@Serializability 可以约束一个类实现
Serializable 接口? 如下:
在我们的Person.javac?d@Serializability Annotations ,把Person.java 中的
//@Serializability //试自定义约?注释Lok?
InvalidValue 的长度是:3 . 验证消息?
bean must be serialiable
. PropertyPath ?null .
PropertyName ? null. Value ? test.annotation.validator.Person@1a73d3c Bean ? test.annotation.validator.Person@1a73d3c
BeanClass ?class test.annotation.validator.Person
q行l果如下:
现在把Personcd?java.io.Serializable 接口 则没有出?验证错误消息.
消息的国际化也是很简单的,?/span>
Serializability 中的message 改ؓ以{}扩住?属性文件的Key可以了
public
@interface Serializability {
int
num()
default
11
;
String message()
default
"{Serializable}";
//"bean must be serialiable";
//消息的国际化
}
然后~辑资料文g. 注意 该资源文件中要包?Hibernate Validator 内徏的资? 可以在该org\hibernate\validator\resources 包里面的资源文g基础上修?,在打包里?q样可以了. 自己打包可能不太方便.你可以把该包里面的文件复制出?然后攑ֈ你自q目包下在自q? 该测试中 我是攑֜ test\resources 包下?
然后?资源文g中添?
Serializable = '''''' q么一? 样例如下:
#DefaultValidatorMessages.properties (DefaultValidatorMessages_zh.properties 不再列出^_^)
#下面?Hibernate Validator 内徏的国际化消息
validator.assertFalse= assertion failed
validator.assertTrue= assertion failed
validator.future= must be a future date
validator.length= length must be between {min} and {max}
validator.max= must be less than or equal to {value}
validator.min= must be greater than or equal to {value}
validator.notNull= may not be null
validator.past= must be a past date
validator.pattern= must match "{regex}"
validator.range= must be between {min} and {max}
validator.size= size must be between {min} and {max}
#下面是自定义的消?/font>
Serializable= Bean not Serializable //加上自己定义的国际化消息.
在构?/span>
ClassValidator
时要M 资源文g 如下:(在测试类?
ClassValidator<Person> classValidator = new ClassValidator<Person> (Person.class,ResourceBundle.getBundle("test.resources.DefaultValidatorMessages"));//加蝲资源
q样可以了 . 当然 你还可以 更改 Hibernate Validator 的消?不是在上面的资源文g中直接修?/font>
validator.length = ... {等
) , q记?Validator 注释中有?message 元素? 你以前用的都是默认?现在你可以该Z自己定义的了.
?validator.length 我把他改?"该字W串的长度不W合规定范围范围". 在资源文件中d一行键值属性对(key定义?"myMsg")如下:
myMsg=该字W串的长度不W合规定范围范围
q且q要?/font> @Length 注释中提供message的引用的key 如下 @Length(min = 4,message = "{ myMsg }")
再一ơ运行测?,我们可以看C面两条自定义l定的消息了 .如下:
InvalidValue 的长度是:3 . 验证消息?/font>: Bean 不是 ?Serializable . PropertyPath ?null .
PropertyName ? null. Value ? test.annotation.validator.Person@1bd4722 Bean ? test.annotation.validator.Person@1bd4722
BeanClass ?class test.annotation.validator.Person
InvalidValue 的长度是:3 . 验证消息?/font>: 该字W串的长度不W合规定范围范围 . PropertyPath ?name .
PropertyName ? name. Value ? ice Bean ? test.annotation.validator.Person@1bd4722
BeanClass ?class test.annotation.validator.Person
怎么?比你惌的简单吧.
OK 上面我们讨论?
Hibernate Validator 的主要用? 但是 该框架有什么用? ^_^
看到q里其实不用我在多说?大家都知道怎么?什么时候用. 作ؓ一介l性文章我q是在此l出一个最常用的例子吧,更好的用方式大家慢慢挖掘吧.
比如 : 你现在在开发一个h力资?HR)pȝ (其实是我们ERP评的一个作?^_^), 里面要处理大量的数据,其是在输入各种资料??登记员工信息. 如果你公司的员工的年龄要求是18 -- 60 那么你所输入的年龄就不能出q个范围. 你可能会说这很容易啊 , 不用Validator可以解军_.q保持数据前验证可以啦 如if ( e.getAge() > 60 || e.getAge() < 18 ) ........ l出错误信息 然后提示重新输入不就OK?用得着 兴师动众的来个第三方框架?
是啊 当就验证q一个属性时, 没有必要?! 但是一个真正的HR pȝ,会只有一个属性要验证? 恐怕要有N多吧
你要是每一个都那样 写一D验证代?是不是很烦啊 ,况且也不方便代码重用. 现在考虑一?Validator 是不是更高效?拦截?U束q例?属?可以直接得?国际化的消息 可以把该消息昄C个弹出对话框?提示更正 !
Validator的用处不只这一U?,你可以想到如何用?! Ƣ迎发表你的高见!!
OK 到此 我们?Hibernate Validator 之旅p先告一D落?. 希望q是令你心旷怡的一ơ寒冬之?
把你学到的应用到你的目中吧,一定会提高你的生率的. 怿?,没错的?^_^ !
M获得Matrix授权的网站,转蝲请保留以下作者信息和链接Q?/span>
作者:icess(作者的blog:http://blog.matrix.org.cn/page/icess)
关键字:Hibernate Validator
我在前面一文?lt;Hibernate Annotations 实战-- ?hbm.xml ?Annotations>:
?有很多开发者在谈论中提?有没有必要从 hbm.xml 往 Annotations 上{U? 那么在这文章中我们来讨论一?hbm.xml ?Annotations的优~点,看看那种情况最适合?
首先,讨论一?xml 配置文g的优? 个h认ؓ主要优点是当你改变底层配置?不需要改变和重新~译代码,只需要在xml 中更改就可以?例如 Hibernate.cfg.xml 当你要更改底层数据库? 只要更改配置文g可以了.Hibernate会ؓ你做好别的事?
那么xml的缺点呢,个h认ؓ有以下几?
描述W多Q不Ҏ记忆,掌握 要深入了解还有看DTD文g
无法做自动校验,需要h工查?
d和解析xml配置要消耗一定时_D应用启动慢,不便于测试和l护
当系l很大时Q大量的xml文g难以理
q行中保存xml配置需要消耗额外的内存
在O/R Mapping的时候需要在java文g和xml配置文g之间交替Q增大了工作?
其中W一 二点 借助于先q的IDE 可能不是什么问? 但是对初学者还是个问题 ^_^.
下面我们看看 Annotations?Ҏ吧! 可以解决xml遇到的问?有以下优?/p>
描述W减。以前在xml配置中往往需要描qjava属性的cdQ关pȝ{。而元数据本n是java语言Q从而省略了大量的描q符
~译期校验。错误的Ҏ在编译期间就会报错?
元数据批注在java代码中,避免了额外的文gl护工作
元数据被~译成java bytecodeQ消耗的内存,d也很快,利于试和维?
关于 映射文g是?hbm.xml 文gq是使用 Annotations 我们来看?者的性能? 先声明一?个h认ؓ映射文g一旦配|好׃会在很大E度上改变了.所以用xml文gq不会带来很大的好处.如果你认?映射文g在你的项目中也经常变?比如一列String数据 ,今天你?length="16" 明天你认?该数据的长度应该更长才能满业务需?于是改ؓlength="128" {等cM的问?. 如果你经常有q方面的变动的话,下面的比较你可以不用看了 , 你应该?xml文g 因ؓAnnotations 无法很好的满你的要?
现在让我们就来看?者的性能比较?
(说明: q里只是比较查找 插入 的时间快?没有比较除运行时间以外的其他性能,?内存占用?{等)
先来看看试E序和配|?
首先?Hibernate.cfg.xml 文g中去掉了
<property name="hibernate.hbm2ddl.auto">update</property>
q一? 因ؓ在前面的实验中以及徏立了数据库表?不再需要更C.如果你是W一ơ运行该例子 q是要该行的.
Test.java 如下:
/*
* Created on 2005
* @author
*/
package test.hibernate.annotation;
import org.hibernate.Session;
import org.hibernate.Transaction;
public class Test {
public static void main(String [] args) {
long start = 0;
long end = 0;
start = System.currentTimeMillis(); //E序开始时?/font>
Session s = HibernateUtil.currentSession();
long mid = System.currentTimeMillis(); //初始化完毕的旉 (可能此时q没有初始化完毕^_^)
Transaction tx = s.beginTransaction();
/********************试d的代?***********************/
Person p = null;
for(int i = 1; i <= 100; i ++) {
p = (Person) s.get(Person.class, i);
System.out.println(p.getName());
}
System.out.println(p.getName());
/********************试d1ơ的代码************************/
Person p = null;
p = (Person) s.get(Person.class, 1);
System.out.println(p.getName());
/*********************试插入的代?************************************/
/*
for (int i = 0; i < 100; i ++) {
Person p = new Person();
p.setAge(i+1);
p.setName("icerain"+i);
p.setSex("male"+i);
s.save(p);
s.flush();
}
*/
tx.commit();
HibernateUtil.closeSession();
end = System.currentTimeMillis(); //试l束旉
System.out.println("String[] - start time: " + start);
System.out.println("String[] - end time: " + end);
System.out.println("Init time : " + (mid-start)); // 打印初始化用的时?/font>
System.out.println("Last time is :" +(end - mid) ); //打印 数据操作的时?/font>
System.out.println("Total time : " +(end - start)); //打印L?br /> }
}
Annotations 包中的Person.java 如下
package test.hibernate.annotation;
import java.util.LinkedList;
import java.util.List;
import javax.persistence.AccessType;
import javax.persistence.Basic;
import javax.persistence.Entity;
import javax.persistence.GeneratorType;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Transient;
/**
* Person generated by hbm2java
*/
@SuppressWarnings("serial")
@Entity(access = AccessType.PROPERTY)
@Table
public class Person implements java.io.Serializable {
private Integer id;
private String name;
private String sex;
private Integer age;
private List list = new LinkedList();
// Constructors
/** default constructor */
public Person() {
}
/** constructor with id */
public Person(Integer id) {
this.id = id;
}
// Property accessors
@Id(generate=GeneratorType.AUTO)
public Integer getId() {
return this.id;
}
public void setId(Integer id) {
this.id = id;
}
@Basic
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
@Basic
public String getSex() {
return this.sex;
}
public void setSex(String sex) {
this.sex = sex;
}
@Basic
public Integer getAge() {
return this.age;
}
public void setAge(Integer age) {
this.age = age;
}
@Transient
public List getList() {
return list;
}
public void setList(List list) {
this.list = list;
}
}
其他的代码几乎没有改?
下面的每U类型的试都测试了3ơ以? 取中间的试旉.
试机器配置:
CPU: AMD Athlon (xp) 2000+
内存: 784880KB
盘: 三星 SP0812N
d一ơ 的比较:(单位: 毫秒)
使用Annotations 的测试数?/td> | 使用Xml文g的测试数?/td> | 要说?/td> | ||
Init time : | 2444 | Init time : | 2431 | 试前我认ؓ该项l果xml应该比较?要读取映文件啊,实际情况不是q样,不知道ؓ什? |
Last time is : | 62 | Last time is : | 85 | 相差比较大不知道Z? |
Total time : | 2506 | Total time : | 2516 | xml文gM上慢了一?/td> |
d100ơ的比较:
使用Annotations 的测试数?/td> | 使用Xml文g的测试数?/td> | 要说?/td> | ||
Init time : | 2437 | Init time : | 2422 | 和前面初始化差不?/td> |
Last time is : | 438 | Last time is : | 484 | 有时间差 |
Total time : | 2875 | Total time : | 2906 | 也是xml文gM上慢了一?/td> |
插入100ơ的比较:
使用Annotations 的测试数?/td> | 使用Xml文g的测试数?/td> | 要说?/td> | ||
Init time : | 2453 | Init time : | 2469 | 和前面初始化差不?/td> |
Last time is : | 469 | Last time is : | 656 | 有时间差 |
Total time : | 2922 | Total time : | 3125 | 也是xml文gM上慢了一?/td> |
从上面的三次Ҏ中大家可以看?初始化的部分几乎两者是一L, 在数据操作上?使用xml文g L比用Annotations 慢一?在我们只操纵一个只有几个属性的持久化cȝ操作中就?几十毫秒的差? 几十毫秒在计机中算不算很大 大家应该都知?我就不在多说?
ȝ: l过 xml 文g 和Annotations 的优~点?性能上的Ҏ.现在使用那个作ؓ你持久化映射{略.我相信大安会正选择?
试后记: l过多次试 感觉有时候很不稳?,有的时候很E_不知道是试有问题还是别的问?大家可以自己试一? 有什么新的发?请大家讨?
CREATE TABLE user (对于q个表格Q您有一个Usercd与之对应Q表g的每一个字D将对应至User实例上的Field成员?br />
id INT(11) NOT NULL auto_increment PRIMARY KEY,
name VARCHAR(100) NOT NULL default'',
age INT
);
import java.io.Serializable;
import net.sf.hibernate.HibernateException;
import net.sf.hibernate.Session;
import net.sf.hibernate.SessionFactory;
import net.sf.hibernate.Transaction;
public class HibernateSessionUtil implements Serializable
{
publicstaticfinal ThreadLocal tLocalsess = new ThreadLocal();
publicstaticfinal ThreadLocal tLocaltx = new ThreadLocal();
/*
* getting the thread-safe session for using
*/
publicstatic Session currentSession(){
Session session = (Session) tLocalsess.get();
//open a new one, if none can be found.
try{
if (session == null){
session = openSession();
tLocalsess.set(session);
}
}catch (HibernateException e){
thrownew InfrastructureException(e);
}
return session;
}
/*
* closing the thread-safe session
*/
publicstatic void closeSession(){
Session session = (Session) tLocalsess.get();
tLocalsess.set(null);
try{
if (session != null && session.isOpen()){
session.close();
}
}catch (HibernateException e){
thrownew InfrastructureException(e);
}
}
/*
* begin the transaction
*/
publicstatic void beginTransaction(){
Transaction tx = (Transaction) tLocaltx.get();
try{
if (tx == null){
tx = currentSession().beginTransaction();
tLocaltx.set(tx);
}
}catch (HibernateException e){
thrownew InfrastructureException(e);
}
}
/*
* close the transaction
*/
publicstatic void commitTransaction(){
Transaction tx = (Transaction) tLocaltx.get();
try{
if (tx != null && !tx.wasCommitted() && !tx.wasRolledBack())
tx.commit();
tLocaltx.set(null);
}catch (HibernateException e){
thrownew InfrastructureException(e);
}
}
/*
* for rollbacking
*/
publicstatic void rollbackTransaction(){
Transaction tx = (Transaction) tLocaltx.get();
try{
tLocaltx.set(null);
if (tx != null && !tx.wasCommitted() && !tx.wasRolledBack()){
tx.rollback();
}
}catch (HibernateException e){
thrownew InfrastructureException(e);
}
}
privatestatic Session openSession() throws HibernateException{
return getSessionFactory().openSession();
}
privatestatic SessionFactory getSessionFactory() throws HibernateException{
return SingletonSessionFactory.getInstance();
}
}
filter中的E式如?/p>
public class HibernateSessionCloser implements Filter{
protected FilterConfig filterConfig = null;
public void init(FilterConfig filterConfig)throws ServletException{
this.filterConfig = filterConfig;
}
public void destroy(){
this.filterConfig = null;
}
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain)
throws IOException, ServletException {
try{
chain.doFilter(request, response);
}
finally{
try{
HibernateSessionUtil.commitTransaction();
}catch (InfrastructureException e){
HibernateSessionUtil.rollbackTransaction();
}finally{
HibernateSessionUtil.closeSession();
}
}
}
}
然後在操作資料n之前加上
HibernateSessionUtil.beginTransaction();
HibernateSessionUtil.currentSession();//取得Session
q个例子使用了HSQL做数据库Qspring的AOP作ؓ基础Q用Acegi做安全控制组件?br />联系人管理的web应用在启动时候,会做一pd初始化动作:
1. dweb.xml文gQ?/p>
2. q解析文仉的内宏V?br />a) context-param元素?br />i. contextConfigLocation属性。这个属性定义了spring所需要的3个属性文件。它们分别是QapplicationContext -acegi-security.xml、applicationContext-common-business.xml?applicationContext-common-authorization.xml
ii. log4jConfigLocation属性。这个属性定义了log4j配置文g?/p>
b) filter元素?br />q里定义了acegi的一个过滤器。Acegi的大部分qo器都是这样配|的。用FilterToBeanProxylgQ给它传递一个targetClass属性。这个targetClass必须实现javax.servlet.Filter接口?br />q里配置的是FilterChainProxy。这个FilterChainProxy比较好用Q可以ؓ它定义一串filter属性。这些filter会按照定义的顺序被调用。例如,
<bean id="filterChainProxy" class="net.sf.acegisecurity.util.FilterChainProxy">
<property name="filterInvocationDefinitionSource">
<value>
CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
PATTERN_TYPE_APACHE_ANT
/**=httpSessionContextIntegrationFilter,authenticationProcessingFilter,basicProcessingFilter,rememberMeProcessingFilter,anonymousProcessingFilter,securityEnforcementFilter
</value>
</property>
</bean>
q个qo器的mapping是?*”?br />c) listener元素?br />i. ContextLoaderListener。这个是Spring使用来加载根applicationcontext。ƈ分别解析 applicationContext-acegi-security.xml、applicationContext-common- business.xml、applicationContext-common-authorization.xml{配|文Ӟ把相关的对象初始?br />iii. Log4jConfigListener。这个是spring用来初始化log4jlg的listener?br />iv. HttpSessionEventPublisher。这个组件将发布HttpSessionCreatedEvent和HttpSessionDestroyedEvent事glspring的applicationcontext?br />d) servlet元素?br />i. contacts。这里采用了spring的MVC框架Q?所以这个servlet是spring MVC的一个核心控制器Qorg.springframework.web.servlet.DispatcherServletQ。这个servlet 启动时候,会从contacts-servlet.xml里面d信息Qƈ做相关的初始化?br />v. remoting。也是spring MVC的一个核心控制器。与contacts不同Q这个servlet主要是提供web services服务。这个servlet启动时候, 会从remoting-servlet.xml里面d信息Qƈ做相关的初始化?br />e) taglib元素。这里定义了spring的标f) {ֺ?br />3. 解析applicationContext-acegi-security.xml?br />a) qo器链。定义了一个FilterChainProxyQb) q指c) 定了一pd的过滤器链。httpSessionContextIntegrationFilter, authenticationProcessingFilter,basicProcessingFilter,rememberMeProcessingFilter,anonymousProcessingFilter,securityEnforcementFilter
d) 认证理器。这个管理器由acegi提供。这个管理器需要一个providers参数。这个providers参数包含了提供系l认证的对象?br />i. daoAuthenticationProvider。一般用戯证?br />ii. anonymousAuthenticationProvider。匿名用戯证?br />iv. rememberMeAuthenticationProvider。记住我认证?/p>
e) 密码加密。这里定义了一个acegi的Md5法加密对象Md5PasswordEncoder?br />f) 定义了一个jdbcDao实现cR这个类由acegi提供的net.sf.acegisecurity.providers.dao.jdbc.JdbcDaoImpl。这个对象需要一个dataSource的参数?br />g) 定义daoAuthenticationProvider。这个对象由acegi提供。它?个属性:
authenticationDao。这里指向前面定义的jdbcDao?br />userCache。这里指向后面定义的user~存对象?br />passwordEncoder。这里指向前面定义的密码加密对象?br />h) 用户~存理?br />Z~存userQ这里用spring的ehcache来缓存user。缓存机Ӟ
i. 定义~存理器――CacheManager。这个对象是spring的EhCacheManagerFactoryBean对象
ii. 定义user~存实际执行对象――UserCacheBackend。这个对象是spring的EhCacheFactoryBean。它有两个属性:
1. cacheManager。这里指向前面定义的~存理器?br />2. cacheName?br />iii. 定义user~存――UserCache。它是acegi提供的EhCacheBasedUserCache对象。它有一个属性:
1. cache。这里指向的是前面定义的userCacheBackend?/p>
i) 定义接收来自DaoAuthenticationProvider的认证事件的listener――LoggerListener?br />j)
4. 解析applicationContext-common-business.xml?br />a) dataSource.
q里使用了spring的DriverManagerDataSource对象。这个对象是一个JDBC数据源的定义?br />b) TransactionManager。这里用spring的DataSourceTransactionManager对象?br />c) 事务拦截器。这里用spring的事务拦截器TransactionInterceptor。它?个属性:
transactionManager。这个属性指向前面定义的TransactionManager?br />transactionAttributeSource。这个属性里Q?指定了ContactManager的各个方法的事务斚w的要求?br />d) DataSourcePopulator?br />使用sample.contact.DataSourcePopulator对象Q往HSQL里创建相关的表结构和数据?br />实现原理QDataSourcePopulator 实现了接?InitializingBean。其中afterPropertiesSetҎ在spring初始化DataSourcePopulator后被调用?br />e) ContactDao。这里指向一个ContactDaoSpring对象。它l承spring?JdbcDaoSupportQg) q实现ContactDao接口。它是真正实现JDBC操作的对象?br />h) ContactManager。这里用的是spring的ProxyFactoryBean。它?个属性:
i. ProxyInterfaces。代理接口:sample.contact.ContactManager
ii. InterceptorNames。拦截器名称。可以有多个Qiv. q里包括QtransactionInterceptor、contactManagerSecurity、contactManagerTarget。其中,v. transactionInterceptor是前面定义的事务拦截器。ContactManagerSecurity则是?applicationContext-common-authorization.xml里定义的Ҏ调用授权?br />i) ContactManagerTarget。这里指向的是sample.contact.ContactManagerBackend对象?ContactManagerBackend实现了ContactManager接口和InitializingBean接口。它?个自定义属性: contactDao和basicAclExtendedDao。这里会调用ACL的APId些创建权限和删除权限的工作?/p>
联系人管理说明了下列中心?span lang="EN-US">Acegi安全控制能力:
ContactManager
服务层对?/span>
包含一些受保护的和公开的方法?/span>
/secure
?/span>
URI
路径被?/span>
Acegi
安全保护Q得没?/span>
ROLE_USER
角色的用h法访问?/span>
.
联系人管理的业务功能描述Q?/span>
1.1. 每个用户d后,可以看到一个联pMh列表。例如,
id |
Name |
|
||
1 |
John Smith |
john@somewhere.com |
||
2 |
Michael Citizen |
michael@xyz.com |
|
|
3 |
Joe Bloggs |
joe@demo.com |
|
|
4 |
Karen Sutherland |
karen@sutherland.com |
说明Q用h有权限访问的联系Z息,不会显C?/span>
2.2. 用户可以增加新的联系Z息?/span>
3.3. 如果有删除权限,用户可以看到在联pMh后面有一个?/span> Del ”链接。用户可以点击这个链接来删除某个联系Z息?/span>
4.4. 如果有管理权限,用户可以看到在联pMh后面有一个?/span> Admin Permission ”链接。用户可以点击这个链接来理讉Kq个联系人的权限。例如,
sample.contact.Contact@26807f: Id: 1; Name: John Smith; Email: john@somewhere.com
|
|
|
|
|
说明Q每一行记录包含有 3 列?/span>
W一列表C权限,例如Q?/span>
-RW-D
”表C可诅R可写、可删除?/span>
W二列也表示权限Q但它是以类?/span> unix 权限的数字表达。例如,?/span> [22] ?/span> , 表示可读、可写、可删除?/span>
W三列是用户名称?/span>
每一行记录后面都有一个?/span> Del ”链接。点击这个链接,可以删除掉指定用户对q个联系Z息的权限?/span>
5.5. 用户可以为某个联pMh信息d权限。例如,