图为需要复制的内容
需求简述:每个年度有不同的树形列表,该功能为复制新增树:先选择某个年度的树,点击复制新增后需要变为指定年度的树,树的结构完全一致,变化的是id,年度;
详情:第一张图中的树是由2部分数据拼接的,其中深度为1-3的树在另一张表中定义,深度4+的树为需要复制的数据;
难点:新生成的id与pid的映射
解决思路:通过cpid中间字段保存旧id,实现映射
代码思路:将原来数组按照树的深度拆分为各个数组,根据深度进行遍历,将每个深度的数组id,pid和年度逐一替换(很笨拙的方法,后续待改进)
后端实现
1、model
用到的实体类有3个,BudgetTreeYear(实体类),BudgetTreeYearVO(用于拼装树,含children),BudgetTreeYearParam(传参用实体类)
BudgetTreeYear
BudgetTreeYearVO
BudgetTreeYearParam
2、dao,平台封装,具体实现不难,这里不赘述
3、service
4、impl
/**
* 复制新增
*
* @param param
* @return
*/
@Override
public Pager<BudgetTreeYear> getCopyMain(BudgetTreeYearParam param) {
String budYear = param.getBudYear();
String newYear = param.getNewYear();
List<BudgetTreeYear> oldList = getBudgetTreeYearByYear(budYear);
List<BudgetTreeYear> list4 = get4List(oldList, newYear);
List<BudgetTreeYear> result = new ArrayList<>();
List<List<BudgetTreeYear>> newList = new ArrayList<>();
int times = getMaxDepth(oldList) - 4;
newList.add(list4);
// 这个循环是重点!!!!!!!
for (int i = 0; i < times; i++) {
newList.add(getNewList(getIList(oldList, i + 5), newList.get(i), newYear));
}
for (List<BudgetTreeYear> i : newList) {
result.addAll(i);
}
Pager<BudgetTreeYear> pager = new Pager<>(param.getPageNo(),param.getPageSize(),result.size(),result);
for (BudgetTreeYear bty: result) {
opeMain(bty);
}
return pager;
}
/**
* 获取同一深度的新数组
*
* @param oldList
* @return
*/
private List<BudgetTreeYear> getNewList(List<BudgetTreeYear> oldList, List<BudgetTreeYear> lastDepthList, String newYear) {
List<BudgetTreeYear> newList = new ArrayList<>();
for (int i = 0; i < oldList.size(); i++) {
BudgetTreeYear bty = oldList.get(i);
bty.setCopyId(bty.getId());
bty.setId(IDUtil.getUUID());
bty.setBudYear(newYear);
bty.setParentId(getIdbyPid(lastDepthList, bty.getParentId()));
newList.add(bty);
}
return newList;
}
/**
* 返回深度为depth的oldList
* @param list
* @param depth
* @return
*/
private List<BudgetTreeYear> getIList(List<BudgetTreeYear> list, int depth) {
List<BudgetTreeYear> listI = new ArrayList<>();
int len = list.size();
for (int i = 0; i < len; i++) {
BudgetTreeYear bty = list.get(i);
int oldDepth = Integer.parseInt(bty.getCateDepth());
if (oldDepth == depth) {
listI.add(bty);
}
}
return listI;
}
/**
* 根据旧的Pid获取新的Pid,通过cid获取
* @param list
* @param pId
* @return
*/
private String getIdbyPid(List<BudgetTreeYear> list, String pId) {
String id = "";
for (BudgetTreeYear bty : list) {
if (pId.equals(bty.getCopyId())) {
id = bty.getId();
}
}
return id;
}
/**
* 深度为3的数据固定,获取深度为4的数据
* @param list
* @param newYear
* @return
*/
private List<BudgetTreeYear> get4List(List<BudgetTreeYear> list, String newYear) {
List<BudgetTreeYear> list4 = new ArrayList<>();
int len = list.size();
for (int i = 0; i < len; i++) {
BudgetTreeYear bty = list.get(i);
int depth = Integer.parseInt(bty.getCateDepth());
if (depth == 4) {
bty.setCopyId(bty.getId());
bty.setId(IDUtil.getUUID());
bty.setBudYear(newYear);
list4.add(bty);
}
}
return list4;
}
/**
* 获取树的最大深度
* @param list
* @return
*/
private int getMaxDepth(List<BudgetTreeYear> list) {
List<Integer> depthList = new ArrayList();
for (BudgetTreeYear bty : list) {
depthList.add(Integer.parseInt(bty.getCateDepth()));
}
return Collections.max(depthList);
}
以上是复制树的代码,拼装树的代码如下:
/**
* 组装树
*
* @param menus
* @param voList
*/
private void buildMenus(List<BudgetTreeYear> menus, List<BudgetTreeYearVO> voList) {
for (BudgetTreeYear menu : menus) {
if (StringUtils.isBlank(menu.getParentId())) {
BudgetTreeYearVO vo = new BudgetTreeYearVO();
BeanUtils.copyProperties(vo, menu);
buildChildrenMenu(menus, vo, menu.getId());
voList.add(vo);
}
}
}
/**
* 组装树
*
* @param menus
* @param vo
* @param menuId
*/
private void buildChildrenMenu(List<BudgetTreeYear> menus, BudgetTreeYearVO vo, String menuId) {
List<BudgetTreeYearVO> children = new ArrayList<BudgetTreeYearVO>();
for (BudgetTreeYear menu : menus) {
if (StringUtils.isNotBlank(menu.getParentId()) &&
menu.getParentId().equals(menuId)) {
BudgetTreeYearVO vo_ = new BudgetTreeYearVO();
BeanUtils.copyProperties(vo_, menu);
buildChildrenMenu(menus, vo_, menu.getId());
children.add(vo_);
}
}
vo.setChildren(children);
}
5、用到的sql(sqlServer)
<?xml version="1.0" encoding="UTF-8"?>
<sqls>
<sql id="get_tree" clazz="com.toone.im.model.bm.BudgetTreeYear">
<![CDATA[
select * from ( select TOP 99.999999 PERCENT * from t_ip_year_budget_def t order by cate_prio) aa
where 1=1
<if null budYear>
AND aa.bud_year like CONCAT(CONCAT('%',:budYear),'%')
</if null budYear>
UNION all
select *,null as bud_year from t_ip_budget_tree
]]>
</sql>
<sqls>
Sql中第一层select TOP 99.999999 是为了 union all 排序,其中t_ip_year_budget_def 存的是树深度为4+的数据,t_ip_budget_tree为深度1-3的数据
一点点积累,慢慢进步鸭QAQ!
-------------------20200716更新------------------------
以上方法蠢到家,以下是新思路
/**
* 复制新增
*
* @param param
* @return
*/
@Override
public Pager<BudgetTreeYear> getCopyMain(BudgetTreeYearParam param) {
String budYear = param.getBudYear();
POCondition condition = new POCondition();
condition.addOrderDesc("budYear");
List<BudgetTreeYear> list = budgetTreeYearDao.findPoList(BudgetTreeYear.class, condition);
String newYear = CalcUtil.getNextCode(list.get(0).getBudYear(), 4);
// 复制原数据
condition = new POCondition();
condition.addEQ("budYear", budYear);
List<BudgetTreeYear> source = budgetTreeYearDao.findPoList(BudgetTreeYear.class, condition);
Map<String, String> idMap = new HashMap<>(source.size());
for (BudgetTreeYear item : source) {
String newId = IDUtil.getUUID();
idMap.put(item.getId(), newId);
item.setId(newId);
item.setBudYear(newYear);
String code = item.getCateCode();
if (StringUtils.isBlank(code) || code.length() < 4) {
continue;
}
item.setCateCode(newYear + code.substring(4));
}
for (BudgetTreeYear b : source) {
String parentId = idMap.get(b.getParentId());
if (parentId != null) {
b.setParentId(parentId);
}
}
budgetTreeYearDao.addPoBatch(source);
// 返回新列表
param.setBudYear(newYear);
return listMain(param);
}
果然,业务功能实现功能方面,思路最重要,越复杂的功能思路越清晰就越简单,想好再动手,省时省力;没想好就动手纯粹浪费时间,当然赶进度除外,害