Java ee Servlet精讲


提示:以下是本篇文章正文内容,下面案例可供参考

一、Servlet是什么

Servlet是一种实现动态页面的技术,是一组Tomcat提供给程序员的API,帮助程序员简单高效的开发一个web app

回顾一下:动态页面 vs 静态页面

静态页面也就是内容始终固定的页面. 即使 用户不同/时间不同/输入的参数不同 , 页面内容也不会发生
变化
. (除非网站的开发人员修改源代码, 否则页面内容始终不变).
对应的, 动态页面指的就是 用户不同/时间不同/输入的参数不同, 页面内容会发生变化

在这里插入图片描述
Servlet主要做的工作
允许程序猿注册一个类, 在 Tomcat 收到某个特定的 HTTP 请求的时候, 执行这个类中的一些代码.
帮助程序猿解析 HTTP 请求, 把 HTTP 请求从一个字符串解析成一个 HttpRequest 对象.
帮助程序猿构造 HTTP 响应. 程序猿只要给指定的 HttpResponse 对象填写一些属性字段, Servlet
就会自动的安装 HTTP 协议的方式构造出一个 HTTP 响应字符串, 并通过 Socket 写回给客户端

ps:当然, Servlet 还支持一些其他的辅助功能, 此处暂时先不介绍.

二、第一个Servlet程序

2.1创建项目

我们使用IDEA创建一个Maven项目

  1. 菜单 -> 文件 -> 新建项目 -> Maven

在这里插入图片描述
2) 选择要项目存放的目录
在这里插入图片描述

稍等片刻,项目就创建完毕了。
在这里插入图片描述
作为一个maven项目,它会自动生成一些目录结构和代码

2.2引入依赖

需要在代码中引入Servlet api,这个api不是JDK内置的,而是第三方Tomcat内置的
Tomcat相对于java官方来说,仍然是第三方。
ps:JDK、Tomcat、Servlet版本要配套,如果版本差太多,可能会出问题

我们现在进入maven中央仓库
maven中央仓库地址
进入网页后,在搜索栏直接搜索Servlet即可
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
复制之后,进入idea,然后先创建一个标签,然后把刚才复制的粘贴进去
在这里插入图片描述

进入之后发现有标红的,别担心,按一下刷新,就可以进行下载了
在这里插入图片描述

2.3创建目录结构

虽然当下maven给我们创建了一些目录,但是还不够,这还不足以支持我们写一个Servlet项目
因此需要手动创建一些目录和文件。

先找到main目录,在main目录下创建一个webapp目录
在这里插入图片描述
在这里插入图片描述
在webapp里面再创建一个WEB-INF目录
在这里插入图片描述
随后,在WEB-INF中创建一个web.xml
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

注意:千万别把目录名字/位置搞错,这是Tomcat和idea默认的一个约定(不要问为什么)

2.4编写代码

可以看到,我们web.xml文件里没有代码的时候是红的,也就是说需要往里面写点内容。
下面这段代码,同学们直接复制即可,手敲容易出错

<!DOCTYPE web-app PUBLIC
        "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
        "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
    <display-name>Archetype Created Web Application</display-name>
</web-app>

在这里插入图片描述
进入之后发现有一处是标红的,还报了警告,怎么办?
点击那个红色的灯,选择第一个选项
在这里插入图片描述
点完等它加载一下就ok了
在这里插入图片描述
接下来我们来正式写代码,在java文件夹下创建一个HelloServlet类
在这里插入图片描述

helloServlet需要基础HttpServlet,然后重写一下doGet方法
(你直接写doGet会自动有提示帮你生成代码的)

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class helloServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.doGet(req, resp);
    }
}

在这里插入图片描述

doGet方法:do是处理,Get是http的get请求。
也就是说,这个方法会在tomcat收到一个http get请求时,会被tomcat调用到。

