?當(dāng)前位置: 首頁(yè) >> 數(shù)據(jù)庫(kù) >> Oracle >> 我的權(quán)限控制(JBX + struts + hibernate + ORACLE)
?
我的權(quán)限控制(JBX + struts + hibernate + ORACLE)?

--------------------------------------------------------------------------------
?
作者::???? 來(lái)源:???? 發(fā)表時(shí)間:2006-06-08???? 瀏覽次數(shù):18??? 字號(hào):大? 中? 小
  
通過(guò)過(guò)濾器判斷用戶(hù)權(quán)限.
第一步:建立UserPermissionFilter類(lèi).


import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
import java.util.*;

import test.system.SysUserApi;
import test.vo.SysUserVO;
import test.system.dao.SysUserDao;
import test.Const;

public class UserPermissionFilter extends HttpServlet implements Filter {

? protected FilterConfig filterConfig = null;

? public void destroy() {
??? this.filterConfig = null;
? }


? public void doFilter(
????? ServletRequest request,
????? ServletResponse response,
????? FilterChain filterChain) throws IOException, ServletException {
??? try {
????? HttpServletRequest req = (HttpServletRequest) request;
????? SysUserVO userSession = new SysUserVO();
????? userSession = (SysUserVO)req.getSession().getAttribute(Const.SESSION_USER);
????? if (userSession == null) {
??????? HttpServletResponse rep = (HttpServletResponse) response;

??????? rep.sendRedirect("/admin/login.jsp");
???????????? }else{
??????? filterChain.doFilter(request, response);
????? }
??? }
??? catch (Exception e) {}
? }
? public void init(FilterConfig filterConfig) throws ServletException {
??? this.filterConfig = filterConfig;
? }
? public FilterConfig getFilterConfig() {
??? return filterConfig;
? }

? public void setFilterConfig(FilterConfig filterConfig) {
??? this.filterConfig = filterConfig;
? }

}


第二步:配置WEB.xml文件
設(shè)置過(guò)濾器:
? <filter>
??? <filter-name>userpermission</filter-name>
??? <filter-class>sports.tools.UserPermissionFilter</filter-class>
? </filter>
設(shè)置過(guò)濾器映射,因?yàn)檫^(guò)濾器不能過(guò)濾全部的程序,所以可以用列表的形式來(lái)增加需要過(guò)濾的文件.如下.一個(gè)過(guò)濾器可以過(guò)濾多個(gè)映射文件.
? <filter-mapping>
??? <filter-name>userpermission</filter-name>
??? <url-pattern>/admin/index.jsp</url-pattern>
? </filter-mapping>

