06、JavaEEJSP基本语法

JSP基本用法

JSP原理

JSP全称是Java Server Pages,和Servlet技术一样都用于开发动态Web资源的技术。

浏览器向服务器发送请求,其实都是在访问Servlet,服务器在执行JSP时,会把JSP翻译成Servlet。 假设我们有如下代码:

index.jsp

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
    String path = request.getContextPath();
    String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
    <base href="<%=basePath%>">
    <title>First Jsp</title>
</head>
<body>
<%
    out.print("Hello Jsp");
%>
</body>
</html>

当我们通过浏览器访问index.jsp时,服务器首先将index.jsp翻译成一个index_jsp.class,在Tomcat服务器的work\Catalina\localhost\项目名\org\apache\jsp

目录下可以看到index_jsp.class的源代码文件index_jsp.java:

public final class index_jsp extends org.apache.jasper.runtime.HttpJspBase
    implements org.apache.jasper.runtime.JspSourceDependent {
  private static final JspFactory _jspxFactory = JspFactory.getDefaultFactory();
  private static java.util.List _jspx_dependants;
  private javax.el.ExpressionFactory _el_expressionfactory;
  private org.apache.AnnotationProcessor _jsp_annotationprocessor;
  public Object getDependants() {
    return _jspx_dependants;
  }
  public void _jspInit() {
    _el_expressionfactory = _jspxFactory.getJspApplicationContext(getServletConfig().getServletContext()).getExpressionFactory();
    _jsp_annotationprocessor = (org.apache.AnnotationProcessor) getServletConfig().getServletContext().getAttribute(org.apache.AnnotationProcessor.class.getName());
  }
  public void _jspDestroy() {
  }
  public void _jspService(HttpServletRequest request, HttpServletResponse response)
        throws java.io.IOException, ServletException {
    PageContext pageContext = null;
    HttpSession session = null;
    ServletContext application = null;
    ServletConfig config = null;
    JspWriter out = null;
    Object page = this;
    JspWriter _jspx_out = null;
    PageContext _jspx_page_context = null;
    try {
      response.setContentType("text/html;charset=UTF-8");
      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;
      out.write('\r');
      out.write('\n');
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
      out.write("\r\n");
      out.write("\r\n");
      out.write("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\r\n");
      out.write("<html>\r\n");
      out.write("  <head>\r\n");
      out.write("    <base href=\"");
      out.print(basePath);
      out.write("\">\r\n");
      out.write("    \r\n");
      out.write("    <title>First Jsp</title>\r\n");
      out.write("\t\r\n");
      out.write("  </head>\r\n");
      out.write("  \r\n");
      out.write("  <body>\r\n");
      out.write("    ");
        out.print("Hello Jsp");
      out.write("\r\n");
      out.write("  </body>\r\n");
      out.write("</html>\r\n");
    } catch (Throwable t) {
      if (!(t instanceof SkipPageException)){
        out = _jspx_out;
        if (out != null && out.getBufferSize() != 0)
          try { out.clearBuffer(); } catch (java.io.IOException e) {}
        if (_jspx_page_context != null) _jspx_page_context.handlePageException(t);
      }
    } finally {
      _jspxFactory.releasePageContext(_jspx_page_context);
    }
  }
}

index_jsp这个类是继承 org.apache.jasper.runtime.HttpJspBase这个类的,通过查看Tomcat服务器的源代码,可以知道在apache-tomcat-6.0.20-src\java\

org\apache\jasper\runtime目录下存HttpJspBase这个类的源代码文件,如下图所示:

我们可以看看HttpJsBase这个类的源代码,如下所示:

public abstract class HttpJspBase extends HttpServlet implements HttpJspPage { 
    protected HttpJspBase() {
    }
    public final void init(ServletConfig config) throws ServletException {
        super.init(config);
    jspInit();
        _jspInit();
    }
    
    public String getServletInfo() {
    return Localizer.getMessage("jsp.engine.info");
    }
    public final void destroy() {
        jspDestroy();
        _jspDestroy();
    }
    /**
     * Entry point into service.
     */
    public final void service(HttpServletRequest request, HttpServletResponse response) 
    throws ServletException, IOException {
        _jspService(request, response);
    }
    
    public void jspInit() {
    }
    public void _jspInit() {
    }
    public void jspDestroy() {
    }
    protected void _jspDestroy() {
    }
    public abstract void _jspService(HttpServletRequest request, 
                     HttpServletResponse response) 
    throws ServletException, IOException;
}

HttpJspBase类是继承HttpServlet的,所以HttpJspBase类是一个Servlet,而index_jsp又是继承自HttpJspBase类的,所以index_jsp类也是一个Servlet。

1、JSP中的HTML排版标签是如何发送给服务端的?

浏览器接收到的下面这些数据

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <base href="http://localhost:8080/JavaWebDemo/">
    <title>First Jsp</title>  
  </head>
  
  <body>
    Hello Jsp
  </body>
</html>

都是在_jspService方法中使用如下的代码输出给浏览器的:

String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
      out.write("\r\n");
      out.write("\r\n");
      out.write("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\r\n");
      out.write("<html>\r\n");
      out.write("  <head>\r\n");
      out.write("    <base href=\"");
      out.print(basePath);
      out.write("\">\r\n");
      out.write("    \r\n");
      out.write("    <title>First Jsp</title>\r\n");
      out.write("\t\r\n");
      out.write("  </head>\r\n");
      out.write("  \r\n");
      out.write("  <body>\r\n");
      out.write("    ");
        out.print("Hello Jsp");
    
      out.write("\r\n");
      out.write("  </body>\r\n");
      out.write("</html>\r\n");