doGet方法要做的工作,就是根据请求,计算响应
ps:一个服务器的工作流程,可以分成三个典型步骤:
1.接收请求并解析
2.根据请求计算响应
3.构造响应数据,并返回给客户端
而1和3tomcat已经帮我们做好了,我们需要做的就是2,也就是要自己实现逻辑(doGet要实现的内容)
在这里插入图片描述
我们这里写一个简单的helloworld

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 java.io.IOException;
@WebServlet("/hello")
//把当前这个HelloServlet这个类,和HTTP请求中的URL里面,路径带有/hello这样的请求给关联起来了
public class helloServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //super.doGet(req, resp);这个super一定要注释掉,不能调用父类的doGet

        System.out.println("hello world");//这个是在idea里面打印

        //如果想在页面上打印hello world,就把hello world字符串放到http响应的body中
        //浏览器就会把body的内容显示到页面上
        resp.getWriter().write("hello world");
        //resp是响应对象,getWriter其实是返回了一个Writer对象(字符流对象)
        //此处的Writer对象就不是往文件里面写了,而是往http响应的body中写入数据
        //write是真正干活,写数据的方法
    }
}

2.5打包

我们上面写的代码是不能单独运行的(没有main方法)
需要把当前的代码打包,然后部署到Tomcat上,由tomcat来进行调用
在这里插入图片描述
在这里插入图片描述
在打包前还需要一些准备工作:
在pom.xml中,在与dependencies同一级标签,写一个packaging标签,里面写上war
在这里插入图片描述
然后再写上build标签,里面写上finalName标签,然后加入你想要的war包名字
在这里插入图片描述
上面的准备工作做完,就可以进行打包了,双击下图中的package即可进行打包
在这里插入图片描述
打包结束后,如果你看到BUILD SUCCESS说明打包成功了
在这里插入图片描述
然后在左侧,点开target目录,你会发现刚才的war包已经出现咯
在这里插入图片描述

2.6部署

部署就是把war包拷贝到tomcat的webapps目录下,这个没啥好说的ctrl+c 然后ctrl+v即可

首先找到我们的war包,然后右击,找到open in 然后Explorer
在这里插入图片描述
出现这样一个目录
在这里插入图片描述
然后打开你的tomcat目录下面的webapps
在这里插入图片描述

把war包复制进去即可
在这里插入图片描述
拷贝完之后,我们启动tomcat看看效果
(tomcat的安装、配置、使用,详情请看笔者上一篇文章tomcat,都是手把手教学,建议收藏)
这是tomcat文章链接
启动完tomcat你可以在里面找到我们刚才的war包
在这里插入图片描述
然后就是运行成功后,war包会被解压缩成一个目录
在这里插入图片描述

2.7验证

部署完之后,我们就可以通过浏览器来验证一下了
在浏览器中输入http://127.0.0.1:8080/servlet_hello/hello
在这里插入图片描述
在这里插入图片描述

我们进入刚才的地址,可以看到下图中的效果
在这里插入图片描述
页面中的hello world就是返回http响应的body部分
在这里插入图片描述
举个例子:比如现在我把之前的打印hello world,改成打印一个时间戳,你每次刷新都会是不同的时间戳,这就是动态的区别。
至于怎么改,就是在之前写hello world的地方修改,然后重复2.4.-2.7的操作(我这里偷懒就不再一一演示了)

2.8后记

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

三、更便捷的部署方式

手动拷贝 war 包到 Tomcat 的过程比较麻烦. 我们还有更方便的办法.
此处我们使用 IDEA 中的 Smart Tomcat 插件完成这个工作.

理解插件:
在这里插入图片描述
相当于合体升级,原先你是擎天柱,然后你和天火合体了,现在你就成了会飞的擎天柱
在这里插入图片描述
现在我们来安装smart tomcat
在idea的File中找到Settings
在这里插入图片描述
在Settings中找到Plugins(也就是插件)
在这里插入图片描述
搜索smart tomcat,点击install,等它下载完点ok,这时最好重启一下idea
在这里插入图片描述
重启idea后,点击右上角的add configuration
在这里插入图片描述
点击之后弹出一个窗口,点击左上角的加号
在这里插入图片描述
点击加号之后,点击smart tomcat
在这里插入图片描述
进入之后,按下图红字提示进行配置,配置完点击ok
在这里插入图片描述
配置完成后,你会发现右上角出现了一个三角符号,以后只要点击一下这个三角符号,就可以自动完成打包、部署、重启tomcat这一系列的操作。
在这里插入图片描述
在启动前,把tomcat关掉,不然你tomcat占了8080的端口,
idea这里再启动,因为端口是不能重复占用的就会报错。

