jsp技术
1.JSP简介
JSP是一种动态网页技术标准。它是在传统的网页HTML文件(*.htm,*.html)中插入Java程序段(Scriptlet)和JSP标记(tag),从而形成JSP文件,后缀名为(*.jsp)。
将内容的生成和显示进行分离。
public class AuthImg extends HttpServlet 然后在其中重写service等方法,对其响应。(假如在里面生成一张图片)。
@注解中指向的url即是Servlet的访问入口,在jsp中可以通过<img name="d" src="authImg">来访问。
MVC(模型Model-视图View-控制器Controller)是一种设计模式,
M(Model)在Java Web里说的是JavaBean,在JavaBean中除了其属性和字段,还可以有行为及其事件,JavaBean可以理解为普通Java对象。Java普通对象,就是符合Java规范的所有对象,这和实体类完全是两回事。业务逻辑和数据访问应该放在Model层,也就是V负责展示数据,Controler除了转发不做业务逻辑。真正的逻辑事务,数据访问,甚至算法都放到Model去。
Controller是控制器的意思,所谓控制器,就是将用户请求转发给模型层,经过处理后把结果返回到界面层展现的一个中间层,那么Controller到底管什么工作呢?先不说.先来看下在Java Web中这三个层一般的定义,一般在Java Web里,JSP充当V,Servlet充当C,JavaBean充当M,这里的Servlet管什么工作呢?接受输入,转到Model层去处理,处理结果保存后转发到JSP,然后展现数据。所以它的功能就是控制器的基本功能,它就管转发,在V和M之间转来转去。在Struts中,还包括它独有的控制器—Action。
MVC没有把业务的逻辑访问看成两个层,这是采用三层架构或MVC搭建程序最主要的区别。当然了。在三层中也提到了Model,但是三层架构中Model的概念与MVC中Model的概念是不一样的,“三层”中典型的Model层是实体类(数据对象)构成的,而MVC里,则是由业务逻辑与访问数据组成的。
2.JSP分析
1.HelloWorld.jsp代码:
<%
String message = "Hello World!";
%>
<%=message%>
这个文件非常简单,仅仅定义了一个String的变量,并且输出。把这个文件放到Tomcat的webapps/ROOT/目录下,启动Tomcat,在浏览器中访问http://localhost:8080/HelloWorld.jsp,浏览器中的输出为“HelloWorld!”
2.HelloWorld_jsp.java代码:
import javax.servlet.*; import javax.servlet.http.*; import javax.servlet.jsp.*; import org.apache.jasper.runtime.*; public class HelloWorld_jsp extends HttpJspBase { private static java.util.List _jspx_dependants; public Object getDependants() { return _jspx_dependants; } public void _jspService(HttpServletRequest request, HttpServletResponse response)throws java.io.IOException, ServletException{ JspFactory _jspxFactory = null; javax.servlet.jsp.PageContext pageContext = null; HttpSession session = null; ServletContext application = null; ServletConfig config = null; JspWriter out = null; Object page = this; JspWriter _jspx_out = null; try { _jspxFactory = JspFactory.getDefaultFactory();//调用JspFactory的getDefaultFactory()方法获取容器实现的一个JspFactory对象的引用 response.setContentType("text/html;charset=ISO-8859-1"); pageContext = _jspxFactory.getPageContext(this, request, response,null, true, 8192, true);//填充一个PageContext返回,并赋给内置变量 pageConext application = pageContext.getServletContext(); config = pageContext.getServletConfig(); session = pageContext.getSession(); out = pageContext.getOut(); _jspx_out = out; String message = "Hello World!"; out.print(message); } catch (Throwable t) { out = _jspx_out; if (out != null && out.getBufferSize() != 0) out.clearBuffer(); if (pageContext != null) pageContext.handlePageException(t); } finally { if (_jspxFactory != null) _jspxFactory.releasePageContext(pageContext); } } }
转到Tomcat的/work/Standalone/localhost/_目录下,可以找到如下的HelloWorld_jsp.java,这个文件就是Tomcat解析HelloWorld.jsp时生成的源文件。由此可见,HelloWorld.jsp在运行时首先解析成一个Java类HelloWorld_jsp.java,该类继承 于org.apache.jasper.runtime.HttpJspBase基类,HttpJspBase实现了HttpServlet接口。因此,JSP在运行前首先将编译为一个Servlet,这就是理解JSP技术的关键。
首先,调用JspFactory的getDefaultFactory()方法获取容器实现的一个JspFactory对象的引用。JspFactory是javax.servlet.jsp包中定义的一个抽象类,其中定义了两个静态方法setDefaultFactory()/getDefaultFactory()。set方法由JSP容器(Tomcat)实例化该页面Servlet(即 HelloWorld_jsp类)的时候置入,所以可以直接调用JspFactory.getDefaultFactory()方法得到这个JSP工厂的 实现类。Tomcat是调用org.apache.jasper.runtime.JspFactoryImpl类。
然后,调用这个JspFactoryImpl的getPageContext()方法,填充一个PageContext返回,并赋给内置变量 pageConext。其它内置对象都经由该pageContext得到。具体过程见上面的代码,这里不再赘述。该页面Servlet的环境设置完毕,开始对页面进行解析。HelloWorld.jsp页面仅仅定义了一个String变量,然后直接输出。解析后的代码如下:
String message = "Hello World!";
out.print(message);
所以说其实所有jsp都被编译成.java文件,所以在jsp中可以直接实例化其它.java文件,并调用它就行。
eg:
1 <% 2 Person p1 = new Person();//实例化Person类 3 //把p1实例放入session生存范围中,并取名为"p1" 4 session.setAttribute("p1",p1); 5 p1.setName("jslee"); //调用方法 6 %> 7 <!-- 调用方法来输出p1中的name属性值 --> 8 <%=p1.getName()%>
3.JSP特殊接口
1)3个编译指令
通知Servlet引擎的处理消息。
<%@ 指令 指令的属性= "属性值" %>
*include JSP语法中的include指令语句指示在JSP语句被解释的过程中包含一个静态文件,同时解析这个被包含文件中的JSP语句。
*page 当前jsp页面的相关属性
*taglib 用于定义和访问自定义标签
2)7个动作指令
运行时的动作。
<jsp:指令 指令的属性= "属性值" />
*include动作指令在于在一个JSP页面包含另一个文件。如果被包含的文件是一个静态文件 ,则功能和include指令相同,它将被包含的文件直接发送给客户端浏览器,由浏览器负责显示。如果被包含的文件是一个动态文件(扩展名为.jsp),则被包含的文件在运行结果包含在一起,再发送给客户端浏览器。
*param动作指令用来向目标JSP页面传参数,在目标页面中可以用request对象的getParameter()等方法获取传来的参数的值。
*useBean动作指令用来在JSP页面中创建一个JavaBean组件,创建后即可使用这个组件。相比于直接new 对象,用useBean可以通过setProper和getProperty动作指令来设置scope属性. 相当于实例的作用域.
*forward动作指令类似于response.sendRedirect(),都是用来重定向页面。不同的是jsp:forward动作指令可以为目标页面指定参数。
*plugin:用于下载JavaBean或Applet到客户端执行。
*Forword和SendRedirect区别
前者仅是容器中控制权的转向,在客户端浏览器地址栏中不会显示出转向后的地址;
后者则是完全的跳转,浏览器将会得到跳转的地址,并重新发送请求链接。这样,从浏览器的地址栏中可以看到跳转后的链接地址。
所以,前者更加高效,在前者可以满足需要时,尽量使用forward()方法,并且,这样也有助于隐藏实际的链接。但在有些情况下,比如,需要跳转到一个其它服务器上的资源,则必须使用sendRedirect()方法。
forward是服务器请求资源,服务器直接访问目标地址的URL,把那个URL的响应内容读取过来,然后把这些内容再发给浏览器,浏览器根本不知道服务器发送的内容是从哪儿来的,所以它的地址栏中还是原来的地址。
redirect就是服务端根据逻辑,发送一个状态码,告诉浏览器重新去请求那个地址,一般来说浏览器会用刚才请求的所有参数重新请求,所以session,request参数都可以获取。
3)9个内置对象
用法: jsp中,<% 对象名.对象方法 %> ,直接用
.java中,ServletContext sc = getServletConfig().getServletContext();
sc.setAttribute(""); 此例是获得application对象。
4.JSP容器与Filter(过滤器)
Servlet容器:
负责处理客户请求、把请求传送给Servlet(运行前首先将JSP编译为一个Servlet)并把结果返回给客户。不同程序的容器实际实现可能有所变化,但容器与Servlet之间的接口是由Servlet API定义好的,这个接口定义了Servlet容器在Servlet上要调用的方法及传递给Servlet的对象类。
Servlet生命周期:
1、Servlet容器创建Servlet的一个实例
2、容器调用该实例的init()方法
3、如果容器对该Servlet有请求,则调用此实例的service()方法
4、容器在销毁本实例前调用它的destroy()方法
5、销毁并标记该实例以供作为垃圾收集
一旦请求了一个Servlet,就没有办法阻止容器执行一个完整的生命周期。
容器在Servlet首次被调用时创建它的一个实例,并保持该实例在内存中,让它对所有的请求进行处理。容器可以决定在任何时候把这个实例从内存中移走。在典型的模型中,容器为每个Servlet创建一个单独的实例,容器并不会每接到一个请求就创建一个新线程,而是使用一个线程池来动态的将线程分配给到来的请求,但是这从Servlet的观点来看,效果和为每个请求创建一个新线程的效果相同。
5.Listener
在Web项目中,我们可以使用Listener接口来监听Container的中一些对象状态的变化,并且根据这些对象的状态的变化做出相应的响应。
Listener是Servlet的监听器,它可以监听客户端的请求、服务端的操作等。通过监听器,可以自动激发一些操作,比如监听在线的用户的数量。当增加一个HttpSession时,就激发sessionCreated(HttpSessionEvent se)方法,这样就可以给在线人数加1。
6.Servlet生命周期
1)init()方法
在Servlet的生命周期中,仅执行一次init()方法。它是在服务器装入Servlet时执行的,可以配置服务器,以在启动服务器或客户机首次访问Servlet时装入Servlet。无论有多少客户机访问Servlet,都不会重复执行init();
2)service()方法
它是Servlet的核心。每当一个客户请求一个HttpServlet对象,该对象的Service()方法就要调用,而且传递给这个方法一个“请求”(ServletRequest)对象和一个“响应”(ServletResponse)对象作为参数。在HttpServlet中已存在Service()方法。默认的服务功能是调用与HTTP请求的方法相应的do功能。
3)destroy()方法
仅执行一次,在服务器端停止且卸载Servlet时执行该方法,有点类似于C++的delete方法。一个Servlet在运行service()方法时可能会产生其他的线程,因此需要确认在调用destroy()方法时,这些线程已经终止或完成。
Tomcat服务器在如下时刻加载和实例化Servlet:
a) 如果已配置自动装入选项,则在启动服务器时自动载入。
b) 在服务器启动后,客户机首次向Servlet发出请求时。
c) 重新装入Servlet时。
当启动Servlet容器时,容器首先去查找一个配置文件web.xml,这个文件中记录了可心提供服务的Servlet。每个Servlet被指定一个Servlet名,也就是这个Servlet实际对应的Java的完整class文件名。Servlet容器会为每个自动装入选项的Servlet创建一个实例。所以,每个Servlet类必须有一个公共的无参数的构造器。
Servlet Engine可以随时随意使用或释放Servlet。因此,你不能依赖Servlet class或其成员存储信息。
当Servlet Engine判断一个Servlet应当被释放时(比如说Engine准备Shut down 或需要回收资源),Engine必须让Servlet 能释放其正在使用的任何资源,并保存持续性的状态信息。这些可以通过调用Servlet的destroy方法实现。
在Servlet Engine 释放一个Servlet 以前,必须让其完成当前实例的service方法或是等到timeout(如果Engine定义了timeout)。当Engine释放一个Servlet以后,Engine将不能再将请求转发给它,Engine必须彻底释放该Servlet并将其标明为可回收的(给garbage collection)。