1.使用JSP的原因

编写Servlet代码的时候,向响应中输出HTML文档是非常不方便的。

PrintWriter writer = response.getWriter();
writer.append("<!DOCTYPE html>\r\n")
.append("<html>\r\n")
.append(" <head>\r\n")
.append(" <title>Hello World Application</title>\r\n")
.append(" </head>\r\n")
.append(" <body>\r\n")
.append(" Nick says, \"Hello, World!\"\r\n")
.append(" </body>\r\n")
.append("</html>\r\n");

在普通的HTML文件中编写上面代码的返回内容是非常简单的。

<!DOCTYPE html>
<html>
<head>
<title>Hello World Application</title>
</head>
<body>
Nick says, "Hello, World!"
</body>
</html>

于是,Java EE规范的创建者就设计了JavaServer Pages(也称为JSP)用于满足这个需求。

JSP结合了Java代码和HTML标签。JSP可以包含除了Java代码之外的任何HTML标签、内建的JSP标签、自定义JSP标签以及表达式语言。

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html>
<head>
<title>Hello World Application</title>
</head>
<body>
Hello, World!
</body>
</html>

<%@ page contentType="text/html;charset=UTF-8" language="java" %>将设置页面的内容类型和字符编码。之前我们使用HttpServletResponse的setContentType和setCharacterEncoding方法进行设置。该JSP中的其他内容都只是普通的HTML,将作为响应内容被发送到客户端。

1.1 JSP在运行时的处理

JSP实际上只是一个精心设计的Servlet。

在编译Java代码的时候,它将被转换成字节码。重要的是我们将使用字节码而不是Java代码。字节码并不是对Java程序最终的渲染。字节码仍然是独立于平台的,并不足以运行在各种不同的操作系统上。

当Java在JRE中运行时,即时编译器将把它编译成机器码(特定于运行JRE的目标机器)。最终执行的实际是机器码。

在运行时,JSP代码将由JSP编译器进行转换,它将解析出JSP代码的所有特性,并将它们转换成Java代码。由JSP创建得到的Java类都将实现Servlet。

在IDE中编译hello-world-jsp项目,启动调试器并打开浏览器访问http://localhost:8080/hello-world-jsp/。在Tomcat的主目录下的work\Catalina\localhost\hello-world-jsp\org\apache\jsp中,可以看到编译过的JSP文件和生成的中间Java文件。

各个Web容器生成的JSP Servlet类看起来并不一致。JSP编译后的类最终取决于它在其中运行的Web容器。重要的一点是:JSP的行为和语法有标准规范,只要使用的Web容器兼容于该规范,那么JSP在所有容器中都将有着相同的行为,即使它们编译生成的代码可能不尽相同。

JSP就像普通的Servlet一样,可以在运行时进行调试(IntelliJ IDEA可以在任何JSP代码中添加断点,Eclipse只允许在JSP的内嵌Java代码中添加断点)。

在某些容器(例如Tomcat)中,JSP将在第一次请求到达时被即时转换并编译。对于之后的请求,可以直接使用编译好的JSP。

JSP可以改善编程速度、效率和开发过程的准确性,所以它是最好的选择。

2.创建第一个JSP

JSP在执行时有很多事情必须处理,但所有的这些事情都已经被处理了。所以,访问一个什么内容都没有的JSP页面不会出现任何错误,一切都正常工作。

JSP默认的内容类型为text/html,默认的字符编码为ISO-8859-1。不过,默认的字符编码与许多特殊字符并不兼容,例如非英语的语言,它们可能会影响应用程序的本地化。

<%@ page contentType="text/html;charset=UTF-8" language="java" %>转换后的代码为:

response.setContentType("text/html;charset=UTF-8");
/*
//等同于
response.setContentType("text/html");
response.setCharacterEncoding("charset=UTF-8");
*/
//也等同于
//response.setHeader("Content-Type","text/html;charset=UTF-8");

2.1 指令、声明、脚本和表达式

<%@ 这是一个指令 %>
<%! 这是一个声明 %>
<% 这是一个脚本 %>
<%= 这是一个表达式 %>

