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

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

(服务注册 -> 服务配置 -> 引入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类,参考我这种写法

总结

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

相关推荐
2401_857439692 小时前
Spring Boot新闻推荐系统:用户体验优化
spring boot·后端·ux
进击的女IT3 小时前
SpringBoot上传图片实现本地存储以及实现直接上传阿里云OSS
java·spring boot·后端
一 乐4 小时前
学籍管理平台|在线学籍管理平台系统|基于Springboot+VUE的在线学籍管理平台系统设计与实现(源码+数据库+文档)
java·数据库·vue.js·spring boot·后端·学习
艾伦~耶格尔7 小时前
Spring Boot 三层架构开发模式入门
java·spring boot·后端·架构·三层架构
man20177 小时前
基于spring boot的篮球论坛系统
java·spring boot·后端
攸攸太上8 小时前
Spring Gateway学习
java·后端·学习·spring·微服务·gateway
罗曼蒂克在消亡8 小时前
graphql--快速了解graphql特点
后端·graphql
潘多编程8 小时前
Spring Boot与GraphQL:现代化API设计
spring boot·后端·graphql
大神薯条老师9 小时前
Python从入门到高手4.3节-掌握跳转控制语句
后端·爬虫·python·深度学习·机器学习·数据分析
2401_857622669 小时前
Spring Boot新闻推荐系统:性能优化策略
java·spring boot·后端