项目随笔_小说阅读器

最近在做一个网页的小说阅读器,因为之前没有接手过正式的项目所以走了很多弯路,现在项目接近尾声,所以做个随笔总结一下:

  • git工具的使用
  • 接口文档的使用
  • 前后端交互的心得
  • 目录树的构建
  • 优化心得

目录树构建

参考链接

vue前端api
后端实现

实现思路

前端使用elementUi框架实现,后端生成树结构的目录节点生成嵌套结构

树节点pojo


package com.dms.guyiyao.pojo;

import lombok.Data;
import lombok.Getter;
import lombok.Setter;

import java.util.List;

@Data
public class TreeNode implements Comparable{
//节点id
    private String id;
  //节点层级
    private Integer grade;
    //章节名
    private  String chapter;
    //父节点id
    private  String parentId;
//子节点
    private List<TreeNode>cataLog;
    /*节点结构化状态*/
    private  boolean flage;
/*
* 排序
* */
    private  int sequence;


    @Override
    public int compareTo(Object o) {
        TreeNode treeNode=(TreeNode)o;
        if (this.getSequence()>treeNode.getSequence())return 1;
        else if (this.getSequence()<treeNode.getSequence()) return  -1;
        return this.chapter.compareTo(treeNode.chapter);
    }
}

网上找到的参考案例是递归算法实现父子结构,如果目录树的节点太深(多)可能会导致栈溢出的问题
在这里插入图片描述
所以优化了一下,改为了非递归的算法:(具体实现除了这个函数以外还有其他两个函数,具体代码去看看上面的第二个链接)

//使用非递归算法构建父子关系,flage判断改节点是否找到父节点,如果为true表明已找到直接跳过
        Stack stack=new Stack<>();
    public TreeNode buildChildTree(TreeNode pNode){
        System.out.println("顶级"+pNode.getId());
        List<TreeNode>childTree=new ArrayList<TreeNode>();
        stack.push(pNode);

        while (stack.size()!=0){
           TreeNode parNode= (TreeNode) stack.pop();
            for (int i = 0; i < nodeList.size(); i++) {
                if(!nodeList.get(i).isFlage()&&nodeList.get(i).getParentId().equals(parNode.getId())){
                    nodeList.get(i).setFlage(true);//子节点已被收纳,不在被其他节点收纳
                    childTree.add(nodeList.get(i));
                    stack.push(nodeList.get(i));//子节点成为新的父节点
                }
            }
//            根据sequence排序
            Collections.sort(childTree);//通过sequence字段排序
            parNode.setCataLog(childTree);
             childTree=new ArrayList<TreeNode>();//清空数组不然会导致栈溢出
        }
//        返回顶级节点
        return pNode;
    }

递归算法->非递归算法的转换

递归:
按照递归算法的做法只有在子节点都不满足递归条件后才会有返回,顶级节点才能返回:可以理解为所有子节点都有返回值父节点才能返回。这个过程会在JVM的栈区消耗大量空间
非递归:
利用Stack,保存父节点的工作进度既:顶级父节点找到他的所有子节点,建立父和子(子节点放入数组),子与子的关系(子与子在数组的排序)后将找到的子作为新的父节点放入栈。然后进行下一次栈循环

优化心得

  • 异步优化
  • IO优化

刚刚开始这个项目的时候,经验不足,导致后期重构了大量的代码。

异步优化

义务需求里面有一个批处理的需求,批量导入excel中的数据到数据库,刚刚开始的时候没有考虑到远程数据库IO特别慢的问题,程序中存在大量的数据库IO,一万两千条数据大概花了2个时候才上传成功,后面上了多线程的异步请求。把IO操作单独独立出来(这里的io是insert操作。他的返回值不会影响他后面的操作,所以程序没有必要阻塞在这里等它)

package com.dms.guyiyao.service.Impl;

import com.dms.guyiyao.mapper.TsBookDifferentMapper;
import lombok.SneakyThrows;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

@Component
public class AsyncService {
    @Autowired
    TsBookDifferentMapper bookDifferentMapper;

    @SneakyThrows
    @Async("asyncPoolTaskExecutor")
    public void DiffAdd_IO(String contentFrom_uuid,String contentTo_uuid, String contentFrom, String contentTo, String chapterIdFrom, String chapterIdTo,String datetime){
        long t1=System.currentTimeMillis();
        bookDifferentMapper.addDiffContent(contentFrom_uuid,contentFrom,chapterIdFrom,datetime);
        bookDifferentMapper.addDiffContent(contentTo_uuid,contentTo,chapterIdTo,datetime);
        bookDifferentMapper.addConnection(contentFrom_uuid,contentTo_uuid,datetime);
        long t2=System.currentTimeMillis();
        System.out.println("IO线程花费时间:"+(t2-t1));
    }
}

参考链接:
@Asnc配置

@Asnc不起作用解决方案

IO优化

优化思路和上面使用异步请求一样。因为像这种接口调用,特别是远程数据库的IO特别拖慢程序的速度,在系统的主体代码完成之后。肯定需要抽离出来进行优化。

这里的思路是减少接口调用次数,一个接口完成多个接口的功能

 <select id="getAllDiffInfo" resultType="com.dms.guyiyao.pojo.ContentDiff">
        SELECT t1.id as contentIdFrom,t1.content as contentFrom,t2.id as diffId,t2.jsonFrom,t2.jsonTo,t11.content as contentTo,t11.id as contentIdTo,a.bookname as bookName,b.id as chapterId, b.chapter_name as chapterName
        FROM ts_book_content_diff as t1,ts_book_different as t2 ,ts_book_content_diff as t11, ts_book as a,ts_book_chapter as b
        WHERE t1.id=t2.ts_book_content_id_from
          and t1.ts_book_chapter_id=#{chapterId} and t1.id=t2.ts_book_content_id_from and t11.id=t2.ts_book_content_id_to and a.id=b.ts_book_id AND b.id=t11.ts_book_chapter_id
    </select>

在编码初期为了快速出效果。所以针对不同的表写了大量的数据库访问接口。产生了大量的IO。后期压缩成一条sql语句。程序效率极大提升。

前后端交互的心得

docway接口文档管理
swagger笔记_狂神
前后端分离是合理的。但是前端和后端交给不同的人来做真的太鸡肋了。特别是如果都没有什么经验的话。前端和后端的交互。就像是程序的接口调用一样。可能项目的结构性和可维护性变强了。但是这个消耗真的太大了。如果前后端一个人贯通的话。对项目开发周期,代码的健壮性,后期扩展性都是极大的提升。

经验

  1. 系统设计不应该是后端一个人的事情,设计数据库时也应该和前端进行交流。因为最后所以的数据都是交给前端在使用。如果前端的实现需要的数据和系统设计的数据库不太一样。开发到一半可能就会发现突然崩盘。因为一个功能模块的实现往往需要其他几个功能模块的支持。(比如这个项目的异文就出现过这种问题)
  2. 接口的规定,应该是并发进行的。如果前端的进度快,前端应该使用docway这种接口文档把接口写好。如果后端的进度更快,则可以直接用swgger这种带测试功能的框架把接口接上。前端拿到后可以直接测试使用。
  3. 后端编码的前期写的代码粒度应该尽可能的小。提高代码的通用性。方便后期有相同需求时直接调用,或者cv后进行修改。(比如这个项目的图片上传和操作excel表就多次使用了某些代码)
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值