Servlet 与 MVC

news2024/11/18 14:49:52

主要内容

  • Servlet 重点

  • MVC 重点

  • Filter 重点

章节目标

  • 掌握 Servlet 的作用

  • 掌握 Servlet 的生命周期

  • 掌握 JSP 的本质

  • 掌握 MVC 的设计思想

  • 掌握 Filter 的作用及使用场景

第一节 Servlet

1. Servlet 概念

Servlet 是在服务器上运行的能够对客户端请求进行处理,并返回处理结果的程序

2. Servlet 体系结构

2.1 Servlet 接口
//Servlet对象的初始化,Servlet 对象初始化后才能处理请求,由 Servlet 容器调用
public void init(ServletConfig config) throws ServletException;
//获取Servlet配置信息
public ServletConfig getServletConfig();
//处理客户端的请求,由 Servlet 容器调用
public void service(ServletRequest req, ServletResponse res)
    throws ServletException, IOException;
//返回有关 Servlet 的信息,比如作者、版本和版权
public String getServletInfo();
//销毁Servlet,由 Servlet 容器调用
public void destroy();
2.2 ServletConfig 接口
//获取Servlet的实例名称
public String getServletName();
//返回正在执行的Servlet所在的上下文对象
public ServletContext getServletContext();
//获取Servlet中给定名称的初始化参数
public String getInitParameter(String name);
//获取Servlet中所有的初始化参数
public Enumeration<String> getInitParameterNames();
2.3 Servlet 案例
  • 编写Servlet

    package com.qf.jsp.servlet;
    
    import javax.servlet.*;
    import java.io.IOException;
    import java.util.Enumeration;
    
    public class LoginServlet implements Servlet {
    
        private ServletConfig servletConfig;
    
        @Override
        public void init(ServletConfig config) throws ServletException {
            this.servletConfig = config;
            String servletName = config.getServletName();
            System.out.println("Servlet 实例的名称:" + servletName);
            //获取Servlet中所有的初始化参数
            Enumeration<String> initParameterNames = config.getInitParameterNames();
            while (initParameterNames.hasMoreElements()) {
                String initParameterName = initParameterNames.nextElement();
                //获取Servlet中给定名称的初始化参数
                String initParameterValue = config.getInitParameter(initParameterName);
                System.out.println("Servlet 初始化参数 " + initParameterName + ":" + initParameterValue);
            }
        }
    
        @Override
        public ServletConfig getServletConfig() {
            return servletConfig;
        }
    
        @Override
        public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
            System.out.println("Servlet 处理请求");
        }
    
        @Override
        public String getServletInfo() {
            return "Login Servlet";
        }
    
        @Override
        public void destroy() {
            System.out.println("Servlet 销毁");
        }
    }
  • 配置 web.xml

    <?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">
      
      <display-name>ServletApp</display-name>
      
      <!--Servlet 实例配置-->
      <servlet>
        <!-- Servlet 实例的名称-->
        <servlet-name>loginServlet</servlet-name>
        <!--Servlet 的类型-->
        <servlet-class>com.qf.jsp.servlet.LoginServlet</servlet-class>
        <init-param>
          <!--初始化参数的名称-->
          <param-name>characterEncoding</param-name>
          <!--初始化参数的值-->
          <param-value>UTF-8</param-value>
        </init-param>
      </servlet>
      <!--Servlet 实例与请求地址的映射配置-->
      <servlet-mapping>
        <!-- Servlet 实例的名称-->
        <servlet-name>loginServlet</servlet-name>
        <!-- Servlet 匹配的请求地址-->
        <url-pattern>/login</url-pattern>
      </servlet-mapping>
      <!--session 配置-->
      <session-config>
        <!--超时时间配置-->
        <session-timeout>30</session-timeout>
      </session-config>
    </web-app>
  • 获取初始化参数信息

    @Override
    public void init(ServletConfig config) throws ServletException {
        this.servletConfig = config;
        String servletName = config.getServletName();
        System.out.println("Servlet 实例的名称:" + servletName);
        //获取Servlet中所有的初始化参数
        Enumeration<String> initParameterNames = config.getInitParameterNames();
        while (initParameterNames.hasMoreElements()){
            String initParameterName = initParameterNames.nextElement();
            //获取Servlet中给定名称的初始化参数
            String initParameterValue = config.getInitParameter(initParameterName);
            System.out.println("Servlet 初始化参数 " + initParameterName + ":" + initParameterValue);
        }
    }
  • 编写 index.jsp

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <!DOCTYPE HTML>
    <html>
      <head>
        <title>登录页面</title>
      </head>
      <body>
        <form action="login" method="post">
          <div>
            <input type="text" name="username">
          </div>
          <div>
            <input type="password" name="password">
          </div>
          <div>
            <input type="submit" value="登录">
          </div>
        </form>
      </body>
    </html>
  • 启动服务器,进行登录操作,查看控制台信息

控制台打印信息中并没有打印 "Servlet 销毁" 信息,由此可以得出:Servlet 处理完了请求后,并没有销毁。

  • 关闭服务器,查看控制台信息

由此可以得出:在 Tomcat 关闭之前,Servlet 被销毁

  • 结论

Servlet 在第一次接收请求时,由容器(如 Tomcat)创建实例,紧接着就由容器调用该 Servlet 的 init 方法完成初始化,然后由容器调用该 Servlet 的 service 方法进行请求处理,请求处理完成后,Servlet 并不会消亡, 而是跟随容器共存亡,在容器关闭之前,由容器调用 Servlet 的 destroy方法进行销毁

  • JSP 本质

package org.apache.jsp;

import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;

public final class index_jsp extends org.apache.jasper.runtime.HttpJspBase
    implements org.apache.jasper.runtime.JspSourceDependent,
                 org.apache.jasper.runtime.JspSourceImports {
}

由此可以得出:JSP 的本质就是Servlet,只是 JSP 注重的是页面内容的展示,而Servlet注重的是业务逻辑的处理。

3. 请求处理与响应

3.1 体系结构

3.2 请求接口
  • ServletRequest 接口常用方法

//从请求中获取给定属性名对应的属性值
Object getAttribute(String attributeName);
//将给定的属性值以给定的属性名存储在请求中
void setAttribute(String attributeName, Object attributeVaue);
//从请求中将给定的属性名移除
void removeAttribute(String attributeName);
//获取请求中存储的所有属性名
Enumeration<String> getAttributeNames();
//从请求中获取给定参数名对应的参数值(参数值是单个数据)
String getParameter(String parameterName);
//从请求中获取给定参数名对应的参数值(参数值是多个数据)
String[] getParameterValues(String parameterName);
//从请求中获取所有的参数名
Enumeration<String> getParameterNames();
//从请求中获取所有的参数名和参数值形成的映射
Map<String, String[]> getParameterMap();
//从请求中获取字符集编码
String getCharacterEncoding();
//设置请求的字符集编码
void setCharacterEncoding(String charset) throws UnsupportedEncodingException;
//从请求中获取字符流,该字符流只能读取请求体中的数据信息,与下面的 getInputStream 方法只能二选一
BufferedReader getReader() throws IOException;
//从请求中获取字节流,该字节流只能读取请求体中的数据信息
ServletInputStream getInputStream() throws IOException;
//从请求中获取当前Servlet所在的上下文对象
ServletContext getServletContext();
//从请求中获取请求转发的对象
RequestDispatcher getRequestDispatcher(String path);
  • 用法

