MapStruct的用法总结及示例

news2025/1/11 5:05:09

       MapStruct是一个代码生成器,它基于约定优于配置的原则,使用Java注解来简化从源对象到目标对象的映射过程。它主要用于减少样板代码,提高开发效率,并且通过编译时代码生成来保证性能。

     我的个人实践方面是在2021年前那时候在项目中使用dozer较多,后来发现MapStruct处理对象映射属性复制更灵活方便,就直接转向使用MapStruct。

    学习MapStruct的用法,最简单高效就是去阅读官网的文档:MapStruct – Java bean mappings, the easy way!以及下载官方的示例代码:GitHub - mapstruct/mapstruct-examples: Examples for using MapStruct

各种用法还是比较详细的

目录

1. java对象基本属性映射

2.设置属性的默认值

3.使用条件表达式

4.映射集合类属性

5.使用自定义映射方法

6.继承和多态

7. 使用组件模型

8.忽略默认值

9.MapStruct的注解

10.使用 @Mapper 注解定义映射器

11.映射多个源对象到一个目标对象

12. 映射一个源对象到多个目标对象

13.SpringBoot项目整合使用MapStruct

 以下是MapStruct的一些常见用法和相应的代码示例:

1. java对象基本属性映射
@Mapper
public interface PersonMapper {
    PersonMapper INSTANCE = Mappers.getMapper(PersonMapper.class);

    @Mapping(target = "address", source = "personAddress")
    PersonDto personToPersonDto(Person person);
}

class Person {
    private String name;
    private Address personAddress;
    // getters and setters
}

class PersonDto {
    private String name;
    private AddressDto address;
    // getters and setters
}

class Address {
    private String street;
    // getters and setters
}

class AddressDto {
    private String street;
    // getters and setters
}

如果有多个属性值的名称不一样,则需要使用@Mappings注解来使用多个 @Mapping来制定属性映射关系

比如:

@Mapper
public interface MyMapper {

    @Mappings({
        @Mapping(target = "name", source = "fullName"),
        @Mapping(target = "age", source = "years")
    })
    void updateTargetFromSource(Source source,Target target);
}
2.设置属性的默认值
@Mapper
public interface UserMapper {
    UserMapper INSTANCE = Mappers.getMapper(UserMapper.class);

    @Mapping(target = "email", expression = "java(email != null ? email : 'default@email.com')")
    UserDto userToUserDto(User user);
}

class User {
    private String name;
    private String email;
    // getters and setters
}

class UserDto {
    private String name;
    private String email;
    // getters and setters
}
3.使用条件表达式
@Mapper
public interface OrderMapper {
    OrderMapper INSTANCE = Mappers.getMapper(OrderMapper.class);

    @Mapping(target = "status", expression = "java(order.isShipped() ? \"SHIPPED\" : \"PENDING\")")
    OrderDto orderToOrderDto(Order order);
}

class Order {
    private boolean shipped;
    // getters and setters
}

class OrderDto {
    private String status;
    // getters and setters
}
4.映射集合类属性
@Mapper
public interface ItemMapper {
    ItemMapper INSTANCE = Mappers.getMapper(ItemMapper.class);

    @Mapping(target = "items", expression = "java(mapItemsToItemDtos(order.getItems()))")
    OrderDto orderToOrderDto(Order order);

    List<ItemDto> mapItemsToItemDtos(List<Item> items);
}

class Order {
    private List<Item> items;
    // getters and setters
}

class OrderDto {
    private List<ItemDto> items;
    // getters and setters
}

class Item {
    // properties and methods
}

class ItemDto {
    // properties and methods
}
5.使用自定义映射方法
@Mapper
public interface CarMapper {
    CarMapper INSTANCE = Mappers.getMapper(CarMapper.class);

    @Mapping("licensePlate", ignore = true)
    CarDto carToCarDto(@MappingTarget CarDto target, Car car);

    void setLicensePlateIfPresent(@MappingTarget CarDto target, Car car);
}

class Car {
    private String make;
    private String licensePlate;
    // getters and setters
}

