悟空CRM(基于Jfinal+vue+ElementUI)核心代码讲解

代码仓库地址https://gitee.com/wukongcrm/7...

悟空CRM采用全新的前后端分离模式,本仓库代码中已集成前端vue打包后文件,可免去打包操作

如需调整前端代码,请单独下载前端代码,前端代码在根目录的ux文件夹中

主要技术栈

核心框架: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

数据交互:Axios

UI框架:Element-UI 2.6.3

悟空CRM是一个基于jfinal的开源crm系统,采用前后端分离的开发模式,提供了Aop,查询缓存,数据库连接池,定时器,excel导入导出等功能。

项目中主要有CRM,OA,项目管理,BI等模块,通过角色,部门,菜单实现了按钮级的功能权限控制和数据权限控制,通过将用户登录信息保存至redis来实现支持项目的热重启和分布式部署。

项目还拥有如下特性:

项目通过jfinal强大的AOP将权限判断从代码中抽离出来,用户无需手动判断登陆角色是否拥有权限,以下为通过权限注解在拦截器判断用户是否拥有访问权限

@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>,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进入不同路由和controller

Controller->对参数进行组装,将数据传入到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("\\", "/"));
                    }
                }
            }
        }
    }
}

以下是系统的部分截图:以下为悟空CRM9.0 JAVA版部分功能系统截图
图片描述

图片描述

悟空CRM9.0

3 声望
2 粉丝
0 条评论
推荐阅读
悟空CRM-11.0介绍
悟空CRM-11.0悟空CRM介绍演示地址:[链接]下载地址:[链接] {代码...} 悟空CRM目录结构 {代码...} 悟空CRM使用的主要技术栈名称版本说明spring-cloud-alibaba2.2.1.RELEASE(Hoxton.SR3)核心框架swagger2.9.2接口...

悟空CRM1阅读 2.1k

如何使用 PHPStorm 进行优雅的项目开发?
PHP Storm 这个开发工具,很多 phper 应该有所耳闻,甚至也有不少人使用其作为生产工具,但是很多人都没有最大限度的使用它,本文就来总结一些优雅开发的小技巧。

唯一丶45阅读 4.8k评论 7

怎样用 PHP 来实现枚举?
在数学和计算机科学理论中,一个集的枚举是列出某些有穷序列集的所有成员的程序,或者是一种特定类型对象的计数。这两种类型经常(但不总是)重叠。枚举是一个被命名的整型常数的集合,枚举在日常生活中很常见,...

唯一丶25阅读 6.4k评论 4

刨根问底 Redis, 面试过程真好使
充满寒气的互联网如何在面试中脱颖而出,平时积累很重要,八股文更不能少!下面带来的这篇 Redis 问答希望能够在你的 offer 上增添一把🔥。

菜农曰17阅读 973

封面图
PHP转Go实践:xjson解析神器「开源工具集」
我和劲仔都是PHP转Go,身边越来越多做PHP的朋友也逐渐在用Go进行重构,重构过程中,会发现php的json解析操作(系列化与反序列化)是真的香,弱类型语言的各种隐式类型转换,很大程度的减低了程序的复杂度。

王中阳Go10阅读 2k评论 3

封面图
万字详解,吃透 MongoDB!
MongoDB 是一个基于 分布式文件存储 的开源 NoSQL 数据库系统,由 C++ 编写的。MongoDB 提供了 面向文档 的存储方式,操作起来比较简单和容易,支持“无模式”的数据建模,可以存储比较复杂的数据类型,是一款非常...

JavaGuide5阅读 847

封面图
计算机网络连环炮40问
本文已经收录到Github仓库,该仓库包含计算机基础、Java基础、多线程、JVM、数据库、Redis、Spring、Mybatis、SpringMVC、SpringBoot、分布式、微服务、设计模式、架构、校招社招分享等核心知识点,欢迎star~

程序员大彬8阅读 1.1k

悟空CRM9.0

3 声望
2 粉丝
宣传栏