[关闭]
@cxm-2016 2016-12-26T10:06:19.000000Z 字数 7903 阅读 2565

Java Web (四)——JSP

Web

版本:2
作者:陈小默
声明:禁止商业,禁止转载


JSP技术

JSP全名为Java Server Pages,其根本是一个简化的Servlet设计。也就是说,看起来像是一个HTML网页的JSP在Tomcat中是以Servlet对象的形式存在的。JSP与Servlet一样,是在服务器端执行的。通常JSP页面很少进行数据处理,只是用来实现网页的静态化页面,只是用来提取数据,不会进行业务处理。

一个JSP会在第一次被访问时翻译成一个Servlet对象,此后所有的响应都由这个对象输出。

JSP运行原理

每个JSP页面在第一次被访问时,WEB容器都会把请求交给JSP引擎去处理。JSP引擎先将JSP翻译成Servlet,然后以Servlet的调用方式调用。以后再访问时不再翻译而是直接使用当前Servlet对象。

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

JSP九大隐式对象

out隐式对象

用于向客户端发送文本数据。

out对象通过调用pageContext对象的getOut方法返回,其作用和用法与ServletResponse.getWriter对象相似。

out对象的类型为JSPWriter,是一个实现了缓存功能的PrintWriter对象。可以通过设置page指令的buffer属性设置缓冲区的大小,也可以关闭缓冲区。

当满足以下任意一个条件后,out对象会去调用ServletResponsegetWriter方法,并将当前out缓冲区的内容写到Servlet的缓冲区中。

pageContext对象

当前页面的上下文对象。

该对象代表了JSP页面的运行环境。其中封装了其他八个隐式对象的引用,并且其自身还是一个域对象。并且,这个对象还封装了web开发中经常使用的一些操作,例如跳转等。

获取其他隐式对象

我们可以通过pageContext对象获取其他对象的引用。

  1. <%
  2. Object page1 = pageContext.getPage();
  3. ServletRequest request1 = pageContext.getRequest();
  4. ServletResponse response1 = pageContext.getResponse();
  5. HttpSession session1 = pageContext.getSession();
  6. ServletConfig config1 = pageContext.getServletConfig();
  7. JspWriter out1 = pageContext.getOut();
  8. ServletContext application1 = pageContext.getServletContext();
  9. Exception exception = pageContext.getException();
  10. %>

作为域

  1. <%
  2. //保存到PageContext域
  3. pageContext.setAttribute("key", 1);
  4. //保存到Application域
  5. pageContext.setAttribute("key", 2, PageContext.APPLICATION_SCOPE);
  6. //保存到Session域
  7. pageContext.setAttribute("key", 3, PageContext.SESSION_SCOPE);
  8. //保存到Request域
  9. pageContext.setAttribute("key", 4, PageContext.REQUEST_SCOPE);
  10. %>

JSP语法

JSP模板元素

JSP页面中的HTML内容都可以被称之为模板元素。

接下来我们在webapp目录下创建一个JSP index.jsp

  1. <%@ page contentType="text/html;charset=UTF-8" language="java" %>
  2. <html>
  3. <head>
  4. <title>index</title>
  5. </head>
  6. <body>
  7. Welcome to Smart JSP !!!
  8. </body>
  9. </html>

由于webapp的可访问性,其中所有的文件,除WEB-INF目录外,都可以被浏览器通过地址直接访问。而文件名为index的文件又具有默认访问的特性。所以我们既可以通过

http://127.0.0.1:8080/smart/index.jsp

形式访问,也可以省略index.jsp,直接通过

http://127.0.0.1:8080/smart

访问。

JSP表达式

  1. <%=System.currentTimeMillis() %>

JSP引擎在翻译表达式时会使用out.print输出表达式中的内容。

JSP脚本

JSP脚本也叫作JSP脚本片段

  1. <%
  2. for (int i = 0; i < 10; i++) {
  3. out.print(i);
  4. out.print("<br>");
  5. }
  6. %>

JSP脚本允许不完整的脚本片段,但是多个片段组合后的脚本片段必须是完整的,比如上面的示例还可以改成这个样子:

  1. <%
  2. for (int i = 0; i < 10; i++) {
  3. out.print(i);
  4. %>
  5. <br>
  6. <%
  7. }
  8. %>

JSP脚本片段会被原封不动的放在生成的Servlet代码中。

JSP声明

JSP页面中编写的代码会被翻译到Servlet的service中,而JSP声明中的java代码会被翻译到_jspService方法的外面。

通常JSP声明被用于

