Servlet原理与应用

一、什么是Servlet

Servlet(Server Applet)是Java Servlet的简称,称为小服务程序或服务连接器,用Java编写的服务器端程序,具有独立于平台和协议的特性,主要功能在于交互式地浏览和生成数据,生成动态Web内容。

狭义的Servlet是指Java语言实现的一个接口,广义的Servlet是指任何实现了这个Servlet接口的类,一般情况下,人们将Servlet理解为后者。Servlet运行于支持Java的应用服务器中。从原理上讲,Servlet可以响应任何类型的请求,但绝大多数情况下Servlet只用来扩展基于HTTP协议的Web服务器。

一个Servlet其实就是一个Java接口,客户端在远程访问资源的时候,通过它来完成请求响应。但是Servlet本身不能直接运行,没有main方法,只能依托于容器执行,比如tomcat。只要实现了一定规范的Java类,就可以作为Servlet接口。

Servlet的作用:将一个浏览器访问地址,通过server服务器转到我们java应用程序中,实现参数传递、处理业务逻辑、返回结果等

二、快速入门

前面说到Servlet是实现了一定规范的Java类,那么具体是什么呢,接下来就创建一个Servlet类

1.创建JavaEE项目

javaEE项目依赖tomcat,需要先配置一个tomcat容器,如果没有,需要先下载

tomcat官网:Apache Tomcat® - Apache Tomcat 10 Software Downloads

下载后,将路径配置为tomcat解压后的根目录

2.添加依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.example</groupId>
    <artifactId>my_servlet</artifactId>
    <version>1.0-SNAPSHOT</version>
    <name>my_servlet</name>
    <packaging>war</packaging>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.target>11</maven.compiler.target>
        <maven.compiler.source>11</maven.compiler.source>
        <junit.version>5.9.2</junit.version>
    </properties>

    <dependencies>

        <!-- tomcat8 使用javax.servlet 4.0.1-->
        <!-- tomcat10 不支持javax.servlet 4.0.1,需要使用jakarta-->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>4.0.1</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>jakarta.servlet</groupId>
            <artifactId>jakarta.servlet-api</artifactId>
            <version>5.0.0</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-api</artifactId>
            <version>${junit.version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-engine</artifactId>
            <version>${junit.version}</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>3.3.2</version>
            </plugin>

            <!-- ant打包工具类-->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-antrun-plugin</artifactId>
                <version>1.8</version>
                <!-- 将target目录的classes打包到todir中ss-->
                <executions>
                    <execution>
                        <phase>process-classes</phase>
                        <configuration>
                            <tasks>
                                <copy todir="src/main/webapp/WEB-INF/classes">
                                    <fileset dir="target/classes"/>
                                </copy>
                            </tasks>
                        </configuration>
                        <goals>
                            <goal>run</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>

        </plugins>
    </build>
</project>

3.定义一个类,实现Servlet接口中的方法

package com.example.web;

import javax.servlet.*;
import java.io.IOException;

public class MyServlet implements Servlet {
    @Override
    public void init(ServletConfig servletConfig) throws ServletException {

    }

    @Override
    public ServletConfig getServletConfig() {
        return null;
    }

    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
        servletResponse.getWriter().write("Servlet  response");
    }

    @Override
    public String getServletInfo() {
        return "";
    }

    @Override
    public void destroy() {

    }
}

3.修改Web.xml配置Servlet

src/main/webapp/WEB-INF/web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">

    <!-- servlet-class 全路径类名-->
    <servlet>
        <servlet-name>myFirstServlet</servlet-name>
        <servlet-class>com.example.web.MyServlet</servlet-class>
        <!-- 整数时,服务启动时,创建servlet;负数时,第一次访问时,创建servlet-->
        <load-on-startup>1</load-on-startup>
    </servlet>
    <!-- url-pattern 访问路径 -->
    <servlet-mapping>
        <servlet-name>myFirstServlet</servlet-name>
        <!--注意这里需要以/开头,不然tomcat启动会找不到路径报错-->
        <url-pattern>/myFirstServlet</url-pattern>
    </servlet-mapping>

