OJ在线评测系统 微服务 OpenFeign调整后端上 内部调用Client代码书写 实现客户端接口 配置服务参数 接口文档

news2024/11/25 19:36:57

OpenFeign内部调用上

我们的代码已经搬运完毕了

但是我们的服务之间是无法相互调用的

我们可以使用OpenFeign进行远程调用

一个http调用客户端

提供了更方便的方式让你远程调用其他的服务

Nacos注册中心获取服务的调用地址

如果没有实现OpenFeign

也能实现跨服务的调用 写死成url也行 从Nacos调用

但是OpenFeign可以直接把服务扔给他 就行

1...梳理服务的调用关系 确定哪些服务(接口)需要给内部调用

用户服务 : 没有其他的依赖

题目服务 : userservice

判题服务 : questionService 和 questionSubmitService

2...确定要提供哪些服务

我们找一下我们的公共接口客户端

3...编写service-client部分的代码

就是在这个包里面

编写client部分的代码

由于这个request没有涉及数据库中的操作

为了防止数据因为没有序列化的问题而丢失了

我们会把这个方法写成默认方法 default

将方法定义为 default 是为了在接口中提供一个默认实现,允许实现该接口的类在不重写此方法的情况下,直接使用它。这种设计有助于减少代码重复,提高可维护性,同时允许实现类根据需要覆盖此方法以实现特定的逻辑。

将方法定义为 default 的原因主要包括以下几点:

  1. 接口演进default 方法允许在接口中添加新方法而不破坏现有实现。这使得可以在不影响已有代码的情况下扩展接口功能。

  2. 代码重用:通过提供默认实现,可以在多个实现类中重用相同的逻辑,减少代码重复。

  3. 灵活性:实现类可以选择重写 default 方法以提供特定实现,或者直接使用默认实现,增强了灵活性。

  4. 简化实现:对于一些常用的方法,提供默认实现可以减少实现类的负担,让开发者专注于独特的功能。

这些优势使得 default 方法在现代 Java 编程中变得非常有用。

    /**
     * 获取当前登录用户
     *
     * @param request
     * @return
     */
    default User getLoginUser(HttpServletRequest request) {
        // 先判断是否已登录
        Object userObj = request.getSession().getAttribute(USER_LOGIN_STATE);
        User currentUser = (User) userObj;
        if (currentUser == null || currentUser.getId() == null) {
            throw new BusinessException(ErrorCode.NOT_LOGIN_ERROR);
        }
        // 可以考虑在这里做全局权限校验
        return currentUser;
    }

这边也是

我们写成默认的方法

也没有必要远程调用

    /**
     * 是否为管理员
     *
     * @param user
     * @return
     */
    default boolean isAdmin(User user) {
        return user != null && UserRoleEnum.ADMIN.getValue().equals(user.getUserRole());
    }

    /**
     * 获取脱敏的用户信息
     *
     * @param user
     * @return
     */
    default UserVO getUserVO(User user) {
        if (user == null) {
            return null;
        }
        UserVO userVO = new UserVO();
        BeanUtils.copyProperties(user, userVO);
        return userVO;
    }

接下来

我们要实现客户端接口

要开启openfeign支持 把我们的接口暴露出去 作为API 给其他服务调用

服务注册到注册中心上去

其他服务从注册中心寻找

怎么实现呢 我们依靠的是一个注解@FeignClient

可以把name的内容理解成客户端要到nacos上去找到的具体服务的名称

@FeignClient(name = "yuoj-backend-user-service", path = "/api/user/inner")

我们的每个服务都有这么一行配置

这段配置主要用于定义一个服务器的基本参数,具体说明如下:

  • address: 0.0.0.0:表示服务器将绑定到所有可用的网络接口上,允许外部访问。

  • port: 8102:服务器将监听8102端口,接收请求。

  • servlet:与服务器处理HTTP请求相关的配置。

    • context-path: /api/user:这是应用的上下文路径,所有访问这个服务器的请求都会以/api/user开头。

  • session

    • cookie

      :用于配置会话的相关属性。

      • max-age: 2592000:设置会话cookie的最大生存时间,这里是2592000秒(即30天)。

      • path: /api:指定cookie的有效路径,表示只有在以/api开头的请求中,服务器才会发送这个cookie。

