Java对象复制

article/2025/8/24 9:59:04

文章目录

  • 前言
  • 何不可变类
  • 对象复制方式
    • 1.直接赋值
    • 2.浅拷贝
    • 3.深拷贝
  • 对象复制方案
    • 1.get/set
    • 2.Spring BeanUtils
    • 3.Apache BeanUtils
    • 4.BeanCopier
    • 5.Orika
    • 6.Dozer
    • 7.MapStruct
    • 8.Bean Mapping
    • 9.Bean Mapping ASM
    • 10.ModelMapper
    • 11.JMapper
    • 12.Json2Json
  • 复制方案选择


前言

在我们实际项目开发过程中,我们经常需要将不同的两个对象实例进行属性复制,从而基于源对象的属性信息进行后续操作,而不改变源对象的属性信息。比如DTO数据传输对象和数据对象DO,我们需要将DO对象进行属性复制到DTO,但是对象格式又不一样,所以我们需要编写映射代码将对象中的属性值从一种类型转换成另一种类型。

这种转换最原始的方式就是手动编写大量的get/set代码,属性少的时候还好,属性多的时候就非常繁琐了,一个合格的程序员显然不会仅仅局限于get/set。

针对这个问题,市场上诞生了很多方便的类库,用于对象拷贝。常用的有apache BeanUtils、spring BeanUtils、Dozer、Orika等拷贝工具。

何不可变类

当类的实例一经创建,其内容便不可改变,即无法修改其成员变量。

Java中有一些特殊的类是不可变类,八个基本类型的包装类和String类都属于不可变类。

不可变类的特殊性:
有两个不可变类对象,当两个对象指向同一引用时,修改某一对象的值,不会对另一个对象造成影响。

下面举例说明

  • 源码:

    public static void main(String[] args) {Integer a = 1;String aa = "1";Integer b = a;String bb = aa;System.out.println("a修改前b:"+b);System.out.println("aa修改前bb:"+bb);a = 2;aa = "2";System.out.println("a修改后b:"+b);System.out.println("aa修改后bb:"+bb);
    }
    
  • debug:
    在这里插入图片描述

  • 日志:

    a修改前b:1
    aa修改前bb:1
    a修改后b:1
    aa修改后bb:1
    

由此可见,a和aa的修改不会影响b和bb的值。

方法参数的传递:

  • 基本类型传递的是值;
  • 引用类型传递的是对象的引用。
    • 不可变类型,在方法里修改了对象的值,也不会影响到原对象(不可变性);
    • 可变类型,在方法里修改了对象的值,原对象相应的值也会变动。

对象复制方式

对象复制有三种方式:直接赋值、浅拷贝、深拷贝。

1.直接赋值

  • 基本数据类型复制的是值;
  • 引用数据类型复制的是对象的引用,原始对象及目标对象引用的是同一个对象。

2.浅拷贝

创建一个新对象,然后将当前对象的非静态字段复制到该新对象。

  • 基本数据类型复制的是值;
  • 引用数据类型复制的是对象的引用(不可变类型特殊)。

注意:String类型、Integer等基本数据类型的包装类型,因为时不可变类型,所以即使进行的是浅拷贝,原始对象的改变并不会影响目标对象。

3.深拷贝

创建一个新对象,然后将当前对象的非静态字段复制到该新对象。

  • 无论该字段是基本类型的还是引用类型,都复制独立的一份。当你修改其中一个对象的任何内容时,都不会影响另一个对象的内容。

对象复制方案

一个好用的属性复制方案,需要有哪些特性:

  1. 支持基本的属性复制;
  2. 支持不同类型的属性赋值,比如基本类型与其包装类型等;
  3. 支持不同字段名的属性赋值,当然字段名应该尽量保持一致,但是实际业务中,确实会有字段名不一致的情况;
  4. 浅拷贝/深拷贝,浅拷贝会引用同一对象,如果稍微不慎,同时改动对象,就会踩到意想不到的坑。

