JavaWeb笔记

JavaWeb简介

**什么是JavaWeb:**JavaWeb 是指,所有通过 Java 语言编写可以通过浏览器访问的程序的总称,叫 JavaWeb。

是基于请求和响应来开发的。

什么是请求: 请求是指客户端给服务器发送数据,叫请求 Request。

什么是响应: 响应是指服务器给客户端回传数据,叫响应 Response。

请求和响应的关系: 请求和响应是成对出现的,有请求就有响应。

Web资源: 静态资源: html、css、js、txt、mp4 视频 , jpg 图片

​ 动态资源: jsp 页面、Servlet 程序

常用的Web服务器: Tomcat: Apache 提供的一种 Web 服务器,提供对 jsp 和 Servlet 的支持。是一种轻量级的 javaWeb 服务

器,也是当前应用最广的 JavaWeb 服务器。

Jboss:是一个遵从 JavaEE 规范的、开放源代码的、纯 Java 的 EJB 服务器,支持所有的 JavaEE 规范(免费)。

GlassFish: Oracle 公司开发的 JavaWeb 服务器(应用很少)。

Resin:是 CAUCHO 公司的产品对 servlet 和 JSP 提供了良好的支持,resin 自身采用 JAVA 语言开发(收费,应用比较多)。

WebLogic:是 Oracle 公司的产品,是目前应用最广泛的 Web 服务器,支持 JavaEE 规范,

而且不断的完善以适应新的开发要求,适合大型项目(收费,适合大公司)。

Tomcat

Tomcat的使用

目录介绍

  1. bin

    专门用来存放 Tomcat 服务器的可执行程序

  2. conf

    专门用来存放 Tocmat 服务器的配置文件

  3. lib
    专门用来存放 Tomcat 服务器的 jar 包

  4. logs

    专门用来存放 Tomcat 服务器运行时输出的日记信息

  5. temp

    专门用来存放 Tomcdat 运行时产生的临时数据

  6. webapps

    专门用来存放部署的 Web 工程。

  7. work

    是Tomcat 工作时的目录,用来存放 Tomcat 运行时 jsp 翻译为

如何启动Tomcat服务器

找到 Tomcat 目录下的 bin 目录下的 startup.bat 文件,双击,就可以启动 Tomcat 服务器。

如何测试 Tomcat 服务器启动成功???

打开浏览器,在浏览器地址栏中输入以下地址测试:

1、http://localhost:8080

2、http://127.0.0.1:8080

3、http://真实 ip:8080

当出现如下界面,说明 Tomcat 服务器启动成功!!!

常见的启动失败的情况有,双击 startup.bat 文件会出现一个黑窗口哦一闪而过。

这个时候,失败的原因基本上都是因为没有配置好 JAVA_HOME 环境变量。

xml

什么是xml

xml 是可扩展的标记性语言。

xml的作用

xml 的主要作用有:

  1. 用来保存数据,而且这些数据具有自我描述性

  2. 它还可以做为项目或者模块的配置文件

  3. 还可以做为网络传输数据的格式(现在 JSON 为主)。

xml语法

  1. 文档声明。

  2. 元素(标签)

  3. xml 属性

  4. xml 注释

  5. 文本区域

文档声明

<?xml version=*"1.0" encoding="UTF-8"?> xml 声明。 

<!-- xml 声明 version 是版本的意思 

encoding 是编码 --> 

而且这个<?xml 要连在一起写,否则会有报错 

属性

version 是版本号

encoding 是 xml 的文件编码

standalone=“yes/no” 表示这个 xml 文件是否是独立的 xml 文件

xml元素

xml 中的元素(标签)也 分成 单标签和双标签:

单标签

​ 格式: <标签名 属性=”值” 属性=”值” … />

双标签

​ 格式:< 标签名 属性=”值” 属性=”值” …>文本数据或子标签</标签名>

xml属性

xml 的标签属性和 html 的标签属性是非常类似的,属性可以提供元素的额外信息

在标签上可以书写属性:

一个标签上可以书写多个属性。每个属性的值必须使用 引号 引起来

的规则和标签的书写规则一致

语法规则

  1. 所有的xml元素都必须有关闭标签

  2. 对大小写敏感

  3. 必须正确嵌套

  4. 必须有根元素

    根元素就是顶级元素,

    没有父标签的元素,叫顶级元素。

    根元素是没有父标签的顶级元素,而且是唯一一个才行。

  5. xml属性值必须加引号

  6. 特殊字符在xml中需要转义

dom4j

需要使用 dom4j 就需要到 dom4j 官网下载 dom4j 的 jar 包。

官方文档在docs目录下的index.html文件

编程步骤

第一步: 先加载 xml 文件创建 Document 对象

第二步:通过 Document 对象拿到根元素对象

第三步:通过根元素.elelemts(标签名); 可以返回一个集合,这个集合里放着。所有你指定的标签名的元素对象

第四步:找到你想要修改、删除的子元素,进行相应在的操作

第五步,保存到硬盘上

xml文件代码:

<?xml version="1.0" encoding="UTF-8"?>
<books> 
    <book sn="SN12341232">
    <name>辟邪剑谱</name> <price>9.9</price>
<author>班主任</author>
    </book> <book sn="SN12341231"> 
    <name>葵花宝典</name>
    <price>99.99</price>
    <author>班长</author> 
    </book> 
</books>
遍历 标签 获取所有标签中的内容

第一步,通过创建 SAXReader 对象。来读取 xml 文件,获取 Document 对象

第二步,通过 Document 对象。拿到 XML 的根元素对象

第三步,通过根元素对象。获取所有的 book 标签对象

第四小,遍历每个 book 标签对象。然后获取到 book 标签对象内的每一个元素,再通过 getText() 方法拿到起始标签和结

束标签之间的文本内容

/** 读取 xml 文件中的内容 */ 
@Test public void readXML() throws DocumentException {
    // 第一步,通过创建 SAXReader 对象。来读取 xml 文件,获取 Document 对象 
    SAXReader reader = new SAXReader(); Document document = reader.read("src/books.xml"); 
    // 第二步,通过 Document 对象。拿到 XML 的根元素对象 
    Element root = document.getRootElement(); 
    // 打印测试 
    // Element.asXML() 它将当前元素转换成为 String 对象 
    // System.out.println( root.asXML() ); 
    // 第三步,通过根元素对象。获取所有的 book 标签对象 
    // Element.elements(标签名)它可以拿到当前元素下的指定的子元素的集合 
    List<Element> books = root.elements("book"); 
    // 第四小,遍历每个 book 标签对象。然后获取到 book 标签对象内的每一个元素, 
    for (Element book : books) { 
        // 测试 
        // System.out.println(book.asXML()); 
        // 拿到 book 下面的 name 元素对象 
        Element nameElement = book.element("name"); 
        // 拿到 book 下面的 price 元素对象 
        Element priceElement = book.element("price"); 
        // 拿到 book 下面的 author 元素对象 
        Element authorElement = book.element("author"); 
        // 再通过 getText() 方法拿到起始标签和结束标签之间的文本内容
        System.out.println("书名" + nameElement.getText() + " , 价格:" + priceElement.getText() + ", 作者:" + 							authorElement.getText()); } 
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZqYDgh5R-1637808790994)(C:\Users\11600\AppData\Roaming\Typora\typora-user-images\image-20211124153341064.png)]

