目录

  • ​​目录​​
  • ​​介绍​​
  • ​​JSP运行原理​​
  • ​​JSP最佳实践​​
  • ​JSP指令​
  • ​​page指令​​
  • ​​include指令​​
  • ​​taglib指令​​
  • ​JSP九大内置对象​
  • ​​out隐式对象​​
  • ​​pageContext隐式对象​​
  • ​​JSP标签​​
  • ​​映射JSP​​
  • ​​知识点​​
  • ​JSP与JavaBean​
  • ​​关于JavaBean的JSP标签​​
  • ​​JSP+JavaBean开发模式​​


介绍

  JSP全称是Java Server Pages,它和Servlet技术一样,都是SUN公司定义的一种用于开发动态Web页面(资源)的技术。
  JSP技术允许在页面中编写Java代码,并且允许开发人员在页面中获取request、response等Web开发常用对象,实现与浏览器的交互,所以JSP也是一种动态Web资源的开发技术。

JSP运行原理

  每个JSP页面在第一次被访问时,Web容器都会把请求交给JSP引擎(即一个Java程序)去处理。JSP引擎先将JSP翻译成一个_jspServlet(实质上也是一个Servlet),然后按照Servlet的调用方式进行调用。(翻译后的Servlet保存在Tomcat的work目录,如:​​H:\MySoftware\Tomcat\apache-tomcat-9.0.0.M4\work\Catalina\localhost\JavaWeb\org\apache\jsp​​​)
  由于JSP第一次访问时会翻译成Servlet,所以第一次访问通常会比较慢,但第二次访问,JSP引擎如果发现JSP没有变化,就不再翻译,而是直接调用,所有程序的执行效率不会受到影响。

JSP最佳实践

  不管是JSP还是Servlet,虽然都可以用于开发动态Web资源。但由于这两门技术各自的特点,在长期的软件实践中,人们逐渐把Servlet作为Web应用中的控制器组件来使用,而把JSP技术作为数据显示模板来使用。
  根据这两门技术的特点,让它们各自负责各的,Servlet只负责响应请求产生数据,并把数据通过转发技术带给JSP,由JSP来进行数据的显示。

JSP指令

page指令

  1. JSP中Page指令的errorPage属性用于设置JSP页面出错时显示的页面内容,errorPage属性的设置值必须使用相对路径,如果以“/”开头,表示相对于当前Web应用程序的根目录(注意不是站点根目录)。
  2. 可以在web.xml文件中使用​​<error-page>​​​元素为整个Web应用程序设置错误处理页面,其中的​​<exception-type>​​​子元素指定异常的完全限定名,​​<location>​​元素指定以“/”开头的错误处理页面的路径。如:
<error-page>
<exception-type>java.lang.ArithmeticException</exception-type>
<location>/errors/error.jsp</location>
</error-page>

 
3. 如果设置了某个页面的Page指令的errorPage属性,那么在web.xml文件中设置的错误处理将不对该页面起作用。
4. 服务器抛404时显示的页面设置:(在web.xml中设置)

<error-page>
<error-code>404</error-code>
<location>/errors/404.jsp</location>
</error-page>

include指令

  include指令,通过该指令可以在一个JSP页面中包含另一个JSP页面。不过该指令是静态包含,也就是说被包含文件中所有内容会被原样包含到该JSP页面中,即使被包含文件中有JSP代码,在包含时也不会被编译执行。
include指令为静态包含(编译时包含),它包含的所有JSP页面都只会同原来的JSP页面编译成一个servlet。语法:

<%@ include file="relativeURL"%>

  其中的file属性用于指定被引入文件的路径。路径以“/”开头,表示代表当前Web应用。
  被引入的文件可以使用任意的扩展名,即使其扩展名是html,JSP引擎也会按照处理JSP页面的方式处理它里面的内容,为了见名知意,JSP规范建议使用.jspf(JSP fragments)作为静态引入文件的扩展名。
  被引入的JSP页面的指令不能冲突(除了pageEncoding和导包除外)。
  
  示例:
index.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ include file="/public/header.jsp"%>
<h4>页面主体内容...</h4>
<%
// 注释
out.write("测试中文输出");
%>
<%@ include file="/public/footer.jsp"%>

被包含页面:header.jsp、footer.jsp(这里以.jspf后缀更好)
header.jsp

<%@ page import="java.util.Date" contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Header</title>
</head>
<body>
<p><%=new Date().toLocaleString()%></p>

footer.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<p>这是页脚</p>
</body>
</html>

  动态包含(运行时包含):包含过程中,所涉及到的所有JSP页面都将对应单独编译成一个servlet。
  示例:
  index.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
request.getRequestDispatcher("/public/header.jsp").include(request, response);
%>
<h4>页面主体内容...</h4>
<%
// 注释
response.getWriter().write("测试中文输出");
%>
<%
request.getRequestDispatcher("/public/footer.jsp").include(request, response);
%>

  此外,静态包含比动态包含的效率要好。

taglib指令

  taglib指令,用于在JSP页面中导入标签库。

JSP九大内置对象

  JSP引擎在调用JSP对应的_jspServlet时,会传递或创建9个与Web开发相关的对象供_jspServlet使用。JSP技术的设计者为便于开发人员在编写JSP页面时获得这些Web对象的引用,特意定义了9个相应变量。
  JSP中的内置对象 request、response、session、application、config、page、exception、out、pageContext。

out隐式对象

  • out隐式对象用于向客户端发送文本数据。
  • out对象是通过调用pageContext对象的getOut方法返回的,其作用和用法与ServletResponse.getWriter方法返回的PrintWriter对象非常相似。
  • JSP页面中的out隐式对象的类型为JspWriter,JspWriter相当于一种带缓存功能的PrintWriter,设置JSP页面的page指令的buffer属性可以调整它的缓存大小,甚至关闭它的缓存。
  • 只有向out对象中写入了内容,且满足如下任何一个条件时,out对象才去调用ServletResponse.getWriter方法,并通过该方法返回的PrintWriter对象将out对象的缓冲区中的内容真正写入到Servlet引擎提供的缓冲区中:
  • 设置page指令的buffer属性关闭out对象的缓存功能;
  • out对象的缓冲区满;
  • 整个JSP页面结束

pageContext隐式对象

  pageContext对象,代表JSP页面的运行环境,封装了对其他8大隐式对象的引用。

getException方法 返回exception隐式对象
getPage方法 返回page隐式对象
getRequest方法 返回request隐式对象
getResponse方法 返回response隐式对象
getServletConfig方法 返回config隐式对象
getServletContext方法 返回application隐式对象
getSession方法 返回session隐式对象
getOut方法 返回out隐式对象

  pageContext对象也是一个域对象(拥有getAttribute和setAttribute方法),作用于页面范围,即page域,不同页面不能共享pageContext中存储的数据。
  pageContext对象中包含findAttribute方法,用于查找各个域中的属性。findAttribute方法的查找顺序为page域(PageContext对象)、request域、session域、application域(ServletContext对象)。(由小到大)如:

<%
pageContext.findAttribute("data");
%>

  相当于EL表达式中的

${data}

  pageContext还拥有forward和include方法用来分别简化和替代RequestDispatcher.forward方法和include方法。方法接收的参数为资源的路径,如果以“/”开头,“/”代表当前Web应用。

JSP标签

  JSP标签也称之为Jsp Action(JSP动作)元素,它用于在JSP页面中提供业务逻辑功能,避免在JSP页面中直接编写Java代码,造成JSP页面难以维护。
  JSP常用标签:
- ​​​<jsp:include>​​标签

<jsp:include page="/1.jsp"></jsp:include>

  相当于(属于动态包含)

pageContext.include("/1.jsp");
  • ​<jsp:forward>​​标签
<jsp:forward page="/1.jsp"></jsp:forward>
  • ​<jsp:param>​​​标签
      示例:
      param.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>JSP常用标签</title>
</head>
<body>
<jsp:forward page="/ServletDemo1">
<jsp:param name="username" value="DreamBoy"/>
<jsp:param name="password" value="123456"/>
</jsp:forward>
</body>
</html>

  ServletDemo1.java

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
* Created by DreamBoy on 2017/5/9.
*/
@WebServlet(name = "ServletDemo1", urlPatterns = {"/ServletDemo1"})
public class ServletDemo1 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String username = request.getParameter("username");
String password = request.getParameter("password");
System.out.println(username);
System.out.println(password);
}
}

映射JSP

  在web.xml中配置jsp页面映射的URL路径(别忘了访问JSP实际上就是访问JSP编译后的Servlet):

<servlet>
<servlet-name>ServletDemo1</servlet-name>
<jsp-file>/index.jsp</jsp-file>
</servlet>
<servlet-mapping>
<servlet-name>ServletDemo1</servlet-name>
<url-pattern>/index.html</url-pattern>
</serlvet-mapping>

知识点

  1. JSP说白了就是Servlet。运行过程中服务器会将JSP编译对应的Servlet。
  2. JSP中的内置对象 request、response、session、application、config、page、exception、out、pageContext。
  3. JSP页面中编写的所有代码,默认会翻译到Servlet的service方法中,而JSP声明中Java代码被翻译到_jspService方法的外面。语法为:
<%!
// Java代码
%>

  JSP声明可用于定义JSP页面转换成Servlet程序的静态代码块、成员变量和方法。
  多个静态代码块、变量和函数可以定义在一个JSP声明中,也可以分别单独定义在多个JSP声明中。
  我们可以理解为在Servlet中定义了一些属性。
4. JSP隐式对象的作用范围仅限于Servlet的_jspService方法,所以在JSP声明中不能使用这些隐式对象(JSP九大内置对象)

JSP与JavaBean

  JavaBean是一个遵循特定写法的Java类,它通常具有如下特点:
- 该Java类必须具有一个无参的构造函数
- 属性必须私有化
- 私有化的属性提供public访问权限的get、set方法暴露给其他程序
  JavaBean的属性可以是任意类型,并且一个JavaBean可以有多个属性。每个属性通常都需要具有相应的​​​getter​​​、​​setter​​​方法。其中​​getter​​​方法称为属性访问器;​​setter​​​方法称为属性修改器。
  一个JavaBean的某个属性也可以只有set方法或get方法,这样的属性通常也称之为只写、只读属性。
  示例:
Person.java

package com.wm103.domain;
import java.util.Date;
/**
* Created by DreamBoy on 2017/5/9.
*/
public class Person {
private String name;
private int age;

public Date getBirthday() {
return birthday;
}

public void setBirthday(Date birthday) {
this.birthday = birthday;
}

private Date birthday;
public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public int getAge() {
return age;
}

public void setAge(int age) {
this.age = age;
}
}

关于JavaBean的JSP标签

  • ​<jsp:useBean>​​标签:用于在指定的域范围内(默认page域,即pageContext)查找指定名称的JavaBean对象。如果存在则直接返回该JavaBean对象的引用。如果不存在则实例化一个新的JavaBean对象并将它以指定的名称存储到指定的域范围中。
<jsp:useBean id="person" class="com.wm103.domain.Person" scope="page"></jsp:useBean>

  其中scope属性的取值只能为page、request、session和application等四个值中的一个,其默认值是page。

  • ​<jsp:setProperty>​​标签:用于在JSP页面中设置一个JavaBean组件的属性。
  • ​<jsp:getProperty>​​​标签:用于在JSP页面中获取一个JavaBean组件的属性。
    读取JavaBean对象的属性,也就是调用JavaBean对象的getter方法,然后将读取的属性值转换成字符串后插入进输出的相应正文中。
    如果一个JavaBean实例对象的某个属性的值为null,那么,使用<jsp:getProperty>标签输出该属性的结果将是一个内容为“null”的字符串。
      示例:
<%--
Created by IntelliJ IDEA.
User: DreamBoy
Date: 2017/5/9
Time: 10:46
To change this template use File | Settings | File Templates.
--%>
<%@ page import="java.util.Date" contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>jsp:setProperty标签的使用</title>
</head>
<body>
<p>
请求
<pre>
http://localhost:8080/day09/2.jsp?name=xiaoxiao&age=18
</pre>
</p>

<jsp:useBean id="person" class="com.wm103.domain.Person"/>

<!-- 手工为bean属性赋值 -->
<jsp:setProperty name="person" property="name" value="DreamBoy"/>
<h4>手工为bean属性赋值</h4>
<p><%=person.getName()%></p>

<!-- 用请求参数给bean属性赋值 -->
<jsp:setProperty name="person" property="name" param="name"/>
<jsp:setProperty name="person" property="age" param="age"/> <!-- 支持8种基本数据类型的转换(把客户机提交的字符串,转成相应的8种基本数据类型,赋值到bean的属性上 -->
<jsp:setProperty name="person" property="birthday" value="<%=new Date()%>"/>
<h4>用请求参数给bean属性赋值</h4>
<p><%=person.getName()%></p>
<p><%=person.getAge()%></p>
<p><%=person.getBirthday()%></p>

<!-- 用所有的请求参数为bean赋值 -->
<jsp:setProperty name="person" property="*"/>
<h4>用所有的请求参数为bean赋值</h4>
<p><%=person.getName()%></p>
<p><%=person.getAge()%></p>

<!-- 获取bean的属性 -->
<jsp:getProperty name="person" property="name"/>
<jsp:getProperty name="person" property="age"/>
</body>
</html>

JSP+JavaBean开发模式

  实现计算器案例:
  JavaBean CalculatorBean.java

package com.wm103.domain;

/**
* Created by DreamBoy on 2017/5/9.
*/

import java.math.BigDecimal;

/**
* 封装计算器数据的Bean
*/
public class CalculatorBean {
private String firstNum;
private char operator;
private String secondNum;
private String result;

public String getFirstNum() {
return firstNum;
}

public void setFirstNum(String firstNum) {
this.firstNum = firstNum;
}

public char getOperator() {
return operator;
}

public void setOperator(char operator) {
this.operator = operator;
}

public String getSecondNum() {
return secondNum;
}

public void setSecondNum(String secondNum) {
this.secondNum = secondNum;
}

public String getResult() {
return result;
}

public void setResult(String result) {
this.result = result;
}

public void calculate() {
if(this.firstNum == null || this.secondNum == null) {
return;
}

BigDecimal first = new BigDecimal(this.firstNum);
BigDecimal second = new BigDecimal(this.secondNum);
switch (this.operator) {
case '+':
this.result = first.add(second).toString();
break;
case '-':
this.result = first.subtract(second).toString();
break;
case '*':
this.result = first.multiply(second).toString();
break;
case '/':
if(second.doubleValue() == 0) {
throw new RuntimeException("被除数不能为0!");
}
this.result = first.divide(second, 2, BigDecimal.ROUND_HALF_UP).toString();
break;
default:
throw new RuntimeException("该运算符不存在!");
}
}
}

  calculator.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! -->
<title>计算器</title>

<!-- Bootstrap -->
<link href="./public/assets/bootstrap-3.3.7/css/bootstrap.min.css" rel="stylesheet">

<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
<!--[if lt IE 9]>
<script src="https://cdn.bootcss.com/html5shiv/3.7.3/html5shiv.min.js"></script>
<script src="https://cdn.bootcss.com/respond.js/1.4.2/respond.min.js"></script>
<![endif]-->
</head>
<body>
<div class="container">
<div style="padding: 50px 20px;" data-example-id="table-within-panel">
<div class="panel panel-primary">
<!-- Default panel contents -->
<div class="panel-heading">
<h3>简易计算器</h3>
</div>

<jsp:useBean id="calculatorBean" class="com.wm103.domain.CalculatorBean"/>
<jsp:setProperty name="calculatorBean" property="*"/>

<div class="panel-body">
<%
try {
calculatorBean.calculate();
} catch (Exception e) {
out.write("<h4>" + e.getMessage() + "</h4>");
}
%>

<%
if (calculatorBean.getResult() != null) {
%>
<h3>
计算结果是:
<jsp:getProperty name="calculatorBean" property="firstNum"/>
<jsp:getProperty name="calculatorBean" property="operator"/>
<jsp:getProperty name="calculatorBean" property="secondNum"/>
=
<jsp:getProperty name="calculatorBean" property="result"/>
</h3>
<%
}
%>
</div>
<form action="calculator.jsp" method="post">
<!-- Table -->
<table class="table table-striped table-hover">
<tbody>
<tr>
<th scope="row">第一个参数</th>
<td><input type="text" class="form-control" name="firstNum" placeholder=""></td>
</tr>
<tr>
<th scope="row">运算符</th>
<td>
<select name="operator" class="form-control">
<option value="+">+</option>
<option value="-">-</option>
<option value="*">*</option>
<option value="/">/</option>
</select>
</td>
</tr>
<tr>
<th scope="row">第二个参数</th>
<td>
<input type="text" class="form-control" name="secondNum" placeholder="">
</td>
</tr>
<tr>
<td colspan="2">
<button type="submit" class="btn btn-info btn-block">提交</button>
</td>
</tr>
</tbody>
</table>
</form>
</div>
</div>
</div>

<!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
<script src="https://cdn.bootcss.com/jquery/1.12.4/jquery.min.js"></script>
<!-- Include all compiled plugins (below), or include individual files as needed -->
<script src="./public/assets/bootstrap-3.3.7/js/bootstrap.min.js"></script>
</body>
</html>

  运行效果:

  

JSP知识随手记_动态包含