栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

使用Servlet技术开发动态资源

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

使用Servlet技术开发动态资源

目录

为什么需要动态资源

Servlet

大体的开发流程

Tomcat内部的大概过程

Tomcat的定位

浏览器中输入URL并回车,直到看到网页内容,期间发生了什么?

接受请求

根据请求计算响应

返回响应

DNS的请求过程

业务根据请求,填充响应的过程

结合网络知识

Servlet的使用

HttpServletRequest  req对象的简单使用

读取请求头:

读取请求体:

HttpResponseServlet Resp对象的使用

HttpServlet是什么?

Servlet的生命周期

 Servlet的日常开发(基于场景描述)


为什么需要动态资源

在某些资源路径固定的情况下,我们需要对应不同的环境、条件,产生不同的内容。

如:各个网站的个人中心页面,博客详情页;

Servlet

Servlet 就是 Tomcat 这个 HTTP 服务器提供给 Java 的一组 API, 来完成构建动态页面这个任务。

大体的开发流程
  1. 通过继承HTTPServlet抽象类,完成我们自己的类(每个都是一个独立的Web资源)
  2. 重写其中的一些方法(get、post、...),输出资源内容的过程
  3. 把动态资源和路径建立绑定关系:可以通过web.xml,或者使用Java中的注解语法完成@WebServlet。

整个过程都需要遵守标准,否则Tomcat不认。 

不需要自己实例化HTTPServlet对象(Tomcat内部在实例化);

也不会调用我们写好的get、post方法(Tomcat内部会在合适的时机去调用);

HTTP请求<->HttpServletRequest(这里的方法以getXXX为主)

HttpServletResponse<->HTTP响应(这里的方法以setXXX为主)

通过web.xml实现绑定:

package com.wh.servlet;

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

//1、声明这个类是一个web资源,via让类继承HTTPServlet这个抽象类
//2、看我们的动态资源支持那些HTTP方法(支持get方法via重写doGet方法)
public class FirstServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //3、读取request对象中的信息(都是来自HTTP请求中的信息)
        //4、根据当下的条件
        //5、准备相应数据 , 通过填写response对象来做到

        //设置状态码是201
        resp.setStatus(201);
        //字符集编码
        resp.setContentType("text/plain;charset=utf-8");
        PrintWriter writer=resp.getWriter();
        writer.printf("你好世界");
        //通过web.xml实现绑定
    }
}

web.xml:





    
        MyFirstServlet
        com.wh.servlet.FirstServlet
    

    
        MyFirstServlet
        
        /first
    

状态码:

 使用Java中的注解语法完成@WebServlet:

package com.wh.servlet;

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.io.PrintWriter;

//通过使用@WebServlet注解修饰类,来实现绑定
@WebServlet("/second")
public class SecondServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setStatus(202);
        resp.setContentType("text/css");
        resp.setContentType("text/plain;charset=utf-8");
        PrintWriter writer=resp.getWriter();
        writer.printf("你好中国");
    }
}

  1.  通过继承HTTPServlet,表示这个类已经是一个有效的Web资源(动态)了。
  2. 重写doGet方法,表示这个资源支持HTTP的 GET方法访问。隐含着:其他的HTTP方法,是不支持的,如果非要使用别的方法(非405)访问这个资源,会405。
  3.         resp.setStatus(202);
            resp.setContentType("text/plain;charset=utf-8");
            PrintWriter writer=resp.getWriter();
            writer.printf("你好中国");

    根据请求或者其他条件构造响应的过程。就是动态资源书写的过程。

  4. //通过使用@WebServlet注解修饰类,来实现绑定
    @WebServlet("/second")

    最后一步,把动态资源和路径绑定,才能对外提供服务。

Tomcat内部的大概过程

1、Tomcat收到了一个HTTP请求

2、Tomcat根据HTTP协议的规定,解析请求,得到请求方法,资源路径,请求头等等

3、Tomcat根据资源路径(Context Path+Servlet Path):

先根据Context Path,决定这个资源是交给哪个Webapp处理(隐含:Tomcat支持多个webapp同时存在)。

确定是哪个webapp后,再根据Servlet Path,找到对应的资源进行处理。

如果是动态资源,根据路径得到一个类名(com.wh.servlet.FirstServlet),如果这个类还没有实例化对象,则实例化其对象,否则直接获取其对象(单例模式)——拿到对象根据请求方法,调用该对象doGet方法或者doPost或者其他方法。

doGet方法执行结束之后,resp对象被填充信息(202,text/csss,你好中国),Tomcat根据这个对象,构造http响应,发送给浏览器。

如果是静态资源,就根据对应的路径去查找对应的文件,并相应文件内容。