声明用于在JSP Servlet类的范围内声明一些东西,例如可以定义实例变量、方法或声明标签中的类。

脚本被复制到_jspService方法的主体中。该方法中的所有局部变量都可以在脚本中使用。可以在脚本中使用条件语句、操作对象和执行数学计算。

表达式的作用域与脚本相同,它也将被复制到_jspService方法中。表达式用于向客户端输出一些内容,把代码的返回值变量输出到客户端。在表达式中可以执行数学计算,还可以调用一些返回字符串、数字或其他原生类型的方法。事实上,任何赋值表达式的整个右侧都可以用在表达式中。

2.2 注释代码

在JSP中实现代码注释的方法有以下4种:

  • XML注释
  • 传统的Java行注释
  • 传统的Java块注释
  • JSP注释

XML注释<!-- 这是一个HTML/XMl注释 -->可以被发送到客户端,重要的是它并未阻止其中Java代码的执行。

可以在JSP的声明和脚本中使用任何合法的Java注释,包括行注释和块注释。

JSP注释<%-- 这是一个JSP注释 --%>不仅不会发送到浏览器,甚至连JSP编译器也不会解释/转换它们。如果需要注释一段包含JSP脚本、表达式、声明、指令和标记的代码的话,这是非常有用的。

2.3 在JSP中导入类

无论何时在JSP中包含直接使用类的Java代码,该JSP要么使用完全限定类名,要么在JSP文件中添加一条导入指令。正如在Java文件中,java.lang包中的所有类都将被隐式地导入一样,它们也会被隐式地导入到JSP文件中。

在JSP中导入Java类的方式:

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

<%@ page contentType="text/html;charset=UTF-8" language="java" import="java.util.*,java.io.IOException"%>

<%@ page import="java.util.Map" %>
<%@ page import="java.util.List" %>
<%@ page import="java.io.IOException" %>

2.4 使用指令

2.4.1 修改页面属性

pageEncoding指定JSP所使用的字符编码,等同于HttpServletResponse中的setCharacterEncoding方法。

在page指令中使用<%@ page contentType="text/html" pageEncoding="UTF-8" language="java" %>取代之前的<%@ page contentType="text/html;charset=UTF-8" language="java" %>

session的值只能是真和假中的一个,表示JSP是否将参与HTTP会话。默认值为真,因此在JSP中可以访问隐式的session变量。

isELIgnored表示JSP编译器是否将解析和转换JSP中的表达式语言(EL)。

如果在JSP的执行过程中出现了错误,errorPage将告诉容器应该将请求转发到哪个JSP。

isErrorPage表示当前的JSP是否被用作错误页面(默认值为假)。

2.4.2 包含其他JSP

<%@ include file="index.jsp" %>

特性file指定需要包含的JSP文件的路径。

如果使用的是绝对路径,容器将从应用程序的Web根目录开始定位该文件。对于存储在WEB-INF目录中的included.jsp文件来说,可以使用路径/WEB-INF/included.jsp包含它。

如果使用的是相对路径,它将从包含指令的JSP文件所在的目录开始定位包含文件。

在JSP被转换成Java之前,编译器将使用被包含JSP文件的内容替换include指令。因此,该过程是静态的并且只发生一次。

<jsp:include page="index.jsp" />是另一种包含JSP页面的方式,它通过动态(运行时)的方式包含。它使用的路径仍然是相对于当前文件的相对路径,或者从Web根目录开始的绝对路径。被包含的文件将会单独编译。在运行时,请求将会被临时地重定向至被包含的JSP,再将该JSP的结果输出到响应中,然后再将控制权返还给主JSP页面。

这两种包含文件的方法各有优劣。指令include速度快,被引用的JSP文件可以引用主JSP文件中定义的所有变量。但这种方法将使JSP文件变大,记住,Java方法编译后的字节数目最大不能超过65534字节。

<jsp:include>在每次页面加载时都会重新计算,并且被包含的JSP文件不能使用主JSP中已定义的变量。

大多数情况下,include指令都是最好的选择。

2.4.3 包含标签库

如果希望在JSP中使用标签库中定义的标签,使用taglib指令引用该标签库即可。

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

