# luck01-parent **Repository Path**: luck19920329/luck01-parent ## Basic Information - **Project Name**: luck01-parent - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2021-05-25 - **Last Updated**: 2021-06-01 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 教学crm系统 ## 项目描述: 该项目企业合作顾问,职业发展老师,项目经理老师,品保经理,教学经理的学员管理,VIP跟进,企业合作信息录入,学员面试情况跟踪,日常备忘录,项目经理的学员信息采集表导入, 学分情况导入,学员模拟面试评估 ## 技术选型: springCloud: nacos注册中心 : 消费提供都需要添加 nacos配置中心 : 需要自动推送配置的项目需要添加 gatway网关 : 独立服务器 openfign远程调用 : 消费远程调用时,需要添加 hystrix-dashboard仪表盘 : 暂无 springSurity授权+jwt授权认证 : 认证独立服务器 auth2第三方授权 : wx,公众号,小程序等 redis缓存 : 需要缓存系统添加 RocketMQ消息队列 : 需要消息服务添加配置,独立服务器 nginx 反向代理服务器 : 入口 mysql数据库 : 提供者需要添加 swagger接口文档 : 正式开发,API接口都需要添加 ## 打包父子项目 ![image-20210427170751746](中山达内项目.assets/image-20210427170751746.png) ## 系统拆分 ![image-20210319114545682](中山达内项目.assets/image-20210319114545682.png) ## 功能模块: ### 注册中心 配置中心 ### 流控系统 ### 缓存服务 ### 前台系统功能模块 ### 后台系统功能模块: #### 系统管理: 菜单 角色 用户 监控 定时任务 #### 企业合作: 学员面试跟踪录入 ,学员就业公司录入 , 当月要毕业学员 #### 职业发展: 脱产职业发展: 导入学员信息采集表,新建班级, 班级职业发展和项目经理, 跟进记录,学员备注 ,学员学分记录表,学员绑定外键,学分扣除记录表 VIP学员跟进记录, VIP备注增值意向,VIP学员CRM导出再导入该系统功能 #### 项目经理: 学员信息采集表导入新建班级,产品线目前实际人数及备忘表,学员模拟面试表,所带班级 #### 教学经理: 以上所有 #### 品保经理: 以上所有 ### 认证授权模块 所有需要认证的业务都需要到认证授权服务器实现 ## 具体技术重点: **springCloud - Alibaba 跟springCloud和springBoot版本的依赖关系**:https://github.com/alibaba/spring-cloud-alibaba/wiki/版本说明 ### sp01-parent.pom.xml ```xml 4.0.0 pom manage-admin common front configuration-management monitor-protection org.springframework.boot spring-boot-starter-parent 2.3.5.RELEASE cn.tedu luck01-parent 0.0.1-SNAPSHOT luck01-parent Demo project for Spring Boot 1.8 3.1.1 3.1.1 1.2.75 org.springframework.cloud spring-cloud-dependencies Hoxton.SR8 import pom com.alibaba.cloud spring-cloud-alibaba-dependencies 2.2.5.RELEASE pom import org.springframework.boot spring-boot-starter org.springframework.boot spring-boot-starter-test test org.springframework.boot spring-boot-maven-plugin ``` ### configuration-management 子系统实现 ### nacos注册中心 集群模式生产环境: https://www.cnblogs.com/zlt2000/p/11381823.html **端口8848** **官方文档:** https://nacos.io/zh-cn/docs/architecture.html **安装nacos** 第一步:Nacos 下载,可在浏览器直接输入如下地址: https://github.com/alibaba/nacos/releases 第二步:选择对应版本,直接下载,如图所示: ![image-20210319141331490](中山达内项目.assets/image-20210319141331490.png) 第三步:解压 Nacos(最好不要解压到中文目录下),其目录结构如下 ![image-20210319141347079](中山达内项目.assets/image-20210319141347079.png) **配置nacos并启动:** 第一步:找到/conf/nacos-mysql.sql 文件里的 sql 脚本,然后登陆 mysql,然后基 于脚本文件中的描述创建数据库,并执行脚本文件,脚本执行成功会创建一些表,如图所示: ![image-20210319141507737](中山达内项目.assets/image-20210319141507737.png) 第二步:打开/conf/application.properties 里打开默认配置,并基于你当前环境 配置要连接的数据库,连接数据库时使用的用户名和密码: ```yml ### If use MySQL as datasource: spring.datasource.platform=mysql ### Count of DB: db.num=1 ### Connect URL of DB: db.url.0=jdbc:mysql://127.0.0.1:3306/nacos_config?characterEncoding= utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnico de=true&useSSL=false&serverTimezone=UTC db.user=root db.password=root ``` **服务启动与访问** Linux/Unix/Mac 启动命令(standalone 代表着单机模式运行,非集群模式): sh startup.sh -m standalone Windows 启动命令(standalone 代表着单机模式运行,非集群模式): startup.cmd -m standalone 打开浏览器,输入 http://localhost:8848/nacos 地址,出现如下登陆页面: 其中,默认账号密码为 nacos/nacos. #### **nacos注册发现配置原理:** https://zhuanlan.zhihu.com/p/353376366 #### 配置nacos-client(服务提供者) 添加依赖 ```xml com.alibaba.cloud spring-cloud-starter-alibaba-nacos-discovery ``` 修改yml文件 ```yml spring: application: name: nacos-provider cloud: nacos: server-addr: localhost:8848 ``` 注意:服务名不要使用下划线(“_”),应使用横杠(“-”),这是规则 #### 配置nacos-client(服务消费者者) ```pom.xml org.springframework.boot spring-boot-starter-web com.alibaba.cloud spring-cloud-starter-alibaba-nacos-discovery ``` yml文件 ```yml server: port: 7001 servlet: context-path: / spring: application: name: web-consumer cloud: nacos: server-addr: localhost:8848 ``` 主启动类配置restTemplate ```java @Bean public RestTemplate restTemplate(){ return new RestTemplate(); } ``` ### nacos配置中心 简介: ![image-20210524165927914](中山达内项目.assets/image-20210524165927914-1621846768845.png) **一.** 可以通过nacos配置sentinel的流控规则,持久化到服务 ,sentinel处拉取,不需要重启 **二.** 搭建nacos配置中心. 一般在nacos配置中心一起搭建 添加依赖 ```xml org.springframework.boot spring-boot-starter-web com.alibaba.cloud spring-cloud-starter-alibaba-nacos-config ``` 编写bootstrap文件 ```yml spring: application: name: nacos-config cloud: nacos: config: server-addr: localhost:8848 group: DEFAULT_GROUP file-extension: yml ``` 启动类 ```java @SpringBootApplication public class NacosConfigApplication { public static void main(String[] args) { SpringApplication.run(NacosConfigApplication.class); } } ``` 以下测试添加配置文件 注册中心 nacos控制台添加配置文件 ![image-20210525151042303](中山达内项目.assets/image-20210525151042303.png) 测试controller ```java package cn.tedu.cn.tedu.controller; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.cloud.context.config.annotation.RefreshScope; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RefreshScope// 支持动态刷新 @RestController @Slf4j //日志 public class TestNacosConfigController { @Value("${logging.level.cn.tedu: info}") private String level; @RequestMapping("/doGetLogLevel") public String doGetLogLevel(){ log.debug("debug:"+level); log.error("error:"+level); return level; } } ``` **总结: 如上步骤添加后, 可以实现,nacos控制台修改配置, 取到的,文件里面的配置动态的刷新, 重点需要添加 @RefreshScope// 支持动态刷新** **如是说: 不需要单独一台配置中心, 可以添加依赖到需要使用配置的client , 然后写上bootstrap引导文件,读取nacos里面新建的配置, 实现控制台刷新client的配置** **实际使用之直接替换application.yml** 添加依赖 ```xml com.alibaba.cloud spring-cloud-starter-alibaba-nacos-config ``` 编写bootstrap.yml引导文件 ```yml spring: application: name: user-provider cloud: nacos: config: server-addr: localhost:8848 group: DEFAULT_GROUP file-extension: yml ``` nacos控制台添加application.yml的配置,注意id = user-provider.yml ,如下图: ![image-20210525154651422](中山达内项目.assets/image-20210525154651422.png) **如果有需要读取yml文件内容的controller . 一定需要添加@RefreshScope// 支持动态刷新** ### Feign 实现消费调用服务提供 添加项目依赖(SpringCloud 团队基于 OpenFeign 研发了 starter) ```xml org.springframework.cloud spring-cloud-starter-openfeign ``` 在启动类上添加@EnableFeignClients 注解 ```java @EnableFeignClients ``` 编写针对某服务提供者的API控制器接口, 交给feign管理 ```java package cn.tedu.controller; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; /** * 声明该接口是一个远程调用接口 */ @FeignClient(name="user-provider")//nacos-providers 为服务提供者名称 只能用在接口上面 @RestController public interface ConsumerApi { @GetMapping("/menu/doFindObjects") public String getMenus(); } ``` 编写controller接收浏览器请求,再通过feign远程调用user-manage ```java package cn.tedu.controller; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class ConsumerController { @Autowired private ConsumerApi consumerApi; @RequestMapping("/menus") public String getMenuList(){ //返回值应该按服务提供者的返回值进行接收或者设置 String menus = consumerApi.getMenus(); return menus; } } ``` Feign实现远程调用总结: https://www.jianshu.com/p/e0218c142d03 1) 通过 @EnableFeignCleints 注解启动 Feign Starter 组件。 2) Feign Starter 在项目启动过程中注册全局配置,扫描包下所有的 @FeignClient 接口 类,并进行注册 IOC 容器。 3) @FeignClient 接口类被注入时,通过 FactoryBean#getObject 返回动态代理对象。 4) 接口被调用时被动态代理类逻辑拦截,将 @FeignClient 请求信息通过编码器生成 Request 对象 5) 请求对象经 Ribbon 进行负载均衡,挑选出一个健康的 Server 实例。 6) 通过 Client 携带 Request 调用远端服务返回请求响应。 7) 通过解码器生成 Response 返回客户端,将信息流解析成为接口返回数据 ![img](中山达内项目.assets/6271376-7635e2dc9b32e3ec.png) ### Sentinel **解决方案 限流熔断 端口 8180** Sentinel 简介(替代hystrix,rabbitmq,zuul的限流,hystrix-dashBoard的仪表盘): Sentinel (分布式系统的流量防卫兵) 是阿里开源的一套用于服务容错的综合性解决 方案。它以流量为切入点, 从**流量控制、熔断降级、系统负载保护**等多个维度来保护服务的 稳定性。 Sentinel 承接了阿里巴巴近 10 年的双十一大促流量的核心场景, 例如秒杀(即 突发流量控制在系统容量可以承受的范围)、**消息削峰填谷、集群流量控制、实时熔断下游 不可用应用**等。 Sentinel 提供了**实时的监控功能**,通过控制台可以看到接入应用的单台机器秒级数 据,甚至 500 台以下规模的集群的汇总运行情况。 Sentinel 提供了开箱即用特性,可以快速实现与它开源框架整合, 例如与 Spring Cloud、Dubbo、gRPC 的整合。只需要引入相应的依赖并进行简单的配置即可快速地接入。 在Sentinel之前其实就有Hystrix做熔断降级的事情,我们都知道出现新的事物肯定是原来的东西有不足的地方。 > 那Hystrix有什么不足之处呢? - Hystrix常用的线程池隔离会造成线程上下切换的overhead比较大。 - Hystrix没有监控平台,需要我们自己搭建。 - Hystrix支持的熔断降级维度较少,不够细粒,而且缺少管理控制台。 Sentinel 核心分为两个部分: ▪ 核心库(Java 客户端):能够运行于所有 Java 运行时环境,同时对 Dubbo /Spring Cloud 等框架也有较好的支持。 ▪ 控制台(Dashboard):基于 Spring Boot 开发,打包后可以直接运行 **第一步**:打开 sentinel 下载网址 https://github.com/alibaba/Sentinel/releases![image-20210412154928787](中山达内项目.assets/image-20210412154928787.png) **第二步**:在 sentinel 对应目录,打开命令行(cmd),启动运行 sentinel ```java java -Dserver.port=8180 -Dcsp.sentinel.dashboard.server=localhost:8180 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.8.0.jar ``` 访问: localhost:8180 用户名: sentinel密码: sentinel **交互端口 8099** **整合到SpringCloud-Alibaba** **添加依赖到consumer** ```xml com.alibaba.cloud spring-cloud-starter-alibaba-sentinel ``` **配置yml文件** ```yml server: port: 7001 servlet: context-path: / spring: application: name: web-consumer cloud: nacos: server-addr: localhost:8848 sentinel: transport: port: 8099 #跟 sentinel 控制台交流的端口,随意指定一个未使用的端口即可 dashboard: localhost:8180 # 指定 sentinel 控制台地址。 ``` 启动服务提供者,服务消费者,然后在浏览器访问消费者 url 观察仪表盘 Sentinel 的控制台其实就是一个 SpringBoot 编写的程序,我们需要将我们的服务注册到 控制台上,即在微服务中指定控制台的地址,并且还要在消费端开启一个与 sentinel 控制 台传递数据端的端口,控制台可以通过此端口调用微服务中的监控程序来获取各种信息 **Sentinel 限流实践** #### **sentinel配置规则底层推送原理** ![image-20210413102817207](中山达内项目.assets/image-20210413102817207.png) **仪表盘版本:** 第一步:选择要限流的链路,如图所示(此处限流会针对当前路径, 粒度较粗,后续会有针对某热点,某数据进行限流) ![image-20210412163700031](中山达内项目.assets/image-20210412163700031.png) ![image-20210412165935721](中山达内项目.assets/image-20210412165935721.png) ![image-20210412170010766](中山达内项目.assets/image-20210412170010766.png) **可以通过消费者实现BlockExceptionHandler来重写对该异常的处理** 底层: @ConditionalOnMissingBean(BlockExceptionHandler.class) 没有该类型才配置默认 ```java package cn.tedu.exception.handler; import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.BlockExceptionHandler; import com.alibaba.csp.sentinel.slots.block.BlockException; import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException; import com.alibaba.csp.sentinel.slots.block.flow.FlowException; import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.stereotype.Component; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.PrintWriter; import java.util.HashMap; import java.util.Map; @Component public class ServiceBlockExceptionHandler implements BlockExceptionHandler { @Override public void handle(HttpServletRequest httpServletRequest, HttpServletResponse response, BlockException e) throws Exception { response.setContentType("text/html;charset=utf-8"); PrintWriter pw = response.getWriter(); Map map = new HashMap<>(); if(e instanceof DegradeException){ map.put("status",601); map.put("message","服务被熔断了"); }else if(e instanceof FlowException){ map.put("status",602); map.put("message","服务被限流了"); }else{ map.put("status",603); map.put("message","Blocked by Sentinel(flow limiting)"); } String jsonResult = new ObjectMapper().writeValueAsString(map); pw.println(jsonResult); pw.flush(); } } ``` ![image-20210413142801210](中山达内项目.assets/image-20210413142801210.png) **代码实现版本:** https://zhuanlan.zhihu.com/p/53641388 #### **sentinel降级熔断仪表盘版:** 处理超时,异常,的熔断 **慢调用设置:** ![image-20210413102151152](中山达内项目.assets/image-20210413102151152.png) ![image-20210413102244954](中山达内项目.assets/image-20210413102244954.png) **注意, 统计时长内发生的多少次请求** #### **sentinel热点数据限流实现** 对于细粒度的控制 异常 : ![image-20210514150617029](中山达内项目.assets/image-20210514150617029.png) 热点代码定义: ```java @GetMapping("/consumer/findById") @SentinelResource("doFindById") public String doFindById(@RequestParam("id") Integer id){//可以多个参数,对于不同参数配置不同的热点限流规则 return "hot id is "+id; } ``` ![image-20210413142542612](中山达内项目.assets/image-20210413142542612.png) ![image-20210413143746411](中山达内项目.assets/image-20210413143746411.png) ![image-20210413143910689](中山达内项目.assets/image-20210413143910689.png) ![image-20210514160848550](中山达内项目.assets/image-20210514160848550.png) ![image-20210514161145682](中山达内项目.assets/image-20210514161145682.png) #### **sentinel系统规则** 对于 整个系统的保护 ![image-20210413150700825](中山达内项目.assets/image-20210413150700825.png) § Load(仅对 Linux/Unix-like 机器生效):当系统 load1 超过阈值,且系统当前的并发线程数超过系统容量时才会触发系统保护。系统容量由系统的 maxQps * minRt(超时时间) 计算得出。设定参考值一般是 CPU cores * 2.5。 § CPU使用率:当系统 CPU 使用率超过阈值即触发系统保护(取值范围 0.0-1.0)。 § RT:当单台机器上所有入口流量的平均 RT (响应时间)达到阈值即触发系统保护,单位是毫秒。 § 线程数:当单台机器上所有入口流量的并发线程数达到阈值即触发系统保护。(基于线程的阈值类型,根据测试结果,线程的设置和接口的响应时间和并发请求个数有一定的关联。 根据对不同的 API 测试) § 入口 QPS:当单台机器上所有入口流量的 QPS 达到阈值即触发系统保护。 系统保护规则是应用整体维度的,而不是资源维度的,并且仅对入口流量生效。入口流量指的是进入应用的流量(EntryType.IN),比如 Web 服务。 **系统保护异常**: SystemBlockException ![image-20210514114259381](中山达内项目.assets/image-20210514114259381.png) #### **sentinel授权规则** ![image-20210414093637252](中山达内项目.assets/image-20210414093637252.png) 黑白名单规则(AuthorityRule)非常简单,主要有以下配置项: § resource:资源名,即限流规则的作用对象 § limitApp:对应的黑名单/白名单,不同 origin 用 , 分隔,如 appA,appB § strategy:限制模式,AUTHORITY_WHITE 为白名单模式,AUTHORITY_BLACK 为黑名单模式,默认为白名单模式 我们可以,实现RequestOriginParser接口,在接口方法中实现区分来源; ```java @Component public class DefaultRequestOriginParser implements RequestOriginParser { @Override public String parseOrigin(HttpServletRequest request) { String origin = request.getParameter("origin"); return origin; } } ``` 也就是后端设置参数, 为origin 前端流控应用可以设置值, 为黑或者白名单 例: localhost:7001/hello?id=1&origin=origin 如果设置黑名单,将被禁止访问 区分pc或者app ![image-20210514151055591](中山达内项目.assets/image-20210514151055591.png) **根据IP地址限流:** ![image-20210517115335724](中山达内项目.assets/image-20210517115335724.png) #### sentinel实现推送配置规则持久 在需要被监听sentinel客户端(一个服务)添加依赖 ```xml com.alibaba.csp sentinel-datasource-nacos ``` ```yml sentinel: transport: port: 8099 #跟 sentinel 控制台交流的端口,随意指定一个未使用的端口即可 dashboard: localhost:8180 # 指定 sentinel 控制台地址。 #web-context-unify: false #可以通过配置spring.cloud.sentinel.web-context-unify=false即可关闭收敛我们当前使用的版本是SpringCloud Alibaba 2.1.0.RELEASE,无法实现链路限流 datasource: ds: nacos: ### nacos连接地址 server-addr: localhost:8848 ## nacos连接的分组 group-id: DEFAULT_GROUP ###路由存储规则 rule-type: flow ### 读取配置文件的 data-id data-id: nacos-consumer ### 读取配置文件类型为json data-type: json ``` ![image-20210520093625502](中山达内项目.assets/image-20210520093625502.png) ```json [ { "resource": "/consumer/doRestEcho", "controlBehavior": 0, "count": 1.0, "grade": 1, "limitApp": "default", "strategy": 0 } ] ``` **总结:** **由nacos配置, 推送给服务,再推送给sentinel,并且持久化到nacos链接数据库** **所以sentinel修改配置规则后, 本身不会持久化, 通过nacos修改后, 会持久化到数据库** **后台业务类使用:** ```java /** * 获取部门表格 * @param commonRequest * @return */ @PostMapping("/queryDepartment") @SentinelResource(value = "queryDepartment", // 资源名 blockHandlerClass = CustomerBlockHandler.class, // 自定义限流处理类,当发生限流时,会去此类调用blockHandler blockHandler = "handlerException") // 限流回调方法 public CommonResponse> doQueryDepartment(@RequestBody CommonRequest commonRequest){ log.info("成功进入【获取部门表格】,commonRequest:{}", commonRequest.toString()); return CommonResponse.Builder.success(pageInfo); } ``` **总结:** 需要限流的路径,添加如上步骤, 重点, data-id和group分组要匹配 .json参考网上 规则存储到nacos的数据库表里面, nacos把规则推送给sentinel ,sentinel-dashboard仪表盘,就把规则读取过去 ![image-20210520095521850](中山达内项目.assets/image-20210520095521850.png) **面试题:** Sentinel模式支持的持久化方式有哪些? 哪里看到, 通过yml配置文件点ds进源码看的 ![image-20210520103535963](中山达内项目.assets/image-20210520103535963.png) Sentinel持久化的流控信息 , 在微服务客户端是如何获取的?(推,拉) ![image-20210520104804335](中山达内项目.assets/image-20210520104804335.png) sentinel持久化的流控信息,在生产环境一般推荐采用什么模式 ? (推模式,实时性比较好,但是服务端压力增大,客户端还有可能产生消息堆积) Sentiel基于nacos持久化实现过程?(依赖,配置-客户端,nacos仪表盘配置,nacos新建配置格式,JSON或以下) ![image-20210520105517563](中山达内项目.assets/image-20210520105517563.png) ![image-20210524163518144](中山达内项目.assets/image-20210524163518144.png) #### sentinel重写源码设计 **sentinel默认没有实现 pull或者push到nacos ,因为sentinel不清楚, 你规则持久化到什么地方,需要直接根据源码或者实现接口如下, 来修改方法, 默认只支持从项目上面pull规则** **所以sentinel修改配置规则后, 本身不会持久化, 通过nacos修改后, 会持久化到数据库** 源码地址 github sentinel - 去掉 pom.xml里面得nacos 得scope =test . 源码中的rule包规则,DynamicRuleProvider pull规则接口 源码中的rule包规则,DynamicRulePublisher push规则接口 底下的FlowRuleApiProvider 实现了pull规则流控的实现方式 底下的FlowRuleApiPublisher实现push规则流控的实现方式 ![image-20210525104937122](中山达内项目.assets/image-20210525104937122.png) **以上配置来自于消费者里面配置的 , 由nacos推送给消费, sentinel跟进本端口拉取** ![image-20210524165509740](中山达内项目.assets/image-20210524165509740.png) 生产环境中用error规则 ​ ## TODU # 关于springCloud 分开打包自动发布 容器化管理的思想. # 做了权限后, 过来把这个放开. 需要用到的用户id