三、用户登陆功能实现
-
接着之前的项目
-
先简述一下登录功能的具体实现流程:
① 在前端页面输入用户名和密码之后;
② 将所输入的对象(用户名和密码)传递给后端;
③ 后端将这个对象的信息与服务器的数据库中的信息进行比对,当发现存在数据库中时,则给前端返回登陆成功的信息,前端则弹出登录成功(可进行跳转) -
我们需要根据我们服务器中用户表中有的信息建立一个模板类,当前端登录页面输入信息后,我们用这个信息根据我们固定的模板生成一个用户对象,把这这个对象和数据库中的用户数据进行比对。在
models
文件夹下创建一个UserInfo
类
package models;
import java.util.*;
public class UserInfo {
private int id;
private Date createtime;
private Date updatetime;
private String username;
private String password;
private int state;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public Date getCreatetime() {
return createtime;
}
public void setCreatetime(Date createtime) {
this.createtime = createtime;
}
public Date getUpdatetime() {
return updatetime;
}
public void setUpdatetime(Date updatetime) {
this.updatetime = updatetime;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public int getState() {
return state;
}
public void setState(int state) {
this.state = state;
}
}
- 要实现登录页面,则需要在webapp下创建登录的前端页面
login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>登录页面</title>
<script src="jquery-1.9.1.min.js"></script>
<script>
function mysub(type) {
var username = jQuery("#username");
var password = jQuery("#password");
if(type == 2){
username.val("");
password.val("");
return false;
}
// 1、非空校验
if(username.val().trim() == ""){
alert("请先输入用户名");
username.focus();
return false;
}
if(password.val().trim() == ""){
alert("请先输入密码");
password.focus();
return false;
}
// 2、请求后端,实现登陆验证
jQuery.getJSON("login",{
"username":username.val(),
"password":password.val()
},function (data) {
if(data != null && data.succ != null && data.succ == 1){
alert("登陆成功,这里进行跳转");
// location.href = "myartlist.html";
// 这里先注释掉,这个是我们下一部分实现的功能,这是一个跳转
}else{
alert("登录失败" + data.msg);
}
});
}
</script>
</head>
<body>
<div style="margin-top: 70px;text-align: center">
<h1>登录</h1>
用户名:<input id="username" name="username" type="text"><p></p>
密码:<input id="password" name="password" type="password"><p></p>
<input type="button" onclick="mysub(1)" value=" 提 交 ">
<input type="button" onclick="mysub(2)" value=" 清 空 ">
</div>
</body>
</html>
- 然后根据前端
jQuery.getJSON()
的第一个参数(路由地址),新建一个服务类,也是类似于模板化的代码
服务类需要改的部分目前开来基本只有:
① 前端传给后端的参数,具体况使用不同的类型接收
② 具体的业务逻辑,这部分是通过是实例化dao
文件下的类,具体根据所需情况编写具体的方法操作(找到对应的厨师,做对应的饭)
③ 返回给前端的结果部分有时也会改动,不过目前不改,因为当前我们给前端的信息只有是否成功(succ)和可能会出现的错误信息(msg)
package service;
import dao.UserInfoDao;
import models.UserInfo;
import utils.ResultJSONUtils;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.sql.SQLException;
import java.util.HashMap;
@WebServlet("/login")
public class LoginServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
int succ = -1; // 1:登录成功
String msg = "";// 错误信息
// 1.得出前端传递的参数
String username = request.getParameter("username");
String password = request.getParameter("password");
// 2.去数据库验证用户名和密码【业务】
if (username != null && !username.equals("") &&
password != null && !password.equals("")
) {
// 参数正确,执行数据库查询
UserInfoDao userInfoDao = null;
try {
userInfoDao = new UserInfoDao();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
try {
// 查询数据库
UserInfo userInfo = userInfoDao.getUser(username, password);
if (userInfo.getId() > 0) {
// 查到用户了,也就是用户名和密码是正确
succ = 1;
// 将用户信息存放到 session
HttpSession session = request.getSession(); // 用来创建会话
// 将用户信息存放到当前session(方便后面查询文章列表时使用)
session.setAttribute("userinfo", userInfo);
} else {
succ = 0;
msg = "用户名或密码输出错误!";
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}
} else {
// 参数不完整,非法请求
msg = "非法请求,参数不完整";
}
// 3.返回结果
HashMap<String, Object> result = new HashMap<>();
result.put("succ", succ);
result.put("msg", msg);
ResultJSONUtils.write(response, result);
}
}
- 在服务类的代码中有一部分需要说明一下:
// 将用户信息存放到 session
HttpSession session = request.getSession(); // 用来创建会话
// 将用户信息存放到当前session(方便后面查询文章列表时使用)
session.setAttribute("userinfo", userInfo);
- 在成功登陆后,因为http是属于无状态协议,所以网页本身并不会保存我们访问后的信息,所以要使用
Session
将我们的用户信息暂时保存起来,这样当我们频繁访问各种信息时就不用每次都去验证一遍 - 上面服务类下的
LoginServlet
写完后,会发现有报红,是我们的操作类UserInfoDao
下没有我们要的的具体操作,之后在我们每次添加一个新功能时,基本也都要对操作类的具体方法进行添加,如下图:
- 把以下代码放进去,这步其实也相对比较模板,需要改的基本就是数据库的查询语句
sql
// 查询用户(登录功能使用)
public UserInfo getUser(String username, String password) throws SQLException {
UserInfo userInfo = new UserInfo();
// 使用JDBC查询数据库
Connection connection = DBUtils.getConnection();
String sql = "select * from userinfo where username=? and password=?";
PreparedStatement statement = connection.prepareStatement(sql);
statement.setString(1,username);
statement.setString(2,password);
// 查询数据库
ResultSet resultSet = statement.executeQuery(); // 此处查找到的是username=root,password=123的所有用户
while(resultSet.next()){
userInfo.setId(resultSet.getInt("id"));
userInfo.setUsername(resultSet.getString("username"));
userInfo.setPassword(resultSet.getString("password"));
}
// 关闭数据库
DBUtils.close(connection,statement,resultSet);
return userInfo;
}
- 跟之前的注册有些不同的是,因为注册至于要将前端给到的用户名和密码写入数据库就好,所以只需要在数据库中添加即可;但登录功能需要将数据库中的用户数据(生成一个对象)拿到,并且返回给前端,所以会多了
ResultSet
这一步 - 接下来就可以运行了,运行IEDA,并且登录
http://localhost:8080/untitled_war/login.html
- 根据我们之前注册的用户名和密码,登录,就可以看到以下页面了,当然你也可以试一下输入错误的账号和密码看看有什么反馈。
- OK,登录的功能也实现了ヽ(✿゚▽゚)ノ
四、个人文章列表功能实现
- 惯例描述一下功能概述:
在前端的登陆页面登陆成功后,跳转到一个文章页面myartlist.html
,文章页面中会根据用户在数据库中的文章表(文章表是和用户表有逻辑相关的,比如每个文章有一个uid属性代表这个文章属于哪个id的用户)显示出文章
1、数据库表的准备
- 我们先在服务器的数据库里把文章表创建了,并且把文章也添加进这个表
-- 创建文章表
drop table if exists articleinfo;
create table articleinfo(
id int primary key auto_increment,
createtime datetime default now(),
updatetime datetime default now(),
title varchar(100) not null,
content text not null,
rcount int default 1,
state int default 1,
uid int not null
);
-- 插入测试数据
insert into userinfo(id,username,password) values(1,'admin','123');
insert into articleinfo(title,content,uid)
values('JavaWeb文章','内容:这里是文章1',1), // 这里的1是用户,根据你服务器中你想给哪个用户添加文章,就这个值改成那个用户
('传世圣经','内容:任天堂是这个世界的主宰',1);
insert into articleinfo(title,content,uid)
values('JavaWeb文章','内容:这里是文章1',2),
('传世圣经','内容:任天堂是这个世界的主宰',2);
- 添加完后可以看看自己的数据库,我因为之前有添加,所以有两个用户和四篇文章
- 这样准备工作就做完了,可以开始进行前后端的代码部分了
2、前端页面部分代码书写
- webapp下创建一个
myartlist.html
文件,显示文章列表
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>文章列表</title>
<script src="jquery-1.9.1.min.js"></script>
<script>
// 查询文章列表功能
jQuery(function () {
// 1、去后台查询我的文章列表
// 因为是从session中那用户的uid,所以前端不需要给后端发送键值对
jQuery.getJSON("myartlist",{},function (data) {
// 2、将table中的信息替换成后台的数据
if(data != null && data.succ ==1){
var html = "";
for (var i = 0; i < data.list.length; i++) {
var article = data.list[i];
html += "<tr>\n" +
"<td>\n" +
article.id + "\n" +
"</td>" +
"<td>\n" +
article.title + "\n" +
"</td>" +
"<td>\n" +
article.createtime + "\n" +
"</td>" +
"<td>\n" +
article.rcount + "\n" +
"</td>" +
"<td>\n" +
"修改" +
"删除\n" +
"</td>" +
"</tr>\n"
}
jQuery("#tab1").append(html);
}else{
alert("操作失败:" + data.msg);
}
})
})
</script>
</head>
<body>
<div style="margin-top: 70px; text-align: center">
<h1>我的文章列表</h1>
<a href="addart.html">添加文章</a>
<table id="tab1" style="width: 80%;margin-left: 100px;" border="1">
<tr>
<td>
编号
</td>
<td>
标题
</td>
<td>
发布时间
</td>
<td>
阅读数
</td>
<td>
操作
</td>
</tr>
</table>
</div>
</body>
</html>
- 前端页面的实现和功能不多做解释,主要看后端,值得一提的是:
该部分的jQuery.getJSON()
功能中并没有从前端给后端发送键值对,这是因为之前在登录之后,用户的信息都保存在Session
中了,我们直接从后端调取Session
中的当前用户信息就好;
还有这个function(data){}
回调函数在之前我们实现的功能中返回的只是标识是否成功的succ和有可能出现的错误信息msg,但在此功能里,需要将用户数据库中的文章表的文章信息也返回给前端 - 前端代码就这样了,但我们需要从登陆页面跳转到当前页面,还记得在用户登录功能的前端代码里注释掉的那条跳转代码吗,现在可以把那个注释取消掉了;
location.href = "myartlist.html";
代码的意思就是跳转到myartlist.html
页面
3、后端服务与具体操作类代码
- 跟用户注册登录时一样,我们也需要专门处理文章的
dao
类(厨师),因此在dao
文件夹下创建ArticleInfoDao
类;同时也需要存放文章信息的模板即在model
文件夹下创建ArticleInfo
类; - 根据数据库中文章表的信息,先把模板
ArticleInfo
类写了:
package models;
import java.util.Date;
public class ArticleInfo {
private int id;
private Date createtime;
private Date updatetime;
private String title;
private String content;
private int rcount;
private int state;
private int uid;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public Date getCreatetime() {
return createtime;
}
public void setCreatetime(Date createtime) {
this.createtime = createtime;
}
public Date getUpdatetime() {
return updatetime;
}
public void setUpdatetime(Date updatetime) {
this.updatetime = updatetime;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public int getRcount() {
return rcount;
}
public void setRcount(int rcount) {
this.rcount = rcount;
}
public int getState() {
return state;
}
public void setState(int state) {
this.state = state;
}
public int getUid() {
return uid;
}
public void setUid(int uid) {
this.uid = uid;
}
}
- 而厨师
ArticleInfoDao
类下的具体方法我们稍后写 - 接下来根据前端页面中
jQuery.getJSON()
的路由地址创建后端服务类MyArtListServlet
package service;
import dao.ArticleInfoDao;
import models.ArticleInfo;
import models.UserInfo;
import utils.ResultJSONUtils;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
@WebServlet
public class MyArtListServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
int succ = -1;
String msg = "";
List<ArticleInfo> list = null;
// 1、拿到前端给的参数(在Session中存放)
HttpSession session = request.getSession(false); // 如果是true,则会在没有session的情况下自动创建一个,为了实现登录才能访问的功能,所以设置为false
if(session == null){
//用户未登录
msg = "非法请求,请先登录!";
}else{
// 用户已登录
UserInfo userInfo = (UserInfo) session.getAttribute("userinfo");
// 那userInfo去查询数据库
int uid = userInfo.getId(); // 从登陆的用户信息中,拿到该用户在数据库中的id号
ArticleInfoDao articleInfoDao = new ArticleInfoDao();
try {
// 根据该id号,在文章表中找到对应的列表
list = articleInfoDao.getListByUID(uid);
succ = 1;
}catch (SQLException throwables){
throwables.printStackTrace();
}
}
// 3、构建和返回后端结果
HashMap<String, Object> result = new HashMap<>();
result.put("succ", succ);
result.put("msg", msg);
result.put("list", list);
ResultJSONUtils.write(response,result);
}
}
- 这里也看以看到一个区别,就是这里在返回后端结果给前端时多了一个
list
列表,这个list里面存放的就是文章表的一些信息。 - 同样,我们去具体操作里面去书写:
- 从这里开始其实就是套路化的东西了
// 拿到数据库中该uid用户下的文章列表
public List<ArticleInfo> getListByUID(int uid) throws SQLException {
List<ArticleInfo> list = new ArrayList<>();
Connection connection = DBUtils.getConnection();
String sql = "select * from articleinfo where uid=?";
PreparedStatement statement = connection.prepareStatement(sql);
statement.setInt(1,uid);
// 查询并返回结果
ResultSet resultSet = statement.executeQuery();
// 将查询的结果存放在list列表中
while(resultSet.next()){
ArticleInfo articleInfo = new ArticleInfo();
articleInfo.setId(resultSet.getInt("id"));
articleInfo.setRcount(resultSet.getInt("rcount"));articleInfo.setTitle(resultSet.getString("title"));
articleInfo.setContent(resultSet.getString("Content"));
articleInfo.setCreatetime(resultSet.getDate("createtime"));
list.add(articleInfo);
}
return list;
}
- 这样我们前后端的代码就写完了,IDEA运行一下试试
- 访问
http://localhost:8080/untitled_war_exploded/login.html
后输入我们之前注册的用户名和密码 - 登陆成功会发现此时跳转了URL也变成了
http://localhost:8080/untitled_war_exploded/myartlist.html
- 并且属于该用户的文章也显示在网页上了
- OK,结束♪(∇*)