@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
    System.out.println("请求的字符集编码需要在读取请求信息之前进行设置,否则,设置的字符集编码格式将不生效");
    System.out.println("请求字符集编码:" + servletRequest.getCharacterEncoding());
    servletRequest.setCharacterEncoding("UTF-8");
    System.out.println("请求字符集编码:" + servletRequest.getCharacterEncoding());

    BufferedReader reader = servletRequest.getReader();
    System.out.println("开始读取请求参数信息");
    String line;
    while ((line = reader.readLine()) != null){
        System.out.println(line);
    }
    System.out.println("请求参数信息读取完毕");
    System.out.println("================");
    System.out.println("开始获取请求中存储的数据");
    Enumeration<String> attributeNames = servletRequest.getAttributeNames();
    while (attributeNames.hasMoreElements()){
        String attributeName = attributeNames.nextElement();
        Object attributeValue = servletRequest.getAttribute(attributeName);
        System.out.println(attributeName + " => " + attributeValue);
    }
    System.out.println("请求中存储的数据获取完毕");
    System.out.println("================");
    System.out.println("方式一:开始获取请求参数信息");
    Enumeration<String> parameterNames = servletRequest.getParameterNames();
    while (parameterNames.hasMoreElements()){
        String parameterName = parameterNames.nextElement();
        String parameterValue = servletRequest.getParameter(parameterName);
        System.out.println(parameterName + " => " + parameterValue);
    }
    System.out.println("方式一:请求参数信息获取完毕");
    System.out.println("================");
    System.out.println("方式二:开始获取请求参数信息");
    Map<String, String[]> parameterMap = servletRequest.getParameterMap();
    parameterMap.forEach((k, values) -> System.out.println(k + " => " + Arrays.toString(values)));
    System.out.println("方式二:请求参数信息获取完毕");
    System.out.println("请求所使用的上下文路径:" + servletRequest.getServletContext().getContextPath());
}
  • POST请求测试

  • GET 请求测试

  • 结论

使用GET方式发送的请求,只能通过getParameter 方法获取;使用POST方式发送的请求,只能使用流来获取。这是因为使用GET方式发送的请求,参数在URL地址中,解析这些参数的时候将其存放在一个Map集合中,因此可以直接获取。而POS方式发送的请求,参数在请求体中,这部分内容只能通过流来读取,然后再进行处理。

3.3 响应接口
  • ServletResponse 接口常用方法

//获取响应的字符集编码
String getCharacterEncoding();
//设置响应的字符集编码
void setCharacterEncoding(String charset);
//获取响应的内容类型
String getContentType();
//设置响应的内容类型
void setContentType(String contentType);
//获取输出流,主要用于下载文件
ServletOutputStream getOutputStream() throws IOException;
//获取打印流,主要用于向页面传输信息
PrintWriter getWriter() throws IOException;
  • 用法(在 service 方法最后追加如下代码)

System.out.println();
System.out.println();
System.out.println("===========================================");
System.out.println("响应的字符集编码:" + servletResponse.getCharacterEncoding());
servletResponse.setCharacterEncoding("UTF-8");
System.out.println("响应的字符集编码:" + servletResponse.getCharacterEncoding());
System.out.println("响应的内容类型:" + servletResponse.getContentType());
servletResponse.setContentType("text/html;charset=utf-8");
System.out.println("响应的内容类型:" + servletResponse.getContentType());
PrintWriter writer = servletResponse.getWriter();
writer.print("登录请求已处理");
writer.flush();
writer.close();
  • 测试

3.4 HTTP 请求和响应
  • HttpServletRequest 接口常用方法

    //从请求中获取Cookie信息
    Cookie[] getCookies();
    //从请求中获取给定请求头名称对应的属性值
    String getHeader(String headerName);
    //从请求中获取所有的请求头名称
    Enumeration<String> getHeaderNames();
    //获取请求的方式:GET、POST、PUT、DELETE等
    String getMethod();
    //从请求中获取上下文路径
    String getContextPath();
    //从请求中获取session
    HttpSession getSession();
    //获取请求地址
    String getRequestURI();
  • HttpServletResponse 接口常用方法

