Servlet学习笔记

Servlet概述

  • Servlet(Server Applet),全称Java Servlet,暂无中文译文。是用Java编写的服务器端程序。其主要功能在于交互式地浏览和修改数据,生成动态Web内容。狭义的Servlet是指Java语言实现的一个接口,广义的Servlet是指任何实现了这个Servlet接口的类,一般情况下,人们将Servlet理解为后者。
  • Servlet运行于支持Java的应用服务器中。从原理上讲,Servlet可以响应任何类型的请求,但绝大多数情况下Servlet只用来扩展基于HTTP协议的Web服务器。
    最早支持Servlet标准的是JavaSoft的Java Web Server,此后,一些其它的基于Java的Web服务器开始支持标准的Servlet。
  • 实现方式
    1. 实现servlet接口
    2. 继承genericservlet
    3. 通过继承httpservlet开发servlet

Servlet规范

  • 一个最基本的 Java Web 项目所需的 jar 包只需要一个 servlet-api.jar ,这个 jar 包中的类大部分都是接口,还有一些工具类,共有 2 个包,分别是 javax.servlet 和 javax.servlet.http。所有的 Servlet 容器都带有这个包,你无需再放到Web项目里,放到这里只不过是编译的需要,运行是不需要的。如果你硬是把 servlet-api.jar 放到 webapp/WEB-INF/lib 目录下,那么 Tomcat 启动时还会报一个警告信息。

  • Servlet 是 J2EE 最重要的一部分,有了 Servlet 就是 J2EE 了,J2EE 的其他方面的内容择需采用。而 Servlet 规范需要掌握的就是 servlet 和 filter 这两项技术。绝大多数框架不是基于 servlet 就是基于 filter,如果它要在 Servlet 容器上运行,就永远也脱离不开这个模型。

  • 为什么 Servlet 规范会有两个包,javax.servlet 和 javax.servlet.http?
    早先设计该规范的人认为 Servlet 是一种服务模型,不一定是依赖某种网络协议之上,因此就抽象出了一个 javax.servlet ,同时在提供一个基于 HTTP 协议上的接口扩展。但是从实际运行这么多年来看,似乎没有发现有在其他协议上实现的 Servlet 技术。

  • Servlet 规范其实就是对 HTTP 协议做面向对象的封装,HTTP协议中的请求和响应就是对应了HttpServletRequest 和 HttpServletResponse 这两个接口。

    可以通过 HttpServletRequest 来获取所有请求相关的信息,包括 URI、Cookie、Header、请求参数等等,别无它路。因此当你使用某个框架时,你想获取HTTP请求的相关信息,只要拿到 HttpServletRequest 实例即可。

    而 HttpServletResponse接口是用来生产 HTTP 回应,包含 Cookie、Header 以及回应的内容等等。HTTP 协议里是没有关于 Session 会话的定义,Session 是各种编程语言根据 HTTP 协议的无状态这种特点而产生的。其实现无非就是服务器端的一个哈希表,哈希表的Key就是传递给浏览器的名为 jsessionid 的 Cookie 值。

  • 当需要将某个值保存到 session 时,容器会执行如下几步:

    a. 获取 jsessionid 值,没有的话就生成一个,也就是 request.getSession() 这个方法

    b. 拿到的 HttpSession 对象实例就相当于一个哈希表,你可以往哈希表里存放数据(setAttribute)

    c. 也可以通过 getAttribute 来获取某个值。而这个名为 jsessionid 的 Cookie 在浏览器关闭时会自动删除。把 Cookie 的 MaxAge 值设为 -1 就能达到浏览器关闭自动删除的效果。

  • 在 servlet 中有一个包 javax.servlet.jsp 是跟 JSP 相关的一些接口规范定义。JSP 比 Servlet 方便的地方在于可直接修改立即生效,不像 Servlet 修改后必须重启容器才能生效。 因此 JSP 适合用来做视图,而 Servlet 则适合做控制层。

