⭐作者介绍:大二本科网络工程专业在读,持续学习Java,努力输出优质文章
⭐作者主页:@逐梦苍穹
⭐所属专栏:Java Web
JSP(JavaServer Pages)是Java Web技术体系中的一种动态网页开发技术,它允许开发人员在HTML网页中嵌入Java代码以及Java EE标签库,从而实现动态生成网页内容的功能。
与静态网页不同,JSP页面可以包含Java代码片段、Java EE标签库以及HTML标签。在客户端请求访问该JSP页面时,Java代码片段将会被服务器端解释执行并生成动态内容,然后将生成的结果作为HTML网页返回给客户端。
在JSP中,可以使用Java语言的所有功能和API。它还提供了许多内置的对象,例如request、response、session、application等,这些对象可以用来处理用户请求和响应的数据。
除了使用Java代码,JSP页面还可以使用标签库(Tag Library)来简化开发。标签库是一组可重用的代码块,类似于HTML的标签,它们可以在JSP页面中使用,以简化常见的Web开发任务。
总之,JSP是Java Web技术体系中重要的组成部分之一,它使得开发人员可以使用Java语言和API来开发动态Web页面,同时也提供了许多内置的对象和标签库,以简化开发过程。
1. 简单易学:JSP技术基于HTML,开发人员可以使用标准的HTML标记语言进行开发,同时可以嵌入Java代码来实现动态内容生成。
2. 可重用性:通过使用JSP标签库(Tag Library),可以将代码块打包成可重用的组件,这些组件可以在不同的JSP页面中共享,提高了代码的可重用性。
3. 高性能:JSP页面在首次访问时需要编译成Java Servlet,之后每次访问时就不需要再次编译,因此可以提高Web应用程序的性能。
4. 容易维护:JSP页面的代码可以分离出来,从而实现模块化和易于维护。
JSP的使用,相比于单纯使用Servlet开发,效率和开发质量大大提升。
在之前直接使用Servlet对浏览器写前端网页的内容,如果内容较多的情况下,会显得非常繁琐,并且代码是写死在程序里面的,不好维护,可读性也较差。因为之前是需要通过Servlet的response对象来向浏览器响应数据的,因此调用的是response.getWriter().write()方法来写,写出来的效果就像这样:
可以看到一个非常简单的前端表单页面,直接拿Servlet响应请求给浏览器显得多么复杂。JSP在当时,就很好的解决了这个问题。
缺点:
在现代Web开发中,越来越多的开发人员转向了使用前端框架来构建动态Web应用,如React、Vue.js等。
同时,Java EE平台在2019年被Oracle放弃维护,取而代之的是Jakarta EE平台,也就是Eclipse基金会维护的Java EE的开源版本。
JSP为什么会逐渐被淘汰?主要有以下原因:
1. 前后端分离:随着前端框架的发展和普及,越来越多的开发人员开始采用前后端分离的开发模式。在这种模式下,后端提供API接口,前端通过AJAX等方式获取数据并动态渲染页面,这种方式更加灵活,更容易实现复杂的Web应用。
2. 低效的开发:JSP中的Java代码片段可能会导致页面变得混乱,降低了可读性和可维护性。同时,使用JSP时,开发人员需要手动处理各种请求和响应,这可能会导致开发效率低下。
3. 安全问题:由于JSP允许在页面中嵌入Java代码,如果编写不当,可能会导致安全漏洞,如SQL注入、XSS等。
4. Java EE平台的变化:Java EE平台在2019年被Oracle放弃维护,取而代之的是Jakarta EE平台,这也导致开发人员不得不转向使用新的技术栈来开发Web应用。
因此,尽管JSP作为一种经典的Web开发技术在一定程度上仍然被广泛应用,但随着前端技术和后端技术的发展,越来越多的开发人员转向使用前后端分离的方式来构建动态Web应用。
学习JavaWeb的过程,就像在学习Web开发领域的发展史,以史为鉴,从历史中总结学习经验,取其精华去其糟粕。因此,时至今日学习JSP仍然具有一定的意义,尤其对于初学者和想要了解Web开发历史和演变过程的人来说。
以下列举几个学习JSP技术的意义所在:
1. 掌握Java Web开发的基本原理:JSP是Java Web开发的重要组成部分,学习JSP可以帮助初学者掌握Java Web开发的基本原理,包括Servlet、HTTP协议、JSP的工作原理等。
2. 理解现代Web开发的演变过程:JSP曾经是Java Web开发的主流技术之一,但现在已经被前后端分离、模板引擎等技术所替代。学习JSP可以帮助人们了解现代Web开发的演变过程,以及现在的Web开发趋势。
3. 学习JSP的一些基本概念对于维护和升级已有的JSP应用程序仍然有用。在很多公司中,可能还有一些老的JSP应用程序需要维护和升级,因此对于熟悉JSP的开发人员来说,仍然具有一定的价值。
总的来说,虽然JSP已经不再是主流的Web开发技术,但学习JSP仍然有其独特的价值,能够帮助开发人员理解Java Web开发的基本原理和现代Web开发的演变过程。
①创建一个Maven的Web项目,编写xml文件(重点是导入jsp的依赖)
4.0.0 org.example JSP_demo 1.0-SNAPSHOT war 17 17 javax.servlet.jsp jsp-api 2.2 provided javax.servlet javax.servlet-api 4.0.1 org.apache.tomcat.maven tomcat7-maven-plugin 2.2
②创建JSP文件,这里创建的是helloJSP.jsp。
③访问JSP
JSP是不能像之前的前端三剑客那样,写出来的代码文件可以直接在浏览器运行的,如果直接选择浏览器运行则会报错。
报错信息写的是:没有找到已配置/正在运行的web服务器。
这说明什么问题?说明这个JSP可能本质上就是个Servlet服务端。事实上真是如此,下面会详细讲述。
在访问JSP的时候出现了如下错误:
显示的是无法编译JSP。
出现这个原因是因为使用了低版本的tomcat和高版本的JDK导致的, 解析出错,无法识别System类。可以尝试更换版本解决。
高版本tomcat配高版本JDK,低版本tomcat配低版本JDK。
这里我使用的是JDK11+tomcat7/tomcat8。两个tomcat版本都是可以适用的。
JSP本质上就是一个Servlet。
浏览器访问JSP的执行流程如下:
1. 浏览器第一次访问 helloJSP.jsp 页面
2. tomcat 会将 helloJSP.jsp 转换为名为 helloJSP_jsp.java 的一个 Servlet
3. tomcat 再将转换的 servlet 编译成字节码文件 hello_jsp.class
4. tomcat 会执行该字节码文件,向外提供服务
为了验证上面的执行流程,可以到磁盘中进行查看。进入该项目的target\tomcat\work\Tomcat\localhost\jsp_demo\org\apache\jsp 目录,而这个目录下就能看到转换后的 servlet。我自己目录如下:
下面贴上一份编译后的helloJSP_jsp.class文件:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//package org.apache.jsp;import java.io.IOException;
import java.util.Map;
import javax.el.ExpressionFactory;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.jsp.JspFactory;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.SkipPageException;
import org.apache.jasper.runtime.HttpJspBase;
import org.apache.jasper.runtime.InstanceManagerFactory;
import org.apache.jasper.runtime.JspSourceDependent;
import org.apache.tomcat.InstanceManager;public final class helloJSP_jsp extends HttpJspBase implements JspSourceDependent {private static final JspFactory _jspxFactory = JspFactory.getDefaultFactory();private static Map _jspx_dependants;private ExpressionFactory _el_expressionfactory;private InstanceManager _jsp_instancemanager;public helloJSP_jsp() {}public Map getDependants() {return _jspx_dependants;}public void _jspInit() {this._el_expressionfactory = _jspxFactory.getJspApplicationContext(this.getServletConfig().getServletContext()).getExpressionFactory();this._jsp_instancemanager = InstanceManagerFactory.getInstanceManager(this.getServletConfig());}public void _jspDestroy() {}public void _jspService(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {JspWriter out = null;JspWriter _jspx_out = null;PageContext _jspx_page_context = null;try {response.setContentType("text/html;charset=UTF-8");PageContext pageContext = _jspxFactory.getPageContext(this, request, response, (String)null, true, 8192, true);_jspx_page_context = pageContext;pageContext.getServletContext();pageContext.getServletConfig();pageContext.getSession();out = pageContext.getOut();out.write("\r\n");out.write("\r\n");out.write("\r\n");out.write("\r\n");out.write(" Title \r\n");out.write("\r\n");out.write("\r\n");out.write(" hello jsp
\r\n");out.write("\r\n");out.write(" ");System.out.println("hello jsp->java code");out.write("\r\n");out.write("\r\n");out.write("\r\n");} catch (Throwable var13) {if (!(var13 instanceof SkipPageException)) {out = (JspWriter)_jspx_out;if (_jspx_out != null && ((JspWriter)_jspx_out).getBufferSize() != 0) {try {out.clearBuffer();} catch (IOException var12) {}}if (_jspx_page_context == null) {throw new ServletException(var13);}_jspx_page_context.handlePageException(var13);}} finally {_jspxFactory.releasePageContext(_jspx_page_context);}}
}
可以发现编译后的class文件中,继承了HttpJspBase,查看HttpJspBase源码:
可以看到HttpJspBase是继承了HttpServlet,所以helloJSP.jsp间接继承了HttpServlet,什么JSP本质上就是Servlet。
HttpJspBase源码:
/** Licensed to the Apache Software Foundation (ASF) under one or more* contributor license agreements. See the NOTICE file distributed with* this work for additional information regarding copyright ownership.* The ASF licenses this file to You under the Apache License, Version 2.0* (the "License"); you may not use this file except in compliance with* the License. You may obtain a copy of the License at** http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/
package org.apache.jasper.runtime;import java.io.IOException;import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.jsp.HttpJspPage;import org.apache.jasper.Constants;
import org.apache.jasper.compiler.Localizer;/*** This is the super class of all JSP-generated servlets.** @author Anil K. Vijendran*/
public abstract class HttpJspBase extends HttpServlet implements HttpJspPage {private static final long serialVersionUID = 1L;protected HttpJspBase() {}@Overridepublic final void init(ServletConfig config)throws ServletException{super.init(config);jspInit();_jspInit();}@Overridepublic String getServletInfo() {return Localizer.getMessage("jsp.engine.info", Constants.SPEC_VERSION);}@Overridepublic final void destroy() {jspDestroy();_jspDestroy();}/*** Entry point into service.*/@Overridepublic final void service(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException{_jspService(request, response);}@Overridepublic void jspInit() {}public void _jspInit() {}@Overridepublic void jspDestroy() {}protected void _jspDestroy() {}@Overridepublic abstract void _jspService(HttpServletRequest request,HttpServletResponse response)throws ServletException, IOException;
}
_jspService方法每次访问的时候都会自动执行,和Servlet中的service方法类似。在_jspService方法中则存放着往浏览器写标签的代码。所以实际上就是以前这部分代码是自己写,现在由tomcat来帮助完成。
JSP脚本是一种在JSP页面中嵌入Java代码的方式,可以在JSP页面中执行Java代码,从而动态生成HTML页面。JSP脚本可以出现在JSP页面的任何位置,包括JSP页面的文本、HTML标记和XML标记之间。JSP脚本可以使用以下语法:
1. <% … %>:内容会直接放到_jspService()方法之中。这是最常用的JSP脚本标记,可以用来嵌入任意的Java代码,包括声明变量、定义方法、调用Java API等。
2. <%= … %>:内容会放到out.print()中,作为out.print()的参数。这个标记可以用来在HTML页面中输出Java表达式的值,类似于Java中的System.out.println()语句。例如:<%= name %>可以输出变量name的值。
3. <%-- --%>:这个标记可以用来注释JSP页面中的代码。
4. <%! … %>:内容会放到_jspService()方法之外,被类直接包含。这个标记用来定义全局变量和方法,这些变量和方法可以在整个JSP页面中使用。
JSP脚本的执行顺序是从上到下,从左到右,与在Java中的执行顺序相同。
下面依次对这几个脚本进行测试:
①<% … %>:上面提到,该脚本会把内容直接放到_jspService()方法之中。
②<%= …%>:内容会放到_jspService()方法中out.print()中,作为out.print()的参数。
③<%! …%>:内容会直接放在类中。
在第二部分简单样例的基础上,编写本次的实践样例。
这次的实践样例中,采用了JDBC操作数据库的方式,获取到数据库中的数据,在前端页面上进行展示。(JDBC的相关代码直接在JSP中完成)
准备工作:打开本地的MySQL服务;在pom.xml中配置MySQL驱动依赖
下面对JSP的编写进行解析:
①HTML部分:
写好表头标签:
编写表格内容的标签:
HTML的这部分中,由于后面是要写Java代码来获取数据填充在HTML页面的表格中,所以这里的表格内容要动态获取,不能写死。
②java代码:
编写jdbc实现代码的步骤:注册驱动、获取连接、定义SQL语句、获取执行SQL对象、执行SQL、处理返回的结果、释放资源。
动态获取数据:
下面是JSP的完整代码:
<%--Created by IntelliJ IDEA.User: 逐梦苍穹Date: 2023/3/19Time: 21:59To change this template use File | Settings | File Templates.
--%>
<%@ page import="java.sql.*" %><%@ page contentType="text/html;charset=UTF-8" language="java" %>
Title
序号 名称 介绍 商品数量 状态 <%Connection conn = null;Statement stmt = null;ResultSet rs = null;try {// 加载MySQL JDBC驱动程序Class.forName("com.mysql.jdbc.Driver");// 建立与数据库的连接conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/jsp", "root", "你的密码");// 创建一个 Statement 对象stmt = conn.createStatement();// 执行查询语句rs = stmt.executeQuery("SELECT * FROM jspDemo");// 处理查询结果while (rs.next()) {%><%=rs.getString("id")%> <%=rs.getString("name")%> <%=rs.getString("information")%> <%=rs.getString("number")%> <%=(rs.getString("status")).equals("1") ? "启用":"禁用"%> 修改 删除 <%}} catch (SQLException ex) {ex.printStackTrace();} catch (ClassNotFoundException ex) {ex.printStackTrace();} finally {// 关闭数据库连接try {if (rs != null) rs.close();if (stmt != null) stmt.close();if (conn != null) conn.close();} catch (SQLException ex) {ex.printStackTrace();}}%>
在写java代码的时候,如果想在其中穿插执行前端代码,可以使用<% %>进行截断。
上一篇:044、复习day02
下一篇: 初三数学教学工作计划