JavaWeb 基础

一、基本概念

1.1 概述

  • Web 开发:
    • web,网页的意思,如:www.baidu.com
  • 静态 Web:
    • html,css;
    • 数据始终不会发生变化;
  • 动态 Web:
    • 数据始终会发生变化,每个访问者,在不同的时间,不同的地点看到的信息各不相同;
    • 技术栈:Servlet/JSP,ASP,PHP;
  • Java 中,动态 web 资源,开发的技术统称为 JavaWeb。

1.2 Web 应用程序

  • Web 应用程序:可以提供浏览器访问的程序;
    • a.html、b.html......这些 Web 资源,可以被外界访问,对外界提供服务;
    • 这些 Web 资源,都存在于这个世界的,某一个角落的计算机上;
    • URL;
    • Web 资源,会被放在同一个文件夹下:
      • Web 应用程序 -->Tomcat:服务器;
    • Web应用组成:(静态 Web,动态 Web)
      • html,css,js;
      • jsp,servlet;
      • Java 程序;
      • jar 包;
      • 配置文件 (Properties);
  • Web 应用程序编写完毕后,若想提供给外界访问,需要一个服务器,来统一管理。

1.3 静态 Web

  • *.htm*.html 都是网页后缀,如果服务器上,一直存在这些资源,可以通过网络,直接进行读取;

  • 静态 Web 的缺点:

    • Web 页面无法动态更新,所有用户看到都是同一个页面;
      • 轮播图,点击特效:伪动态;
      • JavaScript(实际开发中,用的最多);
      • VBScript;
    • 无法和数据库交互(数据无法持久化,用户无法交互)。

1.4 动态 Web

  • 页面动态展示:Web 的页面展示,内容因人而异;

  • 动态 Web 的缺点:

    • 加入服务器的动态 Web 资源,出现了错误,需要重新编写后台程序,重新发布;
    • 停机维护;
  • 优点:

    • 动态更新,所有用户看到都不是同一个页面;
    • 可以与数据库交互(数据持久化:注册、商品信息、用户信息...);

二、Web 服务器

2.1 实现方式

  1. ASP
  • 微软:国内最早流行的就是 ASP;
  • 在 HTML 中嵌入了 VB 的脚本,ASP + COM
  • 在 ASP 开发中,业务代码繁多,页面混乱;
  • 维护成本高;
  • IIS;
  1. php
  • PHP 开发速度快,功能强大,跨平台,代码简单(70% , WP);
  • 无法承载大的访问量(局限性);
  1. JSP/Servlet
  • B/S:浏览器和服务器;
  • C/S:客户端和服务器:
    • Sun 公司主推的 B/S 架构;
    • 基于 Java 语言;
    • 可以承载 高并发、高可用、高性能 带来的影响;
    • 语法类似 ASP;

2.2 Web 应用服务器

  • 服务器是被动的操作,用来处理用户的请求,给用户响应信息;
  • Web 应用服务器:
    • IIS:ASP,Windows 自带;
    • Tomcat:
      • Apache 下 Jakarta 中的核心项目;
      • 最新的 Servlet 和 JSP 规范,能在 Tomcat 中得到体现;
      • 技术先进、性能稳定、免费,目前比较流行的 Web 应用服务器;
      • 轻量级应用服务器,在中小型系统和并发访问,用户不是很多的场合下使用;
      • 开发和调试 JSP 程序的首选;

三、Tomcat

  • 相关链接

四、HTTP

4.1 HTTP 概述

  • Http(超文本传输协议):简单的 请求-响应 协议,运行在 TCP 之上;
    • 文本:html、字符串…. ;
    • 超文本:图片、音乐、视频、定位、地图…;
    • 端口:80;
  • Https:安全的;
    • 端口:443;

4.2 两个时代

  • http1.0:
    • HTTP/1.0:客户端可以与 web 服务器连接后,只能获得一个 web 资源,就断开连接;
  • http2.0:
    • HTTP/1.1:客户端可以与 web 服务器连接后,可以获得多个 web 资源;

4.3 Http 请求

  • 客户端 --- > 发请求(Request)--- > 服务器;
  • 百度测试:
Request URL:https://www.baidu.com/  # 请求地址
Request Method:GET  # get方法/post方法
Status Code:200 OK  # 状态码:200
Remote Address:14.215.177.39:443    # 远程地址
Accept:text/html
Accept-Encoding:gzip, deflate, br
Accept-Language:zh-CN,zh;q=0.9  # 语言
Cache-Control:max-age=0
Connection:keep-alive   # 保持连接
  1. 请求行
  • 请求行中的请求方式:GET;
  • 请求方式:Get、Post、HEAD、DELETE、PUT、TRACT…;
    • Get 请求:能够携带的参数比较少,大小有限制,会在浏览器的 URL 地址栏显示数据内容,不安全,但高效
    • Post 请求:能够携带的参数没有限制,大小没有限制,不会在浏览器的 URL 地址栏显示数据内容,安全,但不高效
  1. 消息头
Accept: # 告诉浏览器,所支持的数据类型
Accept-Encoding:    # 支持编码格式 GBK UTF-8 GB2312 ISO8859-1
Accept-Language:    # 告诉浏览器,语言环境
Cache-Control:  # 缓存控制
Connection: # 告诉浏览器,请求完成是断开还是保持连接
HOST:   # 主机..../.

4.4 Http 响应

  • 服务器 --- > 响应 --- > 客户端
  • 百度测试:
Cache-Control:private   # 缓存控制
Connection:Keep-Alive   # 保持连接
Content-Encoding:gzip   # 编码
Content-Type:text/html  # 文件类型
  1. 响应体
Accept: # 告诉浏览器,所支持的数据类型
Accept-Encoding:    # 支持编码格式 GBK UTF-8 GB2312 ISO8859-1
Accept-Language:    # 告诉浏览器,语言环境
Cache-Control:  # 缓存控制
Connection:# 告诉浏览器,请求完成是断开还是保持连接
HOST:   # 主机..../.
Refresh:    # 告诉客户端,多久刷新一次
Location:# 网页重新定位
  1. 响应状态码
  • 200:请求响应成功 200;
  • 3xx:请求重定向:
    • 重定向:重新到给指定新位置去;
  • 4xx:找不到资源 404;
    • 资源不存在;
  • 5xx:服务器代码错误 500;
    • 502:网关错误;

五、Maven

  • 相关链接

六、Servlet

6.1 Servlet 简介

  • Servlet 是 sun 公司,开发动态 Web 的一门技术;
  • Servlet 是一个 API 接口,开发 Servlet 程序,只需完成两个步骤:
    • 编写类,实现 Servlet 接口;
    • 把开发好的 Java 类,部署到 Web 服务器中;
  • 实现了 Servlet 接口的 Java 程序叫做,Servlet;
  • Serlvet 接口,有两个默认的实现类:HttpServletGenericServlet

