第12课:个人资料修改页面
正式开始本文内容前,我们先做下准备,即在 WEB-INF
下的 personal 文件夹下导入个人资料修改页面 profile.jsp 文件。
通过访问个人主页的修改个人资料进入个人资料修改页面,如图:
点击事件如下:
<a href="${ctx}/profile" >< i class = "icon icon-edit" > </ i > < span style = "margin-left: 10px" > 修改个人资料 </ span > </ a >
如果不想 a 标签出现下划线,可将 a 标签的 style 属性的 text-decoration
值设置为 none,如下:
style ="text-decoration: none"
因为个人资料页面 profile.jsp 在 WEN-INF
下,所以要经过 Controller 处理后跳转,在 PersonalController.java 内添加映射 URL 为 /profile
的方法,如下:
@Autowired
private UserInfoService userInfoService;
@RequestMapping ( "/profile" )
public String profile ( Model model) {
User user = ( User) getSession ( ) . getAttribute ( "user" ) ;
if ( user== null) {
return "../login" ;
}
UserInfo userInfo = userInfoService. findByUid ( user. getId ( ) ) ;
model. addAttribute ( "user" , user) ;
model. addAttribute ( "userInfo" , userInfo) ;
return "personal/profile" ;
}
代码解读如下:
(1)从 Session 中取出用户信息,判断用户是否登录,未登录则跳转登录。
(2)用户登录后,根据用户 id 查询出用户详细信息 userInfo,将 user 和 userInfo 都放入 model 中。
(3)返回到 personal 目录下的 profile.jsp 页面。
重启项目后,点击修改个人资料进入个人资料修改页面,效果如下:
个人资料修改页面准备分四部分来讲:
修改个人头像 基本设置 账号设置 绑定设置
修改个人头像
思路就这样的:通过点击头像图片,弹出选择图片窗口,弹出选择窗口需要将 input 框的 type 设置为 file,选择好图片以后,触发 onchange 事件,发送AJAX,通过提交 form 表单将图片上传,success 回调函数返回上传图片路径,将原图片的 src 路径替换,完成修改个人头像。
个人头像 a 标签及 form 表单代码如下:
<a title="${user.nickName}" class ="avatar" >< img id = "img-change" src = "${user.imgUrl}" onclick = "selectImg();" width = "100" height = "100" style = "border-radius:50%;margin-top: 60px;margin-left: 90px" > </ a >
<form id="upload-form" style="width:auto;" >
< input type = "file" id = "change-img" name = "uploadImg" onchange = "changeImg();" style = "display:none;" >
</ form >
1. 事件源
头像的点击事件 onclick 具体方法如下:
function selectImg ( ) {
document .getElementById("change-img" ).click();
}
获取 id 为 change-img
的对象,触发其点击事件,即弹出图片选择窗口。图片选择完毕以后触发 onchange 事件,onchange 事件方法如下:
function changeImg ( ) {
var formData = new FormData ( $ ( "#upload-form" ) [ 0 ] ) ;
$. ajax ( {
url: '/fileUpload' ,
type: 'POST' ,
data: formData,
async : false ,
cache: false ,
contentType: false ,
processData: false ,
success: function ( data) {
var msg = data[ "error" ] ;
if ( msg== 0 ) {
var url = data[ "url" ] ;
document. getElementById ( "img-change" ) . src = url;
saveImg ( url) ;
}
}
} ) ;
}
function saveImg ( url) {
$. ajax ( {
type: 'post' ,
data: { "url" : url} ,
url: '/saveImage' ,
dataType: 'json' ,
success: function ( data) {
}
} ) ;
}
代码解读如下:
(1)根据 form 表单的 id 通过 new FormData 获取表单对象数据,赋值给 formData。
(2)发送 AJAX,映射 URL 为:/fileUpload
,对应之前上传文件的 UploadController,上传方式为 post 方式,请求参数 data 为 formData。
(3)回调函数 success 返回数据 data,通过 data["error"]
获取上传状态,如果为0说明上传成功,根据 data["url"]
获取上传成功后的图片路径赋值给 URL,然后根据 id 获取 img 标签对象,将其 src 属性值重新赋值为 URL,实现更换头像。
(4)然后调用保存头像方法 saveImg,接收的参数是刚才回调函数返回的URL。
(5)保存头像的方法也是一个 AJAX 异步请求,请求参数 data 是图片的路径 URL,回调函数可返回保存头像的结果,成功还是失败。
2. Java 后台
对应映射 URL 为 /fileUpload
的方法还是之前说过的 UploadController 内的上传文件方法,这里不再赘述。
在 PersonalController 内添加映射 URL 为 /saveImage
的方法:
@Autowired
private UserService userService;
@RequestMapping ("/saveImage" )
@ResponseBody
public Map<String,Object> saveImage (Model model,@RequestParam(value = "url" ,required = false ) String url) {
Map map = new HashMap<String,Object>( );
User user = (User)getSession().getAttribute("user" );
user.setImgUrl(url);
userService.update(user);
map.put("msg" ,"success" );
return map;
}
代码解读如下:
(1)从 Session 中获取用户信息。
(2)将前台传过来的 URL 通过 set 方法赋值给 user 的 imgUrl 属性。
(3)调用 userService 的 update 方法更新用户信息。
(4)将 success 放入 map,返回给前台。
3. 重新启动项目,点击更换头像,效果如下:
发现
个人头像修改之后,发现首页的文章作者头像并未改变。这是我之前挖的一个坑,肯定会有人和我想的一样,想着查询文章信息的时候把用户的昵称和头像也一起查出来,方便省事,事实证明这样做是不好的。因为用户更新了昵称或者个人头像时,都要去更新一遍 user_content
表的 nick_name
和 img_url
字段,这样频繁操作数据库太耗性能。应该怎么解决呢?
解决方法就是使用两表关联查询。查询文章的时候根据用户 id 关联查询用户表 uesr 和文章表 user_content
。这里使用左连接查询:
select u1.*,u2.nick_name name ,u2.img_url url from user_content u1 LEFT JOIN user u2 on u1.u_id = u2.id
代码解读如下:
(1)给 user_content
表起别名为 u1,给 user 表取别名为 u2,起别名主要用于区分和操作表。
(2)select u1.*,u2.nick_name name,u2.img_url url
是指查询 user_content
表中的所有字段、user 表中的 nick_name
和 img_url
字段,并给 nick_name
起别名为 name,给 img_url
起别名为 url。
(3)from user_content u1 LEFT JOIN user u2
是指查询从 user_content
表左连接 user 表,LEFT JOIN 左连接,是指查询的结果以左表为主表,右表为副表,即以 user_content
表为主表,user 表为副表,副表没有数据的字段用 null 补充。
(4)on u1.u_id = u2.id
是指连接条件:user_content
表的 u_id
和 user 表的 id 要相同。
查询效果演示如图:
具体步骤如下:
1. 在 UserContentMapper 接口中增加连接查询方法:
List <UserContent> findByJoin(UserContent userContent);
2. 在映射文件 userContent.xml
中增加查询 SQL:
< ! -- user_content和user表连接查询-- >
< select id= "findByJoin" resultMap= "joinMap" >
select u1. id, u1. u_id, u1. title, u1. category, u1. personal, u1. rpt_time, u1. upvote, u1. downvote, u1. comment_num, u1. content, u2. nick_name nickName, u2. img_url imgUrl from user_content u1 LEFT JOIN user u2 on u1. u_id = u2. id
< where>
< choose>
< when test= 'id!=null and id!=""' >
u1. id = #{ id}
< / when>
< otherwise>
< if test= 'personal!=null and personal!=""' >
u1. personal = #{ personal}
< / if >
< if test= 'personal==null or personal==""' >
u1. personal = '0'
< / if >
< / otherwise>
< / choose>
< / where>
< if test= 'uId!=null and uId!=""' >
and u1. u_id = #{ uId}
< / if >
order by u1. rpt_time desc
< / select>
< resultMap type= "wang.dreamland.www.entity.UserContent" id= "joinMap" >
< ! -- property 表示wang. dreamland. www. entity. UserContent; column 表示表中的列名 -- >
< id property= "id" column= "id" / >
< result property= "uId" column= "u_id" / >
< result property= "title" column= "title" / >
< result property= "category" column= "category" / >
< result property= "personal" column= "personal" / >
< result property= "rptTime" column= "rpt_time" / >
< result property= "imgUrl" column= "img_url" / >
< result property= "nickName" column= "nick_name" / >
< result property= "upvote" column= "upvote" / >
< result property= "downvote" column= "downvote" / >
< result property= "commentNum" column= "comment_num" / >
< result property= "content" column= "content" / >
< / resultMap>
代码解读如下:
(1)id=findByJoin
对应的是 UserContentMapper 接口中的方法名,joinMap 对应某个 resultMap 的唯一 id。
(2)查询 SQL 中没有使用 select *
语句,select *
会降低查询效率,这里把需要查询的字段一一列举出来。注意 其中没有 u1.img_url
和 u1.nick_name
,如果加上会覆盖我们的查询结果,我们要的是 user 表中的 imgUrl 和 nickName,还有别名 nickName、imgUrl 要和 UserContent 实体类中的属性对应,主要是通过属性的 setter 方法赋值,页面通过 getter 方法取值的。
(3)where 标签,当标签内条件成立时会形成 where 语句,choose 标签是一个整体,里面的 when 和 otherwise 标签相当于 if 和 else 的作用,如果文章 id 不为空则根据文章 id 查询,否则如果 personal 为空,则默认查询非私密的所有文章,如果 personal 属性不为空,则通过 #{personal}
以占位符的形式接收 personal 的值进行条件查询
(4)后面的 if 标签表示如果 uId 不为空,则增加查询条件,用 and 连接,并且根据用户 id 查询。
后面的 order by u1.rpt_time desc
是指按时间倒序。
(5)resultMap 标签是结果集的封装,其中 type 代表的是 UserContent 的实体类,给该 resultMap 取一个唯一的 id,供其他 SQL 语句引用。
result 标签中的 property 对应实体类的属性,column 对应表中的字段(列名),通过实体类属性的 setter 方法赋值。
其实这里可以将 user_content
表中的 img_url
和 nick_name
字段删除,将 UserContent 实体类中的 imgUrl 和 nickName 属性上加上 @Transient
注解,代表表中没有此字段。我这里就不操作了,你们可以试一下。
3. 将自定义过滤器 IndexJspFilter 中的方法修改如下:
public void doFilter ( ServletRequest request, ServletResponse response, FilterChain chain ) throws IOException, ServletException {
System.out .println("===========自定义过滤器==========" );
ServletContext context = request.getServletContext();
ApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(context);
UserContentMapper userContentMapper = ctx.getBean(UserContentMapper.class);
PageHelper.startPage(null , null );
List<UserContent> list = userContentMapper.findByJoin(null );
PageHelper.Page endPage = PageHelper.endPage();
request.setAttribute("page" , endPage );
chain.doFilter(request, response);
}
直接调用 userContentMapper 的 findByJoin方法,参数为null,默认查询非私密文章。
4. 将实现类 UserContentServiceImpl 中的三个方法修改如下:
public Page< UserContent> findAll ( UserContent content, Integer pageNum, Integer pageSize) {
System. out. println ( "第" + pageNum+ "页" ) ;
System. out. println ( "每页显示:" + pageSize+ "条" ) ;
PageHelper. startPage ( pageNum, pageSize) ;
List< UserContent> list = userContentMapper. findByJoin ( content) ;
Page endPage = PageHelper. endPage ( ) ;
List< UserContent> result = endPage. getResult ( ) ;
return endPage;
}
public Page< UserContent> findAll ( Integer pageNum, Integer pageSize) {
PageHelper. startPage ( pageNum, pageSize) ;
List< UserContent> list = userContentMapper. findByJoin ( null) ;
Page endPage = PageHelper. endPage ( ) ;
return endPage;
}
public UserContent findById ( long id) {
UserContent userContent = new UserContent ( ) ;
userContent. setId ( id ) ;
List< UserContent> list = userContentMapper. findByJoin ( userContent) ;
if ( list!= null && list. size ( ) > 0 ) {
return list. get ( 0 ) ;
} else {
return null;
}
}
主要是将原来使用 Mapper 的通用方法改成我们自定义的连接查询的方法。
根据文章 id 查询的时候如果有返回结果,只会有一个,所以这里取 list 集合的第一个元素,没有则返回 null。
基本设置
首先说下,这里点击 tab 切换的原理和之前的个人主页的切换原理是一样的。都是通过显示和隐藏来达到切换的效果。比如点击基本设置对应的点击事件如下:
function base_set ( ) {
document. getElementById ( "base" ) . style. backgroundColor = "white" ;
document. getElementById ( "account" ) . style. backgroundColor = "#D1D1D1" ;
document. getElementById ( "binding" ) . style. backgroundColor = "#D1D1D1 " ;
document. getElementById ( "set_title" ) . innerHTML = "基本设置" ;
document. getElementById ( "base_content" ) . style. display = "" ;
document. getElementById ( "account_content" ) . style. display = "none" ;
document. getElementById ( "binding_content" ) . style. display = "none" ;
}
代码解读如下:
(1)将“基本设置”的背景色设置为白色,“账号设置”和“绑定设置”的背景色设置为 #D1D1D1
,和左边背景色一致。
(2)将右侧的标题改为“基本设置”。
(3)将“基本设置”的 display 属性设置为空,即可见。“账号设置”和“绑定设置”的 display 属性设置为 none,即不可见。
右边 div 是一个普通的 form 表单,很简单,这里只说下生日对应的 input 框,我们点击 input 框后弹出日期插件,可供我们选择日期。
日期插件
这里使用的是 ZUI 提供的日期插件,
使用方法说的很明白,主要做三件事情。
1. 单独引入日期插件的 CSS 和 JS 文件。
<link href="${ctx}/css/zui/lib/datetimepicker/datetimepicker.min.css" rel="stylesheet" >
< script src = "${ctx}/css/zui/lib/datetimepicker/datetimepicker.min.js" > </ script >
2. 给 input 框加上指定的 class 属性 form-control form-date
。
<input style="width: 198px;float: right;margin-right: 484px;margin-top: -4px" class ="form-control form-date" readonly="readonly" placeholder="选择一个日期:yyyy-MM-dd" type="text" id="txtEndDate" name="birthday" value="${userInfo.formateBirthday==null?" ":userInfo.formateBirthday}" />< br /> < br />
其它的样式是我加上去的,一个靠右浮动,调整 input 框的长度,以及距离右边的距离,主要是为了与页面协调。
value 中的 EL 表达式是判断 userInfo 的生日是否为空,如果不为空则显示其生日,主要是一个生日信息回显的作用。因为 UserInfo 实体类中没有 getFormateBirthday 方法,所以创建此方法:
public String getFormateBirthday () {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd" );
return simpleDateFormat.format(birthday);
}
主要是将日期类型 birthday 转成字符串类型。
readonly="readonly"
是只读属性,只允许用户选择日期,不可手动输入。
3. 手动调用初始化函数。
$(".form-date" ).datetimepicker(
{
language : "zh-CN" ,
weekStart : 1 ,
todayBtn : 1 ,
autoclose : 1 ,
todayHighlight : 1 ,
startView : 2 ,
minView : 2 ,
forceParse : 0 ,
format : "yyyy-mm-dd"
});
主要是根据 class 属性获取对象,然后调用 datetimepicker 方法进行一些初始化操作。
查看页面效果如下:
感觉还不错!因为我们是做 Java 后台的,页面效果这块肯定没有前端写的好,所以我们要学会利用一些前端框架,将一些组件和插件直接拿来使用。开发时间长了之后,慢慢的也会掌握一些前端开发技能。
保存个人信息
1. 首先看下 form 标签:
<form id="userInfo_form" action=" ${ctx} /saveUserInfo" method="post" >
action 对应的后台映射 URL 为 saveUserInfo
,请求方式为 post 请求。
2. 点击保存对应的点击事件如下:
function saveUserInfo ( ) {
$("#userInfo_form" ).submit();
}
很简单,只有一行代码,就是获取 form 表单对象之后,调用它的 submit 方法进行提交表单。
3. PersonalController.java 中创建映射 URL saveUserInfo
的方法:
@Autowired
private UserInfoService userInfoService;
@Autowired
private UserService userService;
@RequestMapping ( "/saveUserInfo" )
public String saveUserInfo ( Model model, @RequestParam ( value = "name" , required = false ) String name ,
@RequestParam ( value = "nick_name" , required = false ) String nickName,
@RequestParam ( value = "sex" , required = false ) String sex,
@RequestParam ( value = "address" , required = false ) String address,
@RequestParam ( value = "birthday" , required = false ) String birthday) {
User user = ( User) getSession ( ) . getAttribute ( "user" ) ;
if ( user== null) {
return "../login" ;
}
UserInfo userInfo = userInfoService. findByUid ( user. getId ( ) ) ;
boolean flag = false ;
if ( userInfo == null) {
userInfo = new UserInfo ( ) ;
} else {
flag = true ;
}
userInfo. setName ( name) ;
userInfo. setAddress ( address) ;
userInfo. setSex ( sex) ;
Date bir = DateUtils. StringToDate ( birthday, "yyyy-MM-dd" ) ;
userInfo. setBirthday ( bir) ;
userInfo. setuId ( user. getId ( ) ) ;
if ( ! flag) {
userInfoService. add ( userInfo) ;
} else {
userInfoService. update ( userInfo) ;
}
user. setNickName ( nickName) ;
userService. update ( user) ;
model. addAttribute ( "user" , user) ;
model. addAttribute ( "userInfo" , userInfo) ;
return "personal/profile" ;
}
代码解读如下:
(1)首先从 Session 中取出 User,判断是否为空,如果为空,跳转到登录页面。
(2)User 不为空后,根据用户 id 查询出 UserInfo 信息,如果信息不存在,则 new 一个 UserInfo,默认 flag 为 flase,信息存在则 flag 置为 true。
(3)通过set方法将前台传来的参数封装到UserInfo对象中,如果flag 为 false,则代表是插入用户详细信息。如果 flag 为 true 则代表是更新用户详细信息。
(4)更新用户表的昵称信息。
(5)将 user 和 userInfo 对象添加到 model 中,然后返回到个人信息修改页面。
重新启动项目,填写个人信息保存后效果如图:
账号设置
点击“账号设置”切换 tab 和改变右边信息这里就不说了,和上面的原理一样,页面效果如下:
修改密码
首先在 WEB-INF/personal/
目录下引入 repassword.jsp 和 passwordSuccess.jsp,分别是修改密码页面和密码修改成功页面。
修改密码对应的 a 标签:
< a href = "${ctx}/repassword" > < span id = "password_span" style = "color: grey" onmouseover = "changeColor(this);" onmouseout = "backColor(this);" > 修改 </ span > </ a >
其中,
代表一个空格。onmouseover 鼠标悬浮改变字体颜色为紫色,onmouseout 鼠标移除时字体颜色变为灰色。
a 标签的 href 属性链接的 URL 为 /repassword
,在 PersonalController 中创建与之对应的方法,如下:
@RequestMapping ("/repassword" )
public String repassword (Model model) {
User user = (User) getSession().getAttribute("user" );
if (user!=null ) {
model.addAttribute("user" ,user);
return "personal/repassword" ;
}
return "../login" ;
}
主要是从 Session 获取用户 User,判断如果不为空,则把 user 添加到 model 然后返回到修改密码页面,否则跳转到登录页面。
重新启动项目,进入个人信息修改页面,点击密码的“修改”进入修改密码页面,如下:
需要对密码框做如下校验:
密码长度不能小于6位; 旧密码和新密码不能一样; 新密码和确认密码输入必须一致。
1. 旧密码 input 框的离焦事件如下:
var f1 = false ;
function oldPassword ( ) {
var old = $("#old_password" ).val();
if (old==null || old.trim()=='' ){
document .getElementById("old_span" ).innerHTML = "请输入密码!" ;
f1 = false ;
}else if (old.length < 6 ){
document .getElementById("old_span" ).innerHTML = "密码长度少于6位,请重新输入!" ;
f1 = false ;
}
else {
document .getElementById("old_span" ).innerHTML = "" ;
f1 = true ;
}
}
代码解读如下:
(1)定义变量 f1 赋初始值为 false,表示该 input 框状态错误,不可提交表单。
(2)获取旧密码框输入的值,如果为空则提示请输入密码,如果密码长度低于6位则提示密码长度少于6位,请重新输入,f1 都为 false。
(3)否则清空 span 标签内内容,f1 置为true。
2. 新密码 input 框的离焦事件如下:
var f2 = false ;
function newPassword ( ) {
var p = $ ( "#password" ) . val ( ) ;
var old = $ ( "#old_password" ) . val ( ) ;
if ( p== null || p. trim ( ) == '' ) {
document. getElementById ( "old_span" ) . innerHTML = "请输入密码!" ;
f2 = false ;
} else if ( p. length < 6 ) {
$ ( "#old_span" ) . text ( "密码长度少于6位,请重新输入!" ) . css ( "color" , "red" ) ;
f2 = false ;
} else if ( p== old) {
$ ( "#old_span" ) . text ( "新密码与旧密码一致,请重新输入!" ) . css ( "color" , "red" ) ;
f2 = false ;
}
else {
document. getElementById ( "old_span" ) . innerHTML = "" ;
f2 = true
}
}
代码解读如下:
(1)定义变量 f2 赋初始值为 false,表示该 input 框状态错误,不可提交表单。
(2)获取旧密码框和新密码框输入的值,如果新密码为空则提示请输入密码,如果新密码长度低于6位则提示密码长度少于6位,请重新输入,如果新密码和旧密码一致,则提示相应错误,f2 都为false。
(3)否则清空 span 标签内内容,f2 置为 true。
3. 确认密码 input 框的离焦事件如下:
var f3 = false ;
function rePassword ( ) {
var p = $("#repassword" ).val();
var p1 = $("#password" ).val();
if (p==null || p.trim()=='' ){
document .getElementById("old_span" ).innerHTML = "请输入密码!" ;
f3 = false ;
}else if (p!=p1){
document .getElementById("old_span" ).innerHTML = "两次密码不一致!" ;
f3 = false ;
}
else {
document .getElementById("old_span" ).innerHTML = "" ;
f3 = true
}
}
代码解读如下:
(1)定义变量 f3 赋初始值为 false,表示该 input 框状态错误,不可提交表单。
(2)获取新密码框和确认密码框输入的值,如果确认密码为空则提示请输入密码,如果确认密码和新密码不一致,则提示相应错误,f3 都为 false。
(3)否则清空 span 标签内内容,f3 置为true。
4. 提交表单
form 标签如下:
<form action=" ${ctx} /updatePassword" method="post" id="update_password" >
action 对应的请求 URL 为 /updatePassword
,请求方式为 post 请求。
确认按钮的点击事件 surePost 方法如下:
function surePost ( ) {
if (f1 && f2 && f3){
$("#update_password" ).submit();
}<span class="hljs-keyword"><span class="hljs-keyword"><span class="hljs-keyword">else</span></span></span> {
$(<span class="hljs-string"><span class="hljs-string"><span class="hljs-string">"#old_span"</span></span></span>).text(<span class="hljs-string"><span class="hljs-string"><span class="hljs-string">"请重新输入密码!"</span></span></span>).css(<span class="hljs-string"><span class="hljs-string"><span class="hljs-string">"color"</span></span></span>,<span class="hljs-string"><span class="hljs-string"><span class="hljs-string">"red"</span></span></span>);
}
}
function surePost ( ) {
if ( f1 && f2 && f3) {
$ ( "#update_password" ) . submit ( ) ;
} else {
$ ( "#old_span" ) . text ( "请重新输入密码!" ) . css ( "color" , "red" ) ;
}
}
如果上面的校验都成功则提交表单,否则提示错误“请重新输入密码!”。
在 PersonalController 中创建映射 URL 为 /updatePassword
的方法如下:
@RequestMapping ( "/updatePassword" )
public String updatePassword ( Model model, @RequestParam ( value = "old_password" , required = false ) String oldPassword,
@RequestParam ( value = "password" , required = false ) String password) {
User user = ( User) getSession ( ) . getAttribute ( "user" ) ;
if ( user!= null) {
oldPassword = MD5Util. encodeToHex ( Constants. SALT + oldPassword) ;
if ( user. getPassword ( ) . equals ( oldPassword) ) {
password = MD5Util. encodeToHex ( Constants. SALT + password) ;
user. setPassword ( password) ;
userService. update ( user) ;
model. addAttribute ( "message" , "success" ) ;
} else {
model. addAttribute ( "message" , "fail" ) ;
}
}
model. addAttribute ( "user" , user) ;
return "personal/passwordSuccess" ;
}
代码解读如下:
(1)通过 Session 获取用户 User。
(2)如果用户不为空,则根据旧密码进行 MD5 加密后与数据库中的密码进行比较,如果相同则说明密码输入正确,将新密码进行 MD5 加密后替换掉旧密码,然后更新用户信息,并将“success”添加到 model 中,如果不相同则说明密码输入错误,则将“fail”添加到 model 中。
(3)将 user 添加到 model 中,返回修改密码成功页面。
重启项目,修改密码,第一次输入错误密码,修改失败后效果如图:
点击返回按钮,返回到修改密码页面。
第二次输入正确的密码,修改成功后效果如图:
点击重新登录(/loginout
),即先退出登录然后返回到登录页面。
修改手机号
修改手机号这里就不实现了,具体思路如下:
点击手机号“修改”后首先进行密码确认或者手机验证码确认。 输入正确密码或者手机验证码后进入更换手机号页面。 输入手机号,手机号必须是非注册手机号,然后点击获取验证码,输入验证码正确则更换手机号成功!
绑定设置,我们将在下一课中介绍。
第12课百度网盘地址:
链接:https://pan.baidu.com/s/1WnKCHBFewqEfqljVRU947Q 密码:wfmm