实现一个简单的用户管理系统


1 《EasyJWeb EasyJWeb EasyJWeb EasyJWeb 实用开发指南 》 (作者:蔡世友 程强 郭朝斌 等) 简介: 致谢: 在创作本书的过程中, EasyJF 开源团队的很多成员给予了很我们很大的 帮助,在此深 表感谢。 作者邮箱: 蔡世友 caishiyou@sina.com.cn 2 第三章 实现一个简单的用 户管理系统 目录 实现一个简单的用户管理系统 .........................................................................................................1 需求概述 .....................................................................................................................................1 数据模型 .............................................................................................................................1 用户登录 .............................................................................................................................2 用户列表 .............................................................................................................................2 用户详细信息 .....................................................................................................................2 用户添加 .............................................................................................................................3 用户修改 .............................................................................................................................3 用户删除 .............................................................................................................................4 数据有效性验证 .................................................................................................................4 业务层的设计及实现 .................................................................................................................5 领域模型 User的设计 .......................................................................................................5 数据访问层的设计- UserDao..........................................................................................7 业务层逻辑层的设计 UserService....................................................................................8 写单元测试代码 ...............................................................................................................10 数据访问层 (DAO)的实现 ...............................................................................................13 业务逻辑层 (Service)的实现 ............................................................................................15 视图及页面模板 .......................................................................................................................17 index.html-首页及登录页 .............................................................................................17 list.html 用户列表页面 ....................................................................................................18 preview.html-显示用户详情的页面 .............................................................................19 add.html-添加用户的页面 ............................................................................................21 edit.html-修改用户的界面 ............................................................................................23 使用 #parse或#include 来重构 add.html 及edit.html.................................................... 25 Action........................................................................................................................................27 UserAction........................................................................................................................28 UserAction 代码解析 .......................................................................................................31 综合到一起 ...............................................................................................................................32 Action 与页面结合 ...........................................................................................................32 从哪儿得到业务层的对象 33 修改 web.xml 34 编译并运行程序 35 添加验证特性 36 UserDao 基于数据库的实现 38 小结 43 实现 一个 简单的 用户 管理 系统 在前面的一章,我们写了一个非常简单 的 HelloWorld 及一个相对较为复杂的客户管理 程序, 简 单的 HelloWorld 里面没有一点业务逻辑, 无 法体现出企业级 Java EE应用程序的 各 个组成部分;而复杂的客户管理程序则涉及到了 Spring、JPA、Hibernate 及EasyJWeb 中的 IPageList、IQueryObject、 泛型 DAO 等, 对于初学者来说门槛稍为有点高。 因 此, 本章将 通 过一个稍为简单一点的完整示例, 来 详细讲解如何使用 EasyJWeb实现一个 Java Web 应用 程 序的开发。 需求概述 需求概述 需求概述 需求概述 不管是任何系统, 都 必然会有用户这个角色, 因 此用户管理系统是每一个应用中必不 可 少的部分, 在 本章中我们将实现的是一个简单用户管理系统。 因 此, 我 们首先来看看本章 所 要实现的用户管理系统的简单需求。 数据 模型 本系统实现一个简单的用户系统, 所 管理的目标是用户。 系 统中只涉及到用户一个模 型, 涉及到的属性项目有 “ID”、“用户名 (姓名 )”、“密码 ”、“性别 ”、“邮件 ”、“出生日期 ”、“登 录次数 ”、“上次登录时间 ”、“简介 ”等几个属性,其 UML 图如图 3-1 所示。 图3-1 用户 User类的属性 对应的 JavaBean 代码如下: public class User { private String name; private String password; private String sex; private String email; private Date bornDate; private Integer loginTimes=0; private Date lastLoginTime; private String intro; //其它 getter 及setter 方法 } 2 用户 登录 首先给用户一个登录页面, 用 户能输入用户名及密码, 提 交登录后系统判断用户输入 的 用户名及密码是否正确, 若 正确则进入用户列表中管理用户, 若 用户名或密码错误则回到 登 录页面, 显示错误提示信息, 并 要求用户重新输入用户名及密码进行登录, 界面如图 3-2 所 示。 图3-2 用户登录页面 用户 列表 使用表格列出系统中的所有用户信息, 在 列表中显示用户的 ID号、 姓 名、 性 别、 邮 件、 出生日期等选项, 另外还包括针对用户管理的 “查看 ”、“修改 ”、“删除 ”等按钮, 大致如 图 3-3 所示。 图3-3 用户信息列表页面 用户 详细 信息 在用户列表页面中, 需 要提供一个查看连接或按钮, 点 击该按钮可以查看对应的用户 详 细信息, 要显示的详细信息包括 “姓名 ”、“性别 ”、“邮件 ”、“出生日期 ”、“登录次数 ”、“上 次登录时间 ”、“简介 ”等项目,大致如图 3-4 所示。 图3-4 用户信息显示页面 3 用户添加 在用户列表中,应该提供一个“添加用户”的连接或按钮,点击可以进入新用户录入界 面,该界面可以录入用户的“姓名”、“密码”、“性别”、“邮件”、“出生日期”及“简介”等 几个项目,不允许录入“用户登录次数”、“上次登录时间”项目。添加用户的界面应该保住 一个“提交”及“重置”按钮,另外还应该包括一个“返回列表”的连接或按钮,点击“提 交”按钮将保存用户的信息,点击“重置”按钮将清空输入框中的各项,点击“返回列表” 按钮回到用户列表页。用户添加的页面大致如图 3-5 所示。 图3-5 用户信息添加页面 用户修改 在用户列表中,点击每一个用户后面的“修改”按钮,可以调出该用户的相关信息,并 可以修改用户的“姓名”、“密码”、“性别”、“邮件”、“出生日期”及“简介”等几个项目, 其它要求与用户添加类似。用户修改的界面大致如图 3-6 所示。 图3-6 用户信息修改 4 用户 删除 在用户列表页面中, 可 以点击某一个用户后面的删除连接或按钮, 给 予用户删除确认 的 提示, 在 用户确认要执行删除操作后, 则删除该用户, 删 除完成后返回用户列表页面。 删 除 确认的界面大致如图 3-7 所示。 图3-7 删除用户的提示 数据 有效 性验证 不在是数据添加或修改, 都 要保证对于不合法的数据将不接受处理, 并 给与相应的提 示, 确保数据的有效性。数据的有效性验证按照如下的规则执行: 1、用户名及密码两项都不能为空,只能包含 5-20 个字符,少于 5个或多于 20 个的输 入将不予接受; 2、邮箱不能空,并且必须是正确的邮箱格式; 3、日期可以为空,如果要填,则必须填写正确格式的日期数据; 另外, 在 添加用户的时候, 用户名不能与系统中已有的用户重名; 可 以修改用户名, 但 不能修改成系统中已经有其它用户名,大致如图 3-8 所示。 图3-8 数据完整性验证页面 5 业务层的设计及 实现 业务层的设计及 实现 业务层的设计及 实现 业务层的设计及 实现 对于开发企业级应用来说,业务层是核心 及关键。一个层次 分明、良好的业 务层设计 及实现, 可 以让我们开发出容易扩展及重用、 可 维护性强, 能 灵活适应用户业务变化的系 统。 领域 模 型 User User User User 的设 计 作为业务层最基础的部分, 就 是对领域模型的设计。 根 据前面的需求描述, 我 们大概 知 道本应用涉及到一个 User模型,下面是 User类完整代码: package easyjweb.demo.user.domain; import java.util.Date; import com.easyjf.container.annonation.Field; import com.easyjf.container.annonation.FormPO; import com.easyjf.container.annonation.Validator; public class User { private Long id; private String name; private String sex; private String email; private Date bornDate; private Integer loginTimes; private String intro; public User() { } public User(String name, String email, Date bornDate) { this.name = name; this.email = email; this.bornDate = bornDate; this.loginTimes = 5; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getEmail() { return email; } 6 public void setEmail(String email) { this.email = email; } public Date getBornDate() { return bornDate; } public void setBornDate(Date bornDate) { this.bornDate = bornDate; } public Integer getLoginTimes() { return loginTimes; } public void setLoginTimes(Integer loginTimes) { this.loginTimes = loginTimes; } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } public String getIntro() { return intro; } public void setIntro(String intro) { this.intro = intro; } } 7 数据 访问 层的设 计- UserDaoUserDaoUserDao UserDao 对于企业级应用来说,一般都会涉及到数据持久层的应用。因此,在企业级的应用中, 我们都会把与数据持久化相关的操作抽象出来,形成一个数据访问层,即 DAO。在我们的 用户管理系统中,我们通过接口的形式设 计一个数据访问 层 UserDao 接口,负责处理 User 对象的持久化相关操作。 UserDao 的代码如下所示: packagepackagepackage package easyjweb.demo.user.dao; importimportimport import java.util.List; importimportimport import easyjweb.demo.user.domain.User; /** * User模型的数据访问 接口 * *@author@author@author @author 大峡 * */ publicpublicpublic public interfaceinterfaceinterface interface UserDao { /** * 从持久层根据 id加载一个 User对象 * *@param@param@param @param id * 主键值 *@return@return@return @return 如果持久层包括 该对象 ,则返 回该 User,否则返回 null */ User get(Long id); /** * 把一个 User实例化到持久层 中 * *@param@param@param @param user * 要持久化的 user */ voidvoidvoid void save(User user); /** * 更新一个持久化 对象 * *@param@param@param @param id * 要更新的 id *@param@param@param @param user * 更新的对象 */ voidvoidvoid void update(Long id, User user); 8 /** * 从持久层永久删 除指定 id的User对象 * *@param@param@param @param id */ voidvoidvoid void remove(Long id); /** * 从持久层读取所 有的 User对象 * *@return@return@return @return 所有持久化的 User对象,如果没有 则返回 包含 0个元素的空列表 */ List list(); } UserDao 各个接口的说明已经在代码注解中,这里不再重复讲述。 业务 层逻 辑层的 设 计 UserServiceUserServiceUserService UserService 业务层逻辑层是业务层的核心, 业 务层主要实现需求中的各种具体业务逻辑。 根 据前 面 的需求中的各个功能点,我们可以分析设 计出用户系统的业 务接 口 UserService,其代码如 下所示: packagepackagepackage package easyjweb.demo.user.service; importimportimport import java.util.List; importimportimport import easyjweb.demo.user.domain.User; /** * 用户系统的业务 逻辑接 口 *@author@author@author @author 大峡 * */ publicpublicpublic public interfaceinterfaceinterface interface UserService { /** * 根据 id查询用户 * *@param@param@param @param id *@return@return@return @return */ User getUser(Long id); /** * 根据用户名得到 用户 *@param@param@param @param name 用户名 9 *@return@return@return @return 如果存在用户名 指定的 用户, 则返回 该用户 ,否则 返回 null */ User getUser(String name); /** * 保存用户 * *@param@param@param @param user */ voidvoidvoid void saveUser(User user); /** * 修改用户信息 * *@param@param@param @param user */ voidvoidvoid void updateUser(Long id,User user); /** * 删除用户 * *@param@param@param @param user */ voidvoidvoid void delUser(User user); /** * 查询所有用户 *@return@return@return @return 返回用户列表 */ List getAllUser(); /** * 用户登录 *@param@param@param @param userName 用户名 *@param@param@param @param password 密码 *@return@return@return @return 如果登录成功则 返回该 用户的 详细信 息,如 果登录 失败则 返回 null */ User login(String userName,String password); } 各个接口的说明如代码中的注释所示。 10 写单元测试代码 单元测试代码也称为白盒测试,主要是针对程序中的每一方法进行测试,在企业级的应 用开发中,单元测试代码非常重要,他能让我们快速发现代码中的错误,单元测试也可以看 成是需求描述代码。在敏捷开发的实践中,测试先行被证明是一个非常好的方法,形成写单 元测试的习惯会让我们在后面的工作中省很多的事。基于测试先行的原则,我们在设计完接 口后,首先要做的事情就是写单元测试代码。下面是本例中针对数据访问层的单元测试代码 UserDaoTest,该类通过使用 junit 来实现单元测试,代码的全部内容如下: packagepackagepackage package easyjweb.demo.user.dao; importimportimport import java.util.Date; importimportimport import java.util.List; importimportimport import junit.framework.TestCase; importimportimport import easyjweb.demo.user.domain.User; /** * UserDao的测试代码 * *@author@author@author @author 大峡 * */ publicpublicpublic public classclassclass class UserDaoTest extendsextendsextends extends TestCase { privateprivateprivate private UserDao userDao; @Override protectedprotectedprotected protected voidvoidvoid void setUp() throwsthrowsthrows throws Exception { supersupersuper super .setUp(); } /** * 测试get方法 */ publicpublicpublic public voidvoidvoid void testGet() { User user = userDao.get(1l); assertNotNull(user); assertTrue(user.getId().equals(1l)); } /** * 测试save方法 * */ publicpublicpublic public voidvoidvoid void testSave() { 11 User user = newnewnew new User("小王 ","小王 @easyjf.com", newnewnew new Date()); userDao.save(user); User u = userDao.get(user.getId()); assertEquals("小王 ", u.getName()); } /** * 测试 remove方法 */ publicpublicpublic public voidvoidvoid void testRemove() { User user = newnewnew new User("小王 ","小王 @easyjf.com", newnewnew new Date()); userDao.save(user); User u = userDao.get(user.getId()); assertNotNull(u); userDao.remove(user.getId()); u = userDao.get(user.getId()); assertNull(u); } /** * 测试 list方法 */ publicpublicpublic public voidvoidvoid void testList() { List list = userDao.list(); intintint int l = list.size(); User user = newnewnew new User("小王 ","小王 @easyjf.com", newnewnew new Date()); userDao.save(user); list = userDao.list(); assertTrue(list.size() == l + 1); } /** * 测试 update方法 */ publicpublicpublic public voidvoidvoid void testUpdate() { User user = newnewnew new User("小王 ","小王 @easyjf.com", newnewnew new Date()); userDao.save(user); User u = userDao.get(user.getId()); u.setEmail("xiaowang@easyjf.com"); userDao.update(u.getId(), u); User u2 = userDao.get(user.getId()); assertEquals("xiaowang@easyjf.com",u2.getEmail()); } } 12 单元测试写完后, 我 们可以运行单元测试代码, 非 常遗憾的时, 一 开始我们会发现所 有 的测试的都没法通过,图 3-9 演示了在 Eclipse 中运行 UserDaoTest的效果。 图3-9 UserDaoTest在没有实现时的运行效果 而测试驱动开发的一个乐趣就是, 我 们根据单元测试的需求去写实现代码, 直 到把单 元 测试中的每一个红条逐一变成绿条,才表示我们的任务完成,非常直观。 针对业务层的接口同样要写单元测试代码,因为系统中最容易出错的是业务逻辑部分, 所以单元测试显得更加重要。 在 实现的企业级开发中, 由 于数据访问层使用的是比较成熟 的 ORM 系统来实现,因此单元测试代码可以通过工具来生成,在有些时候甚至可以省略,但 是业务逻辑层(即 Service层)的单元测试则是无论如何应该要写的。由于在以后的章节还 会有关业务层测试代码的示例,因此这里我们就省略 了 UserService 的单元测试代码,把这 一任务留给读取来完成,下面我们将实现前面设计的 UserDao 及UserService 接口。 13 数据 访问 层 (DAO)(DAO)(DAO) (DAO) 的实 现 为了演示接口编程的好处以及让初学者能更简单读懂该示例, 在 这里我们先写一个简 单 的UserDao 实现,该实现把数据存放到内存中,本章后面还会给出给出使 用 jdbc 访问数据 库的 UserDao 实现。 UserDao 的简单实现 UserDaoImpl 的代码如下: packagepackagepackage package easyjweb.demo.user.dao.impl; importimportimport import java.util.Date; importimportimport import java.util.List; importimportimport import com.easyjf.container.annonation.Bean; importimportimport import easyjweb.demo.user.dao.UserDao; importimportimport import easyjweb.demo.user.domain.User; publicpublicpublic public classclassclass class UserDaoImpl implementsimplementsimplements implements UserDao { privateprivateprivate private List users = newnewnew new java.util.ArrayList(); publicpublicpublic public UserDaoImpl() { ififif if (list().size()<1){ User u=newnewnew new User("admin","admin@easyjf.com",newnewnew new Date()); u.setPassword("admin"); save(u); } } publicpublicpublic public User get(Long id) { forforfor for (User u : thisthisthis this .users){ ififif if (u.getId().equals(id)) returnreturnreturn return u; } returnreturnreturn return nullnullnull null ; } publicpublicpublic public List list() { returnreturnreturn return users; } publicpublicpublic public voidvoidvoid void remove(Long id) { User user = get(id); users.remove(user); } publicpublicpublic public voidvoidvoid void save(User user) { 14 user.setId(newnewnew new Long(users.size()+1));//设置 id值 ififif if (!users.contains(user)) { users.add(user); } } publicpublicpublic public voidvoidvoid void update(Long id, User user) { User u = get(id); u.setName(user.getName()); u.setPassword(user.getPassword()); u.setEmail(user.getEmail()); u.setBornDate(user.getBornDate()); u.setSex(user.getSex()); u.setLoginTimes(user.getLoginTimes()); } } UserDaoImpl 把用户的对象保存到内存的 List 列表 users中,他只负责数据的保存、删 除或查询等操作, 跟 具体业务逻辑相关的东西一般都不处理。 完 成实现后, 可 以通过前面 的 单元测试代码来检验我们的这个 UserDao 实现是否存在错误。 在 前面 UserDaoTest类的 setUp 方法中加入 userDao=newnewnew new UserDaoImpl()语句 来初始化 userDao,如下所示: @Override protectedprotectedprotected protected voidvoidvoid void setUp() throwsthrowsthrows throws Exception { userDao=newnewnew new UserDaoImpl(); supersupersuper super .setUp(); } 这里再运行单元测试, 如 果所有测试代码都通过的话, 则 表示我们的这个实现基本完 成 了,如图 3-10 所示。 15 图3-10 UserDaoTest全部单元测试通过时的效果 业务 逻辑 层 (Service)(Service)(Service) (Service) 的实 现 业务逻辑层是整个应用的核 心,业务逻 辑层一般通 过调用数据 层来实进行 据的访问操 作, UserServiceImpl 是用户业务逻辑层的实现代码,全部代码如下: packagepackagepackage package easyjweb.demo.user.service.impl; importimportimport import java.util.Date; importimportimport import java.util.List; importimportimport import com.easyjf.container.annonation.Bean; importimportimport import easyjweb.demo.user.dao.UserDao; importimportimport import easyjweb.demo.user.domain.User; importimportimport import easyjweb.demo.user.service.UserService; publicpublicpublic public classclassclass class UserServiceImpl implementsimplementsimplements implements UserService { privateprivateprivate private UserDao userDao; publicpublicpublic public voidvoidvoid void setUserDao(UserDao userDao) { thisthisthis this .userDao = userDao; } publicpublicpublic public User login(String userName, String password) { List users = getAllUser(); forforfor for (User user : users) { // 检测用户名密码 ,如果 正确则 ififif if (userName.equals(user.getName()) && password.equals(user.getPassword())) { user.setLoginTimes(user.getLoginTimes() + 1);// 更改登录 次数 user.setLastLoginTime(newnewnew new Date());// 更改登录时间 thisthisthis this .updateUser(user.getId(), user);// 持久化更改后的 user returnreturnreturn return user; } } returnreturnreturn return nullnullnull null ; } publicpublicpublic public User getUser(String name) { List users = getAllUser(); forforfor for (User user : users) { ififif if (user.getName().equals(name)) 16 returnreturnreturn return user; } returnreturnreturn return nullnullnull null ; } publicpublicpublic public voidvoidvoid void delUser(User user) { userDao.remove(user.getId()); } publicpublicpublic public User getUser(Long id) { returnreturnreturn return userDao.get(id); } publicpublicpublic public List getAllUser() { returnreturnreturn return userDao.list(); } publicpublicpublic public voidvoidvoid void saveUser(User user) { User u = thisthisthis this .getUser(user.getName()); ififif if (u != nullnullnull null ) throwthrowthrow throw newnewnew new java.lang.RuntimeException("当前用户名已经 被占用 !"); userDao.save(user); } publicpublicpublic public voidvoidvoid void updateUser(Long id, User user) { User u = thisthisthis this .getUser(user.getName()); ififif if (u != nullnullnull null &&!u.getId().equals(id)) throwthrowthrow throw newnewnew new java.lang.RuntimeException("当前用户名已经 被占用 !"); userDao.update(id, user); } } 从代码中可以看到,业务逻辑层中有一个 dao 属性,业务层的所有数据访问操作都是 通过调用 dao 来实现。 同 时, 业 务逻辑层的实现中还有很多其它与具体业务逻辑处理有关 的 代码,比如登录,检查用户名是否重复等。 视图及页面模板 视图及页面模板 视图及页面模板 视图及页面模板 对于大型的 Web 应用来说,如果要让程序员来自己设计页面,那将会是非常痛苦的事 情。实现开发中都会由专业 的页面设计 及制作人员 来负责完成 视图及页面 模板的制作 工作 (注意别忘了让他们把相关的脚本代码也加入模板中 )。 17 index.htmlindex.htmlindex.html index.html -首 页及 登录页 在用户管理系统中, 我 们首先需要一个系统首页及登录页面才能进入系统。 为 了简化 页 面的东西,我们可以把这两个页面合并成一个,取名为 index.html,内容如下: 用户信息管理
用户管理系统简介
这是一个非常简单的 EasyJWeb示例程序,模拟演示一个用户添加、 删除、修改、读 取 等应用,在进入演示之前请先登录系统。