声明变量

  1. <%!
  2. private int base = 10;
  3. %>
  4. <%
  5. for (int i = 0; i < 10; i++) {
  6. out.println(base++);
  7. }
  8. %>

代码块

  1. <%!
  2. {
  3. System.out.println("init");
  4. }
  5. %>

定义方法

  1. <%!
  2. private String getCurrent() {
  3. SimpleDateFormat format = new SimpleDateFormat("yyyy年MM月dd日 HH时mm分ss秒");
  4. return format.format(new Date());
  5. }
  6. %>
  7. <%=getCurrent() %>

定义内部类

  1. <%!
  2. private class DateUtil {
  3. String getCurrent() {
  4. SimpleDateFormat format = new SimpleDateFormat("yyyy年MM月dd日 HH时mm分ss秒");
  5. return format.format(new Date());
  6. }
  7. }
  8. %>
  9. <%
  10. DateUtil util = new DateUtil();
  11. out.print(util.getCurrent());
  12. %>

JSP注释

在JSP中注释有三种方式,第一种为JSP注释,该注释不会被保存到Servlet中。

  1. <%-- JSP注释 --%>

第二种是Java注释,这种注释只能在JSP脚本中使用,并且会被写入到Servlet中。

  1. <%
  2. // 单行注释
  3. /*
  4. 多行注释
  5. */
  6. /**
  7. * 文档注释
  8. */
  9. %>

第三种是HTML注释,该注释会被当做模板元素输出。

  1. <!-- HTML -->

对于HTML注释,有一点需要注意:

  1. <% int i = 0; %>
  2. <!--<% i+=10; %> -->
  3. <%=i %>

上述网页会输出数字10
这是因为在JSP翻译为Servlet时,对于模板元素采取的是直接输出:

  1. int i = 0;
  2. out.print("<!--");
  3. i+=10;
  4. out.print("-->");
  5. out.print(i)

JSP指令

JSP指令用于指挥JSP引擎如何处理JSP页面。其中包含三个主要部分pageincludetaglib

page

用于定义JSP页面中各种属性,无论指令在何处,都作用域整个JSP页面。

常用属性有:

language

  1. <%@ page
  2. language="java"
  3. %>

目前仅支持Java语言。

import

  1. <%@ page
  2. language="java"
  3. import="java.util.Date,java.util.ArrayList"
  4. %>

session

  1. <%@ page
  2. language="java"
  3. import="java.util.Date,java.util.ArrayList"
  4. session="false"
  5. %>

当我们将session设置为false之后,我们就无法在JSP脚本中使用session隐式对象了。

errorPage

我们可以通过errorPage标签指定当前页面发生后跳转到的页面。

首先创建一个JSP页面用来显示错误:

  1. <%@ page
  2. contentType="text/html;charset=UTF-8"
  3. language="java"
  4. isErrorPage="true"
  5. %>
  6. <html>
  7. <head>
  8. <title>错误页面</title>
  9. </head>
  10. <body>
  11. 发生了一个错误,错误原因是:<%=exception.getMessage()%>
  12. </body>
  13. </html>

然后在需要的JSP页面中指定错误页面。

  1. <%@ page
  2. language="java"
  3. errorPage="ErrorPage.jsp"
  4. %>
  5. <html>
  6. <head>
  7. <title>Hello</title>
  8. </head>
  9. <body>
  10. <%
  11. throw new RuntimeException("用户未登录");
  12. %>
  13. </body>
  14. </html>

最后也是最重要的就是在web.xml文件中指定错误类型与访问路径的关系。

我们可以使用相应代码:

  1. <error-page>
  2. <error-code>500</error-code>
  3. <location>/ErrorPage.jsp</location>
  4. </error-page>

或者使用错误类型:

  1. <error-page>
  2. <exception-type>java.lang.RuntimeException</exception-type>
  3. <location>/ErrorPage.jsp</location>
  4. </error-page>

include

通知JSP将两个JSP文件翻译成一个Servlet

比如:

  1. <%@ page contentType="text/html;charset=UTF-8" language="java" %>
  2. <html>
  3. <head>
  4. <title>Hello</title>
  5. </head>
  6. <body>
  7. ---------a----------
  8. <%@include file="index.jsp" %>
  9. ---------b----------
  10. </body>
  11. </html>

我们可以从浏览器看到翻译过后的Servlet的输出内容是:

  1. <html>
  2. <head>
  3. <title>Hello</title>
  4. </head>
  5. <body>
  6. ---------a----------
  7. <html>
  8. <head>
  9. <title>index</title>
  10. </head>
  11. <body>
  12. Welcome to Smart JSP !!!
  13. </body>
  14. </html>
  15. ---------b----------
  16. </body>
  17. </html>

