程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> 整合JSF、Hibernate、Spring實現用戶登錄應用

整合JSF、Hibernate、Spring實現用戶登錄應用

編輯:關於JAVA

本文使用的開發包為:jsf 1.2_04+hibernate 3.2.2.ga+spring 2.0.5,開發環境為jdk 1.5+myeclipse 6.0+mysql 5.0。

一、三層設計

本文實現的功能雖然簡單,但是仍然采用了三層的設計:

1)數據訪問層:本文使用Hibernate實現數據訪問。

2)業務邏輯層:本文使用Spring組織業務邏輯。

3)表示層,本文使用JSF進行前台顯示。

分層的好處在於:有利於系統的擴展性、伸縮性和維護性。

下面讓我們演示每一層具體是如何做的,在開始之前,首先看一下我們的數據庫設計:

實現登錄功能,需要一張userinfo表,包含id, username和password字段。

1. logon.sql:#
# Database structure for database 'logon'
#
CREATE DATABASE /*!32312 IF NOT EXISTS*/ `logon` /*!40100 DEFAULT CHARACTER SET latin1 */;
USE logon;
#
# Table structure for table 'userinfo'
#
CREATE TABLE /*!32312 IF NOT EXISTS*/ `userinfo` (
`id` int(11) NOT NULL auto_increment,
`username` varchar(100) NOT NULL default '',
`password` varchar(100) NOT NULL default '',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
#
# Dumping data for table 'userinfo'
#
/*!40000 ALTER TABLE userinfo DISABLE KEYS;*/
LOCK TABLES userinfo WRITE;
REPLACE INTO userinfo (id, username, password) VALUES (1,'admin','admin');
UNLOCK TABLES;
/*!40000 ALTER TABLE userinfo ENABLE KEYS;*/

好了,讓我們開始吧!

二、數據訪問層

因為只有一張userinfo表,所以數據訪問部分也不復雜。

首先,我們定義了一個IUserDAO接口,用於根據用戶名得到該用戶信息。

2. com.it168.logon.model.dao.IUserDAO.java:

package com.it168.logon.model.dao;
import com.it168.logon.model.businessobject.Userinfo;
public interface IUserDAO {
public Userinfo getUser(String username);
}

接著,UserDAO類實現了IUserDAO接口:

3. com.it168.logon.model.dao.impl.UserDAO.java:

package com.it168.logon.model.dao.impl;
import java.util.Iterator;
import java.util.List;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import com.it168.logon.model.businessobject.Userinfo;
import com.it168.logon.model.dao.IUserDAO;
public class UserDAO extends HibernateDaoSupport implements IUserDAO {
public UserDAO() {
super();
}
@SuppressWarnings("unchecked")
public Userinfo getUser(String username) {
Userinfo user = null;
List userList = getHibernateTemplate().findByNamedParam(
"from Userinfo u where u.username = :username", "username",
username);
if (userList != null) {
Iterator i = userList.iterator();
while (i.hasNext()) {
user = (Userinfo) i.next();
}
}
return user;
}
}

大家可以看到,UserDAO類繼承了HibernateDaoSupport類,HibernateDaoSupport類是Spring中的,該類極大地簡化了數據持久化操作。

大家或許注意到:

from Userinfo u where u.username = :username

這和我們平時使用的SQL語句很相似,但這是HQL,它針對的不是表,而是類/對象。既然HQL中使用了Userinfo類,那麼Userinfo類又包括哪些內容呢?

4. com.it168.logon.model.businessobject.Userinfo.java:

package com.it168.logon.model.businessobject;
@SuppressWarnings("serial")
public class Userinfo implements java.io.Serializable {
// Fields
   private Integer id;
private String username;
private String password;
// Constructors
   /** default constructor */
public Userinfo() {
}
/** full constructor */
public Userinfo(String username, String password) {
this.username = username;
this.password = password;
}
// Property accessors
   public Integer getId() {
return this.id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return this.username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return this.password;
}
public void setPassword(String password) {
this.password = password;
}
}

大家可以看到,Userinfo類並沒有什麼神奇的地方,只是一個簡單的POJO類。但是,為什麼這樣一個簡單的POJO類可以和數據庫查詢關聯起來呢?

5. com.it168.logon.model.businessobject.Userinfo.hbm.xml:

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.it168.logon.model.businessobject.Userinfo" table="userinfo">
<id name="id" type="java.lang.Integer">
<column name="id" />
<generator class="increment" />
</id>
<property name="username" type="java.lang.String">
<column name="username" length="100" not-null="true" />
</property>
<property name="password" type="java.lang.String">
<column name="password" length="100" not-null="true" />
</property>
</class>
</hibernate-mapping>

這就是原因所在!Userinfo.hbm.xml中定義了Userinfo類中屬性與Userinfo表中字段的關系。而Hibernate也這是借此實現了ORM映射。

我們的數據庫信息呢?別擔心,在這裡:

6. applicationContext.xml代碼片斷一:

<bean id="dataSource"
class="com.mchange.v2.c3p0.ComboPooledDataSource"
destroy-method="close">
<property name="driverClass">
<value>com.mysql.jdbc.Driver</value>
</property>
<property name="jdbcUrl">
<value>jdbc:mysql://localhost:3306/logon</value>
</property>
<property name="user">
<value>root</value>
</property>
<property name="password">
<value>123456</value>
</property>
<property name="minPoolSize">
<value>5</value>
</property>
<property name="maxPoolSize">
<value>20</value>
</property>
<property name="maxIdleTime">
<value>300</value>
</property>
<property name="maxStatements">
<value>50</value>
</property>
<property name="idleConnectionTestPeriod">
<value>3000</value>
</property>
</bean>

三、業務邏輯層

為了實現登錄功能,這裡只需要一個簡單的登錄邏輯。首先,我們定義了一個IUserService接口,用於根據用戶名和密碼得到用戶信息。

7. com.it168.logon.model.service.IUserService.java:

package com.it168.logon.model.service;
import com.it168.logon.model.businessobject.Userinfo;
public interface IUserService {
public Userinfo login(String username, String password);
}

接著,UserService類實現了該接口:

8. com.it168.logon.model.service.impl.UserService.java:

package com.it168.logon.model.service.impl;
import com.it168.logon.model.businessobject.Userinfo;
import com.it168.logon.model.dao.impl.UserDAO;
import com.it168.logon.model.service.IUserService;
public class UserService implements IUserService {
private UserDAO userDAO;
public void setUserDAO(UserDAO userDAO) {
this.userDAO = userDAO;
}
public Userinfo login(String username, String password) {
Userinfo user = this.userDAO.getUser(username);
if (user != null) {
if (!user.getPassword().equals(password)) {
user = null;
}
}
return user;
}
}

大家或許注意到了這樣一句:

private UserDAO userDAO;

這裡的UserDAO正是數據訪問層中的UserDAO。在UserService類中,我們沒有看到UserDAO的實例化過程,既然沒有實例化,Userinfo user = this.userDAO.getUser(username);這行代碼,又是如何發揮作用的呢?

9. applicationContext.xml代碼片斷二:

<bean id="userDAO" class="com.it168.logon.model.dao.impl.UserDAO">
<property name="hibernateTemplate">
<ref bean="hibernateTemplate" />
</property>
</bean>
<bean id="userService"
class="com.it168.logon.model.service.impl.UserService">
<property name="userDAO">
<ref local="userDAO" />
</property>
</bean>

這也正是Spring的強大所在!它將類的實例化過程交給了Spring容器,從而實現了控制反轉(IoC)。

四、表示層

我們實現了業務邏輯,接下來就看業務邏輯是如何與JSF頁面相關聯的。

首先我們定義了一個UserBean類,該類實現了一個verify()方法,如果登錄成功,返回“success”字符串,如果失敗,則返回“failure”字符串。

10. com.it168.logon.view.bean.UserBean.java代碼片斷:

public String verify() {
Userinfo user = serviceLocator.getUserService().login(this.username,
this.password);
if (user == null) {
this.errorMessage = "登錄失敗";
this.loggedIn = false;
return "failure";
} else {
this.loggedIn = true;
return "success";
}
}

大家可能注意到了這段代碼:

Userinfo user = serviceLocator.getUserService().login(this.username, this.password);

這裡的serviceLocator是ServiceLocatorBean類的實例:

11. com.it168.logon.view.bean.ServiceLocatorBean.java:

package com.it168.logon.view.bean;
import javax.faces.context.FacesContext;
import javax.servlet.ServletContext;
import org.springframework.context.ApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
import com.it168.logon.model.service.IUserService;
import com.it168.logon.model.service.impl.UserService;
import com.it168.logon.view.servicelocator.IServiceLocator;
public class ServiceLocatorBean implements IServiceLocator {
private static final String USER_SERVICE_BEAN_NAME = "userService";
private ApplicationContext appContext;
private UserService userService;
public ServiceLocatorBean() {
ServletContext context = (ServletContext) FacesContext
.getCurrentInstance().getExternalContext().getContext();
this.appContext = WebApplicationContextUtils
.getRequiredWebApplicationContext(context);
this.userService = (UserService) this
         .lookupService(USER_SERVICE_BEAN_NAME);
}
public IUserService getUserService() {
return this.userService;
}
public Object lookupService(String serviceBeanName) {
return appContext.getBean(serviceBeanName);
}
}

ServiceLocatorBean類實現了業務邏輯與JSF頁面上下文的關聯。

現在來看一下JSF頁面如何實現了與UserBean的綁定:

12. login.jsp代碼片斷:

<f:view>
       <h:form rendered="true">
         <div align="center">
           <h:outputText escape="false" rendered="true"
             value="#{userBean.errorMessage}"></h:outputText>
         </div>
         <div align="center">
           <h:outputText value="用戶名: " />
           <h:inputText id="username" required="true"
             value="#{userBean.username}">
           </h:inputText>
           <h:message for="username" />
           <br>
         </div>
         <div align="center">
           <h:outputText value="密 碼: " />
           <h:inputSecret id="password" required="true" rendered="true"
             value="#{userBean.password}" style="width: 154px">
           </h:inputSecret>
           <h:message for="password" />
           <br>
         </div>
         <br>
         <div align="center">
           <h:commandButton rendered="true" value="登錄"
             action="#{userBean.verify}"></h:commandButton>
         </div>
       </h:form>
</f:view>

其中,“userBean”從何而來呢?

13. faces-config.xml代碼片斷一:

<managed-bean>
     <managed-bean-name>userBean</managed-bean-name>
     <managed-bean-class>
       com.it168.logon.view.bean.UserBean
</managed-bean-class>
     <managed-bean-scope>session</managed-bean-scope>
     <managed-property>
       <property-name>serviceLocator</property-name>
       <value>#{serviceLocatorBean}</value>
     </managed-property>
   </managed-bean>

在faces-config.xml文件中的<managed-bean>節點中,我們定義了“userBean”對應的類。

14. faces-config.xml代碼片斷二:

<navigation-rule>
     <from-view-id>/pages/login.jsp</from-view-id>
     <navigation-case>
       <from-outcome>success</from-outcome>
       <to-view-id>/pages/welcome.jsp</to-view-id>
     </navigation-case>
     <navigation-case>
       <from-outcome>failure</from-outcome>
       <to-view-id>/pages/login.jsp</to-view-id>
     </navigation-case>
   </navigation-rule>

在faces-config.xml文件中的<navigation-rule>節點中,我們定義了頁面導航規則。

到目前為止,我們介紹了Hibernate、Spring和JSF如何在三層設計中發揮作用的,現在我們可以看一下實際效果,訪問http://localhost:8080/Logon:

(圖1)

如果登錄成功:

(圖2)

登錄失敗,則:

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved