|
@@ -0,0 +1,393 @@
|
|
|
+# 后端架构
|
|
|
+
|
|
|
+### 服务器架构
|
|
|
+
|
|
|
+* 测试服务器(172.16.0.223)
|
|
|
+ * 内网地址:172.16.0.223
|
|
|
+ * 公网地址:139.159.229.250
|
|
|
+ * ssh端口:22
|
|
|
+ * 安装的服务:
|
|
|
+ * 测试应用
|
|
|
+ * 测试数据库
|
|
|
+ * redis
|
|
|
+ * rocketmq
|
|
|
+* 生产服务器
|
|
|
+ * 生产应用服务器(172.16.0.246)
|
|
|
+ * 内网地址:172.16.0.246
|
|
|
+ * 公网地址:139.159.210.228
|
|
|
+ * ssh端口:7711
|
|
|
+ * 安装的服务
|
|
|
+ * 生产应用
|
|
|
+ * redis
|
|
|
+ * rocketmq
|
|
|
+ * nginx(为前端应用提供web服务)
|
|
|
+ * 生产数据库服务器(172.16.0.159)
|
|
|
+ * 内网地址:172.16.0.159
|
|
|
+ * 公网地址:无
|
|
|
+ * 安装的服务:
|
|
|
+ * 生产数据库
|
|
|
+* 共通服务器
|
|
|
+ * 堡垒机(以后只有堡垒机才有公网访问权限,提供跳板机服务已经nginx转发服务)
|
|
|
+ * 内网地址:172.16.0.99
|
|
|
+ * 公网地址:139.9.56.49
|
|
|
+ * ssh端口:22
|
|
|
+ * 安装的服务:
|
|
|
+ * Jumpserver(提供跳板机服务)
|
|
|
+ * nginx(域名转发)
|
|
|
+ * DevOps服务器
|
|
|
+ * 内网地址:172.16.0.61
|
|
|
+ * 公网地址:139.159.196.162
|
|
|
+ * ssh端口:22
|
|
|
+ * 安装的服务
|
|
|
+ * 在线文档服务
|
|
|
+ * gogs(提供git服务)
|
|
|
+ * YApi(提供接口文档服务)
|
|
|
+ * Jenkins(提供发版服务)
|
|
|
+ * Nexus(提供 maven 私服服务)
|
|
|
+ * 代码生成器
|
|
|
+
|
|
|
+### 网络架构
|
|
|
+
|
|
|
+* 绘服务小程序
|
|
|
+ * 域名:m.huifuwu.cn
|
|
|
+ * 转发地址:http://172.16.0.246:8171
|
|
|
+* 绘管家小程序
|
|
|
+ * 域名:m.huiguanjia.cn
|
|
|
+ * 转发地址:http://172.16.0.246:8171
|
|
|
+* 绘服务Web端
|
|
|
+ * 域名:pm.huiguanjia.cn
|
|
|
+ * 转发:http://172.16.0.246:8171
|
|
|
+* 绘管家Web端
|
|
|
+ * 域名:wy.huiguanjia.cn
|
|
|
+ * 转发:http://172.16.0.246:3000
|
|
|
+* Java后端接口
|
|
|
+ * http://172.16.0.246:8161
|
|
|
+
|
|
|
+### 应用架构
|
|
|
+
|
|
|
+* 公共包
|
|
|
+ * wisdom-common(核心包+各个微服务rpc共用的pojo)
|
|
|
+ * wisdom-ds(动态数据源)
|
|
|
+ * wisdom-generator(代码生成器)
|
|
|
+ * wisdom-mq(mq接入封装)
|
|
|
+ * wisdom-parent(maven parent 统一管理第三方包版本)
|
|
|
+* 监控
|
|
|
+ * wisdom-monitor(微服务健康状况监控)
|
|
|
+ * wisdom-track(微服务请求链追踪)
|
|
|
+
|
|
|
+* 网关
|
|
|
+ * wisdom-gateway
|
|
|
+* 业务
|
|
|
+ * swagger-ui(springfox-swagger2)
|
|
|
+ * 动态数据源(dynamic-datasource-spring-boot-starter)
|
|
|
+ * MyBatis 增强 (tk.mybatis、pagehelper)
|
|
|
+ * Lombok
|
|
|
+ * Feign
|
|
|
+ * OkHttp
|
|
|
+ * Druid
|
|
|
+
|
|
|
+### WEB端访问要完成的事情
|
|
|
+
|
|
|
+* 访问 https://wy.huiguanjia.cn
|
|
|
+
|
|
|
+* 堡垒机域名解析
|
|
|
+
|
|
|
+ ```nginx
|
|
|
+ server {
|
|
|
+ listen 80;
|
|
|
+ server_name wy.huiguanjia.cn;
|
|
|
+ return 301 https://wy.huiguanjia.cn$request_uri;
|
|
|
+ }
|
|
|
+ server {
|
|
|
+ listen 443;
|
|
|
+ server_name wy.huiguanjia.cn;
|
|
|
+
|
|
|
+ root html;
|
|
|
+ index index.html index.htm index.php;
|
|
|
+
|
|
|
+ ssl on;
|
|
|
+ ssl_certificate cert/wy.huiguanjia.cn.pem;
|
|
|
+ ssl_certificate_key cert/wy.huiguanjia.cn.key;
|
|
|
+ ssl_session_timeout 5m;
|
|
|
+ ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
|
|
|
+ ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
|
|
|
+ ssl_prefer_server_ciphers on;
|
|
|
+
|
|
|
+
|
|
|
+ location / {
|
|
|
+ proxy_pass http://172.16.0.246:3000/;
|
|
|
+
|
|
|
+ #Proxy Settings
|
|
|
+ proxy_redirect off;
|
|
|
+ proxy_set_header Host $host;
|
|
|
+ proxy_set_header X-Real-IP $remote_addr;
|
|
|
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
|
+ proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
|
|
|
+ proxy_max_temp_file_size 0;
|
|
|
+ proxy_connect_timeout 300;
|
|
|
+ proxy_send_timeout 300;
|
|
|
+ proxy_read_timeout 300;
|
|
|
+ proxy_buffer_size 4k;
|
|
|
+ proxy_buffers 4 32k;
|
|
|
+ proxy_busy_buffers_size 64k;
|
|
|
+ proxy_temp_file_write_size 64k;
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ ```
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+* 转发请求到应用服务器的前端服务
|
|
|
+
|
|
|
+ ```nginx
|
|
|
+ server {
|
|
|
+ listen 3000;
|
|
|
+ server_name 127.0.0.1;
|
|
|
+
|
|
|
+ root html;
|
|
|
+ index index.html index.htm index.php;
|
|
|
+
|
|
|
+
|
|
|
+ location / {
|
|
|
+ root /data/bin/hgj2/web_publish/admin/public/;
|
|
|
+ index index.html;
|
|
|
+ try_files $uri $uri/ /index.html;
|
|
|
+
|
|
|
+ #Proxy Settings
|
|
|
+ proxy_redirect off;
|
|
|
+ proxy_set_header Host $host;
|
|
|
+ proxy_set_header X-Real-IP $remote_addr;
|
|
|
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
|
+ proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
|
|
|
+ proxy_max_temp_file_size 0;
|
|
|
+ proxy_connect_timeout 300;
|
|
|
+ proxy_send_timeout 300;
|
|
|
+ proxy_read_timeout 300;
|
|
|
+ proxy_buffer_size 4k;
|
|
|
+ proxy_buffers 4 32k;
|
|
|
+ proxy_busy_buffers_size 64k;
|
|
|
+ proxy_temp_file_write_size 64k;
|
|
|
+ }
|
|
|
+
|
|
|
+ location /9ad134a361f8d778/ {
|
|
|
+ proxy_pass http://127.0.0.1:8161/;
|
|
|
+ proxy_read_timeout 600;
|
|
|
+ }
|
|
|
+
|
|
|
+ location /ureport/res/ {
|
|
|
+ proxy_pass http://127.0.0.1:8161/ureport/res/;
|
|
|
+ }
|
|
|
+
|
|
|
+ location /ureport/preview/ {
|
|
|
+ proxy_pass http://127.0.0.1:8161/ureport/preview/;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ ```
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+* 跨域处理,是接口请求同源
|
|
|
+
|
|
|
+ ```nginx
|
|
|
+ location /9ad134a361f8d778/ {
|
|
|
+ proxy_pass http://127.0.0.1:8161/;
|
|
|
+ proxy_read_timeout 600;
|
|
|
+ }
|
|
|
+ ```
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+* 后端gateway网关拦截器拦截所有请求
|
|
|
+
|
|
|
+ ```java
|
|
|
+ // wisdom-gateway
|
|
|
+ // CustomGatewayFilter.java
|
|
|
+ public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain){
|
|
|
+ ....
|
|
|
+ }
|
|
|
+ ```
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+* gateway网关从注册中心获取所有服务的访问地址
|
|
|
+
|
|
|
+ ```properties
|
|
|
+ # eureka
|
|
|
+ eureka.instance.status-page-url-path=/actuator/info
|
|
|
+ eureka.instance.health-check-url-path=/actuator/health
|
|
|
+ eureka.instance.home-page-url-path=/
|
|
|
+ eureka.client.service-url.defaultZone=http://${EUREKA_HOST:localhost}:${EUREKA_PORT:8162}/eureka/
|
|
|
+ ## 表示eureka client间隔多久去拉取服务注册信息,默认为30秒,对于api-gateway,如果要迅速获取服务注册状态,可以缩小该值
|
|
|
+ eureka.client.registry-fetch-interval-seconds=5
|
|
|
+ ## 表示eureka client发送心跳给server端的频率。如果在leaseExpirationDurationInSeconds后,server端没有收到client的心跳,则将摘除该instance
|
|
|
+ eureka.instance.lease-renewal-interval-in-seconds=30
|
|
|
+ ```
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+* gateway网关根据接口正则前缀将请求路由到各个服务
|
|
|
+
|
|
|
+ ```properties
|
|
|
+ ## platform
|
|
|
+ spring.cloud.gateway.routes[0].id=wisdom-platform
|
|
|
+ spring.cloud.gateway.routes[0].uri=lb://wisdom-platform
|
|
|
+ spring.cloud.gateway.routes[0].predicates[0]=Path=/platform/**
|
|
|
+ spring.cloud.gateway.routes[0].filters[0]=GatewaySwaggerHeaderFilter
|
|
|
+ spring.cloud.gateway.routes[0].filters[1]=StripPrefix=1
|
|
|
+ ## asset
|
|
|
+ spring.cloud.gateway.routes[1].id=wisdom-asset
|
|
|
+ spring.cloud.gateway.routes[1].uri=lb://wisdom-asset
|
|
|
+ spring.cloud.gateway.routes[1].predicates[0]=Path=/asset/**
|
|
|
+ spring.cloud.gateway.routes[1].filters[0]=GatewaySwaggerHeaderFilter
|
|
|
+ spring.cloud.gateway.routes[1].filters[1]=StripPrefix=1
|
|
|
+ ## auth
|
|
|
+ spring.cloud.gateway.routes[2].id=wisdom-auth
|
|
|
+ spring.cloud.gateway.routes[2].uri=lb://wisdom-auth
|
|
|
+ spring.cloud.gateway.routes[2].predicates[0]=Path=/auth/**
|
|
|
+ spring.cloud.gateway.routes[2].filters[0]=GatewaySwaggerHeaderFilter
|
|
|
+ spring.cloud.gateway.routes[2].filters[1]=StripPrefix=1
|
|
|
+ ## payment
|
|
|
+ spring.cloud.gateway.routes[3].id=wisdom-payment
|
|
|
+ spring.cloud.gateway.routes[3].uri=lb://wisdom-payment
|
|
|
+ spring.cloud.gateway.routes[3].predicates[0]=Path=/payment/**
|
|
|
+ spring.cloud.gateway.routes[3].filters[0]=GatewaySwaggerHeaderFilter
|
|
|
+ spring.cloud.gateway.routes[3].filters[1]=StripPrefix=1
|
|
|
+ ## serve
|
|
|
+ spring.cloud.gateway.routes[4].id=wisdom-serve
|
|
|
+ spring.cloud.gateway.routes[4].uri=lb://wisdom-serve
|
|
|
+ spring.cloud.gateway.routes[4].predicates[0]=Path=/serve/**
|
|
|
+ spring.cloud.gateway.routes[4].filters[0]=GatewaySwaggerHeaderFilter
|
|
|
+ spring.cloud.gateway.routes[4].filters[1]=StripPrefix=1
|
|
|
+ ## file
|
|
|
+ spring.cloud.gateway.routes[5].id=wisdom-file
|
|
|
+ spring.cloud.gateway.routes[5].uri=lb://wisdom-file
|
|
|
+ spring.cloud.gateway.routes[5].predicates[0]=Path=/file/**
|
|
|
+ spring.cloud.gateway.routes[5].filters[0]=GatewaySwaggerHeaderFilter
|
|
|
+ spring.cloud.gateway.routes[5].filters[1]=StripPrefix=1
|
|
|
+ ## bill
|
|
|
+ spring.cloud.gateway.routes[6].id=wisdom-bill
|
|
|
+ spring.cloud.gateway.routes[6].uri=lb://wisdom-bill
|
|
|
+ spring.cloud.gateway.routes[6].predicates[0]=Path=/bill/**
|
|
|
+ spring.cloud.gateway.routes[6].filters[0]=GatewaySwaggerHeaderFilter
|
|
|
+ spring.cloud.gateway.routes[6].filters[1]=StripPrefix=1
|
|
|
+ ## report
|
|
|
+ spring.cloud.gateway.routes[7].id=wisdom-report
|
|
|
+ spring.cloud.gateway.routes[7].uri=lb://wisdom-report
|
|
|
+ spring.cloud.gateway.routes[7].predicates[0]=Path=/report/**
|
|
|
+ spring.cloud.gateway.routes[7].filters[0]=GatewaySwaggerHeaderFilter
|
|
|
+ spring.cloud.gateway.routes[7].filters[1]=StripPrefix=1
|
|
|
+ ## ureport
|
|
|
+ spring.cloud.gateway.routes[8].id=wisdom-report
|
|
|
+ spring.cloud.gateway.routes[8].uri=lb://wisdom-report
|
|
|
+ spring.cloud.gateway.routes[8].predicates[0]=Path=/ureport/**
|
|
|
+ spring.cloud.gateway.routes[8].filters[0]=GatewaySwaggerHeaderFilter
|
|
|
+ ## log
|
|
|
+ spring.cloud.gateway.routes[9].id=wisdom-log
|
|
|
+ spring.cloud.gateway.routes[9].uri=lb://wisdom-log
|
|
|
+ spring.cloud.gateway.routes[9].predicates[0]=Path=/log/**
|
|
|
+ spring.cloud.gateway.routes[9].filters[0]=GatewaySwaggerHeaderFilter
|
|
|
+ spring.cloud.gateway.routes[9].filters[1]=StripPrefix=1
|
|
|
+ ## task
|
|
|
+ spring.cloud.gateway.routes[10].id=wisdom-task
|
|
|
+ spring.cloud.gateway.routes[10].uri=lb://wisdom-task
|
|
|
+ spring.cloud.gateway.routes[10].predicates[0]=Path=/task/**
|
|
|
+ spring.cloud.gateway.routes[10].filters[0]=GatewaySwaggerHeaderFilter
|
|
|
+ spring.cloud.gateway.routes[10].filters[1]=StripPrefix=1
|
|
|
+ ## hardware
|
|
|
+ spring.cloud.gateway.routes[11].id=wisdom-hardware
|
|
|
+ spring.cloud.gateway.routes[11].uri=lb://wisdom-hardware
|
|
|
+ spring.cloud.gateway.routes[11].predicates[0]=Path=/hardware/**
|
|
|
+ spring.cloud.gateway.routes[11].filters[0]=GatewaySwaggerHeaderFilter
|
|
|
+ spring.cloud.gateway.routes[11].filters[1]=StripPrefix=1
|
|
|
+ ## hris
|
|
|
+ spring.cloud.gateway.routes[12].id=wisdom-hris
|
|
|
+ spring.cloud.gateway.routes[12].uri=lb://wisdom-hris
|
|
|
+ spring.cloud.gateway.routes[12].predicates[0]=Path=/hris/**
|
|
|
+ spring.cloud.gateway.routes[12].filters[0]=GatewaySwaggerHeaderFilter
|
|
|
+ spring.cloud.gateway.routes[12].filters[1]=StripPrefix=1
|
|
|
+ ## app
|
|
|
+ spring.cloud.gateway.routes[13].id=wisdom-app
|
|
|
+ spring.cloud.gateway.routes[13].uri=lb://wisdom-app
|
|
|
+ spring.cloud.gateway.routes[13].predicates[0]=Path=/app/**
|
|
|
+ spring.cloud.gateway.routes[13].filters[0]=GatewaySwaggerHeaderFilter
|
|
|
+ spring.cloud.gateway.routes[13].filters[1]=StripPrefix=1
|
|
|
+ ```
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+* 服务接收到请求之后,先判断header是否指定数据源,否,则接着判断是否有会话,从会话获取当前请求需要访问的数据源名称
|
|
|
+
|
|
|
+ ```java
|
|
|
+ // wisdom-ds
|
|
|
+ // DsCustomerProcessor.java
|
|
|
+ // 从header获取数据源
|
|
|
+ ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest().getHeader("entCode");
|
|
|
+ // 从登陆会话获取数据源
|
|
|
+ UserInfoUtil.getUserDs();
|
|
|
+ ```
|
|
|
+
|
|
|
+* 接口日志拦截
|
|
|
+
|
|
|
+ ```java
|
|
|
+ // wisdom-common
|
|
|
+ // ControllerLoggerAspect.java
|
|
|
+ @Pointcut("@annotation(io.swagger.annotations.ApiOperation)")
|
|
|
+ public void controllerPointCut() {
|
|
|
+ }
|
|
|
+
|
|
|
+ @Around("controllerPointCut()")
|
|
|
+ public Object handlerControllerMethod(ProceedingJoinPoint pjp){
|
|
|
+ ...
|
|
|
+ }
|
|
|
+ ```
|
|
|
+
|
|
|
+* 数据权限拦截
|
|
|
+
|
|
|
+ ```java
|
|
|
+ // wisdom-common
|
|
|
+ // PermissionInterceptor.java
|
|
|
+ 实现小区、数据权限sql拦截
|
|
|
+ ```
|
|
|
+
|
|
|
+* 统一异常拦截
|
|
|
+
|
|
|
+ ```java
|
|
|
+ // wisdom-common
|
|
|
+ // PromiseExceptionHandler.java
|
|
|
+ @ExceptionHandler(PromiseException.class)
|
|
|
+ public ResponseEntity handleBizException(PromiseException ex) {
|
|
|
+ ...
|
|
|
+ }
|
|
|
+ @ExceptionHandler(MethodArgumentNotValidException.class)
|
|
|
+ public ResponseEntity argumentNotValidException(MethodArgumentNotValidException ex) {
|
|
|
+ ...
|
|
|
+ }
|
|
|
+ @ExceptionHandler(FeignException.class)
|
|
|
+ public ResponseEntity handleException(FeignException ex){
|
|
|
+ ...
|
|
|
+ }
|
|
|
+ @ExceptionHandler(BindException.class)
|
|
|
+ public ResponseEntity handleException(BindException ex){
|
|
|
+ ...
|
|
|
+ }
|
|
|
+ @ExceptionHandler(Exception.class)
|
|
|
+ public ResponseEntity handleException(Exception ex) {
|
|
|
+ ...
|
|
|
+ }
|
|
|
+ ```
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+### 需要解决的问题
|
|
|
+
|
|
|
+* quartz定时任务多数据源问题
|
|
|
+* 分布式事务
|
|
|
+* Redis集群
|
|
|
+* MQ集群
|
|
|
+* 单元测试
|
|
|
+* 自动化测试
|
|
|
+* 多数据源运维
|
|
|
+
|
|
|
+
|
|
|
+
|