//添加客户端存储的Cookie信息
void addCookie(Cookie cookie);
//返回错误状态及错误信息
void sendError(int status, String errorMsg) throws IOException;
//返回错误状态
void sendError(int status) throws IOException;
//重定向至新的资源
void sendRedirect(String redirectURL) throws IOException;
//设置响应头信息
void setHeader(String headerName, String headerValue);
//添加响应头信息
void addHeader(String headerName, String headerValue);
//设置响应状态
void setStatus(int status);
  • HttpServlet常用方法(支持 HTTP 协议的 Servlet)

//对父类抽象方法的实现,该方法是对HTTP协议的交互信息的实现,调用的是下面的 service 方法
void service(ServletRequest req,ServletResponse res);
//HTTP协议的交互信息的实现,该方法主要针对不同的请求方式进行处理。GET请求会调用 doGet 方法处理,
//POST请求会调用 doPost 处理, PUT请求会调用 doPut 方法处理, DELETE请求会调用 doDelete 方法处理 
void service(HttpServletRequest  req, HttpServletResponseres);
//GET请求处理
void doGet(HttpServletRequestreq,HttpServletResponse res);
//POST请求处理
void doPost(HttpServletRequestreq,HttpServletResponse res);
//PUT请求处理
void doPut(HttpServletRequestreq,HttpServletResponse res);
//DELETE请求处理
void doDelete(HttpServletRequestreq,HttpServletResponse res);
  • 用法

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.Map;

public class RegisterServlet extends HttpServlet {

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("开始获取请求头信息");
        Enumeration<String> headerNames = req.getHeaderNames();
        while (headerNames.hasMoreElements()){
            String headerName = headerNames.nextElement();
            String headerValue = req.getHeader(headerName);
            System.out.println(headerName + " => " + headerValue);
        }
        System.out.println("请求头信息获取完毕");
        System.out.println("请求方式:" + req.getMethod());
        System.out.println("请求地址:" + req.getRequestURI());
        System.out.println("请求的上下文路径:" + req.getContextPath());
        System.out.println("==================");
        System.out.println("开始读取请求参数");
        Map<String, String[]> parameterMap = req.getParameterMap();
        parameterMap.forEach((k, values) -> System.out.println(k + "=>" + Arrays.toString(values)));
        System.out.println("请求参数读取完毕");
        System.out.println();
        System.out.println();
        System.out.println("=========================");
        System.out.println("响应开始");
        resp.setContentType("text/html;charset=utf-8");
        PrintWriter writer = resp.getWriter();
        writer.print("注册请求已经处理");
        writer.flush();
        writer.close();
    }
}
<!-- register.jsp -->
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE HTML>
<html>
  <head>
    <title>注册页面</title>
  </head>
  <body>
    <form action="createUser" method="post">
      <div>
        <input type="text" name="username">
      </div>
      <div>
        <input type="password" name="password">
      </div>
      <div>
        <input type="submit" value="注册">
      </div>
    </form>
  </body>
</html>
<!-- web.xml 中添加如下配置 -->
<servlet>
    <servlet-name>registerServlet</servlet-name>
    <servlet-class>com.qf.jsp.servlet.RegisterServlet</servlet-class>
</servlet>

<servlet-mapping>
    <servlet-name>registerServlet</servlet-name>
    <url-pattern>/createUser</url-pattern>
</servlet-mapping>
  • 测试

查看控制台信息

3.5 Servlet 交互流程

4. ServletContext

4.1 常用方法
//获取上下文路径
String getContextPath();
//获取给定相对路径对应的绝对路径
String getRealPath(String path);
//获取上下文初始化参数中给定参数名对应的参数值
String getInitParameter(String parameterName);
//获取上下文初始化参数中所有的参数名
Enumeration<String> getInitParameterNames();
//获取上下文存储的数据中给定属性名对应的属性值
Object getAttribute(String attributeName);
//获取上下文存储的数据中所有的属性名
Enumeration<String> getAttributeNames();
//将给定的属性值使用给定的属性名存储在上下文中
void setAttribute(String attributeName, Object attributeValue);
//从上下文存储的数据中将给定的属性名移出
void removeAttribute(String attributeName);
4.2 用法
  • 配置 web.xml

    <context-param>
        <param-name>characterEncoding</param-name>
        <param-value>UFT-8</param-value>
    </context-param>
  • 修改 RegisterServlet

