云R记后端登录流程以及个人中心模块分析

编程入门 行业动态 更新时间:2024-10-10 12:22:55

云R记后端登录流程以及个人中心<a href=https://www.elefans.com/category/jswz/34/1771428.html style=模块分析"/>

云R记后端登录流程以及个人中心模块分析

首先云R记是乐字节的一个初级项目,所使用的技术为servlet+jdbc+tomcat+mysql,在学习java的初级阶段,刚学完servlet和jdbc以及javaweb的时候,拿来做总结的项目还是很不错的,因为时间原因,所以我暂时就写了部分模块的分析,以后有时间会继续更新。

登录界面

前端界面分析

首先是前端是login.jsp文件,我们使用的是form表单提交的方式,在隐藏域中设置了name为
actionName,value为login,说明用户的行为是登录,然后给登录按钮做了一个点击事件

 然后这个是我们在js中去为这个点击事件编写的函数,我们可以在前台先做一次非空校验,然后将整个表单通过id来进行提交。

 web层

我们是通过actionName的值来判断用户是作何种行为,然后编写对应行为的方法,因为我们设置的name为actionName,所以我们可以直接使用实现了HttpServletRequest的request对象,调用
getParameter方法来获取到前台传入的actionName的值。

然后使用ifelse做条件判断,每个行为对应着每个行为的方法,然后我们就可以去编写他们的行为方法。首先是login操作方法名userLogin

@WebServlet("/user")
@MultipartConfig
public class UserServlet extends HttpServlet {
static UserService userService = new UserService();
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws
ServletException, IOException {
// 设置首页导航高亮
request.setAttribute("menu_page", "user");
// 接收用户行为
String actionName = request.getParameter("actionName");
// 判断用户行为,调用对应的方法
if ("login".equals(actionName)) {
// 用户登录
userLogin(request, response);
} else if ("logout".equals(actionName)) {
// 用户退出
userLogOut(request, response);
}else if ("userCenter".equals(actionName)){
//用户中心
userCenter(request,response);
}else if ("userHead".equals(actionName)){
// 加载头像
userHead(request,response);
}else if ("checkNick".equals(actionName)){
// 验证昵称的唯一性
userCheckNick(request,response);
}else if ("updateUser".equals(actionName)){
// 修改用户信息
updateUser(request,response);
}
}

下面就是我们的userlogin方法,首先我们从前台界面拿到用户输入的用户名和密码,然后我们就直接进service层,在service层中,我们会先去做非空校验,再去做密码校验,最后如果在数据库中查询到对应用户,返回1,没有查询到返回0。(resultinfo实体类我这边就不放进来了)
然后我们通过0,1的状态码来判断用户是否登录成功,如果用户登录成功了,我们需要将查到的所有的用户信息保存在session作用域中,这样做的目的就是为了能够在index页面也能去使用这个名为user的

session作用域。然后我们还需要判断的是用户是否有选择记住密码,如果记住密码,那么我们从前端那边拿到的rem的值应该是1,不然就是0,我们先来对1进行判断,如果rem为1,我们就需要将用户的用户名和session存储在cookie中,我们设置cookie是最大时间,单位是秒,然后相应给客户端,如果rem为0,就说明不需要我们记住密码,直接设置cookie为0,清空cookie。

如果登录成功,就将整个session作用域一起重定向到index(注意这里不是index.jsp)因为我们还单独去编写了一个index.servlet来对所有index进行拦截做处理,在index.servlet,我们将页面请求转发到如果登录失败,我们就会将整个resultinfo对象(包含报错信息,状态码等)一起请求转发回登录界面,交于前端去显示

userServlet
private void userLogin(HttpServletRequest request, HttpServletResponse response) throws IOException,
ServletException {
// 1. 获取参数 (姓名、密码)
String userName = request.getParameter("userName");
String userPwd = request.getParameter("userPwd");
// 2. 调用Service层的方法,返回ResultInfo对象
ResultInfo<User> resultInfo = userService.userLogin(userName, userPwd);
// 3. 判断是否登录成功
if (resultInfo.getCode() == 1) { // 如果成功
// 将用户信息设置到session作用域中
request.getSession().setAttribute("user", resultInfo.getResult());
// 判断用户是否选择记住密码(rem的值是1)
String rem = request.getParameter("rem");
// 如果是,将用户姓名与密码存到cookie中,设置失效时间,并响应给客户端
if ("1".equals(rem)) {
// 得到Cookie对象
Cookie cookie = new Cookie("user", userName + "-" + userPwd);
// 设置失效时间
cookie.setMaxAge(3 * 24 * 60 * 60);
// 响应给客户端
response.addCookie(cookie);
} else {
// 如果否,清空原有的cookie对象
Cookie cookie = new Cookie("user", null);
// 删除cookie,设置maxage为0
cookie.setMaxAge(0);
// 响应给客户端
response.addCookie(cookie);
}
// 重定向跳转到index页面
response.sendRedirect("index");
} else { // 失败
// 将resultInfo对象设置到request作用域中
request.setAttribute("resultInfo", resultInfo);
// 请求转发跳转到登录页面
request.getRequestDispatcher("login.jsp").forward(request, response);
}
}
}