在jsp中编写的java和html代码都会被翻译到_jspService方法中去,而HTML代码则会翻译成out.write("<html标签>\r\n");的形式输出到浏览器。

2、Web服务器在调用JSP时,会给JSP提供什么java对象?

查看_jspService方法可以看到,Web服务器在调用jsp时,会给Jsp提供如下的8个java对象

PageContext pageContext;
HttpSession session;
ServletContext application;
ServletConfig config;
JspWriter out;
Object page = this;
HttpServletRequest request, 
HttpServletResponse response

其中page对象,request和response已经完成了实例化,而其它5个没有实例化的对象通过下面的方式实例化

pageContext = _jspxFactory.getPageContext(this, request, response,null, true, 8192, true);
application = pageContext.getServletContext();
config = pageContext.getServletConfig();
session = pageContext.getSession();
out = pageContext.getOut();

这8个java对象在Jsp页面中是可以直接使用的,如下所示:

<%
    session.setAttribute("name", "session对象");//使用session对象,设置session对象的属性
    out.print(session.getAttribute("name")+"<br/>");//获取session对象的属性
    pageContext.setAttribute("name", "pageContext对象");//使用pageContext对象,设置pageContext对象的属性
    out.print(pageContext.getAttribute("name")+"<br/>");//获取pageContext对象的属性
    application.setAttribute("name", "application对象");//使用application对象,设置application对象的属性
    out.print(application.getAttribute("name")+"<br/>");//获取application对象的属性
    out.print("Hello Jsp"+"<br/>");//使用out对象
    out.print("服务器调用index.jsp页面时翻译成的类的名字是:"+page.getClass()+"<br/>");//使用page对象
    out.print("处理请求的Servlet的名字是:"+config.getServletName()+"<br/>");//使用config对象
    out.print(response.getContentType()+"<br/>");//使用response对象
    out.print(request.getContextPath()+"<br/>");//使用request对象
%>

软件开发中,习惯把servlet作为web应用中的控制器组件,而把JSP技术作为数据显示模板。

JSP基础语法

JSP虽然是在JAVA上的一种应用,但是也有自身的扩充语法,而且在JSP中是可以运行所有JAVA语句的。

JSP页面中的HTML内容称之为JSP模板元素,JSP模板元素定义了网页的基本骨架,既定义了页面的结构和外观。

JSP表达式

JSP脚本表达式(expression)用于将程序数据输出到客户端:

<%= 变量或表达式 %>

JSP脚本表达式后面不允许有分号,JSP引擎在翻译脚本表达式时,会将程序数据转成字符串,然后在相应位置用out.print(…) 将数据输给客户端。

JSP脚本片段

JSP脚本片断(scriptlet)用于在JSP页面中编写多行Java代码。语法:

<%
多行java代码
%>
在<% %>中可以定义变量、编写语句,不能定义方法。

范例:在Scriptlet中定义变量、编写语句:

<%
    int sum=0;//声明变量
    /*编写语句*/
    for (int i=1; i<=100; i++){
        sum+=i;
    }
    out.println("<h1>Sum="+sum+"</h1>");
%>

注意事项:

JSP脚本片断中只能出现java代码,不能出现其它模板元素。
JSP脚本片断中的Java代码必须严格遵循Java语法。
在一个JSP页面中可以有多个脚本片断,在两个或多个脚本片断之间可以嵌入文本、HTML标记和其他JSP元素。

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

多个脚本片断组合后的结果必须是完整的Java语句,例如:

<%
    for (int i=1; i<5; i++) {
%>
      <H1>http://localhost:8080/JavaWebDemo/</H1>
<%
    }
%>

JSP声明

多个静态代码块、变量和函数可以定义在一个JSP声明中,也可以分别单独定义在多个JSP声明中。JSP隐式对象的作用范围仅限于Servlet的_jspService方法,

所以在JSP声明中不能使用这些隐式对象。

<%!
    static {
        System.out.println("loading Servlet!");
    }
    private int globalVar = 0;
    public void jspInit(){
        System.out.println("initializing jsp!");
    }
%>
<%!
    public void jspDestroy(){
        System.out.println("destroying jsp!");
    }
%>

JSP注释

在JSP中,注释有两大类:

显式注释:直接使用HTML风格的注释:<!- - 注释内容- ->
隐式注释:直接使用JAVA的注释://、/……/
JSP自己的注释:<%- - 注释内容- -%>

三种注释的区别分别是:

<%
//JAVA中的单行注释
/*
JAVA中的多行注释
*/
%>
<%--JSP自己的注释--%>

HTML的注释在浏览器中查看源文件的时候是可以看得到的,而JAVA注释和JSP注释在浏览器中查看源文件时是看不到注释的内容的,这就是这三种注释的区别。

JSP指令

 JSP指令(directive)是为JSP引擎而设计的,它们并不直接产生任何可见输出,而只是告诉引擎如何处理JSP页面中的其余部分。

在JSP2.0规范中定义三个指令:

指令 描述
<%@ page ... %> 定义网页依赖属性,比如脚本语言、error页面、缓存需求等等。
<%@ include ... %> 包含其他文件
<%@ taglib ... %> 引入标签库的定义

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指令的完整语法:

属性 描述
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 确定脚本元素能否被使用

page指令的import属性

在Jsp页面中,Jsp引擎会自动导入下面的包

