读书人

Nutz+ExtJS示范教程后台Service实

发布时间: 2012-09-05 15:19:35 作者: rapoo

Nutz+ExtJS示例教程——后台Service实现

?

?

后台的结构图如下:

?

Nutz+ExtJS示范教程——后台Service实现

?

这里是模仿了SSH的组织方式,因为毕竟大部分是学SSH过来的(ME也是其中之一),变化太大可能会有理解上的困难。

?

这里的Dao层被去掉了,因为Nutz本身提供的NutzDao就提供了基本的增删改查操作,因此这层可以去掉了,直接并入到Service层中。

?

接下来,先写model层,就是对于数据库表的JavaBean。

详细步骤请参照Nutz?的文档Dao手册这部分:http://code.google.com/p/nutz/wiki/dao_hello

?

以User举例,其他模块类似

?

User类:

?

package org.nutz.demo.model;import java.util.List;import org.nutz.dao.entity.annotation.Column;import org.nutz.dao.entity.annotation.Many;import org.nutz.dao.entity.annotation.Table;/** * 用户。 *  * @author pangwu86@gmail.com *  */@Table("t_user")public class User extends Identity {@Column()private String userName;@Column()private String password;@Column()private String userType;@Many(target = ContactType.class, field = "userId")private List<ContactType> contactTypes;@Many(target = Contact.class, field = "userId")private List<Contact> contacts;@Many(target = Blog.class, field = "userId")private List<Blog> blogs;//  这里省略了get与set}

?

要注意的是,不要忘了加Nutz的注释,同时如果字段与表中列名称有出入的话,要写入@Column("表列名")中,替换掉默认值。

?

下面开始写Service层共通的类,所有的Service都要继承这个基类,就可以实现增删改查的操作了。

?

这里对于增删改三项(查询操作的返回值就是查询的结果集,没有封装的必要)操作的返回值,做了一个简单的封装,其中包含了一部分业务信息,用一个枚举类型代替默认的返回值。

?

DbOperationResultEnum :

package org.nutz.demo.util.database;/** * 封装了各种数据库操作结果。 *  * @author pangwu86@gmail.com *  */public enum DbOperationResultEnum {OPERATION_SUCCESS(true, "操作成功。"),OPERATION_FAILURE(false, "操作失败。"),INSERT_SUCCESS(true, "插入成功。"),INSERT_FAILURE(false, "插入失败。"),UPDATE_SUCCESS(true, "更新成功。"),UPDATE_FAILURE(false, "更新失败。"),DELETE_SUCCESS(true, "删除成功。"),DELETE_FAILURE(false, "删除失败,数据可能被引用,请先删引用关系。"),CLEAR_SUCCESS(true, "批量删除成功。"),CLEAR_FAILURE(false, "批量删除失败,数据可能被引用,请先删引用关系。");private boolean success;private String msg;private DbOperationResultEnum(boolean success, String msg) {this.success = success;this.msg = msg;}public boolean isSuccess() {return success;}public String getMsg() {return msg;}}
?

BaseService:

package org.nutz.demo.service;import java.util.List;import org.nutz.dao.Chain;import org.nutz.dao.Condition;import org.nutz.dao.QueryResult;import org.nutz.dao.sql.Sql;import org.nutz.demo.util.database.DbOperationResultEnum;/** * CRUD基本操作。<br> * 基于泛型类。 *  * @author pangwu86@gmail.com *  * @param <T> *            实体类类型 */public interface BaseService<T> {/** * 从配置SQL文件中取得SQL文。 *  * @param key * @return */public Sql createSql(String key);/** * 直接执行一组SQL语句。 *  * @param sqls * @return */public boolean execute(Sql... sqls);/** * 通用查询。(无分页) *  * @param cdn * @return */public List<T> query(Condition cdn);/** * 通用查询。(带分页信息) *  * @param cdn * @param pageNumber * @param pageSize * @return */public QueryResult query(Condition cdn, int pageNumber, int pageSize);/** * 通用获取,对象中引用的对象。(根据正则匹配) *  * @param obj * @param regex * @return */public T fetchLinks(T obj, String regex);/** * 通用获取。(根据条件) *  * @param cdn * @return */public T fetch(Condition cdn);/** * 通用获取。(根据id) *  * @param id * @return */public T fetch(long id);/** * 通用获取。(根据name) *  * @param name * @return */public T fetch(String name);/** * 通用删除。(根据实体) *  * @param entity * @return */public DbOperationResultEnum delete(T entity);/** * 通用插入。(根据实体) *  * @param entity * @return */public DbOperationResultEnum insert(T entity);/** * 通用更新。(根据条件) *  * @param entity * @return */public DbOperationResultEnum update(Condition cnd, Chain chain);/** * 通用更新。(根据实体) *  * @param entity * @return */public DbOperationResultEnum update(T entity);/** * 通用批量删除。(删除全部) *  * @return */public DbOperationResultEnum clear();/** * 通用批量删除。(根据条件删除) *  * @param cdn * @return */public DbOperationResultEnum clear(Condition cdn);/** * 返回该Service使用的实体类类型。 *  * @return */public Class<T> getEntryClz();}

其中的方法可以根据你的需求再自行添加。

?

?

这里写到后来才发现,BaseService这个基类中的功能与Nutz中org.nutz.service?包下的几个类,EntityService,IdEntityService,NameEntityService提供的功能相似

?

大家可以根据情况直接使用Nutz提供的,或作为参考,根据自身情况写出更符合自己使用习惯的共通类,来进行复用。

?

?

下面是BaseService的实现类:

package org.nutz.demo.service.impl;import java.util.List;import org.nutz.dao.Chain;import org.nutz.dao.Condition;import org.nutz.dao.Dao;import org.nutz.dao.QueryResult;import org.nutz.dao.impl.NutDao;import org.nutz.dao.pager.Pager;import org.nutz.dao.sql.Sql;import org.nutz.demo.exception.BizException;import org.nutz.demo.service.BaseService;import org.nutz.demo.util.DaoUtil;import org.nutz.demo.util.database.DSConfig;import org.nutz.demo.util.database.DbOperationResultEnum;import org.nutz.lang.Mirror;import org.nutz.log.Log;import org.nutz.log.Logs;/** * 通用操作 实现。<br> *  * @author pangwu86@gmail.com *  */public abstract class BaseServiceImpl<T> implements BaseService<T> {protected Log logger = Logs.getLog(getClass());private Mirror<T> mirror;@SuppressWarnings("unchecked")public BaseServiceImpl() {// 尝试获得泛型的类型try {Class<T> entryClass = (Class<T>) Mirror.getTypeParam(getClass(), 0);mirror = Mirror.me(entryClass);if (logger.isDebugEnabled())logger.debugf("获得泛型的实际类型: %s", entryClass.getName());} catch (Throwable e) {if (logger.isWarnEnabled())logger.warn("!!!无法获得泛型类型!", e);throw new RuntimeException(e);}}/** * 方便的提供上层Dao。 *  * @return */public NutDao getDao() {return DaoUtil.getDao();}/** * 方便的提供上层Dao。 *  * @param dbConfig * @return */public NutDao getDao(DSConfig dbConfig) {return DaoUtil.getDao(dbConfig);}/** * 获得当前泛型类型。 *  * @return */public Class<T> getEntryClz() {return mirror.getType();}/** * 从配置SQL文件中取得SQL文。 *  * @param key * @return */public Sql createSql(String key) {return DaoUtil.getSQLDao().sqls().create(key);}/** * 直接执行一组SQL语句。 *  * @param sqls */public boolean execute(Sql... sqls) {try {DaoUtil.getDao().execute(sqls);return true;} catch (Throwable e) {if (logger.isErrorEnabled()) {logger.error("批量执行SQL语句报错。", e);}throw new RuntimeException(e);}}/** * 通用查询。(无分页) *  * @param cdn * @return */public List<T> query(Condition cdn) {return DaoUtil.getDao().query(getEntryClz(), cdn, null);}/** * 通用查询。(带分页信息) *  * @param cdn * @param pageNumber * @param pageSize * @return */public QueryResult query(Condition cdn, int pageNumber, int pageSize) {Dao dao = DaoUtil.getDao();Pager pager = dao.createPager(pageNumber, pageSize);List<T> list = dao.query(getEntryClz(), cdn, pager);if (null != pager) {pager.setRecordCount(dao.count(getEntryClz(), cdn));}return new QueryResult(list, pager);}/** * 通用获取,对象中引用的对象。(根据正则匹配) *  * @param obj * @param regex * @return */public T fetchLinks(T obj, String regex) {return DaoUtil.getDao().fetchLinks(obj, regex);}/** * 通用获取。(根据条件) *  * @param cdn * @return */public T fetch(Condition cdn) {return DaoUtil.getDao().fetch(getEntryClz(), cdn);}/** * 通用获取。(根据id) *  * @param id * @return */public T fetch(long id) {return DaoUtil.getDao().fetch(getEntryClz(), id);}/** * 通用获取。(根据name) *  * @param name * @return */public T fetch(String name) {return DaoUtil.getDao().fetch(getEntryClz(), name);}/** * 通用删除。(根据实体) *  * @param entity * @return */public DbOperationResultEnum delete(T entity) {try {return 1 == DaoUtil.getDao().delete(entity) ? DbOperationResultEnum.DELETE_SUCCESS: DbOperationResultEnum.DELETE_FAILURE;} catch (Throwable e) {if (logger.isErrorEnabled()) {logger.error("删除数据出错。", e);}throw new BizException(DbOperationResultEnum.DELETE_FAILURE, e);}}/** * 通用插入。(根据实体) *  * @param entity * @return */public DbOperationResultEnum insert(T entity) {try {DaoUtil.getDao().insert(entity);return DbOperationResultEnum.INSERT_SUCCESS;} catch (Throwable e) {if (logger.isErrorEnabled()) {logger.error("插入数据出错。", e);}throw new BizException(DbOperationResultEnum.INSERT_FAILURE, e);}}/** * 通用更新。(根据条件) *  * @param entity * @return */public DbOperationResultEnum update(Condition cnd, Chain chain) {try {return DaoUtil.getDao().update(getEntryClz(), chain, cnd) >= 0 ? DbOperationResultEnum.UPDATE_SUCCESS: DbOperationResultEnum.UPDATE_FAILURE;} catch (Throwable e) {if (logger.isErrorEnabled()) {logger.error("更新数据出错。", e);}throw new BizException(DbOperationResultEnum.UPDATE_FAILURE, e);}}/** * 通用更新。(根据实体) *  * @param entity * @return */public DbOperationResultEnum update(T entity) {try {return 1 == DaoUtil.getDao().update(entity) ? DbOperationResultEnum.UPDATE_SUCCESS: DbOperationResultEnum.UPDATE_FAILURE;} catch (Throwable e) {if (logger.isErrorEnabled()) {logger.error("更新数据出错。", e);}throw new BizException(DbOperationResultEnum.UPDATE_FAILURE, e);}}/** * 通用批量删除。(删除全部) *  * @return */public DbOperationResultEnum clear() {return clear(null);}/** * 通用批量删除。(根据条件删除) *  * @param cdn * @return */public DbOperationResultEnum clear(Condition cdn) {try {return DaoUtil.getDao().clear(getEntryClz(), cdn) >= 0 ? DbOperationResultEnum.CLEAR_SUCCESS: DbOperationResultEnum.CLEAR_FAILURE;} catch (Throwable e) {if (logger.isErrorEnabled()) {logger.error("批量删除数据出错。", e);}throw new BizException(DbOperationResultEnum.CLEAR_FAILURE, e);}}}

其中导入的几个新类要简单介绍下:

?

DaoUtil类:

?

package org.nutz.demo.util;import org.nutz.dao.impl.FileSqlManager;import org.nutz.dao.impl.NutDao;import org.nutz.demo.util.database.DSConfig;import org.nutz.demo.util.database.DSContainer;import org.nutz.demo.util.database.DSUtil;import org.nutz.log.Log;import org.nutz.log.Logs;/** * DAO层切换类。 *  * @author pangwu86@gmail.com *  */public abstract class DaoUtil {protected static Log logger = Logs.getLog(DaoUtil.class);private static NutDao sqlDao = new NutDao();private static NutDao defaultDao = new NutDao(DSContainer.getDataSource(DSUtil.getDefaultDSConfig()));/** * 加载配置SQL */static {sqlDao.setSqlManager(new FileSqlManager("/config/sql"));if (logger.isDebugEnabled()) {logger.debugf("加载SQL配置文件成功,共%s条", sqlDao.sqls().count());for (String key : sqlDao.sqls().keys()) {String sql = sqlDao.sqls().get(key);logger.debugf("Key: %s Value: %s", key, sql);}}}public static NutDao getSQLDao() {return sqlDao;}/** * 获得当前选中的Dao。 *  * @return */public static NutDao getDao() {return defaultDao;}/** * 根据数据源配置信息,获得Dao。 *  * @param dbConfig * @return */public static NutDao getDao(DSConfig dbConfig) {return new NutDao(DSContainer.getDataSource(dbConfig));}}

这个类负责返回普通的NutzDao,跟一个用来获得自定义SQL语句的特殊的NutzDao。

?

这里涉及到这个包下的几个类:

Nutz+ExtJS示范教程——后台Service实现

?

大家可能很奇怪为什么这里代码要这么多,这里其实从现有项目中搬过来的,是因为在做的项目中有这样一个需求——适应多数据源。

?

这个适应不只是在配置文件的时候要可以使用不同的数据源,在运行过程中,也要可以随时加入新的数据源,一个Service的每次执行都可以指定使用不同的数据源。

?

当然这里的系统不会有这么复杂的情况,代码的话大家可以选择性的看看,后面有时间了ME会把这部分精简掉。

?

BizException类:

package org.nutz.demo.exception;import org.nutz.demo.util.database.constant.DbOperationResultEnum;/** * 一个包含异常信息跟数据库操作结果信息的异常类。 *  * @author pangwu86@gmail.com *  */@SuppressWarnings("serial")public class BizException extends RuntimeException {private DbOperationResultEnum dbOperationResultEnum = null;private Throwable cause = null;/** * 业务异常。 *  * @param dbOperationResultEnum * @param cause */public BizException(DbOperationResultEnum dbOperationResultEnum, Throwable cause) {super(cause);this.cause = cause;this.dbOperationResultEnum = dbOperationResultEnum;}public Throwable getCause() {return this.cause;}public DbOperationResultEnum getDBResult() {return this.dbOperationResultEnum;}}

包含异常信息跟数据库操作结果信息的异常类,这里是为了保证在数据库出错的时候,仍然能正常的在页面上返回合理的结果,并将这个异常记录下来,这个类会跟后面的AOP配合使用,对其进行拦截,并将其异常写入日志,其结果返回页面。

?

好了,接下来开始实现四个模块的Service

?

这里以User为例子,展示Service接口与实现如何编写。


接口:

package org.nutz.demo.service;import org.nutz.demo.model.User;/** * 用户模块Service接口。 *  * @author pangwu86@gmail.com *  */public interface UserService extends BaseService<User> {}
?

实现:

package org.nutz.demo.service.impl;import org.nutz.demo.model.User;import org.nutz.demo.service.UserService;/** * 用户模块Service实现类。 *  * @author pangwu86@gmail.com *  */public class UserServiceImpl extends BaseServiceImpl<User> implements UserService {}

是不是很简单,就这样,基本的增删改查功能就有了,那么接口与实现还存在的意义,就是在其中加入某个模块所具有的特殊的业务逻辑,而基本CRUD操作实现,你可以一行代码都不用写了,都在基类中实现好了。

?

最终代码如下:

Nutz+ExtJS示范教程——后台Service实现

?

下面把数据库配置文件加入,然后写几个测试类,看看刚才写的Service是否成功。

?

数据库配置文件ME这里采用了过去常用的properties文件,因为很多人还不是太熟悉用json格式(好吧,其实当时是ME忘了用json了)

Nutz+ExtJS示范教程——后台Service实现

?

?

放在这里,同时这里可以放一个log4j的配置文件,反正早晚都需要。

Nutz+ExtJS示范教程——后台Service实现

?

下面是测试类,还是以User为例,其他类似。

?

package org.nutz.demo.service;import java.util.List;import org.junit.After;import org.junit.AfterClass;import org.junit.Assert;import org.junit.Before;import org.junit.BeforeClass;import org.junit.Test;import org.nutz.dao.Cnd;import org.nutz.demo.model.User;import org.nutz.demo.service.impl.UserServiceImpl;import org.nutz.demo.util.database.constant.DbOperationResultEnum;public class UserServiceTest {private static UserService userService;// 测试数据private final static String USERNAME1 = "testUser1";private final static String USERNAME2 = "testUser2";private final static String USERNAME3 = "testUser3";private final static String USERNAME4 = "testUser4";private final static String USERNAME4_2 = "testUser4_2";private final static String PASSWORD = "test123";private final static String ADMIN = "管理员";private final static String USER = "普通用户";@BeforeClasspublic static void beforeClass() {userService = new UserServiceImpl();// 准备测试数据User user1 = new User();user1.setUserName(USERNAME1);user1.setPassword(PASSWORD);user1.setUserType(ADMIN);User user2 = new User();user2.setUserName(USERNAME2);user2.setPassword(PASSWORD);user2.setUserType(USER);User user3 = new User();user3.setUserName(USERNAME3);user3.setPassword(PASSWORD);user3.setUserType(USER);// 清理当前数据userService.clear();// 插入测试数据userService.insert(user1);userService.insert(user2);userService.insert(user3);}@AfterClasspublic static void afterClass() {// 清理所有测试数据userService.clear();}@Beforepublic void beforeMethod() {}@Afterpublic void afterMethod() {}@Testpublic void insert() throws Exception {User user = new User();user.setUserName(USERNAME4);user.setPassword(PASSWORD);user.setUserType(ADMIN);DbOperationResultEnum result = userService.insert(user);Assert.assertTrue(result.isSuccess());}@Testpublic void fetch() throws Exception {User user = userService.fetch(Cnd.where("userName", "=", USERNAME1));Assert.assertNotNull(user);Assert.assertTrue("管理员".equals(user.getUserType()));}@Testpublic void update() throws Exception {User user = userService.fetch(Cnd.where("userName", "=", USERNAME4));user.setUserName(USERNAME4_2);user.setUserType(USER);DbOperationResultEnum result = userService.update(user);Assert.assertTrue(result.isSuccess());}@Testpublic void query() throws Exception {List<User> users1 = userService.query(Cnd.where("userName", "=", USERNAME2).and("userType","=", USER));List<User> users2 = userService.query(null);Assert.assertTrue(users1.size() == 1);Assert.assertTrue(users2.size() == 4);}@Testpublic void delete() throws Exception {User user = new User();user.setId(1000000);DbOperationResultEnum result = userService.delete(user);Assert.assertFalse(result.isSuccess());}@Testpublic void clear() throws Exception {DbOperationResultEnum result = userService.clear(Cnd.where("userName", "=", USERNAME4_2));Assert.assertTrue(result.isSuccess());}}

?

确认无误后,说明后台的增删改查基本功能已经没有问题,可以开始进行下面的编码了。

?

下一集,将讲述MVC与IoC的使用。


PS:附件中为项目源码,无需解压直接导入Eclipse即可。

读书人网 >JavaScript

热点推荐