servlet

servlet (server applet)

因为服务器资源分为静态资源和动态资源,动态资源被不同的客户端访问它所展现的内容是不一样的,所以动态资源中是有一定的逻辑性的,这里的逻辑性就要通过java代码来实现,java类需要依赖服务器(Tomcat)来运行,所以服务器识别和运行Java类就需要有一个规则,而servlet就是定义了java类被服务器识别和访问规则的一个接口。

认识Servlet

Servlet 是什么

Servlet是一个接口
Servlet是Tomcat服务器识别java类的规则

servlet 中的五个方法

Servlet接口源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

// IntelliJ API Decompiler stub source generated from a class file
// Implementation of methods is not available

package javax.servlet;

public interface Servlet {
void init(javax.servlet.ServletConfig servletConfig) throws javax.servlet.ServletException;

javax.servlet.ServletConfig getServletConfig();

void service(javax.servlet.ServletRequest servletRequest, javax.servlet.ServletResponse servletResponse) throws javax.servlet.ServletException, java.io.IOException;

java.lang.String getServletInfo();

void destroy();
}

init

1
void init(javax.servlet.ServletConfig servletConfig) throws javax.servlet.ServletException;
  • 注:init方法只执行一次,在servlet被创建时执行。

getServletConfig

1
javax.servlet.ServletConfig getServletConfig();
  • 注:获取ServletConfig(配置)对象

service

1
void service(javax.servlet.ServletRequest servletRequest, javax.servlet.ServletResponse servletResponse) throws javax.servlet.ServletException, java.io.IOException;
  • 注:提供服务的方法,servlet每次刷新都会被执行

getServletInfo

1
java.lang.String getServletInfo();
  • 注:获取Servlet信息

destroy

1
void destroy();
  • 注: servlet正常结束时被执行

第一个servlet程序

第一步:创建javaEE项目
第二部:配置Tomcat服务器
第三步:编写java类实现servlet接口
第四步:编写servlet配置文件
第五步:运行Tomcat并查看结果
·注:如果使用注解方式@WebServlet(“”)配置servlet就可以省略第四步

创建javaEE项目

1
File -> new -> project -> Java Enterprise -> next -> 勾选Web Platform -> next ->填写Name值给项目起名、Location选择创建项目路径 ->finish

配置Tomcat 服务器

编写servlet实现类

创建java类Servlet01.class

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
package com.wab;

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

public class Servlet01 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.printf("servlet启动成功");
}

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

@Override
public void destroy() {

}
}


·注意:如果实现类继承Servlet接口时报错,并显示没有该包,可以尝试查看项目pom.xml文件中下面该配置是否导入成功:

1
2
3
4
5
6
7
8
<dependencies>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-web-api</artifactId>
<version>8.0.1</version>
<scope>provided</scope>
</dependency>
</dependencies>

编写servlet配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?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>
<servlet-name>Demon01</servlet-name>
<servlet-class>com.wab.Servlet01</servlet-class>
</servlet>
<!--映射-->
<servlet-mapping>
<servlet-name>Demon01</servlet-name>
<!--Demon01这个类可以通过‘/d1’这个路径来访问-->
<url-pattern>/d1</url-pattern>
</servlet-mapping>
</web-app>

运行Tomcat并查看结果

第一步:配置Tomcat 服务
https://froginthewell.github.io/2020/11/09/Maven-%E5%92%8C-Tomcat%E4%BD%BF%E7%94%A8/
第二部:运行Tomcat 服务

1
2
3
4
5
6
http://localhost:8080/tomcat01_war/d1
当服务器接受到客户端浏览器的请求后,会解析请求URL路径,获取访问的Servlet的资源路径
http://localhost:8080 查找计算机和应用程序
tomcat01_war 虚拟路径(虚拟路径可以设置为‘/’)
d1 资源名称

servlet 原理

servlet 注解

注解的使用规则

  1. 路径的规则
    路径名可以一个
1
@WebServlet("/虚拟路径")

路径名也可以多个

1
@WebServlet("/虚拟路径1","/虚拟路径2","/虚拟路径3")
  1. 路径的层次
    路径名可以是一即
    1
    @WebServlet("/虚拟路径")

也可以是多层路径只是在访问时要将路径名全部写上

1
2
@WebServlet("/虚拟路径1/虚拟路径2/虚拟路径3")

*** / ** 通配符,它可以代表任何路径

1
@WebServlet("/*")

注解使用实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
package com.wab;

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

@WebServlet("/d2")
public class Servlet02 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.printf("@WebServlet(\"/d2\") 注解成功");
}

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

@Override
public void destroy() {

}
}

·注:因为再实际应用中servlet会被多次利用,一个项目会有多个servlet的实现类,如果每创建一个servlet类就添加一次servlet配置
会非常的复杂,所以再servlet 3.0 之后的版本开始支持注解@WebServlet(“”)

GenericServlet

GenericServlet介绍

GenericServlet是个抽象类,它实现了javax.servlet.Servlet, javax.servlet.ServletConfig, java.io.Serializable三个接口
GenericServlet类源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

// IntelliJ API Decompiler stub source generated from a class file
// Implementation of methods is not available

package javax.servlet;

