Servlet与Jsp的学习(内含验证码的操作)

本文详细介绍了ServletContext对象的功能,包括获取MIME类型、共享数据以及获取文件服务器路径。接着讲解了会话技术,重点讨论了Cookie的创建、原理、注意事项和作用。此外,还探讨了JSP的基本概念、原理、脚本、内置对象以及Session的使用。最后,文章提到了EL表达式和JSTL标签在简化JSP开发中的作用,以及过滤器的配置和执行流程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. ServletContext对象

1.1 概述

ServletContext 对象代表整个web应用,可以和程序的容器(服务器进行通信)。

1.2 获取该对象

  1. 通过Request对象获取
    • request.getServletContext()
  2. 通过HttpServlet获取(实际是他的父类实现了该方法)
    • this.getServletContext()

演示案例:

@WebServlet("/scd")
public class ServletContextDemo extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        ServletContext servletContext = req.getServletContext();
        ServletContext servletContext1 = this.getServletContext();
        System.out.println(servletContext);
        System.out.println(servletContext1);
        System.out.println(servletContext == servletContext1);
        //两种方式获取的是一个ServletContext对象
    }
}

1.3 功能

1. 获取MIME类型:
  • MIME 类型:在互联网通信过程中定义的一种文件数据类型
  • 格式:大数据类型/小数据类型 比如:text / html , image/jpeg
  • 获取:String getMimeType(String file):通过文件名(包含扩展名)获取MIME的值
    • 扩展名对应的MIME可以去tomcat — conf - web.xml中查看

演示案例:

@WebServlet("/scd2")
public class ServletContextDemo2 extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        ServletContext servletContext = req.getServletContext();
        //定义一个文件名
        String fileName = "index.html";
        //获取MIME
        String mimeType = servletContext.getMimeType(fileName);
        System.out.println(mimeType);
    }
}
2. 域对象:可以共享数据
  • 功能:所有域对象都有该功能

    • void setAttribute(String name,Object obj) : 存储数据
    • Object getAttitude(String name) : 通过键获取值
    • void removeAttribute(String name) : 通过键移除键值对
  • 作用域:

    最大范围,所有用户的所有数据

演示案例:定义两个Servlet,不经过转发获取数据

@WebServlet("/scd3")
public class ServletContextDemo3 extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        ServletContext servletContext = req.getServletContext();
        servletContext.setAttribute("info", "牛逼");
    }
}
@WebServlet("/scd4")
public class ServletContextDemo4 extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        ServletContext servletContext = req.getServletContext();
        Object info = servletContext.getAttribute("info");
        System.out.println(info);
    }
}
3. 获取文件的服务器真实存储路

演示案例:

  1. 分别在src,web,WEB-INF 下创建a.txt, b.txt , c.txt

image-20210122021628423

  1. 测试案例
@WebServlet("/scd6")
public class ServletContextDemo6 extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        ServletContext servletContext = req.getServletContext();
        //获取web目录下的资源
        String realPath = servletContext.getRealPath("/b.txt"); 
        System.out.println(realPath);

        //获取WEB-INF下的资源:到文件夹中找对应文件对比着写. 
        realPath = servletContext.getRealPath("/WEB-INF/c.txt");
        System.out.println(realPath);

        //src下的文件都会被放到WEB-INF下的classes路径中
        realPath = servletContext.getRealPath("/WEB-INF/classes/a.txt");
        System.out.println(realPath);
    }
}

1.4 文件下载

需求:

1. 在一个html文件中写一个超链接
2. 点击超链接,弹出下载提示框
     - 如果超链接的 href属性直接指向图片路径,因为浏览器解析器可以解析图片,所以会直接显示图片而不是下载,但是如果src指向视频,因为浏览器无法解析视频,就会默认的弹出下载框。
3. 下载图片

分析:

需要使用响应头设置资源的打开方式,否则图片无法通过超链接下载

  • Content-disposition :attachment ; filename=xxx

