Java
Java Web基础

JSP页面基本用法

简介:JSP全称是Java Server Pages,它和Servlet技术一样,都是Sun公司定义的一种用于开发动态Web资源的技术。JSP实际上就是Servlet。JSP = HTML + Java。

1. JSP概述

JSP全称是Java Server Pages,它和Servlet技术一样,都是Sun公司定义的一种用于开发动态Web资源的技术。JSP实际上就是Servlet。JSP = HTML + Java。

  • HTML:静态内容
  • Servlet:服务器端的小应用程序,适合编写Java逻辑代码。
  • JSP:适合编写输出动态内容,但不适合编写Java逻辑。

2. JSP的原理

  1. 当用户访问一个JSP页面时,会向一个Servlet容器(Tomcat等)发出请求。
  2. 如果页面有所改动,则Servlet容器首先要把JSP页面(假设为test.jsp)转化为Servlet代码(test.java),再将其转化为class文件(test.class文件);这个编译过程会耗费时间。
  3. JSP容器负责调用从JSP转换来的Servlet,这些Servlet负责提供服务相应用户请求;如果用户有多个请求,则容器会建立多个线程处理多个请求;
  4. 容器执行字节码文件(包括调用的Servlet的字节码),并将其结果返回到客户端(返回的最终方式是有Servlet输出HTML格式的文件流)。

一般来说,Servlet作为控制器,重点编写Java代码逻辑,如获取表单数据、处理业务逻辑、分发转向等,而JSP代码负责根据模板显示数据。

3. JSP的基本语法

  1. JSP模版元素,即网页的静态内容。如:HTML标签和文本。
  2. JSP的脚本
  • 简单脚本:<% out.write("hello"); %>
  • 表达式:<%= 2 + 3 %>
  • 声明:<%! String text = "world"; %>,表示在类中定义全局成员,和静态块。
  • 注释:JSP注释<%-- 被注释的内容 --%>,安全,不会在页面上输出;网页注释<!-- 网页注释 -->,不安全,会在页面上输出%。

示例代码:

  • <%@ page contentType="text/html;charset=UTF-8" language="java" %>
  • <html>
  • <head>
  • <title>Index Page</title>
  • </head>
  • <body>
  • <%! String text = "world"; %>
  • <% out.write("hello " + text); %>
  • <%= 2 + 3 %>
  • <%-- 这是一段注释 --%>
  • </body>
  • </html>

4. JSP的3个指令

JSP指令(directive)是为JSP引擎而设计的,它们并不直接产生任何可见输出,而只是告诉引擎如何处理JSP页面中的其余部分。
在JSP 2.0规范中共定义了三个指令:page、include和taglib。它们的使用语法如下:

  • 统一编写:<%@ 指令名称 属性1="属性值1" 属性2="属性值2" ...%>
  • 分开编写:<%@ 指令名称 属性1="属性值1"%><%@ 指令名称 属性2="属性值2"%>

如:

  • <%- 导入包 -%>
  • <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
  • <%@ page language="java" %>
  • <%@ page import="java.util.*" %>
  1. page:用于定义JSP页面的各种属性,page指令常用的属性定义如下:
属性 定义
language="ScriptLanguage" 指定JSP Container用什么语言来编译,目前只支持Java语言,默认为Java
extends="className" 定义此JSP网页产生的Servlet是继承哪个
import="importList" 定义此JSP网页要使用哪些Java API
session="true|false" 决定此页面是否使用session对象,默认为true
buffer="none|size in kb" 决定输出流(InputStream)是否有缓冲区。默认为8kb
autoFlush="true|false" 决定输出流的缓冲区慢了后是否需要自动清除,缓冲区慢了后会产生异常错误,默认为true
isThreadSafe="true|false" 是否支持线程,默认为true
errorPage="url" 如果此页发生异常,网页会重新指向一个url
isErrorPage="true|false" 表示此页面是否为错误处理页面,默认为false
contentType="text/html;charset=gb2312" 表示MIME类型和JSP的编码方式
pageEncoding="ISO-8859-1" 编码方式
isELLgnored="true|false" 是否支持EL表达式,默认为false

