简介

Servlet (server applet) 是运行在服务端(tomcat)的Java小程序,从代码层面上来讲Servlet就是一个接口

用来接收、处理客户端请求、响应给浏览器的动态资源。在整个Web应用中,Servlet主要负责接收处理请求、协同调度功能以及响应数据。我们可以把Servlet称为Web应用中的控制器

1.tomcat接收到请求后,会将请求报文的信息转换一个HttpServletRequest对象,该对象中包含了请求中的所有信息请求行请求头请求体

2.tomcat同时创建了一个HttpServletResponse对象,该对象用于承装要响应给客户端的信息,后面,该对象会被转换成响应的报文响应行响应头响应体

3.tomcat根据请求中的资源路径找到对应的servlet,将servlet实例化,调用service方法,同时将HttpServIetRequest和HttpServIetResponse对象传入

开发流程(样例)

1.用IDEA创建Servlet项目:先在”项目结构”中添加tomcat依赖,然后”添加框架支持”->”web应用”

2.重写service方法

3.在service方法中定义业务逻辑代码

package com.mikann.servlet;

import jakarta.servlet.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 UserServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String username = req.getParameter("username");

String info ="<h1>NO</h1>";
if("mikannse".equals(username)) {
info="<h1>YES</h1>";
}
resp.setContentType("text/html");
resp.getWriter().println(info);
}
}

4.在web.xml中配置Servlet对应的请求映射路径

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_6_0.xsd"
version="6.0">
<!--
1 配置Servlet类,起一个别名
servlet-class 告诉tomcat对应的要实例化的Servlet类
servlet-name 用于关联请求的映射路径
-->
<servlet>
<servlet-name>userServlet</servlet-name>
<servlet-class>com.mikann.servlet.UserServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>userServlet</servlet-name>
<url-pattern>/userServlet</url-pattern>
</servlet-mapping>
</web-app>

配置构建配置,选择tomcat并且更改上下文路径,构建运行

url-pattern问题

web.xml

<servlet>
<servlet-name>servlet1</servlet-name>
<servlet-class>com.mikann.servlet.Servlet1</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>servlet1</servlet-name>
<url-pattern>/s1</url-pattern>
</servlet-mapping>

访问 http://localhost:8080/demo1/s1

则从url-pattern匹配,然后寻找servlet1(别名),然后寻找servlet-class中的com.mikann.servlet.Servlet1

一个servlet-name能对应多个url-pattern

一个servlet标签可以同时对应多个servlet-mapping标签

1.精确匹配: /servlet1

2.模糊匹配:

*作为通配符

/ 匹配全部,但不包括jsp文件

