(八)JSP 技术知识点总结(来自那些年的笔记)


目录


可能是JSP知识总结的最全的博客之一了,你想要寻找的知识,这里都有 ;

作者:淮左白衣

来源:笔者当时学web的笔记

时间:-2018年5月4日21:25:09

什么是 jsp

JSP全称是 java servlet pages,它和 servlet 技术一样,都是Sun公司定义的一种用于开发动态web页面的技术

  • 为什么jsp也是一种动态web资源的开发技术呢?

    jsp,虽然就像是在写HTML,但是jsp允许在页面中编写java代码,并且允许开发人员在页面中获取requestresponseweb开发常用对象,实现与浏览器的交互,所以jsp也是一种动态web资源的开发技术;

    例子:输出当前时间

Date date = new Date();
//这个out对象是可以直接使用的,它是JspWriter的实例
out.write(date.toLocaleString());

Jsp 调用和运行原理(简略版)

浏览器访问 jsp 页面时,Web 服务器是如何调用并执行一个jsp页面的?

首先知道,我们访问服务器的资源时,无论访问的是什么?比如访问的是HTML、jsp,其实我们访问的都是一个servlet,而不是真正的jsp、html ,因此,我们访问 jsp 其实就是去访问 servlet

Jsp在被访问的时候,服务器会将它 翻译为 servlet,转换后的servlet,被保存在服务器目录下的work/项目名/apache/…

提问:

  • web 服务器在执行jsp页面时,是如何把jsp页面中的HTML排版标签输出给浏览器的?

    这里其实是 jsp 对应的 servlet 的功劳,我们知道服务器会将jsp转为一个servlet 对象,我们去访问jsp的时候,实际访问到的也是这个servlet对象;

    在这个servlet对象对应的类中。它是通过out.writer()语句将 jsp 中的 HTML 语句,原封不动的打给浏览器;遇到<%java代码%>,就直接执行;

  • jsp页面中的java代码,服务器是如何执行的?

    是原封不动的,代码最后都在在servlet类中执行了;

  • Web服务器在调用jsp时,会给jsp提供一些什么java对象

    会提供许多对象;request、response、out、application、session等这些对象,在jsp中是直接可以使用的,因为在jsp对应的servlet类中已经提供好了
    如果想要获得jsp对应的servlet类的对象的自身,使用page,也是它内置提供的;

上面的几个问题,其实都可以翻看对应的 servlet 类的源码,,找到答案;


Jsp语法

  • Jsp模板元素

    Jsp 页面中的 HTML 内容称之为 jsp 模板元素。

    Jsp的模板元素定义了网页的基本骨架,即定义了页面的结构和外观;

下面的几个概念,分清楚了,别混淆;

  • Jsp脚本表达式

    语法:<%= xxxx %>

    jsp脚本表达用于将程序数据输出到客户端,只能写在一行

    Jsp引擎在翻译脚本表达式时,会将程序数据转成字符串,然后在相应的位置用out.print(...),将数据输出给客户端

    Jsp脚本表达式的变量或者表达式后面不能有分号 ,其实原因很简单,脚本表达式是要被放到 out.print(...) 里面的,在结尾加上一个 ; 会被输出,而我们并不想输出这个分号;

  • Jsp脚本片段

    jsp脚本片段用于在jsp页面中编写 多行 java代码;

    语法:

    <%
            多行java代码
    %>

注意jsp脚本片段中只能出现java代码,不能出现其他模板元素因为,jsp引擎在翻译jsp页面时,会将jsp脚本片段中的 java代码原封不动的放到 servlet_jspService 方法中。

jsp脚本片段中的java代码,必须严格遵守java语法!废话,最后被转到servlet中,java代码原封不动的;

