java - 我应该将我的实体 ID 放在 URL 中还是作为隐藏字段放入表单中?
问题描述
我认为就 REST 而言,ID 应该放在 URL 中,例如:
https://example.com/module/[ID]
然后我在那个 URL 上调用 GET、PUT、DELETE。我认为这很清楚。在 Spring MVC 控制器中,我将使用 @PathVariable 获取 ID。作品。
现在,我对 Spring MVC 的实际问题是,如果我这样做,我必须不将 ID 作为表单的一部分包含(以及),Spring 会发出类型的警告
Skipping URI variable 'id' since the request contains a bind value with the same name.
否则。而且只发送一次也很有意义,对吧?如果他们不匹配你会怎么做?
这很好,但我确实有一个用于我的表单支持 bean 的自定义验证器,它需要知道 ID!(它需要检查某个唯一名称是否已被用于不同的实体实例,但不能在不知道提交表单的 ID 的情况下进行)。
我还没有找到一种好方法来告诉验证器来自@PathVariable 的ID,因为验证甚至在我的控制器方法中的代码执行之前就已经发生了。
你将如何解决这个困境?
这是我的控制器(修改):
@Controller
@RequestMapping("/channels")
@RoleRestricted(resource = RoleResource.CHANNEL_ADMIN)
public class ChannelAdminController
{
protected ChannelService channelService;
protected ChannelEditFormValidator formValidator;
@Autowired
public ChannelAdminController(ChannelService channelService, ChannelEditFormValidator formValidator)
{
this.channelService = channelService;
this.formValidator = formValidator;
}
@RequestMapping(value = "/{channelId}/admin", method = RequestMethod.GET)
public String editChannel(@PathVariable Long channelId, @ModelAttribute("channelForm") ChannelEditForm channelEditForm, Model model)
{
if (channelId > 0)
{
// Populate from persistent entity
}
else
{
// Prepare form with default values
}
return "channel/admin/channel-edit";
}
@RequestMapping(value = "/{channelId}/admin", method = RequestMethod.PUT)
public String saveChannel(@PathVariable Long channelId, @ModelAttribute("channelForm") @Valid ChannelEditForm channelEditForm, BindingResult result, Model model, RedirectAttributes redirectAttributes)
{
try
{
// Has to validate in controller if the name is already used by another channel, since in the validator, we don't know the channelId
Long nameChannelId = channelService.getChannelIdByName(channelEditForm.getName());
if (nameChannelId != null && !nameChannelId.equals(channelId))
result.rejectValue("name", "channel:admin.f1.error.name");
}
catch (EmptyResultDataAccessException e)
{
// That's fine, new valid unique name (not so fine using an exception for this, but you know...)
}
if (result.hasErrors())
{
return "channel/admin/channel-edit";
}
// Copy properties from form to ChannelEditRequest DTO
// ...
// Save
// ...
redirectAttributes.addFlashAttribute("successMessage", new SuccessMessage.Builder("channel:admin.f1.success", "Success!").build());
// POST-REDIRECT-GET
return "redirect:/channels/" + channelId + "/admin";
}
@InitBinder("channelForm")
protected void initBinder(WebDataBinder binder)
{
binder.setValidator(formValidator);
}
}
解决方案
我想我终于找到了解决方案。
事实证明,Spring 也将路径变量绑定到形成 bean!我没有在任何地方找到这个文档,也没有预料到它,但是当尝试重命名路径变量时,就像@DavidW 建议的那样(我本来希望在我的控制器方法中只有局部效果),我意识到由于前面提到的,有些东西坏了。
所以,基本上,解决方案是在表单支持对象上也有 ID 属性,但不包括 HTML 表单中的隐藏输入字段。这样,Spring 将使用路径变量并将其填充到表单上。@PathVariable
甚至可以跳过控制器方法中的本地参数。
推荐阅读
- html - 某些图像不会出现在浏览器中
- windows - Traefik:v2 Windows Container 无法检索 docker 客户端和服务器主机的信息
- swift - Mapbox 如何在 MGLPolygonFeature 上设置填充颜色(或添加要素属性)
- swift - 我的 MultiPartFormData 编码器有什么问题?斯威夫特 4
- c# - ASP.NET Core 3.1.1 MVC + angular:我应该如何从用户(id)获取所有食谱?
- angular - 具有范围选择的角材料日期选择器
- javascript - 新的 gulp 插件:正确发出完成信号
- c - 一元 & 运算符遇到 [] 时的行为
- angular - 离子角度ngrx如何访问商店
- c++ - “逆 SFINAE” 避免模棱两可的过载