6.2 构建 ServLet

  1. 构建 Maven 项目
  • 构建一个普通的 Maven 项目,删掉里面的 src 目录,然后在这个项目里,建立 Moudel(模块),这个空的工程就是 Maven 主工程(父工程);

  • 关于 Maven 父子工程的概念:

    • 父项目 pom.xml 中,包含子项目(模块)的名称:

      
      
          servlet-01
      
      
    • 子项目 pom.xml 中,包含父项目的信息:

      
      
          javaweb-02-servlet
          org.example
          1.0-SNAPSHOT
      
      
    • 或在子项目依赖中,添加父项目的依赖:

      • 但父项目依赖添加 dependencyManagement 标签,子项目在显示引用时,会有问题;
      
          com.study
          javaweb-02-servlet
          1.0-SNAPSHOT
      
      
    • 子项目可以直接继承使用父项目内容(反之不行);

      子项目 extends 父项目
      
  1. Maven 环境配置及优化:
  • 父项目 pom.xml 中,添加 Servlet 依赖:

  • Tomcat10 是 jakarta.servlet 包,而不是 javax.servlet

    
    
        jakarta.servlet
        jakarta.servlet-api
        5.0.0
    
    
  • 修改 Web 项目中的版本号 ;

    • web.xml 版本,改为与 Tomcat 一致的;
    • 修改 JDK 版本;
    • 修改其它依赖的版本;
  • 将 Maven 的结构搭建完整(补全相关目录);

  1. 编写 Servlet 程序
  • 编写一个普通类:
  • 实现 Servlet 接口,直接继承 HttpServlet
public class HelloServlet extends HttpServlet {
    // doGet,doPost只是请求实现的不同方式,逻辑一样,可相互调用
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // ServletOutputStream outputStream = resp.getOutputStream();
        // 响应流
        PrintWriter writer = resp.getWriter();
        writer.println("Hello Servlet!");
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}
  • web.xml 中,编写 Servlet 映射:


    
    hello
    
    com.study.servlet.HelloServlet




    hello
    
    /hello

  • 注解方式,创建 Servlet 映射:建议使用注解的方式配置

    // 格式:@WebServlet(name = “userServlet”,urlPatterns ="/userServlet")
    
    // 注释方式1:
    @WebServlet("/test")
    // 注释方式2:
    // @WebServlet(name = "test",urlPatterns = {"/t1"})
    public class HelloServlet extends HttpServlet {
    }
    // 设置多个路径
    @WebServlet({"/test/edit.do", "/test/delete.do"})
    

为什么需要映射:

  • Servlet 是 Java 程序,如通过浏览器访问,浏览器就需要连接 Web 服务器,所以需要在 Web 服务中,要注册 Servlet 程序,并给浏览器提供能够访问的路径;
  1. 配置 Tomcat 测试程序
  • 在 IDEA 中配置 Tomcat 服务;

  • 启动测试:

    • 注:访问地址为 localhost:8080/Tomcat路径映射/路径名

6.3 Servlet 原理

  • Servlet 是由 Web 服务器调用,Web 服务器,收到浏览器请求的执行流程:

