当前位置: 首页 > news >正文

【Digester解析XML文件的三种方式】

Digester解析XML文件的三种方式

    • 1. Digester解析XML文件的三种方式
      • 1.1 作用及依赖jar包
    • 2. 重点和难点
    • 3. XML文件
    • 4. 通过不同的方式解析这个xml文件
      • 4.1 通过java编码方式解析(javabean存储)
      • 4.2 通过java编码方式解析(list和map存储)
      • 4.3 通过xml配置方式解析
        • 4.3.1 OrderConfigRule.xml 配置文件
        • 4.3.2 Java解析
    • 5.总结

1. Digester解析XML文件的三种方式

1.1 作用及依赖jar包

首先明白Digester是干什么的?它是apache开源项目Commons中的一个子项目,用于解析XML文档的工具。Digester底层采用的是SAX解析方式,通过遍历XML文档规则来进行处理。项目中有需要将XML文件中的信息解析为我们需要的内容时(如java类),使用Digester是非常方便的。话不多说,本案例使用的jdk版本是1.6。简单的jar包依赖如下:

  • commons-digester-1.8.jar
  • commons-logging.jar
  • commons-collections-3.2.1.jar
  • commons-beanutils-1.7.0.jar

2. 重点和难点

  • 重点:理解栈的概念
  • 难点:当使用addObjectCreate()方法时,会创建一个对象进栈,许多重要的方法都是相对于栈顶元素或次栈顶元素来进行的。如:
  1. addCallMethod(pattern, methodName):调用栈顶元素的指定方法
  2. addCallMethod(pattern, methodName, paramCount):调用栈顶元素的指定方法,可指定方法的参数个数
  3. addCallMethod(pattern, methodName, paramCount, paramTypes):调用栈顶元素的指定方法,可指定方法的参数个数,类型

3. XML文件

<?xml version="1.0" encoding="UTF-8" ?>
<Orders><Order user="张三" date="2008-11-14" price="12279"><goods id="1"><name>IBM笔记本</name><price>8999</price><count>1</count><total_price>8999</total_price></goods><goods id="2"><name>雅戈尔西服</name><price>1300</price><count>2</count><total_price>2600</total_price></goods></Order>
</Orders>

4. 通过不同的方式解析这个xml文件

4.1 通过java编码方式解析(javabean存储)

根据这个xml文件的各个节点得出,我们可以创建两个javabean来存储解析信息。分别为Order.java和good.java。

