Code Monkey home page Code Monkey logo

matevip / matecloud Goto Github PK

View Code? Open in Web Editor NEW
1.5K 38.0 414.0 13.89 MB

🔥MateCloud是一款基于Spring Cloud Alibaba的微服务架构。目前已经整合Spring Boot 2.7.0、 Spring Cloud 2021、Spring Cloud Alibaba 2021、Spring Security Oauth2、Feign、Dubbo、JetCache、RocketMQ等,支持多租户的低代码平台,Saas平台开发套件

Home Page: http://www.mate.vip

License: Apache License 2.0

Java 82.24% Dockerfile 0.01% CSS 0.09% JavaScript 12.53% FreeMarker 5.12%
springcloud spring-cloud-alibaba spring-boot rocketmq springcloudalibaba springboot-springcloud microservice microservices-architecture cloudspring springboot-admin

matecloud's Introduction

License Stars SpringBoot SpringCloud Spring Cloud Alibaba

🍟 如果您觉得有帮助,请点右上角 "Star" 支持一下谢谢

MateCloud是一款基于Spring Cloud Alibaba的微服务架构。旨在为大家提供技术框架的基础能力的封装,减少开发工作,让您只关注业务。

🎨 系统演示

👉 演示地址:https://cloud.dabu.vip

账号 密码 操作权限
admin matecloud mate-system模块不能执行增删改请求

🍯 商业版:https://plus.dabu.vip

管理员类型 账号 密码 用途
超级管理员 admin matecloud123 超级用户
租户管理员 tenant matecloud123 此处模拟商城系统

注意:租户管理员的菜单完全自定义,可用于扩展开发商城系统、CRM系统、OA系统等任意系统需求。

商业版与开源版对比

📌 版本演进

核心中间件 2.5.8及以下 当前:4.4.9+
Spring Boot 2.3.*.RELEASE SpringBoot
Spring Cloud Hoxton SR* SpringCloud
Spring Cloud Alibaba 2.2.*.RELEASE SpringCloudAlibaba
Nacos 1.4.*及以下 nacos
Sentinel 1.8.1 sentinel

📖 官方文档

👉 文档:http://doc.dabu.vip

👷 技术交流

👉 QQ群:2003638

🍪 技术架构

❓ 部分截图

🔧 功能特点

  • 主体框架:采用最新的Spring Cloud 2021.0.8, Spring Boot 2.7.14, Spring Cloud Alibaba 2021.0.8.0版本进行系统设计;

  • 统一注册:支持Nacos作为注册中心,实现多配置、分群组、分命名空间、多业务模块的注册和发现功能;

  • 统一认证:统一Oauth2认证协议,采用jwt的方式,实现统一认证,并支持自定义grant_type实现手机号码登录,第三方登录集成JustAuth实现微信、支付宝等多种登录模式;

  • 业务监控:利用Spring Boot Admin来监控各个独立Service的运行状态。

  • 内部调用:集成了FeignDubbo两种模式支持内部调用,并且可以实现无缝切换,适合新老程序员,快速熟悉项目;

  • 业务熔断:采用Sentinel实现业务熔断处理,避免服务之间出现雪崩;

  • 身份注入:通过注解的方式,实现用户登录信息的快速注入;

  • 在线文档:通过接入Knife4j,实现在线API文档的查看与调试;

  • 代码生成:基于Mybatis-plus-generator自动生成代码,提升开发效率,生成模式不断优化中,暂不支持前端代码生成;

  • 消息中心:集成消息中间件RocketMQKafka,对业务进行异步处理;

  • 业务分离:采用前后端分离的框架设计,前端采用vue-element-admin,商业版采用antd-pro-vue

  • 链路追踪:自定义traceId的方式,实现简单的链路追踪功能

  • 多租户功能:集成Mybatis Plus,实现SAAS多租户功能

🗿 文件结构

