Quarkus中是否有等价于Spring BeanUtils.copyProperties的属性复制方法?
在Quarkus中替代Spring BeanUtils.copyProperties的方案
你在Spring里常用的BeanUtils.copyProperties属性复制功能,在Quarkus里可以通过以下几种方案实现,避免逐个编写setter方法,同时支持忽略指定属性、跳过null值等需求:
方案1:使用Apache Commons BeanUtils/PropertyUtils
这是通用的Java Bean属性复制工具,Quarkus中可以直接引入依赖使用:
步骤1:添加依赖(Maven)
<dependency> <groupId>commons-beanutils</groupId> <artifactId>commons-beanutils</artifactId> <version>1.9.4</version> </dependency>
步骤2:在Update方法中使用
可以配置忽略指定属性,同时跳过null值:
import org.apache.commons.beanutils.BeanUtilsBean; import org.apache.commons.beanutils.IntrospectionContext; // ... @PUT @Path("/{id}") @Transactional public MyEntity update(@PathParam("id") Long id, MyEntity inputBean) { MyEntity entity = myEntityRepository.findById(id); if(null == entity) { throw new NotFoundException(); } // 配置BeanUtils:忽略id属性,不复制null值 BeanUtilsBean beanUtils = new BeanUtilsBean(); // 跳过null值 beanUtils.getConvertUtils().register(false, false, 0); // 添加忽略属性 beanUtils.getPropertyUtils().addBeanIntrospector((IntrospectionContext context) -> { context.removeProperty("id"); // 可添加更多忽略属性,比如"createdAt"、"updatedAt"等 }); // 执行属性复制 try { beanUtils.copyProperties(entity, inputBean); } catch (Exception e) { // 异常处理,比如日志打印 e.printStackTrace(); } persistAndFlush(entity); return entity; }
方案2:MapStruct(推荐,编译期安全)
MapStruct是编译期生成映射代码的工具,类型安全、性能优异,非常适合复杂实体的属性映射,支持灵活配置忽略属性和null值处理:
步骤1:添加依赖(Maven)
<dependency> <groupId>org.mapstruct</groupId> <artifactId>mapstruct</artifactId> <version>1.5.5.Final</version> </dependency> <dependency> <groupId>org.mapstruct</groupId> <artifactId>mapstruct-processor</artifactId> <version>1.5.5.Final</version> <scope>provided</scope> </dependency>
步骤2:创建Mapper接口
import org.mapstruct.Mapper; import org.mapstruct.Mapping; import org.mapstruct.MappingTarget; import org.mapstruct.NullValuePropertyMappingStrategy; @Mapper(componentModel = "cdi", nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE) public interface MyEntityMapper { // 忽略id属性,并且跳过输入中的null值(不覆盖实体已有非null值) @Mapping(target = "id", ignore = true) void updateEntityFromInput(MyEntity inputBean, @MappingTarget MyEntity entity); }
步骤3:在Update方法中注入使用
import jakarta.inject.Inject; // ... @Inject MyEntityMapper myEntityMapper; @PUT @Path("/{id}") @Transactional public MyEntity update(@PathParam("id") Long id, MyEntity inputBean) { MyEntity entity = myEntityRepository.findById(id); if(null == entity) { throw new NotFoundException(); } // 调用MapStruct生成的映射方法 myEntityMapper.updateEntityFromInput(inputBean, entity); persistAndFlush(entity); return entity; }
方案3:Quarkus Panache原生更新(简单场景)
如果你的更新字段较少,可以直接使用Panache的update方法执行JPQL批量更新,无需先查询实体:
@PUT @Path("/{id}") @Transactional public MyEntity update(@PathParam("id") Long id, MyEntity inputBean) { // 直接执行更新语句 int updatedCount = MyEntity.update( "attribute1 = ?1, attribute2 = ?2 where id = ?3", inputBean.getAttribute1(), inputBean.getAttribute2(), id ); if(updatedCount == 0) { throw new NotFoundException(); } return MyEntity.findById(id); }
方案4:自定义反射工具类(无额外依赖)
如果不想引入第三方依赖,可以自己实现一个轻量的属性复制工具,支持忽略指定属性和跳过null值:
import java.lang.reflect.Field; public class BeanCopyUtil { public static void copyProperties(Object source, Object target, String... ignoreProperties) { if (source == null || target == null) { return; } Class<?> sourceClass = source.getClass(); Class<?> targetClass = target.getClass(); for (Field sourceField : sourceClass.getDeclaredFields()) { sourceField.setAccessible(true); // 检查是否需要忽略当前属性 boolean isIgnored = false; for (String ignoreProp : ignoreProperties) { if (sourceField.getName().equals(ignoreProp)) { isIgnored = true; break; } } if (isIgnored) { continue; } try { Object value = sourceField.get(source); // 跳过null值,避免覆盖实体非null属性 if (value == null) { continue; } Field targetField = targetClass.getDeclaredField(sourceField.getName()); targetField.setAccessible(true); targetField.set(target, value); } catch (NoSuchFieldException | IllegalAccessException e) { // 异常处理,比如记录日志 e.printStackTrace(); } } } }
使用方式
@PUT @Path("/{id}") @Transactional public MyEntity update(@PathParam("id") Long id, MyEntity inputBean) { MyEntity entity = myEntityRepository.findById(id); if(null == entity) { throw new NotFoundException(); } // 复制属性,忽略id BeanCopyUtil.copyProperties(inputBean, entity, "id"); persistAndFlush(entity); return entity; }
内容的提问来源于stack exchange,提问作者develox
相关产品推荐
相关产品推荐

