女朋友不想开Processon会员,我魔改了一个无限制的在线绘图软件

简介: 女朋友不想开Processon会员,我魔改了一个无限制的在线绘图软件

前言

对于复杂的逻辑或者流程来说,画一画流程图可以帮助我们更好的捋清楚逻辑。平时我女朋友也偶尔会用 processon 来画一下流程图, processon 确实是一个很好的软件。

但是免费版只能创建 9 个文件,所以她平时在用的时候只能删了画、画了删,用起来不是那么方便,但是又不想为了这个东西开会员。

于是我找到了一个很棒的开源的流程图软件——draw.io,它同样也提供了在线的地址——drawio在线地址

但她用了一会之后,感觉这个在线地址也不是那么的方便易用,提出了下面的问题:

  1. 这个在线地址部署在国外,平时使用会受网络影响
  2. 本身不提供文件存储的功能,它对接了多种存储介质,比如你可以下载到本地、或者托管到一些云盘或者 GitHub ,虽然说配置起来不是很麻烦,但也并不是开箱即用
  3. 本身不提供文件管理功能,它可以导入一个个文件,感觉就像是一个编辑器而已,并没有把我创建的、编辑的流程图统一管理起来,没有类似文件/文件夹列表的功能

image.png

所以,基于上面的种种问题,我就想着基于 drawio 魔改一个的绘图软件,并且自己后端实现存储,这样就可以让这个东西免费无限制且易用。

其实说是魔改,我们改的东西不多,主要是改变存储、读取的方式,以及有一些功能不需要的可以做一些删减,最后就是自己做一个平台把文件与流程图串起来。

这是项目的体验地址,欢迎大家体验:🌟🌟体验地址🌟🌟

前端实现

首先先把 drawio 的代码拉下来,拉下来之后只需要关注 src/main/webapp 这个目录,所有的前端代码都在里面。

image.png

把前端跑起来

入口是 src/main/webapp/index.html 这个文件,我使用了 express 起了一个服务,一来是充当静态资源服务器,二来是充当开发环境的代理,规避接口调用时的跨域问题。

新建一个 server.js 文件,填入如下内容

// server.js
const express = require("express");
const { createProxyMiddleware } = require("http-proxy-middleware");
const path = require("path");
const compression = require("compression");
const app = express();

app.use(compression());

// 静态资源服务
app.use(express.static(path.join(__dirname, "./src/main/webapp")));

// 接口转发
app.use(
  "/draw-io",
  createProxyMiddleware({
    target: "http://draw.eztool.top",
    changeOrigin: true,
    pathRewrite: {
      "^/draw-io": "/draw-io", // 转发的时候去掉前缀
    },
  })
);

// 启动服务器
const port = 3000;
app.listen(port, () => {
  console.log(`Server is running on http://localhost:${port}`);
});

然后运行一下这个 node 脚本,启动服务。

启动服务之后,这里有两点需要注意的地方:

  1. 如果你的服务器动在 3000 端口,那么你需要访问 http://localhost:3000/?dev=1
  2. 修改 src/main/webapp/index.html 的如下代码,不然静态资源的加载会有问题

image.png

随意修改一些东西,然后打开上述的链接,如果看到修改生效,那么就证明我们的开发环境启动成功了

image.png

初始化数据

大概看了一下 drawio 的代码,发现流程图的内容是 xml 格式的。对于文件的初始化流程,可以大概找到 App.js 的如下代码,绿色代码是我新加的。

image.png mock 一下数据,把文件的标题与内容通过实例化一个 LocalFile ,并调用 loadFile 加载到画布上

image.png

然后我们就可以得到一幅流程图如下图所示

image.png

这里真正实现的时候,是根据 id 调用后端接口,去拿标题和内容,然后加载到编辑器中,到这一步,读取数据已经完成。

保存数据

由于我们上面选择的存储介质是 LocalFile ,所以保存内容的逻辑在 LocalFile 这个类中,具体在下面打印的位置

image.png

在这个位置,我们可以把数据同步给后端进行更新。

除了内容之外,标题的更新我们也需要考虑。

image.png