步骤:

  1. 定义页面,编辑超链接href属性,指向Servlet, 传递资源的名称:filename
  2. 定义servlet
    • 获取文件名
    • 指定response的响应头:
      • Content-disposition :attachment ; filename=xxx
      • MIME
    • 使用字节输入流加载文件进内存
      • 使用ServletContext对象获取实际路径
    • 将数据写出到response输出流

演示案例:

  1. 先在web路径下新建image文件夹,将图片放入该文件夹,再创建一个下载页面:download.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <a href="/book/image/Lucky.jpg">小柯基</a>
        <a href="/book/downloadServlet?filename=Lucky.jpg">皇后</a>
    </body>
    </html>
    
  2. downloadServlet

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.FileInputStream;
import java.io.IOException;

@WebServlet("/downloadServlet")
public class DownloadServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 获取文件名称
        String filename = req.getParameter("filename");
        //找到文件真实路径
        ServletContext servletContext = this.getServletContext();
        String path = servletContext.getRealPath("/image/"+filename);
        //设置响应头
        //MIME类型
        String mimeType = servletContext.getMimeType(filename);
        resp.setHeader("content-type", mimeType);
        //打开方式
        resp.setHeader("content-disposition","attachment;filename="+filename);
        //获取输入输出流
        FileInputStream fis = new FileInputStream(path);
        ServletOutputStream outputStream = resp.getOutputStream();
        byte[] bytes = new byte[1024];
        int len = 0;
        while ((len = fis.read(bytes)) != 0) {
            outputStream.write(bytes, 0, len);
        }

        //释放资源
        fis.close();
    }
}

2. 会话技术

概述:

一次会话中包含多次请求和相应。并且在会话范围内可以共享数据

会话就和谈话的过程一样,你来我往很多次问答。

功能:

共享技术

分类:

1. 客户端会话技术Cookie
2. 服务器端会话技术:Session

2.1 Cookie

  • 概述:客户端会话技术,将数据保存到客户端

  • 步骤:

    1. 创建Cookie对象,绑定参数
    • new Cookie(String name ,String value)
    1. 发送Cookie对象
      • reponse . addCookie(String name)
    2. 获取Cookie对象,拿到对象
      • Cookie[] request.getCookies()

2.2 入门案例:

测试案例:

  1. CookieServlet
@WebServlet("/cookieServlet")
public class CookieServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            //获取cookie对象
        Cookie cookie = new Cookie("msg", "hello");
        //发送cookie
        resp.addCookie(cookie);

    }
}

  1. CookieServlet2
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("/cookieServlet2")
public class CookieServlet2 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doPost(req, resp);
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            //获取cookie
        Cookie[] cookies = req.getCookies();
        //获取数据,遍历cookie
        if (cookies != null) {
            for (Cookie cookie : cookies) {
                String name = cookie.getName();
                String value = cookie.getValue();
                System.out.println(name+":"+value);
            }
        }
    }
}

通过浏览器分别访问这两个servlet,并且读取cookie中的数据

2.3 原理图

image-20210123125657505

image-20210123125657505

2.4 注意事项

  1. 一次发送多个cookie
  • 创建多个cookie对象,多次调用addCookie()方法
  1. Cookie在浏览器中保存多长时间

    • 默认清空下,当浏览器关闭,Cookie数据被销毁
    • 持久化存储:
      • setMaxAge(intt seconds):
        • seconds:
          1. 正数:将Cookie数据写到硬盘文件中,持久化存储 :second具体的数值表示文件存活的时长,以秒为单位。
          2. 负数:默认值
          3. 0:删除cookie信息,因为服务器无法直接操作用户电脑。
  2. Tomcat 8 版本之前,不能直接存储中文数据。 8版本之后,可以直接存储中文

  3. Cookie的获取范围

    一个服务器多个web项目

    • 默认情况下一个tomcat服务器中,多个web项目中的cookie是不能共享的
    • 我们可以方法设置:setPath(“/“),这样cookie就可以共享了

    不同tomcat服务器

    • 通过setDomain()方法,设置相同的一级域名,那么这些一级域名相同的服务器间cookie可以共享
      • tieba.baidu.com baidu.com就是一级域名.