class CarDto {
    private String make;
    // getters and setters
}

// 在项目编译后MapStruct会自动在映射器实现类中实现该方法
void setLicensePlateIfPresent(CarDto target, Car car) {
    if (car.getLicensePlate() != null && !car.getLicensePlate().isEmpty()) {
        target.setLicensePlate(car.getLicensePlate());
    }
}

@MappingTarget 是 MapStruct 中一个重要的注解,用于标识目标对象。在使用 MapStruct 进行对象映射时,有时我们需要将映射结果更新到一个已经存在的实例中,而不是创建一个新的对象。@MappingTarget 就是为此目的而设计的。

或者你可以直接在映射接口中实现一个默认的方法,来自定义映射关系

public interface MyMapper {
    
    // 其他映射方法

    // 自定义映射逻辑的默认方法
 void customMapping(@MappingTarget MyTarget target, MySource source) {
    if (source.getCondition()) {
        target.setSomeProperty("valueIfConditionTrue");
    } else {
        target.setSomeProperty("valueIfConditionFalse");
    }
}
}

或者直接调用另外的映射方法做属性映射: 

/*
 * Copyright MapStruct Authors.
 *
 * Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
 */
package org.mapstruct.example.mapper;

import java.lang.annotation.Target;
import java.util.Map;

import org.mapstruct.AfterMapping;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.MappingTarget;
import org.mapstruct.example.dto.Department;
import org.mapstruct.example.dto.Employee;
import org.mapstruct.factory.Mappers;

/**
 * @author Filip Hrisafov
 */
@Mapper
public interface MapToBeanMapper {

    MapToBeanMapper INSTANCE = Mappers.getMapper(MapToBeanMapper.class);

    @Mapping(target = "department", ignore = true)
    Employee fromMap(Map<String, String> map);

    @AfterMapping
    default void finishEmployee(@MappingTarget Employee employee, Map<String, String> map) {
        employee.setDepartment(fromMapToDepartment(map));
    }

    @Mapping(target = "id", source = "did")
    @Mapping(target = "name", source = "dname")
    Department fromMapToDepartment(Map<String, String> map);
}

 这段代码通过 MapStruct 提供了一个完整的映射解决方案,用于将 Map<String, String> 转换为 Employee 对象,并通过一个 @AfterMapping 方法在映射完成后手动设置 Employee 对象的 department 字段。

6.继承和多态
@Mapper
public interface AnimalMapper {
    AnimalMapper INSTANCE = Mappers.getMapper(AnimalMapper.class);

    AnimalDto animalToAnimalDto(Animal animal);
}

class Animal {
    private String name;
    // getters and setters
}

class Cat extends Animal {
    private String favoriteToy;
    // getters and setters
}

class AnimalDto {
    private String name;
    // getters and setters
}

class CatDto extends AnimalDto {
    private String favoriteToy;
    // getters and setters
}

MapStruct会自动处理继承关系,将子类的属性也映射到相应的DTO中。

7. 使用组件模型

MapStruct允许开发者定义组件,这些组件可以包含自定义的映射逻辑,可以被多个映射器使用。

@Mapper(componentModel = "spring",uses=DepartmentNameMapper.class)
public interface EmployeeMapper {
    EmployeeMapper INSTANCE = Mappers.getMapper(EmployeeMapper.class);

    @Mapping(target = "departmentName", source = "department.name")
    EmployeeDto employeeToEmployeeDto(Employee employee);
}

@Component
public class DepartmentNameMapper {
    public String toDepartmentName(Department department) {
        return department.getName();
    }
}

在这个例子中,DepartmentNameMapper是一个Spring组件,它提供了一个方法来获取部门的名称,这个方法可以在映射过程中被使用。

这些只是MapStruct的一些基本用法。MapStruct非常灵活,支持许多高级特性,如映射多个源对象到一个目标对象、使用自定义的映射方法、处理复杂的数据结构等

8.忽略默认值

在映射过程中,你可能希望忽略源对象中的默认值,只复制非默认值的属性。