java.lang.*
javax.servlet.*
javax.servlet.jsp.*
javax.servlet.http.*

可以在一条page指令的import属性中引入多个类或包,其中的每个包或类之间使用逗号(,)分隔

<%@ page import="java.util.*,java.io.*,java.sql.*"%>

上面的语句也可以改写为使用多条page指令的import属性来分别引入各个包或类

<%@ page import="java.util.Date"%>
<%@ page import="java.io." %>
<%@ page import="java.sql.
" %>

page指令的errorPage属性

errorPage属性的设置值必须使用相对路径,如果以“/”开头,表示相对于当前Web应用程序的根目录(注意不是站点根目录),

否则,表示相对于当前页面,也可以在web.xml文件中使用<error-page>元素为整个Web应用程序设置错误处理页面。

其中<error-page>元素有3个子元素,<error-code>、<exception-type>、<location>

<error-code>子元素指定错误的状态码,例如:<error-code>404</error-code>
<exception-type>子元素指定异常类的完全限定名,例如:<exception-type>java.lang.ArithmeticException</exception-type>
<location>子元素指定以“/”开头的错误处理页面的路径,例如:<location>/ErrorPage/404Error.jsp</location>

如果设置了某个JSP页面的errorPage属性,那么在web.xml文件中设置的错误处理将不对该页面起作用。

(1)使用errorPage属性指明出错后要跳转的页面

比如Test.jsp页面有如下的代码:

<%@ page contentType="text/html;charset=UTF-8" language="java" errorPage="error.jsp" %>
<html>
<head>
    <title>测试page指令的errorPage属性</title>
</head>
    <body>
        <%
            // 运行出错代码
            int x = 1 / 0;
        %>
    </body>
</html>

代码运行出错后会跳转到error.jsp页面:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>错误友好提示界面</title>
</head>
    <body>
        对不起,出问题啦,赶快联系程序员修改代码!
    </body>
</html>

(2)在web.xml中使用<error-page>标签配置全局错误处理

web.xml代码如下:

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" 
    xmlns="http://java.sun.com/xml/ns/javaee" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
    http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
  <display-name></display-name>    
  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
  
  <!-- 针对404错误的处理页面 -->
  <error-page>
      <error-code>404</error-code>
      <location>/ErrorPage/404Error.jsp</location>
  </error-page>
</web-app>

404Error.jsp代码如下:

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<html>
  <head>
    <title>404错误友好提示页面</title>
    <!-- 3秒钟后自动跳转回首页 -->
    <meta http-equiv="refresh" content="3;url=${pageContext.request.contextPath}/index.jsp">
  </head>
  <body>
    <img alt="对不起,你要访问的页面没有找到,请联系管理员处理!" 
    src="${pageContext.request.contextPath}/img/404Error.png"/><br/>
    3秒钟后自动跳转回首页,如果没有跳转,请点击<a href="${pageContext.request.contextPath}/index.jsp">这里</a>
  </body>
</html>

当访问一个不存在的web资源时,就会跳转到在web.xml中配置的404错误处理页面404Error.jsp。

如果错误页面比较小的话,ie可能显示自己的错误页面,而火狐和google浏览器是不存在该问题。解决办法有两种:

a) 修改IE浏览器的设置(不推荐)
操作步骤:在IE【工具】->【Internet选项】->【高级】中勾掉【显示友好http错误提示】
b) 定制错误页面的大小
修改500Error.jsp,多添加一些内容,让页面的字节数大一些,修改后的500Error.jsp的代码如下:

示例代码如下所示:

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<html>
  <head>
    <title>500(服务器错误)错误友好提示页面</title>
    <!-- 3秒钟后自动跳转回首页 -->
    <meta http-equiv="refresh" content="3;url=${pageContext.request.contextPath}/index.jsp">
  </head>
  <body>
    <img alt="对不起,服务器出错了,请联系管理员解决!" 
    src="${pageContext.request.contextPath}/img/500Error.png"/><br/>
    3秒钟后自动跳转回首页,如果没有跳转,请点击<a href="${pageContext.request.contextPath}/index.jsp">这里</a>
  </body>
</html>

经过测试,当定制的错误页面的size=617bytes时,在IE8下已经可以跳转到定制的错误页面。

(3)使用page指令的isErrorPage属性显示声明页面为错误页面

将error.jsp页面显示声明为错误处理页面

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8" isErrorPage="true"%>
<html>
  <head>
    <title>错误信息友好提示页面</title>
  </head>
  <body>
           对不起,出错了,请联系管理员解决!
  </body>
</html>

Jsp有9大内置对象,而一般情况下exception对象在Jsp页面中是获取不到的,只有设置page指令的isErrorPage属性为"true"来显式声明Jsp页面

是一个错误处理页面之后才能够在Jsp页面中使用exception对象。

include指令

在JSP中对于包含有两种语句形式:

@include指令
<jsp:include>指令

  • @include指令

    @include可以包含任意的文件,当然,只是把文件的内容包含进来。它用于引入其他JSP页面,而JSP引擎会将两个JSP翻译成Servlet,

所以这种方式称之为静态引入。

<%@ include file="relativeURL"%>,
其中的file属性用于指定被引入文件的路径。路径以“/”开头,表示代表当前web应用。

include指令细节注意事项:

被引入的文件必须遵循JSP语法。
被引入的文件可以使用任意的扩展名,JSP规范建议使用.jspf(JSP fragments(片段))作为静态引入文件的扩展名。
由于使用include指令将会涉及到2个JSP页面,所以这2个JSP页面的指令不能冲突(除了pageEncoding和导包除外)。

