有一种特殊的文件,我们可以在它内部编写HTML代码、CSS代码、js代码还有Java代码。编写完之后,再有一个工具,将这个特殊的文件转换成Servlet,在转换好的Servlet中,之前写的Java代码还在,而HTML、css、js代码都使用writer的方式给写好。
那这个特殊的文件就是jsp文件。这个工具就是Tomcat服务器中的jsp引擎。
<%@ page import="java.util.List" %>
<%@ page import="com.sh.pojo.Emp" %>
<%@ page import="java.util.ArrayList" %>
<%@ page import="java.util.Date" %>
<%@ page import="java.text.SimpleDateFormat" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
$Title$
<%
//从数据库中查询
List list = new ArrayList<>();
list.add(new Emp(1, "张无忌", "经理", new Date(), 5000.0));
list.add(new Emp(2, "赵敏", "主管", new Date(), 3000.0));
list.add(new Emp(3, "金毛狮王", "职员", new Date(), 2000.0));
list.add(new Emp(4, "灭绝师太", "职员", new Date(), 2000.0));
list.add(new Emp(5, "周芷若", "总监", new Date(), 8000.0));
%>
编号
姓名
职位
生日
工资
<% SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); %>
<% for (Emp emp : list) {%>
<%out.write(emp.getId()+"");%>
<%out.write(emp.getName());%>
<%out.write(emp.getPosition());%>
<%out.write(sdf.format(emp.getBirthday()));%>
<%out.write(emp.getSalary()+"");%>
<% }%>
JSP看似是HTML代码,看似是页面,但其实是一种后端技术。
当我们第一发送请求访问jsp资源时,Tomcat服务器中的JSP加载引擎会将该JSP资源转换成一个 .java 文件(Servlet)。
这个 .java文件其实就是一个Servlet,在这个Servlet中已经将写在JSP中的HTML代码以writer.print()的方式编写好了,然后将数据响应给浏览器的。
JSP本质上就是一个Servlet,JSP中的HTML代码就相当于我们之前在Servlet中写的writer.write()代码。
JSP的执行过程大致可以分为三个时期:转换、编译、执行。
转换/翻译(translation):Tomcat中的JSP引擎将JSP网页转换成Servlet,得到一个.java文件。
编译(compile):通过javac命令将.java文件编译成 .class文件。
.
运行:运行.class字节码文件,处理请求。 具体运行过程:
浏览器发起请求访问jsp。
Tomcat服务器接收到请求后调用对应的Servlet处理请求,调用JspServlet。
JspServlet将请求的jsp文件转换成对应的Java文件并完成编译。
将编译后的class文件加载到内存并执行,其实就是运行一个Servlet。
最后得到结果数据响应浏览器。
jsp页面上所有的HTML相关代码全部被转化成了字符串,并在_jspService方法中,通过流的形式响应给了浏览器。 当JSP页面在执行时,JSP 引擎会做检查工作,如果发现JSP页面中有更新修改时,JSP引擎会再次转换JSP为Servlet,如果没有更新,就直接执行之前转换好的Servlet。
JSP与Servlet执行性能上的差别只在第一次的执行上。因为在第一次执行jsp时,jsp要经过转换、编译、执行三个过程。而之后再次访问jsp页面时,就直接执行第一次所产生的Servlet即可,不需要每次都转换、编译。
JSP本质上是Servlet,在请求jsp时,要经过执行,其内部是通过大量的IO流形式将内容发送给页面的,IO流就是一种比较耗费资源的操作。而HTML本身资源是已经存在的,不需要服务器执行什么操作。
但JSP是动态资源,可以动态的展示数据。
查看Tomcat conf/web.xml文件发现,这里默认配置了一个JSP的加载引擎-JspServlet。
jsp
org.apache.jasper.servlet.JspServlet
fork
false
xpoweredBy
false
3
jsp
*.jsp
*.jspx
JSP加载引擎的作用:
转换JSP页面:将JSP页面转换成一个Servlet。
编译JSP对应的Java文件:JSP引擎调用Java编译器对这个Servlet进行编译,得到可执行文件class。
请求处理:JSP引擎调用java虚拟机来解释执行class文件,得到结果响应浏览器。
HttpJSPBase重写了init,service和destory方法。
并且自定义了 jspInit, jspService, jspDestory。
然后在重写的init方法中调用了 JSPInit,在重写的service方法中调用了 jspService,在重写的destory方法中调用了 jspDestory。
我们JSP的文件编译成JAVA代码后,继承HttpJspBase重写的方法是 jspInit, jspService, jspService。
在jsp中可以通过 <%%> 和 <%!%>两种方式来书写代码,这两种方式中写的Java代码在转换后生成的代码在Servlet中位置是不一样的,前者在_jspService方法中,后者在Servlet中作为类的成员。
<%%>中定义的变量是局部变量
<%!%>中定义的变量是成员变量
JSP本质上是Servlet,在Servlet中我们是不推荐定义一些成员变量的。
JSP中可以写HTML、Java、CSS、JS代码,那么也就可以写这些语言的注释,并且JSP也有自己的注释方式。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
Title
<%--我是jsp注释--%>
推荐在jsp中使用jsp自己的注释:<%--注释内容--%>
JSP和Servlet本质上是相同的。所以说,JSP页面功能和Servlet中功能完全可以互换。
JSP的编码风格是在HTML中嵌入少量的Java代码,它用于展示数据比较方便。
Servlet适合编写Java代码。
所以在MVC分层上,我们往往将Servlet作为控制层(C),将JSP作为视图层(V)。M(model)模型层
以后通过Servlet去处理请求,得到结果,然后通过JSP来进行结果展示。
指令标签是JSP页面上的一种特殊标签,JSP指令可以用来设置整个JSP页面相关的属性,如网页的编码方式、网页使用的脚本语言、导包等。
指令标签的语法:
<%@ directive attribute="value" %>
JSP中的三种指令标签:
指令 | 描述 |
---|---|
<%@ page %> | 定义网页依赖属性,如脚本语言、error页面、缓存需求等等 |
<%@ include %> | 包含其他文件 |
<%@ taglib %> | 引入标签库的定义 |
属性 | 描述 |
---|---|
buffer | 指定out对象使用缓冲区的大小 |
autoFlush | 控制out对象的 缓存区 |
contentType | 指定当前JSP页面的MIME类型和字符编码 |
errorPage | 指定当JSP页面发生异常时需要转向的错误处理页面 |
isErrorPage | 指定当前页面是否可以作为另一个JSP页面的错误处理页 |
extends | 指定servlet从哪一个类继承 |
import | 导入要使用的Java类 |
info | 定义JSP页面的描述信息 |
isThreadSafe | 指定对JSP页面的访问是否为线程安全 |
language | 定义JSP页面所用的脚本语言,默认是Java |
session | 指定JSP页面是否使用session,默认是使用 |
isELIgnored | 指定是否执行EL表达式 |
isScriptingEnabled | 确定脚本元素能否被使用 |
常用的:
contentType:告诉浏览器响应的数据类型及编码格式
contentType="text/html;charset=UTF-8"
errorPage:指定错误页,当前页面发生错误时,显示错误页面的信息
errorPage="error500.jsp
import:导包
import="com.sh.pojo.Emp"
JSP可以通过include指令来包含其他文件。被包含的文件可以是jsp文件、HTML文件或文本文件。
包含的文件就像是jsp文件的一部分,会被同时编译执行。
除了使用include指令标签可以实现引入外,使用jsp:include动作也可以实现引入。
静态引入: @include 被引入的网页和当前页生成代码后形成了一个java文件。
动态引入: jsp:include 被引入的JSP页面会生成独立的java代码。
静态引入,被引入的jsp页面不会单独生成java代码文件,当前页和被引入页会生成一个java文件
<%@ include file="hello2.jsp"%>
动态引入:被引入的页面会生成独立的java代码,在当前页生成的java代码中使用
org.apache.jasper.runtime.JspRuntimeLibrary.include(request, response, "hello3.jsp", out, false);
引入其他页面
可以在jsp页面中引入其他的标签库
<%@ taglib uri="uri" prefix="prefixOfTag" %>
JSP的本质是Servlet,在JSP文件经过转译之后,生成JAVA代码,在运行时,JSP给我们准备好了九个可以直接使用的对象,这九个对象我们称之为内置对象。
四个域对象
pageContext page域 当前页面内可用。
request reqeust域 一次请求。
session session域 一次会话, 多次请求。
application application域 整个项目运行, 多次请求, 多次会话。
响应对象
response 响应对象。
输出流对象
out 打印流对象。
其他三个对象
servletConfig 由于JSP本身也是一个Servlet,所以容器也会给我们准备一个ServletConfig。
page 就是JSP转换的Servlet的对象,也就是当前JSP对象本身 。
exception 异常对象,在错误提示页上使用,当isErrorpage=true 才具有该对象。
注意事项:
response对象 当服务器创建request对象时会同时创建用于响应客户端的response对象。
out对象 是 JspWriter 类的实例,不是PrinterWriter的实例;用来在response对象中写入内容。JspWriter类包含了大部分java.io.PrintWriter类中的方法。不过,JspWriter增了一些专为处理缓存而设计的方法。另外JspWriter类会抛出IOExceptions异常。 最初的JspWriter类对象根据页面是否有缓存来进行不同的实例化操作。可以在page指令中使用。buffered='false'属性来轻松关闭缓存。
pageContext对象 PageContext类的实例,用来代表整个JSP页面;提供对JSP页面所有对象以及命名空间的访问。
创建Jsp文件,在项目的web目录下创建。
使用page指令设置Jsp的转译细节(一般自动生成的就够用)。
使用tablib指令引入第三方的自定义标签来使用(JSTL标签)。
使用HTML,CSS,JQuery完成页面的开发。
使用<%%>声明java脚本片段完成数据的动态拼接。
<%%>:生成在_jspService()方法中
<%! %>:生成在类中
<%= %>:生成在_jspService()方法中,输出
获取request或者session中的数据拼接到当前页面中(内置对象)。
在jsp页面中可以使用EL表达式来获取域对象中的数据
可以获取作用域对象中的数据。
底层使用的是反射,在使用的时候可以通过键名即可获取对应的值。
简化了在jsp页面中使用<%%>获取域对象数据的方式。
基本语法
${键名},键名是域对象中存储的数据的键。
${键名.属性名.属性名…},可以获取域对象中级联属性的值。
${键名[角标]},获取域对象中存储的list集合或者数组中指定角标的数据。
注意:${}不仅可获取域对象中的数据,而且会将该数据打印到浏览器中。如果获取不到数据,也不会报错,只是不显示而已。
作用域数据查找顺序
使用EL表达式获取域数据的时候,如果没有指明作用域,那会按照作用域由小到大的顺序去找,直到找到为止: pageContext ---> request ---> session ---> application
指定获取某个作用域中的数据
${pageScope.键名} 获取page域对象中的数据
${requestScope.键名} 获取request域对象中的数据
${sessionScope.键名} 获取session域对象中的数据
${applicationScope.键名} 获取application域对象中的数据
获取request对象中的请求数据
${param.键名},可以获取request中携带的请求参数的数据
获取request对象中Cookie的key value
${cookie.JSESSIONID.name}
${cookie.JSESSIONID.value}
EL表达式可以使用比较运算和算术运算
${键名 逻辑运算符 键名} ${键名 算术运算符 键名}
注意: + 表示的是算术运算,而不是字符串拼接。
使用脚本方式获取数据
- 获取简单数据:<%out.write(request.getAttribute("name").toString());%>
- 获取对象数据:<%out.write(((Emp)request.getAttribute("emp")).getName());%>
- 获取list集合数据:<%out.write(((List)request.getAttribute("list")).get(0).toString());%>
- 获取map集合数据:<%out.write(((Map)request.getAttribute("map")).get("key1").toString());%>
使用EL表达式方式获取数据
- 获取简单数据:${name}
- 获取对象数据:${emp}
- 获取list集合数据:${list[0]}
- 获取map集合数据:${map.key1}
指明域对象获取数据
- 获取request域数据:${requestScope.requestParam}
- 获取session域数据:${sessionScope.sessionParam}
- 获取application域数据:${applicationScope.applicationParam}
使用逻辑表达式
${3 > 4}
${5 + 8}
可以使用JSTL标签来完成一些例如循环、判断等情况的与数据输出。
JSTL的作用就是:替换在Jsp中声明的Java逻辑代码。
JSTL标签库是第三方发明的自定义的标签,每个标签都有自己特定的含义表示一个具体的java逻辑。我们要在JSP中使用JSTL必须使用taglib标签引入第三方的标签库资源。 标签库的内容有:
核心标签库
SQL标签库
函数标签库
格式化标签库
XML标签库
使用步骤:
在项目中导入JSTL的jar包。
在jsp页面中通过taglib指令引入jstl标签库。
使用jstl标签完成开发。
if判断
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
Title
<%
request.setAttribute("gender", "0");
%>
<%--
c:if 标签的作用就相当于Java中的if判断
格式是: 条件成立输出的内容
--%>
性别是男。
循环
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
Title
${emp.id}---${emp.name}---${emp.position}
${i} --- ${status.index}