背景

数据库字段: id username password email name sex age address
一个修改资料的页面只能修改: name sex age address 字段
在前台页面构建:

1
2
3
4
5
<input type="text" name="name" />
<input type="text" name="age" />
<input type="text" name="sex" />
<input type="text" name="address" />
<input type="submit"/>

使用spring mvc + jpa来进行接收参数和持久化到数据库:

1
2
3
4
5
@RequestMapping(value = "/update/{memberId}", method = RequestMethod.POST)
public String updatePost(@PathVariable(value = "memberId") int memberId, Member member) throws ParseException {
memberService.update(followUp);
return "redirect:/member/";
}

以上是比较常见的一种做法,spring 会自动判断member bean里面有没有传进来的key值,如果有则会自动赋值上,然后直接执行update操作。但这样会存在安全问题。


安全隐患

修改不允许修改的字段

进行过java开发,使用过spring mvc strtus2之类的框架都知道有这个特性,在大量表单更新的地方会用到这样的操作,就拿上面的例子说,本身只能进行更新姓名.年龄.性别.地址的操作.如果用户自己在构造一个表单,或者直接模拟提交:

1
2
<input type="text" name="username"/>
<input type="text" name="password"/>

Spring mvc在member bean 里也找到了username password 的字段,没有经过任何过滤,直接就执行update操作了,把用户名和密码也修改了。

没有赋值的自动设置为空

如果以上接收到的bean执行执行update操作,jpa会去生成这样一条sql:

1
update xxxx set age = :age,name = :name,sex = :sex,address = :address,username = null,password = null,email = null where id = :id

会把bean中的null也设置到数据库中去,这种情况下,在entity的类上加上注解:@DynamicUpdate 在进行更新操作,有时候会出现莫名其妙的问题,阅读官方文档后发现,这个是需要这样操作的:

1
2
3
Member member = memberService.findOne(memberId);
member.setName memeber.setAge .......
memberService.update(member);

首先先要去数据库读出来,让对象有缓存,jpa才能判断拿些字段是改动过的.


解决方案

单独接收每个参数

1
2
3
4
5
6
7
8
9
10
public String updatePost(
@PathVariable(value = "memberId") int memberId,

@RequestParam String name,
@RequestParam String age,
@RequestParam String sex,
@RequestParam String address){

Member member = memberService.findOne(memberId);
member.setName memeber.setAge .......
memberService.update(member);
}

使用HQL(JPQL)

1
2
3
@Modifying 
@Query("update Member m set m.age = :member.age .....")
public int updateMember(Member member);

接收后使用BeanUtil赋值

BeanUtils提供对Java反射和自省API的包装。其主要目的是利用反射机制对JavaBean的属性进行处理。我们知道,一个JavaBean通常包含了大量的属性,很多情况下,对JavaBean的处理导致大量get/set代码堆积,增加了代码长度和阅读代码的难度。

1
2
3
4
5
6
7
8
9
10
public String updatePost(
@PathVariable(value = "memberId") int memberId,
Member memberVo){

Member member = memberService.findOne(memberId);
BeanUtils.setProperty(member,"name",memberVo.getName());
BeanUtils.setProperty(member,"age",memberVo.getAge());
BeanUtils.setProperty(member,"sex",memberVo.getSex());
BeanUtils.setProperty(member,"address",memberVo.getAddress());
memberService.update(member);
}