注1:import:和Java代码中的import是一样的,可以写在一起,如<%@ page import="java.util.Date,java.util.List"%>,也可以分开编写,如<%@ page import="java.util.Date"%><%@ page import="java.util.List"%>
注2:JSP会默认自动导入以下的包:

  • import java.lang.*;
  • import javax.servlet.*;
  • import javax.servlet.http.*;
  • import javax.servlet.jsp.*;
  1. include:静态包含,把其它资源包含到当前页面中,如<%@ include file="/include/header.jsp" %>,相对而言还有动态包含,如<jsp:include page="/include/header.jsp"></jsp:include>两者主要的区别在于编译的时间段不同,静态包含会在编译时就把两个文件合并,而动态包含不会合并文件,当代码执行到include时,才包含另一个文件的内容。一般而言能用静态包含的就不用动态包含。

  2. taglib:在JSP页面中导入JSTL标签库,同时指定标签库前缀,替换JSP中的Java代码片段,如<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>

5. JSP的6个动作

动作表示使用标签的形式来表示一段Java代码,常用的动作有以下六个:

  • <jsp:include>:动态包含。
  • <jsp:forward>:请求转发。
  • <jsp:param>:设置请求参数。
  • <jsp:useBean>:创建一个对象。
  • <jsp:setProperty>:给指定的对象属性赋值。
  • <jsp:getProperty>:取出指定对象的属性值。

这里用一个示例来演示上面的动作如何使用。首先我们有index.jsp、header.js和test.jsp三个页面,它们的主要内容分别如下:

  • index.jsp
  • <%@ page contentType="text/html;charset=UTF-8" language="java" %>
  • <jsp:forward page="test.jsp"></jsp:forward>
  • <html>
  • <head>
  • <title>Index Page</title>
  • </head>
  • <body>
  • <jsp:include page="header.jsp">
  • <jsp:param name="headerName" value="This is a index header name"></jsp:param>
  • </jsp:include>
  • </body>
  • </html>
  • header.jsp
  • <%@ page contentType="text/html;charset=UTF-8" language="java" %>
  • <h3>${param.headerName}</h3>
  • <p>this is header section</p>
  • test.jsp
  • <%@ page contentType="text/html;charset=UTF-8" language="java" %>
  • <html>
  • <head>
  • <title>Test Page</title>
  • </head>
  • <body>
  • <jsp:include page="header.jsp">
  • <jsp:param name="headerName" value="This is a test header name"></jsp:param>
  • </jsp:include>
  • <jsp:useBean id="jspBean" class="com.coderap.jsp.JspBean" scope="page" type="java.lang.Object">
  • <jsp:setProperty name="jspBean" property="name" value="JspBean Name"/>
  • <jsp:setProperty name="jspBean" property="version" value="10"/>
  • <p><jsp:getProperty name="jspBean" property="name"/></p>
  • <p><jsp:getProperty name="jspBean" property="version"/></p>
  • </jsp:useBean>
  • </body>
  • </html>

同时test.jsp中用到的com.coderap.jsp.JspBean类如下:

  • package com.coderap.jsp;
  • public class JspBean {
  • private String name;
  • private int version;
  • public String getName() {
  • return name;
  • }
  • public void setName(String name) {
  • this.name = name;
  • }
  • public int getVersion() {
  • return version;
  • }
  • public void setVersion(int version) {
  • this.version = version;
  • }
  • }

由于在index.jsp中使用了<jsp:forward page="test.jsp"></jsp:forward>,当请求index.jsp时会转发请求到test.jsp页面,显示的也是test.jsp的内容。最终显示的HTML页面代码如下:

  • <html>
  • <head>
  • <title>Test Page</title>
  • </head>
  • <body>
  • <h3>This is a test header name</h3>
  • <p>this is header section</p>
  • <p>JspBean Name</p>
  • <p>10</p>
  • </body>
  • </html>

6. JSP的9个内置对象

内置对象可以在JSP的<%= %><% %>中直接使用,它们的说明如下

