- sample代码架构
- sample代码实现
- Pilot2中航线管理功能
- 机场中航线管理功能
- 开发注意事项
4.4.1 sample代码架构
航线管理功能在Pilot2和机场中是两种不同的实现:
- Pilot2中的航线管理功能是指:在Pilot2中可以将航线文件(kmz文件)可以上传到云端,可以从云端下载到Pilot2本地。
- 机场中的航线管理功能是指云端可以下发航线任务给机场,机场根据下发的指令执行航线任务。
对应的Pilot2中的实现是以http协议进行实现,机场中是以mqtt协议进行实现。
4.4.2 sample代码实现
Pilot2中航线管理功能
1. Pilot2加载api模块,加载mission模块;Pilot2中通过webview界面登录开发者开发的H5页面后,需要通过JSbridge技术,加载对应的模块才能使用Pilot2提供的功能,需要使用Pilot2的航线管理功能,需要加载api模块以及mission模块。
2. 在Pilot2中点击航线--云端航线,Pilot2内部会触发GET /wayline/api/v1/workspaces/{workspace_id}/waylines 请求云端获取航线列表。对应后端sdk中需要实现的方法为:
@GetMapping(PREFIX + "/workspaces/{workspace_id}/waylines")
HttpResultResponse<PaginationData<GetWaylineListResponse>> getWaylineList(
@Valid @ParameterObject GetWaylineListRequest request,
@PathVariable(name = "workspace_id") String workspaceId,
HttpServletRequest req, HttpServletResponse rsp);
在示例代码中,该方法的实现为:WaylineFileController#getWaylineList
@Override
public HttpResultResponse<PaginationData<GetWaylineListResponse>> getWaylineList(@Valid GetWaylineListRequest request, String workspaceId, HttpServletRequest req, HttpServletResponse rsp) {
PaginationData<GetWaylineListResponse> data = waylineFileService.getWaylinesByParam(workspaceId, request);
return HttpResultResponse.success(data);
}
WaylineFileController#getWaylineList方法中通过调用waylineFileService#getWaylinesByParam获取航线文件列表,获取后返回给Pilot2。waylineFileService#getWaylinesByParam实现逻辑如下:
@Override
public PaginationData<GetWaylineListResponse> getWaylinesByParam(String workspaceId, GetWaylineListRequest param) {
// 分页查询,如果数据太多可以分页返回给Pilot2,如果一次没有返回全部数据,Pilot2会分多次请求
// 查询当前空间下的航线文件,如果用户筛选了条件,会将条件进行拼接。
Page<WaylineFileEntity> page = mapper.selectPage(
new Page<WaylineFileEntity>(param.getPage(), param.getPageSize()),
new LambdaQueryWrapper<WaylineFileEntity>()
.eq(WaylineFileEntity::getWorkspaceId, workspaceId)
.eq(Objects.nonNull(param.getFavorited()), WaylineFileEntity::getFavorited, param.getFavorited())
.and(param.getTemplateType() != null, wrapper -> {
for (WaylineTypeEnum type : param.getTemplateType()) {
wrapper.like(WaylineFileEntity::getTemplateTypes, type.getValue()).or();
}
})
// 这里可能会有SQL注入的风险
.last(StringUtils.hasText(param.getOrderBy()), " order by " + param.getOrderBy()));
// 将查询的实体转换为DTO后再返回
List<GetWaylineListResponse> records = page.getRecords()
.stream()
.map(this::entityConvertToDTO)
.collect(Collectors.toList());
return new PaginationData<>(records, new Pagination(page));
}
Pilot2获取到后端返回的结果后,会将航线文件列表展示在Pilot2的界面上。
3. 用户在Pilot2上点击下载航线文件,Pilot2会根据后端结果返回的id请求后端获取航线文件下载地址,GET /wayline/api/v1/workspaces/{workspace_id}/waylines/{id}/url。对应sdk示例代码中需要实现的方法为:
@GetMapping(PREFIX + "/workspaces/{workspace_id}/waylines/{wayline_id}/url")
void getWaylineFileDownloadAddress(
@PathVariable(name = "workspace_id") String workspaceId,
@PathVariable(name = "wayline_id") String waylineId,
HttpServletRequest req, HttpServletResponse rsp);
示例代码中的默认实现为:WaylineFileController#getWaylineFileDownloadAddress
@Override
public void getWaylineFileDownloadAddress(String workspaceId, String waylineId, HttpServletRequest req, HttpServletResponse rsp) {
try {
URL url = waylineFileService.getObjectUrl(workspaceId, waylineId);
rsp.sendRedirect(url.toString());
} catch (IOException | SQLException e) {
e.printStackTrace();
}
}
该方法中通过调用waylineFileService#getObjectUrl获取航线文件下载的url。waylineFileService#getObjectUrl实现如下:该方法首先判断当前工作空间下是否存在该航线文件,不存在直接报错;存在,则调用对应的oss服务获取下载的url地址。
@Override
public URL getObjectUrl(String workspaceId, String waylineId) throws SQLException {
// 判断当前工作空间下是否存在该航线文件
Optional<GetWaylineListResponse> waylineOpt = this.getWaylineByWaylineId(workspaceId, waylineId);
if (waylineOpt.isEmpty()) {
// 不存在直接报错
throw new SQLException(waylineId + " does not exist.");
}
// 存在,则调用对应的oss服务获取下载的url地址
return ossService.getObjectUrl(OssConfiguration.bucket, waylineOpt.get().getObjectKey());
}
4. 用户在Pilot2中点击上传航线文件,Pilot2内部会判断临时上传凭证信息是否过期,如果临时上传凭证信息已过期,则会请求后端获取新的上传临时凭证信息;如果临时上传凭证未过期,则Pilot2会直接使用临时凭证将航线文件上传到对象存储服务器。
5. Pilot2内部上传航线文件(kmz文件)到对象存储服务器后,会调用POST /wayline/api/v1/workspaces/{workspace_id}/upload-callback 上报航线文件上传结果,对应sdk包中需要实现的方法如下:
@PostMapping(PREFIX + "/workspaces/{workspace_id}/upload-callback")
HttpResultResponse fileUploadResultReport(
@PathVariable(name = "workspace_id") String workspaceId,
@Valid @RequestBody WaylineUploadCallbackRequest request,
HttpServletRequest req, HttpServletResponse rsp);
在示例代码中的实现为WaylineFileController#fileUploadResultReport,实现代码如下:
@Override
public HttpResultResponse fileUploadResultReport(String workspaceId, @Valid WaylineUploadCallbackRequest request, HttpServletRequest req, HttpServletResponse rsp) {
// 获取当前登录用户
CustomClaim customClaim = (CustomClaim)req.getAttribute(TOKEN_CLAIM);
// 获取上传媒体文件结果的上传数据,包含飞机产品枚举值、负载产品枚举值、文件在对象存储桶的key等信息
WaylineUploadCallbackMetadata metadata = request.getMetadata();
// 构造传输给service的DTO对象
WaylineFileDTO file = WaylineFileDTO.builder()
.username(customClaim.getUsername())
.objectKey(request.getObjectKey())
.name(request.getName())
.templateTypes(metadata.getTemplateTypes().stream().map(WaylineTypeEnum::getValue).collect(Collectors.toList()))
.payloadModelKeys(metadata.getPayloadModelKeys().stream().map(DeviceEnum::getDevice).collect(Collectors.toList()))
.droneModelKey(metadata.getDroneModelKey().getDevice())
.build();
// 调用waylineFileService#saveWaylineFile方法保存航线文件上传结果
int id = waylineFileService.saveWaylineFile(workspaceId, file);
// 返回给Pilot2本次保存的结果
return id <= 0 ? HttpResultResponse.error() : HttpResultResponse.success();
}
6. 收藏航线文件:在Pilot2界面上,用户可以选中一个航线文件,将航线文件进行收藏,并可以快速筛选收藏过的航线文件。用户点击航线收藏后,Pilot2会调用后端接口POST /wayline/api/v1/workspaces/{workspace_id}/favorites,对应sdk包中需要实现的接口为:
@PostMapping(PREFIX + "/workspaces/{workspace_id}/favorites")
HttpResultResponse batchFavoritesWayline(
@PathVariable(name = "workspace_id") String workspaceId,
@NotNull @Size(min = 1) @RequestParam(name = "id") List<String> ids,
HttpServletRequest req, HttpServletResponse rsp);
对应示例代码中的实现为:WaylineFileController#batchFavoritesWayline
@Override
public HttpResultResponse batchFavoritesWayline(String workspaceId, @NotNull @Size(min = 1) List<String> ids, HttpServletRequest req, HttpServletResponse rsp) {
// 调用waylineFileService#markFavorite方法,将当前工作空间下收藏的航线文件保存到数据库
boolean isMark = waylineFileService.markFavorite(workspaceId, ids, true);
return isMark ? HttpResultResponse.success() : HttpResultResponse.error();
}
7.取消收藏航线文件:在Pilot2界面上,用户可以选中收藏的航线文件,移除收藏的航线文件。Pilot2中用户移除Pilot2会调用后端接口DELETE /wayline/api/v1/workspaces/{workspace_id}/favorites,对应sdk包中需要实现的接口为:
@DeleteMapping(PREFIX + "/workspaces/{workspace_id}/favorites")
HttpResultResponse batchUnfavoritesWayline(
@PathVariable(name = "workspace_id") String workspaceId,
@NotNull @Size(min = 1) @RequestParam(name = "id") List<String> ids,
HttpServletRequest req, HttpServletResponse rsp);
对应示例代码中的实现为:WaylineFileController#batchUnfavoritesWayline
@Override
public HttpResultResponse batchUnfavoritesWayline(String workspaceId, @NotNull @Size(min = 1) List<String> ids, HttpServletRequest req, HttpServletResponse rsp) {
// 调用waylineFileService#markFavorite方法,将当前工作空间下收藏的航线文件关系从数据库移除
boolean isMark = waylineFileService.markFavorite(workspaceId, ids, false);
return isMark ? HttpResultResponse.success() : HttpResultResponse.error();
}
机场中航线管理功能
云端下发航线任务给机场,前端在页面选择需要下发给机场的任务参数(定时任务、立即任务、对应的航线文件、机场)后,通过POST ${url.wayline.prefix}${url.wayline.version}/workspaces/
@PostMapping("/{workspace_id}/flight-tasks")
public HttpResultResponse createJob(HttpServletRequest request, @Valid @RequestBody CreateJobParam param,
@PathVariable(name = "workspace_id") String workspaceId) throws SQLException {
// 获取当前登录用户信息,数据库会记录本次航线任务的发起人信息
CustomClaim customClaim = (CustomClaim)request.getAttribute(TOKEN_CLAIM);
customClaim.setWorkspaceId(workspaceId);
// 调用flighttaskService#publishFlightTask方法下发航线任务给机场
return flighttaskService.publishFlightTask(param, customClaim);
}
调用flighttaskService#publishFlightTask方法下发航线任务给机场,对应的实现代码如下:
@Override
public HttpResultResponse publishFlightTask(CreateJobParam param, CustomClaim customClaim) throws SQLException {
// 填充立即任务的执行时间
fillImmediateTime(param);
for (Long taskDay : param.getTaskDays()) {
LocalDate date = LocalDate.ofInstant(Instant.ofEpochSecond(taskDay), ZoneId.systemDefault());
for (List<Long> taskPeriod : param.getTaskPeriods()) {
long beginTime = LocalDateTime.of(date, LocalTime.ofInstant(Instant.ofEpochSecond(taskPeriod.get(0)), ZoneId.systemDefault()))
.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
long endTime = taskPeriod.size() > 1 ?
LocalDateTime.of(date, LocalTime.ofInstant(Instant.ofEpochSecond(taskPeriod.get(1)), ZoneId.systemDefault()))
.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli() : beginTime;
// 如果航线任务不是立即执行任务,并且已经超过任务可执行时段的结束时间,则跳过本次任务
if (TaskTypeEnum.IMMEDIATE != param.getTaskType() && endTime < System.currentTimeMillis()) {
continue;
}
// 数据库记录本次航线任务
Optional<WaylineJobDTO> waylineJobOpt = waylineJobService.createWaylineJob(param, customClaim.getWorkspaceId(), customClaim.getUsername(), beginTime, endTime);
if (waylineJobOpt.isEmpty()) {
throw new SQLException("Failed to create wayline job.");
}
WaylineJobDTO waylineJob = waylineJobOpt.get();
// 如果是条件任务,那么在Redis中保存该任务执行条件
addConditions(waylineJob, param, beginTime, endTime);
// 调用本类方法发布航线任务,在此方法中,云端会发送消息给机场
HttpResultResponse response = this.publishOneFlightTask(waylineJob);
if (HttpResultResponse.CODE_SUCCESS != response.getCode()) {
return response;
}
}
}
return HttpResultResponse.success();
}
评论
0 条评论
请登录写评论。