6.4 映射路径 Mapping

  • 指定一个映射路径:

    hello
    /hello

  • 指定多个映射路径:多个路径都指向同一个 Servlet

    
        hello
        /hello
    
    
        hello
        /hello1
    
    
        hello
        /hello2
    
    ...
    
  • 指定通用映射路径:* 匹配所有路径 ;

    
        hello
        /hello/*
    
    
  • 默认请求路径:

    
    
        hello
        /*
    
    
  • 指定后缀或者前缀:

    
    
        hello
        *.do
    
    
  • 优先级问题:

    • 指定了固有的映射路径,优先级最高,如果没有,就按默认的处理请求;
    
    
        error
        com.study.servlet.Error
    
    
        error
        /*
    
    

6.5 ServletContext 上下文

  • Web 容器在启动时,会为每个Web 程序,都创建一个对应的 ServletContext 对象,它代表了当前的 Web 应用:

    • 一个 Web 应用,对应一个 ServletContext
  1. 共享数据
  • 在一个 Servlet 中保存的数据,可以在另外一个 Servlet 中拿到;
  • 创建存储数据的 Servlet:
public class HelloServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // this.getInitParameter(); // 初始化参数
        // this.getServletConfig(); // Servlet 配置
        // ServletContext:Servlet 上下文
        ServletContext context = this.getServletContext();
        String username = "测试";
        // 保存数据:格式  键,值
        context.setAttribute("username", username);        
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}
  • 创建读取数据的 Servlet:
public class GetServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 创建 ServletContext 对象
        ServletContext context = this.getServletContext();
        // 获取数据,转换成String类型
        String username = (String) context.getAttribute("username");
        // 设置编码格式
        resp.setContentType("text/html");
        resp.getWriter().println("名字:" + username);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}
  • web.xml 中注册 Servlet:

    set
    com.study.servlet.HelloServlet


    set
    /set


    get
    com.study.servlet.GetServlet


    get
    /get

  1. 获取初始化参数
  • web.xml 配置信息:


    url
    jdbc:mysql://localhost:3306/mybatis

  • 获取信息:
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    ServletContext context = this.getServletContext();
    // 获取参数信息 字符串对应配置文件中的参数名
    String url = context.getInitParameter("url");
    resp.getWriter().println(url);
}
  1. 请求转发
  • 请求转发,URL 地址不会发生改变;
  • 重定向,URL 地址会发生改变;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    ServletContext context = this.getServletContext();
    // 转发的请求路径
    // RequestDispatcher requestDispatcher = context.getRequestDispatcher("/gp");
    // 调用forward实现请求转发;
    // requestDispatcher.forward(req,resp);
    // 字符串为需要转发的另一个Servlet程序路径
    context.getRequestDispatcher("/url").forward(req,resp);
}
  1. 读取资源文件
  • 读取 Properties 配置文件:
    • java 目录下新建 .properties 文件;
    • resources 目录下新建 .properties 文件;
  • 项目打包时,类和资源文件,都被打包到了 classes 同一个路径下,这个路径称为 classpath
  • 用文件流,在指定的路径下读取即可;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    // 文件流读取资源文件,第一个路径前必须要有 /
    // getResourceAsStream 将资源转换为流
    InputStream is = this.getServletContext().getResourceAsStream("/WEB-INF/classes/com/study/servlet/aa.properties");
    // 创建属性集合对象
    Properties prop = new Properties();
    prop.load(is);
    String user = prop.getProperty("username");
    String pwd = prop.getProperty("password");
    resp.setContentType("text/html");
    resp.getWriter().println(user + ":" + pwd);
}
  • 注:项目打包时,资源文件有时导出失败,需要在 pom.xml 中做相应配置:


    
        
            src/main/resources
            
                **/*.properties
                **/*.xml
            
            true
        
        
            src/main/java
            
                **/*.properties
                **/*.xml
            
            true
        
    

6.6 HttpServletResponse 响应

  • Web 服务器接收到客户端的 http 请求,针对这个请求,分别创建:
    • HttpServletRequest 对象:获取客户端 请求 过来的参数;
    • HttpServletResponse 对象:给客户端 响应 信息;
  1. 简单分类
  • 负责向浏览器发送数据的方法:
// 字节流
ServletOutputStream getOutputStream() throws IOException;
// 字符流 中文
PrintWriter getWriter() throws IOException;
  • 负责向浏览器,发送响应头的方法:
void setCharacterEncoding(String var1); // 编码
void setContentLength(int var1);    // 字符长度
void setContentLengthLong(long var1);
void setContentType(String var1);   // 类型
void setDateHeader(String var1, long var2);
void addDateHeader(String var1, long var2);
void setHeader(String var1, String var2);
void addHeader(String var1, String var2);
void setIntHeader(String var1, int var2);
void addIntHeader(String var1, int var2);
  • 响应的状态码:
int SC_CONTINUE = 100;
int SC_SWITCHING_PROTOCOLS = 101;
int SC_OK = 200;    // 响应成功
int SC_CREATED = 201;
int SC_ACCEPTED = 202;
int SC_NON_AUTHORITATIVE_INFORMATION = 203;
int SC_NO_CONTENT = 204;
int SC_RESET_CONTENT = 205;
int SC_PARTIAL_CONTENT = 206;
int SC_MULTIPLE_CHOICES = 300;  // 重定向相关
int SC_MOVED_PERMANENTLY = 301;
int SC_MOVED_TEMPORARILY = 302;
int SC_FOUND = 302;
int SC_SEE_OTHER = 303;
int SC_NOT_MODIFIED = 304;
int SC_USE_PROXY = 305;
int SC_TEMPORARY_REDIRECT = 307;
int SC_BAD_REQUEST = 400;
int SC_UNAUTHORIZED = 401;
int SC_PAYMENT_REQUIRED = 402;
int SC_FORBIDDEN = 403;
int SC_NOT_FOUND = 404; // 找不到资源
int SC_METHOD_NOT_ALLOWED = 405;
int SC_NOT_ACCEPTABLE = 406;
int SC_PROXY_AUTHENTICATION_REQUIRED = 407;
int SC_REQUEST_TIMEOUT = 408;
int SC_CONFLICT = 409;
int SC_GONE = 410;
int SC_LENGTH_REQUIRED = 411;
int SC_PRECONDITION_FAILED = 412;
int SC_REQUEST_ENTITY_TOO_LARGE = 413;
int SC_REQUEST_URI_TOO_LONG = 414;
int SC_UNSUPPORTED_MEDIA_TYPE = 415;
int SC_REQUESTED_RANGE_NOT_SATISFIABLE = 416;
int SC_EXPECTATION_FAILED = 417;
int SC_INTERNAL_SERVER_ERROR = 500; // 服务器错误
int SC_NOT_IMPLEMENTED = 501;
int SC_BAD_GATEWAY = 502;   // 网关错误
int SC_SERVICE_UNAVAILABLE = 503;
int SC_GATEWAY_TIMEOUT = 504;
int SC_HTTP_VERSION_NOT_SUPPORTED = 505;
  • 常用方法
方法名 说明
response.sendRedirect(URL url) 重定向
setContentType(String type) 设置输出内容(MIME)类型(text/html)
setContentLength(int length) 设置响应报文的长度
getWriter( ) 获取输出字符流
addHeader( String name, String value) 添加指定的键值到响应头信息中
containsHeader(String name) 判断响应的头部是否被设置
encodeURL(String url) 编码指定的URL
sendError(int sc) 使用指定状态码发送一个错误到客户端
setHeader( String name, String value) 设置指定响应头的值
setStatus(int sc) 给当前响应设置状态
  1. 下载文件
  • 向浏览器输出消息;
  • 下载文件实现过程:
    1. 获取下载文件的路径;
    2. 下载的文件名;
    3. 设置浏览器的下载支持;
    4. 获取下载文件的输入流;
    5. 创建缓冲区;
    6. 获取 OutputStream 对象;
    7. 将 FileOutputStream 流写入到 buffer 缓冲区;
    8. 使用 OutputStream,将缓冲区中的数据,输出到客户端。
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    // 1.获取下载文件的路径
    String realPath = this.getServletContext().getRealPath("/WEB-INF/classes/images/01.png");
    System.out.println("下载文件的路径:" + realPath);
    // 2.下载的文件名
    String fileName = realPath.substring(realPath.lastIndexOf("\\") + 1);
    // 3.设置浏览器的下载支持(Content-Disposition),并将文件名转码,避免乱码
    resp.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
    // 4.获取下载文件的输入流
    FileInputStream in = new FileInputStream(realPath);
    // 5.创建缓冲区
    int len = 0;
    byte[] buffer = new byte[1024];
    // 6.获取 OutputStream 对象
    ServletOutputStream out = resp.getOutputStream();
    // 7.将 FileOutputStream 流写入到 buffer 缓冲区,使用 OutputStream,将缓冲区中的数据,输出到客户端
    while ((len = in.read(buffer)) > 0) {
        out.write(buffer, 0, len);
    }
    // 8.关闭流
    in.close();
    out.close();
}
  1. 验证码功能
  • 验证码实现:
    • 前端实现;
    • 后端实现:需要用到 Java 的图片类,生成一个图片;
public class ImageServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 让浏览器10秒自动刷新一次;
        resp.setHeader("refresh", "10");
        // 在内存中创建一个图片
        BufferedImage image = new BufferedImage(80, 20, BufferedImage.TYPE_INT_RGB);
        // 得到图片     g 为笔
        Graphics2D g = (Graphics2D) image.getGraphics();
        // 设置图片的背景颜色
        g.setColor(Color.white);
        g.fillRect(0, 0, 80, 20);
        // 给图片写数据
        g.setColor(Color.BLUE);
        g.setFont(new Font(null, Font.BOLD, 20));
        g.drawString(makeNum(), 0, 20);
        // 告诉浏览器,这个请求用图片的方式打开
        resp.setContentType("image/png");
        // 网站存在缓存,不让浏览器缓存
        resp.setDateHeader("expires", -1);
        resp.setHeader("Cache-Control", "no-cache");
        resp.setHeader("Pragma", "no-cache");
        // 把图片写给浏览器
        ImageIO.write(image, "png", resp.getOutputStream());
    }

    // 生成随机数
    private String makeNum() {
        Random random = new Random();
        String num = random.nextInt(9999999) + "";
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < 7 - num.length(); i++) {
            sb.append("0");
        }
        num = sb.toString() + num;
        return num;
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}
  1. 实现重定向
  • 重定向,URL 地址会发生改变:
  • Web 资源 B 收到客户端 A 请求后,B 通知 A 去访问另一个 Web 资源 C,这个过程叫重定向;

  • 常见场景:用户登录

    void sendRedirect(String var1) throws IOException;
    
  • 重定向路径

    • / 表示:http://localhost:8080,与转发的不同
  • 测试:

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    /*
        实现过程:
        resp.setHeader("Location","/r/img");
        resp.setStatus(302);
     */
    //  ‘/’ 表示:http://localhost:8080
    resp.sendRedirect("/r/img");
}
  • 重定向和转发
    • 相同点:
      • 都会实现页面跳转;
    • 不同点:
      • 请求转发,URL 地址不会发生改变;307
      • 重定向,URL 地址会发生改变;302
  1. 简单实现登录重定向
  • Tomcat 10 所需依赖:Tomcat 版本 10.0.16JDK 17

    
    
        jakarta.servlet
        jakarta.servlet-api
        5.0.0
    
    
    
    
    
        com.guicedee.services
        jakarta.servlet.jsp-api
        62
    
    
    
        org.glassfish.web
        jakarta.servlet.jsp.jstl
        2.0.0
    
    

    可能遇到的问题:

    • JSP 中 out 内置对象红色,输入代码无提示:

      • 缺少 jsp-api.jarservlet-api.jar
  • 解决方法:

    • 方法 1:更换依赖版本;
    • 方法 2:从 Tomcat 安装目录 lib 目录下,复制到工程库里;
    • 方法 3:在 IDEA 里直接添加
  • 添加对应版本:

  • 添加成功:

  • 登录页面:
