开发者社区> 悟空CRM> 正文
阿里云
为了无法计算的价值
打开APP
阿里云APP内打开

聊聊这个倾注10年的开源项目,如何一步步火爆GitHub!

简介: 聊聊这个倾注10年的开源项目,如何一步步火爆GitHub!
+关注继续查看

近几年悟空CRM开源项目在GitHub和码云上迅速蹿红,并获得了上千用户的关注。目前累计2,000,000下载量。社区人数达到30,000多人。在国内浩瀚的开源市场,悟空CRM在开源道路上倾注10多年的心血。

2010年初,受国外salesforce、zoho等saas供应商的影响,越来越多的企业开始投入CRM的研发。为找到属于自己的品牌方向,悟空团队以openerp(odoo)为标杆,开始了在开源道路上探索,并为之进行了近十年的投入。

2014年第一个版本发布

悟空CRM项目在2010开始启动,对于初创团队来讲,产品的研发迭代以及投入精力有限,直到2104年悟空CRM推出第一个开源CRM版本V0.0.1,当时的国内企业管理软件的开源市场并未完全成熟,再加上V0.0.1版本存在功能和技术的限制,产品发布后并没有获得大量的用户群体。

2016年继续迭代

悟空CRM在版本迭代上并没有想想的那么快,一部分研发投入开源、一部分研发投入二次开发项目,毕竟对于一个企业来讲,生存是第一要素。经过两年的12次迭代代,2016年悟空CRM版本迭代至V0.4.5,并在码云和Github上发布后,获得了上千家用户的下载和体验。V0.4.5该版本在原有的基础上做了全面升级和改造,是目前市场上使用较为稳定一个版本。

但是在这个技术日新月异的时代。node、vue、微服务、Python、AI各种技术不断兴起,悟空CRM开源提供的技术已经很难满足现有技术爱好者的需求,开源道路在国内再一次受到阻力,开源项目暂且搁置。

2019年一次新的挑战

是否继续开源?是一个很艰难的决定。毕竟开源项目要投入大量的精力。对企业的成本是不小的挑战。但是悟空CRM毕竟在开源道路上已经倾注多年的心血,开源是必将继续!

重整旗鼓!这一次在技术方面面临一个重大的调整,悟空CRM决定推出目前流行的前后端分离技术,后端采用PHP和JAVA 两种开发语言,前端采用最火爆的vue架构。两种后台开发语言架构是国内唯一尝试的,无论是PHP或者JAVA任一技术栈的开发人员都可尝试学习。

2019年做极致的开源产品

2019年4月PHP版发布了:基于TP5.0+vue+ElementUI的前后端分离CRM系统
2019年6月JAVA版发布了:基于jfinal+vue+ElementUI的前后端分离CRM系统项目

下载地址:https://gitee.com/wukongcrm

两个产品同年发布,发布后便获得的大量开源爱好者的关注和亲睐。高质量的源码、高标准的UI设计,这一次不仅仅在技术上悟空CRM投入的大量的时间和精力,在用户体验和UI上也进行了全面的升级的改造。

10年磨一剑,悟空CRM的开源道路还需继续前进,也会不断面临更大的挑战,相信这个开源方向已经嵌入悟空CRM的骨髓,悟空的金箍棒总有一天会变得更强大。

悟空CRM开源项目主要功能:悟空CRM开源版一共包含了100多种模块应用

JAVA版本

核心框架:jfinal3.8
缓存:redis caffeine
数据库连接池:Druid
工具类:hutool,fastjson,poi-ooxml
定时任务:jfinal-cron
项目构建工具:maven
Web容器:tomcat,undertow(默认)
前端MVVM框架:Vue.JS 2.5.x
路由:Vue-Router 3.x
数据交互:AxiosUI框架:Element-UI 2.6.3
项目结构

