Day20-会话技术&JSP


title: Day20-会话技术&JSP
date: 2020-08-03 17:47:51
author: 子陌


会话技术

  1. 会话:一次会话中包含多次请求和响应
    • 一次会话:浏览器第一次给服务器资源发送请求,会话建立,直到有一方断开为止
  2. 功能:在一次会话的范围内的多次请求间,共享数据
  3. 方式:
    1. 客户端会话技术:Cookie
    2. 服务器端会话技术:Session

会话

Cookie

客户端会话数据,将数据保存到客户端

  • 步骤:

    1. 创建Cookie对象,绑定数据

      new Cookie(String name, String value)

    2. 发送Cookie对象

      response.addCookie(Cookie cookie)

    3. 获取Cookie,拿到数据

      Cookie[] request.getCookies()

@WebServlet("/CookieServletDemo")
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    
    
    // 1. 创建Cookie对象,绑定数据
    Cookie cookie = new Cookie("msg", "hello");

    // 2. 发送Cookie对象
    response.addCookie(cookie);
}
@WebServlet("/CookieServletDemo1")
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    
    
    // 3. 获取Cookie,拿到数据
    Cookie[] re = request.getCookies();
    if (re != null){
    
    
        for (Cookie cookie1 : re) {
    
    
            System.out.println(cookie1.getName() + ":" + cookie1.getValue());
        }
    }
}

Cookie实现原理

cookie原理解析

Cookie细节:

  1. 一次可以发送多个cookie,创建多个cookie,调用多次addcookie对象即可

  2. cookie在浏览器中能保存多长时间

    • 默认情况下,当浏览器关闭后,Cookie数据被销毁
    • 持久化存储:setMaxAge(int seconds)
      • second,正数:将Cookie数据写到硬盘的文件中,持久化存储,存活时间为second
      • second,负数:默认值
      • second,0:删除cookie信息
  3. cookie能不能存中文

    • 在tomcat 8之前,不能存储
      • 需要将中文数据转码–一般采用URL编码(%E3)
    • 在tomcat 8之后,可以支持
  4. cookie获取范围

    • 前提:在同一个Tomcat服务器中,多个web项目

      • 默认情况下cookie不能共享,默认设置当前目录
      • setPath(String path) 如果要共享,设为setPath("/")目录下
    • 前提:不同Tomcat服务器中,多个web项目

      • setDomain(String path) 如果设置一级域名相同,那么多个服务器之间cookie可以共享

        例如:setDomain(".baidu.com"),那么tieba.baidu.com和news.baidu.com中cookie可以共享

  • Cookie的特点和作用

    1. cookie存储数据在客户端浏览器
    2. 浏览器对于单个cookie的大小有限制(4KB)以及对用一个域名下的总cookie数量也有限制(20个)
    • 作用:
      1. cookie一般用于存储少量不太敏感的数据
      2. 在不登录的情况下,完成服务器对客户端的身份识别
  • 案例:记住上一次的访问时间
    • 需求:
      1. 访问一个servlet,如果是第一次访问,提示:您好,欢迎首次访问
      2. 如果不是第一次访问,提示:欢迎回来,您上次访问时间为:显示时间字符串
    • 分析:
      1. 可以采用Cookie完成
      2. 在服务器servlet中判断是否有名为lastTime的cookie
        • 有:欢迎回来
        • 没有:首次访问
package com.zimo.cookie;

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 javax.xml.crypto.Data;
import java.io.IOException;
import java.net.URL;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.logging.SimpleFormatter;

/**
 * cookie快速入门
 */
@WebServlet("/CookieServletDemo2")
public class CookieServletDemo2 extends HttpServlet {
    
    
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    
    
        response.setContentType("text/html;charset=utf-8");
        // 1. 获取所有的cookie
        Cookie[] cookies = request.getCookies();
        // 2. 遍历cookie数组
        boolean flag = false;
        if (cookies != null && cookies.length > 0){
    
    
            for (Cookie cookie : cookies) {
    
    
                // 3. 获取cookie名称
                String name = cookie.getName();
                if ("lastTime".equals(name)){
    
    
                    flag = true;
                    // 响应数据
                    String value = cookie.getValue();
                    String decode = URLDecoder.decode(value, "utf-8");
                    response.getWriter().write("欢迎回来,您上次访问时间为:" + decode);
                    // 设置新的cookie
                    Date date = new Date();
                    SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
                    String format = simpleDateFormat.format(date);
                    String encode = URLEncoder.encode(format, "utf-8");
                    cookie.setValue(encode);
                    // 设置存活时间
                    cookie.setMaxAge(60*60*24*30);
                    response.addCookie(cookie);
                    break;
                }
            }
        }
        if (cookies == null || cookies.length == 0 || !flag){
    
    
            // 设置新的cookie
            Date date = new Date();
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
            String format = simpleDateFormat.format(date);
            String encode = URLEncoder.encode(format, "utf-8");
            Cookie cookie = new Cookie("lastTime", encode);
            // 设置存活时间
            cookie.setMaxAge(60*60*24*30);
            response.addCookie(cookie);
            response.getWriter().write("您好,欢迎首次访问!");
        }
    }
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    
    
        doPost(request,response);
    }
}
  • 使用jsp进行修改案例
<%@ page import="java.net.URLDecoder" %>
<%@ page import="java.util.Date" %>
<%@ page import="java.text.SimpleDateFormat" %>
<%@ page import="java.net.URLEncoder" %><%--
  Created by IntelliJ IDEA.
  User: zimo
  Date: 2020/8/4
  Time: 11:22
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>home</title>
</head>
<body>
<%
    response.setContentType("text/html;charset=utf-8");
    // 1. 获取所有的cookie
    Cookie[] cookies = request.getCookies();
    // 2. 遍历cookie数组
    boolean flag = false;
    if (cookies != null && cookies.length > 0){
        for (Cookie cookie : cookies) {
            // 3. 获取cookie名称
            String name = cookie.getName();
            if ("lastTime".equals(name)){
                flag = true;
                // 响应数据
                String value = cookie.getValue();
                String decode = URLDecoder.decode(value, "utf-8");
                out.write("欢迎回来,您上次访问时间为:" + decode);
                // 设置新的cookie
                Date date = new Date();
                SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
                String format = simpleDateFormat.format(date);
                String encode = URLEncoder.encode(format, "utf-8");
                cookie.setValue(encode);
                // 设置存活时间
                cookie.setMaxAge(60*60*24*30);
                response.addCookie(cookie);
                break;
            }
        }
    }
    if (cookies == null || cookies.length == 0 || !flag){
        // 设置新的cookie
        Date date = new Date();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
        String format = simpleDateFormat.format(date);
        String encode = URLEncoder.encode(format, "utf-8");
        Cookie cookie = new Cookie("lastTime", encode);
        // 设置存活时间
        cookie.setMaxAge(60*60*24*30);
        response.addCookie(cookie);
        out.write("您好,欢迎首次访问!");
    }
%>
</body>
</html>

Session

服务器端会话技术,在一次会话的多次请求间共享数据,将数据保存在服务器的对象中。HttpSession

  • 快速入门:
    1. 获取HttpSession对象:
      • HttpSession session = request.getSession();
    2. 使用HttpSession对象:
      1. Object getAttribute(String name)
      2. void setAttribute(String name, Object value)
      3. void removeAttribute(String name)

Session原理

服务器如何确保在一次会话范围内,多次获取的Session对象是同一个

Session是依赖Cookie的

session