市场上的对象转换方案主要分类:

  • 直接编写get、set代码(硬编码);
  • 通过反射实现;
  • 编译期生成get、set代码;
  • 基于AOP、ASM、CGlib等技术实现。

12种对象转换方案归纳:

方案推荐指数性能指数原理点评
get/set★★★☆☆★★★★★手写get、set日常使用最多,性能好,只是较麻烦,需要手写。
Spring BeanUtils★★★☆☆★★★★☆基于反射日常使用较多,性能较好,推荐使用
Apache BeanUtils☆☆☆☆☆★☆☆☆☆基于反射兼容性较差,性能差,不推荐使用
BeanCopier★★★☆☆★★★★☆基于CGlib性能较好,使用也不复杂,可以使用
Orika★★☆☆☆★★★☆☆基于Javasisst字节码增强性能不太突出
Dozer★☆☆☆☆★★☆☆☆基于反射的属性映射(递归映射)性能较差,不太推荐使用
MapStruct★★★★★★★★★★编译期生成get、set性能好,结合到框架中使用方便,推荐使用
Bean Mapping★★☆☆☆★★★☆☆基于反射性能一般,不太推荐使用
Bean Mapping ASM★★★☆☆★★★★☆基于ASM字节码增强性能较好,但暂时不够灵活,可以使用
ModelMapper★★★☆☆★★★☆☆基于反射性能一般,不太推荐使用
JMapper★★★★☆★★★★★映射器方式实现性能较好,使用略微麻烦,可以使用
Json2Json☆☆☆☆☆★☆☆☆☆基于JSON序列化和反序列化野路子,性能较差,不推荐使用

分别测试这12种属性转换操作分别在一百次、一千次、一万次、十万次、一百万次时候的性能时间对比。
在这里插入图片描述

  • BeanUtils.copyProperties是大家代码里最常出现的工具类,但只要你不把它用错成Apache包下的,而是使用Spring提供的,就基本还不会对性能造成多大影响。
  • 但如果说性能更好,可替代手动get、set的,还是MapStruct更好用,因为它本身就是在编译期生成get、set代码,和我们写get、set一样。
  • 其他一些组件包主要基于AOP、ASM、CGlib等技术手段实现的,所以也会有相应的性能损耗。

1.get/set

直接手写get/set方法实现数据的复制。

这种方式也是日常使用的最多的,性能较好,就是操作起来有点麻烦。尤其是当对象属性较多的时候。

减少手写代码的方式:

  1. 通过一些快捷的操作方式,比如你可以通过 Shift+Alt 选中所有属性,Shift+Tab 归并到一列,接下来在使用 Alt 选中这一列,批量操作粘贴 userDTO.set 以及快捷键大写属性首字母,最后切换到结尾补充括号和分号,最终格式化一下就搞定了。
  2. 通过IDEA的插件,如GenerateAllSetter插件。光标移至需生成get/set方法的对象名称,alt+enter出现快捷选项,选择需要生成的选项,自动生成相应的代码。
    在这里插入图片描述

2.Spring BeanUtils

同样是基于反射的属性拷贝(Introspector机制获取到类的属性来进行赋值操作)。Spring 提供的copyProperties要比Apache好用得多,这也是大家用得比较多的一种复制方式。

Spring BeanUtils的实现方式非常简单,就是对两个对象中相同名字的属性进行简单的get/set,仅检查属性的可访问性。成员变量赋值是基于目标对象的成员列表,并且会跳过ignoreProperties的以及在源对象中不存在,不会因为两个对象之间的结构差异导致错误,但是必须保证同名的两个成员变量类型相同。

Introspector
是一个专门处理bean的工具类,用来获取Bean体系里的propertiesDescriptor、methodDescriptor利用反射获取Method信息,是反射的上层。只进行一次反射解析,通过WeakReference静态类级别缓存Method,在jvm不够时会被回收。

特点:

  • 字段名不一致,属性无法复制;
  • 类型不一致,属性无法复制。但是注意,如果类型为基本类型以及基本类型的包装类,这种可以转化;
  • 浅拷贝

依赖:

