day23-服务器端渲染技术01
服务器端渲染技术01
- 为什么需要jsp?
在之前的开发过程中,我们可以发现servlet做界面非常不方便:

引出jsp技术=> jsp=html+java代码+标签+javascript+css
1.JSP基本介绍
- JSP全称是Java Server Pages,Java的服务器页面,就是服务器端渲染技术
- JSP这门技术最大的特点在于,写JSP就像在写HTML
- 相比HTML而言,HTML只能为用户提供静态数据,而JSP技术允许在页面中嵌套java代码,为用户提供动态数据
- 相比Servlet而言,Servlet很难对数据进行排版,而jJSP除了可以用java代码产生动态数据的同时,也很容易对数据进行排版
- JSP技术基于Servlet,可以理解成JSP就是对Servlet的包装,JSP的本质就是Servlet。
- 会使用JSP的程序员,再使用thymeleaf是非常容易的事情,几乎是无缝接轨。
2.JSP的快速入门
2.1应用实例-jsp的基本使用
-
创建web项目,并引入jsp和servlet的jar包(servlet和jsp的jar包在tomcat安装目录下的lib目录下)
-
创建的jsp文件应放在web目录下面
-
配置Tomcat
-
编写jsp
<%-- Created by IntelliJ IDEA. User: li Date: 2022/11/24 Time: 16:59 To change this template use File | Settings | File Templates. --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>jsp简单的求和计算器</title> </head> <body> <h1>jsp简单的求和计算器</h1> <% //1. 在jsp中的该标签内可以写java代码 int i = 10; int j = 20; int res = i + j; //jsp的本质就是servlet,因此servlet可以使用的东西jsp都可以使用 //2.jsp中内置了许多对象,可以直接使用,比如out out.print(i + "+" + j + "=" + res); %> </body> </html> -
运行Tomcat,在浏览器中访问该jsp资源
2.1注意事项和细节
-
jsp页面不能像html页面一样,直接用浏览器运行。只能通过浏览器访问Tomcat来访问jsp页面
-
如何设置jsp模板,设置完模板后,当你再去生成一个jsp文件后就会根据模板的内容自动生成文件头
3.JSP的运行原理
-
jsp页面本质是一个Servlet程序(jsp本质就是java程序),其性能是和java相关的,只是长得丑
-
第一次访问jsp页面的时候,Tomcat服务器会将jsp页面解析成一个java源文件,并且将它编译成一个.clsaa字节码程序。
-
分析下sum_jsp.java源码,可以看出jsp本质就是Servlet
3.1可以看到sum_jsp类继承了一个名叫HttpJspBase的类:
想要看到源码和分析类图,需要加入jasper.jar包。这个包在tomcat/lib下拷贝
3.2我们引入jasper.jar包,查看该类的类图:
4.常用的jsp指令

- language表示jsp翻译后是什么语言文件,只支持java
- contentType表示jsp返回的数据类型,对应源码中response.setContentType()参数值
- pageEncoding属性表示当前jsp页面文件本身的字符集
- import属性和java源代码中一样,用于导包,导类。
5.JSP三种常用脚本
5.1声明脚本基本语法
-
声明脚本的格式是:
<%! 声明java代码 %> -
作用:定义jsp需要的属性,方法,静态代码块和内部类等
应用实例
statement.jsp:
<%-- Created by IntelliJ IDEA. User: li Date: 2022/11/24 Time: 18:28 Version: 1.0 --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>jsp声明脚本</title> </head> <body> <h1>jsp声明脚本</h1> <%! //这里我们可以声明该jsp需要的属性,方法,静态代码块和内部类等, // 也就是给statement.jsp对应的statement_jsp类定义成员 //1.属性 private String name = "jack"; private int age; private static String company; //2.方法 public String getName() { return name; } //3.静态代码块 static { company = "中国移动"; } %> </body> </html>
-
在浏览器中访问该jsp页面,在Tomcat启动时的Using CATALINA_BASE:文件目录下可以看到对应jsp文件生成的java文件:
-
打开该java文件,可以看到在jsp页面中定义的属性和方法等:
5.2表达式脚本基本语法
-
表达式脚本的格式是:
<%=表达式%> 表达式的概念和java基础的表达式一样,只要有一个具体的值返回,都可以称之为一个表达式
-
表达式脚本的作用是:在jsp页面上输出数据
-
脚本中的表达式不能以分号结束
应用实例
expression.jsp:
<%-- Created by IntelliJ IDEA. User: li Date: 2022/11/24 Time: 18:47 Version: 1.0 --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>表达式脚本的使用</title> </head> <body> <h1>表达式脚本的使用</h1> <% String name = "一只大猫咪"; //可以在jsp页面中动态获取一些值,并将其展示出来 String email = request.getParameter("email"); //表达式可以是变量,常量,还可以是动态获取的变量 %> 用户名:<%=name%><br/> 工作是:<%="java工程师"%><br/> 年龄:<%=request.getParameter("age")%><br/> 邮箱:<%=email%> </body> </html>
访问浏览器:http://localhost:8080/jsp/expression.jsp?age=100&email=mimi@qq.com

