在开发中两个服务之间相互调用通常出现在微服务架构中:
(服务注册 -> 服务配置 -> 引入RPC相关依赖 -> 调用请求)但是这一套流程下来对于简单的系统而言有些复杂了,那么这篇文章就通过一些简单的配置,带你去保证服务之间的通信,使用最原始的Http请求去实现服务之间的通信。
项目背景
这两个项目分别都使用了security
框架配合Jwt
进行权限校验,然后我们模拟swagger一样,只需要在头中添加token即可保证服务之间的联通调用, 所以我们的难点就转移到了如何去获取token了。
css
我们先自定义一下服务服务A是数据来源服务,项目B是请求服务
token获取
这里因为我们的token都是根据用户名和密码,所以在另外一个项目里面请求的时候肯定也是去模仿登录的时候入参账号和密码,然后我们在A系统里面单独开一个角色与账户、密码用于另外一个项目访问使用。
这里一般与自己的项目具体业务有关,这里就不多赘述了,然后们就能拿到与这个角色绑定的相关用户信息了(账号密码)接下来我们准备请求工具包
请求util
我们将请求都封装到一个工具里面方便我们多次调用,这里我用的请求方法是okhttp3
与fastjson
去做相关的请求参数转化。
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
类,参考我这种写法
总结
如果有帮助到大家请留下你们的小爱心,感谢支持