2.5 Cookie的特点

  1. cookie存储数据在客户端浏览器不安全
  2. 大小有限制:单个Cookie的大小为 4KB, 同一个域名下的总cookie数 不超过 20 个

2.6 Cookie的作用

  1. 存储少量,内容不敏感的作用
  2. 在不登陆的情况下,完成服务器对客户端的身份识别(主要用途)
    • 比如:用户在不登陆百度的情况下对百度页面进行的个性化设置信息,会被存储在cookie中,下次访问百度。浏览器带着cookie的信息,百度服务器就可以识别其身份,展示用户个性设置的页面

2.7 练习

**需求:**访问网站时给出上一次登录信息:如果是第一次则显示首次登录。

分析:

1. 可以采用Cookie完成
2. 在服务器中的Servlet判断是否有一个lastTime的cookie
 - 有:则不是第一次访问
     - 响应数据
     - 更新Cookie
 - 没有:则是第一次访问
   - 响应:欢迎您,您是首次访问
   - 添加cookie:lastTime = 当前时间戳

代码实现:

@WebServlet("/cookie3")
public class CookieServlet3 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
         //设置响应编码集
        resp.setContentType("text/html;charset=utf-8");

          //1. 获取所有Cookie
        Cookie[] cookies = req.getCookies();
        boolean flag = false;//标记是否有lastTime
        //2.遍历数组
        if (cookies != null && cookies.length > 0) {
            for (Cookie cookie : cookies) {
                //3. 获取cookie名称
                String name = cookie.getName();
                //4.判断
                if ("lastTime".equals(name)) {
                    //存在,不是第一次访问
                    //响应数据
                    String value = cookie.getValue();
                    resp.getWriter().write("<h1>您上一次访问的时间是:"+value+"</h1>");
                    //设置新的cookie时间
                    Date date = new Date();
                    SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
                    String newDate = sdf.format(date);
                    cookie.setValue(newDate);
                    //设置cookie存活时间
                    cookie.setMaxAge(60 * 60 * 24 * 30);//存活一个月
                    //发送cookie
                    resp.addCookie(cookie);
                    flag = true;
                }
            }
        }
        //第一次访问
        if (cookies == null || cookies.length == 0 || flag == false) {
            //设置新的cookie时间
            Date date = new Date();
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
            String newDate = sdf.format(date);
            Cookie cookie = new Cookie("lastTime",newDate);
            //设置cookie存活时间
            cookie.setMaxAge(60 * 60 * 24 * 30);//存活一个月
            resp.addCookie(cookie);
            flag = true;

            resp.getWriter().write("<h1>您是第一次访问</h1>");
        }

    }
}

写好之后会报错,因为 时间格式中有一个空格,虽然Tomcat8 之后对于中文字符可以支持,但是对于特殊字符它还是不支持,所以我们需要将Cookie数据转化为URL编码存储,使用URL解码来解析。

所以:我们需要在存储数据前进行URL编码,在获取数据后进行URL解码

image-20210124004826118

3. JSP

3.1 概述:

JSP - Java Server Page : Java 服务器端页面,该页面中可以写html标签,也可以写Java代码。可以简化动态内容书写量

演示案例:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>$Title$</title>
  </head>
  <body>
     <%
       System.out.println("Hello JSP");
     %>
  <h1>Hello JSP</h1>
  </body>
</html>

当你浏览该页面时,页面既能输出html标签,服务器中又能输出

3.2 原理:

JSP页面本质是一个Servlet

