什么是在Roo 2(RC1)中覆盖控制器方法行为的正确方法?

时间:2017-04-06 13:54:36

标签: java spring spring-roo

我的项目与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());
}

感谢。

1 个答案:

答案 0 :(得分:3)

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以及Controller重定向。那些 LinkFactory 类是使用Spring's MvcUriComponentsBuilder.fromMethodCall utility生成的,{{3}}使用伪方法调用来生成指向该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都将指向新方法。