1.若依中的provider
1.前言
为对前面微服务知识点的巩固,决定实践若依的微服务项目。这篇博客主要是为熟悉该项目的服务提供者provider,其在项目中的应用。在之前的微服务基础学习中,我的认知是将@FeignClient注解添加在consumer包中的接口上面;但是在对若依微服务项目的学习中,我发现将provider的被调用接口方法放在provider包中能更好地复用,减少重复代码。
2.实战
2.1 搭建cloud-ruoyi项目
删除该模块的下面除.idea和pom.xml文件以外的所有文件
2.2 添加依赖
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.ku</groupId> <artifactId>cloud-RuoYi</artifactId> <packaging>pom</packaging> <version>1.0-SNAPSHOT</version> <modules> <module>ruoyi-system</module> <module>ruoyi-common</module> <module>ruoyi-auth</module> </modules> <properties> <ruoyi.version>3.6.3</ruoyi.version> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> <spring-boot.version>2.7.13</spring-boot.version> <spring-cloud.version>2021.0.8</spring-cloud.version> <spring-cloud-alibaba.version>2021.0.5.0</spring-cloud-alibaba.version> <spring-boot-admin.version>2.7.10</spring-boot-admin.version> <swagger.fox.version>3.0.0</swagger.fox.version> <swagger.core.version>1.6.2</swagger.core.version> <tobato.version>1.27.2</tobato.version> <kaptcha.version>2.3.3</kaptcha.version> <pagehelper.boot.version>1.4.7</pagehelper.boot.version> <druid.version>1.2.16</druid.version> <dynamic-ds.version>3.5.2</dynamic-ds.version> <commons.io.version>2.13.0</commons.io.version> <velocity.version>2.3</velocity.version> <fastjson.version>2.0.39</fastjson.version> <jjwt.version>0.9.1</jjwt.version> <minio.version>8.2.2</minio.version> <poi.version>4.1.2</poi.version> <transmittable-thread-local.version>2.14.3</transmittable-thread-local.version> </properties> <!-- 依赖声明 --> <dependencyManagement> <dependencies> <!-- SpringCloud 微服务 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> <!-- SpringCloud Alibaba 微服务 --> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-dependencies</artifactId> <version>${spring-cloud-alibaba.version}</version> <type>pom</type> <scope>import</scope> </dependency> <!-- SpringBoot 依赖配置 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>${spring-boot.version}</version> <type>pom</type> <scope>import</scope> </dependency> <!-- FastDFS 分布式文件系统 --> <dependency> <groupId>com.github.tobato</groupId> <artifactId>fastdfs-client</artifactId> <version>${tobato.version}</version> </dependency> <!-- Swagger 依赖配置 --> <dependency> <groupId>io.swagger</groupId> <artifactId>swagger-models</artifactId> <version>${swagger.core.version}</version> </dependency> <dependency> <groupId>io.swagger</groupId> <artifactId>swagger-annotations</artifactId> <version>${swagger.core.version}</version> </dependency> <!-- 验证码 --> <dependency> <groupId>pro.fessional</groupId> <artifactId>kaptcha</artifactId> <version>${kaptcha.version}</version> </dependency> <!-- pagehelper 分页插件 --> <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper-spring-boot-starter</artifactId> <version>${pagehelper.boot.version}</version> </dependency> <!-- io常用工具类 --> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>${commons.io.version}</version> </dependency> <!-- excel工具 --> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>${poi.version}</version> </dependency> <!-- 代码生成使用模板 --> <dependency> <groupId>org.apache.velocity</groupId> <artifactId>velocity-engine-core</artifactId> <version>${velocity.version}</version> </dependency> <!-- JSON 解析器和生成器 --> <dependency> <groupId>com.alibaba.fastjson2</groupId> <artifactId>fastjson2</artifactId> <version>${fastjson.version}</version> </dependency> <!-- JWT --> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> <version>${jjwt.version}</version> </dependency> <!-- 线程传递值 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>transmittable-thread-local</artifactId> <version>${transmittable-thread-local.version}</version> </dependency> <!-- 核心模块 --> <dependency> <groupId>com.ku</groupId> <artifactId>ruoyi-common-core</artifactId> <version>1.0-SNAPSHOT</version> </dependency> <!--<!– 接口模块 –>--> <!--<dependency>--> <!--<groupId>com.ku</groupId>--> <!--<artifactId>ruoyi-common-swagger</artifactId>--> <!--<version>1.0-SNAPSHOT</version>--> <!--</dependency>--> <!-- 安全模块 --> <dependency> <groupId>com.ku</groupId> <artifactId>ruoyi-common-security</artifactId> <version>1.0-SNAPSHOT</version> </dependency> <!--<!– 权限范围 –>--> <!--<dependency>--> <!--<groupId>com.ku</groupId>--> <!--<artifactId>ruoyi-common-datascope</artifactId>--> <!--<version>1.0-SNAPSHOT</version>--> <!--</dependency>--> <!--<!– 多数据源 –>--> <!--<dependency>--> <!--<groupId>com.ku</groupId>--> <!--<artifactId>ruoyi-common-datasource</artifactId>--> <!--<version>1.0-SNAPSHOT</version>--> <!--</dependency>--> <!--<!– 分布式事务 –>--> <!--<dependency>--> <!--<groupId>com.ku</groupId>--> <!--<artifactId>ruoyi-common-seata</artifactId>--> <!--<version>1.0-SNAPSHOT</version>--> <!--</dependency>--> <!--<!– 日志记录 –>--> <!--<dependency>--> <!--<groupId>com.ku</groupId>--> <!--<artifactId>ruoyi-common-log</artifactId>--> <!--<version>1.0-SNAPSHOT</version>--> <!--</dependency>--> <!-- 缓存服务 --> <dependency> <groupId>com.ku</groupId> <artifactId>ruoyi-common-redis</artifactId> <version>1.0-SNAPSHOT</version> </dependency> <!-- 系统接口 --> <dependency> <groupId>com.ku</groupId> <artifactId>ruoyi-system</artifactId> <version>1.0-SNAPSHOT</version> </dependency> </dependencies> </dependencyManagement> <dependencies> <!-- bootstrap 启动器 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-bootstrap</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>${java.version}</source> <target>${java.version}</target> <encoding>${project.build.sourceEncoding}</encoding> </configuration> </plugin> </plugins> <!--<pluginManagement>--> <!--<plugins>--> <!--<plugin>--> <!--<groupId>org.springframework.boot</groupId>--> <!--<artifactId>spring-boot-maven-plugin</artifactId>--> <!--<version>${spring-boot.version}</version>--> <!--<executions>--> <!--<execution>--> <!--<goals>--> <!--<goal>repackage</goal>--> <!--</goals>--> <!--</execution>--> <!--</executions>--> <!--</plugin>--> <!--</plugins>--> <!--</pluginManagement>--> </build> <repositories> <repository> <id>public</id> <name>aliyun nexus</name> <url>https://maven.aliyun.com/repository/public</url> <releases> <enabled>true</enabled> </releases> </repository> </repositories> <pluginRepositories> <pluginRepository> <id>public</id> <name>aliyun nexus</name> <url>https://maven.aliyun.com/repository/public</url> <releases> <enabled>true</enabled> </releases> <snapshots> <enabled>false</enabled> </snapshots> </pluginRepository> </pluginRepositories> </project>
2.3 搭建ruoyi-system模块
2.3.1 导入依赖
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>cloud-RuoYi</artifactId> <groupId>com.ku</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>ruoyi-system</artifactId> <dependencies> <!-- RuoYi Common Core--> <dependency> <groupId>com.ku</groupId> <artifactId>ruoyi-common-core</artifactId> </dependency> </dependencies> </project>
在ruoyi-system模块中需要导入ruoyi-common-core模块,该模块中包含若依项目中核心的代码部分,包含注解、常量、消息响应、异常、分页、XSS、工具类等功能包的使用。
2.3.2 编写实体类
编写SysDept、SysDictType、SysDictData、SysFile、SysLogininfor、SysOperLog、SysRole、SysRole等实体类的属性及其对应的set和get方法以及toString()方法。
2.3.3 编写provider的三个业务接口的服务降级类
当请求的接口方法中出现异常时,我们通过服务降级方法快速返回异常,以免阻塞其他接口方法的操作。
package com.ku.system.api.factory; import com.ku.common.core.domain.R; import com.ku.system.api.RemoteUserService; import com.ku.system.api.domain.SysUser; import com.ku.system.api.model.LoginUser; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.cloud.openfeign.FallbackFactory; public class RemoteUserFallbackFactory implements FallbackFactory<RemoteUserService> { private static final Logger log = LoggerFactory.getLogger(RemoteUserFallbackFactory.class); @Override public RemoteUserService create(Throwable cause) { log.error("用户服务调用失败:{}", cause.getMessage()); return new RemoteUserService() { @Override public R<LoginUser> getUserInfo(String username, String source) { return R.fail("获取用户失败:"+cause.getMessage()); } @Override public R<Boolean> registerUserInfo(SysUser sysUser, String source) { return R.fail("注册用户失败:"+cause.getMessage()); } }; } }
package com.ku.system.api.factory; import com.ku.common.core.domain.R; import com.ku.system.api.RemoteLogService; import com.ku.system.api.domain.SysLogininfor; import com.ku.system.api.domain.SysOperLog; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.cloud.openfeign.FallbackFactory; public class RemoteLogFallbackFactory implements FallbackFactory<RemoteLogService> { private static final Logger log = LoggerFactory.getLogger(RemoteLogFallbackFactory.class); @Override public RemoteLogService create(Throwable cause) { log.error("日志服务调用失败:{}", cause.getMessage()); return new RemoteLogService() { @Override public R<Boolean> saveLog(SysOperLog sysOperLog, String source) throws Exception { return R.fail("保存操作日志失败:"+cause.getMessage()); } @Override public R<Boolean> saveLogininfor(SysLogininfor sysLogininfor, String source) { return R.fail("保存登录用户信息失败:"+cause.getMessage()); } }; } }
package com.ku.system.api.factory; import com.ku.common.core.domain.R; import com.ku.system.api.RemoteUserService; import com.ku.system.api.domain.SysUser; import com.ku.system.api.model.LoginUser; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.cloud.openfeign.FallbackFactory; public class RemoteUserFallbackFactory implements FallbackFactory<RemoteUserService> { private static final Logger log = LoggerFactory.getLogger(RemoteUserFallbackFactory.class); @Override public RemoteUserService create(Throwable cause) { log.error("用户服务调用失败:{}", cause.getMessage()); return new RemoteUserService() { @Override public R<LoginUser> getUserInfo(String username, String source) { return R.fail("获取用户失败:"+cause.getMessage()); } @Override public R<Boolean> registerUserInfo(SysUser sysUser, String source) { return R.fail("注册用户失败:"+cause.getMessage()); } }; } }
2.3.4 编写provider的三个被调用服务业务接口
provider中的三个通用的服务调用接口,被其他consumer服务调用。
package com.ku.system.api; import com.ku.common.core.constant.ServiceNameConstants; import com.ku.common.core.domain.R; import com.ku.system.api.domain.SysFile; import com.ku.system.api.factory.RemoteFileFallbackFactory; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestPart; import org.springframework.web.multipart.MultipartFile; //作为服务提供者,为其他服务提供服务 //contextId指定Feign客户端的上下文ID,用于区分不同的Feign客户端。 @FeignClient(contextId = "remoteFileService", value = ServiceNameConstants.FILE_SERVICE, fallbackFactory = RemoteFileFallbackFactory.class) public interface RemoteFileService { /** * 上传文件 */ //SpringMVC用于文件上传的注解,MULTIPART_FORM_DATA_VALUE多部分请求,可用于文件上传 @PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) //@RequestPart用于处理文件请求 public R<SysFile> upload(@RequestPart(value = "file")MultipartFile file); }
package com.ku.system.api; import com.ku.common.core.constant.SecurityConstants; import com.ku.common.core.constant.ServiceNameConstants; import com.ku.common.core.domain.R; import com.ku.system.api.domain.SysLogininfor; import com.ku.system.api.domain.SysOperLog; import com.ku.system.api.factory.RemoteLogFallbackFactory; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestHeader; @FeignClient(contextId = "remoteLogService", value = ServiceNameConstants.SYSTEM_SERVICE, fallbackFactory = RemoteLogFallbackFactory.class) public interface RemoteLogService { /** * 保存系统日志 */ @PostMapping("/operlog") public R <Boolean> saveLog(@RequestBody SysOperLog sysOperLog, @RequestHeader(SecurityConstants.FROM_SOURCE) String source) throws Exception; @PostMapping("/logininfor") public R<Boolean> saveLogininfor(@RequestBody SysLogininfor sysLogininfor, @RequestHeader(SecurityConstants.FROM_SOURCE) String source); }
package com.ku.system.api; import com.ku.common.core.constant.SecurityConstants; import com.ku.common.core.constant.ServiceNameConstants; import com.ku.common.core.domain.R; import com.ku.system.api.domain.SysUser; import com.ku.system.api.factory.RemoteUserFallbackFactory; import com.ku.system.api.model.LoginUser; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestHeader; @FeignClient(contextId = "remoteUserService", value = ServiceNameConstants.SYSTEM_SERVICE, fallbackFactory = RemoteUserFallbackFactory.class) public interface RemoteUserService { @GetMapping("/user/info/{username}") //@RequestHeader(SecurityConstants.FROM_SOURCE)用于获取HTTP请求中的指定名称的值 public R<LoginUser> getUserInfo(@PathVariable("username") String username, @RequestHeader(SecurityConstants.FROM_SOURCE) String source); //注册用户信息 @GetMapping("/user/register") public R<Boolean>registerUserInfo(@RequestBody SysUser sysUser, @RequestHeader(SecurityConstants.FROM_SOURCE) String source); }
若依项目链接
RuoYi-Cloud: 🎉 基于Spring Boot、Spring Cloud & Alibaba的分布式微服务架构权限管理系统,同时提供了 Vue3 的版本 (gitee.com)