简单来说,这段配置用于设定一个API服务器的基本连接参数和会话管理。

需要的是修改每一个服务提供者的context-path 全局请求路径

统一一下 便于我们书写接口路径

服务提供者:理解为接口的实现类 实际提供接口的模块

服务消费者:理解为接口的调用方 需要去找到服务提供者 然后调用

还要指定具体服务的地址

   /**
     * 根据 id 获取用户
     * @param userId
     * @return
     */
    @GetMapping("/get/id")
    User getById(@RequestParam("userId") long userId);

    /**
     * 根据 id 获取用户列表
     * @param idList
     * @return
     */
    @GetMapping("/get/ids")
    List<User> listByIds(@RequestParam("idList") Collection<Long> idList);

定义接口方法时 要打上请求注解 注意区分 Get 和 Post

@RequestParam 注解 指定字段

防止数据传输不过去

对于服务 有一些不利于远程调用参数传递 可以不用指定字段

我们默认注册的服务

是写在模块的配置文件里面的

对应@FeignClient注解里面的name

举例

spring:
  application:
    name: yuoj-backend-user-service

这些路径实际上应该写在文档里面 接口文档

题目模块

package com.yupi.yuojbackendserviceclient.service;


import com.yupi.yuojbackendmodel.model.entity.Question;
import com.yupi.yuojbackendmodel.model.entity.QuestionSubmit;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;

/**
* @description 针对表【question(题目)】的数据库操作Service
* @createDate 2023-08-07 20:58:00
*/
@FeignClient(name = "yuoj-backend-question-service", path = "/api/question/inner")
public interface QuestionFeignClient {

    @GetMapping("/get/id")
    Question getQuestionById(@RequestParam("questionId") long questionId);

    @GetMapping("/question_submit/get/id")
    QuestionSubmit getQuestionSubmitById(@RequestParam("questionId") long questionSubmitId);

    @PostMapping("/question_submit/update")
    boolean updateQuestionSubmitById(@RequestBody QuestionSubmit questionSubmit);

}

判题模块

这是之前写在代码沙箱里面的

package com.yupi.yuojbackendserviceclient.service;


import com.yupi.yuojbackendmodel.model.entity.QuestionSubmit;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;

/**
 * 判题服务
 */
@FeignClient(name = "yuoj-backend-judge-service", path = "/api/judge/inner")
public interface JudgeFeignClient {

    /**
     * 判题
     * @param questionSubmitId
     * @return
     */
    @PostMapping("/do")
    QuestionSubmit doJudge(@RequestParam("questionSubmitId") long questionSubmitId);
}

注意的是

@RequestParam 注解用于处理 HTTP 请求参数,主要在 Spring MVC 中使用。它可以将请求中的参数绑定到方法的参数上,方便获取用户输入的值

1.要给接口的每个方法打上请求注解 注意区分Get 和 Post

2.要给请求参数打上注解 比如说RequestParam RequestBody

3.FeignClient定义的请求路径一定要和服务提供方实际的请求路径保持一致

路由划分

用springboot的context-path统一修改个项目的接口前缀

比如 用户服务

/api/user

/api/user/inner(内部调用 网关层面要做限制)

比如 题目服务

/api/question(也包含题目提交信息)

/api/question/inner(内部调用 网关层面要做限制)

比如 判题服务

/api/judge

/api/judge/inner(内部调用 网关层面要做限制)

最终效果

注入客户端对象

实现远程调用

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2195154.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Windows 11 version 24H2 LTSC 2024 中文版、英文版 (x64、ARM64) 下载 (updated Oct 2024)

Windows 11 version 24H2 & LTSC 2024 中文版、英文版 (x64、ARM64) 下载 (updated Oct 2024) Windows 11, version 24H2&#xff0c;企业版 arm64 x64 请访问原文链接&#xff1a;https://sysin.org/blog/windows-11/ 查看最新版。原创作品&#xff0c;转载请保留出处。…

