JSP
一、JSP简介
1、什么是Java Server Pages?
一种动态网页开发技术。它使用JSP标签在HTML网页中插入Java代码。标签通常以<%开头以%>结束。JSP是一种Java servlet,主要用于实现JavaWeb应用程序的用户界面部分。网页开发者们通过结合HTML代码、XHTML代码、XML元素以及嵌入JSP操作和命令来编写JSP。JSP通过网页表单获取用户输入数据、访问数据库及其他数据源,然后动态地创建网页。JSP标签有多种功能,比如访问数据库、记录用户选择信息、访问JavaBeans组件等,还可以在不同的网页中传递控制信息和共享信息。
(servlet:擅长java代码的编写,JSP:擅长页面显示)
2、为什么使用JSP?
JSP程序与CGI程序有着相似的功能,但和CGI程序相比,JSP程序有如下优势:
a、性能更加优越,因为JSP可以直接在HTML网页中动态嵌入元素而不需要单独引用CGI文件。
b、服务器调用的是已经编译好的JSP文件,而不像CGI/Perl那样必须先载入解释器和目标脚本。
c、JSP基于Java Servlet API,因此,JSP拥有各种强大的企业级Java API,包括JDBC,JNDI,EJB,JAXP等等。
d、JSP页面可以与处理业务逻辑的 Servlet 一起使用,这种模式被Java servlet 模板引擎所支持。
最后,JSP是Java EE不可或缺的一部分,是一个完整的企业级应用平台。这意味着JSP可以用最简单的方式来实现最复杂的应用。
3、JSP的优势
a、与ASP相比:JSP有两大优势。首先,动态部分用Java编写,而不是VB或其他MS专用语言,所以更加强大与易用。
b、第二点就是JSP易于移植到非MS平台上。与纯 Servlet 相比:JSP可以很方便的编写或者修改HTML网页而不用去面对大量的println语句。
c、与SSI相比:SSI无法使用表单数据、无法进行数据库链接。
d、与JavaScript相比:虽然JavaScript可以在客户端动态生成HTML,但是很难与服务器交互,因此不能提供复杂的服务,比如访问数据库和图像处理等等。
e、与静态HTML相比:静态HTML不包含动态信息。
4、JSP处理流程
网络服务器需要一个JSP引擎,也就是一个容器来处理JSP页面。容器负责截获对JSP页面的请求使用内嵌JSP容器的Apache来支持JSP开发。JSP容器与Web服务器协同合作,为JSP的正常运行提供必要的运行环境和其他服务,并且能够正确识别专属于JSP网页的特殊元素。
JSP处理:
就像其他普通的网页一样,您的浏览器发送一个HTTP请求给服务器。Web服务器识别出这是一个对JSP网页的请求,并且将该请求传递给JSP引擎。通过使用URL或者.jsp文件来完成。
JSP引擎从磁盘中载入JSP文件,然后将它们转化为servlet。这种转化只是简单地将所有模板文本改用println()语句,并且将所有的JSP元素转化成Java代码。JSP引擎将servlet编译成可执行类,并且将原始请求传递给servlet引擎。
Web服务器的某组件将会调用servlet引擎,然后载入并执行servlet类。在执行过程中,servlet产生HTML格式的输出并将其内嵌于HTTP response中上交给Web服务器。Web服务器以静态HTML网页的形式将HTTP response返回到您的浏览器中。最终,Web浏览器处理HTTP response中动态产生的HTML网页,就好像在处理静态网页一样。
一般情况下,JSP引擎会检查JSP文件对应的servlet是否已经存在,并且检查JSP文件的修改日期是否早于servlet。如果JSP文件的修改日期早于对应的servlet,那么容器就可以确定JSP文件没有被修改过并且servlet有效。这使得整个流程与其他脚本语言(比如PHP)相比要高效快捷一些。
总的来说,JSP网页就是用另一种方式来编写servlet而不用成为Java编程高手。除了解释阶段外,JSP网页几乎可以被当成一个普通的servlet来对待。
5、JSP声明周期
编译阶段:servlet容器编译servlet源文件,生成servlet类。
初始化阶段:加载与JSP对应的servlet类,创建其实例,并调用它的初始化方法。
执行阶段:调用与JSP对应的servlet实例的服务方法。
销毁阶段:调用与JSP对应的servlet实例的销毁方法,然后销毁servlet实例。
二、JSP技术
1、JSP脚本和注释
jsp脚本:
1)<%java代码%> ----- 内部的java代码翻译到service方法的内部。
2)<%=java变量或表达式> ----- 会被翻译成service方法内部out.print()。
3)<%!java代码%> ---- 会被翻译成servlet的成员的内容。
jsp注释: 不同的注释可见范围是不同
1)Html注释:<!--注释内容--> ---可见范围 jsp源码、翻译后的servlet、页面显示html源码。
2)java注释://单行注释 /*多行注释*/ --可见范围 jsp源码和翻译后的servlet。
3)jsp注释:<%--注释内容--%> ----- 可见范围 jsp源码可见。
注:可以自己写个JSP页面,然后查看源码。
2、JSP运行原理----JSP本质就是servlet(面试--JSP的运行原理?)
JSP在第一次被访问时会Web容器翻译成servlet,再进行执行。
过程:
第一次访问----->helloServlet.jsp--------->helloServlet_jsp.java-------->编译运行。
注:被翻译后的servlet在Tomcat的work目录中可以找到。
3、JSP的3个指令
JSP的指令是指定JSP翻译和运行的命令,JSP包括三大指令:
1)page指令 --- 属性最多的指令(实际开发中page指令默认)。
属性最多的一个指令,根据不同的属性,指导整个页面特性:
格式:<%@ page 属性名1= "属性值1" 属性名2= "属性值2" ...%>
常用属性如下:
language:jsp脚本中可以嵌入的语言种类。
pageEncoding:当前jsp文件的本身编码---内部可以包含contentType。
contentType:response.setContentType(text/html;charset=UTF-8)。
session:是否jsp在翻译时自动创建session。
import:导入java的包。
errorPage:当前页面出错后跳转到哪个页面(500)。
isErrorPage:当前页面是一个处理错误的页面。
<!--设置web应用的全局的错误页面 -->
<error-page>
<error-code>404</error-code>
<location>/error.jsp</location>
</error-page>
2)include指令
页面包含(静态包含)指令,可以将一个jsp页面包含到另一个jsp页面中
格式:<%@ include file="被包含的文件地址"%>
开发中用得比较多。
3)taglib指令(用得比较多)
在jsp页面中引入标签库(jstl标签库、struts2标签库)
格式:<%@ taglib uri="标签库地址" prefix="前缀"%>
4、JSP内置/隐式对象(9个)----笔试
jsp被翻译成servlet之后,service方法中有9个对象定义并初始化完毕,我们在jsp脚本中可以直接使用这9个对象。
名称 | 类型 | 描述 |
out | javax.servlet.jsp.JspWriter | 用于页面输出 |
request | javax.servlet.http.HttpServletRequest | 得到用户请求信息, |
response | javax.servlet.http.HttpServletResponse | 服务器向客户端的回应信息 |
config | javax.servlet.ServletConfig | 服务器配置,可以取得初始化参数 |
session | javax.servlet.http.HttpSession | 用来保存用户的信息 |
application | javax.servlet.ServletContext | 所有用户的共享信息 |
page | java.lang.Object | 指当前页面转换后的Servlet类的实例 |
pageContext | javax.servlet.jsp.PageContext | JSP的页面容器 |
exception | java.lang.Throwable | 表示JSP页面所发生的异常,在错误页中才起作用 |
a、out对象
out的类型:JspWriter
out作用就是想客户端输出内容----out.write()
out缓冲区默认8kb,可以设置成0,代表关闭out缓冲区内容直接写到respons缓冲器。
<!--JSP页面输出到客户端方式 -->
aaaaaaaaaa
<%="bbbbbbb" %>
<% out.write("ccccccc"); %>
<% response.getWriter().write("ddddddddd"); %>
输出显示:
ddddddddd aaaaaaaaaa bbbbbbb ccccccc
为什么先输出d,再输出a、b、c?
先将a、b、c直接写到out缓冲区,d是直接写到response缓冲区。而页面响应需要Tomcat引擎从response缓冲区获取内容,所以需要将out缓冲区的内容再写到response缓冲区。
b、pageContext对象
jsp页面的上下文对象,作用如下:
page对象与pageContext对象不是一回事。
1)pageContext是一个域对象
setAttribute(String name,Object obj)
getAttribute(String name)
removeAttrbute(String name)
pageContext可以向指定的其他域中存取数据
setAttribute(String name,Object obj,int scope):scope:PageContext.
getAttribute(String name,int scope)
removeAttrbute(String name,int scope)
findAttribute(String name):依次从小的域到大的域搜索域范围中的name。
---依次从pageContext域,request域,session域,application域中获取属性,在某个域中获取后将不在向后寻找。
<%
//使用pageContext向request域存数据
request.setAttribute("name","zhangsan");
pageContext.setAttribute("name", "lisi", PageContext.REQUEST_SCOPE);
pageContext.setAttribute("name", "wangwu", PageContext.SESSION_SCOPE);
pageContext.setAttribute("name", "tianqi", PageContext.APPLICATION_SCOPE);
%>
<%=request.getAttribute("name") %>
<%=pageContext.getAttribute("name", PageContext.SESSION_SCOPE) %>
四大作用域的总结:
page域:当前jsp页面范围(pageContext)
request域:一次请求
session域:一次会话
application域:整个web应用(ServletContext)
2)pageContext域可以获得其他8大隐式对象
例如:
pageContext.getRequest()
pageContext.getSession()
5、JSP标签(动作)
1)页面包含(动态包含):<jsp:include page="被包含的页面"/>
(静态包含):<%@ include file="被包含的文件地址"%>
2)请求转发:<jsp:forward page="要转发的资源"/>(地址不变)
面试题:静态包含与动态包含的区别?
a、<%@include file="xxx.jsp"%>为jsp中的编译指令,其文件的包含是发生在jsp向servlet转换的时期,而<jsp:include page="xxx.jsp">是jsp中的动作指令,其文件的包含是发生在编译时期,也就是将java文件编译为class文件的时期 。
b、使用静态包含只会产生一个class文件,而使用动态包含会产生多个class文件 。
c、使用静态包含,包含页面和被包含页面的request对象为同一对象,因为静态包含只是将被包含的页面的内容复制到包含的页面中去;而动态包含包含页面和被包含页面不是同一个页面,被包含的页面的request对象可以取到的参数范围要相对大些,不仅可以取到传递到包含页面的参数,同样也能取得在包含页面向下传递的参数 。
三、完成商品列表
1、获得数据库中的商品的数据 ProductServlet
2、获得商品的数据List <Product>
servlet中获得集合数据怎样交个jsp进行显示?request域 List<Product>
3、JSP:页面输出方便
实现步骤:
1、创建数据库,添加信息。
中文乱码问题:alter table product convert to character set utf8; (product为表名)
2、建立ProductListServlet.java,程序获取数据库所有商品信息,然后再转发给product_list.jsp
//1.准备所有商品的数据。。。。List<Product>
QueryRunner runner = new QueryRunner(DataSourceUtils.getDataSource());
String sql = "select * from product";
List<Product> productList = null;
try {
productList = runner.query(sql, new BeanListHandler<Product>(Product.class));
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//2、商品的集合已经准备好了
//将数据存放到request域中,转发给product_list.js 进行显示
request.setAttribute("productList",productList);
request.getRequestDispatcher("/product_list.jsp").forward(request, response);
3、在product_list.jsp页面,获得集合List<Product>,然后显示出来所有商品信息。
<%
//获得集合List<Product>
List<Product> productList = (List<Product>)request.getAttribute("productList");
if(productList!=null){
for(Product product : productList){
out.write("<div class='col-md-2' style='height:250px'>");
out.write("<a href='product_info.htm'>");
out.write("<img src='"+product.getPimage()+"' width='170' height='170' style='display: inline-block;'>");
out.write("</a>");
out.write("<p><a href='product_info.html' style='color: green'>"+product.getPname()+"</a></p>");
out.write("<p><font color='#FF0000'>商城价:¥"+product.getShop_price()+"</font></p>");
out.write("</div>");
}
}
%>
注意:"+ +"