Servlet线程安全

  • servlet中默认线程不安全,单例多线程,因此对于共享的数据(静态变量,堆中的对象实例等)自己维护进行同步控制,不要在service方法或doGet等由service分派出去的方法,直接使用synchronized方法,很显然要根据业务控制同步控制块的大小进行细粒度的控制,将不影响线程安全的耗时操作移出同步控制块。

  • 针对Servlet的线程安全问题,Sun公司是提供有解决方案的:让Servlet去实现一个SingleThreadModel接口,如果某个Servlet实现了SingleThreadModel接口,那么Servlet引擎将以单线程模式来调用其service方法。

  • 查看Sevlet的API可以看到,SingleThreadModel接口中没有定义任何方法和常量,在Java中,把没有定义任何方法和常量的接口称之为标记接口,经常看到的一个最典型的标记接口就是”Serializable”,这个接口也是没有定义任何方法和常量的,标记接口在Java中有什么用呢?主要作用就是给某个对象打上一个标志,告诉JVM,这个对象可以做什么,比如实现了”Serializable”接口的类的对象就可以被序列化,还有一个”Cloneable”接口,这个也是一个标记接口,在默认情况下,Java中的对象是不允许被克隆的,就像现实生活中的人一样,不允许克隆,但是只要实现了”Cloneable”接口,那么对象就可以被克隆了。

    让Servlet实现了SingleThreadModel接口,只要在Servlet类的定义中增加实现SingleThreadModel接口的声明即可。

  • 对于实现了SingleThreadModel接口的Servlet,Servlet引擎仍然支持对该Servlet的多线程并发访问,其采用的方式是产生多个Servlet实例对象,并发的每个线程分别调用一个独立的Servlet实例对象。

  • 实现SingleThreadModel接口并不能真正解决Servlet的线程安全问题,因为Servlet引擎会创建多个Servlet实例对象,而真正意义上解决多线程安全问题是指一个Servlet实例对象被多个线程同时调用的问题。事实上,在Servlet API 2.4中,已经将SingleThreadModel标记为Deprecated(过时的)。

知识点

web.xml配置

标签结构

  1. <web-app>
  2. <!--Servlet标签-->
  3. <servlet>
  4. <servlet-name>Servlet名称</servlet-name>
  5. <servlet-class>包名+类名</servlet-class>
  6. </servlet>
  7. <!--Servlet映射-->
  8. <servlet-mapping>
  9. <servlet-name>Servlet名称</servlet-name>
  10. <url-pattern>URL值</url-pattern>
  11. </servlet-mapping>
  12. </web-app>

常用类

HttpServletRequest类

  • 常见方法
    • getRequestURL()
      浏览器发出请求时的完整URL,包括协议 主机名 端口(如果有)
    • getRequestURI()
      浏览器发出请求的资源名部分,去掉了协议和主机名
    • getQueryString()
      请求行中的参数部分,只能显示以get方式发出的参数,post方式的看不到
    • getRemoteAddr()
      浏览器所处于的客户机的IP地址
    • getRemoteHost()
      浏览器所处于的客户机的主机名
    • getRemotePort()
      浏览器所处于的客户机使用的网络端口
    • getLocalAddr()
      服务器的IP地址
    • getLocalName()
      服务器的主机名
    • getMethod()
      得到客户机请求方式一般是GET或者POST
  • 获取参数

    • getParameter()
      是常见的方法,用于获取单值的参数
    • getParameterValues()
      用于获取具有多值得参数,比如某些注册提交的信息是多选的。
    • getParameterMap()
      用于遍历所有的参数,并返回Map类型。
  • 获取头信息

    • getHeader()
      获取浏览器传递过来的头信息。 比如getHeader(“user-agent”) 可以获取浏览器的基本资料,这样就能判断是firefox、IE、chrome、或者是safari浏览器
    • getHeaderNames()
      获取浏览器所有的头信息名称,根据头信息名称就能遍历出所有的头信息
    • getCookies
      获取浏览器传递来的所有Cookie,返回值是Cookie[]数组
  • 服务器传参
    setAttribute和getAttribute可以用来在进行服务端跳转的时候,在不同的Servlet之间进行数据共享