出国必备神器!这5款中英翻译工具让你秒变外语达人

在这个全球化的时代&#xff0c;中英互译已然成为我们日常生活和工作中不可或缺的一环。面对众多的翻译工具&#xff0c;如何选择一款既高效又人性化的翻译助手呢&#xff1f;今天&#xff0c;就让我为大家揭秘几款热门的中英互译工具&#xff0c;并分享我的使用感受。 一、福昕…

【数据结构与算法】线性表

文章目录 一.什么是线性表&#xff1f;二.线性表如何存储&#xff1f;三.线性表的类型 我们知道从应用中抽象出共性的逻辑结构和基本操作就是抽象数据类型&#xff0c;然后实现其存储结构和基本操作。下面我们依然按这个思路来认识线性表 一.什么是线性表&#xff1f; 定义 线性…

【项目记录】大模型基于llama.cpp在Qemu-riscv64向量扩展指令下的部署

概述 本文在qemu-riscv64平台上&#xff0c;利用向量扩展指令加速运行基于llama.cpp构建的大模型。 参考博客链接&#xff1a; Accelerating llama.cpp with RISC-V Vector Extension 基于RVV的llama.cpp在Banana Pi F3 RISCV开发板上的演示 llama.cpp工程 Llama.cpp是一个基…

C语言-指针变量,常量与数组名的细微区别辨析

本节根据两个选择题进行展开辨析 一、例1 本题答案&#xff1a;C 解析&#xff1a;强干扰选项是B&#xff0c;我相信大多数同学都会在B&#xff0c;C之间犹豫好久&#xff0c;那么为什么答案会最终选择C呢&#xff1f;因为本题在定义函数&#xff0c;所以a首先是一个数组名&a…

【学习笔记】一种使用多项式快速计算 sin 和 cos 近似值的方法

一种使用多项式快速计算 sin 和 cos 近似值的方法 在嵌入式开发、游戏开发或其他需要快速数学计算的领域&#xff0c;sin 和 cos 函数的计算时间可能会影响程序的整体性能。特别是在对时间敏感、精度要求不高的场景中&#xff0c;传统的 sin 和 cos 函数由于依赖复杂的数值方法…

SOMEIP_ETS_168: SD_TestFieldUINT8Reliable

测试目的&#xff1a; 验证DUT能够通过Getter和Setter方法正确地发送和接收TestFieldUINT8Reliable字段的值&#xff0c;并且这些操作是可靠的。 描述 本测试用例旨在确保DUT的ETS能够响应Tester的请求&#xff0c;正确地使用Getter方法获取TestFieldUINT8Reliable的值&…

【MySQL必知会】事务

目录 &#x1f308;前言&#x1f308; &#x1f4c1; 事务概念 &#x1f4c1; 事务操作 &#x1f4c1; 事务提交方式 &#x1f4c1; 隔离级别 &#x1f4c1; MVCC &#x1f4c2; 3个隐藏列字段 &#x1f4c2; undo日志 &#x1f4c2; Read View视图 &#x1f4c1; RR和R…

分治算法(5)_归并排序_排序数组

个人主页&#xff1a;C忠实粉丝 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 C忠实粉丝 原创 分治算法(5)_归并排序_排序数组 收录于专栏【经典算法练习】 本专栏旨在分享学习算法的一点学习笔记&#xff0c;欢迎大家在评论区交流讨论&#x1f48c; 目录 …

JavaSE——面向对象11:内部类(局部内部类、匿名内部类、成员内部类、静态内部类)

目录 一、内部类基本介绍 (一)内部类定义 (二)内部类基本语法 (三)内部类代码示例 (四)内部类的分类 二、局部内部类 三、匿名内部类(重要) (一)基本介绍 (二)基于接口的匿名内部类 (三)基于类的匿名内部类 (四)注意事项与使用细节 (五)匿名内部类的最佳实践——当…

leetcode-42. 接雨水 单调栈