matecloud -- 父项目,各模块分离,方便集成和微服务
│  ├─mate-core -- 核心通用模块,主模块
│  │  ├─mate-starter-common -- 封装通用模块
│  │  ├─mate-starter-cloud -- 封装微服务模块
│  │  ├─mate-starter-auth -- 封装token验证模块
│  │  ├─mate-starter-security -- 封装OAuth2基础模块
│  │  ├─mate-starter-web -- 封装WEB服务基础模块
│  │  ├─mate-starter-database -- 封装Mybatis及数据库基础模块
│  │  ├─mate-starter-dependencies -- 封装所有依赖模块,可作为父项目独立引用
│  │  ├─mate-starter-dubbo -- 封装dubbo基础模块
│  │  ├─mate-starter-feign -- 封装feign基础模块
│  │  ├─mate-starter-jetcache -- 封装JetCache阿里缓存基础模块
│  │  ├─mate-starter-rocketmq -- 封装RocketMQ基础模块
│  │  ├─mate-starter-gray -- 封装灰度发布基础模块
│  │  ├─mate-starter-elasticsearch -- 封装ElasticSearch模块
│  │  ├─mate-starter-oss -- 封装oss存储基础模块,支持阿里云、七牛云、minio等
│  │  ├─mate-starter-log -- 封装日志基础模块
│  │  ├─mate-starter-sharding -- 封装多数据库基础模块
│  │  ├─mate-starter-sms -- 封装短信基础模块
│  │  ├─mate-starter-mail -- 封装邮件模块
│  │  ├─mate-starter-kafka -- 封装kafka基础模块
│  │  ├─mate-starter-rule -- 封装黑名单基础模块
│  │  ├─mate-starter-idempotent -- 封装幂等基础模块
│  │  ├─mate-starter-lock -- 封装分布式锁基础模块
│  │  ├─mate-starter-encrypt -- 封装报文加密模块,支持AES和RSA
│  │  ├─mate-starter-mongodb -- 封装mongodb数据库模块
│  │  ├─mate-starter-strategy -- 封装策略模块
│  │  ├─mate-starter-job -- 封装定时任务基础模块
│  │  ├─mate-starter-validator -- 封装统一检验基础模块
│  │─mate-gateway -- 统一网关模块 [10001]
│  │─mate-uaa -- 统一认证中心模块 [20001]
│  │─mate-platform -- 平台模块项目,目前包含系统子模块
│  │  ├─mate-system-api -- 系统模块的通用模块,供其他模块引用
│  │  ├─mate-system -- 系统模块核心功能 [20002]
│  │  ├─mate-component-api -- 组件模块核心功能,供其他模块引用
│  │  ├─mate-component -- 组件模块核心功能 [20003]
│  │─mate-support -- 支持中心项目,目前包括代码生成、admin模块
│  │  ├─mate-code -- 封装代码生成逻辑 [30002]
│  │  ├─mate-admin -- 封装spring-boot-admin逻辑 [30001]
│  │  ├─mate-job -- xxl-jog定时任务模块
│  │  ├─mate-job-admin -- 定时任务管理平台模块
│  │─mate-mq -- 消息中心项目,支持kafka、RocketMQ等多种消息中间件
│  │  ├─mate-log-producer -- 日志消息生产者,集成kafka [40001]
│  │  ├─mate-message-consumer -- 消息服务消费者 [40002]
│  │  ├─mate-message-producer -- 消息服务生产者 [40003] 

🎨 核心模块提交至**仓库

如何引入依赖

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>vip.mate</groupId>
            <artifactId>mate-starter-dependencies</artifactId>
            <version>4.6.8</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

然后在 dependencies 中添加自己所需使用的依赖即可使用。

🔥 前端重大更新

前端采用Vue 3.2.12Vite 2.5.8Ant-Design-Vue 2.2.8TypeScript 的大型中后台解决方案。

