?當前位置: 首頁 >> 數據庫 >> Oracle >> 我的權限控制(JBX + struts + hibernate + ORACLE)
?
我的權限控制(JBX + struts + hibernate + ORACLE)?

--------------------------------------------------------------------------------
?
作者::???? 來源:???? 發表時間:2006-06-08???? 瀏覽次數:18??? 字號:大? 中? 小
  
通過過濾器判斷用戶權限.
第一步:建立UserPermissionFilter類.


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文件
設置過濾器:
? <filter>
??? <filter-name>userpermission</filter-name>
??? <filter-class>sports.tools.UserPermissionFilter</filter-class>
? </filter>
設置過濾器映射,因為過濾器不能過濾全部的程序,所以可以用列表的形式來增加需要過濾的文件.如下.一個過濾器可以過濾多個映射文件.
? <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
=========================================


? 不重復DAO
===============

?

由于 Java? 5 泛型的采用,有關泛型類型安全 Data Access Object (DAO) 實現的想法變得切實可行。在本文中,系統架構師 Per Mellqvist 展示了基于 Hibernate 的泛型 DAO 實現類。然后展示如何使用 Spring AOP introductions 將類型安全接口添加到類中以便于查詢執行。
對于大多數開發人員,為系統中的每個 DAO 編寫幾乎相同的代碼到目前為止已經成為一種習慣。雖然所有人都將這種重復標識為 “代碼味道”,但我們大多數都已經學會忍受它。其實有解決方案。可以使用許多 ORM 工具來避免代碼重復。例如,使用 Hibernate,您可以簡單地為所有的持久域對象直接使用會話操作。這種方法的缺點是損失了類型安全。

為什么您要為數據訪問代碼提供類型安全接口?我會爭辯說,當它與現代 IDE 工具一起使用時,會減少編程錯誤并提高生產率。首先,類型安全接口清楚地指明哪些域對象具有可用的持久存儲。其次,它消除了易出錯的類型強制轉換的需要(這是一個在查詢操作中比在 CRUD 中更常見的問題)。最后,它有效利用了今天大多數 IDE 具備的自動完成特性。使用自動完成是記住什么查詢可用于特定域類的快捷方法。

在本文中,我將為您展示如何避免再三地重復 DAO 代碼,而仍保留類型安全接口的優點。事實上,您需要為每個新 DAO 編寫的只是 Hibernate 映射文件、無格式舊 Java 接口以及 Spring 配置文件中的 10 行。

DAO 實現

DAO 模式對任何企業 Java 開發人員來說都應該很熟悉。但是模式的實現各不相同,所以我們來澄清一下本文提供的 DAO 實現背后的假設:

系統中的所有數據庫訪問都通過 DAO 進行以實現封裝。
每個 DAO 實例負責一個主要域對象或實體。如果域對象具有獨立生命周期,它應具有自己的 DAO。
DAO 負責域對象的創建、讀取(按主鍵)、更新和刪除(creations, reads, updates, and deletions,CRUD)。
DAO 可允許基于除主鍵之外的標準進行查詢。我將之稱為查找器方法 或查找器。查找器的返回值通常是 DAO 負責的域對象集合。
DAO 不負責處理事務、會話或連接。這些不由 DAO 處理是為了實現靈活性。
泛型 DAO 接口

泛型 DAO 的基礎是其 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);
}

?


實現接口

用 Hibernate 實現清單 1 中的接口十分簡單,如清單 2 所示。它只需調用底層 Hibernate 方法和添加強制類型轉換。Spring 負責會話和事務管理。(當然,我假設這些函數已做了適當的設置,但該主題在 Hibernate 和 Springt 手冊中有詳細介紹。)


清單 2. 第一個泛型 DAO 實現
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 配置中,我創建了 GenericDaoHibernateImpl 的一個實例。必須告訴 GenericDaoHibernateImpl 的構造函數 DAO 實例將負責哪個域類。只有這樣,Hibernate 才能在運行時知道由 DAO 管理的對象類型。在清單 3 中,我將域類 Person 從示例應用程序傳遞給構造函數,并將先前配置的 Hibernate 會話工廠設置為已實例化的 DAO 的參數:


清單 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。
我還沒有完成,但我所完成的確實已經可以使用了。在清單 4 中,可以看到原封不動使用該泛型 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);
}
????????

?

現在,我有一個能夠進行類型安全 CRUD 操作的泛型 DAO。讓子類 GenericDaoHibernateImpl 為每個域對象添加查詢能力將非常合理。因為本文的目的在于展示如何不為每個查詢編寫顯式的 Java 代碼來實現查詢,但是,我將使用其他兩個工具將查詢引入 DAO,也就是 Spring AOP 和 Hibernate 命名的查詢。

Spring AOP introductions