用户名: 密码: #if($msg) ${msg} #end
在index.html 中,我们包含一个
表单,该表单的 action 值为 “?cmd=login”表示 我们将把这个表单提到当前应用的 login 方法处理;表单包含三个元素,一个名称为 name、 值为 $!name的文本框,一个名称为 password 的密码框以及一个提交按钮。最后,页面模板 中还包含一条简单的脚本标记 #if($msg) #end, 表 示如果存在 $msg, 则 输出 #if 及#end 之间 的 内容。 list.html list.html list.html list.html 用户 列表 页面 针对列出所有用户的需要, 我们需要一 个相应的展 示页面,这 个页面取名 为 list.html, 表示数据列表, list.html 的全部内容如下所示: 用户信息管理
用户信息管理
#foreach($info#foreach($info#foreach($info #foreach($info ininin in $list)$list)$list) $list) #end#end #end href="?cmd=preview&id=$!info.id"> href="?cmd=preview&id=$!info.id"> href="?cmd=preview&id=$!info.id"> 查看 href="?cmd=edit&id=$!info.id"> href="?cmd=edit&id=$!info.id"> href="?cmd=edit&id=$!info.id"> 修改 ');">');"> ');"> 删除 #end#end#end #end
说明: 这 是一个简单的添删改查示例, 数 据保存 在 内存中, Web 服务器重启后数据将丢失 !
ID 姓名 性别 邮件 出生日期 添加用户 退出登录
$!info.id$!info.id$!info.id $!info.id $!info.name$!info.name$!info.name $!info.name #if($!info.sex.equals("man"))#if($!info.sex.equals("man"))#if($!info.sex.equals("man")) #if($!info.sex.equals("man")) 男#else#else#else #else 女#end $!info.email$!info.email$!info.email $!info.email $!info.bornDate$!info.bornDate$!info.bornDate $!info.bornDate
同样是一个非常简单的 html 文件,除了一些简单的脚本标签以外,没有关于 java 的任 何东西或特殊的自定义标签。 在 这个页面中, 上 面是添加用户及退出登录的文字连接, 分 别 19 指向 ?cmd=add 及?cmd=logout, 表示点执行该应用中的 add 及logout 方法。 另外,注意黑 体 标注的部分, 该部分使用 #foreach($info in $list) #end 是一个表示循环的脚本语句, 其作用 是 循环 $list 中的各个对象, 并输出循环体中的内容。 在循环体中, 使 用 $info.id、$info.name 等 以“$”开头的语句来输出 User对 象 的 各 个 属 性 。 针对 “性别 ”属性的显示, 使 用了一个 #if($xx) #else #end 的条件语句来判断用户的性别,并显示正确的值;最后每一行都有一个 “查看 ”、 “修改 ”、“删除 ”按 钮 , 分别 连 接 到 “?cmd=preview&id=$!info.id”、“?cmd=edit&id=$!info.id”、 “?cmd=delete&id=$!info.id”等URL,表示要执行 perview、edit、delete 等方法,并传入 一 个id 参数。 preview.htmlpreview.htmlpreview.html preview.html -显 示用 户详情 的页 面 显示用户详情的页面是用来显示用户的各项信息, 该 页面没有任何录入项, preview.html 的全部文件内容如下: 用户信息查看
用户详细信息
20
姓名
性别 #if($sex.equals("man"))#if($sex.equals("man"))#if($sex.equals("man")) #if($sex.equals("man")) 男#else#else#else #else 女#end#end#end #end
邮件 $!email$!email$!email $!email
出生日期 $!bornDate
登录次数 $!loginTimes
上次登录时间 $!lastLoginTime
简介 $!HtmlUtil.addBr($!intro)
在页面中,使用 $!name、$!email 等类似的页面脚本标签来显示用户的各项信息。在显 示用户 简 介 的 时候 , 由 于 要把 输 入 的 回车 符 号 换 成
,因此 使 用 了 EasyJWeb 内置的 $HtmlUtil 工具中的 addBr 方法来实现把 “用户简介 ”intro 的信息显示到页面上。另外该页 面上有一个 “返回 ”按钮,点击可以进入到用户列表页面。 add.htmladd.htmladd.html add.html -添 加用 户的页 面 添加用户的页面是一个普通的用户信息录入表单, add.html 的全部内容如下: 用户信息添加
用户信息添加
21
姓名 $!{errors.name}
密码 $!{errors.password}
性别
邮件 $!{errors.email}
出生日期 $!{errors.bornDate}
简介
22
这个表单的 action 指向?cmd=save,表单使用 post 方式提交,表单的各项与 User域对象 的各个属性一一对应,如用户名 (姓名)这个文本框的 name 属性值为 name、email 这个文本 框的 name 属性值为 name。在每一个输入项的后面使用“$!errors.属性名”来输出验证错误 信息,比如“$!errors.name”、“$!errors.email”等。add.html 在可视化 html 编辑器在的效果 如图 3-11 所示。 图3-11 用户信息添加模板在 Macromedia Dreamweaver 中的显示效果 edit.htmledit.htmledit.html edit.html -修改用户的界面 该页面是用来编辑用户的信息,edit.html 文件的全部内容如下: 用户信息修改 23
用户信息修改
type="hidden"/>type="hidden"/> type="hidden"/> 24
姓名 $!{errors.name}
密码 $!{errors.password}
性别
邮件 $!{errors.email}
出生日期 $!{errors.bornDate}
简介
该页面的内容除了文件的 title 等信息跟 add.html 不一样以外,整个表单
的部分 跟add.html 中的基本相似。 使用 #parse #parse #parse #parse 或#include #include #include #include 来重 构 add.html add.html add.html add.html 及edit.htmledit.htmledit.html edit.html 我们仔细对照 add.html 与edit.html 的中的内容,发现大部份都是一样的,只有 两处区别 : 1、add.html 中元素的 action 为?cmd=save,而 edit.html 的为 ?cmd=update; 2、edit.html 文件中紧接 。 我们可以使用包含文件的形式,把两个文件中相同的部分抽取到一个文件中,然后在 add.html 及edit.html 文件包含这个文件,这样我们以后要修 改 User模型,增加或删除一个 属性,在调整界面的时候我们只需要修改包含文件中的内容即可。   form.htmlform.htmlform.html form.html 这里我们把共同部分的内容抽取到 form.html 文件中,其内容如下:
姓名 $!{errors.name}
密码 $!{errors.password} 25
性别
邮件 $!{errors.email}
出生日期 $!{errors.bornDate}
简介
 add.html 修改 add.html 文件, 把其中已经被抽取的部分删除, 使 用 # parse("/user/form.html")来代 替。修改后的 add.html 文件内容如下: 26 用户信息添加