Session细节

  1. 当客户端关闭后,服务器不关闭,两次获取session是否为同一个
    • 默认情况下,不是。
    • 可以通过创建Cookie,键为JSESSIONID,设置最大存活时间,让cookie持久化保存
      • Cookie c = new Cookie("JSESSIONID", session.getId())
      • c.setMaxAge(60*60)
      • response.addCookie(c)
  2. 当客户端不关闭后,服务器关闭,两次获取session是否为同一个
    • 不是同一个,关闭后session被销毁
    • 要确保数据不丢失,如何实现?
      • session的钝化:正常关闭之前,将session对象序列化到硬盘上
      • session的活化:服务器启动后,将session文件转化为内存中的session对象即可
    • tomcat会自动钝化和活化而idea不会
  3. session的销毁或失效时间
    1. 服务器关闭
    2. session对象调用invalidate()。
    3. session默认失效时间:30分钟
      • 选择性配置修改:web.xml
      • <session-config> <session-timeout>30</session-timeout> </session-config>
  4. session的特点:
    1. session用于存储一次会话的多次请求的数据,存在服务器端
    2. session可以存储任意类型,任意大小的数据
  5. session和cookie的区别:
    1. session存储数据在服务器端,而cookie在客户端
    2. session没有数据大小限制,cookie有
    3. session数据安全,cookie相对于不安全
  • 案例:验证码
    • 需求:
      1. 访问带有验证码的登录页面login.jsp
      2. 用户输入用户名,密码及验证码
        • 如果用户名和密码输入有误,跳转登录页面,提示:用户名或密码错误
        • 如果验证码输入有误,跳转登录页面,提示:验证码错误
        • 如果全部输入正确,则跳转到主页success.jsp,显示:用户名,欢迎您
    • 分析:
      • 设置request的编码
      • 获取参数map集合
      • 获取验证码
      • 用户信息封装到User对象
      • 判断验证码和用户输入的验证码是否一致
        • 从session获取程序生成的验证码
        • 一致,判断用户名密码是否一致,
          • 一致:存储数据session,跳转success.jsp重定向
          • 不一致:跳转登录页面
        • 不一致,跳转登录页面
<%--
  Created by IntelliJ IDEA.
  User: zimo
  Date: 2020/8/4
  Time: 16:43
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>login</title>
    <script>
        window.onload = function(){
            document.getElementById("img").onclick = function () {
                this.src = "/zimo/checkCodeDemo?time="+new Date().getTime();
            }
        }
    </script>
</head>
<body>
    <form action="/zimo/LoginServlet" method="post">
        <table>
            <tr>
                <td>用户名:</td>
                <td><input type="text" name="username"></td>
            </tr>
            <tr>
                <td>密码:</td>
                <td><input type="password" name="password"></td>
            </tr>
            <tr>
                <td>验证码:</td>
                <td><input type="text" name="checkcode"></td>
            </tr>
            <tr>
                <td colspan="2"><img id="img" src="/zimo/checkCodeDemo"></td>
            </tr>
            <tr>
                <td colspan="2"><input type="submit" name="登录"></td>
            </tr>
        </table>
    </form>
    <div><%=request.getAttribute("cc_err") == null ? "" : request.getAttribute("cc_err")%></div>
    <div style="color: red"><%=request.getAttribute("login_err") == null ? "" : request.getAttribute("login_err")%></div>
</body>
</html>
<%--
  Created by IntelliJ IDEA.
  User: zimo
  Date: 2020/8/4
  Time: 17:51
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>home</title>
</head>
<body>
    <h1><%=request.getSession().getAttribute("user")%>,欢迎你</h1>
</body>
</html>
package com.zimo.checkCode;
import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Random;

@WebServlet("/checkCodeDemo")
public class CheckCodeServlet extends HttpServlet {
    
    
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
        doPost(req, resp);
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
        int width = 100;
        int height = 50;
        // 1.创建对象,在内存中画图(验证码图片对象)
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        // 2.美化图片
        // 2.1 填充背景色
        Graphics graphics = image.getGraphics();    // 获取画笔对象
        graphics.setColor(Color.PINK);  // 设置填充颜色
        graphics.fillRect(0, 0, width, height); // 填充范围
        // 2.2 画边框
        graphics.setColor(Color.blue);      // 设置画笔颜色
        graphics.drawRect(0, 0, width-1, height-1);
        // 2.3 写验证码
        String checkCode = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
        StringBuilder code = new StringBuilder();   // 存储生成的验证码
        Random random = new Random();
        for (int i = 1;i <= 4; i++) {
    
    
            int tmp = random.nextInt(checkCode.length());        // 生成随机角标
            char c = checkCode.charAt(tmp);    // 随机字符
            code.append(c);
            graphics.drawString(c+"", width/5*i, height/2);
        }
        String codeString = code.toString();
        // 将验证码存入session
        req.getSession().setAttribute("checkCode", codeString);
        // 2.4 画干扰线
        graphics.setColor(Color.GREEN);
        for (int i=0; i< 10; i++){
    
    
            // 随机生成坐标点
            int x1 = random.nextInt(width);
            int x2 = random.nextInt(width);
            int y1 = random.nextInt(height);
            int y2 = random.nextInt(height);
            graphics.drawLine(x1,y1,x2,y2);
        }
        // 3.将图片输出页面展示
        ImageIO.write(image, "jpg", resp.getOutputStream());
    }
}
package com.zimo.checkCode;

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