@Override
public void init(ServletConfig config) throws ServletException {
    System.out.println("开始读取上下文参数信息");
    ServletContext servletConte
        xt = config.getServletContext();
    Enumeration<String> initParameterNames = servletContext.getInitParameterNames();
    while (initParameterNames.hasMoreElements()){
        String initParameterName = initParameterNames.nextElement();
        String initParameterValue = servletContext.getInitParameter(initParameterName);
        System.out.println( initParameterName + " => " + initParameterValue);
    }
}
  • 测试

查看控制台信息

第二节 MVC

1. 什么是 MVC

模型-视图-控制器(MVC模式)是一种非常经典的软件架构模式,在UI框架和UI设计思路中扮演着非常重要的角色。从设计模式的角度来看,MVC模式是一种复合模式,它将多个设计模式在一种解决方案中结合起来,用来解决许多设计问题。MVC模式把用户界面交互分拆到不同的三种角色中,使应用程序被分成三个核心部件:Model(模型)、View(视图)、Control(控制器)

  • 模型:模型持有所有的数据、状态和程序逻辑。模型独立于视图和控制器。

  • 视图:用来呈现模型。视图通常直接从模型中取得它需要显示的状态与数据。对于相同的信息可以有多个不同的显示形式或视图。

  • 控制器:位于视图和模型中间,负责接受用户的输入,将输入进行解析并反馈给模型

MVC模式将它们分离以提高系统的灵活性和复用性,不使用MVC模式,用户界面设计往往将这些对象混在一起。MVC模式实现了模型和视图的分离,使得其具有以下优点:

  • 一个模型提供不同的多个视图表现形式,也能够为一个模型创建新的视图而无须重写模型。一旦模型的数据发生变化,模型将通知有关的视图,每个视图相应地刷新自己。

  • 模型可复用。因为模型是独立于视图的,所以可以把一个模型独立地移植到新的平台工作。

  • 提高开发效率。在开发界面显示部分时,仅仅需要考虑的是如何布局一个好的用户界面;开发模型时,仅仅要考虑的是业务逻辑和数据维护,这样能使开发者专注于某一方面的开发,提高开发效率。

2. JSP 中的 MVC

在 JSP 中 Servlet 扮演的是控制器, JSP 页面扮演的是视图,Java Bean 扮演的是模型。

案例: 将用户信息呈现在页面上

  • 编写视图 user.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>显示用户信息</title>
</head>
<body>
    <a href="showUserInfo">显示用户信息</a>
</body>
</html>
  • 编写模型 User

package com.qf.jsp.pojo;

public class User {

    private String username;

    private String name;

    private String sex;

    private int age;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "User{" +
                "username='" + username + '\'' +
                ", name='" + name + '\'' +
                ", sex='" + sex + '\'' +
                ", age=" + age +
                '}';
    }
}
  • 编写控制器 UserInfoServlet

package com.qf.jsp.servlet;

import com.qf.jsp.pojo.User;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

public class UserInfoServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        User user = new User();
        user.setUsername("admin");
        user.setName("管理员");
        user.setSex("男");
        user.setAge(20);
        resp.setContentType("text/html;charset=utf-8");
        resp.setCharacterEncoding("UTF-8");
        PrintWriter writer = resp.getWriter();
        //告知视图需要展示的模型
        writer.print(user.toString());
        writer.flush();
        writer.close();
    }
}
  • 配置 web.xml

<servlet>
    <servlet-name>userInfoServlet</servlet-name>
    <servlet-class>com.qf.jsp.servlet.UserInfoServlet</servlet-class>
</servlet>

<servlet-mapping>
    <servlet-name>userInfoServlet</servlet-name>
    <url-pattern>/showUserInfo</url-pattern>
</servlet-mapping>

第三节 过滤器

