当前位置: 首页 > news >正文

工信部网站手机备案查询二维码推广赚佣金平台

工信部网站手机备案查询,二维码推广赚佣金平台,设计模板的软件,杭州设计公司税务筹划原文:Learn Java for Web Development 协议:CC BY-NC-SA 4.0 零、简介 这本书是为具有不同经验水平的现代 Java web 开发人员编写的。 学习 Java 编程语言是一项崇高的事业,但是在现实世界中,仅仅学习 Java 语言是不够的。Java …

原文:Learn Java for Web Development

协议:CC BY-NC-SA 4.0

零、简介

这本书是为具有不同经验水平的现代 Java web 开发人员编写的。

学习 Java 编程语言是一项崇高的事业,但是在现实世界中,仅仅学习 Java 语言是不够的。Java 开发人员必须学习 Java EE,这是一个相关服务器端技术的集合,以便将他们的 Java 技能投入到任何实际应用中。

但是学习 Java EE 也是不够的。Java 语言和 Java EE 可能足以为同一个组织中的项目开发 web 应用,作为一种可重用性的手段,但是 web 上 Java 的多样化前景渗透着几个 Web 框架,如 Spring Web MVC,这使得开发更加容易;因此,Java web 开发人员必须了解这些 web 框架。

但是这还不够。在这篇介绍的第一行,我提到这本书是为现代 Java web 开发人员编写的。现代 Java 不仅仅是一种语言;它现在是一个完全优化的平台,因为其他几种语言,如 Groovy 和 Scala,称为 JVM 语言,现在运行在 Java 虚拟机(JVM)上。所有这样的 JVM 语言,尤其是 Groovy,都与 Java 有着密切的联系,不久你就会遇到 Java 和其他 JVM 语言协同工作的 web 应用。最雄心勃勃的项目将要求您使用这些 JVM 语言构建 web 应用。

这本书满足了现代 Java web 开发人员的所有需求。它是为初学者到中级开发人员设计的,并在 Web 上解释了 Java 的细节。例如,这本书非常适合那些知道 MVC 这样的技术,但还不明白它们是如何以及为什么改变了 web 应用构建方式的开发人员。

这本书也适用于那些想学习 JSF 2(与 Java EE 捆绑在一起)之外的框架的开发人员。这本书涵盖了四种类型的 web 框架:基于请求的、基于组件的、快速的和反应式的。在这四种类型中,本书涵盖了五种成熟的 web 框架:Struts 2、Spring Web MVC、JSF 2、Grails 2 和 Play 2。

此外,这本书面向那些没有 Java、Groovy 和 Scala 编程语言经验,但渴望创建 web 应用的开发人员。本书在附录中提供了这三种语言的要点。

Learn Java for web Development通过一个真实的书店应用展示了最流行的 Web 框架的优势,而不是简单地宣布一个 Web 框架是最好的。开发一个完整的真正的应用需要动态功能的无缝协作,而构建这样的组件的代码是人为设计的,而且过于复杂。这本书没有把重点放在开发这样的移动部件上,而是把注意力集中在利用每个 web 框架的优势上。

这本书的结构

这本书由八章组成,我将在接下来描述,加上前面提到的介绍 Java、Groovy 和 Scala 语言的三个附录。

第一章:Java Web 开发简介

第一章解释了塑造本书的主要目标,并强调了后续章节中出现的内容。本章首先讨论了 Java 领域的一个重大变化,它的含义,以及 Java 在今天到底意味着什么。本章随后讨论了构建现代 Java web 应用的三个主要参与者:JVM 语言、Java EE 和 Java web 框架。

本章介绍了现代 Java web 应用的关键特性,如 Ajax 和 REST、用于实时 web 应用的 WebSocket、用于反应式 web 应用的类型安全堆栈,以及用于响应式和单页 web 应用的客户端 MVC 框架。最后,本章介绍了现代 web 开发的一些重要方面,这些方面超出了本书的范围,如 Web 上的 Java 信息检索,并简要介绍了 Web 3.0 的核心组件,它仍然是一个开放的研究主题,即语义 Web。

第二章:使用 Servlets 和 JSP 构建 Web 应用

第二章从讨论 web 应用的发展和架构开始。本章接着强调了如何使用标准的 web API。示例应用的第一步仅使用 servlets 和 JSP。然后,本章将向您展示如何构建与 Model 2 应用相同的应用。

第三章:Java EE Web 开发的最佳实践

第三章分析了导致需要遵循最佳实践的因果链。本章解释了开发项目的必要性,并介绍了表达式语言和 JSTL。本章随后讨论了 Java EE web 层模式。

第四章:使用 Struts 2 构建一个 Web 应用

在第四章中,您将了解 Struts 2。Struts 2 已经不像以前那样流行了,在本书中,Struts 2 被介绍给那些必须维护遗留应用的开发人员。本章首先介绍 Struts 2 的关键架构组件。然后您将学习使用 Struts 2 和 Maven 4 开发您的第一个应用。接下来,您将学习开发书店应用并与 Tiles 3 集成。

第五章:用 Spring Web MVC 构建 Java Web 应用

第五章解释了 Spring 框架的三个关键目标:使用依赖注入的松散耦合,使用 AOP 处理横切关注点,以及使用 Spring 模板移除样板代码。阐明 Spring 3 如何工作,本章介绍了 Spring Web MVC 架构。然后,您将学习使用 Spring 3 web MVC 构建您的第一个 Web 应用。本章还向您展示了如何构建书店应用。你将学会使用最新版本的 SpringSource 工具套件。

第六章:使用 JSF 的基于组件的 Web 开发

第六章向您介绍一个基于组件的框架,名为 JSF 2,它与 Java EE 捆绑在一起。在你熟悉了第四章和第五章中提出的基于请求的框架之后,理解《JSF 2》将会容易得多。这一章向你展示了 JSF 新协议如何代表了 web 开发中的一个范式转变,并向你介绍了 JSF 新协议体系结构的关键组件。在你牢固掌握了体系结构组件之后,本章将向你展示如何开发你的第一个 JSF 2 应用,同时你将学习 JSF 2 应用的生命周期阶段。然后,本章向您展示了如何将 JSF 2 与 Spring 框架集成,以便您可以通过 Spring 模板从 JSF 2 web 层访问数据库。最后,本章向您展示了如何开发书店应用。

第七章:使用 Grails 进行快速 Web 开发

Grails 是一个快速的应用开发框架,可以让您在创纪录的时间内创建 web 应用。第七章向您介绍了用 Grails 生成 web 应用的两种技术:静态和动态搭建。然后,本章将带您浏览生成的代码,并一步一步地解释代码是如何工作的。给出生成的代码后,本章将向您展示如何使用 Grails 2 开发书店应用。本章还介绍了单元测试,这是一个在应用开发中经常被忽视的任务。本章向您展示了如何使用 JUnit 测试框架为您的 web 应用构建测试。然后,本章将向您展示如何使用内存数据库 H2。在本章中,您还将学习使用最新版本的 Groovy-Grails 工具套件。

第八章:玩转 Java 和 Scala

第八章介绍了 Typesafe 堆栈的关键 web 播放器 Play 2 框架,并解释了 Typesafe 堆栈如何提供 Java EE 的替代方案来构建基于 Java 和 Scala 的应用。首先,您将学习使用 Play 2 开发一个基于 Java 的 web 应用。然后您将学习使用 Play 2 开发一个基于 Scala 的 web 应用。随后,本章将展示如何在行动 2 中使用该模型和访问数据库。

一、Java Web 开发简介

一旦被一个新的想法拉伸,头脑就再也不会回到它最初的维度。

拉尔夫·瓦尔多·爱默生 Ralph Waldo Emerson

智能机器是一种能扩展其想象力的机器。这方面的一个例子是名为 invokeDynamic, 1 的指令,它是在 Java 7 中引入的,用于优化动态类型语言在 Java 虚拟机(JVM)上的性能。最初为 Java 设计的 JVM 现在可以托管无数的编程语言,包括 Groovy 2 和 Scala。 3 这导致了 Java web 开发的复兴。这种交叉授粉的新范例和多样化的、有根据的选项在 Java 生态系统中开辟了许多利基市场,导致了比以往任何时候都更加丰富的 web 景观。

开源社区利用运行在 JVM 上的语言所提供的多平台能力,通过 web 框架,极大地提高了 web 开发的效率。Java EE 4 推进了这一势头,由 Spring、 5 等 Java 框架通过标准化和改进 API 和运行时环境开创了这一势头。此外,lambdas 形式的函数式编程结构已经被添加到 Java 8 中。因此,Java 正在反弹,成为一个超级解决方案。

本章通过介绍构建现代 Java web 应用的三个主要参与者为本书做准备:JVM 语言、Java EE 和 Java web 框架。

注意 JVM 语言代表了在 JVM 上运行的一种新的语言类别。有了最新版本 Java 8,Java 不再是一种特权 JVM 语言,现在只是运行在 JVM 上的许多语言之一。

本章首先介绍 JVM 语言,然后介绍 Java EE。Java EE 平台是一组 API 规范,充当开发 web 应用的构建块。然后这一章强调了 Java web 框架,这将是本书从第四章开始的主题。

JVM 语言

JVM 是一个运行时环境,它使您能够使用不同的编程语言来构建 web 应用。JVM 语言可以大致分为两种类型:为 JVM 设计的语言和移植到 JVM 的现有语言。

为 JVM 设计的语言

许多语言是专门为 JVM 设计的;表 1-1 描述了其中的几个。除了 Clojure 之外的所有内容都在本书中讨论。

表 1-1 。为 JVM 设计的语言

|

为 JVM 设计的语言

|

描述

|
| — | — |
| Clojure 6 | Clojure 是一种动态类型的函数式语言。 |
| 绝妙的 | Groovy 是一种动态的编译语言,语法类似于 Java,但更灵活。 |
| Java | Java 是一种静态类型的命令式语言。Java 的最新版本 Java 8 支持函数式编程的各个方面。 |
| 斯卡拉 | Scala 是一种静态类型的编译语言,支持函数式编程的各个方面,并执行大量的类型推断,很像一种动态语言。 |

以下是一些重要的定义:

  • 动态类型化 :动态类型化通过携带变量中保存的值的类型信息来跟踪关于变量包含何种值的信息。
  • 静态类型 :在静态类型中,类型信息都是关于变量的,而不是变量中的值。
  • 命令式语言 :这些语言中的指令可以改变语言的状态。
  • 函数式语言 :在函数式语言中,函数像在过程式语言中一样对值进行操作,但函数不是改变状态,而是返回新值的纯数学函数。

图 1-1 显示了 Java 8、Groovy、Scala 和 Clojure 在函数式语言连续体中的位置。Java 8 引入了 lambdas,这使得它稍微有点函数性,Groovy 从一开始就有函数构造,在 Groovy 2.0 中功能性更强,Scala 是三种面向对象(OO)语言中功能性最强的。另一方面,Clojure 是一种纯函数式的非 OO 语言。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1-1 。 JVM 语言的功能分级

注意在图 1-1 中,没有提到 Groovy、Scala 和 Clojure 的版本号,因为 Java 只支持从 Java 8 开始的函数式编程。

移植到 JVM 的语言

JRuby、Jython 和 Rhino 是现有语言的几个主流 JVM 实现。表 1-2 描述了它们。

表 1-2 。移植到 JVM 的语言

|

移植到 JVM 的语言

|

描述

|
| — | — |
| JRuby 7 | JRuby 是 Ruby 编程语言的 JVM 重新实现。Ruby 是一种动态类型的 OO 语言,具有一些功能特性。 |
| jython8 | Jython 是 Python 在 JVM 上的重新实现,所以它是一种动态语言。 |
| 犀牛 9 | Rhino 在 JVM 上提供了 JavaScript 的实现。JavaScript 是一种动态类型的面向对象语言。 |

这本书基于一些专门为 JVM 设计的主流面向对象 JVM 语言,即 Java、Groovy 和 Scala。

Java EE

Java 最初是一种为构建独立应用而设计的编程语言,并迅速发展到其他领域。Java 的流行很大程度上可以归功于它在创建 web 应用中的使用。web 应用由静态和动态(交互式)网页组成。静态网页 包含各种类型的标记语言(HTML、XHTML 等),通常用于提供信息;动态网页 另一方面,能够在附加 web 组件的帮助下生成内容(在第二章中介绍)。因此,网络应用是网页的集合,并且能够响应请求生成动态内容。与仅用于提供信息的网页不同,web 应用允许您执行一些活动并保存结果。然而,开发 web 应用与构建独立的应用有着本质的不同,需要您理解以下三个关键要素:

  • Java EE 平台 :这是一组 API 规范,是 web 应用的构建块。
  • web 容器:web 容器实现 Java EE 平台的 API 规范。具体来说,web 容器提供了用于管理和执行 web 组件的服务,比如 servlets、JSP、过滤器、监听器和向客户端呈现响应。web 容器包含在第二章中。

注意有几种类型的容器,但是本书将集中讨论主要用于 web 应用的 web 容器。您必须根据您想要开发的应用的类型来选择容器。

  • Web 组件:这些组件由容器托管。这些 web 组件,比如 servlets、JSP、过滤器和监听器,将在第二章的中介绍。

Java EE 平台

Java EE 平台由以下两个目标驱动 :

  • 提供作为 web 应用构建块的 API 规范。
  • 标准化和降低企业应用开发的复杂性。它通过提供一个应用模型来实现这一点,该模型定义了将服务实现为多层应用的架构。

图 1-2 总结了 Java EE 的发展,为了简洁起见,只显示了每个版本中添加的新规范。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1-2 。 Java EE 的演变

注意 修剪(也称为标记为删除)由一个建议的特性列表组成,这些特性可能会在下一个 Java EE 版本中删除,以减小平台的大小或防止其膨胀。

Web Profile 的目标是允许开发人员使用适当的技术创建 Web 应用。

Java EE 平台旨在通过提供一个应用模型来标准化和降低企业应用开发的复杂性,该应用模型定义了将服务实现为多层应用的体系结构。在多层应用中,应用的功能被分成不同的功能区域,称为。图 1-3 展示了 Java EE 应用模型中典型的多层架构 。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1-3 。Java 中的多层架构

客户端层

客户机层是多层 Java EE 架构中的顶层;它由向 Java EE 服务器发出请求的应用客户机组成,javaee 服务器通常位于不同的机器上。服务器处理请求并向客户端返回响应。客户端的一个例子是 web 浏览器或独立应用。

Web 层

web 层由处理客户端和业务层之间交互的组件组成。从客户端收到请求后,web 层执行以下操作:

  1. 收集来自客户端的输入
  2. 控制客户端上屏幕或页面的流动
  3. 维护用户会话的数据状态
  4. 从业务层中的组件获取结果
  5. 为客户端生成各种格式的动态内容

如图图 1-2 所示,Java EE 7 中增加了一个新的 Web Profile 规范。 10 表 1-3 列出了 Web Profile 规范中包含的技术。如前所述,Web Profile 的目标是允许开发人员使用适当的技术创建 Web 应用。

表 1-3 。Web Profile 7 规范

|

规格

|

版本

|

统一资源定位器

|
| — | — | — |
| 联合打击战斗机 | Two point two | JCP . org/en/JSR/detail?id=344 |
| JSP | Two point three | JCP . org/en/JSR/detail?id=245 |
| 标准标记库(JSP Standard Tag Library) | One point two | JCP . org/en/JSR/detail?id=52 |
| 小型应用 | Three point one | JCP . org/en/JSR/detail?id=340 |
| WebSocket | One | JCP . org/en/JSR/detail?id=356 |
| 表达语言 | Three | JCP . org/en/JSR/detail?id=341 |
| 哦,我的上帝 | Three point two | JCP . org/en/JSR/detail?id=345 |
| 作业的装配区(JobPackArea) | Two point one | JCP . org/en/JSR/detail?id=338 |
| JTA | One point two | JCP . org/en/JSR/detail?id=907 |
| Bean 验证 | One point one | JCP . org/en/JSR/detail?id=349 |
| 受管 Beans | One | JCP . org/en/JSR/detail?id=316 |
| 截击机 | One point two | JCP . org/en/JSR/detail?id=318 |
| 上下文和依赖注入 | One point one | JCP . org/en/JSR/detail?id=346 |
| Java 的依赖注入 | One | JCP . org/en/JSR/detail?id=330 |
| 对其他语言的调试支持 | One | JCP . org/en/JSR/detail?id=45 |
| JAX-RS 啊 | Two | JCP . org/en/JSR/detail?id=339 |
| JSON-P | One | JCP . org/en/JSR/detail?id=353 |

