第一次抛开restful,改用jsonrpc2.0方式提供接口,其中也遇到了不少问题,由此记录一下。
一,协议基本介绍百度搜索 jsonrpc2.0,这里就不细说了。
二,前置配置
1,引入pom.xml。
<!-- jsonrpc start -->
<dependency>
<groupId>com.github.briandilley.jsonrpc4j</groupId>
<artifactId>jsonrpc4j</artifactId>
<version>1.5.3</version>
</dependency>
<!-- jsonrpc end -->
2,配置类
package com.config;
import com.googlecode.jsonrpc4j.MultipleInvocationListener;
import com.googlecode.jsonrpc4j.spring.AutoJsonRpcServiceImplExporter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
/**
* 1,格式参照jsonrpc格式
*
* @Description TODO
* @Author zhaojilong
* @Date 2021/9/27 11:14
* @Version 1.0
**/
@Configuration
@ComponentScan(basePackages = {"com.rpcservice"})
public class RpcConfig {
@Bean
public AutoJsonRpcServiceImplExporter rpcServiceImplExporter() {
AutoJsonRpcServiceImplExporter rpc = new AutoJsonRpcServiceImplExporter();
rpc.setRegisterTraceInterceptor(true);
MultipleInvocationListener invocationListener = new MultipleInvocationListener();
rpc.setInvocationListener(invocationListener);
rpc.setShouldLogInvocationErrors(false);
rpc.setContentType("application/json-rpc;charset=utf-8");
//替换默认的json序列化
//rpc.setObjectMapper(ModelObject.OBJECT_MAPPER);
//自定义错误处理器,便于记录log
//rpc.setErrorResolver(new CodeRpc());
return rpc;
}
}
3,接口类,这里服务名是否必须以 rpc/ 打头,可以再试试
package com.rpcservice;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.googlecode.jsonrpc4j.JsonRpcParam;
import com.googlecode.jsonrpc4j.JsonRpcService;
import org.springframework.web.bind.annotation.RequestParam;
/**
* 操作日志 rpc接口
* jsonrpc协议
* 服务名必须以 rpc/ 打头
*/
@JsonRpcService("/rpc/sysOrgDept")
public interface RpcSysOrgDeptService {
/**
* 分页查询
* @param page
* @return
*/
ResultData findPage(@JsonRpcParam("page") Page page);
}
4,接口实现类
package com.rpcservice.impl;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.googlecode.jsonrpc4j.JsonRpcClientException;
import com.googlecode.jsonrpc4j.spring.AutoJsonRpcServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import javax.transaction.Transactional;
import java.util.Arrays;
import java.util.List;
/**
* @Description TODO
* @Author zhaojilong
* @Date 2021/9/23 9:49
* @Version 1.0
**/
@Service
@AutoJsonRpcServiceImpl
@Slf4j
public class RpcSysOrgDeptServiceImpl implements RpcSysOrgDeptService {
@Override
public ResultData findTree() {
log.debug("start findTree method");
JSONArray deptTree = new JSONArray();
return ResultData.success();
}
}
5,访问地址
三,遇到的问题
1, 传参问题
1) jsonrpc请求一般为get和post。而post居多,也方便传入参数。如果用get,则所有的参数都需要urlencode转码。
2) 如果接口定义的参数是对象,则传入参数也需要以对象传入(普通http请求,在controller接收参数,一个@requestbody就搞定了)。如果没有值,也必须传{}(这就很不爽- -)
2, 异常抛出
1) 我自己遇到的一个问题。如果程序发生异常或者自定义异常,正确的返回值应该是:
{
"id": 0,
"jsonrpc": "2.0",
"error": {
"code": -36010,
"message": "自定义提示",
"data":null
}
}
而我当时只要是异常抛出,永远都是下面这样的
{
"id": 0,
"jsonrpc": "2.0",
"result": null
}
这是因为我之前写过拦截器,将返回值给拦截了然后null处理了(这蛋疼了相当久,希望读者不要遇到这个问题- -),一般是不会有这问题出现的
2) 当我处理完上面的问题后,发现jsonrpc没法自定义错误code,只能自定义错误message。抛出异常的写法:
throw new JsonRpcClientException(-32002, "请传入正确的名称", null);
然后收到的是:
{
"id": 0,
"jsonrpc": "2.0",
"error": {
"code": -36001,
"message": "请传入正确的名称",
"data":null
}
}
发现有上面不同没有,抛出的code是-32002,返回的是-36001。然后就去看jsonrpc4j的代码,找到它是在这个类进行默认处理了,统一的错误code都是-36001,所以才没生效
3) 解决方法:
重写这个类
package com.googlecode.jsonrpc4j;
import com.fasterxml.jackson.databind.JsonNode;
import com.googlecode.jsonrpc4j.ErrorData;
import com.googlecode.jsonrpc4j.ErrorResolver;
import com.googlecode.jsonrpc4j.JsonRpcClientException;
import java.lang.reflect.Method;
import java.util.List;
import static com.googlecode.jsonrpc4j.ErrorResolver.JsonError.ERROR_NOT_HANDLED;
/**
* 重写jsonrpc2.0中的异常处理类
* @Description TODO
* @Author zhaojilong
* @Date 2021/10/22 11:21
* @Version 1.0
**/
public enum DefaultErrorResolver implements ErrorResolver {
INSTANCE;
/**
* {@inheritDoc}
*/
public JsonError resolveError(Throwable t, Method method, List<JsonNode> arguments) {
//新增异常判断,并且带入错误code
if (t instanceof JsonRpcClientException) {
JsonRpcClientException rpcException = ((JsonRpcClientException) t);
return new JsonError(rpcException.getCode(), rpcException.getMessage(), new ErrorData(t.getClass().getName(), rpcException.getMessage()));
}
return new JsonError(ERROR_NOT_HANDLED.code, t.getMessage(), new ErrorData(t.getClass().getName(), t.getMessage()));
}
}