Servlet

什么是Servlet

  1. Servlet 是 JavaEE 规范之一。规范就是接口

  2. Servlet 就 JavaWeb 三大组件之一。三大组件分别是:Servlet 程序、Filter 过滤器、Listener 监听器。

  3. Servlet 是运行在服务器上的一个 java 小程序,它可以接收客户端发送过来的请求,并响应数据给客户端。

Servlet程序

public class HelloServlet implements Servlet {

    public HelloServlet1(){
        System.out.println("第一步,构造器方法");
    }

    @Override
    public void init(ServletConfig servletConfig) throws ServletException {
        /* ServletConfig:
        *   1.可以获取Servlet程序的别名servlet-name的值
        *       getServletName()
        *   2.获取初始化参数init-param
        *       getInitParameter()
        *   3.获取ServletContext对象
        *       getServletContext()
        * */

        System.out.println("第二步,初始化方法");
    }

    @Override
    public ServletConfig getServletConfig() {
        return null;
    }

    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
      //获取请求类型的方式(GET/POST)
/*      HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
        String method = httpServletRequest.getMethod();
        System.out.println(method);*/
        System.out.println("第三步");
    }

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

    @Override
    public void destroy() {
        System.out.println("第四步");
    }
}

通过继承httpServlet实现Servlet程序

一般在实际项目开发中,都是使用继承 HttpServlet 类的方式去实现 Servlet 程序。

  1. 编写一个类去继承 HttpServlet 类

  2. 根据业务需要重写 doGet 或 doPost 方法

  3. 到 web.xml 中的配置 Servlet 程序的访问地址

post请求和get请求分别会调用不同的Servlet方法

@WebServlet(name = "helloServlet", value = "/hello-servlet")
public class HelloServlet extends HttpServlet { 
    /*** doGet()在 get 请求的时候调用 
    * @param req 
    * @param resp 
    * @throws ServletException 
    * @throws IOException */ 
    @Override 
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 
        System.out.println("HelloServlet2 的 doGet 方法"); 
    }
    /*** doPost()在 post 请求的时候调用 
    * @param req 
    * @param resp 
    * @throws ServletException 
    * @throws IOException */ 
    @Override 
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("HelloServlet2 的 doPost 方法"); 
    } 
}

ServletConfig类

ServletConfig 类从类名上来看,就知道是 Servlet 程序的配置信息类。

Servlet 程序和 ServletConfig 对象都是由 Tomcat 负责创建,我们负责使用。

Servlet 程序默认是第一次访问的时候创建,ServletConfig 是每个 Servlet 程序创建时,就创建一个对应的 ServletConfig 对

象。

ServletConfig类的作用

  1. 可以获取 Servlet 程序的别名 servlet-name 的值

  2. 获取初始化参数 init-param

  3. 获取 ServletContext 对象

<!-- servlet 标签给 Tomcat 配置 Servlet 程序 -->
<servlet>
    <!--servlet-name 标签 Servlet 程序起一个别名(一般是类名) --> 
    <servlet-name>HelloServlet</servlet-name>
<!--servlet-class 是 Servlet 程序的全类名--> 
    <servlet-class>com.atguigu.servlet.HelloServlet</servlet-class>
    <!--init-param 是初始化参数-->
    <init-param>
        <!--是参数名-->
        <param-name>username</param-name>
        <!--是参数值-->
        <param-value>root</param-value>
    </init-param> 
    <!--init-param 是初始化参数-->
    <init-param>
        <!--是参数名-->
        <param-name>url</param-name>
        <!--是参数值-->
        <param-value>jdbc:mysql://localhost:3306/test</param-value>
    </init-param>
</servlet> 
<!--servlet-mapping 标签给 servlet 程序配置访问地址-->
<servlet-mapping>
    <!--servlet-name 标签的作用是告诉服务器,我当前配置的地址给哪个 Servlet 程序使用-->
    <servlet-name>HelloServlet</servlet-name>
    <!--url-pattern 标签配置访问地址 <br/> / 斜杠在服务器解析的时候,表示地址为:http://ip:port/工程路径 <br/> /hello 表示地址为:http://ip:port/工程路径/hello <br/> -->
    <url-pattern>/hello</url-pattern>
</servlet-mapping>

Servlet代码:

@Override public void init(ServletConfig servletConfig) throws ServletException {
    System.out.println("2 init 初始化方法");
    // 1、可以获取 Servlet 程序的别名 servlet-name 的值 
    System.out.println("HelloServlet 程序的别名是:" + servletConfig.getServletName());
    // 2、获取初始化参数
    init-param System.out.println("初始化参数 username 的值是;" + servletConfig.getInitParameter("username")); System.out.println("初始化参数 url 的值是;" + servletConfig.getInitParameter("url")); 
    // 3、获取 ServletContext 对象 
    System.out.println(servletConfig.getServletContext()); 
}

**注意:**重写的init方法里面一定要调用父类的init操作

ServletContext类

什么是ServletContext

  1. ServletContext 是一个接口,它表示 Servlet 上下文对象

  2. 一个 web 工程,只有一个 ServletContext 对象实例。

  3. ServletContext 对象是一个域对象。

  4. ServletContext 是在 web 工程部署启动的时候创建。在 web 工程停止的时候销毁。

什么是域对象?

域对象,是可以像 Map 一样存取数据的对象,叫域对象。

这里的域指的是存取数据的操作范围,整个 web 工程。

存数据取数据删除数据
mapput()get()remove()
域对象setAttribute()getAttribute()removeAttribute()

ServletContext类的作用

  1. 获取 web.xml 中配置的上下文参数 context-param

  2. 获取当前的工程路径,格式: /工程路径

  3. 获取工程部署后在服务器硬盘上的绝对路径

  4. 像 Map 一样存取数据

实例代码

