我有一个模型,其描述方式如下:
@Table
@Entity
@Data
@Builder
@ToString
@EqualsAndHashCode
@AllArgsConstructor
@NoArgsConstructor
public class User {
// ...skipped...
private String foo;
}
我还有一个 service ,它具有创建新实体的方法:
@Service
public class UserService {
// ...skipped...
public User createUser(User user) {
Date currentDate = new Date();
user.setCreated(currentDate);
userRepository.save(user);
return user;
}
}
我还有一个 controller 和一个映射方法:
@Controller
@RequestMapping(UserRouteRegistry.FIRST_LEVEL + "/*")
public class UserController {
// ...skipped...
@PostMapping(UserRouteRegistry.SIGN_UP)
public String signUp(
@ModelAttribute("user") @Validated(User.CreateUserGroup.class) User user,
BindingResult result,
WebRequest request,
RedirectAttributes redirectAttributes
) {
// ...mercellessly skipped...
userRegistered = userService.createUser(user);
// ...mercellessly skipped...
}
一切都很简单,对吧?
我在网络表单中没有foo
字段,并且我不需要网络用户来设置此字段,它应该是一些真正的私有字段,不受网络用户的影响直接。
发出自定义POST请求时,我看到正在创建一个新实体,其中的foo
字段由请求中设置的数据填充:
POST /user/sign-up HTTP/1.1
Host: 127.0.0.1:8080
Origin: http://127.0.0.1:8080
Content-Type: application/x-www-form-urlencoded
Referer: http://127.0.0.1:8080/user/sign-up
Cookie: SL_G_WPT_TO=ru; SL_GWPT_Show_Hide_tmp=1; SL_wptGlobTipTmp=1; BL_D_PROV=; BL_T_PROV=; JSESSIONID=E1190293BD183C647245BAE03E6DCDDA
cache-control: no-cache
Postman-Token: e572bccf-ff0a-4b0b-a181-dd0aa20dca99
foo=13
> SELECT foo FROM user ORDER BY id DESC LIMIT 1 \G
*************************** 1. row ***************************
foo: 13
1 row in set (0.0005 sec)
是的,这似乎很正确,但是有什么办法可以以某种方式防止呢?
在 service 级别上为{private”字段分配null
值?那将是非常乏味的,但是它将起作用。在 model 级别的此字段上设置一些@annotation(顺便说一下,应该是什么注释?)?我不确定这是否合乎逻辑。在 controller 级别上过滤参数,在某处列出所有允许的参数?也许是这样吗?
正确的方法是什么?
谢谢!
答案 0 :(得分:1)
您可以在反序列化时忽略该字段
@JsonProperty(access = Access.READ_ONLY)
private String zaloopa;
答案 1 :(得分:1)
将模型和DTO(在前端和后端控制器之间转移的DTO)分开是一个好习惯,因为有时可能会有更多的事情,只有一个字段可以排除或处理不同的问题。也可能是在其他上下文中需要该字段,因此不能在模型本身中将其排除。
因此,当您的控制器现在接收User
模型时,它应该接收UserDTO
,该模型仅具有所需的允许字段。
这当然使事情变得更加困难,因为然后您需要在UserDTO
之间映射User
。但幸运的是,也有ModelMapper之类的库来处理。
答案 2 :(得分:1)
如果您要发布表单数据,则可以按照以下方式进行操作,即,创建一个用@InitBinder
方法注释的方法,然后在提供的{{ 1}}实例。
此方法可以添加到您的控制器,Spring MVC控制器建议或两者中。对于所有实体共享的字段,您可以添加控制器建议,然后在相关控制器上注册其他实体特定的字段。
WebDataBinder
如果您要发布 JSON数据,则可以通过杰克逊注释来实现。您可以将这些字段直接放置在实体的字段中,也可以使用Jackson的mixin类来避免因网络层问题而“污染”域模型。
注释实体或mixin中的字段:
@InitBinder()
public void initBinder(WebDataBinder binder) {
binder.setDisallowedFields(new String[] { "id", "version" });
}
要注册混音:
@JsonProperty(access = Access.READ_ONLY)
private String myField;