启动后发现一堆红色的字,这是报错吗?——不是,因为本来就是红色的字/doge
在这里插入图片描述
ps:如果你遇到下面的错误,说明你没把tomcat关掉,8080端口被占用了。tomcat关掉再启动idea即可
在这里插入图片描述
我们之前在2.7说过,如果想改就要重复2.4-2.7的操作,我们现在由于有了这种更简便的方法,就可以直接修改内容了,然后idea会帮我们完成2.4-2.7一系列的操作。我们来试试效果。
我们现在是下图这样的页面
在这里插入图片描述

现在我要在hello word后面加一个时间戳
然后点击右上角三角运行
在这里插入图片描述
在页面中点击刷新一下,就可以发现后面跟了时间戳
在这里插入图片描述
你每次点刷新,产生的数都是不一样的
在这里插入图片描述
在这里插入图片描述

只能说一句,idea牛逼
在这里插入图片描述

四、访问出错怎么办?

我们初学servlet的时候,会出现很多的错误,这些错误一般是由于我们某个操作不正确引起的,
笔者将这些错误进行了一些简单的汇总:

4.1出现 404

404 表示用户访问的资源不存在. 有两种可能情况:
1)你请求访问的资源路径写的不对(大概率)
2)路径写对了,但是服务器没有正确把资源加载起来(小概率)

比如我们正确的路径为:
在这里插入图片描述

错误实例1:少写了context path
在这里插入图片描述

错误实例2:少写了 Servlet Path
在这里插入图片描述
错误实例3:Servlet Path 写的和 URL 不匹配
在这里插入图片描述
错误实例4:web.xml 写错了

比如你清空了web.xml
在这里插入图片描述
在这里插入图片描述

4.2出现 405

405 表示对应的 HTTP 请求方法没有实现
错误实例:没有实现 doGet 方法.

@WebServlet("/hello")
public class HelloServlet extends HttpServlet {
}

比如原先我们http://127.0.0.1:8080/servlet_hello/hello下的页面是正常的
在这里插入图片描述

我们如果把idea中toget方法改成topost方法看看效果怎么样
在这里插入图片描述
修改完后,用我们之前弄的smartTomcat一键部署,点击右上角的绿三角
在这里插入图片描述
点击完三角后,重启tomcat

在浏览器中访问, 可以看到:
在这里插入图片描述

在浏览器地址栏直接输入 URL , 会发送一个 HTTP GET 请求.
此时就会根据 /servlet_hello/hello 这个路径找到 HelloServlet 这个类. 并且尝试调用
HelloServlet 的 doGet 方法.
但是如果没有实现 doGet 方法, 就会出现上述现象
在这里插入图片描述
注:如果是你的toGet方法中忘记注释掉super.doGet,也会出现405
在这里插入图片描述
在这里插入图片描述
为什么会出现这种情况?我们点进父类的toGet方法
在这里插入图片描述

4.3出现 500

500也是一个高频错误,5开头,一般是服务器出问题了
一般500就是服务器代码中抛出异常了,但是我们的代码没有处理这个异常
这个异常就抛到tomcat那里了
ps:如果代码中出现异常,可以用catch来捕捉到
如果catch没捕捉到(类型不匹配,压根没catch),异常就会沿着调用栈,向上传递
有点类似我们同学有矛盾,小矛盾可以自己私下处理;
如果处理不了,老师帮你们处理;如果还处理不了,校长帮你们处理。。。
在这里插入图片描述
然后smartTomcat启动一下,重启tomcat,再访问网页

