管道流设计模式结合业务

文章目录

    • 流程图
    • 代码实现
      • pom
      • context
        • EventContext
        • BizType
        • AbstractEventContext
      • filter
        • EventFilter
        • AbstractEventFilter
        • EventFilterChain
        • FilterChainPipeline
        • DefaultEventFilterChain
      • selector
        • FilterSelector
        • DefaultFilterSelector
    • 调用代码
      • PipelineApplication
      • controller
      • entity
      • service
      • service.business1
      • service.business1.context
      • service.business1.filters
      • service.business1.plugins
      • service.business2
      • service.business2.context
      • service.business2.filters
      • service.business2.plugins
      • service.config
      • service.selector
      • application.yml

流程图

请添加图片描述

代码实现

请添加图片描述

完整代码:https://gitee.com/gitee_pikaqiu/easy-pipeline

pom

<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.plugin</groupId><artifactId>spring-plugin-core</artifactId><version>${spring.plugin.core.version}</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>${hutool.version}</version></dependency>
</dependencies>

context

EventContext
public interface EventContext {/*** 是否继续调用链*/boolean continueChain();/*** 获取当前过滤器选择器*/FilterSelector getFilterSelector();}
BizType
public interface BizType {/*** 获取业务类型码值*/Integer getCode();/*** 业务类型名称**/String getName();}
AbstractEventContext
public abstract class AbstractEventContext implements EventContext{private final BizType businessType;private final FilterSelector filterSelector;protected AbstractEventContext(BizType businessType, FilterSelector filterSelector) {this.businessType = businessType;this.filterSelector = filterSelector;}@Overridepublic boolean continueChain() {return true;}@Overridepublic FilterSelector getFilterSelector() {return filterSelector;}}

filter

