JSP
前言
在web开发中,服务器利用网络,将数据通过IO流的形式传输给浏览器。但是,浏览器,只支持超文本标记语言,多种数据。例如:HTML,CSS,Javascript,音频和视频等等。而然,不管是哪种数据,都是通过HTTP协议传输给浏览器,且常用的数据是HTML相关数据。所以,WEB开发,需要将原生数据,组装成HTML语言类型的数据,然后再传输给浏览器。此时,JavaWeb的设计发现,开发相对麻烦。因为对原生数据进行加工时,在做重复的工作,且工作量相对较大。基于这样大的原因,JavaWeb利用,模板技术,将公共部分进行封装,然后再公共部分中进行解析动态的数据,这样就形成一套模板技术,例如:freemarker,Thymeleaf,Velocity,jsp等等。而JSP这个模板技术,是Java自身的。
1.JSP介绍
1.1.什么是JSP
JSP(全称JavaServer Pages)是由[Sun Microsystems](https://baike.baidu.com/item/Sun Microsystems)公司主导创建的一种动态网页技术标准。JSP部署于网络服务器上,可以响应客户端发送的请求,并根据请求内容动态地生成HTML、XML或其他格式文档的Web网页,然后返回给请求者。JSP技术以Java语言作为脚本语言,为用户的HTTP请求提供服务,并能与服务器上的其它Java程序共同处理复杂的业务需求。
JSP将Java代码和特定变动内容嵌入到静态的页面中,实现以静态页面为模板,动态生成其中的部分内容。JSP引入了被称为“JSP动作”的XML标签,用来调用内建功能。另外,可以创建JSP标签库,然后像使用标准HTML或XML标签一样使用它们。标签库能增强功能和服务器性能,而且不受跨平台问题的限制。JSP文件在运行时会被其编译器转换成更原始的Servlet代码。JSP编译器可以把JSP文件编译成用Java代码写的Servlet,然后再由Java编译器来编译成能快速执行的二进制机器码,也可以直接编译成二进制码。
JSP通俗而言,就是一个可以书写Java代码的页面技术。JSP本质其实一个类。
1.2.JSP的特征
JSP本质是一个类,所以在JSP页面中,代码默认是自上而下执行的,且需要书写Java代码时,必须使用<%%>或者
<%= %>包裹,注意,<% %> 中包裹的代码会当做Java代码进行执行,而<%=%> 包裹的代码会将代码运算结果输出到页面。
例如:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
jsp demo
<%
/* 会执行的java代码 */
System.out.print("元宵快乐");
String message = "元宵快乐";
%>
<%=message %>
9*9乘法表
<%
for(int i=1;i<=9;i++){
for(int m = 1;m<=i;m++){
String str = i+"*"+m +"="+i*m+" ";
%>
<%=str %>
<%
}
%>
<%
}
%>
注意: 被<%%>包裹的是Java代码
1.3.jsp为什么能写java代码
因为所有的jsp页面,在第一个被访问时,会被翻译成一个对应的java文件,jsp名称作为java文件名前缀,使用_jsp进行拼接的java文件。然后,会将java文件进行编译产生class文件,再将编译后的字节码文件加载到JVM中进行运行。
每一个jsp,都会被翻译成一个实现了servlet接口的类,所以所有的jsp本质上是一个类,且是一个Servlet类。jsp中的内容,被这个类中的_jspService方法进行了处理。在这个方法中,获取了一个对应的输出流对象,这个输出流对象会将jsp页面中内容,默认当做字符串进行流输出。当遇到<%%>包裹的内容时,会当做java代码不进行输出。会将<%=%>包裹的内容,使用输出流进行打印(会使用print进行打印输出,writer只能输出字符串之类的类型,而print可以输出任意类型,而被输出的java内容,可能是任意类型,所以不能使用writer)。这样就生成 了一个HTML页面。
翻译示例:
public void _jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response)
throws java.io.IOException, javax.servlet.ServletException {
final java.lang.String _jspx_method = request.getMethod();
if (!"GET".equals(_jspx_method) && !"POST".equals(_jspx_method) && !"HEAD".equals(_jspx_method) && !javax.servlet.DispatcherType.ERROR.equals(request.getDispatcherType())) {
response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, "JSPs only permit GET POST or HEAD");
return;
}
final javax.servlet.jsp.PageContext pageContext;
javax.servlet.http.HttpSession session = null;
final javax.servlet.ServletContext application;
final javax.servlet.ServletConfig config;
javax.servlet.jsp.JspWriter out = null;
final java.lang.Object page = this;
javax.servlet.jsp.JspWriter _jspx_out = null;
javax.servlet.jsp.PageContext _jspx_page_context = null;
try {
response.setContentType("text/html; charset=UTF-8");
pageContext = _jspxFactory.getPageContext(this, request, response,
null, true, 8192, true);
_jspx_page_context = pageContext;
application = pageContext.getServletContext();
config = pageContext.getServletConfig();
session = pageContext.getSession();
out = pageContext.getOut();
_jspx_out = out;
out.write("\r\n");//换行
out.write("\r\n");
out.write("\r\n");
out.write("\r\n");
out.write("\r\n");
out.write("jsp demo \r\n");
out.write("\r\n");
out.write("\r\n");
/* 会执行的java代码 */
System.out.print("元宵快乐");// 在控制台打印。 System.out 和 out
String message = "元宵快乐";// 定义了一个变量
out.write("\r\n");// 换行 2行
out.write("\r\n");
out.print(message );
out.write("\r\n");
out.write("9*9乘法表
\r\n");
for(int i=1;i<=9;i++){
for(int m = 1;m<=i;m++){
String str = i+"*"+m +"="+i*m+" ";
out.write("\t\r\n");
out.write("\t\r\n");
out.write("\t");
out.print(str );
out.write('\r');
out.write('\n');
out.write(' ');
}
out.write("\t\r\n");
out.write("\t\r\n");
out.write("\t\t
\r\n");
out.write("\t");
}
out.write("\r\n");
out.write("\r\n");
out.write("\r\n");
out.write("");
} catch (java.lang.Throwable t) {
if (!(t instanceof javax.servlet.jsp.SkipPageException)){
out = _jspx_out;
if (out != null && out.getBufferSize() != 0)
try {
if (response.isCommitted()) {
out.flush();
} else {
out.clearBuffer();
}
} catch (java.io.IOException e) {}
if (_jspx_page_context != null) _jspx_page_context.handlePageException(t);
else throw new ServletException(t);
}
} finally {
_jspxFactory.releasePageContext(_jspx_page_context);
}
}
1.4.JSP案例
由于JSP本质是一个类,那么在一个类中调用另外一个类中方法是理所当然的。那么,使用JSP将数据库中的数据呈现在页面。
使用JSP,将数据库中数据展示现在页面。
<%@page import="com.sxt.pojo.Student"%>
<%@page import="java.util.List"%>
<%@page import="java.util.HashMap"%>
<%@page import="java.util.Map"%>
<%@page import="com.sxt.dao.StudentDao"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
学生信息列表
<%
/* 在jsp中 一样需要 import 包 ,在jsp中使用 alt+/ */
Map param = new HashMap();
//调用dao层方法 获取数据库中所有学生数据
List sts = new StudentDao().selectList(param);
%>
ID
学号
名称
性别
年龄
总分
<%
for(int i=0;i
<%=st.getId() %>
<%=st.getStNo() %>
<%=st.getName() %>
<%=st.getSex() %>
<%=st.getAge() %>
<%=st.getScore() %>
<%} %>
效果:
注意: 此时JSP页面就充当了View(视图,界面)的角色。
1.5.JSP的作用
在web中,JSP可以转化为WEB页面,所以JSP可以充当视图,界面。用于,与用户进行交互。JSP还能接收用户的请求,且对这个请求作出处理,生成动态数据相关web网页,且将网页数据返回给客户端。用户的请求request,用户请求的是服务器。
1.6.JSP九大内置对象
tomcat在处理jsp页面时,会自动生成9个对象(内建对象),所以被称之为9大内置对象:
对象名 | 类型 | 描述 |
---|---|---|
request | javax.servlet.http.HttpServletRequest | 用于处理客户端的请求的对象,服务器将请求信息都封装在这个对象中 |
response | javax.servlet.http.HttpServletResponse | 用于向客户端作出响应的对象。可以通过该对象,向客户端作出数据响应 |
pageContext | javax.servlet.jsp.PageContext | 当前页面容器对象,包含其它内置对象 |
config | javax.servlet.ServletConfig | Servlet配置对象,每个JSP都是一个Servlet,可以通过该对象获取初始化配置参数 |
page | java.lang.Object | 表示当前jsp对应的类对象 |
application | javax.servlet.ServletContext | 表示整个应用的容器的对象 |
session | javax.servlet.http.HttpSession | 表示当前会话的,会话对象 |
out | javax.servlet.jsp.JspWriter | 表示一个输出对象,可以将数据输出到页面 |
exception | java.lang | 表示一个异常对象,当JSP页面发生异常时,异常信息就会封装在该对象中 |
注意: 以上九大内置对象需要默写下来,因为9大内置对象,属于面试的内容之一。
9大内置对象,可以在JSP页面直接使用。
<%
/* request对象
此时是没有创建 request 对象的
如果一下打印语句 不为null 那说明,程序中内部存在request对象
request 对象是用于 处理客户端的请求信息的对象 request 对象 代表就是客户端的请求信息
客户端的请求信息 都被封装在该对象中
*/
System.out.println(request);
// getParameter("name") : 根据名称 获取对应的请求参数的值 ,name就是请求参数的key
System.out.println(request.getParameter("name"));
System.out.println(request.getParameter("age"));
/* response 对象 用于向客户端作出响应数据的对象 */
System.out.println(response);
// 获取与客户端相关联的输出流对象 字符流
PrintWriter pw = response.getWriter();
//pw.print("元宵节快乐!!!");
//字节流 这个用于向客户端输出 非文本信息的数据 多媒体数据
//ServletOutputStream os = response.getOutputStream();
/*pageContext : 当前页面容器。 该容器包含,其他内置对象 */
System.out.println("pageContext:"+pageContext);
System.out.println("request:"+pageContext.getRequest());
System.out.println("response:"+pageContext.getResponse());
/*config 对象 具体的讲解 待 servlet时进行讲解*/
/*page 对象: 表示当前jsp对应类的对象*/
System.out.println("page:"+page);
/*application对象 : 表示当前应用一个全局容器对象 注意,整个应用启动时就会创建该对象,有且只有一个*/
System.out.println("application对象:"+application);
/*session对象: 表示与当前请求关联的会话对象,一个会话包含多个请求,默认会话对象有效30分钟,一般会话对象
从第一次就浏览器请求,到关闭浏览器窗口(30分钟内)
*/
System.out.println("session对象:"+session);
/* out对象:根据当前response对象,获取的一个输出对象,用于将一般的数据输出给客户端 */
out.print("元宵节快乐!!!");
%>
1.7.四大作用域
1.7.1.什么是作用域?
域:范围。作用域: 有效的范围。
1.7.2.四大作用域
在JSP中,9大内置对象由于某些内置对象的特殊性,区分出了4大作用域,如下:
对象名 | 作用域 | 描述 |
---|---|---|
pageContext | 当前页面 | 在pageContext中存储的数据,只能被当前页面获取到 |
request | 一次请求 | 在request中存储的数据,在同一次请求中可以获取到 |
session | 一次会话 | 在session中存储的数据,在同一次会话中可以获取到 |
application | 当前应用 | 在application中存储的数据,在当前应用中生效 |
注意:所有作用域对象,有一些功能的方法:存储数据/获取数据/删除数据等
setAttribute(name, value) :向作用域中存储数据,以key-value的形式存储
getAttribute("name") :从作用域中获取数据
removeAttribute(“name”):从作用域中删除数据,根据name作为key,从容器中删除数据
1.7.3.pageContext与request
pageContext的范围,是单纯当前页面,而request的返回是一次请求,一次请求可以包含多个页面。
可以通过内部转发的形式,将一个请求传递到另外一个页面中,此时一次请求可能经历多个页面。所以就是一个请求可以包含多个页面。
注意:
根据以上分析:四大作用于,其范围从小到大:pageContext --- > request ---> session ----> application作用域的意义,在于存储数据,进行数据传递。那么在程序开发,若需要将数据进行传输,需要使用4大作用域。4个作用域,根据其范围,也有其特定的生命周期,最大的作用域,生命周期其贯穿整个程序,任何人都能访问。若数据存在里面,不安全。session,作用域,是同一次会话,session默认是30分钟,只要创建session对象,那么这个对象就会驻留在内存中30分钟。可能存在浪费内存的行为,一般用于处理,多次请求的数据,会将多次请求需要使用的共享数据放入session。request对象,一般用于同一次请求中,不同地址间的数据传输。若在其他页面(地址)需要使用当前一些数据,可以存在request中,使用内部转发,跳转到指定的地址。pageContext作用,一般不做业务数据的存储,只用于获取其他内置对象。所以,在程序开发中,尽量选择作用域范围小的作用域对象。节约资源。
1.7.4.内部转发和重定向
在之前的例子中,可以使用:内部转发
request.getRequestDispatcher("地址").forward(request, response);
进行页面跳转,而且还可以进行数据传输.这种跳转方式被称之为内部转发。JavaWeb还提供了一种方式,重定向:重定向
response.sendRedirect("地址");
以上两种方式都可以实现页面跳转。那么差别在哪里:
比较 | 重定向 | 内部转发 |
---|---|---|
URL地址栏 | 地址栏会发生改变 | 地址栏不会发生改变 |
参数传递 | 不能将request作用域数据进行传递 | 可以将request作用域中数据进行传递 |
浏览器请求 | 会通知浏览器进行多次请求 | 服务器内部处理,只需要一次请求 |
思考:重定向和内部转发都能实现地址的跳转,需要进行地址跳转时,使用哪种?
重定向与内部转发对比而言,内部转发在数据的传递上更具优势,所以若涉到数据传递,就优先使用内部转发。但是,使用内部转发的程序,一旦发生页面刷新。期间,所有已经执行过的程序,会重新执行。容易造成服务器的压力和异常,其根本原因,是因为浏览器URL地址栏,没有发生改变,所以刷新后,会重新请求。
而重定向,会改变浏览器URL地址栏上的地址,所以刷新时,没有相关问题,所以,若要实现地址的跳转,优先使用重定向,若涉及到数据的传输,重定向无法满足,考虑使用内部转发。