week13_day01_Jsp&&Listener

关于昨天作业的分析:
在这里插入图片描述

1.JSP
Java Server Pages是java动态页面的规范。tomcat做了实现。
jsp的特点:
1.就可以把jsp当做html来对待,但是它相较于html还有很大的优势
2.这里面可以嵌套java代码,然后显示动态数据
3.java代码不可以随意的书写,需要在特殊的标签里才有效

1.1.jsp原理
从本质上来说,jsp也就是servlet。
从访问http://localhost:8080/index.jsp开始分析。
1.当前请求会交给谁?tomcat里面配置了一个servlet,它的url-pattern是*.jsp *.jspx,所以当前请求会交给它
2.这个servlet其实就是jsp引擎。该引擎做了一个什么事情呢?首先根据你访问的资源index.jsp,到指定目录下去寻找该文件,如果找得到,则将该文件翻译成java文件(其实就是servlet,形成index_jsp.java文件),之后再经过编译,形成index_jsp.class文件
3.会调用servlet的service方法,然后显示出页面里面的数据

1.1.1.既然jsp本质来说就是servlet,那么在哪?
在这里插入图片描述
该目录就是IDEA复制tomcat配置文件,开启新的tomcat的目录。
查看java文件源码,发现的确就是servlet。
index_jsp.java:
在这里插入图片描述
HttpJspBase是继承自HttpServlet的,所以jsp本质上也是Servlet
在这里插入图片描述
Servlet三要素:init、service、destroy
在这里插入图片描述
service方法就是调用Writer写出数据到响应报文中。
在这里插入图片描述
对于绝大多数的数据,完全是直接包裹起来,写给客户端
只是在jsp一些特殊标签里面,会做一些处理。

1.1.2.既然jsp也是servlet,为什么大费周章地去弄一个jsp
利用各自的长处,各司其职。代码会比较容易进行维护。逻辑代码变更不会影响到页面代码,页面代码需要维护,也不会一不小心影响到逻辑代码。

不管是JSP还是Servlet,虽然都可以用于开发动态web资源。但由于这2门技术各自的特点,在长期的软件实践中,人们逐渐把servlet作为web应用中的控制器组件来使用,而把JSP技术作为数据显示模板来使用。
其原因为,程序的数据通常要美化后再输出:
让JSP既用java代码产生动态数据,又做美化会导致页面难以维护。
让servlet既产生数据,又在里面嵌套html代码美化数据,同样也会导致程序可读性差,难以维护。
因此最好的办法就是根据这两门技术的特点,让它们各自负责各得,servlet只负责响应请求产生数据,并把数据通过转发技术带给jsp,数据的显示jsp来做。
在这里插入图片描述

1.2.jsp语法
jsp其实就是将绝大多数的代码原封不动的发送给客户端,让客户端去处理,但是自己只会去处理一部分,这部分其实就是jsp语法。

1.2.1.jsp表达式
在这里插入图片描述
jsp表达式里面的java代码,会原封不动地被out.print方法包裹起来。最终翻译过后要符合java的语法。
1.2.2.jsp脚本片段
在这里插入图片描述

注释完全可以写
在这里插入图片描述
jsp脚本片段可以写多个,每一个的话允许不符合java语法,但是最终拼接出来的结果一定要符合java语法。
1.2.2.1.jsp脚本片段和jsp表达式是否都可以向客户端输出数据
jsp表达式肯定可以输出。脚本片段能不能输出,取决于你调不调用response相关代码。
out.print(i);就是response相关代码。

<%
  for (int i = 0; i < 10; i++) {
    out.print(i);
%>
  <h1>hello world</h1>
<%
  }
%>

1.2.3.jsp声明
在这里插入图片描述
1.2.4.jsp注释
是写在主体区域里面的,不能嵌套在jsp表达式、脚本片段、声明这些里面,只能写在页面的主体部分。
在这里插入图片描述
html注释会原封不动的翻译到客户端。
jsp注释,在翻译成为java代码时,就会消失。