关于表 1-3 中列出的网页简介规格:

  • 在 Java EE 7 中,没有对 JSP 和 JSTL 进行任何更改,因为这些规范还没有更新。
  • 表达式语言已经从 JSP 中移除,现在有了自己的 JSR (341)。
  • Servlets 和 JSF 都得到了更新。
  • WebSocket 1.0 是在 Java EE 7 中引入的。

这本书专注于 Java EE 的 web 层;我们将在第二章中深入探讨 web 层。

Java EE 的多层架构对 Java 企业应用的开发有着巨大的影响。 Java 企业应用 可以定义为利用 Java EE 提供的企业服务的 Java 应用。事实上,如果一个 web 应用以打包在 web 层中的组件的形式利用 Java EE 服务,那么它可以被归类为企业应用。如图 1-3 所示,Java EE 通过提供一个构建 Java 企业应用的应用模型,将这些服务从功能上隔离到不同的层中。因此,Java 企业应用反映了 Java EE 的多层架构。图 1-4 展示了一个典型的 web 应用层的一般视图。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1-4 。一个企业应用中各层的综合视图

图 1-4 中的每一层都是关注的一个区域,用于应用。例如,web 层只处理使用 Java EE 的 web 层组件。在一个应用中拥有不同的层会导致所谓的关注点分离。就实现而言,这种关注点的分离是使用粗粒度接口实现的。

关注点是应用开发人员需要关注的特性、功能或业务功能。横切这样的关注点在复杂系统中是固有的,并导致代码分散,这是当一个关注点的代码跨越许多模块时,以及代码缠结,这是当一个模块中的代码集中处理多个关注点时。代码分散和代码纠缠导致缺乏清晰性、冗余性、刚性和持续重构。图 1-5 说明了日志、事务和安全的系统服务如何横切应用的业务功能。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1-5 。涉及系统服务的图书服务

图 1-5 中的 BookService 与系统服务过于相关。每个对象都知道并负责日志记录、安全性和事务。例如,在 BookService 中购买一本书的方法应该只关心如何购买这本书,而不关心它是安全的还是事务性的。关注点分离是软件工程的主要目标之一,它允许您单独处理每个服务,从而完成以下任务:

  • 在系统的整个生命周期中,促进系统中工件内部和之间的可追溯性
  • 控制由变化引起的影响,从而提供进化和非侵入性适应的范围
  • 促进内聚单元的开发,从而促进重用

关注点分离

术语关注点分离 (SoC) 是 Edsger W. Dijkstra 在他的论文《论科学思想的作用》中创造的 11 迪杰斯特拉在以下条款中解释道:

让我试着向你解释,对我来说,什么是所有智能思维的特征。那就是,一个人愿意为了自己的一致性而孤立地深入研究他的主题的一个方面,始终知道自己只专注于其中的一个方面。我们知道一个程序必须是正确的,我们只能从这个角度来研究它;我们也知道它应该是高效的,可以说我们可以改天再研究它的效率。在另一种情绪下,我们可能会问自己,这个项目是否值得,如果值得,为什么值得。但是什么也得不到——相反!—通过同时处理这些不同的方面。这就是我有时称之为“关注点分离”的方法,即使不完全可能,但据我所知,这是有效整理一个人思想的唯一可行的方法。这就是我所说的“将一个人的注意力集中在某个方面”:这并不意味着忽略其他方面,这只是公正地对待这样一个事实,即从这个方面的观点来看,其他方面是不相关的。这是一个和多个轨道的思想同时存在。

网页层

web 应用的 web 层由 Java EE 的 web 层组件组成,如 servlets 和 JSP。web 层可以访问服务层,但是 web 层和服务层之间不应该有紧密的耦合。也就是说,更改服务层不会影响 web 层。

服务层

服务层由 Java EE 的业务层组件组成,比如 Enterprise JavaBean s(EJB)。服务层可以访问数据访问层,但是服务层和数据访问层之间不应该有紧密的耦合。事实上,服务层不应该知道任何关于 web 或数据访问层的事情。服务层为 web 层提供了粗粒度的接口。

数据访问层

数据访问层由 Java EE 的数据层组件组成,如 JDBC 和 JPA。这一层不应该包含任何业务逻辑。该层通过向服务层提供粗粒度接口,从服务层抽象出实际的持久性机制(换句话说,JDBC 或 JPA)。

注意这种架构的调用流程总是从顶层到底层。换句话说,服务层应该能够调用数据访问层,而不是相反。

在本章中,您将构建书店应用的数据访问层,并通过独立的 Java 应用对其进行查询。在第二章中,您将使用 Java EE 的 web 层组件(特别是 servlets 和 JSP)将这个独立的 Java 应用替换为 web 层。在本书中你将会用到这个数据访问层,从第四章开始,你将会通过使用不同的 web 框架重新构建 web 层来重复构建 web 应用。

Oracle 和 Java 社区进程(JCP)提供了标准化的企业组件,如果可以使用这些组件构建成功的企业应用,那么我们为什么还需要 web 框架呢?web 框架是用来做什么的?下一节将回答这些问题。

Java Web 框架

虽然 Java EE 在标准化企业基础设施、提供应用模型和提供足以开发 web 应用的组件方面做得很好,但是有两个主要问题与之相关。

  • 直接与 Java EE 组件交互通常会产生大量样板代码,甚至代码冗余。
  • 使用 Java EE 基础设施创建企业应用是一项艰巨的任务,需要大量的专业知识。通常参与创建企业 Java EE 应用的团队成员扮演着不同的角色,他们可能并不都具有满足 Java EE 标准的专业水平。

框架解决了这两个主要问题(以及在第三章中详细讨论的其他几个问题)。表 1-4 描述了你将在本书中学到的 web 框架。

表 1-4 。基于 JVM 的 Web 框架

|

Web 框架

|

语言

|

从下载

|
| — | — | — |
| 支柱 2 | Java | struts.apache.org/download.cgi#struts2314 |
| 框架 | Java | www.springsource.org/spring-community-download |
| JSF 2 | Java | www.oracle.com/technetwork/java/javaee/downloads/index.html |
| Grails 2 | 绝妙的 | www.grails.org/download |
| 游戏 2 | Java 和 Scala | www.playframework.com/download |

既然您已经看到了构建现代 Java web 应用的三个主要参与者(JVM 语言、Java EE 和 Java web 框架),那么是时候深入研究 Java 的一些细节了。

下一节将介绍 Java,这样您就可以构建自己的第一个独立 Java 应用。由于这本书是以使用 Java 的 web 开发为中心,而不是关于 Java 作为一种编程语言,所以对 Java 的介绍是简短的——这足以帮助语言新手理解后面的章节。

Java 入门

一个 Java 应用是一个当你使用 Java 命令启动 JVM 时执行的计算机程序。在 Java 编程语言中,所有的源代码首先都是用。java 扩展。javac 编译器将源文件编译成。包含字节码指令的类文件。JVM 读取这些字节码指令,并将它们翻译成每台计算机执行的机器语言操作。通过使 JVM 在许多平台上可用,Sun 将 Java 转变成了一种跨平台语言。如图 1-6 所示,完全相同的字节码可以在任何开发了 JVM 的操作系统上运行。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1-6 。跨平台 Java

因为 JVM 可以在许多不同的操作系统上使用,所以。类文件能够在 Windows、Unix、Linux 或 Mac OS 上运行。在接下来的部分,我将向您展示如何编译和运行您的第一个 Java 应用。但是首先您需要设置开发环境。

设置开发环境

Java 软件有两个发行版。

  • Java 运行时环境(JRE )
  • Java 开发工具包(JDK )

JRE 包括一个 JVM 和核心库;它本质上只是一个运行字节码的环境。JDK 包括 JRE、Java 编译器(javac)和其他工具——编写和编译 Java 程序所需的基本软件。

在开始编译和运行 Java 程序之前,您需要下载并安装 JDK,并配置一些系统环境变量。

本书大部分代码需要 Java 7,但部分代码基于 Java 8,所以你应该安装 Java 8。要获得最新版本的 JDK),请按照下列步骤操作:

  1. 在网络浏览器中打开www.oracle.com/technetwork/java/javase/downloads/index.html。
  2. 单击下载 JDK 按钮。
  3. 按照网站提供的说明进行操作。
  4. 运行安装程序并接受任何默认值。

要确认您已经正确安装了 JDK,请在命令行上从您机器上的任何目录键入 javac。如果您看到如何正确运行 javac 的说明,那么您已经成功安装了它。

创建并运行您的第一个 Java 应用

本节演示了如何在 Windows 上创建、编译和执行一个简单的 Java 应用。每个 Java 应用都有一个作为程序起点的类(通常称为入口点)。清单 1-1 展示了一个 HelloWorld 入口点类。

清单 1-1 。一款 HelloWorld Java 应用

1.    public class HelloWorld {
2.    public static void main(String[] args) {
3.    System.out.println("Hello World.");
4.     }
5.    }
  • 第 2 行:第 2 行中的 main 方法使这个类成为入口点类。该方法接受输入并启动程序。

Java 应用的名称应该是入口点类的名称,保存 Java 类的文件必须与该类同名。因此,清单 1-1 中的 HelloWorld 类必须存储在一个名为 HelloWorld.java 的文件中。

注意每个 Java 应用只有一个 main 方法。

您使用 JDK 安装目录的 bin 目录中的 javac 程序来编译 Java 程序。假设您已经在计算机上编辑了 PATH 环境变量,那么您应该能够从任何目录调用 javac。要编译清单 1-1 中的 HelloWorld 类,请执行以下操作:

  1. 打开命令提示符,转到保存 HelloWorld.java 文件的目录。

  2. 键入以下命令:

    javac HelloWorld.java
    

如果一切顺利,javac 将在您的工作目录中创建一个名为 HelloWorld.class 的文件。

运行 Java 应用

要运行您的 java 应用,您必须使用 Java 程序,该程序是带有命令 java 的 JDK 的一部分。同样,添加了 PATH 环境变量后,您应该能够从任何目录调用 java。从您的工作目录中,键入以下内容:

java  HelloWorld

请注意,您不包括。运行 Java 应用时的类扩展。您将在控制台上看到以下内容:

Hello World.

用 IDE 开发 Java 应用

在本书中,您将使用 Eclipse Kepler 集成开发环境(IDE)。要下载软件,请遵循以下步骤:

  1. 在网络浏览器中打开www.eclipse.org/downloads/。
  2. 按照网站提供的说明进行操作。
  3. 运行安装程序并接受任何默认值。

在 IDE 中创建您的第一个项目

启动 Eclipse 后,您可以创建一个新项目,如下所示:

  1. 从“文件”菜单中,选择“新建”,然后选择“项目”。将出现“新建项目”窗口。

  2. In the New Project window, double-click Java Project. The New Java Project window appears, as illustrated in Figure 1-7.

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

    图 1-7 。创建 Java 项目

  3. 在“项目名称”字段中输入 chapter1

  4. 单击完成。您可以在这里更改许多其他选项。然而,对于我们的目的来说,默认设置就可以了。

创建应用

要为您的第一个程序创建一个包含 main 方法的类,请按照下列步骤操作:

  1. Right-click the chapter1 project in the Eclipse Package Explorer, choose New, and then choose Class. The New Java Class window displays, as shown in Figure 1-8.

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

    图 1-8 。创建 Java 类

    一个将类分组在一起。在 Name 字段中,您可以键入类名,即 HelloWorld。选中提供 main 方法(public static void main(String args[]))的复选框。当你完成后,你应该有一个类似于清单 1-2 中的类。

  2. 点击“生成评论”这个很快会解释。

清单 1-2 。简单的 Java 应用

packageapress.helloworld;/*** A Hello World Java application* @author Vishal Layka**/
public class HelloWorld {/*** Entry point* @paramargs*/public static void main(String[] args){System.out.println("Hello World");}}

现在,您可以通过单击工具栏中的“运行”按钮或从“运行”菜单中选择“运行”来运行应用。

然后,Eclipse 会在代码区域下显示一个控制台面板,显示程序的输出。在这种情况下,它说“你好,世界。”

Javadoc 注释

