需要用户提交原始密码和新密码,再根据当前登录的用户进行信息的修改操作。
update t_user set password = ?, modified_user = ?, modified_time = ? where uid = ?;
根据uid查询用户的数据。在修改密码之前,首先要保证当前这个用户的数据存在,还要检测是否被标记为已经删除、检测输入的原始密码是否正确。select * from t_user where uid = ?;
/**
* 根据用户的uid来修改用户密码
* @param uid 用户的id
* @param password 用户输入的新密码
* @param modifiedUser 表示修改的执行者
* @param modifiedTime 表示修改数据的时间
* @return 返回值为受影响的行数
*/
Integer updatePasswordByUid(Integer uid,
String password,
String modifiedUser,
Date modifiedTime);
//根据用户id查询用户数据
User fndByUid(Integer uid);
<update id="updatePasswordByUid">
update t_user set
password = #{password},
modified_user = #{modifiedUser},
modified_time = #{modifiedTime}
where uid = #{uid}
update>
<select id="fndByUid" resultMap="UserEntityMap">
select * from t_user where uid = #{uid}
select>
做单元测试。@Test
public void updatePasswordByUid() {
userMapper.updatePasswordByUid(9,"543","管理员",new Date());
}
@Test
public void fndByUid() {
System.out.println(userMapper.fndByUid(9));
}
void changePassword(Integer uid, String username,
String oldPassword,
String newPassword);
在实现类中实现当前的抽象方法。@Override
public void changePassword(Integer uid, String username, String oldPassword, String newPassword) {
User result = userMapper.fndByUid(uid);
if(result == null || result.getIsDelete() == 1) {
throw new UserNotFoundException("用户数据不存在");
}
//原始密码和数据库中密码进行比较
String oldMd5Password = getMD5Password(oldPassword,result.getSalt()); //对输入的密码加密再和数据库中的密码比较
if(!result.getPassword().equals(oldMd5Password)) {
throw new PasswordNotMatchException("密码错误");
}
//将新的密码设置到数据库中,将新的密码进行加密再去更新
String newMd5Password = getMD5Password(newPassword, result.getSalt());
Integer rows = userMapper.updatePasswordByUid(uid, newMd5Password, username,new Date());
if(rows != 1) {
throw new UpdateException("更新数据产生未知的异常");
}
}
单元测试@Test
public void changePassword() {
userService.changePassword(10,"管理员","123","321");
}
else if (e instanceof UpdateException) {
result.setState(5003);
result.setMessage("更新数据时产生未知的异常");
}
/users/change_password
post
String oldPassword, String newPassword, HttpSession session //需要和表单中的name属性值保持一致
JsonResult
@RequestMapping("change_password")
public JsonResult<Void> changePassword(String oldPassword,
String newPassword,
HttpSession session) {
Integer uid = getuidFromSession(session);
String username = getUsernameFromSession(session);
userService.changePassword(uid, username,oldPassword,newPassword);
return new JsonResult<>(OK);
}
在password.html中,添加ajax请求的处理,不再手动去编写ajax结构,直接复制原来的,然后修改参数。
<script type="text/javascript">
$("#btn-change-password").click(function () {
$.ajax({
url: "/users/change_password",
type: "post",
data: $("#form-change-password").serialize(),
dataType: "JSON",
success: function (json) {
if(json.state == 200) {
alert("密码修改成功");
} else {
alert("密码修改失败");
}
},
error: function (xhr) {
alert("修改密码时产生未知的异常" + xhr.message);
}
});
});
</script>
update t_user set phone = ?,email = ?,gender = ?,modified_user = ?,modified_time = ? where uid = ?;
2.根据用户名查询用户的数据select * from t_user where uid = ?;
//更新用户的信息
Integer updateInfoByUid(User user);
<update id="updateInfoByUid">
update t_user
set
<if test="phone != null">phone = #{phone},if>
<if test="email != null">email = #{email},if>
<if test="gender != null">gender = #{gender},if>
modified_user = #{modifiedUser},
modified_time = #{modifiedTime}
where uid = #{uid}
update>
在测试类中测试@Test
public void updateInfoByUid() {
User user = new User();
user.setUid(9);
user.setPhone("1883424234");
user.setEmail("[email protected]");
user.setGender(1);
userMapper.updateInfoByUid(user);
}
异常规划
1.设计两个功能
2.打开页面的时候可能找不到用户的数据,点击修改按钮之前需要再次的去检测用户的数据是否存在。
接口和抽象方法
主要有两个功能的模块,对应的是两个抽象的方法的设计。
//根据用户的id查询用户的数据
User getByUid(Integer uid);
//更新用户的数据操作
void changeInfo(Integer uid, String username, User user);
实现抽象方法
在UserServiceImpl类中添加两个抽象方法的具体实现。
@Override
public User getByUid(Integer uid) {
User result = userMapper.fndByUid(uid);
if(result==null || result.getIsDelete()==1) {
throw new UserNotFoundException("用户数据不存在");
}
User user = new User();
user.setUsername(result.getUsername());
user.setPhone(result.getPhone());
user.setEmail(result.getEmail());
user.setGender(result.getGender());
return user;
}
@Override
public void changeInfo(Integer uid, String username, User user) {
User result = userMapper.fndByUid(uid);
if(result==null || result.getIsDelete()==1) {
throw new UserNotFoundException("用户数据不存在");
}
user.setUid(uid);
user.setUsername(username);
user.setModifiedUser(username);
user.setModifiedTime(new Date());
Integer rows = userMapper.updateInfoByUid(user);
if(rows != 1) {
throw new UpdateException("更新数据产生的异常");
}
}
在测试类中进行测试
@Test
public void getByUid() {
System.out.println(userService.getByUid(9));
}
@Test
public void changeInfo() {
User user = new User();
user.setPhone("13932243424");
user.setEmail("[email protected]");
user.setGender(0);
userService.changeInfo(9,"管理员",user);
}
/users/get_by_uid
GET
HttpSession session
JsonResult
2.点击修改按钮发送用户的数据修改操作请求的设计/users/change_info
POST
User user, HttpSession session
JsonResult
@RequestMapping("get_by_uid")
public JsonResult<User> getByUid(HttpSession session) {
User data = userService.getByUid(getuidFromSession(session));
return new JsonResult<>(OK, data);
}
@RequestMapping("change_info")
public JsonResult<Void> changeInfo(User user, HttpSession session) {
//user对象有四部分的数据:username、phone、email、gender
//uid也要封装到user对象中
Integer uid = getuidFromSession(session);
String username = getUsernameFromSession(session);
userService.changeInfo(uid,username,user);
return new JsonResult<>(OK);
}
1.在打开userdata.html页面自动发送ajax请求(get_by_uid),查询到的数据填充到这个页面。
<script type="text/javascript">
/**
* $(document).ready(function() {
* //业务代码
* });
*/
$(document).ready(function() {
$.ajax({
url: "/users/get_by_uid",
type: "get",
data: $("#form-change-info").serialize(),
dataType: "JSON",
success: function (json) {
if(json.state == 200) {
$("#username").val(json.data.username);
$("#phone").val(json.data.phone);
$("#email").val(json.data.email);
let radio = json.data.gender == 0 ?
$("#gender-female") : $("#gender-male");
//prop()表示给某个元素添加属性及属性的值
radio.prop("checked","checked");
} else {
alert("用户的数据不存在");
}
},
error: function (xhr) {
alert("查询用户信息时产生未知的异常" + xhr.message);
}
});
});
</script>
2.在检测到用户点击了修改按钮之后,发送一个ajax请求(change_info)。
$("#btn-change-info").click(function () {
$.ajax({
url: "/users/change_info",
type: "post",
data: $("#form-change-info").serialize(),
dataType: "JSON",
success: function (json) {
if(json.state == 200) {
alert("用户信息修改成功");
location.href = "userdata.html";
} else {
alert("用户信息修改失败");
}
},
error: function (xhr) {
alert("用户信息修改时产生未知的异常" + xhr.message);
}
});
});
update t_user set avatar = ?, modified_user = ?, modified_time = ? where uid = ?;
//根据用户uid值来修改用户的头像
/*
@Param("Sql映射文件中#{}占位符的变量名")
解决的问题:当SQL语句的占位符和映射的接口方法参数名不一致时,需要将某个参数强行注入到某个占位符变量上时
可以用@Param这个注解来标注映射关系
*/
Integer updateAvatarByUid(
@Param("uid") Integer uid,
@Param("avatar") String avatar,
@Param("modifiedUser") String modifiedUser,
@Param("modifiedTime") Date modifiedTime);
<update id="updateAvatarByUid">
update t_user
set
avatar = #{avatar},
modified_user = #{modifiedUser},
modified_time = #{modifiedTime}
where
uid = #{uid}
update>
@Test
public void updateAvatarByUid() {
userMapper.updateAvatarByUid(9,"/upload/avatar.png","管理员",new Date());
}
规划异常
1.用户数据不存在,找不到对应的用户数据
2.更新的时候,各种未知异常产生
无需重复开发
设计接口和抽象方法
//修改用户的头像
void changeAvatar(Integer uid, String avatar, String username);
实现抽象方法
@Override
public void changeAvatar(Integer uid, String avatar, String username) {
User result = userMapper.fndByUid(uid);
if(result == null || result.getIsDelete().equals(1)) {
throw new UserNotFoundException("用户数据不存在");
}
Integer rows = userMapper.updateAvatarByUid(uid, avatar, username, new Date());
if(rows != 1) {
throw new UpdateException("更新用户头像产生未知异常");
}
}
在测试类中测试
@Test
public void changeAvatar() {
userService.changeAvatar(9,"/upload/test.png","小明");
}
文件异常的父类:
FileUploadException:泛指文件上传的异常(父类)继承RuntimeException
子类:
FileEmptyException:文件为空的异常
FileSizeException:文件大小超出限制
FileStateException:文件状态异常(比如已经打开)
FileTypeException:文件类型异常
FileUploadIOException:文件读写的异常
五个构造方法显示的声明出来,去继承父类
else if (e instanceof FileEmptyException) {
result.setState(6000);
} else if (e instanceof FileSizeException) {
result.setState(6001);
} else if (e instanceof FileTypeException) {
result.setState(6002);
} else if (e instanceof FileStateException) {
result.setState(6003);
} else if (e instanceof FileUploadIOException) {
result.setState(6004);
}
然后在异常统一处理方法的参数列表上增加新的异常处理作为它的参数。@ExceptionHandler({ServiceException.class, FileUploadException.class})
/users/change_avatar
post (get请求提交数据2KB)
HttpSession session, MutipartFile file
JsonResult
//设置上传文件的最大值
public static final int AVATAR_MAX_SIZE = 10 * 1024 * 1024;
//限制上传文件的类型
public static final List<String> AVATAR_TYPE = new ArrayList<>();
static {
AVATAR_TYPE.add("images/jpeg");
AVATAR_TYPE.add("images/png");
AVATAR_TYPE.add("images/bmp");
AVATAR_TYPE.add("images/gif");
}
/*
MultipartFile接口是SpringMVC提供的一个接口,这个接口为我们包装了获取文件类型的数据(任何类型的file都可以接收)
SpringBoot它又整合了SpringMVC,只需要在处理请求的方法参数列表上声明一个参数类型为MultipartFile的参数,
然后SpringBoot自动将传递给服务器的文件数据赋值给这个参数。
@RequestParam:表示请求中的参数,将请求中的参数注入请求处理方法的某个参数上,
如果名称不一致则可以使用@RequestParam注解进行标记和映射
*/
@RequestMapping("change_avatar")
public JsonResult<String> changeAvatar(HttpSession session, @RequestParam("file") MultipartFile file) {
if(file.isEmpty()) {
throw new FileEmptyException("文件为空");
}
if(file.getSize() > AVATAR_MAX_SIZE) {
throw new FileSizeException("文件超出限制大小");
}
//判断文件的类型是否是我们规定的后缀类型
String contentType = file.getContentType();
if(!AVATAR_TYPE.contains(contentType)) {
throw new FileTypeException("文件类型不支持");
}
String parent = session.getServletContext().getRealPath("upload");
//File对象指向这个路径,File是否存在
File dir = new File(parent);
if(!dir.exists()) { //检测目录是否存在
dir.mkdirs(); //创建当前目录
}
//获取到这个文件名称,UUID工具类生成一个新的字符串作为文件名
String originalFilename = file.getOriginalFilename();
System.out.println("OriginalFilename:" + originalFilename);
int index = originalFilename.lastIndexOf(".");
String suffix = originalFilename.substring(index);
String filename = UUID.randomUUID().toString().toUpperCase() + suffix;
File dest = new File(dir, filename); //空文件
//参数file中数据写入到这个空文件汇总
try {
file.transferTo(dest);
} catch (IOException e) {
throw new FileUploadIOException("文件读写异常");
}catch (FileStateException e) {
throw new FileStateException("文件状态异常");
}
Integer uid = getuidFromSession(session);
String username = getUsernameFromSession(session);
//返回头像的路径 /upload/test.png
String avatar = "/upload" + filename;
userService.changeAvatar(uid, avatar,username);
//返回用户头像的路径给前端页面,将来用于头像展示使用
return new JsonResult<>(OK,avatar);
}
在upload页面中编写上传头像的代码。
说明:如果直接使用表单进行文件的上传,需要给表单显示的添加一个属性enctype=“multipart/form-data”,表示不会将目标文件的数据结构做修改再上传。
1. 上传的图片超出1MB:更改默认的大小限制
SpringMVC默认1MB大小的文件可以进行上传,手动的去修改SpringMVC默认上传文件的大小。
直接在配置文件中进行配置:
spring.servlet.multipart.maxFileSize=10MB
spring.servlet.multipart.maxRequestSize=15MB
2. 显示头像
在页面中通过ajax请求来提交文件,提交完成后返回了json串,解析出data中数据,设置到img头像标签的src属性上。
new FormData($("#form")[0]);
processData: false, //处理数据的形式,关闭处理数据
contentType: false, //提交数据的形式,关闭默认提交数据的形式
<script type="text/javascript">
$("#btn-change-avatar").click(function () {
$.ajax({
url: "/users/change_avatar",
type: "post",
data: new FormData($("#form-change-avatar")[0]),
processData: false, //处理数据的形式,关闭处理数据
contentType: false, //提交数据的形式,关闭默认提交数据的形式
dataType: "JSON",
success: function (json) {
if(json.state == 200) {
alert("头像修改成功");
//将服务器端返回的头像地址设置img标签的src属性上
//attr(属性,属性的值)
$("#img-avatar").attr("src", json.data);
} else {
alert("头像修改失败");
}
},
error: function (xhr) {
alert("修改头像时产生未知的异常" + xhr.message);
}
});
});
</script>
3. 登录后显示头像
可以更新头像成功后,将服务器返回的头像路径保存在客户端cookie对象,然后每次检测到用户打开上传头像页面,在这个页面中通过ready()方法来自动检测去读取cookie中头像并设置到src属性上。
<script src="../bootstrap3/js/jquery.cookie.js" type="text/javascript" charset="utf-8"></script>
在login.html中调用cookie方法if(json.state == 200) {
//alert("登录成功");
location.href = "index.html";
//将服务器返回的头像设置到cookie中
$.cookie("avatar",json.data.avatar,{expires: 7});
}
$(document).ready(function () {
let avatar = $.cookie("avatar");
//将cookie值获取出来设置到头像的src属性上
$("#img-avatar").attr("src", avatar);
});
4. 显示最新的头像
在更改完头像后,将最新的头像地址,再次保存到cookie,同名保存会覆盖cookie中的值。
//将头像保存在cookie中
$.cookie("avatar",json.data,{expires: 7});