如果动态或者静态资源都没有找到,就会404。

Tomcat的定位

1、HTTP服务器(读取+解析HTTP请求;构造+发送HTTP相应)

2、Servlet容器(遵守Servlet标准,可以按照标准,调用对应方法处理请求)

当浏览器给服务器发送请求的时候,通过HTTP协议和HTTP进行交流,Tomcat(HTTP服务器)接收这个请求。然后Tomcat会调用Servlet里我们实现的类,Servlet的类会读取数据库的数据。如图:

浏览器中输入URL并回车,直到看到网页内容,期间发生了什么?

只站在应用层的角度:

接受请求

用户在浏览器输入一个URL(如果是域名,通过DNS服务器,将域名换成ip的过程),浏览器构建一个HTTP请求。

这个HTTP请求经过网络协议栈逐层封装称二进制的比特流,通过物理层的硬件设备转换称某些物理信号传输出去。

这些物理信号通过互联网的网络设备,到达目标主机。

服务器主机接收到物理信号,通过网络协议栈逐层分用解析,还原HTTP请求,交给Tomcat进程进行处理(通过端口号进行确定)。

Tomcat通过Socket读取解析HTTP请求,根据请求中的Context Path确定webapp,再通过Servlet Path确定一个具体的类,根据当前请求方法(GET,POST...),决定调用这个类中的哪个方法(doGet,doPost...)。此时类的对应方法的第一个参数HttpServletRequest就包含了这个HTTP请求的详细信息。

根据请求计算响应

在Servlet类中,我们重写的方法中执行代码,这些代码会根据请求中的一些信息,来给HttpServletRequest对象设置一些属性。例如这些:

        resp.setStatus(202);//状态码
        resp.setContentType("text/plain;charset=utf-8");//字符集编码
        PrintWriter writer=resp.getWriter();
        writer.printf("你好中国");//内容

返回响应

对应类的重写方法(doGet,doPost...)执行完毕之后,Tomcat会自动把HttpServletRequest这个我们刚设置好的对象转换成一个符合HTTP协议的字符串,通过Socket把这个响应发出去。

然后响应数据在服务器的主机上通过网络协议栈层次封装,得到一个二进制bit流,通过物理层硬件设备转换成物理信号传输出去。

这些物理信号通过互联网的一系列网络设备,最终到达浏览器所在的主机。

浏览器主机收到这些物理信号,通过网络协议栈逐层进行分用解析,还原HTTP响应,交给浏览器处理。

浏览器也通过Socket读到这个响应(一个字符串),按照HTTP响应的格式来解析这个响应,把body中的数据按要求显示在浏览器的界面上。如果这个响应中还包含html或者js等,可能还会触发产生新的HTTP请求。

DNS的请求过程

1、浏览器可能有本地DNS缓存

2、如果缓存中没有,去调用OS系统调用,去要DNS换IP

OS读取本地hosts文件(俗称固定host)

OS会发送DNS请求,给本地DNS服务器。

如果本地DNS有记录,直接返回,如果没有,再去它的上一级要记录结果。最终这个过程走到了权威DNS(根DNS:全球一共13台)。

业务根据请求,填充响应的过程

1、直接填充

2、配合数据库中的数据进行填充(比如验证登录)

3、还有其他的存储/接口服务(比如Redis、ES(搜索引擎),MongoDB等)

结合网络知识

1、纯TCP的角度也可以讲述:要发送HTTP请求,收到HTTP响应,首先得有TCP连接。可以展开TCP三次握手,通信,四次挥手。

2、站在发送端主机的角度:应用层->传输层->网络层->数据链路层->物理层(网卡),按照各种协议封装;

站在接收端主机的角度:物理层(网卡)->数据链路层->网络层->传输层->应用层,按照协议解包+分用;

3、只针对网络层的路由(路由表的作业(把长期目标->短期目标)、ARP表(把局域网IP换成MAC地址))。

4、NAT服务器怎么做IP和端口(port)替换映射的。


Servlet的使用

HttpServletRequest类的方法了解(配合HTTP请求格式理解)

HttpServletRequest对象是对HTTP请求的对象化

HttpServletRequest  req对象的简单使用

HTTP请求中有哪些信息?

请求方法,资源路径URL,请求版本,请求头们,请求体(如果存在的话)

这些信息都可以通过req对象获取(有的是直接获取,有些被Tomcat加工成更方便我们的格式)

