【问题标题】:what's the right way to override Controller Methods behaviour in Roo 2 (RC1)?在 Room 2 (RC1) 中覆盖控制器方法行为的正确方法是什么?
【发布时间】:2017-04-06 13:54:36
【问题描述】:

我的带有 roo 生成 CRUD 的项目工作正常,但现在我需要更改一些实体的保存方式(例如,我有一个“用户”属性,我想在用户登录时动态设置)

目前我只是将 save() 方法从方面移动到 .java 并根据需要对其进行修改。到目前为止它运行良好,但 roo 控制台似乎不喜欢它,因为一旦我更改方法返回类型或其他内容,它就会在方面重新创建方法。

我不需要对此示例的具体答案,而是想知道这是否是修改/覆盖 roo 提供的实体的开箱即用创建/显示功能的最佳方法.


编辑:添加示例

我的一个实体是 "Servicio",它有一些 "ServiciosCollectionThymeleafController_Roo_Thymeleaf.aj" 和一个 "ServiciosCollectionThymeleafController.create" 方法。我继续将所有 .aj 推入 "ServiciosCollectionThymeleafController.java"

然后我在 create 方法中做了一些小改动并保存了它。它有效,但是当我打开 roo 控制台时,控制台再次生成了推送的 aj,只是使用我之前编辑的方法。

方面的原始创建方法:

 /**
 * TODO Auto-generated method documentation
 * 
 * @param servicio
 * @param result
 * @param model
 * @return ModelAndView
 */
@PostMapping(name = "create")
public ModelAndView ServiciosCollectionThymeleafController.create(@Valid @ModelAttribute Servicio servicio, BindingResult result, Model model) {
    if (result.hasErrors()) {
        populateForm(model);

        return new ModelAndView("/servicios/create");
    }
    Servicio newServicio = getServicioService().save(servicio);
    UriComponents showURI = getItemLink().to(ServiciosItemThymeleafLinkFactory.SHOW).with("servicio", newServicio.getId()).toUri();
    return new ModelAndView("redirect:" + showURI.toUriString());
}

将相同的方法推入 .java,以及我的修改:

 /**
 * TODO Auto-generated method documentation
 * 
 * @param servicio
 * @param result
 * @param model
 * @return ModelAndView
 */
@PostMapping(name = "create")
public ModelAndView create(@Valid @ModelAttribute Servicio servicio, BindingResult result, Model model, Principal principal, Pageable pageable) {
    if (result.hasErrors()) {
        populateForm(model);

        return new ModelAndView("/servicios/create");
    }

    Prestador current = (Prestador) personaService.findByUsername(principal.getName(), pageable).getContent().get(0);

    if (current == null) { 
        populateForm(model);
        return new ModelAndView("/servicios/create");
    }
    servicio.setPrestador(current);     
    Servicio newServicio = getServicioService().save(servicio);
    return new ModelAndView("redirect:/ver-servicio/" + newServicio.getId());
}

谢谢。

【问题讨论】:

    标签: java spring spring-roo


    【解决方案1】:

    Roo 通过查找方法签名(方法的名称和参数类型)来检查方法是否已包含在 Java 文件中,因为这是 java 中支持的重载方法的方式。

    在您的情况下,一旦您更改了 create 方法参数,它就不再是相同的方法签名,这就是 Roo 再次生成它的原因。

    通常这不是问题,因为您必须更改该方法的客户端才能使用新方法。例如,如果您向 Service 添加新方法,您还将更改 Controller 的实现以使用该新方法,而 Roo 生成的方法不会影响你。

    在控制器方法的情况下,问题与映射有关。在您的情况下,您最终会得到两种方法,一种由您添加,另一种由 Roo 生成,具有相同的请求映射。要解决它,您只需添加由 Roo 生成的方法,而不需要映射注释。

    在您的情况下,代码如下:

    public ModelAndView create(@Valid @ModelAttribute Servicio servicio, BindingResult result, Model model) {
      throw new UnsupportedOperationException();
    }
    
    @PostMapping(name = "create")
    public ModelAndView create(@Valid @ModelAttribute Servicio servicio, BindingResult result, Model model, Principal principal, Pageable pageable) {
        if (result.hasErrors()) {
            populateForm(model);
    
            return new ModelAndView("/servicios/create");
        }
    
        Prestador current = (Prestador) personaService.findByUsername(principal.getName(), pageable).getContent().get(0);
    
        if (current == null) { 
            populateForm(model);
            return new ModelAndView("/servicios/create");
        }
        servicio.setPrestador(current);     
        Servicio newServicio = getServicioService().save(servicio);
        return new ModelAndView("redirect:/ver-servicio/" + newServicio.getId());
    }
    

    由于您拥有带有默认签名的 create 方法,因此 Roo 不会重新生成它。此外,它没有 PostMapping 注释,因此 Spring MVC 将忽略它,它将使用新签名调用 create 方法。

    补充说明:

    您还必须更改生成该方法的链接的方式。 Roo 生成的所有 Thymeleaf 控制器都有一个伴随类(以 LinkFactory 结尾),用于生成指向该控制器方法的链接,避免在 Thymeleaf 页面中使用硬编码的 URI 以及控制器重定向。这些 LinkFactory 类是使用 Spring's MvcUriComponentsBuilder.fromMethodCall utility 生成的,它使用假方法调用来生成到该 Controller 方法的链接。

    由于您有一个新的方法签名,您必须更改 ServiciosCollectionThymeleafController toUri 方法的默认实现。将 toUri 方法推入 Java 文件并将实现更改为类似这样。

    public UriComponents toUri(String methodName, Object[] parameters, Map<String, Object> pathVariables) {
    
        ...
        if (methodName.equals(CREATE)) {
            return SpringletsMvcUriComponentsBuilder.fromMethodCall(SpringletsMvcUriComponentsBuilder.on(getControllerClass()).create(null, null, null, null, null)).buildAndExpand(pathVariables);
        }
        ... 
    }
    

    注意,我在 create 方法调用中添加了两个额外的空参数,使用新方法签名。通过此更改,所有从 Thymeleaf 页面生成的 URI 都将指向新方法。

    【讨论】:

    • 很抱歉没有早点注意到,但在今天之前我无法使用此解决方法进行大量测试。仅创建具有确切方法签名的方法是行不通的。我收到一个错误(完整的错误日志:pastebin.com/CXXnvxHV)(测试与我发布的示例不在同一个控制器上,但它的上下文完全相同)
    • 我在答案中添加了一个附加注释,以解释如何将 URI 的生成更改为新的控制器方法,这是您现在遇到的错误,因为它正在尝试使用不再有请求映射的旧方法。
    猜你喜欢
    • 2013-03-08
    • 2015-05-06
    • 1970-01-01
    • 2019-05-04
    • 2020-07-22
    • 1970-01-01
    • 1970-01-01
    • 2012-05-14
    • 1970-01-01
    相关资源
    最近更新 更多