<dependency><groupId>org.springframework</groupId><artifactId>spring-beans</artifactId><version>5.2.8.RELEASE</version>
</dependency>

方法:

/*** source:源对象* target:目标对象* editable:目标对象类的Class对象(需复制的属性基于该Class,当该值为null时需复制的属性基于目标对象的Class)* ignoreProperties:需忽略的属性列表*/
BeanUtils.copyProperties(Object source, Object target)BeanUtils.copyProperties(Object source, Object target, Class<?> editable)BeanUtils.copyProperties(Object source, Object target, String... ignoreProperties)

实现:

public static void main(String[] args) {UserDTO userDTO = new UserDTO();userDTO.setId(1);userDTO.setUserName("哈哈");userDTO.setCreateTime(new Date());UserVO userVO = new UserVO();BeanUtils.copyProperties(userDTO, userVO);System.out.println(JSON.toJSONString(userVO));
}

3.Apache BeanUtils

推荐☆☆☆☆☆
性能★☆☆☆☆
手段:Introspector机制获取到类的属性来进行赋值操作
点评:兼容性交差,效率较低,不建议使用

Apache BeanUtils使用起来很方便,不过其底层源码为了追求完美,加了过多的包装,使用了很多反射,做了很多校验,做了类型的转换,甚至还会检验对象所属的类的可访问性,可谓相当复杂,过度的追求完美反而导致兼容性变差,也导致了性能较低,所以阿里巴巴开发手册上强制避免使用Apache BeanUtils。

特点:

  • 字段名不一致的属性无法被复制;
  • 类型不一致的字段,将会进行默认类型转化;
  • 浅拷贝

依赖:

<dependency><groupId>commons-beanutils</groupId><artifactId>commons-beanutils</artifactId><version>1.9.4</version>
</dependency>

方法:

/*** dest:目标对象* orig:源对象*/
BeanUtils.copyProperties(Object dest, Object orig)

实现:

public static void main(String[] args) throws InvocationTargetException, IllegalAccessException {UserDTO userDTO = new UserDTO();userDTO.setId(1);userDTO.setUserName("哈哈");userDTO.setCreateTime(new Date());UserVO userVO = new UserVO();BeanUtils.copyProperties(userVO, userDTO);System.out.println(JSON.toJSONString(userVO));
}

4.BeanCopier

Cglib BeanCopier的原理与上面两个Beanutils原理不太一样,其主要使用CGlib字节码技术动态生成一个代理类,代理类实现get和set方法。生成代理类过程存在一定开销,但是一旦生成,我们可以缓存起来重复使用,所有Cglib性能相比以上两种Beanutils性能比较好。

特点:

  • 字段名不一致,属性无法复制
  • 类型不一致,属性无法复制。如果类型为基本类型/基本类型的包装类型,这两者也无法被拷贝。但可自定义转换器实现不同类型的拷贝
  • 浅拷贝

依赖:

<dependency><groupId>cglib</groupId><artifactId>cglib</artifactId><version>3.3.0</version>
</dependency>

方法:

/*** source   源Class* target   目Class* useConverter 是否使用转换器* from 源对象* to   目标对象* converter    转换器*/
BeanCopier beanCopier = BeanCopier.create(Class source, Class target, boolean useConverter);
beanCopier.copy(Object from, Object to, Converter converter);

实现:

public static void main(String[] args) {UserDTO userDTO = new UserDTO();userDTO.setId(1);userDTO.setUserName("哈哈");userDTO.setCreateTime(new Date());UserVO userVO = new UserVO();BeanCopier beanCopier = BeanCopier.create(UserDTO.class, UserVO.class, false);beanCopier.copy(userDTO, userVO, null);System.out.println(JSON.toJSONString(userVO));
}

5.Orika

Orika也是一个跟Dozer类似的重量级属性复制工具类,也提供诸如Dozer类似的功能。但是Orika无需使用繁琐 XML配置,它自身提供一套非常简洁的 API 用法,非常容易上手。

Orika底层基于Javassist生成字段属性的映射的字节码,然后直接动态加载执行字节码文件,相比于Dozer的这种使用反射原来的工具类,速度上会快很多。Orika的整个流程其实是需要使用到Java的反射的,只是在真正拷贝的属性的时候没有使用反射。

Orika的执行流程:

  1. 先通过内省(反射)把JavaBean的属性(getset方法等)解析出来;
  2. 进而匹配目标和源的属性;
  3. 接着根据这些属性和目标/源的匹配情况基于Javasisst生成一个 GeneratedMapper的代理对象(真正的执行复制的对象)并放到缓存中;
  4. 接着就基于这个对象的 mapAtoB和mapBtoA方法对属性进行复制。

Orikade的使用需要创建两个对象MapperFactory与MapperFacade,其中MapperFactory 可以用于字段映射,配置转换器等,而MapperFacade 的作用就与Beanutils一样,用于负责对象的之间的映射。

特点:

  • 默认支持类型不一致(基本类型/包装类型)转换
  • 指定不同字段名映射关系,属性可以被成功复制
  • 深拷贝

依赖:

<dependency><groupId>ma.glasnost.orika</groupId><artifactId>orika-core</artifactId><version>1.5.4</version>
</dependency>

方法:

/*** sourceObject 源对象* destinationClass 目标Class* targetObject 目标对象*/
MapperFactory mapperFactory = new DefaultMapperFactory.Builder().build();
MapperFacade mapper = mapperFactory.getMapperFacade();
D targetObject = mapper.map(S sourceObject, Class<D> destinationClass);

实现:

public static void main(String[] args) {UserDTO userDTO = new UserDTO();userDTO.setId(1);userDTO.setUserName("哈哈");userDTO.setCreateTime(new Date());MapperFactory mapperFactory = new DefaultMapperFactory.Builder().build();MapperFacade mapper = mapperFactory.getMapperFacade();UserVO userVO = mapper.map(userDTO, UserVO.class);System.out.println(JSON.toJSONString(userVO));
}

6.Dozer

Dozer相对BeanUtils这类工具类来说,拥有许多高级功能,所以相对来说这是一个重量级工具类。其底层本质上还是使用了反射完成属性的复制(属性映射,递归的方式复制对象),所以执行速度并不是那么理想。

Dozer需要我们新建一个DozerBeanMapper,这个类作用等同与BeanUtils,负责对象之间的映射,属性复制。
生成DozerBeanMapper实例需要加载配置文件,随意生成代价比较高。因此在我们应用程序中,应该尽量使用单例模式,重复使用DozerBeanMapper。

另外,强大的配置功能,我们可以通过XML、API或注解的方式配置源对象和目标对象属性映射关系和类型转换。

特点:

  • 类型不一致的字段,属性被复制
  • 通过配置字段名的映射关系,不一样字段的属性也被复制
  • 深拷贝

依赖:

<dependency><groupId>net.sf.dozer</groupId><artifactId>dozer</artifactId><version>5.4.0</version>
</dependency>

方法:

/*** source   源对象* destinationClass 目标Class* target   目标对象*/
DozerBeanMapper mapper = new DozerBeanMapper();
T target = mapper.map(Object source, Class<T> destinationClass);

实现:

public static void main(String[] args) {UserDTO userDTO = new UserDTO();userDTO.setId(1);userDTO.setUserName("哈哈");userDTO.setCreateTime(new Date());DozerBeanMapper mapper = new DozerBeanMapper();UserVO userVO = mapper.map(userDTO, UserVO.class);System.out.println(JSON.toJSONString(userVO));
}

7.MapStruct

MapStruct运行速度与硬编码差不多,这是因为他在编译期间就生成了Java Bean属性复制的代码(属性对应的get、set),运行期间就无需使用反射或者字节码技术,所以确保了高性能。

与硬编码方式相比,不管使用反射,还是使用字节码技术,这些都需要在代码运行期间动态执行所以它们的执行速度都会比硬编码慢很多。

特点:

  • 名不一致,默认不支持复制
  • 类型不一致,默认不支持复制(但支持基本类型与包装类型、基本类型的包装类型与String的自动转换)
  • 可通注解配置实现名称不一致、类型不一致的复制
  • 深拷贝