</web-app>

4.IDEA配置Tomcat

可以使用Tomcat Server(IDEA旗舰版自带)或者Smart Tomcat(需要从Market下载plugins),

这里我使用的是Smart Tomcat

测试访问 http://localhost:8080/my_servlet/myFirstServlet

三、执行原理

拿前面的访问路径来举例

http://localhost:8080/my_servlet/myFirstServlet

  1. 在这个访问中,首先会根据域名端口,找到Tomcat服务
  2. 通过 /my_servlet 找到对应的项目
  3. 通过 /myFirstServlet,去weabapp目录下,找Web.xml里面配置的url-pattern
  4. 通过url-pattern找到对应的servlet-name
  5. tomcat会将servlet-name对应的servlet-class的全类名的class字节码文件加载到内存中
  6. 创建对应的java对象
  7. 调用对象中的service方法

四、Servlet生命周期

1.创建Servlet,执行一次init方法

  • 默认情况下,第一次被访问的时候执行;
  • 只会执行一次,说明Servlet在内存中只存在一个对象,是单例模式的
  • 如果有配置容器启动时加载Servlet(如下配置load-on-startup),就会在容器启动时执行
    <servlet>
        <servlet-name>myFirstServlet</servlet-name>
        <servlet-class>com.example.web.MyServlet</servlet-class>
        <!-- 整数时,服务启动时,创建servlet;负数时,第一次访问时,创建servlet-->
        <load-on-startup>1</load-on-startup>
    </servlet>

2.提供服务service

执行service方法,可以执行多次,每次访问Servlet,service方法都会被调用一次

3.销毁Servlet

  • 服务正常关闭时,执行一次
  • 一般用于释放资源

五、Servlet3.0注解配置

在Servlet2.0之前,每个Servlet的地址访问都需要在Web.xml配置,这使得配置文件会十分庞大,难以维护,于是Servlet3.0就推出了注解的模式,简化配置。

JavaEE6(JDK6)之后,开始支持Servlet3.0。

在这之后就不需要创建Web.xml,只需要在Servlet类上加上WebServlet注解就可以了。


1.urlPatterns写法

这三种写法是等效的
@WebServlet(urlPatterns = "/myWebServlet")

@WebServlet(value = "/myWebServlet")

@WebServlet("/myWebServlet")

2.urlPatterns 可以是数组,代表多个地址都可以映射到当前的Servlet

