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" %>将设置页面的内容类型和字符编码。之前我们使用HttpServletResponsesetContentTypesetCharacterEncoding方法进行设置。该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. hadoop组件概念理解

    一.HADOOP 二.HIVE 三.SQOOP 1.来由和作用 sqoop由一些封装好的MR程序的jar包构成,后演变成框架,但sqoop只有map任务没有reduce任务. 用于 hdfs.hive ...

  2. Netty源码分析第3章(客户端接入流程)---->第5节: 监听读事件

    Netty源码分析第三章: 客户端接入流程 第五节: 监听读事件 我们回到AbstractUnsafe的register0()方法: private void register0(ChannelPro ...

  3. openstack系列文章(二)

    学习openstack的系列文章-keystone openstack 架构 Keystone 基本概念 Keystone 工作流程 Keystone Troubleshooting 1.  open ...

  4. PASSWORD MySQL 5.6.21-1ubuntu14.04_amd64

    /***************************************************************************** The main idea is that ...

  5. bc命令详解

    基础命令学习目录首页 原文链接:https://www.cnblogs.com/lovevivi/p/4359296.html 最近经常要在linux下做一些进制转换,看到了可以使用bc命令,如下: ...

  6. JVM调优(2)

    堆大小设置JVM 中最大堆大小有三方面限制:相关操作系统的数据模型(32-bt还是64-bit)限制:系统的可用虚拟内存限制:系统的可用物理内存限制.32位系统下,一般限制在1.5G~2G:64为操作 ...

  7. iOS 动态库、静态库 . framework 总结(2017.1.25 修改)

    修改于2017.1.25 使用Xcode Version 8.2.1 1.怎么创建.framework? 打开Xcode, 选择File ----> New ---> Project 选择 ...

  8. 将项目托管到GitHub实现步骤

    修改于:2017.1.14 第一步:先注册一个Github的账号 注册地址:Github官网注册入口 第二步:准备工作 gitHub网站使用Git版本管理工具来对仓库进行管理,但是它们并不等同. gi ...

  9. Beta发布 _thunder_文案+美工展示

    作业要求:https://edu.cnblogs.com/campus/nenu/SWE2017FALL/homework/1366 团队介绍:thunder 组成员及各位博客地址: 1.王航:htt ...

  10. 今日事——Sprint计划会议

    一.   Sprint需求: 解屏提醒部分 界面设计 登录功能 备忘功能 成就系统 二.工作认领: 因有成员请假回家,所以延后认领,目前主要任务是学习如何在andriod平台开发并搭建开发环境. 网上 ...