// 订单类
package cn.com.bean;import java.util.ArrayList;
/*** Order.java:订单类* @author ypykip**/
public class Order {private String user;    //对应<Order>标签中的user属性private String date;    //对应<Order>标签中的date属性private String price;   //对应<Order>标签中的price属性//对应<Order>标签下的所有<good>标签private ArrayList<Goods> goodsList = new ArrayList<Goods>();//省略getter和setter...// 添加商品到订单public void add(Goods goods){this.getGoodsList().add(goods);}// 重写toString()方法,方便于观察结果@Overridepublic String toString() {return "Order [user=" + user + ", date=" + date + ", price=" + price+ ", goodsList=" + goodsList.toString() + "]";}}
// 商品类
package cn.com.bean;package cn.com.bean;/*** Goods.java:商品类* @author ypykip**/
public class Goods {private String id;private String name;private String price;private String count;private String total_price;//省略getter和setter...@Overridepublic String toString() {return "Goods [id=" + id + ", name=" + name + ", price=" + price+ ", count=" + count + ", total_price=" + total_price +"]";}
}// 解析类
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;import org.apache.commons.digester.Digester;
import org.xml.sax.SAXException;import cn.com.bean.Goods;
import cn.com.bean.Order;/*** title:通过digester的方式来解析Order.xml* @author grk* 重点:理解栈的概念* 当使用addObjectCreate()方法时,创建一个对象进栈* 以下的所有操作(有一种情况除外,表明调用的方法)都是对栈顶元素来讲的,除非调用* addSetNext()方法,移除栈顶元素并执行次栈顶元素的指定方法* * addCallMethod(pattern, methodName):调用栈顶元素的指定方法* addCallMethod(pattern, methodName, paramCount):调用栈顶元素的指定方法,可指定方法的* 参数个数addCallMethod(pattern, methodName, paramCount, paramTypes):调用栈顶元素的* 指定方法,可指定方法的参数个数,类型* * addCallParam(pattern, paramIndex):默认设置指定paramIndex参数为标签内容* addCallParam(pattern, paramIndex, fromStack):设置指定paramIndex参数为栈顶元素* addCallParam(pattern, paramIndex, stackIndex):设置指定paramIndex参数为?* addCallParam(pattern, paramIndex, attributeName):设置指定paramIndex参数为标签属性* attributeName的值 addObjectParam(pattern, paramIndex, paramObj):设置指定paramIndex* 参数为paramObj** addSetNext(pattern, methodName):调用次栈顶元素的methodName方法,一般为有一个参数的方法,* 将栈顶元素作为入参,如list的add方法*  */
public class ParseOrder {public static void main(String[] args) {parseByJavaBean();}/*** 使用javaBean进行存储*/public static void parseByJavaBean(){// 1.初始化Digester实例对象Digester digester = new Digester();// 2.解析<Order>标签节点//list进栈,栈顶元素的list对象digester.addObjectCreate("Orders", ArrayList.class);//Order实例进栈,栈顶元素时Order实例对象digester.addObjectCreate("Orders/Order", Order.class);//设置<Order>标签的属性digester.addSetProperties("Orders/Order");// 3.解析<goods>标签节点//Goods实例对象进栈digester.addObjectCreate("Orders/Order/goods", Goods.class);digester.addSetProperties("Orders/Order/goods");//设置<goods>下的其他标签内容digester.addBeanPropertySetter("Orders/Order/goods/name");digester.addBeanPropertySetter("Orders/Order/goods/price");digester.addBeanPropertySetter("Orders/Order/goods/count");digester.addBeanPropertySetter("Orders/Order/goods/total_price");//Goods对象实例出栈digester.addSetNext("Orders/Order/goods", "add");//Order对象实例出栈digester.addSetNext("Orders/Order", "add");// 4.加载配置文件String filePath = "";filePath = System.getProperty("user.dir")+"/bin/config/Order.xml";File file = new File(filePath);// 5.解析try {ArrayList list = (ArrayList) digester.parse(file);System.out.println(list.toString());} catch (IOException e) {e.printStackTrace();} catch (SAXException e) {e.printStackTrace();}}
}

运行结果
[Order [user=张三, date=2008-11-14, price=12279, goodsList=[Goods [id=1, name=IBM笔记本, price=8999, count=1, total_price=8999], Goods [id=2, name=雅戈尔西服, price=1300, count=2, total_price=2600]]]]

4.2 通过java编码方式解析(list和map存储)