Javadoc 注释 以/*字符序列开始,以/字符序列结束。编译器会忽略这些字符序列之间的所有内容。在 Eclipse 中,您可以通过选择类或方法名并按 Alt+Shift+J 来添加 Javadoc 注释。

要生成 Javadoc,在 Eclipse 中选择项目,选择项目菜单,点击 Generate Javadoc,如图图 1-9 所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1-9 。生成 Javadoc

将会打开一个窗口(图 1-10 ),您可以在其中选择需要生成 Javadoc 的 Java 项目或其底层资源。还有其他几种选择;您可以选择是否为公共/私有 API 生成 Javadoc,等等。现在,在“Javadoc 命令”字段中配置 javadoc.exe 文件,浏览并选择应该生成 Javadoc 的目标文件夹。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1-10 。生成 Javadoc

单击完成。在控制台上,您可以看到 Javadoc 生成的进度。图 1-11 显示了生成的 Javadoc。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1-11 。HelloWorld 类的 Javadoc

现在,您将学习如何创建一个简单但功能强大的独立书店应用版本,您将在本书中使用它。

书店应用

这本书不是简单地宣称一个 web 框架是最好的,而是打算通过一个真实世界的书店应用来展示最流行的 web 框架的优势。开发一个完整的真正的应用需要动态功能的无缝协作,而构建这样的组件的代码是人为设计的,而且过于复杂。这本书没有把重点放在开发这样的移动部件上,而是把注意力集中在利用每个 web 框架的优势上。在整本书中,您将学习如何使用 Java EE 和 Java web 框架来构建书店 web 应用。在本章中,您将通过构建一个传统的独立 Java 书店应用迈出第一步。在第二章中,你将把单机应用转换成 web 应用。

在本书中,我将使用一个 web 应用案例研究来演示如何使用 servlets 和 JSP 以及不同的 web 框架(如 JSF、Struts 2、Spring web MVC)和快速 Web 开发框架(如 Grails 和 Play)来编写 Web 应用。该应用允许用户通过关键字查看和搜索书籍,通常是通过作者的名字或姓氏以及书名。

书店应用的数据模型

本节介绍了一个简单的数据模型,该模型将用于本书中的书店 web 应用。当需要时,我将在每章中逐步扩展这个模型。该模型是一个简单的图书数据库,由三个表组成。

  • 类别表存储不同类别的书籍;类别包括 Java、Scala 等等。
  • 图书表存储图书的详细信息,比如书名。
  • 作者表存储作者的详细信息。

每个类别可以有零本或多本书。例如,书店里可能没有或有更多属于 Java 类别的书籍。换句话说,Category 和 Book 表之间是一对多的关系。同样,每本书可以有一个或多个作者。换句话说,Book 和 Author 表之间是一对多的关系。图 1-12 中的实体关系图说明了这种关系。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1-12 。数据模型的实体关系图

这个数据模型还不能用于生产,因为您可以在类别和图书之间建立多对多的关系,在图书和作者之间建立多对多的关系。我保持数据模型简单,这样数据模型的复杂性就不会妨碍学习构建 web 应用的技巧。然而,你可以,例如,在书和作者之间建立一个多对多的关系,如图 1-13 所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1-13 。书籍和作者之间的多对多关系

BookAuthor 表的唯一目的是提供图书和作者之间的多对多关系。

如图图 1-13 所示,图书与图书作者之间是一对多关系,作者与图书作者之间是一对多关系。事实上,BookAuthor 表的唯一目的是提供图书和作者之间的多对多关系,换句话说,一个作者可以写很多本书,一本书可以有很多作者。

由于跨几个领域的 web 应用大量涌现,许多关系和非关系数据库如 NoSQL 12 已经出现。在本书中,我将使用 MySQL 13 ,因为它是使用最广泛的免费数据库管理系统(DBMS)。要安装 MySQL,请转到dev.mysql.com/downloads/并点击下载。可以下载 MySQL Server 5.5 或更新版本。你可以在dev.mysql.com/doc/refman/5.5/en/installing.html看到安装 MySQL 的说明。

要创建图书数据库,请使用以下命令:

create database books;

您需要使用以下命令指示 MySQL 在 books 数据库中创建表:

use books;

现在您可以使用清单 1-3 中的语句创建表格。

清单 1-3 。为书店创建桌子

CREATE  TABLE CATEGORY (
ID  INT NOT NULL  AUTO_INCREMENT ,
CATEGORY_DESCRIPTION  VARCHAR(20)  NOT NULL ,
PRIMARY KEY (ID)
);CREATE  TABLE BOOK (
ID  INT NOT  NULL AUTO_INCREMENT,
CATEGORY_ID  INT  NOT  NULL ,
BOOK_TITLE  VARCHAR(60) NOT NULL,
PUBLISHER  VARCHAR(60) NOT NULL ,
PRIMARY KEY (ID) ,
CONSTRAINT  FK_BOOK_1  FOREIGN KEY (CATEGORY_ID) REFERENCES CATEGORY(ID));CREATE  TABLE  AUTHOR (
ID  INT  NOT NULL AUTO_INCREMENT ,
BOOK_ID  INT  NOT  NULL ,
FIRST_NAME  VARCHAR(20)  NOT NULL ,
LAST_NAME  VARCHAR(20)  NOT NULL ,
PRIMARY KEY (ID) ,
CONSTRAINT FK_AUTHOR_1 FOREIGN KEY (BOOK_ID) REFERENCES BOOK (ID)
);

您可以使用显示表格命令验证创建的表格,如图图 1-14 所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1-14 。数据库中的所有表

您也可以使用命令 describe 或 desc 检查表格的结构,如图图 1-15 所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1-15 。表格的结构

现在使用 insert 语句填充这些表,如下所示:

insert into category (category_description) values ('Clojure');
insert into category (category_description) values ('Groovy');
insert into category (category_description) values ('Java');
insert into category (category_description) values ('Scala');

您可以验证填充的类别表,如图图 1-16 所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1-16 。类别表中的所有类别

insert into Book (CATEGORY_ID, BOOK_TITLE, PUBLISHER) values (1, 'Practical Clojure', 'Apress');
insert into Book (CATEGORY_ID, BOOK_TITLE, PUBLISHER) values (2, 'Beginning Groovy, Grails and Griffon', 'Apress');
insert into Book (CATEGORY_ID, BOOK_TITLE, PUBLISHER) values (2, 'Definitive Guide to Grails 2', 'Apress');
insert into Book (CATEGORY_ID, BOOK_TITLE, PUBLISHER) values (2, 'Groovy and Grails Recipes', 'Apress');
insert into Book (CATEGORY_ID, BOOK_TITLE, PUBLISHER) values (3, 'Modern Java Web Development', 'Apress');
insert into Book (CATEGORY_ID, BOOK_TITLE, PUBLISHER) values (3, 'Java 7 Recipes', 'Apress');
insert into Book (CATEGORY_ID, BOOK_TITLE, PUBLISHER) values (3, 'Java EE 7 Recipes', 'Apress');
insert into Book (CATEGORY_ID, BOOK_TITLE, PUBLISHER) values (3, 'Beginning Java 7 ', 'Apress');
insert into Book (CATEGORY_ID, BOOK_TITLE, PUBLISHER) values (3, 'Pro Java 7 NIO.2', 'Apress');
insert into Book (CATEGORY_ID, BOOK_TITLE, PUBLISHER) values (3, 'Java 7 for Absolute Beginners', 'Apress');
insert into Book (CATEGORY_ID, BOOK_TITLE, PUBLISHER) values (3, 'Oracle Certified Java Enterprise Architect Java EE7', 'Apress');
insert into Book (CATEGORY_ID, BOOK_TITLE, PUBLISHER) values (4, 'Beginning Scala', 'Apress');

您可以验证如图图 1-17 所示的已填充的图书表。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1-17 。图书表中的所有图书

insert into Author (BOOK_ID, FIRST_NAME, LAST_NAME) values (1, 'Luke', 'VanderHart');
insert into Author (BOOK_ID, FIRST_NAME, LAST_NAME) values (2, 'Vishal', 'Layka');
insert into Author (BOOK_ID, FIRST_NAME, LAST_NAME) values (3, 'Jeff', 'Brown');
insert into Author (BOOK_ID, FIRST_NAME, LAST_NAME) values (4, 'Bashar', 'Jawad');
insert into Author (BOOK_ID, FIRST_NAME, LAST_NAME) values (5, 'Vishal', 'Layka');
insert into Author (BOOK_ID, FIRST_NAME, LAST_NAME) values (6, 'Josh',  'Juneau');
insert into Author (BOOK_ID, FIRST_NAME, LAST_NAME) values (7, 'Josh', 'Juneau');
insert into Author (BOOK_ID, FIRST_NAME, LAST_NAME) values (8, 'Jeff', 'Friesen');
insert into Author (BOOK_ID, FIRST_NAME, LAST_NAME) values (9, 'Anghel', 'Leonard');
insert into Author (BOOK_ID, FIRST_NAME, LAST_NAME) values (10, 'Jay',  'Bryant');
insert into Author (BOOK_ID, FIRST_NAME, LAST_NAME) values (11, 'B V', 'Kumar');
insert into Author (BOOK_ID, FIRST_NAME, LAST_NAME) values (12, 'David', 'Pollak');

您可以验证填充的作者表,如图图 1-18 所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1-18 。作者表中的所有作者

书店应用的数据访问层

现在数据库已经准备好了,您将为应用构建数据访问层。数据访问层将通过 JDBC 从数据库中检索数据,并将结果集直接映射到 Java 对象中。这些 Java 对象是应用中的域对象,是数据库中表的 Java 表示。数据访问层负责以透明的方式与底层持久性机制进行交互,以便从数据库中存储和检索对象。这种透明性意味着数据访问层可以将持久化机制从普通的 JDBC 14 切换到 ORM 15 持久化技术如 Hibernate、 16 JPA、 17 等,而不影响数据访问层的客户端。这种透明性是通过数据访问对象(DAO)模式实现的,如图 1-19 所示。DAO 对象提供了到数据库或底层持久化机制的接口,从而从客户端抽象出底层实现。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1-19 。道模式

DAO 将应用调用映射到持久性机制,并提供特定的数据操作,而不公开数据库的细节。DAO 接口抽象了从客户机(应用对象)访问数据的实现细节,并提供了客户机(应用对象)需要的特定于域的对象。

首先,您需要为数据库表的 Java 对象表示创建特定于领域的类。清单 1-4 、 1-5 和 1-6 分别显示了图书、作者和类别领域类。

清单 1-4 。型号:类别

package com.apress.books.model;public class Category {private Long id;private String categoryDescription;public Long getId() {return id;}public void setId(Long id) {this.id = id;}public String getCategoryDescription() {returncategoryDescription;}public void setCategoryDescription(String categoryDescription) {this.categoryDescription = categoryDescription;}public String toString() {return "Category - Id: " + id + ", Category Description: "+ categoryDescription;}}

清单 1-5 。型号:书本

package com.apress.books.model;import java.util.List;
import com.apress.books.model.Author;public class Book {private Long id;private Long categoryId;private String bookTitle;private List<Author> authors;private String publisherName;public Long getId() {return id;}public void setId(Long id) {this.id = id;}public Long getCategoryId() {return categoryId;}public void setCategoryId(Long categoryId) {this.categoryId = categoryId;}public String getBookTitle() {return bookTitle;}public void setBookTitle(String bookTitle) {this.bookTitle = bookTitle;}public List<Author> getAuthors() {return authors;}public void setAuthors(List272103_1_En authors) {this.authors = authors;}public String getPublisherName() {return publisherName;}public void setPublisherName(String publisherName) {this.publisherName = publisherName;}public String toString() {return "Book - Id: " + id + ", Book Title: " + bookTitle;}}

清单 1-6 。型号:作者

package com.apress.books.model;public class Author {private Long id;private Long bookId;private String firstName;private String lastName;public Long getId() {return id;}public void setId(Long id) {this.id = id;}public Long getBookId() {return bookId;}public void setBookId(Long bookId) {this.bookId = bookId;}public String getFirstName() {return firstName;}public void setFirstName(String firstName) {this.firstName = firstName;}public String getLastName() {return lastName;}public void setLastName(String lastName) {this.lastName = lastName;}public String toString() {return "Author - Id: " + id + ", Book id: " + bookId + ", First Name: "+ firstName + ", Last Name: " +lastName;}}

现在让我们从 BookDAO 的一个简单接口开始,它封装了 web 应用访问的所有数据。清单 1-7 显示了 BookDAO 接口。

清单 1-7 。书道界面

 1.    package com.apress.books.dao;2.3.    import java.util.List;4.5.    import com.apress.books.model.Book;6.    import com.apress.books.model.Category;7.8.    public interface BookDAO {9.        public List<Book>findAllBooks();
10.
11.        public List<Book>searchBooksByKeyword(String keyWord);
12.
13.        public List<Category>findAllCategories();
14.
15.        public void insert(Book book);
16.
17.        public void update(Book book);
18.
19.        public void delete(Long bookId);
20.
21.    }
  • 第 9 行:这是 findAllBooks()方法,用于列出数据库中的所有书籍。
  • 第 11 行 : SearchBooksByKeyword(字符串关键字)允许用户通过书名中的关键字或者作者的名和姓来搜索书籍。
  • 应用需要 findAllCategories()来提供图书的分类列表。

该接口中的方法对应于应用的 CRUD 术语(换句话说,创建、读取、更新和删除)。清单 1-8 展示了 BookDAO 接口的实现。

清单 1-8 。BookDAO 接口的实现

 1.    package com.apress.books.dao;2.3.    import java.sql.Connection;4.    import java.sql.DriverManager;5.    import java.sql.PreparedStatement;6.    import java.sql.ResultSet;7.    import java.sql.SQLException;8.    import java.sql.Statement;9.    import java.util.ArrayList;
10.    import java.util.List;
11.
12.    import java.apress.books.model.Author;
13.    import java.apress.books.model.Book;
14.    import java.apress.books.model.Category;
15.
16.    public class BookDAOImpl implements BookDAO {
17.
18.        static {
19.            try {
20.                Class.forName("com.mysql.jdbc.Driver");
21.            } catch (ClassNotFoundException ex) {
22.            }
23.        }
24.
25.        private Connection getConnection() throws SQLException {
26.            return DriverManager.getConnection("jdbc:mysql://localhost:3306/books",
27.                    "root", "password");
28.        }
29.
30.        private void closeConnection(Connection connection) {
31.            if (connection == null)
32.                return;
33.            try {
34.                connection.close();
35.            } catch (SQLException ex) {
36.            }
37.        }
38.
39.        public List<Book> findAllBooks() {
40.            List<Book> result = new ArrayList<>();
41.            List<Author> authorList = new ArrayList<>();
42.
43.            String sql = "select * from book inner join author on book.id = author.book_id";
44.
45.            Connection connection = null;
46.            try {
47.                connection = getConnection();
48.                PreparedStatement statement = connection.prepareStatement(sql);
49.                ResultSet resultSet = statement.executeQuery();
50.                while (resultSet.next()) {
51.                    Book book = new Book();
52.                    Author author = new Author();
53.                    book.setId(resultSet.getLong("id"));
54.                    book.setBookTitle(resultSet.getString("book_title"));
55.                    book.setCategoryId(resultSet.getLong("category_id"));
56.                    author.setBookId(resultSet.getLong("book_Id"));
57.                    author.setFirstName(resultSet.getString("first_name"));
58.                    author.setLastName(resultSet.getString("last_name"));
59.                    authorList.add(author);
60.                    book.setAuthors(authorList);
61.                    book.setPublisherName(resultSet.getString("publisher"));
62.                    result.add(book);
63.                }
64.            } catch (SQLException ex) {
65.                ex.printStackTrace();
66.            } finally {
67.                closeConnection(connection);
68.            }
69.            return result;
70.        }
71.
72.
73.        public List<Book> searchBooksByKeyword(String keyWord) {
74.            List<Book> result = new ArrayList<>();
75.            List<Author> authorList = new ArrayList<>();
76.
77.            String sql = "select * from book inner join author on book.id = author.book_id"
78.                    + " where book_title like '%"
79.                    + keyWord.trim()
80.                    + "%'"
81.                    + " or first_name like '%"
82.                    + keyWord.trim()
83.                    + "%'"
84.                    + " or last_name like '%" + keyWord.trim() + "%'";
85.
86.            Connection connection = null;
87.            try {
88.
89.                connection = getConnection();
90.                PreparedStatement statement = connection.prepareStatement(sql);
91.                ResultSet resultSet = statement.executeQuery();
92.                while (resultSet.next()) {
93.                    Book book = new Book();
94.                    Author author = new Author();
95.                    book.setId(resultSet.getLong("id"));
96.                    book.setBookTitle(resultSet.getString("book_title"));
97.                    book.setPublisherName(resultSet.getString("publisher"));
98.                    author.setFirstName(resultSet.getString("first_name"));
99.                    author.setLastName(resultSet.getString("last_name"));
100.                    author.setBookId(resultSet.getLong("book_id"));
101.                    authorList.add(author);
102.                    book.setAuthors(authorList);
103.                    result.add(book);
104.                }
105.            } catch (SQLException ex) {
106.                ex.printStackTrace();
107.            } finally {
108.                closeConnection(connection);
109.            }
110.
111.            return result;
112.        }
113.
114.        public List<Category> findAllCategories() {
115.            List<Category> result = new ArrayList<>();
116.            String sql = "select * from category";
117.
118.            Connection connection = null;
119.            try {
120.                connection = getConnection();
121.                PreparedStatement statement = connection.prepareStatement(sql);
122.                ResultSet resultSet = statement.executeQuery();
123.                while (resultSet.next()) {
124.                    Category category = new Category();
125.                    category.setId(resultSet.getLong("id"));
126.                    category.setCategoryDescription(resultSet
127.                            .getString("category_description"));
128.                    result.add(category);
129.                }
130.            } catch (SQLException ex) {
131.                ex.printStackTrace();
132.            } finally {
133.                closeConnection(connection);
134.            }
135.            return result;
136.        }
137.
138.        public void insert(Book book) {
139.        }
140.
141.        public void update(Book book) {
142.        }
143.
144.        public void delete(Long bookId) {
145.
146.        }
147.    }

清单 1-8 是 BookDao 接口的一个实现,用于与;这种交互包括连接到数据库,并通过纯 JDBC 选择、删除和更新数据。JDBC 提供了特定于每个数据库的驱动程序,并允许 Java 对数据库进行编码。

  • 第 18 到 37 行:这几行显示了管理 JDBC 连接所需的代码。
  • 第 26 行:getConnection()方法返回一个驱动实现的 java.sql.Connection 接口。这个接口允许您对数据库运行 SQL 语句。为此,您需要提供一个 MySQL 连接器/J JAR 文件。MySQL Connector/J 是一个本地 Java 驱动程序,它将 JDBC 调用转换成 MySQL 数据库可以理解的网络协议。DriverManager 管理驱动程序,并提供建立数据库连接的静态方法。

注意你可以从 http://dev.mysql.com/downloads/connector/j/下载 MySQL 连接器/J。将这个连接器 JAR 放在项目的类路径中。

  • 第 30 行到第 37 行:需要关闭连接,因为就应用的性能而言,连接是很昂贵的。
  • 第 39 到 144 行:这几行是 BookDAO 接口中 CRUD 服务的实现。
  • 第 67、108 和 133 行:您为 CRUD 服务中的每个语句创建了一个连接。您需要关闭这些连接;让它们保持打开状态会导致应用的性能下降。

数据访问层的客户端

现在您的数据访问层已经准备好了,您将使用独立的 Java 应用查询它。在第二章中,你将用一个网络应用替换这个 Java 应用。清单 1-9 展示了 Java 应用。

清单 1-9 。单机书店 Java App

 1.    package com.apress.books.client;2.    import java.util.List;3.4.    import com.apress.books.dao.BookDAO;5.    import com.apress.books.dao.BookDAOImpl;6.    import com.apress.books.model.Book;7.8.    public class BookApp {9.        private static BookDAO bookDao = new BookDAOImpl();
10.
11.        public static void main(String[] args) {
12.            // List all books
13.            System.err.println("Listing all Books:");
14.            findAllBooks();
15.            System.out.println();
16.            // search book by keyword
17.            System.err.println("Search book by keyword  in book title : Groovy:");
18.
19.            searchBooks("Groovy");
20.            System.out.println();
21.
22.            System.err.println("Search book by keyword  in author's name  : Josh:");
23.
24.            searchBooks("Josh");
25.
26.
27.        }
28.
29.        private static void findAllBooks() {
30.            List<Book> books = bookDao.findAllBooks();
31.            for (Book book : books) {
32.                System.out.println(book);
33.            }
34.        }
35.        private static void searchBooks(String keyWord) {
36.            List<Book> books = bookDao.searchBooksByKeyword(keyWord);
37.            for (Book book : books) {
38.                System.out.println(book);
39.            }
40.        }
41.    }

图 1-20 说明了独立应用的目录结构。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1-20 。独立书店应用的目录结构

运行此应用会产生以下输出:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在下一章中,您将开发 web 层来代替这个客户端,并调用书店 web 应用中的数据访问层。

Java Web 领域的趋势和技术

现在是时候深入研究当今 Java web 领域的趋势和技术了。对于 Java 新手来说,这可能令人望而生畏,但目标是让您熟悉 Java web 应用开发中的工具、技术和趋势,以便让您对现代 Java 前景有一个初步了解。当您学习使用 Grails 2 和 Play 2 等快速 web 框架开发 web 应用时,您会发现这些工具和技术中的大多数都是现成的。

正如本章所提到的,JVM 最初是为 Java 设计的,现在可以支持无数的编程语言,包括 Groovy 和 Scala。作为这种新兴的多道程序设计范例的结果,现代 web 应用通常具有以下一种或多种特征:

  • 响应式 web 应用
  • 单页 web 应用
  • 实时网络应用
  • 反应式 web 应用
  • 混搭和 web 服务

响应式网络应用

网络最大的优势之一就是它的灵活性。然而,这种灵活性也是其最大的弱点。当在一个浏览器上测试的 web 应用在另一个浏览器上被查看并且不能正常运行时,这个弱点就显现出来了。随着智能手机的出现,这种跨浏览器兼容性问题越来越严重。如图 1-21 所示,截至 2013 年底,全球有 68 亿移动用户,到 2016 年这一数字将增长到 80 亿(【www.itu.int/ITU-D/ict/facts/index.html】??)。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1-21 。移动订阅

Web 应用既可以在桌面上运行,也可以在智能手机上运行,但是为桌面和智能手机创建单独的 web 应用会带来巨大的开发和维护开销。2010 年 5 月,Ethan Marcotte 为 List Apart 写了一篇名为“响应式网页设计”的文章,定义了一种突破性的方法。他使用现有的工具(这将在本节稍后解释)创建了一个在不同设备上显示精美的网站,如图图 1-22 和图 1-23 所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1-22 。Ethan Marcotte 的响应网站

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1-23 。智能手机上的同一个响应网站

web 应用是与设备无关的,因为它们可以适应运行它们的设备。这项技术甚至重新思考了页面布局的设计方式。您可以更进一步,在设计 web 应用时考虑最小的屏幕(智能手机),然后逐步增强应用以在桌面屏幕上运行。这种技术被称为移动优先设计。移动优先设计的理念是,如果你设计的界面和网络组件能够在智能手机上以可接受的性能运行,那么在桌面屏幕上的性能将会非常快。此外,明智地使用智能手机也将适用于桌面屏幕,这将使应用的可用性更好。

开发响应式 web 应用所采用的核心技术有 CSS3、18jQuery19和 jQuery 插件、 20 LESS、21coffee script、 22 以及 Bootstrap、 23 Polyfills

以下是响应式世界中的一些重要定义:

  • 不引人注目的 JavaScript24:不引人注目的 JavaScript 是一种分离关注点的手段,即把外观和感觉从行为关注点中分离出来。这就产生了一个纯标记,JavaScript(行为)在不同的浏览器和设备上不引人注目地工作。jQuery 是一个流行的库,有助于编写不引人注目的 JavaScript。CoffeeScript 编译成 JavaScript。它被用作 JavaScript 的替代品,并大大减少了代码。
  • CSS3 媒体查询 :媒体查询是让 web 应用做出响应的主要手段。媒体查询使用 CSS 文件中的媒体特征(如设备宽度、设备高度、方向和设备纵横比)来开发响应性 web 应用。
  • LESS : LESS 是 CSS3 样式表变得不可管理时使用的 CSS 预处理器。LESS 扩展了 CSS 的动态行为,比如混合和函数。
  • Polyfills : Polyfills 是 JavaScript,用于制作支持 HTML5 的浏览器。聚合填充提供了浏览器中缺少的功能,并提供了一个后备。
  • Modernizr : Modernizr 是一个 JavaScript 库,可以检测浏览器中的 HTML5 和 CSS3 特性,并有条件地加载 polyfills。

单页 Web 应用(SPA)

web 应用开发的另一个趋势是单页面 web 应用的出现。

  • 客户端代码——如 HTML、JavaScript 和 CSS——通过单个页面加载进行检索;在该过程中的任何时候都不会重新加载页面,并且控件也不会转移到另一个页面。
  • 资源(如图像)会动态加载并添加到页面以响应事件。

spa 是使用 Node.js 25 作为 web 服务器构建的。AngularJS 是一个功能齐全的 SPA 框架。

实时 Web 应用

一个实时 web 应用根据事件的性质,通过客户端和服务器之间的异步双向通信,在可测量和可接受的时间段内对事件做出响应。WebSocket 是开发实时 web 应用的核心技术。WebSocket 通过单一 TCP 连接提供全双工和双向通信协议。也就是说,客户端和服务器可以相互发送消息,并且相互独立。

需要实时功能的应用的几个例子是聊天应用、多人在线游戏、股票事务应用等等。

注意【WebSocket 的 Java API 定义为 JSR 356;参见表 1-3 。

反应式网络应用

反应式应用是一类新的应用,与传统的基于网络的应用有着本质的不同,由类型安全 26 反应式平台驱动。Typesafe 反应式平台是一套集成产品,包括 Play 2 框架、Akka、 27 和 Scala,以及用于命令和控制的 Typesafe 控制台。由于多核处理器以及它提倡异步和基于事件的编程,反应式编程变得至关重要。Play 框架是企业 Java 堆栈的替代方案。Play 是为现代 web 和移动应用的需求而构建的,利用了 REST、JSON 和 WebSocket 等技术。这些技术允许创建通过任何现代浏览器呈现的丰富、高度交互的用户界面,同时使并行呈现页面的各个部分以及进行部分页面更新或渐进式增强变得更加容易。

混搭和网络服务

mashup 是一个 web 应用,它使用来自多个来源的内容来创建一个显示在单一图形界面中的新服务。使用 mashups,您可以通过组合 web 服务来开发强大的应用。你可以在 www.programmableweb.com/apis/directory/1?sort=mashups 的找到流行的混搭 API。这一节将关注 web 服务,然后触及一个迷人的趋势,这仍然是一个研究领域:语义 Web。

一个 web 服务 是一个存储在一台机器上的软件组件,可以被另一台机器上的应用(或其他软件组件)通过网络访问。web 服务所在的机器被称为 web 服务主机。客户端应用通过网络向 web 服务主机发送请求,web 服务主机处理请求并返回响应。使 web 服务可用于接收客户端请求被称为发布web 服务;从客户端应用使用 web 服务被称为消费web 服务。

Web 服务使用 XML 和 JSON 28 等技术进行数据交换。

JavaScript 对象符号

JavaScript 对象符号(JSON) 用于表示数据,作为 XML 的替代。JSON 减少了 web 请求的负载,提高了 web 应用的整体性能。JSON 是一种基于文本的数据交换格式,用于将 JavaScript 中的对象表示为由字符串表示的名称-值对的集合。

JSON 处理在 JSR 353 中定义为 JSON 处理的 Java API 参见表 1-3 。

两个 Java APIs 促进了 web 服务:

  • JAX-WS :这是基于简单对象访问协议(SOAP), 29 这是一种基于 XML 的协议,允许 web 服务和客户端进行通信,即使客户端和 web 服务是用不同的语言编写的。
  • JAX-RS :这使用了表述性状态转移(REST),这是一种网络架构,使用 Web 的传统请求-响应机制,如 GET 和 POST 请求。

简单对象访问协议

简单对象访问协议(SOAP)是一个独立于平台的协议,它使用 XML 与 web 服务进行交互,通常是通过 HTTP。每个请求和响应都封装在 SOAP 消息中,SOAP 消息是包含 web 服务处理消息所需信息的 XML 标记。SOAP web 服务的工作方式如下:

  1. 当调用 SOAP web 服务的方法时,请求被封装在 SOAP 信封中的 SOAP 消息中,并发送到 web 服务所在的服务器。
  2. 当 SOAP )web 服务收到此消息时,它会解析表示消息的 XML,然后处理消息的内容。
  3. 然后,web 服务在处理完请求后,在另一个 SOAP 消息中将响应发送给客户端。
  4. 客户端解析响应。

代表性状态转移

罗伊·菲尔丁于 2000 年在加州大学欧文分校的博士论文 30 中引入并定义了术语表征状态转移 (REST) 。REST 指的是一种实现 web 服务的架构风格,称为 RESTful web 服务。RESTful web 服务中的每个方法都由唯一的 URL 标识。

注意 RESTful web 服务被定义为 JSR 339,如表 1-3 所示。

与 SOAP 不同,REST 执行以下操作:

  • 将资源标识为 URI
  • 使用一组定义良好的 HTTP 方法来访问资源
  • 使用资源的多种表示格式

语义网(Web 3.0)

Web 2.0 在 2004 年开始成形。它由谷歌开创,随后是视频分享、社交网络、微博、照片分享、维基百科等社交应用,以及第二人生等虚拟世界。混搭在社交应用和 Web 2.0 的发展中扮演了重要角色。

术语语义网指的是 W3C 对链接数据网的设想。语义网可以被看作是一套标准,允许机器理解网上信息的意思。今天的网络由本身没有意义的数据组成,而这些意义必须在从网络上收集数据后手工构建。语义 Web 技术使您能够在 Web 上创建数据存储,构建词汇表,并编写处理数据的规则。关联数据是通过 RDF、 31 SPARQL、 32 和 OWL 等技术实现的。语义网是网络的未来,也是一个正在研究的课题。我推荐艾伦·施瓦茨的一个可编程的 Web:一个未完成的工作 34 作为语义 Web 上的优秀资源。你也可以关注语义网上的最新消息。

摘要

本章介绍了 Java 语言,然后带您进行了一次旋风式的 Java 之旅。Java 世界的多样化景观由几个 web 框架(如 Struts 2、Spring Web MVC、JSF 2、Grails 2 和 Play 2)组成,这些框架使开发变得容易得多;因此,作为 Java web 开发人员,您需要熟悉这些 web 框架。现代 Java 不仅仅是一种语言;现在,它是一个针对其他几种行业优势语言(如 Groovy、Clojure 和 Scala)的完全优化的平台。所有这些语言,尤其是 Groovy,都与 Java 有着密切的联系,不久您将会遇到 web 应用,其中 Java 和这些替代的 JVM 语言将协同工作。

随后的章节将解决现代 Java web 开发人员的所有这些需求。具体来说,在下一章中,您将创建一个 Hello World web 应用,它利用了 web 应用的基本构件,即 servlets 和 Java 服务器页面。然后,您将把这个独立的应用转换成您的第一个成熟的 web 应用:一个使用 servlets 和 JSP 的书店应用。

Cr . open JDK . Java . net/√jrose/pres/2009 910-vml . pdf

2【http://groovy.codehaus.org/】??

3【www.scala-lang.org/】??

4【www.oracle.com/technetwork/java/javaee/overview/index.html】??

5【http://spring.io/】??

6【http://clojure.org/】??

7【http://jruby.org/】??

8【www.jython.org/】??

9T3developer . Mozilla . org/en-US/docs/Rhino _ documentation

10【www.oracle.com/technetwork/java/javaee/tech/index.html】??

11www . cs . ute xas . edu/users/EWD/transcriptions/ewd 04 xx/ewd 447 . html

12【http://nosql-database.org/】??

13【www.mysql.com/】??

14【www.oracle.com/technetwork/java/overview-141217.html】??

15【http://en.wikipedia.org/wiki/Object-relational_mapping】??

16【www.hibernate.org/】??

17www . Oracle . com/tech network/Java/javaee/tech/persistence-JSP-140049 . html

18【www.w3.org/Style/CSS/current-work.en.html】??

19【http://jquery.com/】??

【20】【http://plugins . jquery . com/

21【http://lesscss.org/】??

22【http://coffeescript.org/】??

23【http://getbootstrap.com/】??

24【www.w3.org/wiki/The_principles_of_unobtrusive_JavaScript】??

25【http://nodejs.org/】??

26【http://typesafe.com/】??

27【http://akka.io/】??

28【www.json.org/】??

29【www.w3.org/TR/soap/】??

30www . ics . UCI . edu/∞fielding/pubs/dissertation/rest _ arch _ style . htm

31【www.w3.org/RDF/】??

32【www.w3.org/TR/rdf-sparql-query/】??

33【www.w3.org/TR/owl-features/】??

34www . morganclaypool . com/doi/pdf/10.2200/s 00481 ed 1v 01y 201302 wbe 005

二、使用 Servlets 和 JSP 构建 Web 应用

协议就是一切。

弗朗索瓦·朱利亚尼

核心互联网协议充实并支撑着 web,因此理解这些协议是理解 Web 应用如何开发的基础。

互联网是一个巨大的网络网络,一般来说,互联网上的所有机器都可以分为两类:服务器和客户端。客户端是请求一些信息的机器,而服务器是提供这些信息的机器。从信息提供者(即服务器)流向信息请求者(即客户端)的信息数据受一个明确的规则的约束,该规则管理服务器传输的信息的编组和客户端翻译或读取的信息的解组。这个规则被称为 协议。web 浏览器(即客户端)、web 服务器(即服务器)和 web 应用都通过超文本传输协议(HTTP)相互通信。 客户端向 web 服务器发送 HTTP 请求,web 服务器以 HTTP 响应的形式返回请求的数据。HTTP 客户端和 HTTP 服务器是万维网的基石,HTTP 是万维网的通用语言。

HTTP 是一种请求-响应无状态协议,其必然结果是,从 web 服务器的角度来看,任何请求都是来自 web 浏览器的第一个请求。当客户端请求资源时,该请求还以统一资源定位符(URL) 的形式包含所请求资源的标识。在 RFC 3986 1 中,URL 被描述为唯一标识资源的统一方式。URL 被设计成通过描述资源在网络上的“位置”来隐含地提供定位资源的方法。

URL 是统一资源标识符(URI)的一种具体形式,是一种区分实体的机制。但是 URIs 本身是抽象的。URI 有两种具体形式:URL 和统一资源名(URN)。骨灰盒仍然是实验性的,没有被广泛采用。

通用 URL 是由组件组成的分层序列,其结构为 scheme://hostName:port number/path/resource?查询字符串。

要识别 URL 的各个部分,请考虑一个列出书店网站上某本书的详细信息的 URL,如下所示:

http://www.yourbookstore.com/bookstore/bookServlet?action=bookDetails

图 2-1 展示了这个 URL 的各个部分。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-1 。URL 的剖析

主机名和端口号一起被称为机构。默认情况下,像 Tomcat 这样的 web 服务器会监听端口 8080 上的传入请求。在图 2-1 中显示的 URL 的某些部分是可选的,包括端口号(默认为众所周知的端口 80 和 443,分别用于 HTTP 和 HTTPS 方案)和查询字符串。

注意 HTTPS 是安全套接字层(SSL)上的 HTTP;它允许安全、加密的通信。

如果存在,查询字符串是一系列名称-值对,前面有一个问号(?)并用一个&符号分隔这些对。

注意只有 GET 方法支持查询字符串。还有其他 HTTP 协议方法,如 POST、DELETE 和 PUT。

web 应用是协同工作以在 web 上提供特定功能的 Web 组件的集合。在 Java EE 规范中,web 组件被定义为一个 Servlet 或一个 Java 服务器页面(JSP )页面。

注意除了 servlets 和 JSP 页面,web 应用还可以包括静态资源,例如 HTML 文档、图像和定义 web 应用属性的元数据或配置文件;但是,这些不被认为是 web 组件。

web 应用及其组成组件在 web 容器中管理和执行,也称为 servlet 容器 ,它为 web 应用提供了额外的功能,如安全性。当 web 服务器收到对特定 web 组件(如 servlet 或 JSP 页面)可以提供的特定功能的请求时,web 服务器会将请求转发给 web 组件所在的 servlet 容器。所有对动态内容的请求(也就是对负责生成动态内容的 web 组件的所有请求)都由 servlet 容器来协调,如图 2-2 中的所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-2 。动态内容请求

Java EE servlet 和 JSP 规范描述了 Servlet 容器必须提供的服务契约,并指定了 Servlet 应该如何使用这些服务。就实现而言, servlet 是一个 Java 类,充当动态 web 资源。

小型应用

Servlets 是 Java web 应用的中央处理单元,负责 web 应用所需的大部分处理。具体来说,servlet 是一个实现 javax.servlet.Servlet 接口的 Java 类。Servlet 接口定义了所有 Servlet 必须实现的方法。“一枚戒指统治他们所有人!”这个接口和其他方法一起定义了关键的生命周期方法,比如 init()、service()和 destroy(),分别用于初始化 servlet、服务请求和从服务器中删除 servlet。表 2-1 描述了 javax.servlet.Servlet 接口的所有方法。

表 2-1 。Servlet 接口的生命周期和非生命周期方法

|

修饰符和类型

|

方法

|
| — | — |
| 空的 | init(ServletConfig config) |
| 空的 | 服务(ServletRequest req,ServletResponse res) |
| 空的 | 销毁() |
| 如何获取 | getServletConfig() |
| 线 | getServletInfo() |

在 servlet 的生命周期中,容器在适当的时刻按以下顺序调用生命周期方法:

  1. servlet 被构造,然后用 init 方法初始化。
  2. 客户端对服务方法的任何调用都会得到处理。
  3. 然后用 destroy 方法销毁 servlet,回收垃圾,并最终完成。

这里解释一下表 2-1 中说明的 Servlet 接口方法:

  • init(ServletConfig):在实例化 servlet 后由 servlet 容器调用一次。在 servlet 成为接收任何请求的候选者之前,该方法必须成功完成。
  • service():在 servlet 的 init()方法成功完成之后,由 servlet 容器调用,以允许 servlet 响应请求。
  • destroy():由容器调用以销毁 servlet,并作为一种方法,在 servlet 被销毁之前,必须释放获取的资源。
  • getServletConfig():允许 servlet 以该方法返回的 ServletConfig 对象的形式获取启动信息。ServletConfig 对象包含 servlet 的初始化和启动参数。
  • getServletInfo():允许 servlet 返回自己的信息,比如 servlet 的作者和版本。

使用 Servlet 的第一个 Web 应用

在第一章中,你安装了 Eclipse 开普勒 IDE。在本节中,您将在 Eclipse 中开发您的第一个 web 应用。具体来说,您将使用 Tomcat 7 作为 HTTP 服务器和 servlet 容器。你可以从tomcat.apache.org/download-70.cgi下载 Tomcat 的源代码发行版作为 ZIP 文件来安装 Tomcat 7。

启动 Eclipse,选择窗口外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传首选项菜单选项,显示首选项对话框,如图 2-3 所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-3 。首选项对话框,验证安装的 JRE

在这个对话框的左窗格中,深入到 Java 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 Installed JREs,并验证您以前安装的 JRE8/JDK 8 版本是否出现。如果没有,请单击添加按钮添加对您的 JDK 的引用。选择文件外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传新建外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传动态 Web 项目,创建一个动态 Web 项目,如图图 2-4 所示。将项目命名为 helloworld ,如图图 2-5 所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-4 。创建新项目

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-5 。创建 helloworld 项目

点击下一步,勾选“生成 web.xml 部署描述符”,如图图 2-6 所示。稍后我们将看到如何在没有 web.xml 的情况下配置 web 模块。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-6 。配置网络模块设置

点击完成,创建一个新的 Java 类,如图图 2-7 所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-7 。创建一个 Java 类:servlet

用清单 2-1 中的代码修改生成的 HelloWorld 类。

清单 2-1 。HelloWorld Servlet

1.package apress.helloworld;
2.
3.import java.io.IOException;
4.import java.io.PrintWriter;
5.
6.import javax.servlet.http.HttpServlet;
7.import javax.servlet.http.HttpServletRequest;
8.import javax.servlet.http.HttpServletResponse;
9.
10.public class HelloWorld extends HttpServlet{
11.
12.protected void doGet(HttpServletRequest request,
13.HttpServletResponse response)
14.{
15.try
16.{
17.response.setContentType("text/html");
18.PrintWriter printWriter = response.getWriter();
19.printWriter.println("<h2>");
20.printWriter.println("Hello World");
21.printWriter.println("</h2>");
22.}
23.catch (IOException ioException)
24.{
25.ioException.printStackTrace();
26.}
27.}
28.
29.}

用清单 2-2 中的代码修改 web.xml 文件。

清单 2-2 。Web.xml:部署描述符

1.<?xml version="1.0" encoding="UTF-8"?>
2.<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3.fontname">http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
4.xsi:schemaLocation="http://java.sun.com/xml/ns/javaeehttp://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
5.id="WebApp_ID" version="3.0">
6.<display-name>helloworld</display-name>
7.<servlet>
8.<servlet-name>HelloWorld</servlet-name>
9.<servlet-class>apress.helloworld.HelloWorld</servlet-class>
10.</servlet>
11.<servlet-mapping>
12.<servlet-name>HelloWorld</servlet-name>
13.<url-pattern>/hello</url-pattern>
14.</servlet-mapping>
15.<welcome-file-list>
16.<welcome-file>index.html</welcome-file>
17.<welcome-file>index.htm</welcome-file>
18.<welcome-file>index.jsp</welcome-file>
19.<welcome-file>default.html</welcome-file>
20.<welcome-file>default.htm</welcome-file>
21.<welcome-file>default.jsp</welcome-file>
22.</welcome-file-list>
23.</web-app>

现在我们需要在 Tomcat 中将 HelloWorld servlet 配置为 web 模块。在 Eclipse 的菜单栏中选择 Window 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 Show View 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 Servers,如图图 2-8 所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-8 。添加服务器

在 Servers 选项卡上,右键单击并添加 Tomcat 7 作为新的服务器,如图图 2-9 所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-9 。定义服务器

接下来你必须定义一个新的服务器,如图 2-10 所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-10 。定义 Tomcat 服务器

现在通过将资源移动到 configured 部分的右边来配置 helloworld 项目,如图 2-11 所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-11 。在服务器上配置资源

单击“添加”,将在服务器上配置该资源。然后单击完成。启动服务器,使用图 2-12 中所示的 URL 访问应用。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-12 。启动服务器

你现在可以通过 URLlocalhost:8080/hello world/hello访问你的第一个 web 应用,如图图 2-13 所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-13 。运行 helloworld web 应用

在下一节中,您将了解请求如何流经应用,以及容器如何在您开发的 helloworld 应用中找到 servlet。然后,您将使用 HelloWorld servlet 来理解 servlet 的生命周期方法。

HelloWorld Servlet 的请求流

在 HelloWorld servlet 可以生成响应之前,来自 web 浏览器的请求会流经 web 服务器和 servlet 容器,如下面几节所述。

HTTP 请求消息

用于访问 helloworld web 应用的 URL 是localhost:8080/hello world/hello。当用户通过这个 URL 访问 web 应用时,web 浏览器创建 HTTP 请求,如清单 2-3 所示。

清单 2-3 。HttpRequest 消息

1.GET /helloworld/hello HTTP/1.1
2.Host: localhost:8080
3.User-Agent: Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.31 (KHTML, like Gecko)
Chrome/26.0.1410.43 Safari/537.31
  • 第 3 行:这一行描述了特定的用户代理(web 浏览器),它通过使用 HTTP 请求特定的资源来发起通信,如第 1 行所述。

  • Line 1: The request made by the user agent is of the form shown in Figure 2-14.

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

    图 2-14 。HTTP 请求消息剖析

  • Line 2 :运行 web 服务器的这台机器(你的机器)是服务器机器。指定 Localhost,否则您将使用计算机的主机名。例如,将安装在运行 HTTP 服务器的系统上的浏览器指向 localhost ,将显示安装在该系统上的网站的主页,如图图 2-15 所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-15 。网络服务器的主页

图 2-15 显示的是 Tomcat 的主页,当你在你的机器上运行 Tomcat 的 bin 目录下的 startup.bat,你就会看到这个主页。服务器使用带编号的端口使其服务对互联网可用,服务器上可用的每个服务一个端口。例如,如果一台服务器正在运行一个 web 服务器,那么这个 web 服务器通常位于端口 80 上,对于 Tomcat 来说是 8080。

审查请求

当客户端(web 浏览器)发出请求(在本例中是 GET 请求)时,web 服务器(Tomcat)在第 1 行的请求中看到资源路径/helloworld/hello,并确定用户请求的资源不是静态页面(例如. html 文件),因此将请求转发给 web 容器(Tomcat)。敏锐的读者会注意到 Tomcat 充当了 web 服务器和 web 容器的角色。

定位 Servlet

请求中的资源路径(清单 2-3 中的第 1 行)通过清单 2-2 中的 web.xml 文件映射到 HelloWorld servlet 。这个 web.xml 文件被称为部署描述符,因为它向 web 容器描述了部署的 servlet。通过部署描述符,web 容器确定需要调用哪个 servlet 来服务 web 浏览器发起的原始 HTTP 请求。为了方便读者,web.xml 再次显示在清单 2-4 中。

清单 2-4 。web.xml

1.<?xml version="1.0" encoding="UTF-8"?>
2.<web-app fontname">http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaeehttp://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0">
3.<servlet>
4.<servlet-name>HelloWorld </servlet-name>
5.<servlet-class>
6.apress.helloworld.HelloWorld
7.</servlet-class>
8.</servlet>
9.<servlet-mapping>
10.<servlet-name>HelloWorld</servlet-name>
11.<url-pattern>/hello </url-pattern>
12.</servlet-mapping>
13.</web-app>
  • 第 1 行到第 2 行:这些行包含样板 XML,说明 XML 文件使用的版本、编码和模式。
  • 第 3 行到第 8 行:标签用于配置我们的 servlet。它包含两个嵌套标签:< servlet-name >定义 servlet 的逻辑名称,而< servlet-class >表示定义 servlet 的 Java 类。
  • 第 9 行到第 12 行:XML 标签用于配置我们的 servlet。它包含两个嵌套标签:< servlet-name >匹配在< servlet >标签中设置的值,而< url-pattern >设置 servlet 将执行的 url 模式。

Java EE web 应用从上下文根中运行。上下文根是 URL 中服务器名称和端口之后的第一个字符串。比如在 URLlocalhost:8080/helloworld/hello 中,字符串 hello world 就是上下文根。< url-pattern >的值相对于应用的上下文根。Java EE web.xml 文件可以包含许多附加的 xml 标记。除了将 URL 映射到实际的 servlets,您还可以使用部署描述符定制 web 应用的其他方面,比如安全角色、错误页面、标记库和初始配置信息。但是,这个 helloworld 应用不需要这些额外的标记。web 容器加载 HelloWorld servlet 类并实例化它。只创建 HelloWorld servlet 的一个实例,对 HelloWorld servlet 的并发请求在同一个实例上执行。每个客户端请求都会生成一对新的请求和响应对象。容器运行多个线程来处理对 HelloWorld servlet 的单个实例的多个请求。

注意在分布式 web 应用中,每个 JVM 都有一个特定 servlet 的实例,但是每个 JVM 仍然只有那个 servlet 的一个实例。

生命周期法

对象的生命周期描述了对象在其存在期间必须经历的一系列步骤。servlet 的生命不同于普通的 Java 类,因为 servlet 必须在 web 容器内部执行。图 2-16 显示了 HelloWorld servlet 的层次结构。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-16 。HelloWorld servlet 的层次结构

通用服务器

大多数 servlet 通过 Servlet API 提供的抽象 javax.servlet.GenericServlet 类提供类似的基本功能。GenericServlet 类的实现是独立于协议的,因此它是否必须响应 HTTP 或 FTP 请求并不重要。GenericServlet 抽象类定义了一个 init()方法,默认的 init(ServletConfig)方法调用该方法来执行任何特定于应用的 Servlet 初始化。

http servlet〔??〕

在 web 应用中,GenericServlet 类中缺少任何依赖于协议的处理意味着开发人员必须在自己创建的任何子类中编写处理代码。由于 HTTP 是 Web 上最著名和最广泛使用的协议,Servlet API 还包括 GenericServlet 的一个更抽象的子类:javax.servlet.http.HttpServlet。

注意 HTTP/1.1 定义了七种请求方法。HttpServlet 类为这些方法中的每一个提供了默认实现,您可以在 Servlet 中覆盖这些方法。然而,大多数 web 应用包含只覆盖 doGet()和 doPost()方法的 servlets。

对 HttpServlet 子类的 HTTP 请求要经过许多步骤:

  1. 容器对公共服务(ServletRequest,ServletResponse)方法的调用。
  2. 将此调用委托给 HttpServlet 的受保护服务(HttpServletRequest,HttpServletResponse)方法。
  3. 受保护的服务(HttpServletRequest,HttpServletResponse)方法然后委托给适当的 doXxx 方法,这取决于用于请求的 HTTP 方法。

HelloWorld Servlet

如前一节所述,servlet 的超类包括 init()的两个版本,一个采用 ServletConfig,另一个没有参数。init(ServletConfig)方法调用无参数 init(),因此您只需要覆盖无参数版本。

init( )

容器在 servlet 实例上调用 init()。您可以覆盖它,以便获得向其他对象注册的数据库连接。否则,运行 Genericservlet 中的 init()方法。

  1. 创建 servlet 实例时,会调用它的 init()方法。init()方法允许 servlet 在处理第一个请求之前初始化自己。您可以在 web.xml 文件中或通过注释为 servlet 指定 init()参数。
  2. web 容器调用 servlet 的 init()方法(在 servlet 的生命周期中只调用一次),init()方法必须在容器可以调用 service()方法之前完成。

服务()

容器调用 servlet 的 service()方法。这个方法查看请求,确定 HTTP 方法的类型,并在 servlet 上调用匹配的 doGet()或 doPost()。你永远不能超越它。您的工作是覆盖 doGet()或 doPost(),让来自 HTTPServlet 的服务实现担心调用正确的那个。

  • 当在 servlet 上调用 service()方法时,它将被传递对实现 HttpServletRequest 和 HttpServletResponse 接口的 HttpServletRequest 和 HttpServletResponse 对象的引用。容器实现了这些接口。
  • 对于 servlet 收到的每个请求,都会调用 servlet 的 service()方法。对于 HttpServlet 子类,通常调用 doGet()、doPost()等方法之一。容器创建两个对象:HTTPServletRequest 和 HttpServletResponse。
  • 只要 servlet 在 servlet 容器中是活动的,就可以多次调用 service()方法。
  • service()方法调用 doGet()/doPost()。您总是在 servlet 中覆盖至少其中一个。

destroy( )

servlet 容器调用 servlet 上的 destroy()方法,这个方法只被调用一次。这个方法为 servlet 提供了一个机会,在它被破坏之前释放获得的资源。

ServletContext 和 ServletConfig

调用 init()方法后,servlet 为每个 servlet 获取一个 ServletConfig 对象,为每个 web 应用获取一个 ServletContext。在分布式环境中,每个 JVM 都有一个 ServletContext。ServletContext 是一种方法,通过它 servlet 可以连接容器和 web 应用的其他部分。在 servlet 中,只有当您的 servlet 不是 HttpServlet 或 GenericServlet 时,才需要通过 ServletConfig 来获取 ServletContext。

servlet config 对象可用于执行以下操作:

  • 将您不希望硬编码到 servlet 中的部署时信息(如数据库或企业 bean 查找名称)传递给 servlet。这个部署时信息被称为 servlet 初始化参数。servlet init 参数将在下一节讨论。
  • 访问 ServletContext。

ServletContext 对象可用于执行以下操作:

  • 访问 web 应用参数
  • 设置应用的所有组件都可以访问的属性
  • 获取服务器信息,包括容器的名称和版本以及支持的 API 版本

servlet 可以有三种类型的参数:

  • 请求参数
  • 初始化(init)参数
  • 上下文初始化(context-init)参数

初始化参数

初始化参数在 web.xml 文件中定义,如清单 2-5 所示。

清单 2-5 。定义初始化参数

<servlet>
<init-param>
<param-name>email </param-name>
<param-value>vishalway@.gmail.com</param-value>
</init-param>
</servlet>

在 servlet 初始化之前,不能使用 init-parameters。您的 servlet 继承了 getServletConfig(),因此您可以从 servlet 中的任何方法调用它来获得对 ServletConfig 的引用。一旦有了 ServletConfig 引用,就可以调用 getInitParam()。

当容器初始化 servlet 时,会发生以下情况:

  1. 容器为 servlet 创建一个惟一的 ServletConfig。
  2. 容器从部署描述符中读取 init 参数,并在 ServletConfig 对象中设置它们。
  3. 然后,容器将 ServletConfig 传递给 servlet 的 init (servletConfig)方法。

注意一旦容器在 ServletConfig 中设置了 init 参数,容器就不再从部署描述符中读取 init 参数,除非 servlet 被重新部署。

上下文初始化参数

上下文初始化参数类似于初始化参数。context-init 参数和 init 参数之间的主要区别在于,context 参数适用于整个 web 应用,而 init 参数仅适用于 servlet。清单 2-6 展示了 web.xml 文件中的上下文初始化参数。

清单 2-6 。定义上下文初始化参数

<context-param>
<param-name>email </param-name>
<param-value>vishalway@gmail.com</param-value>
</context-param>

元素没有嵌套在元素中。

清单 2-7 展示了如何从 servlet 中获取 context-init 参数。

清单 2-7 。获取上下文初始化参数

out.println(getServletContext().getInitParameter("email");

每个 servlet 都继承了一个 getServletContext()方法。getServletContext()方法返回一个 ServletContext 对象。

请求调度员

在 web 应用中,有两种方法可以改变请求流。

  • 重定向请求:请求被重定向到一个完全不同的 URL。重定向可以通过在响应对象上调用 sendRedirect() 来完成。重定向是由浏览器完成的。
  • 分派请求:请求被分派给 web 应用中的另一个组件,通常是 JSP 页面。请求分派不同于重定向,因为它在服务器端完成工作。对请求调用 RequestDispatcher,对响应调用 redirect。

图 2-17 显示了 RequestDispatcher 接口中的方法。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-17 。请求调度程序接口

您可以通过两种方式获得 RequestDispatcher。

  • 从 ServletRequest 获取 RequestDispatcher
  • 从 ServletContext 获取 RequestDispatcher

从 ServletRequest 获取 RequestDispatcher】

RequestDispatcher view = request.getRequestDispatcher("bookDetails.jsp");

ServletRequest 中的 getRequestDispatcher()方法获取请求转发到的资源的路径。如果路径以正斜杠(/)开头,则容器认为它是从 web 应用的根目录开始的。如果路径不是以正斜杠开头,容器认为它是相对于原始请求的。

从 ServletContext 获取 RequestDispatcher】

RequestDispatcher view = getServletContext().getRequestDispatcher("/bookDetails.jsp");

getRequestDispatcher()方法接受一个资源的字符串路径,请求将被转发到该资源。从上下文或请求中获得的 RequestDispatcher 可用于转发到资源,因为 RequestDispatcher 知道您要转发到的资源,换句话说,就是作为参数传递给 getRequestDispatcher()的资源。清单 2-8 展示了在 RequestDispatcher 上调用 forward。

清单 2-8 。在 RequestDispatcher 上呼叫转发

RequestDispatcher view = request.getRequestDispatcher("bookDetails.jsp");
view.forward(request, response);

过滤器

过滤器是一个可重用的 Java 组件,可以转换 HTTP 请求、响应和头信息的内容。过滤器用于以下用途:

  • 在调用请求之前访问静态或动态内容或修改请求头
  • 在调用后拦截 web 组件的调用
  • 通过以特定顺序使用过滤器链来提供对 web 组件的操作
  • 在呈现响应头和响应数据之前修改它们

过滤器是通过实现 javax.servlet.Filter 接口并提供一个无参数构造函数来创建的。过滤器是在 web 应用中配置的,要么在部署描述符中使用元素,要么在@WebFilterannotation 中配置(在下一节中介绍)。在元素中,必须声明以下内容:

  • :用于将过滤器映射到 servlet 或 URL
  • :容器用来标识过滤器类型

注意你也可以声明一个过滤器的初始化参数。

清单 2-9 展示了过滤器的声明。

清单 2-9 。声明过滤器

<filter>
<filter-name>ResponseFilter</filter-name>
<filter-class>com.apress.ResponseServlet</filter-class>
</filter>

可以使用元素将过滤器与 servlet 相关联。清单 2-10 将响应过滤器 Filter 映射到 ResponseServlet servlet。

清单 2-10 。将过滤器映射到 Servlet

<filter-mapping>
<filter-name>Response Filter</filter-name>
<servlet-name>ResponseServlet</servlet-name>
</filter-mapping>

过滤器可以使用< urlpattern >与 servlets 组相关联,如清单 2-11 所示。

清单 2-11 。将过滤器与一组 Servlets 相关联

<filter-mapping>
<filter-name>Response Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

在清单 2-11 中,响应过滤器应用于 web 应用中的所有 servlets。

web 应用通常包含以下过滤组件:

  • 认证过滤器
  • 缓存过滤器
  • 数据压缩过滤器
  • 加密过滤器
  • 图像转换过滤器
  • 日志和审计过滤器

通过注释配置 Servlet

从 Servlet 3.0 开始,可以通过 web.xml 或使用注释或两者来配置 Servlet。表 2-2 描述了符合 Servlet 3.0 的 web 容器所支持的注释。

表 2-2 。配置 Servlet 的注释

|

注释

|

描述

|
| — | — |
| @ web 过滤器 | 在 web 应用中定义筛选器 |
| @WebInitParam | 指定要传递给 servlet 或过滤器的初始化参数 |
| @WebListener | 注释一个侦听器以获取事件 |
| @webservlet | 定义 web 应用中的组件 |
| @MultipartConfig | 指示请求属于 mime/multipart 类型 |

在接下来的小节中,您将开发一个 helloworld 项目,在这个项目中,您将通过注释来配置 servlet。右键单击项目 helloworld,创建一个新的 servlet 类,并将类名命名为 HelloWorld,如图图 2-18 所示。单击下一步。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-18 。创建 servlet

在下一个屏幕上,您可以填写与部署描述符相关的信息,例如初始化参数和 URL 映射,如图 2-19 中的所示。对于 HelloWorld 应用,您不必填写初始化参数的值。URL 映射的默认值,在本例中是/HelloWorld,就可以了。“URL mappings”字段中的值是 URL 的 servlet 路径,如前一节所述。单击下一步。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-19 。网址映射

在下一个屏幕上,指定修饰符、要实现的接口和要生成的方法存根,如图 2-20 所示。如果尚未检查 doGet 和 doPost,请检查它们。然后单击完成。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-20 。指定方法

IDE 生成清单 2-12 中的 HelloWorld servlet。

清单 2-12 。使用注释的 HelloWorld Servlet

1.package apress.helloworld;
2.
3.import java.io.IOException;
4.import javax.servlet.ServletException;
5.import javax.servlet.annotation.WebServlet;
6.import javax.servlet.http.HttpServlet;
7.import javax.servlet.http.HttpServletRequest;
8.import javax.servlet.http.HttpServletResponse;
9.
10./**
11\. * Servlet implementation class HelloWorld
12\. */
13.@WebServlet(urlPatterns = { "/HelloWorld" }, description = "A hello world servlet")
14.public class HelloWorld extends HttpServlet {
15.private static final long serialVersionUID = 1L;
16.
17.    /**
18.     * @see HttpServlet#HttpServlet()
19.     */
20.    public HelloWorld() {
21.        super();
22.        // TODO Auto-generated constructor stub
23.    }
24.
25./**
26\. * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
27\. */
28.protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
29.// TODO Auto-generated method stub
30.}
31.
32./**
33\. * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
34\. */
35.protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
36.// TODO Auto-generated method stub
37.}
38.
39.}
  • 第 13 行:这一行显示了@WebServlet 注释的用法。HelloWorld servlet 使用@WebServlet 注释来指定名称、URL 模式、初始化参数和通常在 web.xml 部署描述符中指定的其他配置项。
  • 第 14 行:这一行显示 HelloWorld servlet 扩展了 HTTPServlet。
  • 第 28 到 37 行:这几行显示了 IDE 生成的 doGet 和 doPost 方法。