? <filter-mapping>
??? <filter-name>userpermission</filter-name>
??? <url-pattern>/admin/edit/*</url-pattern>
? </filter-mapping>
?
?
?
======================================
http://www.itwenzhai.com/data/2006/0608/article_22958.htm
=========================================
http://www.itwenzhai.com/data/2006/0626/article_25178.htm
=========================================


? 不重復(fù)DAO
===============

?

由于 Java? 5 泛型的采用,有關(guān)泛型類(lèi)型安全 Data Access Object (DAO) 實(shí)現(xiàn)的想法變得切實(shí)可行。在本文中,系統(tǒng)架構(gòu)師 Per Mellqvist 展示了基于 Hibernate 的泛型 DAO 實(shí)現(xiàn)類(lèi)。然后展示如何使用 Spring AOP introductions 將類(lèi)型安全接口添加到類(lèi)中以便于查詢(xún)執(zhí)行。
對(duì)于大多數(shù)開(kāi)發(fā)人員,為系統(tǒng)中的每個(gè) DAO 編寫(xiě)幾乎相同的代碼到目前為止已經(jīng)成為一種習(xí)慣。雖然所有人都將這種重復(fù)標(biāo)識(shí)為 “代碼味道”,但我們大多數(shù)都已經(jīng)學(xué)會(huì)忍受它。其實(shí)有解決方案??梢允褂迷S多 ORM 工具來(lái)避免代碼重復(fù)。例如,使用 Hibernate,您可以簡(jiǎn)單地為所有的持久域?qū)ο笾苯邮褂脮?huì)話操作。這種方法的缺點(diǎn)是損失了類(lèi)型安全。

為什么您要為數(shù)據(jù)訪問(wèn)代碼提供類(lèi)型安全接口?我會(huì)爭(zhēng)辯說(shuō),當(dāng)它與現(xiàn)代 IDE 工具一起使用時(shí),會(huì)減少編程錯(cuò)誤并提高生產(chǎn)率。首先,類(lèi)型安全接口清楚地指明哪些域?qū)ο缶哂锌捎玫某志么鎯?chǔ)。其次,它消除了易出錯(cuò)的類(lèi)型強(qiáng)制轉(zhuǎn)換的需要(這是一個(gè)在查詢(xún)操作中比在 CRUD 中更常見(jiàn)的問(wèn)題)。最后,它有效利用了今天大多數(shù) IDE 具備的自動(dòng)完成特性。使用自動(dòng)完成是記住什么查詢(xún)可用于特定域類(lèi)的快捷方法。

在本文中,我將為您展示如何避免再三地重復(fù) DAO 代碼,而仍保留類(lèi)型安全接口的優(yōu)點(diǎn)。事實(shí)上,您需要為每個(gè)新 DAO 編寫(xiě)的只是 Hibernate 映射文件、無(wú)格式舊 Java 接口以及 Spring 配置文件中的 10 行。

DAO 實(shí)現(xiàn)

DAO 模式對(duì)任何企業(yè) Java 開(kāi)發(fā)人員來(lái)說(shuō)都應(yīng)該很熟悉。但是模式的實(shí)現(xiàn)各不相同,所以我們來(lái)澄清一下本文提供的 DAO 實(shí)現(xiàn)背后的假設(shè):

系統(tǒng)中的所有數(shù)據(jù)庫(kù)訪問(wèn)都通過(guò) DAO 進(jìn)行以實(shí)現(xiàn)封裝。
每個(gè) DAO 實(shí)例負(fù)責(zé)一個(gè)主要域?qū)ο蠡驅(qū)嶓w。如果域?qū)ο缶哂歇?dú)立生命周期,它應(yīng)具有自己的 DAO。
DAO 負(fù)責(zé)域?qū)ο蟮膭?chuàng)建、讀?。ò粗麈I)、更新和刪除(creations, reads, updates, and deletions,CRUD)。
DAO 可允許基于除主鍵之外的標(biāo)準(zhǔn)進(jìn)行查詢(xún)。我將之稱(chēng)為查找器方法 或查找器。查找器的返回值通常是 DAO 負(fù)責(zé)的域?qū)ο蠹稀?
DAO 不負(fù)責(zé)處理事務(wù)、會(huì)話或連接。這些不由 DAO 處理是為了實(shí)現(xiàn)靈活性。
泛型 DAO 接口

泛型 DAO 的基礎(chǔ)是其 CRUD 操作。下面的接口定義泛型 DAO 的方法:


清單 1. 泛型 DAO 接口
public interface GenericDao <T, PK extends Serializable> {

??? /** Persist the newInstance object into database */
??? PK create(T newInstance);

??? /** Retrieve an object that was previously persisted to the database using
???? *?? the indicated id as primary key
???? */
??? T read(PK id);

??? /** Save changes made to a persistent object.? */
??? void update(T transientObject);

??? /** Remove an object from persistent storage in the database */
??? void delete(T persistentObject);
}

?


實(shí)現(xiàn)接口

用 Hibernate 實(shí)現(xiàn)清單 1 中的接口十分簡(jiǎn)單,如清單 2 所示。它只需調(diào)用底層 Hibernate 方法和添加強(qiáng)制類(lèi)型轉(zhuǎn)換。Spring 負(fù)責(zé)會(huì)話和事務(wù)管理。(當(dāng)然,我假設(shè)這些函數(shù)已做了適當(dāng)?shù)脑O(shè)置,但該主題在 Hibernate 和 Springt 手冊(cè)中有詳細(xì)介紹。)