因为,能在web服务器运行的java程序肯定是Servlet。我们通过前面的案例也能体会到如果我们通过Servlet的response对象响应静态资源工作量非常大的。所以将动态资源和静态资源统一定义在JSP中,服务器启动后,会将JSP转换成对应的Servlet的class字节码文件。里面的方法就是处理动态资源 和 对静态内容的输出

3.3 脚本:

就是定义了JSP中Java代码的书写方式

  1. <% 代码%>: 定义的java代码,相当于定义在Servlet中的service()方法中
  2. <%! 代码%>:定义的Java代码,相当于定义在Servlet中的成员位置,即成员变量和成员方法
  3. <%= 代码%>:输出语句,使用JSP的内置对象 Out(后面讲)

演示案例:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>$Title$</title>
  </head>
  <body>
     <%
       System.out.println("Hello JSP");
     %>
      
     <%! int i = 10;%>
     <% i = 3; %>
     <%= i%>
  <h1>Hello JSP</h1>
  </body>
</html>

效果:

image-20210124012418635

3.4 内置对象:

  1. **概述:**直接在JSP页面中,不需要获取和创建,可以直接使用的对象

  2. 分类:九大内置对象

    • request
    • response
    • session
    • out
    • page
    • application
    • pageContext
    • config
    • exception
    内置对象名真实数据类型作用
    requestHttpServletRequest一次请求中共享数据
    responseHttpServletResponse响应对象
    sessionHttpSession一次会话中共享数据
    outJspWriter输出对象,输出数据到当前页面
    pageObjcet(this-当前jsp页面)当前页面的对象
    applicationServletContext所有用户间共享数据
    pageContextPageContext当前页面共享数据,还可以获取其他8个内置对像
    configServletConfigServlet配置对象
    exceptionThrowable只有异常页面有该对象
  3. response.getWriter() 和 out对象输出:由于web服务器的工作机制,对于页面的输出,服务器都会先访问response缓冲区,再访问out缓冲区,所以无论 response.getWriter()的编写位置在哪里,它都会先与out对象的输出。

3.5 Session

  1. 概念:服务器端会话技术 - HttpSession

  2. 功能

    • 获取HttpSession对象
      • request.getSession()
    • 使用HttpSession对象:
      • Object getAttribute(String name)
      • void setAttribute(String name Object value)
      • void removeAttribute(String name)
  3. 原理:

    session的实现时依赖于cookie的。

    第一次发送请求,服务器会创建Session对象,并设置一个唯一的ID属性,并在相应时将该Session对象的的ID 存入响应头:set-cookie : JSESSIONID= id属性。

    当客户端发送第二次请求时,cookie中就会有对应的Session id , web服务器读取到头信息后,就会将两次会话中使用的Session对象指向同一个session对象。

  4. 注意

    1. 客户端关闭后,再次开启客户端获取的Sesion是同一个吗?

      • 默认情况下不是,因为客户端关闭,cookie会被清空
      • 如果需要相同,可以通过设置cookie
      @WebServlet("/session1")
      public class SessionDemo extends HttpServlet {
          @Override
          protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
              this.doPost(req, resp);
          }
      
          @Override
          protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
               //获取session对象
              HttpSession session = req.getSession();
              //System.out.println(session);//没有设置cookie存活时间前,session不是同一个
              //设置cookie存活时长
              Cookie cookie = new Cookie("JSESSIONID", session.getId());
              cookie.setMaxAge(60 * 60);
              resp.addCookie(cookie);
              System.out.println(session);
          }
      }
      
      
      1. 服务器重新启动后,两个会话的Sesion是同一个吗?
      • 因为Session 对象会被清空,所以很难相同。但是我们不能因为重启服务器而丢失Session数据

        • 解决:Session的钝化 和 活化
          1. 钝化:就是将Seession对象序列化到磁盘上
          2. 活化:在服务器启动后,将session文件反序列化成Session对象即可。
          3. **注意:**Tomcat可以自动完成Session的活化和钝化,但是Idea无法演示出效果,因为idea重启服务器会先将work目录删除,再重新创建。而钝化的session文件就是在work目录中
        1. Session的什么时候销毁
      • 服务器关闭

      • session对象调用invalidate():将自己杀死

      • session默认失效时间:30分钟

        • 可以通过tomcat — > conf —->web.xml配置失效时间
  5. 特点:

    • session 用于存储一次会话中多次请求的数据,存储在服务器端
    • session可以存储任意类型,任意大小的数据
  6. Session 与 cookie的区别

    • session存储在服务器端,cookie存储在客户端
    • session没有数据大小的限制,Cookie有
    • session数据安全,cookie相对不安全