将清单 2-13 中的代码添加到 HelloWorld servlet 的 doGet 方法中。

清单 2-13 。印刷“Hello World”

PrintWriter out = response.getWriter();
out.println("<h2>Hello World !</h2>");

您必须导入 java.io.Printwriter。您可以在 Eclipse 中通过选择 Source 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 Add Import 或按 Ctrl+Shift+M;现在,您可以在服务器上运行应用了。在 Eclipse 的 helloworld 项目中右键单击 HelloWorld.java,然后选择 Run As 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 Run on Server。在这种情况下,您使用的服务器是 Tomcat 7.0。然后使用以下 URL 访问该应用:

http://localhost:8080/helloworld/HelloWorld

图 2-21 显示了输出。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-21 。访问应用

有关 Java Servlet 技术的更多信息,请参考 Java Servlet 3.1 规范 2 和 Java Servlet 网站。 3

Java 服务器页面

Servlets 使 web 服务器能够生成动态内容。然而,servlets 有一个主要的缺点,即 HTML 代码需要硬连接到 Java 代码中。为了消除这种横切关注点,Java Server Pages (JSP) 技术应运而生。JSP 使用静态 HTML 内容和动态内容的组合来生成 web 页面,从而分离了在 Java 代码中嵌入 HTML 内容的顾虑。