    /*** 使用list和map进行存储(过程复杂,不建议使用)*/public static void parseByMap(){Digester digester = new Digester();// 1.定义Orders节点规则,创建一个List集合digester.addObjectCreate("Orders", ArrayList.class);// 2.定义Orders/Order节点规则,创建一个Map集合用来存储属性和内容,并将此Map放在上一节点中的Listdigester.addObjectCreate("Orders/Order", HashMap.class);digester.addSetNext("Orders/Order", "add");// 3.定义Orders/Order节点的属性digester.addCallMethod("Orders/Order", "put", 2);//调用栈顶元素map的put方法digester.addObjectParam("Orders/Order", 0, "name");//设置keydigester.addCallParam("Orders/Order", 1, "name");//设置valuedigester.addCallMethod("Orders/Order", "put", 2);digester.addObjectParam("Orders/Order", 0, "date");digester.addCallParam("Orders/Order", 1, "date");digester.addCallMethod("Orders/Order", "put", 2);digester.addObjectParam("Orders/Order", 0, "price");digester.addCallParam("Orders/Order", 1, "price");// 4.定义一个List集合,用来存储Orders/Order节点下的标签digester.addCallMethod("Orders/Order", "put", 2);digester.addObjectCreate("Orders/Order", ArrayList.class);digester.addObjectParam("Orders/Order", 0, "goodsList");digester.addCallParam("Orders/Order", 1, true);// 5.定义Orders/Order/goods节点规则,分别存储id,name,price,count,total_price属性或标签digester.addObjectCreate("Orders/Order/goods", HashMap.class);digester.addSetNext("Orders/Order/goods", "add");digester.addCallMethod("Orders/Order/goods", "put", 2);digester.addObjectParam("Orders/Order/goods", 0, "id");digester.addCallParam("Orders/Order/goods", 1, "id");digester.addCallMethod("Orders/Order/goods/name", "put", 2);digester.addObjectParam("Orders/Order/goods/name", 0, "name");digester.addCallParam("Orders/Order/goods/name", 1);digester.addCallMethod("Orders/Order/goods/price", "put", 2);digester.addObjectParam("Orders/Order/goods/price", 0, "price");digester.addCallParam("Orders/Order/goods/price", 1);digester.addCallMethod("Orders/Order/goods/count", "put", 2);digester.addObjectParam("Orders/Order/goods/count", 0, "count");digester.addCallParam("Orders/Order/goods/count", 1);digester.addCallMethod("Orders/Order/goods/total_price", "put", 2);digester.addObjectParam("Orders/Order/goods/total_price", 0, "total_price");digester.addCallParam("Orders/Order/goods/total_price", 1);String filePath = System.getProperty("user.dir")+"/bin/config/Order.xml";System.out.println(filePath);File file = new File(filePath);System.out.println(file.getAbsolutePath());try {ArrayList list = (ArrayList) digester.parse(file);System.out.println(list.toString());} catch (IOException e) {e.printStackTrace();} catch (SAXException e) {e.printStackTrace();}}

4.3 通过xml配置方式解析

4.3.1 OrderConfigRule.xml 配置文件
<?xml version="1.0" encoding="UTF-8"?>
<digester-rules><pattern value="Orders"><object-create-rule classname="java.util.ArrayList" />  <!-- 配置<Order>标签 --><pattern value="Order"><object-create-rule classname="cn.com.bean.Order" /><set-properties-rule/><!-- 配置<goods>标签 --><pattern value="goods"><object-create-rule classname="cn.com.bean.Goods" /><set-properties-rule><alias attr-name="id" prop-name="id" /><!-- id属性对应javabean的id --></set-properties-rule><bean-property-setter-rule pattern="name" propertyname="name" /><!-- name属性对应javabean的name --><bean-property-setter-rule pattern="price" propertyname="price" /><!-- price标签对应javabean的price --><bean-property-setter-rule pattern="count" propertyname="count" /><!-- count标签对应javabean的count --><bean-property-setter-rule pattern="total_price" propertyname="total_price" /><!-- total_price标签对应javabean的total_price --><set-next-rule methodname="add" paramtype="cn.com.bean.Goods"/></pattern><set-next-rule methodname="add" paramtype="cn.com.bean.Order"/></pattern></pattern>
</digester-rules>  
4.3.2 Java解析
public static void parseByXmlConfig() throws IOException, SAXException, URISyntaxException{// 1.加载规则配置文件URL rule = Thread.currentThread().getContextClassLoader().getResource("config/OrderConfigRules.xml");// 2.加载待解析的配置文件Order.xmlReader reader = null;try {reader = new InputStreamReader(new FileInputStream(new File(System.getProperty("user.dir") + "/bin/config/Order.xml")), "utf-8");} catch (FileNotFoundException e) {e.printStackTrace();}// 3.根据规则配置文件创建Digester实例对象InputSource in = new InputSource(new InputStreamReader(new FileInputStream(new File(rule.toURI()))));Digester digester = DigesterLoader.createDigester(in);// 4.进行解析并打印结果List list = (List) digester.parse(reader);System.out.println(list.toString());try {if(reader != null){reader.close();}} catch (Exception e) {e.printStackTrace();}}

结果
[Order [user=张三, date=2008-11-14, price=12279, goodsList=[Goods [id=1, name=IBM笔记本, price=8999, count=1, total_price=8999], Goods [id=2, name=雅戈尔西服, price=1300, count=2, total_price=2600]]]]

5.总结

  • 如果需要调用addSetNext()方法时,addObjectCreate()方法和addSetNext()方法最好成对出现
  • 首先要知道addSetNext()方法是调用次栈顶元素的方法,一般以栈顶元素为参数。如上例中使用list和map的方式进行存储时,创建顺序分别是Orders—>Order—>goods,对应的list和map分别是list(Orders)—>map(Order)—>list(goodsList)—>map(goods)。当遇到Orders/Order节点时,分别创建了一个map和一个list,分别表示订单和商品集合。当遇到 < /order> 结束标签时需要调用list(Orders)的add()方法,即需要此时的栈顶元素是map(Order)和次栈顶元素是list(Orders)。如果addSetNext()写在了list(goodsList)创建之后,此时的栈顶元素和次栈顶元素分别是list(goodsList),map(Order),而map是没有add方法的,所以会报错:

java.lang.NoSuchMethodException: No such accessible method: add() on object: java.util.HashMap

  • 通过使用java编码和配置规则两种方式都可以实现解析,其实两者看上去十分相似熟练了其中一种,另一种也就无师自通了

相关文章:

【Digester解析XML文件的三种方式】

Digester解析XML文件的三种方式 1. Digester解析XML文件的三种方式1.1 作用及依赖jar包 2. 重点和难点3. XML文件4. 通过不同的方式解析这个xml文件4.1 通过java编码方式解析&#xff08;javabean存储&#xff09;4.2 通过java编码方式解析&#xff08;list和map存储&#xff0…...

MATLAB curve fitting toolbox没有怎么办?

版本&#xff1a;MATLAB R2023b 如果在安装MATLAB时仅仅选择了安装MATLAB&#xff0c;而并未选择其他选项&#xff0c;则在进入MATLAB后会发现顶部的APP栏中无法找到曲线拟合工具箱。 本人跟随MATLAB中的教程进行下载时&#xff0c;出现了如下报错&#xff1a; 最终解决方案&a…...

Linux之快速入门(CentOS 7)

文章目录 一、Linux目录结构二、常用命令2.1 切换用户2.2查看ip地址2.3 cd2.4 目录查看2.5 查看文件内容2.6 创建目录及文件2.7 复制和移动2.8 其他2.9 tar3.0 which3.1 whereis3.2 find&#xff08;这个命令尽量在少量用户使用此软件时运行&#xff0c;因为此命令是真的读磁盘…...

Spring框架中的设计模式

&#x1f389;欢迎来到Spring专栏&#xff1a;Spring框架中的设计模式 &#x1f4dc;其他专栏&#xff1a;java面试 数据结构 源码解读 故障分析 &#x1f3ac;作者简介&#xff1a;大家好&#xff0c;我是小徐&#x1f947;☁️博客首页&#xff1a;CSDN主页小徐的博客&#x…...

Java数据结构与算法:邻接矩阵和邻接表

Java数据结构与算法&#xff1a;邻接矩阵和邻接表 大家好&#xff0c;我是免费搭建查券返利机器人赚佣金就用微赚淘客系统3.0的小编&#xff0c;也是冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01; 什么是邻接矩阵和邻接表&#xff1f; 在图的表示中&#xff0c…...

【温故而知新】JavaScript类、类继承、静态方法

文章目录 前言一、类二、类继承三、静态方法四、热门文章 前言 JavaScript是一种广泛使用的编程语言&#xff0c;主要用于Web开发。它是一种脚本语言&#xff0c;这意味着它不需要像编译语言那样预先编译&#xff0c;而是在运行时解释和执行。JavaScript可以直接在浏览器中运行…...

小黑艰难的前端啃bug之路:内联元素之间的间隙问题

今天开始学习前端项目&#xff0c;遇到了一个Bug调了好久&#xff0c;即使margin为0&#xff0c;但还是有空格。 小黑整理&#xff0c;用四种方法解决了空白问题 <!DOCTYPE html> <html><head><meta charset"utf-8"><title></tit…...

Ubuntu 申请 SSL证书并搭建邮件服务器

文章目录 Log 一、域名连接到泰坦&#xff08;Titan&#xff09;电子邮件二、NameSilo Hosting 避坑三、Ubuntu 搭建邮件服务器1. 环境准备2. 域名配置3. 配置 Postfix 和 Dovecot① 安装 Nginx② 安装 Tomcat③ 申请 SSL 证书&#xff08;Lets Encrypt&#xff09;④ 配置 pos…...

视频监控方案设计:EasyCVR视频智能监管系统方案技术特点与应用

随着科技的发展&#xff0c;视频监控平台在各个领域的应用越来越广泛。然而&#xff0c;当前的视频监控平台仍存在一些问题&#xff0c;如视频质量不高、监控范围有限、智能化程度不够等。这些问题不仅影响了监控效果&#xff0c;也制约了视频监控平台的发展。 为了解决这些问…...

pyspark.sql.types 中的类型有哪些

对 pyspark.sql.types 中的类型做个记录 1、首先正常使用的时候&#xff0c;我们需要引用他们&#xff1a; from pyspark.sql.types import MapType,StringType # 或者 from pyspark.sql.types import *PySpark SQL TYPES是PySpark模型中的一个类&#xff0c;用于定义PySpark数…...

开源CRM客户管理系统-FeelCRM

FeelCRM客户管理系统 开源项目介绍 FeelCRM客户管理系统&#xff0c;符合中小企业业务流程&#xff1b;支持线索管理、客户管理、商机管理、合同管理、审核管理等多个模块&#xff1b;希望能为广大中小企业以及开发者们提供一个更多的可能性&#xff1b;本版本是我公司跨语言…...

Linux创建新分区挂载后普通用户没有读写权限

Linux创建新分区挂载后普通用户没有读写权限 为了使用更大的空间&#xff0c;楼主按照 ubuntu 16.04 硬盘分区&#xff0c;挂载&#xff0c;硬盘分区方案 这个教程新建硬盘分区给普通用户挂载后&#xff0c;发现普通用户没有权限对挂载的文件夹进行读写。 导致无论是创建文…...

清越 peropure·AI 国内版ChatGP新功能介绍

当OpenAI发布ChatGPT的时候,没有人会意识到,新一代人工智能浪潮将给人类社会带来一场眩晕式变革。其中以ChatGPT为代表的AIGC技术加速成为AI领域的热门发展方向,推动着AI时代的前行发展。面对技术浪潮,清越科技(PeroPure)立足多样化生活场景、精准把握用户实际需求,持续精确Fin…...

力扣1027. 最长等差数列

动态规划 思路&#xff1a; 可以参考力扣1218. 最长定差子序列目前不清楚公差&#xff0c;可以将序列最大最小值找到&#xff0c;公差的范围是 [-(max - min), (max - min)]&#xff0c;按公差递增迭代遍历求出最长等差数列&#xff1b; class Solution { public:int longest…...

GraphicsMagick 的 OpenCL 开发记录(二十三)

文章目录 ImageMagick和GraphicsMagick函数及宏对照表 <2022-04-14 周四> ImageMagick和GraphicsMagick函数及宏对照表 在开发过程中收集了这两个项目中的一些相同或相似功能的函数或者宏定义&#xff0c;希望对大家有所帮助&#xff0c;如下&#xff1a; TypeImageMa…...

通过Android Logcat分析firebase崩溃

参考&#xff1a;UnityIL2CPP包Crash闪退利用Android Logcat还原符号表堆栈日志 - 简书 一、安装Android Logcat插件 1、新建空白unity工程&#xff0c;打开PackageManager窗口&#xff0c;菜单栏Window/PackageManager 2、PackageManager中安装Android Logcat日志工具 3、安…...

【AI大模型】WikiChat超越GPT-4:在模拟对话中事实准确率提升55%终极秘密

WikiChat&#xff0c;这个名字仿佛蕴含了无尽的智慧和奥秘。它不仅是一个基于人工智能和自然语言处理技术的聊天机器人&#xff0c;更是一个能够与用户进行深度交流的智能伙伴。它的五个突出特点&#xff1a;高度准确、减少幻觉、对话性强、适应性强和高效性能&#xff0c;使得…...

【C语言刷题系列】水仙花数的打印及进阶

1.水仙花数问题 水仙花数&#xff08;Narcissistic number&#xff09;也被称为超完全数字不变数&#xff08;pluperfect digital invariant, PPDI&#xff09;、自恋数、自幂数、阿姆斯壮数或阿姆斯特朗数&#xff08;Armstrong number&#xff09; 水仙花数是指一个 3 位数&a…...

ICSpector:一款功能强大的微软开源工业PLC安全取证框架

关于ICSpector ICSpector是一款功能强大的开源工业PLC安全取证框架&#xff0c;该工具由微软的研究人员负责开发和维护&#xff0c;可以帮助广大研究人员轻松分析工业PLC元数据和项目文件。 ICSpector提供了方便的方式来扫描PLC并识别ICS环境中的可疑痕迹&#xff0c;可以用于…...

HCIA——29HTTP、万维网、HTML、PPP、ICMP;万维网的工作过程;HTTP 的特点HTTP 的报文结构的选择、解答

学习目标&#xff1a; 计算机网络 1.掌握计算机网络的基本概念、基本原理和基本方法。 2.掌握计算机网络的体系结构和典型网络协议&#xff0c;了解典型网络设备的组成和特点&#xff0c;理解典型网络设备的工作原理。 3.能够运用计算机网络的基本概念、基本原理和基本方法进行…...

Cursor实现用excel数据填充word模版的方法

cursor主页&#xff1a;https://www.cursor.com/ 任务目标&#xff1a;把excel格式的数据里的单元格&#xff0c;按照某一个固定模版填充到word中 文章目录 注意事项逐步生成程序1. 确定格式2. 调试程序 注意事项 直接给一个excel文件和最终呈现的word文件的示例&#xff0c;…...

ES6从入门到精通:前言

ES6简介 ES6&#xff08;ECMAScript 2015&#xff09;是JavaScript语言的重大更新&#xff0c;引入了许多新特性&#xff0c;包括语法糖、新数据类型、模块化支持等&#xff0c;显著提升了开发效率和代码可维护性。 核心知识点概览 变量声明 let 和 const 取代 var&#xf…...

Prompt Tuning、P-Tuning、Prefix Tuning的区别

一、Prompt Tuning、P-Tuning、Prefix Tuning的区别 1. Prompt Tuning(提示调优) 核心思想:固定预训练模型参数,仅学习额外的连续提示向量(通常是嵌入层的一部分)。实现方式:在输入文本前添加可训练的连续向量(软提示),模型只更新这些提示参数。优势:参数量少(仅提…...

spring:实例工厂方法获取bean

spring处理使用静态工厂方法获取bean实例&#xff0c;也可以通过实例工厂方法获取bean实例。 实例工厂方法步骤如下&#xff1a; 定义实例工厂类&#xff08;Java代码&#xff09;&#xff0c;定义实例工厂&#xff08;xml&#xff09;&#xff0c;定义调用实例工厂&#xff…...

2025季度云服务器排行榜

在全球云服务器市场&#xff0c;各厂商的排名和地位并非一成不变&#xff0c;而是由其独特的优势、战略布局和市场适应性共同决定的。以下是根据2025年市场趋势&#xff0c;对主要云服务器厂商在排行榜中占据重要位置的原因和优势进行深度分析&#xff1a; 一、全球“三巨头”…...

Go 语言并发编程基础:无缓冲与有缓冲通道

在上一章节中&#xff0c;我们了解了 Channel 的基本用法。本章将重点分析 Go 中通道的两种类型 —— 无缓冲通道与有缓冲通道&#xff0c;它们在并发编程中各具特点和应用场景。 一、通道的基本分类 类型定义形式特点无缓冲通道make(chan T)发送和接收都必须准备好&#xff0…...

免费PDF转图片工具

免费PDF转图片工具 一款简单易用的PDF转图片工具&#xff0c;可以将PDF文件快速转换为高质量PNG图片。无需安装复杂的软件&#xff0c;也不需要在线上传文件&#xff0c;保护您的隐私。 工具截图 主要特点 &#x1f680; 快速转换&#xff1a;本地转换&#xff0c;无需等待上…...

iview框架主题色的应用

1.下载 less要使用3.0.0以下的版本 npm install less2.7.3 npm install less-loader4.0.52./src/config/theme.js文件 module.exports {yellow: {theme-color: #FDCE04},blue: {theme-color: #547CE7} }在sass中使用theme配置的颜色主题&#xff0c;无需引入&#xff0c;直接可…...

【从零开始学习JVM | 第四篇】类加载器和双亲委派机制(高频面试题)

前言&#xff1a; 双亲委派机制对于面试这块来说非常重要&#xff0c;在实际开发中也是经常遇见需要打破双亲委派的需求&#xff0c;今天我们一起来探索一下什么是双亲委派机制&#xff0c;在此之前我们先介绍一下类的加载器。 目录 ​编辑 前言&#xff1a; 类加载器 1. …...

客户案例 | 短视频点播企业海外视频加速与成本优化:MediaPackage+Cloudfront 技术重构实践

01技术背景与业务挑战 某短视频点播企业深耕国内用户市场&#xff0c;但其后台应用系统部署于东南亚印尼 IDC 机房。 随着业务规模扩大&#xff0c;传统架构已较难满足当前企业发展的需求&#xff0c;企业面临着三重挑战&#xff1a; ① 业务&#xff1a;国内用户访问海外服…...