标题更新的时候会走到下面这个方法,我们可以在这个方法中来发送接口给后端更新文档的标题

image.png

至此,基本的数据流向问题已经解决,在流程图层面,我们已经解决了读取数据及更新数据的问题,解决了这两个问题之后,我们就可以把流程图内容信息存在我们自己的服务器中。

其他配置项修改

还有一些其他配置项的修改,这个就根据我们自身的情况来,看看哪些东西是我们不想要的,哪些东西是要改的。

这里就得耐心去读一下它的源码了,没什么技巧,找到你自己想要改的地方,改它。这里我举两个例子。

第一个,图标的修改

image.png

上面框出来的图标,在下面的文件中,修改成你想要的图标就行。

image.png

第二个,菜单的修改,我这里对【文件】这个菜单删了很多,只保留了我觉得必要的东西

image.png

菜单在下面这个文件中,基本上就是找到你不想要的东西把它注释掉或者删掉。

image.png

打包部署

这个项目打包的工具用的 ant ,它是一个基于 java 的打包工具。所以要打包我们先要装好 javajdk 以及 ant

安装好后进入到 /etc/build 这个目录下,执行 ant 命令,就可以发现打包成功了。

部署的时候使用 nginx 开了一个目录,然后我比较偷懒。我把整个 webapp 目录都丢了上去,但是呢 webapp 目录又很大,我也不想每次通过 ftp 工具去传。

于是我就建了一个 git 仓库,把在我本地的 webapp 目录推了上去,然后在服务器拉取这个仓库。这样做了以后,我每次通过 ant 打包完之后推送代码,然后在服务器 pull 一下,代码就更新了。

还有一点要注意的是,这个项目的前端并没有使用一些现代化的打包工具,打包出来的文件名不会有 hash

为了避免缓存导致代码不生效的问题,我在 nginx 配置的时候使用了协商缓存,配置如下

  location ~* \.(js|css|html)$ {
        add_header cache-control no-cache;
    }

image.png

首屏加载优化

在打包部署完成之后,发现了加载还是挺慢的,一个是我服务器的带宽比较小,另一个是确实加载了几个比较大的 js 文件。

image.png

首先 app.min.js 这个是主包,是不能省略的。然后看到 stenceils.min.jsextensions.min.js ,看看他们可不可以不阻塞主流程。

大概看了一下 stenceils.min.js 的内容,它里面都是模版,好家伙,怪不得这么大;其次关于 extensions.min.js ,看了一下 /etc/build/build.xml 打包文件,它大概是做一些拓展逻辑的,比如说一些导入导出之类的。

所以这两个包的加载完毕与否,是不影响正常的主绘制流程使用的。

image.png

这里便是上面提到的两个包的加载入口,让这个加载函数加载完第一个包之后就执行回调函数即可。

image.png

这样之后,我们不需要再等待这个包加载完成就能开始用主要的绘图逻辑,这个包加载了 13S ,也就是说,我们不需要再等这 13S

image.png

首屏加载速度提升了 10多秒 啊兄弟们,恐怖如斯~

现在没有缓存的情况下,首屏加载 3S 左右,还是挺丝滑的

image.png

平台实现

我另外用 React 实现了一个用户登录、管理文件的平台,目前做的功能有:

  • 登录/注册/修改密码
  • 文件列表,新增,修改,删除,重命名

image.png

image.png

image.png

image.png

目前来说做的还比较简单,只提供了最基本的文件管理功能,这个平台跟上面的绘图页面可以理解为是两个项目。

在新建或者打开的时候,会从这个平台跳转到绘图项目:

export const openDraw = (id) => {
  const dev = location.href.includes("localhost");
  let url;
  if (dev) {
    url = `http://localhost:3000?dev=1&id=${id}`;
  } else {
    url = `http://draw.eztool.top/draw?id=${id}`;
  }
  window.open(url);
};

后端

后端使用的 java ,使用的是 SpringBoot 搭建的项目。

相关技术栈:

  • JWT:鉴权
  • MongoDB:使用 Mongo-Plus 作为数据存储
  • Redis:缓存
  • Spring mail:邮件发送验证码
  • transmittable-thread-local:上下文信息传输

