Servlet
Servlet简介
-
servlet是sun公司开发动态web的一门技术
-
sun公司在这些API中提供了一个接口叫做Sevlet
-
如果你想开发一个Servlet程序,只需要:
-
编写一个类,实现Servlet接口
-
把开发好的Java类部署到web服务器
-
总结:把实现了Sevlet接口的java程序叫做 Servlet
Servlet有两个默认的实现类:HttpServlet、GenericServlet
第一个Servlet程序
-
构建一个普通的Maven项目,在这个项目工程中新建子工程,即Module
-
Maven父子工程:
在父工程中的pom.xml中多了
<modules> <module>servlet-01</module> </modules>
在子工程的pom.xml中有
<parent> <artifactId>javaweb-02-servlet</artifactId> <groupId>com.wang</groupId> <version>1.0-SNAPSHOT</version> </parent>
父项目中的jar包,子项目可以直接使用,就像是继承关系
-
Maven环境优化
-
修改web.xml 的版本
-
将Maven的结构搭建完整
-
-
编写Servlet程序
-
编写普通类
-
继承HttpServlet
package com.wang.servlet; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServlet; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter; public class HelloServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { PrintWriter writer = resp.getWriter(); writer.print("Hello,Servlet"); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req,resp); } }
-
为什么重写这两个方法请看源码剖析
-
编写Servlet的映射
为什么需要映射?
我们写的是java程序,但是要通过浏览器访问,而浏览器需要连接web服务器,所以我们需要在web服务器中注册我们写的Servlet,还需要给他一个浏览器能够访问的路径。
在web.xml中注册Servlet 和 Servlet的映射
<!--注册servlet--> <servlet> <servlet-name>hello</servlet-name> <servlet-class>com.wang.servlet.HelloServlet</servlet-class> </servlet> <!--Servlet的请求路径--> <servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>/hello</url-pattern> </servlet-mapping>
-
在servlet标签中有两个标签为:servlet-name 、servlet-class
-
servlet-name 标签中是 给这个servlet起个名字
-
servlet-class 标签是对应上面写的Servlet类,访问的是这个类的代码
-
-
在servlet-mapping标签中有两个标签:servlet-name 、url-pattern
-
servlet-name就是Servlet的名字,必须和servlet标签中的servlet-name相同
-
url-pattern就是在浏览器中要访问的路径
-
-
-
配置Tomcat
-
访问
源码剖析
-
在HttpServlet类中,继承了GenericServlet
public abstract class HttpServlet extends GenericServlet implements Serializable
-
在GenericServlet类中,实现了Servlet接口
public abstract class GenericServlet implements Servlet, ServletConfig, Serializable
所以我们自己的类、HttpSevlet、GenericServlet、Servlet的关系如下图:
所以我们自己写的类只需要继承HttpServlet 即可
在Serlet中有一些方法:
public interface Servlet {
void init(ServletConfig var1) throws ServletException;
ServletConfig getServletConfig();
void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;
String getServletInfo();
void destroy();
}
主要的方法是 service()
在GenericServelt中,没有对service() 进行处理:
public abstract void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;
在HttpServlet中实现了service()方法:
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String method = req.getMethod();
long lastModified;
if (method.equals("GET")) {
lastModified = this.getLastModified(req);
if (lastModified == -1L) {
this.doGet(req, resp);
} else {
long ifModifiedSince = req.getDateHeader("If-Modified-Since");
if (ifModifiedSince < lastModified / 1000L * 1000L) {
this.maybeSetLastModified(resp, lastModified);
this.doGet(req, resp);
} else {
resp.setStatus(304);
}
}
} else if (method.equals("HEAD")) {
lastModified = this.getLastModified(req);
this.maybeSetLastModified(resp, lastModified);
this.doHead(req, resp);
} else if (method.equals("POST")) {
this.doPost(req, resp);
} else if (method.equals("PUT")) {
this.doPut(req, resp);
} else if (method.equals("DELETE")) {
this.doDelete(req, resp);
} else if (method.equals("OPTIONS")) {
this.doOptions(req, resp);
} else if (method.equals("TRACE")) {
this.doTrace(req, resp);
} else {
String errMsg = lStrings.getString("http.method_not_implemented");
Object[] errArgs = new Object[]{method};
errMsg = MessageFormat.format(errMsg, errArgs);
resp.sendError(501, errMsg);
}
}
我们发现在service() 中 是对请求方式的判断 如 get、post等
在HttpServlet中,有这些请求方式默认的方法,如 doGet()、doPost()等
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(405, msg);
} else {
resp.sendError(400, msg);
}
}
protected long getLastModified(HttpServletRequest req) {
return -1L;
}
protected void doHead(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
NoBodyResponse response = new NoBodyResponse(resp);
this.doGet(req, response);
response.setContentLength();
}
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(405, msg);
} else {
resp.sendError(400, msg);
}
}
所以我们要做的事情,就是重写这些方法
我们主要重写 doGet()、doPost()
它们两个只是请求实现不同的方式,可以相互调用,因为业务逻辑相同
所以我们可以在一个里面调用另一个
Servlet 原理
Servlet是由web服务器调用,web服务器收到请求后,要进行以下操作:
Mapping问题
一个Servlet可以指定一个映射路径
<servlet>
<servlet-name>hello</servlet-name>
<servlet-class>com.wang.servlet.HelloServlet</servlet-class>
</servlet>
<!--Servlet的请求路径-->
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
一个Servlet可以指定多个映射路径
<!--注册servlet-->
<servlet>
<servlet-name>hello</servlet-name>
<servlet-class>com.wang.servlet.HelloServlet</servlet-class>
</servlet>
<!--Servlet的请求路径-->
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello2</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello3</url-pattern>
</servlet-mapping>
在浏览器的url中,可以输入 /hello /hello2 /hello3 都能够进入hello这个Servlet
一个Servlet可以指定通用的映射路径
使用通配符 *
<servlet>
<servlet-name>hello</servlet-name>
<servlet-class>com.wang.servlet.HelloServlet</servlet-class>
</servlet>
<!--Servlet的请求路径-->
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello/*</url-pattern>
</servlet-mapping>
在浏览器的url中,可以输入/hello/* * 可以代表任何请求,都可以成功
默认映射路径
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
浏览器一访问就进入hello这个Servlet,是默认的,把之前的index.jsp顶替了
指定前缀或后缀的映射路径
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
可以自定义前缀或后缀,访问时只要后缀为.do就可以访问
注意:* 前面不能加映射路径
优先级问题
指定了固有的映射路径优先级最高,如果找不到就会走默认的处理请求
举例:
新创建一个Servlet 叫做ErrorServlet
package com.wang.servlet;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
public class ErrorServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("test/html");
resp.setCharacterEncoding("utf-8");
PrintWriter writer = resp.getWriter();
writer.print("<h1>肆零肆</h1>");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
它的映射路径为
<servlet>
<servlet-name>error</servlet-name>
<servlet-class>com.wang.servlet.ErrorServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>error</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
就是默认的映射路径
我们运行一下
项目的index.jsp被替换成了 这个Servlet
如果我们访问一下/hello 呢?
结果就是,依旧是HelloServlet 那个 Servlet
如果任意访问,就会使用默认的/* 映射路径
标签:ServletException,Servlet,resp,req,笔记,学习,servlet,hello From: https://www.cnblogs.com/wztblogs/p/16782178.html