基于grpc从零开始搭建一个准生产分布式应用(6) - 02 - MapStruct数据转换

一、基础转换

1.1、基础类型

基本类型、包装类、BigDecimal转String默认使用DecimalFormat格式化,@Mapping#numberFormat可以指定格式,Date转String默认使用SimpleDateFormat格式化,如默认格式不符要求,可以用,@Mapping可以指定格式。

  1. enum和String:可直接转枚举定义的值,不支持MappingConstants.ANY_REMAINING
  2. BigDecimal(等)、基本数据类(包括包装类)和String:
  3. java.time.LocalDateTime(等)和String:
  4. java.util.Date转String:Date->String,
  5. java.sql.Timestamp和java.util.Date:

注意在@Mapping#target、source设置的属性的含义。mapstruct并不是按照设置的属性找到字段,在找此字段的getter/setter方法的,而是直接通过get/set前缀 + 属性值找到相应的方法。所以如果属性名与getter和setter方法名不对象,则会报错。

@Data
public class TransformBO {private String level;private int price;private String date;private Date timestamp;private String localDateTime
}
@Data
public class TransformPO {private LevelEnum level;private BigDecimal price;private Date date;private Timestamp timestamp;private LocalDateTime localDateTime;
}@Mapper
public interface TestMapper {TransformBO toTransformBO(TransformPO transformPO);TransformPO toTransformPO(TransformBO transformPO);
}//@Mapping(target = "date", dateFormat = "yyyy-MM-dd HH:mm")
//@Mapping(target = "price", numberFormat = "$#.00")TransformBO transformBO = new TransformBO();
transformBO.setLevel("PERFECT");
transformBO.setPrice(12);
transformBO.setDate("2022-01-31 01:30:19");
transformBO.setTimestamp(new Date(System.currentTimeMillis()));
transformBO.setLocalDateTime("2022-01-31T01:34:47.986");
System.out.println(mapper.toTransformPO(transformBO));-->互转后Date的出入值是比较大的,需要特殊处理
TransformBO(level=PERFECT, price=12, date=2022-01-31 01:35:21, timestamp=2022-01-31 01:35:21.024, localDateTime=2022-01-31T01:35:21.107)
TransformPO(level=PERFECT, price=12, date=Mon Jan 31 01:30:19 CST 2022, timestamp=2022-01-31 01:35:21.138, localDateTime=2022-01-31T01:34:47.986)

1.2、Booble

private Boolean delete;
private String delete;transformPO.setDelete(false);
//正常输出

二、集合转换

2.1、List

这个比较简单,需要定义一个集合类和一个单体转换类,类的名字随意,但建议起成对的名字,便于记录。

@Mapper
public interface TestMapper {TestBO testToBO(TestPO testPO);List<TestBO> testToBOS(List<TestPO> testPOS);
}

2.2、Map

@Mapper
public interface TestMapper {TestBO testToBO(TestPO testPO);Map<TestBO, TestBO> testToBOS(Map<TestPO, TestPO> testPOS); 
}

2.3、Enum

枚举通常是直接映射到同名的枚举对象中,不同名需@ValueMapping指定,并且源和目标上可以设置

  • MappingConstants.ANY_REMAINING:只能用在source上,标识source中除了同名自动映射和指定映射外,其余所有对象都映射到指定的target对象上;
  • MappingConstants.ANY_UNMAPPED:只能用在source上,不能和MappingConstants.ANY_REMAINING同时使用,会将source除指定对象(不包括同名自动映射)的剩余对象映射到target对象,只是为了省事;
  • MappingConstants.NULL:设置在source上表示source是null时,会被映射到指定的target;设置在target上表示source对象映射到null。