HttpServletRespond类

  • 设置响应内容
    通过getWriter()获取一个PrintWriter 对象
    可以使用println(),append(),write(),format()等等方法设置返回给浏览器的html内容。
  • 设置响应格式
    通过setContentType()设置格式,对应头信息HttpServletRequest.getHeader(“accept”)。浏览器不能识别,那么打开此servlet就会弹出一个下载的对话框。
  • 设置响应编码
    设置响应编码有两种方式,这两种方式都需要在HttpServletRespond.getWriter调用之前执行才能生效。

    • setContentType(“text/html; charset=UTF-8”);
      不仅发送到浏览器的内容会使用UTF-8编码,而且还通知浏览器使用UTF-8编码方式进行显示。所以总能正常显示中文
    • setCharacterEncoding(“UTF-8”);
      仅仅是发送的浏览器的内容是UTF-8编码的,置于浏览器是用哪种编码方式显示不管。 所以当浏览器的显示编码方式不是UTF-8的时候,就会看到乱码,需要手动再进行一次设置。
  • 设置缓存
    使用缓存可以加快页面的加载,降低服务端的负担。但是也可能看到过时的信息,可以通过如下手段通知浏览器不要使用缓存:

    1. response.setDateHeader("Expires",0 );
    2. response.setHeader("Cache-Controll","no-cache");
    3. response.setHeader("pragma","no-cache");
  • 客户端跳转
    客户端有两种跳转

    • 302 表示临时跳转
      使用sendRedirect( “XXXX.html”)方法重定向
    • 301 表示永久性跳转
      setStatus(301),setHeader(“Location”, “XXXX.html”);
  • 添加Cookie
    通过response.addCookie()方法,将cookie保存在浏览器端

Cookie

使用javax.servlet.http.Cookie类

  • 常用方法
    • setMaxAge
      设置Cookie保存时间,如果为0,表示浏览器一关闭就销毁。基础单位为秒。
    • setPath
      Path表示服务器的主机名,只有浏览器通过这个主机名访问服务器的时候才会提交这个cookie到服务端

常用方法

doPost(HttpServletRequest , HttpServletResponse )

当浏览器使用post方式提交数据的时候,servlet需要提供doPost()方法

  • post方式种类
    • 在form上显示设置 method=”post”的时候
    • ajax指定post方式的时候

doGet(HttpServletRequest , HttpServletResponse )

当浏览器使用get方式提交数据的时候,servlet需要提供doGet()方法

  • get方式种类
    • form默认的提交方式,即method=”get”的时候
    • 如果通过一个超链访问某个地址
    • 如果在地址栏直接输入某个地址
    • ajax指定使用get方式的时候

service(HttpServletRequest , HttpServletResponse )

Servlet子类除继承了HttpServlet类,同时也继承了service()方法
实际上,在执行doGet()或者doPost()之前,都会先执行service(),由service()方法进行判断,到底该调用doGet()还是doPost()
可以发现,service(), doGet(), doPost() 三种方式的参数列表都是一样的。
所以,有时候也会直接重写service()方法,在其中提供相应的服务,就不用区分到底是get还是post。

跳转

  • 服务端跳转
    request.getRequestDispatcher("XXXX.html").forward(request, response);
    服务端跳转可以看到浏览器的地址依然是原路径,并不会变成XXXX.html
  • 客户端跳转
    response.sendRedirect("XXXX.html");
    在Servlet中进行客户端跳转,即发送重定向,浏览器地址发生改变,转到XXXX.html
  • 图解

上传文件

  • 页面准备
    html文件内form标签的method必须是post的
    需要加上enctype="multipart/form-data,表示提交的数据是二进制文件
    需要提供input标签type=”file” 的字段进行上传
  • 准备上传文件的Servlet继承类
    一般需要用到commons-io和commons-fileupload这两个Apache的jar包,除导入到项目中还应存放在WEB-INF/lib目录下
    一般通过如下代码拿到Items的迭代器,遍历得到的每一个item对应为一个浏览器提交的数据

    1. String filename = null;
    2. DiskFileItemFactory factory = new DiskFileItemFactory();
    3. ServletFileUpload upload = new ServletFileUpload(factory);
    4. // 设置上传文件的大小限制为1M
    5. factory.setSizeThreshold(1024 * 1024);
    6. List<?> items = null;
    7. try
    8. {
    9. items = upload.parseRequest(request);
    10. } catch (FileUploadException e)
    11. {
    12. e.printStackTrace();
    13. }
    14. Iterator<?> iter = items.iterator();
    15. while (iter.hasNext())
    16. {
    17. FileItem item = (FileItem) iter.next();
    18. // isFormField()来判断是否是常规字段还是提交的文件。 返回true的时候,就表示是常规字段。false则为文件
    19. if (!item.isFormField())
    20. {
    21. ............
    22. }
    23. }
  • 配置web.xml
    配置Servlet继承类,并将form标签的action属性名称关联到servlet-mapping下的url-pattern标签,注意servlet-name前后要一致

