一、什么是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
- 在这个访问中,首先会根据域名端口,找到Tomcat服务
- 通过 /my_servlet 找到对应的项目
- 通过 /myFirstServlet,去weabapp目录下,找Web.xml里面配置的url-pattern
- 通过url-pattern找到对应的servlet-name
- tomcat会将servlet-name对应的servlet-class的全类名的class字节码文件加载到内存中
- 创建对应的java对象
- 调用对象中的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("/新地址");
=========================================================================
创作不易,请勿直接盗用,使用请标明转载出处。
喜欢的话,一键三连,您的支持是我一直坚持高质量创作的原动力。