在 Roo 2 (RC1) 中覆盖控制器方法行为的正确方法是什么?
what's the right way to override Controller Methods behaviour in Roo 2 (RC1)?
我的带有 roo 生成的 CRUD 的项目工作正常,但现在我需要更改某些实体的保存方式(例如,我有一个 "User" 属性,我想在用户登录时动态设置)
目前我只是将 save() 方法从方面移动到 .java 并根据需要修改它。到目前为止它运行良好,但 roo 控制台似乎不喜欢它,因为它会在我更改方法 return 类型或其他内容后立即重新创建方面中的方法。
我不需要对此示例的具体答案,而是想知道这是否是实现 modify/override 开箱即用 create/show 功能的最佳方法对于 roo 提供的实体。
编辑:添加示例
我的一个实体是 "Servicio",它有一些 "ServiciosCollectionThymeleafController_Roo_Thymeleaf.aj" 和 "ServiciosCollectionThymeleafController.create"方法。我继续将所有 .aj 推入 "ServiciosCollectionThymeleafController.java"
然后我在创建方法中做了一些小改动并保存了它。它有效,但是当我打开 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());
}
谢谢。
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 方法新签名。
补充说明:
此外,您还必须更改 link 方法的生成方式。 Roo 生成的所有 Thymeleaf 控制器都有一个伴侣 class(以 LinkFactory 结尾),用于为该控制器方法生成 links,避免使用Thymeleaf 页面中的硬编码 URI 以及控制器重定向。那些 LinkFactory classes 是使用 Spring's MvcUriComponentsBuilder.fromMethodCall utility 生成的,它使用伪造的方法调用来生成对该控制器方法的 link。
因为你有一个新的方法签名,你必须更改 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 都将指向新方法。
我的带有 roo 生成的 CRUD 的项目工作正常,但现在我需要更改某些实体的保存方式(例如,我有一个 "User" 属性,我想在用户登录时动态设置)
目前我只是将 save() 方法从方面移动到 .java 并根据需要修改它。到目前为止它运行良好,但 roo 控制台似乎不喜欢它,因为它会在我更改方法 return 类型或其他内容后立即重新创建方面中的方法。
我不需要对此示例的具体答案,而是想知道这是否是实现 modify/override 开箱即用 create/show 功能的最佳方法对于 roo 提供的实体。
编辑:添加示例
我的一个实体是 "Servicio",它有一些 "ServiciosCollectionThymeleafController_Roo_Thymeleaf.aj" 和 "ServiciosCollectionThymeleafController.create"方法。我继续将所有 .aj 推入 "ServiciosCollectionThymeleafController.java"
然后我在创建方法中做了一些小改动并保存了它。它有效,但是当我打开 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());
}
谢谢。
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 方法新签名。
补充说明:
此外,您还必须更改 link 方法的生成方式。 Roo 生成的所有 Thymeleaf 控制器都有一个伴侣 class(以 LinkFactory 结尾),用于为该控制器方法生成 links,避免使用Thymeleaf 页面中的硬编码 URI 以及控制器重定向。那些 LinkFactory classes 是使用 Spring's MvcUriComponentsBuilder.fromMethodCall utility 生成的,它使用伪造的方法调用来生成对该控制器方法的 link。
因为你有一个新的方法签名,你必须更改 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 都将指向新方法。