可以使用 Spring AOP 中的 introductions 將功能添加到現有對象,方法是將功能包裝在代理中,定義應實現的接口,并將所有先前未支持的方法指派到單個處理程序。在我的 DAO 實現中,我使用 introductions 將許多查找器方法添加到現有泛型 DAO 類中。因為查找器方法是特定于每個域對象的,因此將其應用于泛型 DAO 的類型化接口。

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 的配置文件中,我定義了三個 Spring bean。第一個 bean 是 FinderIntroductionAdvisor,它處理引入到 DAO 的所有方法,這些方法在 GenericDaoHibernateImpl 類中不可用。我稍后將詳細介紹 Advisor bean。

第二個 bean 是 “抽象的”。在 Spring 中,這意味著該 bean 可在其他 bean 定義中被重用,但不被實例化。除了抽象特性之外,該 bean 定義只指出我想要 GenericDaoHibernateImpl 的實例以及該實例需要對 SessionFactory 的引用。注意,GenericDaoHibernateImpl 類僅定義一個構造函數,該構造函數接受域類作為其參數。因為該 bean 定義是抽象的,所以我將來可以無數次地重用該定義,并將構造函數參數設置為合適的域類。

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

3。

擴展 GenericDAO

當然,每個 DAO 的接口都基于 GenericDao 接口。我只需使該接口適應特定的域類并擴展該接口以包括查找器方法。在清單 6 中,可以看到為特定目的擴展的 GenericDao 接口示例:


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

?

?

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

配置 PersonDao

因為 Spring 配置依賴于先前定義的 “抽象” bean,因此它變得相當簡潔。我需要指出 DAO 負責哪個域類,并且需要告訴 Springs 該 DAO 應實現哪個接口(一些方法是直接使用,一些方法則是通過使用 introductions 來使用)。清單 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 中,可以看到使用了這個更新后的 DAO 版本:


清單 8. 使用類型安全接口
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 中的代碼是使用類型安全 PersonDao 接口的正確方法,但 DAO 的實現并不完整。調用 findByName() 會導致運行時異常。問題在于我還沒有實現調用 findByName() 所必需的查詢。剩下要做的就是指定查詢。為更正該問題,我使用了 Hibernate 命名查詢。


?

Hibernate 命名查詢

使用 Hibernate,可以在 Hibernate 映射文件 (hbm.xml) 中定義 HQL 查詢并為其命名。稍后可以通過簡單地引用給定名稱來在 Java 代碼中使用該查詢。該方法的優點之一是能夠在部署時優化查詢,而無需更改代碼。您一會將會看到,另一個優點是無需編寫任何新 Java 實現代碼,就可以實現 “完整的” DAO。清單 9 是帶有命名查詢的映射文件的示例:


清單 9. 帶有命名查詢的映射文件
?<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 定義了域類 Person 的 Hibernate 映射,該域類具有兩個屬性:name 和 weight。Person 是具有上述屬性的簡單 POJO。該文件還包含一個在數據庫中查找 Person 所有實例的查詢,其中 “name” 等于提供的參數。Hibernate 不為命名查詢提供任何真正的名稱空間功能。出于討論目的,我為所有查詢名稱都加了域類的短(非限定)名稱作為前綴。在現實世界中,使用包括包名稱的完全類名可能是更好的主意。


?

逐步概述

您已經看到了為任何域對象創建和配置新 DAO 所必需的全部步驟。三個簡單的步驟是:

定義一個接口,它擴展 GenericDao 并包含所需的任何查找器方法。
將每個查找器的命名查詢添加到域對象的 hbm.xml 映射文件。
為 DAO 添加 10 行 Spring 配置文件。
查看執行查找器方法的代碼(只編寫了一次!)來結束我的討論。

4。

可重用的 DAO 類

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


清單 10. FinderIntroductionAdvisor 的實現
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 的實現中惟一缺少的是 executeFinder() 實現。該代碼查看調用的類和方法的名稱,并使用配置上的約定將其與 Hibernate 查詢的名稱相匹配。還可以使用 FinderNamingStrategy 來支持其他命名查詢的方法。默認實現查找叫做 “ClassName.methodName” 的查詢,其中 ClassName 是不帶包的短名稱。清單 11 完成了泛型類型安全 DAO 實現:


清單 11. executeFinder() 的實現
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();
?}
?

?

結束語

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

幾乎本文的所有代碼都是可重用的。盡管您的 DAO 類可能包含此處沒有實現的查詢和操作類型(比如,批操作),但使用我所展示的技術,您至少應該能夠實現其中的一部分。參閱 參考資料 了解其他泛型類型安全 DAO 類實現。

致謝

自 Java 語言中出現泛型以來,單個泛型類型安全 DAO 的概念已經成為主題。我曾在 JavaOne 2004 中與 Don Smith 簡要討論了泛型 DAO 的靈活性。本文使用的 DAO 實現類旨在作為示例實現,實際上還存在其他實現。例如,Christian Bauer 已經發布了帶有 CRUD 操作和標準搜索的實現,Eric Burke 也在該領域做出了工作。我確信將會有更多的實現出現。我要額外感謝 Christian,他目睹了我編寫泛型類型安全 DAO 的第一次嘗試并提出改進建議。最后,我要感謝 Ramnivas Laddad 的無價幫助,他審閱了本文。

?