@WebServlet("/LoginServlet")
public class LoginServlet extends HttpServlet {
    
    
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    
    
        // 1.设置request编码
        request.setCharacterEncoding("utf-8");
        // 2.获取参数map
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        String checkcode = request.getParameter("checkcode");
        // 3.先判断验证码是否正确
        // 获取生成的验证码
        String sessionCheck = (String)request.getSession().getAttribute("checkCode");
        // 让验证码失效,下次不能使用
        request.getSession().removeAttribute("checkCode");
        if (null != sessionCheck && sessionCheck.equalsIgnoreCase(checkcode)){
    
    
            // 忽略大小写
            if ("admin".equals(username) && "123456".equals(password)){
    
    
                response.sendRedirect(request.getContextPath() + "/login/success.jsp");
                request.getSession().setAttribute("user", username);
            }else {
    
    
                request.setAttribute("login_err", "用户名或密码错误!");
                request.getRequestDispatcher("/login/login.jsp").forward(request, response);
            }
        }else {
    
    
            // 验证失败
            // 存储提示信息
            request.setAttribute("cc_err", "验证码错误!");
            // 转发到登录页面
            request.getRequestDispatcher("/login/login.jsp").forward(request, response);
        }
    }
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    
    
        doPost(request, response);
    }
}

JSP入门

Java Server Page: Java服务器端页面,一个特殊的页面,既可以写html标签,又可以写Java代码

  • 用于简化书写!

JSP原理:

jsp本质上就是一个servlet

jso原理解析

JSP脚本

  • jsp定义Java代码的方式:
    1. <% java code %>:定义在service方法中,在service方法中可以定义什么,该脚本就可以定义什么
    2. <%! java code %>:定义的Java代码,在jsp转换后的Java类的成员位置
    3. <%= java code %>:定义的Java代码,会输出到页面上。输出语句中可以定义什么,该脚本就可以定义什么

JSP内置对象

  • 在jsp页面中不需要创建和获取,可以直接使用的对象

  • 指令:

    • 作用:用于配置jsp页面,导入资源文件
    • 格式:<%@ 指令名称 属性名1=属性值1 属性名2=属性值2... %>
    • 分类:
      1. page:用于配置jsp页面
        • contentType:等同于response.setContentType(),设置响应体的mime类型及字符集,设置当前jsp页面的编码
        • import:导包
        • errorPage:当前页面发生异常后,会自动跳转到指定的错误页面
        • isErrorPage:
          • true:是,可以使用exception对象
          • false:否。默认值。不可以使用内置对象exception
      2. include:页面包含的。导入页面的资源文件
        • <%@include file="top.jsp"%>
      3. taglib:导入资源
        • <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
          • prefix:前缀,自定义的
  • 注释:

    • html注释:<!-- -->,只能注释html代码片段
    • jsp注释:<%-- --%>,可以注释所有
  • jsp一共有9个内置对象:

    不需要创建直接使用

    1. request(类型:HttpServletRequest):一次请求访问的多个资源(转发)
    2. response(类型:HttpServletResponse):响应对象
    3. out(类型:JspWriter):字符输出流对象。可以讲数据输出到页面上,和response.getWriter()类似
      • response.getWriter()和out.write()区别:tomcat服务器再给客户端做出响应之前,会先找response缓冲区数据,再找out缓冲区数据
      • response.getWriter()数据永远在out.write()之前
    4. pageContext(类型:PageContext):当前页面共享数据,还可以获取其他八个内置对象
    5. session(类型:HttpSession):一次会话的多个请求间
    6. application(类型:ServletContext):所有用户间共享数据
    7. page(类型:Object):当前页面(servlet)的对象 this
    8. config(类型:ServletConfig):servlet的配置对象
    9. exception(类型:Throwable):异常对象

