常见问题
如果在使用Java Chassis的过程中碰到问题或者疑问,可以在 Java Chassis Github Issues 提交问题和搜索答案。
- Q: 契约生成会报错 Caused by: java.lang.Error: OperationId must be unique,不支持函数重载?
- Q: Map类型的key必须使用 String 类型?
- Q: 参数返回值不能使用接口?
- Q: 参数返回值不能使用泛型?
- Q: 实现类中 public 方法全部被发布为接口,如何排除?
- Q: 如何自定义某个Java方法对应的REST接口里的HTTP Status Code?
- Q: 使用HTTP Header参数出现乱码如何处理?
Q: 契约生成会报错 Caused by: java.lang.Error: OperationId must be unique,不支持函数重载?
- A: 支持函数重载,但是需要注意每个接口必须有唯一的operation id。可以加上
@Operation
标签给重载的接口指定唯一 的 operation id。示例代码如下:
@Path("/sayHello")
@GET
@Produces("text/plain;charset=UTF-8")
@Operation(operationId = "sayHello", summary = "say hello without parameter")
public String sayHello() {
return "Hello";
}
@Path("/sayHelloName")
@GET
@Produces("application/json;charset=UTF-8")
@Operation(operationId = "sayHelloName", summary = "say hello with name parameter")
public String sayHello(@ApiParam("name") String name) {
return "Hello " + name;
}
Q: Map类型的 key 必须使用 String 类型?
- A: 是的。java-chassis 遵循 Open API 规范, MAP 类型的 key 必须使用 String 类型。 业务可以结合实际情况,使用符合规范的类型。 如果必须使用其他类型, 可以考虑接口定义使用 Object 规避,客户端可以对返回值结果自行进行 json 转换。
Q: 参数返回值不能使用接口?
- A: 是的。java-chassis 不允许参数、返回值的类型为
Interface
或者Abstract Class
。因为这些类型 无法生成正确的 swagger 描述。如果必须使用这些类型,可以考虑接口定义使用 Object 规避,客户端可以对返回值结果自行进行 json 转换。
Q: 参数返回值不能使用泛型?
- A: 可以使用泛型。但是必须明确泛型类型。比如:
@PostMapping(path = "holderUser")
public Holder<User> holderUser(@RequestBody Holder<User> input) {
Assert.isInstanceOf(Holder.class, input);
Assert.isInstanceOf(User.class, input.value);
return input;
}
@GetMapping(path = "/genericParams")
@ApiOperation(value = "genericParams", nickname = "genericParams")
public List<List<String>> genericParams(@RequestParam("code") int code, @RequestBody List<List<String>> names) {
return names;
}
未指定泛型类型是不允许的。比如:
@GetMapping(path = "/genericParams")
@ApiOperation(value = "genericParams", nickname = "genericParams")
public List genericParams(@RequestParam("code") int code, @RequestBody List names) {
return names;
}
如果业务必须使用泛型,并且不能确定类型,可以考虑接口定义使用 Object 规避,客户端可以对返回结果自行进行 json 转换。
Q: 实现类中 public 方法全部被发布为接口,如何排除?
- A: java chassis 会将所有 public 方法发布为接口。 如果有些接口不需要发布为接口,可以使用 @Operation 标签声明不发布为接口。例子如下:
@Operation(summary = "", hidden = true)
public void hidden() {
}
更加复杂的情况,比如:
@RpcSchema(schemaId = "MyService")
public MyService extends AbstractMyService implements MyInterface {
}
那么 AbstractMyService
的公共方法也会发布为 RPC 接口。 这种情况可以声明为只发布接口里面的方法, 比如:
@RpcSchema(schemaId = "MyService", schemaInterface = MyInterface.class)
public MyService extends AbstractMyService implements MyInterface {
}
Q: 如何自定义某个Java方法对应的REST接口里的HTTP Status Code?
- A: 参考多个返回值和错误码
Q: 使用HTTP Header参数出现乱码如何处理?
- A: 根据HTTP协议,HTTP Header的值只允许ASCII字符。虽然HTTP协议历史上有些改进,但目前的标准场景,仍然建议只使用ASCII字符,否则会出现乱码。 因此,在使用HTTP Header参数的情况,如果使用了非ASCII字符集,需要在请求前对内容进行编码,在收到响应后,需要对内容进行解码。
// HTTP header只允许 ASCII 字符。
// 在Header参数中使用特殊字符,需要在发送请求前进行编码,在收到响应后进行解码,具体编码方式可以业务自行选择。
// 如果不进行编码,则可能会出现乱码(HTTP协议历史上只标准化了ASCII字符,其他字符集可能工作,可能不工作)。
String encodedResult = controller.sayHei(HttpUtils.encodeURLParam("中文HTTP Header"));
TestMgr.check("hei 中文HTTP Header", HttpUtils.decodeURLParam(encodedResult));
注意:InvocationContext也会使用HTTP Header进行传输,如果包含特殊字符,也需要在设置前编码,使用前解码。
最佳实践:尽可能不在Header参数中使用特殊字符,特殊内容使用Body传输。