您的第一个使用 JSP 的 Web 应用

现在您将使用 JSP 创建一个“Hello World”应用。因为您之前已经创建了一个同名的项目,所以请确保先删除或重命名旧项目。然后在项目浏览器中点击右键,选择动态 Web 项目,如图图 2-22 所示。将项目命名为 helloworld

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-22 。创建 helloworld 项目

右键单击项目 helloworld,创建一个新的 JSP 文件,命名为helloworld.jsp。单击下一步。在下一个屏幕上单击完成。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-23。创建 JSP 文件

修改 helloworld.jsp 的代码,如清单 2-14 所示。

清单 2-14 。helloworld.jsp

<!DOCTYPE html >
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Hello World</title>
</head>
<body>
Hello World!
</body>
</html>

在服务器上部署应用,如图图 2-24 所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-24 。在服务器上运行应用

使用localhost:8080/hello world/hello . JSP启动应用。

图 2-25 显示了输出。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-25 。访问 JSP

JSP 基础

这一节将介绍基本的 JSP 构造。对经典方法的正确理解对于理解其局限性和欣赏更高级技术的力量是必不可少的,比如表达式语言,这是下一章的主题。在表达式语言被添加到 JSP 规范之前,十亿个 JSP 页面是使用传统方法编写的,您可能仍然需要维护它们或重构它们。对向后兼容性的需求是 JSP 规范仍然涵盖经典组件的原因之一。但是当您必须在应用中编写新的 JSP 时,您不应该编写向后兼容的代码;相反,你应该使用最佳实践方法,这将在下一章中解释。当 JSP 1.0 在 1999 年被添加到 JSP 规范中时,它意味着通过在模板数据中嵌入业务逻辑代码来生成动态的、基于 web 的内容。为此,提供了以下 JSP 元素,用于在 JSP 页面中操纵 Java 对象并对其执行操作,从而支持动态内容的生成:

  • 指令
  • 声明
  • 公式
  • 脚本片断
  • 隐式对象
  • 标准动作