MVC开发模式

  1. jsp演变历史

    1. 早期只有servlet,只能使用response输出标签数据,非常麻烦
    2. 后来有jsp,简化了servlet的开发,如果过度使用jsp,造成难于维护分工协作
    3. 再后来,Javaweb开发,借鉴mvc开发模式,使得程序的设计更加合理性
  2. MVC:

    1. M:Model,模型(JavaBean)
      • 完成具体的业务操作,如:查询数据库,封装对象
    2. V:View,视图(JSP)
      • 展示数据
    3. C:Controller,控制器(Servlet)
      1. 获取客户端的输入
      2. 调用模型
      3. 将数据交给视图展示
    • 优缺点:

      优点:

      1. 耦合性低,方便维护,可以利于分工协作
      2. 重用性高

      缺点:

      1. 使得项目架构变得复杂,对开发人员要求高

MVC模型

EL表达式

  1. 概念:Expression Language表达式语言

  2. 作用:替换和简化jsp页面中Java代码的编写

  3. 语法:${表达式}

  4. 注意:jsp默认支持EL表达式

    1. 忽略EL表达式:<%@ page isELIgnored="true"%>
    2. \${表达式}:忽略这个表达式
  5. 使用:

    1. 运算:

      • 算术运算符【+,-,*,/(div),%(mod)】

      • 比较运算符【>,<,>=,<=,==,!=】

      • 逻辑运算符【&&(and),||(or),!(not)】

      • 空运算符:empty

        • **功能:**用于判断字符串、集合、数组对象是否为null并且长度是否为0

        • 用法:${empty str}判断str是否为空,或长度是否为0

          ${not empty str}判断str不为空,且长度是否为不0

    2. 获取值:

      1. el表达式只能从域对象中获取值

      2. 语法:

        • ${域名称.键名}:从指定域中获取指定键的值
          • 域名称:
            1. pageScope:pageContext对象中获取
            2. requestScope:request对象中获取
            3. sessionScope:session对象中获取
            4. applicationScope:application对象中获取
          • 例如:再request域中存储name = “张三”
          • 获取:${request.name}
        • ${键名}:表示依次从最小的域中查找是否有该对应的值,直到找到为止
          • 获取:${name}
        • 获取对象、List集合、Map集合的值
          • 对象:${域名称.键名.属性名}本质上会去调用getter方法
          • List集合:${域名称.键名[索引]}
          • Map集合:${域名称.键名["key名称"]}${域名称.键名.key名称}
      3. 隐式对象:el表达式有11个隐式对象

        1. ${pageContext.属性}:同样可以获取到其他的8个对象

          再jsp动态获取虚拟目录${pageContext.request.contextPath}

JSTL标签

  • 概念:JavaServer Page Tag Library JSP标准标签库

    是由Apache组织提供的开源的免费的jsp标签

  • 作用:用于简化和替换jsp页面上的Java代码

  • 使用步骤:

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

    • if:相当于Java if语句
      • 属性:test必须属性,接收boolean表达式,如果结果为true,则显示标签内容
      • 一般情况下根据el表达式一起使用
      • 该标签没有else情况
    • choose:相当于Java switch语句
      • choose:相当于switch
      • when:相当于case
      • otherwise:相当于default
    • foreach:相当于Java for循环
      • begin:开始值(包含)
      • end:结束值(包含)
      • var:临时遍历(相当于i)
      • step:步长1(相当于i++)
      • varStatus:循环状态对象
        • index:容器中元素的索引,从0开始
        • count:循环的次数,从1开始
      • 容器对象遍历:
        • items:容器对象
        • var:容器临时变量