3.urlPatterns的配置格式

  •   /url_xxx   单路径匹配
  •   /url_xxx/url_yyy  多路径匹配,目录形式
  • /*    通配符的方式,任意地址都可以访问到,如果有其他能匹配到的地址,优先访问其他的

六、IDEA的Tomcat配置

  • IDEA会给每个tomcat部署的项目独立创建一份配置文件

        启动tomcat的时候,控制台查看CATALINA_BASE对应的值,可以查看到。

  • 工作空间项目(IDEA存项目的空间)和Tomcat部署的项目是两个目录

        tomcat访问的是tomcat部署的web项目,这个目录的内容对应着工作空间的webapp下的所有资源,是IDEA拷贝过去的。

  • 直接放在WEB-INF下的资源是不能直接被浏览器访问的,需要其他请求转换

七、HTTP

1.概念

Hyper Text Transfer Protocol 超文本传输协议

定义了客户端和服务器传输数据的格式

2.特点

  • 基于TCP/IP的高级协议
  • 默认端口号是80
  • 基于请求响应模型,一次请求一次响应
  • 是无状态的,每次请求是相互独立的,不能交互数据

3.请求行

GET/POST URL HTTP/1.1

  • 请求方式,有7种,常见的是GET/POST
  • 请求地址

  • 协议

GET

  • 请求参数在地址URL后
  • 请求地址长度有限制

  • 不太安全(明文)

POST

  • 请求参数在请求体中
  • 请求地址长度没有限制

  • 相对安全

4.请求头

请求头信息的键值对

2.1User-Agent  浏览器版本信息,让服务器可以取到浏览器版本,解决版本兼容问题

2.2Referer  访问来源

       作用

  • 防盗 服务器通过Referer判断是否来自于自己预想的首页,其他的不让访问当前资源
  • 统计 各种来源渠道的信息

5.请求空行

空行,用于分割post请求的请求头和请求体

6.请求体

Post方式才会有

八、Request

封装请求消息的对象

1.简介

在浏览器访问tomcat服务器时,由服务器创建Request和Response对象,并调用Servlet的service方法,将Request和Response作为入参。Request用来给我们获取请求的相关信息,Response用来封装响应请求。

2.Servlet继承体系

 HttpServletRequest接口 继承-> ServletRequest接口

tomcat的 org.apache.catalina.connector.RequestFacade实现了HttpServletRequest接口

3.Request功能

获取请求消息数据

3.1获取请求行

eg:   http://localhost:8080/servlet/myservlet?name=Jerry

以上链接,可以通过Request的方法获取以下信息

  • 获取请求方式  getMethod()  GET/POST
  • 获取虚拟目录   getContextPath()   /servlet  
  • 获取Servlet路径  getServletPath()    /myservlet
  • 获取get方式的请求参数 getQueryString()   name=Jerry
  • 获取请求URI  getRequestURI()  /servlet/myservlet
  • 获取请求URL  getRequestURL()   http://localhost:8080/servlet/myservlet
  • 获取协议及版本  getProtocol()  HTTP/1.1
  • 获取客户机的地址  getRemoteAddr()   127.0.0.1

        

3.2请求头
  • 获取请求头 getHeaderNames()    得到Enumeration迭代器,可以便利请求头中的参数
Enumeration<String> headerNames = request.getHeaderNames();

//遍历请求头中的参数

while(headerNames.hasMoreElements()){

        String name = headerNames.getNextElement();

        //根据名称获取请求头的值

        String value = request.getHeader(name);

}

  • 获取请求头信息 request.getHeader("User-Agent")
  • 获取访问来源 request.getHeader("referer") 当没有从其他主页来的时候,获取到的是 null

3.3请求体
  • 只有post方式才有请求体
  • 获取方式  获取流对象,再从流对象中拿数据

        BufferedReader getReader() 获取字符输入流,只能操作字符数据

        ServletInputStream getInputStream() 获取字节输入流,可以操作所有类型的数据

3.4其他方法
3.4.1获取请求参数
  • String getParameter(String name)    获取指定名称参数
  • String[] getParameterValues(String name) 获取参数数组
  • Enumeration<String> getParameterNames() 获取所有请求的参数名称
  • Map<String,String[]> getParameterMap() 获取所有参数的map集合
  • setCharacterEncoding("utf-8") 解决中文乱码问题

3.4.2请求转发

一种在服务器内资源跳转的方式,只能访问内部资源,不能访问外链资源

转发只是一次请求,不会产生两次

request.getRequestDispatcher("/目的Servlet地址").forward(request,response);

3.4.3共享数据

在请求转发中,两个请求之间需要共享数据,通过以下方法

  • void  setAttribute(String name, Object obj)  保存键值对数据
  • Object getAttribute(String name)  获取键值对数据
  • void removeAttribute(String name)  移除键值对数据

3.4.4获取ServletContext

ServletContext getServletContext()

九、Response

1.简介

封装响应消息的对象。用来协助响应Request的对象,返回数据到客户端。

2.方法

2.1输出数据

输出文本

response.getWriter().write("javax.servlet.http.HttpServlet response");

输出二进制

response.getOutputStream().write("javax.servlet.http.HttpServlet response".getBytes());
  • getWriter和getOutPutStream不能同时使用输出,否则会抛出异常
  • 设置输出内容的格式,可以解决乱码问题
response.setContentType("text/html;charset=utf-8");

2.重定向

跳转到一个新的资源地址,使用了重定向,相当于是新的请求(加上之前的共两次),和前面”3.4.2请求转发“的不同。

response.sendRedirect("/新地址");

=========================================================================
创作不易,请勿直接盗用,使用请标明转载出处。

喜欢的话,一键三连,您的支持是我一直坚持高质量创作的原动力。

  • 21
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值