【JavaEE】使Cookie与Session失效-表白墙退出登录操作-Servlet上传文件操作-表白墙注册上传头像+登录显示头像功能
1. Cookie与Session的删除
Cookie与Session基础博客:【JavaEE】Cookie与Session的前后端交互-表白墙登录设计_s:103的博客-CSDN博客
- 虽然Cookie和Session都是暂时存在的,不久就会被删掉,但是我们要退出登录的时候,就不能等待其自然消除了~
- 因为点击退出登录之后,到达登录页面,如果这个时候,浏览器和服务器保留了Cookie和Session,就会自动登录了~
- (用户自己手动删Cookie,不现实)
这里就是一个固定的做法了:
- 一些东西是固定的,目前看不懂也没事,不是本文章重点
- 创建一个新的Servlet程序:Remove(/remove)
- 注解的斜杠一定不要忘,不仅仅是这个程序会出错,而是整个项目全部出错!
-
获取Session,调用invalidate => 使session这个小哈希表无效
-
获取Cookie,Cookie对象不是哈希表,而是一个键值对对象,而报文的Cookie里包含很多键值对(甚至key可以重复)
- getCookies方法获取请求的Cookie所有键值对,返回Cookie数组
- 遍历数组,找到key为login,pwd,id的键值对,将cookie的寿命改为0,并通过响应发回浏览器(调用addCookie方法)
-
重定向
当其实,只要打断其中的一条路,就可以打破登录状态了(使Cookie失效/使Session失效)
1.1 表白墙页面增加登录出口
在wall.html(表白墙html)添加导航栏和登录出口:
- 没错,用到的css修饰,一样是照抄博客系统的:(common.css中)
1.2 点击链接退出登录
- 跳转到登录页面
- 调用remove函数发送请求给服务器,使Session/Cookie失效
1.3 测试
2. 上传文件
- 这里只讲解一种:通过form表单的file类型input按钮上传,submit按钮提交
先看成品(预计效果):
- 我们现在已经具备了登录的功能,但是我们也需要注册的功能,才能让用户使用看到的表白墙有他们的特性~
- 登录设计博客:【JavaEE】Cookie与Session的前后端交互-表白墙登录设计_s:103的博客-CSDN博客
- 在此基础上,增加头像显示的功能(当输入了用户名,且点击了密码框的情况下)
设计稿:
数据库表的设计:
- 表名为image
- 用户名
- 文件名
2.1 后端对上传文件的处理
2.1.1 HttpServletRequest 类方法
方法 | 描述 |
---|---|
Part getPart(String name) | 获取请求中给定 name 的文件 |
Collection getParts() | 获取所有的文件 |
2.1.2 Part 类方法
方法 | 描述 |
---|---|
String getSubmittedFileName() | 获取提交的文件名 |
String getContentType() | 获取提交的文件类型 |
long getSize() | 获取文件的大小 |
void write(String path) | 把提交的文件数据写入磁盘文件 |
高亮的为本文的重点方法~
2.1.3 操作
而form在这里提交的应该是post请求,其中的正文(用户名)可以用getParameter去获取
@MultipartConfig
@WebServlet("/reg")//form表单提交~
public class Register extends HttpServlet {
//Part为一个Servlet提供
//在这里确定这张照片是否应该存入数据库
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
Part part = req.getPart("file");
String fileName = part.getSubmittedFileName();
part.write("D:\\马库\\mara-circle-june-2023\\showLove\\src\\main\\webapp\\" + fileName);
String username = req.getParameter("name");
resp.setContentType("text/html; charset=utf8");
if(Save.isExistence("users", username) || Save.isExistence("image", username)) {
resp.getWriter().write("<h1>已存在!</h1>");
}else {
Save.insert("image", username, fileName);
resp.getWriter().write("<h1>提交成功!</h1>");
}
}
}
2.1.5 Image类
点击密码输入框发送请求获取头像的操作:
@WebServlet("/image")
public class Image extends HttpServlet {
ObjectMapper objectMapper = new ObjectMapper();
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html; charset=utf8");
User img = objectMapper.readValue(req.getInputStream(), User.class);
//不能处理一个只有一个成员的类!
String username = img.name;
DataSource dataSource = new MysqlDataSource();
((MysqlDataSource)dataSource).setUrl("jdbc:mysql://127.0.0.1:3306/Loves?characterEncoding=utf8&useSSL=false");
((MysqlDataSource)dataSource).setUser("root");
((MysqlDataSource)dataSource).setPassword("mmsszsd666");//这是俺的微信号,欢迎添加,相互学习!
try {
Connection connection = dataSource.getConnection();
String sql = "select * from image where name = '" + username + "';";
PreparedStatement preparedStatement = connection.prepareStatement(sql);
//这里的Set并不是,对象为Love的Set集合,而是一个迭代器!
ResultSet set = preparedStatement.executeQuery();
//迭代他(是next方法而不是hasNext)
if(set.next()) {
resp.getWriter().write(set.getString("fileName"));
}else {
resp.getWriter().write("No");
}
set.close();
preparedStatement.close();
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
- 若数据库中并没有这个头像,返回No~
2.1.4 Save类
- 这个类是我自己包装的类,包装了:
- 在数据库中查询用户名是否注册过
- 在数据库中查询用户名是否与头像绑定国
- 给数据库的一张表中插入键值对
- 通过用户名获取图片
其中第一和第二为此方法:
//传入表的名字,和username
public static boolean isExistence(String tableName, String username) {
DataSource dataSource = new MysqlDataSource();
((MysqlDataSource) dataSource).setUrl("jdbc:mysql://127.0.0.1:3306/Loves?characterEncoding=utf8&useSSL=false");
((MysqlDataSource) dataSource).setUser("root");
((MysqlDataSource) dataSource).setPassword("mmsszsd666");//这是俺的微信号,欢迎添加,相互学习!
boolean ret = false;
try {
Connection connection = dataSource.getConnection();
String sql = "select * from " + tableName + " where name = '" + username + "';";
PreparedStatement preparedStatement = connection.prepareStatement(sql);
//这里的Set并不是,对象为Love的Set集合,而是一个迭代器!
ResultSet set = preparedStatement.executeQuery();
//迭代他(是next方法而不是hasNext)
ret = set.next();
set.close();
preparedStatement.close();
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
return ret;//true 存在,false不存在
}
第三为此方法:
public static void insert(String tableName, String key, String value) {
DataSource dataSource = new MysqlDataSource();
((MysqlDataSource)dataSource).setUrl("jdbc:mysql://127.0.0.1:3306/Loves?characterEncoding=utf8&useSSL=false");
((MysqlDataSource)dataSource).setUser("root");
((MysqlDataSource)dataSource).setPassword("mmsszsd666");//这是俺的微信号,欢迎添加,相互学习!
Connection connection = null;
try {
connection = dataSource.getConnection();
String sql = "insert into " + tableName + " values(?, ?)";
PreparedStatement preparedStatement = connection.prepareStatement(sql);
preparedStatement.setString(1, key);
preparedStatement.setString(2, value);
preparedStatement.executeUpdate();
preparedStatement.close();
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
第四为此方法:
public static String getImage(String username) {
DataSource dataSource = new MysqlDataSource();
((MysqlDataSource) dataSource).setUrl("jdbc:mysql://127.0.0.1:3306/Loves?characterEncoding=utf8&useSSL=false");
((MysqlDataSource) dataSource).setUser("root");
((MysqlDataSource) dataSource).setPassword("mmsszsd666");//这是俺的微信号,欢迎添加,相互学习!
String ret = null;
try {
Connection connection = dataSource.getConnection();
String sql = "select * from image where name = '" + username + "';";
PreparedStatement preparedStatement = connection.prepareStatement(sql);
//这里的Set并不是,对象为Love的Set集合,而是一个迭代器!
ResultSet set = preparedStatement.executeQuery();
//迭代他(是next方法而不是hasNext)
if(set.next()) {
ret = set.getString("fileName");
}else {
ret = "https://img1.baidu.com/it/u=4205447136,2730860147&fm=253&fmt=auto&app=138&f=JPEG?w=300&h=300";
}
set.close();
preparedStatement.close();
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
return ret;
}
- 与isExistence不同的是,此方法返回一个文件名
- 找得到:返回文件名
- 找不到:返回默认头像
注意:由于我直接将头像保存到了webapp目录下,所以直接用用户名就可以访问到
所以刚才的 form表单请求处理操作中的这一段的解释为:
- 在这里千万不能改编码为utf8,会报500!
2.1.5 注册按钮
Save类本身也是个Servlet程序~
ObjectMapper objectMapper = new ObjectMapper();
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
User user = objectMapper.readValue(req.getInputStream(), User.class);
resp.setContentType("text/html; charset=utf8");
String username = user.name;//获取key对应值
String password = user.password;
if(isExistence("users", username)) {
resp.getWriter().write("No");//存在此用户了!
}else {
insert("users", username, password);
}
}
- 存在此用户,返回No
- 不存在则注册成功,在users中插入用户信息
2.2 前端设计
- 这个页面几乎照搬登录页面,只是增加了一些元素罢了~
- 用的css也直接用logIn.css和common.css
不包含js代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>注册页</title>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.4/jquery.min.js"></script>
<link rel="stylesheet" href="common.css" />
<link rel="stylesheet" href="logIn.css" />
<style>
#i {
transition: all 0.618s;
opacity: 61.8%;
}
#i:hover {
opacity: 100%;
}
</style>
</head>
<body>
<div class="navigation">
<!-- 头像 -->
<img
src="https://img1.baidu.com/it/u=4205447136,2730860147&fm=253&fmt=auto&app=138&f=JPEG?w=300&h=300"
alt="未登录"
/>
<div class="title">未登录</div>
<div class="space"></div>
<a href="login.html" onclick="remove()">登录</a>
</div>
<!-- 登录页面 -->
<div class="login-Container">
<div class="dialog">
<h3>注册</h3>
<form
target="_blank"
action="reg"
method="POST"
enctype="multipart/form-data"
>
<div id="fileImage">
<input id="i" type="button" value="请上传头像" onclick="judge();" />
<input type="file" name="file" style="display: none" />
<div id="conf">
<input
type="submit"
value="确认"
id="co"
onclick="alert(
'如果你需要上传头像,则需要注意以下几点\n' +
'1. 点击右侧的确认按钮后,此用户名将无法更改头像!\n' +
'2. 用户名应为英文字符,否则虽然注册成功但是头像无法与您进行匹配!\n' +
'3. 若用户名已被注册过或者已绑定头像,则无法正常注册!\n' +
'4. 只有填写用户名后才能上传图片,只有上传了图片才能点击确认,否则会出错\n'
);"
/>
</div>
</div>
<div class="row">
<label for="username">用户名</label>
<input type="text" id="username" name="name" />
</div>
</form>
<div class="row">
<label for="password">密码</label>
<input type="password" id="password" onclick="getImage()" />
</div>
<div class="r">
<input type="submit" id="submit" value="注册" onclick="reg()" />
</div>
</div>
</div>
</body>
</html>
2.2.1 form提交文件
- 由于上传文件按钮的样式难以更改,所以我们这里改为一下这种方式
- 用点击button代替点击上传文件按钮,并且让上传文件按钮消失
提交form的post请求按钮:
2.2.2 js代码
- 上传头像要在输入用户名后才能进行(judge函数的非空校验)
function judge() {
var name = jQuery("#username");
var password = jQuery("#password");
if (name.val().trim() == "") {
alert("请输入名字");
name.focus();
return;
} else {
javascript: $("input[name='file']").click();
jQuery("#i").val("");
}
}
- 确认按钮为form的方式去提交请求的,所以跟js无关~
- 点击密码框,显示头像
function getImage() {
var name = jQuery("#username");
var password = jQuery("#password");
if (name.val().trim() == "") {
alert("请输入名字!");
name.focus();
return;
}
var keyValue = {
name: name.val(),
password: password.val(),
};
jQuery.ajax({
type: "post",
url: "image",
contentType: "application/json; charset=utf8",
data: JSON.stringify(keyValue),
success: function (body) {
if (body != "No") {
jQuery("#i").css("background-image", "url(" + body + ")");
jQuery("#i").val("");
} else {
jQuery("#i").css(
"background-image",
"url(https://img1.baidu.com/it/u=4205447136,2730860147&fm=253&fmt=auto&app=138&f=JPEG?w=300&h=300)"
);
jQuery("#i").val("头像");
}
},
});
}
- 提交注册
function reg() {
var name = jQuery("#username");
var password = jQuery("#password");
if (name.val().trim() == "") {
alert("清输入名字!");
name.focus();
return;
}
if (password.val().trim() == "") {
alert("清输入密码!");
password.focus();
return;
}
var keyValue = {
name: name.val(),
password: password.val(),
};
jQuery.ajax({
type: "post",
url: "save",
contentType: "application/json; charset=utf8",
data: JSON.stringify(keyValue),
success: function (body) {
if (body == "No") {
alert("用户存在");
name.val("");
password.val("");
name.focus();
jQuery("#i").css(
"background-image",
"url(https://img1.baidu.com/it/u=4205447136,2730860147&fm=253&fmt=auto&app=138&f=JPEG?w=300&h=300)"
);
} else {
alert("注册成功");
window.location.href = "login.html";
}
},
});
}
2.2.3 补充:登录页头像显示
- 原理一致~
3. 登录页面提供注册与忘记密码按钮
- 源码直接在码云看就行了~
3.1 注册按钮
简单的跳转~
3.2 忘记密码
- 忘记密码特别简单,就是直接在数据库里拿到密码,然后返回给输入框~
function toGetPassword() {
var name = jQuery("#username");
var password = jQuery("#password");
if (name.val().trim() == "") {
alert("请输入是谁!");
name.focus();
return;
}
var keyValue = {
name: name.val(),
password: password.val(),
};
jQuery.ajax({
type: "POST",
url: "remind",
contentType: "application/json; charset=utf8",
data: JSON.stringify(keyValue),
success: function (body) {
if (body != "No") {
jQuery("#password").val(body);
} else {
alert("不存在这个用户!");
}
},
});
}
后端中(新的servlet类 Remind):
@WebServlet("/remind")
public class Remind extends HttpServlet {
ObjectMapper objectMapper = new ObjectMapper();
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
User user = objectMapper.readValue(req.getInputStream(), User.class);
resp.setContentType("text/html; charset=utf8");
String name = user.name;
DataSource dataSource = new MysqlDataSource();
((MysqlDataSource)dataSource).setUrl("jdbc:mysql://127.0.0.1:3306/Loves?characterEncoding=utf8&useSSL=false");
((MysqlDataSource)dataSource).setUser("root");
((MysqlDataSource)dataSource).setPassword("mmsszsd666");//这是俺的微信号,欢迎添加,相互学习!
try {
Connection connection = dataSource.getConnection();
String sql = "select * from users where name = '" + name + "';";
PreparedStatement preparedStatement = connection.prepareStatement(sql);
ResultSet set = preparedStatement.executeQuery();
if(set.next()) {
resp.getWriter().write(set.getString("password"));
}else {
resp.getWriter().write("No");
}
set.close();
preparedStatement.close();
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}