import com.sun.xml.internal.ws.util.StringUtils;

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("/req-info")
public class GetRequestInfoServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 1. 请求方法
        String method = req.getMethod();
        System.out.println("HTTP 方法: " + method);
        System.out.println();
        System.out.println();

        String requestURI = req.getRequestURI();
        System.out.println("requestURI: " + requestURI);
        StringBuffer requestURL = req.getRequestURL();
        System.out.println("requestURL: " + requestURL.toString());
        String pathInfo = req.getPathInfo();
        System.out.println("pathInfo: " + pathInfo);
        String contextPath = req.getContextPath();
        System.out.println("contextPath: " + contextPath);
        String servletPath = req.getServletPath();
        System.out.println("servletPath: " + servletPath);
        String pathTranslated = req.getPathTranslated();
        System.out.println("pathTranslated: " + pathTranslated);
        String queryString=req.getQueryString();
        System.out.println("queryString: " + queryString);
        System.out.println();
        System.out.println();

        String serverName = req.getServerName();
        System.out.println("serverName: " + serverName);
        int serverPort = req.getServerPort();
        System.out.println("serverPort: " + serverPort);
        String scheme = req.getScheme();
        System.out.println("schema: " + scheme);
        String protocol = req.getProtocol();
        System.out.println("protocol: " + protocol);
    }
}

读取请求头:
        //请求头们(本质就是一组Key-value:不同之处Key是可以重复的)
        Enumeration headerNames = req.getHeaderNames();
        //Enumeration类似Iterator(hasNext()+next())
        while (headerNames.hasMoreElements()) {
            String name = headerNames.nextElement();
            String value = req.getHeader(name);
            System.out.println(name + " += " + value);
        }

读取请求体:

准备携带请求体的POST请求

准备一个html,里面有form表单,通过form表单来发送HTTP POST请求;

准备一个动态资源,仅支持POST方法,打印读取到的请求体(这个动态资源不能用GET方法访问)。

HttpResponseServlet Resp对象的使用

读取响应:

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.io.OutputStream;
import java.io.PrintWriter;

@WebServlet("/set-resp")
public class setRespServlet extends HttpServlet{
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //设置响应状态
        resp.setStatus(204);
        //设置响应头
        //1、标准响应头:比如Content-Type(PS:Content-Length 不需要设置)
        //2、非标准响应头:填什么都可以(中文不行)
        resp.setHeader("Content-Type","text/plain;charset=utf-8");
        resp.setHeader("X-My-Class","Java");
        
        //响应体内容是字符(使用较多的)
        resp.setCharacterEncoding("utf-8");
        resp.setContentType("text/plain");
        PrintWriter writer=resp.getWriter();//设置相应字符集要在getWriter()之前
        writer.print("你好");
        
        //响应体内容是字节流
        OutputStream outputStream=resp.getOutputStream();
        outputStream.write('H');
        outputStream.write('e');
    }

HttpServlet是什么?

Servlet标准,大概规定的是一个请求-响应服务器模型(不仅仅针对HTTP协议)

interface Servlet-> abs class HttpServlet->MyServlet

Servlet的生命周期

被抽象成三个阶段:

1、初始化阶段 init(...);有且仅有一次

2、处理 请求-响应阶段 service(req,resp);每次请求-响应都会执行一次

3、销毁阶段 destroy();有且仅有一次

重写构造方法(必须是无参)、init()、doGet()、doPost()

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("/lifecycle")
public class LifecycleServlet extends HttpServlet {
    public LifecycleServlet() {
        System.out.println("Lifecycle 的构造方法被调用");
    }

    @Override
    public void init() throws ServletException {
        System.out.println("Lifecycle.init() 被调用");
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("Lifecycle.doGet() 被调用");
    }

    @Override
    public void destroy() {
        System.out.println("Lifecycle.destroy() 被调用");
    }
}

通过打印+调试:

1、init()、service()、destroy()的被调用次数以及被调用时机

2、类是被Tomcat的代码实例化的

3、这里写的方法是被Tomcat调用的

4、对象是单例模式管理的

5、Tomcat使用的是懒汉模式创建的单例对象

6、diGet、doPost等方法都是在HttpServlet中重写Service然后调用的

7、对象是运行在Tomcat启动管理的线程池中的

8、javax.servlet.*下的类是官方提供的;org.apache.catalina.*下的类是Tomcat提供的


这里写的Servlet下的方法是运行在多线程环境下+类的对象是单例的 (写代码时要避免使线程不安全的操作和代码)

 Servlet的日常开发(基于场景描述)

1、@WebServlet(...)这里填写的资源路径的问题:

必须以/开头;

路径不能重复出现;

正常情况有:"/hello"  "/hello/world"  "/hello/html"  "/hello.jpg"...

两个特殊情况:

通配符("*.do"):只要路径后缀名是.do的URL都归我管的;

"/":所有的URL都归我管的;

" "(空格):代表根URL;

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/969775.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号