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>
cloud-ruoyi项目依赖
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-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());
}
};
}
}
RemoteFileFallbackFactory
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());
}
};
}
}
RemoteLogFallbackFactory
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());
}
};
}
}
RemoteUserFallbackFactory
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);
}
RemoteFileService
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);
}
RemoteLogService
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);
}
RemoteUserService
若依项目链接
RuoYi-Cloud: 🎉 基于Spring Boot、Spring Cloud & Alibaba的分布式微服务架构权限管理系统,同时提供了 Vue3 的版本 (gitee.com)