在这里插入图片描述
我们到idea中看看是不是500给出的异常位置,可以看到,确实是doGet方法中,且在第23行
在这里插入图片描述

4.4出现空白页面

在这里插入图片描述
启动smartTomcat,然后重启tomcat,再打开网页就是下图中,啥也没有
在这里插入图片描述
所以出现空白页面,去查一查自己是不是代码中没有响应

4.5出现“无法访问此网站”

这种情况一般是tomcat没有正确启动(或者就没有启动)
在这里插入图片描述
没有启动tomcat你进网站的话,就相当于饭馆没开门,你进去吃饭。。。

五、Servlet运行原理

5.1Tomcat的定位

Servlet是属于上层建筑,下面的传输层、网络层、数据链路层…都是属于经济基础
在这里插入图片描述
当浏览器给服务器发送请求的时候, Tomcat 作为 HTTP 服务器, 就可以接收到这个请求

HTTP 协议作为一个应用层协议, 需要底层协议栈来支持工作. 如下图所示:
在这里插入图片描述
在这里插入图片描述

更详细的交互过程可以参考下图:
在这里插入图片描述
浏览器和服务器直接交互数据,这个过程中,
是否会涉及TCP三次握手、确认应答?
是否会涉及IP的分包组包?
是否会涉及以太网的MTU?
答案都是——会

5.2Tomcat的伪代码

下面的代码通过 “伪代码” 的形式描述了 Tomcat 初始化/处理请求 两部分核心逻辑.
ps:所谓 “伪代码”, 并不是一些语法严谨, 功能完备的代码, 只是通过这种形式来大概表达某种逻辑.

5.2.1Tomcat 初始化流程

class Tomcat {
// 用来存储所有的 Servlet 对象
 private List<Servlet> instanceList = new ArrayList<>();
 public void start() {
       // 根据约定,读取 WEB-INF/web.xml 配置文件;
        // 并解析被 @WebServlet 注解修饰的类
       
        // 假定这个数组里就包含了我们解析到的所有被 @WebServlet 注解修饰的类. 
        Class<Servlet>[] allServletClasses = ...;
        
        // 这里要做的的是实例化出所有的 Servlet 对象出来;
        for (Class<Servlet> cls : allServletClasses) {
            // 这里是利用 java 中的反射特性做的
           // 实际上还得涉及一个类的加载问题,因为我们的类字节码文件,是按照约定的
            // 方式(全部在 WEB-INF/classes 文件夹下)存放的,所以 tomcat 内部是
            // 实现了一个自定义的类加载器(ClassLoader)用来负责这部分工作。
            
            Servlet ins = cls.newInstance();
            instanceList.add(ins);
       }
        
        // 调用每个 Servlet 对象的 init() 方法,这个方法在对象的生命中只会被调用这一次;
        for (Servlet ins : instanceList) {
            ins.init();
       }
        
        // 利用我们之前学过的知识,启动一个 HTTP 服务器
        // 并用线程池的方式分别处理每一个 Request
        ServerSocket serverSocket = new ServerSocket(8080);
        // 实际上 tomcat 不是用的固定线程池,这里只是为了说明情况
        ExecuteService pool = Executors.newFixedThreadPool(100);
        
        while (true) {
            Socket socket = ServerSocket.accept();
            // 每个请求都是用一个线程独立支持,这里体现了我们 Servlet 是运行在多线程环境下的
            pool.execute(new Runnable() {
               doHttpRequest(socket); 
           });
       }
        // 调用每个 Servlet 对象的 destroy() 方法,这个方法在对象的生命中只会被调用这一次;
        for (Servlet ins : instanceList) {
            ins.destroy();
       }
   }
    
    public static void main(String[] args) {
        new Tomcat().start();
   }
}

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
ps:
正常流程:比如Tomcat 8005端口(管理端口),可通过该端口关闭Tomcat,这就是“正常流程”
非正常流程:直接结束进程(大部分是这种情况)

5.2.2Tomcat 处理请求流程