JSP 指令

JSP 指令是 JSP 容器的指令,在页面翻译过程中进行处理。指令提供了一种机制,使 JSP 引擎可以使用页面级信息。指令在指令分隔符之间声明,并采用以下形式:

<%@ directive {attribute="value"}* %>

页指令

page 指令用于提供容器生成底层 servlet 所使用的特定 JSP 页面的相关说明。以下是页面指令的基本语法:

<%@ page attribute="value" %>

表 2-3 描述了与页面指令相关的属性。

表 2-3 。页面指令的属性

|

属性

|

目的

|
| — | — |
| 自动冲洗 | 控制 servlet 输出缓冲区的行为。它指示缓冲区满时是否应该自动写入。 |
| 缓冲器 | 指定 servlet 输出流的缓冲模型。它表示缓冲区的大小。 |
| 内容类型 | 指定响应的 MIME 类型和字符编码方案。 |
| 错误页 | 指定处理错误条件并报告运行时异常的 JSP 的 URL。 |
| 延伸 | 指示生成的 servlet 必须扩展的超类。 |
| 进口 | 指定在 JSP 页面中使用的类,类似于 Java 中的 import 语句。 |
| 信息 | 为 servlet 的 getServletInfo()方法指定一个字符串。 |
| isELIgnored?isELEnabled | 指定 JSP 页面中是否允许 EL 表达式。 |
| isErrorPage | 指定此 JSP 页面是否用于处理错误情况和报告运行时异常。 |
| isScriptingEnabled | 指定 JSP 页面中是否允许脚本元素。 |
| 是线程安全的 | 指示 JSP 页是否可以处理并发请求。 |
| 语言 | 指示 JSP 页面中使用的脚本语言。 |
| 会议 | 指定 JSP 页面是否参与 HTTP 会话。 |

包含指令

include 指令用于指定应该包含在当前 JSP 页面翻译单元中的静态资源。include 指令有一个名为 file 的属性,它指定应该包含的资源的 URL。该指令的一般形式如下:

<%@ include file="relative url" >

以下示例演示了如何使用 include 指令在当前翻译单元中包含标准的 JSP 页眉和页脚(清单 2-15 )。你可以创建一个像你的第一个 web 应用 helloworld 一样的项目,用 main.jsp 替换 helloworld.jsp。【清单 2-15 展示了 main.jsp 的 ??。

清单 2-15 。main.jsp

1.<%@ include file="header.jsp" %>
2.
3.<p>content</p>
4.
5.<%@ include file="footer.jsp" %>
  • 第 1 行:这一行包括翻译时 main.jsp 文件中的 header.jsp。
  • 第 5 行:这一行包括翻译时 main.jsp 文件中的 footer.jsp。

清单 2-16 展示了 header.jsp。

清单 2-16 。header.jsp

1.<html>
2.<head></head>
3.<body>
4.<%out.print("header"); %>
  • 第 4 行:这一行使用了一个隐式对象 out。隐式对象将在本章后面介绍。隐式 out 对象表示 JspWriter 类的一个实例,用于将字符数据写入响应流。

清单 2-17 展示了 footer.jsp。

清单 2-17 。footer.jsp

1.<%out.print("footer"); %>
2.</body>
3.</html>

图 2-26 显示了输出。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-26 。使用 include 指令

Taglib 指令

Java Server Pages API 提供了封装功能的标准动作,下一节将对此进行介绍。JSP API 还允许您定义实现自定义行为的自定义操作。几个这样的定制动作,也称为定制标签,被组装在一个名为标签库的库中。taglib 指令用于定义当前 JSP 页面中标记库的前缀和位置。taglib 指令使用以下语法:

<%@ taglib uri="uri" prefix="tagPrefix" >

uri 属性值是指定标记库位置的绝对或相对路径,prefix 属性指定要在当前 JSP 中使用的自定义操作。清单 2-18 展示了 taglib 指令在一个名为 helloTagLib 的示例标签库中的用法,该标签库包含一个名为 hello 的标签,用于打印“Hello World”消息。

清单 2-18 。Taglib 指令的用法

1.<%@ taglib uri="/ helloTagLib" prefix="helloTag" %>
2.<html>
3.<body>
4.<helloTag:hello/>
5.</body>
6.</html>
  • Line1 :库 helloTagLib 的 URI 和前缀 helloTag
  • 第 4 行:通过前缀使用 hello 标签

声明

使用声明,JSP 允许您在 JSP 页面中声明方法和变量。一旦它们出现在 JSP 页面中,就可以在整个页面中被 scriptlets 和表达式使用。JSP 声明放在声明分隔符之间。由于声明与表达式和 script let 一起使用,所以我将在下面的小节中介绍表达式和 script let,然后我将向您展示如何在 JSP 页面中使用声明、script let 和表达式。

表情

表达式类似于 scriptlets,但是它们计算一个常规的 Java 表达式,并作为响应的一部分向客户机返回一个结果,这个结果是一个字符串或者可以转换成字符串的东西。一般语法如下:

<%= expression %>

小脚本

Scriptlets 是包含在分隔符中的 Java 代码块,用于创建动态内容。清单 2-19 用一个脚本和表达式说明了声明的用法。

清单 2-19 。声明、脚本和表达式的用法

1.<%!
2.public String hello() {
3.String msg = "Hello World";
4.return msg;
5.}
6.%>
7.Message from <b>Scriptlet</b>: <%hello();%><br/>
8.Message from <b>Expression</b>: <%=hello() %>
  • 第 1 行到第 6 行 : 这些行包含一个 JSP 声明,声明了一个 hello()方法。第 1 行是开始标记,第 6 行是声明的结束标记。
  • 第 7 行:第 1 行到第 6 行声明的 hello()方法用在了第 7 行的一个表达式中。

2-27 举例说明了声明、脚本和表达式的用法。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-27 。使用声明、scriptlet 和表达式

隐式对象

在 web 应用中,多个 web 组件通过作为四个范围对象的属性维护的对象来相互协作和共享信息。您可以通过使用代表作用域的类的 getAttribute 和 setAttribute 方法来访问这些属性。表 2-4 列出了范围对象。

表 2-4 。范围对象

|

范围对象

|

中文版

|

可从访问。。。

|
| — | — | — |
| 应用/web 上下文 | javax.servlet.ServletContext | 应用中的 Web 组件 |
| 请求 | javax.servlet.ServletRequest 的子类型 | 处理请求的 Web 组件 |
| 会议 | javax.servlet.http.HttpSession | 会话中的 Web 组件 |
| 页 | javax . servlet . JSP . JSP 上下文 | 创建对象的 JSP 页面 |

