JSP(Java Server Page)基础
Servlet和JSP的相同点
JSP和Servlet从本质上,是相同的技术.
继承结构如下:
接口源代码
public interface JspPage extends Servlet {
public void jspInit();
public void jspDestroy();
}
public interface HttpJspPage extends JspPage {
public void _jspService(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException;
}
Servlet是一个特殊的Java程序,它运行于服务器的JVM中,能够依靠服务器的支持向浏览器提供显示内容。JSP本质上是Servlet的一种简易形式,JSP会被服务器处理成一个类似于Servlet的Java程序,可以简化页面内容的生成。
Servlet和JSP最主要的不同点
Servlet的应用逻辑是在Java文件中,并且完全从视图层中的HTML分离开来。而JSP是Java和HTML组合成一个扩展名为.jsp的文件。JSP侧重于视图,Servlet更侧重于控制逻辑,在MVC架构模式中,JSP适合充当视图(view)而Servlet适合充当控制器(Controller)。
JSP的执行流程
Servlet/JSP容器首先将JSP页面转换成一个JSP页面的实现类,这是一个实现了JspPage接口或其子接口HttpJspPage的Java类。JspPage接口是Servlet的子接口,因此每个JSP页面都是一个Servlet。转换成功后,容器会编译Servlet类,之后容器加载和实例化Java字节码,并执行它通常对Servlet所做的生命周期操作。对同一个JSP页面的后续请求,容器会查看这个JSP页面是否被修改过,如果修改过就会重新转换并重新编译并执行。如果没有则执行内存中已经存在的Servlet实例。
例子
JSP页面:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<%= new Date()%>
<%!
int anInt = 20180713;
%>
<%
out.print("2018年07月13日");
%>
</body>
</html>
该JSP页面会被容器编译为以下内容,其本质就是Servlet,简化了开发者对视图的开发,避免硬编码.
/*
* Generated by the Jasper component of Apache Tomcat
* Version: Apache Tomcat/7.0.86
* Generated at: 2018-07-13 07:43:45 UTC
* Note: The last modified time of this file was set to
* the last modified time of the source file after
* generation to assist with modification tracking.
*/
package org.apache.jsp;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;
import java.util.Date;
public final class index_jsp extends org.apache.jasper.runtime.HttpJspBase
implements org.apache.jasper.runtime.JspSourceDependent {
// 声明标签内的内容的生成位置
int anInt = 20180713;
private static final javax.servlet.jsp.JspFactory _jspxFactory =
javax.servlet.jsp.JspFactory.getDefaultFactory();
private static java.util.Map<java.lang.String,java.lang.Long> _jspx_dependants;
private volatile javax.el.ExpressionFactory _el_expressionfactory;
private volatile org.apache.tomcat.InstanceManager _jsp_instancemanager;
public java.util.Map<java.lang.String,java.lang.Long> getDependants() {
return _jspx_dependants;
}
public javax.el.ExpressionFactory _jsp_getExpressionFactory() {
if (_el_expressionfactory == null) {
synchronized (this) {
if (_el_expressionfactory == null) {
_el_expressionfactory = _jspxFactory.getJspApplicationContext(getServletConfig().getServletContext()).getExpressionFactory();
}
}
}
return _el_expressionfactory;
}
public org.apache.tomcat.InstanceManager _jsp_getInstanceManager() {
if (_jsp_instancemanager == null) {
synchronized (this) {
if (_jsp_instancemanager == null) {
_jsp_instancemanager = org.apache.jasper.runtime.InstanceManagerFactory.getInstanceManager(getServletConfig());
}
}
}
return _jsp_instancemanager;
}
public void _jspInit() {
}
public void _jspDestroy() {
}
public void _jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response)
throws java.io.IOException, javax.servlet.ServletException {
// JSP 内置对象
final javax.servlet.jsp.PageContext pageContext;
javax.servlet.http.HttpSession session = null;
final javax.servlet.ServletContext application;
final javax.servlet.ServletConfig config;
javax.servlet.jsp.JspWriter out = null;
final java.lang.Object page = this;
javax.servlet.jsp.JspWriter _jspx_out = null;
javax.servlet.jsp.PageContext _jspx_page_context = null;
try {
response.setContentType("text/html;charset=UTF-8");
pageContext = _jspxFactory.getPageContext(this, request, response,
null, true, 8192, true);
_jspx_page_context = pageContext;
application = pageContext.getServletContext();
config = pageContext.getServletConfig();
session = pageContext.getSession();
out = pageContext.getOut();
_jspx_out = out;
out.write("\n");
out.write("\n");
out.write("<html>\n");
out.write("<head>\n");
out.write(" <title>Title</title>\n");
out.write("</head>\n");
out.write("<body>\n");
// 赋值标签内的内容生成位置
out.print( new Date());
out.write('\n');
out.write('\n');
out.write('\n');
out.write('\n');
// 脚本标签内的内容生成位置
Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
out.println(sdf.format(date));
out.write("\n");
out.write("</body>\n");
out.write("</html>\n");
} catch (java.lang.Throwable t) {
if (!(t instanceof javax.servlet.jsp.SkipPageException)){
out = _jspx_out;
if (out != null && out.getBufferSize() != 0)
try {
if (response.isCommitted()) {
out.flush();
} else {
out.clearBuffer();
}
} catch (java.io.IOException e) {}
if (_jspx_page_context != null) _jspx_page_context.handlePageException(t);
else throw new ServletException(t);
}
} finally {
_jspxFactory.releasePageContext(_jspx_page_context);
}
}
}
JSP的三种原始标签
声明标签
<%!
int anInt = 20180713;
%>
根据上面JSP文件编译的结果,可知在声明标签中所编写的代码,最终是类的成员变量.
脚本标签
<%
Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
out.println(sdf.format(date));
%>
根据上面JSP文件编译的结果,可知在脚本标签中所编写的代码,最终会在类的_jspService(..)的方法体中出现
赋值标签
<%= new Date() %>
根据上面JSP文件编译的结果,可知在赋值标签中所编写的代码,最终会成为字符输出流的方法参数.
JSP的常用指令标签
- <%@ page %>
- language属性 指定当前页面的语言,目前只支持java
- import属性:导入包
- contentType属性: 设置JSP的响应类型,该属性中的值最终会被填充到response.setContentType(..)方法
- pageEncoding属性:当前页面从字符到字节用什么字符集转换.如果响应类型是text/html,并且contentType中没有指定字符集,则会在_jspService(..)方法中的response.setContentType(..)方法中默认使用该参数.
- sesssion属性:可选值true/false.如果true,访问当前JSP页面就会创建一个Session;如果false,反之则不创建.
- errorPage属性: 当前页面发生异常后跳转到指定的错误页面
- isErrorPage属性:只能在errorPage页面使用,可选值true/false.如果true,则当前页面可以获取到exception对象并且输出.
- <%@ include %>
JSP的9个内置对象
内置对象不用开发者手动创建,可以直接使用
查看上面JSP编译后的代码中的_jspService方法,参数是request和response,方法体里创建了其余的6个内置对象.由于page指令标签中没有isErrorPage=”true”,所以exception对象没有创建.
JSP | Servlet |
---|---|
request | HttpServletRequest |
response | HttpServletResponse |
application | ServletContext |
session | HttpSession(该对象是否创建取决于page指令标签中的session属性,若true则自动创建,若false,反之) |
config | ServletConfig |
out | PrintWriter的兄弟类JspWriter |
exception | Throwable(该对象是否创建取决于page指令标签中的isErrorPage属性,若true则创建.若false,反之) |
page | |
pageContext |
请求转发和重定向的区别
请求转发 | 重定向 |
---|---|
服务器端完成 | 客户端完成 |
速度快 | 速度慢 |
一次请求和一次响应的过程 | 两次请求和两次响应的过程 |
浏览器地址栏不改变 | 浏览器地址栏要改变 |
可以利用request对象来传递数据 | 不能使用request对象传递数据 |
只能是在同一个服务器下完成 | 可以在不同的服务器间完成 |
JSTL和EL表达式
参考该博客
JSTL 表达式与 EL 语言