# 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)); } } ```