class Tomcat {
    void doHttpRequest(Socket socket) {
        // 参照我们之前学习的 HTTP 服务器类似的原理,进行 HTTP 协议的请求解析,和响应构建
        HttpServletRequest req = HttpServletRequest.parse(socket);
        HttpServletRequest resp = HttpServletRequest.build(socket);
        
        // 判断 URL 对应的文件是否可以直接在我们的根路径上找到对应的文件,如果找到,就是静态
内容
        // 直接使用我们学习过的 IO 进行内容输出
        if (file.exists()) {
            // 返回静态内容
            return;
       }
        
        // 走到这里的逻辑都是动态内容了
        
        // 根据我们在配置中说的,按照 URL -> servlet-name -> Servlet 对象的链条
        // 最终找到要处理本次请求的 Servlet 对象
        Servlet ins = findInstance(req.getURL());
        
        // 调用 Servlet 对象的 service 方法
        // 这里就会最终调用到我们自己写的 HttpServlet 的子类里的方法了
        try {
       ins.service(req, resp); 
       } catch (Exception e) {
            // 返回 500 页面,表示服务器内部错误
       }
   }
}

在这里插入图片描述

5.2.3 Servlet 的 service 方法的实现

class Servlet {
    public void service(HttpServletRequest req, HttpServletResponse resp) {
        String method = req.getMethod();
        if (method.equals("GET")) {
            doGet(req, resp);
       } else if (method.equals("POST")) {
            doPost(req, resp);
       } else if (method.equals("PUT")) {
            doPut(req, resp);
       } else if (method.equals("DELETE")) {
            doDelete(req, resp);
       } 
       ......
   }
}

在这里插入图片描述

5.2.4小结

在这里插入图片描述

六、Servlet API 详解

6.1HttpServlet

我们自己写代码,也是通过继承这个HttpServlet类,重写其中方法,来被Tomcat执行到的

6.1.1核心方法

在这里插入图片描述
在这里插入图片描述

6.1.2代码示例: 处理 GET 请求

创建 MethodServlet.java, 创建 doGet 方法

@WebServlet("/method")
public class MethodServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) 
throws ServletException, IOException {
        resp.getWriter().write("GET response");
   }
}

doGet在前面已经讲了很多了,我们这里不再详细说明,可以在本文前面找一下

6.1.3代码示例: 处理 POST 请求

在 MethodServlet.java 中, 新增 doPost 方法

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws
ServletException, IOException {
    resp.setContentType("text/html; charset=utf-8");
    resp.getWriter().write("POST 响应");
}

创建 testMethod.html, 放到 webapp 目录中, 形如
在这里插入图片描述

在 testMethod.html 中, 新增一个按钮, 和对应的点击事件处理函数(外部框架用!快捷键即可,下面的代码写入body中)

<button onclick="sendPost()">发送 POST 请求</button>
<script>
    function sendPost() {
        ajax({
            method: 'POST',
            url: 'method',
            callback: function (body, status) {
                console.log(body);
           }
       })
   }
</script>

重新部署程序, 使用 URL http://127.0.0.1:8080/ServletHelloWorld/testMethod.html 访问页面.
在这里插入图片描述

6.2HttpServletRequest

6.2.1核心方法

在这里插入图片描述
在这里插入图片描述
通过这些方法可以获取到一个请求中的各个方面的信息
ps: 请求对象是服务器收到的内容, 不应该修改.
因此上面的方法也都只是 “读” 方法, 而不是 “写” 方法.

6.2.2代码示例: 打印请求信息

创建 ShowRequest 类

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 java.io.IOException;
import java.util.Enumeration;
@WebServlet("/showRequest")
public class ShowRequestServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{
        //调用刚才用的关键api,并且把得到的结果组织到一个html中,并作为响应的body