public class ContextServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // ContextServlet的作用
        //1.获取web.xml中配置的上下文参数context-param
        ServletContext context = getServletConfig().getServletContext();
        String username = context.getInitParameter("username");
        System.out.println("username的值是:" + username);
        //2.获取当前工程路径
        String contextPath = context.getContextPath();
        System.out.println(contextPath);
        //3.获取工程部署后在服务器硬盘上的绝对路径
        System.out.println("工程部署路径是:" + context.getRealPath("/")); //D:\Java\Tomcat\Tomcat9\webapps\servlet_war\

        //4.像Map一样存储数据(在web工程部署的时候创建,停止的时候销毁,数据随之消失)
        context.setAttribute("key", "value");
        System.out.println("值为:" + context.getAttribute("key"));
    }
}

HTTP协议

什么是HTTP协议

什么是协议?

协议是指双方,或多方,相互约定好,大家都需要遵守的规则,叫协议。

所谓 HTTP 协议,就是指,客户端和服务器之间通信时,发送的数据,需要遵守的规则,叫 HTTP 协议。

HTTP 协议中的数据又叫报文。

请求的HTTP协议格式

客户端给服务器发送数据叫请求。

服务器给客户端回传数据叫响应。

请求又分为 GET 请求,和 POST 请求两种

GET请求
  1. 请求行

    1. 请求的方式 GET
    2. 请求的资源路径[+?+请求参数]
    3. 请求的协议的版本号 HTTP/1.1
  2. 请求头

    key : value 组成 不同的键值对,表示不同的含义。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xah2QwhC-1637808790995)(C:\Users\11600\AppData\Roaming\Typora\typora-user-images\image-20211124155943607.png)]

POST请求
  1. 请求行

    1. 请求的方式 POST
    2. 请求的资源路径[+?+请求参数]
    3. 请求的协议的版本号 HTTP/1.1
  2. 请求头 key : value 不同的请求头,有不同的含义

    空行

  3. 请求体 ===>>> 就是发送给服务器的数据

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lfaBET3l-1637808790996)(C:\Users\11600\AppData\Roaming\Typora\typora-user-images\image-20211124160151808.png)]

常用请求头的说明

Accept: 表示客户端可以接收的数据类型

Accpet-Languege: 表示客户端可以接收的语言类型

User-Agent: 表示客户端浏览器的信息

Host: 表示请求时的服务器 ip 和端口号

哪些是GET请求,哪些是POST请求

GET 请求有哪些:

  1. form 标签 method=get

  2. a 标签

  3. link 标签引入 css

  4. Script 标签引入 js 文件

  5. img 标签引入图片

  6. iframe 引入 html 页面

  7. 在浏览器地址栏中输入地址后敲回车

POST 请求有哪些:

  1. form 标签 method=post

响应的HTTP协议格式

  1. 响应行

    1. 响应的协议和版本号
    2. 响应状态码
    3. 响应状态描述符
  2. 响应头

    1. key : value
    2. 不同的响应头,有其不同含义

    空行

  3. 响应体

    1. 就是回传给客户端的数据

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Bw8SX1mm-1637808790997)(C:\Users\11600\AppData\Roaming\Typora\typora-user-images\image-20211124161242678.png)]

常用响应码说明

200 表示请求成功

302 表示请求重定向(明天讲)

404 表示请求服务器已经收到了,但是你要的数据不存在(请求地址错误)

500 表示服务器已经收到请求,但是服务器内部错误(代码错误)

HttpServletRequest类

HttpServletRequest类有什么作用

每次只要有请求进入 Tomcat 服务器,Tomcat 服务器就会把请求过来的 HTTP 协议信息解析好封装到 Request 对象中。

然后传递到 service 方法(doGet 和 doPost)中给我们使用。我们可以通过 HttpServletRequest 对象,获取到所有请求的

信息。

HttpServletRequest类有什么作用

方法名作用
i. getRequestURI()获取请求的资源路径
ii. getRequestURL()获取请求的统一资源定位符(绝对路径)
iii.getRemoteHost()获取客户端的 ip 地址
iv. getHeader()获取请求头
v. getParameter()获取请求的参数
vi. getParameterValues()获取请求的参数(多个值的时候使用)
vii. getMethod()获取请求的方式 GET 或 POST
viii. setAttribute(key, value);设置域数据
ix. getAttribute(key);获取域数据
x. getRequestDispatcher()获取请求转发对象

示例代码:

  <form action="http://localhost:8888/servlet_war_exploded/requestAPIServlet" method="get">
      用户名:<input type="text" name="username"><br/>
      密码:<input type="password" name="password"><br/>
      兴趣爱好:<input type="checkbox" name="hobby" value="cpp">C++
      <input type="checkbox" name="hobby" value="Java">Java
      <input type="checkbox" name="hobby" value="js">JavaScript
      <br/>
      <input type="submit">
  </form>
public class RequestAPIServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        /*
        * 1.getRequestURI()     获取请求的资源路径
        * 2.getRequestURL()     获取请求的统一资源定位符(绝对路径)
        * 3.getRemoteHost()     获取客户端ip地址
        * 4.getHeader()         获取请求头
        * 5.getMethod()         获取请求的方式GET或POST
        * */
        System.out.println(req.getRequestURI()); //servlet_war_exploded/requestAPIServlet
        System.out.println(req.getRequestURL()); //http://localhost:8888/servlet_war_exploded/requestAPIServlet
        System.out.println(req.getRemoteHost()); //0:0:0:0:0:0:0:1
        System.out.println(req.getHeader("User-Agent")); //Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36
        System.out.println(req.getMethod()); //GET

        //获取请求参数
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        String[] hobbies = req.getParameterValues("hobby");
        System.out.println("用户名:" + username);
        System.out.println("密码:" + password);
        System.out.println("兴趣:" + Arrays.asList(hobbies));
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //设置请求体的字符集为UTF-8,解决POST请求的中文乱码问题
        //需要在获取请求参数之前调用
        req.setCharacterEncoding("UTF-8");
    }
}

GET和POST请求中文乱码解决

get:

// 获取请求参数 
String username = req.getParameter("username"); 
//1 先以 iso8859-1 进行编码 
//2 再以 utf-8 进行解码
username = new String(username.getBytes("iso-8859-1"), "UTF-8");

post

// 设置请求体的字符集为 UTF-8,从而解决 post 请求的中文乱码问题
req.setCharacterEncoding("UTF-8");

HttpServletResponse类

HttpServletResponse类的作用

HttpServletResponse 类和 HttpServletRequest 类一样。每次请求进来,Tomcat 服务器都会创建一个 Response 对象传递给 Servlet 程序去使用。HttpServletRequest 表示请求过来的信息,HttpServletResponse 表示所有响应的信息,

我们如果需要设置返回给客户端的信息,都可以通过 HttpServletResponse 对象来进行设置

