刚接触 JSP 技术的时候让我想起了在大学学的 Asp+VBScript,记得当时我还用 aspstudy 做了一个小的新闻发布系统作为期末作品,也正是在那时候在卢哥卢老师的指导下走向编程的道路,对编程越来越感兴趣。为什么会让我想起 asp 呢?因为 Jsp 和它还挺类似的,asp 本身就是把 vbscript 都放在 asp 页面,没有像 asp.net 那样界面与逻辑分离,这样更加清楚。
一、工作原理与生命周期
JSP 编译之后也是一个继承 HttpServlet 的类,所以也能完成 HttpServlet 能完成的所有事。只是工作方式和 Servlet 不一样,Servlet 是先编译后部署,而 jsp 是先部署后编译。jsp 是一个 Servlet 那它的生命周期也和 Servlet 一样,只是它有自己的初始化和销毁方法。
- public void _jspInit() {}
- public void _jspDestroy() {}
我们可以查看下它生成的 java 类是什么样的。在工作空间下找到下面的路径. metadata\.plugins\org.eclipse.wst.server.core\tmp0\work\Catalina\localhost\HelloWorld\org\apache\jsp, 会出现两个文件,一个是. java 文件,一个是. class 文件,当客户端第一次请求时 Tomcat 先将 test.jsp 文件转化为. java 文件,并将. java 文件编译成. class 文件,该. class 便是 jsp 对应的 Servlet,编译完之后再运行. class 文件来响应客户请求,以后客户访问会直接调用. class 来响应, 下面的代码是. java 的代码。
View Code
- /*
- * Generated by the Jasper component of Apache Tomcat
- * Version: Apache Tomcat/8.5.9
- * Generated at: 2017-03-18 03:41:35 UTC
- * Note: The last modified time of this file was set to
- * the last modified time of the source file after
- * generation to assist with modification tracking.
- */
- package org.apache.jsp;
- import javax.servlet.*;
- import javax.servlet.http.*;
- import javax.servlet.jsp.*;
- import com.test.cyw.Person;
- public final class test_jsp extends org.apache.jasper.runtime.HttpJspBase
- implements org.apache.jasper.runtime.JspSourceDependent,
- org.apache.jasper.runtime.JspSourceImports {
- private static final javax.servlet.jsp.JspFactory _jspxFactory =
- javax.servlet.jsp.JspFactory.getDefaultFactory();
- private static java.util.Map _jspx_dependants;
- private static final java.util.Set _jspx_imports_packages;
- private static final java.util.Set _jspx_imports_classes;
- static {
- _jspx_imports_packages = new java.util.HashSet<>();
- _jspx_imports_packages.add("javax.servlet");
- _jspx_imports_packages.add("javax.servlet.http");
- _jspx_imports_packages.add("javax.servlet.jsp");
- _jspx_imports_classes = new java.util.HashSet<>();
- _jspx_imports_classes.add("com.test.cyw.Person");
- }
- private volatile javax.el.ExpressionFactory _el_expressionfactory;
- private volatile org.apache.tomcat.InstanceManager _jsp_instancemanager;
- public java.util.Map getDependants() {
- return _jspx_dependants;
- }
- public java.util.Set getPackageImports() {
- return _jspx_imports_packages;
- }
- public java.util.Set getClassImports() {
- return _jspx_imports_classes;
- }
- public javax.el.ExpressionFactory _jsp_getExpressionFactory() {
- if (_el_expressionfactory == null) {
- synchronized (this) {
- if (_el_expressionfactory == null) {
- _el_expressionfactory = _jspxFactory.getJspApplicationContext(getServletConfig().getServletContext()).getExpressionFactory();
- }
- }
- }
- return _el_expressionfactory;
- }
- public org.apache.tomcat.InstanceManager _jsp_getInstanceManager() {
- if (_jsp_instancemanager == null) {
- synchronized (this) {
- if (_jsp_instancemanager == null) {
- _jsp_instancemanager = org.apache.jasper.runtime.InstanceManagerFactory.getInstanceManager(getServletConfig());
- }
- }
- }
- return _jsp_instancemanager;
- }
- public void _jspInit() {
- }
- public void _jspDestroy() {
- }
- public void _jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response)
- throws java.io.IOException, javax.servlet.ServletException {
- final java.lang.String _jspx_method = request.getMethod();
- if (!"GET".equals(_jspx_method) && !"POST".equals(_jspx_method) && !"HEAD".equals(_jspx_method) && !javax.servlet.DispatcherType.ERROR.equals(request.getDispatcherType())) {
- response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, "JSPs only permit GET POST or HEAD");
- return;
- }
- final javax.servlet.jsp.PageContext pageContext;
- javax.servlet.http.HttpSession session = null;
- final javax.servlet.ServletContext application;
- final javax.servlet.ServletConfig config;
- javax.servlet.jsp.JspWriter out = null;
- final java.lang.Object page = this;
- javax.servlet.jsp.JspWriter _jspx_out = null;
- javax.servlet.jsp.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\n");
- out.write("\r\n");
- out.write("\r\n");
- out.write("\r\n");
- out.write("\r\n");
- out.write("\r\n");
- out.write("\r\n");
- out.write("\r\n");
- out.write("\r\n");
- Person person=new Person("CuiYW",25);
- out.write('\r');
- out.write('\n');
- response.setCharacterEncoding("UTF-8");
- request.setCharacterEncoding("UTF-8");
- session.setAttribute("Person", person) ;
- session.setAttribute("ID", "123456");
- session.setAttribute("ID", "abcdef");
- session.removeAttribute("ID");
- out.write("\r\n");
- out.write("\r\n");
- out.write("\r\n");
- out.write("");
- } catch (java.lang.Throwable t) {
- if (!(t instanceof javax.servlet.jsp.SkipPageException)){
- out = _jspx_out;
- if (out != null && out.getBufferSize() != 0)
- try {
- if (response.isCommitted()) {
- out.flush();
- } else {
- out.clearBuffer();
- }
- } catch (java.io.IOException e) {}
- if (_jspx_page_context != null) _jspx_page_context.handlePageException(t);
- else throw new ServletException(t);
- }
- } finally {
- _jspxFactory.releasePageContext(_jspx_page_context);
- }
- }
- }
二、JSP 指令
JSP 的语法这块比较简单,就此略过。在新建 jsp 页面时会在页面的第一行会有类似下面的一行代码, 它就是 jsp 指令,
- <%@ page language="java" contentType="text/html; charset=UTF-8"
- pageEncoding="UTF-8" import="com.test.cyw.Person"%>
jsp 指令主要来声明 jsp 页面的一些属性, 格式为 <%directive{attribute=}*%>,* 表示一个或多个属性。JSP 最常见的有 3 种指令: Page,include,taglib.
1.Page 指令
Page 指令一般生命页面属性,多个属性可以写在一个 Page 指令或多个 Page 指令中。不过属性只能出现一次,除了 import 属性除外。Page 指令中常见属性如下:
language 属性 | language 属性主要用来声明所使用的脚本语言种类,目前暂时只能使用 Java 语言。不过不排除以后可以使用如 C、C++ 或其他语言的可能。language 属性的默认值也是 java。 | <%@ page language="java"> |
extends 属性 | extends 属性用来指定该 JSP 页面生成的 Servlet 是继承于哪个父类,设定时必须指定该类的全名,即包名加类名。一般很少使用,而且必须慎重的使用,否则可能限制到 JSP 的编译能力。 | <%@ page extends=" 继承的父类 "%> |
import 属性 | import 属性用来指定导入的 Java 包,和 Java 语言基础中的 import 语句作用类似。不过有些包在 JSP 编译时就已经导入了,可以不用再进行导入 | <%@ page import=" 导入的包名 "%> |
session 属性 | session 属性用来指定该 JSP 页面中是否可以使用 session 对象。如果设置为 true,则表示该 JSP 页面中可以使用 session 对象;如果设置为 false,则表示该 JSP 页面中不可以使用 session 对象。session 属性的默认值为 true。 | <%@ page session="true | false "%> |
buffer 属性 | buffer 属性用来指定输出流是否具有缓冲区,以及设置缓冲区大小。如果设置为 none,则表示输出流不具有缓冲功能;如设置为具体的数据,如 "40KB",则表示设置的缓冲区大小为 40KB。其默认值为 8KB。 | <%@ page buffer="none | 40KB"%> |
autoFlush 属性 | autoFlush 属性用来指定缓冲区是否自动进行强制输出。如果设置为 true,那么当缓冲区满的时候仍然能够输出正常;如果设置为 false,那么当缓冲区满的时候,将会产生异常。如果 buffer 属性设置为 none,那么就不能将 autoFlush 属性设置为 false。autoFlush 属性的默认值为 true。 | <%@ page autoFlush="true | false"%> |
isThreadSafe 属性 | isThreadSafe 属性用来指定该 JSP 文件是否支持多线程使用。如果设置为 true,则表示该 JSP 文件支持多线程的使用,也就是表示该 JSP 文件能够同时处理多个用户的请求;如果设置为 false,则表示该 JSP 文件不支持多线程的使用,也就是表示该 JSP 文件只能一次处理一个用户的请求。isThreadSafe 属性的默认值为 true。 | <%@ page isThreadSafe="true | false"%> |
info 属性 | info 属性用来设置该 JSP 文件的相关信息,可以是任何的信息字符串,并通过 Servlet.getServletInfo 方法来取得该信息。 | <%@ page info="JSP 文件相关信息 "%> |
errorPage 属性 | errorPage 属性用来设置如果当前 JSP 文件发生异常错误时,网页重新跳转到能够处理异常的 JSP 文件。 | <%@ page errorPage=" 错误处理页面 "%> |
isErrorPage 属性 | isErrorPage 属性用来指定该 JSP 文件是否为能够处理异常的 JSP 文件,其默认值为 false。 | <%@ page isErrorPage="true | false"%> |
contentType 属性 | contentType 属性用来指定该 JSP 文件的 MIME 格式,以及网页编码格式。 | <%@ page contentType="text/html;charset=ISO-8859-1"%> |
pageEncoding 属性 | pageEncoding 属性用来制定网页的编码格式 | <%@ page pageEncoding=" ISO-8859-1"%> |
isELIgnored 属性 | isELIgnored 属性用来指定该 JSP 文件是否支持 EL 表达式。如果设置为 true,则表示 JSP 文件讲忽略 EL 表达式,也就是 EL 表达式不会被执行;如果设置为 false,则表示 EL 表达式不会被忽略,该 EL 表达式将会被执行。 | <%@ page isELIgnored="true | false"%> |
下面来做个实验主要使用下 errorPage、isErrorPage 属性。
首先新建一个错误页面 error.jsp,isErrorPage="true"
View Code
- <%@ page language="java" contentType="text/html; charset=UTF-8"
- pageEncoding="UTF-8" isErrorPage="true"%>
- this is error page
在 test.jsp 制造一个错误 1/0, 抛出异常 errorPage="/error.jsp"
View Code
- <%@ page language="java" contentType="text/html; charset=UTF-8"
- pageEncoding="UTF-8" import="com.test.cyw.Person" errorPage="/error.jsp"%>
- <% Person person=new Person("CuiYW",25); %>
- <%
- response.setCharacterEncoding("UTF-8");
- request.setCharacterEncoding("UTF-8");
- session.setAttribute("Person", person) ;
- session.setAttribute("ID", "123456");
- session.setAttribute("ID", "abcdef");
- session.removeAttribute("ID");
- %>
- <%=1/0 %>
浏览器请求 test.jsp 时会跳转到错误页面 error.jsp
2.include 指令
include 指令格式:<%@include file="relativeURL"%>,relativeURL 可以是本应用的 jsp 或 html 文件路径,用它可以将复用的页面分离出来,类似模板页的功能。
还是接着上面的 demo, 新建一个 jsp 页面,part.jsp
View Code
- <%@ page language="java" contentType="text/html; charset=UTF-8"
- pageEncoding="UTF-8"%>
- 这是错误页面的一部分
在 error.jsp 中使用 include 指令引入 part.jsp
View Code
- this is error page
- <%@include file="/part.jsp" %>
刷新 test.jsp 请求
3.taglib 指令
三、行为
1.<jsp:include/> 行为
include 行为用于运行时包含某个文件。如果被包含的文件是 jsp 程序,则先会执行 jsp 程序,后把执行的结果包含进来。语法:<jsp:include page="relativeURL"flush="true"/>, 属性 page 是必需的,为被包含文件的相对路径必须为本 web 应用程序内的文件。属性 flush 布尔类型,默认 false, 设置读入被保存文件内容前是否清空缓存。
这个与 jsp 指令中的 include 指令有点类似, 把 test.jsp 中的 include 指令换成下面的语句也是显示一样的结果。
- <jsp:include page="/part.jsp" flush="true">
- </jsp:include>
不过,两个的实现原理并不一样。include 指令是编译时包含,包含的是源代码,而行为是运行时包含,只保护运行结果,我们可以看下. metadata\.plugins\org.eclipse.wst.server.core\tmp0\work\Catalina\localhost\HelloWorld\org\apache\jsp 文件夹的文件变化就知道了。
(1). 首先使用指令包含 part.jsp,请求 test.jsp 页面, 然后查看上面路径文件夹下的文件
- <%@include file="/part.jsp" %>
(2). 清空该文件下的文件,使用行为来引入 part.jsp
- <jsp:include page="/part.jsp" flush="true">
- </jsp:include>
可以看到上面的两个运行之后生成的文件,使用指令是包含源代码,把 part.jsp 包含在 error.jsp 中,程序都是先编译后运行,按一个文件编译, 编译时包含, 而行为是两个分开编译,只是运行的时候把结果包含。
2. 使用 Java Bean(POJO)Plain Ordinary Java Object 普通的 Java 类
在 asp.net 中提交表单数据, 从表单中获取数据, 在没有 MVVM 模式的情况下,如果表单中数据比较多,也要一行一行的获取, 这样就会变得特别麻烦。MVC 中有了 MVVM 之后可以直接把页面数据映射到 VM 对象中,这样也不用一行一行的获取变量了,非常方便, JavaBean 与它很类似。JavaBean 行为是一组与 JavaBean 相关的行为,包括 useBean 行为、setProperty 行为、getProperty 行为。
(1).useBean 行为
用于在 jsp 中定义一个 POJO 对象. 格式:<jsp:useBean id="beanId"class="calssName"scope="value"/>
属性用法:
id: 命名引用该 Bean 的变量。如果能够找到 id 和 scope 相同的 Bean 实例,jsp:useBean 动作将使用已有的 Bean 实例而不是创建新的实例。
class: 指定 Bean 的完整包名。
scope: 指定 Bean 在哪种上下文内可用,可以取下面的四个值之一:page,request,session 和 application。
默认值是 page,表示该 Bean 只在当前页面内可用(保存在当前页面的 PageContext 内)。
request 表示该 Bean 在当前的客户请求内有效(保存在 ServletRequest 对象内)。
session 表示该 Bean 对当前 HttpSession 内的所有页面都有效。
application,则表示该 Bean 对所有具有相同 ServletContext 的页面都有效。
scope 之所以很重要,是因为 jsp:useBean 只有在不存在具有相同 id 和 scope 的对象时才会实例化新的对象;如果已有 id 和 scope 都相同的对象则直接使用已有的对象,此时 jsp:useBean 开始标记和结束标记之间的任何内容都将被忽略。
(2)getProperty 行为
useBean 定义了对象之后, 使用 getProperty 行为来获取 useBean 对象的属性.<jsp:getProperty name="beanName"property="propertyName"/>
(3)setProperty 行为
useBean 定义了对象之后, 使用 getProperty 行为来设置 useBean 对象的属性.<jsp:setProperty name="beanName"property="propertyName"value=""/>
实验一 : 提交表单
1. 新建 User 类
View Code
- package com.test.cyw;
- public class User {
- 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;
- }
- public boolean isSex() {
- return sex;
- }
- public void setSex(boolean sex) {
- this.sex = sex;
- }
- private String name;
- private int age;
- private boolean sex;
- }
2. 新建 useBean.jsp 页面
在这个页面中将页面提交给自己,判断是否是 post 提交,如果是则实例化一个 User 对象,然后从 request 中获取值给 user 对象赋值,最后获取值。
View Code
- <%@ page language="java" contentType="text/html; charset=UTF-8"
- pageEncoding="UTF-8"%>
- <%
- request.setCharacterEncoding("UTF-8");
- if(request.getMethod().toString().equalsIgnoreCase("post")){%>
- class="com.test.cyw.User" scope="page">
- 姓名:
- 年龄:
- 性别:
- <%
- }
- %>
实验二、scope 实现计数器
上面列了 scope 的作用范围,这个 demo 主要是对 scope 的使用。利用它的作用域不同可以实现计数器功能。当 scope 为 session 时统计该用户的访问次数,使用 application 时统计该网站的访问次数。使用两个浏览器来刷新, 不然两个的数量是相等的。
View Code
- <%@ page language="java" contentType="text/html; charset=UTF-8"
- pageEncoding="UTF-8" import="com.test.cyw.Person" errorPage="/error.jsp"%>
- class="com.test.cyw.Counter" scope="session">
- class="com.test.cyw.Counter" scope="application">
- 个人访问次数:
- 总访问次数:
3.<jsp:forward/> 行为
.<jsp:forward/> 行为是对 request.getRequestDispatcher() 的封装, 使用它也可以实现页面挑战, 也可以添加参数
View Code
- <jsp:forward page="test.jsp">
- <jsp:param value="qaz" name="name"/>
- </jsp:forward>
四、JSP 隐藏对象
jsp 中有 9 大隐藏对象, 隐藏就是默认存在,可以直接使用 1.out 输出流对象
隐藏对象 out 是 javax.servlet.jsp.JspWriter 类的实例。服务器向客户端输出的字符类内容可以通过 out 对象输出。
2.request 请求对象
隐藏对象 request 是 javax.servlet.ServletRequest 类的实例。代表客户端的请求。request 包含客户端的信息以及请求的信息,如请求哪个文件,附带的地址栏参数等。每次客户端请求都会产生一个 request 实例。
3.response 响应对象
隐藏对象 response 是 javax.servlet.ServletResponse 类的实例,代表服务器端的响应。服务器端的任何输出都是通过 response 对象发送到客户端浏览器。每次服务器端都会产生一个 response 实例。
4.config 配置对象
隐藏对象 config 是 javax.servlet.ServletConfig 类的实例,ServletConfig 封装了配置在 web.xml 中初始化 JSP 的参数。JSP 中通过 config 获取这些参数。每个 JSP 文件都有一个 config 对象。
5.session 会话对象
隐藏对象 session 是 javax.servlet.http.HttpSession 类的实例。session 与 cookie 是记录客户访问信息的两种机制,session 用于服务器端保存用户信息,cookie 用于客户端保存用户信息。
Servlet 通过 request.getSession() 获取 session 对象,而在 JSP 中可以直接使用。如果 JSP 中配置了 <%@ page session="false"%>,则隐藏对象 session 不可用。每个用户对应一个 session 对象。
6.application 应用程序对象
隐藏对象 application 是 javax.servlet.ServletContext 类的对象。application 封装了 JSP 所在的 Web 应用程序的信息,例如 web.xml 中配置的全局的初始化信息。Servlet 中 application 对象通过 ServletConfig.getServletContext() 来获取。整个 Web 应用程序对应一个 application 对象。
7.page 页面对象
隐藏对象 page 为 javax.servlet.jsp.HttpJspPage 类的实例,page 对象代表当前 JSP 页面,是当前 JSP 编译后的 Servlet 类的对象。page 相当于普通 java 类中的关键字 this。
8.pageContext 页面上下文对象
隐藏对象 pageContext 为 javax.servlet.jsp.PageContext 类的实例。pageContext 对象代表当前 JSP 页面编译后的内容。通过 pageContext 能够获取到 JSP 中的资源。
9.exception 异常对象
隐藏对象 exception 为 java.lang.Exception 类的对象。exception 封装了 JSP 中抛出的异常信息。要使用 exception 对象,需要设置 <%@ page isErrorPage="true"%>。隐藏对象 exception 通常被用来处理错误页面。
五、配置
配置和 Servlet 的一样, 只是在将 <servlet-class> 转换为 <jsp-file> 即可。
六、EL 表达式
POJO 是为了简便获取页面请求的参数而生的, EL 则是为了方便获取对象或变量而生的, 以往获取对象或者属性需要使用 XXX().XXXX().XX() 这种, 如果树比较深那就需要一直调用方法, 也是比较麻烦的事情, 而有了 EL 这个就很好解决。
View Code
- <%@ page language="java" contentType="text/html; charset=UTF-8"
- pageEncoding="UTF-8"%>
- <%
- request.setCharacterEncoding("UTF-8");
- if(request.getMethod().toString().equalsIgnoreCase("post")){%>
- class="com.test.cyw.User" scope="page">
- 姓名:
- 年龄:
- 性别:
- 姓名:${user.name}
- 年龄:${user.age}
- 性别:${user.sex}
- <%
- }
- %>
隐含对象名称 | 描 述 |
---|---|
pageContext | 对应于 JSP 页面中的 pageContext 对象(注意:取的是 pageContext 对象。) |
pageScope | 代表 page 域中用于保存属性的 Map 对象 |
requestScope | 代表 request 域中用于保存属性的 Map 对象 |
sessionScope | 代表 session 域中用于保存属性的 Map 对象 |
applicationScope | 代表 application 域中用于保存属性的 Map 对象 |
param | 表示一个保存了所有请求参数的 Map 对象 |
paramValues | 表示一个保存了所有请求参数的 Map 对象,它对于某个请求参数,返回的是一个 string[] |
header | 表示一个保存了所有 http 请求头字段的 Map 对象 |
headerValues | 同上,返回 string[] 数组。注意:如果头里面有"-",例 Accept-Encoding,则要 headerValues["Accept-Encoding"] |
cookie | 表示一个保存了所有 cookie 的 Map 对象 |
initParam | 表示一个保存了所有 web 应用初始化参数的 map 对象 |
来源: http://www.cnblogs.com/5ishare/p/6572706.html