enum LevelEnum {PERFECT(1, "完美"),PASS(2, "合格"),normal_status(3, "普通"),failed(4, "不及格"),normal(5, "正常");
}enum DisableStatus {able_status(1, "完美"),disable_status(2, "合格"),normal_status(3, "普通"),failed_status(4, "不及格"),ok_status(5, "还行"),fine_status(6, "可以");
}@Mapper
interface TestMapper {@ValueMappings({@ValueMapping(source = "able_status", target = "PERFECT"),//一对一映射@ValueMapping(source = MappingConstants.NULL, target = "PASS"),//@ValueMapping(source = "failed_status", target = MappingConstants.NULL),//==在新代码中failed_status=null@ValueMapping(source = MappingConstants.ANY_REMAINING, target = "normal"),//==default=normal})LevelEnum toEnum(DisableStatus disableStatus);
}
public class TestMapperImpl implements TestMapper {@Overridepublic LevelEnum toEnum(DisableStatus disableStatus) {if ( disableStatus == null ) {return LevelEnum.PASS;//--------}LevelEnum levelEnum;switch ( disableStatus ) {case able_status: levelEnum = LevelEnum.PERFECT;break;case failed_status: levelEnum = null;break;case normal_status: levelEnum = LevelEnum.normal_status;break;default: levelEnum = LevelEnum.normal;}return levelEnum;}
}
//生成的代码
@Mapper
public interface TestMapper {@ValueMappings({@ValueMapping(source = MappingConstants.ANY_UNMAPPED, target = "normal_status"),})LevelEnum toEnum(DisableStatus disableStatus);
}@Component
public class TestMapperImpl implements TestMapper {@Overridepublic LevelEnum toEnum(DisableStatus disableStatus) {if ( disableStatus == null ) {return null;} LevelEnum levelEnum;switch ( disableStatus ) {default: levelEnum = LevelEnum.normal_status;}return levelEnum;}
}

2.3.1、自定义名称转换

可以通过删除或添加源枚举字符串的前后缀来映射目标枚举对象,这也是一种快捷方式。@EnumMapping#nameTransformationStrategy支持的参数有:suffix(添加源后缀)、stripSuffix(删除源后缀)、prefix(添加源前缀)、stripPrefix(删除源前缀)。

@Mapper
public interface TestMapper {@EnumMapping(nameTransformationStrategy = "stripSuffix", configuration = "_status")LevelEnum toEnum(DisableStatus disableStatus);
}
//比如原Enum值为
public enum LevelEnum { able_status(1, "完美")
}
//生成的源码为
@Overridepublic LevelEnum toEnum(DisableStatus disableStatus) {if ( disableStatus == null ) {return null;}LevelEnum levelEnum; switch ( disableStatus ) {case able_status: levelEnum = LevelEnum.able;break;case disable_status: levelEnum = LevelEnum.disable;break;case normal_status: levelEnum = LevelEnum.normal;break;case failed_status: levelEnum = LevelEnum.failed;break;case ok_status: levelEnum = LevelEnum.ok;break;case fine_status: levelEnum = LevelEnum.fine;break;default: throw new IllegalArgumentException( "Unexpected enum constant: " + disableStatus );}return levelEnum;}

三、数据映射策略

3.1、@mappingControl属性映射优先级策略(不建议修改)

在mapStruct框架中可以从【全局-类-属性】等地方可以配置映射策略,@MappingConfig,@Mapper,@BeanMapping,@Mapping越往后的优先级越高,这4个注解都有mappingControl属性,默认值是MappingControl.class,可选值还有NoComplexMapping.class、DeepClone.class,用于控制每个字段属性映射的方式;

3.1.1、MappingControl.class的优先级逻辑如下:

  1. MappingControl.Use.DIRECT——直接复制具有相同属性类型的字段,但如果有自定义的映射配置@Mapping和导入了其他Mapper的自定义的映射,会将直接赋值覆盖;自定义的映射配置@Mapping优先级高于导入了其他Mapper的自定义的映射;
  2. MappingControl.Use.MAPPING_METHOD——属性类型不同的字段,会去查找将源属性的类型作为参数,将目标属性的类型作为返回的映射方法(包括自定义方法、抽象类实现方法和接口默认方法);
  3. MappingControl.Use.BUILT_IN_CONVERSION——如果不存在上述方法,查找内置转换方法,就像BigDecimal转String;
  4. MappingControl.Use.COMPLEX_MAPPING——如果内置转换方法不存在,将进行一些复杂转换,也就是结合现有的映射方法和内置转换,互相嵌套生成一个能够映射的方法;
  5. 如果都没有,则会自动生成子映射方法,就像上面的例子若是不指定TestPO到TestBO的接口方法,则也会主动生成;
  6. 若这也没法生成则编译就会报错了。

3.1.2、NoComplexMapping.class的优先级逻辑如下:

  1. MappingControl.Use.DIRECT——直接复制具有相同属性类型的字段,但如果有自定义的映射配置@Mapping和导入了其他Mapper的自定义的映射,会将直接赋值覆盖;自定义的映射配置@Mapping优先级高于导入了其他Mapper的自定义的映射;
  2. MappingControl.Use.MAPPING_METHOD——属性类型不同的字段,会去查找将源属性的类型作为参数,将目标属性的类型作为返回的映射方法(包括自定义方法、抽象类实现方法和接口默认方法);
  3. MappingControl.Use.BUILT_IN_CONVERSION——如果不存在上述方法,查找内置转换方法,就像BigDecimal转String;
  4. 如果都没有,则会自动生成子映射方法,就像上面的例子若是不指定TestPO到TestBO的接口方法,则也会主动生成;
  5. 若这也没法生成则编译就会报错了。

3.1.3、DeepClone.class的优先级逻辑如下:

  • MappingControl.Use.MAPPING_METHOD——属性类型不同的字段,会去查找将源属性的类型作为参数,将目标属性的类型作为返回的映射方法(包括自定义方法、抽象类实现方法和接口默认方法)。
//比如使用DeepClone的mappingControl,这样我们就只能进行MappingControl.Use.MAPPING_METHOD映射了
@Mapper(mappingControl = DeepClone.class)
public interface TestMapper {@Mapping(target = "localDateTime", dateFormat = "yyyy-MM-dd HH")TransformBO toTransformBO(TransformPO transformPO);
}

3.2、@TargetType泛型的应用-将映射目标类型传递给自定义映射器

就是在使用@Mapper#uses()时,使用的自定义映射器中的方法可以接受Class<T>对象,要使用 @TargetType标注。可用于一些通用设置。

@Data
public class BasePO {private Long id;
}@Data
public class TestFivePO {private TestFourPO test;
}
@EqualsAndHashCode(callSuper = true)
@Data
public class TestFourPO extends BasePO {
}//-----
@Data
public class BaseBO {private Long id;private String name;
}
@Data
public class TestSevenBO {private TestSixBO test;
}
@EqualsAndHashCode(callSuper = true)
@Data
public class TestSixBO extends BaseBO {}
------------源码实现--------------------------------@Mapper(uses = {BaseMapper.class})
public interface TestMapper { TestSevenBO testToBO(TestFivePO testPO);
}@Mapper
public class BaseMapper {public <T extends BaseBO> T testToBO(BasePO basePO, @TargetType Class<T> baseBOClass)  {try {T t = baseBOClass.newInstance();t.setId(basePO.getId());return t;} catch (Exception e) {return null;}}
}
------------生成的源码实现--------------------------------
@Component
public class TestMapperImpl implements TestMapper {@Autowiredprivate BaseMapper baseMapper;public TestMapperImpl() {}public TestSevenBO testToBO(TestFivePO testPO) {if (testPO == null) {return null;} else {TestSevenBO testSevenBO = new TestSevenBO();testSevenBO.setTest((TestSixBO)this.baseMapper.testToBO(testPO.getTest(), TestSixBO.class));return testSevenBO;}}
}

3.3、@Context将上下文ThreadLocal或状态对象传递给自定义方法

就是线程间共享值的一种方式,用了ThreadLocal特性。

@Data
public class ThreadLocalContext {private ThreadLocal<Object> threadLocal;public ThreadLocalContext() {threadLocal = new ThreadLocal<>();}
}@Mapper
public class BaseMapper {public TestSixBO toTestSixBOWithContext(TestFourPO testFourPO, @Context ThreadLocalContext threadLocalContext) {TestSixBO testBO = new TestSixBO();testBO.setId(testFourPO.getId());testBO.setName((String) threadLocalContext.getThreadLocal().get());return testBO;}
}@Mapper(uses = {BaseMapper.class})
public interface TestMapper {TestSevenBO testToBO(TestFivePO testPO, @Context ThreadLocalContext threadLocalContext);
}@Component
public class TestMapperImpl implements TestMapper {@Autowiredprivate BaseMapper baseMapper;@Overridepublic TestSevenBO testToBO(TestFivePO testPO, ThreadLocalContext threadLocalContext) {if ( testPO == null ) {return null;}TestSevenBO testSevenBO = new TestSevenBO();testSevenBO.setTest( baseMapper.toTestSixBOWithContext( testPO.getTest(), threadLocalContext ) );return testSevenBO;}
}ThreadLocalContext threadLocalContext = new ThreadLocalContext();
threadLocalContext.getThreadLocal().set("xx");TestFivePO testFivePO = new TestFivePO();
TestFourPO testFourPO = new TestFourPO();
testFourPO.setId(1L);
testFivePO.setTest(testFourPO);
System.out.println(testMapper.testToBO(testFivePO, threadLocalContext));---
TestSevenBO(test=TestSixBO(super=BaseBO(id=1, name=xx)))

3.4、@Qualifier区别相同参数类型和返回类型的映射方法

@Mapper
public class BaseMapper {public String toString1(String name) {return name + "1";}public String toString2(String name) {return name + "2";}
}
toString1、toString2方法的参数类型和返回类型相同,编译直接报错 
@Mapper(uses = {BaseMapper.class})
public interface TestMapper {TestSixBO testToBO(TestFourPO testPO); 
}

3.4.1、解决方案1-自定义注解ElementType.METHOD

@Qualifier
@Target(ElementType.METHOD) //ElementType.TYPE
@Retention(RetentionPolicy.CLASS)
public @interface StringToString1 {
}
@Qualifier
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.CLASS)
public @interface StringToString2 {
}
------------------------------
@Mapper(uses = {BaseMapper.class})
public interface TestMapper {@Mapping(target = "name", qualifiedBy = {StringToString1.class})//qualifiedBy属性TestSixBO testToBO(TestFourPO testPO);
}@Mapper
public class BaseMapper {@StringToString1public String toString1(String name) {return name + "1";}@StringToString2public String toString2(String name) {return name + "2";}
}
------------------------生成的代码如下------------------------
@Component
public class TestMapperImpl implements TestMapper {@Autowiredprivate BaseMapper baseMapper;@Overridepublic TestSixBO testToBO(TestFourPO testPO) {if ( testPO == null ) {return null;}TestSixBO testSixBO = new TestSixBO();// 使用qualifiedBy中设置的注解的方法testSixBO.setName( baseMapper.toString1( testPO.getName() ) );testSixBO.setId( testPO.getId() );return testSixBO;}
}

3.4.2、解决方案2-自定义注解ElementType.TYPE

@Qualifier
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.CLASS)
public @interface StringToString1 {
}@Qualifier
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.CLASS)
public @interface StringToString2 {
}@Mapper
@StringToString1//----------------------
public class BaseMapper {public String toString1(String name) {return name + "1";}
}@Mapper
@StringToString2
public class BaseMapper2 { public String toString2(String name) {return name + "2";}
}@Mapper(uses = {BaseMapper.class, BaseMapper2.class})
public interface TestMapper {@Mapping(target = "name", qualifiedBy = {StringToString2.class})TestSixBO testToBO(TestFourPO testPO);
}

3.4.3、解决方案3-@Named取代定义一个@Qualifier的接口

//若类上注解了@Named,mapper中引入了此类,要想使用引入类中自定义的映射方法,映射字段时就必须指定qualifiedByName
@Mapper
@Named("StringToString1")
public class BaseMapper {public String toString1(String name) {return name + "1";}
}@Mapper
@Named("StringToString2")
public class BaseMapper2 {public String toString2(String name) {return name + "2";}
}@Mapper(uses = {BaseMapper.class, BaseMapper2.class})
public interface TestMapper {@Mapping(target = "name", qualifiedByName = {"StringToString2"})//qualifiedByName属性TestSixBO testToBO(TestFourPO testPO);}

四、集合策略

通过@Mapping#collectionMappingStrategy设置集合的映射策略:CollectionMappingStrategy.ACCESSOR_ONLY(默认)、CollectionMappingStrategy.SETTER_PREFERRED、CollectionMappingStrategy.ADDER_PREFERRED、CollectionMappingStrategy.TARGET_IMMUTABLE。

public class TestPOS {private List<TestPO> list; public List<TestPO> getList() {return list;}public void addList(TestPO testPO) {this.list.add(testPO);}
}public class TestBOS {private List<TestBO> list;public List<TestBO> getList() {return list;} public void addList(TestBO testBO) {this.list.add(testBO);}
}@Mapper(collectionMappingStrategy = CollectionMappingStrategy.ADDER_PREFERRED)
public interface TestMapper {TestBO toBO(TestPO testPO);TestBOS toBOS(TestPOS testPOS);
}

4.1、使用默认集合策略CollectionMappingStrategy.ACCESSOR_ONLY

@Data
public class TestPOS {private List<TestPO> list;
} 
@Data
public class TestBOS {private List<TestBO> list;
}@Mapper
public interface TestMapper {TestBO toBO(TestPO testPO);void toBOS(TestPOS testPOS, @MappingTarget TestBOS testBOS);
}
testBOS.getList().clear();
testBOS.getList().addAll( list )//先清空再添加

4.2、使用CollectionMappingStrategy.ADDER_PREFERRED策略

手动创建add方法,使用CollectionMappingStrategy.ADDER_PREFERRED

这里在介绍下List属性字段名的映射规则,

public class TestBOS {private List<TestBO> oneTest_;public List<TestBO> getOneTestList() {return oneTest_;}public void addOneTest(TestBO testBO) {//手动创建了此方法oneTest_.add(testBO);}
}@Mapper(collectionMappingStrategy = CollectionMappingStrategy.ADDER_PREFERRED)
public interface TestMapper {@Mapping(target = "oneTest_", source = "tests") //这处的oneTest_要改成oneTestList才能正确调用addOneTest方法TestBOS toBean(TestPOS testPO);
}

自定义add方法,使用CollectionMappingStrategy.ADDER_PREFERRED

public class TestBOS {private List<Integer> oneTest_;public List<TestBO> getOneTestList() {return new ArrayList<>();}public void addOneTest(Integer integer) {//入参不一样oneTest_.add(integer);}
}
//testBOS.getOneTestList().addAll( list )
public class TestBOS {private List<Integer> oneTest_;public List<TestBO> getOneTestList() {return new ArrayList<>();}public void addOneTest(TestBO testBO) {//入参不一样oneTest_.add(testBO.getId().intValue());}
}
//testBOS.addOneTest( testPOToTestBO( test ) )

只有add方法,使用CollectionMappingStrategy.ADDER_PREFERRED策略

TestBOS testBOS = new TestBOS();if ( testPOS.getList() != null ) {for ( TestPO list : testPOS.getList() ) {testBOS.addList( toBO( list ) );}}

去掉add方法,使用CollectionMappingStrategy.ACCESSOR_ONLY策略

TestBOS testBOS = new TestBOS();if ( testBOS.getList() != null ) {List<TestBO> list = testPOListToTestBOList( testPOS.getList() );if ( list != null ) {testBOS.getList().addAll( list );}}
//以上结论是一样的,都是保持原集合内容不变,再增加新内容。

4.3、使用CollectionMappingStrategy.TARGET_IMMUTABLE策略

@Data
public class TestPOS {private List<TestPO> list;
} 
@Data
public class TestBOS {private List<TestBO> list;
}@Mapper(collectionMappingStrategy = CollectionMappingStrategy.TARGET_IMMUTABLE)
public interface TestMapper {TestBO toBO(TestPO testPO);void toBOS(TestPOS testPOS, @MappingTarget TestBOS testBOS);
}
@Overridepublic void toBOS(TestPOS testPOS, TestBOS testBOS) {if ( testPOS == null ) {return;}testBOS.setList( testPOListToTestBOList( testPOS.getList() ) );}//这个直接使用setter方式,会覆盖掉原集合的内容

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

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

相关文章

53 个 CSS 特效 3(完)

53 个 CSS 特效 3&#xff08;完&#xff09; 前两篇地址&#xff1a; 53 个 CSS 特效 153 个 CSS 特效 2 这里是第 33 到 53 个&#xff0c;很多内容都挺重复的&#xff0c;所以这里解释没之前的细&#xff0c;如果漏了一些之前的笔记会补一下&#xff0c;写过的就会跳过。…

Error: PostCSS plugin autoprefixer requires PostCSS 8 问题解决办法

报错&#xff1a;Error: PostCSS plugin autoprefixer requires PostCSS 8 原因&#xff1a;autoprefixer版本过高 解决方案&#xff1a; 降低autoprefixer版本 执行&#xff1a;npm i postcss-loader autoprefixer8.0.0

【配置环境】Visual Studio 配置 OpenCV

目录 一&#xff0c;环境 二&#xff0c;下载和配置 OpenCV 三&#xff0c;创建一个 Visual Studio 项目 四&#xff0c;配置 Visual Studio 项目 五&#xff0c;编写并编译 OpenCV 程序 六&#xff0c;解决CMake编译OpenCV报的错误 一&#xff0c;环境 Windows 11 家庭中…

Super Resolve Dynamic Scene from Continuous Spike Streams论文笔记

摘要 近期&#xff0c;脉冲相机在记录高动态场景中展示了其优越的潜力。不像传统相机将一个曝光时间内的视觉信息进行压缩成像&#xff0c;脉冲相机连续地输出二的脉冲流来记录动态场景&#xff0c;因此拥有极高的时间分辨率。而现有的脉冲相机重建方法主要集中在重建和脉冲相…

C语言入门 Day_12 一维数组0

目录 前言 1.创建一维数组 2.使用一维数组 3.易错点 4.思维导图 前言 存储一个数据的时候我们可以使用变量&#xff0c; 比如这里我们定义一个记录语文考试分数的变量chinese_score&#xff0c;并给它赋值一个浮点数&#xff08;float&#xff09;。 float chinese_scoe…

解决WebSocket通信:前端拿不到最后一条数据的问题

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页——&#x1f405;&#x1f43e;猫头虎的博客&#x1f390; &#x1f433; 《面试题大全专栏》 &#x1f995; 文章图文…

CTFhub-SSRF-内网访问

CTFHub 环境实例 | 提示信息 http://challenge-8bf41c5c86a8c5f4.sandbox.ctfhub.com:10800/?url_ 根据提示&#xff0c;在url 后门添加 127.0.0.1/flag.php http://challenge-8bf41c5c86a8c5f4.sandbox.ctfhub.com:10800/?url127.0.0.1/flag.php ctfhub{a6bb51530c8f6be0…

自动化运维:Ansible之playbook基于ROLES部署LNMP平台

目录 一、理论 1.playbook剧本 2.ROLES角色 3.关系 4.Roles模块搭建LNMP架构 二、实验 1.Roles模块搭建LNMP架构 三、问题 1.剧本启动php报错语法问题 2.剧本启动mysql报错语法问题 3.剧本启动nginx开启失败 4.剧本安装php失败 5.使用yum时报错 6.rpm -Uvh https…

springsecurity+oauth 分布式认证授权笔记总结12

一 springsecurity实现权限认证的笔记 1.1 springsecurity的作用 springsecurity两大核心功能是认证和授权&#xff0c;通过usernamepasswordAuthenticationFilter进行认证&#xff1b;通过filtersecurityintercepter进行授权。springsecurity其实多个filter过滤链进行过滤。…

11 - 深入了解NIO的优化实现原理

Tomcat 中经常被提到的一个调优就是修改线程的 I/O 模型。Tomcat 8.5 版本之前&#xff0c;默认情况下使用的是 BIO 线程模型&#xff0c;如果在高负载、高并发的场景下&#xff0c;可以通过设置 NIO 线程模型&#xff0c;来提高系统的网络通信性能。 我们可以通过一个性能对比…

STM32f103入门(8)TIM输入捕获输入捕获测频率PWMI测占空比

TIM输入捕获 频率测量输入捕获基本结构PWMI基本结构主从触发模式输入捕获测量频率PWMI测占空比 频率测量 输入捕获基本结构 CNT计数一个周期&#xff0c;转运到CCR1里面去&#xff0c;CNT0 这时候CCR1N FxFc/N Fc cnt的驱动时钟 这时候就可以得到频率 Fc72M/PSC PWMI基本结构 …

设计模式之组合模式

文章目录 一、介绍二、案例 一、介绍 组合模式(Composite Pattern)&#xff0c;属于结构型设计模式。组合模式常用于树形的数据结构&#xff0c;比如&#xff1a;多级菜单、部门层级关系、html文本中的dom树。它的特点是使用户对单个对象和组合对象的使用是相同的。 二、案例…

mac制作ssl证书|生成自签名证书,nodejs+express在mac上搭建https+wss(websocket)服务器

注意 mac 自带 openssl 所以没必要像 windows 一样先安装 openssl&#xff0c;直接生成即可 生成 ssl/自签名 证书 生成 key # 生成rsa私钥&#xff0c;des3算法&#xff0c;server_ssl.key是秘钥文件名 1024位强度 openssl genrsa -des3 -out server_ssl.key 1024让输入两…

走进低代码平台| iVX-困境之中如何突破传统

前言&#xff1a; “工欲善其事,必先利其器”&#xff0c;找到和使用一个优质的工具平台&#xff0c;往往会事半功倍。 文章目录 1️⃣认识走近低代码2️⃣传统的低代码开发3️⃣无代码编辑平台一个代码生成式低代码产品iVX受面性广支持代码复用如何使用&#xff1f; 4️⃣总结…

如何自定义iview树形下拉内的内容

1.使用render函数给第一层父级定义 2. 使用树形结构中的render函数来定义子组件 renderContent(h, {root, node, data}) {return data.children.length0? h(span, {style: {display: inline-block,width: 400px,lineHeight: 32px}}, [h(span, [h(Icon, {type: ios-paper-outli…

PY32F003F18P单片机概述

PY32F003F18P单片机是普冉的一款ARM微控制器&#xff0c;内核是Cortex-M0。这个单片机的特色&#xff0c;就是价格便宜&#xff0c;FLASH和SRAM远远超过8位单片机&#xff0c;市场竞争力很强大。 一、硬件资源&#xff1a; 1)、FLASH为64K字节&#xff1b; 2)、SRAM为8K字节&…

解决gitee仓库中 .git 文件夹过大的问题

最近&#xff0c;许多项目都迁移到gitee。使用的也越来越频繁&#xff0c;但是今天突然收到一个仓库爆满的提示。让我一脸懵逼。本文将详细为你解答&#xff0c;这种情况如何处理。 1、起因 我收到的报错如下&#xff1a; remote: Powered by GITEE.COM [GNK-6.4] remote: T…

车载监管模块项目需求分析报告

目录 1 文档说明.......................................................................................... 4 2 参考文件.......................................................................................... 4 3 概述.......................................…

YOLOv7框架解析

YOLOv7概念 YOLOv7是基于YOLO系列的目标检测算法&#xff0c;由Ultra-Light-Fast-Detection&#xff08;ULFD&#xff09;和Scaled-YOLOv4两种算法结合而来。它是一种高效、准确的目标检测算法&#xff0c;具有以下特点&#xff1a; 1. 高效&#xff1a;YOLOv7在保持准确率的…

Qt应用开发(基础篇)——颜色选择器 QColorDialog

一、前言 QColorDialog类继承于QDialog&#xff0c;是一个设计用来选择颜色的对话框部件。 对话框窗口 QDialog QColorDialog颜色选择器一般用来让用户选择颜色&#xff0c;比如画图工具中选择画笔的颜色、刷子的颜色等。你可以使用静态函数QColorDialog::getColor()直接显示对…