├──  LICENSE
├──  README.md
├──  build                        //  配置
│      ├──  build.js
│      ├──  check-versions.js
│      ├──  logo.png
│      ├──  utils.js
│      ├──  vue-loader.conf.js
│      ├──  webpack.base.conf.js
│      ├──  webpack.dev.conf.js
│      └──  webpack.prod.conf.js
├──  config
│      ├──  dev.env.js
│      ├──  index.js
│      └──  prod.env.js
├──  favicon.ico
├──  index.html                      //  入口html文件
├──  package-lock.json
├──  package.json                     //  定义项目所需要的各种模块,以及配置信息
├──  src
│      ├──  App.vue                   //  页面入口
│      ├──  api                        //  api接口
│      │      ├──  businessIntelligence    //  商业智能
│      │      ├──  common.js                   //  公共
│      │      ├──  customermanagement        //  客户管理
│      │      ├──  login.js                   //  登录
│      │      ├──  oamanagement                    //办公
│      │      ├──  personCenter
│      │      └──  systemManagement
│      ├──  assets                            //  图片和图标
│      │      ├──  401_images
│      │      ├──  404_images
│      │      ├──  iconfont
│      │      └──  img
│      ├──  components                         //  自定义组件
│      │      ├──  CreateCom                     //  新建
│      │      │      ├──  CrmRelative.vue              //  关联客户管理列表
│      │      │      ├──  CrmRelativeCell.vue
│      │      │      ├──  CrmRelativeTable.vue
│      │      │      ├──  XhBusinessStatus.vue        //  商机状态
│      │      │      ├──  XhCustomerAddress.vue  //  新建客户下的地图位置
│      │      │      ├──  XhDate.vue                        //  时间选择
│      │      │      ├──  XhDateTime.vue
│      │      │      ├──  XhFiles.vue                        //  附件
│      │      │      ├──  XhInput.vue                      //  单行输入框
│      │      │      ├──  XhMultipleSelect.vue        //  多选
│      │      │      ├──  XhProduct.vue                  //  产品关联
│      │      │      ├──  XhProuctCate.vue              //  产品类别
│      │      │      ├──  XhReceivablesPlan.vue      //  回款计划
│      │      │      ├──  XhSelect.vue                        //  单选
│      │      │      ├──  XhStrucUserCell.vue            //  员工部门选择框
│      │      │      ├──  XhStructure.vue                    //  部门选择
│      │      │      ├──  XhStructureCell.vue
│      │      │      ├──  XhTextarea.vue                      //  多行输入框
│      │      │      ├──  XhUser.vue                            //  员工选择
│      │      │      ├──  XhUserCell.vue
│      │      │      ├──  arrayMixin.js                            //  公共逻辑
│      │      │      ├──  index.js
│      │      │      ├──  objMixin.js
│      │      │      └──  stringMixin.js
│      │      ├──  CreateSections.vue                          //  容器布局
│      │      ├──  CreateView.vue
│      │      ├──  DetailCell.vue
│      │      ├──  EditImage.vue                                    //  编辑图片
│      │      ├──  Examine                                          //  审批展示和操作
│      │      ├──  MapView.vue                                      //  地图预览位置
│      │      ├──  SlideView.vue
│      │      ├──  emoji.vue                                              //  表情
│      │      ├──  flexbox                                                  //  flex
│      │      │      ├──  flexbox-item.vue
│      │      │      ├──  flexbox.vue
│      │      │      └──  index.js
│      │      ├──  relatedBusiness.vue                              //  关联客户内容
│      │      ├──  reminder.vue
│      │      ├──  selectEmployee                                    //  选择员工
│      │      └──  vuePictureViewer                                  //  文件预览
│      ├──  directives                                            //  自定义指令
│      │      ├──  empty
│      │      ├──  photo
│      ├──  filters                                          //  过滤器
│      ├──  main.js                                         //  程序入口
│      ├──  permission.js                                                    //  路由处理
│      ├──  route加载更多

复制代码通过权限注解在拦截器判断用户是否拥有访问权限

