/* ================================================================== * Created [2009-4-27 下午11:32:55] by Jon.King * ================================================================== * TSS * ================================================================== * mailTo:jinpujun@hotmail.com * Copyright (c) Jon.King, 2009-2012 * ================================================================== */ package com.jinhe.tss.component.support.persistence; import java.util.ArrayList; import java.util.List; import com.jinhe.tss.component.support.persistence.entityaop.DecodeUtil; import com.jinhe.tss.component.support.persistence.entityaop.IDecodable; import com.jinhe.tss.core.exception.BusinessException; import com.jinhe.tss.core.persistence.BaseDao; import com.jinhe.tss.core.persistence.IEntity; import com.jinhe.tss.core.util.BeanUtil; /** * 支持树形结构的实体操作的DAO。 */ public class TreeSupportDao<T extends IDecodable> extends BaseDao<T> implements ITreeSupportDao<T> { protected String entityName; public TreeSupportDao(Class<T> type) { super(type); entityName = type.getName(); } /** * 读取同一层下节点的下一序号(当前最大序号 + 1)。 * TODO 并发操作时,如何避免产生相同的seqNo? 加唯一性约束【parentId, seqNo】 or 【decode】(都不行,排序等操作时候将会保存不了) * * @param entityName * @param parentId * @return */ public Integer getNextSeqNo(Long parentId) { return getNextSeqNo(entityName, parentId); } public Integer getNextSeqNo(String entityName, Long parentId) { String hql = "select nvl(max(o.seqNo), 0) + 1 from " + entityName + " o where o.parentId = ?"; List<?> list = getEntities(hql, parentId); return (!list.isEmpty() && list.get(0) != null) ? (Integer) list.get(0) : new Integer(1); } public Integer getNextSeqNo( Long parentId, String parentIdName ) { return getNextSeqNo(entityName, parentId, parentIdName); } public Integer getNextSeqNo(String entityName, Long parentId, String parentIdName) { String hql = "select nvl(max(o.seqNo), 0) + 1 from " + entityName + " o where o." + parentIdName + " = ?"; List<?> list = getEntities(hql, parentId); return (!list.isEmpty() && list.get(0) != null) ? (Integer) list.get(0) : new Integer(1); } /** * 读取指定节点的所有子节点,不包括指定节点自身 * @param entityName * @param decode * @return */ @SuppressWarnings("unchecked") public List<T> getChildrenByDecode(String decode){ String hql = "from " + entityName + " o where o.decode <> ? and o.decode like ? order by o.decode"; return (List<T>) getEntities(hql, decode, decode + "%"); } /** * 读取指定节点的所有子节点,连同指定节点一并返回 * @param id * @return */ @SuppressWarnings("unchecked") public List<T> getChildrenById(Long id){ return (List<T>) getChildrenById(entityName, id); } public List<?> getChildrenById(String entityName, Long id){ String hql = "select o from " + entityName + " o, " + entityName + " o1 " + " where o.decode like o1.decode||'%' and o1.id=? order by o.decode"; return getEntities(hql, id); } /** * 读取指定节点的所有子节点,不包含指定节点 * @param id * @return */ @SuppressWarnings("unchecked") public List<T> getChildrenExcludeSelfById(Long id){ String hql = "select o from " + entityName + " o, " + entityName + " o1 " + " where o.decode like o1.decode||'%' and o.decode <> o1.decode and o1.id=? order by o.decode"; return (List<T>)getEntities(hql, id); } @SuppressWarnings("unchecked") public List<T> getChildrenExcludeSelfByDocode(String decode){ String hql = "select o from " + entityName + " o " + " where o.decode like ? and o.decode <> ? order by o.decode"; return (List<T>)getEntities(hql, decode + "%", decode); } /** * 读取指定节点的所有父节点,连同指定节点一并返回 * @param id * @return */ @SuppressWarnings("unchecked") public List<T> getParentsById(Long id){ return (List<T>)getParentsById(entityName, id); } public List<?> getParentsById(String entityName, Long id){ String hql = "select o from " + entityName + " o, " + entityName + " o1 " + " where o1.decode like o.decode||'%' and o1.id=? order by o.decode"; return getEntities(hql, id); } /** * 读取指定节点(id)到截止节点(breakId)之间的所有父节点,连同指定节点和截止节点一并返回。 * @param id * @param breakId 截止节点的ID * @return */ @SuppressWarnings("unchecked") public List<T> getParentsById(Long id, Long breakId) { return (List<T>) getParentsById(entityName, id, breakId); } public List<?> getParentsById(String entityName, Long id, Long breakId) { IDecodable startnode = (IDecodable) getEntity(BeanUtil.createClassByName(entityName), id); IDecodable breaknode = (IDecodable) getEntity(BeanUtil.createClassByName(entityName), breakId); //如果资源表中找不到了该id对应的资源,则可能该资源已经被删除 if(startnode == null) return new ArrayList<Object>(); String hql = "from " + entityName + " o where ? like o.decode || '%' "; if (breaknode != null) { hql += " and decode like ? "; } hql += " order by decode"; return getEntities(hql, startnode.getDecode(), breaknode.getDecode() + "%"); } /** * 读取排序时移动节点和目标节点之间的节点列表。 * @param entityName * @param parentId * @param sourceOrder * @param targetOrder * @return */ @SuppressWarnings("unchecked") public List<T> getRelationsNodeWhenSort(Long parentId, Integer sourceOrder, Integer targetOrder){ Integer max = sourceOrder.compareTo(targetOrder) > 0 ? sourceOrder : targetOrder; Integer min = sourceOrder.compareTo(targetOrder) > 0 ? targetOrder : sourceOrder; String hql = " from " + entityName + " o where o.seqNo < ? and o.seqNo > ? and o.parentId = ?"; return (List<T>) getEntities(hql, new Object[]{max, min, parentId}); } /** * 对同层节点进行排序。 * @param id 排序节点 * @param targetId 排序节点目标位置的节点 * @param direction -1:向上移动 1:向下移动 * @return */ public List<T> sort(Long id, Long targetId, int direction) { T sourceItem = getEntity(id); T targetItem = getEntity(targetId); if(!sourceItem.getParentId().equals(targetItem.getParentId())) { throw new BusinessException("排序节点和目标节点不属于同一层的节点(父节点不一致),不能排序。"); } Integer sourceSeqNo = sourceItem.getSeqNo(); Integer targetSeqNo = targetItem.getSeqNo(); int tag = (sourceSeqNo < targetSeqNo ? 1 : -1); List<T> returnList = new ArrayList<T>(); List<T> list = getRelationsNodeWhenSort(sourceItem.getParentId(), sourceSeqNo, targetSeqNo); for (T temp : list) { temp.setSeqNo(temp.getSeqNo() - tag); saveItem4Sort(temp, returnList); } sourceItem.setSeqNo(targetSeqNo + (direction - tag) / 2); targetItem.setSeqNo(targetSeqNo - (direction + tag) / 2); saveItem4Sort(sourceItem, returnList); saveItem4Sort(targetItem, returnList); return returnList; // 返回后 } /** 保存排序中受影响的节点的所有子节点以维护decode值,并修复每个子节点下面用户的decode值信息 */ void saveItem4Sort(T sortedNode, List<T> returnList) { String oldDecode = sortedNode.getDecode(); saveDecodeableEntity(sortedNode, returnList); // 保存目标节点的子节点时,有可能把刚保存完的排序源节点给一起查出来了,需要过滤掉。 List<T> children = getChildrenExcludeSelfByDocode(oldDecode); for (T temp : children) { saveDecodeableEntity(temp, returnList); } } /** * 保存树形结构的对象,并依据自身信息及父节点信息自动维护其decode值。 * @param entity */ public void saveDecodeableEntity(T entity) { saveDecodeableEntity(entity, null); } private void saveDecodeableEntity(T entity, List<T> returnList) { Integer levelNo = new Integer(1); int sectSize = DecodeUtil.getSectSize(); //默认值,parentId==null || parentNode==null(像菜单)时取默认值 String decode = DecodeUtil.getDecode(entity.getSeqNo(), sectSize); //首先根据当前保存的节点找到其父节点, 然后根据其父节点的信息和本身的seqNo生成decode,levelNo Long parentId = entity.getParentId(); if(parentId != null ) { // 找的到父节点的处理(资源试图中将 "全部" 节点id = 0注册进来) IEntity parentNode = getEntity(entity.getParentClass(), parentId); if(parentNode != null) { IDecodable parent = (IDecodable) parentNode; levelNo = (parent.getLevelNo() == null ? 0 : parent.getLevelNo()) + 1; // 层级加一 decode = DecodeUtil.getDecode(parent.getDecode(), entity.getSeqNo(), sectSize); } } entity.setDecode(decode); entity.setLevelNo(levelNo); if(entity.getId() == null) { // ID为null,说明是新建 createWithoutFlush(entity); } else { updateWithoutFlush(entity); } if( returnList != null && !returnList.contains(entity) ) { returnList.add(entity); } } }