1.用户信息页面跳转及信息展示
用户模块不只有登录、注册功能,还包括用户信息展示、头像上传、用户信息修改、安全退出等功能。用户信息功能的主要实现步骤为三步:
- 用户信息页面跳转请求实现
- 用户信息页面样式设置
- 用户信息页面信息展示
1.1 Controller 处理跳转请求
在 BBSUserController.java 控制器中新增用户信息跳转处理功能。该方法用于处理 /userSet 请求,即用户信息页面的跳转处理,由于用户信息页面需要展示的是登录者的用户信息,而登录者的信息已经在登录成功后,放入 session 对象中,所以这里并不需要进行额外的查询操作,将 session 对象中的对象取出并放入 request 域中即可。之后 return 视图语句,跳转到 templates/user 目录下的 set.html 中。
/**
* 用户信息页面跳转
* @param request
* @return
*/
@GetMapping("/userSet")
public String userSetPage(HttpServletRequest request) {
// 从session中获取登陆用户的信息
BBSUser currentUser = (BBSUser) request.getSession().getAttribute(Constants.USER_SESSION_KEY);
request.setAttribute("bbsUser", currentUser);
return "user/set";
}
1.2 配置登陆拦截器
这里还需要在拦截器配置中,将 /userSet 请求进行拦截设置,即登录成功后才可以访问用户信息页面,否则会跳转至登录页面。
public void addInterceptors(InterceptorRegistry registry) {
// 登陆拦截
registry.addInterceptor(myBBSLoginInterceptor)
.excludePathPatterns("/register")
.excludePathPatterns("/login")
.addPathPatterns("/index")
.addPathPatterns("/userSet");
}
1.3 创建用户中心设置页面
使用 Thymeleaf 语法读取用户信息,包括用户头像、用户名等内容,代码为:
th:src="@{${bbsUser.headImgUrl}}"
th:value="${bbsUser.loginName}"
th:value="${bbsUser.location}"
th:text="${bbsUser.introduce}"
新建 set.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head th:replace="header::head-fragment('基本设置')">
</head>
<body>
<div th:replace="header::header-fragment"></div>
<div class="layui-container fly-marginTop fly-user-main">
<ul class="layui-nav layui-nav-tree layui-inline" lay-filter="user">
<li class="layui-nav-item">
<a th:href="@{${'/userCenter/'+bbsUser.userId}}">
<i class="layui-icon"></i>
我的主页
</a>
</li>
<li class="layui-nav-item">
<a th:href="@{/myCenter}">
<i class="layui-icon"></i>
用户中心
</a>
</li>
<li class="layui-nav-item layui-this">
<a th:href="@{/userSet}">
<i class="layui-icon"></i>
基本设置
</a>
</li>
</ul>
<div class="fly-panel fly-panel-user" pad20>
<div class="layui-tab layui-tab-brief" lay-filter="user">
<ul class="layui-tab-title" id="LAY_mine">
<li class="layui-this" lay-id="info">我的资料</li>
<li lay-id="avatar">头像</li>
<li lay-id="pass">密码</li>
</ul>
<div class="layui-tab-content" style="padding: 20px 0;">
<div class="layui-form layui-form-pane layui-tab-item layui-show">
<form method="post" id="updateInfoForm" onsubmit="return false;" action="##">
<div class="layui-form-item">
<label for="loginName" class="layui-form-label">邮箱</label>
<div class="layui-input-inline">
<input type="text" id="loginName" name="loginName"
autocomplete="off" th:value="${bbsUser.loginName}" disabled class="layui-input">
</div>
<div class="layui-form-mid layui-word-aux">登录邮箱不可更改</div>
</div>
<div class="layui-form-item">
<label for="nickName" class="layui-form-label">昵称</label>
<div class="layui-input-inline">
<input type="text" id="nickName" name="nickName" required lay-verify="required"
autocomplete="off" th:value="${bbsUser.nickName}" class="layui-input">
</div>
<div class="layui-form-mid layui-word-aux">支持2-8位的英文和数字昵称</div>
</div>
<div class="layui-form-item">
<label for="userGender" class="layui-form-label">性别</label>
<div class="layui-input-inline">
<select name="userGender" id="userGender">
<option value="1" th:selected="${bbsUser.gender=='男'} ?true:false">男</option>
<option value="2" th:selected="${bbsUser.gender=='女'} ?true:false">女</option>
</select>
</div>
</div>
<div class="layui-form-item">
<label for="location" class="layui-form-label">城市</label>
<div class="layui-input-inline">
<input type="text" id="location" name="location" autocomplete="off"
th:value="${bbsUser.location}"
class="layui-input">
</div>
</div>
<div class="layui-form-item layui-form-text">
<label for="introduce" class="layui-form-label">签名</label>
<div class="layui-input-block">
<textarea placeholder="随便写些什么刷下存在感" id="introduce" name="introduce" autocomplete="off"
th:text="${bbsUser.introduce}"
class="layui-textarea" style="height: 80px;"></textarea>
</div>
</div>
<div class="layui-form-item">
<button class="layui-btn" key="set-mine" lay-filter="*" lay-submit onclick="updateInfo()">
确认修改
</button>
</div>
</form>
</div>
<div class="layui-form layui-form-pane layui-tab-item">
<div class="layui-form-item">
<div class="avatar-add">
<p>建议尺寸168*168,支持jpg、png、gif,最大不能超过1M</p>
<button type="button" id="uploadHeadImg" class="layui-btn upload-img">
<i class="layui-icon"></i>上传头像
</button>
<img id="userHeadImg" th:src="@{${bbsUser.headImgUrl}}">
<span class="loading"></span>
</div>
</div>
<div class="layui-form-item">
<button class="layui-btn" key="set-mine" lay-filter="*" lay-submit onclick="updateHeadImg()">
确认修改
</button>
</div>
</div>
<div class="layui-form layui-form-pane layui-tab-item">
<form method="post" id="passwordForm" onsubmit="return false;" action="##">
<div class="layui-form-item">
<label for="originalPassword" class="layui-form-label">当前密码</label>
<div class="layui-input-inline">
<input type="password" id="originalPassword" name="originalPassword" required
lay-verify="required"
autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label for="newPassword" class="layui-form-label">新密码</label>
<div class="layui-input-inline">
<input type="password" id="newPassword" name="newPassword" required
lay-verify="required"
autocomplete="off" class="layui-input">
</div>
<div class="layui-form-mid layui-word-aux">6到20个字符</div>
</div>
<div class="layui-form-item">
<button class="layui-btn" key="set-mine" lay-filter="*" lay-submit onclick="updatePassword()">
确认修改
</button>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="fly-footer">
<p>My-BBS社区 2021 © <a href="填写自己的博客" target="_blank">picacho</a></p>
</div>
<script th:src="@{/layui/layui.js}"></script>
</body>
</html>
1.4 测试跳转用户中心功能
访问http://localhost:8080/userSet。由于有拦截器的缘故会跳转到登陆界面,完成登陆后继续访问该路径就可以登陆到set.html界面了。
2.用户信息修改
用户信息页面中,“我的资料”、“头像”、“密码”三个栏目底部都有一个功能按钮,为“确认修改”。如果想要修改这些信息,也可以对这些用户信息字段进行修改并点击“确认修改”按钮。
这三个功能按钮在点击后都会执行对应的功能,所以在按钮上分别绑定了触发事件,我们需要新增三个 js 方法,分别为 updateInfo() 方法、updateHeadImg() 方法和 updatePassword()方法,作用分别是修改个人信息、修改头像、修改密码。
2.1 修改个人信息
前端页面修改用户信息
updateInfo()方法是修改用户信息,该方法的逻辑如下:
- 前端对用户输入的数据进行简单的正则验证
- 封装用户信息实体的参数
- 向对应的后端修改用户信息接口/updateUserInfo发送 Ajax 请求
- 请求成功后提醒用户请求成功
- 请求失败则提醒对应的错误信息
在set.html文件添加js脚本,实现前端的用户信息上传。
<script th:src="@{/js/public.js}"></script>
<script th:src="@{/js/ajaxupload/ajaxupload.js}"></script>
<script type="text/javascript">
layui.use(['layer', 'element', 'jquery', 'form'], function () {
var layer = layui.layer, $ = layui.$, element = layui.element, form = layui.form;
var device = layui.device();
//阻止IE7以下访问
if (device.ie && device.ie < 8) {
layer.alert('如果您非得使用 IE 浏览器访问社区,那么请使用 IE8+');
}
//修改个人信息
window.updateInfo = function () {
var $ = layui.$;
var nickName = $("#nickName").val();
if (!validUserName(nickName)) {
layer.alert('请输入正确的昵称!', {title: '提醒', skin: 'layui-layer-molv', icon: 2});
return false;
}
var userGender = $('#userGender option:selected').val();
if (isNull(userGender)) {
layer.alert('请选择性别!', {title: '提醒', skin: 'layui-layer-molv', icon: 2});
return;
}
var location = $("#location").val();
if (isNull(location)) {
layer.alert('请输入所在城市!', {title: '提醒', skin: 'layui-layer-molv', icon: 2});
return;
}
var introduce = $("#introduce").val();
if (isNull(introduce)) {
layer.alert('请输入个性签名!', {title: '提醒', skin: 'layui-layer-molv', icon: 2});
return;
}
var params = $("#updateInfoForm").serialize();
var url = '/updateUserInfo';
$.ajax({
type: 'POST',//方法类型
url: url,
data: params,
success: function (result) {
if (result.resultCode == 200) {
layer.alert('修改成功!', {title: '信息', skin: 'layui-layer-molv', icon: 1});
} else {
layer.msg(result.message);
}
;
},
error: function () {
layer.alert('操作失败!', {title: '提醒', skin: 'layui-layer-molv', icon: 2});
}
});
}
});
</script>
修改个人信息接口
该接口负责接收前端发送的修改用户信息的 POST 请求并处理其中的参数,接收的参数为 nickName 字段、userGender 字段、location 字段和 introduce 字段。接口的映射地址为 /updateUserInfo,请求方法为 POST。
/**
* 更新用户基本信息
* @param nickName
* @param userGender
* @param location
* @param introduce
* @param httpSession
* @return
*/
@PostMapping("/updateUserInfo")
@ResponseBody
public Result updateInfo(@RequestParam("nickName") String nickName,
@RequestParam("userGender") int userGender,
@RequestParam("location") String location,
@RequestParam("introduce") String introduce,
HttpSession httpSession) {
if (!StringUtils.hasLength(nickName)) {
return ResultGenerator.genFailResult("nickName参数错误");
}
if (userGender < 1 || userGender > 2) {
return ResultGenerator.genFailResult("userGender参数错误");
}
if (!StringUtils.hasLength(location)) {
return ResultGenerator.genFailResult("location参数错误");
}
if (!StringUtils.hasLength(introduce)) {
return ResultGenerator.genFailResult("introduce参数错误");
}
BBSUser bbsUser = (BBSUser) httpSession.getAttribute(Constants.USER_SESSION_KEY);
bbsUser.setNickName(nickName);
if (userGender == 1) {
bbsUser.setGender("男");
}
if (userGender == 2) {
bbsUser.setGender("女");
}
bbsUser.setLocation(location);
bbsUser.setIntroduce(introduce);
if (bbsUserService.updateUserInfo(bbsUser, httpSession)) {
Result result = ResultGenerator.genSuccessResult();
return result;
} else {
Result result = ResultGenerator.genFailResult("修改失败");
return result;
}
}
业务层
@Override
public Boolean updateUserInfo(BBSUser bbsUser, HttpSession httpSession) {
BBSUser userTemp = (BBSUser) httpSession.getAttribute(Constants.USER_SESSION_KEY);
BBSUser userFromDB = bbsUserMapper.selectByPrimaryKey(userTemp.getUserId());
//当前用户非空且状态正常才可以进行更改
if (userFromDB != null && userFromDB.getUserStatus().intValue() == 0) {
userFromDB.setIntroduce(SystemUtil.cleanString(bbsUser.getIntroduce()));
userFromDB.setLocation(SystemUtil.cleanString(bbsUser.getLocation()));
userFromDB.setGender(SystemUtil.cleanString(bbsUser.getGender()));
userFromDB.setNickName(SystemUtil.cleanString(bbsUser.getNickName()));
if (bbsUserMapper.updateByPrimaryKeySelective(userFromDB) > 0) {
httpSession.setAttribute(Constants.USER_SESSION_KEY, userFromDB);
return true;
}
}
return false;
}
数据持久层
BBSUser selectByPrimaryKey(Long userId);
<select id="selectByPrimaryKey" parameterType="java.lang.Long" resultMap="BaseResultMap">
select
<include refid="Base_Column_List" />
from tb_bbs_user
where user_id = #{userId,jdbcType=BIGINT}
</select>
测试效果
2.2 修改头像
前端页面修改头像
updateHeadImg()方法是修改用户头像,该方法的逻辑如下:
- 首先获取用户上传的图片 URL,之后进行简单的正则验证
- 向对应的后端修改用户头像接口/updateHeadImg发送请求
- 请求成功后提醒用户修改成功
- 请求失败则提醒对应的错误信息
//图片上传插件初始化 用于头像上传
new AjaxUpload('#uploadHeadImg', {
action: '/uploadFile',
name: 'file',
autoSubmit: true,
responseType: "json",
onSubmit: function (file, extension) {
if (!(extension && /^(jpg|jpeg|png|gif)$/.test(extension.toLowerCase()))) {
alert('只支持jpg、png、gif格式的文件!');
return false;
}
},
onComplete: function (file, r) {
if (r != null && r.resultCode == 200) {
$("#userHeadImg").attr("src", r.data);
return false;
} else {
alert("error");
}
}
});
//修改头像
window.updateHeadImg = function () {
var $ = layui.$;
var userHeadImg = $('#userHeadImg')[0].src;
if (isNull(userHeadImg)) {
layer.alert('头像不能为空字符串!', {title: '提醒', skin: 'layui-layer-molv', icon: 2});
return false;
}
var url = '/updateHeadImg?userHeadImg='+userHeadImg;
$.ajax({
type: 'POST',//方法类型
url: url,
success: function (result) {
if (result.resultCode == 200) {
layer.alert('上传成功!', {title: '信息', skin: 'layui-layer-molv', icon: 1});
} else {
layer.msg(result.message);
}
;
},
error: function () {
layer.alert('操作失败!', {title: '提醒', skin: 'layui-layer-molv', icon: 2});
}
});
}
修改头像接口
该接口负责接收前端发送的修改用户头像的 POST 请求并处理其中的参数,接收的参数为 userHeadImg 字段,相对来说比较简单,只是修改一个字段而已。
首先需要上传图片然后回显,由UploadController类的方法处理。
@PostMapping({"/uploadFile"})
@ResponseBody
public Result upload(HttpServletRequest httpServletRequest, @RequestParam("file") MultipartFile file) throws URISyntaxException
之后修改头像,接口的映射地址为 /updateHeadImg,请求方法为 POST。
/**
* 修改头像
* @param userHeadImg
* @param httpSession
* @return
*/
@PostMapping("/updateHeadImg")
@ResponseBody
public Result updateHeadImg(@RequestParam("userHeadImg") String userHeadImg,
HttpSession httpSession) {
if (!StringUtils.hasLength(userHeadImg)) {
return ResultGenerator.genFailResult("userHeadImg参数错误");
}
BBSUser bbsUser = (BBSUser) httpSession.getAttribute(Constants.USER_SESSION_KEY);
bbsUser.setHeadImgUrl(userHeadImg);
if (bbsUserService.updateUserHeadImg(bbsUser, httpSession)) {
Result result = ResultGenerator.genSuccessResult();
return result;
} else {
Result result = ResultGenerator.genFailResult("修改失败");
return result;
}
}
业务层
@Override
public Boolean updateUserHeadImg(BBSUser bbsUser, HttpSession httpSession) {
BBSUser userFromDB = bbsUserMapper.selectByPrimaryKey(bbsUser.getUserId());
//当前用户非空且状态正常才可以进行更改
if (userFromDB != null && userFromDB.getUserStatus().intValue() == 0) {
userFromDB.setHeadImgUrl(bbsUser.getHeadImgUrl());
if (bbsUserMapper.updateByPrimaryKeySelective(userFromDB) > 0) {
httpSession.setAttribute(Constants.USER_SESSION_KEY, userFromDB);
return true;
}
}
return false;
}
用户头像修改接口中,首先会对参数进行校验,之后交给业务层代码进行数据封装并进行数据库 update 操作,具体操作步骤如下:
- 查询用户信息是否存在以及用户状态是否正常
- 用户信息修改并执行入库操作
- 重新设置 session 中的用户信息
数据持久层就是前面通过主键查询用户,然后修改字段的方法,这里就不列举了。
测试效果
2.3 修改密码
前端页面修改密码
updatePassword()方法是修改密码,该方法的逻辑如下:
- 前端对用户输入的密码字段进行简单的正则验证和比较
- 封装密码请求所需的参数
- 向对应的后端修改用户信息接口/updatePassword发送 Ajax 请求
- 请求成功后提醒用户修改成功
- 请求失败则提醒对应的错误信息
//修改密码
window.updatePassword = function () {
var $ = layui.$;
var originalPassword = $("#originalPassword").val();
if (!validPassword(originalPassword)) {
layer.alert('请输入正确的密码格式!', {title: '提醒', skin: 'layui-layer-molv', icon: 2});
return false;
}
var newPassword = $("#newPassword").val();
if (!validPassword(newPassword)) {
layer.alert('请输入正确的密码格式!', {title: '提醒', skin: 'layui-layer-molv', icon: 2});
return false;
}
if (newPassword != newPassword) {
layer.alert('确认密码与密码字段不相同!', {title: '提醒', skin: 'layui-layer-molv', icon: 2});
return false;
}
var params = $("#passwordForm").serialize();
var url = '/updatePassword';
$.ajax({
type: 'POST',//方法类型
url: url,
data: params,
success: function (result) {
if (result.resultCode == 200) {
layer.alert('修改成功!', {title: '信息', skin: 'layui-layer-molv', icon: 1});
} else {
layer.msg(result.message);
}
;
},
error: function () {
layer.alert('操作失败!', {title: '提醒', skin: 'layui-layer-molv', icon: 2});
}
});
}
修改密码接口
该接口负责接收前端发送的修改用户密码的 POST 请求并处理其中的参数,接收的参数为 originalPassword 字段和 newPassword 字段。
接口的映射地址为 /updatePassword,请求方法为 POST。
@PostMapping("/updatePassword")
@ResponseBody
public Result passwordUpdate(HttpServletRequest request, @RequestParam("originalPassword") String originalPassword,
@RequestParam("newPassword") String newPassword) {
if (!StringUtils.hasLength(originalPassword) || !StringUtils.hasLength(newPassword)) {
return ResultGenerator.genFailResult("参数不能为空");
}
BBSUser currentUser = (BBSUser) request.getSession().getAttribute(Constants.USER_SESSION_KEY);
if (bbsUserService.updatePassword(currentUser.getUserId(), originalPassword, newPassword)) {
//修改成功后清空session中的数据,前端控制跳转至登录页
request.getSession().removeAttribute(Constants.USER_SESSION_KEY);
return ResultGenerator.genSuccessResult();
} else {
return ResultGenerator.genFailResult("修改失败");
}
}
业务层
public Boolean updatePassword(Long userId, String originalPassword, String newPassword) {
BBSUser bbsUser = bbsUserMapper.selectByPrimaryKey(userId);
//当前用户非空且状态正常才可以进行更改
if (bbsUser != null && bbsUser.getUserStatus().intValue() == 0) {
String originalPasswordMd5 = MD5Util.MD5Encode(originalPassword, "UTF-8");
String newPasswordMd5 = MD5Util.MD5Encode(newPassword, "UTF-8");
//比较原密码是否正确
if (originalPasswordMd5.equals(bbsUser.getPasswordMd5())) {
//设置新密码并修改
bbsUser.setPasswordMd5(newPasswordMd5);
if (bbsUserMapper.updateByPrimaryKeySelective(bbsUser) > 0) {
//修改成功则返回true
return true;
}
}
}
return false;
}
首先会对参数进行校验,之后交给业务层代码进行数据封装并进行数据库 update 操作,具体操作步骤如下:
- 查询用户信息是否存在以及用户状态是否正常
- 比较原密码 originalPassword 是否与数据库中存储的密码一致,如果不一致不允许修改
- 重新设置新密码并执行入库操作
- 由于修改了密码,最后清空了 session 对象中的 user 信息,需要重新登录了
数据持久层就是前面通过主键查询用户,然后修改字段的方法,这里就不列举了。
测试效果
至此,个人中心设置页面模块就完成了。