自启动

有的时候会有这样的业务需求: tomcat一启动,就需要执行一些初始化的代码,比如校验数据库的完整性等。但是Servlet的生命周期是在用户访问浏览器对应的路径开始的。如果没有用户的第一次访问,就无法执行相关代码。 这个时候,就需要Servlet实现自启动。即:伴随着tomcat的启动,自动启动初始化,在初始化方法init()中,就可以进行一些业务代码的工作了。

  • 设置方法:
    在web.xml中,配置Servlet的地方,增加一句<load-on-startup>1-99</load-on-startup>
    取值范围是1-99,表示优先级。配置完成后,即表明该Servlet会随着Tomcat的启动而初始化。

生命周期

一个Servlet的生命周期由 实例化,初始化,提供服务,销毁,被回收 几个步骤组成

  • 实例化
    当用户通过浏览器输入一个路径,这个路径对应的servlet被调用的时候,该Servlet就会被实例化
    无论访问了多少次HttpServlet子类,该类构造方法只会执行一次,所以Serlvet是单例的。
  • 初始化
    HttpServlet子类同时继承了init(ServletConfig)方法,init是一个实例方法,所以会在构造方法执行后执行。无论访问多少次该类,init方法仅执行一次。
  • 提供服务
    接下来就是执行service()方法,然后通过浏览器传递过来的信息进行判断,是调用doGet()还是doPost()方法,在service()中编写我们的业务代码。
  • 销毁
    接着是销毁destroy()
    在如下几种情况下,会调用destroy():

    • 该Servlet所在的web应用重新启动。serverl.xml中<Context path="/" docBase="..." debug="0" reloadable="false" />,reloadable表示有任何类发生更新时,web应用是否自动重启。当web应用自动重启的时候,destroy()方法就会被调用。
    • 关闭tomcat的时候 destroy()方法会被调用,但是这个一般都发生的很快,不易被发现
  • 被回收
    当该Servlet被销毁后,就满足垃圾回收的条件了。 当下一次垃圾回收GC来临的时候,就有可能被回收。