        //把api执行的结果,往这个stringBuilder里面塞
        StringBuilder stringBuilder=new StringBuilder();
        stringBuilder.append("<h3>header 首行部分</h3>");
        stringBuilder.append(req.getProtocol());
        stringBuilder.append("<br>");
        stringBuilder.append(req.getMethod());
        stringBuilder.append("<br>");
        stringBuilder.append(req.getRequestURI());
        stringBuilder.append("<br>");
        stringBuilder.append(req.getContextPath());
        stringBuilder.append("<br>");
        stringBuilder.append(req.getQueryString());
        stringBuilder.append("<br>");
        stringBuilder.append("<h3>header 部分</h3>");
        Enumeration<String> headerNames=req.getHeaderNames();
        while(headerNames.hasMoreElements()){
            String headerName=headerNames.nextElement();
            String headerValue=req.getHeader(headerName);
            stringBuilder.append(headerName+": "+headerValue+"<br>");
        }
        resp.setContentType("text/html; charset=utf8");
        resp.getWriter().write(stringBuilder.toString());
    }
}

在网页中输入URL:http://127.0.0.1:8080/servlet_hello/showRequest
(这个URL你自己当时写的可能和我不一样,可以改成你写的那个)
可以看到相关信息
在这里插入图片描述

6.2.3代码示例: 获取 GET 请求中的参数

GET 请求中的参数一般都是通过 query string 传递给服务器的. 形如
https://v.bitedu.vip/personInf/student?userId=1111&classId=100
此时浏览器通过 query string 给服务器传递了两个参数, userId 和 classId, 值分别是 1111 和 100
在服务器端就可以通过 getParameter 来获取到参数的值.

创建 GetParameter 类

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 java.io.IOException;
@WebServlet("/getParameter")
public class GetParameterServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //预期浏览器传来一个形如这样的请求:/getParameter?userId=123&classId=456
        String userId=req.getParameter("userId");
        String classId= req.getParameter("classId");
        resp.getWriter().write("userId="+userId+",classId="+classId);

    }
}

网页效果如下
(1)URL中不加参数(也就是没有?userId=123&classId=456)
在这里插入图片描述
(2)URL中加参数(参数不一定是123,456,也可以是其他值)
在这里插入图片描述

6.2.4代码示例: 获取 POST 请求中的参数

在这里插入图片描述
1.x-www-form-urlencoded
如果请求是这种格式,服务器如何获取参数呢?
获取参数的方式和GET一样,也是getParameter

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 java.io.IOException;

@WebServlet("/postGetParameter")
public class PostGetParameterServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //假设传过来的参数是userId=10&classId=20
        //服务器也是通过req.getParameter来获取到内容的
        String userId=req.getParameter("userId");
        String classId=req.getParameter("classId");
        resp.getWriter().write("userId="+userId+"classId="+classId);
    }
}

然后改一下前端代码

<!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>Document</title>
</head>
<body>
    <form action="postGetParameter" method="post">
        <input type="text" name="userId">
        <input type="text" name="classId">
        <input type="submit" value="提交">
    </form>
<!-- 想用ajax需要引入jquery -->
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script>
        // $.ajax({
        //     type:'post',
        //     url:'method',
        //     success:function(body){
        //         console.log(body);
        //     }
        // });
    </script>
</body>
</html>

启动服务器,进入网页
在这里插入图片描述
输入你想要的userId和classId,点击提交
在这里插入图片描述

在这里插入图片描述

这里可能会有同学遇到404的问题,404大概率是你路径不对,在idea中检查一下,test.html是不是和webapp在同级目录下
在这里插入图片描述

2.json格式
在这里插入图片描述
maven中央仓库地址

进入网页后直接搜索Jackson
在这里插入图片描述
我们就用最上面的这个即可
在这里插入图片描述
选版本的话可以自己挑一个,笔者这里挑的是2.12.6.1
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
上面的步骤完成后,还有两个步骤

在这里插入图片描述

<!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>Document</title>
</head>
<body>
    <!-- 要向构造一个json格式的请求,就不需要再使用form了,可以使用ajax -->
        <input type="text" id="userId">
        <input type="text" id="classId">
        <input type="button" value="提交" id="submit">
    
