Hybris OCC只读购物车控制器下,如何修改DTO到Data对象的默认映射?
我完全懂你的困扰——SAP Commerce OCC的核心控制器是只读的,没法直接修改ADDRESS_MAPPING常量,但又得让新增的RegionWsDTO属性顺利映射到AddressData。下面是几个可行的方案,按推荐程度排序:
方案1:扩展DataMapper映射配置(最优雅的方式)
Commerce的Webservices DataMapper支持通过自定义配置扩展或覆盖默认属性组,完全不需要修改原控制器:
第一步:创建自定义映射配置类
在你的自定义扩展里新建一个配置类,注册新增属性的映射规则,把它们加入到原有的ADDRESS_MAPPING映射组中:@Configuration public class CustomAddressMappingConfig { @Autowired private DataMapper dataMapper; @PostConstruct public void extendAddressMapping() { // 获取原ADDRESS_MAPPING对应的映射定义 MappingDefinition addressMapping = dataMapper.getMappingDefinition(AddressWsDTO.class, AddressData.class, "ADDRESS_MAPPING"); // 添加新增的Region属性(这里假设你新增的属性名是region1、region2、region3) // 如果是嵌套的RegionWsDTO对象,直接映射整个对象即可 addressMapping.addFieldMapping("region1", "region1"); addressMapping.addFieldMapping("region2", "region2"); addressMapping.addFieldMapping("region3", "region3"); // 若需要映射Region内部的字段(比如isocode),可以明确指定 // addressMapping.addFieldMapping("region1.isocode", "region1.isocode"); // 重新注册更新后的映射定义 dataMapper.registerMappingDefinition(addressMapping); } }注意属性名要和你在
AddressWsDTO、AddressData、AddressModel中新增的字段完全一致。第二步:加载自定义配置
在你的扩展spring.xml中扫描这个配置类,确保Spring能加载到它。
这样原控制器里的getDataMapper().map(address, AddressData.class, ADDRESS_MAPPING)就会自动包含你新增的属性映射了。
方案2:重写控制器方法(灵活但需注意优先级)
如果方案1不适用,你可以创建自定义控制器继承原CartsController,重写目标方法并使用自定义映射常量:
第一步:创建自定义控制器
确保控制器URL和原控制器一致,并且通过配置让Spring优先加载你的控制器:@Controller @RequestMapping(value = "/{baseSiteId}/users/{userId}/carts") // 用@Order注解设置更高优先级,保证Spring先加载这个控制器 @Order(Ordered.HIGHEST_PRECEDENCE) public class CustomCartsController extends CartsController { // 定义包含新增属性的自定义映射常量 private static final String CUSTOM_ADDRESS_MAPPING = "firstName,lastName,titleCode,phone,line1,line2,town,postalCode,country(isocode),region(isocode),defaultAddress,region1(isocode),region2(isocode),region3(isocode)"; @Override @Secured({ "ROLE_CUSTOMERGROUP", "ROLE_CUSTOMERMANAGERGROUP", "ROLE_GUEST", "ROLE_TRUSTED_CLIENT" }) @RequestMapping(value = "/{cartId}/addresses/delivery", method = RequestMethod.POST, consumes = { MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE }) @ResponseStatus(HttpStatus.CREATED) @ResponseBody public AddressWsDTO createCartDeliveryAddress(@RequestBody final AddressWsDTO address, @RequestParam(defaultValue = DEFAULT_FIELD_SET) final String fields) { LOG.debug("Custom createCartDeliveryAddress with extended fields"); validate(address, OBJECT_NAME_ADDRESS, getAddressDTOValidator()); // 使用自定义映射常量完成转换 AddressData addressData = getDataMapper().map(address, AddressData.class, CUSTOM_ADDRESS_MAPPING); addressData = createAddressInternal(addressData); setCartDeliveryAddressInternal(addressData.getId()); return getDataMapper().map(addressData, AddressWsDTO.class, fields); } }第二步:配置控制器加载
在你的扩展web-spring.xml中注册这个控制器,确保它的加载顺序早于原控制器。
方案3:使用Dozer自定义映射(适配用Dozer的Commerce版本)
如果你的Commerce版本用Dozer作为映射框架,可以通过自定义Dozer配置文件实现属性映射:
第一步:创建Dozer映射文件
在你的扩展resources目录下新建dozer-bean-mappings.xml,添加新增属性的双向映射:<?xml version="1.0" encoding="UTF-8"?> <mappings xmlns="http://dozer.sourceforge.net" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://dozer.sourceforge.net http://dozer.sourceforge.net/schema/beanmapping.xsd"> <mapping type="bi-directional"> <class-a>de.hybris.platform.webservicescommons.dto.address.AddressWsDTO</class-a> <class-b>de.hybris.platform.commercefacades.address.data.AddressData</class-b> <!-- 映射新增的Region属性 --> <field> <a>region1</a> <b>region1</b> </field> <field> <a>region2</a> <b>region2</b> </field> <field> <a>region3</a> <b>region3</b> </field> </mapping> </mappings>第二步:注册Dozer配置
在你的扩展spring.xml中配置加载这个自定义映射文件:<bean id="customDozerMapper" class="org.dozer.spring.DozerBeanMapperFactoryBean"> <property name="mappingFiles"> <list> <value>classpath:dozer-bean-mappings.xml</value> <!-- 继承基础Dozer映射 --> <ref bean="baseDozerMappings"/> </list> </property> </bean>
这样Dozer在映射时会自动处理新增属性,不受原ADDRESS_MAPPING常量的限制。
内容的提问来源于stack exchange,提问作者Cesar Miguel