过滤器Filter

  • 概念
    Filter就像一个一个哨卡,用户的请求需要经过Filter,并且可以有多个过滤器

  • 实现

    1. 编写Filter类,继承Filter接口,重写doFilter、init、destroy等方法
      • doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
        添加过滤条件,在方法内部通过chain.doFilter()方法设置过滤器
      • init(FilterConfig arg0)
        与Servlet需要配置自启动才会随着服务器的启动而执行相比,init()方法不一样。Filter一定会随着服务器的启动自启动。Filter是web应用非常重要的一个环节,如果Filter启动失败,或者本身有编译错误,不仅这个Filter不能使用,整个web应用会启动失败,导致用户无法访问页面
    2. 配置web.xml,标签结构如下:
      1. <web-app>
      2. <!--filter标签-->
      3. <filter>
      4. <filter-name>过滤器名</filter-name>
      5. <filter-class>报名+类名</filter-class>
      6. </filter>
      7. <!--filter映射-->
      8. <filter-mapping>
      9. <filter-name>过滤器名</filter-name>
      10. <url-pattern>需要过滤的URL(/*:表示过滤所有)</url-pattern>
      11. </filter-mapping>
      12. </web-app>

监听Listener

Listener 的作用是用于监听 web应用的创建和销毁,以及在其上attribute发生的变化。 web应用即ServletContext对象(jsp的隐式对象application)
除了对web应用的监听外,还能监听session和request的生命周期,以及他们的attribute发生的变化。

  • 监听 Context
    • 监听web应用,继承接口ServletContextListener,重写contextDestroyed、contextInitialized方法,对应当前web应用的初始化、销毁。
    • 监听web应用属性,继承接口ServletContextAttributeListener,重写attributeAdded、attributeRemoved、attributeReplaced方法,对应监听属性的增加、删除、替换。
  • 监听Session
    对Session的监听分生命周期的监听,和Session上Attribute变化的监听两种。

    • 监听Session,继承接口HttpSessionListener,重写sessionCreated、sessionDestroyed方法,对应Session会话创建和销毁的执行
    • 监听Session属性,继承接口HttpSessionAttributeListener,重写attributeAdded、attributeRemoved、attributeReplaced方法,对应监听属性的增加、删除、替换。
  • 监听Request
    对Request的监听分生命周期的监听,和Request上Attribute变化的监听两部分。

    • 监听Request,继承接口ServletRequestListener,重写sessionCreated、sessionDestroyed方法,对应Session会话创建和销毁的执行
    • 监听Request属性,继承接口ServletRequestAttributeListener,重写attributeAdded、attributeRemoved、attributeReplaced方法,对应监听属性的增加、删除、替换。
  • 配置web.xml,格式如下:

    1. <listener>
    2. <listener-class>Listener类名</listener-class>
    3. </listener>

Servlet(Filter)中的url-pattern

  • Serlvet和Filter有三种不同的匹配规则:

    • (1)精确匹配:/foo;
    • (2)路径匹配:/foo/*;
    • (3)后缀匹配:*.html;
  • Serlvet的匹配顺序是:
    首先进行精确匹配;如果不存在精确匹配的进行路径匹配;最后根据后缀进行匹配;一次请求只会匹配一个Servlet;(Filter是只要匹配成功就添加到FilterChain)
    PS:其他写法(/foo/,/.html,/foo)都不对;“/foo*”不能匹配/foo,/foox;

JSP学习笔记

JSP概述

  • JSP(全称JavaServer Pages)是由Sun Microsystems公司倡导和许多公司参与共同建立的一种使软件开发者可以响应客户端请求,而动态生成HTML、XML或其他格式文档的Web网页的技术标准。JSP技术是以Java语言作为脚本语言的,JSP网页为整个服务器端的Java库单元提供了一个接口来服务于HTTP的应用程序。
  • JSP使Java代码和特定的预定义动作可以嵌入到静态页面中。JSP句法增加了被称为JSP动作的XML标签,它们用来调用内建功能。另外,可以创建JSP标签库,然后像使用标准HTML或XML标签一样使用它们。标签库提供了一种和平台无关的扩展服务器性能的方法。
  • JSP被JSP编译器编译成Java Servlets。一个JSP编译器可以把JSP编译成JAVA代码写的servlet然后再由JAVA编译器来编译成机器码,也可以直接编译成二进制码。

执行过程

编写一jsp文件,命名为hello.jsp,执行流程如下:

  1. 把 hello.jsp转译为hello_jsp.java
  2. hello_jsp.java 位于\tomcat\work\Catalina\localhost_\org\apache\jsp
  3. hello_jsp.java是一个servlet
  4. 把hello_jsp.java 编译为hello_jsp.class
  5. 执行hello_jsp.class,生成html
  6. 通过http协议把html 响应返回给浏览器

JSP指令

JSP指令控制JSP编译器如何去生成servlet,以下是可用的指令:

  • 包含指令include
    包含指令通知JSP编译器把另外一个文件完全包含入当前文件中。效果就好像被包含文件的内容直接被粘贴到当前文件中一样。这个功能和C预处理器所提供的很类似。被包含文件的扩展名一般都是”jspf”(即JSP Fragment,JSP片段):
    <%@ include file="somefile.jsp" %>
  • 页面指令page
    页面指令有以下几个选项:
    • import 使一个JAVA导入声明被插入到最终页面文件。注意:在同一个JSP文件中只有”import”导入页面指令可以被多次使用,如果导入多个类,彼此用,逗号隔开。
    • contentType 规定了生成内容的类型。当生成非HTML内容或者当前字符集character set并非默认字符集时使用。如contentType=”text/html; charset=UTF-8″
    • pageEncoding 页面的字符设置
    • errorPage 处理HTTP请求时,如果出现异常则显示该错误提示信息页面。
    • isErrorPage 如果设置为TRUE,则表示当前文件是一个错误提示页面。
    • isThreadSafe 表示最终生成的servlet是否线程安全(thread safe)。
      1. <%@ page import="java.util.*" %> //example import导入样例
      2. <%@ page contentType="text/html" %> //example contentType页面类型样例
      3. <%@ page isErrorPage=false %> //example for non error page无错页面样例
      4. <%@ page isThreadSafe=true %> //example for a thread safe JSP线程安全JSP样例
  • 标签库指令taglib
    标签库指令描述了要使用的JSP标签库。该指令需要指定一个前缀prefix(和C++的命名空间很类似)和标签库的描述URI:
    <%@ taglib prefix="myprefix" uri="taglib/mytag.tld" %>

JSP页面元素

  • 标准脚本变量
    以下是永远可用的脚本变量:
    • out:JSPWriter,用来写入响应流的数据
    • page:servlet自身
    • pageContext:一个PageContext实例包括和整个页面相联系的数据,一个给定的HTML页面可以在多个JSP之间传递。
    • request:HTTP request(请求)对象
    • response:HTTP response(响应)对象
    • session:HTTP session(服务端会话)对象
  • 脚本元素
    有三个基本的脚本元素,作用是使JAVA代码可以直接插入servlet。
    • 一种是声明标签,在JAVA SERVLET的类体中放入一个变量的定义。静态的数据成员也可以如此定义。
      <%! int serverInstanceVariable = 1; %>
    • 一种是脚本标签,在JAVA SERVLET的类的_jspService()方法中放入所包含的语句。
      <% int localStackBasedVariable = 1; out.println(localStackBasedVariable); %>
    • 一种是表达式标签,在JAVA SERVLET的类中放入待赋值的表达式,表达式注意不能以分号结尾,一般用于输出一段html。
      <%= "expanded inline data " + 1 %>相当于<%out.println( "expanded inline data " + 1); %>
  • 页面元素
    总结,JSP的页面元素组成如下:
    • 静态内容
      就是html,css,javascript等内容
    • 指令
      <%@开始 %> 结尾,比如<%@page import="java.util.*"%>
    • 表达式
      <%=...%>用于输出一段html
    • Scriptlet
      <%...%>之间,可以写任何java 代码
    • 声明
      <%!......%>之间可以声明字段或者方法。但是不建议这么做。
    • 动作
      <jsp:include page="Filename" >在jsp页面中包含另一个页面。
    • 注释
      <%-- .....-- %>,不同于 html的注释<!-- -->通过jsp的注释,浏览器也看不到相应的代码,相当于在servlet中注释掉了

JSP动作

JSP动作是一系列可以调用内建于网络服务器中的功能的XML标签。JSP提供了以下动作:

  • jsp:include
    和子过程类似,JAVA SERVLET暂时接管对其它指定的JSP页的请求和响应。当处理完该JSP页后就马上把控制权交还当前JSP页。这样JSP代码就可以在多个JSP页中共享而不用复制。(注意区别指令include,指令include会导致多个jsp文件合并为一个java文件,动作include是独立访问,但需注意传参jsp:param)
  • jsp:param
    可以在jsp:include, jsp:forward或jsp:params块之间使用。指定一个将加入请求的当前参数组中的参数。
  • jsp:forward
    用于处理对另一个JSP或SERVLET的请求和响应。控制权永远不会交还给当前JSP页。相当于Servlet服务端跳转的简化,即:
    request.getRequestDispatcher("XXX.jsp").forward(request, response);
  • jsp:plugin
    Netscape Navigator的老版本和Internet Explorer使用不同的标签以嵌入一个applet。这个动作产生为嵌入一个APPLET所需要的指定浏览器标签。
  • jsp:fallback
    如果浏览器不支持APPLETS则会显示的内容。
  • jsp:getProperty
    从指定的JavaBean中获取一个属性值。
  • jsp:setProperty
    在指定的JavaBean中设置一个属性值。
  • jsp:useBean
    创建或者复用一个JavaBean变量到JSP页。

作用域

JSP有4个作用域,分别是 :

  • pageContext
    pageContext表示当前页面作用域,只能在当前页面访问,在其他页面不能访问
    常用写法是:
    pageContext.setAttribute(key,value);
    pageContext.getAttribute(key)
  • requestContext
    requestContext 表示一次请求。随着本次请求结束,其中的数据也就被回收。
    常用写法是:
    request.setAttribute(key,value);
    request.getAttribute(key)
  • sessionContext
    sessionContext 指的是会话,从一个用户打开网站的那一刻起,无论访问了多少网页,链接都属于同一个会话,直到浏览器关闭。 所以页面间传递数据,也是可以通过session传递的。但是,不同用户对应的session是不一样的,所以session无法在不同的用户之间共享数据。
    常用写法是:
    session.setAttribute(key,value);
    session.getAttribute(key)
  • applicationContext
    applicationContext 指的是全局,所有用户共享同一个数据,在JSP中使用application对象, application对象是ServletContext接口的实例也可以通过request.getServletContext()来获取。所以 application == request.getServletContext() 会返回true,application映射的就是web应用本身。
    常用写法是:
    application.setAttribute(key,value);
    application.getAttribute(key)

隐式对象

JSP的隐式对象指的是不需要显示定义,直接就可以使用的对象,比如request,response
JSP一共有9个隐式对象,分别是 :

  • request
    请求
  • response
    响应
  • out
    输出
  • pageContext
    当前页面作用域
  • session
    会话作用域
  • application
    全局作用域
  • page
    page 对象即表示当前对象,JSP 会被编译为一个Servlet类 ,运行的时候是一个Servlet实例。 page即代表this
  • config
    config可以获取一些在web.xml中初始化的参数。
    在JSP中使用config比较复杂,一般较少使用。需要如下几个步骤:
    1. 在web.xml中进行配置
    2. 创建一个jsp文件,通过config.getInitParameter(param-name) 获取参数
    3. 访问路径,获取web.xml中配置的参数
  • exception
    exception 对象只有当前页面的<%@page 指令设置为isErrorPage=”true”的时候才可以使用。
    同时,在其他页面也需要设置 <%@page 指令 errorPage=”” 来指定一个专门处理异常的页面。

JSTL标准标签库

JSP标准标签库(JSP Standard Tag Library)是Java EE网络应用程序开发平台的组成部分。它在JSP规范的基础上,扩充了一个JSP的标签库来完成一些通用任务,比如XML数据处理、条件执行、数据库访问、循环和国际化。JSTL允许开人员可以像使用HTML标签 那样在JSP中开发Java功能。
JSTL库有core, i18n, fmt, sql 等等,jar包放在web/WEB-INF/lib 下。
下面是全部六个JSTL标签库的描述:

  1. 核心库,如和。
  2. 格式化库,具有国际化功能。
  3. 数据库标签库,包括查询、创建和更新数据库表的标签。
  4. XML库。
  5. 函数库。
  6. TLV(允许JSP页面的XML视图在翻译时验证。JSTL提供的TLV允许标签库作者根据JSP页面中脚本元素的使用和被允许的标签库来执行限制条件。
  • 常用核心库指令
    在页面中使用JSTL需要在jsp中 通过指令进行设置,<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
    • set
      <c:set var="name" value="${'gareen'}" scope="request" />
      在作用域request中设置name,相当于
      <%request.setAttribute("name","gareen")%>
    • out
      <c:out value="${name}" />
      相当于 <%=request.getAttribute("name")%>
    • remove
      <c:remove var="name" scope="request" />
      在作用域request中删掉name,相当于
      <%request.removeAttribute("name")%>
      作用域可以是pageContext, request, session, application
    • if else
      JSTL通过<c:if test=""> 进行条件判断,但是JSTP没有<c:else,所以常用的办法是在<c:if的条件里取反
      配合if使用的还有通过empty进行为空判断,empty可以判断对象是否为null,字符串长度是否为0,集合长度是否为0
    • choose
      虽然JSTL没有提供else标签,但是提供了一个else功能的标签
      1. <c:choose>
      2. <c:when test="${hp<5}">
      3. </c:when>
      4. <c:otherwise>
      5. </c:otherwise>
      6. </c:choose>
    • forEach
      可以在JSP中使用for循环,但是其可读性很差。 借助JSTL的c:forEach标签,可以改善可读性。
      <c:forEach items="${lists}" var="name" varStatus="st" >
      items=”${key}” 表示遍历,此处key是集合
      var=”name” 表示把每一个集合中的元素放在name上
      varStatus=”st” 表示遍历的状态,特性如下:
    • forTokens
      <c:forTokens items="${key} " delims="...." var="name">专门用于字符串拆分,并且可以指定多个分隔符
      items=”${key}”是分割前字符串
      delims=”….” 表示分隔符
      var=”name”表示分割后新字符串名称
  • 常用格式化库指令
    fmt 标签常用来进行格式化,使用之前要加上
    <%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix='fmt' %>

    • fmt:formatNumber
      格式化数字,例:
      <fmt:formatNumber type="number" value="${money}" minFractionDigits="2"/>
      <fmt:formatNumber type=”number” 表示格式化数字
      minFractionDigits 小数点至少要有的位数
      maxFractionDigits 小数点最多能有的位数
    • fmt:formatDate
      格式化日期,例:
      <fmt:formatDate value="${now}" pattern="G yyyy年MM月dd日 E"/>
      <fmt:formatDate value="${now}" pattern="a HH:mm:ss.S z"/>
      <fmt:formatDate value="${now}" pattern="yyyy-MM-dd HH:mm:ss"/>

      <fmt:formatDate 表示格式化日期
      yyyy 表示年份
      MM 表示月份
      dd 表示日期
      E 表示星期几
      a 表示是上午还是下午
      HH 表示小时
      mm 表示分钟
      ss 表示秒
      S 表示毫秒
      z 表示时区
  • 常用函数库指令
    fn标签提供各种实用功能,首先使用之前使用加入如下指令:
    <%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>

函数 描述
fn:contains(string, substring) 如果参数string中包含参数substring,返回true
fn:containsIgnoreCase(string, substring) 如果参数string中包含参数substring(忽略大小写),返回true
fn:endsWith(string, suffix) 如果参数 string 以参数suffix结尾,返回true
fn:escapeXml(string) 将有特殊意义的XML (和HTML)转换为对应的XML character entity code,并返回
fn:indexOf(string, substring) 返回参数substring在参数string中第一次出现的位置
fn:join(array, separator) 将一个给定的数组array用给定的间隔符separator串在一起,组成一个新的字符串并返回。
fn:length(item) 返回参数item中包含元素的数量。参数Item类型是数组、collection或者String。如果是String类型,返回值是String中的字符数。
fn:replace(string, before, after) 返回一个String对象。用参数after字符串替换参数string中所有出现参数before字符串的地方,并返回替换后的结果
fn:split(string, separator) 返回一个数组,以参数separator 为分割符分割参数string,分割后的每一部分就是数组的一个元素
fn:startsWith(string, prefix) 如果参数string以参数prefix开头,返回true
fn:substring(string, begin, end) 返回参数string部分字符串, 从参数begin开始到参数end位置,包括end位置的字符
fn:substringAfter(string, substring) 返回参数substring在参数string中后面的那一部分字符串
fn:substringBefore(string, substring) 返回参数substring在参数string中前面的那一部分字符串
fn:toLowerCase(string) 将参数string所有的字符变为小写,并将其返回
fn:toUpperCase(string) 将参数string所有的字符变为大写,并将其返回
fn:trim(string) 去除参数string 首尾的空格,并将其返回

EL表达式语言

  • 概述
    表达式语言(Expression Language),是Java中的一种特殊的通用编程语言,借鉴于JavaScript和XPath。主要作用是在Java Web应用程序嵌入到网页(如JSP)中,用以访问页面的上下文以及不同作用域中的对象 ,取得对象属性的值,或执行简单的运算或判断操作。EL在得到某个数据时,会自动进行数据类型的转换。
    不同版本的tomcat是否默认开启对EL表达式的支持,是不一定的。为了保证EL表达式能够正常使用,需要在<%@page 标签里加上isELIgnored=”false”
  • 语法
    • 以“${”开始,以“}”作为结束:${EL表达式}
    • 获取某对象的值可以直接写入对象的名称,如获取对象名为“user”的对象的值:${user}
    • 获取某对象的属性的值使用点操作符(“.”操作符),如获取对象user的name属性和age属性的值的语法如下:${user.name} ${user.age}
  • 作用域优先级
    EL表达式可以从pageContext,request,session,application四个作用域中取到值,如果4个作用域共有属性,EL会按照从小到大的优先级顺序获取 :
    pageContext>request>session>application
  • JavaBean
    EL可以很方便的访问JavaBean的属性
    • JavaBean概念
      JavaBeans是Java中一种特殊的类,可以将多个对象封装到一个对象(bean)中。特点是可序列化,提供无参构造器,提供getter方法和setter方法访问对象的属性。名称中的“Bean”是用于Java的可重用软件组件的惯用叫法。特点:
      1. 供无参public的构造方法(默认提供)
      2. 每个属性,都有public的getter和setter
    • 获取JavaBean属性
      获取JavaBean的属性,只需要通过.符号操作就可以,如:${Student.name}
  • eq
    进行条件判断,大大简化了 JSTL的 c:if 和 c:choose 代码
    格式:${key键 判断符 值? 条件1:条件2 }
    常见判断符:
    eq相等 ne、neq不相等,
    gt大于, lt小于
    gt大于, lt小于
    gte、ge大于等于
    lte、le 小于等于
    not非 mod求模
    is [not] div by是否能被某数整除
    is [not] even是否为偶数
    is [not] odd是否为奇