# ncmed-eos2025
**Repository Path**: oxygen-therapy-platform/ncmed-eos2025
## Basic Information
- **Project Name**: ncmed-eos2025
- **Description**: No description available
- **Primary Language**: Unknown
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2025-01-21
- **Last Updated**: 2025-01-21
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# 大氧疗平台框架项目
### 1、介绍
项目基于Spring Boot 2 和Spring Cloud Finchley.RELEASE 来搭建的分布式开发框架,其中包含具备用户管理、资源权限管理、网关API管理等多个模块,
支持多业务系统并行开发。核心技术采用Eureka、Fegin、Ribbon、GateWay、Hystrix、Security、JWT Token、Mybatis等主要框架和中间件。
接口部分集成增强版[Swagger2(knife4j)](https://doc.xiaominfo.com),将所有微服务接口文档进行统一管理。
### 2、模块功能介绍
模块名称 | 说明 | 端口 | 备注
---|---|---|---
ncmed-auth-client | 认证客户端包 | 无 | 需要进行用户认证和授权的服务引入该模块
ncmed-auth-common | 认证公共包 | 无 |
ncmed-auth-server | 认证服务 | 随机 | 用户认证和授权服务
ncmed-common | 公共服务包 | 无 | 提供公共的 service、exception、util 等功能
ncmed-doc | 文档服务中心 | 10003 | 所有微服务接口统一到该服务进行呈现
ncmed-gateway | 网关 | 8088 | 用户认证、鉴权等
ncmed-system | 系统管理服务 | 随机 | 包含用户、角色、菜单、字典、权限
ncmed-bby | 抱抱氧服务 | 随机 | 抱抱氧设备管理、订单管理等相关业务处理
ncmed-equip | 制氧机IOT服务 | 随机&8886(socket通讯) | 制氧机设备物联网加持,监控设备运行状况,远程控制设备
ncmed-generator | 基本代码生成器 | 无 | 生成 Controller Serivce Dao xml 文件
ncmed-lbs | 腾讯地图服务 | 随机 | 提供抱抱氧设备地图服务,标注设备位置等信息
ncmed-monitor | 监控服务 | 8764 | 为各种 Spring Boot 微服务提供性能监控
ncmed-settlement | 结算中心 | 随机 | 结算中心,包含支付与分帐,建行惠市宝实现
ncmed-wechat | 微信服务 | 随机 | 提供微信公众号小程序相关功能实现
### 3、模块详细介绍
#### ncmed-gateway
网关是整个微服务API请求的入口,负责拦截所有请求,分发到服务上去。可以实现日志拦截、权限控制、解决跨域问题、限流、熔断、负载均衡,隐藏服务端的ip,黑名单与白名单拦截、授权等。
目前主要实现权限控制、解决跨域问题。权限控制通过AccessGatewayFilter实现,跨域通过CorsConfig实现。
#### ncmed-auth-server
该部分涵盖了用户认证服务及微服务间远程调用认证,采用JWT+Redis进行权限认证。
PC端、微信端以及不同身份的用户都是在该服务中进行认证及授权。
服务间远程调用会话以及服务会话通过JWT产生的Token,配合ncmed-auth-client jar包进行会话的用户信息传递。
#### ncmed-auth-client
该工程已jar包的形式体现在各个微服务中,如果某个服务需要用到认证鉴权则需要引入该jar包,并且在启动类上配置@EnableNCmedAuthClient,例如ncmed-lbs服务不需要用到认证模块则不引用该jar包。
@IgnoreClientToken:忽略远程接口调用Token认证
@IgnoreUserToken:忽略Restful接口调用Token认证
#### ncmed-system
用户管理:用户是系统操作者,该功能主要完成系统用户配置。
部门管理:配置系统组织机构(公司、部门、小组),树结构展现支持数据权限。
岗位管理:配置系统用户所属担任职务。
菜单管理:配置系统菜单,操作权限,按钮权限标识等。
角色管理:角色菜单权限分配、设置角色按机构进行数据范围权限划分。
字典管理:对系统中经常使用的一些较为固定的数据进行维护。
参数管理:对系统动态配置常用参数。
原氧疗业务难以拆分没有拆出来。
#### ncmed-equip
拉取制氧设备数据远程操控设备。
通过netty实现,底层单片机通过Socket与云平台进行指令传输。
#### ncmed-wechat
提供微信公众号及小程序相关服务api。
提供了氧疗终端服务H5页面所需要的api接口。
#### ncmed-lbs
地图服务,实现了根据定位坐标查询周边氧疗机的地图服务,并且提供了相对应的远程调用接口,将氧疗机标注到腾讯地图上。
### 4、项目工程结构层次介绍
业务服务系统结构分三个层次进行拆分,包括api、core、feign。
api:为远程接口调用提供顶层接口及传输dto、vo实体
feign:提供远程feign调用接口,服务之间的调用通过引入该包实现
core:具体业务服务
### [knife4j集成GateWay介绍](https://doc.xiaominfo.com/guide/ui-front-gateway.html)
ncmed-doc 通过Spring Cloud网关聚合所有服务接口
####pom引入相关jar包
```
org.springframework.cloud
spring-cloud-starter-netflix-eureka-client
org.springframework.cloud
spring-cloud-starter-gateway
com.github.xiaoymin
knife4j-spring-boot-starter
```
- spring-cloud-starter-netflix-eureka-client:eureka客户端
- spring-cloud-starter-gateway:gateway网关
- knife4j-spring-boot-starter:knife4j提供的前端ui和后端代码
#### 注意
在集成Spring Cloud Gateway网关的时候,会出现没有basePath的情况(即定义的例如/eos-system、/eos-auth等微服务的前缀),这个情况在使用zuul网关的时候不会出现此问题,因此,在Gateway网关需要添加一个Filter实体Bean,并且在配置Filter的时候,需要将其放在第一行。代码如下:
```
package com.ncmed.eos.doc.config;
import org.apache.commons.lang3.StringUtils;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
/**
* @author 李意(manliyi @ 163.com)
* @Classname SwaggerHeaderFilter
* @Description TODO
* @Date 2019/11/5 17:26
*/
@Component
public class SwaggerHeaderFilter extends AbstractGatewayFilterFactory {
private static final String HEADER_NAME = "X-Forwarded-Prefix";
/**
* 匹配到该路径的时候,加上gateway访问前缀,防止swagger测试接口报404
*/
private static final String URI = "/v2/api-docs-ext";
@Override
public GatewayFilter apply(Object config) {
return (exchange, chain) -> {
ServerHttpRequest request = exchange.getRequest();
String path = request.getURI().getPath();
if (!StringUtils.endsWithIgnoreCase(path,URI )) {
return chain.filter(exchange);
}
String basePath = path.substring(0, path.lastIndexOf(URI));
ServerHttpRequest newRequest = request.mutate().header(HEADER_NAME, basePath).build();
ServerWebExchange newExchange = exchange.mutate().request(newRequest).build();
return chain.filter(newExchange);
};
}
}
```
#### 配置文件
```
server:
port: 10003
eureka:
client:
serviceUrl:
defaultZone: http://${EUREKA_SERVER_ADDRESS}:8761/eureka/
registry-fetch-interval-seconds: 5
instance:
lease-expiration-duration-in-seconds: 15
lease-renewal-interval-in-seconds: 5
prefer-ip-address: true
instance-id: ${spring.application.name}:${server.port}
management:
endpoints:
web:
exposure:
include: "*"
endpoint:
health:
show-details: always
logging:
level:
root: info
com.ncmed: debug
org.springframework.cloud.gateway: trace
file: logs/${spring.application.name}.log
# 配置gateway路由
spring:
application:
name: eos-doc
cloud:
config:
discovery:
enabled: true
serviceId: eos-configs
profile: ${PROFILE_ACTIVE}
fail-fast: true
gateway:
discovery:
locator:
#小写serviceId
lowerCaseServiceId: true
# 是否可以通过其他服务的serviceId来转发到具体的服务实例。默认为false
# 为true,自动创建路由,路由访问方式:http://Gateway_HOST:Gateway_PORT/大写的serviceId/**,其中微服务应用名默认大写访问
enabled: true
routes:
- id: eos-system
uri: lb://eos-system
order: 0
predicates:
- Path=/api-system/**
filters:
- SwaggerHeaderFilter
- StripPrefix=1
- id: eos-auth
uri: lb://eos-auth
order: 0
predicates:
- Path=/api-auth/**
filters:
- SwaggerHeaderFilter
- StripPrefix=1
```
###服务接口端配置
每个微服务只需要引入和swagger相关的后端jar包即可,不需要引入swagger的前端Ui包,knife4j为我们提供了微服务项的starter,供开发者使用
```
com.github.xiaoymin
knife4j-micro-spring-boot-starter
```
项目的jar包引入完成后,接下来是配置swagger的相关配置,SwaggerConfiguration.java配置如下:
```
package com.ncmed.eos.system.config;
import com.github.xiaoymin.knife4j.spring.annotations.EnableSwaggerBootstrapUi;
import com.google.common.collect.Lists;
import io.swagger.annotations.Api;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.core.annotation.Order;
import org.springframework.web.context.request.async.DeferredResult;
import springfox.bean.validators.configuration.BeanValidatorPluginsConfiguration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.*;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.service.contexts.SecurityContext;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
import java.util.List;
/**
* @author 李意(manliyi @ 163.com)
* @Classname RestApiConfig
* @Description TODO
* @Date 2019/11/5 14:20
*/
@Configuration
@EnableSwagger2
@EnableSwaggerBootstrapUi
@Import(BeanValidatorPluginsConfiguration.class)
public class SwaggerConfiguration {
@Bean(value = "System Api")
@Order(value = 1)
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
// .groupName("系统管理模块")
.genericModelSubstitutes(DeferredResult.class)
.useDefaultResponseMessages(false)
// .forCodeGeneration(false)
.select()
.apis(RequestHandlerSelectors.withClassAnnotation(Api.class))
.paths(PathSelectors.any())
.build().securityContexts(Lists.newArrayList(securityContext())).securitySchemes(Lists.newArrayList(apiKey()));
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("系统管理RESTful APIs")
.contact(new Contact("李意","https://me.csdn.net/liyi124368766","manliyi@163.com"))
.version("1.0")
.license("Apache 2.0")
.licenseUrl("http://www.apache.org/licenses/LICENSE-2.0.html")
.build();
}
private ApiKey apiKey() {
return new ApiKey("BearerToken", "Authorization", "header");
}
private SecurityContext securityContext() {
return SecurityContext.builder()
.securityReferences(defaultAuth())
.forPaths(PathSelectors.regex("/.*"))
.build();
}
List defaultAuth() {
AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
authorizationScopes[0] = authorizationScope;
return Lists.newArrayList(new SecurityReference("BearerToken", authorizationScopes));
}
}
```