Dataway接口配置服务扩展能力说明文档。以下是实例。
CompilerSpiListener 也叫做编译拦截器,DataQL 在真正执行查询之前调用。可以使用这个拦截器来实现数据库方言的配置,这样前台就可以只关注 SQL 了。
// 编译拦截器(统一处理SQL方言)
apiBinder.bindSpiListener(CompilerSpiListener.class, new CompilerSpiListener() {
@Override
public QIL compiler(ApiInfo apiInfo, String query, DataQL dataQl) throws IOException {
if (query.contains(DataBaseType.MySQL.value)) {
query = "hint FRAGMENT_SQL_PAGE_DIALECT = \"mysql\" ;" + query;
} else {
query = "hint FRAGMENT_SQL_PAGE_DIALECT = \"postgresql\" ;" + query;
}
return dataQl.compilerQuery(query);
}
});
FxSqlCheckChainSpi 是 4.2.0 加入的新特性,应用可以通过这个扩展点对于执行 @@sql 时对 SQL 进行检查和改写。可以用来查看执行的 SQL 或统一修改某些规则。
// 如果存在后续 那么继续执行检查,否则使用 EXIT 常量控制退出后续的检查。
apiBinder.bindSpiListener(FxSqlCheckChainSpi.class, infoObject -> {
System.out.println(String.format("[%s] %s", infoObject.getSourceName(), infoObject.getQueryString().trim()));
// 可以用来查看执行的 SQL 或统一修改某些规则。
return FxSqlCheckChainSpi.NEXT;
});
一个已经发布的接口被调用之后,一定会触发这个拦截器。而 ResultProcessChainSpi 拦截器的处理有两个方法,分别应对了两个不同的情况:
// 返回结果封装
apiBinder.bindSpiListener(ResultProcessChainSpi.class, new ResultProcessChainSpi() {
@Override
public Object callAfter(boolean formPre, ApiInfo apiInfo, Object result) {
return BaseResult.getInstance(result);
}
});
// 所有返回的结果,都把 API 的 Method 和 path 返回
apiBinder.bindSpiListener(ResultProcessChainSpi.class, new ResultProcessChainSpi() {
@Override
public Object callError(boolean formPre, ApiInfo apiInfo, Throwable e) {
return new HashMap<String, Object>() {{
put("method", apiInfo.getMethod());
put("path", apiInfo.getApiPath());
put("errorMessage", e.);
}};
}
});
实现调用缓存
public class ApiCacheSpi implements PreExecuteChainSpi, ResultProcessChainSpi {
private Map<String,Object> cacheMap = ... // for example
public void preExecute(ApiInfo apiInfo, BasicFuture<Object> future) {
String cacheKey = ...
if (this.cacheMap.containsKey(cacheKey)) {
Object cacheValue = cacheMap.get(cacheKey);
future.completed(cacheValue);
return;
}
}
public Object callAfter(boolean formPre, ApiInfo apiInfo, Object result) {
// formPre 为 true,表示 preExecute 已经处理过。
// apiInfo.isPerform() 为 true 表示,API 调用是从 UI 界面发起的。
if (formPre || apiInfo.isPerform()) {
return result;
}
//
String cacheKey = ...
this.cacheMap.put(cacheKey, result);
return result;
}
}
SerializationChainSpi 是 4.1.7 加入的新特性,这个接口允许开发者自定义 Dataway 结果的序列化逻辑。它的使用场景如下:
// 不输出为空数据
apiBinder.bindSpiListener(SerializationChainSpi.class, (apiInfo, mimeType, result) ->
JSON.toJSONString(result));
// 二进制序列化
apiBinder.bindSpiListener(SerializationChainSpi.class, (apiInfo, mimeType, result) -> {
BufferedImage bi = new BufferedImage(150, 70, BufferedImage.TYPE_INT_RGB); //高度70,宽度150
Graphics2D g2 = (Graphics2D) bi.getGraphics();
// background color
g2.fillRect(0, 0, 150, 70);
g2.setColor(Color.WHITE);
// text
g2.setFont(new Font("宋体", Font.BOLD, 18));
g2.setColor(Color.BLACK);
g2.drawString(String.valueOf(result), 3, 50);
// save to bytes
ByteArrayOutputStream oat = new ByteArrayOutputStream();
try {
ImageIO.write(bi, "JPEG", oat);
} catch (IOException e) {
e.printStackTrace();
}
// response
return SerializationChainSpi.SerializationInfo.ofBytes(//
mimeType.getMimeType("jpeg"), // response context-type
oat.toByteArray() // response body
);
});