<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %>
<html>
    <head>
        <title>JSTL标签</title>
    </head>
    <bdoy>
        <%--
    		c:if标签
    			1.属性:
    				* test必须属性,接收boolean表达式,如果结果为true,则显示标签内容
    	--%>
        <c:if test="true">aaaaaaaaaaaa</c:if>
        <%
        	List list = new ArrayList();
        	list.add("aaaa");
        	request.setAttribute("list",list)
        %>
        <c:if test="${not empty list}">遍历集合</c:if>
        
        <%-- choose标签 --%>
        <%
        	request.setAttribute("week", 3);
        %>
        <c:chooes>
            <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:chooes>

        <%--
    		c:foreach标签
    			1.属性:
    				* begin:开始值(包含开始)
    				* end:结束值(包含结束)
    				* var:临时变量相当于i
    				* stee:步长
    				* varStatus:.index元素索引  .count循环次数
    	--%>
        <c:forEach begin="1" end="10" step="1" var="i" varStatus="s">
            ${i} <span>${s.index}</span><br/>
        </c:forEach>
         <%--
    		for(User u : uList)
    		c:foreach标签遍历容器
    			1.属性:
					* items:容器对象 uList
					* var:容器中元素临时变量 u
    	--%>       
        <%
        	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">
            ${str}<span>${s.index}${s.count}</span><br/>
        </c:forEach>
    </bdoy>
</html>

三层架构

软件设计架构

  1. 界面层(表示层):用户看得见得界面。用户可以通过界面上的组件和服务器进行交互
  2. 业务逻辑层:处理业务逻辑的
  3. 数据访问层:操作数据存储文件

三层架构

案例:用户信息列表展示

  1. 需求:用户信息的增删改查操作

  2. 设计:

    • 技术选型:Servlet+JSP+MySQL+JDBCTemplate+Druid+BeanUtils+Tomcat
    • 数据库设计:user表创建
    CREATE DATABASE test;
    USE test;
    CREATE TABLE USER (
    	id INT PRIMARY KEY AUTO_INCREMENT,
    	NAME VARCHAR(20) NOT NULL,
    	gender VARCHAR(5),
    	age INT,
    	addr VARCHAR(32),
    	qq VARCHAR(20),
    	email VARCHAR(50)
    );
    
  3. 开发:

    • 环境搭建:创建数据库环境
    • 创建项目:导入需要的jar包
    • 编码
  4. 测试

  5. 部署

  • 添加

增加联系人

  • 删除

删除联系人

  • 删除选中

删除选中

  • 修改

修改联系人

  • 分页功能

分页功能

Filter:过滤器

当访问服务器资源时,过滤器可以将请求拦截下来,完成一些特殊功能。

  • 过滤器的作用:
    • 一般用于完成通用的资源:如登录验证、设置编码、敏感字符过滤等…
  • 步骤:
    • 定义一个类,实现接口Fileter
    • 复写方法
    • 配置:拦截路径
      1. web.xml
      2. 注解:@WebFilter("/*"):访问所有资源之前都会执行该过滤器
package com.zimo.filter;

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

/**
 * Filter快速入门
 */
@WebFilter("/*")    // 访问所有资源之前都会执行该过滤器
public class FilterDemo implements Filter {
    
    
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    
    
    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
    
    
        // 对request对象请求消息增强
        System.out.println("我来了");
        // 放行
        chain.doFilter(req, resp);
        // 对response对象请求消息增强
        System.out.println("我走了");
    }

    @Override
    public void destroy() {
    
    
    }
}