1. 什么是过滤器

过滤器的概念过滤器是一个服务器端的组件,可以拦截客户端的请求和响应信息并对这些信息进行过滤。

2. 过滤器体系结构

  • 启动服务器,访问 user.jsp,然后测试

2.1 Filter接口
//过滤器初始化
default void init(FilterConfig filterConfig) throws ServletException {
}
//过滤操作,与协议无关
void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException;
//过滤器销毁
default void destroy() {
}
2.2 FilterConfig 接口
//获取过滤器实例的名称
String getFilterName();
//获取Servlet上下文
ServletContext getServletContext();
//从过滤器初始化配置中获取给定属性名对应的属性值
String getInitParameter(String parameterName);
//获取过滤器初始化配置中所有的属性名
Enumeration<String> getInitParameterNames();
2.3 案例

使用过滤器完成中文乱码处理

  • 编写过滤器 CharacterEncodingFilter

package com.qf.jsp.filter;

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

public class CharacterEncodingFilter implements Filter {

    private String characterEncoding;

    @Override
    public void init(FilterConfig config) throws ServletException {
        System.out.println("过滤器初始化");
        this.characterEncoding = config.getInitParameter("characterEncoding");
    }

    @Override
    public void doFilter(ServletRequest request,
                         ServletResponse response,
                         FilterChain chain)
            throws IOException, ServletException {
        System.out.println("过滤器过滤操作");
        request.setCharacterEncoding(characterEncoding);
        response.setCharacterEncoding(characterEncoding);
        //让过滤器链中的其他过滤器执行,这行代码必不可少,否则,无法进入后面的Servlet执行
        chain.doFilter(request, response);
    }

    @Override
    public void destroy() {
        System.out.println("过滤器销毁");
    }
}
  • 在 web.xml 中配置过滤器

<filter>
    <filter-name>characterEncodingFilter</filter-name>
    <filter-class>com.qf.jsp.filter.CharacterEncodingFilter</filter-class>
    <init-param>
        <param-name>characterEncoding</param-name>
        <param-value>UTF-8</param-value>
    </init-param>
</filter>