Service层

我们在service的操作就很简单了
第一步:判断用户名密码是否为空
第二步:连接数据库(dao层queryUserbyName),通过用户名去数据库中查找,是否有对应的用户(查询结果是一个user实体类,与数据库user表字段一一对应)
第三步:对密码进行md5加密,然后去与数据库中密码进行比较。


public ResultInfo<User> userLogin(String userName,String userPwd){
ResultInfo<User> resultInfo = new ResultInfo<>();
// 数据回显:当登录实现时,将登录信息返回给页面显示
User u = new User();
u.setUname(userName);
u.setUpwd(userPwd);
resultInfo.setResult(u);
// 1. 判断参数是否为空
// 如果为空
// 设置ResultInfo对象的状态码和提示信息
// 返回resultInfo对象
System.out.println("name" + u.getUname() + "pwd" + u.getUpwd());
if (StrUtil.isBlank(userName) || StrUtil.isBlank(userPwd)){
resultInfo.setCode(0);
resultInfo.setMsg("用户名或密码为空");
System.out.println(resultInfo.getMsg());
return resultInfo;
}
//2. 如果不为空,通过用户名查询用户对象
User user = userDao.queryUserbyName(userName);
//3. 判断用户对象是否为空
// 如果为空
// 设置ResultInfo对象的状态码和提示信息
// 返回resultInfo对象
if (user == null){
resultInfo.setCode(0);
resultInfo.setMsg("用户不存在");
return resultInfo;
}
// 4. 如果用户对象不为空,将数据库中查询到的用户对象的密码与前台传递的密码作比较 (将密码加
密后再比较)
// 如果密码不正确
// 设置ResultInfo对象的状态码和提示信息
// 返回resultInfo对象
userPwd = DigestUtil.md5Hex(userPwd);
//一个是网页上获取的pwd一个是数据库获取的存储在user类中的pwd
if (!userPwd.equals(user.getUpwd())){
resultInfo.setCode(0);
resultInfo.setMsg("用户密码不正确");
return resultInfo;
}
resultInfo.setResult(user);
return resultInfo;
}

Dao层

jdbc的七个步骤,然后对结果集进行一个处理,sql语句是查询是否有相同uname的用户的所有信息,最后返回这个user对象

