13. 用户-修改密码-业务层
(a) 规划可能出现的异常
最终需要执行的是更新密码操作,则可能出现更新失败的问题,则应该抛出UpdateException
;
在执行更新之前,应该检查用户数据是否存在,如果用户数据不存在,则抛出UserNotFoundException
;
并且,继续检查用户数据状态是否正确,例如isDelete
是否为0
,否则,将抛出UserNotFoundException
;
在执行更新密码之前,还应该检查原密码是否正确,如果不匹配,则抛出PasswordNotMatchException
。
所以,需要在cn.tedu.store.service.ex
包中创建UpdateException
。
(b) 业务接口及抽象方法
在IUserService
接口中添加抽象方法:
void changePassword(Integer uid, String oldPassword, String newPassword, String username);
(c) 实现抽象方法
在UserServiceImpl
类中实现以上抽象方法:
public void changePassword(Integer uid, String oldPassword, String newPassword, String username) {
// 日志:输出原密码,新密码
// 基于参数uid调用userMapper的findByUid()查询用户数据
// 判断查询结果是否为null
// 是:UserNotFoundException
// 判断查询结果中的isDelete是否为1
// 是:UserNotFoundException
// 从查询结果中取出盐值
// 日志:“将原密码执行加密”
// 将参数oldPassword结合盐值执行加密,得到oldMd5Password
// 日志:输出查询结果中的password
// 判断oldMd5Password与查询结果中的password是否不一致
// 是:PasswordNotMatchException
// 日志:“将新密码执行加密”
// 将参数newPassword结合盐值执行加密,得到newMd5Password
// 调用userMapper的updatePasswordByUid()执行更新密码,并获取返回的受影响的行数
// 判断受影响的行数是否不为1
// 是:UpdateException
}
具体代码为:
@Override
public void changePassword(Integer uid, String oldPassword, String newPassword, String username) {
// 日志:输出原密码,新密码
System.err.println("UserServiceImpl.changePassword()");
System.err.println("\t原密码:" + oldPassword);
System.err.println("\t新密码:" + newPassword);
// 基于参数uid调用userMapper的findByUid()查询用户数据
User result = userMapper.findByUid(uid);
// 判断查询结果是否为null
if (result == null) {
// 是:抛出UserNotFoundException
throw new UserNotFoundException(
"修改密码失败!用户数据不存在!");
}
// 判断查询结果中的isDelete是否为1
if (result.getIsDelete() == 1) {
// 是:抛出UserNotFoundException
throw new UserNotFoundException(
"修改密码失败!用户数据不存在!");
}
// 从查询结果中取出盐值
String salt = result.getSalt();
// 日志:“将原密码执行加密”
System.err.println("\t将原密码执行加密");
// 将参数oldPassword结合盐值执行加密,得到oldMd5Password
String oldMd5Password = getMd5Password(oldPassword, salt);
// 日志:输出查询结果中的password
System.err.println("\t数据库中的密码:" + result.getPassword());
// 判断oldMd5Password与查询结果中的password是否不一致
if (!oldMd5Password.equals(result.getPassword())) {
// 是:PasswordNotMatchException
throw new PasswordNotMatchException(
"修改密码失败!原密码错误!");
}
// 日志:“将新密码执行加密”
System.err.println("\t将新密码执行加密");
// 将参数newPassword结合盐值执行加密,得到newMd5Password
String newMd5Password = getMd5Password(newPassword, salt);
// 调用userMapper的updatePasswordByUid()执行更新密码,并获取返回的受影响的行数
Integer rows = userMapper.updatePasswordByUid(uid, newMd5Password, username, new Date());
// 判断受影响的行数是否不为1
if (rows != 1) {
// 是:UpdateException
throw new UpdateException(
"修改密码失败!执行更新密码时出现未知错误!请联系系统管理员!");
}
}
完成后,在UserServiceTests
中编写单元测试:
@Test
public void changePassword() {
try {
Integer uid = 15;
String oldPassword = "1234";
String newPassword = "8888";
String username = "密码管理员";
service.changePassword(uid, oldPassword, newPassword, username);
System.err.println("OK.");
} catch (ServiceException e) {
System.err.println(e.getClass().getName());
System.err.println(e.getMessage());
}
}
14. 用户-修改密码-控制器层
(a) 处理新创建的异常
需要处理UpdateException
。
(b) 设计所需要处理的请求
请求路径:/users/password/change
请求参数:String oldPassword, String newPassword, HttpSession session
请求方式:POST
响应结果:JsonResult<Void>
(c) 处理请求
在UserController
中添加处理请求的方法:
// http://localhost:8080/users/password/change?oldPassword=0000&newPassword=1234
@RequestMapping("password/change")
public JsonResult<Void> changePassword(String oldPassword, String newPassword, HttpSession session) {
// 从参数session取出uid和username
Integer uid = Integer.valueOf(session.getAttribute("uid").toString());
String username = session.getAttribute("username").toString();
// 调用业务对象的方法执行修改密码
service.changePassword(uid, oldPassword, newPassword, username);
// 返回
return new JsonResult<>(OK);
}
注意:测试时,必须先登录,然后再执行测试!
15. 用户-修改密码-前端页面
16. 使用拦截器处理登录验证
由于需要登录后才可以执行操作比较多,所以,应该使用拦截器进行统一处理!在处理过程中,如果获取不到用户的登录信息,则可以将用户的请求重定向到登录页面!
首先,应该在cn.tedu.store.interceptor
包中创建LoginInterceptor
拦截器类,实现HandlerInterceptor
接口,重写preHandle()
方法,在该方法中验证登录:
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
if (request.getSession()
.getAttribute("uid") == null) {
response.sendRedirect("/web/login.html");
return false;
}
return true;
}
}
在SpringBoot项目中,并没有XML文件用于配置,所以,需要编写配置类来完成拦截器的配置!则在cn.tedu.store.config
包中创建InterceptorConfigurer
配置类:
@Configuration
public class InterceptorConfigurer implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
HandlerInterceptor interceptor
= new LoginInterceptor();
List<String> patterns = new ArrayList<>();
patterns.add("/users/reg");
patterns.add("/users/login");
patterns.add("/web/register.html");
patterns.add("/web/login.html");
patterns.add("/bootstrap3/**");
patterns.add("/css/**");
patterns.add("/images/**");
patterns.add("/js/**");
registry.addInterceptor(interceptor)
.addPathPatterns("/**")
.excludePathPatterns(patterns);
}
}
17. 用户-修改资料-持久层
(a) 规划所需要执行的SQL语句
关于“修改资料”,应该由2部分功能来组成,分别是“打开页面时就显示当前登录的用户的信息”和“点击修改按钮时执行修改”。
显示当前登录的用户信息应该是根据当前登录的用户id查询用户数据,该查询功能已经完成,无需重复开发!
修改用户资料需要执行的SQL语句大致是:
update t_user set phone=?, email=?, gender=?, modified_user=?, modified_time=? where uid=?
在执行修改之前,依然应该检查用户数据是否存在、是否被标记为已删除,这些检查功能已经完成,无需重复开发!
(b) 接口与抽象方法
在UserMapper
接口中添加抽象方法:
/**
* 根据用户的id更新用户基本信息
* @param user 封装了用户的id和新的信息的对象
* @return 受影响的行数
*/
Integer updateInfoByUid(User user);
(c) 配置映射
在UserMapper.xml中配置以上抽象方法的映射:
<!-- 根据用户的id更新用户基本信息 -->
<!-- Integer updateInfoByUid(User user) -->
<update id="updateInfoByUid">
UPDATE
t_user
SET
phone=#{phone},
email=#{email},
gender=#{gender},
modified_user=#{modifiedUser},
modified_time=#{modifiedTime}
WHERE
uid=#{uid}
</update>
在UserMapperTests
中测试:
@Test
public void updateInfoByUid() {
User user = new User();
user.setUid(18);
user.setPhone("13100131001");
user.setEmail("root@163.com");
user.setGender(1);
Integer rows = mapper.updateInfoByUid(user);
System.err.println("rows=" + rows);
}
18. 用户-修改资料-业务层
(a) 规划可能出现的异常
在处理“打开页面时就显示当前登录的用户的信息”时,可能因为用户数据不存在、数据状态异常而导致失败,则可能抛出UserNotFoundException
。
在处理“点击修改按钮时执行修改”时,仍需要先检查用户数据是否存在、数据状态是否异常,则可能抛出UserNotFoundException
,检查通过后,执行更新时可能抛出UpdateException
。
以上所有异常都已创建!
(b) 业务接口及抽象方法
在IUserService
中添加抽象方法:
/**
* 显示当前登录用户的基本信息
* @param uid 当前登录的用户的id
* @return 该用户的基本信息
*/
User showInfo(Integer uid);
/**
* 修改用户的基本资料
* @param uid 用户的id
* @param username 用户名
* @param user 封装了用户的新资料的对象
*/
void changeInfo(Integer uid, String username, User user);
(c) 实现抽象方法
在UserServiceImpl
中实现以上抽象方法:
public User showInfo(Integer uid) {
// 根据参数uid查询用户数据
// 判断查询结果是否为null
// 是:抛出UserNotFoundException
// 判断查询结果中的isDelete是否为1
// 是:抛出UserNotFoundException
// 创建新的User对象
// 将查询结果中的username、phone、email、gender封装到新对象中
// 返回新User对象
}
public void changeInfo(Integer uid, String username, User user) {
// 根据参数uid查询用户数据
// 判断查询结果是否为null
// 是:抛出UserNotFoundException
// 判断查询结果中的isDelete是否为1
// 是:抛出UserNotFoundException
// 向参数user中封装uid:user.setUid(uid)
// 向参数user中封装username到modifiedUser属性:user.setModifiedUser(username)
// 向参数user中封装当前时间到modifiedTime属性:user.setModifiedTime(new Date());
// 调用持久层userMapper的updateInfoByUid(user)执行更新,获取返回的受影响的行数
// 判断受影响的行数是否不为1
// 是:抛出UpdateException
}
具体代码:
@Override
public User showInfo(Integer uid) {
// 基于参数uid调用userMapper的findByUid()查询用户数据
User result = userMapper.findByUid(uid);
// 判断查询结果是否为null
if (result == null) {
// 是:抛出UserNotFoundException
throw new UserNotFoundException(
"获取用户信息失败!用户数据不存在!");
}
// 判断查询结果中的isDelete是否为1
if (result.getIsDelete() == 1) {
// 是:抛出UserNotFoundException
throw new UserNotFoundException(
"获取用户信息失败!用户数据不存在!");
}
// 创建新的User对象
User user = new User();
// 将查询结果中的username、phone、email、gender封装到新对象中
user.setUsername(result.getUsername());
user.setPhone(result.getPhone());
user.setEmail(result.getEmail());
user.setGender(result.getGender());
// 返回新User对象
return user;
}
@Override
public void changeInfo(Integer uid, String username, User user) {
// 基于参数uid调用userMapper的findByUid()查询用户数据
User result = userMapper.findByUid(uid);
// 判断查询结果是否为null
if (result == null) {
// 是:抛出UserNotFoundException
throw new UserNotFoundException(
"修改用户资料失败!用户数据不存在!");
}
// 判断查询结果中的isDelete是否为1
if (result.getIsDelete() == 1) {
// 是:抛出UserNotFoundException
throw new UserNotFoundException(
"修改用户资料失败!用户数据不存在!");
}
// 向参数user中封装uid:
user.setUid(uid);
// 向参数user中封装username到modifiedUser属性:
user.setModifiedUser(username);
// 向参数user中封装当前时间到modifiedTime属性:
user.setModifiedTime(new Date());
// 调用持久层userMapper的updateInfoByUid(user)执行更新,获取返回的受影响的行数
Integer rows = userMapper.updateInfoByUid(user);
// 判断受影响的行数是否不为1
if (rows != 1) {
// 是:UpdateException
throw new UpdateException(
"修改用户资料失败!执行更新用户资料时出现未知错误!请联系系统管理员!");
}
}
完成后,在UserServiceTests
中测试:
@Test
public void showInfo() {
try {
Integer uid = 18;
User result = service.showInfo(uid);
System.err.println("OK. " + result);
} catch (ServiceException e) {
System.err.println(e.getClass().getName());
System.err.println(e.getMessage());
}
}
@Test
public void changeInfo() {
try {
Integer uid = 18;
String username = "资料管理员";
User user = new User();
user.setPhone("13900139999");
user.setEmail("root@qq.com");
user.setGender(1);
service.changeInfo(uid, username, user);
System.err.println("OK.");
} catch (ServiceException e) {
System.err.println(e.getClass().getName());
System.err.println(e.getMessage());
}
}
19. 用户-修改资料-控制器层
(a) 处理新创建的异常
(b) 设计所需要处理的请求
请求路径:/users/info/show
请求参数:HttpSession session
请求方式:GET
响应结果:JsonResult<User>
(c) 处理请求
// http://localhost:8080/users/info/show
@GetMapping("info/show")
public JsonResult<User> showInfo(HttpSession session) {
// 从session中获取uid
Integer uid = Integer.valueOf(session.getAttribute("uid").toString());
// 调用业务对象的showInfo()方法查询用户数据
User data = userService.showInfo(uid);
// 返回OK与以上调用时的返回结果
return new JsonResult<>(OK, data);
}
20. 用户-修改资料-前端页面
---------------- 以上仅用于复制 ----------------
17. 用户-修改资料-持久层
(a) 规划所需要执行的SQL语句
(b) 接口与抽象方法
(c) 配置映射
18. 用户-修改资料-业务层
(a) 规划可能出现的异常
(b) 业务接口及抽象方法
(c) 实现抽象方法
19. 用户-修改资料-控制器层
(a) 处理新创建的异常
(b) 设计所需要处理的请求
请求路径:
请求参数:
请求方式:
响应结果:JsonResult<?>
(c) 处理请求