我们知道Web页面通常使用HTML超文本标记语言排版,JavaEE中最基础的服务端组件是Servlet,然而Servlet只能通过Java代码拼接字符串的方式输出文本信息,直接使用Servlet输出Web页面会给编程造成很大困难。JSP(JavaServer Pages)则是一种专门用于创建网页的JavaEE技术,它允许开发人员在服务端动态生成Web页面。不过实际上JSP并不是一种新的服务端组件,它还是基于Servlet实现的。在Servlet容器内部,JSP会由JSP引擎编译成Servlet,因此底层其实还是利用Servlet输出JSP的内容。
在实际开发中,JSP可以包含Java代码,不过现在更一般的情况是使用JSP作为视图层(View)模板实现MVC架构,控制器(Controller)仍然使用Servlet实现。
下面例子我们编写一个最简单的JSP页面,它每次访问时会由服务端计算并动态输出当前的时间。
index.jsp
<%@ page contentType="text/html;charset=UTF-8" %>
<%@ page import="java.util.Date" %>
<%@ page import="java.text.SimpleDateFormat" %>
<%--这是注释--%>
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Hello</title>
</head>
<body>
<%
Date now = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
out.println("当前时间:" + sdf.format(now));
%>
</body>
</html>
代码中第1-3行是page
编译指令,第1行说明这个文件是JSP语言支持是Java,这一行通常为固定写法;第2-3行使用import
语句导入了一些类供后面使用;第4行演示了JSP注释的用法;接下来就是普通的HTML的内容,这些内容会输出到浏览器中进行渲染,而<% %>
包围的部分则是Java代码,由服务端动态计算输出。
注意JSP中注释的写法为<%-- --%>
,这和HTML注释有着本质的区别,JSP注释不会从服务器输出,HTML注释则会输出到浏览器,只是浏览器不渲染HTML注释而已。
我们将这个index.jsp
文件放置在JavaWeb工程的webapp
目录下,启动服务器后使用浏览器访问http://localhost:8080/demoweb/index.jsp
,其中/demoweb
是我们项目的ContextPath,index.jsp
是访问的文件名,此时JSP会由Servlet容器解析执行,向浏览器输出最终合成的HTML页面。
page指令用于指定JSP的属性,前面例子中我们使用过contentType
和import
属性,实际上很多属性相关的功能在MVC架构中通常是由控制器进行处理,因此并不常用,此处仅做了解,我们可能用到的一些page指令如下。
指令属性 | 功能 |
---|---|
language | 使用的编程语言,它的默认值是java ,通常也只有一个可选项,一般无需设置此项 |
extends | JSP编译得到的Java类的父类或接口,MVC中JSP通常不会编写太多Java代码,一般很难用到该属性 |
import | 导入的类,用于JSP中嵌入的Java代码使用,实际开发中使用MVC模式很少在JSP中嵌入Java代码,因此也不太常用 |
session | 这个JSP是否使用Session,默认值为true ,一般无需额外设置此项 |
buffer | 输出缓冲区大小,通常使用默认值即可,一般无需设置此项 |
autoFlush | buffer缓冲区满后自动刷新输出,一般无需额外设置此项 |
errorPage | JSP出错时的处理页,实际开发中业务逻辑通常位于控制器,业务逻辑出错时通常也由控制器进行处理,因此该属性很少用到 |
contentType | HTTP头信息中的值,文件类型和字符集,一般固定使用text/html;charset=UTF-8 |
pageEncoding | 生成网页的编码字符集,contentType配置中实际上包含了页面编码设置,因此不必单独指定该属性 |
isErrorPage | 该JSP是否是出错处理页 |
include指令可以将外部文件嵌入当前JSP文件中。使用include
指令嵌入后,经过JSP引擎编译,另一个JSP的内容将完全融入当前JSP生成的Servlet中,也就是说它们会被编译为同一个Servlet,而不是请求了两次的HTML页面嵌入,此外目标的编译指令也会被导入到当前JSP页面。下面是一个include指令的使用例子,该页面导入了test.jsp
页面。
<%@ page contentType="text/html;charset=UTF-8" %>
<html>
<head>
<title>hello</title>
</head>
<body>
<%@include file="test.jsp" %>
<h2>Hello World!</h2>
</body>
</html>
include指令是比较常用的,在实际开发中,我们经常会把顶部导航条、底部栏等封装到单独的JSP文件,在各处引用。
taglib指令用于声明使用JSP标签库,实际开发中,我们经常能用到的标签库包括JSP核心标签库(JSTL),Struts2标签库等。其中JSTL核心标签库是最常用的,一些页面上的渲染逻辑,如if
、foreach
等都需要核心标签库的支持。
引入核心标签库使用如下代码:
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
注意:引入核心标签库还需要额外的Maven依赖。
<dependency>
<groupId>javax.servlet.jsp.jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
有关标签库的具体使用将在后续章节介绍。
JSP动作指令用于在JSP页面中嵌入Java代码或者执行特定的操作,例如包含其他资源、设置页面属性等,MVC开发模式下,实际上下面大部分动作指令都没什么用,这里仅作了解,我们可能用到的一些动作指令如下。
动作指令 | 功能 |
---|---|
jsp:forward | 请求转发 |
jsp:param | 用于传递参数,转发时添加的参数可以被接收 |
jsp:include | 动态引入,效果类似静态引入 |
jsp:plugin | 通常用于下载JavaBean或applet到客户端 |
jsp:useBean | 创建JavaBean |
jsp:setProperty | 设置JavaBean属性 |
jsp:getProperty | 得到JavaBean属性 |
注意jsp:include
是动态嵌入JSP,它和之前介绍的page指令的include
有一些区别,它只导入页面的内容而不会导入编译指令,编译后实际上是两个Servlet(内部互相调用),但是输出时仍然是一个页面。
一个JSP页面包含了9大内置对象,它们是在JSP页面中自动创建并可供开发人员使用的对象,这些内置对象对应Servlet API,提供了对不同的功能和环境的访问。
内置对象 | Servlet API | 功能 |
---|---|---|
application | javax.servlet.ServletContext的实例 | 该实例代表Web应用上下文 |
config | javax.servlet.ServletConfig的实例 | 代表该JSP的配置信息 |
exception | java.lang.Throwable的实例 | 该页面是错误处理页面时才有用,代表其他页面的错误信息 |
out | javax.servlet.jsp.JspWriter的实例 | 用于控制JSP的输出流 |
page | this 对象 |
对应JSP自身 |
pageContext | javax.servlet.jsp.PageContext的实例 | 代表JSP页面上下文,可以访问页面中的共享数据 |
request | javax.servlet.http.HttpServletRequest的实例 | 请求对象,封装了请求信息 |
response | javax.servlet.http.HttpServletResponse的实例 | 响应对象,封装了响应信息 |
session | javax.servlet.http.HttpSession的实例 | 封装Session信息 |
注:application
作用域是整个应用,session
是一次会话,request
是一次请求,page
是一个JSP页面,这4个对象比较常用,经常用于我们在不同的作用域上存取参数。