范例:

新建head.jspf页面和foot.jspf页面,分别作为jsp页面的头部和尾部,存放于WebRoot下的jspfragments文件夹中,代码如下:

head.jspf和foot.jspf内容如下:

head.jspf:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<h1 style="color: red;">网页头部</h1>
foot.jspf:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<h1 style="color: blue">网页尾部</h1>

在WebRoot文件夹下创建一个IncludeTagTest.jsp页面,在IncludeTagTest.jsp页面中使用@include指令引入head.jspf页面和foot.jspf页面,代码如下:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
    <head>
        <title>jsp的include指令测试</title>
    </head>
    <body>
        <%--使用include标签引入其他JSP页面--%>
        <%@include file="/jspfragment/head.jspf"%>
        <h1>网页主体部分</h1>
        <%@include file="/jspfragment/foot.jspf"%>
    </body>
</html>

最后总结一下使用方法:

使用@include可以包含任意的后缀名的文件内容,属于静态包含。
jsp:include页面是JSP,则先处理再将结果包含,称为动态包含,而如果是非*.jsp文件,则是把文件静态包含。

JSP九大内置对象

JSP引擎在调用JSP对应的_jspServlet时,会传递或创建9个与web开发相关的对象供_jspServlet使用。JSP技术的设计者为便于开发人员在编写

JSP页面时获得这些web对象的引用,特意定义了9个相应的变量,开发人员在JSP页面中通过这些变量就可以快速获得这9大对象的引用。

内置对象 类型
pageContext javax.servlet.jsp.PageContext
request javax.servlet.http.HttpServletRequest
response javax.servlet.http.HttpServletResponse
session javax.servlet.http.HttpSession
application javax.servlet.ServletContext
config javax.servlet.ServletConfig
out javax.servlet.jsp.JspWriter
page java.lang.Object
exception java.lang.Throwable

内置对象使用

page对象

page对象表示当前JSP页面,可以理解为对象本身,了解即可。

out对象

out对象用于向客户发送文本数据,它通过调用pageContext.getOut()方法返回,其作用和用法和ServletReponse.getWriter()方法非常类似。

JSP页面中的out对象的类型为JspWriter,JspWriter相当于一种带缓存功能的PrintWriter,设置JSP页面的page指令的buffer属性可以调整它

的缓存大小,甚至关闭它的缓存。

  只有向out对象中写入了内容,且满足如下任何一个条件时,out对象才去调用ServletResponse.getWriter方法,并通过该方法返回的Print

Writer对象将out对象的缓冲区中的内容真正写入到Servlet引擎提供的缓冲区中:

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

out对象的工作原理图:

pageContext对象

pageContext对象是JSP技术中最重要的一个对象,它代表JSP页面的运行环境,这个对象不仅封装了对其它8大隐式对象的引用,它自身还是一个

域对象(容器),可以用来保存数据。并且,这个对象还封装了web开发中经常涉及到的一些常用操作,例如引入和跳转其它资源、检索其它域对象中的属性等。

我们可以通过pageContext中的如下方法来获得其他隐式对象:

getException方法返回exception隐式对象
getPage方法返回page隐式对象
getRequest方法返回request隐式对象
getResponse方法返回response隐式对象
getServletConfig方法返回config隐式对象
getServletContext方法返回application隐式对象
getSession方法返回session隐式对象
getOut方法返回out隐式对象

除此之外,pageContext还可以作为容器来使用,可以将一些数据存储在pageContext对象中。

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)
public java.lang.Object findAttribute(java.lang.String name)

当要查找某个属性时,findAttribute方法按照查找顺序"page→request→session→application"在这四个对象中去查找,只要找到了就返回属性值,如果四

个对象都没有找到要查找的属性,则返回一个null。

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@page import="java.util.*"%>
<head>
    <title>pageContext的findAttribute方法查找属性值</title>
</head>
<%
    pageContext.setAttribute("name1", "legend");
    pageContext.setAttribute("name2", "vincent");
    pageContext.setAttribute("name3", "uding");
    application.setAttribute("name4", "kevin");
%>
<%
    // 使用pageContext的findAttribute方法查找属性
    String refName1 = (String) pageContext.findAttribute("name1");
    String refName2 = (String) pageContext.findAttribute("name2");
    String refName3 = (String) pageContext.findAttribute("name3");
    String refName4 = (String) pageContext.findAttribute("name4");
    // 查找一个不存在的属性
    String refName5 = (String) pageContext.findAttribute("name5");
%>
<h1>pageContext的findAttribute方法找到的属性值如下:</h1>
<h1>name1:<%=refName1%></h1>
<h1>name2:<%=refName2%></h1>
<h1>name3:<%=refName3%></h1>
<h1>name4:<%=refName4%></h1>
<h1>name5:<%=refName5%></h1>
<hr/>
<h1>使用EL表达式进行输出:</h1>
<h3>pageContext对象的name1属性:${name1}</h3>
<h3>request对象的name2属性:${name2}</h3>
<h3>session对象的name3属性:${name3}</h3>
<h3>application对象的name4属性:${name4}</h3>
<h3>不存在的name5属性:${name5}</h3>

EL表达式语句在执行时,会调用pageContext.findAttribute方法,用标识符为关键字,分别从page、request、 session、application四个域中查找相应的

对象,找到则返回相应对象,找不到则返回""(注意,不是null,而是空字符串)。

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

使用pageContext访问其他域:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>pageContext访问其他域</title>
    <%
        // session中存放name属性
        pageContext.setAttribute("name", "legend", PageContext.SESSION_SCOPE);
    %>
    <%
        // 取得session对象属性,使用pageContext对象获得
        String name = (String) pageContext.getAttribute("name", PageContext.SESSION_SCOPE);
        // 直接获取属性
        String name1 = (String) session.getAttribute("name");
    %>
    <h1>取出存在session对象中的属性值</h1>
    <p>第一种方式:使用pageContext取出session对象中的值</p>
    <h3>姓名:<%=name%></h3>
    <p>第二种方式:使用session直接获取对象中的值</p>
    <h3>姓名:<%=name1%></h3>
</html>

PageContext引入和跳转到其他资源

PageContext类中定义了一个forward方法(用来跳转页面)和两个include方法(用来引入页面)来分别简化和替代RequestDispatcher.forward方法和include

方法。方法接收的资源如果以“/”开头, “/”代表当前web应用。

a) 使用PageContext的forward()跳转其他页面

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>使用PageContext的forward方法跳转页面</title>
</head>
    <%
        //方式一: 使用pageContext的forward()跳转到其他jsp页面
        pageContext.forward("/index.jsp");
        //方式二: 使用RequstDispatch的forward()方法实现跳转
        pageContext.getRequest().getRequestDispatcher("/index.jsp").forward(request,response);
    %>
</html>

在开发中,一般会使用<jsp:forward>标签来实现跳转,<jsp:forward>标签用于把请求转发给另外一个资源。

b) 使用pageContext的include方法引入资源

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
    <head>
        <h1>使用pageContext的include()方法引入资源</h1>
        <%
            pageContext.include("/jspfragment/head.jsp");
            pageContext.include("jspfragment/foot.jsp");
        %>
    
        <hr/>
    
        <h1>使用jsp的include方式引入资源</h1>
        <jsp:include page="/jspfragment/head.jsp"/>
        <jsp:include page="/jspfragment/foot.jsp"/>
    </head>
</html>

在实际开发中,使用pageContext的include方法引入页面这种做法也很少用,一般都使用jsp:include标签引入资源,因此这种做法了解一下即可。

JSP属性范围

JSP的属性范围就是当一个属性设置后,可以经过多少个其他页面后仍然可以访问的范围。它有四种属性范围,分别如下:

当前页:属性只能当前页面中取得,跳转到其他页面后无法使用。
服务请求:一个页面中设置的属性,只要经过服务器跳转,跳转之后的页面可以继续使用。
会话:一个用户设置的内容,只要是与与此用户相关的页面都可以访问。
上下文:在整个服务器上设置的属性,所有人都可以访问。

其中四种属性范围中都将包含如下的属性操作方法:

方法 描述
public void setAttribute(String name,Object value) 设置属性
public object getAttribute(String name) 取得属性
public void removeAttribute(String name) 删除属性

四种属性范围

  • Page属性范围(PageContext)

    Page属性范围在一个页面设置的属性,跳转到其他页面则无法访问,它可以表示一个页面中的所有内容。

范例:演示在本页中存储属性和获取属性:

<%@ page import="java.util.Date" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
    // pageContext设置的属性只能在当前页取得
    pageContext.setAttribute("name", "legend");
    pageContext.setAttribute("date", new Date());
%>
<%
    // 取得设置的属性
    String refName = (String) pageContext.getAttribute("name");
    Date refDate = (Date) pageContext.getAttribute("date");
%>
<h1>姓名:<%=refName%></h1>
<h1>日期:<%=refDate%></h1>

注意:pageContext存储的属性只能在当前页面中获取。

  • request属性范围

    request属性范围表示在一次服务器跳转中有效,只要是服务器跳转,则设置request属性可以一直传递下去。

范例:演示request在一次跳转中获取属性:

pageContextSet.jsp

<%@ page import="java.util.Date" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
    request.setAttribute("name", "legend");
    request.setAttribute("date", new Date());
%>
<jsp:forward page="/PageContextGet.jsp" />

pageContextGet.jsp

<%@ page import="java.util.Date" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
    String refName = (String) request.getAttribute("name");
    Date refDate = (Date) request.getAttribute("date");
%>
<h1>姓名:<%=refName%></h1>
<h1>日期:<%=refDate%></h1>

运行结果:

姓名:legend
日期:Fri Jun 30 10:06:38 CST 2017

从运行结果来看,程序跳转了后,request对象还可以获取属性,如果现在有第三个页面,它也可以继续向后进行传递。

注意:request对象在多次跳转后依然可以获取属性值,如果使用超链接的形式跳转的话,则无法再获取属性。

session属性范围

session设置的属性不管如何跳转,都可以取得,但是只能针对一个用户来说。

范例:演示session的属性范围

sessionSet.jsp

<%@ page import="java.util.Date" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
    // 此时设置的属性只能在本页相关的任意页面中获得
    session.setAttribute("name", "legend");
    session.setAttribute("date", new Date());
%>
<jsp:forward page="sessionGet.jsp"/>

sessionGet.jsp

<%@ page import="java.util.Date" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
    String refName = (String) session.getAttribute("name");
    Date refDate = (Date) session.getAttribute("date");
%>
<h1>姓名:<%=refName%></h1>
<h1>日期:<%=refDate%></h1>
<%--使用超链接的方式跳转--%>
<h1><a href="${pageContext.request.contextPath}/sessionGet1.jsp">继续跳转</a></h1>

sessionGet1.jsp

<%@ page import="java.util.Date" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
    String refName = (String) session.getAttribute("name");
    Date refDate = (Date) session.getAttribute("date");
%>
<h1>姓名:<%=refName%></h1>
<h1>日期:<%=refDate%></h1>

输出结果:

sessionGet1.jsp中获得:
姓名:legend
日期:Fri Jun 30 10:23:06 CST 2017

注意:session存储的属性不管如何跳转,只要跟当前页面有关的页面都能获取到,但是只针对某一个用户而言。

  • application属性范围

    application属性范围是在服务器上设置的一个属性,所以一旦设置之后任何用户都可以浏览到此属性。

范例:演示观察application属性范围。

applicationSet.jsp

<%@ page import="java.util.Date" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
    // 设置的属性任何用户都可以获取
    application.setAttribute("name", "legend");
    application.setAttribute("date", new Date());
%>
<h1><a href="${pageContext.request.contextPath}/applicationGet.jsp">跳转</a></h1>

applicationGet.jsp

<%@ page import="java.util.Date" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
    String refName = (String) application.getAttribute("name");
    Date refDate = (Date) application.getAttribute("date");
%>
<h1>姓名:<%=refName%></h1>
<h1>日期:<%=refDate%></h1>

注意:application的属性可以供所有用户访问,除非关闭服务器。过多使用会影响服务器性能。

PageContext的Scope

上面所讲解的四种属性范围都是通过PageContext属性范围设置上的,PageContext类继承了JspContext类,在JspContext类中定义了setAttribute()方法,如下所示:

public abstract void setAttribute(String name,Object value,int scope)

范例:PageContext以REQUEST_SCOPE模式存储存储,然后用request对象获取属性。

PageContextSet.jsp

<%@ page import="java.util.Date" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
    pageContext.setAttribute("name", "legend", PageContext.REQUEST_SCOPE);
    pageContext.setAttribute("date", new Date(), PageContext.REQUEST_SCOPE);
%>
<jsp:forward page="RequestGet.jsp"/>

RequestGet.jsp

<%@ page import="java.util.Date" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
    String refName = (String) request.getAttribute("name");
    Date refDate = (Date) request.getAttribute("date");
%>
<h1>姓名:<%=refName%></h1>
<h1>日期:<%=refDate%></h1>

运行结果:

姓名:legend
日期:Fri Jun 30 13:28:16 CST 2017

四种属性的使用场景

request:如果客户向服务器发请求,产生的数据,用户看完就没用了,像这样的数据就存在request域,像新闻数据,属于用户看完就没用的。
session:如果客户向服务器发请求产生的数据,用户用完了等一会儿还有用,像这样的数据就存在session域中。
application(servletContext):如果客户向服务器发请求产生的数据,用户用完了,还要给其它用户用,像这样的数据就存在application(servletContext)域中。

JSP动作标签

JSP标签也成为Jsp Action元素,它用于JSP页面中提供业务逻辑功能,避免在JSP页面中直接编写java代码而造成难以维护。

常用动作标签

JSP有如下标签,其中常用的是include、forward、param标签:

标签 描述
<jsp:include /> 在页面被请求的时候引入一个文件。
<jsp:useBean /> 寻找或者实例化一个JavaBean。
<jsp:setProperty /> 设置JavaBean的属性。
<jsp:getProperty /> 输出某个JavaBean的属性。
<jsp:forward /> 把请求转到一个新的页面。
<jsp:plugin /> 根据浏览器类型为Java插件生成OBJECT或EMBED标记。
<jsp:element /> 定义动态XML元素
<jsp:attribute /> 设置动态定义的XML元素属性。
<jsp:body /> 设置动态定义的XML元素内容。
<jsp:text /> 在JSP页面和文档中使用写入文本的模板

所有的动作要素都有两个属性:id属性和scope属性。

id属性:id属性是动作元素的唯一标识,可以在JSP页面中引用。动作元素创建的id值可以通过PageContext来调用。
scope属性:该属性用于识别动作元素的生命周期。 id属性和scope属性有直接关系,scope属性定义了相关联id对象的寿命。

<jsp:include>标签

<jsp:include>标签是把另外一个资源的内容插入到当前的JSP输出的页面之中,这种方式称之为动态引入。

jsp<jsp:include page="relativeURL | <%=expression%>" flush="true|false" />

其中page属性指定被引入资源的相对路径。flush属性指定在插入其他输出内容时,是否将当前已输出内容刷新到客户端。

范例:演示<jsp:include>标签引入资源

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
    <title>jsp的jsp:include标签测试</title>
</head>
    <body>
        <%--引入其它JSP页面--%>
        <jsp:include page="/jspfragments/head.jsp"/>
        <h1>网页主体内容</h1>
        <jsp:include page="/jspfragments/foot.jsp"/>
    </body>
</html>

<jsp:include>和include指令区别

<jsp:include>标签是动态引入, <jsp:include>标签涉及到的2个JSP页面会被翻译成2个servlet,这2个servlet的内容在执行时进行合并。

include指令是静态引入,涉及到的2个JSP页面会被翻译成一个servlet,其内容是在源文件级别进行合并。

通过下面的例子来说明<jsp:include>标签与include指令的区别

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
   <%!
        int i=1000;
   %>
<h1>demo.jsp中i的值为:<%=i%></h1>

分别使用include指令和<jsp:include>标签两种包含语句,包含以上的demo.jsp

a) 使用@include静态包含

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
   <%!
       int i=10;
   %>
<h1>i的值为:<%=i%></h1>
<h1><%@include file="/jspfragments/demo.jsp"%></h1>

此时在编译jsp时就已经提示出错了,如下所示

因为静态包含是将全部内容包含进来之后,再进行处理,属于先包含后处理。

b) 使用动态包含

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<h1>JspIncludeTagDemo02.jsp</h1>
<%!
    int i=10;
%>
<h1>i的值为:<%=i%></h1>
<h1><jsp:include page="/jspfragments/demo.jsp" /></h1>

发现结果已经可以正确地显示,而且不会互相影响,这是因为使用jsp:include属于动态包含,动态包含就是指先将各个页面分别处理,处理完之后再将处理后的

结果包含进来。

*.jspf在jsp:include、@include和c:import中的区别

JSP规范建议使用.jspf(JSP fragments)作为静态引入文件的扩展名。正常情况下只有@include指令才行正常解析jspf文件,而使用jsp:include和JSTL的

c:import都无法解析jspf文件,会把其当成纯文本文件处理。

解决方式有两种,他们分别如下:

a) 第一种方式:修改web.xml文件,添加对扩展名为*.jspf文件的映射

<servlet-mapping>
    <servlet-name>jsp</servlet-name>
    <url-pattern>*.jsp</url-pattern>
    <!-- 让jspf扩展名同样成为JSP Servlet处理的文件。-->
    <url-pattern>*.jspf</url-pattern>
</servlet-mapping>

b)第二种方式:修改Tomcat服务器的web.xml文件,添加对*.jspf的映射

<!-- The mappings for the JSP servlet -->
<servlet-mapping>
    <servlet-name>jsp</servlet-name>
    <url-pattern>*.jsp</url-pattern>
    <url-pattern>*.jspx</url-pattern>
</servlet-mapping>

添加如上两种配置信息后,此时tomcat服务器就可以正常解析执行*.jspf文件了。

<jsp:forward>标签

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

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

page属性用于指定请求转发到的资源的相对路径,它也可以通过执行一个表达式来获得。

范例:演示使用<jsp:forwar>标签跳转页面

forwardDemo01.jsp

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%--使用<jsp:forward>标签跳转到forwarddemo02.jsp--%>
<jsp:forward page="/forwardDemo02.jsp"/>

forwardDemo02.jsp

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<h1>跳转之后的页面!!</h1>

<jsp:include>跳转后页面改变,而地址栏不会改变,因此它的跳转属于服务器端的跳转。

<jsp:param>标签

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

语法1:
    <jsp:include page="relativeURL | <%=expression%>">
        <jsp:param name="parameterName" value="parameterValue|<%= expression %>" />
    </jsp:include>
语法2:
    <jsp:forward page="relativeURL | <%=expression%>">
        <jsp:param name="parameterName" value="parameterValue|<%= expression %>" />
    </jsp:include>

<jsp:param>标签的name属性用于指定参数名,value属性用于指定参数值。在<jsp:include>和<jsp:forward>标签中可以使用多个<jsp:param>标签来传递多个参数。
范例:使用<jsp:param>标签向被包含的页面传递参数。

JspIncludeDemo.jsp

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<h1>JspIncludeTagDemo.jsp</h1>
<hr/>
<jsp:include page="/jspfragments/Inc.jsp">
    <jsp:param name="parm1" value="legend" />
    <jsp:param name="parm2" value="vincent" />
</jsp:include>

Inc.jsp

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<h1>接收从JspIncludeDemo.jsp页面中传递过来的参数:</h1>
<h2><%=request.getParameter("parm1")%></h2>
<h2><%=request.getParameter("parm2")%></h2>

范例:使用<jsp:param>标签向跳转的页面传递参数。

forwardDemo01.jsp

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<jsp:forward page="/forwarddemo01.jsp">
    <jsp:param name="ref1" value="legend" />
    <jsp:param name="ref2" value="vincent" />
</jsp:forward>

forwardDemo02.jsp

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<h1>跳转之后的页面!!</h1>
<h1>接收从forwarddemo03.jsp传递过来的参数:</h1>
<h1>ref1:<%=request.getParameter("ref1")%></h1>
<h1>ref2:<%=request.getParameter("ref2")%></h1>

JavaBean

JavaBean是一个遵循特定写法的Java类,它通常具备如下特点:

这个Java类必须具有一个无参的构造函数
属性必须私有化。
私有化的属性必须通过public类型的方法暴露给其它程序,并且方法的命名也必须遵守一定的命名规范。

JavaBean的格式如下:

public class User {
    private String name;
    private int age;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
}

JavaBean在J2EE开发中,通常用于封装数据,对于遵循以上写法的JavaBean组件,其它程序可以通过反射技术实例化JavaBean对象,并且通过反射那些遵守命名规范的方法,

从而获知JavaBean的属性,进而调用其属性保存数据。

JSP中使用JavaBean

JSP技术提供了三个关于JavaBean组件的动作元素,即JSP标签,它们分别为:

<jsp:useBean>标签:用于在JSP页面中查找或实例化一个JavaBean组件。
<jsp:setProperty>标签:用于在JSP页面中设置一个JavaBean组件的属性。
<jsp:getProperty>标签:用于在JSP页面中获取一个JavaBean组件的属性。

<jsp:useBean>标签

<jsp:useBean>标签用于在指定的域范围内查找指定名称的JavaBean对象,如果存在则直接返回该JavaBean对象的引用,如果不存在则实例化一个新的JavaBean对象并将它

以指定的名称存储到指定的域范围中。

<jsp:useBean id="beanName" class="package.className" scope="page|request|session|application"/>
"id"属性用于指定JavaBean实例对象的引用名称和其存储在域范围中的名称。
"class"属性用于指定JavaBean的完整类名(即必须带有包名)。
"scope"属性用于指定JavaBean实例对象所存储的域范围,其取值只能是page、request、session和application的一个,默认值是page。

范例:演示JavaBean的使用。

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%--在jsp中使用jsp:useBean标签来实例化java对象--%>
<jsp:useBean id="user" class="com.legend.jsp.User" scope="page"/>
<%--给User对象进行赋值--%>
<%
    user.setName("legend");
    user.setAge(18);
%>
<html>
<head>
    <title>标签使用范例</title>
</head>
    <body>
        <h2>姓名:<%=person.getName()%></h2>
        <h2>年龄:<%=person.getAge()%></h2>
    </body>
</html>

运行结果:

姓名:legend
年龄:18

带标签体的<jsp:useBean>标签

语法如下所示:

<jsp:useBean ...>
Body
</jsp:useBean>

Body部分的内容只在<jsp:useBean>标签创建JavaBean的实例对象时才执行。这种做法用得不多,了解一下即可。

<jsp:setProperty>标签

<jsp:setProperty>标签用于设置和访问JavaBean对象的属性。

语法格式一:
  <jsp:setProperty name="beanName" property="propertyName" value="string字符串"/>
语法格式二:
  <jsp:setProperty name="beanName" property="propertyName" value="<%= expression %>" />
语法格式三:
  <jsp:setProperty name="beanName" property="propertyName" param="parameterName"/>
语法格式四:
  <jsp:setProperty name="beanName" property= "*" />

其中解释如下:

name属性用于指定JavaBean对象的名称。
property属性用于指定JavaBean实例对象的属性名。
value属性用于指定JavaBean对象的某个属性的值。
param属性用于将JavaBean实例对象的某个属性值设置为一个请求参数值。

范例一:演示使用jsp:setProperty标签设置User对象的属性值

<%@ page import="java.util.Date" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<jsp:useBean id="user" class="com.legend.jsp.User" scope="page"/>
<jsp:setProperty name="user" property="name" value="legend"/>
<jsp:setProperty name="user" property="age" value="18"/>
<%--birthday属性是Date类型,属于复合数据类型,无法转换成字符串--%>
<jsp:setProperty name="user" property="birthday" value="<%=new Date()%>"/>
<html>
<head>
    <title>jsp:setProperty标签使用</title>
</head>
    <body>
        <h2>姓名:<%=user.getName()%></h2>
        <h2>年龄:<%=user.getAge()%></h2>
        <h2>生日:<%=user.getBirthday()%></h2>
    </body>
</html>

运行结果:

姓名:legend
年龄:18
生日:Sat Jul 01 19:45:19 CST 2017

范例二:使用请求参数为bean属性赋值

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<jsp:useBean id="usr" class="com.legend.jsp.User" scope="page"/>
<jsp:setProperty name="usr" property="name" param="param_name"/>
<html>
<head>
    <title>jsp:setProperty标签使用</title>
</head>
    <body>
        <h2>姓名:<%=usr.getName()%></h2>
    </body>
</html>

在浏览器中需要拼接param_name参数,输出结果如下:

http://localhost:8080/javaBean03.jsp?param_name=legend
姓名:legend

范例三:用所有的请求参数为bean属性赋值

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<jsp:useBean id="user" class="com.legend.jsp.User" scope="page"/>
<%--*代表bean的所有属性--%>
<jsp:setProperty name="user" property="*"/>
<html>
<head>
    <title>jsp:setProperty标签使用</title>
</head>
    <body>
        <h2>姓名:<%=user.getName()%></h2>
        <h2>年龄:<%=user.getAge()%></h2>
    </body>
</html>

输出结果:

http://localhost:8080/javaBean04.jsp?name=legend&age=18
姓名:legend
年龄:18

<jsp:getProperty>标签

<jsp:getProperty>标签用于读取JavaBean对象的属性,也就是调用JavaBean对象的getter方法,然后将读取的属性值转换成字符串后插入进输出的响应正文中。

<jsp:getProperty name="beanInstanceName" property="PropertyName" />
   name属性用于指定JavaBean实例对象的名称,其值应与<jsp:useBean>标签的id属性值相同。
   property属性用于指定JavaBean实例对象的属性名。

如果一个JavaBean实例对象的某个属性的值为null,那么,使用<jsp:getProperty>标签输出该属性的结果将是一个内容为“null”的字符串。

范例:演示jsp:getProperty获取bean对象的属性值

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<jsp:useBean id="user" class="com.legend.jsp.User" scope="page"/>
<%--设置属性值--%>
<jsp:setProperty name="user" property="name" value="legend"/>
<jsp:setProperty name="user" property="age" value="18"/>
<html>
    <head>
        <title>jsp:getProperty标签使用范例</title>
    </head>
    <body>
        <%--获取属性值--%>
        <h2><jsp:getProperty name="user" property="name"/></h2>
        <h2><jsp:getProperty name="user" property="age"/></h2>
    </body>
</html>

输出结果:

legend
18

原文地址:https://www.cnblogs.com/pengjingya/p/14410143.html