@Mapper
public interface ProductMapper {
    ProductMapper INSTANCE = Mappers.getMapper(ProductMapper.class);

    @Mapping(target = "price", ignore = true)
    ProductDto productToProductDto(Product product);
}

class Product {
    private double price = 0.0; // 默认值
    // 其他属性和getter/setter
}

class ProductDto {
    private double price;
    // getter/setter
}

在这个例子中,ProductDtoprice 字段将不会被 Product 对象的默认值 0.0 填充

9.MapStruct的注解

MapStruct 允许你使用 @Mapping 注解来指定映射关系,包括如何从源属性映射到目标属性。

@Mapper
public interface UserMapper {
    UserMapper INSTANCE = Mappers.getMapper(UserMapper.class);

    @Mapping(target = "fullName", expression = "java(user.getFirstName() + ' ' + user.getLastName())")
    UserDto userToUserDto(User user);
}

class User {
    private String firstName;
    private String lastName;
    // getters and setters
}

class UserDto {
    private String fullName;
    // getter/setter
}

在这个例子中,UserDtofullName 属性是通过连接 User 对象的 firstNamelastName 属性来生成的。

使用@MappingTarget可以自定义源对象到目标对象的属性的映射关系;

使用 @AfterMapping@BeforeMapping 注解结合 @MappingTarget 来在映射前后执行自定义逻辑。上边的有结合 @AfterMapping的示例

@AfterMapping相对应,MapStruct还提供了@BeforeMapping注解,用于在映射开始之前执行自定义逻辑。

@Mapper
public interface UserMapper {
    UserMapper INSTANCE = Mappers.getMapper(UserMapper.class);

    @BeforeMapping
    default void beforeMapping(@MappingTarget UserDto target, User source) {
        // 执行映射前的自定义逻辑,例如初始化或验证源对象
        if (source == null) {
            throw new IllegalArgumentException("Source user cannot be null");
        }
    }

    UserDto userToUserDto(User user);
}
10.使用 @Mapper 注解定义映射器

@Mapper 注解用于定义映射器接口,你可以通过这个注解来配置映射器的行为,从而使用其他的自定义的映射器

@Mapper(uses = {DateMapper.class, EnumMapper.class})
public interface MyCustomMapper {
    // 映射方法
}

@Mapper
public abstract class DateMapper {
    @Mapping(target = "dateAsString", expression = "java(java.time.format.DateTimeFormatter.ISO_LOCAL_DATE.format(source.getDate()))")
    abstract void mapDate(@MappingTarget MyTarget target, MySource source);
}

@Mapper
public abstract class EnumMapper {
    // 映射枚举类型的逻辑
}

在这个例子中,MyCustomMapper 使用了 uses 属性来指定其他映射器类,这些类提供了额外的映射逻辑。

示例二

/*
 * Copyright MapStruct Authors.
 *
 * Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
 */
package org.mapstruct.example.mapper;

import org.mapstruct.InheritInverseConfiguration;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.example.dto.Customer;
import org.mapstruct.example.dto.CustomerDto;
import org.mapstruct.factory.Mappers;

/**
 * @author Filip Hrisafov
 */
@Mapper(uses = { OrderItemMapper.class })
public interface CustomerMapper {

    CustomerMapper MAPPER = Mappers.getMapper( CustomerMapper.class );

    @Mapping(source = "orders", target = "orderItems")
    @Mapping(source = "customerName", target = "name")
    Customer toCustomer(CustomerDto customerDto);

    @InheritInverseConfiguration
    CustomerDto fromCustomer(Customer customer);
}
/*
 * Copyright MapStruct Authors.
 *
 * Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
 */
package org.mapstruct.example.mapper;


import org.mapstruct.InheritInverseConfiguration;
import org.mapstruct.Mapper;
import org.mapstruct.example.dto.OrderItem;
import org.mapstruct.example.dto.OrderItemDto;
import org.mapstruct.factory.Mappers;

/**
 * @author Filip Hrisafov
 */
@Mapper
public interface OrderItemMapper {

