Servlet实践操作

news2024/11/16 0:42:32

Servlet运行原理

  1. Tomcat 的代码内置了 main 方法,当我们启动 Tomcat 的时候,就是从 Tomcat 的 main 方法开始执行的

  2. 被 @WebServlet 注解修饰的类会在 Tomcat 启动的时候就被获取并集中管理

  3. Tomcat 通过反射这样的语法机制来创建被 @WebServlet 注解修饰的类的实例

  4. 这些实例被创建完之后,就会调用其中的 init 方法进行初始化

  5. 这些实例被销毁之前,就会调用其中的 destory 方法进行收尾工作

  6. Tomcat 内部也是通过 Socket API 进行网络通信

  7. Tomcat 为了能够同时处理多个 HTTP 请求,采取了多线程的方式实现,因此 Servlet 是运行在多线程环境下的

 Post请求测试

浏览器直接发送的是get请求,这里使用Postman进行接口测试

@WebServlet("/testDoPost")
public class TestDoPostServlet extends HttpServlet {

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.getWriter().write("testPost success!");
    }
}

 Response重定向到其他页面

public class RedirectServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.sendRedirect("https://blog.csdn.net/weixin_44610169");
    }
}

post请求体body中携带信息获取

@WebServlet("/postParameter")
public class PostParameterServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/html;charset=utf-8");
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        resp.getWriter().write("username = " + username + " password = " + password);
    }
}

body内容格式为JSON数据获取

JSON格式的数据需要解析,Java内置库没有对JSON的解析,所以这里导入第三方数据库jackson,使用jackson解析读取请求中body内的数据.

        <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.17.1</version>
        </dependency>

 

//定义一个JavaBean类
class UserInfo{
    public String username;
    public String password;
}
//读取请求中所有body
    public String readBody(HttpServletRequest req) throws IOException {
        //获取请求体长度
        int contentLength = req.getContentLength();
        //获取请求体内容
        byte[] bytes = new byte[contentLength];
        //读取请求体内容
        ServletInputStream inputStream = req.getInputStream();
        //将请求体内容读取到bytes中
        inputStream.read(bytes);
        //将bytes转换为字符串返回
        return new String(bytes, StandardCharsets.UTF_8);
    }
@WebServlet("/jsonParameter")
public class JsonParameterServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/html;charset=UTF-8");
        //读取请求体内容
        String body = readBody(req);
        //将请求体内容转换为JavaBean对象
        UserInfo userInfo = new ObjectMapper().readValue(body, UserInfo.class);
        //输出解析结果
        resp.getWriter().write("username: " + userInfo.username);
        resp.getWriter().write("password: " + userInfo.password);
    }
}

 Cookie

  • Cookie 是什么?

Cookie 是浏览器提供的在客户端存储数据的一种机制(由于浏览器禁止了网页中的代码直接访问本地磁盘的文件,因此想要在网页中实现持久化存储,就可以通过 Cookie 这样的机制)

  • Cookie 里面存什么?

Cookie 存储的数据都是程序员自定义的,存储的数据是一个字符串,是键值对结构的,键值对之间使用 ; 分割,键和值之间使用 = 分割

  • Cookie 从哪里来?

服务器返回响应的时候,可以把要在客户端保存的数据以 Set-Cookie 这个 header 的方式返回给浏览器

  • Cookie 到哪里去?

客户端下次访问服务器的时候,就会把之前保存好的 Cookie 再发送给服务器

  • Cookie 的典型应用场景:

可以使用 Cookie 来保存用户的登录信息。比如我们登录过某个网站后,下次登录时就不需要重新输入用户和密码了

  • Cookie 的缺陷:

每次请求都要把该域名下所有的 Cookie 通过 HTTP 请求传给服务器,因此 Cookie 的存储容量是有限的。

Session

在计算机中,尤其是在网络应用中,Session 称为“会话控制”。Session 对象存储特定用户会话所需的属性及配置信息。当用户在应用程序的 Web 页之间跳转时,存储在 Session 对象中的变量将不会丢失,而是在整个用户会话中一直存在下去。当用户请求来自应用程序的 Web 页时,如果该用户还没有会话,则 Web 服务器将自动创建一个 Session 对象。当会话过期或被放弃后,服务器将终止该会话。Session 对象最常见的一个用法就是存储用户的首选项。例如,如果用户指明不喜欢查看图形,就可以将该信息存储在 Session 对象中。注意会话状态仅在支持 Cookie 的浏览器中保留。