1.3.jsp九大对象
在service方法内部会创建出来9个对象,可以直接供我们来使用。默认情况下只能看到8个,如果想看到第9个,需要设置isErrorPage=true
在这里插入图片描述
Request
Response
pageContext
Session
Exception
Application–servletContext
Config
Out
Page

演示session的时候,我把项目完成以后打开页面的勾选去掉了,为什么?和jsp有关系。不让它自动去打开jsp页面。
如果让jsp页面自动打开,那么就会去创建一个session,创建了session,后面在servlet中演示的时候,就会看不到创建session的过程。

1.3.1.pageContext对象
九大对象中最为核心的一个对象。通过该对象可以获得其他八个对象。

1.3.1.1.API
本身也是一个域。Request、session、application。
该域大小是当前页面内。
1.域API
在这里插入图片描述

2.可以给其他域赋值
第三个参数表示一个范围,通过设定这个参数给其他域赋值。
在这里插入图片描述

如果让你来实现,你怎么实现?

setAttribute(key,value,scope){
	If(scope ==1){
		pageContext.setAttribute(key,value)
	}else if(scope == 2){
	pageContext.getRequest.setAttribute(key,value)
	}
}

3.findAttribute
演示步骤:
Object.jsp:
在这里插入图片描述
Page.jsp:
在这里插入图片描述

  1. 首先在当前页面内先不转发,直接打印pageContext.findAttribute(“name”)
    显示的是page
  2. 调用转发,然后在被转发页面打印该语句,显示的是request
  3. 直接访问被转发页面page.jsp,打印的是session
  4. 在page.jsp中调用session.invalidate,打印的是application

得出结论:
一级一级去查找。从最小域pageContext域开始,依次request、session、application域去查找,在某个域找到数据则结束,找不到则接着下一个,,,,,,

1.3.2.out对象
输出数据到客户端。带有缓存功能的Writer。
冲洗条件:
1.buffer缓冲区满
2.关闭buffer缓冲区
3.页面需要响应

Tip: out隐式对象的工作原理图
在这里插入图片描述
在这里插入图片描述
先输出ServletResponse.getWriter()中的数据,再输出out中的数据
我们可以关闭JspWriter对象的缓冲区功能,通过在page中设置buffer=”none”
为什么要有这个JspWriter对象的缓冲区呢?
减缓了频繁向response中进行书写。

Vue才是工作中真正的页面解决技术。
Jsp是比较老旧的技术

1.4.如何servlet debug
1.明确代码执行流程是什么样的?
2.找到servlet的入口,service方法(doGet或者doPost)(看form的method, a标签默认get请求)
3.在方法第一行打一个断点。
4.一步一步调试
5.该看的都看了之后,点击resume program,会直接执行到下一个断点,如果没有下一个断点,则直接全部执行完毕
登录案例:
Login.jsp:

<%--
  Created by IntelliJ IDEA.
  User: zsquirrel
  Date: 2020/6/29
  Time: 2:42 下午
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <form action="<%=request.getContextPath()%>/user" method="post">
        <%--type="hidden"意思就是可以用来传输数据,但是不会显示在页面上--%>
        <%--整个逻辑:这是登录界面,提交后跳转到/app/user--%>
        <input type="hidden" name="op" value="login">
        <input type="text" name="username"><br>
        <input type="password" name="password"><br>
        <input type="submit">
    </form>
</body>
</html>

UserServlet:

package com.cskaoyan.login;

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;
import java.io.UnsupportedEncodingException;

/**
 * @author shihao
 * @create 2020-06-30 21:23
 */