6.6 登录案例优化

  1. 将验证码实际内容存储到session对象中进行共享
  2. 将错误提示信息显示在对应标签后部

image-20210124031848431

3.将验证码设置为一次性验证码

3.7 JSP指令

  1. **作用:**用于配置JSP页面,导入资源文件
  2. 格式:<%@ 指令名称 属性名1=属性值1 属性名1=属性值1 %>
  3. 分类:
    • page:配置JSP页面
    • include:页面包含。(基本不用)
    • taglib:导入资源,后面使用的JSTL标签就需要使用该指令导入

3.6 page指令

  1. 常见属性:

    • contentType:等同于response.setContentType():设置响应体的Mime类型及编码集。并且可以设置当前JSP的编码集(高级开发工具才有的功能)

    • pageEncoding: 当前页面的编码集

    • language:jsp语言,当年想统一所有表现层语言,结果没实现,所以现在的language只有 java这个属性值。

    • buffer:缓冲区大小,因为jsp中使用输出流,需要缓冲区

    • import :导包,高级开发工具会自动导包

    • errorPage:

      当前页面如果报错,会自动跳转至该属性配置的页面。

      • 演示:在演示案例页面中写入<% int i = 3 /0%>,指定errorPage属性跳转路径,即可看到效果
    • isErrorPage:标注当前页面是否是错误页面,如果为 true, 则可以使用 Exception这个内置对象

3.7 taglib

我们常用于引入标签库,后面学习JSTL会用到

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

  • prefix : 前缀,自定义

3.8 mvc开发模式

早期还没有jsp时,都是使用servlet开发,只能使用response输出标签数据,工作量非常大。后来jsp出现后,简化了 servlet的开发,开发人员开始过度的使用jsp,导致前后端无法分离,并且代码结构混乱,阅读性非常差。为了解决这写问题 后来的java开发就借鉴了MVC开发模式,具体的规定了什么代码写什么位置,使得程序设计更加合理。

  1. MVC
  • M - Model 模型 JavaBean
    • 完成具体的业务操作:比如:查询数据库,封装对象等。
  • V - View 视图层 JSP
  • 展示数据
  • C - Controller 控制器 Servlet
    • 获取用户的输入(请求)
    • 调用模型
    • 将数据交给视图层展示

image-20210124043647608

2.优点

  • 耦合性低:将代码分为三部分,各司其职,便于维护,
  • 重用性高:

3.缺点

  • 使得架构变复杂,对程序员要求比较高。

因为三部分各司其职,所以JSP页面仅仅做展示,所以我们需要学习替换他的两外两个技术 EL表达式 和 JSTL标签。

4.EL表达式

4.1 概述

EL - EXpression Language 表达式语言,jsp本使支持EL表达式

4.2 作用

替换 和 简化 jsp页面中java代码的编写

4.3 语法

${ 表达式 }

演示案例:

${ 3>4}
结果:页面会直接输出运算结果

\${表达式}
结果:他会原样输出4

4.4 使用

  1. 运算
  • 算数运算:+,- ,*,/ ,%
  • 比较运算:> ,< , >= , < = , >= , == ,!=
  • 逻辑运算:&& (and) , ||(or) , ! (非)
  • 空运算符:empty 用于判断 字符串,集合 数组对象是否为null 并且长度是否为0