session的本质

  • 会话的本质就是一个哈希表,其中存储了一些键值对结构,key 叫做 sessionId,是一个不随机的、不重复的、唯一的字符串,value 就是要保存的身份信息,通过 HttpSession 对象来保存。key 和 value 都是 Servlet 自动创建的。

  • 每个用户登录都会生成一个会话,服务器会以哈希表的方式将这些会话管理起来

  • 一个会话的详细数据通过一个 HttpSession 对象来存储,并且 HttpSession 对象中存储的数据也是键值对结构,key 和 value 都是程序员自定义的

  • 当用户成功登录之后,服务器在 Session 中会生成一个新的记录,并把 sessionId 返回给客户端(例如 HTTP 响应中可以通过 Set-Cookie 字段返回,其中 Cookie 的 key 为 “JSESSION”,value 为服务器生成的 sessionId 的具体的值)

  • 然后客户端只需要保存这个 sessionId ,当后续再给服务器发送请求时,请求中就会带上 sessionId(例如 HTTP 请求中会带上 Cookie 字段用于传递 Session)

  • 服务器收到请求后,就会根据请求中的 sessionId 在 Session 中查询对应用户的身份信息,在进行后续操作

 Servlet实现登录测试

前端页面login.html使用form表单发送数据,servlet接收后进行操作

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Login</title>
</head>
<body>
    <form action="/servlet_test/login1" method="post">
        <input type="text" placeholder="用户名" name="username"/>
        <input type="password" placeholder="密码" name="password"/>
        <input type="submit" value="登录">
    </form>

</body>
</html>
@WebServlet("/login1")
public class loginServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/html;charset=utf-8");
        String username = req.getParameter("username");
        String password = req.getParameter("password");

        if (username == null || username.isEmpty() || password == null || password.isEmpty()){
            resp.getWriter().write("<h3>用户名或密码不能为空</h3>");
            return;
        }
        if (!username.equals("root") && !password.equals("root")){
            resp.getWriter().write("<h3>用户名或密码错误</h3>");
            return;
        }
        if (username.equals("root") && password.equals("root")){
            // 登录成功后创建session
            HttpSession session = req.getSession(true);
            session.setAttribute("visitCount", 0);
            // 登录成功后跳转页面
            resp.sendRedirect("index");
        }

    }
}
@WebServlet("/index")
public class LoginSuccessServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/html;charset=utf-8");
        HttpSession session = req.getSession(false);
        if(session == null){
            // 如果为空重定向到登录页面
            resp.sendRedirect(req.getContextPath() + "/login.html");
            return;
        }
        // 登录成功后获取session中的数据
        Integer visitCount = (Integer) session.getAttribute("visitCount");
        visitCount += 1;
        session.setAttribute("visitCount", visitCount);
        resp.getWriter().write("登录成功,欢迎回来!您已经登录" + visitCount + "次!");
    }
}

文件上传

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>上传文件</title>
</head>
<body>
<!--通过 form 表单构造上传文件,要加上一个 enctype 字段,
    它表示 body 中的数据格式,它的默认值为:x-www-form-urlencoded,
    这里要修改成:multipart/form-data,它是上传文件或者图片的数据格式-->
  <form action="/servlet_test/uploadFile" method="post" enctype="multipart/form-data">>
    <input type="file" name="file1">
    <input type="submit" value="上传">
  </form>
</body>
</html>
@MultipartConfig
@WebServlet("/uploadFile")
public class uploadFileServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/html;charset=UTF-8");
        Part file1 = req.getPart("file1");
        String fileName = file1.getSubmittedFileName();
        String contentType = file1.getContentType();
        long size = file1.getSize();
        System.out.println("文件名:" + fileName + ",文件类型:" + contentType + ",文件大小:" + size + "字节");
        file1.write("C:\\Users\\86152\\Desktop\\" + fileName);

        resp.getWriter().write("文件上传成功");
    }
}
传文件操作还需要给 Servlet 加上一个 @MultipartConfig 注解,否则服务器代码无法使用 getPart() 方法

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1839623.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Day 27:2596. 检查骑士巡视方案