特性uri指定了目标标签库所属的URI命名空间,特性prefix则定义了用于引用库中标签时使用的别名。

2.5 使用JSP标签

通过<jsp:forward page="/some/other/page.jsp" />标签可以将当前JSP正在处理的一些请求转发至其他JSP。在该标签之前生成的任何响应内容仍然会被发送到客户端浏览器中。任何在此标签之后的代码都将被忽略。

<jsp:useBean>标签在页面中声明一个JavaBean。

<jsp:getProperty>将从使用<jsp:useBean>声明的bean中获取属性值。

<jsp:setProperty>将用于设置该实例的属性。

<jsp:useBean>标签创建的bean可以通过其他JSP标签、JSP脚本和表达式访问;如果在脚本中声明一个bean,那么该实例只能用于脚本表达式中。

3.在JSP中使用Java

3.1 使用JSP中隐式的变量

JSP文件提供了几个可在脚本和表达式中使用的隐式变量。之所以称它们为隐式变量:是因为不需要在任何位置定义或声明即可使用它们。它们被定义在JSP执行的Servlet方法的开头。

import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*; public final class index_jsp extends org.apache.jasper.runtime.HttpJspBase
implements org.apache.jasper.runtime.JspSourceDependent,
org.apache.jasper.runtime.JspSourceImports { //... public void _jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response)
throws java.io.IOException, javax.servlet.ServletException { //...
//隐式变量(pageContext、session、application、config、out、page)的声明。
//另外,_jspService方法的参数request和response也是隐式变量
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变量。不过,在大多数情况下,都可以直接使用表达式,或者在JSP中编写文本或HTML内容。

pageContext提供了获取请求特性和会话特性值、访问请求和响应、包含其他文件、转发请求的几个便利方法。

因为page指令的isErrorPage特性的默认值为假,所以exception变量没有在上面出现。如果创建了一个isErrorPage被设置为真的JSP,那么页面中将会自动定义一个隐式变量exception,类型为Throwable。

示例源码链接:https://pan.baidu.com/s/17tSRQEQg1nlyVnjexbYfrA 密码:tsqn

3.2 不应该在JSP中使用Java的原因

JavaServer Pages是一门用于开发表示层(也称为视图)的技术。

尽管可以在表示层中混合数据库访问操作或数学计算,但并不是一个好主意。函数型语言、脚本语言和其他从文件头执行到尾的语言,例如PHP,当然可以这么做。但是不可能在选择Java作为平台语言的时候,还继续以这种方式进行开发。

在一个具有良好结构、干净代码的应用程序中,表示层通常会与业务层分隔开,同样也与数据持久层分隔开。实际上,在JSP中显示动态内容,可以不使用一行Java代码。这使得应用开发者可以专注于业务和数据逻辑,而用户界面开发者则负责JSP的开发。

4.结合使用Servlet和JSP

4.1 将Servlet中的请求转发给JSP

使用请求派发器

    private void showTicketForm(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException
{
request.getRequestDispatcher("/WEB-INF/jsp/view/ticketForm.jsp")
.forward(request, response);
}

请求转发之后,浏览器的URL不会改变。

示例源码链接:https://pan.baidu.com/s/1x6nSWQWV6bKdRn6nkshWag 密码:xx6t

参考:《Java Web高级编程》第4章

Java EE之JSP的更多相关文章

  1. java ee 中 Jsp 页面的定时的跳转(数字倒数)

    java ee 中 Jsp 页面的定时的跳转,实现数字倒计时跳转固定页面 1,Servlet类  RefreshServlet类实现 package org.servlet; import java. ...

  2. 利用Java EE里jsp制作登录界面

    jsp连接数据库.百度经验. 1.在新建的Project中右键新建Floder 2.创建名为lib的包 3.创建完毕之后的工程目录 4.接下来解压你下载的mysql的jar包,拷贝其中的.jar文件 ...

  3. 关于JAVA EE项目在WEB-INF目录下的jsp页面如何访问WebRoot中的CSS和JS文件

    找了这么久资料,总算解决了 感谢博客园:http://www.cnblogs.com/xsht/p/5275081.html 感谢百度:http://zhidao.baidu.com/link?url ...

  4. JavaWeb学习----JSP简介及入门(含Eclipse for Java EE及Tomcat的配置)

    ​[声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/ ...

  5. Java EE基础之JSP

    从本篇文章开始,我会用文章记录下我在学习Java EE过程中的一些笔记和感悟,至于还没有更新结束的Java SE还是会继续写的,只是我觉得一直写语法很枯燥,自己也没法继续下去,所以带着点web学习,会 ...

  6. Eclipse Java EE IDE中jsp页面编码修改

    Eclipse Java EE IDE模板编码是ISO8859,肯定不是我们需要的,修改方法如下图: 依次点击:Window---->Preference---->Web---->J ...

  7. Java EE - JSP 小结

    Table of Contents 前言 JSP 与 Servlet JSP 初始化参数 脚本元素 page 指令 禁用脚本元素 EL 表达式 EL 函数 taglib 指令 标记 TLD 文件的位置 ...

  8. 【Java EE 学习 67 下】【OA项目练习】【SSH整合JBPM工作流】【JBPM项目实战】

    一.SSH整合JBPM JBPM基础见http://www.cnblogs.com/kuangdaoyizhimei/p/4981551.html 现在将要实现SSH和JBPM的整合. 1.添加jar ...

  9. 轻量级Java EE企业应用实战(第4版):Struts 2+Spring 4+Hibernate整合开发(含CD光盘1张)

    轻量级Java EE企业应用实战(第4版):Struts 2+Spring 4+Hibernate整合开发(含CD光盘1张)(国家级奖项获奖作品升级版,四版累计印刷27次发行量超10万册的轻量级Jav ...

随机推荐

  1. Kettle日常使用汇总整理

    Kettle日常使用汇总整理 Kettle源码下载地址: https://github.com/pentaho/pentaho-kettle Kettle软件下载地址: https://sourcef ...

  2. 新手Python第一天(接触)

    Python 变量 Python的变量由字母,数字,下划线组成不包含特殊字符,不能以数字开头 可以使用的名称 例如:name,name2,my_name 不可使用的名称 例如:if...(Python ...

  3. idea最常使用的快捷键

    撤销 反撤销 : Ctrl+Z / Ctrl+Shift+Z 删除一行 : Ctrl+Y 跳到实现类 : Ctrl+Alt+B 重命名文件:   shift+F6 控制台放大缩小: ctrl+shif ...

  4. Scrum Meeting 11.08

    成员 今日任务 明日计划 用时 徐越       赵庶宏       薄霖       卞忠昊 WebView和JavaScript交互基础 Bitmap(位图)全解析 Part1 3h  武鑫 设计 ...

  5. 实验二 Java面向对象程序化设计

    实验二 Java面向对象程序设计 一.  实验要求 1.完成实验.撰写实验报告,以博客方式发表在博客园 2.实验报告重点是运行结果.遇到的问题(工具查找,安装,使用,程序的编辑,调试,运行等).解决办 ...

  6. 炸弹人——NABCD分析

    炸弹人——NABCD分析结果 N:需求:本软件应用于学生,学生可以在课余时间放松心情,缓解学习压力. A:做法:使用Cocosdx和Visual Studio 2010结合,之间用Python使其结合 ...

  7. Task 6.3 冲刺Two之站立会议2

    今天主要将聊天的主界面加以改善,添加了用户登陆后的提示,实现了好友的增删和查询以及自己的账号的个人信息,也可以使用户实现对自己的头像以及个性签名.个人信息等的管理.

  8. Task2 四则运算2

    1.任务要求:对之前的自动出题系统提出了新的要求:(1).题目避免重复:(2).可定制(数量/打印方式):(3)可以控制下列参数:是否有乘除法.数值范围.加减有无负数.除法有无余数.是否支持分数... ...

  9. C++ MOOC

    相关课程列表: C++远征之起航篇 C++远征之离港篇 C++远征之封装篇 上 C++远征之封装篇 下 C++远征之继承篇 C++远征之多态篇 授课老师:james_yuan 在寒假,我主要选择 C+ ...

  10. ThoughtWorks.QRCode类库

    ThoughtWorks.QRCode一个二维码生成类库.