浅谈JSP技术
1.JSP简述
JSP(Java Servlet Pages)是由Sun公司倡导、许多企业参与建立起来的一种动态技术标准。从本质上来讲,JSP就是嵌入Java代码的Html文件。
1.1 使用Servlet程序输出Html页面的弊端
下面是PrintHtmlServlet程序:
public class PrintHtmlServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//通过响应的输出流回传html页面数据
resp.setContentType("text/html;charset=utf-8");
PrintWriter writer = resp.getWriter();
writer.write(" <!DOCTYPE html>\r\n");
writer.write("<html lang=\"en\">\r\n");
writer.write(" <head>\r\n");
writer.write("<meta charset=\"UTF-8\">\r\n");
writer.write("<title>Title</title>\r\n");
writer.write("<title>Title</title>\r\n");
writer.write("</head>\r\n");
writer.write("<body>\r\n");
writer.write("这是html页面数据\r\n");
writer.write("</body>\r\n");
writer.write("</html>\r\n");
}
}
运行后的结果为:
在引入JSP页面之前,在Web应用程序中,所有的业务逻辑和HTML的响应都是在Servlet中进行实现的,使用这种方式时,存在一个很大的弊端: 必须要给用户响应的视图组装成一个很长的HTML格式的字符串写入println()方法中。
使用上述的方式进行编程,在编写一段很长的HTML格式的字符时非常容易出错,而且代码的可读性非常差,由于业务逻辑与视图没有进行分离,系统的可维护性与可扩展性都比较差。
1.2 JSP优点
JSP的引入在一定程度上解决了Servlet存在的缺点。其实现理念是让每个Servlet只负责其对应的业务逻辑的处理,让JSP来负责用户的HTML显示,因此实现了业务逻辑与视图实现的分离,从而提高了系统的可扩展性。
引入JSP后,Servlet的实现结构如下:
public class MyServlet extends HttpServlet{
public void doGet(HttpServletRequest request,HttpServlet Response response) throws ServletException,IO Exception{
//business logic code(业务逻辑代码)
//forward the request to a JSP page(请求转发到JSP页面)
}
}
1.3 演示:在web工程中创建一个jsp动态页面
- 1.选中WebContent目录,右键创建一个jsp文件。
- 2.输入jsp页面的文件名
- 3.在body标签中可以进行显示需要编写的文件内容
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
这是jsp页面
</body>
</html>
- 4.在浏览器中输入jsp页面的访问地址
注意:jsp页面的访问地址和html页面的访问路径一样,皆为http://ip:port/工程名/文件名。
jsp页面页面的访问千万不能像HTML页面一样,托在浏览器中,只能通过浏览器访问Tomcat服务器再访问jsp页面。
2.JSP的本质
JSP页面本质上就是一个Servlet程序。当我们第一次访问JSP页面的时候,Tomcat服务器会帮我们把JSP页面翻译成一个Java源文件,并且对它进行编译成功为.class字节码文件。
从源码上可以可以看出,HttpBase类直接继承了HttpServlet类。JSP翻译出来的java类,它间接继承了HttpServlet类,实质上就是一个Servlet程序。
3.JSP与Servlet的异同
JSP与Servlet的异同点 |
---|
相同点:JSP可以看作是一个特殊的Servlet,它只不过是对Servlet的扩展。只要是JSP可以完成的工作,使用Servlet都可以完成,例如生成动态页面。由于JSP页面最终是要被转换成Servlet来运行,因此处理请求实际上是编译后的Servlet。 |
不同点:1.Servlet的实现方式是在Java中嵌入HTML代码,编写和修改HTML非常不方便,它比较适合做流程控制、业务处理;JSP的实现方式为在HTML代码中嵌入Java代码,比较适合页面的显示。2.Servlet中没有内置对象,JSP中的内置对象都是通过HttpServletRequest对象、HttpServletResponse对象以及HttpServlet对象得到。 |
4.jsp的三种语法
4.1 jsp头部的page指令
jsp的page指令可以修改jsp页面中一些重要的属性,或者行为。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
jsp头部的page指令 | 含义 |
---|---|
language属性 | 表示翻译后是什么语言文件,暂时只支持java。 |
contentType 属性 | 表示 jsp 返回的数据类型是什么。也是源码中 response.setContentType()参数值 |
pageEncoding 属性 | 表示当前 jsp 页面文件本身的字符集。 |
import属性 | 与java源代码中一样,用于导包,导类。 |
autoFlush 属性 | 设置当 out 输出流缓冲区满了之后,是否自动刷新冲级区。默认值是 true。 |
buffer 属性 | 设置 out 缓冲区的大小。默认是 8kb |
errorPage 属性 | 设置当 jsp 页面运行时出错,自动跳转去的错误页面路径。errorPage 表示错误后自动跳转去的路径,这个路径一般都是以斜杠打头,它表示请求地址为 http://ip:port/工程路径。 |
isErrorPage 属性 | 设置当前 jsp 页面是否是错误信息页面。默认是 false。如果是 true 可以获取异常信息。 |
session 属性 | 设置访问当前 jsp 页面,是否会创建 HttpSession 对象。默认是 true。 |
extends 属性 | 设置 jsp 翻译出来的 java 类默认继承谁。 |
4.2 jsp中的常用脚本
4.2.1 声明脚本
在jsp中声明脚本的格式是:
<%!声明 java 代码%>
声明脚本的作用:可以给jsp翻译出来的java类定义属性和方法甚至是静态代码块,内部类等。
声明脚本代码实例:
<%--1、声明类属性--%>
<%!
private Integer id;
private String name;
private static Map<String,Object> map;
%>
<%--2、声明static静态代码块--%>
<%!
static {
map = new HashMap<String,Object>();
map.put("key1", "value1");
map.put("key2", "value2");
map.put("key3", "value3");
}
%>
<%--3、声明类方法--%>
<%!
public int abc(){
return 12;
}
%>
<%--4、声明内部类--%>
<%!
public static class A {
private Integer id = 12;
private String abc = "abc";
}
%>
声明脚本对应的翻译后的代码为:
4.2.2 表达式脚本
在jsp中表达式脚本的格式是:
<%=表达式%>
表达式脚本的作用是:在jsp页面上输出数据。
表达式脚本的特点:
- 1.表达式脚本都会被翻译到_jspService()方法中。
- 2.表达式脚本都会被翻译成out.print()输出页面上。
- 3.由于表达式脚本翻译的内容都在_jspService()方法中,所以_jspService()方法中的对象都可以直接使用。
表达式脚本格式:
<%--练习:
1.输出整型
2.输出浮点型
3.输出字符串
4.输出对象 --%>
<%=12 %> <br>
<%=12.12 %> <br>
<%="我是字符串" %> <br>
<%=map%> <br>
<%=request.getParameter("username")%>
表达式脚本翻译后的代码如下:
4.2.3 代码脚本
代码脚本的格式是:
<%java 语句%>
jsp中代码脚本的作用是:在jsp页面中,可以在代码脚本中编写需要的功能。代码脚本中写的是java语句。
代码脚本的特点是:
- 1.代码脚本翻译之后都在_jspService方法中。
- 2.代码脚本由于翻译到_jspService()方法中,在_jspService()方法中的现有对象都可以直接使用。
- 3.可以由多个代码脚本块组合完成一个java语句。
- 4.代码脚本可以与表达式脚本一起组合使用,在jsp页面上输出数据。
<%--代码脚本--%>
<%--1.代码脚本--if语句--%>
<%
int i=1;
if(i==1){
System.out.println("输入的数等于1");
}else{
System.out.println("输入的数不等于1");
}
%>
<%--2.代码脚本--for 循环语句--%>
<br>
<%
for (int j=0;j<10;j++){
%><%=j%><br>
<% }
%>
<%--3.翻译后的java文件中_jspService方法内的代码都可以写--%>
<%
String username = request.getParameter("username");
System.out.println("用户名的请求参数为:"+username);
%>
4.3 jsp中的三种注释
4.3.1 html注释
html注释的格式为:
<!-- 这是 html 注释-->
html代码会被翻译成java源代码中,在_jspService方法里,是以out.write()进行输出到客户端。
4.3.2 java注释
java注释的格式为:
<%
// 单行 java 注释
/*多行 java 注释*/
%>
java注释会被翻译到java源码中。
4.3.3 jsp注释
jsp注释的格式为:
<%-- 这是 jsp 注释--%>
注意:jsp注释可以注释掉jsp页面中的所有代码。
5.JSP中的内置对象
在JSP中,内置对象又被称为隐含对象,是指在不声明和不创建的情况下就可以被使用的一些成员变量。
JSP中一共提供有9个内置对象:request(请求对象)、response(响应对象)、pageContext(页面上下文对象)、session(会话对象)、application(应用程序对象)、out(输出对象)、config(配置对象)、page(页面对象)与exception(例外对象)。
JSP内置对象名称 | 描述 |
---|---|
request | 客户端请求,此请求包含来自GET/POST请求的参数。客户端的请求信息被封装在request对象中,通过它才能了解到客户端的需求,然后做出响应,所以request对象是用来获取请求请求参数的非常重要的途径。它是HttpServletRequest类的实例。 |
response | 用来表示服务器端对客户端的响应,将Web服务器处理后的结果返回到客户端。但在JSP中很少使用到它。它是HttpServletResponse类的实例。 |
pageContext | 提供了对JSP页面的所有对象及命名空间的访问,也就是说,用它可以访问到本页面的所有其他对象,它的本类名也叫做pageContext。 |
session | 用来表示客户端与服务器的一次会话。从客户端与Web服务器建立连接的时候会话开始,直到关闭浏览器时结束会话。它是HttpSession类的实例。 |
application | 代表JSP所属的Web应用本身。application对象可以存放全局变量,因此可以实现用户间的数据共享。它的生命周期与服务器的生命周期一致,也就是说,服务器启动海后这个对象即被创建出来,直到服务器停止后这个对象的生命周期才停止。它是ServletContext类的实例。 |
out | 用于在客户端浏览器内输出信息。它是JSPWriter类的实例 |
config | 主要作用是取得服务器的配置信息。当一个Servlet初始化时,容器把某些信息通过config对象传递给这个Servlet,Servlet可以使用这个对象获取所需的配置信息 |
page | 表示当前的JSP页面,类似于Java中this指针。它是java.lang.Object类的实例。 |
exception | 用来表示异常。当一个页面在运行过程中产生例外,就会产生这个对象。如果JSP需要使用这个对象,就必须把isErrorPage设为true,否则将无法进行编译。它是java.lang.Throwable的对象。 |
6.JSP中四大域对象
JSP中四大域对象 | 作用范围 |
---|---|
pageContext(PageContextImpl类) | 当前jsp页面范围内有效 |
request(HttpServletRequest类) | 一次请求内有效 |
session(HttpSession类) | 一次会话范围内有效(打开浏览器访问服务器,直到关闭浏览器) |
application(ServletContext类) | 整个web工程范围内都有效(只要web工程不停止,数据都在) |
域对象是可以像Map一样可以进行存取数据的对象操作。四个域对象功能一样。不同的是它们对于数据的存取范围。
虽然四个域对象都可以存取数据。在使用上它们是有优先顺序的。四个域在使用的时候,优先顺序分别是,他们从小到大的范围的顺序。
pageContext====>>>request====>>>session====>>>application
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>这是scope.jsp页面</h1>
<%
pageContext.setAttribute("key","pageContext");
request.setAttribute("key","request");
session.setAttribute("key","session");
application.setAttribute("key","application");
%>
pageContext域是否有值:<%=pageContext.getAttribute("key")%><br>
request域是否有值:<%=request.getAttribute("key")%><br>
session域是否有值:<%=session.getAttribute("key")%><br>
application域是否有值:<%=application.getAttribute("key")%><br>
<%
// request.getRequestDispatcher("/scope2.jsp").forward(request,response);
%>
<%--<jsp:forward page=""></jsp:forward>是请求转发标签,它的功能就是请求转发
page属性设置请求转发的路径
--%>
<jsp:forward page="/scope2.jsp"></jsp:forward>
</body>
</html>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>scope2.jsp页面</h1>
pageContext域是否有值:<%=pageContext.getAttribute("key")%><br>
request域是否有值:<%=request.getAttribute("key")%><br>
session域是否有值:<%=session.getAttribute("key")%><br>
application域是否有值:<%=application.getAttribute("key")%><br>
</body>
</html>
7.jsp中的out输出和response.getWriter输出的区别
response中表示响应,经常用于设置返回给客户端的内容(输出)。out也是给用户输出使用的。
由于jsp翻译之后,底层源代码都是使用out来进行输出的,在jsp页面中统一使用out来进行输出。避免打乱页面输出内容的顺序。
8.JSP的常用标签
8.1 jsp静态包含
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
头部信息<br>
主体内容<br>
<%--
<%@include file=""%>就是静态包含
file属性指定你要包含的jsp页面的路径
地址中第一个斜杠表示http://ip:port/工程路径 映射到IDEA中的web目录
静态包含的特点:
1.静态包含不会翻译被包含的jsp页面
2.动态包含其实是把被包含的jsp页面的代码拷贝到包含的位置执行输出
--%>
<%@include file="/include/foot.jsp"%>
</body>
</html>
8.2 jsp动态包含
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
头部信息<br>
主体内容<br>
<%--
<jsp:include page=""></jsp:include> 这是动态包含
page属性是指定你要包含的jsp页面的路径
动态包含也可以像静态包含一样,将被包含的内容执行输出到包含位置
动态包含的特点:
1.动态包含会把包含的jsp页面也翻译成java代码
2.动态包含底层代码使用如下代码去调用被包含的jsp页面执行输出
JspRuntimeLibrary.include(request, response, "/include/footer.jsp", out, false);
3.动态包含还可以传递参数
--%>
<jsp:include page="/include/foot.jsp">
<jsp:param name="username" value="zhangsan"/>
<jsp:param name="password" value="123456"/>
</jsp:include>
</body>
</html>
8.3 jsp转发
<%--
<jsp:forward page=""></jsp:forward> 是请求转发标签,它的功能就是请求转发
page 属性设置请求转发的路径
--%>
<jsp:forward page="/scope2.jsp"></jsp:forward>
9.Listener监听器
- 1.Listener 它是 JavaEE 的规范,就是接口。
- 2.Listener 监听器它是 JavaWeb 的三大组件之一。JavaWeb 的三大组件分别是:Servlet 程序、Filter 过滤器、Listener 监听器。
- 3.监听器的作用是,监听某种事物的变化。然后通过回调函数,反馈给客户(程序)去做一些相应的处理。
9.1 ServletContextListener 监听器
ServletContextListener 它可以监听 ServletContext 对象的创建和销毁。
ServletContext 对象在 web 工程启动的时候创建,在 web 工程停止的时候销毁。
监听到创建和销毁之后都会分别调用 ServletContextListener 监听器的方法反馈。
public interface ServletContextListener extends EventListener {
/**
* 在 ServletContext 对象创建之后马上调用,做初始化
*/
public void contextInitialized(ServletContextEvent sce);
/**
* 在 ServletContext 对象销毁之后调用
*/
public void contextDestroyed(ServletContextEvent sce);
}
9.2 ServletContextListener 监听器监听 ServletContext 对象
ServletContextListener 监听器监听 ServletContext 对象操作使用步骤为:
- 1.编写一个类实现ServletContextListener。
- 2.实现上面两个回调方法。
- 3.在web.xml配置文件中去配置监听器。
监听器实现类:
ublic class MyServletContextListenerImpl implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
System.out.println("ServletContext 对象被创建了");
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
System.out.println("ServletContext 对象被销毁了");
}
}
web.xml配置文件:
<listener>
<listener-class>com.westos.listener.ServletContextListenerImpl</listener-class>
</listener>
运行后的结果为: