javaEE(6)_JSP

一、什么是JSP

1、JSP全称是Java Server Pages,它和servle技术一样,都是SUN公司定义的一种用于开发动态web资源的技术,只用JSP就可以开发动态web资源.

2、为什么JSP技术也是一种动态web资源的开发技术?

答:因为JSP技术允许在页面中嵌套java代码,以产生动态数据,并且web服务器在执行jsp时,web服务器会传递web开发相关的对象给jsp,jsp通过这些对象,可以与浏览器进行交互,所以jsp当然也是一种动态web资源开发技术.

3、强调一个概念:对现在的用户而言,认为通过浏览器看到的东西都是网页.但我们程序员心里要清楚,开一个浏览器访问网页,这些网页有可能是一个html页面(即静态web资源),也有可能是一个动态web资源(即servlet或jsp程序输出的).

4、JSP这门技术的最大的特点在于,写jsp就像在写html,但:
•它相比html而言,html只能为用户提供静态数据,而Jsp技术允许在页面中嵌套java代码,为用户提供动态数据.
•相比servlet而言,servlet很难对数据进行排版,而jsp除了可以用java代码产生动态数据的同时,也很容易对数据进行排版.
5、Jsp快速入门:在jsp页面中输出当前时间.观察jsp编译后的class文件,发现其实jsp就是servlet,jsp中嵌套的java代码会原封不动的放到JSP的service方法中.打印日期的jsp页面和编译后class源码:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" import="java.util.Date"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
    <%
        Date date = new Date();
    %>
    <%= date %>
</body>
</html>
package org.apache.jsp.jsp;

import java.io.IOException;
import java.util.Date;
import java.util.Map;
import javax.el.ExpressionFactory;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.jsp.JspApplicationContext;
import javax.servlet.jsp.JspFactory;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.SkipPageException;
import org.apache.jasper.runtime.HttpJspBase;
import org.apache.jasper.runtime.InstanceManagerFactory;
import org.apache.jasper.runtime.JspSourceDependent;
import org.apache.tomcat.InstanceManager;

public final class NewFile_jsp extends HttpJspBase
  implements JspSourceDependent
{
  private static final JspFactory _jspxFactory = JspFactory.getDefaultFactory();
  private static Map<String, Long> _jspx_dependants;
  private ExpressionFactory _el_expressionfactory;
  private InstanceManager _jsp_instancemanager;

  public Map<String, Long> getDependants()
  {
    return _jspx_dependants;
  }

  public void _jspInit() {
    this._el_expressionfactory = _jspxFactory.getJspApplicationContext(getServletConfig().getServletContext()).getExpressionFactory();
    this._jsp_instancemanager = InstanceManagerFactory.getInstanceManager(getServletConfig());
  }

  public void _jspDestroy()
  {
  }

  public void _jspService(HttpServletRequest request, HttpServletResponse response)
    throws IOException, ServletException
  {
    JspWriter out = null;

    JspWriter _jspx_out = null;
    PageContext _jspx_page_context = null;
    try
    {
      response.setContentType("text/html; charset=UTF-8");
      PageContext pageContext = _jspxFactory.getPageContext(this, request, response, 
        null, true, 8192, true);
      _jspx_page_context = pageContext;
      pageContext.getServletContext();
      pageContext.getServletConfig();
      pageContext.getSession();
      out = pageContext.getOut();
      _jspx_out = out;

      out.write("
");
      out.write("<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
");
      out.write("<html>
");
      out.write("<head>
");
      out.write("<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
");
      out.write("<title>Insert title here</title>
");
      out.write("</head>
");
      out.write("<body>
");
      out.write("	");

      Date date = new Date();

      out.write(13);
      out.write(10);
      out.write(9);
      out.print(date);
      out.write("
");
      out.write("</body>
");
      out.write("</html>");
    } catch (Throwable t) {
      if (!(t instanceof SkipPageException)) {
        out = _jspx_out;
        if ((out != null) && (out.getBufferSize() != 0)) try {
            out.clearBuffer(); } catch (IOException localIOException) {
          } if (_jspx_page_context != null) _jspx_page_context.handlePageException(t); else
          throw new ServletException(t);
      }
    } finally {
      _jspxFactory.releasePageContext(_jspx_page_context);
    }
  }
}
View Code

二、JSP技术在开发中该怎么去用

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

三、JSP语法

1、JSP模版元素

JSP页面中的HTML内容称之为JSP模版元素,JSP模版元素定义了网页的基本骨架,即定义了页面的结构和外观.
2、JSP脚本表达式
JSP脚本表达式(expression)用于将程序数据输出到客户端
语法:<%= 变量或表达式 %>

举例:当前时间:<%= new java.util.Date() %>
JSP引擎(把jsp翻译为servlet的程序,也就是tomcat)在翻译脚本表达式时,会将程序数据转成字符串,然后在相应位置用out.print(…) 将数据输给客户端.
JSP脚本表达式中的变量或表达式后面不能有分号(;).
3、JSP脚本片断
1>JSP脚本片断(scriptlet)用于在JSP页面中编写多行Java代码.语法:
<%
  多行java代码
%>
注意:JSP脚本片断中只能出现java代码,不能出现其它模板元素, JSP引擎在翻译JSP页面中,会将JSP脚本片断中的Java代码将被原封不动地放到Servlet的_jspService方法中.JSP脚本片断中的Java代码必须严格遵循Java语法.
2>在一个JSP页面中可以有多个脚本片断,在两个或多个脚本片断之间可以嵌入文本、HTML标记和其他JSP元素.例:
<%
  int x = 10;
  out.println(x);
%>
<p>这是JSP页面文本</p>
<%
  int y = 20;
  out.println(y);
%>

多个脚本片断中的代码可以相互访问,犹如将所有的代码放在一对<%%>之中的情况.如:out.println(x);

3>单个脚本片断中的Java语句可以是不完整的,但是,多个脚本片断组合后的结果必须是完整的Java语句,例:

<%
    for (int i=1; i<5; i++) {
%>
<H1>www.it315.org</H1>
<%
    }
%> 

4、JSP声明,一般很少使用

JSP页面中编写的所有代码,默认会翻译到servlet的service方法中, 而Jsp声明中的java代码被翻译到_jspService方法的外面.语法:
<%!
  java代码
%>
所以,JSP声明可用于定义JSP页面转换成的Servlet程序的静态代码块、成员变量和方法 .多个静态代码块、变量和函数可以定义在一个JSP声明中,也可以分别单独定义在多个JSP声明中.JSP隐式对象的作用范围仅限于Servlet的_jspService方法,所以在JSP声明中不能使用这些隐式对象,java脚本片段中是不能加方法,静态代码块等的,因为这些代码会被放到jsp的service方法中.
5、JSP注释
1>JSP注释的格式:<%-- 注释信息 --%>
2>JSP引擎在将JSP页面翻译成Servlet程序时,忽略JSP页面中被注释的内容.注意和HTML注释区别.
<%-- date --%> //jsp注释
<!-- date-->      //html注释,jsp中采用这个会增加网络流量,这个是打回浏览器后浏览器不显示.
6、JSP指令
1.JSP指令(directive)是为JSP引擎而设计的,它们并不直接产生任何可见输出,而只是告诉引擎如何处理JSP页面中的其余部分.在JSP 2.0规范中共定义了三个指令:•page指令•Include指令•taglib指令.
2.JSP指令的基本语法格式:
  <%@ 指令 属性名="" %>
  举例:<%@ page contentType="text/html;charset=gb2312"%>
如果一个指令有多个属性,这多个属性可以写在一个指令中,也可以分开写.例:
<%@ page contentType="text/html;charset=gb2312"%>
<%@ page import="java.util.Date"%><%@ page contentType="text/html;charset=gb2312" import="java.util.Date"%>

Page指令

page指令用于定义JSP页面的各种属性,无论page指令出现在JSP页面中的什么地方,它作用的都是整个JSP页面,为了保持程序的可读性和遵循良好的编程习惯,page指令最好是放在整个JSP页面的起始位置.
*JSP 2.0规范中定义的page指令的完整语法:
<%@ page 
[ language="java" ]  //页面嵌套的语言
[ extends="package.class" ]  //jsp servlet继承的包,一般不要修改
[ import="{package.class | package.*}, ..." ]  //jsp Servlet引入的包
[ session="true | false" ]   //是否引入session,ture的话,jsp引擎会传给jsp Session 对象
[ buffer="none | 8kb | sizekb" ]  //关于缓存
[ autoFlush="true | false" ]      //关于缓存
[ isThreadSafe="true | false" ]  //ture的话JSP servlet 会继承SingleThreadModel
[ info="text" ]      
[ errorPage="relative_url" ]  //JSP出错的错误页面(必须采用相对路径),web.xml也可设置
[ isErrorPage="true | false" ]  //true的话,JSP引擎会传给jsp错误的Excepiotn 对象
[ contentType="mimeType [ ;charset=characterSet ]" | "text/html ; charset=utf-8" ]//页面类型
[ pageEncoding="characterSet | ISO-8859-1" ] //页面采用的编码,只写这句就可解决JSP乱码问题
[ isELIgnored="true | false" ]  //是否支持使用el表达式
%>

include指令

include指令用于引入其它JSP页面,如果使用include指令引入了其它JSP页面,那么JSP引擎将把这两个JSP翻译成一个servlet.所以include指令引入通常也称之为静态引入.
语法:

<%@ include file="relativeURL"%>

其中的file属性用于指定被引入文件的相对路径.  file属性的设置值必须使用相对路径,如果以“/”开头,表示相对于当前WEB应用程序的根目录(注意不是站点根目录),否则,表示相对于当前文件.
细节:
被引入的文件必须遵循JSP语法.(被引入的jsp文件不要有架构性的标签,可以有指令)
被引入的文件可以使用任意的扩展名,即使其扩展名是html,JSP引擎也会按照处理jsp页面的方式处理它里面的内容,为了见明知意,JSP规范建议使用.jspf(JSP fragments)作为静态引入文件的扩展名.
由于使用include指令将会涉及到2个JSP页面,并会把2个JSP翻译成一个servlet,所以这2个JSP页面的指令不能冲突(除了pageEncoding和导包除外).

taglib指令

用于引入标签库。

四、JSP运行原理和九大隐式对象

1、每个JSP 页面在第一次被访问时,WEB容器都会把请求交给JSP引擎(即一个Java程序)去处理.JSP引擎先将JSP翻译成一个_jspServlet(实质上也是一个servlet) ,然后按照servlet的调用方式进行调用.

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

3、JSP引擎在调用JSP对应的_jspServlet时,会传递或创建9个与web开发相关的对象供_jspServlet使用.JSP技术的设计者为便于开发人员在编写JSP页面时获得这些web对象的引用,特意定义了9个相应的变量,开发人员在JSP页面中通过这些变量就可以快速获得这9大对象的引用.

4、JSP九大隐式对象与servlet的对应关系

request   HttpServletRequest
response  HttpServletResponse
session   HttpSession
application servletContext
config    servletConfig
out       JspWriter  ----->   PrintWriter
exception
page      this
pageContext

out隐式对象
1、out隐式对象用于向客户端发送文本数据.
2、out对象是通过调用pageContext对象的getOut方法返回的,其作用和用法与ServletResponse.getWriter方法返回的PrintWriter对象非常相似.
3、JSP页面中的out隐式对象的类型为JspWriter,JspWriter相当于一种带缓存功能的PrintWriter,设置JSP页面的page指令的buffer属性可以调整它的缓存大小,甚至关闭它的缓存.
4、只有向out对象中写入了内容,且满足如下任何一个条件时,out对象才去调用ServletResponse.getWriter方法,并通过该方法返回的PrintWriter对象将out对象的缓冲区中的内容真正写入到Servlet引擎提供的缓冲区中:
1>设置page指令的buffer属性关闭了out对象的缓存功能,2>out对象的缓冲区已满,3>整个JSP页面结束

5、out工作原理图,底层其实是调用response的writer回写给客户端的.


*开发的时候不用同时使用servlet中的Writer和Jsp中的out,否则可能打印到页面的内容会有先后问题,因为缓冲的原因.
pageContext对象

pageContext对象是JSP技术中最重要的一个对象,它代表JSP页面的运行环境,这个对象不仅封装了对其它8大隐式对象的引用,它自身还是一个域对象,可以用来保存数据.并且,这个对象还封装了web开发中经常涉及到的一些常用操作,例如引入和跳转其它资源、检索其它域对象中的属性等.
1、通过pageContext可以获得其它八大对象,它存在的意义是什么呢,因为我们可以直接在jsp中获得九大对象.它的意义在于统一管理入口,比如用在自定义标签中,我们只要传递这一个对象给标签解析器,标签就可获得其它所有对象而不需要传递所有的对象给标签,这应该是一种思想,很多地方有体现.

2、pageContext作为域对象(page域)

public void setAttribute(java.lang.String name,java.lang.Object value)
public java.lang.Object getAttribute(java.lang.String name)
public void removeAttribute(java.lang.String name)

3、pageContext对象中还封装了访问其它域的方法,同样的问题,我们可以直接获得相应域,为什么还要间接通过pageContext?同样的答案.

public java.lang.Object getAttribute(java.lang.String name,int scope)
public void setAttribute(java.lang.String name, java.lang.Object value,int scope)
public void removeAttribute(java.lang.String name,int scope)

上面方法会用到下面代表各个域的常量:

PageContext.APPLICATION_SCOPE
PageContext.SESSION_SCOPE
PageContext.REQUEST_SCOPE
PageContext.PAGE_SCOPE

4、findAttribute方法    (*重点,查找各个域中的属性),其实el表达式就是在各个域中查找.
5、web开发的四个域对象,重点,1>域的含义;2>生命周期;3>什么时候使用什么域

pageContext(称之为page域) 
request(称之为request域)
session(称之为session域)
servletContext(称之为application域)

6、PageContext类中定义了一个forward方法和两个include方法来分别简化和替代RequestDispatcher.forward方法和include方法,传递给这些方法的资源路径都只能是相对路径,如果路径以“/”开头,表示相对于当前WEB应用程序的根目录,否则,表示相对于当前JSP所映射到的访问路径.这写方法基本不用,动态包含,用的少.而且后面有专门的标签来使用动态包含.

五、JSP标签

1、虽然我们希望JSP页面仅用作数据显示模块,不要嵌套任何java代码引入任何业务逻辑,但在实际开发中不引入一点业务逻辑是不可能的,但引入业务逻辑会导致页面出现难看java代码,怎么办?Sun公司允许用户开发自定义标签封装页面的java代码,以便jsp页面不出现一行java代码.当然sun公司在jsp页面中也内置了一些标签(这些标签叫做jsp标签),开发人员使用这些标签可以完成页面的一些常用业务逻辑.JSP标签也称之为Jsp Action(JSP动作)元素,它用于在JSP页面中提供业务逻辑功能.
2、JSP常用标签:<jsp:include>标签、<jsp:forward>标签 、<jsp:param>标签
3、<jsp:include>标签

<jsp:include>标签用于把另外一个资源的输出内容插入进当前JSP页面的输出内容之中,这种在JSP页面执行时的引入方式称之为动态引入.
语法:
<jsp:include page="relativeURL | <%=expression%>" flush="true|false" />
page属性用于指定被引入资源的相对路径,它也可以通过执行一个表达式来获得.
flush属性指定在插入其他资源的输出内容时,是否先将当前JSP页面的已输出的内容刷新到客户端.

4、<jsp:include>与include指令的比较
1><jsp:include>标签是动态引入, <jsp:include>标签涉及到的2个JSP页面会被翻译成2个servlet,这2个servlet的内容在执行时进行合并.
2>而include指令是静态引入,涉及到的2个JSP页面会被翻译成一个servlet,其内容是在源文件级别进行合并.
3>不管是<jsp:include>标签,还是include指令,它们都会把两个JSP页面内容合并输出,所以这两个页面不要出现重复的HTML全局架构标签,否则输出给客户端的内容将会是一个格式混乱的HTML文档
4、<jsp:forward>标签

<jsp:forward>标签用于把请求转发给另外一个资源.
语法:

<jsp:forward page="relativeURL | <%=expression%>" /> 

page属性用于指定请求转发到的资源的相对路径,它也可以通过执行一个表达式来获得.
使用场景:比如在首页中,在tomcat,web.xml中<welcome-file-list>标签中可以指定jsp页面,但是不能指定servlet,这时可以使用<jsp:forward>转发给一个servlet.<welcome-file-list>的作用:只要输域名,就可调到首页.

5、<jsp:param>标签,了解即可

当使用<jsp:include>和<jsp:forward>标签引入或将请求转发给其它资源时,可以使用<jsp:param>标签向这个资源传递参数.

6、映射JSP,例:其实和servlet一样,感觉用的不多,一般是通过servlet跳转到jsp,而不会直接访问jsp.

<servlet>
    <servlet-name>SimpleJspServlet</servlet-name>
    <jsp-file>/jsp/simple.jsp</jsp-file>
    <load-on-startup>1</load-on-startup >
</servlet>
    ……
<servlet-mapping>
    <servlet-name>SimpleJspServlet</servlet-name>
    <url-pattern>/xxx/yyy.html</url-pattern>
</servlet-mapping>
原文地址:https://www.cnblogs.com/wangweiNB/p/4955941.html