对象名 类型 说明
request javax.servlet.http.HttpServletRequest
response javax.servlet.http.HttpServletResponse
session javax.servlet.http.HttpSession session="true"开关
application javax.servlet.ServletContext
exception java.lang.Throwable isErrorPage="false"开关
page java.lang.Object当前对象this 当前servlet实例
config javax.servlet.ServletConfig
out javax.servlet.jsp.JspWriter 字符输出流,相当于printWriter对象
pageContext javax.servlet.jsp.PageContext

这里主要讲一下pageContext,这个内置对象非常重要,它有以下特点:

  1. 它本身也是一个域对象,可以操作其它三个域对象(request、session和application)的数据。它是一个抽象类,继承了javax.servlet.jsp.JspContext,在Tomcat容器内具体表现为org.apache.jasper.runtime.PageContextImpl对象。
  • abstract public void setAttribute(String name, Object value);
  • abstract public Object getAttribute(String name);
  • abstract public void removeAttribute(String name);
  • // 自动从page、request、session、application依次查找,找到了就取值,结束查找
  • abstract public Object findAttribute(String name);

操作其它域对象的方法

  • abstract public void setAttribute(String name, Object value, int scope);
  • abstract public Object getAttribute(String name, int scope);
  • abstract public void removeAttribute(String name, int scope);

注:以上的方法都是从它的父类javax.servlet.jsp.JspContext继承而来。

scpoe的取值如下:

  • PageContext.PAGE_SCOPE:当前页面。
  • PageContext.REQUEST_SCOPE:当前请求。
  • PageContext.SESSION_SCOPE:当前会话。
  • PageContext.APPLICATION_SCOPE:当前应用。

这四个值的类型都是整型。

  1. 它可以创建其它的8个隐式对象,在普通类中可以通过PageContext获取其他JSP隐式对象。

  2. 提供了一些简易方法,如:

  • abstract public void forward(String relativeUrlPath) throws ServletException, IOException;
  • abstract public void include(String relativeUrlPath) throws ServletException, IOException;

7. 四大域对象

  • PageContext:即pageConext,存放的数据在当前页面有效,开发时使用较少。
  • ServletRequest:即request,存放的数据在一次请求(转发)内有效,使用非常多。
  • HttpSession:即session,存放的数据在一次会话中有效,使用的比较多。如:存放用户的登录信息、购物车功能。
  • ServletContext:即application,存放的数据在整个应用范围内都有效。因为范围太大,应尽量少用。

8. EL表达式

EL表达式是一种JSP技术,能够代替JSP中原本要用Java语言进行显示的语句,使得代码更容易编写与维护。最基本的语法是${express}。它的用法有以下几种:

  1. 获取并显示数据
  • 从四个域中通过key找到简单数据并显示出来。表达式代码:

${name}:类比于<%= pageContext.findAttribute("name") %>,四个域的寻找顺序是page、request、session、application。用EL表达式还有个好处,若找不到键值为name的属性值,不会显示null,会显示空字符串。若是确定键值是在request域中,则可以用如下EL表达式代码${requestScope.name},其他域也类似。

  • 从存储在WEB域中的封装了数据的JavaBean中得到对象的某个属性值并显示出来:
  • <%
  • Person person = new Person();
  • Address address = new Address();
  • address.setProvince("CA");
  • address.setCity("Alameda");
  • person.setName("Tom");
  • person.setAge(20);
  • person.setAddress(address);
  • session.setAttribute("person", person);
  • %>
  • ${person.name} <%-- 从Web域中找到键值为person的对象然后再person对象中找到name属性 --%>
  • ${person.address.city}
  • ${person['name']} <%-- 也可以用[]方式 --%>
  • ${person['address']['city']}