@Override
public void intercept(Invocation invocation) {
    //TODO 权限功能后台拦截
    Permissions permissions=invocation.getMethod().getAnnotation(Permissions.class);
    if(permissions!=null&&permissions.value().length>0){
        JSONObject jsonObject= Aop.get(AdminRoleService.class).auth(BaseUtil.getUserId());
        //组装应有权限列表
        List<String> arr=queryAuth(jsonObject, "");
        boolean isRelease=false;
        for (String key : permissions.value()) {
            if(!isRelease){
                if(arr.contains(key)){
                    isRelease=true;
                }
            }
        }
        if(!isRelease){
            invocation.getController().renderJson(R.error("无权访问"));
            return;
        }
    }
    invocation.invoke();

}复制代码通过AOP和注解对数据进行非空校验,无需一个个判断参数是否为空,数据为空直接返回 自定义分页数据接收,自动处理分页参数和数据对象,给controller方法加上参数 BasePageRequest,T为对象类型,然后参数就会自动组装成分页参数和定义的对象类,以下为实现代码:

public class PageParaGetter extends ParaGetter<BasePageRequest> {
    public PageParaGetter(String parameterName, String defaultValue) {
        super(parameterName, defaultValue);
    }
    @Override
    protected BasePageRequest to(String s) {
        return null;
    }
@Override
@SuppressWarnings("unchecked")
public BasePageRequest get(Action action, Controller controller) {
    Parameter[] parameters=action.getMethod().getParameters();
    Class clazz=null;
    for (Parameter parameter:parameters){
        if(BasePageRequest.class.isAssignableFrom(parameter.getType())){
            Type parameterizedType=parameter.getParameterizedType();
            if (parameterizedType instanceof ParameterizedType) {
                Type[] params = ((ParameterizedType) parameterizedType).getActualTypeArguments();
                clazz= TypeUtils.getClass(params[0]);
            }
            break;
        }
    }
    boolean isJson=controller.getHeader("Content-Type")!=null&&controller.getHeader("Content-Type").toLowerCase().contains("application/json");
    return isJson?new BasePageRequest(controller.getRawData(),clazz):new BasePageRequest(controller.getKv(),clazz);
}
}

复制代码自定义json工厂,实现对数据的个性化解析返回,如实现将数据返回时将数据转成驼峰规则,自定义某种类型的对象的返回格式等。可以自定义错误处理模板,在出现错误或者其他异常的情况下,可以给予用户一个清晰的提示,避免用户看到一些无用的错误信息等功能文件可以上传到项目目录之外,避免了重新打包项目后文件的丢失

@Override
public void configConstant(Constants me) {
    me.setDevMode(prop.getBoolean("jfinal.devMode", true));
    me.setInjectDependency(true);
    //设置上传文件到哪个目录
    me.setBaseUploadPath(BaseConstant.UPLOAD_PATH);
    me.setBaseDownloadPath(BaseConstant.UPLOAD_PATH);
  //自定义json工厂
    me.setJsonFactory(new ErpJsonFactory());
    //限制上传100M
    me.setMaxPostSize(104857600);
}

复制代码采用项目分层化的设计,职责分工明确,降低代码的耦合性Hander->对指定规则的url进行捕获或者放心Interceptor->环绕式AOP拦截,对访问权限,数据权限,参数等进行校验,可以配置在全局,单个路由,单个controller,单个方法等上面,可进行自定义实现,对数据进行处理Router->对不同规则的数据进行分发,不同url进入不同路由和controllerController->对参数进行组装,将数据传入到service处理后进行render返回Service->对业务代码进行处理,并将数据转入Db处理或缓存 Db->对数据库进行操作 Render->将service返回的数据在controller进行返回,以及出错后通过SQL模板功能,将sql写入到xx.sql文件中,如果sql文件有变动,无需重新编译打包,直接改动sql文件中的sql即可,以下为自动扫描指定路径下sql文件的代码:

private void getSqlTemplate(String path, ActiveRecordPlugin arp) {
    File file = new File(path);
    if (file.exists()) {
        File[] files = file.listFiles();
        if (files != null && files.length > 0) {
            for (File childFile : files) {
                if (childFile.isDirectory()) {
                    getSqlTemplate(childFile.getAbsolutePath(), arp);
                } else {
                    if (childFile.getName().toLowerCase().endsWith(".sql")) {
                        arp.addSqlTemplate(childFile.getAbsolutePath().replace(PathKit.getRootClassPath(), "").replace("\\", "/"));
                    }
                }
            }
        }
    }
}