public User queryUserbyName(String userName){
User user = null;
用户退出
前端代码
我们这边使用的是一个超链接的形式来传输的actionName。
Connection connection =null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
try {
//1. 获取数据库连接
connection = DBUtil.getConnetion();
//2. 定义sql语句
String sql = "select * from tb_user where uname = ?";
// 3. 预编译
preparedStatement = connection.prepareStatement(sql);
// 4. 设置参数
preparedStatement.setString(1,userName);
// 5. 执行查询,返回结果集
resultSet = preparedStatement.executeQuery();
// 6. 判断并分析结果集
if (resultSet.next()){
user = new User();
user.setUname(userName);
user.setUserId(resultSet.getInt("userId"));
user.setUpwd(resultSet.getString("upwd"));
user.setHead(resultSet.getString("head"));
user.setMood(resultSet.getString("mood"));
user.setNick(resultSet.getString("nick"));
}
}catch (Exception e){
e.printStackTrace();
}finally {
DBUtil.close(resultSet,preparedStatement,connection);
}
return user;
}
}

个人中心界面

在我们进入index界面的时候我们需要注意的是,我们将整个index界面中一直不变的上方导航栏和左边导航栏卸载了index.jsp中,导航栏每个模块对应的内容都被我们单独拿出去了,我们使用了一个changePage的参数来进行处理,如果我们后台传值回来了,那么将页面设置为我们传值进来的界面,没有的话我们就默认是note包下的list.jsp界面

用户退出

前端代码

web层

可以参考登录模块的代码。先判断用户的行为,logout,然后编写对应的退出方法