<%--这里提交的路径,需要寻找到项目的路径--%> <%--${pageContext.request.contextPath}代表当前的项目--%>

  • servlet:
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    // 处理请求  getParameter:获取参数
    String username = req.getParameter("username");
    String password = req.getParameter("password");
    System.out.println(username + ":" + password);
    // 注意,路径问题(/r1虚拟映射地址),否则404;
    resp.sendRedirect("/r1/success.jsp");
}
  • 注册 Servlet:

    request
    com.study.servlet.RequestTest


    request
    /login

  • 跳转页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>


    success


登录成功

6.7 HttpServletRequest 请求

  • HttpServletRequest 代表客户端的请求,用户通过 HTTP 协议访问服务器,请求中的所有信息,都会被封装到 HttpServletRequest,通过这个 HttpServletRequest 的方法,获得客户端的所有信息;
  • 常用方法:
方法名 含义
String getHeader(String name) 获取请求中的报头信息
Enumeration getHeaderNames() 获取请求中所有报头名的集合
String getContextPath() 获取请求上下文路径(webapp的)
String getRequestURI() 获取请求中的 URI
String getMethod( ) 获取 HTTP 请求方法,GET 还是 POST
getRemoteAddr() 远程 IP,即客户端 IP
  • 获取客户端的参数:
方法名 含义
String getParameter(String name) 获取请求(表单)中参数名为 name 的参数值
String[] getParameterValues(String name) 获取请求中(表单)中所有参数名为 name 的参数值的集合(数组)
Enumeration getParameterNames( ) 获取请求中所有参数名的集合(枚举 不常用)
  • 其它方法:
方法名 说明
setCharacterEncoding("utf-8") 设置请求的编码方式
getLocalAddr() 获取本地 IP,即服务器 IP
getLocalName() 获取本地名称,即服务器名称
getLocalPort() 获取本地端口号,即 Tomcat 端口号
getLocale() 用户的语言环境
getProtocol() 协议,http协议
getQueryString() 查询字符串
getRemotePort() 远程端口,即客户端端口
getRemoteUser() 远程用户
getRequestedSessionId() 客户端的 Session 的 ID
getRequestURI() 用户请求的 URL
getScheme() 协议头,例如 http
getServerName() 服务器名称
getServerPort() 服务器端口
getServletPath() Servlet 路径

HttpServletRequest 测试:获取表单信息

  • 登录页面

运动 阅读 购物 电影

  • servlet
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    // 设置请求的编码
    req.setCharacterEncoding("utf-8");
    // 设置响应的编码
    resp.setCharacterEncoding("utf-8");
    String username = req.getParameter("username");
    String password = req.getParameter("password");
    String[] hobbies = req.getParameterValues("hobbies");
    // 后台接收中文乱码问题
    System.out.println("username:" + username);
    System.out.println("password:" + password);
    System.out.println("========================");
    System.out.println(Arrays.toString(hobbies));
    System.out.println("========================");

    System.out.println(req.getContextPath());
    // 通过请求转发
    // 这里的 / 代表当前的web应用
    req.getRequestDispatcher("/success.jsp").forward(req, resp);
}
  • 注册 servlet

    login
    com.study.servlet.LoginServlet


    login
    /login

getRequestDispatcher 转发的两种方式:

  • request.getRequestDispatcher(“url”)

    • 可以是相对路径,或绝对路径;
  • this.getServletContext().getRequestDispatcher(“url”)

    • 只能是绝对路径
  • 获取前端传递的参数

    • getParameter():一个参数值;
    • getParameterValues():多个参数值,数组;

七、Cookie、Session

7.1 会话

  • 会话:用户打开浏览器,打开很多超链接,访问多个 Web 资源,关闭浏览器,这个过程可以称之为会话;
  • 有状态会话:用户访问服务器,下次再访问时,服务器知道这个用户访问过,即有状态会话;
  • 服务器如何知道客户端访问过:
    • 服务端给客户端一个信件,客户端下次访问服务端,带上信件就可以; cookie
    • 服务器登记客户端信息,下次客户端访问时,由服务器来匹配客户端; seesion

7.2 保存会话的两种技术

  • cookie:客户端技术(响应,请求);
  • session:服务器技术,把信息或者数据,放在 Session 中;
  • 常见应用:网站登录后,下次不用再登录,可以直接访问;

7.3 Cookie

  • 从请求中拿到 cookie 信息;

  • 服务器响应给客户端 cookie;

  • 测试:Cookie

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    // 解决乱码问题
    req.setCharacterEncoding("utf-8");
    resp.setCharacterEncoding("utf-8");
    resp.setContentType("text/html");
    // 获取响应流
    PrintWriter out = resp.getWriter();
    // 服务器从客户端请求中获取Cookie,返回数组(Cookie存在多个)
    Cookie[] cookies = req.getCookies();
    // 判断Cookie是否存在
    if (cookies != null) {
        // 如果Cookie存在
        out.write("上一次访问时间:");
        // 遍历 cookies
        for (int i = 0; i < cookies.length; i++) {
            Cookie cookie = cookies[i];
            // 获取Cookie的名字
            if (cookie.getName().equals("lastLoginTime")) {
                // 获取Cookie的值,并转化成长整型(时间戳)
                Long lastLoginTime = Long.parseLong(cookie.getValue());
                // 将时间戳转换为日期格式
                Date date = new Date(lastLoginTime);
                out.write(date.toLocaleString());
            }
        }
    } else {
        out.write("第一次访问!");
    }
    // 服务器给客户端响应(发送)一个Cookie
    // System.currentTimeMillis()+"":获取时间,并转成字符串
    Cookie cookie = new Cookie("lastLoginTime", System.currentTimeMillis() + "");
    // 设置Cookie有效期,1天
    cookie.setMaxAge(24 * 60 * 60);
    resp.addCookie(cookie);
}
  • Cookie 常用方法:
// 获得Cookie
Cookie[] cookies = req.getCookies();
// 获得cookie中的key
cookie.getName();
// 获得cookie中的vlaue
cookie.getValue();
 // 新建一个cookie(设置新的cookie)
new Cookie("lastLoginTime", System.currentTimeMillis()+"");
// 设置cookie的有效期1天
cookie.setMaxAge(24*60*60);
// 响应(发送)给客户端一个cookie
resp.addCookie(cookie);
  • cookie:一般会保存在本地的用户目录下 appdata;
  • cookie 存储上限:
    • 一个 Cookie 只能保存一个信息;
    • 一个 Web 站点,可以给浏览器发送多个 cookie(最多20个);
    • Cookie 大小有限制 4kb;
    • 浏览器上限:300 个 Cookie;
  • 删除 Cookie:
    • 不设置有效期,关闭浏览器,自动失效;
    • 设置有效期时间为 0 ;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    // 创建另一个Cookie,名字与之前的必须相同(键不能重复)
    Cookie cookie = new Cookie("lastLoginTime", System.currentTimeMillis() + "");
    // 设置Cookie有效期为0
    cookie.setMaxAge(0);
    resp.addCookie(cookie);
}
  • Cookie 传递中文数据时乱码,解决方法:编码、解码
// 对中文Value值编码
URLEncoder.encode("中文的Cookie数据","utf-8")
// 解码
URLDecoder.decode(cookie.getValue(),"UTF-8")

7.4 Session(重点)

  • 什么是 Session:
    • 服务器会给每一个用户(浏览器),创建一个 Seesion 对象;
    • 一个 Seesion 独占一个浏览器,只要浏览器没有关闭,这个 Session 就存在;
    • 用户登录之后,整个网站都可以访问;
  • Session 常用方法:
方法名 说明
getCreationTime():long 返回 Session 的创建时间
getId():String 返回 Session 的唯一 ID
getLastAccessedTime():long 返回 Session 的最后活跃时间
getServletContext():ServletContext 获取 Servlet 上下文(Web 服务)
getMaxInactiveInterval():int 返回 Session 的超时时间,秒
setMaxInactiveInterval(int interval) 设置 Session 的超时时间,秒
getAttribute(String name):Object 返回 Session 属性
setAttribute(String name, Object value) 设置 Session 属性
getAttributeNames():Enumeration 返回 Session 中存在的属性名
removeAttribute(String name) 移除 Session 属性
invalidate() 注销
isNew():boolean 判断 Session 是否是新创建
  • Session 和 Cookie 的区别:
    • Cookie 是把用户的数据,写给浏览器,由 浏览器保存(可以多个);
    • Session 把用户的数据,写到 用户独占 Session 中(每个浏览器一个Session)服务器端保存(保存重要的信息,减少服务器资源的浪费);
    • Session 对象由 服务器创建
  • 使用场景:
    • 保存一个登录用户的信息;
    • 购物车信息;
    • 在整个网站中,经常会使用的数据,将它保存在 Session 中;

Session 测试:

  • Servlet 1:存储 Session 的数据;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    // 解决乱码
    req.setCharacterEncoding("utf-8");
    resp.setCharacterEncoding("utf-8");
    resp.setContentType("text/html");

    // 获取Session
    HttpSession session = req.getSession();
    // Session中存值
    session.setAttribute("name", "Session测试");
    // Session 中存储对象
    session.setAttribute("name1", new Person("学生1",20));

    // 获取Session的ID
    String id = session.getId();

    //Session创建的时候,把Session ID响应(发送)给了Cookie
    // Cookie cookie = new Cookie("JSESSIONID",sessionId);
    // resp.addCookie(cookie);

    // 判断Session是不是新创建
    if (session.isNew()) {
        resp.getWriter().write("Session 创建成功,ID:" + id);
    } else {
        resp.getWriter().write("Session ID:" + id);
    }
}
  • Servlet 2:获取 Session 中的数据,并响应(发送)给客户端
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    // 解决乱码
    req.setCharacterEncoding("utf-8");
    resp.setCharacterEncoding("utf-8");
    resp.setContentType("text/html");

    // 获取Session
    HttpSession session = req.getSession();
    // 获取Session的值
    String name = (String) session.getAttribute("name");
    // 获取Session存储的对象
    Person name1 = (Person) session.getAttribute("name1");

    // 把Session的值响应(发送)给客户端
    resp.getWriter().write("name:" + name);
    resp.getWriter().write("
"); resp.getWriter().write("name1:" + name1); // 输出到控制台测试 System.out.println(name); System.out.println("=========================="); System.out.println(name1); }
  • Servlet 3:移除 Session 属性、注销
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    // 获取Session
    HttpSession session = req.getSession();
    // 移除 Session 属性
    session.removeAttribute("name");
    // 手动注销Session:注销后,会重新生成Session ID
    session.invalidate();
}
  • 注册 Servlet:web.xml
  • 会话自动过期:web.xml 配置;


    
    3

  • 多用户访问:

八、JSP

8.1 什么是 JSP

  • JSP:Java Server Pages,java 服务器端页面,和 Servlet 一样,用于动态Web。
  • 特点:
    • JSP 类似 HTML;
    • 区别:
      • HTML 只给用户提供 静态数据
      • JSP 页面中,可以嵌入 JAVA 代码,为用户提供 动态数据

8.2 JSP原理

分析 JSP 执行的过程:

  • JSP 代码层面:查看打包后的文件,没有发生变化;

  • 服务器内部分析:

    • Tomcat 服务器中有 work 目录;

    • IDEA 中使用 Tomcat,会在 IDEA 的 Tomcat 中生产 work 目录:

    • Catalina 目录下,生成 java 文件:

结论:

  • 浏览器向服务器发送请求,不管访问什么资源,其实都是在访问 Servlet
  • JSP 最终也会被转换成为一个 Java 类;
  • JSP 本质上就是 Servlet
  • JSP 的三个方法:
// 初始化
public void _jspInit() {
}
// 销毁
public void _jspDestroy() {
}
// JSPService
public void _jspService(HttpServletRequest request, HttpServletResponse response) {
}

