|
首先抽象实体Bean的父类BaseModel,包括通用的创建时间、分页等基本信息:
public abstract class BaseModel implements Serializable {
private static final long serialVersionUID = -665036712667731957L;
/**
* 排序 升 降
*/
private String order;
/**
* 排序字段
*/
private String orderBy;
private String orderType;
/**
* 分页用当前页号
*/
private Integer page = 1;
/**
* 分页用记录开始位置
*/
private Integer startPos;
/**
* 分页用页面大小
*/
private Integer pageSize = 20;
/**
* 记录创建时间
*/
private Date createTime;
/**
* 记录最后一次修改时间
*/
private Date updateTime;
/**
* 创建人ID
*/
private Integer creatorID;
/**
* 创建人用户名
*/
private String creatorUserName;
/**
* 创建人姓名
*/
private String creatorName;
public abstract Object getId();
@Override
public String toString() {
ToStringBuilder builder = new ToStringBuilder(this);
Field[] fields = this.getClass().getDeclaredFields();
try {
for (Field f : fields) {
f.setAccessible(true);
builder.append(f.getName(), f.get(this));
}
} catch (Exception e) { // Suppress
builder.append("toString builder encounter an error");
}
return builder.toString();
}
}
之后定义一个通用的泛型化的DAO接口,该接口里包含了比较通用的CRUD操作的方法声明。通过继承该接口,使你的DAO接口免去声明这些比较通用的CRUD方法的工作。
public interface IGenericDao<T extends BaseModel, ID extends Serializable> {
/**
* 添加新实体
*/
void save(T t);
/**
* 批量添加新实体
*/
void batchSave(List<T> list);
/**
* 删除实体(软册除status=2)
*/
void delete(ID id);
/**
* 批量删除实体(软删除status=2)
*/
void batchDelete(List<ID> list);
/**
* 修改实体
*/
void update(T t);
/**
* 通过ID获取实体
*/
T get(ID id);
/**
* <p>
* 带分页的查询列表,与分页相关的语句需要自己编写,mybatis将不会干扰。
* </p>
*/
PaginatedArrayList<T> listByLimit(T t);
/**
* <p>
* 不带分页的列表查询。
* </p>
*/
List<T> list(T t);
/**
* 通过id列表获取实体列表
*/
List<T> getbyIdList(@Param("ids") List<ID> list);
/**
* 根据条件查记录数
*/
int count(T t);
}
这样具体业务实体的DAO接口直接继承IGenericDAO即可,当然也可以添加其他的方法,比如根据用户角色查询用户列表:
public interface IUserDAO extends IGenericDao<User, Integer> {
/**
* 根据角色获取所有用户
*/
List<User> getUserByRoleId(Integer roleId);
}
通用的Service接口与DAO接口基本一样,下面代码是通用Service接口的抽象实现类:
public abstract class AbstractGenericService<T extends BaseModel, ID extends Serializable> implements
GenericService<T, ID> {
private static final Logger LOG = LoggerFactory.getLogger(AbstractGenericService.class);
@SuppressWarnings("unchecked")
private Class<T> getTClass() {
return ((Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0]);
}
@Resource
protected GenericCacheManager cacheManager;
@Resource
private TaskExecutor taskExecutor;
public abstract IGenericDao<T, ID> getDao();
@Override
public void save(T t) {
if (t == null) {
LOG.info("待插入的实体为null,class:{}", this.getTClass().getName());
return;
}
this.getDao().save(t);
}
@Override
public void saveOrUpdate(T t) {
if (t == null) {
return;
}
if (t.getId() == null) {
this.save(t);
} else {
this.update(t);
}
}
/**
* 删除实体(软册除status=2)
*
* @param id
* @throws Exception
*/
@Override
@Transactional
public void delete(ID id) {
if (id == null) {
return;
}
this.getDao().delete(id);
this.cacheManager.remove(CacheKeyHelper.ENTITY_REGION, this.makeCacheKey(id));
}
/**
* 批量删除实体
*/
@Override
@Transactional
public void batchDelete(List<ID> list) {
if (list == null || list.size() <= 0) {
return;
}
this.getDao().batchDelete(list);
// 从缓存中删除id所管理的实体
for (ID id : list) {
this.cacheManager.remove(CacheKeyHelper.ENTITY_REGION, this.makeCacheKey(id));
}
}
/**
* 修改实体
*/
@Override
@Transactional
public void update(T t) {
if (t == null) {
LOG.info("待更新的实体为null,class:{}", this.getTClass().getName());
return;
}
// TODO 此处应该填充上修改时间,但是需要BaseModel中有modifytime字段,且子类都继承该字段
this.getDao().update(t);
// 从缓存中删除实体,实体会在get的时候再次填入到缓存中
this.cacheManager.remove(CacheKeyHelper.ENTITY_REGION, this.makeCacheKey(t.getId()));
}
/**
* 通过ID获取实体
*/
@Override
@SuppressWarnings("unchecked")
public T get(ID id) {
if (id == null) {
return null;
}
// 从缓存中读取实体
T t = (T) this.cacheManager.get(CacheKeyHelper.ENTITY_REGION, this.makeCacheKey(id));
if (t != null) {
return t;
}
// 未从缓存中读取到则从数据库中读取实体
t = this.getDao().get(id);
if (t != null) {
this.cacheManager.put(CacheKeyHelper.ENTITY_REGION, this.makeCacheKey(t.getId()), t);
}
return t;
}
@Override
public T getDetail(ID id) {
T t = this.get(id);
if (t == null) {
return null;
}
this.fillDetail(t);
return t;
}
/**
* <p>
* 带分页的列表查询。
* </p>
*/
@Override
public PaginatedList<T> listByLimit(T t) {
if (t == null) {
return new PaginatedArrayList<T>(0, 0, 0);
}
// 查询数据库中记录的总数
int total = this.getDao().count(t);
// 构造带有分页信息的List
PaginatedList<T> resultList = new PaginatedArrayList<T>(total, t.getPage(), t.getPageSize());
t.setStartPos(resultList.getStartPos());
List<T> queryResultList = this.getDao().listByLimit(t);
resultList.addAll(queryResultList);
return resultList;
}
@Override
public PaginatedList<T> listDetailByLimit(T t) {
PaginatedList<T> resultList = this.listByLimit(t);
for (T item : resultList) {
this.fillDetail(item);
}
return resultList;
}
/**
* <p>
* 不带分页的列表查询。
* </p>
*/
@Override
public List<T> list(T t) {
return this.getDao().list(t);
}
@Override
public List<T> listDetail(T t) {
List<T> resultList = this.list(t);
for (T item : resultList) {
this.fillDetail(item);
}
return resultList;
}
/**
* 通过id列表获取实体列表
*/
@Override
@SuppressWarnings("unchecked")
public List<T> getbyIdList(List<ID> list) {
if (list == null || list.size() <= 0) {
return Collections.EMPTY_LIST;
}
List<T> resultList = new ArrayList<T>();
List<ID> missedIds = new ArrayList<ID>();
// 先从缓存中读取实体
T t;
for (ID id : list) {
if (id == null) {
continue;
}
// 根据id从缓存中读取实体信息
t = (T) this.cacheManager.get(CacheKeyHelper.ENTITY_REGION, this.makeCacheKey(id));
if (t != null) {
resultList.add(t);
} else {
missedIds.add(id); // 未从缓存中读取到实体,则将该实体的id放入到missedIds列表中,稍后从数据库中读取这些实体
}
}
// 如果有些实体未从缓存中取到
if (missedIds.size() > 0) {
// 则从数据库中读取这些实体
List<T> missedModels = this.getDao().getbyIdList(missedIds);
// 如果数据库中有,则添加到缓存中,然后返回
if (missedModels != null) {
for (T model : missedModels) {
this.cacheManager.put(CacheKeyHelper.ENTITY_REGION, this.makeCacheKey(model.getId()), model);
}
resultList.addAll(missedModels);
}
}
return resultList;
}
/**
* 根据条件查记录数
*/
@Override
public int count(T t) {
return this.getDao().count(t);
}
/**
* <p>
* 生成cache中该实体的key。 key生成的规则为: 实体短类名 + ":" + 实体id.
* 例如:id为123的代理商信息的实体在缓存中的key即为:Agent:123 . 子类可以覆盖该方法以生成特殊的key。
* </p>
*/
protected String makeCacheKey(Object id) {
return CacheKeyHelper.getEntityCacheKey(this.getTClass(), id);
}
/**
* 填充引用信息,抽象类中默认不做任何操作,如需填充引用信息,在子类中覆盖此方法
protected void fillDetail(T t) {
}
@Override
public <M extends BaseModel> void fillListDetailByMultiThread(List<M> list,
final FillDetailable<M> fillDetailable) {
if (!CollectionUtils.isEmpty(list)) {
Integer size = list.size();
final CountDownLatch latch = new CountDownLatch(size);
for (final M u : list) {
taskExecutor.execute(new Runnable() {
@Override
public void run() {
try {
fillDetailable.fillDetail(u);
} finally {
latch.countDown();
}
}
});
}
try {
latch.await();
} catch (InterruptedException e) {
e.printStackTrace();
LOG.error(e.getMessage());
}
}
}
}
这样使用了缓存,可以是如Ehcache等JVM缓存,也可以使用Memcached等分布式缓存,由于会有一些联表查询,实体Bean中会有一些冗余字段,使用fillDetail()方法来进行相应设置。为了提高效率,使用多线程的方式对列表中的实体对象进行fillDetail操作,因此需要FillDetailable接口:
public interface FillDetailable<T extends BaseModel> {
void fillDetail(T t);
}
具体的Service实现是需要继承AbstractGenericService即可:
@Service("userService")
public class UserServiceImpl extends AbstractGenericService<User, Integer> implements IUserService {
protected static final Logger LOG = LoggerFactory.getLogger(UserServiceImpl.class);
@Autowired
protected IUserDAO userDAO;
@Override
public void fillDetail(User user) {
UserDepartment filter = new UserDepartment();
filter.setUserId(user.getId());
List<UserDepartment> userDepartmentList = userDepartmentService.list(filter);
final List<Integer> deptIds = new ArrayList<Integer>();
final List<Integer> deptLevels = new ArrayList<Integer>();
final List<String> deptNames = new ArrayList<String>();
this.fillListDetailByMultiThread(userDepartmentList, new FillDetailable<UserDepartment>() {
@Override
public void fillDetail(UserDepartment userDepartment) {
Department department = departmentSerive.get(userDepartment.getDepartmentId());
if (department != null) {
userDepartment.setDepartmentName(department.getName());
deptIds.add(userDepartment.getDepartmentId());
deptLevels.add(userDepartment.getIndeptlevel());
deptNames.add(department.getName());
}
}
});
user.setDeptIds(deptIds);
user.setDeptLevels(deptLevels);
user.setDeptNames(deptNames);
user.setUserDepartmentList(userDepartmentList);
List<Role> roles = roleService.getUserRoles(user.getId());
if (roles != null) {
user.setRoles(roles);
}
}
@Override
public IGenericDao<User, Integer> getDao() {
return userDAO;
}
} |
|
|