EventFilter
public interface EventFilter<T extends EventContext> {/*** 过滤逻辑封装点** @param context 上下文对象* @param chain   调用链*/void doFilter(T context, EventFilterChain<T> chain);}
AbstractEventFilter
public abstract class AbstractEventFilter<T extends EventContext> implements EventFilter<T> {@Overridepublic void doFilter(T context, EventFilterChain<T> chain) {// 执行if (context.getFilterSelector().matchFilter(this.getClass().getSimpleName())) {handler(context);}// 是否继续执行调用链if (context.continueChain()) {chain.nextHandler(context);}}/*** 执行器** @param context 上下文对象*/protected abstract void handler(T context);}
EventFilterChain
public interface EventFilterChain<T extends EventContext> {/*** 执行当前过滤器** @param context 上下文对象*/void handler(T context);/*** 跳过当前过滤器 执行下一个执行过滤器** @param context 上下文对象*/void nextHandler(T context);}
FilterChainPipeline
@Slf4j
@Component
public class FilterChainPipeline<F extends EventFilter>{private DefaultEventFilterChain<EventContext> last;public FilterChainPipeline<F> append(F filter){last = new DefaultEventFilterChain<>(last, filter);return this;}public FilterChainPipeline<F> append(String description, F filter){log.debug("过滤器调用链管道开始设置 {} 过滤器",description);last = new DefaultEventFilterChain<>(last, filter);return this;}public DefaultEventFilterChain<EventContext> getFilterChain() {return this.last;}}
DefaultEventFilterChain
public class DefaultEventFilterChain<T extends EventContext> implements EventFilterChain<T> {private final EventFilterChain<T> next;private final EventFilter<T> filter;public DefaultEventFilterChain(EventFilterChain<T> next, EventFilter<T> filter) {this.next = next;this.filter = filter;}@Overridepublic void handler(T context) {filter.doFilter(context,this);}@Overridepublic void nextHandler(T context) {if (next != null) {next.handler(context);}}}

selector

FilterSelector
public interface FilterSelector {/*** 匹配过滤器** @param currentFilterName 过滤器名称* @return true 匹配成功*/boolean matchFilter(String currentFilterName);/*** 获取当前所有过滤器名称** @return 过滤器名称*/List<String> getAllFilterNames();
}
DefaultFilterSelector
public class DefaultFilterSelector implements FilterSelector{@Setterprivate  List<String> filterNames = CollUtil.newArrayList();@Overridepublic boolean matchFilter(String currentFilterName) {return filterNames.stream().anyMatch(s -> Objects.equals(s,currentFilterName));}@Overridepublic List<String> getAllFilterNames() {return filterNames;}}

调用代码

请添加图片描述

PipelineApplication

@SpringBootApplication
@EnablePluginRegistries(value = {Business1PostPlugin.class, Business2PostPlugin.class})
public class PipelineApplication {public static void main(String[] args) {SpringApplication.run(PipelineApplication.class, args);}
}

controller

@RestController
@RequestMapping("/pipelineTest")
public class PipelineController {@Autowiredprivate Business1Service business1PipelineTestService;@Autowiredprivate Business2Service business2PipelineTestService;@GetMapping("/business1")public void business1(){PipelineRequestVo pipelineTestRequest = new PipelineRequestVo();pipelineTestRequest.setUuid("business1-1110-1111231afsas-123adss");pipelineTestRequest.setBusinessCode("business1");pipelineTestRequest.setModel2(new Business1Model2());pipelineTestRequest.setModel1(new Business1Model1());business1PipelineTestService.doService(pipelineTestRequest);}@GetMapping("/business2")public void business2(){PipelineRequestVo pipelineTestRequest = new PipelineRequestVo();pipelineTestRequest.setUuid("business2-1110-1111231afsas-123adss");pipelineTestRequest.setBusinessCode("business2");pipelineTestRequest.setModel3(new Business2Model1());pipelineTestRequest.setModel4(new Business2Model2());business2PipelineTestService.doService(pipelineTestRequest);}}

entity

@Data
public class PipelineRequestVo {private String uuid;private String businessCode;/*** 在自定义的filter中处理*/@Setter@Getterprivate Business1Model1 model1;/*** 在自定义的filter中处理*/@Setter@Getterprivate Business1Model2 model2;/*** 在自定义的filter中处理*/@Setter@Getterprivate Business2Model1 model3;/*** 在自定义的filter中处理*/@Setter@Getterprivate Business2Model2 model4;}

service

@Getter
@AllArgsConstructor
public enum BusinessTypeEnum implements BizType {BUSINESS_1(1,"业务1"),BUSINESS_2(2,"业务2"),BUSINESS_3(3,"业务3"),;private Integer code;private String name;}

service.business1

public interface Business1Service {void doService(PipelineRequestVo pipelineTestRequest);
}
@Slf4j
@Service
public class Business1ServiceImpl implements Business1Service {@Qualifier("business1PipelineSelectorFactory")@Autowiredprivate  PipelineSelectorFactory business1PipelineSelectorFactory;@Autowiredprivate  FilterChainPipeline<Business1PipelineFilter> filterChainPipeline;@Autowiredprivate  PluginRegistry<Business1PostPlugin, Business1Model1> business1PostPlugin;@Overridepublic void doService(PipelineRequestVo pipelineTestRequest) {log.info("===============business1开始===============");// 处理器参数log.info("===============开始获取FilterSelector===============");FilterSelector filterSelector = business1PipelineSelectorFactory.getFilterSelector(pipelineTestRequest);Business1Context pipelineEventContext = new Business1Context(BusinessTypeEnum.BUSINESS_1, filterSelector);log.info("获取FilterSelector完成: {}",filterSelector.getAllFilterNames());log.info("===============获取FilterSelector完成===============");// 处理log.info("===============开始执行过滤器===============");pipelineEventContext.setPipelineTestRequest(pipelineTestRequest);pipelineEventContext.setModel2(pipelineTestRequest.getModel2());pipelineEventContext.setModel1(pipelineTestRequest.getModel1());filterChainPipeline.getFilterChain().handler(pipelineEventContext);log.info("===============执行过滤器完成===============");// 处理后获取值log.info("===============开始执行后置处理器===============");Business1Model2 model2 = pipelineEventContext.getModel2();Business1Model1 model1 = pipelineEventContext.getModel1();PipelineRequestVo pipelineTestRequest1 = pipelineEventContext.getPipelineTestRequest();business1PostPlugin.getPluginsFor(model1).forEach(handler -> handler.postProcessing(model1));log.info("===============执行后置处理器完成===============");log.info("===============business1结束===============");}}

service.business1.context

public class Business1Context extends AbstractEventContext {/*** 在自定义的filter中处理*/@Setter@Getterprivate Business1Model1 model1;/*** 在自定义的filter中处理*/@Setter@Getterprivate Business1Model2 model2;/*** 在自定义的filter中处理*/@Setter@Getterprivate PipelineRequestVo pipelineTestRequest;public Business1Context(BizType businessType, FilterSelector filterSelector) {super(businessType, filterSelector);}@Overridepublic boolean continueChain() {return true;}}
@Data
public class Business1Model1 {private Integer id;private String name1;private String name2;private String name3;}
@Data
public class Business1Model2 {private Integer id;private String name;private String desc;private String age;}

service.business1.filters

public interface Business1PipelineFilter extends EventFilter<Business1Context> {int order();
}
@Slf4j
@Component
public class Business1Filter1 extends AbstractEventFilter<Business1Context> implements Business1PipelineFilter {@Overridepublic void handler(Business1Context context) {// 模拟操作数据库 等业务操作 可以利用门面模式进行解耦Business1Model1 model1 = context.getModel1();model1.setName1("张三");model1.setName2("李四");model1.setName3("王五");model1.setId(1);Business1Model2 model2 = context.getModel2();model2.setId(2);model2.setDesc("");model2.setAge("18");model2.setName("小白");log.info("Filter1执行完毕...");// 存入新的值到上下文对象中 下个处理器继续处理context.setModel1(model1);context.setModel2(model2);}@Overridepublic int order() {return 1;}
}
@Slf4j
@Component
public class Business1Filter2 extends AbstractEventFilter<Business1Context>  implements Business1PipelineFilter {@Overridepublic void handler(Business1Context context) {// 模拟操作数据库 等业务操作 可以利用门面模式进行解耦Business1Model1 model1 = context.getModel1();model1.setName1(model1.getName1() + "-------------");model1.setName2(model1.getName2() + "-------------");model1.setName3(model1.getName3() + "-------------");model1.setId(100);log.info("Filter2执行完毕...");// 存入新的值到上下文对象中 下个处理器继续处理context.setModel1(model1);context.setModel2(context.getModel2());}@Overridepublic int order() {return 2;}
}

service.business1.plugins

public interface Business1PostPlugin extends Plugin<Business1Model1> {/*** 后置处理** @param model 处理参数*/void postProcessing(Business1Model1 model);}
@Slf4j
@Component
public class Business1ServicePluginImpl implements Business1PostPlugin {@Overridepublic boolean supports(Business1Model1 pipelineEventContext) {return true;}@Overridepublic void postProcessing(Business1Model1 model) {log.info("===>{}",model.getId());}}
@Slf4j
@Component
public class Business1ServicePluginImpl2 implements Business1PostPlugin {@Overridepublic boolean supports(Business1Model1 model) {return true;}@Overridepublic void postProcessing(Business1Model1 model) {log.info("===>{}",model.getId());}}

service.business2

public interface Business2Service {void doService(PipelineRequestVo pipelineTestRequest);
}
@Slf4j
@Service
public class Business2ServiceImpl implements Business2Service {@Qualifier("business2PipelineSelectorFactory")@Autowiredprivate PipelineSelectorFactory business2PipelineSelectorFactory;@Autowiredprivate FilterChainPipeline<Business2PipelineFilter> filterChainPipeline;@Autowiredprivate PluginRegistry<Business2PostPlugin, Business2Model1> business2PostPlugin;@Overridepublic void doService(PipelineRequestVo pipelineTestRequest) {log.info("===============business2开始===============");// 处理器参数log.info("===============开始获取FilterSelector===============");FilterSelector filterSelector = business2PipelineSelectorFactory.getFilterSelector(pipelineTestRequest);Business2Context pipelineEventContext = new Business2Context(BusinessTypeEnum.BUSINESS_2, filterSelector);log.info("获取FilterSelector完成: {}",filterSelector.getAllFilterNames());log.info("===============获取FilterSelector完成===============");// 处理log.info("===============开始执行过滤器===============");pipelineEventContext.setPipelineTestRequest(pipelineTestRequest);pipelineEventContext.setModel2(pipelineTestRequest.getModel4());pipelineEventContext.setModel1(pipelineTestRequest.getModel3());filterChainPipeline.getFilterChain().handler(pipelineEventContext);log.info("===============执行过滤器完成===============");// 处理后获取值log.info("===============开始执行后置处理器===============");Business2Model2 model2 = pipelineEventContext.getModel2();Business2Model1 model1 = pipelineEventContext.getModel1();PipelineRequestVo pipelineTestRequest1 = pipelineEventContext.getPipelineTestRequest();business2PostPlugin.getPluginsFor(model1).forEach(handler -> handler.postProcessing(model1));log.info("===============执行后置处理器完成===============");log.info("===============business2结束===============");}}

service.business2.context

public class Business2Context extends AbstractEventContext {/*** 在自定义的filter中处理*/@Setter@Getterprivate Business2Model1 model1;/*** 在自定义的filter中处理*/@Setter@Getterprivate Business2Model2 model2;/*** 在自定义的filter中处理*/@Setter@Getterprivate PipelineRequestVo pipelineTestRequest;public Business2Context(BizType businessType, FilterSelector filterSelector) {super(businessType, filterSelector);}@Overridepublic boolean continueChain() {return true;}}
@Data
public class Business2Model1 {private Integer id;private String name1;private String name2;private String name3;}
@Data
public class Business2Model2 {private Integer id;private String name;private String desc;private String age;}

service.business2.filters

public interface Business2PipelineFilter extends EventFilter<Business2Context> {int order();
}
@Slf4j
@Component
public class Business2Filter1 extends AbstractEventFilter<Business2Context> implements Business2PipelineFilter {@Overridepublic void handler(Business2Context context) {// 模拟操作数据库 等业务操作 可以利用门面模式进行解耦Business2Model1 model1 = context.getModel1();model1.setName1("张三");model1.setName2("李四");model1.setName3("王五");model1.setId(1);Business2Model2 model2 = context.getModel2();model2.setId(2);model2.setDesc("");model2.setAge("18");model2.setName("小白");log.info("Filter1执行完毕...");// 存入新的值到上下文对象中 下个处理器继续处理context.setModel1(model1);context.setModel2(model2);}@Overridepublic int order() {return 1;}
}
@Slf4j
@Component
public class Business2Filter2 extends AbstractEventFilter<Business2Context>  implements Business2PipelineFilter {@Overridepublic void handler(Business2Context context) {// 模拟操作数据库 等业务操作 可以利用门面模式进行解耦Business2Model1 model1 = context.getModel1();model1.setName1(model1.getName1() + "-------------");model1.setName2(model1.getName2() + "-------------");model1.setName3(model1.getName3() + "-------------");model1.setId(100);log.info("Filter2执行完毕...");// 存入新的值到上下文对象中 下个处理器继续处理context.setModel1(model1);context.setModel2(context.getModel2());}@Overridepublic int order() {return 2;}
}

service.business2.plugins

public interface Business2PostPlugin extends Plugin<Business2Model1> {/*** 后置处理** @param model 处理参数*/void postProcessing(Business2Model1 model);}
@Slf4j
@Component
public class Business2ServicePluginImpl implements Business2PostPlugin {@Overridepublic boolean supports(Business2Model1 pipelineEventContext) {return true;}@Overridepublic void postProcessing(Business2Model1 model) {log.info("===>{}",model.getId());}}
@Slf4j
@Component
public class Business2ServicePluginImpl2 implements Business2PostPlugin {@Overridepublic boolean supports(Business2Model1 model) {return true;}@Overridepublic void postProcessing(Business2Model1 model) {log.info("===>{}",model.getId());}}

service.config

@ConfigurationProperties(prefix = "test")
@Component
@Data
public class FilterConfigProperties {private Map<String, List<String>> configs;public Map<String, List<String>> getConfigs() {if (configs == null) {configs = MapUtil.newHashMap(16);}return configs;}}
@Component
@RequiredArgsConstructor
public class PipelineFilterConfig {private final List<Business1PipelineFilter> business1PipelineFilter;private final FilterChainPipeline<Business1PipelineFilter> business1FilterChainPipeline;private final List<Business2PipelineFilter> business2PipelineFilter;private final FilterChainPipeline<Business2PipelineFilter> business2FilterChainPipeline;private final FilterConfigProperties filterConfigProperties;@Beanpublic FilterChainPipeline<Business1PipelineFilter> business1ChargePipeline() {Map<String, List<String>> configs = filterConfigProperties.getConfigs();if (business1PipelineFilter.isEmpty() || configs.isEmpty()){return business1FilterChainPipeline;}Set<Map.Entry<String, List<String>>> filtersName = configs.entrySet();long distinctCount = filtersName.stream().distinct().count();if (distinctCount > business1PipelineFilter.size()) {throw new IllegalArgumentException("设置的过滤器数量大于实际过滤器数量");}business1PipelineFilter.stream().sorted(Comparator.comparing(Business1PipelineFilter::order)).forEach(business1FilterChainPipeline::append);return business1FilterChainPipeline;}@Beanpublic FilterChainPipeline<Business2PipelineFilter> business2ChargePipeline() {Map<String, List<String>> configs = filterConfigProperties.getConfigs();if (business2PipelineFilter.isEmpty() || configs.isEmpty()){return business2FilterChainPipeline;}Set<Map.Entry<String, List<String>>> filtersName = configs.entrySet();long distinctCount = filtersName.stream().distinct().count();if (distinctCount > business2PipelineFilter.size()) {throw new IllegalArgumentException("设置的过滤器数量大于实际过滤器数量");}business2PipelineFilter.stream().sorted(Comparator.comparing(Business2PipelineFilter::order)).forEach(business2FilterChainPipeline::append);return business2FilterChainPipeline;}}

service.selector

public interface PipelineSelectorFactory {FilterSelector  getFilterSelector(PipelineRequestVo request);
}
@Component("business1PipelineSelectorFactory")
public class Business1PipelineSelectorFactory implements PipelineSelectorFactory {@Autowiredprivate FilterConfigProperties filterConfigProperties;@Overridepublic FilterSelector getFilterSelector(PipelineRequestVo request) {String businessCode = request.getBusinessCode();DefaultFilterSelector defaultFilterSelector = new DefaultFilterSelector();if (businessCode.equals("business1")){defaultFilterSelector.setFilterNames(filterConfigProperties.getConfigs().getOrDefault(businessCode, Collections.unmodifiableList(new ArrayList<>())));}return defaultFilterSelector;}
}
@Component("business2PipelineSelectorFactory")
public class Business2PipelineSelectorFactory implements PipelineSelectorFactory {@Autowiredprivate FilterConfigProperties filterConfigProperties;@Overridepublic FilterSelector getFilterSelector(PipelineRequestVo request) {String businessCode = request.getBusinessCode();DefaultFilterSelector defaultFilterSelector = new DefaultFilterSelector();if (businessCode.equals("business2")){defaultFilterSelector.setFilterNames(filterConfigProperties.getConfigs().getOrDefault(businessCode, Collections.unmodifiableList(new ArrayList<>())));}return defaultFilterSelector;}}

application.yml

server:port: 8080test:configs:business1:- Business1Filter1- Business1Filter2business2:- Business2Filter1- Business2Filter2

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/630792.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MySql安装(Linux)

一、清除原来的mysql环境 在前期建议使用root用户来进行操作&#xff0c;使用 su -来切换成root用户&#xff0c;但是如果老是提示认证失败&#xff0c;那么有可能我们的root密码并没有被设置&#xff0c; 我们可以先设置root的密码 sudo passwd root 然后就可以切换了。 …

遥感图像分割 | 基于一种类似UNet的Transformer算法实现遥感城市场景图像的语义分割_适用于卫星图像+航空图像+无人机图像

项目应用场景 面向遥感城市场景图像语义分割场景&#xff0c;项目采用类似 UNet 的 Transformer 深度学习算法来实现&#xff0c;项目适用于卫星图像、航空图像、无人机图像等。 项目效果 项目细节 > 具体参见项目 README.md (1) 安装依赖 conda create -n airs python3.8…

neo4j使用详解(终章、neo4j的java driver使用模板及工具类——<可用于生产>)

Neo4j系列导航: neo4j安装及简单实践 cypher语法基础 cypher插入语法 cypher插入语法 cypher查询语法 cypher通用语法 cypher函数语法 neo4j索引及调优 neo4j java Driver等更多 1. 简介 本文主要是java使用neo4j driver操作neo4j的模板项目及非常有用的工具类,主要包括: 图…

python中对列表的复制操作(浅拷贝与深拷贝)

python中对列表的复制操作用的比较广泛&#xff0c;之前写过一篇博客Python&#xff1a;复制列表&#xff0c;禁止函数修改列表&#xff08;副本&#xff0c;切片表示法[:]&#xff09;详细讲述了python中的 [:] 操作&#xff0c;但是 [:] 操作仅仅只是浅拷贝&#xff0c;具有很…

C++:深入理解operator new/operator delete

动态内存管理 1.语法层面1.基本语法注意点 2.new/delete和malloc/free的区别3.operator new和operator delete函数&#xff08;底层重点&#xff09;1.operator new/delete原理2.图解1.new/new[]2.delete/delete[] 3.new[n]和delete[] 4.定位new1.定义2.使用格式 1.语法层面 1…

JVM虚拟机(十)Java内存泄漏的排查思路

目录 一、可能产生内存泄露的地方二、复现堆内存泄漏三、如何排查堆内存问题&#xff1f;3.1 获取对内存快照 dump3.2 使用 Visual VM 去分析 dump 文件3.3 定位内存溢出问题 一、可能产生内存泄露的地方 在进行排查 Java 的内存泄漏问题之前&#xff0c;首先我们要知道哪里可…

Vue接收接口返回的mp3格式数据并支持在页面播放音频

一、背景简介 在实际工作中需要开发一个转音频工具&#xff0c;并且能够在平台页面点击播放按钮播放音频 二、相关知识介绍 2.1 JS内置对象Blob Blob对象通常用于处理大量的二进制数据&#xff0c;可以读取/写入/操作文件、音视频等二进制数据流。Blob表示了一段不可变的二…

AI热潮下,公链基础设施赛道都有哪些变化?

最近在一级市场&#xff0c;最火热的赛道无疑是AI&#xff0c;其次是BTC&#xff0c;每天聊的项目80%都集中在这两个赛道&#xff0c;我个人最多的时候一天可以聊5&#xff0c;6个AI项目。 可以预见的是AI泡沫会在明后年达到顶峰&#xff0c;随着数以百计的AI新项目上线&#…

【EI会议征稿通知】2024年图像处理、机器学习与模式识别国际学术会议(IPMLP 2024)

2024年图像处理、机器学习与模式识别国际学术会议&#xff08;IPMLP 2024) 2024 International Conference on Image Processing, Machine Learning and Pattern Recognition 重要信息 大会官网&#xff1a;www.ipmlp.net&#xff08;点击参会/投稿/了解会议详情&#xff09;…

政安晨:【Keras机器学习示例演绎】(一)—— 利用类 U-Net 架构进行图像分割

目录 下载数据 准备输入图像的路径和目标分割掩码 一幅输入图像和相应的分割掩码是什么样子的&#xff1f; 准备数据集&#xff0c;以加载和矢量化成批数据 准备 U-Net Xception 风格模型 预留验证分割 训练模型 可视化预测 政安晨的个人主页&#xff1a;政安晨 欢迎 &…

京东微服务microApp使用总结

前言 基于现有业务门户进行微服务基础平台搭建 主应用框架&#xff1a;vue3vite 子应用框架&#xff1a;vue2webpack / vue3vite在这里插入代码片 本地调试即可&#xff1a;主应用子应用进行打通&#xff08;注意&#xff1a;两者都是vue3vite&#xff09; 问题总结 1.嵌入…

OpenHarmony多媒体-video_trimmer

简介 videotrimmer是在OpenHarmony环境下&#xff0c;提供视频剪辑能力的三方库。 效果展示&#xff1a; 安装教程 ohpm install ohos/videotrimmerOpenHarmony ohpm环境配置等更多内容&#xff0c;请参考 如何安装OpenHarmony ohpm包 。 使用说明 目前支持MP4格式。 视频…