# 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接口都需要添加
## 打包父子项目

## 系统拆分

## 功能模块:
### 注册中心 配置中心
### 流控系统
### 缓存服务
### 前台系统功能模块
### 后台系统功能模块:
#### 系统管理:
菜单 角色 用户 监控 定时任务
#### 企业合作:
学员面试跟踪录入 ,学员就业公司录入 , 当月要毕业学员
#### 职业发展:
脱产职业发展: 导入学员信息采集表,新建班级, 班级职业发展和项目经理, 跟进记录,学员备注 ,学员学分记录表,学员绑定外键,学分扣除记录表
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
第二步:选择对应版本,直接下载,如图所示:

第三步:解压 Nacos(最好不要解压到中文目录下),其目录结构如下

**配置nacos并启动:**
第一步:找到/conf/nacos-mysql.sql 文件里的 sql 脚本,然后登陆 mysql,然后基 于脚本文件中的描述创建数据库,并执行脚本文件,脚本执行成功会创建一些表,如图所示:

第二步:打开/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配置中心
简介:

**一.** 可以通过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控制台添加配置文件

测试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 ,如下图:

**如果有需要读取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 返回客户端,将信息流解析成为接口返回数据

### 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
**第二步**:在 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配置规则底层推送原理**

**仪表盘版本:**
第一步:选择要限流的链路,如图所示(此处限流会针对当前路径, 粒度较粗,后续会有针对某热点,某数据进行限流)



**可以通过消费者实现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();
}
}
```

**代码实现版本:**
https://zhuanlan.zhihu.com/p/53641388
#### **sentinel降级熔断仪表盘版:**
处理超时,异常,的熔断
**慢调用设置:**


**注意, 统计时长内发生的多少次请求**
#### **sentinel热点数据限流实现**
对于细粒度的控制
异常 : 
热点代码定义:
```java
@GetMapping("/consumer/findById")
@SentinelResource("doFindById")
public String doFindById(@RequestParam("id") Integer id){//可以多个参数,对于不同参数配置不同的热点限流规则
return "hot id is "+id;
}
```





#### **sentinel系统规则**
对于 整个系统的保护

§ 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

#### **sentinel授权规则**

黑白名单规则(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

**根据IP地址限流:**

#### 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
```

```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仪表盘,就把规则读取过去

**面试题:**
Sentinel模式支持的持久化方式有哪些? 哪里看到, 通过yml配置文件点ds进源码看的

Sentinel持久化的流控信息 , 在微服务客户端是如何获取的?(推,拉)

sentinel持久化的流控信息,在生产环境一般推荐采用什么模式 ?
(推模式,实时性比较好,但是服务端压力增大,客户端还有可能产生消息堆积)
Sentiel基于nacos持久化实现过程?(依赖,配置-客户端,nacos仪表盘配置,nacos新建配置格式,JSON或以下)


#### 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规则流控的实现方式

**以上配置来自于消费者里面配置的 , 由nacos推送给消费, sentinel跟进本端口拉取**

生产环境中用error规则
## TODU
# 关于springCloud 分开打包自动发布 容器化管理的思想.
# 做了权限后, 过来把这个放开. 需要用到的用户id