除了用.方式获得对象的属性,也可以用[]方式,当然遇到键值名字中有特殊字符的或者key值为数字开头,则只能用[]方式。

  • 从List集合对象中获取某个值并显示。表达式代码:
  • <%
  • List<Person> list = new ArrayList<Person>();
  • list.add(new Person("Tom"));
  • list.add(new Person("Jack"));
  • list.add(new Person("Marry"));
  • application.setAttribute("list", list);
  • %>
  • ${list[1].name}
  • 从Map中获取某个值并显示。表达式代码:
  • <%
  • Map map = new HashMap();
  • map.put("1", new Person("Tom"));
  • map.put("Jack", new Person("Jack"));
  • map.put("Marry", new Person("Marry"));
  • request.setAttribute("map", map);
  • %>
  • ${map['1'].name} <%-- 数字为键的情况下只能用[]方式取值 --%>
  • ${map.Jack.name}
  1. 执行运算
  • 语法:${运算表达式}
  • 常见运算符:==(eq)!=(ne)<(lt)>(gt)<=(le)>=(ge)&&(and)||(or)!(not)
  • 判断是否为空:${empty name}
  • 三目运算符:${name == null? "null" : name }
  1. 获取常用对象,语法:${隐式对象名称},隐式对象表如下:
对象名 用法 等价JSP代码或作用
param ${param.name} request.getParameter(name)
paramValues ${paramValues.name} request.getParameterValues(name),返回一个字符串数组
header ${header.name} request.getHeader(name)
headerValues ${headerValues.name} request.getHeaderValues(name)
cookie ${cookie.name.value} request.getCookie()
initParam ${initParam.name} ServletContext.getInitparameter(name)
contextPath ${pageContext.request.contextPath} 获取Web应用名
sessionid ${pageContext.request.sessionid} 获取sessionId
remoteAddr ${pageContext.request.remoteAddr} 获取主机名

注:EL表达式在获取某个对象的属性值时,先将某个属性值首字母变成大写,然后加上get前缀,拼接成getter方法,通过反射将该对象构建出来,然后再对该对象执行getter方法,这与私有属性并没有关系,所以要注意,JavaBean的属性名要小写,且要有getter方法,不然会报错。

9. JSTL标签库

JSTL全称JSP Standard Tag Library,常被用来代替传统的Java片段语言来实现页面逻辑,与控制程序输出的EL表达式相结合,两者相辅相成。在使用JSTL标签之前,先要导入jstl.jar的包,如果是通过Maven创建项目的话,直接在pom.xml里添加依赖即可,如:

  • <!-- https://mvnrepository.com/artifact/javax.servlet.jsp.jstl/jstl -->
  • <dependency>
  • <groupId>javax.servlet.jsp.jstl</groupId>
  • <artifactId>jstl</artifactId>
  • <version>1.2</version>
  • </dependency>

另外还需要在JSP页面开头添加指令,如<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>。uri是指tld文件中某个库的uri,prefix是指前缀,如果是c.tld库中的,一般写成c,可以区别包里相同的标签。然后就可以用如<c:out/>这样的格式调用标签了。接下来将介绍常用标签库的用法。

9.1. 通用标签

  • <c:out>:输出内容。语法格式:
  • <%-- value值为显示的值引号内可以写EL表达式[]内属性为非必填属性escapeXml的默认值为true代表其中的标签就按照字符串显示不按照标签语%义进行显示default为当value值为null时显示的默认值 -->
  • <c:out value="value" [escapeXml="{true|false}"] [default="defaultValue"]/>
  • <c:set>:设置值。语法格式1:
  • <%-- 这句话就相当于在某个特定范围内加一个属性 --%>
  • <c:set value="value" var="name" [scope="{page|request|session|application}"]/>

或者语法格式2:

  • <%-- 把Web域中某个属性key值为person的JavaBean对象的name属性值赋成value值 --%>
  • <c:set value="Mike" target="${person}" property="name"/>
  • <c:remove>:移除某个域中的属性值。语法格式:
  • <%-- 移除某个域中的某个名为var的属性值 --%>
  • <c:remove var="person" scope="request"/>
  • <c:catch>:捕获异常。语法格式:
  • <c:catch var="exception">
  • <%
  • int a = 5 / 0;
  • %>
  • </c:catch>
  • <c:out value="${exception}"/>

