- Servlet 说明
- Servlet初步入门尝试
- Servlet生命周期
- Servlet方法说明和体系结构
- 方法说明
- 体系结构说明
- 一些优化封装
- urlParrern配置
首先我们需要了解浏览器访问服务器
我们这里还是以tomcat作为服务器参考对象。
①:Tomcat将http请求文本接收并解析,然后封装成HttpServletRequest类型的request对象,所有的HTTP头数据读可以通过request对象调用对应的方法查询到。
②:Tomcat同时会要响应的信息封装为HttpServletResponse类型的response对象,通过设置response属性就可以控制要输出到浏览器的内容,然后将response交给tomcat,tomcat就会将其变成响应文本的格式发送给浏览器
就那我么部署的项目来说。我们开启服务后。然后我们通过一段链接来访问我们的服务器然后得到响应数据。
http://localhost/login.html
localhost后面还有个80这里省略了。
我们可以根据localhost:80端口号找到tomcat服务器,然后后面的路径分别指定了访问项目路径和访问的内容。
我们在访问tomcat的时候会有一个默认的servlet数据处理。
我们也可以在web.xml查看内容。
我们没有创建Servlet类,里面的一些处理以及默认参数都是按照服务端默认数据进行,我们需要大致了解这些过程。
另外我们需要了解到如果我们在java中运用这个技术,就可以做出动态web开发。
Servlet初步入门尝试我们运用maven在idea里面添加Servlet依赖坐标
javax.servlet javax.servlet-api 3.1.0 provided
然后我们创建一个类,来实现Servlet接口,并重写接口当中所有方法。
package jgd;
import javax.servlet.*;
import javax.servlet.annotation.WebServlet;
import java.io.IOException;
@WebServlet("/demo1")
public class ServletDemo01 implements Servlet {
public void init(ServletConfig servletConfig) throws ServletException {
}
public ServletConfig getServletConfig() {
return null;
}
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
//Servlet被访问的时候service会自动执行
System.out.println("servlet hello world");
}
public String getServletInfo() {
return null;
}
public void destroy() {
}
}
上面的注解说明了访问路径。
启动!
对的什么也没有,我们来看控制台。
我们执行后,service方法被调用了。
Servlet生命周期Servlet由web服务器创建,Servlet方法由web服务器调用
我们自定义的Servlet,必须实现Servlet接口并复写其方法,而Servlet接口中有service方法
ServletDemo1实现了Servlet接口,所以类中必然会重写service方法供Tomcat Web服务器进行调用
service方法中有ServletRequest和ServletResponse两个参数,ServletRequest封装的是请求数据,ServletResponse封装的是响应数据,后期我们可以通过这两个参数实现前后端的数据交互
在Java中对象的生命周期指一个对象从被创建到被销毁的整个过程。
我们可以将Servlet大致划分为四个阶段
1:加载和实例化,我们的默认情况下,没有自己指定值的话,Servlet在被第一次被访问的时候,会由容器创建Servlet对象。
默认情况,Servlet会在第一次访问被容器创建,但是如果创建Servlet比较耗时的话,那么第一个访问的人等待的时间就比较长,用户的体验就比较差,那么我们能不能把Servlet的创建放到服务器启动的时候来创建,具体如何来配置?
@WebServlet(urlPatterns = “/demo1”,loadOnStartup = 1)
loadOnstartup的取值有两类情况
(1)负整数:第一次访问时创建Servlet对象
(2)0或正整数:服务器启动时创建Servlet对象,数字越小优先级越高
2:初始化,继加载和实例化之后然后Servlet的init()方法会实现初始化对象。初始化完成的工作就是加载配置文件,创建连接等初始化工作。初始化的方法只会执行一次。
3:请求处理,每次请求Servlet都会自动调用service请求进行处理。
4:服务终止,当需要释放内存或者容器关闭时,容器就会调用Servlet实例的==destroy()==方法完成资源的释放。在destroy()方法调用之后,容器会释放这个Servlet实例,该实例随后会被Java的垃圾收集器所回收
测试用例
package jgd;
import javax.servlet.*;
import javax.servlet.annotation.WebServlet;
import java.io.IOException;
@WebServlet(urlPatterns = "/demo2", loadOnStartup = 1)
public class ServletDemo02 implements Servlet {
public void init(ServletConfig servletConfig) throws ServletException {
// 初始化方法
// 1:调用时机:默认情况下Servlet被第一次访问的时候调用
// 2:调用次数:只会被调用一次
System.out.println("init");
}
public ServletConfig getServletConfig() {
return null;
}
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
//每次Servlet被访问的时候service会自动执行
System.out.println("servlet hello world");
}
public String getServletInfo() {
return null;
}
public void destroy() {
System.out.println("destory---");
}
}
Servlet方法说明和体系结构
方法说明
在上文中已经说明了三个方法。初始化,服务,以及销毁。
1:初始化方法,只执行一次,默认在Servlet被第一次访问执行。
init(ServletConfig servletConfig)
2:服务方法,每次Servlet被访问的时候会默认访问,主要用于编写处理的访问逻辑.
void service(ServletRequest servletRequest, ServletResponse servletResponse)
3:销毁方法,Servlet被销毁的时候,该方法被调用。在内存释放或者服务器关闭的时候销毁Servlet。需要进行正常的关闭,如果关掉java进程就来不及等到对象被销毁。
destroy()
4:获取Servlet信息,一般的话不怎么用,给它返回空字符串和空就可以
String getServletInfo()
5:获取ServletConfig对象
ServletConfig getServletConfig()
我们研究一下如何获取到这个对象,我们可以这样做。主要是扩大作用范围。看看就明白了。
package jgd;
import javax.servlet.*;
import javax.servlet.annotation.WebServlet;
import java.io.IOException;
@WebServlet(urlPatterns = "/demo3", loadOnStartup = 1)
public class ServletDemo02 implements Servlet {
private ServletConfig servletConfig;
public void init(ServletConfig servletConfig) throws ServletException {
// 初始化方法
// 1:调用时机:默认情况下Servlet被第一次访问的时候调用
// 2:调用次数:只会被调用一次
System.out.println("init");
//将servletConfig值赋给了局部变量
this.servletConfig=servletConfig;
}
public ServletConfig getServletConfig() {
return servletConfig;
}
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
//每次Servlet被访问的时候service会自动执行
System.out.println("servlet hello world");
}
public String getServletInfo() {
return null;
}
public void destroy() {
System.out.println("destory---");
}
}
该对象在init方法的参数中有,而Tomcat Web服务器在创建Servlet对象的时候会调用init方法,必定会传入一个ServletConfig对象,我们只需要将服务器传过来的ServletConfig进行返回即可
体系结构说明之前写的Servlet类都是来自继承,并且需要重写方法等等。
了解到的体系结构
因为我们将来开发B/S架构的web项目,都是针对HTTP协议,所以我们自定义Servlet,会通过继承HttpServlet
所以我们来操作一下。尝试继承这个类。
package jgd;
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("/demo4")
public class ServletDemo4 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// super.doGet(req, resp);
System.out.println("get...");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// super.doPost(req, resp);
System.out.println("post...");
}
}
这里个方法分别可以代表get和post的处理逻辑。根据不同的请求方式来调用相应的方法以及做出方法提里面的处理逻辑。
在继承HttpServlet时,为什么只重写doGet和doPost
get方法我们就直接在浏览器地址栏访问到项目,如果是post我么就可以去编写一个表单,然后提交到对应web项目地址。
我们现在运行这个项目。直接访问地址。
这里成功输出了get。
然后我们写一个表单,表单的action路径要指定到你的项目路径,也就是Servlet路径。
不妨用之前那个表单
欢迎注册
欢迎注册
已有帐号? 登录
注意:
启动!一定要定位到表单html。
这回我们的post请求就可以得到了。
前端发送GET和POST请求的时候,参数的位置不一致,GET请求参数在请求行中,POST请求参数在请求体中
为了能处理不同的请求方式,我们得在service方法中进行判断,然后写不同的业务处理,这样能实现,但是每个Servlet类中都将有相似的代码,针对这个问题,有什么可以优化的策略么?
package jgd;
import javax.servlet.*;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
public class ServletDemo5 implements Servlet {
public void init(ServletConfig servletConfig) throws ServletException {
}
public ServletConfig getServletConfig() {
return null;
}
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
// 根据请求方式的不同,进行分别的处理
// 获取请求方式
// 先转换为http协议下的逻辑
HttpServletRequest request = (HttpServletRequest) servletRequest;
//获取到方法
String method = request.getMethod();
// 进行判断
if ("GET".equals(method)) {
// get方式的处理逻辑
} else if ("POST".equals(method)) {
// post方式的处理逻辑
}
}
public String getServletInfo() {
return null;
}
public void destroy() {
}
}
比如上面这段代码,我不想每次写的时候都写逻辑判断,这是一段重复的代码。我不想每次写。这里的逻辑处理还不是很多,如果很多很多的话,我们该如何如理?我们每次都需要这样处理的话,我们就应该进行封装调用。
现在我们自己定义一个类
package jgd;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
public class MyHttpServlet implements Servlet {
public void init(ServletConfig servletConfig) throws ServletException {
}
public ServletConfig getServletConfig() {
return null;
}
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
// 根据请求方式的不同,进行分别的处理
// 获取请求方式
// 先转换为http协议下的逻辑
HttpServletRequest request = (HttpServletRequest) servletRequest;
//获取到方法
String method = request.getMethod();
// 进行判断
if ("GET".equals(method)) {
doGet(servletRequest, servletResponse);
// get方式的处理逻辑
} else if ("POST".equals(method)) {
// post方式的处理逻辑
doPost(servletRequest, servletResponse);
}
}
protected void doPost(ServletRequest servletRequest, ServletResponse servletResponse) {
}
protected void doGet(ServletRequest servletRequest, ServletResponse servletResponse) {
}
public String getServletInfo() {
return null;
}
public void destroy() {
}
}
我们把方法定义好,参数安排好。可以让之后的类继承到这个类。然后实现调用统一的功能。
后面就简化了好多,这也是继承的好处。也是一种功能封装。
package jgd;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebServlet;
@WebServlet("/demo6")
public class ServletDemo6 extends MyHttpServlet {
@Override
protected void doGet(ServletRequest servletRequest, ServletResponse servletResponse) {
// super.doGet(servletRequest, servletResponse);
System.out.println("get...");
}
@Override
protected void doPost(ServletRequest servletRequest, ServletResponse servletResponse) {
// super.doPost(servletRequest, servletResponse);
System.out.println("post..");
}
}
urlParrern配置
之前我们采用注解的方式配置这个访问路径,只设置了一个访问路径。其实还可以配置多个访问路径。就像这样。
@WebServlet(urlPatterns = {"/demo7","/demo07"})
其实我们这样的配置就是一种路径匹配规则或者说是项目匹配访问规则。
下面我们介绍几种匹配规则
1:精确匹配
我们在注解中这样写的话,将来我们访问的化需要通过这个完整的路径来访问项目。
eg:
@WebServlet("/jgdabc/666")
2:目录匹配
eg:
/@WebServlet(urlPatterns = "/user/*") 目录匹配
将来我们访问的时候首先需要输入user,然后后面可以跟上任何路径。
3:扩展名匹配
@WebServlet("*.do")
将来访问的时候前面可以加上任何路径,但是后面需要加上do的扩展名。
4:任意匹配
//@WebServlet("/")
//@WebServlet("/*")
任意匹配不建议使用
- 当我们的项目中的Servlet配置了 “/”,会覆盖掉tomcat中的DefaultServlet,当其他的url-pattern都匹配不上时都会走这个Servlet
- 当我们的项目中配置了"/*",意味着匹配任意访问路径
- DefaultServlet是用来处理静态资源,如果配置了"/"会把默认的覆盖掉,就会引发请求静态资源的时候没有走默认的而是走了自定义的Servlet类,最终导致静态资源不能被访问
测试用例
package jgd;
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("/jgdabc/666")
//可配置多个访问路径,这是精确匹配
//@WebServlet(urlPatterns = {"/demo7","/demo07"})
//@WebServlet(urlPatterns = "/user/*") 目录匹配
//当精确匹配和目录匹配同时都满足的时候,精确匹配优先级别更高
//@WebServlet("*.do") 扩展名匹配
//任意匹配
// /* 的优先级高于/
//@WebServlet("/")
//@WebServlet("/*")
public class ServletDemo7 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("demo7get...");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// super.doPost(req, resp);
}
}
注:未完续更。



