【JavaEE】使Cookie与Session失效-Servlet上传文件操作-优化表白墙

本文涉及的产品
云数据库 RDS MySQL Serverless,0.5-2RCU 50GB
云数据库 RDS MySQL Serverless,价值2615元额度,1个月
简介: 虽然Cookie和Session都是暂时存在的,不久就会被删掉,但是我们要退出登录的时候,就不能等待其自然消除了~

【JavaEE】使Cookie与Session失效-表白墙退出登录操作-Servlet上传文件操作-表白墙注册上传头像+登录显示头像功能


1. Cookie与Session的删除


Cookie与Session基础博客:【JavaEE】Cookie与Session的前后端交互-表白墙登录设计_s:103的博客-CSDN博客


虽然Cookie和Session都是暂时存在的,不久就会被删掉,但是我们要退出登录的时候,就不能等待其自然消除了~

因为点击退出登录之后,到达登录页面,如果这个时候,浏览器和服务器保留了Cookie和Session,就会自动登录了~

(用户自己手动删Cookie,不现实)

这里就是一个固定的做法了:


一些东西是固定的,目前看不懂也没事,不是本文章重点


4b44cfcef5fc44738aa441dcc3354dac.png

创建一个新的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 表白墙页面增加登录出口


89641268ed0e47ed875835fcc040c9df.png

在wall.html(表白墙html)添加导航栏和登录出口:


16c8e68881a7445da7dd8e1047a57b9c.png


没错,用到的css修饰,一样是照抄博客系统的:(common.css中)

24baa73f99c8445ba4180f1edc8a9b9f.png


头像是默认的头像(这里为什么是用户的头像,后文提到)


1973dfd7bb294dd595163579a0a92257.png

9a94170d42e9465d9cf42376510f6413.png


1.2 点击链接退出登录


跳转到登录页面

调用remove函数发送请求给服务器,使Session/Cookie失效

c2dce0bf4806400b99d102cf23d1c647.png


1.3 测试

image.png


2. 上传文件


这里只讲解一种:通过form表单的file类型input按钮上传,submit按钮提交

先看成品(预计效果):


0b90e52e4d6f4f95bbd52f8e63925f62.png

9576faa363b24aaa9e47cae13b50fb8e.png


我们现在已经具备了登录的功能,但是我们也需要注册的功能,才能让用户使用看到的表白墙有他们的特性~

登录设计博客:【JavaEE】Cookie与Session的前后端交互-表白墙登录设计_s:103的博客-CSDN博客

在此基础上,增加头像显示的功能(当输入了用户名,且点击了密码框的情况下)

设计稿:

dbbdddb32ea54457868c93f03ab7b08e.png


数据库表的设计:


表名为image

用户名

文件名

5b531490f6f94fa98891e87d37b76169.png


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 操作

823a29aae3a74c56bd7472a74d4c63a3.png

对于确认按钮,点击它就是触发了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>");
        }
    }
}



解析:

4a6367e977d7454bb3151c8e9b64fa6c.png



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不存在
}


0350335ee2024eb3bebd053773de50fc.png


第三为此方法:


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!

de6a53cd2695418e9e24dcb9ceced154.png


2.1.5 注册按钮


6064b85546814158ad9bd119fb7a4d77.png

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中插入用户信息


相关实践学习
基于CentOS快速搭建LAMP环境
本教程介绍如何搭建LAMP环境,其中LAMP分别代表Linux、Apache、MySQL和PHP。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
2月前
|
存储 自然语言处理 API
Session、cookie、token有什么区别?
Session、cookie、token有什么区别?
24 1
|
3天前
|
存储 Java
Servlet 教程 之 Servlet Cookie 处理 1
Servlet教程讲解了如何处理Cookie,用于识别和跟踪用户。服务器发送Cookie(如姓名、年龄)到浏览器,浏览器存储并随后续请求回传。教程涵盖设置、读取和删除Cookie,以及中文编码解码:`URLEncoder.encode()`用于编码,`URLDecoder.decode()`用于解码。
8 0
|
1天前
|
存储
Servlet 教程 之 Servlet Cookie 处理 7
Servlet教程展示了如何删除Cookie。Servlet `DeleteCookies`通过设置setMaxAge()为零,从响应头移除名为&quot;url&quot;的Cookie。当运行此Servlet,之前的ReadCookies返回的url将是null。代码包括检查请求中的Cookie,匹配名称后删除,并显示删除确认信息。
4 0
|
1天前
Servlet 教程 之 Servlet Cookie 处理 6
该教程展示了如何使用Servlet读取Cookie。在`doGet`方法中,通过`HttpServletRequest`的`getCookies()`获取Cookie数组,然后遍历并使用`getName()`和`getValue()`获取每个Cookie的详细信息。如果找到名为&quot;name&quot;的Cookie,将其最大生存期设为0以删除。输出显示Cookie的名称和解码后的值。当无Cookie时,则显示相应消息。
4 0
|
2天前
|
XML 数据格式
Servlet 教程 之 Servlet Cookie 处理 5
Servlet教程展示了如何处理Cookie。创建Cookie涉及构造函数(键值对),设置最大生存周期(如24小时)并将其添加到HTTP响应头。给定示例显示了一个Servlet,它从表单接收名字和URL,编码为Cookie,设置过期时间,然后在响应中发送。HTML表单用于触发Servlet。需在web.xml配置Servlet并用HTML页面调用。
7 1
|
2天前
|
安全 网络安全 数据安全/隐私保护
Servlet 教程 之 Servlet Cookie 处理 3
Servlet教程中的Cookie处理介绍了12个关键方法:设置/获取域名、最大生存时间、名称、值、路径和安全属性,以及评论的设置与获取。这些方法用于在Servlet中创建和管理Cookie的行为,如设定有效期、作用域及安全性。
9 1
|
3天前
|
存储 JavaScript 前端开发
Servlet 教程 之 Servlet Cookie 处理 2
Servlet教程探讨了Cookie处理,用于识别返回用户。服务器发送Cookie到浏览器,浏览器存储并随后续请求发送。处理中文Cookie需用URLEncoder/URLDecoder进行编码解码。设置Cookie通过HTTP头的Set-Cookie字段,包含名值对、过期时间、路径和域。浏览器在到期前保存并自动发送匹配的Cookie。Servlet利用request.getCookies()获取Cookie数组。
8 0
|
4天前
|
存储 安全 前端开发
禁用Cookie后Session还能用吗?
禁用Cookie后Session还能用吗?
14 1
|
4天前
|
Java
Cookie和Session
Cookie和Session
11 0
|
15天前
|
存储 JSON 安全