<h3>算数运算符</h3>
${1+2 }<br>
${1-2 }<br>
${1*2 }<br>
${1/2 }<br>
${1%2 }<br>
<h3>逻辑运算符</h3>
${ 3>4 && 5<6}
${ 3>4 and 5<6}

  1. 获取值
    • EL表达式只能从域对象中获取值
    • 语法:${域名称. 键名} 从指定域中获取指定键的值
      • 域名称:
        1. pageScope —>pageContext
        2. requestScope —> requestScope
        3. sessionScope —>session
        4. applicationScope —>application
      • 举例:取出request域中的 name属性值:${request.name}

演示案例1:

<%    
	request.setAttribute("name","刘德华");
%>
${requestScope.name}
${requestScope.age} 读不出数据也不会显示null,而是显示空格

演示案例2:

<%    
	request.setAttribute("name","刘德华");    
	session.setAttribute("name","周杰伦")
%>
${name}

语法2:${ 键名} :默认会从最小的域以此向上寻找

4.5 获取对象 和 集合

  1. user类
package cn.itcast.domain;

import java.text.SimpleDateFormat;
import java.util.Date;

public class User {

    private String name;
    private int age;
    private Date birthday;


    public User(String name, int age, Date birthday) {
        this.name = name;
        this.age = age;
        this.birthday = birthday;
    }

    public User() {
    }

    /**
     * 逻辑视图
     * @return
     */
    public String getBirStr(){

        if(birthday != null){
            //1.格式化日期对象
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            //2.返回字符串即可
            return sdf.format(birthday);

        }else{
            return "";
        }
    }


    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

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

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }
}

演示案例:

<html>
<head>
    <title>el获取数据</title>
</head>
<body>

    <%
        User user = new User();
        user.setName("张三");
        user.setAge(23);
        user.setBirthday(new Date());


        request.setAttribute("u",user);


        List list = new ArrayList();
        list.add("aaa");
        list.add("bbb");
        list.add(user);

        request.setAttribute("list",list);


        Map map = new HashMap();
        map.put("sname","李四");
        map.put("gender","男");
        map.put("user",user);

        request.setAttribute("map",map);

    %>

<h3>el获取对象中的值</h3>
${requestScope.u}<br> 这里打印的是对象的字符串表示形式

<%--
    * 通过的是对象的属性来获取
        * setter或getter方法,去掉set或get,在将剩余部分,首字母变为小写。
        * setName --> Name --> name
--%>

    ${requestScope.u.name}<br>
    ${u.age}<br>
    ${u.birthday}<br>
    ${u.birthday.month}<br>//调用的Date类中的getMonth方法
	
    //如果我们想获取到格式化后的日期,我们可以去user类中提供一个方法getBirStr()(下面定义)
    ${u.birStr}<br>

    <h3>el获取List值</h3>
    ${list}<br>
    ${list[0]}<br>
    ${list[1]}<br>
    ${list[10]}<br>//越界 不会报错,显示空

    ${list[2].name}

    <h3>el获取Map值</h3>
    ${map.gender}<br>
    ${map["gender"]}<br>
    ${map.user.name}

</body>
</html>

4.6 隐式对象

**概述:**el表达式中直接可以使用的对象,

只需要知道通过pageContext对象可以获取其他8个jsp内置对象

常用的是获取request对象,再获取项目的虚拟目录

${pageContext.request}<br><h4>在jsp页面动态获取虚拟目录</h4>${pageContext.request.contextPath}Copy

5. JSTL 标签

5.1 概述:

JavaServer Pages Tag Library JSP标准标签库 ,用于简化和替换jsp页面上的java代码

5.2 使用

  1. 导入jstl相关jar包
  2. 引入标签库:taglib指令: <%@ taglib %>
  3. 使用标签

5.3 if

<%@ page import="java.util.List" %>
<%@ page import="java.util.ArrayList" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<html>
<head>
    <title>if标签</title>