给定 n 个非负整数表示每个宽度为 1 的柱子的高度图&#xff0c;计算按此排列的柱子&#xff0c;下雨之后能接多少雨水。 示例 1&#xff1a; 输入&#xff1a;height [0,1,0,2,1,0,1,3,2,1,2,1] 输出&#xff1a;6 解释&#xff1a;上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表…

Chrome浏览器调用ActiveX控件--allWebOffice控件

背景 allWebOffice控件能够实现在浏览器窗口中在线操作文档的应用&#xff08;阅读、编辑、保存等&#xff09;&#xff0c;支持编辑文档时保留修改痕迹&#xff0c;支持书签位置内容动态填充&#xff0c;支持公文套红&#xff0c;支持文档保护控制等诸多办公功能&#xff0c;本…

vim编辑器安装,并修改配置使其默认显示行数

centOS默认是未安装vim编辑器的&#xff0c;而vim编辑器相比vi编辑器更易用一些&#xff0c;如需使用vim编辑器&#xff0c;需要进行安装。 1.需要先配置本地yum源&#xff0c;参见如下链接&#xff1a; 点击查看如何配置本地yum源 2.安装vim编辑器&#xff0c;并修改配置。…

滑动窗口_找出字符串中所有字母异位词、串联所有单词的子串_C++

滑动窗口_找出字符串中所有字母异位词、串联所有单词的子串_C 1. 题目解析2. 算法分析3. 代码实现4. 举一反三&#xff1a;串联所有单词的子串 1. 题目解析 leetcode链接&#xff1a;https://leetcode.cn/problems/VabMRr/ 给定两个字符串 s 和 p&#xff0c;找到 s 中所有 p …

helm 测试安装redis

helm search repo redis # 搜索redis的chart helm show readme bitnami/redis # 展示安装相关文档&#xff08;readme文件&#xff09; 拉取指定版本的安装包&#xff08;chart&#xff09; helm pull bitnami/redis --version 17.4.3 解压安装包 tar -xf redis-17.4.3.tgz …

Vue3 动态路由实现的一种方法

动态路由 目的&#xff1a; 根据服务器传回来的数据动态的注册路由信息&#xff0c;登录用户的角色不同生成的菜单不同 使用插件做动态路由的好处&#xff1a; 路由页面增加或者减少时&#xff0c;只需要增加或减少相关的路由文件&#xff0c;不需要再修改代码 服务器返回的信…

POI数据的处理与分析

POI概念 POI&#xff08;Point of Interest&#xff0c;兴趣点&#xff09;数据指的是地理空间数据中的一类&#xff0c;表示某一具体地点或位置的信息。通常&#xff0c;这些数据包含位置坐标&#xff08;经纬度&#xff09;、名称、地址、类别和其他相关信息。POI 数据广泛应…

毕业设计 深度学习水果识别

文章目录 1 前言2 开发简介3 识别原理3.1 传统图像识别原理3.2 深度学习水果识别 4 数据集5 部分关键代码5.1 处理训练集的数据结构5.2 模型网络结构5.3 训练模型 6 识别效果 1 前言 Hi&#xff0c;大家好&#xff0c;这里是丹成学长&#xff0c;今天做一个 基于深度学习的水果…

算法剖析:双指针

文章目录 双指针算法一、 移动零1. 题目2. 算法思想3. 代码实现 二、 复写零1. 题目2. 算法思想3. 代码实现 三、 快乐数1. 题目2. 算法思想3. 代码实现 四、 盛水最多的容器1. 题目2. 算法思想3. 代码实现 五、有效三角形的个数1. 题目2. 算法思想3. 代码实现 六、 和为 s 的两…

【EXCEL数据处理】000020 案例 保姆级教程,附多个操作案例。EXCEL使用表格。

前言&#xff1a;哈喽&#xff0c;大家好&#xff0c;今天给大家分享一篇文章&#xff01;创作不易&#xff0c;如果能帮助到大家或者给大家一些灵感和启发&#xff0c;欢迎收藏关注哦 &#x1f495; 目录 【EXCEL数据处理】000020 案例 保姆级教程&#xff0c;附多个操作案例。…