JSP 规范
介绍:
- 来自JavaEE 规范中的一种
- JSP规范制定了如何开发JSP 文件代替响应对象将处理结果写入到响应体的开发过程
- JSP 规范指定了HTTP 服务器应该如何调用管理 JSP 文件
响应对象存在的弊端
(response的弊端)
- 适合将数量较少的处理结果写入到响应体
- 如果处理结果数量较多,使用响应体对象,增加开发的难度(用PrintWriter流来拼凑输出一大堆html代码,可想而知……)
JSP 文件中如何书写 Java 命令
JSP 文件时如何识别 Java 命令和 HTML 标记的呢?
执行标记的语法格式
在 JSP 文件中,只有书写在执行标记中的内容才会被当做 Java命令
可以声明的运行表达式:数学运算,逻辑运算,关系运算
注意,虽然在 JSP 里可以执行 数学运算,逻辑运算,关系运算,但一般对于参数的处理是不会在 JSP里处理的
在实际开发中,是 Servlet 和 Service 来对参数处理,JSP 来输出,所以,JSP 并不需要做复杂的判断和循环
<% Java 命令 %>
输出标记语法格式
在 JSP 文件,通过输出标记,通知 JSP 将 Java 变量的值写入到响应体中,也可以将Java 变量的运行结果写入响应体
格式:<%= 变量 %>
比如:
<%
int i = 100;
int j = 200;
int sum = i + j;
%>
<!--通过输出标记,输出变量sum-->
sum的值:<%=sum%>
<!--浏览器上运行效果:sum的值:300 -->
JSP 文件的内置对象
- 请求作用域对象:request
- 会话作用域对象:session
- 全局作用域对象:application
- 当前页作用域对象:pageContext
在 JSP 文件执行时,可以借助内置的作用域对象,读取共享数据的参数信息
JSP 与 Servlet 的分工
分工
- Servlet :负责处理业务,并得到【处理结果】
- JSP :不负责业务处理,主要任务将 Servlet 中的【处理结果】写入到响应体
Servlet 与 JSP 的调用关系
Servlet 将处理结果添加到【作用域对象】
JSP 文件在运行时,从【作用域对象】中得到处理结果
HTTP 服务器调用 JSP 文件的步骤
- 1、HTTP 服务器将 JSP 文件内容【编辑】成一个 Servlet 接口的实现类( .java 文件)
- 2、HTTP 服务器将 Servlet 接口的实现类【编译】成一个 class 文件( .class)
- 3、HTTP 服务器负责创建这个 class 的实例对象,这个实例对象就是 Servlet 实例对象
- 4、HTTP 服务器通过 Servlet 实例对象调用 _jspService 方法,将 .jsp 文件内容写入到响应体
JSP 文件的位置
在 .IntelliJIdeaxxx.x\system\tomcat\工作空间
Tomcat 工作空间下的 work 文件夹下,work\Catalina\localhost\myweb\org\apache\jsp
EL 表达式
EL工具包
- 是由 Java 技术开发的一个 jar 包
- 作用是降低 JSP 文件开发时 Java 命令的开发强度
- Tomcat 服务器本身自带了 EL 工具包(Tomcat 的安装地址的 lib 文件夹中)
若不想配置MySQL的 jar 包,可以吧 MySQL 的 jar 包复制进 tomcat 的 lib 中。tomcat就自带 mysql 的 jar 包了,不用手动配置
EL 表达式的语法格式
1、一般取值情况
<!--假设在 Servlet 中,请求作用域对象中存在共享属性,并且对JSP文件共享-->
request.setAttribute("key1","value1");
<!--通过请求转发的方式,调用JSP文件-->
request.getRequestDispatcher("/jsp_1.jsp");
======================
则在 JSP 中,可以直接对这个请求作用域对象做取值操作
key1 = ${requestScope.key1}
<!--在浏览器的运行效果:
key1 = value1
-->
2、假如,请求作用域对象中存放的value值是一个Object类型,则取出数据的方式:
<!-- 在 Servlet 文件中 -->
Student stu = new Student(001,"zhangsan");<!--Student类型中有:sno,sname 属性-->
request.setAttribute("key1",stu);
request.getRequestDispatcher("/jsp_1.jsp");
<!-- 在 JSP 文件中 -->
studentNo = ${requestScope.key1.sno}
studentName = ${requestScope.key1.sname}
<!--在浏览器的运行效果:
studentNo = 001
studentName = zhangsan
-->
3、假如,共享数据是个集合
<!-- 在 Servlet 文件中 -->
Student stu1 = new Student(001,"zhangsan");
Student stu2 = new Student(002,"lisi");
Student stu3 = new Student(003,"wangwu");
List stuList = new ArrayList();<!-- 数组 -->
stuList.add(stu1); 将对象填充入数组
stuList.add(stu2); 将对象填充入数组
stuList.add(stu3); 将对象填充入数组
request.setAttribute("key1",stuList);<!-- 将集合放入请求作用域对象 -->
request.getRequestDispatcher("/jsp_1.jsp");
<!-- 在 JSP 文件中 -->
需要遍历取出,这时候不能用上 EL 表达式了,要用 JSTL(没学)
<%
List stuList = (Student)request.getAttribute("key1");
//然后逐一遍历出来
%>
EL 表达式简化版
EL 表达式允许开发人员开发时,省略作用域对象的别名
${共享数据名}
工作原理
EL 表达式简化版由于没有指定作用域对象,所以在执行时采用【猜】的算法
- 首先到【 pageContext 】定位共享数据,如果存在,则直接读取输出结束执行
- 如果在【 pageContext 】没定位成功,则到【 request 】定位共享数据,如果存在,则直接读取输出结束执行
- 如果在【 request 】没定位成功,则到【 session 】定位共享数据,如果存在,则直接读取输出结束执行
- 如果在【 session 】没定位成功,则到【 application 】定位共享数据,如果存在,则直接读取输出结束执行
- 如果在【 application 】没定位成功,则返回 null
pageContext --------> request --------> session --------> application
存在隐患
- 1、容易降低程序的执行速度
- 2、如果不同的作用域对象存在相同的 [ key ],则容易导致数据定位错误
- 3、可读性很差
应用场景
既然设计师设计出来这个功能,自然有他的价值
-
设计目的,就是简化从 pageContext 读取共享数据并输出的难度
因为一开始就去pageContext 中找,所以不存在什么效率问题
EL 表达式其他的内置对象
param
paramValues
${paramValues.请求参数名[下标]}
作用:如果浏览器发送的请求参数是【一个请求参数关联多个值】,此时可以通过 paramValues 读取请求参数下指定位置的值,并写入到响应体
-
比如命令:http://localhost:8080/myweb/index_1.jsp?pageNo=1&pageNo=2&pageNo=3
(比如 checkbox 中,name相同的一组复选框作为一组参数)
此时 pageNo 请求参数在请求包中是以数组的形式存在:pageNo[1,2,3]
jsp 老式命令来输出
<%
//用一个数组来接收 请求参数组
String[] array = request.getParameterValues("pageNo");
%>
第一个值:<%=array[0]%>
第二个值:<%=array[1]%>
第三个值:<%=array[2]%>