    OrderItemMapper MAPPER = Mappers.getMapper(OrderItemMapper.class);

    OrderItem toOrder(OrderItemDto orderItemDto);

    @InheritInverseConfiguration
    OrderItemDto fromOrder(OrderItem orderItem);
}

@InheritInverseConfiguration 是 MapStruct 中的一个注解,用于继承已有映射方法的逆向配置。这在需要定义双向映射(从一个类到另一个类,然后从另一个类再映射回第一个类)时非常有用,可以减少代码重复,提高代码的可维护性。

11.使用 @Named 注解

在mapstruct的源码中@Named注解类就有对应的示例:

/*
 * Copyright MapStruct Authors.
 *
 * Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
 */
package org.mapstruct;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * Marks mapping methods with the given qualifier name. Can be used to qualify a single method or all methods of a given
 * type by specifying this annotation on the type level.
 * 
 * Will be used to select the correct mapping methods when mapping a bean property type, element of an iterable type
 * or the key/value of a map type.
 * 
 * Example (both methods of {@code Titles} are capable to convert a string, but the ambiguity is resolved by applying
 * the qualifiers in {@code @Mapping}:
 *
 * 
 * @Named("TitleTranslator")
 * public class Titles {
 *
 *   @Named("EnglishToGerman")
 *   public String translateTitleEG(String title) {
 *       // some mapping logic
 *   }
 *
 *   @Named("GermanToEnglish")
 *   public String translateTitleGE(String title) {
 *       // some mapping logic
 *   }
 * }
 *
 * @Mapper( uses = Titles.class )
 * public interface MovieMapper {
 *
 *    @Mapping( target = "title", qualifiedByName = { "TitleTranslator", "EnglishToGerman" } )
 *    GermanRelease toGerman( OriginalRelease movies );
 *
 * }
 *
 * The following implementation of {@code MovieMapper} will be generated:
 *
 
 *
 * public class MovieMapperImpl implements MovieMapper {
 *     private final Titles titles = new Titles();
 *
 *     @Override
 *     public GermanRelease toGerman(OriginalRelease movies) {
 *         if ( movies == null ) {
 *             return null;
 *         }
 *
 *         GermanRelease germanRelease = new GermanRelease();
 *
 *         germanRelease.setTitle( titles.translateTitleEG( movies.getTitle() ) );
 *
 *         return germanRelease;
 *     }
 * }
 *
 *
 * @author Sjaak Derksen
 * @see org.mapstruct.Mapping#qualifiedByName()
 * @see IterableMapping#qualifiedByName()
 * @see MapMapping#keyQualifiedByName()
 * @see MapMapping#valueQualifiedByName()
 */
@Target( { ElementType.TYPE, ElementType.METHOD } )
@Retention( RetentionPolicy.CLASS )
@Qualifier
public @interface Named {

    /**
     * A name qualifying the annotated element
     *
     * @return the name.
     */
    String value();
}

在 MapStruct 中,@Named 注解主要用于自定义方法,以便在映射器中引用这些方法。通过给这些方法加上 @Named 注解,并在 @Mapping 注解中引用这些方法,可以实现复杂的映射逻辑。MapStruct 支持 JSR-330 的 @Named 注解,这使得定义和使用自定义的转换逻辑更加灵活和清晰。

使用@Named注解定义自定义方法

假设我们有一个自定义的方法需要在映射过程中使用,我们可以使用 @Named 注解为该方法命名,并在 @Mapping 注解中引用它。

示例

假设我们有以下两个类:

public class Source {
    private String name;
    private String date;

    // getters and setters
}

public class Target {
    private String fullName;
    private LocalDate birthDate;

    // getters and setters
}

我们想要将 Sourcename 映射到 TargetfullName,并将 date 字符串转换为 LocalDate 并映射到 birthDate。为此,我们可以定义一个自定义的日期转换方法。

定义映射器接口和自定义方法

import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.Named;
import org.mapstruct.factory.Mappers;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;

@Mapper
public interface SourceToTargetMapper {

    SourceToTargetMapper INSTANCE = Mappers.getMapper(SourceToTargetMapper .class);

    @Mapping(source = "name", target = "fullName")
    @Mapping(source = "date", target = "birthDate", qualifiedByName = "stringToLocalDate")
    Target sourceToTarget(Source source);

    @Named("stringToLocalDate")
    default LocalDate stringToLocalDate(String date) {
        return LocalDate.parse(date, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
    }
}

测试使用映射器

public class TestMapping {
    public static void main(String[] args) {
        Source source = new Source();
        source.setName("John Doe");
        source.setDate("1980-01-01");

        Target target = SourceToTargetMapper.INSTANCE.sourceToTarget(source);

        System.out.println("Full Name: " + target.getFullName()); // 输出: John Doe
        System.out.println("Birth Date: " + target.getBirthDate()); // 输出: 1980-01-01
    }
}
11.映射多个源对象到一个目标对象

MapStruct允许你映射多个源对象到一个目标对象;这对于需要将来自不同源的数据合并到一个目标对象的情况非常有用。MapStruct 提供了灵活的注解配置,使得这种映射变得直观和易于实现。

示例:假设我们有以下两个源对象 Source1Source2,以及一个目标对象 Target

public class Source1 {
    private String name;
    private String email;

    // getters and setters
}

public class Source2 {
    private String address;
    private String phoneNumber;

    // getters and setters
}

public class Target {
    private String name;
    private String email;
    private String address;
    private String phoneNumber;

    // getters and setters
}

我们希望将 Source1Source2 的属性合并到 Target 对象中

定义映射器接口

我们需要在映射器接口中定义一个方法,该方法接受多个源对象并返回目标对象。

import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.factory.Mappers;

@Mapper
public interface MyMapper {
    MyMapper INSTANCE = Mappers.getMapper(MyMapper.class);

    @Mapping(source = "source1.name", target = "name")
    @Mapping(source = "source1.email", target = "email")
    @Mapping(source = "source2.address", target = "address")
    @Mapping(source = "source2.phoneNumber", target = "phoneNumber")
    Target map(Source1 source1, Source2 source2);
}

由于两个源对象和目标对象中的属性名称一致,所以也可以省略掉方法上的四个@Mapping 

测试类

public class TestMapping {
    public static void main(String[] args) {
        Source1 source1 = new Source1();
        source1.setName("John Doe");
        source1.setEmail("john.doe@example.com");

        Source2 source2 = new Source2();
        source2.setAddress("123 Main St");
        source2.setPhoneNumber("555-1234");

        Target target = MyMapper.INSTANCE.map(source1, source2);

        System.out.println("Name: " + target.getName()); // 输出: John Doe
        System.out.println("Email: " + target.getEmail()); // 输出: john.doe@example.com
        System.out.println("Address: " + target.getAddress()); // 输出: 123 Main St
        System.out.println("Phone Number: " + target.getPhoneNumber()); // 输出: 555-1234
    }
}
12. 映射一个源对象到多个目标对象

使用 @MappingTarget 注解,可以一次映射到多个目标对象。

示例:

假设我们有一个源对象 Source 和两个目标对象 Target1Target2,我们希望将 Source 对象的一部分属性映射到 Target1,另一部分属性映射到 Target2

public class Source {
    private String name;
    private String email;
    private String address;
    private String phoneNumber;

    // getters and setters
}

public class Target1 {
    private String name;
    private String email;

    // getters and setters
}

public class Target2 {
    private String address;
    private String phoneNumber;

    // getters and setters
}

定义映射接口

 我们需要在映射器接口中定义一个方法,该方法接受 Source 对象和两个目标对象,并将 Source 对象的属性映射到相应的目标对象中。

import org.mapstruct.Mapper;
import org.mapstruct.MappingTarget;
import org.mapstruct.factory.Mappers;

@Mapper
public interface MyMapper {
    MyMapper INSTANCE = Mappers.getMapper(MyMapper.class);

    void toMultiTargets(Source source, @MappingTarget Target1 target1, @MappingTarget Target2 target2);
}

 或者也可以自定义辅助方法实现具体的映射逻辑

@Mapper
public interface MyMapper {
    MyMapper INSTANCE = Mappers.getMapper(MyMapper.class);

    void toMultiTargets(Source source, @MappingTarget Target1 target1, @MappingTarget Target2 target2);

    default void toMultiTargets(Source source, @MappingTarget Target1 target1, @MappingTarget Target2 target2) {
        if (source != null) {
            target1.setName(source.getName());
            target1.setEmail(source.getEmail());

            target2.setAddress(source.getAddress());
            target2.setPhoneNumber(source.getPhoneNumber());
        }
    }
}

测试类:

public class TestMapping {
    public static void main(String[] args) {
        Source source = new Source();
        source.setName("John Doe");
        source.setEmail("john.doe@example.com");
        source.setAddress("123 Main St");
        source.setPhoneNumber("555-1234");

        Target1 target1 = new Target1();
        Target2 target2 = new Target2();

        MyMapper.INSTANCE.toMultiTargets(source, target1, target2);

        System.out.println("Target1 Name: " + target1.getName()); // 输出: John Doe
        System.out.println("Target1 Email: " + target1.getEmail()); // 输出: john.doe@example.com
        System.out.println("Target2 Address: " + target2.getAddress()); // 输出: 123 Main St
        System.out.println("Target2 Phone Number: " + target2.getPhoneNumber()); // 输出: 555-1234
    }
}
13.SpringBoot项目整合使用MapStruct

在Spring Boot项目中集成MapStruct主要涉及几个步骤:添加依赖、配置Mapper组件、使用MapStruct注解以及享受自动映射带来的便利。下面是详细的步骤和用法示例:

添加依赖

首先,需要在Spring Boot项目的pom.xml(对于Maven项目)或build.gradle(对于Gradle项目)中添加MapStruct的依赖。

Maven:

<dependencies>
    <!-- MapStruct依赖 -->
    <dependency>
        <groupId>org.mapstruct</groupId>
        <artifactId>mapstruct</artifactId>
        <version>1.5.2.Final</version>
    </dependency>
    <!-- 处理器依赖,用于生成映射代码 -->
    <dependency>
        <groupId>org.mapstruct</groupId>
        <artifactId>mapstruct-processor</artifactId>
        <version>1.5.2.Final</version>
        <scope>provided</scope>
    </dependency>
</dependencies>

Gradle

dependencies {
    // MapStruct依赖
    implementation 'org.mapstruct:mapstruct:1.5.2.Final'
    // 处理器依赖,用于生成映射代码
    annotationProcessor 'org.mapstruct:mapstruct-processor:1.5.2.Final'
}

2.配置Mapper组件

package com.example.demo.mapper;

import org.mapstruct.Mapper;
import org.springframework.stereotype.Component;

@Mapper(componentModel = "spring")
public interface MyEntityMapper {

   MyDto entityToDto(MyEntity entity);

    @Mapping(target = "createdDate", expression = "java(java.time.LocalDate.now())")
    MyDto entityToDtoWithDefaultDate(MyEntity entity);
}

在Spring组件中,通过自动装配MapStruct Mapper接口来实现对象之间的自动映射。

package com.example.demo.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.example.demo.mapper.MyEntityMapper;
import com.example.demo.entity.MyEntity;
import com.example.demo.dto.MyDto;

@Service
public class MyService {

    private final MyEntityMapper myEntityMapper;

    @Autowired
    public MyService(MyEntityMapper myEntityMapper) {
        this.myEntityMapper = myEntityMapper;
    }

    public MyDto convert(MyEntity entity) {
        return myEntityMapper.entityToDto(entity);
    }
}

确保Spring Boot的启动类或配置类中包含了@EnableAutoConfiguration@SpringBootApplication注解,这样Spring Boot就能自动配置应用程序,包括MapStruct的Mapper组件。

package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}

更多用法可以详细参照官方的example示例代码,分类挺详细的:

 

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2024/06/13--代码随想录算法(贪心)3/6|134.加油站、135.分发糖果、860.柠檬水找零、406.根据身高重建队列

134.加油站 力扣链接 class Solution:def canCompleteCircuit(self, gas: List[int], cost: List[int]) -> int:curSum 0 # 当前累计的剩余油量totalSum 0 # 总剩余油量start 0 # 起始位置for i in range(len(gas)):curSum gas[i] - cost[i]totalSum gas[i] - co…

区间合并——Acwing.803区间合并

区间合并 定义 区间合并是指将一组有重叠或相邻的区间合并成一个或多个更大的区间。 运用情况 图像处理&#xff1a;在图像的区域分析中&#xff0c;可能需要将相邻的具有相似特征的区域进行合并。时间区间处理&#xff1a;比如将多个连续时间段进行合并。行程规划&#xf…

AMS深入浅出

目标&#xff1a; 1. 一、AMS启动流程 ActivityManagerService是 安卓10 以后&#xff0c;将AMS拆分出ActivityTaskManagerService。 1.1 启动入口 AMS是由SystemServer进程启动&#xff0c;在启动过程 startBootStripService&#xff0c;会启动AMS和ATMS服务。 SystemSe…

关于学习Token、JWT、Cookie等验证授权方式的总结

目录 一、为什么Cookie无法防止CSRF攻击&#xff0c;而Token可以&#xff1f; 二、为什么无论采用Cookie-session的方式&#xff0c;还是Token&#xff08;JWT&#xff09;的方式&#xff0c;在一个浏览器里&#xff0c;同一个网站只能保证一个用户处于登录状态&#xff1f; …

阻容感的串联和并联

文章目录 电阻的串联电容的串联 电阻的串联 电容的串联 CC1C2/(C1C2) 串联后电容反而变小了&#xff0c;所以实际应用中&#xff0c;电容不串联&#xff08;我没见过电容串联使用的&#xff09; 类似于电导的分压&#xff0c; 电容一般是并联使用 电感一般串联使用

【Go】用 DBeaver、db browser 和 SqlCipher 读取 SqlCipher 数据库

本文档主要描述如何用 DBeaver、db browser 和 SqlCipher 上打开加密的 SQLite3 数据库(用 SqlCipher v3 加密) 软件版本 DBeaver&#xff1a;v24.1.0 SQLite-driver: sqlite-jdbc-3.46.0.0.jar dbbrowser-for-sqlite-cipher&#xff1a;3.12.2 SqlCipher cli(ubuntun)&am…

Honor of Kings 2024.06.13 (2)

【第一局】准确的说&#xff0c;其实对面优势更加明显&#xff0c;可惜黄忠和墨子喜欢杀人&#xff0c;而我又是不喜欢杀人的&#xff0c;打了好几次失误 【第二局】阵容本来很有优势&#xff0c;这个二呆射手跟第一局黄忠一样爱杀人&#xff0c;应该说三路的输出都爱杀人&…

Golang的GC

目录 介绍GC 概要 什么是根对象 三色标记法 什么情况下三色标记法会失效 屏障机制 “强-弱” 三色不变式 插入屏障 (强三色) 删除屏障(弱三色) Go 的混合写屏障机制 混合写屏障规则 介绍GC 概要 作用范围&#xff1a;只回收堆内存&#xff0c;不回收栈内存&#xf…

Stability AI发布新版文生图模型:依然开源

Stability AI最近发布了Stable Diffusion 3 Medium&#xff08;简称SD3 Medium&#xff09;&#xff0c;这是其最新的文生图模型&#xff0c;被官方称为“迄今为止最先进的开源模型”。SD3 Medium的性能甚至超过了Midjourney 6&#xff0c;特别是在生成手部和脸部图像方面表现出…

汇聚荣科技有限公司在拼多多评价上好不好?

汇聚荣科技有限公司在拼多多平台的评价如何&#xff0c;这是很多消费者在选择购买该公司产品时会关心的问题。通过深入分析&#xff0c;我们可以从多个维度来探讨这一问题。 一、产品质量 对于任何公司而言&#xff0c;产品的质量是其生存和发展的根本。根据用户反馈和相关评价…

Python的Pillow(图像处理库)非常详细的学习笔记

Python的Pillow库是一个非常强大的图像处理库。 安装Pillow库&#xff1a; 在终端或命令行中输入以下命令来安装Pillow&#xff1a; pip install pillow 安装后查看是否安装成功以及当前版本 pip show Pillow 升级库&#xff1a; pip install pillow --upgrade 一些基…

css入门基础

目录 1. CSS前景 2.什么是CSS 3.CSS发展史 4.CSS的3种样式格式 5.CSS 的语法 6.CSS的字体样式 7.选择器类型 8.CSS外观属性 1. CSS前景 从HTML被发明开始&#xff0c;样式就以各种形式存在。不同的浏览器结合它们各自的样式语言为用户提供页面效果的控制。最初的HTML只…

【我是产品经理_注册安全分析报告】

前言 由于网站注册入口容易被黑客攻击&#xff0c;存在如下安全问题&#xff1a; 暴力破解密码&#xff0c;造成用户信息泄露短信盗刷的安全问题&#xff0c;影响业务及导致用户投诉带来经济损失&#xff0c;尤其是后付费客户&#xff0c;风险巨大&#xff0c;造成亏损无底洞 …

JavaScript的函数(几种函数的定义和使用)

天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物。 每个人都有惰性&#xff0c;但不断学习是好好生活的根本&#xff0c;共勉&#xff01; 文章均为学习整理笔记&#xff0c;分享记录为主&#xff0c;如有错误请指正&#xff0c;共同学习进步。…

UKP3D用户定制图框的思路

为用户定制图框&#xff0c;记录以下图框制作方法&#xff0c;便于用户自已修改。 1.轴测图与平面图的图框&#xff1a; 1.1.图框在安装目录下&#xff0c;例如&#xff1a;E:\Program Files (x86)\UKSoft\UKP3d9.2\config\TemplateAndBlock\CADTemplate\ 1.2.配置文件在安装…

Qt creator day1 练习

自由发挥登录窗口的应用场景&#xff0c;实现一个登录窗口界面&#xff0c;要求&#xff1a;第行代码都有注释 #include "mywidget.h"MyWidget::MyWidget(QWidget *parent): QWidget(parent) {this->setWindowTitle("贪玩蓝月——是兄弟就来砍我 登入&#…

Google play,应用被下架,活跃用户断崖式下跌?

相信在Google paly上架应用的开发者&#xff0c;都经历过应用被下架的情况。不少开发者吐槽&#xff0c;应用被下架之后&#xff0c;前期推广积累的活跃用户也会一个星期内断崖式下跌&#xff0c;这就很难搞了&#xff0c;严重影响了收益。 &#xff08;想与众多开发者交流谷歌…

Armbian OS(基于ubuntu24) 源码编译mysql 5.7

最近弄了个S905X3的盒子刷完Armbian OS &#xff08;基于ubuntu24&#xff09;&#xff0c;开始折腾Arm64之旅。第一站就遇到了MySQL的问题&#xff0c;由于MySQL没有提供Arm64版本&#xff0c;又不想塞Docker镜像&#xff0c;因此选择源码来编译MySQL5.7。下面记录详细过程和遇…

磁盘管理 以及磁盘的分区 详细版

磁盘管理 track:磁道&#xff0c;就是磁盘上同心圆&#xff0c;从外向里&#xff0c;依次1号、2号磁道sector&#xff1a;扇区&#xff0c;将磁盘分成一个一个扇形区域&#xff0c;每个扇区大小是512字节&#xff0c;从外向里&#xff0c;依次是1号扇区、2号扇区cylinder&…

swift5 在当前控制器先dismiss后pop

如下图需要在present当前控制器时用全局变量firmwareUpgradePresentingVC先引用上一个控制器&#xff08;下面的代码亲测有效&#xff09; func dismissAndPop() {self.dismiss(animated: false) {firmwareUpgradePresentingVC.navigationController!.popViewController(animat…