两个输出流的说明

方法作用
字节流getOutputStream();常用于下载(传递二进制数据)
字符流getWriter();常用于回传字符串(常用)

两个流同时只能使用一个。

使用了字节流,就不能再使用字符流,反之亦然,否则就会报错。

如何往客户端回传数据

public class ResponseAPIServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //设置服务器字符集和客户端浏览器浏览器字符集字符集(需要在获取流对象之前设置才有效)
        resp.setContentType("text/html;charset=UTF-8");
        //往客户端传递字符串信息
        PrintWriter writer = resp.getWriter();
        writer.write("沃尔夫斯堡");
    }
}

响应乱码解决方案:

//设置服务器字符集和客户端浏览器浏览器字符集字符集(需要在获取流对象之前设置才有效)
resp.setContentType("text/html;charset=UTF-8");

请求转发

什么是请求的转发?

请求转发是指,服务器收到请求后,从一次资源跳转到另一个资源的操作叫请求转发。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YFxrRZJ0-1637808790998)(C:\Users\11600\AppData\Roaming\Typora\typora-user-images\image-20211124162637550.png)]

Servlet1:

public class Servlet1 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //获取请求参数
        String username = req.getParameter("username");
        System.out.println("Servlet1中的参数" + username);

        //标记参数,传递到Servlet2中
        req.setAttribute("key", "Servlet1的标记");
        RequestDispatcher requestDispatcher = req.getRequestDispatcher("/servlet2");
        //前往Servlet2
        requestDispatcher.forward(req, resp);
    }
}

Servlet2:

public class Servlet2 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //获取请求参数
        String username = req.getParameter("username");
        System.out.println("Servlet2中的参数" + username);

        Object key = req.getAttribute("key");
        System.out.println("Servlet2:" + key);
    }
}

请求重定向

请求重定向,是指客户端给服务器发请求,然后服务器告诉客户端说。我给你一些地址。你去新地址访问。叫请求重定向(因为之前的地址可能已经被废弃)。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RMipgz3u-1637808790999)(C:\Users\11600\AppData\Roaming\Typora\typora-user-images\image-20211124163648910.png)]

设置方法:resp.sendRedirect(“http://locahost:8080”);

/* 请求重定向
    * 方法一:当Response1接口废弃时,浏览器访问这个接口需要告诉浏览器一个新的访问地址并且设置响应码302
    *       浏览器解析Response1的结果再次发起请求访问Response2接口
    *       特点:浏览器地址栏会发生变化
    *            两次请求
    *            不共享Response中的数据
    *            不能访问WEB-INF下的资源
    *            可以访问工程外的资源
    * 方法二(推荐):
* */

public class Response1 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("Response1");

        /*(方法一,不推荐使用)//设置响应状态码,表示重定向
        resp.setStatus(302);
        //设置响应头,说明新地址
        resp.setHeader("Location", "http://localhost:8888/servlet_war_exploded/response2");*/

        //方法二(推荐使用)
        resp.sendRedirect("http://localhost:8888/servlet_war_exploded/response2");
    }
}
public class Response2 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.getWriter().write("Response2...");
    }
}

Base标签

base标签可以设置当前页面所有相对路径使用时参照哪个路径来跳转

<!--写base标签,永远固定相对路径跳转的结果-->
<base href="http://localhost:8888/book/">

JSP

jsp 的全名是 java server pages。Java 的服务器页面。

jsp 的主要作用是代替 Servlet 程序回传 html 页面的数据。

因为 Servlet 程序回传 html 页面数据是一件非常繁锁的事情。开发成本和维护成本都极高

jsp的访问方式和html相同

jsp本质是一个Servlet程序

JSP语法

头部的page命令

jsp 的 page 指令可以修改 jsp 页面中一些重要的属性,或者行为。

<%@ page contentType="text/html;charset=UTF-8" language="java" %>

contentType 属性:

​ 表示 jsp 返回的数据类型是什么。也是源码中 response.setContentType()参数值

jsp常用脚本

声明脚本(使用少)
<%--
1.声明类属性
2.声明static静态代码块
3.声明类方法
4.声明内部类
--%>
    <%!
        private int id;
        private String name;
        private static Map map;
    %>

    <%!
        static {
            map = new HashMap();
            map.put("key1","value1");
            map.put("key2","value2");
        }
    %>

    <%!
        public void ex(){
            System.out.println(111);
        }
    %>

    <%!
        public static class A{
            private int id;
            private String name;
        }
    %>
表达式脚本
<%-- 表达式脚本
特点:都会被翻译到_jspService()方法中,都会被翻译为out.print()输出到页面上,
        _jspService()方法中的对象都可以直接使用,
    1.输出整型
    2.输出浮点型
    3.输出字符串
    4.输出对象
--%>
    <%= 12 %>
    <%= 12.12 %>
    <%= "字符串" %>
    <%= map %>
    <%=request.getParameter("username")%>
代码脚本
<%-- 代码脚本
作用:可以在jsp页面中编写自己需要的功能(java语句)
特点:代码脚本翻译之后都在_jspService()方法中
     代码脚本由于翻译到_jspService()方法中,所以在_jspService()方法中的现有对象都可以使用
     可以由多个代码脚本块组合完成一个java语句
if语句,for循环,在_jspService()方法内可以写的在代码脚本中都可以写
--%>
    <%
        if (true){
            System.out.println(true);
        }
        for (int i = 0; i < 10; i++) {
            System.out.print(i);
        }
    %>
    <%--代码脚本块组合:--%>
    <table border="1" cellspacing="0"></table>
    <%
        for (int i = 0; i < 10; i++) {
    %>
        <tr>
            <td>第<%= i + 1%>行</td>
        </tr>
    <%
        }
    %>

jsp九大内置对象

对象名称作用
request 对象 请求对象可以获取请求信息
response 对象 响应对象可以设置响应信息
pageContext 对象 当前页面上下文对象可以在当前上下文保存属性信息
session 对象 会话对象可以获取会话信息
exception 对象异常对象只有在 jsp 页面的 page 指令中设置 isErrorPage=“true” 的时候才会存在
application 对象ServletContext 对象实例,可以获取整个工程的一些信息
config 对象ServletConfig 对象实例,可以获取 Servlet 的配置信息
out 对象输出流
page 对象表示当前 Servlet 对象实例(无用,用它不如使用 this 对象)

jsp四大域对象

对象名称作用
pageContext (PageContextImpl 类)可以保存数据在同一个 jsp 页面中使用,其它jsp页面访问不了
request (HttpServletRequest 类)可以保存数据在同一个 request 对象中使用。经常用于在转发的时候传递数据
session (HttpSession 类)可以保存在一个会话中使用,浏览器不关闭数据就存在
application (ServletContext类)就是 ServletContext 对象,服务器不关闭数据就不会销毁