userServlet
else if ("logout".equals(actionName)) {
// 用户退出
userLogOut(request, response);

退出方法其实就很简单了,我们直接就将对应的session,以及cookie销毁,然后重定向回登录页面。

private void userLogOut(HttpServletRequest request, HttpServletResponse response) throws
IOException {
// 1. 销毁Session对象
request.getSession().invalidate();
// 2. 删除Cookie对象
Cookie cookie = new Cookie("user", null);
cookie.setMaxAge(0); // 设置0,表示删除cookie
response.addCookie(cookie);
// 3. 重定向跳转到登录页面
response.sendRedirect("login.jsp");

个人中心模块

前端实现

我们给个人中心设置一个超链接并且设置了actionName为userCenter

Web层 

当我们点击个人中心导航栏,我们就触发了超链接,然后我们对actionName进行判断,判断出来是想要进入个人中心界面,然后编写对应方法

else if ("userCenter".equals(actionName)){
//用户中心
userCenter(request,response);

其实这一步也很简答,就是修改一下之前说的前端的changePage,然后请求转发回index.jsp界面,就可以实现了

private void userCenter(HttpServletRequest request, HttpServletResponse response) throws
ServletException, IOException {
// 1. 设置首页动态包含的页面值
request.setAttribute("changePage","user/info.jsp");
// 2. 请求转发跳转到index
request.getRequestDispatcher("index.jsp").forward(request,response);
}

加载头像功能

前端

同样一个超链接,设置actionName,后面的imageName是我们要完成的一个头像显示的功能

Web 

显示actionName判定事件,然后写对应方法

else if ("userHead".equals(actionName)){
// 加载头像
userHead(request,response);

但是我们图片显示的功能就需要稍微复杂一些了,首先我们先去拿到前台对应的图片名称,然后再去拿到图片的真实路径,我们使用file对象来对图片进行处理,我们需要得到这个图片的格式,我们使用字符串截取的方法,截取到最后出现的.后面的所有字符串。然后我们对这个字符串来进行判断equalsIgnoreCase这个方法是不区分大小写。

response.setContentType("image/png")这个servlet中设置相应内容类型的语句,告诉客户端浏览器返回的是什么格式,比如说这边就是png的图片格式最后再使用FileUtils中的copyFile方法,将图片拷贝给浏览器,实现了头像上传的功能

我们这边还需要注意一个注解,就是我们最上面有一个@MultipartConfig注解,这个注解就是辅助
Httpservletrequest实现文件上传的功能。

private void userHead(HttpServletRequest request, HttpServletResponse response) throws IOException {
// 1. 获取参数 (图片名称)
String head = request.getParameter("imageName");
// 2. 得到图片的存放路径 (得到项目的真实路径:request.getServletContext().getealPath("/"))
String realPath = request.getServletContext().getRealPath("/WEB-INF/upload/");
// 3. 通过图片的完整路径,得到file对象
File file = new File(realPath+"/"+head);
// 4. 通过截取,得到图片的后缀
String pic = head.substring(head.lastIndexOf(".")+1);
// 5. 通过不同的图片后缀,设置不同的响应的类型
//equalsIgnoreCase 是 Java 中的一个字符串方法,用于比较两个字符串的内容是否相等,而不考虑
大小写。
if ("PNG".equalsIgnoreCase(pic)){
//response.setContentType 是一个用于设置响应内容类型的方法,
// 通常用于在Servlet或类似的Web应用程序中设置响应头信息。它指定了将要发送到客户端的数
据的媒体类型。
response.setContentType("image/png");
}else if ("JPG".equalsIgnoreCase(pic) || "JPEG".equalsIgnoreCase(pic)){
response.setContentType("image/jpeg");
}else if ("GIF".equalsIgnoreCase(pic)) {
response.setContentType("image/gif");
}
// 6. 利用FileUtils的copyFile()方法,将图片拷贝给浏览器
FileUtils.copyFile(file,response.getOutputStream());
}

验证昵称唯一性

我们想要进入个人中心对昵称进行修改,那么就必须要有一步就是验证昵称唯一性,确保更改后的昵称在数据库中没有相同名字的用户

前端

我们先是对昵称那个文本框做了一个失焦事件,然后进行判断,如果更改后没有输入用户名,那么就提示报错信息,并且将修改的按钮禁用,方法返回结束。如果不为空。

进行第二次判断判断昵称是否有被修改,如果昵称没有被修改,那就什么都不需要修改,直接return

如果对昵称进行了修改,那么就使用ajax的方式去请求后台,验证昵称是否可用,首先是一个get请求,url是user,可以对应到我们的userServlet中的webServlet注解中的数据,然后传入actionName,以及nick(修改后的昵称)给后台,最后后台处理成功返回一个code状态码回来,对状态码进行判断,如果为1,有提示信息就进行一个清空操作,设置按钮可用,如果为0,就提示报错信息,按钮不可用。

$("#nickName").blur(function (){
// 1. 获取昵称文本框的值
web层
先拿到actionName进行判断,是验证昵称的操作,然后编写对应的方法
var nickName = $("#nickName").val();
// 2. 判断值是否为空
if (isEmpty(nickName)) {
// 如果为空,提示用户,禁用按钮,并return
$("#msg").html("用户昵称不能为空!")
$("#btn").prop("disabled", true);
return;
}
// 3. 判断昵称是否做了修改
// 从session作用域中获取用户昵称
var nick = '${user.nick}';
// 如果用户昵称与session中的昵称一致,则return
if (nickName == nick) {
return;
}
// 4. 如果昵称做了修改
// 发送ajax请求后台,验证昵称是否可用
$.ajax({
type:"get",
url:"user",
data:{
actionName:"checkNick",
nick:nickName
},
success:function (code) {
// 如果可用,清空提示信息,按钮可用
if (code == 1) {
// 1. 清空提示信息
$("#msg").html("")
// 2. 按钮可用
$("#btn").prop("disabled", false);
} else {
// 1. 清空提示信息
$("#msg").html("该昵称已存在,请重新输入!")
// 2. 按钮可用
$("#btn").prop("disabled", true);
}
}
});
}).focus(function (){
// 1. 清空提示信息
$("#msg").html("")
// 2. 按钮可用
$("#btn").prop("disabled", false);
});

Web层

先拿到actionName进行判断,是验证昵称的操作,然后编写对应的方法

else if ("checkNick".equals(actionName)){
// 验证昵称的唯一性
userCheckNick(request,response);

我们在方法中,通过前端ajax传来的nick,可以拿到现在网页中用户修改的昵称,然后我们从之前前台登录传入的session中的user,拿到对应的用户信息,我们这边使用的是用户修改后的昵称和用户id来进行的判断

先去调用service中的判断和数据库中的查找,最后得到一个code,+“”的操作是将其转换为字符串的形式

我们在对这个code使用一个流的方式传回给前端的ajax请求,需要注意的是要关闭资源

private void userCheckNick(HttpServletRequest request, HttpServletResponse response) throws
IOException {
// 1. 获取参数(昵称)
String nick = request.getParameter("nick");
// 2. 从session作用域获取用户对象,得到用户ID
User user = (User) request.getSession().getAttribute("user");
// 3. 调用Service层的方法,得到返回的结果
Integer code = userService.userCheckNick(nick, user.getUserId());
// 4. 通过字符输出流将结果响应给前台的ajax的回调函数
response.getWriter().write(code + "");
// 5. 关闭资源
response.getWriter().close();
}

service层

service层做的判断就很简单,同样也要去判断一次昵称是否为空,在不为空的前提调用dao层连接数据库做查询操作,判断是否有修改后昵称对应的用户存在,最后返回一个code,如果有相同的名字用户返回0,没有相同的名字用户返回1。

public Integer userCheckNick(String nick, Integer userId) {
// 1. 判断昵称是否为空
if (StrUtil.isBlank(nick)) {
return 0;
}
// 2. 调用Dao层,通过用户ID和昵称查询用户对象
User user = userDao.queryUserByNickAndUserId(nick, userId);
// 3. 判断用户对象存在
if (user != null) {
return 0;
}
return 1;
}

Dao层

dao层也是一个很简单的sql语句,查询除了自己id之外有没有想同的nick,最后将用户返回回去

public User queryUserByNickAndUserId(String nick, Integer userId) {
// 1. 定义SQL语句
String sql = "select * from tb_user where nick = ? and userId != ?";
// 2. 设置参数集合
List<Object> params = new ArrayList<>();
params.add(nick);
params.add(userId);
// 3. 调用BaseDao的查询方法
User user = (User) BaseDao.queryRow(sql,params,User.class);
return user;
}

修改用户信息

前端

图1和图2都在一个form表单中,图一是设置的隐藏域,设置的actionName,判断用户行为,图二是一个修改的button按钮,为其设置了一个点击事件

 这边是按钮的点击事件的代码 ,简单的做个判断,然后就去编写我们的后端

function updateUser() {
// 获取昵称文本框的值
var nickName = $("#nickName").val();
// 判断值是否为空
if (isEmpty(nickName)) {
// 如果为空,提示用户,禁用按钮,并return
$("#msg").html("用户昵称不能为空!")
$("#btn").prop("disabled", true);
return false;
}
return true;
}

Web层

首先还是对actionName进行判断,确定用户操作,然后写对应的方法

else if ("updateUser".equals(actionName)){
// 修改用户信息
updateUser(request,response);
private void updateUser(HttpServletRequest request, HttpServletResponse response) throws
ServletException, IOException {
ResultInfo<User> resultInfo = userService.updateUser(request);
request.setAttribute("resultInfo",resultInfo);
request.getRequestDispatcher("user?actionName=userCenter").forward(request,response);
}

我们唯一需要注意的一点是,我们这边为什么请求转发的是一个url,其实我们是将页面修改完成之后,将resultinfo更新并且回到更新后的userCenter界面


service层

service层会比较复杂一些,首先是要去获取界面中用户的昵称和心情,再继续对昵称做一个非空判断然后从session作用域中拿到用户对象,然后对用户对象头像进行操作,我们需要使用part对象,使用getPart方法拿到(前端图片那边的name为img,value也为img)img,然后使用part对象获取文件上传的文件名,然后因为是请求头的形式,是键值对,这种后面一般是=加一个空格,所以我们使用substring做拦截,取最后一个=然后做+2的操作,拿到对应的值。

然后将这个值再使用截取的方式转为名为fileName的字符串,也就是我们的文件名了,然后对文件名做一个非空的判断,如果不为空,说明用户上传了头像想要更新头像,那我们就将user中的head属性设置为我们现在的文件名,然后再来获取图片的存储路径,将上传的文件到我们的地址目录,还需要加上我们的文件名

最后我们使用dao层的方法来进行判断,如果更新之后更改行数>0说明有更改,返回code1,否则说明更改失败设置code0,并且返回报错信息

public ResultInfo<User> updateUser(HttpServletRequest request) {
ResultInfo<User> resultInfo = new ResultInfo<>();
// 1. 获取参数(昵称、心情)
String nick = request.getParameter("nick");
String mood = request.getParameter("mood");
// 2. 参数的非空校验(判断必填参数非空)
if (StrUtil.isBlank(nick)){
// 如果昵称为空,将状态码和错误信息设置resultInfo对象中,返回resultInfo对象
resultInfo.setCode(0);
resultInfo.setMsg("用户昵称不能為空!");
return resultInfo;
}
// 3. 从session作用域中获取用户对象(获取用户对象中默认的头像)
User user = (User) request.getSession().getAttribute("user");
user.setNick(nick);
user.setMood(mood);
try {
// 1. 获取Part对象 request.getPart("name"); name代表的是file文件域的name属性值
Part part = request.getPart("img");
// 2. 通过Part对象获取上传文件的文件名 (从头部信息中获取上传的文件名)
String header = part.getHeader("Content-Disposition");
// 获取具体的请求头对应的值
dao层
dao层就比较简单了,根据id和传入的所有user数据来做一个更新操作,更新成功了,就会有受影响行
数,更新失败了就不会显示受影响函数。
String str = header.substring(header.lastIndexOf("=")+2);
// 获取上传的文件名
String fileName = str.substring(0,str.length()-1);
// 3. 判断文件名是否为空
if (!StrUtil.isBlank(fileName)){
// 如果用户上传了头像,则更新用户对象中的头像
user.setHead(fileName);
// 4. 获取文件存放的路径 WEB-INF/upload/目录中
String realPath = request.getServletContext().getRealPath("/WEB-INF/upload/");
// 5. 上传文件到指定目录
part.write(realPath+"/"+fileName);
}
}catch (Exception e){
e.printStackTrace();
}
// 6. 调用Dao层的更新方法,返回受影响的行数
int row = UserDao.updateUser(user);
if (row>0){
resultInfo.setCode(1);
// 更新session中用户对象
request.getSession().setAttribute("user",user);
}else{
resultInfo.setCode(0);
resultInfo.setMsg("更新失败!");
}
return resultInfo;
}
}

Dao层

dao层就比较简单了,根据id和传入的所有user数据来做一个更新操作,更新成功了,就会有受影响行数,更新失败了就不会显示受影响函数。

public static int updateUser(User user) {
String sql = "update tb_user set nick = ?, mood = ?, head = ? where userId = ? ";
// 2. 设置参数集合
List<Object> params = new ArrayList<>();
params.add(user.getNick());
params.add(user.getMood());
params.add(user.getHead());
params.add(user.getUserId());
// 3. 调用BaseDao的更新方法,返回受影响的行数
int rows = BaseDao.executeUpdate(sql,params);
return rows;
}

总结

整体来说,这个项目的难度并不高,但是可以很好的帮助初学者理解什么是分层思想,为接下来所需要学习的框架打下了基础,还是很值得一看的,视频链接:【【念安小姐姐2021最新项目】Java入门级-个人博客系统云R记Bootstrap+Jsp+Servlet+MySQL+Tomcat、MongoDB、Redis】 /?share_source=copy_web&vd_source=a5f58d634ca65e1ae979c44dd3b874e4

有需要源码的小伙伴也可以直接私信我。

更多推荐

云R记后端登录流程以及个人中心模块分析

本文发布于:2024-02-27 16:21:38,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1707344.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:模块   后端   流程   中心

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!