9.2. 条件标签

  • <c:if>:用于判断条件。基本用法:
  • <%-- test的中的表达式就相当于if()括号中的语句Body就相当于test的值为true后执行的语句 --%>
  • <c:if test="${5 / 1 == 5}">
  • Body
  • </c:if>
  • <c:choose><c:when><c:otherwise>:这三个标签基本一起用,choose为父标签,作为选项的开始,每个when是一个选项,最后的其它就是otherwise。基本语法:
  • <c:choose>
  • <c:when test="${5 / 1 == 1}">
  • BodyA
  • </c:when>
  • <c:when test="${5 / 1 == 2}">
  • BodyB
  • </c:when>
  • <c:otherwise>
  • BodyC
  • </c:otherwise>
  • </c:choose>

9.3. 迭代标签

  • <c:forEach>:假设servlet将数据存在某个Web域中,以下是两种容器迭代方式的代码:
  • <%
  • List<Person> list = new ArrayList<Person>();
  • list.add(new Person("Jack"));
  • list.add(new Person("Tom"));
  • list.add(new Person("Marry"));
  • application.setAttribute("list", list);
  • Map<String, Person> map = new HashMap<String, Person>();
  • map.put("1", new Person("Tom"));
  • map.put("Jack", new Person("Jack"));
  • map.put("Marry", new Person("Marry"));
  • request.setAttribute("map", map);
  • %>
  • <c:forEach items="${list}" var="person" begin="0" end="2" step="1">
  • ${person.name }
  • </c:forEach>
  • <c:forEach items="${map}" var="entry" begin="0" end="2" step="1"> <%-- 遍历Map类对象先转换为EntrySet再遍历 --%>
  • ${entry.key } ${entry.value.name }<br>
  • </c:forEach>

9.4. URL标签

  • <c:import><c:import url=""/><jsp:include page=""/>都是动态加载,但是import更灵活,可以加载Web App范围外的url。

  • <c:redirect>:用于重定向到某个URL。语法格式:

  • <c:redirect url="value" [context="context"]/>
  • <c:url>:用于产生一个链接。语法格式:
  • <c:url value=""[context=""] [var=""] [scope=""] />

9.5. 国际化标签库

  • <fmt:formatDate>:日期格式化。语法格式:
  • <fmt:formatDate value="<%=new Date() %>" pattern="yyyy年MM月dd日HH点mm分ss秒"/>
  • <fmt:formatNumber>:数字格式化。语法格式:
  • <%-- 小数点保留四位 --%>
  • <fmt:formatNumber value="${5/3 }" pattern=".0000"/>

9.6. 数据库标签库

  • <sql:setDataSource>:准备数据库。对于没有默认数据库的JSP页面,该标签能准备一个数据库以供使用。语法格式:
  • <%-- var代表数据库的变量名在稍后的查询将会用到 --%>
  • <sql:setDataSource var="demo" driver="com.mysql.jdbc.Driver" url="jdbc:mysql://localhost:3306/db"
  • user="root" password="admin" />
  • <sql:query>:查询数据库。在连接了数据库后,即可使用该标签执行SQL语句查询数据库。查询后的结果集存在rs中,然后用<c:forEach>标签遍历结果集的每一行记录。语法格式:
  • <%-- 查询数据 --%>
  • <sql:query var="rs" dataSource="${demo}">
  • SELECT * FROM info
  • </sql:query>
  • <%-- 遍历显示数据 --%>
  • <table>
  • <c:forEach items="${rs.rows}" var="row" varStatus="s">
  • <tr>
  • <td>${s.index}</td>
  • <td>${row.name}</td>
  • <td>${row.age}</td>
  • </tr>
  • </c:forEach>
  • </table>

也可以将Body中的sql语句写到标签里面。

  • <%-- 更新数据库 --%>
  • <sql:query var="rs" dataSource="${demo}" sql="SELECT * FROM info">
  • <sql:update>:更新数据库。语法格式1:
  • <sql:update var="update" sql="" dataSource="${demo}"/>

或者语法格式2:

  • <sql:update var="update" dataSource="${demo}">
  • UPDATE info SET age=? where name=?
  • <sql:param value="1"/>
  • <sql:param value="xxx"/>