域对象是可以像 Map 一样存取数据的对象。四个域对象功能一样。不同的是它们对数据的存取范围。

虽然四个域对象都可以存取数据。在使用上它们是有优先顺序的。

四个域在使用的时候,优先顺序分别是,他们从小到大的范围的顺序。

pageContext ====>>> request ====>>> session ====>>> application

jsp中out输出和response.getWriter输出的区别

response 中表示响应,我们经常用于设置返回给客户端的内容(输出)out 也是给用户做输出使用的。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uXIwaQ9b-1637808791000)(C:\Users\11600\AppData\Roaming\Typora\typora-user-images\image-20211124170001698.png)]

<%-- jsp中out输出流和response.getWriter()输出流
    所有jsp中out输出流的内容都必须要先flush(清楚缓冲区)写入到Response的writer对象的缓冲区中,才能输出到客户端
    而jsp的out输出到Response的Writer对象的缓冲区,永远是追加到writer缓冲区的末尾
--%>

jsp常用标签

静态包含

<%-- 静态包含(常用)
    <%@include file=""%>
    file属性指定要包含的jsp页面

特点: 静态包含不会翻译被包含的jsp页面
      静态包含其实就是把被包含的jsp页面的代码拷贝到包含的位置执行输出
--%>
<%@include file="/"%>

动态包含

<%-- 动态包含
    <jsp:include page="/"></jsp:include>
    page属性指定要包含的jsp页面的路径
    动态包含也可以想静态包含一样,把被包含的内容执行输出到包含位置
特点:会把包含的jsp页面也翻译成java代码
     底层代码使用如下代码去调用被包含的jsp页面执行输出
        JspRuntimeLibary.include(request,response,"/...",out,false);
        回向路径页面传递request,response,out对象给页面使用
     还可以传递参数
--%>
<jsp:include page="index.jsp">
    <jsp:param name="username" value="lzy"/>
</jsp:include>

动态包含底层原理:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oPbyyNl8-1637808791001)(C:\Users\11600\AppData\Roaming\Typora\typora-user-images\image-20211124170234167.png)]

请求转发标签

<%-- 请求转发标签
    <jsp:forward page=""></jsp:forward>
--%>
<jsp:forward page="index.jsp"></jsp:forward>

Listener监听器

  1. Listener 监听器它是 JavaWeb 的三大组件之一。JavaWeb 的三大组件分别是:Servlet 程序、Filter 过滤器、Listener 监

听器。

  1. Listener 它是 JavaEE 的规范,就是接口

  2. 监听器的作用是,监听某种事物的变化。然后通过回调函数,反馈给客户(程序)去做一些相应的处理。

ServletContextListener监听器

ServletContextListener 它可以监听 ServletContext 对象的创建和销毁。

ServletContext 对象在 web 工程启动的时候创建,在 web 工程停止的时候销毁。

监听到创建和销毁之后都会分别调用 ServletContextListener 监听器的方法反馈。

public class MyServletContextListenerImpl implements ServletContextListener {
    @Override
    public void contextInitialized(ServletContextEvent sce) {
        System.out.println("ServletContext被创建了");
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        System.out.println("ServletContext被销毁了");
    }
}

如何使用 ServletContextListener 监听器监听 ServletContext 对象。

使用步骤如下:

  1. 编写一个类去实现 ServletContextListener

  2. 实现其两个回调方法

  3. 到 web.xml 中去配置监听器

web.xml 中的配置:

<listener>
    <listener-class>com.example.Listener.MyServletContextListenerImpl</listener-class>
</listener>

EL表达式

EL表达式的作用

EL 表达式的全称是:Expression Language。是表达式语言。

EL 表达式的什么作用:EL 表达式主要是代替 jsp 页面中的表达式脚本在 jsp 页面中进行数据的输出。

因为 EL 表达式在输出数据的时候,要比 jsp 的表达式脚本要简洁很多。

<%
    request.setAttribute("key", "value");
%>
表达式输出key的值是:<%=request.getParameter("key1")==null ? "" : request.getParameter("key1")%>
EL表达式输出的值:${key1}
${empty key} -- 不为空,false
注:如果查询的结果是null,EL会输出空串,表达式会输出null(不希望)

EL表达式搜索域顺序

EL 表达式主要是在 jsp 页面中输出数据。

主要是输出域对象中的数据。

当四个域中都有相同的 key 的数据的时候,EL 表达式会按照四个域的从小到大的顺序去进行搜索,找到就输出。

EL表达式的11个隐含对象

变量类型作用
pageContextPageContextImpl它可以获取 jsp 中的九大内置对象
pageScopeMap<String,Object>它可以获取 pageContext 域中的数据
requestScopeMap<String,Object>它可以获取 Request 域中的数据
sessionScopeMap<String,Object>它可以获取 Session 域中的数据
applicationScopeMap<String,Object>它可以获取 ServletContext 域中的数据
paramMap<String,String>它可以获取请求参数的值
paramValuesMap<String,String[]>它也可以获取请求参数的值,获取多个值的时候使用。
headerMap<String,String>它可以获取请求头的信息
headerValuesMap<String,String[]>它可以获取请求头的信息,它可以获取多个值的情况
cookieMap<String,Cookie>它可以获取当前请求的 Cookie 信息
initParamMap<String,String>它可以获取在 web.xml 中配置的上下文参数

获取四个特定域中的属性

pageScope ====== pageContext 域 
requestScope ====== Request 域 
sessionScope ====== Session 域 
applicationScope ====== ServletContext 域
<%
    pageContext.setAttribute("key2", "pageContext2");
    request.setAttribute("key2", "request");
    session.setAttribute("key2", "session");
    application.setAttribute("key2", "application"); 
%>
    ${ applicationScope.key2 }

pageContext对象的使用

  1. 协议

  2. 服务器 ip

  3. 服务器端口

  4. 获取工程路径

  5. 获取请求方法

  6. 获取客户端 ip 地址

  7. 获取会话的 id 编号

pageContext:
<%-- 
    request.getScheme() 它可以获取请求的协议
    request.getServerName() 获取请求的服务器 ip 或域名
    request.getServerPort() 获取请求的服务器端口号
    getContextPath() 获取当前工程路径
    request.getMethod() 获取请求的方式(GET 或 POST)
    request.getRemoteHost() 获取客户端的 ip 地址