PHP版本后端框架:

ThinkPHP 5.0.2
前端MVVM框架:Vue.JS 2.5.x
路由:Vue-Router 3.x
数据交互:AxiosUI
框架:Element-UI 2.6.3
悟空crm9.0的运行环境要求PHP5.6以上悟空CRM9.0(PHP)版本应用部署
目录结构

├─application           应用目录(可设置)
│  ├─admin               系统设置目录
│  │  ├─config.php      模块配置文件
│  │  ├─common.php      模块函数文件
│  │  ├─controller      控制器目录
│  │  ├─model           模型目录
│  │  ├─validate        验证器目录
│  │  ├─view            视图目录
│  │  └─lang            语言包
│  ├─bi                  商业智能模块目录
│  │  ├─config.php      模块配置文件
│  │  ├─common.php      模块函数文件
│  │  ├─controller      控制器目录
│  │  ├─model           模型目录
│  │  ├─validate        验证器目录
│  │  ├─view            视图目录
│  │  └─lang            语言包
│  ├─common              公共模块目录
│  │  ├─adapter         认证权限类目录
│  │  ├─behavior        行为(钩子)目录
│  │  ├─controller      公共控制器目录
│  │  └─lang            语言包
​
│  ├─crm                 客户管理目录
│  │  ├─config.php      模块配置文件
│  │  ├─common.php      模块函数文件
│  │  ├─controller      控制器目录
│  │  ├─model           模型目录
│  │  ├─validate        验证器目录
│  │  ├─view            视图目录
│  │  └─lang            语言包
│  ├─lang                语言包
│  ├─oa                  办公目录
│  │  ├─config.php      模块配置文件
│  │  ├─common.php      模块函数文件
│  │  ├─controller      控制器目录
│  │  ├─model           模型目录
│  │  ├─validate        验证器目录
│  │  ├─view            视图目录
│  │  └─lang            语言包
│  ├─work                项目管理目录
│  │  ├─config.php      模块配置文件
│  │  ├─common.php      模块函数文件
│  │  ├─controller      控制器目录
│  │  ├─model           模型目录
│  │  ├─validate        验证器目录
│  │  ├─view            视图目录
│  │  └─lang            语言包
│  ├─command.php        命令行工具配置文件
│  ├─common.php         应用公共(函数)文件
│  ├─tags.php           应用行为扩展定义文件
├─config                配置目录(可定义)
│  ├─config.php         应用(公共)配置文件
│  ├─database.php       数据库配置文件
│  ├─route_admin.php    系统设置路由文件
│  ├─route_bi.php       商业智能路由文件
│  ├─route_crm.php      客户管理路由文件
│  ├─route_oa.php       办公路由文件
│  ├─route_work.php     项目管理路由文件
│  └─version.php        版本信息文件
├─extend                扩展类库目录(可定义)
├─public                WEB 部署目录(对外访问目录)
│  ├─sql                安装及更新sql目录
│  ├─static             静态资源存放目录(css,js,image)
│  └─.uploads           上传文件目录
├─runtime               应用的运行时目录(可写,可设置)
├─static                前端VUE打包目录=
├─vendor                第三方类库目录(Composer)
├─thinkphp              框架系统目录
│  ├─lang               语言包目录
│  ├─library            框架核心类库目录
│  │  ├─think           Think 类库包目录
│  │  └─traits          系统 Traits 目录
│  ├─tpl                系统模板目录
│  ├─.htaccess          用于 apache 的重写
│  ├─.travis.yml        CI 定义文件
│  ├─base.php           基础定义文件
│  ├─composer.json      composer 定义文件
│  ├─console.php        控制台入口文件
│  ├─convention.php     惯例配置文件
│  ├─helper.php         助手函数文件(可选)
│  ├─LICENSE.txt        授权说明文件
│  ├─phpunit.xml        单元测试配置文件
│  ├─README.md          README 文件
│  └─start.php          框架引导文件
├─composer.json         composer 定义文件
├─LICENSE.txt           授权说明文件
├─README.md             README 文件
├─think                  命令行入口文件
├─index.php             应用入口文件
├─index.html            前端展示入口文件复制代码系统截图

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
github上开源的UVCCamera为什么不能正常运行
github上开源的UVCCamera为什么不能正常运行
0 0
名垂千古的机会到了,一文说清【给开源大项目贡献代码】二三事(github,pr,fork,ci)
名垂千古的机会到了,一文说清【给开源大项目贡献代码】二三事(github,pr,fork,ci)
0 0
Github 上最大的开源算法库,还能学机器学习!
Github 上最大的开源算法库,还能学机器学习!
0 0
开源多年后,Facebook这个调试工具,再登Github热门榜
让许多工程师合作开发大型应用大多会面临一个挑战,通常没有一个人知道每个模块是如何工作的,这种技能会让开发新功能、调查Bug或优化性能变得困难,为了解决这个问题,Facebook创建并开源了Flipper,一个可扩展的跨平台的调试工具,用来调试 iOS 和 Android 应用。近日又双叒登上了Github热榜。
0 0
Github上热搜的Java开源商城项目合集,这个是真的好
mall-swarm是一套微服务商城系统,采用了 Spring Cloud Hoxton & Alibaba、Spring Boot 2.3、Oauth2、MyBatis、Docker、Elasticsearch等核心技术,同时提供了基于Vue的管理后台方便快速搭建系统。mall-swarm在电商业务的基础集成了注册中心、配置中心、监控中心、网关等系统功能。文档齐全,附带全套Spring Cloud教程。 其它的先不说,一起来看看运行效果,首先是注册中心注册服务信息:
0 0
造孽啊!阿里内部的神级项目和JDK源码阅读指南竟惨遭GitHub开源
背景 今天逛GitHub,发现了一个神级项目,作者将整理/记录阅读JDK源码时的理解与体会分享出来,便于大家学习。这里将项目分享出来,让小伙伴们能更好地学习Java。
0 0
同程内网流传的分布式凤凰缓存系统手册,竟遭GitHub强行开源下载
什么是分布式缓存? 分布式缓存能够处理大量的动态数据,因此比较适合应用在Web 2.0时代中的社交网站等需要由用户生成内容的场景。从本地缓存扩展到分布式缓存后,关注重点从CPU、内存、缓存之间的数据传输速度差异也扩展到了业务系统、数据库、分布式缓存之间的数据传输速度差异。 今天给大家分享的是一本从大型互联网大厂系统角度探讨分布式系统的手册,从原理、框架、架构、案例等多个视角对分布式缓存进行了探讨
0 0
聚变!牛客网开源1240页字节算法实录,无意中掀起GitHub刷题热潮
众所周知,字节跳动因为需要较高的推送准确率,所以对于数据结构与算法看得十分重要,放眼全球,字节跳动的数据结构与算法都可以说是“首屈一指”的,可以称得上是最锋利的“矛”,更有甚者说掌握了字节的算法,基本上半个身子就算是进了大厂了,所以算法刷一份字节跳动的算法,还是很有必要的。 应众粉丝要求,凯撒可以说是“跑断了腿,求没了人,熬坏了眼”,终于是搞出了一份相当全面的《字节千题算法实录》,共十四部分,今天免费分享给大家,以感谢大家一直以来对我的支持,一起看下:
0 0
真香!Github一夜爆火,阿里性能优化不传之秘终于开源
性能调优,是从开发岗跃迁至架构岗的拦路虎。如果你是一个小白,那么恭喜你性能优化这个东西你暂时还不需要扛着。但如果你是公司的中坚力量,想把技术水平往架构层面靠近,那么性能优化这个东西你必须要扛下来,并且解决它。
0 0
Github 标星 5.2K+!bloomberg 开源 Python 内存分析器“Memray”
Github 标星 5.2K+!bloomberg 开源 Python 内存分析器“Memray”
0 0
+关注
文章
问答
文章排行榜
最热
最新
相关电子书
更多
Elastic(中国)基础开发宝典
立即下载
蚂蚁金服高级开发工程师萧恺:IDEA 插件开发入门教程
立即下载
开发者专场-三红 kingsum Dragonwell云栖最终版
立即下载