public abstract class GenericServlet implements javax.servlet.Servlet, javax.servlet.ServletConfig, java.io.Serializable {
private static final java.lang.String LSTRING_FILE = "javax.servlet.LocalStrings";
private static java.util.ResourceBundle lStrings;
private transient javax.servlet.ServletConfig config;

public GenericServlet() { /* compiled code */ }

public void destroy() { /* compiled code */ }

public java.lang.String getInitParameter(java.lang.String name) { /* compiled code */ }

public java.util.Enumeration<java.lang.String> getInitParameterNames() { /* compiled code */ }

public javax.servlet.ServletConfig getServletConfig() { /* compiled code */ }

public javax.servlet.ServletContext getServletContext() { /* compiled code */ }

public java.lang.String getServletInfo() { /* compiled code */ }

public void init(javax.servlet.ServletConfig config) throws javax.servlet.ServletException { /* compiled code */ }

public void init() throws javax.servlet.ServletException { /* compiled code */ }

public void log(java.lang.String msg) { /* compiled code */ }

public void log(java.lang.String message, java.lang.Throwable t) { /* compiled code */ }

public abstract void service(javax.servlet.ServletRequest servletRequest, javax.servlet.ServletResponse servletResponse) throws javax.servlet.ServletException, java.io.IOException;

public java.lang.String getServletName() { /* compiled code */ }
}

优点

再GenericServlet类中service方法也是抽象的,所以在编而写Servlet实现类只需要service方法时,可以直接继承GenericServlet这个抽象类,然后实现service方法即可,简化了代码量

实例测试

创建Servlet03.class继承GenericServlet抽象类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package com.wab;

import javax.servlet.GenericServlet;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebServlet;
import java.io.IOException;

@WebServlet("/d3")
public class Servlet03 extends GenericServlet {
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.printf("service调用成功");
}
}

HttpServlet

HttpServlet也是个抽象类

doGet方法原型

1
2
3
4
5
6
7
8
9
10
11
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
String protocol = req.getProtocol();
String msg = lStrings.getString("http.method_get_not_supported");
if (protocol.endsWith("1.1")) {
resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);
} else {
resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
}
}

doPost方法原型

1
2
3
4
5
6
7
8
9
10
11
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
String protocol = req.getProtocol();
String msg = lStrings.getString("http.method_post_not_supported");
if (protocol.endsWith("1.1")) {
resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);
} else {
resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
}
}

service方法原型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
String method = req.getMethod();

if (method.equals(METHOD_GET)) {
long lastModified = getLastModified(req);
if (lastModified == -1) {
// servlet doesn't support if-modified-since, no reason
// to go through further expensive logic
doGet(req, resp);
} else {
long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
if (ifModifiedSince < lastModified) {
// If the servlet mod time is later, call doGet()
// Round down to the nearest second for a proper compare
// A ifModifiedSince of -1 will always be less
maybeSetLastModified(resp, lastModified);
doGet(req, resp);
} else {
resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
}
}

} else if (method.equals(METHOD_HEAD)) {
long lastModified = getLastModified(req);
maybeSetLastModified(resp, lastModified);
doHead(req, resp);

} else if (method.equals(METHOD_POST)) {
doPost(req, resp);

} else if (method.equals(METHOD_PUT)) {
doPut(req, resp);

} else if (method.equals(METHOD_DELETE)) {
doDelete(req, resp);

} else if (method.equals(METHOD_OPTIONS)) {
doOptions(req,resp);

} else if (method.equals(METHOD_TRACE)) {
doTrace(req,resp);

} else {
//
// Note that this means NO servlet supports whatever
// method was requested, anywhere on this server.
//

String errMsg = lStrings.getString("http.method_not_implemented");
Object[] errArgs = new Object[1];
errArgs[0] = method;
errMsg = MessageFormat.format(errMsg, errArgs);

resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);
}
}


/*
* Sets the Last-Modified entity header field, if it has not
* already been set and if the value is meaningful. Called before
* doGet, to ensure that headers are set before response data is
* written. A subclass might have set this header already, so we
* check.
*/
private void maybeSetLastModified(HttpServletResponse resp,
long lastModified) {
if (resp.containsHeader(HEADER_LASTMOD))
return;
if (lastModified >= 0)
resp.setDateHeader(HEADER_LASTMOD, lastModified);
}

使用doGet方法

创建Servlet04.class类,继承HttpServlet类,重写doGet方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package com.wab;

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("/d4")
public class Servlet04 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.printf("doGet方法被调用");
}

}

运行浏览器:

1
http://localhost:8080/tomcat01_war/d4

使用doPost方法

·第一步:编写实现类
·第二步:编写.html文件,创建表单

编写实现类

·注:HTML文件必须编写在wabapp文件下
创建Servlet05.class类,继承HttpServlet类,重写doPost方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package com.wab;

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("/d5")
public class Servlet05 extends HttpServlet {

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.printf("doPost方法被调用");
}

}

.html文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>doPost请求</title>
</head>
<body>
<form action="/d5" method="post">
<p>
用户名:
<input id="userName" type="text" size="11">
</p>
<p>
用户密码
<input id="userPassword" type="password" size="11">
</p>
<p>
<input id="subm" type="submit" value="登录">
</p>

</form>
</body>
</html>

查看运行结果


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 jaytp@qq.com

×

喜欢就点赞,疼爱就打赏