session.getId() 获取会话的唯一标识
--%>
<% pageContext.setAttribute("req", request); %>
<%=request.getScheme() %> <br>
1.协议: ${ req.scheme }<br>
2.服务器 ip:${ pageContext.request.serverName }<br>
3.服务器端口:${ pageContext.request.serverPort }<br>
4.获取工程路径:${ pageContext.request.contextPath }<br>
5.获取请求方法:${ pageContext.request.method }<br>
6.获取客户端 ip 地址:${ pageContext.request.remoteHost }<br>
7.获取会话的 id 编号:${ pageContext.session.id }<br>

EL 表达式其他隐含对象的使用

param、paramValues:
输出请求参数 username 的值:${ param.username } <br>
输出请求参数 password 的值:${ param.password } <br>
输出请求参数 username 的值:${ paramValues.username[0] } <br>
输出请求参数 hobby 的值:${ paramValues.hobby[0] } <br>
输出请求参数 hobby 的值:${ paramValues.hobby[1] } <br>

输出请求头【User-Agent】的值:${ header['User-Agent'] } <br>
输出请求头【Connection】的值:${ header.Connection } <br>
输出请求头【User-Agent】的值:${ headerValues['User-Agent'][0] } <br>

header、headerValues:
输出请求头【User-Agent】的值:${ header['User-Agent'] } <br> 
输出请求头【Connection】的值:${ header.Connection } <br> 
输出请求头【User-Agent】的值:${ headerValues['User-Agent'][0] }<br>

cookie:
获取 Cookie 的名称:${ cookie.JSESSIONID.name } <br>
获取 Cookie 的值:${ cookie.JSESSIONID.value } <br>

JSTL标签库

JSTL 标签库 全称是指 JSP Standard Tag Library JSP 标准标签库。是一个不断完善的开放源代码的 JSP 标签库。

EL 表达式主要是为了替换 jsp 中的表达式脚本,而标签库则是为了替换代码脚本。这样使得整个 jsp 页面变得更佳简洁。

使用步骤

1.导入jstl的jar包
2.使用taglib指令引入标签库

核心库使用

<c:set/> 作用:set标签可以往域中保存数据 (使用少)
         使用:域对象.setAttribute(key,value);
                scope属性设置保存到哪个域
                page表示PageContext域(默认值)
                request表示Request域
                session表示Session域
                application表示ServletContext域
                var属性设置key值
                value属性设置value值
<c:if test=""/> 作用:用来做if判断
                test属性表示判断的条件(使用EL表达式)如果表达式成立则执行标签内的语句
<c:choose> <c:when> <c:otherwise> 作用:多路判断,相当于if else
    choose开始判断
    when表示判断每一种情况,test表示判断的内容
    otherwise表示剩下的情况
    注意:标签里面不能使用HTML注释,可以用jsp注释
          when标签的父标签一定是choose标签

<c:forEach begin="" end=""> 遍历操作
    begin属性设置开始的索引
    end属性设置结束的索引
    var属性表示循环的变量
    step表示步长值,1相当于i++
    varStatus表示当前遍历到的数据的状态
    遍历数组:for(Object item : arr)
                item表示被遍历的数据
                var表示遍历到的数据
--%>
<%--set--%>
    <c:set scope="page" var="key" value="value"/>

<%--if--%>
    <c:if test="10 == 10">
        <h1>相等</h1>
    </c:if>

<%--choose,when,otherwise--%>
    <%
        request.setAttribute("height", 185);
    %>
    <c:choose>
        <c:when test="${ requestScope.height > 190}">
            <h2>身高大于190</h2>
        </c:when>
        <c:when test="${ requestScope.height > 180}">
            <h2>身高大于180</h2>
        </c:when>
        <c:otherwise>
            <h2>身高小于180</h2>
        </c:otherwise>
    </c:choose>

<%--forEach--%>
    <c:forEach begin="1" end="10" var="i">
        ${i}
    </c:forEach>
    <%
        request.setAttribute("arr", new String[]{"qq", "ww", "ee"});
    %>
    <c:forEach items="${requestScope.arr}" var="items">
        ${items}
    </c:forEach>
    <%
        Map<String , Object> map = new HashMap<>();
        map.put("key1","value1");
        map.put("key2","value2");
        map.put("key3","value3");
        request.setAttribute("map", map);
    %>
    <c:forEach items="${requestScope.map}" var="m">
        ${m.key}
    </c:forEach>

Cookie&Session

Cookie

什么是Cookie

  1. Cookie 是服务器通知客户端保存键值对的一种技术。

  2. 客户端有了 Cookie 后,每次请求都发送给服务器。

  3. 每个 Cookie 的大小不能超过 4kb

Cookie的增删改

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-N292rJDK-1637808791002)(C:\Users\11600\AppData\Roaming\Typora\typora-user-images\image-20211124190802144.png)]

public class CookieServlet extends BaseServlet {

    protected void createCookie(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //创建Cookie对象
        Cookie cookie = new Cookie("key1", "value1");
        Cookie cookie2 = new Cookie("key2", "value2");
        //通知客户端保存cookie
        resp.addCookie(cookie);
        resp.addCookie(cookie2);
        resp.getWriter().write("Cookie创建成功");
    }

    protected void getCookie(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //得到需要的Cookie值
        Cookie[] cookies = req.getCookies();
        for (Cookie cookie : cookies) {
            //getName():返回cookie的key,getValue():返回cookie的value
            resp.getWriter().write("Cookie[" + cookie.getName() + "=" + cookie.getValue() + "]<br/>");
        }
        Cookie iWantCookie = CookieUtils.findCookie("key1", cookies);
        if (iWantCookie != null) {
            resp.getWriter().write("找到了需要的Cookie");
        }
    }

    protected void updateCookie(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //方案一:Cookie值的修改,客户端有则修改,没有则创建
//        Cookie cookie = new Cookie("key1", "newValue1");
//        resp.addCookie(cookie);

        //方案二
        //找到需要修改的Cookie
        Cookie cookie = CookieUtils.findCookie("key2", req.getCookies());
        if (cookie != null) {
            //调用setValue()赋予新的值
            cookie.setValue("newValue2");
            resp.addCookie(cookie);
        }
    }

    protected void defaultLifeCookie(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        Cookie cookie = new Cookie("key4", "value4");
        cookie.setMaxAge(-1); //设置存活时间,默认值
        resp.addCookie(cookie);
        resp.getWriter().write("默认值设置成功");
    }

    protected void nowDeleteCookie(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        Cookie cookie = CookieUtils.findCookie("key1", req.getCookies());
        if (cookie != null) {
            cookie.setMaxAge(0);//设置存活时间
            resp.addCookie(cookie);
        }
        resp.getWriter().write("key1的Cookie被删除");
    }