<filter-mapping>
    <filter-name>characterEncodingFilter</filter-name>
    <!-- * 标识通配符,匹配所有-->
    <url-pattern>/*</url-pattern>
</filter-mapping>
  • 测试

  • 结论

2.4 HttpFilter 抽象类
//重写无协议过滤器操作,调用下面支持HTTP协议请求过滤操作的方法
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {}
//HTTP协议请求过滤操作的方法
protected void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {}
2.5 案例

使用过滤器完成登录超时处理

  • 编写过滤器

package com.qf.jsp.filter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;

public class TimeoutFilter extends HttpFilter {

    @Override
    protected void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpSession session = request.getSession();
        Object username = session.getAttribute("username");
        //session中没有数据了,说明session已经过期了,当前的session是一个新的session
        if(username == null){
            //首页的地址 就是上下文路径
            String homePageUrl = request.getContextPath();
            if("".equalsIgnoreCase(homePageUrl)){//上下文路径为空字符串时给一条斜杠即可
                homePageUrl = "/";
            }
            response.sendRedirect(homePageUrl);
        } else {
            //让过滤器链中的其他过滤器执行,这行代码必不可少,否则,无法进入后面的Servlet执行
            chain.doFilter(request, response);
        }
    }
}
  • 在 web.xml 中配置过滤器

<filter>
    <filter-name>timeoutFilter</filter-name>
    <filter-class>com.qf.jsp.filter.TimeoutFilter</filter-class>
</filter>

<filter-mapping>
    <filter-name>timeoutFilter</filter-name>
    <!-- * 标识通配符,匹配所有-->
    <url-pattern>/*</url-pattern>
</filter-mapping>
2.6 Filter 交互流程

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1407110.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

leetcode 刷题2

二分查找的绝妙运用&#xff1a; 看到有序数列&#xff0c;算法复杂度 0033. 搜索旋转排序数组 class Solution { public:int search(vector<int>& nums, int target) {int left 0;int right nums.size() - 1;while (left < right) {int mid left (right - …

Debezium发布历史85

原文地址&#xff1a; https://debezium.io/blog/2020/03/05/db2-cdc-approaches/ 欢迎关注留言&#xff0c;我是收集整理小能手&#xff0c;工具翻译&#xff0c;仅供参考&#xff0c;笔芯笔芯. 运行 Db2 更改数据捕获的方法 2020 年 3 月 5 日 作者&#xff1a; Luis Garcs…

JanusGraph图数据库的应用以及知识图谱技术介绍

目录 JanusGraph介绍 JanusGraph 的主要优势 JanusGraph的应用&#xff1a; JanusGraph 的行业应用&#xff1a; 架构概览 分布式技术应用 横向扩展能力 程序与janus的交互 Janus与图数据库相关概念 结构化存储 图结构存储 实体关系存储 知识存储技术 JanusGraph介…

数据结构<1>——树状数组

树状数组&#xff0c;也叫Fenwick Tree和BIT(Binary Indexed Tree)&#xff0c;是一种支持单点修改和区间查询的&#xff0c;代码量小的数据结构。 那神马是单点修改和区间查询&#xff1f;我们来看一道题。 洛谷P3374(模板): 在本题中&#xff0c;单点修改就是将某一个数加上…

销售额稳居行业第二!苏州金龙2023年跑出高质量发展加速度

2023年&#xff0c;苏州金龙海格客车销量同比去年增25.75%&#xff0c;实现销售11453辆、销售额78亿元的业绩&#xff0c;稳居行业第二位&#xff0c;更跑赢行业大盘&#xff01; 聚焦主业&#xff0c;及时呼应客户需求&#xff1b;聚力新能源技术提升&#xff0c;抓住商用车价…

LabVIEW高级CAN通信系统

LabVIEW高级CAN通信系统 在现代卫星通信和数据处理领域&#xff0c;精确的数据管理和控制系统是至关重要的。设计了一个基于LabVIEW的CAN通信系统&#xff0c;它结合了FPGA技术和LabVIEW软件&#xff0c;主要应用于模拟卫星平台的数据交换。这个系统的设计不仅充分体现了FPGA在…

时间序列大模型:TimeGPT

论文&#xff1a;https://arxiv.org/pdf/2310.03589.pdf TimeGPT&#xff0c;这是第一个用于时间序列的基础模型&#xff0c;能够为训练期间未见过的多样化数据集生成准确的预测。 大规模时间序列模型通过利用当代深度学习进步的能力&#xff0c;使精确预测和减少不确定性成为…

光流估计概念和算法

什么是光流&#xff1f; 光流就是物体和观测者之间的互相运动&#xff0c;亮度变化的速度矢量&#xff0c;下图两张图片表示了光流的原理。 光流的算法有几个基本不变的假设&#xff1a; 1&#xff0c;光强不变假设&#xff1b; 一元的n阶泰勒公式&#xff1a; 在这里插入图…

Mysql复习1--理论基础+操作实践--更新中

Mysql 索引索引的分类 索引InnoDB引擎MyISAM引擎Memory引擎Btree索引支持支持支持hash索引不支持不支持支持R-tree索引不支持支持不支持Full-text索引5.6版本以后支持支持不支持 索引 解释说明: 索引指的是帮助mysql高效的获取数据的结构叫做索引(有序) 没有建立索引的时候–…

Shell 虚拟机基线配置脚本示例

这是一个配置虚拟机基线的示例&#xff0c;包含关闭防火墙、禁用SElinux、设置时区、安装基础软件等。 这只是一个简单的模板&#xff0c;基线配置方面有很多&#xff0c;后续可以按照这个模板去逐步添加 代码示例 [rootbogon ~]# cat bastic.sh #!/bin/bashRED\E[1;31m GRE…

微信万能表单源码系统:自定义表单内容+自由创建多表单 附带完整的代码包以及安装部署教程

在当今信息化社会&#xff0c;在线表单已经成为收集、处理数据的重要工具。无论是企业还是个人&#xff0c;都需要通过表单来进行信息的收集、调查、报名等操作。然而&#xff0c;传统的表单系统往往功能单一&#xff0c;无法满足复杂多变的需求。为了解决这一问题&#xff0c;…

Hadoop3完全分布式搭建

一、第一台的操作搭建 修改主机名 使用hostnamectl set-hostname 修改当前主机名 关闭防火墙和SELlinux 1&#xff0c;使用 systemctl stop firewalld systemctl disable firewalld 关闭防火墙 2&#xff0c;使用 vim /etc/selinux/config 修改为 SELINUXdisabled 使用N…

【操作系统】实验五 添加内核模块

&#x1f57a;作者&#xff1a; 主页 我的专栏C语言从0到1探秘C数据结构从0到1探秘Linux &#x1f618;欢迎关注&#xff1a;&#x1f44d;点赞&#x1f64c;收藏✍️留言 &#x1f3c7;码字不易&#xff0c;你的&#x1f44d;点赞&#x1f64c;收藏❤️关注对我真的很重要&…

《Linux设备驱动开发详解》读书笔记

《Linux设备驱动开发详解》读书笔记 本书主要介绍linux设备驱动开发的方法&#xff0c;共有21章&#xff1a; linux设备驱动概述及开发环境搭建驱动设计的硬件基础linux内核及内核编程linux内核模块linux文件系统与设备文件字符设备驱动linux设备驱动中的并发控制linux设备驱…

Stable Diffusion学习

参考 Stable Diffusion原理详解_stable diffusion csdn-CSDN博客 Stable Diffusion是stability.ai开源的图像生成模型&#xff0c;可以说Stable Diffusion的发布将AI图像生成提高到了全新高度&#xff0c;其效果和影响不亚于Open AI发布ChatGPT。 图像生成的发展 在Stable D…

代码随想录算法训练营第41天|343. 整数拆分、96.不同的二叉搜索树

文章目录 343. 整数拆分思路代码 96.不同的二叉搜索树思路代码 343. 整数拆分 题目链接&#xff1a;343. 整数拆分 文章讲解&#xff1a;代码随想录|343. 整数拆分 视频讲解&#xff1a;整数拆分 思路 1.dp[i]:整数i拆分成k个数的最大乘积 2.dp[i] max(dp[i], max((i - j) *…

DAY08_SpringBoot—整合Mybatis-Plus

目录 1 MybatisPlus1.1 MP介绍1.2 MP的特点1.3 MybatisPlus入门案例1.3.1 导入jar包1.3.2 编辑POJO对象1.3.3 编辑Mapper接口1.3.4 编译YML配置文件1.3.5 编辑测试案例 1.4 MP核心原理1.4.1 需求1.4.2 原理说明1.4.3 对象转化Sql原理 1.5 MP常规操作1.5.1 添加日志打印1.5.2 测…

unity刷新grid,列表

获取UIGrid 组件&#xff0c;更新列表 listParent.GetComponent().repositionNow true;

书生·浦语大模型--第四节课笔记--XTuner大模型单卡低成本微调

文章目录 Finetune简介指令跟随微调增量预训练微调LoRA QLoRA XTuner介绍快速上手 8GB显卡玩转LLM动手实战环节 Finetune简介 增量预训练和指令跟随 通过指令微调获得instructed LLM 指令跟随微调 一问一答的方式进行 对话模板 计算损失 增量预训练微调 不需要问题只…

C++高精度问题

高精度前言 C中int不能超过2^31-1&#xff0c;最长的long long也不能超过2^63-1,所以我们在题目中如果碰到了很长很长的数&#xff0c;并且需要进行大数运算时&#xff0c;就需要高精度存储。 高精度总体思路 由于int和long long的限制&#xff0c;我们要想存放很长的数就需…