后端实现主要分为三块:

鉴权

在之前做 工具网站 的时候用到了 sa-token 框架,这个框架整体来说功能挺强大的,但对于小网站来说可能很多东西都不太需要。所以我这次基于 hutool 的工具类自己包了一层,实现了一个较为简洁的 JWT 鉴权流程。


@Slf4j
@UtilityClass
public class JwtUtil {

    String jwtStr  = "xxxxxxx";

    public String getToken(User user) {
        return JWTUtil.createToken(BeanUtil.toBean(user,Map.class), jwtStr.getBytes());
    }

   public Boolean verify(String token) {
       return JWTUtil.verify(token, jwtStr.getBytes());
   }


   public void isLogin(String token){
        if (StrUtil.isBlank(token)) {
            throw new BusinessException("请先登录");
        }
        if (!verify(token)) {
            throw new BusinessException("请先登录");
        }
   }

   public User getUser(String token){
       isLogin(token);
       JWTPayload payload = JWTUtil.parseToken(token).getPayload();
       if (Objects.isNull(payload)){
           throw new BusinessException("用户信息为空");
       }
       return User.tpJWTPayload(payload);
   }

}

这里封装了一个设置 token 以及解析 token 的工具类,登录成功后 token 就被设置到 cookie 中,请求过来时解析 cookie 中的 token 以获取用户信息。

用户信息

这里包含了用户的注册、登录、修改密码等功能。

用户信息表的结构如下:

{
    "userId": "",
    "ip": "",
    "name": "",
    "account": "",
    "password": "",
    "id": "",
    "createTime": "",
    "updateTime": ""
}

注册这里用到了邮箱验证码作为校验,验证码发送出去后会存在 redis 中,并设有有效期。

然后注册一个新邮箱作为发送验证码的邮箱,以 163邮箱 为例。

image.png

在这里开通 SMTP

image.png

然后引入邮件依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-mail</artifactId>
</dependency>

配置yml

spring:
  mail:
    # 设置邮箱主机
    host: smtp.163.com
    # SMTP 服务器的端口
    port: 587
    # 设置用户名,这里使用你邮箱账号就行
    username: 123456789@163.com
    # 设置密码,该处的密码是邮箱开启SMTP的授权码而非邮箱密码
    password: SODJSHAUHGQWRQWE
    default-encoding: UTF-8
    protocol: smtps
    properties:
      mail:
        smtp:
          ssl:
            enable: true

具体的实现如下:

@Slf4j
@Service
@RequiredArgsConstructor
public class MailServiceImpl  implements MailService {

    private final JavaMailSender javaMailSender;
    
    //发送邮件
    @Override
    public void sendEmail(String email,String subject, String text) {
        try {
            SimpleMailMessage mailMessage = new SimpleMailMessage();
            //你的邮箱账号
            mailMessage.setFrom("123456789@163.com");
            //接收方的邮箱账号
            mailMessage.setTo(email);
            //标题
            mailMessage.setSubject(subject);
            //内容
            mailMessage.setText(text);
            //发送邮件
            javaMailSender.send(mailMessage);
        } catch (Exception e) {
            e.printStackTrace();
            log.info("发送邮箱失败:{}",e.getMessage());
        }
    }

}

文件表

文件表里包括文件夹跟文件,主要通过 type 去区分。更详尽的表结构字段如下:

{
    "fileId": "", //文件ID
    "parentId": "", //上级文件id
    "name": "", //名称
    "type": "", //文件类型 0=文件 1=文件夹
    "content": "", //文件内容
    "isSub": false, //是否有下级(针对文件夹点击下拉判断)
    "createId": "", //创建用户id
    "updateId": "", //修改用户id
    "delFlag": "", //逻辑删除 0=正常 1=删除
    "id": "",
    "createTime": "",
    "updateTime": ""
}

剩下的就是关于文件的一些增删改查逻辑,这里就不再放具体的代码。通过维护 parentIdfileId 的对应关系,就可以实现文件树的逻辑。

最后