在一个jsp页面中可以有多个脚本片段,在脚本片段之间是可以写上模板元素的;并且多个脚本片段之间的数据是共享的;(了解下底层原理,就知道为啥共享了

单个脚本片段中的java代码可以是不完整的,但是多个脚本片段中,java代码必须完整了 ;

  • Jsp声明

    在jsp中,脚本片段中java代码,都被翻译到servlet的jspService方法中了;

    那么假如,我们想要将java代码,写到jspService方法外面的话,就需要使用jsp声明了;

<%!
    java代码
%>

我们就可以为servlet类添加方法字段等属性了,但是一般没啥人使用这个技术;

  • Jsp注释

    格式:

<%--
    注释信息
--%>

JSP引擎在将 jsp 页面翻译成 servlet 程序时,会 忽略jsp页面中被注释的内容 ;注意是被jsp引擎翻译时,就抛弃了,也就是在servlet类中将没有这个注释的内容;但是你要是使用HTML的注释,就不行了;

  • Jsp指令

    jsp指令 是为 jsp引擎 而设计的。它们并不直接产生任何可见输出而只是告诉引擎如何处理jsp页面中的其余部分
    jsp2.0规范中共定义3个指令:

    今天2018年4月23日,jsp规范,早就不是2.0点了。需要注意下,但是不影响你学习JSP
    

    page指令
    Include指令
    taglib指令


Jsp指令简介

  • jsp指令的基本语法格式:
<%@ 指令 属性名=“值” %>

举例:

<%@ page contentType="text/html; ISO-8859-1" %>

如果一个指令有多个属性,这多个属性可以写在一个指令中,用 空格 分隔多个属性,也可以分开写 ;

下面讲解3大指令;


Page指令

page指令用于定义jsp页面的各种属性,无论page指令出现在jsp页面中的什么地方,它作用的都是整个jsp页面;

为了保持程序的可读性和遵循良好的编程习惯,page指令最好是放在整个jsp页面的初始位置。

Jsp2.0规范中定义的 page指令 的完整语法:

属性名 = “ 作 用
pageEncoding = "xxx" 指明翻译 jsp 的时候,使用 xxx 码表
contentType = "text/html;charset=UTF-8" 指明jsp翻译成的 servlet 文件,里面的 response 使用的码表
language = "java" 指明 jsp 页面中的语言是 java
extends = "xxx.class" 表名生成jsp翻译的servlet类继承自xxx,不过一般,继承自默认类,即可。不需要改动
import = "xxx" 表示,我们的java语句,需要导入的包,一般自动导包就好了,不用我们手动去指定这个属性
session = "false / true " false 表示,翻译过去的servlet中不要自动创建session 对象,目的是为了,在不需要 session 的情况下,避免生成 session,减轻服务器的压力。或者我们需要session对象,但是,我们想手动让服务器创建session对象的
buffer = "8kb / none / xx kb" out.print()的数据,不是直接写到浏览器中(效率太慢),还是先写到缓冲区中,再写到浏览器,buffer指定缓冲区的大小,默认是8kb
autoFlush = "false / true" 是否自动刷新缓冲区,默认为true
isThreadSafe = "true" 翻译过去的servlet是否是线程安全的,这个最TM奇怪了,默认为true。但是表示默认线程不安全
isErrorPage = "true" 表示该jsp是页面 错误处理 页面,属性值置为true时,jsp 翻译为 servlet时,会传进去一个异常对象,表示错误的异常;

作用 当服务器出错了,跳到错误页面(404页面),然后返回给浏览器,但这404是个正确的页面,服务器就会返回200状态码,我们 为了告知浏览器我们出错了,就在页面中加上这个属性值,服务器将返回500
isELIgnored = "true" 是否忽略 EL表达式
errorPage = "url" 用来指定当前页面出错时,跳转的界面。属性值必须使用相对路径,以 / 开头则相对当前 web 应用;没有 / 打头,则相对于当前页面;

当然,我们也可以在服务器的 web.xml 文件 使用<error-page>元素为整个web应用指定错误处理页面,其中的两个子标签,一个用于指明异常的类型(写全名),这个子标签还可以写成状态码,一个用于指明出现该异常。跳准的界面地址;

如果我们在 jsp 中写明了 errorPage 属性,那么web.xml文件中的错误处理配置,对此jsp不生效

Include指令

include 指令用于引入 jsp 页面,如果使用 include 引入其他 jsp 页面,那么 jsp 引擎将把这两个jsp翻译为一个servlet,所以,include指令引入通常也称为 静态导入

属性名 = “ 作 用
file = "url" 其中的file属性用于指定被引入文件的路径。路径以“/”开头,来表示当前web应用;

细节

  • 被引入的文件必须遵循jsp语法
  • 被引入的文件可以使用任意的扩展名,即使是HTML扩展名,jsp引擎还是会按照处理jsp页面的方式处理页面的内容;为了,见名思意,jsp规范建议使用 .jspf 作为静态导入文件的扩展名;
  • 由于使用.jspf指令会涉及到两个jsp页面,并会把2个jsp翻译为一个servlet,所有这两个jsp页面的指令不能冲突
  • 被导入的页面,不要包含HTML语句了,否则页面将不是一个完成的页面,会出现两个 <head> 这样的标签;

动态包含

语法: request.getRequestDispatcher("url").include(request,response);

这是在运行时包含,会将 每一个 jsp 都对应生成一个servlet也就是最终生成不止一个 servlet

我们一般选择静态导入,性能高 ;


taglib指令

在讲标签库的时候,再讲;


Jsp乱码问题

乱码产生的根由无外乎两种

  • jsp文件 保存的编码和服务器翻译 servlet 的时候的编码不一致
  • 浏览器的编码和翻译的servletresponse 的编码编码不一致;

解决方法<%@ page pageEncoding="utf-8" contentType="text/html;charset=UTF-8" %>

我们发现只要这两个地方使用相同的编码,乱码就不会产生;

pageEncoding=”xxx” 告诉服务器翻译时使用什么码表;

contentType="text/html;charset=UTF-8" 再告诉浏览器用什么码表打开 ;

其实可以不告诉浏览器用什么码表,因为 只要告诉服务器翻译的码表,服务器会自动将servlet的response的码表设为一致的;但是,我们还是写上吧


jsp运行原理(详细版)

每个jsp页面在 第一次 被访问时,web容器 都会把请求交给 jsp引擎(即一个java程序)去处理。Jsp引擎 先将 jsp 翻译成一个_jspServlet(实际上就是一个servlet),然后按照 servlet 的调用方式进行调用 ;

由于JSP第一次访问时,会被翻译成servlet,所有第一次访问通常会比较慢但是第二次访问,JSP引擎 如果发现 JSP 没有变化,就不再翻译,而是直接调用,所以程序的执行效率不会受到影响


JSP中的九大隐式对象

JSP引擎 在调用 JSP 对应的 _JspServlet 时,会 传递或创建 9个与WEB开发相关的对象供_JspServlet使用

JSP技术的设计者为了方便web开发人员在编写JSP页面时,获得这些对象的引用,特意定义了9个相应的变量,开发人员在JSP页面中通过这9个变量就可以快速的获得这9大对象的引用

这九大隐式对象就是:responserequestsessionapplication(ServletContext)page (jsp对象自身)、config(servlertConfig)exceptionout(JspWriter)PageContext

前面7个,在学JSP之前,都已经学过了,这里重点讲最后两个;

  • Out隐式对象

    作用Out隐式对象 用于向客户端发送文本数据;

    Out对象 是通过调用 PageContext 对象的 getOut() 方法返回的,其作用和用法与servletResponse.getWriter方法返回的 PrintWriter 对象非常相似。

    JSP页面中的out隐式对象的类型为JspWriterJspWriter相当于一种带缓存功能PrintWriter,设置JSP页面的page指令的buffer属性可以调整它的缓存大小,甚至关闭它的缓存(buffer属性的值为none);

    只有向out对象中写入了内容,且 满足如下任何一个条件时(相当于刷新缓冲区)out对象才会去调用servletResponse.getWriter方法,并且通过该方法返回PrinterWriter对象将out对象缓冲区中的内容 真正的写入 servlet引擎提供的缓冲区中(response缓冲区):

    条件
    √ 设置page指令的buffer属性关闭了out对象的缓存功能
    out对象的缓冲区已满 ;
    √ 整个JSP页面结束;

    备注
    Out对象输出的数据 可能滞后于 response.getWriter 对象输出的数据,原因就在于out对象自己的缓冲区;out对象的缓存区满了,才将数据刷新到response的缓冲区;服务器发现response缓冲区有数据,才会将数据发送到客户端


PageContext对象

jsp技术中最重要的一个对象,它代表jsp页面的运行环境

生命周期是一个jsp页面;

这个对象自身就封装可其他8大隐式对象的引用;(这个最厉害了)

它自身还是一个域对象,可以用来保存数据;

这个对象中,还封装了web开发中经常涉及到的一些常用操作,例如引入和跳转其他资源、检索其他域对象中的属性;


通过PageContext对象获得其他对象

通过 getXXX()方法;

PageContext对象中包含其他8大隐式对象的引用;

首先知道一个事实:JSP页面中是不应该出现java代码,良好的jsp中,是不应该出现一行java代码的;

但是有些时候,我们为了获取servlet传过来的数据,不得已要使用java代码,这时候,我们就需要一个技术:自定义标签;(以后会讲这个技术)

我们把java代码替换成一个自定义标签,这个标签对应着一个java类,我们需要把web中的这些对象传给java类,一个一个传,很麻烦的,因此,我们就直接传一个pageContext对象过去;


Javaweb的四个域

范围(从小到大
Page域: pageContext,最小的域,只能在页面中使用
Request域: 请求域
Session域: 会话级别的域
ServletContext域: 最大的域,在整个应用程序中可用

PageContext域的方法

获取数据

pageContext.getAttribute(String) ;

设置数据

pageContext.setAttribute(String,String);

移除数据

pageContext.removeAttribute(String);

PageContext跨域访问的方法

获取id对应的域的数据

pageContext.getAttribute(String,id) ;

设置id对应的域数据

pageContext.setAttribute(String,String,id);

移除id对应的域数据

pageContext.removeAttribute(String,id);

PageContext查找属性的方法

pageContext.findAttribute(String)

用于查找某个属性的属性值,它会依次从pagerequestsessionapplication四个域,从小到大的查找,在某个域中查到数据,即刻返回这个数据,不会再继续查下去。如果四个域都没查到,则返回null

这个方法,便利于我们可以在jsp中直接使用这个方法来查找数据,而不要去关注数据在哪一个域中;


引入和跳转到其他资源

PageContext类中定义了一个forward方法和两个include方法来分别简化和替代RequestDispatcher(...).forward方法和RequestDispatcher(...).include方法。

原始的操作

// forward
request.getRequestDispatcher("/xxx").forward(request, response);
// include
request.getRequestDispatcher("/xxx").include(request, response);

使用pageContext简化:

// forward
pageContext.forward("/xxx");
// include
pageContext.include("/xxxx");

方法接受的资源如果以 / 开头,/ 代表当前web应用;


JSP标签

JSP Action (JSP动作)它用于jsp页面中提供业务逻辑功能,避免在JSP页面中直接编写java代码,造成jsp页面难以维护

常用的三种标签:


// 动态包含
<jsp:include page=""> </jsp:include>  

 //跳转页面
<jsp:forward page="">    

// 负责带数据到另一个JSP页面中,value的值,可以是脚本表达式
// 一般和包含include便签一起使用
 <jsp:param name="" value=""></jsp:param>

// 将数据带到xxx.jsp 中
<jsp:include page="xxxx.jsp">  
    <jsp:param name="xxx" value="xxx"/>  
</jsp:include> 

其中 </jsp:forward> Jsp跳转 应用场景:

在配置欢迎首页的时候,是不让配置servlet的,只能配置成jsp 因此,在jsp中进行跳转页面;


映射JSP

<servlet>
    <servlet-name>myform</servlet-name>
    <!--Jsp的路径需要 / 来指认 -->
    <jsp-file>/form.jsp</jsp-file>
</servlet>
<servlet-mapping>
    <servlet-name>myform</servlet-name>
    <url-pattern>/myform.html</url-pattern>
</servlet-mapping>

JSP抽风时好时坏的原因

如果访问JSP的时候,出现服务器报错,紧接着再次访问,服务器又不报错的情况,像神经病一样一时好一时坏;

出现这样的问题的原因在于:JSP文件被我们写错了;并其写错之前,这个JSP曾经被我们正确写对过,并且在服务器中有翻译过的servlet,这样,当我们把JSP修改出错以后,再次访问,服务器发现JSP被修改过,就会重新翻译一次,生成新的servlet,覆盖之前的servlet。但是由于,JSP语法有错,无法被正确的翻译为servlet这样旧的servlet就不会被覆盖掉。还存在在服务器中

这样,当我们第一次访问的时候,服务器翻译JSP失败,就会爆错,但是我们紧接着,再次访问,服务器发现,这人怎么回事啊,我刚翻译完这个servlet啊,它就不会再次翻译servlet,而是把之前旧的servlet当成上一次翻译的servlet这个过程,跟JSP变没变,没有任何关系,应该是JSP设计者,为了减轻服务器的压力设计的),给我们;这就是我们第一次报错,紧接着再次访问,就正确的原因;

当我们,过一会再次访问,服务器就会发现,我曹这个JSP,我并没有翻译啊,就会再次翻译,然后,就会再次报错,周而复始,给我们的感觉就是JSP在抽风,时好时坏;


仿佛一下子回到了90年代的夏天,你光着上身,穿着大裤衩,一双简单的人字拖,摇着一把破旧的芭蕉扇,VCD里转动着盗版的碟片,满满都是广东香港泛滥到内地的流行歌曲和港片,手里的冰激凌在融化,碟片偶尔会卡,你拿起遥控摁了一下快进键,一下子就这么快进了十几年。
写的真好!

《over》


原文地址:https://www.cnblogs.com/young-youth/p/11665719.html