Servlet
Servlet 是运行在服务端的 Java 小程序,是 Sun 公司提供一套规范,用来处理客户端请求、响应给浏览器的动态资源。
Servlet 的实质就是 Java 代码,通过 Java 的 API 动态的向客户端输出内容。
1. Servlet 2.5
a. Servlet 规范
查阅 JavaEE 手册(帮助文档)阅读 Servlet 规范:
根据文档总结,了解到书写 Servlet 一个三个步骤: (1)创建一个 class 实现 Servlet 接口 (2)重写 service 方法 (3)创建的类必须在 web.xml 文件中做配置
b. 为什么要配置 web.xml?
必须将请求路径和 Java 程序的对应关系建立起来。
c. Servlet 与普通的 Java 程序的区别
必须实现 Servlet 接口
必须在 Servlet 容器(服务器)中运行
Servlet 程序可以接收用户请求参数以及向浏览器输出数据
d. 代码实现 Servlet 2.5 的步骤
在工程下创建 webappPractice 包,在包下创建一个类实现 Servlet 接口;
实现 service 方法;
在 web.xml 中配置书写好的 Servlet。
e. Servlet 2.5 代码实现
在 webappPractice 包下创建一个类 DemoServlet 实现 Servlet 接口:
import javax. servlet. *;
import java. io. IOException;
public class DemoServlet 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 {
System. out. println ( "Hello Servlet" ) ;
}
@Override
public String getServletInfo ( ) {
return null;
}
@Override
public void destroy ( ) {
}
}
<?xml version="1.0" encoding="UTF-8"?>
< web-app xmlns = " http://java.sun.com/xml/ns/javaee"
xmlns: xsi= " http://www.w3.org/2001/XMLSchema-instance"
xsi: schemaLocation= " http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version = " 2.5" >
< servlet>
< servlet-name> demoServlet</ servlet-name>
< servlet-class> DemoServlet</ servlet-class>
</ servlet>
< servlet-mapping>
< servlet-name> demoServlet</ servlet-name>
< url-pattern> /demo</ url-pattern>
</ servlet-mapping>
</ web-app>
f. 常见报错
出现 HTTP Status 500 – Internal Server Error
可能是版本不兼容导致的文件未找到错误。
Console 报错:Error:java: 无效的源发行版: 12
的修复办法:
ctrl + alt + shift +s,以下两个选择框中选择相同版本的 JDK:
2. Servlet 3.0
a. Servlet 2.5 与 Servlet 3.0 的区别
Servlet 3.0 相较于 Servlet 2.5: 新增了一些注解,简化 JavaWeb 代码开发,可以省略 web.xml 配置文件 支持异步处理(多线程技术) 支持可插性特性(书写的代码编译后生成的 class 文件可以直接部署到其他项目的,自动加载执行)
b. 代码实现 Servlet 3.0 的步骤
创建 JavaEE 6(含 6)以上的工程;
创建 Servlet,在 @WebServlet 注解中添加 urlPatterns = “/hello”,作为请求路径。
c. Servlet 3.0 代码实现
创建 JavaEE 6 以上(含 6)的工程:
3.0 以上的版本没有了 web.xml:
注解开发 Servlet 代码演示:
import javax. servlet. *;
import javax. servlet. annotation. WebServlet;
import java. io. IOException;
@WebServlet ( name = "DemoServlet" , urlPatterns = "/demo" )
public class DemoServlet 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 {
System. out. println ( "Hello Servlet 3.0" ) ;
}
@Override
public String getServletInfo ( ) {
return null;
}
@Override
public void destroy ( ) {
}
}
3. Servlet 生命周期
a. 什么是生命周期?
一个对象从创建到消亡的过程,就是生命周期。因此,Servlet 的生命周期就是指 Servlet 什么时候创建,什么时候销毁的过程。
b. Servlet 生命周期相关的方法
首先来回顾 Servlet 接口的文档内容,其中一部分如图所示:
i. API 介绍
上图中,可以注意到两个点,Servlet 的创建和销毁由两个相关的方法 init 方法和 destroy 方法。
void destroy ( ) 销毁servlet的方法
void init ( ServletConfig config) 初始化servlet的方法
ii. 使用步骤
创建 LifeCycleServlet 初始化
复写 init、service、destroy 方法
访问 Servlet 测试初始化 LifeCycleServlet
关闭服务器测试销毁 LifeCycleServlet
iii. Servlet 2.5 代码实现
import javax. servlet. ServletException;
import javax. servlet. ServletRequest;
import javax. servlet. ServletResponse;
import javax. servlet. http. HttpServlet;
import java. io. IOException;
public class LifeCycleServlet extends HttpServlet {
@Override
public void init ( ) throws ServletException {
super . init ( ) ;
System. out. println ( "LifeCycleServlet 初始化。。。" ) ;
}
@Override
public void service ( ServletRequest req, ServletResponse res) throws ServletException, IOException {
System. out. println ( "LifeCycleServlet 执行。。。" ) ;
}
@Override
public void destroy ( ) {
super . destroy ( ) ;
System. out. println ( "LifeCycleServlet 销毁。。。" ) ;
}
}
<?xml version="1.0" encoding="UTF-8"?>
< web-app xmlns = " http://java.sun.com/xml/ns/javaee"
xmlns: xsi= " http://www.w3.org/2001/XMLSchema-instance"
xsi: schemaLocation= " http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version = " 2.5" >
< servlet>
< servlet-name> LifeCycleServlet</ servlet-name>
< servlet-class> LifeCycleServlet</ servlet-class>
</ servlet>
< servlet-mapping>
< servlet-name> LifeCycleServlet</ servlet-name>
< url-pattern> /life</ url-pattern>
</ servlet-mapping>
</ web-app>
c. Servlet 生命周期流程
虽然简单使用过了 Servlet 生命周期相关的方法,但是 Servlet 从创建到销毁的过程还是没说清楚,因此,接下来会以时序图的方式展示 Servlet 的运行过程,注意图中每一步都由序号,按照序号查看每一个步骤。
Servlet 在初始化一次之后,就不再创建,因此如果多次访问同一个 Servlet 的效果是这样的: LifeCycleServlet初始化。。。 LifeCycleServlet执行。。。 LifeCycleServlet执行。。。 LifeCycleServlet执行。。。
因此 Servlet 是一个单例线程不安全的对象。
4. Servlet 的体系结构
目前已经介绍了创建一个类实现 Sevlet 接口的方式开发 Servlet 程序,实现 Servlet 接口的时候,必须实现接口的所有方法。但是,在 Servlet 中,真正执行程序逻辑的是 service,对于 Servlet 的初始化和销毁,由服务器调用执行,开发者本身不需要关心。因此,有没有一种更加简洁的方式来开发 Servlet 程序呢?
查阅 API 回顾 Servlet 接口:
由上图可知在 Servlet 接口规范下,官方推荐使用继承的方式,继承 GenericServlet 或者 HttpServlet 来实现接口,接下来再去查看一下这两个类的 API:
a. GenericServlet
阅读上图 API 可知,GenericServlet 是一个类,它简化了 Servlet 的开发,已经提供好了一些 Servlet 接口所需的方法,开发者只需要重写 service 方法即可。
使用 GenericServlet 创建 Servlet 的步骤:
创建一个类
继承 GenericServlet
重写 service 方法
import javax. servlet. GenericServlet;
import javax. servlet. ServletException;
import javax. servlet. ServletRequest;
import javax. servlet. ServletResponse;
import java. io. IOException;
public class DemoGenericServlet extends GenericServlet {
@Override
public void service ( ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System. out. println ( "DemoGenericServlet执行......." ) ;
}
}
<?xml version="1.0" encoding="UTF-8"?>
< web-app xmlns = " http://java.sun.com/xml/ns/javaee"
xmlns: xsi= " http://www.w3.org/2001/XMLSchema-instance"
xsi: schemaLocation= " http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version = " 2.5" >
< servlet>
< servlet-name> demoGenericServlet</ servlet-name>
< servlet-class> DemoGenericServlet</ servlet-class>
</ servlet>
< servlet-mapping>
< servlet-name> demoGenericServlet</ servlet-name>
< url-pattern> /generic</ url-pattern>
</ servlet-mapping>
</ web-app>
b. HttpServlet
虽然,GenericServlet 已经简化了 Servlet 开发,但是平时开发程序需要按照一种互联网传输数据的协议来开发程序——HTTP 协议,因此, Sun 公司又专门提供了 HttpServlet,来适配这种协议下的开发。
阅读上图的 API 可知,继承 HttpServlet,需要重写 doGet、doPost 等方法中一个即可,根据 HTTP 不同的请求,实现相应的方法。
使用 HttpServlet 创建 Servlet 的步骤:
创建一个类
继承 HttpServlet
重写 doGet 方法
import javax. servlet. GenericServlet;
import javax. servlet. ServletException;
import javax. servlet. ServletRequest;
import javax. servlet. ServletResponse;
import java. io. IOException;
public class DemoGenericServlet extends GenericServlet {
@Override
public void service ( ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System. out. println ( "DemoGenericServlet执行......." ) ;
}
}
<?xml version="1.0" encoding="UTF-8"?>
< web-app xmlns = " http://java.sun.com/xml/ns/javaee"
xmlns: xsi= " http://www.w3.org/2001/XMLSchema-instance"
xsi: schemaLocation= " http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version = " 2.5" >
< servlet>
< servlet-name> demoHttpServlet</ servlet-name>
< servlet-class> DemoHttpServlet</ servlet-class>
</ servlet>
< servlet-mapping>
< servlet-name> demoHttpServlet</ servlet-name>
< url-pattern> /http</ url-pattern>
</ servlet-mapping>
</ web-app>
通过以上两个 API 阅读,注意到 HttpServlet 是 GenericServlet 的子类,它增强了 GenericServlet 一些功能,因此,在后期使用的时候,一般选择继承 HttpServlet 来开发 Servlet 程序。
既然目前开发 Servlet 的选择继承类已经确定,那么这些浏览器、服务器、Servlet 等,到底是如何运行的?接下来将介绍 Servlet 的运行原理。
c. Servlet 的运行原理
Servlet 对象是由 Tomcat 服务器创建;
request 与 response 对象也是由 Tomcat 服务器创建;
request 对象封装了浏览器过来的所有请求信息,response 对象代表了服务器的响应信息。
5. Servlet 的配置
a. url-pattern 配置
在创建 Servlet 后,如果想要这个 Servlet 可以被访问到,必须在 web.xml 文件中对其进行配置。在其中有一个标签 url-pattern 是用于确定访问一个 Servlet 的路径,它是用于确定访问的 Servlet 路径,接下来详细介绍一下关于这个标签的配置。
一个 Servlet 是否可以被不同的路径映射?(即多个不同配置是否可以映射同一个 Servlet) 答案是肯定的。可以通过下面的示例来说明上面的问题:
<?xml version="1.0" encoding="UTF-8"?>
< web-app xmlns = " http://java.sun.com/xml/ns/javaee"
xmlns: xsi= " http://www.w3.org/2001/XMLSchema-instance"
xsi: schemaLocation= " http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version = " 2.5" >
< servlet>
< servlet-name> demoHttpServlet</ servlet-name>
< servlet-class> DemoHttpServlet</ servlet-class>
</ servlet>
< servlet-mapping>
< servlet-name> demoHttpServlet</ servlet-name>
< url-pattern> /http</ url-pattern>
</ servlet-mapping>
< servlet-mapping>
< servlet-name> demoHttpServlet</ servlet-name>
< url-pattern> /http2</ url-pattern>
</ servlet-mapping>
</ web-app>
< servlet-mapping>
< servlet-name> jsp</ servlet-name>
< url-pattern> *.jsp</ url-pattern>
< url-pattern> *.jspx</ url-pattern>
</ servlet-mapping>
优先级: 完全匹配 > 目录匹配 > 扩展名匹配
注意:当它的值是 /
时,它表示一个默认(缺省)的 Servlet。默认的 Servlet 其作用是用于处理其它的 Servlet 处理不了的请求。例如:
< servlet-mapping>
< servlet-name> default</ servlet-name>
< url-pattern> /</ url-pattern>
</ servlet-mapping>
b. load-on-startup 配置
在标签中添加了一个 load-on-startup,设定值为2,那么这时 DemoHttpServlet 就会在服务器启动时,跟随启动。 注意:值越小代表的是优先级越高。例如:
<?xml version="1.0" encoding="UTF-8"?>
< web-app xmlns = " http://java.sun.com/xml/ns/javaee"
xmlns: xsi= " http://www.w3.org/2001/XMLSchema-instance"
xsi: schemaLocation= " http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version = " 2.5" >
< servlet>
< servlet-name> demoHttpServlet</ servlet-name>
< servlet-class> DemoHttpServlet</ servlet-class>
< load-on-startup> 2</ load-on-startup>
</ servlet>
< servlet-mapping>
< servlet-name> demoHttpServlet</ servlet-name>
< url-pattern> /http</ url-pattern>
</ servlet-mapping>
</ web-app>
6. Servlet 的路径
在开发中,经常在页面上通过表单或超连接向服务器发送请求,如果我们访问的是一个 Servlet,那么这时访问 Servlet 的路径应该如何书写?
a. 访问服务器端资源的方式
在地址栏上直接输入 URL;
超连接的方式;
通过表单方式;
通过 JS 的 location.href 方式。
对于以上方式,只有表单提交的方式才可能有 POST 请求,其它的都是 GET 请求。
b. doGet 和 doPost 方法的区别
doGet() 和 doPost() 分别对应 HTTP 协议中的 GET 和 POST 方法,请求是 GET 方法就调用 doGet() ,请求是 POST 方法就调用 doPost() 方法。
GET 和 post 方法有本质的区别: GET 只有一个流,参数附加到 URL 后,大小个数都有严格的限制,且只能是字符串; POST 的参数不通过 URL 而是通过其他流的传递参数,所以可以很大,也可以传递二进制数据,例如上传文件。
POST 比 GET 安全: 由 Web 浏览器或通过 HTML、JSP 直接访问 Servlet 的 URL 时,一般用 GET 调用。GET 调用会把传递给 Servlet 的参数在 URL 里显示出来,这样对系统安全方面存在问题; 而 POST 请求则通过其他流传递参数,不会在 URL 中显示,更安全;例如用户登录时,如果是用 GET 调用会把用户账号密码都显示在 URL 中,用 POST 调用则不会显示。
服务器接收方式: 服务器随机接受 GET 方法的数据,一旦断电等原因,服务器也不知道信息是否发送完毕; 而 POST 方法,服务器先接受数据信息的长度,然后再接受数据。
这种区别是浏览器完成的功能,不需要在 doGet 和 doPost 方法中体现。
get 和 post 都是明文,都不安全,用 HTTPS 才安全。
c. Servlet 的访问路径
创建 DemoServelet 并继承 HttpServlet:
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 DemoServlet extends HttpServlet {
@Override
protected void doGet ( HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System. out. println ( "get请求访问" ) ;
}
@Override
protected void doPost ( HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System. out. println ( "post请求访问" ) ;
}
}
<?xml version="1.0" encoding="UTF-8"?>
< web-app xmlns = " http://java.sun.com/xml/ns/javaee"
xmlns: xsi= " http://www.w3.org/2001/XMLSchema-instance"
xsi: schemaLocation= " http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version = " 2.5" >
< servlet>
< servlet-name> demoServlet</ servlet-name>
< servlet-class> DemoServlet</ servlet-class>
</ servlet>
< servlet-mapping>
< servlet-name> demoServlet</ servlet-name>
< url-pattern> /demo</ url-pattern>
</ servlet-mapping>
</ web-app>
<%--
Created by IntelliJ IDEA.
User: 80626
Date: 2020/4/13
Time: 11:17
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
< html>
< head>
< title> $Title$</ title>
</ head>
< body>
$END$
< h1> 带协议的绝对路径</ h1>
< a href = " http://localhost:8080/webappPractice/demo" > DemoServlet</ a>
< h1> 不带协议的绝对路径</ h1>
< a href = " /webappPractice/demo" > DemoServlet</ a>
< h1> 相对路径</ h1>
< a href = " demo" > DemoServlet</ a>
</ body>
</ html>
以上访问均是 get 请求,均可以在 Console 输出 get请求访问
。
开发中使用不带协议的绝对路径会比较多一些;带协议的绝对路径只有在访问站外资源时才会使用;相对路径需要分析文件间的相对关系才能使用,例如:如果上面的 index.jsp 移动到 http://localhost:8080/webappPractice/main 目录下,那么这三种方式中,只有相对路径会报错,要是想正常访问,可以修改为:<a href="../demo">DemoServlet</a>
原文链接:https://qwert.blog.csdn.net/article/details/105481464