    protected void Life3600Cookie(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        Cookie cookie = new Cookie("key3", "value3");
        cookie.setMaxAge(60 * 60); //设置存活时间
        resp.addCookie(cookie);
        resp.getWriter().write("一小时设置成功");
    }

    protected void setPath(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        Cookie cookie = new Cookie("key5", "value5");
        cookie.setPath(req.getContextPath() + "/abc"); //工程路径/abc
        resp.addCookie(cookie);
        resp.getWriter().write("创建了一个带有Path的Cookie");
    }
}

Cookie的生命控制

Cookie 的生命控制指的是如何管理 Cookie 什么时候被销毁(删除)

setMaxAge()

  1. 正数,表示在指定的秒数后过期

  2. 负数,表示浏览器一关,Cookie 就会被删除(默认值是-1)

  3. 零,表示马上删除 Cookie

Session

什么是Session会话

  1. Session 就一个接口(HttpSession)。

  2. Session 就是会话。它是用来维护一个客户端和服务器之间关联的一种技术。

  3. 每个客户端都有自己的一个 Session 会话。

  4. Session 会话中,我们经常用来保存用户登录之后的信息。

如何创建和获取Session

如何创建和获取 Session。它们的 API 是一样的。 
request.getSession() 
	第一次调用是:创建 Session 会话 
	之后调用都是:获取前面创建好的 Session 会话对象。 
isNew(); 判断到底是不是刚创建出来的(新的) 
	true 表示刚创建 
	false 表示获取之前创建 
每个会话都有一个身份证号。也就是 ID 值。而且这个 ID 是唯一的。 
getId() 得到 Session 的会话 id 值。

Session域数据的存取

public class SessionServlet extends BaseServlet {

    protected void createAndGetSession(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //创建和获取Session对象
        HttpSession session = req.getSession();
        //判断当前Session会话是否是新创建的
        boolean isNew = session.isNew();
        //获取Session会话的唯一标识id
        String id = session.getId();

        resp.getWriter().write("得到的Session id为:" + id + "<br/>");
        resp.getWriter().write("得到的Session 是否是新创建的:" + isNew + "<br/>");
    }

    protected void setAttribute(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //设置session的值
        req.getSession().setAttribute("key1", "value1");
        resp.getWriter().write("保存成功");
    }

    protected void getAttribute(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //获取session的值
        Object key1 = req.getSession().getAttribute("key1");
        resp.getWriter().write("取出的数据为:" + key1);
    }

    protected void defaultLifeSession(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //设置Session的默认超时时长
        int maxInactiveInterval = req.getSession().getMaxInactiveInterval();
        resp.getWriter().write("Session的默认超时时长:" + maxInactiveInterval);
    }

    protected void setLifeSession(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        HttpSession session = req.getSession();
        //设置当前session三秒后超时(指的是触发后三秒内客户端不发请求则销毁当前session)、负数表示永不超时(少用)
        session.setMaxInactiveInterval(3);
        resp.getWriter().write("设置3秒后超时成功");
    }

    protected void deleteNowSession(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        HttpSession session = req.getSession();
        //让会话马上超时
        session.invalidate();
        resp.getWriter().write("设置立即销毁成功");

    }

}

Session生命周期控制

public void setMaxInactiveInterval(int interval) 设置 Session 的超时时间(以秒为单位),超过指定的时长,Session就会被销毁。

​ 值为正数的时候,设定 Session 的超时时长。

​ 负数表示永不超时(极少使用)

public int getMaxInactiveInterval()获取 Session 的超时时间

public void invalidate() 让当前 Session 会话马上超时无效。

Session 默认的超时时间长为 30 分钟。

因为在 Tomcat 服务器的配置文件 web.xml中默认有以下的配置,它就表示配置了当前 Tomcat 服务器下所有的 Session

超时配置默认时长为:30 分钟。

30

以上相同的配置。就可以修改你的 web 工程所有 Seession 的默认超时时长。 

*<!--**表示当前* *web* *工程。创建出来 的所有* *Session* *默认是* *20* *分钟 超时时长**-->* 

<**session-config**> 

<**session-timeout**>20</**session-timeout**> 

</**session-config**>

如果你想只修改个别 Session 的超时时长。就可以使用上面的 API。setMaxInactiveInterval(int interval)来进行单独的设置。

session.setMaxInactiveInterval(int interval)单独设置超时时长。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-e6UeOZR1-1637808791003)(C:\Users\11600\AppData\Roaming\Typora\typora-user-images\image-20211124192904501.png)]

浏览器和 Session 之间关联的技术内幕

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1PpT9Ilv-1637808791004)(C:\Users\11600\AppData\Roaming\Typora\typora-user-images\image-20211124193004642.png)]

Filter过滤器

Filter过滤器简介

  1. Filter 过滤器它是 JavaWeb 的三大组件之一。三大组件分别是:Servlet 程序、Listener 监听器、Filter 过滤器

  2. Filter 过滤器它是 JavaEE 的规范。也就是接口

  3. Filter 过滤器它的作用是:拦截请求,过滤响应。

拦截请求常见的应用场景有:

  1. 权限检查

  2. 日记操作

  3. 事务管理

    ……等等

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kszyl2e8-1637808791005)(C:\Users\11600\AppData\Roaming\Typora\typora-user-images\image-20211125100714663.png)]

Filter代码

public class AdminFilter implements Filter {

    public AdminFilter(){
        System.out.println("Filter过滤器方法");
    }

    /**
     * FilterConfig初始化
     * @param filterConfig
     * @throws ServletException
     */
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        //获取Filter的名称Filter-name的内容
        String filterName = filterConfig.getFilterName();
        //获取在web.xml中配置的init-param初始化参数
        String username = filterConfig.getInitParameter("username");
        String url = filterConfig.getInitParameter("url");
        //获取ServletContext对象
        System.out.println(filterConfig.getServletContext());
    }

    /**
     * 专门用于拦截请求,可做权限检查
     * @param servletRequest
     * @param servletResponse
     * @param filterChain
     * @throws IOException
     * @throws ServletException
     */
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
        HttpSession session = httpServletRequest.getSession();
        Object user = session.getAttribute("user");
        if (user == null){
            //用户还未登录,请求转发到登录页面
            servletRequest.getRequestDispatcher("/login.jsp").forward(servletRequest, servletResponse);
            return;
        }

    }

    @Override
    public void destroy() {
        Filter.super.destroy();
    }
}

Filter生命周期

Filter 的生命周期包含几个方法

  1. 构造器方法

  2. init 初始化方法

    第 1,2 步,在 web 工程启动的时候执行(Filter 已经创建)

  3. doFilter 过滤方法

    第 3 步,每次拦截到请求,就会执行

  4. destroy 销毁

    第 4 步,停止 web 工程的时候,就会执行(停止 web 工程,也会销毁 Filter 过滤器)