@WebServlet("/user")
//高内聚,低耦合
//相关联的代码写的紧密一些,模块和模块之间尽可能松散的耦合,不会产生过多的依赖
public class userServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String op = request.getParameter("op");
        //首先会来到这,因为刚开始我们就设定的op=login
        if ("login".equals(op)) {
            login(request, response);
        }
    }

    private void login(HttpServletRequest request, HttpServletResponse response) throws UnsupportedEncodingException {
        request.setCharacterEncoding("utf-8");
        //MIME类型,如果浏览器解析不了就会下载下来
        response.setContentType("text/html;charset=utf-8");
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        if ("admin".equals(username) && "admin".equals(password)) {
            request.getSession().setAttribute("username", username);
            request.getSession().setAttribute("password", password);
            //刷新到/app/info.jsp页面
            response.setHeader("refresh", "2,url=" + request.getContextPath() + "/info.jsp");
        }
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String op = request.getParameter("op");
        if ("logout".equals(op)) {
            //从infor.jsp页面中返回的数据中op=logout
            logout(request, response);
        }
    }

    private void logout(HttpServletRequest request, HttpServletResponse response) throws IOException {
        request.setCharacterEncoding("utf-8");
        response.setContentType("text/html;charset=utf-8");
        request.getSession().invalidate();
        response.getWriter().println("注销成功,调转回登录页面");
        response.setHeader("refresh", "2,url=" + request.getContextPath() + "/login.jsp");
    }
}

Info.jsp:

<%--
  Created by IntelliJ IDEA.
  User: Administrator
  Date: 2020/6/30
  Time: 21:02
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<%--超链接到/app/user?op=logout页面,这个时候op=logout--%>
欢迎您,<a href="<%=request.getContextPath()%>/user?op=logout"><%=session.getAttribute("username")%>点我注销</a>
</body>
</html>

2.Listener(监听器)–记住一个listener即可,过程能够掌握更好
监听器。这个listener是接下来Spring开始的入口。
现实生活中的案例:
监听对象:艺人明星
监听事件:吸毒嫖娼
监听器:朝阳人民群众
触发事件:报警

Web:
监听对象:ServletContext
监听事件:context创建和销毁
监听器:自己编写的一个监听器
触发事件:监听器里面的代码执行

20年前写好的代码是怎么知道去调用现在编写的一个方法的呢?

2.1.如何去编写一个listener呢?

  1. 编写一个类实现ServletContextListener接口
  2. 注册该Listener(@WebListener)

MyServletContextListener :

import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;

/**
 * @author shihao
 * @create 2020-06-30 22:41
 */
@WebListener
public class MyServletContextListener implements ServletContextListener {

    @Override
    public void contextInitialized(ServletContextEvent servletContextEvent) {
        System.out.println("context init");
    }

    @Override
    public void contextDestroyed(ServletContextEvent servletContextEvent) {
        System.out.println("context destroy");
    }
}

2.2.回调案例
员工老板。员工工作工作完成之后汇报给老板。
整一个leader接口,manager和boss都继承leader
Leader:

package update;

public interface Leader {

    void report();
}

Employee:

package update;

public class Employee {

    private Leader leader;

    public Employee(Leader leader) {
        this.leader = leader;
    }

    public void work(){
        System.out.println("员工在工作");
        System.out.println("........");
        System.out.println(".........");
        System.out.println(".........");
        leader.report();
    }
}

Test:

package update;

public class Test {

    public static void main(String[] args) {
        //Leader leader = new Boss();
        Leader leader = new Manager();
        // listener注册然后将其注入到context中
        Employee employee = new Employee(leader);
        // context.init()---内部 listener.contextInitialized
        employee.work();
    }
}

Listener的实现原理:
Listener 就可以类比以上代码的关系,ServletContext相当于employee,ServletContextListener相当于leader接口,MyServletContextListener相当于boss和manager类。
而注册listener就相当于在ServletContext的创建代码中有这么一段:listener.contextInitialized、在ServletContext的销毁代码中有这么一段:
Listener.contextDestroyed
在这里插入图片描述
listener分类:三个域对象创建销毁的listener

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

-玫瑰少年-

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

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

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

打赏作者

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

抵扣说明:

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

余额充值