依赖:

<dependency><groupId>org.mapstruct</groupId><artifactId>mapstruct</artifactId><version>1.3.1.Final</version>
</dependency>

插件:
由于MapStruct需要在编译器期间生成代码,所以我们需要maven-compiler-plugin插件中配置。

<plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.8.1</version><configuration><source>1.8</source> <!-- depending on your project --><target>1.8</target> <!-- depending on your project --><annotationProcessorPaths><path><groupId>org.mapstruct</groupId><artifactId>mapstruct-processor</artifactId><version>1.3.1.Final</version></path><path><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.12</version></path><!-- other annotation processors --></annotationProcessorPaths></configuration>
</plugin>

方法:

@Mapper
public interface UserMapper {UserMapper INSTANCE = Mappers.getMapper(UserMapper.class);@Mappings({@Mapping(source = "id", target = "id"),@Mapping(source = "createTime", target = "createTime")})UserVO dtoToVo(UserDTO userDTO);
}

编译:
MapStruct没有想象中的神奇,其实就是在编译期生成了接口的实现类,里面的转换方法实现了转换功能。相当于帮我们手写get/set设值,所以它的性能会很好。

public class UserMapperImpl implements UserMapper {public UserMapperImpl() {}public UserVO dtoToVo(UserDTO userDTO) {if (userDTO == null) {return null;} else {UserVO userVO = new UserVO();userVO.setIdd(userDTO.getId());userVO.setCreateTime(userDTO.getCreateTime());userVO.setUserName(userDTO.getUserName());return userVO;}}
}

实现:

public static void main(String[] args) {UserDTO userDTO = new UserDTO();userDTO.setId(1);userDTO.setUserName("哈哈");userDTO.setCreateTime(new Date());UserVO userVO = UserMapper.INSTANCE.dtoToVo(userDTO);System.out.println(JSON.toJSONString(userVO));
}

可能出现的问题:

  • 如果我们对象使用 Lombok 的话,使用 @Mapping指定不同字段名,编译期间可能会抛出如下的错误
    在这里插入图片描述
    原因主要是因为Lombok也需要编译期间自动生成代码,这就可能导致两者冲突,当MapStruct生成代码时,还不存在Lombok生成的代码。解决办法可以在 maven-compiler-plugin插件配置中加入Lombok。
    在这里插入图片描述

8.Bean Mapping

基于反射的属性拷贝。0.0.2版本引入了@BeanMapping,通过@BeanMapping注解可实现灵活的复制方式。

注解定义在 bean-mapping-api 模块中,bean-mapping-core 会默认引入此模块。

特点:

  • 名不一致,不支持复制
  • 类型不一致,不支持复制(但支持基本类型转为包装类型,反过来不支持)
  • 通过@BeanMapping注解来灵活控制复制,支持名称不一致的复制、类型不一致的复制和控制是否复制。
  • 浅拷贝

依赖:

<dependency><groupId>com.github.houbb</groupId><artifactId>bean-mapping-core</artifactId><version>0.2.5</version>
</dependency>

注解:

@Inherited
@Documented
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface BeanMapping {/*** 字段别名* 如果不填,则默认使用字段的名称* 会将source的属性值赋值给target和当前name属性一致的属性* @return 字段别名*/String name() default "";/*** 生效条件(默认为生效)* 1.当放在source字段上时,表示是否将值赋给target字段* 2.当放在target字段上时,表示是否接受赋值。* 3.source+target只有同时生效时,才会发生赋值。* @return 具体的生效实现*/Class<? extends ICondition> condition() default ICondition.class;/*** 类型转换(默认不进行转换)* 当source的值转换后可以设置给target,才会将source转换后的值赋值给target对应属性,其他情况不会对值产生影响。* @return 具体的转换实现*/Class<? extends IConvert> convert() default IConvert.class;}

方法:

/*** source   源对象* target   目标对象*/
BeanUtil.copyProperties(Object source, Object target)

实现:

public static void main(String[] args) {UserDTO userDTO = new UserDTO();userDTO.setId(1);userDTO.setUserName("哈哈");userDTO.setCreateTime(new Date());UserVO userVO = new UserVO();BeanUtil.copyProperties(userDTO, userVO);System.out.println(JSON.toJSONString(userVO));
}

9.Bean Mapping ASM

推荐★★★☆☆
性能★★★★☆
手段:基于ASM字节码框架实现
点评:与普通的Bean Mapping 相比,性能有所提升,可以使用。

Bean Mapping基于ASM的字节码增强技术的复制方式要比Bean Mapping普通的方式新能要提升不少,但有个缺点就是暂不支持@BeanMapping注解等更加丰富的功能。

特点:

  • 名不一致,不支持复制
  • 类型不一致,不支持复制(但支持基本类型转为包装类型,反过来不支持)
  • 效率比传统的Bean Mapping要好些,但暂不支持@BeanMapping注解的灵活复制
  • 浅拷贝

依赖:

<dependency><groupId>com.github.houbb</groupId><artifactId>bean-mapping-asm</artifactId><version>0.2.5</version>
</dependency>

方法:

/*** source   源对象* target   目标对象*/
AsmBeanUtil.copyProperties(Object source, Object target)

实现:

public static void main(String[] args) {UserDTO userDTO = new UserDTO();userDTO.setId(1);userDTO.setUserName("哈哈");userDTO.setCreateTime(new Date());UserVO userVO = new UserVO();AsmBeanUtil.copyProperties(userDTO, userVO);System.out.println(JSON.toJSONString(userVO));
}

10.ModelMapper

ModelMapper是利用反射的原理实现的。转换对象数量较少时性能不错,如果同时大批量转换对象,性能有所下降。

依赖:

<dependency><groupId>org.modelmapper</groupId><artifactId>modelmapper</artifactId><version>2.3.0</version>
</dependency>

实现:
简单使用

public static void main(String[] args) {UserDTO userDTO = new UserDTO();userDTO.setId(1);userDTO.setUserName("哈哈");userDTO.setCreateTime(new Date());UserVO userVO = new UserVO();ModelMapper modelMapper = new ModelMapper();modelMapper.map(userDTO, userVO);System.out.println(JSON.toJSONString(userVO));
}

ModelMapper的具体使用可参考文章:实体映射类库(modelmapper和MapStruct)

11.JMapper

JMapper通过映射器方式实现。

依赖:

<dependency><groupId>com.googlecode.jmapper-framework</groupId><artifactId>jmapper-core</artifactId><version>1.6.0</version>
</dependency>

实现:

public static void main(String[] args) {UserDTO userDTO = new UserDTO();userDTO.setId(1);userDTO.setUserName("哈哈");userDTO.setCreateTime(new Date());JMapper<UserVO, UserDTO> jMapper = new JMapper<>(UserVO.class, UserDTO.class, new JMapperAPI().add(JMapperAPI.mappedClass(UserVO.class).add(JMapperAPI.attribute("id").value("id")).add(JMapperAPI.attribute("userName").value("userName")).add(JMapperAPI.attribute("createTime").value("createTime"))));UserVO userVO = jMapper.getDestination(userDTO);System.out.println(JSON.toJSONString(userVO));
}

12.Json2Json

这种通过JSON序列化和反序列化的方式,把源对象转为JSON串,再把JSON串转为目标对象,虽然也能达到复制的目的,但不推荐使用。

实现:

public static void main(String[] args) {UserDTO userDTO = new UserDTO();userDTO.setId(1);userDTO.setUserName("哈哈");userDTO.setCreateTime(new Date());UserVO userVO = JSON.parseObject(JSON.toJSONString(userDTO), UserVO.class);System.out.println(JSON.toJSONString(userVO));
}

复制方案选择

  1. 手写get/set肯定是效率最高的;
  2. 不要使用Apache Beanutils,因为效率低,阿里巴巴规范都直接禁止使用;
  3. 一般情况使用Spring Beanutils就可以了,效率OK,且本来就是Spring中的东西,不用依赖其它包。