JSP 的执行过程

  1. 判断请求:

    • GET;
    • POST;
  2. 内置一些对象:

    // 页面上下文
    final jakarta.servlet.jsp.PageContext pageContext;
    // session
    jakarta.servlet.http.HttpSession session = null;
    // applicationContext    ServletContext改名
    final jakarta.servlet.ServletContext application;
    // 配置
    final jakarta.servlet.ServletConfig config;
    // out:输出
    jakarta.servlet.jsp.JspWriter out = null;
    // page:当前
    final java.lang.Object page = this;
    
    // 请求
    HttpServletRequest request
    // 响应
    HttpServletResponse response
    
  3. 输出页面前,增加的代码:

    // 设置响应的页面类型
    response.setContentType("text/html");
    pageContext = _jspxFactory.getPageContext(this, request, response,null, true, 8192, true);
    _jspx_page_context = pageContext;
    application = pageContext.getServletContext();
    config = pageContext.getServletConfig();
    session = pageContext.getSession();
    out = pageContext.getOut();
    _jspx_out = out;
    
  4. 以上的对象,可以在 JSP 页面中直接使用;

  • 流程图:

  • JSP 页面输出格式:

  • JAVA 代码就会原封不动的输出;

  • HTML代码,会被转换为:

    out.write("\r\n");
    

