系列写到这里也差不多可以收尾了,本文将是系列的最后一篇。主要的参考资料是《Tomcat与Java Web开发技术详解》和 菜鸟笔记。菜鸟笔记的问题在于,学完之后还是觉得什么都不会,因为没有人指导去做个项目,因而对真正的项目没有概念。而《Tomcat》则提供了一些项目的感觉。
没错,JSP已经不再流行了,但是想学习Java Web,JSP和Servlet的基本功的修行是必不可少的。何况,很多技术都是触类旁通的。我会继续加油的!
表达式语言EL
这个还是蛮简单的。阅读菜鸟笔记就可以。回想起来,第一遍看它,还觉得它跟WPF中的属性绑定很像(也许是“.”号的提醒)。但其实用点号表示属性还是比较普遍的。
自定义标签
自定义标签就是对JSP内置标签的扩展,可以让开发人员创建可重用的第三方标签,帮助处理复杂的逻辑和事物,让JSP代码更加简洁。
例如,下面是一些自定义标签的用法:
<mm:hello/>
<mm:message key="hello.hi" />
<mm:greeting>How are you. </mm:greeting>
自定义标签是从JSP 1.1版本出现的,后来在JSP 2.0中又加入了简单标签。下面先来看看传统的自定义标签。
要让JSP容器理解自定义标签的含义,很显然需要定义一些约定和接口。通常会把一组功能相关的标签放在同一个标签库中。开发标签库的步骤如下:
- 创建自定义标签的处理类(Tag Handler),实现标签的具体功能。
- 创建TLD标签库描述文件,描述标签的用法等。
方法 | 描述 |
---|---|
setPageContext() | 由容器调用,传入当前的PageContext对象 |
setParent() | 由容器调用,传入此标签的父标签的处理对象 |
getParent() | 得到父标签的处理对象 |
doStartTag() | 容器解析到标签的起始标志时调用 |
doEndTag() | 容器解析到标签的结束标志时调用 |
release() | 释放Tag资源时调用。 |
自定义标签处理类要继承Tag接口:
方法 | 描述 |
---|---|
setPageContext() | 由容器调用,传入当前的PageContext对象 |
setParent() | 由容器调用,传入此标签的父标签的处理对象 |
getParent() | 得到父标签的处理对象 |
doStartTag() | 容器解析到标签的起始标志时调用 |
doEndTag() | 容器解析到标签的结束标志时调用 |
release() | 释放Tag资源时调用。 |
为了帮助编写Tag Handler,JSP还提供了TagSupport和BodyTagSupport两个具体类,可以继承其中之一。
使用自定义标签时,需要把Tag Handler的class文件以及TLD文件拷到WEB-INF下,然后在web.xml中指明引入标签库:
<jsp-config>
<taglib>
<taglib-uri>/mytaglib</taglib-uri>
<taglib-location>/WEB-INF/mytaglib.tld</taglib-location>
</taglib>
</jsp-config>
在JSP中使用自定义标签前用<%@taglib>
指令声明对标签库的生命。属性prefix指明前缀。
<%@page contentType="text/html; charset=GB2312" %>
<%@taglib uri="/mytaglib" prefix="mm" %>
<html><head><title>greet</title></head>
<body>
<mm:greet count="3">
<font size="<%=size++ %>">
Hi,${param.username} <br>
</font>
</mm:greet>
</body></html>
简单标签
传统自定义标签的编写还是太复杂了,因此JSP 2.0推出了简单标签(SimpleTag)。这个接口基本上只需要你实现doTag()方法来完成主要工作。更棒的是,还可以让你用采用JSP语法的标签文件制作标签,其原理和思想就像用JSP写Servlet一样。一个简单的greetings.tag示例:
<%@ tag pageEncoding="UTF8" %>
朋友们,大家好!
和编译JSP文件一样,容器也会编译标签文件,生成Tag Handler类。标签文件甚至也有隐含对象和指令,确实和JSP异曲同工。
标准标签库JSTL
既然可以随意自定义JSP标签,那往往会有一套官方标准库。一般标签库往往把所有文件打成JAR包,内含所有的class和TLD文件。对于官方标准库,只需要把JAR包放入WEB-INF/lib目录下,在JSP文件中使用时先用<%@ taglib>
的uri属性指定具体的库就行了。如:
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
JSTL主要包括以下五个部分:
-
标签 描述 <c:out> 用于在JSP中显示数据,就像<%= ... > <c:set> 用于保存数据 <c:if> 与我们在一般程序中用的if一样 <c:forEach> 基础迭代标签,接受多种集合类型 标签 描述 <c:out> 用于在JSP中显示数据,就像<%= ... > <c:set> 用于保存数据 <c:if> 与我们在一般程序中用的if一样 <c:forEach> 基础迭代标签,接受多种集合类型 - 格式标签库。用来格式化并输出文本、日期、时间、数字,提供国际化支持。
- SQL标签库。与数据库交互的标签。现在肯定没人用。
- XML标签库。操作XML文档。
- Functions标签库。包含一系列标准函数,大部分是通用的字符串处理函数。
设计网站模板
这里说的模板可不是后来出现的FreeMarker这样的模板引擎。这里说的是,同一个Web应用的页面往往需要保持外观上的统一的风格,因而可以定义统一的网页模板,不同的页面通过模板来动态生成。这里介绍的是利用自定义的JSP标签来实现。
假设对于一个bookstore应用,所有的网页都有如下结构:
<html>
<head>
<title>
<!-- title -->
</title>
</head>
<body>
<!-- banner -->
<!-- body -->
</body>
</html>
所有网页都有title、banner、body这三部分。可以创建一个template.jsp文件,当客户请求某个网页时,采用某种方法把这三个部分动态地填充进去,生成客户所需的网页。
因此就需要让所有的请求都被template.jsp文件处理。这里是使用一个DispatcherServlet类,接受所有的客户请求,然后把URL保存到request中,再转发给template.jsp。
模板JSP文件的内容是这样的:
<!-- template.jsp -->
<%@ page contentType="text/html; charset=GB2312" %>
<%@ taglib uri="/mytaglib" prefix="mm" %>
<%@ page errorPage="errorpage.jsp" %>
<%@ page import="java.util.*" %>
<%@ include file="screendefinitions.jsp" %>
<html>
<head>
<title>
<mm:insert definition="bookstore" parameter="title"/>
</title>
</head>
<mm:insert definition="bookstore" parameter="banner"/>
<mm:insert definition="bookstore" parameter="body"/>
</body>
</html>
自定义的<insert>
标签在其他自定义标签的帮助下,可以根据客户请求的具体URL,把对应的内容JSP文件包含进来。
以上就完成了主要功能。其实介绍这个项目是为后面的MVC话题做个铺垫。
引入MVC
MVC的概念和优点就不介绍了,直接进入主题。
JSP Model 1和JSP Model 2
早期的JSP页面把业务逻辑和控制网页流程的事情都干了,造成代码非常混乱。为了解决问题,SUN公司先后制定了两种设计模式,分别为JSP Model 1和JSP Model 2。
下图为Model 1. 它采用了JavaBean处理业务逻辑(Model),但JSP仍要干 View + Controller的活。只适应简单应用的需要。
Model 1Model 2模式则联合使用了JSP和Servlet,吸取了它们各自的优点,用JSP生成表示层的内容,让Servlet完成深层次的处理任务。在这里,Servlet充当控制器的角色,负责处理客户请求,创建JSP页面需要使用的JavaBean对象,并返回合适的JSP页面给客户。JSP页面没有流程控制的逻辑,只负责把由Servlet创建的JavaBean对象包含的数据作为动态内容插入到静态模板中。下面为结构图:
Model 2Struts框架
Struts是一个经典的Web MVC框架,是在JSP Model 2的基础上实现的。下面是其结构图:
Struts结构Struts框架是利用其核心过滤器FilterDispatcher来拦截所有的客户请求,然后映射到不同的Action模块中处理。Action类继承自Action接口,核心是用execute()方法来处理客户请求。为方便,可以继承Struts的实现类ActionSupport。
Action类调用Model组件(JavaBean等)处理业务并返回结果,核心过滤器再根据映射配置转发到具体的视图(如JSP),视图页面生成响应内容返回给核心过滤器,后者再把响应发送到客户端。
Struts流程以上过程解释了如何根据请求定位到具体页面。可是如何用视图页面返回动态内容呢?也就是如何让JSP页面获得JavaBean的数据?
有两种方法。
- Struts提供的自定义标签。Struts 2甚至不需要你的Action类继承Action接口,只需要在类中定义一些属性和get/set方法,在JSP中使用Struts标签
<s:property>
就能访问到。使用<s:text>
标签则能够访问struts资源文件中的属性。 - 在Action中访问Servlet API中的各种对象,就可以在对象中设置各种Attributes。通过ActionContext.getContext()可以得到HttpServletRequest的一个封装类。实现ServletContextAware、ServletRequestAware等接口则可以直接获得Servlet API的核心对象。
网友评论