</head>
<body>

    <%--

    c:if标签
        1. 属性:
            * test 必须属性,接受boolean表达式
                * 如果表达式为true,则显示if标签体内容,如果为false,则不显示标签体内容
                * 一般情况下,test属性值会结合el表达式一起使用

        2. 注意:c:if标签没有else情况,想要else情况,则可以在定义一个c:if标签


    --%>

    <c:if test="true">
        <h1>我是真...</h1>
    </c:if>
    <br>

    <%
        //判断request域中的一个list集合是否为空,如果不为null则显示遍历集合

        List list = new ArrayList();
        list.add("aaaa");
        request.setAttribute("list",list);
		
		//判断number的奇偶性
        request.setAttribute("number",4);

    %>

    <c:if test="${not empty list}">
        遍历集合...

    </c:if>
    <br>

    <c:if test="${number % 2 != 0}">

            ${number}为奇数

    </c:if>

    <c:if test="${number % 2 == 0}">

        ${number}为偶数

    </c:if>

</body>
</html>

17.4 choose

<html>
<head>
    <title>choose标签</title>
</head>
<body>

    <%--
        完成数字编号对应星期几案例
            1.域中存储一数字
            2.使用choose标签取出数字         相当于switch声明
            3.使用when标签做数字判断         相当于case
            4.otherwise标签做其他情况的声明  相当于default
    --%>

    <%
        request.setAttribute("number",51);
    %>

    <c:choose>
        <c:when test="${number == 1}">星期一</c:when>
        <c:when test="${number == 2}">星期二</c:when>
        <c:when test="${number == 3}">星期三</c:when>
        <c:when test="${number == 4}">星期四</c:when>
        <c:when test="${number == 5}">星期五</c:when>
        <c:when test="${number == 6}">星期六</c:when>
        <c:when test="${number == 7}">星期天</c:when>

        <c:otherwise>数字输入有误</c:otherwise>
    </c:choose>


</body>
</html>

17.5 foreach

<%@ page import="java.util.ArrayList" %>
<%@ page import="java.util.List" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>

<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<html>
<head>
    <title>foreach标签</title>
</head>
<body>

<%--

    foreach:相当于java代码的for语句
        1. 完成重复的操作
            for(int i = 0; i < 10; i ++){

            }
            * 属性:
                begin:开始值(包含)
                end:结束值(包含)
                var:临时变量 - 相当于i
                step:步长,每次改变量
                varStatus:循环状态对象,在普通for循环中 与 var 相同
                    index:容器中元素的索引,从0开始
                    count:循环次数,从1开始
        2. 遍历容器
            List<User> list;
            for(User user : list){

            }

            * 属性:
                items:容器对象-list 集合
                var:容器中元素的临时变量 - 遍历操作中存储集合元素的临时变量
                varStatus:循环状态对象- 循环第几次
                    index:容器中元素的索引,从0开始
                    count:循环次数,从1开始


--%>
//打印1-10的基数
<c:forEach begin="1" end="10" var="i" step="2" varStatus="s">
    ${i} <h3>${s.index}<h3> <h4> ${s.count} </h4><br>

</c:forEach>

    <hr>


    <%
        List list = new ArrayList();
        list.add("aaa");
        list.add("bbb");
        list.add("ccc");

        request.setAttribute("list",list);


    %>
	//遍历集合
    <c:forEach items="${list}" var="str" varStatus="s">

            ${s.index} ${s.count} ${str}<br>

    </c:forEach>


</body>
</html>

练习:

<html>
<head>
    <title>test</title>
</head>
<body>

<%

    List list = new ArrayList();
    list.add(new User("张三",23,new Date()));
    list.add(new User("李四",24,new Date()));
    list.add(new User("王五",25,new Date()));

    request.setAttribute("list",list);


%>