5.3代码脚本基本语法
-
代码脚本的语法是:
<% java代码 %> -
代码脚本的作用是:可以在jsp页面中,编写我们需要的功能(使用java)
-
可以由多个代码脚本块组合完成一个完整的java语句
-
代码脚本还可以和表达式脚本一起组合使用,在jsp页面上输出数据
应用实例
在src文件夹下创建一个Monster类:
package com.li.entity; public class Monster { private Integer id; private String name; private String skill; public Monster(Integer id, String name, String skill) { this.id = id; this.name = name; this.skill = skill; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getSkill() { return skill; } public void setSkill(String skill) { this.skill = skill; } }
javaCode.jsp:
<%@ page import="java.util.ArrayList" %> <%@ page import="com.li.entity.Monster" %> <%-- Created by IntelliJ IDEA. User: li Date: 2022/11/24 Time: 19:16 Version: 1.0 --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>演示代码脚本的使用</title> </head> <body> <h1>演示代码脚本的使用</h1> <% //先创建ArrayList,放入两个monster对象(使用的类会自动导入) ArrayList<Monster> monsterList = new ArrayList<>(); monsterList.add(new Monster(1, "牛魔王", "芭蕉扇")); monsterList.add(new Monster(2, "蜘蛛精", "吐丝")); %> </body> <%--tr 是行标签,th是表头标签,td是单元格标签--%> <table bgcolor="#f0f8ff" border="1px" width="300px"> <tr> <th>id</th> <th>名字</th> <th>技能</th> </tr> <% for (int i = 0; i < monsterList.size(); i++) { //先取出monster对象 Monster monster = monsterList.get(i); %> <tr> <th><%=monster.getId()%></th> <th><%=monster.getName()%></th> <th><%=monster.getSkill()%></th> </tr> <% } %> </table> </html>
-
在浏览器访问:
http://localhost:8080/jsp/javaCode.jsp
-
在Tomcat启动时的Using CATALINA_BASE:文件目录下可以看到对应jsp文件生成的java文件。
可以看到jsp文件中的for循环被解析成如下形式:
6.JSP注释
jsp可以写java代码和html,可以使用java代码的注释,以及html的注释<!--html注释-->
。此外还可以使用jsp自己的注释方式<%--jsp注释--%>
7.JSP的内置对象
-
基本介绍
- JSP内置对象(已经创建好的对象,可以直接使用-inbuild),是指Tomcat在翻译jsp页面成为Servlet后,内部提供的九大对象,称为内置对象
- 内置对象可以在jsp页面直接使用,不需要手动定义
-
JSP九大内置对象
- out:向客户端输出数据,out.println("");
- request:客户端的http请求
- response:响应对象
- session:会话对象
- application:对应 ServletContext
- pageContext:jsp页面的上下文,是一个域对象,可以setAttribute(),作用范围是本页面
- exception:异常对象,getMessage()
- page:代表jsp这个实例本身
- config:对应ServletConfig
-
对照Servlet来理解就轻松了
只要学某个类,建议熟悉该类的继承关系
应用实例
inbuild.jsp:
<%-- Created by IntelliJ IDEA. User: li Date: 2022/11/24 Time: 20:05 Version: 1.0 --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>jsp内置对象</title> </head> <body> <h1>jsp内置对象</h1> <% //jsp的内置对象 //1.out 的类型是 JspWriter out.print("jsp out"); //2.request 的类型是 HttpServletRequest request.getParameter("age"); //3.response 的类型是 HttpServletResponse //response.sendRedirect("http://www.baidu.com"); //4.session 的类型是 HttpSession session.setAttribute("中国", "北京"); //5.application 的类型 ServletContext application.setAttribute("name", "jack"); //6.pageContext 的类型是PageContext //该对象可以存放数据(属性),但是该数据只能在本页使用 pageContext.setAttribute("age", 99); //7.exception:异常对象使用比较少,忽略 //8.page 内置对象,类似this out.print("page对象= " + page);//org.apache.jsp.inbuild_jsp@2ac0d5df //9.config 的内置对象就是ServletConfig String password = config.getInitParameter("password"); %> </body> age:<%=pageContext.getAttribute("age")%> </html>
对照一下servlet的对象使用,其实是大同小异的:

8.JSP域对象
所谓"作用域"就是"信息共享的范围",也就是说一个信息能够在多大的范围内有效。所谓的域对象就是在某个范围存数据和取数据的对象。
8.1JSP四大域对象介绍
JSP中四大作用域详解- 博客园 (cnblogs.com)
Web交互的最基本单位为HTTP请求。每个用户从进入网站到离开网站这段过程称为一个HTTP会话,一个服务器的运行过程中会有多个用户访问,就是多个HTTP会话。
名称 | 作用域 |
---|---|
application(应用程序作用域) | 整个web应用运行期间有效 |
session(会话作用域) | 存放的数据在一次会话内有效 |
request(请求作用域) | 存放的数据在一次request请求有效 |
page(页面作用域) | 存放的数据只能在当前页面有效 |




8.2应用实例
scope.jsp:
<%-- Created by IntelliJ IDEA. User: li Date: 2022/11/25 Time: 15:36 Version: 1.0 --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>scope文件</title> </head> <body> <% //在不同的域对象中,放入数据 //因为四个域对象是不同的对象,因此name相同(key相同)并不会冲突 pageContext.setAttribute("k1", "pageContext数据v1"); request.setAttribute("k1", "request数据v1"); session.setAttribute("k1", "session数据v1"); application.setAttribute("k1", "application数据v1"); //做一个请求转发的操作 //因为是在服务器解析的,可以不用写 web工程路径 //request.getRequestDispatcher("/scope2.jsp").forward(request, response); //重定向 //因为是在浏览器解析的,需要写 web工程路径 response.sendRedirect("/jsp/scope2.jsp"); %> <h1>四个域对象在本页面获取数据的情况</h1> pageContext-k1:<%=pageContext.getAttribute("k1")%><br/> request-k1:<%=request.getAttribute("k1")%><br/> session-k1:<%=session.getAttribute("k1")%><br/> application-k1:<%=application.getAttribute("k1")%> </body> </html>
scope2.jsp:
<%-- Created by IntelliJ IDEA. User: li Date: 2022/11/25 Time: 15:44 Version: 1.0 --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>scope2</title> </head> <body> <h1>在scope2页面获取数据的情况</h1> pageContext-k1:<%=pageContext.getAttribute("k1")%><br/> request-k1:<%=request.getAttribute("k1")%><br/> session-k1:<%=session.getAttribute("k1")%><br/> application-k1:<%=application.getAttribute("k1")%> </body> </html>
-
首先访问scope.jsp页面,可以看到在本页设置的四个域对象都可以获取到数据
-
访问scope.jsp,它请求转发到scope2.jsp页面, pageContext对象不能取到数据,其余对象可以取出数据
-
访问scope.jsp,它重定向到scope2.jsp,pageContext和request对象不能取到数据,其余对象可以取出数据
-
换一个浏览器直接访问scope2.jsp。只有application对象可以访问到数据,其余对象不能取到数据。
- jsp四大域对象注意事项和细节
- 域对象是可以像Map一样存储数据的对象。四个域对象功能一样,不同的是它们对数据的存储范围。
- 从存储范围(作用域范围来看):pageContext < request < session < application
9.JSP请求转发标签
<jsp:forward page="xxx"></jsp:forward>
是请求转发标签,它的功能就是请求转发到page属性设置的路径
应用实例
aa.jsp:
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>aa.jsp</title> </head> <body> <h1>aa.jsp</h1> <%-- 请求转发标签的本质等价于 request.getRequestDispacher("/bb.jsp").forward(request,response); --%> <jsp:forward page="/bb.jsp"></jsp:forward> </body> </html>
bb.jsp:
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>bb.jsp</title> </head> <body> <h1>bb.jsp</h1> </body> </html>
浏览器访问aa.jsp,可以看到请求转发到了bb.jsp页面(请求转发的地址栏不变)

10.练习
需求分析:使用jsp页面完成一个简单的计算器,需求如下:

-
要求在前端页面对输入的num1和num2进行校验,必须是整数(提示:使用正则表达式)
-
验证成功,提交数据给服务器,能够显示结果
-
点击超链接,可以返回界面
-
思考题:如果用户这样提交:
http://localhost:8080/jsp/calServlet?num1=null&num2=bb
,需要你返回calculator.jsp页面,并给出提示信息如下:
练习
思路:

calculator.jsp:
<%-- Created by IntelliJ IDEA. User: li Date: 2022/11/25 Time: 16:30 Version: 1.0 --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>jsp计算器</title> <script type="text/javascript"> //使用js+正则表达式完成校验 function check() { //得到num1,num2的值 var num1 = document.getElementById("num1").value; var num2 = document.getElementById("num2").value; //验证-必须是整数 var regStr = /^[-]?([1-9]\d*|0)$/; if (!regStr.test(num1)) {//如果不是整数 window.alert("num1不是一个整数"); return false;//代表不提交表单 } if (!regStr.test(num2)) {//如果不是整数 window.alert("num2不是一个整数"); return false;//代表不提交表单 } return true; } </script> </head> <body> <h1>jsp计算器</h1> <form action="/jsp/calServlet" method="post" onsubmit="return check()"> num1:<input type="text" id="num1" name="num1"/> <%=request.getAttribute("num1") != null ? request.getAttribute("num1") : ""%> <br/><br/> num2:<input type="text" id="num2" name="num2"/> <%=request.getAttribute("num2") != null ? request.getAttribute("num2") : ""%> <br/><br/> 运算符号:<select name="operator"> <option value="+">+</option> <option value="-">-</option> <option value="*">*</option> <option value="/">/</option> </select> <input type="submit" value="计算"> </form> </body> </html>
calServlet:
package com.li.servlet; import com.utils.WebUtils; import javafx.scene.Parent; import javax.servlet.*; import javax.servlet.http.*; import javax.servlet.annotation.*; import java.io.IOException; import java.util.regex.Matcher; import java.util.regex.Pattern; @WebServlet(name = "CalServlet", value = "/calServlet") public class CalServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("calServlet was run .."); //1.正则验证-防止用户直接在地址栏请求CalServlet String regStr = "^[-]?([1-9]\\d*|0)$"; boolean matches = Pattern.matches(regStr, request.getParameter("num1")); boolean matches2 = Pattern.matches(regStr, request.getParameter("num2")); //如果用户直接通过地址栏输入非法数据,可以先正则验证出哪个数据非法 //再将提示转发回计算器页面这里使用request域对象 if ((!matches) || (!matches2)) { request.setAttribute("num1", "你输入num1=" + request.getParameter("num1")); request.setAttribute("num2", "你输入num2=" + request.getParameter("num2")); //请求转发到显示页面 request.getRequestDispatcher("/calculator.jsp").forward(request, response); return; } //2.将用户输入的数据转成double类型 double num1 = WebUtils.parseDouble(request.getParameter("num1"), 0); double num2 = WebUtils.parseDouble(request.getParameter("num2"), 0); String operator = request.getParameter("operator"); //3.完成计算 double result = 0.0;//使用一个变量来接收运算结果 if ("+".equals(operator)) { result = num1 + num2; } else if ("-".equals(operator)) { result = num1 - num2; } else if ("*".equals(operator)) { result = num1 * num2; } else if ("/".equals(operator)) { if (0 == num2) { System.out.println("被除数不能为0"); } else { result = num1 / num2; } } else { System.out.println(operator + "不正确.."); } //4.一次请求对应一次计算,因此将结果保存到request中 // 将结果保存到一个字符串中,方便下一个页面显示。使用String.format,可以格式化字符串 String resInfo = String.format("%s %s %s = %s", num1, operator, num2, result); request.setAttribute("resInfo", resInfo); //5.请求转发到显示页面 request.getRequestDispatcher("/calResult.jsp").forward(request, response); } }
WebUtils:
package com.utils; public class WebUtils { public static double parseDouble(String strNum, int defaultVal) { try { return Double.parseDouble(strNum); } catch (NumberFormatException e) { System.out.println(strNum + "不能转成整数"); } return defaultVal; } }
calResult.jsp:
<%-- Created by IntelliJ IDEA. User: li Date: 2022/11/25 Time: 17:22 Version: 1.0 --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>计算结果</title> </head> <body> <h1>计算结果</h1> <h1> <%=request.getAttribute("resInfo")%> <br/> </h1> <h3><a href="/jsp/calculator.jsp">返回再来玩一次</a></h3> </body> </html>
-
在表单中输入合法数据:
-
表单输入非法数据:
-
在地址栏中输入非法数据:
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!