👉 技术栈

  • Vue 3.2.45
  • Pinia 2.0.28
  • Vue-i18n 9.1.8
  • Ant-design-vue 2.2.6
  • Axios 1.2.1
  • Vue-router 4.3.8
  • Vite 3.2.5

👉 版本发布

4.6.8版本已经发布,完善了系统管理的基础功能,主要包括菜单管理、用户管理、角色管理、部门管理、日志管理、客户端管理等功能。后续功能正在加紧开发中,欢迎体验。

🌭 项目源码

项目 GITHUB 码云
MateCloud后端源码 https://github.com/matevip/matecloud https://gitee.com/matevip/matecloud
Artemis前端源码 https://github.com/matevip/artemis https://gitee.com/matevip/artemis
MateBoot后端源码 https://github.com/matevip/mateboot https://gitee.com/matevip/mateboot

🥥 微服务项目示例

🌭 Swagger2 - OpenAPI3

Swagger2 OpenAPI3 注解位置
@Api @Tag(name = "接口类描述") Controller 类上
@ApiOperation @Operation(summary ="接口方法描述") Controller 方法上
@ApiImplicitParam @Parameter(description="参数描述") Controller 方法上 @Parameters 里
@ApiImplicitParams @Parameters Controller 方法上
@ApiParam @Parameter(description="参数描述") Controller 方法的参数上
@ApiIgnore @Parameter(hidden = true) 或 @Operation(hidden = true) 或 @Hidden ----
@ApiModel @Schema Entity类上
@ApiModelProperty @Schema Entity属性上

🍻 贡献者名单

欢迎提交PR一起完善项目,以下为开源项目贡献的战友(排名不分先后):

@L.cm、@Z先生、@苏慕彦、@简、@madi、@yunfei08、@hackerdom

✨ 特别鸣谢

特别感谢卢神对MateCloud项目提供的技术支持!

📚 开源项目推荐

matecloud's People

Contributors

aaronuu avatar dependabot[bot] avatar fuce1314 avatar matevip avatar wangyiidii avatar yunfei08 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

matecloud's Issues

Using hardcoded/Constant cryptographic key when creating and verifing Json Web Token.

Hi, we are a research group to help developers build secure applications. We designed a cryptographic misuse detector on Java language(Our main concern is the secure implementation and use of Json Web Token). We found your great public repository (i.e., matecloud
Public) from GitHub, and several security issues detected by our detector are shown in the following. The specific security issues we found are as follows:
(1) Location: Package: cpackage vip.mate.uaa.config; Class: AuthServerConfig .class
Method:jwtAccessTokenConverter
Hard-coded key: public static final String SIGN_KEY = "MATE";
Security issue: Using predictable/constant cryptographic key when creating and verifing Json Web Token.
Using a hard-coded secret does not conform to the security implementation specification of JWT, which may bring security risks to your system. It is recommended that you use a more secure way to store the secret used to generate the JWT. (For the hazards of hardcoded keys, you can refer to CWE-321, NIST Special Publication 800-57).

We wish the above security issues cloud truly help you to build a secure application. If you have any concern or suggestion, please feel free to contact us, we are looking forward to your reply. Thanks.

ExcelUtil类defaultExport方法有bug

private static void defaultExport(List list, Class pojoClass, String fileName,
HttpServletResponse response, ExportParams exportParams) {
Workbook workbook = ExcelExportUtil.exportExcel(exportParams,pojoClass,list);
if (workbook != null); downLoadExcel(fileName, response, workbook);
}

if (workbook != null)之后多了一个分号

MyBatis-Plus自动填充功能

看作者在mate-starter-database模块中用的mybatis-plus版本为3.4.0, 使用自带的handler处理createTime填充时,插入一直为null, 使用旧版的strictInsertFill()才好用,是怎么回事? 下面解释掉的两种方试都不管用

   /*this.strictUpdateFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now());
    this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());*/

    /*this.strictUpdateFill(metaObject, "createTime", () -> LocalDateTime.now(), LocalDateTime.class);
    this.strictUpdateFill(metaObject, "updateTime", () -> LocalDateTime.now(), LocalDateTime.class);*/

    log.info("start insert fill ....");
    this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now());
    this.strictInsertFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());

