文章目录
一、JSP底层原理
1.运行原理
我在idea新建了一个javaweb项目,然后在web文件夹里面会自动生成index.jsp文件,把里面的内容删了,也就是一个空白的jsp文件
启动tomcat,这时会自动生成一个文件夹
去到这个文件夹,找到jsp项目,发现里面什么都没有
然后在浏览器访问jsp,会发现文件夹多了两个文件,一个是java文件,一个是class文件,当我们再次访问的时候,不会生成对应文件。
总结:jsp的运行原理是,当我们第一次访问jsp的时候,这个index.jsp会被tomcat翻译生成index_jsp.java文件,然后tomcat服务器又将index_jsp.java编译生成index_jsp.class文件,然后执行。
2.底层实现
点开刚刚生成的index_jsp.java文件
发现index_jsp 类继承 HttpJspBase,而我们点开HttpJspBase文件
又发现,HttpJspBase类继承的是HttpServlet
总结:jsp的生命周期和Servlet的生命周期完全相同。所以可以理解index_jsp类就是一个Servlet类。与Servlet一样JSP是一个假单例,因为构造方法没有私有化,这个对象的创建Tomcat只创建了一个,导致了单例。
那么JSP和Servlet有什么不同:
- Servlet的职责:收集数据。(Servlet的强项是逻辑处理,业务处理,然后链接数据库,获取/收集数据。)
- JSP的职责:展示数据。(JSP的强项是做数据的展示)
第一次JSP文件是比较慢的,因为
- 要把jsp文件翻译生成java源文件
- java源文件要编译生成class字节码文件
- 然后通过class去创建servlet对象
- 然后调用servlet对象的init方法
- 最后调用servlet对象的service方法。
第二次就比较快,因为第二次直接调用Servlet对象的service即可。
二、什么是JSP?
JSP是java程序。(JSP本质还是一个Servlet),JavaServer Pages的缩写。(基于Java语言实现的服务器端的页面。)
JSP是一套规范。所有的web容器/web服务器都是遵循这套规范的,都是按照这套规范进行的“翻译”。
每一个web容器/web服务器都会内置一个JSP翻译引擎。
重点:所以当JSP进行错误调试的时候,要直接打开JSP文件对应的java文件,检查java代码。不要在JSP页面看半天
三、JSP的基础语法
1.直接编写文字
在jsp编写以下代码,然后浏览器访问
结果:
我们查看jsp的Java文件,看到jsp的Service里面多了以下几行代码。
总结:在JSP中编写的HTML CSS JS代码,这些代码对于JSP来说只是一个普通的字符串。会被翻译到类的service方法的out.write(),被java程序当做普通字符串打印输出到浏览器。
2.JSP中编写Java程序
(1)<%java程序%>
例如,在index.jsp文件编写一个打印hello jsp,浏览器访问
结果:
去查看jsp的Java代码发现,在out.write()外面出现了一句java语句
总结:当有<%%>的时候会被翻译到service方法的方法体里面,而不会被当作普通字符串处理。
注意:当编写的Java程序出现语法错误,也就是编译时的错误,访问的时候jsp也会翻译为java程序,但是编译不会通过,不会产生class文件,浏览器会报500错误。
(2)<%!java程序 %>
例如,编写以下代码,然后访问
结果:
总结:在这个符号当中编写的java程序会自动翻译到service方法之外,也就是在jsp类里面。
注意:这个语法很少用,因为在service方法外面写静态变量和实例变量,都会存在线程安全问题,因为JSP就是servlet,servlet是单例的,多线程并发的环境下,这个静态变量和实例变量一旦有修改操作,必然会存在线程安全问题。
(3)<%= %>
在index.jsp编写如下代码
然后访问,其结果为
并且在翻译的java程序为
总结:<%= %>翻译到service方法体内部,翻译为:out.print();
当输出的内容中含有java的变量,输出的内容是一个动态的内容,不是一个死的字符串,就可以使用这个语法。
3.JSP的专业注释
<%--JSP的专业注释,不会被翻译到java源代码当中。--%>
<!--这种注释属于HTML的注释,这个注释信息仍然会被翻译到java源代码当中,不建议使用。-->
4.JSP指令
指令的作用:指导JSP的翻译引擎如何工作(指导当前的JSP翻译引擎如何翻译JSP文件。)
指令包括哪些呢?
- include指令:包含指令,在JSP中完成静态包含,很少用了。
- taglib指令:引入标签库的指令。这个到JSTL标签库的时候再学习。现在先不管。
- page指令:目前重点学习一个page指令。
指令的使用语法:
<%@指令名 属性名=属性值 属性名=属性值 属性名=属性值....%>
include指令
include指令用于在编译阶段包括一个文件。这个指令告诉容器在编译阶段将其他外部文件的内容合并到当前JSP文件中。可在JSP页面的任何位置使用include指令进行编码。
主要用于一个页面包含多个公共页面
指令语法:
<%@ include file = "url" >//url是路径
为了更好的理解,写一个例子
index.jsp - 网站主页
header.jsp - 顶部菜单和公共内容
foot.jsp - 显示公共信息
index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>主页</title>
</head>
<body>
<%@include file="header.jsp"%>
<center>
<p>这是index.jsp页面的内容~</p>
<p>JSP是一套规范。所有的web容器/web服务器都是遵循这套规范的,都是按照这套规范进行的“翻译”。</p>
</center>
<%@include file="foot.jsp"%>
</body>
</html>
header.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>header</title>
</head>
<body>
<center>
<p>
<a href="index.jsp">首页</a> | <a href="header.jsp">页头</a> | <a href="foot.jsp">页尾</a>
</p>
</center>
</body>
</html>
foot.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>foot</title>
</head>
<body>
<%!int pageCount = 0;
void addCount() {
pageCount++;
}%>
<%
addCount();
%>
<center>
<p>联系我们:54864684@qq.com | 访问次数:<%=pageCount%></p>
</center>
</body>
</html>
结果:每次刷新都会增加访问次数
taglib指令
这个放在JSTL标签库的时候再学习
page指令
关于page指令的常用属性
<%@page session="true|false" %>
true表示启用JSP的内置对象session,表示一定启动session对象。没有session对象会创建。
如果没有设置,默认值就是session="true"
session="false" 表示不启动内置对象session。当前JSP页面中无法使用内置对象session。
<%@page contentType="响应内容类型" %>
contentType属性用来设置响应的内容类型
默认为response.setContentType("text/html");
但同时也可以设置字符集。
<%@page contentType="text/json;charset=UTF-8" %>
<%@page pageEncoding="字符类型" %>
pageEncoding="UTF-8" 表示设置响应时采用的字符集。与上面设置字符集作用一样
都是在response.setContentType("");里面加个charset=UTF-8
<%@page import="包" %>
import语句,导包。
<%@page errorPage="路径" %>
当前页面出现异常之后,跳转到“路径”页面。
errorPage属性用来指定出错之后的跳转位置。
<%@page isErrorPage="true|false" %>
表示启用JSP九大内置对象之一:exception
默认值是false。
<%@page isELIgnored="true|false" %>
isELIgnored="true" 表示忽略EL表达式
isELIgnored="false" 表示不忽略EL表达式。(这是默认值)
isELIgnored="true" 这个是全局的控制。
可以使用反斜杠进行局部控制:\${} 这样也可以忽略EL表达式。
四、JSP九大内置对象
-
jakarta.servlet.jsp.PageContext pageContext (页面作用域)
-
jakarta.servlet.http.HttpServletRequest request (请求作用域)
-
jakarta.servlet.http.HttpSession session (会话作用域)
-
jakarta.servlet.ServletContext application (应用作用域)
- pageContext < request < session < application
- 以上四个作用域都有:setAttribute、getAttribute、removeAttribute方法。
- 以上作用域的使用原则:尽可能使用小的域。
-
java.lang.Throwable exception
-
jakarta.servlet.ServletConfig config
-
java.lang.Object page (其实是this,当前的servlet对象)
-
jakarta.servlet.jsp.JspWriter out (负责输出)
-
jakarta.servlet.http.HttpServletResponse response (负责响应)