参考文章:对比 12 种 Bean 自动映射工具


http://chatgpt.dhexx.cn/article/D7pUiQMU.shtml

相关文章

Java 复制Excel工作表

本文归纳了关于Java如何复制Excel工作表的方法&#xff0c;按不同复制需求&#xff0c;可分为&#xff1a; 1. 复制工作表 1.1 在同一个工作簿内复制工作表 1.2 在不同工作簿间复制工作表 2. 复制指定单元格数据 对于复制方法copy()&#xff0c;这里简单整理了一个表格&am…

个人如何接入微信支付和支付宝等支付接口,免签约

企业的资质足够高了才能够得到微信或者支付宝官方的支付接口&#xff08;而且这个官方接口收费的最低费率在0.38%以上&#xff09;那么个人如何做&#xff1f; 个人开发者或者小微企业团队如何使用在线收款支付功能呢&#xff1f; 第四方支付&#xff0c;市面上各种收款工具要…

微信支付接口开发详流程

微信支付 文章目录 1.支付接口分析2. 开发创建订单接口3. 开发根据订单id查询订单详情接口4. 开发生成二维码接口5. 开发查询订单支付状态接口 1.支付接口分析 引入依赖 <dependencies><dependency><groupId>com.github.wxpay</groupId><artifact…

微信支付API v3接口使用应用篇

目录 前言版本应用基础配置1.申请商户API证书2.设置接口密钥3.下载平台证书 接口实测微信支付API官方客户端1.客户端2.支付调起参数签名3.回调通知 参考资料 前言 最近新项目中有涉及到微信支付相关接口业务的交互&#xff0c;毕竟原先开发接触过支付这块&#xff0c;轻车熟路…

Java对接微信、支付宝、银联第三方支付

一、微信支付 1、业务平台介绍&#xff1a; &#xff08;1&#xff09;微信公众平台 微信公众平台是微信公众账号申请入口和管理后台。商户可以在公众平台提交基本资料、业务资料、财务资料申请开通微信支付功能。 &#xff08;2&#xff09; 微信开放平台 微信开放平台是商…

php微信支付宝第三方接口开发平台,帝国CMS第三方个人支付接口微信支付宝免签约即时到账api_帝国网站管理系统插件...

帝国CMS网站管理系统是一个高效的网站解决方案,本文将给出开发好的帝国CMS第三方个人免签约支付接口插件(支持支付宝/微信扫码即时到账支付),可用于帝国系统收款使用,供有需求的用户参考或快速接入。本代码无加密完全开源,欢迎参考/使用。 概述 环境 本接口插件基于帝国CMS…

第三方支付接口之微信扫码支付

此篇文章是为了记录学习如何编写第三方支付接口&#xff0c;熟悉这个流程。使用的是威富通第三方支付平台https://open.swiftpass.cn/ 对接的是微信扫码和公总号支付 基本成员&#xff1a;用户&#xff0c;商户&#xff0c;第三方支付方 扫码支付业务流程&#xff1a; 接口…

第三方支付接口有哪些?怎么申请?

第三方支付接口有哪些&#xff1f; 目前中国国内的第三方支付产品主要有支付宝&#xff08;阿里巴巴旗下&#xff09;、微信&#xff08;腾讯公司&#xff09;、QQ钱包&#xff08;财付通公司&#xff09;、云闪付&#xff08;中国银联旗下&#xff09;等。其中最用户数量最大…

调用微信和支付宝第三方接口方法总结

最近项目上用到了调用微信和支付宝的第三方支付接口&#xff0c;因为以前没用过&#xff0c;所以这次用到了之后总结一下分享给大家&#xff0c;这里介绍两种支付方式&#xff0c;即app支付和扫码支付方式。 一、app支付&#xff08;这里只介绍java端调用支付&#xff0c;安卓…

第三方支付:微信公众号接入支付宝支付开发

第三方支付&#xff1a;微信公众号接入支付宝支付开发 引言 这篇文章使用一些简单的代码例子来解释微信接入支付宝支付功能的操作步骤&#xff0c;即使新手也可以轻松参透的。 第三方支付是指具备一定实力和信誉保障的独立机构&#xff0c;采用与各大银行签约的方式&#xff…

