1、JSP的细节
(1)JSP表达式输出语句
格式:<%=变量(变量的表达式)%>
实际:通过Java源码可以看出是out.print(变量)的形式输出到浏览器
等价的两种方式:out.print(变量)--字节流的形式、out.write(变量)--字符流的形式
在JSP脚本中写java代码输出不再是syso的形式,而是out.write(变量)--常用
备注:out.write()与out.print()的区别?---讲到JspWriter out的内置对象的时候再说
说明:在代码中出现的位置不同
(2)注意事项
1)只要是在标签内写Java代码,都要用<% %>包含起来;不能用<% %>把标签包含进去---标签的范围比较大
2)我们平常所讲的JSP脚本实质:<% Java代码 %>
3)JSP的模板就是html标签
4)%的位置
5)对比:直接访问Servlet走的是web.xml文件的映射,它是如何获取到的
练习:表达式语句、for循环、9*9乘法表(代码一会补)
2、JSP的声明--很少用
(1)定义一个成员变量或成员方法
错误思路:在JSP脚本中用传统的Java变量和方法的声明
正确的JSP的声明:格式<%! 声明变量或方法%>
(2)声明为何是这种格式?
原因:通过翻译成的Java文件--可以看出脚本代码(<% %>)会在java源码的_JspService()方法中解析出来---在这里面定义的成
员变量和成员方法不能在此成员方法中定义,语法错误(在方法里定义成员变量和成员方法不符合语法规则);java中的成员位置出现
3、JSP核心内容
总结:三大指令、六大动作、九大内置对象、EL表达式、核心标签库、自定义标签库
(1) 三大指令
(1)page指令的属性
1)language="java" -----Jsp页面中使用的语言格式
2)import="java.util.*" -----Jsp页面所使用的语言(Java脚本)所需的包
注意:导包的时候多个包以","隔开(只需一个import)
3)contentType="text/html; charset=UTF-8" ------服务器告诉浏览器显示JS页面的格式(响应编码)
注意:3等价于在Servlet中设置response.setContentType("text/html; charset=UTF-8")--浏览器以何种形式解析
4)pageEncoding="utf-8" -------当前JSP页面的编码格式(默认ISO-8895-1不能写中文)
乱码分析:由于Jsp页面运行经历两个阶段:1(翻译) 、2(编译)
过程: JSP文件写完后--保存在硬盘上默认格式gbk(此JSP文件的编码格式)----翻译的时候,通过page指令的pageEncoding
属性对应的值的格式进行编码(java文件的编码格式)---编译后,在浏览器运行,通过page指令的contentType属性对应的格式进
行解码,保证JSP页面在浏览器显示不会出现乱码就需要编译和翻译要一致。
5)errorPage="链接" -------指定一个跳转的错误页面(相对路径和绝对路径???)
需求:不想让用户看到具体的错误原因--用户体验(在跳转的错误页面中使用下面的属性)
在page指令中设置isErrorpage="true" ---如果是错误页面,是否应用exception对象(内置)
注意:如果在当前的JSP页面使用这个exception对象,必须给跳转的错误页面中的isErrorage属性指定为true
练习:有关错误页面的配置
例如:脚本代码
<%
String name=null;
name.split(",");
%>
说明:运行JSP页面的时候,程序出现异常(500--服务器问题),用户体验不好,怎么解决?
解决方案:两种配置方式--局部(errorPage、isErrorpage两个属性有关)和全局的(在web.xml配置全局的错误页面)
局部的省略;全局的配置---只要出现常见的错误页面都可以自动跳转
<!-- 配置全局的错误页面处理 -->
<error-page>
<error-code>404</error-code>
<location>/common/404.html</location>
</error-page>
<error-page>
<error-code>500</error-code>
<location>/common/505.jsp</location>
</error-page>
注意:位置与servlet标签平级,更新配置文件了,得重新启动服务器
补充:也可以针对异常进行错误页面的处理。
page指令的其他属性(一般设置成最佳状态)--了解即可
---------------------
6)
session="true" ---
是否使用域对象---默认是true(支持)
作用:可以在JSP脚本中使用session域对象保存数据或获取数据。
保存数据:session.setAttribute("name", "wzj");
把数据发送过去:pageContext
7)
isELIgnored="false"---
是否忽略"EL表达式"---默认:true表示不忽略
8)buffer="8kb" ---默认指定JSP out缓冲区的大小(可以自己设置)
实验:
(1)比较out.write("123");和response.getWriter().write("456");
实验结果:456先输出,123后输出
分析:out是内置对象,有一个缓冲区,除非强制刷新(out.flush())将其输出去
(2)查看缓冲区的大小以及剩余的缓冲区大小
当前缓冲区剩余的大小:out.getRemaining()
当前设置的缓冲区的的大小:+out.getBufferSize());
说明:对于缓冲区大小包括"html注释以及空格占用"的内存空间(所以跟预想的不一样很正常)
思考:脚本里面的java注释占空间吗?
----------------------------------------------------------
(2)include指令
形式:<@include file=""common/header.jsp"">---可以把外部的JSP页面导入过来--类似于把其他页面作为组件嵌入该页面
作用:页面布局
特点:先把JSP文件合并,然后再编译--再运行--静态包含的方式(优先使用)
实验结果:被合并的JSP并没有Java和class文件
缺陷:使用静态方式的时候,打开合并之后生成的java文件,发现另一个文件的那些html里的html声明和head中的内容都被out.write重复输出了,冗余!!!
解决办法:删除当前文件的尾部html闭合标签,删除被包含文件的头部标签,这样一个保留开头的部分一个保留结尾的部分,组成一个文件后,不冗余了。
静态的理解:包含的JSP会在被包含的的一个静态代码块中
后面贴图(很重要)
(3)talib指令
<%@taglib>---与jstl核心标签库有关--到时候再复习
至此,三大指令暂时讲解完毕
--------------------------------------
(2)九大内置对象
特点:在jsp页面中直接使用,不需要声明
1)HttpSession session -----会话对象
说明:这些内置对象都在_jspService()的方法中,所以
JSP在脚本中就可以
使用这些内置对象
2)ServletContext application --
上下文对象
3)HttpServletRequest request --
请求对象
4)JspWriter out --带有
缓存功能的
输出对象
5)Object page = this; --代表
当前JSP页面
翻译后的
JAVA类对象
6)Throwable exception --当前JSP页面的
异常对象(打印异常的消息字符串)
7)ServletConfig config --
page对象
8)PageContext pageContext --代表JSP
传递数据的域对象(
非常重要-EL表达式中使用)
9)PageContext _jspx_page_context --基本不用
out细说 -----JSP的
缓存机制(向浏览器输出内容)
JSP输出页面1:response.getWrite().write("abc")
说明:response.getWriter()---字符打印流(PrinrWrter)---没有缓存的
JSP输出页面2:out.write("123")
结果:abc(无缓存) 123(有缓存)
说明:不是直接输出,中间有个缓冲区:out属于JSP九大内置对象的一种,属于JspWriter
此输出的内置对象相当于带缓存的字符打印流(PrintWriter)何时输出?
(1)8kb缓存满了:buffer="8kb"
(2)手动刷新:flush();
过程:out.write("123")---带缓存的JspWriter的缓存中---不带缓存的PrintWriter--浏览器显示123
查看翻译的的Java(Servlet)代码可知:将标签输出到浏览器的形式:out.write()也占一定内存,所以当前缓冲区剩余的大小不是
预先设定的JSP页面中的文档声明以及标签它都会将这些内容加载到带有缓存功能的JspWriter类中。
注意:区分
域
对象和
内置
对象
重点:内置对象有四个域对象;
域对象特点:setAttribute()---getAttribute()--能将数据保存域对象中,从域对象中获取数据;利用域对象传递数据的
需求1:通过PageContext对象,获取其它域对象(项目中使用的比较多)
结论:pageContext(俗称page域)内置对象可以获取当前JSP页面中的其它域对象
<%
//使用JSP内置对象session域对象保存数据
//Servlet的做法:request.getSession.setAttribute("名字")
//不使用传统的方法,使用JSP内置对象的方式--必须首先在page指令中开启session对象
//session.setAttribute("name", "name");
//pageContext获取其它的域对象
out.write("相等吗?"+(pageContext.getRequest()==request)+"<br/>");
//结果是True的话说明pageContext获取其它的域对象
out.write("相等吗?"+(pageContext.getSession()==session));
%>
setAttribute("数据名称",Object obj)---存储任意类型的数据
关键字:任意类型的数据(包括对象)
需求2:利用pageContext对象将数据保存在其它域对象中--利用setAttribute(三个参数)
pageContext.setAttribute("name", "康康", PageContext.REQUEST_SCOPE);
注意:第三个参数PageContext大写--这里是保存到request域对象中
scope---域--
作用范围
REQUEST_SCOPE--2
APPLICATION_SCOPE--4
SESSION_SCOPE--3
PAGE_SCOPE--1
pageContext作用(重点!)
(1)将数据保存到此域对象中
(2)利用此对象将数据保存到
其它域对象中
(3)从此域对象中获取数据
(4)利用此对象从其他域对象中获取数据
需求3:把
域对象(数据)从当前页面
传递到另一个页面--
页面跳转
思考:从当前页面中
跳转到另外一个JSP页面,观察能
从哪些域中获取对象?
结论:page域只在当前页面有作用,此域保存的数据不能"请求转发"到其它JSP页面--其它页面获取不到!
重定向---两次请求
说明:如果09页面重定向到10页面---10页面也接受不到request域对象数据(request域对象数据仅限当前的请求,由于重定向是两次请求,所以获取不到)
说明:request域对象仅限于:当前的一次请求
application:作用域最大--当前网站的全局参数
session域范围:仅限当前的会话数据(多次请求转发,只有浏览器和服务器没有断开!)
------------------
pageContext作用
String message = (String)pageContext.findAttribute("message")
说明:自动从"当前"JSP中搜索域对象---从小到大的范围搜索
练习:分别注释域对象中保存的数据,看此方法的搜索顺序
至此内置对象和域对象讲完了--重点
pageContext域对象!
(7)EL表达式的语法
引出:EL表达式是为了替代原始脚本的<%=%>的形式
语法:${说明:这里面获取的数据必须放到域对象中才能获取}
--------------------------
JSP静态数据
理解:是一个没有内嵌JAVA或动作的HTML页面;说白了就是JSP中的HTML部分
(3)JSP比HTML高级在哪?---JSP和HTML区别?
(4)显示当前系统的时间---引申了page指令的import---导入某个包下具体的类--java.*.*(错误)--导入到java.util.*