include指令属于静态引入,也就是源文件级别的合并,并最终生成一个Servlet。

需要注意的是

taglib

用于在JSP页面中导入标签库

  1. <%@ taglib uri="http://java.sun.com/jstl/core" prefix="c"%>

我们将

JSP映射访问

  1. <servlet>
  2. <servlet-name>helloJsp</servlet-name>
  3. <jsp-file>/WEB-INF/view/HelloJsp.jsp</jsp-file>
  4. </servlet>
  5. <servlet-mapping>
  6. <servlet-name>helloJsp</servlet-name>
  7. <url-pattern>/view/hello</url-pattern>
  8. </servlet-mapping>

JSP实现方式

JSP最终是以Servlet的方式运行的。那么一个JSP最终转换成的Servlet结构是什么样子的?

首先我们创建一个最简单的JSP页面:

  1. <%@ page import="java.text.SimpleDateFormat" %>
  2. <%@ page import="java.util.Date" %>
  3. <%@ page contentType="text/html;charset=UTF-8" language="java" %>
  4. <html>
  5. <head>
  6. <title>Hello</title>
  7. </head>
  8. <body>
  9. <%!
  10. private String getDate() {
  11. SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
  12. return format.format(new Date());
  13. }
  14. %>
  15. <%-- 注释1 --%>
  16. <%=getDate()%>
  17. <%
  18. //注释2
  19. for (int i = 0; i < 10; i++) {
  20. out.print(i);
  21. %>
  22. <br>
  23. <!--<%
  24. }
  25. %>-->
  26. </body>
  27. </html>

那么生成的Servlet页面源码如下(已精简)

  1. package org.apache.jsp;
  2. ...
  3. import java.text.SimpleDateFormat;
  4. import java.util.Date;
  5. public final class HelloJsp_jsp extends org.apache.jasper.runtime.HttpJspBase
  6. implements org.apache.jasper.runtime.JspSourceDependent,
  7. org.apache.jasper.runtime.JspSourceImports {
  8. /**
  9. * 使用JSP声明定义的方法
  10. */
  11. private String getDate() {
  12. SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
  13. return format.format(new Date());
  14. }
  15. ...
  16. /**
  17. * JSP生命周期的初始化方法,在第一次被访问时调用
  18. */
  19. public void _jspInit() {
  20. }
  21. /**
  22. * JSP生命周期的销毁,在JSP被移除出容器时调用
  23. */
  24. public void _jspDestroy() {
  25. }
  26. /**
  27. * 模板元素在这里被输出,JSP脚本在这里被运行
  28. */
  29. public void _jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response)
  30. throws java.io.IOException, javax.servlet.ServletException {
  31. ...
  32. final javax.servlet.jsp.PageContext pageContext;
  33. javax.servlet.http.HttpSession session = null;
  34. final javax.servlet.ServletContext application;
  35. final javax.servlet.ServletConfig config;
  36. javax.servlet.jsp.JspWriter out = null;
  37. final java.lang.Object page = this;
  38. javax.servlet.jsp.JspWriter _jspx_out = null;
  39. javax.servlet.jsp.PageContext _jspx_page_context = null;
  40. //以上声明隐式对象
  41. try {
  42. response.setContentType("text/html;charset=UTF-8");
  43. pageContext = _jspxFactory.getPageContext(this, request, response,
  44. null, true, 8192, true);
  45. _jspx_page_context = pageContext;
  46. application = pageContext.getServletContext();
  47. config = pageContext.getServletConfig();
  48. session = pageContext.getSession();
  49. out = pageContext.getOut();
  50. _jspx_out = out;
  51. //以上初始化隐式对象
  52. out.write("\n");
  53. out.write("\n");
  54. out.write("\n");
  55. out.write("<html>\n");
  56. out.write("<head>\n");
  57. out.write(" <title>Hello</title>\n");
  58. out.write("</head>\n");
  59. out.write("<body>\n");
  60. out.write('\n');
  61. out.write('\n');
  62. out.print(getDate());
  63. out.write('\n');
  64. //注释2
  65. for (int i = 0; i < 10; i++) {
  66. out.print(i);
  67. out.write("\n");
  68. out.write("<br>\n");
  69. out.write("<!--");
  70. }
  71. out.write("-->\n");
  72. out.write("</body>\n");
  73. out.write("</html>\n");
  74. } catch (java.lang.Throwable t) {
  75. ...
  76. } finally {
  77. ...
  78. }
  79. }
  80. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注