用户信息添加
method="post">method="post"> method="post"> #parse("/user/form.html")#parse("/user/form.html")#parse("/user/form.html") #parse("/user/form.html")
  edit.htmledit.htmledit.html edit.html 同理,修改 edit.html 页面,把共同的部分使用 #parse来代替。修改后的 edit.html 内容 如下: 用户信息修改
用户信息修改
method="post">method="post"> method="post"> type="hidden"/>type="hidden"/> type="hidden"/> #parse("/user/form.html")#parse("/user/form.html")#parse("/user/form.html") #parse("/user/form.html")
这样我们就算完成了该应用的所有页面的 设计及脚本代码的 添加。本例中我 们只有一 个名为用户管理的应用程序,假设我们准备使用 user.ejf 的形式来访问应用,默认情况下我 们需要把这些模板文件都存放到 WEB-INF\views\user 目录下,如图 3-12 所示。 27 图3-12 模板文件在项目中的位置 ActionActionAction Action 完成了业务层的编写,下一步我们要做的就是写 Web 层的内容了。 Web 层需要一个控 制器, 这 个控制器在表示层及业务层之间打交道, 负 责把业务层传来的数据进行处理, 并 交 给业务层的组件进行处理。 UserActionUserActionUserAction UserAction 在EasyJWeb框架,由 EasyJWeb的ActionServlet 与用户写的 Action 一起扮演控制器 的 角色。基于模块 化的原 则,我 们把用 户管理 的所有 功能都 封装到 一个模 块 UserAction 中, 针对每一个功能点使用一个单独的方法来 实现。下面 是 UserAction 的全部代码,我们将会 在后面对每一个代码进行简单的解析: importimportimport import com.easyjf.container.annonation.Inject; importimportimport import com.easyjf.web.ActionContext; importimportimport import com.easyjf.web.Module; importimportimport import com.easyjf.web.WebForm; importimportimport import com.easyjf.web.core.AbstractPageCmdAction; importimportimport import easyjweb.demo.user.domain.User; importimportimport import easyjweb.demo.user.service.UserService; publicpublicpublic public classclassclass class UserAction extendsextendsextends extends AbstractPageCmdAction { privateprivateprivate private UserService service; publicpublicpublic public voidvoidvoid void setService(UserService service) { thisthisthis this .service = service; } /** * 在执行所有的方 法前先 执行的 方法, 可以用 来实现 简单的 权限验 证等 */ @Override publicpublicpublic public Object doBefore(WebForm form, Module module) { 28 String cmd = (String) form.get("cmd"); ififif if (cmd != nullnullnull null &&!"login".equals(cmd) &&!"init".equals(cmd)) { User user = (User) ActionContext.getContext().getSession() .getAttribute("user"); ififif if (user == nullnullnull null ){ form.addResult("msg","请先登录系统 !"); returnreturnreturn return page("index"); } } returnreturnreturn return nullnullnull null ; } /** * 登录 * *@param@param@param @param form */ publicpublicpublic public voidvoidvoid void login(WebForm form) { String name = (String) form.get("name"); String password = (String) form.get("password"); User user = service.login(name, password); ififif if (user == nullnullnull null ){ form.addResult("msg","用户名或密码不 正确, 请重新 输入 !"); page("index"); } elseelseelse else { ActionContext.getContext().getSession().setAttribute("user", user); forward("list"); } } /** * 修改用户 * *@param@param@param @param form */ publicpublicpublic public voidvoidvoid void edit(WebForm form) { String id = (String) form.get("id"); User user = thisthisthis this .service.getUser(newnewnew new Long(id)); form.addPo(user); } 29 /** * 查看用户详情 * *@param@param@param @param form */ publicpublicpublic public voidvoidvoid void preview(WebForm form) { String id = (String) form.get("id"); User user = thisthisthis this .service.getUser(newnewnew new Long(id)); form.addPo(user); } /** * 保存新增用户 * *@param@param@param @param form */ publicpublicpublic public voidvoidvoid void save(WebForm form) { User user = form.toPo(User.classclassclass class ); ififif if (hasErrors()) { page("add"); returnreturnreturn return ; } service.saveUser(user); forward("list"); } /** * 修改用户 * *@param@param@param @param form */ publicpublicpublic public voidvoidvoid void update(WebForm form) { Long id = newnewnew new Long((String) form.get("id")); User user = form.toPo(User.classclassclass class ); ififif if (hasErrors()) { page("edit"); returnreturnreturn return ; } service.updateUser(id, user); forward("list"); } /** * 删除用户 30 * *@param@param@param @param form */ publicpublicpublic public voidvoidvoid void delete(WebForm form) { String id = (String) form.get("id"); User user = thisthisthis this .service.getUser(newnewnew new Long(id)); service.delUser(user); go("list"); } /** * 显示用户列表 * *@param@param@param @param form */ publicpublicpublic public voidvoidvoid void list(WebForm form) { form.addResult("list", service.getAllUser()); } /** * 注销用户 */ publicpublicpublic public voidvoidvoid void logout() { ActionContext.getContext().getSession().removeAttribute("user"); page("index"); } } UserAction UserAction UserAction UserAction 代码 解析 UserAction 实现了前面需求中的各个功能, 包 括 “登录验证 ”、“添加用户 ”、“修改用 户”、 “删除用户 ”、“退出 ”等功能。下面我们对每一个方法逐一分析: 1、在 最 前 面 的 setService(UserService service)提供 给 IOC 容器 使 用 设 值 方 法 注 入 UserService 对象的接口。 2、doBefore 方法是 EasyJWeb的AbstractCmdAction 中设置的一个钩子拦截方法, 该 方 法会在执行其它所有方法之 前执行。 doBefore 方法如果返回 null 则不会改变程序的执行顺 序,如果返回一个 Page 对象,则会截断程序的执行流程,直接把 结果返回 给 EasyJWeb 的 核心处理器进行处理。在本 例中,我们 判 断 cmd 参数的值 (即当前命令 )如果不是 “login”、 “init”或null 三个中的一个, 则要通过 session 判断用户是否已经登录, 若没有登录则使 用 return page("index");语句直接返回 index 视图模板, 这个模板也就是登录模板。 在该方法中 , 我们通过 ActionContext.getContext().getSession()可以在方法中得到 HttpSession 对 象 , 并通 过 检测该对象是否包含名为 user 的属性来判断是否已经是登录用户。 3、login 用来处理登录,该方法带一个参数 WebForm,通过这个 form 参数可以直接访 问页面表单中传来属性信息。该方法使 用 WebForm 的get 方法来得到前台页面中的表单各 31 项信息,并调用 UserSerivce 的login 方法来进行登录,如果登录失败,则使用 WebForm 的 addResult 方法来添加一个名为 msg的视图结果,用于前台提示信息;如果登录成功,则使 用ActionContext.getContext().getSession()的setAttribute 方法把 用户 对 象保 存 到 session 中, 并把程序导向 list 方法继续执行。 4、edit 方法用来编辑用户, 该 方法通过前台传来的 id 参数值, 使用 UserService 来得 到 一个 User对象,并使用 WebForm 的addPo 方法,直接把这个 User对象添加到视图结果集 中,便于用户访问。 5、preview 方法用来显示用户详细信息,其代码与 edit 方法一模一样。 6、save方法用来保存新增的用户信息,注意这里我们使用 WebForm 的toPo 方法可以 直接把前台表单中的数据传进一个对象中 。 toPo 方法的参数如果是类名,则会先创建该类 的一个实例,然后再把表单中的各项值保存到该对象对应的各个属性中。在执行 完 toPo 方 法后,我们可以立即使用 hasErrors方法来判断是否存在数据校验错误,如果出错,则继续 返回添加用户页面,让用户重新录入信息。如果没有校验错误,则直接调 用 UserService 的 saveUser 方法来保存用户信息,然后使用 forward 方法跳转到 list 方法继续执行。 7、update 方法用来修改用户信息。 该 方法首先根据前台的 id 通过 UserService 的getUser 方法得到一个完整的用户信 息,再使 用 WebForm 的toPo 方法把页面表单中的信息保 存 到 user 中。 注 意该方法除了跟一个 user 以外, 还 有另外一个参数 true, 表示如果验证出现错 误 的话将要 回 滚所 有 对 user 数据的修 改 。 与 save 方法一样 , 这里 执行 完 toPo 后立即使 用 hasErrors方法来查看是否存在验证错误,如果出错 则返回到信息录入 界面重新录入, 否则 继续往下执行则,使用 UserService 的updateUser 方法来把修改结果持久化起来,并返回到 列表 list 方法继续执行。 8、delete 方法用来根据 id 删除用户信息,该方法的实现比较简单。执行完删除操作后 直接使用 go 方法发起一个新的请求到 list 方法执行,也即回到用户列表页面。 9、list 方法 用来 显 示 用 户 列 表 信息 , 只 包 含 一 句代 码 , 就 是 通 过 调 UserService 的 getAllUser 方法得到一个用户列表 List,然后把这个结果添加到视图结果集中,名称 为list。 10、logout 方法 用 来 执 行 “退出 登 录 ”的操 作 , 该 方 法 通 过 ActionContext 来调 用 HttpSession 中的 removeAttribute 方法, 删除在登录成功时添加到 session 中的 user 属性, 实 现用户注销,然后返回到首页(登录页) 。 综合到一起 综合到一起 综合到一起 综合到一起 到现在为止, 我 们用户系统中的各部分可以说都已经实现。 然 而各个部分都是相互独 立 的, UserAction 中的 service是一个接口,何 时给他 赋值这 个我们 还不知 道。同 样的道 理, 在UserService 的实现类 UserServiceImpl 中用来进行数据访问的 userDao 属性同样也只是接 口, 我们还没有在代码中明确的告诉他使用哪一个实现。 另 外, UserAction 是如何跟页面 模 板结 合起来的?他是如何知道何时使用index.html,何 时 使 用 add.html 或list.html 的? UserAction 是如何得到一 个UserService 实例,UserSeriveImpl 又是如何得到一个 UserDao 实 例的?总的来说, 我 们要把整个应用中 DAO 层、 Service层及表示层的东西结合起来, 本 小 节将简单讲述这些内容。 32 Action Action Action Action 与页 面结 合 由于 EasyJWeb 会自动通过包来 找到系 统中 的 Action,由此我们知道 我们使 用 user.ejf 可以访问到 UserAction 这个类。根据惯例原则, EasyJWeb在执行 UserAction 中各方法的 时 候,默认情况(没有调用任何页面跳转的方法如 forward、page、go 等)下会自动到 WEB- INF\views\user 这个目录中去查找与方法名相对应的各个页面,比如 “?cmd=add”会直把 调 用导入 add.html 这个视图页面,“?cmd=preview”会使用 preview.html 来作为视图模板等等 。 因此, 我 们只需要把前面设计的页面模板存放到 WEB-INF\views\user 目录, 这样 UserAction 在执行的时候,就能找到正确的页面模板来输出用户信息了。 因此,我们不需要像 Struts、JSF 等传统 MVC 框架那样需要很多烦琐的配置文件来说 明哪一个逻辑名称与哪一个目录中的哪一个文件相对应, 更 不用去定义很多剪不断拟还乱 的 页面导向及跳转, EasyJWeb能根据惯例能判断出模板应该在哪儿。 当然, 如 果你已经非常习惯使用配置文件了, 或 者是你的程序必须要通过配置文件来 实 现三天两天要改一下页面物理路径这样的 特殊需求,那么 在 EasyJWeb 中也可以像 Struts、 JSF 等框架一样,在专门的 EasyJWeb配置文件中配置页面逻辑名称与实现文件名的对应关 系,我们将在后面的相关章节作简单讲解。 从哪 儿得 到业务 层的 对象 我们知道, 要 让整个程序能跑起来, 必 须确保 UserAction 中的 service有一个具体的值 , 同样也需要 UserServiceImpl 中的 userDao 有一个具体的值,否则一旦 这个程序跑 起来,肯 定就会到处都拖出 NullPointer 异常。 我们需要明确地使用 new 方法来给这两个类中所需要属性赋值吗? 由于我们是针对接 口编程的, 所以 UserAction 不用知道 UserServiceImpl 的存在; 同 样的道理, UserServiceImpl 不用知道 UserDaoImpl 的存在,因此不可能在 UserSerivceImpl 中出现 UserDaoImpl。 在IOC 容器没有出来之前,我们也许只有老老实实地使用 new 或其它工厂方法来构造 出UserSerivce 及UserDao 的实例, 并赋值给相应的属性。但有了 IOC 容器,我们则把这 些 工作全部交给 IOC 容器来处理, IOC 容器会知道类与类之间的依赖关系,并会 想办法给对 象依赖的属性中注入具体的值。 对于初学者来说,关于 IOC 容器的具体内容,我们将在本书的七章作讲解。对于学习 过Spring 等IOC 容器使用的读者来说, 你 只要知道 EasyJWeb除了是一个 Web MVC 框架 以 外, EasyJWeb中还包含了一个 IOC 容器实现,实现了构造子注入及设值方法注入两种依 赖 注入方式。在实际应用中, EasyJWeb的IOC 容器更多的时候是作为一个超级容器使用, 他 里面可以容纳 Spring IOC 容器、 Guice IOC 容器、 甚至 EJB 容器等, 把 这些容器作为他的 子 容器使用,为 EasyJWeb应用中的 Action 或相关业务对 象提供服务。 111 1 、依赖注入 在基于 MVC 框架的应用程序中, Controller 处于整个应用最顶层,一般情况下他需要 业务逻辑层的业务组件才能执行具体的操作。 对于 EasyJWeb来说, Controller 层主要就是 前 端应用模块 Module 或Action 这一层。在 EasyJWeb的IOC 容器中, 除了特殊情况下需要 使 用配置文件配置业务组件或 Action 以外, 更 多的时候 Action 这一层我们都不使用配置信息 。 要注入 Action 所依赖的业务组件, 比如 UserAction 中的 service属性, 则只需要该属性声 明 的地方, 加 上一个 @Inject 标签 即可。 因 此, 前面的 UserAction 中的 service声明简单改成 下 面的形式: 33 import com.easyjf.container.annonation.Inject; publicpublicpublic public classclassclass class UserAction extendsextendsextends extends AbstractPageCmdAction { @Inject privateprivateprivate private UserService service; publicpublicpublic public voidvoidvoid void setService(UserService service) { thisthisthis this .service = service; } … } 这样 EasyJWeb 就能保证在 执 行 UserAction 的时候,会 自动 给 service 注入适当的 值, 其中的 public 的setService方法是设值方法注入的接口,这是必须的。 同样的道理, UserServiceImpl 类中的 userDao 也是可以通过 IOC 容器进行注入,直接 在UserServiceImpl 的userDao 属性声明处加上一个 @Inject 标签即可。 222 2 、业务组件声明 那么 EasyJWeb又是如何知道我们要注入的 UserServiceImpl 及UserDaoImpl 这两个类 的 实例呢?换句话说也就是从 哪儿找到注 入到目标对 象的这些依 赖对象?这 里我们不用 讲具 体的细节,你 只需 要知道 通过 在 UserServiceImpl 及UserDaoImpl 中添加一 个 EasyJWeb 的 @Bean注解标签, 这样 EasyJWeb就会把这两个类作为一个业务组件加载到其 IOC 容器中 , 供其它需要的组件或 Action 使用。添加了 @Bean标签的 UserServiceImpl 如下所示: @Bean public class UserServiceImpl implements UserService { private UserDao userDao; public void setUserDao(UserDao userDao) { this.userDao = userDao; } … } 添加了 @Bean标签的 UserDaoImpl 如下所示: @Bean(inject="none") public class UserDaoImpl implements UserDao { private List users = new java.util.ArrayList(); … } 这里注意两个的区别,只要加了 @Bean标签,默认情况下, EasyJWeb会认为你需要 他 帮你注入该类中的所有字段 属性,因此 ,我们可以 不用 在 UserServiceImpl 的userDao 字段 声明前使用 @Inject 标签, IOC 容器就会自动注入 userDao。 而 对于 UserDaoImpl 类来说, 由 于他的 users这个字段是不需要从外部注入的,因此我们需要把这个 @Bean标签的 inject 属 性设置成 “none”,表示不使用自动注入。如 果不 把 inject 设置成 “none”,则需要在 users 字段声明前加一个标签 @ InjectDisable 来明确告知 IOC 容器:“这个字段不用你帮我注入, 我自己来处理 ”。 34 修改web.xmlweb.xmlweb.xml web.xml 通过使用 @Inject 标签及 @Bean标签,我们可以实现了业务组件及 Action 的依赖注入, 业务组件初始化等, 这 样整个程序就被连接起来了。 下 面别忘了修改 web.xml 文件, 告 诉 他 把.ejf 扩展名的请求交给 EasyJWeb 处理,并通过添加 defaultActionPackages 参数告诉他到 easyjweb.demo 包及其所有子包中查询业务组件及 Action。配置代码摘录如下: defaultActionPackages easyjweb.demo easyjf com.easyjf.web.ActionServlet 1 easyjf *.ejf 详情请参考第二章第 2节对 web.xml 配置文件讲解的部分内容。 编译 并运 行程序 最后是进行程序的编译及发布,如果使 用 Eclipse 等工具,配置好 web 项目开发插件, 则可以直接编译及发布。如果你是使 用 easyjweb project 来生成项目骨架的,那么你可以切 换到命令行在该应用的 bin 目录下, 使用 easyjweb war来生成 war包, 再把这个 war包拷 到 Tomcat 的webapps 目录下 执 行, 这 里 假 设 war 包名为 simplecrud.war,在浏 览 器中 输 入 http://localhost:8080/simplecrud/user.ejf 即可进入到应用。如图 3-13 到3-15 所示: 图3-13 simplecrud 首页登录运行效果 35 图3-14 simplecrud 用户列表运行效果 图3-15 simplecrud 编辑用户信息运行效果 添加 验证 特性 通过执行前面打包发布的程序,可以发现我们满足了用户前面需 求 80%的功能 ,但是还 差一点就是数据有效性的验证功能还没有实现。 说 到验证首先想到的是在页面上写 javascript 脚本,或者是像 Struts那样写一堆配置文件来解决,但在 EasyJWeb中推荐的是另外一种更 加简单的方法。 EasyJWeb提供了比较灵活的验证支持, 在 域模型对象中可以使用 @Validator 注解来标注验证规则。因此,我们可以在 User对象上直接使用注解标签来实现数据验证需 求,针对需求中的前三条验证规则,添加上 @Validator 标签后的 User.java 内容如下所示: @FormPO(disInject = "id,loginTimes,lastLoginTime") publicpublicpublic public classclassclass class User { @Field(name = "姓名 ", validator = @Validator(name = "string", value = "trim;blank;min:5;max:20", required = truetruetrue true )) privateprivateprivate private String name; 36 @Field(name = "密码 ", validator = @Validator(name = "string", value = "trim;blank;min:5;max:20", required = truetruetrue true )) privateprivateprivate private String password; @Field(name = "电子邮件 ", validator = @Validator(name = "email", required = truetruetrue true )) privateprivateprivate private String email; … } 上面的代码中, @FormPO 中的 disInject 属性值表示 User类中不允许直接通过 toPo 注 入的属性, 这 样可以使 User类的 id、loginTimes、lastLoginTime 等三个属性变成了只读, toPo 方法会忽略处理这三个属性。另外 @Field 放在属性的定义之前,其中的 validator 用来定义 验证器, 本 例中使用了 string 验证器来验证字符的长度, 使用 email 验证器来验证邮件格式 , 关于验证器的使用我们将在第八章进行讲解。 另外, 对 于确保用户名唯一的数据验证需求由于涉及到具体的业务逻辑, 我 们不能简 单 的使用 @Validator 来实现, 因 此需要在 Action 中的 save及update 方法中添加的代码来判断 , 加入了用户唯一性检查的 save及update 方法代码如下: publicpublicpublic public voidvoidvoid void save(WebForm form) { User user = form.toPo(User.classclassclass class ); ififif if (service.getUser(user.getName())!=nullnullnull null ) { thisthisthis this .addError("name","用户名 "+user.getName()+"已经存在! "); } ififif if (hasErrors()) { page("add"); returnreturnreturn return ; } service.saveUser(user); forward("list"); } publicpublicpublic public voidvoidvoid void update(WebForm form) { Long id = newnewnew new Long((String) form.get("id")); String name=(String)form.get("name"); User u2=thisthisthis this .service.getUser(name); User user = thisthisthis this .service.getUser(id); ififif if (u2!=nullnullnull null &&!u2.getId().equals(id)) { thisthisthis this .addError("name","用户名 "+name+"已经被其它的用 户占用 ! "); } form.toPo(user,truetruetrue true ); ififif if (hasErrors()) { 37 page("edit"); returnreturnreturn return ; } service.updateUser(id, user); forward("list"); } 在代码中,使 用 this.addError 可以往应用程序 中添加 验证错 误信息 ,这些 信息 跟 toPo 方法产生的验证错误信息一样可以在视图模板中使用 $!{errors.name}的形式来得到。 再编译、 打 包并发布程序, 重 新运行一下, 在 添加或修改用户的时候输入一些非法的 数 据,你会发现前面需求中的数据验证需求在这里已经完全实现,如图 3-16 所示。 图3-16 添加了验证功能后的运行效果 如果到这里一切都顺利, 那么恭喜你,你的第一个较为完整的基于 EasyJWeb框架开 发 的Java Web 应用程序已经成功完成。 当然, 你也可以通过 EasyJWeb的官方网站下载已经打包成 war的完整示例, 下载地 址 为: ftp://ftp1.easyjf.com/easyjweb/easyjweb-1.0-m3/simple.war。 UserDao UserDao UserDao UserDao 基于数据库的实 现 基于数据库的实 现 基于数据库的实 现 基于数据库的实 现 当然,前面的 UserDaoImpl 由于只是把用户信息保存在内容中,重 启 Web 服务器后这 些信息就会消失。为了实现真正的持久化 ,我们需要另外一 个能操作数据库 的 DAO 实现, 下面是一个通过 jdbc 来操作数据库的 UserDao 实现, UserDaoJdbcImpl 的全部代码如下: packagepackagepackage package easyjweb.demo.user.dao.impl; importimportimport import java.util.Date; importimportimport import java.util.List; importimportimport import org.apache.commons.dbcp.BasicDataSource; importimportimport import com.easyjf.container.annonation.Bean; importimportimport import easyjweb.demo.user.dao.UserDao; 38 importimportimport import easyjweb.demo.user.domain.User; /** * UserDao的另一个实现, 该实现 用来读 取数据 库 * *@author@author@author @author 大峡 * */ @Bean(inject = "none") publicpublicpublic public classclassclass class UserDaoJdbcImpl implementsimplementsimplements implements UserDao { privateprivateprivate private javax.sql.DataSource dataSource; publicpublicpublic public UserDaoJdbcImpl() { java.util.Properties p = newnewnew new java.util.Properties(); trytrytry try { p.load(thisthisthis this .getClass().getResourceAsStream("/db.properties")); String driver = p.getProperty("database.driverClassName"); String url = p.getProperty("database.url"); String userName = p.getProperty("database.username"); String password = p.getProperty("database.password"); BasicDataSource bdds = newnewnew new BasicDataSource(); bdds.setDriverClassName(driver); bdds.setUrl(url); bdds.setUsername(userName); bdds.setPassword(password); thisthisthis this .dataSource = bdds; } catchcatchcatch catch (java.io.IOException e) { } } publicpublicpublic public UserDaoJdbcImpl(javax.sql.DataSource dataSource) { thisthisthis this .dataSource = dataSource; } publicpublicpublic public voidvoidvoid void setDataSource(javax.sql.DataSource dataSource) { thisthisthis this .dataSource = dataSource; } publicpublicpublic public User get(finalfinalfinal final Long id) { User user = (User) newnewnew new SqlExecute() { Object doExecute() throwsthrowsthrows throws java.sql.SQLException { stat = conn.prepareStatement("select * from User where id=?"); 39 stat.setLong(1, id); rs = stat.executeQuery(); ififif if (rs.next()) { returnreturnreturn return rs2user(rs); } elseelseelse else returnreturnreturn return nullnullnull null ; } }.execute(); returnreturnreturn return user; } publicpublicpublic public List list() { java.util.List users = (List) newnewnew new SqlExecute() { Object doExecute() throwsthrowsthrows throws java.sql.SQLException { stat = conn.prepareStatement("select * from User"); rs = stat.executeQuery(); java.util.List list = newnewnew new java.util.ArrayList(); whilewhilewhile while (rs.next()) { list.add(rs2user(rs)); } returnreturnreturn return list; } }.execute(); returnreturnreturn return users; } publicpublicpublic public voidvoidvoid void remove(Long id) { newnewnew new SqlExecute() { Object doExecute() throwsthrowsthrows throws java.sql.SQLException { stat = conn.prepareStatement("delete * from User where id=?"); returnreturnreturn return stat.executeUpdate(); } }.execute(); } publicpublicpublic public voidvoidvoid void save(finalfinalfinal final User user) { newnewnew new SqlExecute() { Object doExecute() throwsthrowsthrows throws java.sql.SQLException { stat = conn .prepareStatement("insert into User(name,password,sex,email,bornDate,loginTimes,lastLoginTime,intro, id) values(?,?,?,?,?,?,?,?,?)"); 40 List list = list(); user.setId(newnewnew new Long(list == nullnullnull null ? 1 : list.size() + 1)); stat.setString(1, user.getName()); stat.setString(2, user.getPassword()); stat.setString(3, user.getSex()); stat.setString(4, user.getEmail()); stat.setDate(5, user.getBornDate() == nullnullnull null ? nullnullnull null : newnewnew new java.sql.Date(user.getBornDate().getTime())); stat.setInt(6, user.getLoginTimes()); stat.setDate(7, user.getLastLoginTime() == nullnullnull null ? nullnullnull null : newnewnew new java.sql.Date(user.getLastLoginTime().getTime())); stat.setString(8, user.getIntro()); stat.setLong(9, user.getId()); returnreturnreturn return stat.executeUpdate(); } }.execute(); } publicpublicpublic public voidvoidvoid void update(finalfinalfinal final Long id, finalfinalfinal final User user) { newnewnew new SqlExecute() { Object doExecute() throwsthrowsthrows throws java.sql.SQLException { stat = conn .prepareStatement("update User set name=?,password=?,sex=?,email=?,bornDate=?,loginTimes=?,lastLoginTime =?,intro=? where id=?"); stat.setString(1, user.getName()); stat.setString(2, user.getPassword()); stat.setString(3, user.getSex()); stat.setString(4, user.getEmail()); stat.setDate(5, user.getBornDate() == nullnullnull null ? nullnullnull null : newnewnew new java.sql.Date(user.getBornDate().getTime())); stat.setInt(6, user.getLoginTimes()); stat.setDate(7, user.getLastLoginTime() == nullnullnull null ? nullnullnull null : newnewnew new java.sql.Date(user.getLastLoginTime().getTime())); stat.setString(8, user.getIntro()); stat.setLong(9, user.getId()); returnreturnreturn return stat.executeUpdate(); } }.execute(); 41 } privateprivateprivate private User rs2user(java.sql.ResultSet rs) throwsthrowsthrows throws java.sql.SQLException { Long id = rs.getLong("id"); String name = rs.getString("name"); String password = rs.getString("password"); String sex = rs.getString("sex"); String email = rs.getString("email"); Date bornDate = rs.getDate("bornDate"); Integer loginTimes = rs.getInt("loginTimes"); Date lastLoginTime = rs.getDate("lastLoginTime"); String intro = rs.getString("intro"); User u = newnewnew new User(name, email, bornDate); u.setId(id); u.setPassword(password); u.setLoginTimes(loginTimes); u.setLastLoginTime(lastLoginTime); u.setSex(sex); u.setIntro(intro); returnreturnreturn return u; } abstractabstractabstract abstract classclassclass class SqlExecute { protectedprotectedprotected protected java.sql.Connection conn = nullnullnull null ; protectedprotectedprotected protected java.sql.PreparedStatement stat = nullnullnull null ; protectedprotectedprotected protected java.sql.ResultSet rs = nullnullnull null ; Object execute() { trytrytry try { conn = dataSource.getConnection(); returnreturnreturn return doExecute(); } catchcatchcatch catch (java.sql.SQLException e) { e.printStackTrace(); trytrytry try { ififif if (rs != nullnullnull null ) rs.close(); ififif if (stat != nullnullnull null ) stat.close(); } catchcatchcatch catch (java.sql.SQLException e2) { throwthrowthrow throw newnewnew new java.lang.RuntimeException(e2.getMessage()); } } finallyfinallyfinally finally { 42 trytrytry try { ififif if (conn != nullnullnull null &&!conn.isClosed()) conn.close(); } catchcatchcatch catch (java.sql.SQLException e2) { throwthrowthrow throw newnewnew new java.lang.RuntimeException(e2.getMessage()); } } returnreturnreturn return nullnullnull null ; } abstractabstractabstract abstract Object doExecute() throwsthrowsthrows throws java.sql.SQLException; } } 由于使用到数据库,要求我们先创建一个数据库,并在数据库中创建一个名 为 User的 表,并加入与 User类中各个属性对应的各字段,图 3-17 是My Sql 中User表的定义。 图3-17 My Sql 中的 User表结构图 UserDaoJdbcImpl 在构造函数中通过一个名为 db.properties 的属性文件来加载数据库配 置信息, db.properties 的文件内容需要根据你的实际数据库环境进行修改,其大致如下: database.driverClassName = org.gjt.mm.mysql.Driver database.username= root database.password= 123 database.url= jdbc:mysql://localhost:3306/easyjweb- demo?useUnicode=true&characterEncoding=gbk&autoReconnect=true UserDaoJdbcImpl 默认 使 用 的 是 Apache 的dbcp 来管 理数据源,因此我们还需要把 common-dbcp-xx.jar、common-pools-xx.jar 以及数 据 库的 驱 动 如 mysql-connector-java-xx.jar 等库文件加载到 classpath(或WEB-INF\lib目录 )里面。 最后把之前 UserDaoImpl 类中前面的 @Bean标签删除掉, 这样 EasyJWeb就不会初始 化 UserDaoImpl,而会初始化带 @Bean的UserDaoJdbcImpl。重新编译、打包及发布应 用,你 会惊喜的发现我们的用户管理系统已经能把用户信息保存到数据库了。 当然, UserDaoJdbcImpl 是直接通过 jdbc 传递 sql 语句来实现 User对象的持久化的, 在 ORM 系统已经比较成熟的今天,这种办法虽然直接,太实现起来确实需要太多繁琐的细节 43 需要处理,大多数时候肯定不能成为企业级 Java应用开发中的首选方案,因此在实际应用 中可以使用某一种 ORM 框架 (如Hibenate、iBatis 或EasyDBO 等)来写一个 UserDao 的实现 , 这样会省很多事。 面向接口编程的原则一个好处就我们要更还系统中的某一个部件, 而 其它的部分的代 码 都不用任何改变,这样大大提高的系统中各个组件的灵活性、可维护及可扩展性。 小结 小结 小结 小结 本章通过一个教为完整实例, 没有使用 EasyJWeb中内置的其它代码生成工具, 从零 开 始一步一步讲解如何实现一个简单的用户管理系统,演示 了 Java企业级应用程序设计及开 发的流程。 同 时通过对示例中代码的讲解, 让 我们对使用 EasyJWeb开发 Java Web 应用有 了 一定的认识,并对 EasyJWeb在整个 JavaEE 应用中的位置有了一个较为清晰的认识。 另外, 通 过示例我们知道 EasyJWeb除了 MVC 框架实现,EasyJWeb中还包含了一个 IOC 容 器 实 现 , 可以 通 过 @Inject、@Bean等注解标签来实现对象依赖关系管理、 注 入等, EasyJWeb 还提供了对数据验证提供了丰富的支持。
还剩44页未读

继续阅读

下载pdf到电脑,查找使用更方便

pdf的实际排版效果,会与网站的显示效果略有不同!!

需要 6 金币 [ 分享pdf获得金币 ] 0 人已下载

下载pdf