1. JSP简介
JSP: Java Service Pages,Java服务器端页面和Servlet一样,JSP本质也是Servlet,用于动态Web技术,JSP标签在HTML网页中嵌入Java代码类似于早些年的ASP。但是对比ASP有了很大的语法简化。
JSP的优势
-
对比HTML:HTML只给用户提供静态的数据,JSP可以动态获取数据进行展示
-
对比ASP:在HTML中嵌入了VB的脚本,页面极其混乱,维护性差。
-
对比Servlet :JSP可以很方便的编写或者修改HTML网页而不用去面对大量的write / printlnln语句。在JSP的编译成的.class文件中,JSP依旧是转为了Servlet,但是这些转换是服务器做的。
JSP的劣势
前后端没有进行分离,而且现在已经提倡前后端分离,JSP也在慢慢退出企业级的开发,但是这并不影响学习JSP这个技术栈为后期的框架打下一个好基础。
2. JSP原理
JSP本质是Servlet,而Servlet本质也是Java代码,所以可以在Tomcat的工作区找到 jsp 编译成的Java代码。
查看JSP编译成的Java类:"C:\Users\用户\AppData\Local\JetBrains\IntelliJIdea2020.1\tomcat\项目\work\Catalina\localhost\hello\org\apache\jsp"这里可以看到两个文件,一个是.class一个是.java。
打开.class可以看到一个完整的代码,由于很多代码是不需要分析或者分析意义不大的,最后可以删减成下面。
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;
public final class index_jsp extends org.apache.jasper.runtime.HttpJspBase
implements org.apache.jasper.runtime.JspSourceDependent,
org.apache.jasper.runtime.JspSourceImports {
//对比Servlet接口及其的相似
public void _jspInit() { //JSP的初始化
}
public void _jspDestroy() { //摧毁
}
//JSP的Service 基本上就是一个Servlet的Service
public void _jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response)
throws java.io.IOException, javax.servlet.ServletException {
final javax.servlet.jsp.PageContext pageContext; //网页上下文
javax.servlet.http.HttpSession session = null; //session 会话
final javax.servlet.ServletContext application; //application 本质是ServletContext上下文对象
final javax.servlet.ServletConfig config; //ServletConfig 配置
javax.servlet.jsp.JspWriter out = null; //网页输出流对象
final java.lang.Object page = this; //当前网页
HttpServletRequest //请求
HttpServletResponse //响应
javax.servlet.jsp.JspWriter _jspx_out = null;
javax.servlet.jsp.PageContext _jspx_page_context = null;
try {
response.setContentType("text/html"); //设置响应格式
pageContext = _jspxFactory.getPageContext(this, request, response,
null, true, 8192, true); //网页上下文
_jspx_page_context = pageContext;
application = pageContext.getServletContext(); //Servlet上下文
config = pageContext.getServletConfig(); //配置
session = pageContext.getSession();
out = pageContext.getOut(); //输出
_jspx_out = out;
//在基础的JSP文件中就是一个html被转换成用Java流输出了。
out.write("<html>\n");
out.write("<body>\n");
out.write("<h2>Hello World!</h2>\n");
out.write("</body>\n");
out.write("</html>\n");
} catch (java.lang.Throwable t) {
} finally {
}
}
}
当服务器第一次收到请求一个JSP页面的时候会将这个页面进行如下的转化,之后再次访问无论是不是同一个用户访问都会直接读取编译完成生成的字节码文件。只要不重新发布重新编写就不会进行二次转换编译。
3. JSP基础语法
<%%> //JSP嵌入Java代码段 注意冲突域
<%=%> //JSP变量/表达式输出到网页
<%!%> //JSP声明
<%----%> //JSP注释
- JSP表达式:<%=变量 / 表达式%>用来将变量或者表达式输出到客户端。
<%= new java.util.Date()%> new一个Date类并且写入到网页中
- JSP代码片段:<%%>可以将任何一段语法正确的Java代码嵌入到JSP中,所有的<%%>都是属于同一个Java代码域,经过编译后都会放在_jspService方法中因此需要注意变量的作用域。并且代码段中是不允许定义方法的。
<%
int sum = 0;
for(int i = 0;i <= 100;i++){
sum += i;
}
out.println("sum = " + sum);
%>
<%
int sum = 0; //与上面的int sum = 0冲突,变量重复定义页面500错误
%>
- JSP嵌入HTML标签
<%for(int i = 0;i < 5;i++){%>
<h1>Hello World! <%=i%> </h1>
<%}%>
- JSP声明:<%!%>声明的代码会供全局使用,不会在_jspService方法当中生成。声明的代码在任意的表达式中都能取到,没有先后顺序。即使在最后面声明,在第一行依然能取到。因为声明的变量是一个Servlet静态全局变量,只有最开始访问的时候才会初始化一次。之后访问再也不初始化。多个用户访问也是使用同一个变量。而声明中定义的方法是一个page页面的方法,供这个页面使用。
<%!
static { //最先加载
System.out.println("this is static block");
}
private int globalvar = 100;
public int getGlobalvar(){
System.out.println("globalvar = " +globalvar);
return globalvar;
}
%>
web服务器请求jsp生成的.java文件编译后的样子。
4. 页面错误处理
- 使用JSP标签声明错误请求页面:当发生错误时会通过<%@ page errorPage=“error/500.jsp” %>请求这个页面。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page import="java.util.*" %> <%-- 导入Java的包--%>
<%@ page errorPage="error/500.jsp" %> <%-- 出现错误请求的页面--%>
<%--<%@page isErrorPage="true" %> 显示声明为一个错误页面--%>
<html>
<head>
<title>Title</title>
</head>
<body>
<%
int x = 1 / 0; //算术运算异常错误
out.write("没有发生错误, 不会请求错误页面");
%>
</body>
</html>
- 使用Web.xml配置文件手动配置错误页面,可以定制固定错误代码请求的页面。
<!-- 手动定制错误页面 -->
<error-page>
<error-code>404</error-code>
<location>/error/404.jsp</location>
</error-page>
<error-page>
<error-code>500</error-code>
<location>/error/500.jsp</location>
</error-page>