注意除了标准的 servlet 请求、会话和应用作用域,JSP 添加了第四个作用域,称为页面作用域

JSP 页面可以通过脚本变量访问一些特定的对象。这些对象由 JSP 容器提供,被称为隐式对象。这些隐式对象可以在 scriptlets、表达式或作为 EL 表达式的一部分来访问。(EL 表达式在第三章的中介绍。)表 2-5 列出了对应 API 的九个隐式对象。

表 2-5 。隐式对象

|

隐含对象

|

使用

|

应用接口

|
| — | — | — |
| 应用 | 访问应用级对象 | ServletContext |
| 配置 | 提供配置信息 | 如何获取 |
| 例外 | 访问错误状态 | JSP 异常 |
| 在外 | 访问 JSP 输出流 | 对象 |
| 页,面,张,版 | 提供对当前 JSP 的引用 | 目标 |
| 对象 | 访问 JSP 容器 | 对象 |
| 请求 | 提供对客户端请求的访问 | ServletRequest |
| 反应 | 提供对 JSP 响应的访问 | servlet 响应 |
| 会议 | 跨客户端请求共享信息 | 会话 |

这些隐式对象将在下面的章节中详细描述。

应用

隐式应用对象提供了对 javax.servlet.ServletContext 接口的引用。ServletContext 接口用于提供对任何上下文初始化参数的访问,这些参数是通过 web 应用的部署描述符为 JSP 页面配置的。web 容器存储在其中的 ServletContext 对象和参数可供整个 web 应用使用。application 对象为 JSP 页面的开发人员提供了对 ServletContext 对象的访问。

配置

与 application 对象类似,config 对象提供了对 web 应用的 ServletConfig 接口的引用。ServletConfig 接口用于通过 web 应用的部署描述符提供对已经为 JSP 页面配置的任何初始化参数的访问。config 对象为 JSP 开发人员提供了对 ServletConfig 对象的访问。

例外〔??〕

JSP 可以使用隐式异常对象来处理错误条件,并使用 errorPage 页面指令报告运行时异常。

出局

隐式 out 对象表示用于将字符数据写入响应流的 JspWriter 类的实例。

页〔??〕

JSP 隐式页面对象是 object 类的一个实例,表示当前 JSP 页面。

page context〔??〕

pageContext 通过提供对与 JSP 页面相关联的所有名称空间和几个页面属性的访问来提供上下文信息。此外,它还包含对隐式对象的引用。

请求

请求对象是 javax . servlet . http . http servlet request 接口的实例。它代表客户端请求。请求隐式对象通常用于获取请求参数、请求属性、头信息和查询字符串值。

响应

隐式响应对象是 javax . servlet . http . http servlet response 接口的一个实例,表示要给客户机的响应。隐式响应对象通常用于设置响应内容类型、添加 cookies 和重定向响应。

会话

JSP 隐式会话对象是实现 javax.servlet.http.HttpSession 接口的 Java 类的实例。它用于存储客户端的会话状态。

清单 2-20 展示了常用隐式对象的用法。首先,它展示了在 servlet 的请求、会话和应用范围中设置 book 属性的常见任务。然后显示它们的 JSP 等价物。

清单 2-20 。常见隐式对象的用法

1.getServletContext().setAttribute("book", book);
2.request.setAttribute("book", book);
3.request.getSession().setAttribute("book", book);
4.application.setAttribute("book" book);
5.request.setAttribute("book" book);
6.session.setAttribute("book" book);
7.pageContext.setAttribute("book" book);
  • Line 1 :在 ServletContext 中设置 book 属性,不使用隐式对象。
  • 第 2 行:设置请求对象中的 book 属性。请求对象也是 JSP 中的隐式对象。因此,在 servlet 中设置属性类似于在 JSP 页面中设置属性。
  • 第 3 行:在 session 中设置 book 属性,不使用隐式对象。
  • 第 4 行:使用 application 隐式对象设置 ServletContext 中的 book 属性。
  • 第 5 行:设置请求对象中的 book 属性。request 也是 JSP 中的隐式对象。因此,在 JSP 中设置属性类似于在 servlet 中设置属性。
  • 第 6 行:使用 session 隐式对象设置 session 中的 book 属性。
  • 第 7 行:使用 pageContext 隐式对象设置 PageContext 中的 book 属性。servlet 中没有 pageContext 的等价物。PageContext 实例提供对与 JSP 页面相关联的所有名称空间的访问,提供对几个页面属性的访问,并提供实现细节之上的一层。隐式对象会自动添加到 pageContext。

标准动作

JSP 标准操作提供了一种完成以下任务的方法:

  • 操纵 JavaBeans
  • 动态包含文件
  • 执行 URL 转发

行动

动作提供了一种在运行时包含指令的方法,该指令用于在声明 JSP 页面中包含单独 web 组件的内容。使用标准包含动作的语法如下:

<jsp:include page="relativeURL" flush="true"/>

我们将创建两个 jsp,如清单 2-21 和清单 2-22 所示,来说明< jsp:include >动作的使用。

清单 2-21 。main.jsp

1.<html>
2.<head>
3.</head>
4.<body>
5.<%out.print("Inside main.jsp"); %><br/>
6.<jsp:include page="sub.jsp"/>
7.</body>
8.</html>
  • 第 6 行:使用< jsp:include >来包含目标 jsp 页面(sub.jsp)

清单 2-22 。sub.jsp

1.<html>
2.<head>
3.</head>
4.<body>
5.<%out.print("Inside sub.jsp"); %><br/>
6.</body>
7.</html>

图 2-28 显示了访问 main.jsp 时的输出。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-28 。使用< jsp:include >动作

动作

动作用于将当前请求转发给另一个资源,比如静态页面、JSP 页面或 servlet。该操作的语法如下:

<jsp:forward page="relativeURL" />

我们将使用前一节中创建的两个 JSP 来说明动作的使用,如清单 2-23 和清单 2-24 中所示。

清单 2-23 。利用 main.jsp 的前进行动

1.<html>
2.<head>
3.</head>
4.<body>
5.<%out.print("Inside main.jsp"); %><br/>
6.<jsp:forward page="sub.jsp"/>
7.</body>
8.</html>
  • 第 6 行:使用< jsp:forward >转发到目标 jsp 页面(sub.jsp)。

清单 2-24 。sub.jsp

1.<html>
2.<head>
3.</head>
4.<body>
5.<%out.print("Inside sub.jsp"); %><br/>
6.</body>
7.</html>

图 2-29 显示了访问 main.jsp 时的输出。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-29 。前进动作的用法

为了理解 include 动作和 forward 动作之间的区别,比较清单 2-21 和清单 2-23 以及图 2-28 和图 2-29 。在清单 2-23 中,我们在 main.jsp 中使用了转发动作,而不是包含动作。转发操作将控制权转移给 sub.jsp,就像包含操作一样。但是当 sub.jsp 完成时,与 include 操作不同,控制权不会回到 main.jsp。

、和动作

这三个标准动作可以消除大量的脚本代码,包括声明、scriptlets 和表达式。

useBean 动作用于声明和初始化 Bean 对象。一旦 bean 被初始化,就可以使用 jsp:setProperty 和 jsp:getProperty 操作来设置和获取 bean 属性

动作的语法如下:

<jsp:useBean id="someId" class="SomeClass" />

动作设置 bean 的属性。

动作具有以下语法,其中 someId 是 useBean 的 Id:

<jsp:setProperty name="someId" property="someProperty" .../>

<jsp: getproperty=“”>动作,顾名思义,获取给定属性的值。如果属性不是字符串,它会将其转换为字符串。</jsp:>

<jsp: getproperty=“”>动作具有以下语法,其中 someId 是 useBean 的 Id:</jsp:>

<jsp:getProperty name="someId" property="someProperty" .../>

清单 2-25 展示了如何创建用户 bean,而清单 2-26 展示了这三个动作在 JSP 页面中的用法。

清单 2-25 。用户 Bean

1.package com.apress.jspactions;
2.
3.public class User {
4.
5.private String name;
6.
7.public String getName() {
8.return name;
9.}
10.
11.public void setName(String name) {
12.this.name = name;
13.}
14.
15.}

清单 2-25 中的用户 bean 将在 user.jsp 使用,如清单 2-26 中的所示。

清单 2-26 。user.jsp

1.<html>
2.<head>
3.</head>
4.<body>
5.<jsp:useBean id="user" class="com.apress.jspactions.User" />
6.<jsp:setProperty name="user" property="name" value="vishal" />
7.Hello&nbsp;<jsp:getProperty name="user" property="name" />
8.</body>
9.</html>

图 2-30 显示了访问 user.jsp 时的输出。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-30 。useBean、getProperty 和 setProperty 操作的用法

MVC 模式

自从有了面向对象编程的概念,模型-视图-控制器(MVC) 模式的动机就一直存在。在 MVC 之前,浏览器直接访问 JSP 页面。换句话说,JSP 页面直接处理用户请求。这被称为模型 1 架构,如图 2-31 所示。模型 1 架构展示了分散的应用控制,这导致了紧密耦合和脆弱的表示层。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-31 。模型 1 架构

设计 JSP 页面的 Model-2 架构实际上是应用于 web 应用的 MVC 模式。MVC 起源于 Smalltalk,后来发展到了 Java 社区。图 2-32 显示了模型 2(换句话说,MVC)架构。在 Model-2 中,控制器处理用户请求,而不是另一个 JSP 页面。控制器被实现为一个 servlet。当用户提交请求时,执行以下步骤:

  1. 控制器 servlet 处理用户的请求。
  2. 控制器 servlet 根据请求实例化适当的 JavaBeans。
  3. 控制器 servlet 与中间层通信或直接与数据库通信,以检索所需的数据。
  4. 控制器在以下上下文之一中设置 JavaBeans:请求、会话或应用。
  5. 控制器基于请求 URL 将请求分派到下一个视图。
  6. 视图使用步骤 4 中的 JavaBeans 来显示数据。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-32 。模型 2 架构

书店应用

在前一章中,我们为书店应用开发了数据访问层,并使用独立的 Java 应用对其进行了查询。在这一章中,我们将用表示层取代独立的 Java 层。底部的数据访问层保持不变,如图图 2-33 所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-33 。用表示层替换独立的 Java 客户端

在生产就绪的应用中,您还应该添加一个服务层来处理数据库异常。随着应用的增长,一个分区的应用保持关注点的清晰分离。图 2-34 显示了书店应用的目录结构。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-34 。书店应用的目录结构

主页

图 2-35 显示了应用的主页。在输入 URL(localhost:8080/book web/books)时,主页会显示菜单,其中包含书店数据库中可用书籍的类别。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-35 。书店应用的主页

图 2-36 显示了书店应用的 MVC 架构。为了简洁和理解类别在主页上的显示方式,图中只显示了与主页和类别相关的组件。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-36 。MVC 在书店中的应用

在图 2-36 所示的 MVC 架构中, M 代表类别, V 代表 home.jsp, C 代表 BookController。应用流程包括六个步骤,如以下部分所述。

步骤 1:从请求中定位 Servlet

URL(localhost:8080/book Web/books)用于动态内容,因此 web 服务器将请求转发给 servlet 容器(Tomcat)。清单 2-27 展示了部署描述符。

清单 2-27 。BookstoreWeb 应用的部署描述符

1.<?xml version="1.0" encoding="UTF-8"?>
2.<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3.fontname">http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
4.xsi:schemaLocation="http://java.sun.com/xml/ns/javaeehttp://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
5.id="WebApp_ID" version="3.0">
6.<display-name>bookWeb</display-name>
7.<servlet>
8.<servlet-name>BookServlet</servlet-name>
9.<servlet-class>com.apress.bookweb.controller.BookController</servlet-class>
10.<init-param>
11.<param-name>base</param-name>
12.<param-value>/bookWeb/books</param-value>
13.</init-param>
14.<init-param>
15.<param-name>imageURL</param-name>
16.<param-value>/bookWeb/images</param-value>
17.</init-param>
18.<load-on-startup>1</load-on-startup>
19.</servlet>
20.<context-param>
21.<param-name>param1</param-name>
22.<param-value>/bookWeb/books</param-value>
23.</context-param>
24.<context-param>
25.<param-name>imageURL</param-name>
26.<param-value>/bookWeb/images</param-value>
27.</context-param>
28.<servlet-mapping>
29.<servlet-name>BookServlet</servlet-name>
30.<url-pattern>/books </url-pattern>
31.</servlet-mapping>
32.<welcome-file-list>
33.<welcome-file>index.html</welcome-file>
34.<welcome-file>index.htm</welcome-file>
35.<welcome-file>index.jsp</welcome-file>
36.<welcome-file>default.html</welcome-file>
37.<welcome-file>default.htm</welcome-file>
38.<welcome-file>default.jsp</welcome-file>
39.</welcome-file-list>
40.</web-app>
  • 第 30 行 : url-pattern/books 被映射到< Servlet-mapping >元素中的 BookServlet,该元素被映射到第 9 行的 servlet 类 BookController。
  • 第 20 到 27 行:我们在 web.xml 文件中为 servlet 指定上下文参数,因为上下文参数可用于整个 web 应用。当一个 servlet 实例被创建时,它的 init()方法被 servlet 容器调用。init()方法允许 servlet 在处理第一个请求之前初始化自己。我们在 BookController 中重写 init(ServletConfig config)方法,以便从书店数据库中获取类别。这些类别将对整个应用可用。BookController 中被覆盖的 init(ServletConfig config)如清单 2-28 中的所示。

步骤 2 和步骤 3:通过 DAO 访问数据库,从数据库中获取类别,并在模型中设置类别

清单 2-28 显示了图书控制器。

清单 2-28 。BookController 的 init()方法

1.public void init(ServletConfig config) throws ServletException {
2.super.init(config);
3.BookDAO bookDao = new BookDAOImpl();
4.// calling DAO method to retrieve bookList from Database
5.List<Category> categoryList = bookDao.findAllCategories();
6.ServletContext context = config.getServletContext();
7.context.setAttribute("categoryList", categoryList);
8.}
  • 第 5 行:这个类别列表是通过调用 bookDao 对象上的 findallcocategories()从数据库中获得的。
  • Line7 :类别列表是在 ServletContext 中设置的,这样整个 webapp 都可以使用这个列表。

步骤 4:分派到视图

随着 init()方法在前一步中完成,容器调用 servlet 的 service()方法(在 servlet 的生命周期方法中讨论)。这个方法查看请求,确定 HTTP 方法,并在 servlet 上调用匹配的 doget()或 dopost()。清单 2-29 展示了 servlet 的 doGet()和 doPost()方法。

清单 2-29 。BookController 中的 doGet()和 doPost()

1.protected void doGet(HttpServletRequest request,
2.HttpServletResponse response) throws ServletException, IOException {
3.doPost(request, response);
4.}
5.
6.protected void doPost(HttpServletRequest request,
7.HttpServletResponse response) throws ServletException, IOException {
8.String base = "/jsp/";
9.String url = base + "home.jsp";
10.String action = request.getParameter("action");
11.String category = request.getParameter("category");
12.String keyWord = request.getParameter("keyWord");
13.if (action != null) {
14.switch (action) {
15.case "allBooks":
16.findAllBooks(request, response);
17.url = base + "listOfBooks.jsp";
18.break;
19.case "category":
20.findAllBooks(request, response);
21.url = base + "category.jsp?category=" + category;
22.break;
23.case "search":
24.searchBooks(request, response, keyWord);
25.url = base + "searchResult.jsp";
26.break;
27.
28.}
29.}
30.RequestDispatcher requestDispatcher = getServletContext()
31..getRequestDispatcher(url);
32.requestDispatcher.forward(request, response);
33.}
  • 第 3 行:doPost()方法是从 doGet()方法调用的。
  • 第 9 行:这一行构造了指向主页视图(home.jsp)的 URL。
  • 第 10 行:该行从请求中获取动作参数。但是由于这是一个主页,没有关联的 action 参数,所以变量 action 为 null。
  • 第 13 行到第 29 行:跳过第 13 行到第 29 行的代码块,因为动作为空。如果 action 不为 null,URL 将被重新构造为指向不同的视图,这取决于 action 值是 allBooks 还是 category 或 search。
  • 第 32 行:request dispatcher 转发到第 31 行 URL 中的视图名。

步骤 5:从视图中访问模型

在前面的步骤中,控制器使用 RequestDispatcher 将 home.jsp 转发到视图。

清单 2-30 展示了 home.jsp 的一个片段,其中包括 leftColumn.jsp。leftColumn.jsp 文件使用模型类别在主页的左侧菜单上显示类别。

