表白墙退出登录操作-表白墙注册上传头像+登录显示头像功能
文章目录
- 【JavaEE】使Cookie与Session失效-表白墙退出登录操作-Servlet上传文件操作-表白墙注册上传头像+登录显示头像功能
- 1. Cookie与Session的删除
- 1.1 表白墙页面增加登录出口
- 1.2 点击链接退出登录
- 1.3 测试
- 2. 上传文件
- 2.1 后端对上传文件的处理
- 2.1.1 HttpServletRequest 类方法
- 2.1.2 Part 类方法
- 2.1.3 操作
- 2.1.5 Image类
- 2.1.4 Save类
- 2.1.5 注册按钮
- 2.2 前端设计
- 2.2.1 form提交文件
- 2.2.2 js代码
- 2.2.3 补充:登录页头像显示
- 3. 登录页面提供注册与忘记密码按钮
- 3.1 注册按钮
- 3.2 忘记密码
- 4. 测试
【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失效)
简单了解:
Cookie不仅仅有名字和值两个属性,还有域(domain)、路径(path)等属性。其中,不同的域、不同的路径下可以存在同样名字的cookie。一般我们设置cookie的方法是用一个同样名字、一个值。这时就一定要搞清楚你要设置的cookie的域和路径,否则就会产生问题中的情况。
Cookie机制其实还可以存储很多其他的信息,但在本文章不做研究,暂时用不到
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表单的提交,将用户名和头像一同提交给服务器
- 细节:由于form的编码是特定的编码,如果在后端以utf8去理解,会报错,所以只有在用户名不为中文或者什么特殊字符的时候才能正常的与头像进行绑定~
- 中文虽然不会导致文件上传失败,但是这个中文用户名不会绑定到头像,也就是说此后这个账号将只显示默认的头像,而不是自己的头像
而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>");
}
}
}
解析:
write方法是直接写道硬盘上,建议不要使用相对路径,因为其默认的当前目录不是我们的项目目录~
- 后面的文件名可以写自己的,但是尽量不要该文件的类型
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>
改动1:头像触摸变化
改动2:头像和按钮
- form包住了头像和用户名输入框
- 在确认的时候做一些提示~
- 登录 -> 注册
改动3:对新增元素进行css修饰
#fileImage { display: flex; justify-content: center; align-items: center; justify-content: space-around; } #conf { display: flex; justify-content: center; align-items: center; } #co { width: 100px; height: 50px; color: rgba(255, 255, 255, 0.618); font-weight: 900; background-color: rgb(251, 114, 153); line-height: 50px; text-align: center; border-radius: 30px; border: none; transition: all 0.618s; } #co:hover { background-color: rgb(101, 94, 252); color: rgba(0, 0, 0, 0.618); } #i { width: 200px; height: 200px; border-radius: 100px; background-image: url(https://img1.baidu.com/it/u=4205447136,2730860147&fm=253&fmt=auto&app=138&f=JPEG?w=300&h=300); background-repeat: no-repeat; background-position: center center; background-size: cover; border: rgba(251, 114, 153, 0.5) 2px solid; }
改动4:对其他元素进行微调(不演示)
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();
}
}
}
4. 测试
登录与退出登录测试:
注册测试:
重复注册测试:
文章到此结束!谢谢观看
可以叫我 小马,我可能写的不好或者有错误,但是一起加油鸭🦆!表白墙即将到达尾声,最后一步就是优化“甜言蜜语”的显示了!
码云链接:代码
敬请期待(^-^)V