看了《 使用JSF 构建数据库驱动的应用程序》 一文后,动手做了练习。这是一个 订阅时事通讯的示例 Web 应用程序。订户通过提供他们的电子邮件地址、姓名和首选项进行注册。他们还必须选择一个口令,
以便以后可以更改他们的配置文件。 收获不少。
1、
这个没有什么可说的。
2、
<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %>
<%@ taglib prefix="f" uri="http://java.sun.com/jsf/core" %>
<%@ taglib prefix="h" uri="http://java.sun.com/jsf/html" %>
<head>
</body>
典型的jstl加jsf,看来要好好学习jsp2.0了,赶上不形势啊!
点击链接
Subscribe可进入subscribe.jsp(如图一),填订单页面。
命令按钮的"action"绑定到了视图loginInfo Bean的loginAction()方法,
loginAction() 方法会根据登录用户的角色(订户或管理员)返回 profile 或 list(导航法则在faces-config.xml文件中定义) ,
请求转向订户修改配置文件页面 profile.jsp(图二) 或订户列表页面 list.jsp(图三)。先看看LoginInfoBean.java源码:
package jsfdb.view; import jsfdb.model.LoginInfo; import jsfdb.model.Subscriber; import jsfdb.model.ModelUtils; import jsfdb.model.err.LoginException; import jsfdb.model.err.IncorrectPasswordException; import jsfdb.model.err.UnknownSubscriberException; public class LoginInfoBean extends LoginInfo { public String loginAction() { //初始化一个SubscriberBean对象 SubscriberBean subscriber= (SubscriberBean) ViewUtils.eval("#{subscriber}"); //获取管理员的邮件地址,管理员的邮件在web.xml文件中配置 String adminEmail= (String) ViewUtils.eval("#{initParam.adminEmail}"); try { Subscriber selectedSubscriber = ModelUtils.getSubscriberDAO().select(this);//通过数据库验证口令与email ModelUtils.copy(selectedSubscriber, subscriber);//订户数据复制进视图bean subscriber.setLoggedIn(true);//登录标志设为true if (subscriber.getEmail().equals(adminEmail)) return "list";//如果是超级管理员,转向list.jsp else return "profile";//如果是订户,转向profile.jsp } catch (LoginException x) { ViewUtils.addExceptionMessage(x); return null; } catch (UnknownSubscriberException x) { ViewUtils.addExceptionMessage(x); return null; } catch (IncorrectPasswordException x) { ViewUtils.addExceptionMessage(x); return null; } } }
图一(填订单)
<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %>
<%@ taglib prefix="f" uri="http://java.sun.com/jsf/core" %>
<%@ taglib prefix="h" uri="http://java.sun.com/jsf/html" %>
<head>
</body>
这是SubscriberBean.java源码
package jsfdb.view; import jsfdb.model.Subscriber; import jsfdb.model.ModelUtils; import jsfdb.model.err.ProfileException; import jsfdb.model.err.SubscribeException; import jsfdb.model.err.UnsubscribeException; import javax.faces.component.UIComponent; import javax.faces.component.EditableValueHolder; import javax.faces.context.FacesContext; public class SubscriberBean extends Subscriber { public final static String INVALID_EMAIL_ID = "jsfdb.view.SubscriberBean.INVALID_EMAIL"; public final static String SELECT_NEWSLETTER_ID = "jsfdb.view.SubscriberBean.SELECT_NEWSLETTER"; private transient boolean loggedIn = false; public boolean isLoggedIn() { return loggedIn; } public void setLoggedIn(boolean loggedIn) { this.loggedIn = loggedIn; } public void emailValidator(FacesContext context, UIComponent comp, Object value) { String email = (String) value; if (email.indexOf("@") == -1) { String compId = comp.getClientId(context); ViewUtils.addErrorMessage(context, compId, INVALID_EMAIL_ID); ((EditableValueHolder) comp).setValid(false); } } public String subscribeAction() { if (countNewsletters() == 0) { ViewUtils.addErrorMessage( FacesContext.getCurrentInstance(), null, SELECT_NEWSLETTER_ID); return null; } try { ModelUtils.getSubscriberDAO().insert(this); setLoggedIn(true); return "subscribed"; } catch (SubscribeException x) { ViewUtils.addExceptionMessage(x); return null; } } public String profileAction() { if (!loggedIn) return "login"; if (countNewsletters() == 0) { ViewUtils.addErrorMessage( FacesContext.getCurrentInstance(), null, SELECT_NEWSLETTER_ID); return null; } try { ModelUtils.getSubscriberDAO().update(this); return null; } catch (ProfileException x) { ViewUtils.addExceptionMessage(x); return null; } } public String unsubscribeAction() { if (!loggedIn) return "login"; try { ModelUtils.getSubscriberDAO().delete(this); return "unsubscribed"; } catch (UnsubscribeException x) { ViewUtils.addExceptionMessage(x); return null; } } public String cancelAction() { if (!loggedIn) return "login"; else return "cancel"; } public int getDailyConst() { return TYPE_DAILY; } public int getWeeklyConst() { return TYPE_WEEKLY; } public int getMonthlyConst() { return TYPE_MONTHLY; } } 这是修改配置的页面:
图二
再看看list.jsp
图三
<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %>
<%@ taglib prefix="sql" uri="http://java.sun.com/jstl/sql" %>
<%@ taglib prefix="f" uri="http://java.sun.com/jsf/core" %>
<%@ taglib prefix="h" uri="http://java.sun.com/jsf/html" %>
SELECT * FROM subscribers ORDER BY subscriberEmail
<head>
</body>
这个页面用jstl标记访问数据库!
数据适配层和数据访问对象DAO
这个应用通过ModelUtils类访问后端数据源,
提供了 SubscriberDAO 接口的两个实现,一个(JDBCSubscriberDAO.java)基于 JDBC API,另一个(TopLinkSubscriberDAO.java)使用 Oracle TopLink。下面是ModelUtils类的源码:
package jsfdb.model; import jsfdb.model.dao.SubscriberDAO; import java.beans.BeanInfo; import java.beans.Introspector; import java.beans.PropertyDescriptor; import java.beans.IntrospectionException; import java.lang.reflect.Method; import java.lang.reflect.InvocationTargetException; import java.util.ResourceBundle; import java.util.MissingResourceException; import java.util.logging.Level; import java.util.logging.Logger; public class ModelUtils { public static final String RESOURCES = ModelUtils.class.getPackage().getName() + ".res.ModelResources"; private static ResourceBundle resources; private static SubscriberDAO subscriberDAO; public static void log(Throwable x) { Logger.global.log(Level.SEVERE, x.getMessage(), x); } public static synchronized ResourceBundle getResources() { if (resources == null) try { resources = ResourceBundle.getBundle(RESOURCES); } catch (MissingResourceException x) { log(x); throw new InternalError(x.getMessage()); } return resources; } public static String getResource(String key) { return getResources().getString(key); } public synchronized static SubscriberDAO getSubscriberDAO() { if (subscriberDAO == null) try { Class daoClass = Class.forName(getResource("DAO")); subscriberDAO = (SubscriberDAO) daoClass.newInstance(); } catch (ClassNotFoundException x) { log(x); throw new InternalError(x.getMessage()); } catch (IllegalAccessException x) { log(x); throw new InternalError(x.getMessage()); } catch (InstantiationException x) { log(x); throw new InternalError(x.getMessage()); } return subscriberDAO; } public static void copy(Object source, Object dest) { try { Class sourceClass = source.getClass(); Class destClass = dest.getClass(); BeanInfo info = Introspector.getBeanInfo(sourceClass); PropertyDescriptor props[] = info.getPropertyDescriptors(); Object noParams[] = new Object[0]; Object oneParam[] = new Object[1]; for (int i = 0; i < props.length; i++) { Method getter = props[i].getReadMethod(); if (getter == null) continue; Object value = getter.invoke(source, noParams); Method setter = props[i].getWriteMethod(); if (setter != null && sourceClass != destClass) try { setter = destClass.getMethod( setter.getName(), setter.getParameterTypes()); } catch (NoSuchMethodException x) { setter = null; } if (setter != null) { oneParam[0] = value; setter.invoke(dest, oneParam); } } } catch (IntrospectionException x) { log(x); throw new InternalError(x.getMessage()); } catch (IllegalAccessException x) { log(x); throw new InternalError(x.getMessage()); } catch (IllegalArgumentException x) { log(x); throw new InternalError(x.getMessage()); } catch (SecurityException x) { log(x); throw new InternalError(x.getMessage()); } catch (InvocationTargetException x) { log(x.getTargetException()); throw new InternalError( x.getTargetException().getMessage()); } } }
此类的getSubscriberDAO()方法返回 SubscriberDAO 接口的一个实例,该接口定义了在关系数据库中选择、删除、插入、更新 Subscriber 对象的方法。 你的应用中具体使用哪一个后端数据源,在 ModelResources资源包有一个 DAO 参数,用于指定要使用的 DAO 实现.
这是ModelResources.properties文件:
DAO=jsfdb.model.dao.JDBCSubscriberDAO
# DAO=jsfdb.model.dao.TopLinkSubscriberDAO
TopLinkSession=JSFDBSession
JavaCompEnv=java:comp/env
DataSource=jdbc/OracleDS
SelectStatement=SELECT \
subscriberPassword, \
subscriberName, \
managerFlag, \
developerFlag, \
administratorFlag, \
subscriptionType \
FROM subscribers \
WHERE subscriberEmail=?
InsertStatement=INSERT INTO subscribers ( \
subscriberEmail, \
subscriberPassword, \
subscriberName, \
managerFlag, \
developerFlag, \
administratorFlag, \
subscriptionType ) \
VALUES (?, ?, ?, ?, ?, ?, ?)
UpdateStatement=UPDATE subscribers SET \
subscriberPassword=?, \
subscriberName=?, \
managerFlag=?, \
developerFlag=?, \
administratorFlag=?, \
subscriptionType=? \
WHERE subscriberEmail=?
DeleteStatement=DELETE FROM subscribers \
WHERE subscriberEmail=?
SubscribeException=Subscription failed. \
Please try another email address.
ProfileException=Couln't update your profile. \
Please contact the Webmaster.
UnsubscribeException=Unsubscription failed. \
Please contact the Webmaster.
LoginException=Login failed. \
Please contact the Webmaster.
UnknownSubscriberException=Unknown subscriber. \
Please subscribe.
IncorrectPasswordException=Incorrect password. \
Please try to login again.
我做这个例子时用了Access数据库
package jsfdb.model.dao; import jsfdb.model.LoginInfo; import jsfdb.model.Subscriber; import jsfdb.model.ModelUtils; import jsfdb.model.err.IncorrectPasswordException; import jsfdb.model.err.LoginException; import jsfdb.model.err.ProfileException; import jsfdb.model.err.SubscribeException; import jsfdb.model.err.UnknownSubscriberException; import jsfdb.model.err.UnsubscribeException; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException;
public class JDBCSubscriberDAO implements SubscriberDAO { // private DataSource dataSource; public JDBCSubscriberDAO() { Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); } private void close(Connection conn, PreparedStatement ps) throws SQLException { if (ps != null) ps.close(); if (conn != null) conn.close(); } public Subscriber select(LoginInfo loginInfo) throws LoginException, UnknownSubscriberException, IncorrectPasswordException { Connection conn = DriverManager.getConnection("jdbc:odbc:jsfdb"); PreparedStatement ps = null; try { conn = dataSource.getConnection(); ps = conn.prepareStatement( ModelUtils.getResource("SelectStatement")); ps.setString(1, loginInfo.getEmail()); ResultSet rs = ps.executeQuery(); if (!rs.next()) throw new UnknownSubscriberException(); String password = rs.getString(1); if (!loginInfo.getPassword().equals(password)) throw new IncorrectPasswordException(); Subscriber subscriber = new Subscriber(); subscriber.setEmail(loginInfo.getEmail()); subscriber.setPassword(loginInfo.getPassword()); subscriber.setName(rs.getString(2)); subscriber.setManager(rs.getBoolean(3)); subscriber.setDeveloper(rs.getBoolean(4)); subscriber.setAdministrator(rs.getBoolean(5)); subscriber.setSubscriptionType(rs.getInt(6)); return subscriber; } catch (SQLException x) { ModelUtils.log(x); throw new LoginException(); } finally { try { close(conn, ps); } catch (SQLException x) { ModelUtils.log(x); throw new LoginException(); } } } public void insert(Subscriber subscriber) throws SubscribeException { Connection conn = DriverManager.getConnection("jdbc:odbc:jsfdb"); PreparedStatement ps = null; try { conn = dataSource.getConnection(); ps = conn.prepareStatement( ModelUtils.getResource("InsertStatement")); ps.setString(1, subscriber.getEmail()); ps.setString(2, subscriber.getPassword()); ps.setString(3, subscriber.getName()); ps.setBoolean(4, subscriber.isManager()); ps.setBoolean(5, subscriber.isDeveloper()); ps.setBoolean(6, subscriber.isAdministrator()); ps.setInt(7, subscriber.getSubscriptionType()); int rowCount = ps.executeUpdate(); if (rowCount != 1) throw new SubscribeException(); } catch (SQLException x) { ModelUtils.log(x); throw new SubscribeException(); } finally { try { close(conn, ps); } catch (SQLException x) { ModelUtils.log(x); throw new SubscribeException(); } } } public void update(Subscriber subscriber) throws ProfileException { Connection conn = DriverManager.getConnection("jdbc:odbc:jsfdb"); PreparedStatement ps = null; try { conn = dataSource.getConnection(); ps = conn.prepareStatement( ModelUtils.getResource("UpdateStatement")); ps.setString(1, subscriber.getPassword()); ps.setString(2, subscriber.getName()); ps.setBoolean(3, subscriber.isManager()); ps.setBoolean(4, subscriber.isDeveloper()); ps.setBoolean(5, subscriber.isAdministrator()); ps.setInt(6, subscriber.getSubscriptionType()); ps.setString(7, subscriber.getEmail()); int rowCount = ps.executeUpdate(); if (rowCount != 1) throw new ProfileException(); } catch (SQLException x) { ModelUtils.log(x); throw new ProfileException(); } finally { try { close(conn, ps); } catch (SQLException x) { ModelUtils.log(x); throw new ProfileException(); } } } public void delete(Subscriber subscriber) throws UnsubscribeException { Connection conn = DriverManager.getConnection("jdbc:odbc:jsfdb"); PreparedStatement ps = null; try { conn = dataSource.getConnection(); ps = conn.prepareStatement( ModelUtils.getResource("DeleteStatement")); ps.setString(1, subscriber.getEmail()); int rowCount = ps.executeUpdate(); if (rowCount != 1) throw new UnsubscribeException(); } catch (SQLException x) { ModelUtils.log(x); throw new UnsubscribeException(); } finally { try { close(conn, ps); } catch (SQLException x) { ModelUtils.log(x); throw new UnsubscribeException(); } } } }
↑返回目录
前一篇: JSF实例学习--JSF Weekly 电子报订阅
后一篇: 面向对象的类设计原则