清單 2. 第一個(gè)泛型 DAO 實(shí)現(xiàn)
public class GenericDaoHibernateImpl <T, PK extends Serializable>
??? implements GenericDao<T, PK>, FinderExecutor {
??? private Class<T> type;

??? public GenericDaoHibernateImpl(Class<T> type) {
??????? this.type = type;
??? }

??? public PK create(T o) {
??????? return (PK) getSession().save(o);
??? }

??? public T read(PK id) {
??????? return (T) getSession().get(type, id);
??? }

??? public void update(T o) {
??????? getSession().update(o);
??? }

??? public void delete(T o) {
??????? getSession().delete(o);
??? }

??? // Not showing implementations of getSession() and setSessionFactory()
??????????? }
?


Spring 配置

最后,在 Spring 配置中,我創(chuàng)建了 GenericDaoHibernateImpl 的一個(gè)實(shí)例。必須告訴 GenericDaoHibernateImpl 的構(gòu)造函數(shù) DAO 實(shí)例將負(fù)責(zé)哪個(gè)域類(lèi)。只有這樣,Hibernate 才能在運(yùn)行時(shí)知道由 DAO 管理的對(duì)象類(lèi)型。在清單 3 中,我將域類(lèi) Person 從示例應(yīng)用程序傳遞給構(gòu)造函數(shù),并將先前配置的 Hibernate 會(huì)話工廠設(shè)置為已實(shí)例化的 DAO 的參數(shù):


清單 3. 配置 DAO
<bean id="personDao" class="genericdao.impl.GenericDaoHibernateImpl">
??????? <constructor-arg>
??????????? <value>genericdaotest.domain.Person</value>
??????? </constructor-arg>
??????? <property name="sessionFactory">
??????????? <ref bean="sessionFactory"/>
??????? </property>
</bean>
????????
2。
我還沒(méi)有完成,但我所完成的確實(shí)已經(jīng)可以使用了。在清單 4 中,可以看到原封不動(dòng)使用該泛型 DAO 的示例:


清單 4. 使用 DAO
public void someMethodCreatingAPerson() {
??? ...
??? GenericDao dao = (GenericDao)
???? beanFactory.getBean("personDao"); // This should normally be injected

??? Person p = new Person("Per", 90);
??? dao.create(p);
}
????????

?

現(xiàn)在,我有一個(gè)能夠進(jìn)行類(lèi)型安全 CRUD 操作的泛型 DAO。讓子類(lèi) GenericDaoHibernateImpl 為每個(gè)域?qū)ο筇砑硬樵?xún)能力將非常合理。因?yàn)楸疚牡哪康脑谟谡故救绾尾粸槊總€(gè)查詢(xún)編寫(xiě)顯式的 Java 代碼來(lái)實(shí)現(xiàn)查詢(xún),但是,我將使用其他兩個(gè)工具將查詢(xún)引入 DAO,也就是 Spring AOP 和 Hibernate 命名的查詢(xún)。

Spring AOP introductions

可以使用 Spring AOP 中的 introductions 將功能添加到現(xiàn)有對(duì)象,方法是將功能包裝在代理中,定義應(yīng)實(shí)現(xiàn)的接口,并將所有先前未支持的方法指派到單個(gè)處理程序。在我的 DAO 實(shí)現(xiàn)中,我使用 introductions 將許多查找器方法添加到現(xiàn)有泛型 DAO 類(lèi)中。因?yàn)椴檎移鞣椒ㄊ翘囟ㄓ诿總€(gè)域?qū)ο蟮模虼藢⑵鋺?yīng)用于泛型 DAO 的類(lèi)型化接口。

Spring 配置如清單 5 所示:


清單 5. FinderIntroductionAdvisor 的 Spring 配置
<bean id="finderIntroductionAdvisor" class="genericdao.impl.FinderIntroductionAdvisor"/>

<bean id="abstractDaoTarget"
??????? class="genericdao.impl.GenericDaoHibernateImpl" abstract="true">
??????? <property name="sessionFactory">
??????????? <ref bean="sessionFactory"/>
??????? </property>
</bean>

<bean id="abstractDao"
??????? class="org.springframework.aop.framework.ProxyFactoryBean" abstract="true">
??????? <property name="interceptorNames">
??????????? <list>
??????????????? <value>finderIntroductionAdvisor</value>
??????????? </list>
??????? </property>
</bean>
????????

?

在清單 5 的配置文件中,我定義了三個(gè) Spring bean。第一個(gè) bean 是 FinderIntroductionAdvisor,它處理引入到 DAO 的所有方法,這些方法在 GenericDaoHibernateImpl 類(lèi)中不可用。我稍后將詳細(xì)介紹 Advisor bean。

第二個(gè) bean 是 “抽象的”。在 Spring 中,這意味著該 bean 可在其他 bean 定義中被重用,但不被實(shí)例化。除了抽象特性之外,該 bean 定義只指出我想要 GenericDaoHibernateImpl 的實(shí)例以及該實(shí)例需要對(duì) SessionFactory 的引用。注意,GenericDaoHibernateImpl 類(lèi)僅定義一個(gè)構(gòu)造函數(shù),該構(gòu)造函數(shù)接受域類(lèi)作為其參數(shù)。因?yàn)樵?bean 定義是抽象的,所以我將來(lái)可以無(wú)數(shù)次地重用該定義,并將構(gòu)造函數(shù)參數(shù)設(shè)置為合適的域類(lèi)。

最后,第三個(gè)也是最有趣的 bean 將 GenericDaoHibernateImpl 的 vanilla 實(shí)例包裝在代理中,賦予其執(zhí)行查找器方法的能力。該 bean 定義也是抽象的,不指定希望引入到 vanilla DAO 的接口。該接口對(duì)于每個(gè)具體的實(shí)例是不同的。注意,清單 5 顯示的整個(gè)配置僅定義一次。

3。

擴(kuò)展 GenericDAO

當(dāng)然,每個(gè) DAO 的接口都基于 GenericDao 接口。我只需使該接口適應(yīng)特定的域類(lèi)并擴(kuò)展該接口以包括查找器方法。在清單 6 中,可以看到為特定目的擴(kuò)展的 GenericDao 接口示例:


清單 6. PersonDao 接口
public interface PersonDao extends GenericDao<Person, Long> {
??? List<Person> findByName(String name);
}

?

?

很明顯,清單 6 中定義的方法旨在按名稱(chēng)查找 Person。必需的 Java 實(shí)現(xiàn)代碼全部是泛型代碼,在添加更多 DAO 時(shí)不需要任何更新。

配置 PersonDao

因?yàn)?Spring 配置依賴(lài)于先前定義的 “抽象” bean,因此它變得相當(dāng)簡(jiǎn)潔。我需要指出 DAO 負(fù)責(zé)哪個(gè)域類(lèi),并且需要告訴 Springs 該 DAO 應(yīng)實(shí)現(xiàn)哪個(gè)接口(一些方法是直接使用,一些方法則是通過(guò)使用 introductions 來(lái)使用)。清單 7 展示了 PersonDAO 的 Spring 配置文件:


清單 7. PersonDao 的 Spring 配置
<bean id="personDao" parent="abstractDao">
??? <property name="proxyInterfaces">
??????? <value>genericdaotest.dao.PersonDao</value>
??? </property>
??? <property name="target">
??????? <bean parent="abstractDaoTarget">
??????????? <constructor-arg>
??????????????? <value>genericdaotest.domain.Person</value>
??????????? </constructor-arg>
??????? </bean>
??? </property>
</bean>
????????

?

在清單 8 中,可以看到使用了這個(gè)更新后的 DAO 版本:


清單 8. 使用類(lèi)型安全接口
public void someMethodCreatingAPerson() {
??? ...
??? PersonDao dao = (PersonDao)
???? beanFactory.getBean("personDao"); // This should normally be injected

??? Person p = new Person("Per", 90);
??? dao.create(p);

??? List<Person> result = dao.findByName("Per"); // Runtime exception
}
????????

?

雖然清單 8 中的代碼是使用類(lèi)型安全 PersonDao 接口的正確方法,但 DAO 的實(shí)現(xiàn)并不完整。調(diào)用 findByName() 會(huì)導(dǎo)致運(yùn)行時(shí)異常。問(wèn)題在于我還沒(méi)有實(shí)現(xiàn)調(diào)用 findByName() 所必需的查詢(xún)。剩下要做的就是指定查詢(xún)。為更正該問(wèn)題,我使用了 Hibernate 命名查詢(xún)。


?

Hibernate 命名查詢(xún)

使用 Hibernate,可以在 Hibernate 映射文件 (hbm.xml) 中定義 HQL 查詢(xún)并為其命名。稍后可以通過(guò)簡(jiǎn)單地引用給定名稱(chēng)來(lái)在 Java 代碼中使用該查詢(xún)。該方法的優(yōu)點(diǎn)之一是能夠在部署時(shí)優(yōu)化查詢(xún),而無(wú)需更改代碼。您一會(huì)將會(huì)看到,另一個(gè)優(yōu)點(diǎn)是無(wú)需編寫(xiě)任何新 Java 實(shí)現(xiàn)代碼,就可以實(shí)現(xiàn) “完整的” DAO。清單 9 是帶有命名查詢(xún)的映射文件的示例:


清單 9. 帶有命名查詢(xún)的映射文件
?<hibernate-mapping package="genericdaotest.domain">
???? <class name="Person">
???????? <id name="id">
???????????? <generator class="native"/>
???????? </id>
???????? <property name="name" />
???????? <property name="weight" />
???? </class>

???? <query name="Person.findByName">
???????? <![CDATA[select p from Person p where p.name = ? ]]>
???? </query>
?</hibernate-mapping>
????????

?

清單 9 定義了域類(lèi) Person 的 Hibernate 映射,該域類(lèi)具有兩個(gè)屬性:name 和 weight。Person 是具有上述屬性的簡(jiǎn)單 POJO。該文件還包含一個(gè)在數(shù)據(jù)庫(kù)中查找 Person 所有實(shí)例的查詢(xún),其中 “name” 等于提供的參數(shù)。Hibernate 不為命名查詢(xún)提供任何真正的名稱(chēng)空間功能。出于討論目的,我為所有查詢(xún)名稱(chēng)都加了域類(lèi)的短(非限定)名稱(chēng)作為前綴。在現(xiàn)實(shí)世界中,使用包括包名稱(chēng)的完全類(lèi)名可能是更好的主意。


?

逐步概述

您已經(jīng)看到了為任何域?qū)ο髣?chuàng)建和配置新 DAO 所必需的全部步驟。三個(gè)簡(jiǎn)單的步驟是:

定義一個(gè)接口,它擴(kuò)展 GenericDao 并包含所需的任何查找器方法。
將每個(gè)查找器的命名查詢(xún)添加到域?qū)ο蟮?hbm.xml 映射文件。
為 DAO 添加 10 行 Spring 配置文件。
查看執(zhí)行查找器方法的代碼(只編寫(xiě)了一次?。﹣?lái)結(jié)束我的討論。

4。

可重用的 DAO 類(lèi)

使用的 Spring advisor 和 interceptor 很簡(jiǎn)單,事實(shí)上它們的工作是向后引用 GenericDaoHibernateImplClass。方法名以 “find” 打頭的所有調(diào)用都傳遞給 DAO 和單個(gè)方法 executeFinder()。


清單 10. FinderIntroductionAdvisor 的實(shí)現(xiàn)
public class FinderIntroductionAdvisor extends DefaultIntroductionAdvisor {
??? public FinderIntroductionAdvisor() {
??????? super(new FinderIntroductionInterceptor());
??? }
}

