酷大师插件后端开发指南
- ApiResult
- GeneralModelInfo & GeneralModelData & ResourceTypeEnum
- ExampleController
- ExampleService
- ExampleServiceImpl
如果您认为您的插件需要一个后端服务来实现一些业务逻辑,则可以使用任何后端技术栈来开发这个服务。
酷大师插件后端可以两种方式和酷大师后端交互:
- 酷大师插件后端调用酷大师后端Restful API,获取酷大师方案的3d模型数据
- 酷大师插件后端提供一些WebHook API,供酷大师后端在特定时刻调用
用第一种交互方式,可以实现对酷大师方案中3d模型的后处理。例如:
- 获取酷大师方案中的3d模型,渲染一张高清效果图。
- 获取酷大师方案中的3d模型,进行网格剖分,做力学仿真分析
- 获取酷大师方案中的3d模型,将它3d打印出来
这种交互方式比较简单,主要是理解酷大师后端 REST API 返回的数据格式即可。
用第二种交互方式,可以实现将插件后端定义的3d模型,插入到酷大师方案中。例如酷大师官方内置的“智能模型”,“智能灯箱”等插件,都是将一些插件定义的3d参数化模型,插入到了酷大师方案中。
这种交互方式略微复杂一些,下面用一些Java语言代码来示例说明
ApiResult
定义Web API的返回值类型
ApiResult
public class ApiResult<T> {
private T resData;
private boolean success;
private int code;
private String msg;
public static <T> ApiResult<T> pack(final T resultData) {
final ApiResult<T> result = new ApiResult<>();
result.success = true;
result.resData = resultData;
// 0 表示成功
result.setCode(0);
return result;
}
}
GeneralModelInfo & GeneralModelData & ResourceTypeEnum
GeneralModelInfo & GeneralModelData
@Getter
@Setter
public class GeneralModelInfo {
/**
* 返回状态码
*/
@JsonProperty("c")
private int code;
/**
* 返回信息体
*/
@JsonProperty("m")
private String msg;
/**
* 外部模型具体数据
*/
@JsonProperty("d")
private GeneralModelData data;
}
@Getter
@Setter
public class GeneralModelData<T> {
/**
* @see ResultTypeEnum,这里填ResultTypeEnum.getDesc()
*/
@JsonProperty("t")
private String type;
/**
* resource与上面的type相对应。
* 如果type是dmxdesigndata,resource则应该是DMxDesignData对象
* 如果type是renderinfo,resource则应该是mesh包的List<ModelWithMatrix> 、List<DisplayComponent>等类
* @return
*/
@JsonProperty("r")
private T resource;
}
@Getter
public enum ResourceTypeEnum {
RENDER_INFO(0, "renderinfo"),
DMX_DESIGN_DATA(1, "dmxdesigndata");
private Integer code;
private String desc;
ResourceTypeEnum(final Integer code, final String desc) {
this.code = code;
this.desc = desc;
}
}
ExampleController
定义Web API
ExampleController
@RestController
public class ExampleController {
private static final String MODEL_USAGE_HEADER = "x-qh-model-usage";
// 以下webhook url可以自定义,与各自的执行函数相对应
private static final String URL_GET = "/myplugin/model";
private static final String URL_COPY = "/myplugin/modelindex/copy";
private static final String URL_DELETE = "/myplugin/modelindex";
// 这个url创建无需注册,但是需要提供给iPaas插件iFrame
private static final String URL_MODELINDEX_CREATE = "/myplugin/modelindex/create";
@Autowired
private ExampleService exampleService;
// GetMapping 代表Get请求,后面的url与注册的获取模型的webhook url相对应
//MODEL_USAGE_HEADER = x-qh-model-usage,从header 中获取,用于定义获取 “精模--0” 还是“粗模--1”(分别用于后端渲染和前端显示)
@GetMapping(URL_GET)
public ApiResult<GeneralModelInfo> getModel(
@RequestParam("modelIndex")
@NotEmpty(message = "modelIndex can not be empty") final String modelIndex,
final HttpServletRequest request) {
final ModelUsageEnum modelUsage = ModelUsageEnum.getByCodeStr(request.getHeader(MODEL_USAGE_HEADER));
return ApiResult.pack(exampleService.buildModel(modelIndex,modelUsage));
}
// PostMapping 代表Post请求,后面的url与注册的复制模型的webhook url相对应
// 插件方的复制逻辑可以不做具体实现,但至少要提供一个copy接口签名
@PostMapping(URL_COPY)
public ApiResult<String> copyModelIndex(
@RequestParam("modelIndex")
@NotEmpty(message = "modelIndex can not be empty") final String modelIndex) {
return ApiResult.pack(exampleService.copyModel(modelIndex));
}
// DeleteMapping 代表Delete请求,后面的url与注册的删除模型的webhook url相对应
// 插件方的删除逻辑可以不做具体实现,但至少要提供一个delete接口签名
@DeleteMapping(URL_DELETE)
public ApiResult<String> deleteModelIndex(
@RequestParam("modelIndex")
@NotEmpty(message = "modelIndex can not be empty") final String modelIndex) {
return ApiResult.pack(exampleService.deleteModel(modelIndex));
}
// param 代表iFrame传过来的参数,按照这套参数,返回一个索引(modelIndex)与之对应。
// 后续建模,酷大师就根据这个索引来查询模型数据
@PostMapping(URL_MODELINDEX_CREATE)
public ApiResult<String> createModelIndex(@RequestBody final T param, final String modelIndex) {
return ApiResult.pack(exampleService.createModelIndex(param));
}
}
ExampleService
实现获取、拷贝、删除模型的业务逻辑
ExampleService
public interface ExampleService {
/**
* 通过modelIndex获取模型
* @param modelIndex
* @param modelUsage
* @return
*/
GeneralModelInfo buildModel(final String modelIndex,final ModelUsageEnum modelUsage);
/**
* 拷贝modelIndex
* @param modelIndex
* @return
*/
String copyModelIndex(final String modelIndex);
/**
* 删除modelIndex
* @param modelIndex
* @return
*/
String deleteModelIndex(final String modelIndex);
/**
* 创建modelIndex
* @param param
* @return
*/
String createModelIndex(final T param);
}
ExampleServiceImpl
ExampleServiceImpl
@Component
public class ExampleServiceImpl implements ExampleService {
@Override
// buildModel的核心逻辑是根据modelIndex构建模型,并转化为酷大师需要的数据格式
public GeneralModelInfo buildModel(final String modelIndex,final ModelUsageEnum modelUsage) {
// todo
// 根据modelIndex 构建自己的模型
// MyPluginModel 类是用户自己定义的类
MyPluginModel myPluginModel = buildModel(modelIndex);
// 由于酷大师后端目前只支持dmxdesigndata和displayinfo两种类型,因此插件后端需要实现将自己的模型转换为这两种类型
GeneralModelInfo result = new GeneralModelInfo();
if(RENDER_INFO.equeals(modelUsage){
DMxDesignData designData = convert2DesignData(myPluginModel);
result.setData(designData);
}else{
RenderInfo = convert2RenderInfo(myPluginModel);
result.setData(designData);
}
return result;
}
/**
* 如果不提供复制操作,可以不做业务逻辑的编写,返回null即可;如果需要实现,建议复制一份modelIndex即可,不需要复制modelIndex所指向的数据本身,以免影响其他同样使用了该数据的方案
* @param modelIndex
* @return
*/
@Override
public String copyModelIndex(final String modelIndex) {
final String copiedModelIndesx = copyModel(modelIndex);
return copiedModelIndesx;
}
/**
* 如果不提供删除操作,可以不做业务逻辑的编写,返回null即可;如果需要实现,建议删除该modelIndex即可,不需要删除modelIndex所指向的数据本身,以免影响其他同样使用了该数据的方案
* @param modelIndex
* @return
*/
@Override
public String deleteModelIndex(final String modelIndex) {
// todo
return null;
}
private PluginModel buildModel(final String modelIndex) {
// todo
return null;
}
private DMxDesignData convert2DesignData(final PluginModel pluginModel) {
// todo
return null;
}
}
最后,插件后端定义好的 Web Hook API, 需要用酷大师插件开发教程提及的 WebHook 注册页面工具,或 WebHook API 提及的 WebHook 注册 REST API,注册到酷大师后端