服务之间的通信(原始方式)

在开发中两个服务之间相互调用通常出现在微服务架构中:

(服务注册 -> 服务配置 -> 引入RPC相关依赖 -> 调用请求)但是这一套流程下来对于简单的系统而言有些复杂了,那么这篇文章就通过一些简单的配置,带你去保证服务之间的通信,使用最原始的Http请求去实现服务之间的通信。


项目背景

这两个项目分别都使用了security框架配合Jwt进行权限校验,然后我们模拟swagger一样,只需要在头中添加token即可保证服务之间的联通调用, 所以我们的难点就转移到了如何去获取token了。

css 复制代码
   我们先自定义一下服务服务A是数据来源服务,项目B是请求服务

token获取

这里因为我们的token都是根据用户名和密码,所以在另外一个项目里面请求的时候肯定也是去模仿登录的时候入参账号和密码,然后我们在A系统里面单独开一个角色与账户、密码用于另外一个项目访问使用。

这里一般与自己的项目具体业务有关,这里就不多赘述了,然后们就能拿到与这个角色绑定的相关用户信息了(账号密码)接下来我们准备请求工具包

请求util

我们将请求都封装到一个工具里面方便我们多次调用,这里我用的请求方法是okhttp3fastjson去做相关的请求参数转化。

pom依赖

xml 复制代码
<dependency>
    <groupId>com.squareup.okhttp3</groupId>
    <artifactId>okhttp</artifactId>
    <version>${okHttp.version}</version>
</dependency>
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>${fastjson.version}</version>
</dependency>

请求的util,这里我就只演示post请求了

java 复制代码
/**
 * 发送post请求
 */
public static <T> String realNameVerify(String url, T entity) {
    Response response = getResponse(url, entity);
    String respBody = null;
    try {
        respBody = response.body().string();
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
    TypeReference<CommonResult<?>> typeRef = new TypeReference<CommonResult<?>>() {};
    CommonResult<?> commonResult = JSON.parseObject(respBody, typeRef);
    log.info("请求地址:" + url + ",返回内容:" + respBody);
    if (CommonResultCode.SUCCESS.getCode()==commonResult.getCode()) {
        if (ObjUtil.isNull(commonResult.getData())) {
            return null;
        }
        return commonResult.getData().toString();
    }else if (commonResult.getCode()==CommonResultCode.UNAUTHORIZED.getCode()
            || commonResult.getCode()==CommonResultCode.PERMISSION_EXPIRATION.getCode()){
        log.info("请求过期,重新获取token时间:"+System.currentTimeMillis());
        Map<String, String> map = new HashMap<String,String>(){{
            put("account",SalesConstants.ACCOUNT);
            put("pwd",SalesConstants.PWD);
        }};
        try {
            respBody = Objects.requireNonNull(getResponse(SalesConstants.LOGIN, map).body()).string();
            Authori = (String) JSON.parseObject(respBody, typeRef).getData();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return realNameVerify(url,entity);
    }else {
        throw new RuntimeException(commonResult.getMessage());
    }
}

这里可以看到我定义了一个CommonResult方法对应的是A项目中public CommonResult<String> getToken(@RequestBody) 返回的公共数据,所以我在接收的时候使用了CommonResult<?>这个语法糖可以接受任意的范型,方便我们后续处理

java 复制代码
/**
 * 发送请求
 */
@NotNull
private static <T> Response getResponse(String url, T entity) {
    Response response = null;
    ObjectMapper objectMapper = new ObjectMapper();
    OkHttpClient client = new OkHttpClient();
    log.info("请求地址:"+ url +",请求内容:" + entity);
    try {
        String jsonBody = objectMapper.writeValueAsString(entity);
        Request request = new Request.Builder()
                .url(url)
                .addHeader("Authori-zation", Authori)
                .post(RequestBody.create(MediaType.parse("application/json"), jsonBody))
                .build();
        response = client.newCall(request).execute();
    } catch (IOException e) {
        throw new RuntimeException("crmeb服务异常:", e);
    }
    return response;
}

这里的Authori是我们通过调用请求登录方法获取到的token,这里具体请求项目使用的什么校验方式就修改为什么校验方式,比如我这里就使用的Authori-zation这种校验方式,然后在我代码中可以看到如果登录过期,那么它就会自动去请求登录信息,然后将获取到的token给赋值到一个全局Authori中,方便后续的使用。

在我的代码中还有许多地方都使用了常量,因为在我们请求服务的时候会用到大量请求地址,这里我就统一使用一个常量类对其管理 # 管理url 将一些配置抽离出来到一个单独的类中,方便后续维护,就比如我这里将登录请求的地址账号密码统一都抽取出来到yml中:

yml 复制代码
    url: http://localhost:8080
    account: root
    pwd: root

然后在引入到常量类中

java 复制代码
@Component
public class SalesConstants {

    @Value("${url}")
    private String crmebUrl;

    @Value("${account}")
    private String account;

    @Value("${pwd}")
    private String pwd;

    /** 登录 **/
    public static String LOGIN;
    public static String ACCOUNT;
    public static String PWD;

//    =====================初始化=====================
    @PostConstruct
    public void init() {
        LOGIN = crmebUrl + "/api/admin/get";
        ACCOUNT = account;
        PWD = pwd;
    }

}

因为我们在使用的时候是直接使用的static修饰的静态方法,而我们使用Value或者其他注入方式注入的时候只能注入到普通的方法中,所以这里我们添加了init方法如上将获取到的值赋值给静态变量。同样的如果还有其他的请求方法需要加入到这里,也可以模仿上面的实现如下:

java 复制代码
String data = realNameVerify(SalesConstants.GET_CUSTOMER, request);
TypeReference<<UserResponse>> typeRef = new TypeReference<<UserResponse>>() {};
return JSON.parseObject(data, typeRef);

我们拿到请求的body之后,再次使用TypeReference这个方法转化为我们需要的UserResponse类,参考我这种写法

总结

如果有帮助到大家请留下你们的小爱心,感谢支持

相关推荐
代码吐槽菌2 小时前
基于SSM的毕业论文管理系统【附源码】
java·开发语言·数据库·后端·ssm
豌豆花下猫2 小时前
Python 潮流周刊#78:async/await 是糟糕的设计(摘要)
后端·python·ai
YMWM_2 小时前
第一章 Go语言简介
开发语言·后端·golang
码蜂窝编程官方2 小时前
【含开题报告+文档+PPT+源码】基于SpringBoot+Vue的虎鲸旅游攻略网的设计与实现
java·vue.js·spring boot·后端·spring·旅游
hummhumm3 小时前
第 25 章 - Golang 项目结构
java·开发语言·前端·后端·python·elasticsearch·golang
J老熊3 小时前
JavaFX:简介、使用场景、常见问题及对比其他框架分析
java·开发语言·后端·面试·系统架构·软件工程
AuroraI'ncoding3 小时前
时间请求参数、响应
java·后端·spring
好奇的菜鸟3 小时前
Go语言中的引用类型:指针与传递机制
开发语言·后端·golang
Alive~o.03 小时前
Go语言进阶&依赖管理
开发语言·后端·golang
许苑向上3 小时前
Dubbo集成SpringBoot实现远程服务调用
spring boot·后端·dubbo