Skip to main content

酷大师插件后端开发指南

如果您认为您的插件需要一个后端服务来实现一些业务逻辑,则可以使用任何后端技术栈来开发这个服务。

酷大师插件后端可以两种方式和酷大师后端交互:

  1. 酷大师插件后端调用酷大师后端Restful API,获取酷大师方案的3d模型数据
  2. 酷大师插件后端提供一些WebHook API,供酷大师后端在特定时刻调用

用第一种交互方式,可以实现对酷大师方案中3d模型的后处理。例如:

  1. 获取酷大师方案中的3d模型,渲染一张高清效果图。
  2. 获取酷大师方案中的3d模型,进行网格剖分,做力学仿真分析
  3. 获取酷大师方案中的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,注册到酷大师后端