问题是这样的:在一个jsp页面怎么只刷新时间,而不把时间以外的其他部分不刷新。原始代码welcome.jsp大概是这样的:
<%@page import="java.text.SimpleDateFormat"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ page import="java.util.*" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Spring Boot JSP Example</title>
</head>
<body>
<h1>Hello, Spring Boot JSP!</h1>
<%
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String date = sdf.format(new Date());
out.println(date);
response.setHeader("refresh", "1");
%>
<p>
欢迎您,svygh123
</p>
<a href="logout.jsp">注销</a>
</body>
</html>
因为代码有了refresh,1,代表了1秒后自动刷新页面,这种页面全局刷新,其实html也有方法实现,就是在header标签下加上以下代码:
<meta http-equiv="refresh" content="1">
而且还可以在后面加上目标页面的地址,就是自动跳转,不加就是刷新本页
response.setHeader("refresh", "1;welcome2.jsp");
<meta http-equiv="refresh" content="1;welcome2.jsp">
要做到局部刷新有2种方法:
第一种方法是用ajax(Asynchronous JavaScript and XML),即异步JavaScript和XML,是一种用于创建更好更快以及交互性更强的Web应用程序的技术。
把打印时间的代码抽离放到一个jsp页面,当做服务端:getServerTime.jsp
<%@page import="java.util.Date"%>
<%@page import="java.text.SimpleDateFormat"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>获取服务器时间</title>
</head>
<body>
<%
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String date = sdf.format(new Date());
out.println(date);
%>
</body>
</html>
而welcome.jsp则改为ajax访问:
<%@page import="java.util.Date"%>
<%@page import="java.text.SimpleDateFormat"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>欢迎页</title>
</head>
<body>
<!-- 用一个div显示当前时间 -->
<div id="nowDiv"></div>
<p>
欢迎您,svygh123
</p>
<a href="logout.jsp">注销</a>
<script type="text/javascript">
function getServerTime() {
var xhr;
if (window.XMLHttpRequest) {
// IE7+, Firefox, Chrome, Opera, Safari 浏览器执行代码
xhr = new XMLHttpRequest();
} else {
// IE6, IE5 浏览器执行代码
xhr = new ActiveXObject("Microsoft.XMLHTTP");
}
xhr.onreadystatechange = function() {
if (xhr.readyState == 4 && xhr.status == 200) {
document.getElementById("nowDiv").innerHTML = xhr.responseText;
}
}
xmlhttp.open("GET","getServerTime.jsp",true);
xmlhttp.send();
}
// 每秒发送一次请求
setInterval(() => {
getServerTime();
}, 1000);
</script>
</body>
</html>
第二种方法则是将时间显示区域改成iframe,然后刷新iframe:
<%@page import="java.util.Date"%>
<%@page import="java.text.SimpleDateFormat"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>欢迎页</title>
</head>
<body>
<iframe id="iframe_id" src="getServerTime.jsp" width="300" height="40" frameborder="0" style="border:none;"></iframe>
<p>
欢迎您,svygh123
</p>
<a href="logout.jsp">注销</a>
<script type="text/javascript">
// 获取iframe元素
var iframe = document.getElementById("iframe_id");
// 创建一个定时器函数,让iframe每秒刷新一次
function refreshIFrame() {
// 刷新iframe的内容
iframe.contentWindow.location.reload();
// 设置定时器,一秒后再次调用刷新函数
setTimeout(refreshIFrame, 1000);
}
// 首次启动定时刷新
refreshIFrame();
</script>
</body>
</html>
不过这种方法也会有很明显的刷新痕迹,因此体验最好的还是使用ajax 。
今天的重点是JSP(Java Server Pages),从名字就能理解:java服务器页面。而最终也是这么做的:
核心原理是将HTML、CSS、JavaScript与Java代码混合的JSP页面在运行时转换成Java Servlet,然后执行Servlet来动态生成HTML内容返回给客户端浏览器
以下是JSP的编译过程和原理概述:
JSP编译过程:
-
客户端请求:
- 用户通过浏览器发起对JSP页面的请求。
-
预处理阶段:
- 当Web服务器接收到对JSP页面的第一次请求时,JSP引擎开始工作。
- JSP引擎读取JSP文件的内容,并对其进行解析。
- 解析过程中,将JSP页面中的静态内容(HTML、CSS、JavaScript等)和动态内容(Java代码片段、JSP标签等)分离出来。
- 动态内容会被翻译成Java代码,比如JSP表达式会被转换成
out.println()
方法的调用,JSP脚本元素和声明会被转换为Servlet类的方法体。
-
编译阶段:
- JSP引擎将预处理阶段生成的Java源代码编译成一个Java Servlet类。
- 编译后的Servlet类通常会继承自
javax.servlet.http.HttpServlet
或者专门针对JSP设计的基类(如org.apache.jasper.runtime.HttpJspBase
)。 - 编译得到的Servlet类文件(
.java
)随后被编译器编译成字节码文件(.class
)。
-
加载和执行阶段:
- Web容器(如Tomcat)加载编译好的Servlet类,并实例化该类的对象。
- 当再次收到对该JSP页面的请求时,Web容器调用Servlet对象的生命周期方法(如
init()
,service()
等)来处理请求。 - Servlet根据JSP页面中的原始逻辑,执行必要的业务处理,并动态生成HTML响应内容。
- 生成的HTML内容随HTTP响应发送回客户端浏览器。
-
缓存与重编译:
- 如果JSP页面未发生变化,Web容器会直接使用已编译好的Servlet来处理后续请求,无需重复编译。
- 若JSP文件被修改,Web容器会检测到文件变动并重新触发编译过程。
看个例子:
我们建一个javaweb项目jsptest,然后新建一个welcome.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>首页</title>
</head>
<body>
<%
out.println("测试理解jsp编译原理");
%>
</body>
</html>
一般jsp编译会在这个路径能找到:apache-tomcat-8.5.93/work/Catalina/localhost/jsptest(最后是项目名称)
启动项目之后是这样的
说明jsp文件还没有编译
访问一下:http://localhost:8080/jsptest/welcome.jsp
再看文件夹
已经编译出来了
welcome_jsp.java核心代码如下:
package org.apache.jsp;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;
public final class welcome_jsp extends org.apache.jasper.runtime.HttpJspBase
implements org.apache.jasper.runtime.JspSourceDependent,
org.apache.jasper.runtime.JspSourceImports {
......
public void _jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response)
throws java.io.IOException, javax.servlet.ServletException {
......
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("\r\n");
out.write("<!DOCTYPE html>\r\n");
out.write("<html>\r\n");
out.write("<head>\r\n");
out.write("<meta charset=\"UTF-8\">\r\n");
out.write("<title>首页</title>\r\n");
out.write("</head>\r\n");
out.write("<body>\r\n");
out.write(" ");
out.println("测试理解jsp编译原理");
out.write("\r\n");
out.write("</body>\r\n");
out.write("</html>");
} catch (java.lang.Throwable t) {
......
} finally {
_jspxFactory.releasePageContext(_jspx_page_context);
}
}
}
其中out.write就是响应给客户端的内容,再对照上面的JSP编译过程,更容易理解。
那么springboot内嵌的tomcat,编译的jsp在哪里呢?