jsp技术

  1.JSP简介

  JSP是一种动态网页技术标准。它是在传统的网页HTML文件(*.htm,*.html)中插入Java程序段(Scriptlet)和JSP标记(tag),从而形成JSP文件,后缀名为(*.jsp)。

  将内容的生成和显示进行分离。

  用JSP技术,Web页面开发人员可以使用HTML或者XML标识来设计和格式化最终页面,并使用JSP标识或者小脚本来生成页面上的动态内容(内容是根据请求变化的,例如请求账户信息或者特定的一瓶酒的价格等)。生成内容的逻辑被封装在Servlet和JavaBeans组件(两个都是.java)中,并且捆绑在脚本中,所有的脚本在服务器端运行。由于核心逻辑被封装在标识和JavaBeans中,所以Web管理人员和页面设计者,能够编辑和使用JSP页面,而不影响内容的生成。
  在服务器端,JSP引擎解释JSP标识和脚本,生成所请求的内容(例如,通过访问JavaBeans组件,使用JDBC技术访问数据库或者包含文件),并且将结果以HTML(或者XML)页面的形式发送回浏览器。这既有助于作者保护自己的代码,又能保证任何基于HTML的Web浏览器的完全可用性。
  弦外:*Servlet控制器,接收请求封装‘Type1’(下行解释)的JavaBean、调用‘Type2’的JavaBean的相应业务逻辑方法、向客户端发出响应
      @WebServlet(urlPatterns={"authImg.jsp"})       

      public class AuthImg extends HttpServlet 然后在其中重写service等方法,对其响应。(假如在里面生成一张图片)。

      @注解中指向的url即是Servlet的访问入口,在jsp中可以通过<img name="d" src="authImg">来访问。

     *JavaBean:普通的java类,模型,逻辑事务,数据访问。
       1)只有属性声明和该属性对应的setXxx和getXxx方法不包含业务逻辑;这种JavaBean可以简单地理解为“数据对象”即可。
      2)还有一种JavaBean,其内包含业务处理逻辑,用于处理特定的业务数据。
     *JSP视图,
      1)仅仅是视图,只是表现层角色,拿到数据后显示出来。(MVC推荐)
      2)除了表现层,还包括一些逻辑处理。

  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对象。

  *request对象封装了客户端的请求信息,通过它才能了解到客户的需求,然后做出响应。它是HttpServletRequest类的实例。request对象具有请求域,即完成客户端的请求之前,该对象一直有效。
  *response对象包含了响应客户请求的有关信息,但在JSP中很少直接用到它。它是HttpServletResponse类的实例。response对象具有页面作用域,即访问一个页面时,该页面内的response对象只能对这次访问有效,其它页面的response对象对当前页面无效。
  *session对象指的是客户端与服务器的一次会话,从客户端连到服务器的一个WebApplication开始,直到客户端与服务器断开连接为止。它是HttpSession类的实例。Session对象是一个JSP内置对象,它在第一个JSP页面被装载时自动创建,完成会话期管理。从一个客户打开浏览器并连接到服务器开始,到客户关闭浏览器离开这个服务器结束,被称为一个会话。当一个客户访问一个服务器时,可能会在这个服务器的几个页面之间切换,服务器应当通过某种办法知道这是一个客户,就需要Session对象。session对象具有会话作用域
  *out对象是JspWriter类的实例,是向客户端输出内容常用的对象
  *page对象就是指向当前JSP页面本身,有点象类中的this指针,它是java.lang.Object类的实例
  *application对象实现了用户间数据的共享,可存放全局变量。它开始于服务器的启动,直到服务器的关闭,在此期间,此对象将一直存在;这样在用户的前后连接或不同用户之间的连接中,可以对此对象的同一属性进行操作;在任何地方对此对象属性的操作,都将影响到其他用户对此的访问。服务器的启动和关闭决定了application对象的生命。它是ServletContext类的实例。
  *exception对象是一个例外对象,当一个页面在运行过程中发生了例外,就产生这个对象。如果一个JSP页面要应用此对象,就必须把isErrorPage设为true,否则无法编译。他实际上是java.lang.Throwable的对象
  *pageContext对象提供了对JSP页面内所有的对象及名字空间的访问,也就是说他可以访问到本页所在的SESSION,也可以取本页面所在的application的某一属性值。
  *config对象是在一个Servlet初始化时,JSP引擎向它传递信息用的,此信息包括Servlet初始化时所要用到的参数(通过属性名和属性值构成)以及服务器的有关信息(通过传递一个ServletContext对象)

  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的观点来看,效果和为每个请求创建一个新线程的效果相同。

  filter使用户可以改变一个request和修改一个response. Filter 不是一个servlet,它不能产生一个response,它能够在一个request到达servlet之前预处理request,也可以在response离开servlet时处理response.换种说法,filter其实是一个“servlet chaining“(servlet 链).
包括
  1. 在servlet被调用之前截获;
  2. 在servlet被调用之前检查servlet request;
  3. 根据需要修改request头和request数据;
  4. 根据需要修改response头和response数据;
  5. 在servlet被调用之后截获.
  filter和listener都配置在web.xml文件中。
  它和Struts中的拦截器不同,过滤器是在JSP和生成servlet之间过滤,而拦截器是在执行Action方法前或后调用(AOP)!

  5.Listener

  在Web项目中,我们可以使用Listener接口来监听Container的中一些对象状态的变化,并且根据这些对象的状态的变化做出相应的响应。

  Listener是Servlet的监听器,它可以监听客户端的请求、服务端的操作等。通过监听器,可以自动激发一些操作,比如监听在线的用户的数量。当增加一个HttpSession时,就激发sessionCreated(HttpSessionEvent se)方法,这样就可以给在线人数加1。

  6.Servlet生命周期

  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)。 

参考:百科
  轻量级javaEE企业应用实战
原文地址:https://www.cnblogs.com/jslee/p/3439441.html