<table border="1" width="500" align="center">
    <tr>
        <th>编号</th>
        <th>姓名</th>
        <th>年龄</th>
        <th>生日</th>
    </tr>
    <%--数据行--%>
    <c:forEach items="${list}" var="user" varStatus="s">

        <c:if test="${s.count % 2 != 0}">

            <tr bgcolor="red">
                <td>${s.count}</td>
                <td>${user.name}</td>
                <td>${user.age}</td>
                <td>${user.birStr}</td>
            </tr>
        </c:if>

        <c:if test="${s.count % 2 == 0}">

            <tr  bgcolor="green">
                <td>${s.count}</td>
                <td>${user.name}</td>
                <td>${user.age}</td>
                <td>${user.birStr}</td>
            </tr>
        </c:if>

    </c:forEach>

</table>
</body>
</html>

5. 过滤器

5.1 概述

1. 概述:当访问服务器资源时,过滤器可以将请求拦截下来,进行一些特殊的功能
2. 作用:一般用于完成通用的操作,比如登录操作,统一编码处理,过滤敏感字符

5.2 快速入门

步骤:

  1. 定义一个类,实现接口Fileter
  2. 复写方法
  3. 配置拦截路径。

演示案例

创建一个类,实现Filter接口,启动服务器,如果没有放行代码,则jsp中内容将不会给展示。

/**
 * @author lp
 * @version 1.0
 */
@WebFilter("/*")//访问所有资源都会被执行
public class FilterDemo1 implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("过滤器被执行。。。。");
        //放行
        filterChain.doFilter(servletRequest,servletResponse);
    }

    @Override
    public void destroy() {

    }
}

5.3 执行流程

通过代码来演示Filter的执行流程:

新建一个过滤器

@WebFilter("/*")//访问所有资源都会被执行
public class FilterDemo2 implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("过滤器被执行。。。。");
        //放行
        filterChain.doFilter(servletRequest,servletResponse);

        System.out.println("过滤器又被执行了。。。");
    }

    @Override
    public void destroy() {

    }
}

再index.jsp中添加一条输出语句

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>$Title$</title>
  </head>
  <body>
  <%
    System.out.println("JSP被执行");
  %>
  </body>
</html>

执行结果:

image-20210127224246497

为什么会这样呢? 因为过滤器是对访问数据和响应数据进行处理的,所以访问前,过滤会执行一次,处理request中的对象,jsp页面执行完毕后,过滤器又会对response中的数据进行处理。

有一点需要注意的是,过滤器再次被执行就从 放行语句后开始执行

5.4 过滤器配置:(只讲注解方式)

  • 拦截路径配置:

    1. 具体资源路径: /index.jsp   只有访问index.jsp资源时,过滤器才会被执行
    2. 拦截目录: /user/* 访问/user下的所有资源时,过滤器都会被执行
    3. 后缀名拦截: *.jsp 访问所有后缀名为jsp资源时,过滤器都会被执行
    4. 拦截所有资源:/* 访问所有资源时,过滤器都会被执行
    
    
  • 拦截方式配置:资源被访问的方式:直接访问,转发等

    1. 注解配置:
      • 设置dispatcherTypes属性
        • REQUEST:默认值。浏览器直接请求资源
        • FORWARD:转发访问资源
        • INCLUDE:包含访问资源
        • ERROR:错误跳转资源 :jsp 中配置
        • ASYNC:异步访问资源
@WebFilter(value = "/index.jsp",dispatcherTypes = DispatcherType.REQUEST)//配置一种方式
@WebFilter(value = "/index.jsp",dispatcherTypes = {DispatcherType.REQUEST,DispatcherType.FORWARD})//配置多种访问方式被拦截

5.5 过滤器链

这里我们只需要了解执行顺序即可

  • 执行顺序:如果有两个过滤器:过滤器1和过滤器2
    1. 过滤器1
    2. 过滤器2
  1. 资源执行
  2. 过滤器2
  3. 过滤器1
  • 过滤器先后顺序:按照类名字符串比较顺序。xml配置按照配置先后。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值