FilterConfig类

FilterConfig 类见名知义,它是 Filter 过滤器的配置文件类。

Tomcat 每次创建 Filter 的时候,也会同时创建一个 FilterConfig 类,这里包含了 Filter 配置文件的配置信息。

FilterConfig 类的作用是获取 filter 过滤器的配置内容

  1. 获取 Filter 的名称 filter-name 的内容

  2. 获取在 Filter 中配置的 init-param 初始化参数

  3. 获取 ServletContext 对象

FilterChain过滤器链

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PPCn8OIZ-1637808791005)(C:\Users\11600\AppData\Roaming\Typora\typora-user-images\image-20211125101054391.png)]

Filter拦截器

精确匹配

<url-pattern>/target.jsp</url-pattern>

以上配置的路径,表示请求地址必须为:http://ip:port/工程路径/target.jsp

目录匹配

<url-pattern>/admin/*</url-pattern>

以上配置的路径,表示请求地址必须为:http://ip:port/工程路径/admin/*

后缀名匹配

<url-pattern>*.html</url-pattern>

以上配置的路径,表示请求地址必须以.html 结尾才会拦截到

<url-pattern>*.do</url-pattern>

以上配置的路径,表示请求地址必须以.do 结尾才会拦截到

<url-pattern>*.action</url-pattern>

以上配置的路径,表示请求地址必须以.action 结尾才会拦截到

ThreadLocal

ThreadLocal 的作用,它可以解决多线程的数据安全问题。

ThreadLocal 它可以给当前线程关联一个数据(可以是普通变量,可以是对象,也可以是数组,集合)

ThreadLocal 的特点:

  1. ThreadLocal 可以为当前线程关联一个数据。(它可以像 Map 一样存取数据,key 为当前线程)

  2. 每一个 ThreadLocal 对象,只能为当前线程关联一个数据,如果要为当前线程关联多个数据,就需要使用多个ThreadLocal 对象实例。

  3. 每个 ThreadLocal 对象实例定义的时候,一般都是 static 类型

  4. ThreadLocal 中保存数据,在线程销毁后。会由 JVM 虚拟自动释放

使用ThreadLocal可以使整个线程使用同一个连接,避免了大量创建连接的操作

public class JdbcUtils {

    private static DruidDataSource dataSource;

    private static ThreadLocal<Connection> conns = new ThreadLocal<>();

    static {
        try {
            Properties properties = new Properties();
            //读取jdbc.properties属性
            InputStream inputStream = JdbcUtils.class.getClassLoader().getResourceAsStream("jdbc.properties");
            //读取数据
            properties.load(inputStream);
            //获取连接
            dataSource = (DruidDataSource) DruidDataSourceFactory.createDataSource(properties);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取数据库连接池中的连接
     * @return
     */
    public static Connection getConnection(){
        Connection conn = conns.get();
        if (conn == null){
            try {
                conn = dataSource.getConnection();
                //保存到ThreadLocal对象中
                conns.set(conn);
                conn.setAutoCommit(false); //手动管理事务
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        return conn;
    }

    /**
     * 提交事务,关闭连接
     */
    public static void commitAndClose(){
        Connection conn = conns.get();
        if (conn != null){
            try {
                conn.commit(); //提交事务
            } catch (SQLException e) {
                e.printStackTrace();
            } finally {
                try {
                    conn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
        //必须执行,因为Tomcat服务器使用了线程池
        conns.remove();
    }

    /**
     * 回滚事务,关闭连接
     */
    public static void rollbackAndClose(){
        Connection conn = conns.get();
        if (conn != null){
            try {
                conn.rollback();   //回滚事务
            } catch (SQLException e) {
                e.printStackTrace();
            } finally {
                try {
                    conn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
        //必须执行,因为Tomcat服务器使用了线程池
        conns.remove();
    }
}

使用Filter和ThreadLocal组合管理事务

使用 ThreadLocal 来确保所有 dao 操作都在同一个 Connection 连接对象中完

项目中所有的异常都需抛出由 TransactionFilter 统一处理

public class TransactionFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        Filter.super.init(filterConfig);
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        try {
            filterChain.doFilter(servletRequest, servletResponse);
            JdbcUtils.commitAndClose();
        } catch (Exception e) {
            JdbcUtils.rollbackAndClose();
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    @Override
    public void destroy() {
        Filter.super.destroy();
    }
}

在xml中的配置

<filter-mapping>
    <filter-name>TransactionFilter</filter-name>
    <!--拦截路径-->
    <url-pattern>/*</url-pattern>
</filter-mapping>

<error-page>
    <!--错误类型-->
    <error-code>500</error-code>
    <!--出错后跳转的页面-->
    <location>/pages/error/error500.jsp</location>
</error-page>

<error-page>
    <!--错误类型-->
    <error-code>404</error-code>
    <!--出错后跳转的页面-->
    <location>/pages/error/error404.jsp</location>
</error-page>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7nSGCYYi-1637808791006)(C:\Users\11600\AppData\Roaming\Typora\typora-user-images\image-20211125103321286.png)]

(); //回滚事务
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
//必须执行,因为Tomcat服务器使用了线程池
conns.remove();
}
}


## 使用Filter和ThreadLocal组合管理事务

**使用** **ThreadLocal** **来确保所有** **dao** **操作都在同一个** **Connection** **连接对象中完** **成** 

项目中所有的异常都需抛出由 TransactionFilter 统一处理

```java
public class TransactionFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        Filter.super.init(filterConfig);
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        try {
            filterChain.doFilter(servletRequest, servletResponse);
            JdbcUtils.commitAndClose();
        } catch (Exception e) {
            JdbcUtils.rollbackAndClose();
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    @Override
    public void destroy() {
        Filter.super.destroy();
    }
}

在xml中的配置

<filter-mapping>
    <filter-name>TransactionFilter</filter-name>
    <!--拦截路径-->
    <url-pattern>/*</url-pattern>
</filter-mapping>

<error-page>
    <!--错误类型-->
    <error-code>500</error-code>
    <!--出错后跳转的页面-->
    <location>/pages/error/error500.jsp</location>
</error-page>

<error-page>
    <!--错误类型-->
    <error-code>404</error-code>
    <!--出错后跳转的页面-->
    <location>/pages/error/error404.jsp</location>
</error-page>

[外链图片转存中…(img-7nSGCYYi-1637808791006)]
笔记都是从哔哩哔哩里面的尚硅谷整理出来的,想学习的小伙伴可以点击下方连接加入学习
尚硅谷最新版JavaWeb全套教程,java web零基础入门完整版

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

轩尼诗道-

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值