清单 2-30 。包括 home.jsp 的 leftColumn.jsp

1.<body>
2.<div id="centered">
3.
4.<jsp:include page="header.jsp" flush="true" />
5.<br />
6.<jsp:include page="leftColumn.jsp" flush="true" />
7.<span class="label">Featured Books</span>
8...........
9.</div>
10.</body>
  • 第 6 行:JSP:include标签用于包含 leftColumn.jsp。这样做是因为应用的左侧栏(菜单)对应用中的所有屏幕都是通用的,但是我们没有在所有屏幕中编写左侧栏,而是将它编写在一个 JSP 页面中,并在需要的任何地方包含它,作为一种可重用性的方法。(在接下来关于 web 框架的几章中,我们将看到更多重用 JSP 的高级技术。)

清单 2-31 展示了与 leftColumn.jsp 类别相关的代码片段,其中类别被访问。

清单 2-31 。在 leftColumn.jsp 访问类别模型

1.<li><div><span class="label" style="margin-left: 15px;">Categories</span></div>
2.<ul>
3.<%
4.List<Category> categoryList1 = (List<Category>) application.getAttribute("categoryList");
5.Iterator<Category> iterator1 = categoryList1.iterator();
6.while (iterator1.hasNext()) {
7.Category category1 = (Category) iterator1.next();%>
8.<li><a class="label"href="<%=param1%>?action=category&categoryId=<%=category1.getId()%>&category=<%=category1.getCategoryDescription()%>"><spanclass="label" style="margin-left: 30px;"><%=category1.getCategoryDescription()%></span></a>
9.</li>
10.<%}%>
11.</ul></li>
  • 第 4 行:这一行从 ServletContext 中获取类别列表。我们已经将类别列表保存在步骤 2 中从数据库获得的 ServletContext 中。
  • 第 6 行到第 10 行:类别细节显示在标记中,比如你在主页上看到的类别描述。

注意清单 2-31 中的 JSP 页面使用 scriptlets 和表达式来获取类别并显示它们。使用 scriptlets 和表达式是不好的做法,应该尽可能避免。这是下一章的主题,它将向您展示如何用 JSTL 和 EL 替换 scriptlets 和表达式。

步骤 6:发送响应

上一步中构建的视图被交付给浏览器。

列出所有的书

当用户点击菜单上的所有书籍时,显示所有书籍的列表,如图图 2-37 所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-37 。列出所有书籍

“所有书籍”链接在 leftColumn.jsp 文件中。清单 2-32 展示了菜单上所有书籍链接的代码片段。

清单 2-32 。leftColumn.jsp 所有图书链接

1.<li><div>
2.<a class="link1" href="<%=param1%>?action=allBooks"><span
3.style="margin-left: 15px;" class="label">All Books</span></a>
4.</div></li>
  • 第 2 行:这一行是菜单中显示的所有书籍链接。当点击这个链接时,action-allBooks 的值作为参数添加到 URL 中,如 URL:

    http:localhost:8080/bookWeb/books?action=allBooks
    

    所示

执行步骤 2,从请求中定位 servlet,但是这一次动作不为 null,值为 allBooks。因此,执行 BookController 中 doPost()方法的代码块,如清单 2-33 所示。

清单 2-33 。BookController 中 doPost()中的所有书籍

1.protected void doPost(HttpServletRequest request,
2.HttpServletResponse response) throws ServletException, IOException {
3.String base = "/jsp/";
4.String url = base + "home.jsp";
5.String action = request.getParameter("action");
6.String category = request.getParameter("category");
7.String keyWord = request.getParameter("keyWord");
8.if (action != null) {
9.switch (action) {
10.case "allBooks":
11.findAllBooks(request, response);
12.url = base + "listOfBooks.jsp";
13.break;
14.case "category":
15.findAllBooks(request, response);
16.url = base + "category.jsp?category=" + category;
17.break;
18.case "search":
19.searchBooks(request, response, keyWord);
20.url = base + "searchResult.jsp";
21.break;
22.
23.}
24.}
25.RequestDispatcher requestDispatcher = getServletContext()
26..getRequestDispatcher(url);
27.requestDispatcher.forward(request, response);
28.}
  • 第 8 行:动作不为空,动作的值为 allBooks。
  • 第 10 行到第 12 行:调用帮助器方法 findAllBooks(request,response),重新构造 URL 指向 listOfBooks.jsp,RequestDispatcher 转发到以 URL 形式提供给 RequestDispatcher 的视图。

清单 2-34 显示了 BookController 中的帮助器方法 findAllBooks(请求,响应)。

清单 2-34 。BookController 中的 findAllBooks()

1.private void findAllBooks(HttpServletRequest request,
2.HttpServletResponse response) throws ServletException, IOException {
3.try {
4.BookDAO bookDao = new BookDAOImpl();
5.List<Book> bookList = bookDao.findAllBooks();
6.request.setAttribute("bookList", bookList);
7.
8.} catch (Exception e) {
9.System.out.println(e);
10.}
11.}
  • 第 5 行到第 6 行:使用 DAO 上的 findAllBooks()方法从数据库中获得所有书籍的列表,并在请求中设置为一个属性。

按类别搜索书籍

当用户点击菜单上的特定类别时,显示该类别的图书列表,如图图 2-38 所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-38 。按类别搜索图书

我们在上一节中看到,这些类别位于 leftColumn.jsp。清单 2-35 展示了类别的代码片段。

清单 2-35 。菜单上的类别链接(leftColumn.jsp)

1.<li>
2.<a class="label" href="<%=param1%>?action=category&categoryId=<%=category1.getId()%>&category=<%=category1.getCategoryDescription()%>"><span class="label" style="margin-left: 30px;"><%=category1.getCategoryDescription()%></span></a>
3.</li>
  • 第二行:这是菜单中显示的类别的链接。当点击这个链接时,类别的 ID 和描述以及动作类别的名称作为参数被添加到 URL 中,如下面的 URL 所示:

    http:localhost:8080/bookWeb/books?action=category&categoryId=1&category=clojure
    

再次执行步骤 2,从请求中定位 servlet,这一次动作不为 null,并且有一个值类别。因此,执行 BookController 中 doPost()方法的代码块,如清单 2-36 所示。

清单 2-36 。BookController 中的 doPost()

1.protected void doPost(HttpServletRequest request,
2.HttpServletResponse response) throws ServletException, IOException {
3.String base = "/jsp/";
4.String url = base + "home.jsp";
5.String action = request.getParameter("action");
6.String category = request.getParameter("category");
7.String keyWord = request.getParameter("keyWord");
8.if (action != null) {
9.switch (action) {
10.case "allBooks":
11.findAllBooks(request, response);
12.url = base + "listOfBooks.jsp";
13.break;
14.case "category":
15.findAllBooks(request, response);
16.url = base + "category.jsp?category=" + category;
17.break;
18.case "search":
19.searchBooks(request, response, keyWord);
20.url = base + "searchResult.jsp";
21.break;
22.
23.}
24.}
25.RequestDispatcher requestDispatcher = getServletContext()
26..getRequestDispatcher(url);
27.requestDispatcher.forward(request, response);
28.}
  • 第 8 行:动作不为空,动作的值为类别。
  • 第 15 行到第 16 行:调用帮助器方法 findAllBooks(request,response),重新构造 URL 指向 listOfBooks.jsp,RequestDispatcher 转发给以 URL 形式提供给 RequestDispatcher 的视图。

清单 2-37 显示了 BookController 中的帮助器方法 findAllBooks(请求,响应)。

清单 2-37 。BookController 中的 findAllBooks()

1.private void findAllBooks(HttpServletRequest request,
2.HttpServletResponse response) throws ServletException, IOException {
3.try {
4.BookDAO bookDao = new BookDAOImpl();
5.List<Book> bookList = bookDao.findAllBooks();
6.request.setAttribute("bookList", bookList);
7.
8.} catch (Exception e) {
9.System.out.println(e);
10.}
11.}
  • 第 5 行到第 6 行:使用 DAO 上的 findAllBooks()方法从数据库中获得所有书籍的列表,并在请求中设置为属性。

通过关键字搜索书籍

您可以通过作者姓名或书名中的关键词来搜索图书,如图图 2-39 所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-39 。通过关键字搜索图书

在我们讨论关键字搜索如何工作之前,让我们先来看看搜索的一个可用性方面。搜索栏旁边有一个问号,用于帮助用户。换句话说,鼠标悬停时,会显示一个工具提示,指示要使用的搜索参数,如图 2-40 所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-40 。搜索参数的工具提示

为了理解工具提示是如何工作的,请看一下搜索字段的标记,它在 leftColumn.jsp,如清单 2-38 所示。

清单 2-38 。搜索字段标记

1.<form class="search">
2.<input type="hidden" name="action" value="search" />
3.<input id="text"type="text" name="keyWord" size="12" />
4.<spanclass="tooltip_message">?</span>
5.<p />
6.<input id="submit" type="submit" value="Search" />
7.</form>
  • 第 4 行:这有一个类 tooltip_message。工具提示在这个类上使用 jQuery 和 CSS。
Listing 2-39 illustrates the jQuery code.

清单 2-39 。工具提示的 jQuery

1.$(document).ready(function () {
2.$("span.tooltip_message").hover(function () {
3.$(this).append('<div class="message"><p>Search by Keyword in:<ul><li>Author First Name </li><li>Author Last Name <li>Title of the book </li></ul></p></div>');
4.},function () {
5.$("div.message").remove();
6.});
7.});
  • 第 2 行:类 tooltip_message 和< span >标签被用作调用悬停功能的选择器。
  • 第 3 行:将在工具提示中显示的消息附加到第 2 行选择器返回的对象上。

以类似的方式,工具提示可以添加到主屏幕上的图像,如图图 2-41 所示。清单 2-40 说明了所使用的 jQuery 函数。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-41 。图像的工具提示

清单 2-40 。图像提示的 jQuery 函数

$("span.tooltip_img1").hover(function(){$(this).append('<div class="message"><ul><li>Title - Beginning Groovy, Grails and Griffon</li><li>Author: Vishal Layka</li><li>Publisher: Apress</li></ul></div>');
}, function(){$("div.message").remove();});
Listing 2-41 illustrates the CSS code for the tooltip.

清单 2-41 。工具提示的 CSS

1.span.tooltip_message,span.tooltip_img1 {
2.cursor: pointer;
3.display: inline-block;
4.background-color: #F20B26;
5.width: 16px;
6.height: 18px;
7.color: #ffffff;
8.font-size: 12px;
9.font-weight: bold;
10.text-align: center;
11.position: relative;
12.}
13.
14.span.tooltip_message:hover {
15.background-color: #04FF97;
16.}
17.
18.div.message {
19.background-color: #04FF97;
20.color: #000000;
21.position: absolute;
22.left: 18px;
23.top: -18px;
24.z-index: 1000000;
25.text-align: left;
26.width: 280px;
27.}This CSS and jQuery code in Listing 2-40 and Listing 2-41 are included in leftColumn.jsp, as illustrated in Listing 2-42.

清单 2-42 。在 leftColumn.jsp 访问 CSS 和 jQuery 文件

1.<link rel="stylesheet" href="css/bookstore.css" type="text/css" />
2.<script src="js/bookstore.js" type="text/javascript"></script>
3.<script type="text/javascript" src="js/jquery-1.9.1.js"></script>
  • 第 1 行:这是清单 2-41 所示规则的外部化 CSS 文件
  • 第 2 行:这是清单 2-40 中 jQuery 函数的外部化 JavaScript 文件
  • 第 3 行:第 3 行指定了我们正在使用的 jQuery 库。

现在,我们将从 web 应用中的关键字搜索功能开始。清单 2-43 展示了搜索字段的标记。

清单 2-43 。搜索字段标记

1.<form class="search">
2.<input type="hidden" name="action" value="search" /><input id="text"
3.type="text" name="keyWord" size="12" /><span
4.class="tooltip_message">?</span>
5.<p />
6.<input id="submit" type="submit" value="Search" />
7.</form>
  • 第 2 行:该行指定动作值搜索。
  • 第 6 行:该行提交请求。

当用户提交搜索请求时(再次从请求中定位 servlet),执行第 2 步,这一次操作是值搜索。因此,执行 BookController 中 doPost()方法中的搜索用例,如清单 2-44 中的所示。

清单 2-44 。BookController 中的 doPost()

1.protected void doPost(HttpServletRequest request,
2.HttpServletResponse response) throws ServletException, IOException {
3.String base = "/jsp/";
4.String url = base + "home.jsp";
5.String action = request.getParameter("action");
6.String category = request.getParameter("category");
7.String keyWord = request.getParameter("keyWord");
8.if (action != null) {
9.switch (action) {
10.case "allBooks":
11.findAllBooks(request, response);
12.url = base + "listOfBooks.jsp";
13.break;
14.case "category":
15.findAllBooks(request, response);
16.url = base + "category.jsp?category=" + category;
17.break;
18.case "search":
19.searchBooks(request, response, keyWord);
20.url = base + "searchResult.jsp";
21.break;
22.
23.}
24.}
25.RequestDispatcher requestDispatcher = getServletContext()
26..getRequestDispatcher(url);
27.requestDispatcher.forward(request, response);
28.}
  • 第 18 行:执行案例搜索,动作值为 search
  • 第 19 行:调用 search books()方法。searchBooks()在列表 2-45 中有说明。
  • *第 20 行:*第 20 行构造了视图的 URL。
  • 第 26 行:视图的 URL 被提供给 RequestDispatcher。

清单 2-45 展示了控制器用来调用 DAO 的 searchBooks()助手方法。

清单 2-45 。BookController 中的 searchBooks()

1.private void searchBooks(HttpServletRequest request,
2.HttpServletResponse response, String keyWord)
3.throws ServletException, IOException {
4.try {
5.BookDAO bookDao = new BookDAOImpl();
6.List<Book> bookList = bookDao.searchBooksByKeyword(keyWord);
7.
8.request.setAttribute("bookList", bookList);
9.
10.} catch (Exception e) {
11.System.out.println(e);
12.}
13.}
14.
  • 第 6 行:调用 BookDAO 中定义的 searchBooksByKeyword()方法,根据搜索关键字获取图书列表。我们在第一章中为 web 应用构建数据访问层时使用了这种方法。

摘要

本章介绍了 servlets 和 JSP,并向您展示了如何使用这些 web 组件创建您的第一个 web 应用。然后,本章实现了现实世界中基于 MVC 的 Java web 应用,一个使用 servlets 和 JSP 的书店。在下一章中,我们将扩充这个应用,以使用 JSTL 和表达式语言将业务逻辑关注点从表示中分离出来的最佳实践。

www . IETF . org/RFC/RFC 3986 . txt

JCP . org/en/JSR/detail?id=340

3【www.oracle.com/technetwork/java/index-jsp-135475.html】??

http://www.hengruixuexiao.com/news/10833.html

相关文章:

  • 建个网站大概多少钱怎么让百度搜出自己
  • 上海网站备案核验郑州seo优化外包公司
  • 平面设计图用什么软件百度ocpc怎么优化
  • 招聘网站毕业设计网上国网推广
  • 莱芜手机网站设计公司十大放黄不登录不收费
  • 做网站可以不做后端吗今日热搜榜排行榜
  • 网站建设厘金手指排名二二快速排名优化推广排名
  • 我们做网站 出教材 办育心经杭州谷歌seo公司
  • 景县网站建设seo站内优化教程
  • 怎么做一个购物平台网站青岛百度seo代理
  • 怎么设计自己logo360优化大师安卓版下载
  • 网站建设10年后的目标淘宝怎么优化关键词排名
  • 优斗士网站建设引流推广多少钱一个
  • 课程网站开发卷宗网络舆情软件免费入口
  • 网站程序定制长沙seo步骤
  • 二维码生成器网页版网站优化软件费用
  • 2014 网站建设营销型网站建设实训总结
  • 网站查询功能怎么做360站长平台链接提交
  • 南京广告公司一览表网站用户体验优化
  • 做网站前端需要懂得多用户建站平台
  • 济南高新区 网站制作河南关键词排名顾问
  • wordpress 头像打岔揭阳百度快照优化排名
  • 做户外照明有哪些网站站长工具5g
  • 织梦做的网站首页出现空白西安网站seo公司
  • 备案网站用户名是什么网站建设与管理主要学什么
  • 制作一个网站数据库怎么做怎么样拓展客户资源
  • 杭州网站建设制作联系电话seo资源网站 排名
  • 中山网站设计收费标准成都网站快速开发
  • 网站开发java好还是php好如何在百度发布短视频
  • 怀柔网站建设成都百度推广代理公司