在 hybris 电商平台中,为注册页面添加自定义属性是常见的业务需求,例如添加一个用于收集用户 pan 号码的字段。然而,这个过程不仅仅是修改前端页面那么简单,它涉及到数据模型的扩展、数据传输的正确配置以及业务逻辑层的处理。如果处理不当,可能会遇到 modelsavingexception: missing values for [attributename] 这类错误,或者即使没有报错,自定义属性的值也无法被正确存储。本文将提供一个端到端的解决方案,帮助您正确地在 hybris 注册流程中集成并持久化自定义属性。
首先,您需要在 Hybris 的数据模型中定义新的属性。这通常在您的核心扩展(例如 mystorefrontcore)的 resources/mystorefrontcore-items.xml 文件中完成。以添加 pan 属性到 CustomerModel 为例:
PAN Card Number
说明:
完成 items.xml 修改后,需要执行 ant all 或 ant clean all 然后启动 Hybris 服务器,进行 update running system 或 initialize,以使新的数据模型生效。
为了将前端页面上的输入值传输到后端,我们需要在表单对象和数据传输对象中添加对应的字段。
RegisterForm 是 Spring MVC 控制器用来绑定前端表单数据的对象。您需要在您的前端扩展(例如 mystorefront)中找到或创建 RegisterForm 类,并添加 pan 字段:
// mystorefront/web/src/de/hybris/platform/mystorefront/forms/RegisterForm.java
package de.hybris.platform.mystorefront.forms;
import javax.validation.constraints.NotEmpty; // 示例:添加校验注解
public class RegisterForm {
// ... 现有字段
@NotEmpty(message = "{register.pan.invalid}") // 示例:添加非空校验
private String pan;
public String getPan() {
return pan;
}
public void setPan(String pan) {
this.pan = pan;
}
// ... 其他字段的getter和setter
}RegisterData 是在业务逻辑层(Facade 层)之间传递数据的对象。它通常位于您的核心或 Facade 扩展中(例如 mystorefrontcore 或 acceleratorfacades)。您需要为 RegisterData 添加 pan 字段:
// mystorefront/core/src/de/hybris/platform/mystorefront/data/RegisterData.java (或 acceleratorfacades/customer/data/RegisterData.java)
package de.hybris.platform.mystorefront.data;
public class RegisterData {
// ... 现有字段
private String pan;
public String getPan() {
return pan;
}
public void setPan(String pan) {
this.pan = pan;
}
// ... 其他字段的getter和setter
}控制器是连接前端和后端业务逻辑的桥梁。您需要修改或扩展 RegistrationPageController(通常是 de.hybris.platform.acceleratorstorefronts.controllers.pages.RegistrationPageController)的 doRegister 方法,以确保从 RegisterForm 中获取 pan 值并将其传递给 RegisterData。
示例:
// mystorefront/web/src/de/hybris/platform/mystorefront/controllers/pages/MyRegistrationPageController.java
package de.hybris.platform.mystorefront.controllers.pages;
import de.hybris.platform.acceleratorstorefronts.controllers.pages.RegistrationPageController;
import de.hybris.platform.cms2.exceptions.CMSItemNotFoundException;
import de.hybris.platform.acceleratorfacades.customer.data.RegisterData;
import de.hybris.platform.mystorefront.forms.RegisterForm; // 引入您的自定义RegisterForm
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import javax.annotation.Resource;
import javax.validation.Valid;
@Controller
@RequestMapping(value = "/register")
public class MyRegistrationPageController extends RegistrationPageController {
// 假设您已经正确配置了customerFacade的bean
// @Resource(name = "customerFacade")
// private CustomerFacade customerFacade; // 实际项目中,通常通过父类或Spring注入
@RequestMapping(value = "/register", method = RequestMethod.POST)
public String doRegister(@Valid @ModelAttribute("registerForm") final RegisterForm form,
final BindingResult bindingResult, final Model model,
final RedirectAttributes redirectModel) throws CMSItemNotFoundException {
// ... 现有验证逻辑和错误处理
if (bindingResult.hasErrors()) {
// 如果有错误,返回注册页面并显示错误信息
return getViewForPage(model);
}
// 创建 RegisterData 实例并从 RegisterForm 填充数据
final RegisterData registerData = new RegisterData();
// 填充现有字段
registerData.setFirstName(form.getFirstName());
registerData.setLastName(form.getLastName());
registerData.setUid(form.getEmail()); // 通常UID是邮箱
registerData.setPassword(form.getPassword());
registerData.setTitleCode(form.getTitleCode());
// ... 填充其他现有字段
// 将自定义的 pan 字段从 RegisterForm 复制到 RegisterData
registerData.setPan(form.getPan()); // <-- 关键步骤
try {
// 调用父类的customerFacade或您自定义的customerFacade进行注册
getCustomerFacade().register(registerData); // 假设通过getter获取customerFacade
// ... 注册成功后的逻辑,例如登录用户,重定向到主页
return REDIRECT_TO_HOMEPAGE;
} catch (final Exception e) { // 捕获可能发生的异常,例如DuplicateUidException
// ... 错误处理逻辑
return getViewForPage(model);
}
}
// ... 其他方法
}注意事项:
最后,在业务逻辑层,您需要确保 pan 字段的值从 RegisterData 传递到 CustomerModel 并最终保存到数据库。这通常发生在 CustomerFacade 的 register 方法中,该方法会调用 CustomerService 来处理实际的业务逻辑和数据持久化。
您需要扩展 DefaultCustomerFacade(通常是 de.hybris.platform.acceleratorfacades.customer.impl.DefaultCustomerFacade)并重写 register 方法:
// mystorefront/facades/src/de/hybris/platform/mystorefront/facades/customer/impl/MyDefaultCustomerFacade.java package de.hybris.platform.mystorefront.facades.customer.impl; import de.hybris.platform.acceleratorfacades.customer.impl.DefaultCustomerFacade; import de.hybris.platform.acceleratorfacades.customer.data.RegisterData; import de.hybris.platform.core.model.user.CustomerModel; import de.hybris.platform.servicelayer.exceptions.DuplicateUidException; import de.hybris.platform.servicelayer.model.ModelService; import de.hybris.platform.customerreview.CustomerReviewService; // 假设需要注入 import javax.annotation.Resource; public class MyDefaultCustomerFacade extends DefaultCustomerFacade { @Resource(name = "modelService") private ModelService modelService; // 您可能还需要注入 customerService,如果您的register方法依赖它 // @Resource(name = "customerService") // private CustomerService customerService; @Override public void register(final RegisterData registerData) throws DuplicateUidException { // 调用父类的register方法,或者复制其逻辑 // 如果父类register方法已经处理了CustomerModel的创建和大部分字段的填充, // 您可以尝试在调用父类方法后,再设置pan字段。 // 但更稳妥的做法是,在创建CustomerModel后,手动设置所有字段。 final CustomerModel customerModel = getModelService().create(CustomerModel.class); // 填充现有字段 customerModel.setUid(registerData.getUid()); customerModel.setName(registerData.getFirstName() + " " + registerData.getLastName()); customerModel.setLoginDisabled(false); customerModel.setCustomer(true); // ... 填充其他现有字段 // 设置自定义的 pan 字段 customerModel.setPan(registerData.getPan()); // <-- 关键步骤 // 保存 CustomerModel。如果customerService有register方法,通常会调用它。 // 例如:getCustomerService().register(customerModel, registerData.getPassword()); // 如果没有,直接使用modelService保存 getModelService().save(customerModel); // ... 其他注册后逻辑,如发送邮件等 } }
注意事项:
最后,确保您的注册页面(通常是 registrationPage.jsp 或相关片段)包含一个用于输入 pan 字段的表单元素,并且其 name 属性与 RegisterForm 中的字段名一致。
<%-- 示例:在 registrationPage.jsp 或相关片段中 --%>
说明:
通过以上步骤,您已经完整地实现了在 Hybris 注册页面添加自定义属性并确保其正确存储的流程: