目录
业务说明:生成大疆航线kmz文件,kmz是一种压缩文件格式,大疆的航线文件点进去之后是一个【wpmz】文件夹,文件夹中有2个文件【template.kml】和【waylines.wpml】,内容均为xml格式。
一、生成xml文件
这里介绍2种方法,一种是利用hutool的xml工具将实体对象转成xml字符串后直接导出,另一种是使用dom4j生成xml文件
1. 方法一:hutool的xml工具
1.1 引入hutool依赖
<dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.8.11</version> </dependency>
1.2 构建实体类
实体类的属性名称跟xml对应的标签名保持一致(本人业务中的标签名中含有“:”冒号,而Java变量命名不允许用冒号,所以用“_”替代,最后在生成的xml字符串中统一替换);xml中的一个子标签即代表实体对象的一个对象属性。
注:若xml文件结构比较复杂,实体类的结构也将比较复杂
下面贴出我的实体类部分代码
public class TemplateDocument {
// 文件创建作者-非必填
private String wpml_author;
// 文件创建时间(Unix Timestamp)-非必填
private String wpml_createTime;
// 文件更新时间(Unix Timestamp)-非必填
private String wpml_updateTime;
// 任务信息
private MissionConfig wpml_missionConfig;
// 航点信息文件夹
private Folder Folder;
@Data
@Builder
public static class MissionConfig {
// 飞向首航点模式(safely:安全模式,pointToPoint:倾斜飞行模式)
private String wpml_flyToWaylineMode;
// 航线结束动作(goHome,noAction,autoLand,gotoFirstWaypoint)
private String wpml_finishAction;
// 失控是否继续执行航线(goContinue,executeLostAction)
private String wpml_exitOnRCLost;
// 失控动作类型(goBack:返航,landing:降落,hover:悬停)
private String wpml_executeRCLostAction;
// 安全起飞高度([1.5, 1500] m)
private String wpml_takeOffSecurityHeight;
// 参考起飞点-非必填
private String wpml_takeOffRefPoint;
// 参考起飞点海拔高度-非必填
private String wpml_takeOffRefPointAGLHeight;
// 全局航线过渡速度([1,15]m/s)
private String wpml_globalTransitionalSpeed;
private String wpml_globalRTHHeight;
// 飞行器机型信息
private DroneInfo wpml_droneInfo;
// 负载机型信息
private PayloadInfo wpml_payloadInfo;
@Data
@AllArgsConstructor
public static class DroneInfo {
/**
* 飞行器机型主类型
* 89(机型:M350 RTK),
* 60(机型:M300 RTK),
* 67(机型:M30/M30T),
* 77(机型:M3E/M3T/M3M)
*/
private String wpml_droneEnumValue;
/**
* 飞行器机型子类型
* 当“飞行器机型主类型”为“67(机型:M30/M30T)”时:
* 0(机型:M30双光),
* 1(机型:M30T三光)
* 当“飞行器机型主类型“为”77(机型:M3E/M3T/M3M)“时:
* 0(机型:M3E)
* 1(机型:M3T)
* 2(机型:M3M)
*/
private String wpml_droneSubEnumValue;
}
@Data
@AllArgsConstructor
public static class PayloadInfo {
/**
* 负载机型主类型
* 42(H20),
* 43(H20T),
* 50(P1),
* 52(M30双光相机),
* 53(M30T三光相机),
* 61(H20N),
* 90742(L1)
* 66(Mavic 3E 相机)
* 67(Mavic 3T 相机)
* 68(Mavic 3M 相机)
* 65534(PSDK 负载)
*/
private String wpml_payloadEnumValue;
/**
* 负载机型子类型
* ZENMUSE_P1:
* 0(LENS_24mm),
* 1(LENS_35mm),
* 2(LENS_50mm)
*/
private String wpml_payloadSubEnumValue;
/**
* 负载挂载位置
* 0:飞行器1号挂载位置。M300 RTK,M350 RTK机型,对应机身左前方。其它机型,对应主云台。
* 1:飞行器2号挂载位置。M300 RTK,M350 RTK机型,对应机身右前方。
* 2:飞行器3号挂载位置。M300 RTK,M350 RTK机型,对应机身上方
*/
private String wpml_payloadPositionIndex;
}
}
}
1.3 生成xml字符串
使用hutool的XML.toXml()即可生成xml字符串
// xml的开始和结束部分的标签内容不好生成,故这里直接写死获取并进行拼接
String xmlHead = KmzDocument.getXmlHead();
String xmlTail = KmzDocument.getXmlTail();
// 将实体对象转换为hutool的JSONObject对象
JSONObject jsonObject = JSONUtil.parseObj(templateDocument);
// 将对象转成xml字符串
String toXml = XML.toXml(jsonObject);
// 将字符串中的 _ 替换为 :
String xml = toXml.replaceAll("wpml_", "wpml:");
// 拼接出所有的xml内容
String templateXml = xmlHead + xml + xmlTail;
1.4 导出结果如下
<?xml version="1.0" encoding="UTF-8"?><kml xmlns="http://www.opengis.net/kml/2.2" xmlns:wpml="http://www.dji.com/wpmz/1.0.3"><Document><wpml:author>jack</wpml:author><wpml:createTime>1684810374696</wpml:createTime><wpml:updateTime>1684811716307</wpml:updateTime><wpml:missionConfig><wpml:flyToWaylineMode>safely</wpml:flyToWaylineMode><wpml:finishAction>goHome</wpml:finishAction><wpml:exitOnRCLost>executeLostAction</wpml:exitOnRCLost><wpml:executeRCLostAction>goBack</wpml:executeRCLostAction><wpml:takeOffSecurityHeight>70</wpml:takeOffSecurityHeight><wpml:takeOffRefPoint>31.830240,117.126300,42.700000</wpml:takeOffRefPoint><wpml:takeOffRefPointAGLHeight>11</wpml:takeOffRefPointAGLHeight><wpml:globalTransitionalSpeed>15</wpml:globalTransitionalSpeed><wpml:globalRTHHeight>100</wpml:globalRTHHeight><wpml:droneInfo><wpml:droneEnumValue>67</wpml:droneEnumValue><wpml:droneSubEnumValue>1</wpml:droneSubEnumValue></wpml:droneInfo><wpml:payloadInfo><wpml:payloadEnumValue>53</wpml:payloadEnumValue><wpml:payloadSubEnumValue>0</wpml:payloadSubEnumValue><wpml:payloadPositionIndex>0</wpml:payloadPositionIndex></wpml:payloadInfo></wpml:missionConfig></Document></kml>
优点:方便,将实体类设计好,就可以直接生成了
缺点:1、生成的结果如上结果所示,是一行长字符串(用浏览器打开是分结构展示的)
2、xml的内容含有较多标签属性时,该方法就不好用了
2. dom4j生成xml文件
2.1 引入dom4j依赖
<dependency> <groupId>org.dom4j</groupId> <artifactId>dom4j</artifactId> <version>2.1.3</version> </dependency>
2.2 生成xml文件
// 获取源数据(沿用上文的实体对象)
TemplateDocument templateDocument = getTemplateDocument();
// 创建dom对象
Document document = DocumentHelper.createDocument();
// 添加节点,同时可以添加命名空间和属性信息
Element kml = document.addElement("kml", "http://www.opengis.net/kml/2.2")
.addNamespace("wpml", "http://www.dji.com/wpmz/1.0.3");
Element doc = kml.addElement("Document");
doc.addElement("wpml:author").addText(templateDocument.getWpml_author());
doc.addElement("wpml:createTime").addText(templateDocument.getWpml_createTime());
doc.addElement("wpml:updateTime").addText(templateDocument.getWpml_updateTime());
Element missionCon = doc.addElement("wpml:missionConfig");
missionCon.addElement("wpml:flyToWaylineMode").addText(templateDocument.getWpml_missionConfig().getWpml_flyToWaylineMode());
missionCon.addElement("wpml:finishAction").addText(templateDocument.getWpml_missionConfig().getWpml_finishAction());
Element mc_droneInfo = missionCon.addElement("wpml:droneInfo");
mc_droneInfo.addElement("wpml:droneEnumValue").addText(templateDocument.getWpml_missionConfig().getWpml_droneInfo().getWpml_droneEnumValue());
mc_droneInfo.addElement("wpml:droneSubEnumValue").addText(templateDocument.getWpml_missionConfig().getWpml_droneInfo().getWpml_droneSubEnumValue());
doc.addElement("Folder");
// 格式化模版
OutputFormat format = OutputFormat.createPrettyPrint();
format.setEncoding("UTF-8");
// 生成xml文件
ByteArrayOutputStream out = new ByteArrayOutputStream();
XMLWriter writer = new XMLWriter(out, format);
writer.write(document);
writer.close();
// 导出文件
String fileName = "C:\\Users\\admin\\Desktop\\dom.xml";
FileOutputStream fos = new FileOutputStream(fileName);
fos.write(out.toByteArray());
fos.close();
2.3 导出结果如下
<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://www.opengis.net/kml/2.2" xmlns:wpml="http://www.dji.com/wpmz/1.0.3">
<Document>
<wpml:author>jack</wpml:author>
<wpml:createTime>1684810374696</wpml:createTime>
<wpml:updateTime>1684811716307</wpml:updateTime>
<wpml:missionConfig>
<wpml:flyToWaylineMode>safely</wpml:flyToWaylineMode>
<wpml:finishAction>goHome</wpml:finishAction>
<wpml:droneInfo>
<wpml:droneEnumValue>67</wpml:droneEnumValue>
<wpml:droneSubEnumValue>1</wpml:droneSubEnumValue>
</wpml:droneInfo>
</wpml:missionConfig>
<Folder/>
</Document>
</kml>
优点:1、可以通过设置模版使导出的内容结构化展示
2、可以自由的设置节点及命名空间和属性
缺点:xml的结构复杂或者内容较多时,代码量是巨大的
二、web下载zip压缩文件
结合上面生成xml文件的方法一来说明
思路:导出的 OutputStream 从【HttpServletResponse】中取得,再使用【ZipOutputStream】依次输出文件。
代码如下:
方法代码
public AjaxResult exportKmzFile(HttpServletResponse response, KmzDocument document) {
// 转换xml内容
String xmlHead = KmzDocument.getXmlHead();
String xmlTail = KmzDocument.getXmlTail();
String templateXml = xmlHead + XML.toXml(JSONUtil.parseObj(document.getTemplateDocument())).replaceAll("wpml_", "wpml:") + xmlTail;
String waylinesXml = xmlHead + XML.toXml(JSONUtil.parseObj(document.getWaylinesDocument())).replaceAll("wpml_", "wpml:") + xmlTail;
// 导出kmz文件
String fileName = document.getKmzName() + ".kmz";
response.setContentType("application/octet-stream");
response.setCharacterEncoding("utf-8");
// new String()中的操作是为了消除中文乱码
response.setHeader("content-disposition", "attachment;filename=" + new String(fileName.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1));
try (ServletOutputStream outputStream = response.getOutputStream();
CheckedOutputStream checkedOS = new CheckedOutputStream(outputStream, new CRC32());
ZipOutputStream zipOS = new ZipOutputStream(checkedOS, StandardCharsets.UTF_8)) {
// wpmz 为上层文件夹 / 为间隔符号
ZipEntry kmlEntry = new ZipEntry("wpmz" + "/" + "template.kml");
zipOS.putNextEntry(kmlEntry);
zipOS.write(templateXml.getBytes(StandardCharsets.UTF_8));
ZipEntry wpmlEntry = new ZipEntry("wpmz" + "/" + "waylines.wpml");
zipOS.putNextEntry(wpmlEntry);
zipOS.write(waylinesXml.getBytes(StandardCharsets.UTF_8));
} catch (Exception e) {
log.error("导出kmz文件失败!", e);
return AjaxResult.error("文件下载失败!");
}
return AjaxResult.success();
}
controller代码
@PostMapping("/exportKmzFile")
@ApiOperation(value = "生成kmz文件")
public void exportKmzFile(HttpServletResponse response, @RequestBody KmzDocument document) {
// 文件名不可为空
if (ObjectUtil.isEmpty(document.getKmzName())) {
return;
}
droneWaylineInfoService.exportKmzFile(response, document);
}
导出结果如下(kmz是压缩文件的一种格式):
参考文档:
JAVA生成Zip文件并导出_java导出zip文件_message丶小和尚的博客-CSDN博客
使用Java压缩文件生成各种zip包总结(整理为工具类版)_java文件压缩成zip_mmm.c的博客-CSDN博客
response.setContentType()的作用及参数_爱吃小猫的大鱼@的博客-CSDN博客
JavaWeb实现文件下载功能_javaweb下载_Brisk Walking的博客-CSDN博客