第三方支付接入(微信,支付宝)

写在最前面 以下内容关于微信相关的&#xff0c;除了binarywang&#xff0c;个人认为都不要再用了。相比较王大哥的封装&#xff0c;我自己写的真是连弟弟都不如。 支付宝相关的&#xff0c;好久不用了&#xff0c;不知道还能不能工作。建议找创建时间比较新的文章来看。 关…

微信第三方支付接口java调用详细文档

1.显示支付二维码 支付流程 首先用户选好商品后 跳到结算页面 在点击支付提交时应先将表单的数据保存到数据库(一般都会有订单表一二级) 经过后台保存数据后再转发到前台(二维码是后台调用微信生成的) 看到扫码页面 当用户扫码成功后 更改订单状态为已支付(一般情况 根据业务…

微信支付接口配置教程(下)

微信第三方平台微信支付接口配置教程&#xff08;下&#xff09; 上传微信支付证书 登录后台系统&#xff0c;在后台微信商城里&#xff0c;点击微信支付证书。这一步我们需要上传对应的微信支付证书&#xff0c;这个证书就是文章《微信第三方平台微信支付接口配置教程&#…

聊一聊对“事务”的理解

什么是事务 事务即英文Transaction&#xff0c;在软件开发过程中&#xff0c;难免需要考虑处理事务。从微观层面看亦或者从成员最早了解到这个词汇看&#xff0c;事务通常指多条写入数据库的语句需要并发成功执行&#xff0c;从宏观层面看得话则是客户端发出的并发请求需要一致…

聊一聊wifi6

引言 8.11&#xff0c;小米十周年&#xff0c;雷军即将召开发布会&#xff0c;相信又是are you ok 放大招的时候了。作为小米各种产品的使用者&#xff08;包括但不限于手机&#xff0c;路由器&#xff0c;音响&#xff0c;手环&#xff0c;中性笔… &#xff09;&#xff0c;…

聊一聊我对测试开发的看法

前言 在一线大厂&#xff0c;没有测试这个岗位&#xff0c;只有测开这个岗位 即使是做业务测试&#xff0c;那么你的title也是测开 所以想聊一聊测开的看法 但不代表这是正确的看法&#xff0c;仅供参考 还没来阿里之前&#xff0c;我对测开的看法 一直以为专职做自动化测…

聊一聊,我对DDD的关键理解

作者&#xff1a;闵大为 阿里业务平台解决方案团队 当我们在学习DDD的过程中&#xff0c;感觉学而不得的时候&#xff0c;可能会问&#xff1a;我们还要学么&#xff1f;这的确引人深思。本文基于工作经验&#xff0c;尝试谈谈对DDD的一些理解。 一、序 《阿甘正传》中&#xf…

聊一聊Kotlin的泛型

Kotlin的泛型 简介 与java一样&#xff0c;kotlin也支持泛型&#xff0c;用法和java泛型差别不大&#xff0c;kotlin特色是型变支持。 基本用法&#xff1a; 定义类&#xff1a; 跟java相同&#xff0c;定义在类后面的尖括号&#xff1a; open class Basket<T>{}定…

聊一聊学习方法

聊一聊学习方法 为什么学习没效果&#xff1f;你只是看起来很努力自知与不自知&#xff0c;真的不是一字之差什么时候真的能出效果&#xff1f;学习方法一&#xff08;拍照式记忆&#xff09;学习方法二&#xff08;殊途同归&#xff09;学习方法三&#xff08;精细化管理&…

聊一聊ThreadLocal内存泄漏的问题

回答任何一个问题的时候应该要遵循&#xff1a;明确题意-->深入浅出-->举例说明-->总结&#xff0c;这四个步骤很重要&#xff0c;可以让你沉着冷静&#xff0c;思路清晰&#xff0c;避免尴尬。 01 — 明确题意 明确题意的意思就是先明确一下面试官的题目&#xff0…