Leetcode 2596. 检查骑士巡视方案 骑士在一张 n x n 的棋盘上巡视。在 **有效 **的巡视方案中&#xff0c;骑士会从棋盘的 左上角 出发&#xff0c;并且访问棋盘上的每个格子 恰好一次 。 给你一个 n x n 的整数矩阵 grid &#xff0c;由范围 [0, n * n - 1] 内的不同整数组成&…

超神级!Markdown最详细教程,程序员的福音

超神级&#xff01;Markdown最详细教程&#xff0c;程序员的福音Markdown最详细教程&#xff0c;关于Markdown的语法和使用就先讲到这里&#xff0c;如果喜欢&#xff0c;请关注“IT技术馆”。馆长会更新​最实用的技术&#xff01;https://mp.weixin.qq.com/s/fNzhLFyYRd3skG-…

linux环境编程基础学习

Shell编程&#xff1a; 相对的chmod -x xx.sh可以移除权限 想获取变量的值要掏点dollar&#xff08;&#xff04;&#xff09; 多位的话要加个花括号 运算&#xff1a;expr 运算时左右两边必须要加空格 *号多个含义必须加转义符 双引号可以加反单&#xff0c;但是发过来就不行 …

containerd手动配置容器网络

containerd手动配置容器网络 机器详情nerdctl启动一个不带网络的容器获取容器ID、PID与network namespace路径准备bridge插件的执行配置文件通过下面的命令调用bridge插件准备tuning插件文件执行下面的命令调用tuning插件准备portmap插件文件执行下面的命令调用portmap插件删除…

算法竞赛数论杂题

menji 和 gcd 题目&#xff1a; 一开始以为是只有l不确定&#xff0c;r是确定的&#xff0c;这样的话我们可以枚举r的所有约数&#xff0c;然后对其每个约数x进行判断&#xff0c;判断是否满足题意&#xff0c;具体做法是先让l % x如果 0则该约数可行&#xff0c;如果不可行…

文件扫描工具都有哪些?职场大佬都在用的文本提取工具大盘点~

回想起刚毕业初入职场那阵子&#xff0c;领导让帮忙把纸质文件扫描提取为文本时&#xff0c;还只会傻乎乎地一点点操作&#xff0c;属实是费劲得很&#xff01; 好在后面受朋友安利&#xff0c;找到了4个能够快速实现文件扫描文字提取的方法&#xff0c;这才让我的办公效率蹭蹭…

[SCAU 课程设计参考] 活动管理程序

(仅供参考!!!!!!) 废话不多说&#xff0c;直接上代码&#xff01;(但是量有点多&#xff0c;放前面影响观感&#xff0c;所以还是先不放了&#xff0c;文章末尾有链接) 题目的要求: 提要:我的设计只是一个参考&#xff0c;当时还是大一的时候写的&#xff0c;代码比较青涩&a…

[学习笔记]-MyBatis-Plus简介

简介 Mybatis-Plus&#xff08;简称 MP&#xff09;是一个 MyBatis (opens new window)的增强工具&#xff0c;在 MyBatis 的基础上只做增强不做改变&#xff0c;为简化开发、提高效率而生。 简言之就是对单表的增删改查有了很好的封装。基本不用再单独写sql语句了。目前此类…

微博舆情分析系统可以继续完善的基于python 前端vue

微博舆情分析系统可以继续完善的&#xff0c;前后端分离&#xff0c;前端基于vue 后端基于python的flask可以说是非常的简洁&#xff0c;支持实时更新数据。界面如图 主要工作点体现在后端实时更新数据跟数据的处理方面上&#xff0c;后续有空会用hadoop来处理海量数据真…

数据库 | 试卷四

1.数据库系统的特点是 数据共享、减少数据冗余、数据独立、避免了数据不一致和加强了数据保护 2.关系模型的数据结构是二维表结构 3.聚簇索引 cluster index 4. 这里B&#xff0c;C都是主属性&#xff0c;所以B->C不是非主属性对码的部分函数依赖 候选键&#xff08;AC&a…