<!-- 想用ajax需要引入jquery -->
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script>
        // $.ajax({
        //     type:'post',
        //     url:'method',
        //     success:function(body){
        //         console.log(body);
        //     }
        // });
        let userIdInput=document.querySelector('#userId');
        let classIdInput=document.querySelector('#classId');
        let button=document.querySelector('#submit');
        button.onclick=function(){
            $.ajax({
                type:'post',
                url:'postJson',
                contentType:'application/json',
                data:JSON.stringify({
                userId:userIdInput.value,
                classId:classIdInput.value
            }),
                
            success: function(body){
                console.log(body);
            }
        });
        }
    </script>
</body>
</html>

在这里插入图片描述

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 java.io.IOException;
import com.fasterxml.jackson.databind.ObjectMapper;


class User{
    public  int userId;
    public  int classId;
    //当前这两个属性都设置成public,
    //如果设为private,同时提供getter,setter,效果是一样的
}
@WebServlet("/postJson")
public class PostJsonServlet extends HttpServlet {
    //1.创建一个jackson核心对象
    private ObjectMapper objectMapper=new ObjectMapper();
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
       //2.读取body中的请求,然后使用ObjectMapper来解析成需要的对象
        //readValue就是把JSON格式的字符串,转成Java的对象

        User user=objectMapper.readValue(req.getInputStream(),User.class);
        //第一个参数,表示对哪个字符串进行转换,这个参数可以填成一个String,也可以填一个InputStream对象,还可以填一个File对象
        //第二个参数,表示要把这个JSON格式的字符串,转成哪个java对象
        //readValue是怎么完成转换的?
        //1.先把getInputStream对应的流对象里面的数据都读取出来

        //2.针对这个json字符串进行解析,从字符串转换成键值对,
        //比如key:userId;value:123  key:classId;value:456

        //3.遍历这个键值对,依次获取到每一个key,根据这个key名字,和User类里面的属性名字对比一下
        //如果发现匹配的属性,就把当前的key对应的value赋值到该User属性中(赋值过程中会同时进行类型转换)

        //4.当把所有的键值对都遍历结束,User对象也就被构造的差不多了


        resp.getWriter().write("userId: "+user.userId+",classId: "+user.classId);
    }
}

写完上述代码后,运行smartTomcat,打开相关页面及其控制台
在这里插入图片描述
我们这里随便输入点东西,点击提交,控制台也会有相应的userId,classId
在这里插入图片描述

6.3HttpServletResponse

Servlet 中的 doXXX 方法的目的就是根据请求计算得到相应,
然后把响应的数据设置到HttpServletResponse 对象中.
然后 Tomcat 就会把这个 HttpServletResponse 对象按照 HTTP 协议的格式,
转成一个字符串, 并通过Socket 写回给浏览器

6.3.1核心方法

在这里插入图片描述

6.3.2代码示例: 设置状态码

实现一个程序, 用户在浏览器通过参数指定要返回响应的状态码
创建 StatusServlet 类

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 java.io.IOException;


@WebServlet("/status")
public class StatusServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setStatus(200);
        resp.getWriter().write("hello");
    }
}

在这里插入图片描述
进入网页,如果你这时用fiddler抓包,会抓到如下结果,可以看到状态码为200
在这里插入图片描述
在这里插入图片描述

6.3.3代码示例:自动刷新

实现一个程序, 让浏览器每秒钟自动刷新一次. 并显示当前的时间戳

想实现一个“自动刷新”的效果,给HTTP响应中设置一个header.Refresh即可

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 java.io.IOException;

@WebServlet("/redirect")
public class RedirectServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //在这里返回一个302重定向响应,让浏览器自动跳转到搜狗主页
        resp.setStatus(302);
        resp.setHeader("Location","https://www.sogou.com");

         //法二:Servlet提供了一个更简便的实现重定向的写法,如下
        //resp.sendRedirect("https://www.sogou.com");
    }
}

这里你启动服务器后打开网站,会自动跳转到搜狗

  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

劲夫学编程

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值