过滤器细节:

  1. web.xml配置

    <filter>
        <filter-name>filterDemo1</filter-name>
        <filter-class>com.zimo.filter.FilterDemo1</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>filterDemo1</filter-name>
        <url-pattern>/*</url-pattern>	<!-- 拦截路径 -->
    </filter-mapping>
    
  2. 过滤器执行流程

    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
          
          
        // 对request对象请求消息增强
        System.out.println("before");
        // 放行
        chain.doFilter(req, resp);
        // 对response对象请求消息增强
        System.out.println("after");
    }
    
  3. 过滤器生命周期方法

        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
          
          
            System.out.println("服务器启动,创建Filter对象时,只执行一次,一般用于加载资源");
        }
    
        @Override
        public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) {
          
          
    		System.out.println("多次请求,多次拦截,每次拦截执行一次");
        }
    
        @Override
        public void destroy() {
          
          
            System.out.println("服务器关闭后,Filter对象被销毁,只执行一次,一般用于释放资源");
        }
    
  4. 过滤器配置详解

    1. 拦截路径配置:

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

      1. 注解配置:设置dispatcherTypes属性

        • REQUEST:默认值。浏览器直接请求资源

          @WebFilter(value="/index.jsp", dispatcherTypes=Dispatcher.REQUEST)

        • FORWARD:转发访问资源

          @WebFilter(value="/index.jsp", dispatcherTypes=Dispatcher.FORWARD)

        • INCLUDE:包含访问资源

        • ERROR:错误跳转资源

        • ASYNC:异步访问资源

      2. web.xml:

        <filter>
            <filter-name>filterDemo1</filter-name>
            <filter-class>com.zimo.filter.FilterDemo1</filter-class>
        </filter>
        <filter-mapping>
            <filter-name>filterDemo1</filter-name>
            <url-pattern>/*</url-pattern>	<!-- 拦截路径 -->
            <dispatcher>REQUEST</dispatcher>
        </filter-mapping>
        
  5. 过滤器链(配置多个过滤器)

    1. 执行顺序:如果有n个过滤器,执行方式跟递归类似,123 资源 321
    2. 先后顺序:
      • 注解配置:按类名的字符串比较规则,值小先执行
      • xml配置:谁定义(<filter-mapping>)在上面,谁先执行

Listener:监听器

web三大组件之一:Servlet、Filter、Listener

  • 事件监听机制:

    • 事件:一件事
    • 事件源:事件发生的地方
    • 监听器:一个对象
    • 注册监听:将事件、事件源、监听器绑定在一起。当事件源上发生某个事件后,执行监听器代码
  • ServletContextListener:监听ServletContext对象的创建和销毁

    • void contextDestroyed(ServletContextEvent sce):ServletContext对象被销毁之前调用该方法
    • void contextInitialized(ServletContextEnent sce):ServletContext对象创建后会调用该方法
  • 步骤:

    1. 定义一个类,实现ServletContextListener接口

    2. 复写方法

    3. 配置

      1. web.xml:

        <!-- 注册监听器 -->
        <listener>
            <listener-class>com.zimo.listener.ContextLoaderListener</listener-class>
        </listener>
        <!-- 指定初始化参数 -->
        <context-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/classes/applicationContext.xml</param-value>
        </context-param>
        
      2. 注解:@WebListener

        package com.zimo.listener;
        
        import javax.servlet.ServletContext;
        import javax.servlet.ServletContextEvent;
        import javax.servlet.ServletContextListener;
        import javax.servlet.annotation.WebListener;
        import java.io.FileInputStream;
        import java.io.FileNotFoundException;
        
        @WebListener
        public class ContextLoaderListener implements ServletContextListener {
                  
                  
            @Override
            public void contextInitialized(ServletContextEvent servletContextEvent) {
                  
                  
                System.out.println("ServletContextEvent对象被创建了");
                // 加载资源文件
                // 1.获取ServletContext对象
                ServletContext servletContext = servletContextEvent.getServletContext();
                // 2.加载资源文件
                String contextConfigLocation = servletContext.getInitParameter("contextConfigLocation");
                // 3.获取真实路径
                String realPath = servletContext.getRealPath(contextConfigLocation);
                // 4.加载进内存
                try {
                  
                  
                    FileInputStream fileInputStream = new FileInputStream(realPath);
                } catch (FileNotFoundException e) {
                  
                  
                    e.printStackTrace();
                }
            }
        
            @Override
            public void contextDestroyed(ServletContextEvent servletContextEvent) {
                  
                  
                System.out.println("ServletContextEvent对象被销毁了");
            }
        }
        

猜你喜欢

转载自blog.csdn.net/qq_38205875/article/details/109097339