8.3 JSP 基础语法

  • JSP 在 Java 的基础上,增加了扩充的语法(了解);

  • JSP 表达式<%= %>

    <%--表示注释--%>
    <%--
        JSP 表达式:
        作用:将程序的输出内容,输出到客户端
        格式:<%= 变量或者表达式%>
    --%>
    <%--输出当前时间--%>
    <%= new java.util.Date()%>
    
  • JSP 脚本片段<% %>

    <%--jsp脚本片段--%>
    <%
        int sum = 0;
        for (int i = 1; i <= 100; i++) {
            sum += i;
        }
        out.println("

    Sum=" + sum + "

    "); %>
  • JSP 脚本片段的再实现:

    <%--JSP 脚本片段的再实现--%>
    <%
        int x = 10;
        out.println(x);
    %>
    

    这是一个JSP文档

    <% int y = 2; out.println(y); %>
    <%--在代码嵌入HTML元素--%> <% for (int i = 0; i < 5; i++) { %>

    Hello,World <%=i%>

    <% } %>
  • JSP 声明<%! %>

    • JSP 声明,被 编译到 JSP 生成的 Java 类中,其他代码,被生成到 _jspService 方法中,在 JSP,嵌入 Java 代码即可;
    <%--JSP声明--%>
    <%!
        static {
            System.out.println("Loading Servlet!");
        }
    
        private int globalVar = 0;
    
        public void test() {
            System.out.println("进入了方法test");
        }
    %>
    
  • JSP 的注释:<%-- --%> 不会在客户端显示,HTML 的注释,会显示到客户端;

8.4 JSP 指令

  • 格式:
<%@ 指令名称 属性1="属性值1" 属性2="属性值2" ... 属性n="属性值n" %>
  1. page 指令
  • 定义网页依赖属性,比如脚本语言、error页面、缓存需求等;
  • 格式:<%@ page ... %>
<%--设置文件格式和编码格式--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%--导入包--%>
<%@ page import="java.util.Date" %>
<%--自定义错误页面--%>
<%@ page errorPage="error/500.jsp" %>
  • 通过 web.xml 配置跳转页面:

    
    404
    
    /error/404.jsp

  • 属性说明:
属性 描述
buffer 指定 out 对象使用缓冲区的大小
autoFlush 控制 out 对象的 缓存区
contentType 指定当前 JSP 页面的MIME类型和字符编码
errorPage 指定当 JSP 页面发生异常时需要转向的错误处理页面
isErrorPage 指定当前页面是否可以作为另一个 JSP 页面的错误处理页面
extends 指定 servlet 从哪一个类继承
import 导入要使用的 Java 类
info 定义 JSP 页面的描述信息
isThreadSafe 指定对 JSP 页面的访问是否为线程安全
language 定义 JSP 页面所用的脚本语言,默认是 Java
session 指定 JSP 页面是否使用 session
isELIgnored 指定是否执行 EL 表达式
isScriptingEnabled 确定脚本元素能否被使用
  1. Include 指令
  • 静态包含(统一编译):会将两个页面以静态方式编译,合二为一;
  • 格式:<%@ include ... %>
<%@ include file="included.jsp"%>

<%--
    JSP标签方式拼接
    jsp:include:拼接页面,每个页面还是单独的整体
--%>
  1. Taglib 指令
  • 用于在 JSP 页面中导入标签库(JSP 标准标签库、第三方、自定义) ;
  • 格式:<%@ taglib ... %>
<%--核心标签(c)是最常用的 JSTL标签 --%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

8.5 JSP 内置对象及作用域

  • 9 大内置对象:

    • PageContext:存东西;
    • Request:存东西;
    • Session 存东西;
    • Application 【SerlvetContext】 存东西;
    • Response;
    • config 【SerlvetConfig】;
    • out;
    • page,不用了解 ;
    • exception;
  • 作用域图示:

  • 测试:在对象中存值,并测试取值

<%--内置对象:存入属性值--%>
<%
    // 保存的数据只在一个页面中有效
    pageContext.setAttribute("name1", "pageContext");
    // 保存的数据只在一次请求中有效,请求转发会携带这个数据
    request.setAttribute("name2", "request");
    // 保存的数据只在一次会话中有效,从打开浏览器到关闭浏览器
    session.setAttribute("name3", "session");
    // 保存的数据只在服务器中有效,从打开服务器到关闭服务器
    application.setAttribute("name4", "application");
%>
<%--取出属性值--%>
<%
    // JSP代码内的java代码,必须保证语法的正确
    // 通过寻找方式取值,从底层到高层(作用域)
    String name1 = (String) pageContext.findAttribute("name1");
    String name2 = (String) pageContext.findAttribute("name2");
    String name3 = (String) pageContext.findAttribute("name3");
    String name4 = (String) pageContext.findAttribute("name4");
    String name5 = (String) pageContext.findAttribute("name5");
%>
<%--测试转发携带数据--%>
<%
    pageContext.forward("/jsp3.jsp");
    // 作用等同
    // request.getRequestDispatcher("/index.jsp").forward(request,response);
%>

<%--使用EL表达式输出 ${变量}--%>

取出的值为:

${name1}

${name2}

${name3}

${name4}

${name5}

// 未创建变量,页面不显示 <%--EL表达式会过滤 null值,普通表达式不能--%>

<%= name5 %>

// 未创建变量,页面显示 null
  • 测试:在另一个页面中,取值上个页面的值

取出的值为:

${name1}

${name2}

${name3}

${name4}

${name5}

对象作用域及应用场景:

  • request:客户端向服务器发送请求,产生的数据,用户看完就没用了;
    • 比如:新闻;
  • session:客户端向服务器发送请求,产生的数据,用户用完一会还有用;
    • 比如:购物车;
  • application:客户端向服务器发送请求,产生的数据,一个用户用完了,其他用户还可能使用;
    • 比如:聊天数据;

8.6 JSP 标签、JSTL 标签、EL 表达式

  • EL 表达式:${ }
    • 获取数据;
    • 执行运算;
    • 获取 web 开发的常用对象;
  • JSP 标签:
<%--包含页面--%>


<%--
http://localhost:8080/test.jsp?name=liu&age=20
--%>
<%--转发、携带参数转发--%>

    
    

  • JSTL 标签:
    • JSTL 标签库的使用,是为了弥补 HTML 标签的不足;
    • 自定义许多标签,标签的功能和 Java 代码一样
    • 分类:核心标签、格式化标签、SQL标签、XML 标签;

核心标签(掌握):

  • 引用核心标签库的语法:使用前,必须在页面头部引用
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
  • 标签说明:

  • JSTL 标签库使用步骤:

    • 引入对应的 taglib;
    • 使用其中的方法;
    • 复制依赖包到 Tomcat lib 目录下,否则会报错:JSTL 解析错误

标签库添加依赖说明:Tomcat 版本 10.0.16

  1. pom.xml 文件中,增加依赖,导入标签库依赖;

    
    
        org.apache.taglibs
        taglibs-standard-spec
        1.2.5
    
    
    
    • 依赖关系图:
  2. 将导入的 jar 包,复制到 Tomcat 服务器的 lib 目录下:(避免 JSTL 解析错误

    • jakarta.servlet.jsp.jstl-api-2.0.0.jar

    • jakarta.servlet.jsp.jstl-2.0.0.jar

    • taglibs-standard-spec-1.2.5.jar

    • Tomcat 的 lib 目录:

  • 标签测试:
<%--表单测试:以get方式,提交给当前页面--%>
<%-- EL表达式获取表单中的数据:${param.参数名} --%> <%--如果用户名=admin,登录成功 var 为布尔值--%> <%--输出布尔值,注意自闭合标签--%>
  • 标签测试:
<%--定义一个变量score,值为85--%>


    <%--从上往下匹配--%>
    
        优秀
    
    
        良好
    
    
        一般
    
    
        不及格
    

  • 标签测试:
<%
    // 创建集合,并添加数据,注意:索引从0开始
    ArrayList people = new ArrayList<>();
    people.add(0, "张三");
    people.add(1, "李四");
    people.add(2, "王五");
    people.add(3, "赵六");
    people.add(4, "田七");
    // 把集合添加到request(请求)中
    request.setAttribute("list", people);
%>
<%--
    var:每一次遍历出来的变量
    items:要遍历的对象
    begin:哪里开始
    end:到哪里
    step:步长
--%>
<%--从请求中遍历数据,注意:被取值的变量要包含在 ${} 中}--%>

    


可能遇到的问题

  • JavaWeb 项目不生成 target 目录:
    • 解决方法:查看链接

九、JavaBean

9.1 实体类

  • 实例类:一般和数据中的 表结构一一对应;
  • JavaBean 有特定的写法:
    • 必须要有一个无参构造
    • 属性必须私有化
    • 必须有对应的 get/set 方法

9.2 字段映射

  • JavaBean 一般用来和数据库的字段做映射(ORM);

  • ORM :对象关系映射:

    • 表 ---> 类;
    • 字段 ---> 属性;
    • 行记录 ----> 对象;
  • 数据表示例:people

    id name age address
    1 张三 20 北京
    2 李四 18 上海
    3 王五 22 深圳
    // 类-->表
    class People{
        private int id;   // 属性-->字段
        private String name;
        private int age;
        private String address;
    }
    class A{
        new People(1,"张三",20,"北京");   // 对象-->一条记录
        new People(2,"李四",18,"上海");
        new People(3,"王五",22,"深圳");
    }
    
  • 测试:

<%
    // People people = new People();
    // people.setId();
    // people.setName();
    // people.setAge();
    // people.setAddress();
%>
<%--创建对象--%>

<%--给对象赋值:数据库一条记录--%>




<%--取值--%>
<%--表达式方式:<%=people.getAddress()%>--%>
ID:
姓名:
年龄:
地址:

十、MVC 三层架构

  • MVC:
  • Model:模型,指实体类对应数据库中的字段;
  • view:视图,指 JSP 页面;
  • Controller:控制器,指 Servlet,负责跳转页面;

10.1 以前的架构

  • Servlet 和 JSP 都可以写 Java 代码;

    • Servlet 专注于处理请求,以及控制视图跳转;
    • JSP 专注于显示数据;
  • 用户直接访问控制层,控制层,可以直接操作数据库;

  • Servlet 的代码中:处理请求、响应、视图跳转、处理JDBC、处理业务代码、处理逻辑代码;

    • Servlet --> CRUD --> 数据库;
    • 弊端:程序臃肿,不利于维护;
  • 架构:没有什么是加一层解决不了的,如果不行,再加一层

    /*  
           程序员调用
               |
             JDBC
               |
      Mysql Oracle SqlServer...
    */
    

10.2 MVC 三层架构

  • 架构图:

  • Model:模型

    • 业务处理:业务逻辑(Service);
    • 数据持久层:CRUD(Dao);
  • View:视图

    • 展示数据;
    • 提供链接发起 Servlet 请求 (a,form,img…)
  • Controller(Servlet):控制器

    • 接收用户的请求:(req:请求参数、Session 信息….);
    • 交给业务层处理对应的代码;
    • 控制视图的跳转;
    登录 --> 接收用户的登录请求 --> 处理用户的请求(获取用户登录的参数,username,password)--> 交给业务层处理登录业务(判断用户名密码是否正确:事务)--> Dao层(查询用户名和密码是否正确) --> 数据库
    

十一、Filter(重点):过滤器

11.1 Filter 概述

  • Filter:过滤器,过滤网站数据;

  • 应用:

    • 处理中文乱码;
    • 登录验证...;

11.2 Filter 开发步骤

  1. 导包:

    • 注意:不要导错包,选 Servlet 包;

  2. 编写过滤器:

    • 实现 Filter 接口, 重写对应的方法;
    // 通过注解,设置过滤路径:show下的所有请求都被过滤
    // 也可以通过 web.xml 文件配置
    @WebFilter("/show/*")
    public class CharacterEncodingFilter implements Filter {
        // 初始化:web服务器启动,过滤器就初始化了,随时等待过滤对象出现
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
            System.out.println("CharacterEncodingFilter 初始化");
        }
    
        // FilterChain : 链
        /*
            1.过滤中的所有代码,在过滤特定请求的时候,都会执行
            2.必须要让过滤器继续执行
            filterChain.doFilter(request,response);
        */
        @Override
        public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
            System.out.println("过滤器执行前");
            // 设置过滤执行的内容
            servletRequest.setCharacterEncoding("utf-8");
            servletResponse.setCharacterEncoding("utf-8");
            servletResponse.setContentType("text/html;charset=UTF-8");
    
            // 让请求继续执行,如果不写,程序到这里就被拦截,停止!
            filterChain.doFilter(servletRequest, servletResponse);
            System.out.println("过滤器执行后");
        }
    
        // 销毁:web服务器关闭的时候,过滤器才会销毁
        @Override
        public void destroy() {
            System.out.println("CharacterEncodingFilter 销毁");
        }
    }
    
  3. web.xml 中配置 Filter:

    • 也可以通过注解方式:@WebFilter("/show/*")
    
        CharacterEncodingFilter
        com.study.filter.CharacterEncodingFilter
        
    
        CharacterEncodingFilter
        
        /show/*
            
        
    
    

十二、监听器 Listener(了解)

  • 实现监听器的接口(有 N 种);
  • 编写一个监听器,实现监听器的接口:
// 统计网站在线人数:统计session
// 注解方式:注册监听,也可以通过web.xml设置
@WebListener
public class OnlineCountListener implements HttpSessionListener {
    // 创建session监听:监测程序执行
    // 一旦创建Session,就触发一次这个事件
    @Override
    public void sessionCreated(HttpSessionEvent se) {
        // 获取上下文:作用域提升到最大
        ServletContext context = se.getSession().getServletContext();
        // 获取在线人数
        Integer onlineCount = (Integer) context.getAttribute("onlineCount");
        // 如果为空,赋值为1
        if (onlineCount == null) {
            onlineCount = 1;
        } else {
            // 不为空,值自增
            onlineCount++;
        }
        // 将属性存储到上下文
        context.setAttribute("onlineCount", onlineCount);
        System.out.println("监听初始化");
    }

    // 销毁session监听
    // 一旦销毁Session,就触发一次这个事件
    @Override
    public void sessionDestroyed(HttpSessionEvent se) {
        // 过程与创建相反
        ServletContext context = se.getSession().getServletContext();
        Integer onlineCount = (Integer) context.getAttribute("onlineCount");
        // 如果为空,赋值为0
        if (onlineCount == null) {
            onlineCount = 0;
        } else {
            onlineCount--;
        }
        // 将属性存储到上下文
        context.setAttribute("onlineCount", onlineCount);
        System.out.println("监听销毁");
    }
    /*
        Session销毁:
        1.手动销毁:getSession().invalidate();
        2.自动销毁:设置web.xml
    */
}
  • JSP 页面获上下文属性:
<%=this.getServletConfig().getServletContext().getAttribute("onlineCount")%>
  • web.xml 中注册监听器:或用注解方式:@WebListener

    com.study.listener.OnlineCountListener

十三、过滤器、监听器常见应用

13.1 监听器在 GUI 中的应用

  • GUI 基础
  • 实例:监听器在 GUI 编程中使用;
public class TestPanel {
    public static void main(String[] args) {
        // 新建一个窗体
        Frame frame = new Frame("GUI 监听测试");
        // 面板
        Panel panel = new Panel(null);
        // 设置窗体的布局
        frame.setLayout(null);
        // 设置背景颜色
        frame.setBounds(300, 300, 500, 500);
        frame.setBackground(new Color(217, 217, 217));
        panel.setBounds(50, 50, 300, 300);
        // 设置背景颜色
        panel.setBackground(new Color(70, 142, 192));
        frame.add(panel);
        frame.setVisible(true);
        // 监听事件:监听关闭事件
        frame.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }
        });
    }
}

13.2 Filter 实现权限拦截:

  • 过滤器在用户登录中的使用;
    • 用户登录后,向 Sesison 中放入用户的数据;
    • 进入主页时,判断用户是否已经登录,未登录,进行页面跳转;

测试:

  • JSP 页面:
<%--login.jsp--%>
<%--error.jsp--%>

没有权限,用户名错误

返回登录页面

<%--/sys/success.jsp--%>

登录成功

注销

  • 常量类:便于后期管理
public class Constant {
    public static final String USER_SESSION = "USER_SESSION";
}
  • Servlet:登录
@WebServlet("/login")
public class LoginServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 获取前端的请求参数
        String username = req.getParameter("username");

        if (username.equals("admin")) {
            // 登录成功:把属性值存入session
            req.getSession().setAttribute(Constant.USER_SESSION, req.getSession().getId());
            // 获取路径后,再拼接地址
            // 注意:如果路径用相对路径表示,”/“表示:http://localhost:8080,与转发的不同
            resp.sendRedirect(req.getContextPath()+"/sys/success.jsp");
        } else {
            // 登录失败
            // 请求转发
            // req.getRequestDispatcher("/error.jsp").forward(req,resp);
            // 重定向
            resp.sendRedirect(req.getContextPath()+"/error.jsp");
        }
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}
  • Servlet:注销
@WebServlet("/logout")
public class LogoutServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 获取session
        Object user_session = req.getSession().getAttribute(Constant.USER_SESSION);
        // 如果不为空,移除 Session 属性
        if (user_session != null) {
            req.getSession().removeAttribute(Constant.USER_SESSION);
        }
        // 重定向
        resp.sendRedirect(req.getContextPath() + "/login.jsp");
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}
  • 过滤器:
// 过滤所有sys下的请求
@WebFilter("/sys/*")
public class SysFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {
        // 类型转换:获取session,重定向
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) resp;
        // 过滤:所有session为空,跳转页面
        if (request.getSession().getAttribute(Constant.USER_SESSION) == null) {
            response.sendRedirect(request.getContextPath() + "/error.jsp");
        }
        chain.doFilter(req, resp);
    }

    @Override
    public void destroy() {
    }
}
  • 注册:web.xml 配置,或通过注解;

过滤器实现,不同用户登录不同页面

  • 思路:建立不同等级用户文件夹及页面,如:VIP1、VIP2、VIP3...;
  • 过滤器里设置,不同等级对应的跳转页面;
// 通过对象属性判断
if (request.getSession().getAttribute(Constant.USER_SESSION).Level == VIP1) {
    response.sendRedirect( "vip1/index.jsp");
}
if (request.getSession().getAttribute(Constant.USER_SESSION).Level == VIP2) {
    response.sendRedirect( "vip2/index.jsp");
}
if (request.getSession().getAttribute(Constant.USER_SESSION).Level == VIP3) {
    response.sendRedirect( "vip3/index.jsp");
}

十四、JDBC

  • JDBC 基础

14.1 实验环境搭建

  • 创建 MySQL 数据库:相关链接

  • 导入 JDBC 依赖:



    mysql
    mysql-connector-java
    8.0.28




  com.alibaba
  druid
  1.2.8

  • IDEA 中连接数据库:相关链接

14.2 JDBC 固定步骤

  • 相关链接
  1. 加载驱动;
  2. 连接数据库,代表数据库;
  3. 向数据库发送 SQL 的对象 Statement : CRUD;
  4. 编写 SQL(根据业务,不同的 SQL);
  5. 执行 SQL;
  6. 关闭连接;

14.3 事务

  • 相关链接

14.4 Junit 单元测试

  • Junit 依赖:

    
    
        junit
        junit
        4.13.2
    
    
  • 使用方式:

    • @Test 注解,只有在方法上有效;
    • 只要加了这个注解的方法,不需要 main 方法,就可以直接运行;
    @Test
    public void test(){
        System.out.println("Hello World");
    }
    
    • 错误时,报红色信息;

你可能感兴趣的:(JavaWeb 基础)