Jlink下载固件到RAM区

Jlink下载固件到RAM区 准备批处理搜索exe批处理调用jlink批处理准备jlink脚本 调用执行 环境&#xff1a;J-Flash V7.96g 平台&#xff1a;arm cortex-m3 准备批处理 搜索exe批处理 find_file.bat echo off:: 自动识别脚本名和路径 set "SCRIPT_DIR%~dp0" set &qu…

开发者黑板报#65

第65期 AI 谷歌Gemini 终于&#xff0c;GPT-4独霸时代终结了&#xff01; 过去一个月里&#xff0c;四款大模型横空出世&#xff0c;在各项关键基准测试中与GPT-4相匹敌&#xff0c;甚至更胜一筹。 谷歌Gemini 1.5突破100万个tokens&#xff0c;是GPT-4的近8倍&#xff0c…

【Docker】——安装镜像和创建容器,详解镜像和Dockerfile

前言 在此记录一下docker的镜像和容器的相关注意事项 前提条件&#xff1a;已安装Docker、显卡驱动等基础配置 1. 安装镜像 网上有太多的教程&#xff0c;但是都没说如何下载官方的镜像&#xff0c;在这里记录一下&#xff0c;使用docker安装官方的镜像 Docker Hub的官方链…

易舟云财务软件:开启云记账新时代

在数字化浪潮的推动下&#xff0c;财务管理正经历着深刻的变革。易舟云财务软件&#xff0c;作为一款引领时代的云记账平台&#xff0c;以其卓越的功能和便捷的操作&#xff0c;为企业带来了全新的财务管理体验。 云记账&#xff0c;财务管理的未来趋势 云记账&#xff0c;即基…

【紫光同创盘古PGX-Nano教程】——(盘古PGX-Nano开发板/PG2L50H_MBG324第十一章)模拟波形实验例程说明

本原创教程由深圳市小眼睛科技有限公司创作&#xff0c;版权归本公司所有&#xff0c;如需转载&#xff0c;需授权并注明出处&#xff08;www.meyesemi.com) 适用于板卡型号&#xff1a; 紫光同创PG2L50H_MBG324开发平台&#xff08;盘古PGX-Nano&#xff09; 一&#xff1a;…

Shopify 如何实现 Sticky 功能

Shopify 如何实现 Sticky 功能 介绍 在网页设计中&#xff0c;Sticky 功能是一种常见的技术&#xff0c;它使得网页上的元素在滚动时保持固定位置。这对于创建吸引人的用户体验和提高网站的可用性非常重要。Shopify 作为一个流行的电商平台&#xff0c;提供了丰富的功能和工具…

基于PHP的奶茶商城系统

有需要请加文章底部Q哦 可远程调试 基于PHP的奶茶商城系统 一 介绍 此奶茶商城系统基于原生PHP开发&#xff0c;数据库mysql&#xff0c;ajax实现数据交换。系统角色分为用户和管理员。系统在原有基础上添加了糖度的选择。 技术栈 phpmysqlajaxphpstudyvscode 二 功能 用户…

双层循环和循环语句

echo 打印 echo -n 表示不换行输出 echo -e 表示输出转义字符 echo \b 相当于退格键&#xff08;backspace&#xff09; echo \n 换行&#xff0c;相当于回车 echo \f 换行&#xff0c;换行后的新行的开头连着上一行的行尾 echo \t 相当于tab健 &#xff08;…

回归洛伦兹变换

现在再回到洛伦兹变换&#xff0c; 将其写成上角标表示惯性系的形式&#xff08;注意不是幂次&#xff09;&#xff0c; 并且认为洛伦兹变换中的两个方程的比例常数&#xff0c; 并不仅仅是因为虚数单位数量巨大导致的“误判”&#xff0c;虽然这也是说得通的。因为我们已经看到…

APP自动化测试-Appium常见操作之详讲

一、基本操作 1、点击操作 示例&#xff1a;element.click() 针对元素进行点击操作 2、初始化&#xff1a;输入中文的处理 说明&#xff1a;如果连接的是虚拟机&#xff08;真机无需加这两个参数&#xff0c;加上可能会影响手工输入&#xff09;&#xff0c;在初始化配置中…