/*匹配全部,包含jsp文件

注解方式配置Servlet

@WebServlet(urlPatterns = {"/s1","/s2"})
public class Servlet1 extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html");
resp.getWriter().println("<h1>哈哈</h1>");

使用”@WebServlet()”,则无需在web.xml中配置上下文

生命周期

  • 应用程序中的对象不仅在空间上有层次结构的关系,在时间上也会因为处于程序运行过程中的不同阶段而表现出不同状态和不同行为——这就是对象的生命周期。
  • 简单的叙述生命周期,就是对象在容器中从开始创建到销毁的过程。

Servlet容器

  • Servlet对象是Servlet容器创建的,生命周期方法都是由容器(目前我们使用的是Tomcat)调用的。这一点和我们之前所编写的代码有很大不同。在今后的学习中我们会看到,越来越多的对象交给容器或框架来创建,越来越多的方法由容器或框架来调用,开发人员要尽可能多的将精力放在业务逻辑的实现上。

1.实例化 构造器 第一次请求

2.初始化 init 构造完毕

3.接受请求,处理请求 服务 service 每次请求

4.销毁 destory 关闭服务

package com.mikann.servlet;

import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

import java.io.IOException;

@WebServlet(value = "/servletLifeCycle",loadOnStartup = 100)
public class ServletLifeCycle extends HttpServlet {
public ServletLifeCycle() {
System.out.println("构造器执行了");
}

@Override
public void init() throws ServletException {
System.out.println("初始化");
}

@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("服务");
}
@Override
public void destroy() {
System.out.println("destroy");
}
}

loadOnStartup默认为-1,则不会自动加载或者初始化

DefaultServlet:处理所有静态资源所用的Servlet

ServletConfig

  • 为Servlet提供初始配置参数的一种对象,每个Servlet都有自己独立唯一的ServletConfig对象
  • 容器会为每个Servlet实例化一个ServletConfig对象,并通过Servlet生命周期的init方法传入给Servlet作为属性
<servlet-name>servlet1</servlet-name>
<servlet-class>com.mikann.servlet.Servlet1</servlet-class>
<init-param>
<param-name>keya</param-name>
<param-value>valueA</param-value>
</init-param>
<init-param>
<param-name>keyb</param-name>
<param-value>valueb</param-value>
</init-param>
public class Servlet1 extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletConfig servletConfig=getServletConfig();
String keya = servletConfig.getInitParameter("keya");
System.out.println("keya="+keya);
}
}

ServletContext

  • ServletContext对象有称呼为上下文对象,或者叫应用域对象(后面统一讲解域对象)
  • 容器会为每个app创建一个独立的唯一的ServletContext对象
  • ServletContext对象为所有的Servlet所共享
  • ServletContext可以为所有的Servlet提供初始配置参数

获取资源的真实路径

String realPath = servletContext.getRealPath("资源在web目录中的路径");
  • 例如我们的目标是需要获取项目中某个静态资源的路径,不是工程目录中的路径,而是部署目录中的路径;我们如果直接拷贝其在我们电脑中的完整路径的话其实是有问题的,因为如果该项目以后部署到公司服务器上的话,路径肯定是会发生改变的,所以我们需要使用代码动态获取资源的真实路径. 只要使用了servletContext动态获取资源的真实路径,那么无论项目的部署路径发生什么变化,都会动态获取项目运行时候的实际路径,所以就不会发生由于写死真实路径而导致项目部署位置改变引发的路径错误问题

获取项目的上下文路径

String contextPath = servletContext.getContextPath();
  • 项目的部署名称,也叫项目的上下文路径,在部署进入tomcat时所使用的路径,该路径是可能发生变化的,通过该API动态获取项目真实的上下文路径,可以帮助我们解决一些后端页面渲染技术或者请求转发和响应重定向中的路径问题
API 功能解释
void setAttribute(String key,Object value); 向域中存储/修改数据
Object getAttribute(String key); 获得域中的数据
void removeAttribute(String key); 移除域中的数据

请求转发和响应重定向

  • 请求转发和响应重定向是web应用中间接访问项目资源的两种手段,也是Servlet控制页面跳转的两种手段

  • 请求转发通过HttpServletRequest实现,响应重定向通过HttpServletResponse实现

请求转发

  • 请求转发通过HttpServletRequest对象获取请求转发器实现

  • 请求转发是服务器内部的行为,对客户端是屏蔽的

  • 客户端只发送了一次请求,客户端地址栏不变

  • 服务端只产生了一对请求和响应对象,这一对请求和响应对象会继续传递给下一个资源

  • 因为全程只有一个HttpServletRequset对象,所以请求参数可以传递,请求域中的数据也可以传递

  • 请求转发可以转发给其他Servlet动态资源,也可以转发给一些静态资源以实现页面跳转

  • 请求转发可以转发给WEB-INF下受保护的资源

  • 请求转发不能转发到本项目以外的外部资源

  • ServletA

@WebServlet("/servletA")
public class ServletA extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 获取请求转发器
// 转发给servlet ok
RequestDispatcher requestDispatcher = req.getRequestDispatcher("servletB");
// 转发给一个视图资源 ok
//RequestDispatcher requestDispatcher = req.getRequestDispatcher("welcome.html");
// 转发给WEB-INF下的资源 ok
//RequestDispatcher requestDispatcher = req.getRequestDispatcher("WEB-INF/views/view1.html");
// 转发给外部资源 no
//RequestDispatcher requestDispatcher = req.getRequestDispatcher("http://www.atguigu.com");
// 获取请求参数
String username = req.getParameter("username");
System.out.println(username);
// 向请求域中添加数据
req.setAttribute("reqKey","requestMessage");
// 做出转发动作
requestDispatcher.forward(req,resp);
}
}
  • ServletB
@WebServlet("/servletB")
public class ServletB extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 获取请求参数
String username = req.getParameter("username");
System.out.println(username);
// 获取请求域中的数据
String reqMessage = (String)req.getAttribute("reqKey");
System.out.println(reqMessage);
// 做出响应
resp.getWriter().write("servletB response");
}
}

响应重定向

  • 响应重定向通过HttpServletResponse对象的sendRedirect方法实现

  • 响应重定向是服务端通过302响应码和路径,告诉客户端自己去找其他资源,是在服务端提示下的,客户端的行为

  • 客户端至少发送了两次请求,客户端地址栏是要变化的

  • 服务端产生了多对请求和响应对象,且请求和响应对象不会传递给下一个资源

  • 因为全程产生了多个HttpServletRequset对象,所以请求参数不可以传递,请求域中的数据也不可以传递

  • 重定向可以是其他Servlet动态资源,也可以是一些静态资源以实现页面跳转

  • 重定向不可以到给WEB-INF下受保护的资源

  • 重定向可以到本项目以外的外部资源

  • ServletA

@WebServlet("/servletA")
public class ServletA extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 获取请求参数
String username = req.getParameter("username");
System.out.println(username);
// 向请求域中添加数据
req.setAttribute("reqKey","requestMessage");
// 响应重定向
// 重定向到servlet动态资源 OK
resp.sendRedirect("servletB");
// 重定向到视图静态资源 OK
//resp.sendRedirect("welcome.html");
// 重定向到WEB-INF下的资源 NO
//resp.sendRedirect("WEB-INF/views/view1");
// 重定向到外部资源
//resp.sendRedirect("http://www.atguigu.com");
}
}
  • ServletB
@WebServlet("/servletB")
public class ServletB extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 获取请求参数
String username = req.getParameter("username");
System.out.println(username);
// 获取请求域中的数据
String reqMessage = (String)req.getAttribute("reqKey");
System.out.println(reqMessage);
// 做出响应
resp.getWriter().write("servletB response");

}
}

MVC模式

MVC(Model View Controller)是软件工程中的一种**软件架构模式,它把软件系统分为模型视图控制器**三个基本部分。用一种业务逻辑、数据、界面显示分离的方法组织代码,将业务逻辑聚集到一个部件里面,在改进和个性化定制界面及用户交互的同时,不需要重新编写业务逻辑。

  • M:Model 模型层,具体功能如下

    1. 存放和数据库对象的实体类以及一些用于存储非数据库表完整相关的VO对象
    2. 存放一些对数据进行逻辑运算操作的的一些业务处理代码
  • V:View 视图层,具体功能如下

    1. 存放一些视图文件相关的代码 html css js等
    2. 在前后端分离的项目中,后端已经没有视图文件,该层次已经衍化成独立的前端项目
  • C:Controller 控制层,具体功能如下

    1. 接收客户端请求,获得请求数据
    2. 将准备好的数据响应给客户端