5. 用户-修改个人信息
5.1. 用户-修改个人信息-持久层
在UserMapper.java
接口中声明抽象方法:
Integer changeInfo(User user);
在UserMapper.xml
配置映射:
UPDATE t_user
SET username=?,gender=?,avater=?,phone=?,email=?
WHERE uid=?
每做完一部分,应该及时测试。
5.2. 用户-修改个人信息-业务层
在IUserService
接口中声明抽象方法:
void changeInfo(User user);
在UserServiceImpl
类中实现抽象方法:
public void changeInfo(User user) {
User result = getUserById(user.getId());
if (result != null) {
// 补充日志,即:modifiedUser和modifiedTime
Integer rows = userMapper.changeInfo(user);
if (rows != 1) {
throw new UpdateDataException("xxx");
}
} else {
throw new UserNotFoundException("xxx");
}
}
执行测试
5.3. 用户-修改个人信息-控制器层
已知修改个人信息功能会抛出UserNotFoundException
和UpdateDataException
,这2个异常已经被处理过了,所以,此次不需要调整BaseController
中关于异常的处理!
接下来,分析处理修改个人信息的请求:
请求路径:/user/handle_change_info.do
请求类型:POST
请求参数:uid(*,session),username,gender,avatar,phone,email
响应方式:ResponseBody
是否拦截:是,请检查拦截器配置,拦截当前路径
则,在UserController
添加方法:
@RequestMapping(value="/handle_change_info.do")
@ResponseBody
public ResponseResult handleChangeInfo(User user,
HttpSession session) {
// 判断用户名和邮箱,如果为"",则设为null
// 从session获取uid
// 将uid封装到参数user中
// 执行修改:userService.changeInfo(user)
// 返回
}
测试,先打开登录页,完成登录,然后再通过浏览器地址栏来访问,例如http://localhost:8080/TeduStore/user/handle_change_info.do?username=xx&gender=1&avatar=hello&phone=111&email=222
5.4. 用户-修改个人信息-前端页面
其它
1. 把多个类都需要调用的方法提取出来
如果多个类,或多个类中的多个方法都需要执行相同的任务,则可以把执行这项任务的相关代码提取到专门的方法中,当每次需要执行任务时,调用该方法即可!
提取出来的方法,可以:1) 放在多个类的共同的父类中,那么,这些类将自然继承得到该方法,即可直接调用该方法;2) 新建一个工具类,甚至把该方法声明为静态的,方便调用。
关于这种做法,选取的原则是:该方法的调用者的定位!例如某个方法可能只有多个控制器类需要调用,则可以把方法放在控件器类的基类中!如果某个方法既可能被控制器类调用,又可能被业务类调用,甚至其它类也会调用,则应该把方法放在工具类中!
2. 到底是先有父类还是先有子类
先有父类,再有子类:当创建对象时,会先创建父类的对象,然后在此基础之上,扩展出子类的对象(所以,继承的关键字extends
本身也就是“扩展”的意思,并且,在子类的构造方法中,第1行有效代码一定是调用父类的构造方法)。
先有子类,再有父类:从设计过程来说,通常,并不会直接设计出父类这样定位的类别,而是因为创建了若干个具有相同特征的类以后,才将相同的特征提取到某个专门的类中,这个类就是父类!
3. 什么时候检查数据的有效性
所谓“数据的有效性”,多指数据是否达到最基本的格式要求,例如:数据已提交、数据的类型、数据的长度、数据的字符组成……
通常,在获取数据的第一时间,就应该验证数据的有效性!
比较理想的做法是在前端页面(html/jsp……)中使用JavaScript对用户输入的内容进行验证,如果不符合数据格式要求,则不允许提交到服务器!但是,前端页面的不确定因素太多,例如可能被跳过,或者某个应用有多种不同的客户端不统一……所以,前端验证是不可靠的!
当然,尽管前端验证不可靠,但是,仍然需要做相关验证!因为,无论有多少风险,前端的验证还可以阻挡大部分正常用户的非法数据提交,避免所有非法数据都提交到服务器再验证,从而减轻服务器压力!
由于前端验证不可靠,所以,服务器端仍然需要验证数据的有效性!通常,WEB服务器在处理用户的请求时,是最先由控制器获取数据,然后调用业务层,再由业务层调用持久层,来完成相关的数据操作,在这样的流程中,控制器就应该是验证数据有效性的“第一时间”!
即:当控制器接收到请求,准备处理之前,就应该验证数据的有效性,如果数据格式有误,则直接响应错误提示,而不会向后执行到业务层甚至持久层!
所以说:控制器必须在接收到请求的第一时间验证数据的有效性!
在绝大部分情况下,控制器验证了数据之后,业务层可以不必再验证数据的有效性,因为,在标准的MVC流程中,是控制器中的代码调用业务层的方法,也就是控制器先验证数据的有效性,然后调用业务层方法,在业务层方法的执行过程中,还是使用之前已经验证过的数据,当然就不必反复验证!但是,特殊情况在于:并不是每次业务方法的执行,都是由控制器调用的!因为可能存在:某个业务方法直接调用另一个业务方法,甚至是由于某些计划任务导致业务方法被调用,在这样的过程中,控制器自始至终都没有被执行!所以,在这些特殊情况下,业务层还是得验证数据的有效性!
小结:首先,前端的验证是必须的,尽管它不可靠,但是,对于普通的用户来说,可以视为可靠,则可以拦截下许多非法的请求,从而避免这些请求提交到服务器,进而减轻服务器压力!然后,服务器端的控制器中是必须在处理请求的第一时间就验证数据的有效性的,避免非法的数据向后(向业务层甚至持久层)提交!如果能够确定当前项目中,只有控制器层才会调用业务层,则业务层可以不验证数据的有效性,但是,如果当前项目中,还存在例如计划任务等功能会导致业务层的执行,并不事先经过控制器层,则业务层也需要验证数据的有效性!
4. Spring文件上传
1. 添加依赖
基于Spring的文件上传,除了需要spring-webmvc
以外,还需要commons-fileupload
:
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.3</version>
</dependency>
2. 前端页面
必须使用<input type="file" />
标签,用于浏览所需要上传的文件,并且,该标签所在的<form>
必须配置请求方式为POST
,添加enctype="multipart/form-data"
属性,例如:
<form action="upload.do" method="post"
enctype="multipart/form-data">
<div>请选择您要上传的文件:<input type="file" name="file" /></div>
<div><input type="submit" value="上传" /></div>
</form>
3. 添加配置
在Spring的配置文件中添加以下配置:
<!-- 配置CommonsMultipartResolver -->
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver" />
此项配置的id属性是必须的,且值必须是multipartResolver
。
4. 处理请求
在控制器类中:
@RequestMapping("/upload.do")
public String handleUpload(
@RequestParam CommonsMultipartFile file)
throws IllegalStateException, IOException {
// 目标文件,即上传的文件数据保存到哪里
File dest = new File("e:/201811051647.jpg");
// 将用户上传的文件数据(尚且在内存中)保存为文件
file.transferTo(dest);
return null;
}