这就是我基于 drawio 魔改的一个在线绘图软件,对于我们自身的要求来说是够用了。后续的拓展的话,我尽量还是以平台拓展为主,绘图功能拓展为辅,因为这个绘图功能已经很强大了,甚至对我来说,这个绘图我常用的还不到它功能的 10% ,所以我也不太想花太多精力去改它。

后续可能会拓展的点:

  • 模版创建
  • 模版市场
  • 回收站
  • 分享

如果你也有像我们一样的痛点,欢迎你体验我们的站点。如果你觉得有哪里用得觉得不舒服的地方,也欢迎随时与我们反馈。希望这个对你会有帮助~

以上就是本文的全部内容,如果你觉得有意思的话,点点关注点点赞吧~

相关文章
|
监控 安全 Java
Java多线程调试技巧:如何定位和解决线程安全问题
【4月更文挑战第6天】本文探讨了Java并发编程中的线程安全问题,包括数据不一致、死锁和性能下降。为解决这些问题,文章介绍了理解线程安全的重要性,如互斥、同步和避免死锁,并提供了识别问题的迹象和调试工具,如JConsole、VisualVM、堆栈跟踪和Thread Dump分析。此外,还建议使用原子类、线程安全数据结构和静态代码分析工具来加强同步和减少锁粒度。最后,强调了避免共享状态和合理设计的重要性,以确保多线程程序的正确性和效率。
524 2
Maven之阿里云镜像仓库配置
方式一:全局配置可以添加阿里云的镜像到maven的setting.xml配置中,这样就不需要每次在pom中,添加镜像仓库的配置,在mirrors节点下面添加子节点: <id>nexus-aliyun</id> <mirrorOf>central</mirrorOf> <name>Nexus aliyun</name> <url>http://maven.
|
Oracle Ubuntu Java
Ubuntu安装JDK
一. Ubuntu 安装JDK的两种方式 1. 通过apt安装. 2. 通过官网下载安装包安装. 这里推荐第1种,因为可以通过 apt-get upgrade 方式方便获得jdk的升级 二. 通过apt安装(jdk有很多版本, 这里介绍两种: openjdk和oracle的JDK) 1.
72080 4
|
应用服务中间件 nginx
Nginx的启动、停止与重启
启动  启动代码格式:nginx安装目录地址 -c nginx配置文件地址 例如: [root@LinuxServer sbin]# /usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.
13646 0
|
安全 关系型数据库 Linux
一文教你搭建个人网盘filerun,拥有私人文件服务器
一文教你搭建个人网盘filerun,拥有私人文件服务器
一文教你搭建个人网盘filerun,拥有私人文件服务器
|
运维 监控 安全
盘点Linux服务器运维管理面板
随着云计算和大数据技术的迅猛发展,Linux服务器在运维管理中扮演着越来越重要的角色。传统的Linux服务器管理方式已经无法满足现代企业的需求,因此,高效、安全、易用的运维管理面板应运而生。
|
前端开发 JavaScript
用iframe的方式实现微前端
微前端是最近几年火起来的概念,iframe是早期实现微前端的理想方案,而现在有了其它的方案,比如qianduan框架,single-spa,以及webpack5带来的联邦模块方案。但是每一个方案都有其优缺点,感兴趣的可以去实践一下。
|
10月前
|
机器学习/深度学习 人工智能 监控
X-R1:3090也能训7B模型!开源框架X-R1把训练成本打下来了:10美元训出企业级LLM
X-R1 是一个基于强化学习的低成本训练框架,能够加速大规模语言模型的后训练开发。仅需4块3090或4090 GPU,1小时内完成训练,成本低于10美元。
657 5
X-R1:3090也能训7B模型!开源框架X-R1把训练成本打下来了:10美元训出企业级LLM
|
自动驾驶 物联网 5G
标题:5G频段解析:低频、中频与毫米波的奥秘
标题:5G频段解析:低频、中频与毫米波的奥秘
1462 65
|
11月前
|
开发工具 git iOS开发
阿里同学都在用的开发环境和工具
本文主要介绍后端开发同学常用的工具以及开发环境搭建。