限流、熔断统一处理类 WebfluxHandler 不生效

限流、熔断统一处理类 WebfluxHandler 不生效

WebfluxHandler.java 44 line

    /**
     * 限流、熔断统一处理类
     */
    @Configuration
    @ConditionalOnClass(ServerResponse.class)
    public static class WebfluxHandler {
        @Bean
        public BlockRequestHandler webfluxBlockExceptionHandler() {
            return (exchange, t) ->
                    ServerResponse.status(HttpStatus.TOO_MANY_REQUESTS)
                            .contentType(MediaType.APPLICATION_JSON)
                            .body(BodyInserters.fromValue(Result.fail(t.getMessage())));
        }
    }

跨域问题

你好在网关没有看到cros相关的代码,请问作者是怎么解决跨域的呢?niginx还是?

EnableMateFeign的一个BUG

复现步骤:

  1. 在一个Feign[POST]请求中,连续调用两个Feign[GET]请求

现象:连续两个调用中,永远第一个成功,第二个失败

错误信息:

feign.FeignException$BadRequest: [400 Bad Request] during [GET] to [http://ums/rpc/staff/query?partyId=20210326113752311294202859057154] [UmsStaffFeignClient#queryByPartyId(String)]: []
        at feign.FeignException.clientErrorStatus(FeignException.java:195)
        at feign.FeignException.errorStatus(FeignException.java:177)
        at feign.FeignException.errorStatus(FeignException.java:169)
        at feign.codec.ErrorDecoder$Default.decode(ErrorDecoder.java:92)
        at feign.AsyncResponseHandler.handleResponse(AsyncResponseHandler.java:96)
        at feign.SynchronousMethodHandler.executeAndDecode(SynchronousMethodHandler.java:138)
        at feign.SynchronousMethodHandler.invoke(SynchronousMethodHandler.java:89)
        at com.alibaba.cloud.sentinel.feign.SentinelInvocationHandler.invoke(SentinelInvocationHandler.java:107)
        at com.sun.proxy.$Proxy218.queryByPartyId(Unknown Source)

gateway动态路由似乎没有移除废弃路由规则的这个功能?

gateway模块动态路由的实现方式似乎没有删除废弃路由的逻辑。我做了如下改造,不知道是否可行?

package com.example.gateway.config.route;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.nacos.api.NacosFactory;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.listener.Listener;
import com.alibaba.nacos.api.exception.NacosException;
import com.example.gateway.config.NacosGatewayProperties;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.cloud.gateway.event.RefreshRoutesEvent;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionRepository;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.context.annotation.DependsOn;
import org.springframework.lang.NonNull;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;

import javax.annotation.PostConstruct;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.Executor;


/**
 * @author hcq
 * @date 2020/11/4 19:31
 */
@Slf4j
@Component
@DependsOn({"nacosProperties"})
public class DynamicRouteConfig implements ApplicationEventPublisherAware {

    /**
     * 路由规则仓库
     */
    private final RouteDefinitionRepository definitionRepository;

    /**
     * 发布Application事件
     */
    private ApplicationEventPublisher publisher;

    /**
     * NacosConfig Client用于监听Nacos配置变更
     */
    private ConfigService configService;

    private DynamicRouteConfig(RouteDefinitionRepository definitionRepository) {
        this.definitionRepository = definitionRepository;
    }

    @Override
    public void setApplicationEventPublisher(@NonNull ApplicationEventPublisher publisher) {
        this.publisher = publisher;
    }

    @PostConstruct
    public void init() {
        // 初始化Nacos配置的路由规则,并获取NacosClient
        configService = initConfig();
        // 监听Nacos配置文件
        dynamicRouteByNacosListener(NacosGatewayProperties.NACOS_ROUTE_DATA_ID, NacosGatewayProperties.NACOS_ROUTE_GROUP);
    }

    /**
     * 初始化NacosRoutes
     */
    private ConfigService initConfig() {
        log.info("gateway route init...");
        ConfigService configService = null;
        try {
            Properties properties = new Properties();
            properties.setProperty("serverAddr", NacosGatewayProperties.NACOS_SERVER_ADDR);
            properties.setProperty("namespace", NacosGatewayProperties.NACOS_NAMESPACE);
            configService = NacosFactory.createConfigService(properties);
            if (configService == null) {
                log.warn("initConfigService fail");
                throw new IllegalArgumentException("initConfigService fail");
            }
            String configInfo = configService.getConfig(NacosGatewayProperties.NACOS_ROUTE_DATA_ID, NacosGatewayProperties.NACOS_ROUTE_GROUP, NacosGatewayProperties.DEFAULT_TIMEOUT);
            // 初始化路由规则
            if (StringUtils.isNotBlank(configInfo)) {
                updateRouteRule(configInfo);
            }
        } catch (Exception e) {
            log.error("初始化网关路由时发生错误", e);
        }
        return configService;
    }

    /**
     * 根据Nacos中配置的路由规则json串更新路由规则
     *
     * @param routesStr Nacos中配置的路由规则json串
     */
    private void updateRouteRule(String routesStr) {
        System.out.println(this);
        log.info("更新gateway路由规则\n\r{}", routesStr);
        definitionRepository.getRouteDefinitions().collectMap(RouteDefinition::getId).subscribe(oldRoutes -> {
            List<RouteDefinition> nowRoutes = JSONObject.parseArray(routesStr, RouteDefinition.class);
            // 删除原有规则
            for (RouteDefinition oldRoute : oldRoutes.values()) {
                log.info("gateway remove route {}", oldRoute);
                definitionRepository.delete(Mono.just(oldRoute.getId())).subscribe();
            }
            // 加载配置文件中的规则
            for (RouteDefinition route : nowRoutes) {
                log.info("gateway add route {}", route);
                definitionRepository.save(Mono.just(route)).subscribe();
            }
            this.publisher.publishEvent(new RefreshRoutesEvent(this));
        });
    }

    /**
     * 监听Nacos下发的动态路由配置
     *
     * @param dataId 路由规则
     * @param group  路由规则group
     */
    private void dynamicRouteByNacosListener(String dataId, String group) {
        try {
            DynamicRouteConfig routeConfig = this;
            configService.addListener(dataId, group, new Listener() {
                @Override
                public void receiveConfigInfo(String configInfo) {
                    System.out.println(this);
                    System.out.println(routeConfig);
                    routeConfig.updateRouteRule(configInfo);
                }

                @Override
                public Executor getExecutor() {
                    log.info("getExecutor\n\r");
                    return null;
                }
            });
        } catch (NacosException e) {
            log.error("从nacos接收动态路由配置出错!!!", e);
        }
    }


}

uaa认证模块中的验证码存在NPE

String codeFromRedis = redisService.get(Oauth2Constant.CAPTCHA_KEY + key).toString();

object如果是null,.toString(),就会出现NPE,不会进入下面的判断!

if (codeFromRedis == null) {
throw new UserDeniedAuthorizationException("验证码已过期");
}

PreRequestFilter 中的transID在RequestLogFilter并未使用到

在PreRequestFilter 中定义了transID,在RequestLogFilter也有获取,但是之后的打印并未使用到,参见:
RequestLogFilter.java lines:36,
String traceId = exchange.getRequest().getHeaders().getFirst(MateConstant.MATE_TRACE_ID);
这个变量并未在该过滤器之后的逻辑中使用。

Integrate dubbo-admin

1,Integrate dubbo-admin console program, and visualize dubbo interface information and configuration information

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.