public class FinderIntroductionInterceptor implements IntroductionInterceptor {

??? public Object invoke(MethodInvocation methodInvocation) throws Throwable {

??????? FinderExecutor genericDao = (FinderExecutor) methodInvocation.getThis();

??????? String methodName = methodInvocation.getMethod().getName();
??????? if (methodName.startsWith("find")) {
??????????? Object[] arguments = methodInvocation.getArguments();
??????????? return genericDao.executeFinder(methodInvocation.getMethod(), arguments);
??????? } else {
??????????? return methodInvocation.proceed();
??????? }
??? }

??? public boolean implementsInterface(Class intf) {
??????? return intf.isInterface() && FinderExecutor.class.isAssignableFrom(intf);
??? }
}
?

?

executeFinder() 方法

清單 10 的實(shí)現(xiàn)中惟一缺少的是 executeFinder() 實(shí)現(xiàn)。該代碼查看調(diào)用的類(lèi)和方法的名稱(chēng),并使用配置上的約定將其與 Hibernate 查詢(xún)的名稱(chēng)相匹配。還可以使用 FinderNamingStrategy 來(lái)支持其他命名查詢(xún)的方法。默認(rèn)實(shí)現(xiàn)查找叫做 “ClassName.methodName” 的查詢(xún),其中 ClassName 是不帶包的短名稱(chēng)。清單 11 完成了泛型類(lèi)型安全 DAO 實(shí)現(xiàn):


清單 11. executeFinder() 的實(shí)現(xiàn)
public List<T> executeFinder(Method method, final Object[] queryArgs) {
???? final String queryName = queryNameFromMethod(method);
???? final Query namedQuery = getSession().getNamedQuery(queryName);
???? String[] namedParameters = namedQuery.getNamedParameters();
???? for(int i = 0; i < queryArgs.length; i++) {
???????????? Object arg = queryArgs[i];
???????????? Type argType =? namedQuery.setParameter(i, arg);
????? }
????? return (List<T>) namedQuery.list();
?}

?public String queryNameFromMethod(Method finderMethod) {
???? return type.getSimpleName() + "." + finderMethod.getName();
?}
?

?

結(jié)束語(yǔ)

在 Java 5 之前,該語(yǔ)言不支持編寫(xiě)既類(lèi)型安全又 泛型的代碼,您必須只能選擇其中之一。在本文中,您已經(jīng)看到一個(gè)結(jié)合使用 Java 5 泛型與 Spring 和 Hibernate(以及 AOP)等工具來(lái)提高生產(chǎn)率的示例。泛型類(lèi)型安全 DAO 類(lèi)相當(dāng)容易編寫(xiě) —— 您只需要單個(gè)接口、一些命名查詢(xún)和為 Spring 配置添加的 10 行代碼 —— 而且可以極大地減少錯(cuò)誤并節(jié)省時(shí)間。

幾乎本文的所有代碼都是可重用的。盡管您的 DAO 類(lèi)可能包含此處沒(méi)有實(shí)現(xiàn)的查詢(xún)和操作類(lèi)型(比如,批操作),但使用我所展示的技術(shù),您至少應(yīng)該能夠?qū)崿F(xiàn)其中的一部分。參閱 參考資料 了解其他泛型類(lèi)型安全 DAO 類(lèi)實(shí)現(xiàn)。

致謝

自 Java 語(yǔ)言中出現(xiàn)泛型以來(lái),單個(gè)泛型類(lèi)型安全 DAO 的概念已經(jīng)成為主題。我曾在 JavaOne 2004 中與 Don Smith 簡(jiǎn)要討論了泛型 DAO 的靈活性。本文使用的 DAO 實(shí)現(xiàn)類(lèi)旨在作為示例實(shí)現(xiàn),實(shí)際上還存在其他實(shí)現(xiàn)。例如,Christian Bauer 已經(jīng)發(fā)布了帶有 CRUD 操作和標(biāo)準(zhǔn)搜索的實(shí)現(xiàn),Eric Burke 也在該領(lǐng)域做出了工作。我確信將會(huì)有更多的實(shí)現(xiàn)出現(xiàn)。我要額外感謝 Christian,他目睹了我編寫(xiě)泛型類(lèi)型安全 DAO 的第一次嘗試并提出改進(jìn)建議。最后,我要感謝 Ramnivas Laddad 的無(wú)價(jià)幫助,他審閱了本文。

?