2019.06.11

第一章 JAVA Web 入门

1.1 Web应用概述

Web应用是一种通过互联网访问的应用程序,使用网页语言编写,通过浏览器运行的动静态网站。在实际应用中大多数网站采用动静结合的原则,网站中内容需要频繁更新,可采用动态网页技术,内容不需要更新,采用静态网页进行显示。
动态网站:由大量的动态页面。后台处理程序以及用于存储内容的数据库组成,具有交互性,自动更新,多样性的特点。动态网站技术有CGI,ASP,ASP.NET,PHP,Servlet和JSP等几个重要的动态网站技术。

  1. CGI:在早期互联网发展过程中,动态网站技术主要采用CGI(通用网关接口)来实现,CGI程序在服务器端运行,能够根据不同的客户端请求输出相应的HTNL页面,同时可以访问存储在数据库中的数据以及其他系统中的文件,从而实现动态生成的效果(Perl和Shell)。
  2. ASP和ASP.NET:ASP(动态服务器接口)是微软公司推出的一种动态网页语言。ASP也可以运行在服务器端,可以包含HTML标记,普通文本,脚本命令以及对一些特定微软应用程序的的调用。
  3. PHP:PHP(超文本预处理语言):是基于开源代码的脚本式语言,与ASP一样,php也是采用脚本嵌入到HTML中,但PHP中混合了C,JAVA,Perl等语言语法的优秀部分。
  4. Servlet:sun公司发布基于Servlet的Web服务器,并建立了Java Servlet APL(应用程序编程接口)的编码标准。易于书写java代码,
  5. JSP:JSP是基于Java语言的服务器端脚本语言,是实现HTML代码和Java代码混合的编码技术。JSP是Servlet APL的一个扩展,能够支持多个操作系统平台。易于实现页面设计。

web应用架构

C/S(Client/Server)客户端/服务器:采用功能分布的原则,客户端负责数据处理,数据表示以及用户接口等功能;服务器端负责数据管理等核心功能,两端共同配合来完成复杂的业务应用。提高响应速度。
B/S(Borwser/Server)浏览器/服务器:是基于特定的HTTP通信协议的C/S结构,对CS架构的一种变化或者该进的结构,web应用架构即是指这种架构。
web应用运行过程
基于B/S结构的web应用,通常有客户端浏览器,Web服务器和数据库服务器构成

  • web服务器负责运行使用动态网站技术编写的Web应用程序;
  • 数据库服务器负责管理应用程序使用到的数据;
  • 浏览器负责帮助用户访问运行在Web服务器上的应用程序。

Web应用程序“请求——处理——响应”的基本运行流程

  1. Web浏览器发送请求: 客户通过URL地址发送的请求转换为标准的HTTP请求,并将服务器响应返回的HTML代发转换为客户端能够看到的图形界面。在典型的web应用程序中,一般通过运行在浏览器端的HTML和脚本代码来提供用户的输入数据的入口以及对数据进行初始化验证。浏览器会将数据通过HTTP协议的GET或POST方法发送到服务器端。
  2. 服务器端处理用户的请求:Web服务器首先需要检查请求的文件地址是否正确,若错误,返回错误信息,若正确,服务器将根据请求的GET或POST方法及文件的类型进行相应的处理,将结果以HTML或XML或着二进制文件等数据形式表示。并按照HTTP协议的响应消息格式反馈给浏览器,浏览器会根据消息附带的信息查看并显示该信息。
  3. 将结果返回给浏览器:一般情况下,服务器将处理结果返回给客户端浏览器时,要指明响应的内容类型,内容长度,然后把响应内容写入到输出流中,客户端浏览器收到响应后,首先查看响应头的内容类型,确实输入流中响应的信息的MIME类型,返回的内容可以是HTML.文本,XML,图像视频流等。

Java web应用的优势
Java web应用是用Java技术来解决相关的web互联网应用领域的技术总和 ,web应用包括web服务器端应用和web客户端应用两部分,Java在客户端的应用有Java Applet,在服务器端有Serve了他,JSP和第三方框架等,都遵循统一的Java EE技术标准,
常用的web服务器有:IIS,Apache,Tomcat,JBoss,Tomcat。

第二章 ,Servlet基础

Servlet是基于Java语言的Web服务器段编程技术,是运行在Servlet容器中的Java类,它能够处理Web客户的http请求,并产出http响应。Servlet对请求的处理和响应过程分为:

  • 1,接受HTTP请求。
  • 2,取得请求信息,包括请求接头和请求参数数据。
  • 3,调用其他Java类方法,完成具体的业务功能。
  • 4,实现到其他Web组件的跳转(包括重新定向和请求转发)。
  • 5,生出HTTP响应。servlet具有高效,方便,功能强大,可移植性好。

Servlet体系结构

Servlet是使用Servlet API及相关类和方法的Java程序,有两个软件包。
Javax.servlet包:包含支持所有协议的通用的Web组件和类,主要有javax.servlet.Servlet接口,javax.servlet.GenericServlet类,javax.servlet.ServletRequest接口,javax.servlet.ServletResponse接口。
javax.servlet.http包:包含支持http协议的接口和类,主要有javax.servlet.http.HttpServlet类,javax.servlet.http.HttpServletRequest接口,javax.servlet.http.HttpServletResponse接口。

Servlet接口:
javax.servlet.Servlet的定义如下:public interface Servlet,所有的Servlet都必须直接或间接实现javax.servlet.Servlet接口。Servlet接口规定了必须由Servlet类实现并且由Servlet引擎识别和管理的方法集。Servlet接口的基本目标是提供与Servlet生命周期相关的方法,如init(),service().

Servlet接口的方法

方法 方法描述
init(ServletConfig config) Servlet的初始方法。在Servlet实例化后,容器调用该方法进行Servlet的初始化;Servlet API规定对任何Servlet实例init()方法只能被调用一次,如果此方法没有正常结束,就会抛出一个ServletException异常,且不再执行,随后在次调用会导致容器重新加载并再次运行init()方法。
service(ServletRequset req,ServleResponse resp) Servlet的服务方法。当用户对Servlet发出请求时容器会调用该方法处理用户的请求;ServletRequest参数提供请求数据的方法,ServletResponse参数提供Servlet的构造响应的方法
destroy() Servlet的销毁方法。容器在终止Servlet服务前掉用此方法,容器调用此方法前必须给Service()线程足够时间来结束执行,因此接口规定当service()正在执行时,destroy()不被执行
getServletconfig() 此方法可以让Servlet在任何时候获得ServletConfig对象
getServletInfo() 此方法返回一个String对象,该对象包含Servlet的信息,例如开发者,描述信息等

GenericServlet类
javax.servlet.GenericServlet的定义:public abstrace class GenericServlet extends Object inlpements Servlet,ServletConfig,Serializable
Generic是一个抽象类,是Servlet接口的直接实现,除了service()方法外,提供有关其他的Servlet生命周期的方法,

GenericServlet类的主要方法

方法 方法描述
init(ServletConfig config) 该方法来源于Servlet接口,若重写该方法,必须调用super.init(config),这样GenericServlet类的其他方法才能正常工作
init(ServletConfig config) 该方法重载Servlet接口的上一个init()方法而无需调用super.init(config),而ServletConfig对象依然可以通过调用getServletConfig()方法获得
service(ServletRequst req,ServletRequest req,SrevletResponse resp) 这是一个抽象方法,当为执行网络请求继承GenericServlet类时必须实现
destroy() 与Servlet接口中的destroy()方法相同
getServletConfig() 返回一个Servlet的ServletConfig对象
getServletContext() 返回一个Servlet的ServletContext对象,通过ServletConfig。getServletContext()获得
getServletInfo() 该方法来源于Servlet接口,可以重写该方法以产生有意义的信息

GenericServlet类同时实现了ServletConfig接口,可以在不用获得ServletConfig对象的情况下直接调用ServletConfig的方法,例如:getInitParameter(),getInitParameterNames()和getServletContext()

HttpServlet类

若要实现一个在Web中处理HTTP请求的Servlet。则需要使用HttpServlet,Javax.servlet.http.HttpServlet的定义如下:
public abstract class Httpservlet exends GenericServlet implements Serlizable
HttpServlet类扩展了GenericServlet类并且对Servlet接口提供了与HTTP相关的实现,是在web开发中定义的Servlet最常用的类。
Httpservlet的主要方法

方法 方法描述
service(HttpservletRequest req,HTTPServletResponse resp) HTTPServlet在现实Servlet接口时,重写了Servlet()方法,该方法会自动判断用户的请求方式:若为GET()请求,则调用HTTPServlet的doGET()方法。若为POST请求,则调用doPost()方法,因此,开发人员在编写Servlet时,通常重写doGet()和doPost()方法,不用重写servlet方法,如果Servlet收到一个HTTP请求而没有重新加载相应的do方法,它就返回一个方法对资源不可用的标准HTTP错误
doGet(HttpServletRequest req,HttpServletResponse resp) 此方法被本类的service()方法调用,处理HTTP请求
doPost(HttpServletRequest req,HttpServletRespose resp) 此方法被本类的service()方法调用,处理Http请求

HttpServlet作为Http请求的分发器,还提供了Http的其他请求类型:HEAD,OPTIONS,DELETE,PUT和TRACE也提供了相应的处理方法。HttpServlet能够处理HTTP请求的Servlet,在Servlet接口上添加了对HTTP协议的处理,在编写Servlet时,通常继承这个类。
其实Servlet中,service方法是一直存在的,因为最高层的接口Servlet(像HTTPServlet等具体的servlet实现类都直接或则间接的实现了这个接口)里就有这个方法,所以不管是怎样的Servlet类都有service方法,如果写一个Servlet后,重写了service方法,那么servlet容器就会把请求交给这个方法处理,在service方法中没有调用doGet或者doPost方法,doGet和doPost方法就不会起作用。如果要重写需要在末尾添加super.service()可以解决问题,一般service方法不需要重写它会根据请求的方式,调用doGet或者doPost方法。
Servlet生命周期
Servlet本身不直接在Java虚拟机上运行,而是由Servlet容器负责管理其整个生命周期,Servlet生命周期是指Servlet实例从创建到响应客户端请求,直至销毁的过程,会经过创建,初始化,服务可用,服务不可用,处理请求,终止服务和销毁服务7种状态。

  • 加载和实例化:Servlet创建,在服务器运行中,客户机首次向Servlet发送请求,重新装入Servlet时,在为Servlet配置了自动装入选项(load-on-startup)时。
  • 初始化:Servlet容器调用Servlet的init(ServletConfig config)方法来对Servlet实例进行初始化。读取固定数据,初始化JDBC连接等资源连接,init()方法的参数ServletConfig对象由Servlet容器创建并传递给Servlet,一直存在,直到销毁。
  • 处理请求:服务器接受到客户端请求后,会为该请求创建一个请求对象和响应对象,并调用service()方法,service()方法在调用其他方法。
  • 销毁:当Servlet容器需要终止Servlet,它会先调用Servilet的destroy()方法.

Serlvet的声明配置

Servlet代码编写完成,若要进行运行访问,还需要对其进行声明配置,Servlet的声明配置信息主要包括Servlet的描述,名称,初始参数,类路径以及访问地址等,在Servlet3.x中可以使用注解方式实现,注解**@WebServlet**用于将一个类声明为Servlet,容器会根据具体的属性配置把相应的类部署为Servlet。对于自动生成代码@WebServlet("/HelloServlet")表示当请求的URL地址匹配/HellServlet映射地址时,加载执行此Servlet,这种配置为最简声明配置。

@Webservlet(name = "Servlet的名字",utlPatterns = {"/xx"},initParams  ={ @WebInitParam(name = "username",value = "qst")},loadOnStartup = 0,asyncSupported = true,displayName = "XXServliet",description = "Servlet 样例")//Servlet 的最简声明配置。

注释@WebServlet的属性及其描述

属性名 类型 描述
name String 指定Servlet的名字,可以为任何字符串,一般与Servlet的类名相同,如果没有显示指定,则该Servlet的取值即为类的权限定名
urlPatterns String[] 指定一组Servlet的URL匹配模式,可以是匹配地址映射(如/SimpleServlet),匹配目录映射(/servlet/ 通配符)和匹配扩展名映射(如 通配符.action)
value String[] 该属性等价于urlParams,不能同时使用
loadOnStrams int 指定servlet的加载顺序。当此选项没有时,表示容器在该Servlet第一次被请求时才加载;当值为0或者大于0时,表示容器在启动时就加载这个Servlet.,值越小,启动该Servlet的优先级越高
initParams WebInitParam[] 指定一组Servlet初始化参数,可选
asyncription boolean 声明Servlet是否支持异步操作模式,默认false
description String 指定该Servlet的描述信息
displayName String 指定该Servlet的显示名,通常配合工具使用

通过项目得配置文件web.xhl完成,内容遵循XML语法格式,

<servlet><description>Servletrliexi</description>//指定Servlet的描述信息,等价于@WebServlet的description属性<display-name>asd</display-name>//指定Servlet的显示名<servlet-name>aServlet</servlet-name>//指定Servlet的名称,一般与Servlet类名相同,要求在web.xml文件内名字唯一,等价于@WenServlet的displayName属性<servlet-class>com.liruilong.zuiyan.aservlet</servlet-class>//指定Servlet的全限名,包名.类名<init-paranm>//指定Servlet的初始化参数,可选,等价于@WebServlet的initParams属性,可重复定义。<param-name>username</param-name>//指定初始参数名<param-value>qst<param-value>//指定对应的值</init-paranm><load-on-started>0</load-on-started>//指定Servlet 的加载顺序,等价于@Webservlet的loadOnStartup属性<async-supported>true</async-supported>//指定Servlet是否支持异步操作模式。默认false
</servlet>
<servlet-mapping>//用于指定URL的映射<servlet-name>aServlet</servlet-name>指定要映射的Servlet名称,要与<servlet>的<servlet-name>值一致<url-pattern>*.jsp</url-pattern>//指定servlet的URL匹配模式,等价于@WebServlet的urlPatterns属性或value属性
</servlet-mapping>```

###Servlet应用
Servlet是运行在Web服务器端的Java程序,在Web开发中,Servlet常用于在服务器端处理一些与界面无关的任务,例如客户端请求数据的处理,HTTP请求报头和响应报头的处理,请求链的传递和转向控制等。
数据处理:在Web应用中,客户端向服务器请求数据的方式通常有两种

  • 通过超链接形式查询数据;语法<a href = "URL地址?参数值[&参数 = 参数值...]" >链接文本</a>//即Web中以GET方式提交数据。数据部分和地址部分由?隔开,参数之间由&隔开,但安全性差,以明文方式显示。在发送的请求的URI地址可以是绝对地址,也可以是相对地址,开发中一般使用相对地址,便于开发移植。当用户通过超链接发送的请求到达Servlet容器时,包含数据的请求将被容器转换为ServletRequest对象,如果用户的请求使用的是HTTP协议,请求还将进一步包装成HTTPS而vletRequset对象,对请求的处理工作就是由HTTPServletRequest对象完成。
    Httpsrevletrequest对象常用的数据处理方法
方法 描述
public String getParamenter(String name) 返回由name指定的用户请求参数的值
public String[] getParamenterValuse(String name) 返回由name指定的一组用户请求参数的值
public Enumeration getparameterNames() 返回所有客户端请求的参数名
 容器在讲请求转换为HTTPServletRequest对象之后,对用超链接的GET请求则会调用doGet()方法;对于Form表单的POST请求则会调用doPost()方法。
  • 通过Form表单形式更新数据
  • 语法:<form action = "URL" method = "GET/POST"><input type = "submit"/></form>

重定向与请求转发
Servlet在对客户端请求的数据处理完成后,会向客户端返回响应结果,响应结果可以由当前Servlet对象的PrintWriter输出流直接输出到页面上的信息,也可以是一个新的URI地址对应的信息,这个地址可以是HTML,JSP,Servlet或是其他形式的HTML地址。在Servlet中可以通过两种主要方式完成对新的URL地址的转向:重定性和请求转发。
1,重定向:指由原请求地址重新定位到某个新地址,原有的请求失效,客户端看到的是新的请求返回的响应结果,客户端浏览器地址栏变成了新的请求地址,在重定性过程中客户端和服务器会经过两次请求和两次响应,其中第二次请求由客户端发起。第一次请求到服务器后,由服务器响应指定重定向的第二请求,返回客户端后第二请求发出,最后经过服务器发返回响应。
重定向通过HttpServletResponse对象的sendRedirect()方法实现的,该方法会通知客户端去重新访问新指定的URL地址:public void sendRedirect(string location)throws java.io.IOExcetion//location为重定向的URL地址,可以是相对路劲或绝对路径,可以重定向到当前应用程序中的资源,还可以重定向到同一站点的其他资源,使用绝对URL可以定位到其他站点的资源。
2,请求转发:指将请求转发到其他地址,使用同一个请求,转发后的浏览器地址内容不变,即经过一次请求响应,转发过程发生在服务器内部,服务器只能从当前应用内部查找相应的转发资源,而不能转发其他资源,
使用RequesDispatcher接口中的forward()方法来实现,该方法可以把请求转发给另外一个资源,并让该资源对此请求进行响应RequestDispatcher接口还有一个include()//将其他资源并入到当前请求中。RequestDispatcher是一个接口,需要通过使用HttpResquest对象的getrequesDispatcher()方法获得该接口的实例对象。

   RequestDispatcher dispatcher =request.getrequestDispatcher(String path).forward(ServletRequeste request,Servletresponse response);

path为指定转发的URL地址(只能为相对路径),“/”表示当前应用程序的根目录。在重定向的相对路径中“/”表示整个web站点。
请求转发与重定向的区别;

  1. 转发只能将请求转发给同一个Web应用中的组件,重定向可以重定向到当前资源,同一个站点的其他资源,以及其他站点资源。
  2. 重定向访问后的URL会发生改变,请求转发URL地址保持不变。
  3. 重定向是由服务器告诉浏览器去重新请求一个URL,请求转发是服务器程序内部发生转发行为,
  4. 请求转发服务器之间共享请求对象和响应对象,属于同一个访问请求过程,重定向调用者与被调用者使用各自的请求和转发对象。属于两个独立的访问请求和响应过程。

Servlet 3.0特性
注解支持
可插性支持
动态配置
异步处理:
在Servlet的业务处理中Servlet的线程会一直处于阻塞状态,对于打的项目,可能造成性能瓶颈,Servlet3.0提出异步处理的方式,Servlet接受到请求之后,可能首先需要对其请求携带的数据做预处理,其次,Servlet线程将请求转交给一个异步线程来执行业务处理,线程本身返回至容器,此时Servlet线程将请求转交给一个异步线程来执行业务处理,线程本身返回至容器,此时的Srevlet还没有生成响应数据:异步线程处理完业务后,可以直接生成响应数据,或者将请求继续转发给其他Servlet,异步处理可以应用与Servlet和过滤器两种组件

第三章 Servlet的核心接口

servlet的核心接口;

  • ServletConfig接口:用于获取Servlet初始化参数和ServletContext对象;
  • ServletContext接口:代表当前Servlet运行环境,Servlet可以通过ServletContext对象来访问Servlet容器中的各种资源。
  • HttpServletRrequest接口:用于封装HTTP的请求信息;
  • HttpServletResponse接口:用于封装HTTP响应消息;

ServletConfig接口:(获取Servlet信息)

容器在初始化一个Servlet时。将为该Servlet创建一个唯一的ServletConfig对象,并将这个ServletConfig对象通过init方法传递并保存到此Servlet对象中。Servlet接口中的方法主要访问Servlet初始化话参数和ServletContext对象,可以通过
ServletConfig接口的主要方法

方法 描述
getInitParameter(String param) :根据给定得初始化参数名称,返回参数值,若参数不存在,返回null
getInitParameterNames() :返回一个Enumeration对象,里面包含了所有的初始化参数名称。
getServletContext() :返回当前ServletContext()对象。
getServletName() :返回当前Servlet的名字,即@WebServlet的name属性值,如果没有配置,返回Servlet类的全限定名。

可以采用Servlet初始化化参数来配置一些需求不断变更的信息。可以通过web.xml文件配置初始化参数使用ServletConfig对象获取初始化参数:
urlurl地址串
String url = conig.getInitParameter(“url”);
当更换数据库连接信息时,只需要更换配置属性即可。

ServletContext接口:

ServletContext也称为Servlet上下文,代表当前Servlet运行环境,是Servlet与Servlet容器之间直接的接口,Servlet容器在启动一个Web应用时,会为该应用创建一个唯一的ServletContext对象供该应用中所有的servlet 对象共享,servlet对象可以通过ServletContext对象访问容器中各种资源。
获取servletContext对象可以通过以下两种方式:
通过ServletConfig接口的getServletContext()方法获取ServletContext对象;
通过GenericServlet抽象类的getServletContext()方获得ServletContext对象.//调用ServletConfig的getServletContext()方法。
ServletContext接口提供了以下几种类型的方法:

  • **获取应用范围的初始化参数的方法。
  • 存取应用范围域属性的方法。
  • 获取当前Web应用信息的方法。
  • 获取当前容器信息和输出日志的方法。
  • 获取服务器端文件资源的方法。
一,**获取应用初始化参数:通过Web.xml可以配置应用范围的初始化参数,应用程序加载读取,存入ServletContext对象中

getInitParameter(String name):返回Web应用范围内指定的初始化参数值,在web.xml中使用元素表示应用范围内的初始化参数。
getInitParameterNames()返回一个包含所有初始化参数的名称的Enumeration对象。
EnumetionparamNames =super().getInitParameterNames()//使用ServletContext获取对象所有初始化参数。

二,存取应用域属性

ServletContext对象可以理解为容器内的一个共享空间,可以存储应用级别作用域的数据。文本应用中组件可以共享数据,数据以key/value形式存储在ServletContext对象中,
应用域:表示Web应用的生命周期构成的时间段,也表示在Web应用范围内的可访问性。

方法 描述
setAttribute(Stirng name,Object object) 把一个对象和一个属性名绑定并存放到ServletContext中,参数name指定属性名,参数Object表示共享的数据
getAttribute(String name) 根据参数给定的属性名,返回一个Object类型的对象
getAttributeNames() 返回一个Enumeration对象,该对象包含了所有存放在ServletContext中的属性名
removeAttribute(String name) 根据参数指定的属性名,从ServletContext对象中删除匹配的属性。

对于存储在ServletContext对象中的属性,不同的servlet都可以通过ServletContext对象对其进行访问和修改,要考虑异步以及线程问题。

三,获取应用信息

servletContext对象还包含了Web应用的信息,当前Web应用的根路径,应用的名称,应用组件间的转发以及容器下其他的Web应用的ServletContext对象等。
getContextPath():返回当前Web应用的根路径。
getServletContextName():返回Web应用的名字,即元素中元素的值。
getRequestDispatcher(String path):返回一个用于向其他Web组件转发请求的RequestDispatcher对象。
getContext(String urlpath):根据参数指定的URL返回当前Servlet容器中其他web 应用的ServletContext()对象URL必须是以“/”开头的绝对路径。(即当前目录下的绝对路径)。

四,获取容器信息**

ServletContext接口还提供了获取有关容器信息和向容器输出日志的方法。

  • getServletInfo():返回Web容器的名字和版本。
  • getMajorVersion():返回Web容器支持的ServletAPI的主版本号。
  • getMinorVersion():返回web 容器支持的ServletAPI的次版本号。
  • log(String msg):用于记录一般的日志。
  • log(String message,Throwable throw):用于记录异常的堆栈日志。
五,获取服务器文件的资源

使用ServletContext接口可以直接访问Web应用中的静态内容文件,HTML,GIF,Properties文件等。还可以获取文件资源的MIEM类型以及服务器中存在的真实的路径。

  • getResourceAsStream(String path):返回一个读取参数指定的文件的输入流,参数路径必须以“/”开头。
  • getResource(String path):返回由path指定的资源路径对应的一个URL对象,参数路径必须以“/”开头。
  • getRealPath(String path):根据参数指定的虚拟路径,返回文件系统中一个真实的路径。
  • getMimeType(String file):返回参数指定的文件的MIME类型。

HttpServletRequest接口:

在ServletAPI中,servletRequest接口被定义为用于封装请求的信息,ServletRequest对象由Servlet容器在用户每次请求Servlet时被创建并传入Servlet的service()方法中。HTTPServletRequest接口继承了ServletRequest接口。专用于处理HTTP协议的子接口。
HTttpServletRequest接口提供处理HTTP请求的方法

  • 获取请求报文信息。
  • 获取网络连接信息的方法。
  • 存取请求域属性的方法。
    一,获取取请求行信息:请求行由请求方法,请求URL,HTTP版本组成。
方法 描述
getMethod(): 获取使用请求的HTTP方法
getRequestURI(): 获取请求行中的资源名部分。
getProtocol(): 获取使用的协议版本和版本号。
getQueryString(): 获取请求URL后面的查询字符串。GET
getServletPath(): 获取Servlet所映射的路径。
getContextPath(): 获取请求资源所属于的Web应用的路径。
二,获取请求头信息:

在Servlet中,可以通过HTTPServletRequest的
getHeadNames():方法获取所有请求头名称,此方法返回一个Enumeration(枚举)类型的值。
getHeader():方法来根据指定的请求头名称读取对应的请求头信息。如果当前的请求中提供了对应的请求头,则返回对应的值,否则返回空。
getIntHeader(String name):获取整数类型参数名为name的HTTP头部。
getDateHeader(String name):获取long类型参数名为name的http头部。
getContentLength():获取请求内容的长度,以字节为单位。
getContentType():获取请求的文档类型编码方式。
getLocale():获取用户浏览器设置的Locale的信息。
getCookies():获取一个Cookie[]数组,该数组包含这个请求当中的所有cookie,如果这个 请求中没有cookie,返回空数组。
GET请求内容长度为-1,文档类型为null;

三,获取请求正文信息

使用applicantion/x-www-form-urlencoded编码方式的请求正文,可以使用HTTPServletrequest接口的方法获取其请求参数信息

方法 描述
String getParameter(String name): 返回由name指定的用户请求参数的值。
Enumeration getParameterName(): 返回所有用户请求的参数名。
String []getParameterValues(String name): 返回由name指定的用户请求参数对应的一组值。
Map getParameterMap(): 返回一个请求参数的Map对象,Map中的键为参数的名称,值为参数名对应的参数值。
multipart/form-data编码方式的请求正文由描述头,空行 ,主体三部分构成。非文件类型的元素的主体内容就是表单设置的值,文件类型的元素主体内容为文件的二进制数据形式,
ServletInputStream getInputStream(): 获取上传文件二进制输入流。
Buffererequest getrequest(): 获取上传文件字符缓存输入流。

对于Servlet中文件上传参数的获取问题,有很多第三方插件。Apache Commons FileUpload smartUpload等。

四,请求参数中的中文问题

服务器端Servlet在调用HttpServletRequest对象的getParameter()方法获取参数时会以HttpservletRequest 对象的getCharacterEncoding()方法返回的字符集对其进行解码。而getCharacterEncoding()方法返回值在未经过setCharacterEncoding(charset)方法设置编码的情况下为null,这时getParameter()方法将服务器默认的ISO-8859-I字符集对参数进行解码。对于post请求,服务器端Servlet在调用HttpServletRequest对象的getParameter()方法前先调用setCharacterEncoding(charset)方法设定页面请求编码相同的解码字符集。;在JSP页面中浏览器可以根据页面的编码格式,以及java.net包下的URLEncoder类的encode(string,charset)的方法对URL中的中文字符 编码。
对于浏览器使用其他的编码字符集进行编码的情况,可以在配置文件serlver.xml中设置connector元素的URIEncoding属性来指定解码字符集。

五**,获取网络连接信息**

HttpServletRequest接口还为客户端和服务器的网络通信提供了相应的网络连接信息。

方法 描述
getRemoterAddr(): 获取请求用户的IP地址。
getRemoteHost(): 获取请求用户的主机名称。
getremotePort(): 获取请求用户的主机所使用的网络端口号。
getLocalAddr(): 获取Web服务器的IP地址。
getLocalName(): 获取Web服务器的主机名。
getLocalPort(): 获取Web服务器所使用的网络端口号。
getServletPort(): 获取URl请求的端口号。
getServletName(): 获取网站的域名。
getScheme(): 获取请求使用的协议,例如http或https;
getRequestURL(): 获取请求的URL地址。
六,获取请求域的属性:

存储在HttpServletrequest对象中的对象称之为请求域的属性,属于同一个请求的多个处理组件之间可以通过请求域属性来传递对象数据。

方法 描述
void setAttribute(String name,Object value): 设定name属性的值为value,保存在request范围内。
Object getAttribute(String name): 从request范围内获取那么属性的值。
viod removerAttribute(String name): 从request范围内移除那么属性的值。
EnumerationgetAttributeNames(): 获取所有Names范围内的属性。

HttpServletRepose接口

在ServletAPI中,ServletRepose接口被定义为用于创建响应消息,ServletResponse对象由Servlet容器在用户每次请求Servlet时创建,并传入Servlet的service()方法中,HttpServletResponse接口继承自ServletResponse接口,专用于HTTP协议的子接口,用于封装HTTP响应的消息。在HttpServlet类的service()方法中,传入的ServletResponse对象被强制转换为HttpServletResponse对象来进行HTTP响应响应信息处理。
HttpServletResponse接口方法:

  1. 设置响应状态的方法。
  2. 构建响应头的方法。
  3. 创建响应正文的方法。
一,设置响应状态

HttpServletPrsponse接口提供了设置状态码并生成响应状态行的方法,

方法 描述
setStatus(int sc): 以指定的状态码将响应返回给客户端。
setError(int sc): 使用指定的状态码向客户端返回一个错误响应。
sendError(int sc,String msg): 使用指定的状态码和原因短语向客户端返回一个错误响应。
sendRedirect(String location): 请求的重定向,会设定响应Location抱头以及改变状态码。

在实际开发中,一般不需要人为的修改设置状态码,容器会自动响应发送相应的状态码。

二,构建响应信息

在servlet中,可以通过HttpServletRespose的setHeader()方法来设置Http响应消息头,它接受两个参数用于指定响应消息头的名称和对应的值。
语法:

方法 描述
public abstract void setHeader(String headerName,String headerValue) //String类型的报文
public abstract void setIntHeader(String headerName,int headerValue) //整数类型的报文
public abstract void setDateHeader(String headerName,long millisecs) //日期类型的报文

对于常用的消息头,ServletAPI 中也提供了一些特定的方法来设置。

方法 描述
setContentType(String mime): 设定Content-Type消息头。
setContentLength(int length): 设定Content-Length消息头。
addHeader(String name,String value): 新增String类型的值到名为name的http头部。
addIntHeader(String name,int value): 新增int类型的值到名为name的http头部。
addDateHeader(String name,long date): 新增long类型的值到名为name的http头部。
addCookie(Cookie c): 为Set-Cookie消息头增加一个值。
三,创建响应正文

在Servlet中,向客户端输出的响应数据是通过输出流对象来完成的,HttpServletResponse接口提供了两个获取不同类型输出流对象方法。
getOutputStream():返回字节输出流对象ServletOutputStream。
getWriter():返回字符输出流对象PrintWriter。

servletOutputStream对象主要用于输出二进制字节数据,例如,配合setContentType()方法响应输出一个图像,视屏等。PwintWriter对象主要用于输出字符文本内容。但其内部实现还是将字符串转换成了某种字符集编码的字节数组后再进行输出。
当向ServletOutputStream或PrintWriter对象中写入数据后,Servlet容器会将这些数据作为响应消息的正文,然后再与响应状态行和各行响应头组合成完整的响应报文输出的客户端。在Servlet的service方法结束后,容器还将检查getwriter()或getOutputStream()方法返回的输出流对象是否已经调用过close()方法。

四,响应输出中的中文问题

当Servlet程序需要输出纯文本格式的响应正文时,通常会调用Sevletresponse对象的getWriter()方法返回一个PrintWriter对象,然后使用PrintWriter对象将文本内容写入到客户端。
ServletResponse接口中定义了setCharacterEncoding(),setContentType()和setLocale()等方法来指定ServletResponse.getWriter()方法返回的PrintWriter对象所使用的字符集编码。
Response.setCharacterEncoding(“UTF-8”);//只能设置PrintWriter输出流中字符的编码方式,它的优先权最高,可有覆盖后面的两种方法。
Response.setContentType(“text/html;charset =UTF-8”);//既可以设置PrintWriter输出流中字符的编码方式,也可以设置浏览器接受到这些字符后以什么编码方式来解码,优先权低于第一项,高与第三项。
Response.setLocale(new java.util.Locale(“zh”,“CN”));//只能用来设置PrintWriter输出流中字符的编码方式,优先权最低。
小结


容器在初始化一个Servlet时,会为这个Servlet创建一个ServletConfig对象,并将这个对象通过init(ServletConfig config)方法传递并保存在此Servlet对象中。
使用ServletConfig接口中的方法主要可以访问两项内容:Servlet初始化参数和ServletContext对象,前者通过由容器从Servlet的配置属性中读取(如initParams或所指定的对象,后者为Servlet提供有关的容器信息)

  • ServletContext对象代表当前Servlet运行环境,Servlet容器在启动一个Web应用时,会为该应用创建一个唯一 的ServletContext对象供该应用中的所有Servlet对象共享,Servlet对象可以通过ServletContext来访问容器中的各种资源。

  • ServletContext对象可以获得应用范围的初始化参数,在应用范围内存取共享数据,访问当前Web应用的信息,访问当前容器的信息和输出日志和访问服务器端的文件系统资源。

  • HttpServletRequest接口用于封装HTTP请求信息,对象用于获取请求报文信息,获取网络连接信息和存取请求域属性。

  • HttpServletResponse接口用于封装HTTP响应信息,创建响应报文,ServletContex对象,

  • HttpServletRequest对象具有相同的存取域的方法。

**ServletConfig对象有何作用,在Servlet中如何使用?**
每个Servlet拥有唯一的ServletConfig对象,Servlet可以通过ServletConfig对象获取初始化参数和ServletContext对象。在Servlet中使用@WebServlet(initParams = {@WebInitParam(name = “xx”,value = “xx”)});或者在web.xml中定义元素的子元素来指定初始化参数,在Servlet的init()方法中调用ServletConfig参数getInitParameter()方法来获取初始化参数的值,调用ServletConfig对象的getServletContext()方法来获取ServletContext对象。
**ServletContext对象和ServletConfig对象的getInitParameter()方法有何区别?**
ServletContext对象的getInitParameter()方法用来访问整个应用范围内的初始化参数,参数通过web.xml的元素来指定,所有的servlet都可访问,ServletConfig对象对象的getInitParameter()方法用来访问当前Servlet的初始化参数,参数通过web.xml的来指定。仅当前配置的Servlet可访问。
**ServletContext对象如何存取自定义属性,属性的访问范围是什么?**
ServletContext对象通过setAttribute(name,value)方法来存取自定义属性,通过getAttribute(name)来取自定义属性值。ServletContext对象的自定义属性也被称为应用域属性,表示在web应用的整个生命周期内,可以被web应用范围内的所有组件所共享
**HttpServletRequest对象如何自定义属性,属性的访问范围是什么?**
HttpServletrequest对象通过setAttribute(name,value)方法来自定义一个域属性,HttpServletRequest对象自定义属性也被称为请求域属性,表示在本次请求和响应的生命周期内供本次请求对象所访问,
HttpServletResponse对象通过调用getOutputStream()方法获取字节输出流对象ServletOutputStream,用于创建包含二进制数据的响应正文,通过调用getWriter()方法获取字符输出流对象PrintWriter,用于创建包含字符数据的响应正文。


第四章 会话跟踪

Internet通信协议分为两大类:**有状态协议(Stateful)与无状态(Stateless)协议,**两者最大的差别在与客户端与服务器之间维持联机上不同,
会话跟踪技术:

Cookie技术

Cookie对象的创建:Cookie unameCookie = new Cookie(“username”,“SQL”);指定Cookie的属性名和属性值。
可以使用HttpServletRespose对象的addCookie()方法,通过增加Set-Cookie响应头的方式将将响应返回给浏览器,
服务器向客户端响应Cookie:Response.addCookie(unameCookie);
存储在客户端的Cookie通过HttpServletrequest对象的getCookie()方法获取,返回所访问网站的所有Cookie的对象数组,遍历该数组可以获得各个Cookie对象,

Cookie [] cookie = request.getCookie();
if(cookie != null)
for(Cookie c:cookies){out.println("属性名:"+c.getName());out.println("属性值:"+c.getValue());
}

设置Cookie在某个应用下(服务器所有应用)的访问路径:unameCookie.setPath("/chapter/jsp/");unameCookie.setPath("/");
设置Cookie的存活时间:unameCookie.setMaxAge(72460*60);//存货时间为一周的cookie,
Cookie的缺点主要集中在安全性和隐私保护上,Cookie的大小和个数受限,单个Cookie保存的数据不能超过4KB,很多浏览器都限制一个站点最多保存20个Cookie。

Session技术

Session技术是指使用HttpSession对话实现会话跟踪技术,HttpSession对象是Javax.servlet.http.HttpSession接口的实例,也称会话对象,该对象用来保存单个用户访问时的 一些信息,是服务器在无状态的Http协议下用来识别和维护具体某个用户的重要方式。
HttpSession对象会在用户第一次访问服务器时由容器创建(在访问JSP,Servlet,等程序才会创建,只访问HTML,IMAGE等静态资源并不会创建),当用户调用其失效方法(invalidate())或超过其最大不活动时间时会失效,在此期间,用户与服务器之间的多次请求都属于同一个会话。服务器在创建会话时,会分配一个唯一的会话标识:Session,以“JSESSIONID”的属性名保存在客户端Cookie中,在用户随后的请求的中,通过JSESSIONID属性来识别不同的用户。
获取HttpSession对象的方法及描述
getSession():获取与客户端请求关联的当前的有效的Session,若没有Seeion关联则新建一个。

HttpSession session = request.getSession();

getSession(boolean create):获取与客户端请求关联的当前的有效的session,若没有Session关联,当参数为真是,Session被新建。 HttpSession session = request.getSession(true);
HttpSession接口提供了存取会话域属性和管理会话生命周期的方法

方法 描述
void setAttribute(String key,Object value): 以key/value的形式将对象保存在HttpSession对象中。
Object getAttribute(String key) :通过key获取对象值。
void removeAttribute(String key): 从HttpSession对象中删除指定名称key所对应的对象。
void invalidate(): 设置HttpSession对象失效。
void setMaxInactiveInterval(int interval): 设定HttpSession对象的非活动时间,若超过这个时间,HttpSession对象将会失效。
int getMaxInactiveInterval(): 获取HttpSession对象的有效非活动时间(以秒为单位)。
String getId(): 获取HttpSession对象的标识sessionid。
long getCrationTime(): 获取HttpSession对象产生的时间,单位毫秒。
long getLastAccessedTime(): 获取用户最后通过这个HttpSession对象送出请求的时间。

在Web中设置会话的不活动时间:

<session -config><session-timeout>10</session-timeout></session-config>

服务器在执行会话失效代码后,会清楚会话对象及其所有会话域属性。同时响应客户端浏览器清除Cookie中JSESSIONID。实际中多用于安全退出。一般认为通过关闭浏览器即可结束本次会话,但是错误的,服务器端的会话仍会存在。

URL重写技术

URL重写是服务器程序对接受的URL请求重写成网站可以处理的另一个URL的过程。实现动态网站的会话跟踪,使用URL重写技术可以对请求URL地址追加会话标识。实现会话跟踪功能。
URL重写:http://localhost:8080/chapter04/EncodeURLServlet;EncodeURLServlet;jessionid=24665464dsf5456erw4……
jessionid为追加的会话标识。服务器通过它来识别跟中某个用户的访问。URL重写通过HttpServletRespose的encodeURL()方法和endeRedirect()方法的URL进行重写。若包含该请求,会将URL原样输出,若不包含,则会将会话标识重写到URL中。
在客户端浏览起完全禁用了Cookie后,通过在请求地址后附加会话标识的URL重写技术任可实现会话的跟踪技术,如果应用重写URL,必须对应用的所有请求都(超链接,表单,action属性,重定向地址)重写,将JSESSIONID维持下去。 由于浏览器对URL地址长度的限制,特别是在对含有查询参数的GET请求进行URL重写,需要注意长度,由于静态页面不能进行会话标识的传递,因此所有的URL地址都必须为动态请求地址。

隐藏表单域

利用Form表单的隐藏表单域,可以在完全脱离浏览器对Cookie的使用权限以及在用户无法显示页面看到的隐藏标识的情况下,将标识随请求一起穿送给服务器处理。实现会话跟踪。
Cookie技术与Session技术的区别:
Cookie数据存储在客户端浏览器上,Session数据存储在服务器上。Cookie存储在客户端,安全性差,Session会在一定时间内存储在服务器上,但当访问量增多时,会造成服务器加重,Cookie存储在客户端,不占用服务器内存。Cookie的大小由浏览器限制,Session的大小有服务器内存决定。Session中存储的是对象,Cookie中存储的是字符串。Session不区分访问路径,同一个用户在访问一个网站期间,所有的请求地址都可以访问到Session,而Cookie如果设置参数路径,那么同一网站中不同路径下的


Cookie是相互访问不到的。Session需要借助Cookie才能正常工作,
会话对象的生命周期?

HttpSession对象会在用户第一次访问服务器有容器创建,在用户调用其失效方法或超过最大不活动时间时失效。
何时使用URL重写技术?
当不确定客户端浏览器是否Cookie的情况下,使用URL重写技术可以对请求的URL地址追加会话标识,从而实现用户的会话跟踪功能。


JSP概述

JSP(Java Servlet pages)是一种动态网页技术标准,用于开发包含动态内容的Web页面的技术,与Servlet一样,是一种基于Java的服务器端技术,主要用于产生动态网页内容。服务器端脚本语言,JSP本质上就是Servlet,实际上JSP首先被翻译为Servlet后才编译运行的,因此JSP技术能够实现Servlet的所有功能。
优点:JSP使用输出维护HTML更容易,JSP可以使用标准的HTML工具,JSP通过标签库等机制能够很好的与HTML结合。一次编写,各处执行,简单快捷,组件重用。易于部署,升级和维护。
JSP文件开头使用"<%@page%>"指令进行页面设置,JSP文件大部分是HTML代码,在HTML代码中标签体中,使用<% %>声明一段Java脚本
JSP执行原理:JSP与Servlet一样,都运行的servlet 容器中,执行过程:

  1. 客户端向服务器发送JSP页面请求。
  2. 容器检索请求的JSP页面,第一次请求,则将静态数据与动态数据 转换为JAVA代码,使JSP文件翻译为一个Java文件(servlet)
  3. 容器将翻译后的Servlet源代码编译编译字节码文件(.class),对于Tomcat服务器而言,生成的字节码文件默认存放在<Tomcat安装目录的>\work目录下。
  4. 编译后的字节码文件被加载到容器内存中执行,并根据用户的请求生成HTML格式的响应内容,
  5. 容器将响应内容返回客户端。

当同一个JSP页面再次被请求时,只要该JSP文件没有发生过改变,容器将直接调用已加载的字节码文件,而不会再执行翻译和编译的过程
**

JSP基本结构

**
JSP页面就是有JSP元素的常规的Web页面,它由模板文档和JSP元素构成,模板文档可以是任何HTML,XML,纯文本,JSP并不依赖于HTML,它可以 使用任何一种标记语言,模板文本通常被直接传递给浏览器,在处理一个JSP页面时,模板文本和JSP元素所生成的内容会合并后发送。
JSP有三种元素,脚本元素(scripting element),指令元素(directive element),和动作元素( action element)

JSP元素 内容
脚本元素 脚本<%%>,表达式<%=%>,声明<%!%>注释<%-- --%>
指令元素 <%@page>,<%@include,<%@taglib
脚本元素 < jsp:include>,< jsp:forward>,< jsp:param>,< jsp:userBean>’

**

脚本元素

:将小段的Java代码添加到JSP页面,包括脚本,表达式,申明和注释。**
脚本代码(Scriptlet):就是JSP中的代码部分,可以使用任何的Java语法。
JSP表达式:一种简单的输出形式,要有输出的值。
JSP声明:用于声明一个或多个变量和方法,并不输出任何的文本到输出流,在声明元素中声明的变量和方法将在JSP页面初始化时进行初始化。<%JSP声明%>中的变量在编译时作为类的属性存在,而放在脚本中的变量将在类的方法内部被声明。
JSP注释:在JSP中使用<%-- --%>的方式注释

**

指令元素

**:向JSP容器提供编译的信息,指令并不向客户端产生输出,指令都只在当前页面中有效,page,include,taglib指令。
page指令:描述与页面的相关信息,位于开头部分,可以多次出现,每个指令属性不能重复,重复会覆盖。
语法:<%@page 属性列表%>

language 设定JSP页面的脚本语言,默认java
import 指定导入的Java软件包或类名列表,多个逗号隔开
isThreadSafe 指定JSP容器执行JSP程序的模式,两种,一种为默认值true,代表JSP容器会以多线程的方式运行JSP页面,另一种false,单线程,建议为true
contentType 指定MIME类型和JSP页面响应时编码方式,默认为text/html;charset=ISO8859-1,设置该属性会改变JSP输出内容的处理方式
pageEncoding 指定JSP页面本身的编码方式,
session 指定是否使用session对象
errorPage 设定JSP页面发生异常时重新指向的页面URL,指向的页面文件要把isErrorpage设置为true
isErrorpage 指定JSP是否为异常处理的页面,默认true
isELIgnored 指定JSP页面是否忽略El表达式,默认false
buffer 指定输出流是否需要缓存,默认8kb,与autoFlush一起使用,确定是否自动刷新输出缓存,true时,输出缓存区满时,刷新缓存区而不是跑出异常
autoFiush 如果页面缓存区满时,要自动刷新输出,设置为true时,否则设置为false时,页面缓存满时抛出一个异常

include指令:在页面翻译期间引入另一个文件,被包含的文件可以是JSP,HTML或文本文件。
语法:<%@include file = “文件”%>,该指令将JSP翻译为Servlet时,当前JSP和被包含的文本会融合到一起形成一个Servlet,然后进行编译运行,此过程也称为"静态包含",包含文件与被包含文件不能定义同名的变量,
taglib指令:用于指定JSP页面所使用的标签库,通过该指令可以在JSP页面中使用标签库中的标签
语法:<%@taglib uri = “标签库URI” prefix = “标签前缀”%>:uri指定描述这个标签库的位置的URI,可以是相对或绝对。prefix:指定使用标签库中标签的前缀。保留前缀:jsp,jspx,java,javax,servlet,sun,sunw。
Servlet更于进行业务逻辑和数据处理,JSP擅长于进行动态数据展示和用户的交互。

动作元素(JavaBean概述):

在JSP中可以使用XML语法格式的一些特殊标记来控制行为,称为JSP标准动作库(Standard Action),利用JSP动作库可以实现很多功能:动态插入文本,调用JavaBean组件,重定向页面和Java插入生成HTML代码:
JSP规范定义的标准动作:
< jsp:include>:动作用于在页面被请求时引入一个文件;可以引入一个静态或动态的页面,也称为动态包含,不和JSP页面合并,运行时才处理,该动作可以包含一个或几个< jsp:param>子动作,用于向要引入 的页面传递数据。

语法:
< jsp:include page = "urlSpec" flush = "true"/>或者
< jsp:include page = "urlSpec" flush = "true">
<jsp:include param name = "name" value  = "value"/>
……
< /jsp:include>

//page:指定引入文件的地址。
//flush="true"表示设定是否自动刷新缓存区,默认为false,可省略,在页面包含大量数据时,可将一部分数据先行输出,
//name:指定传入文件的变量名。
//value:指定传入文件的变量名对应的值。
include指令元素和include动作元素的异同:
共同点:include指令元素和include动作元素都是实现包含文件代码复用。
区别:对包含文件的处理方式和处理指令不同。include指令元素在翻译阶段就引入所包含的文件,被处理的文件在逻辑上和语法上依赖于当前的JSP页面,优点执行速度快。include动作元素是在JSP页面运行时才引入包含文件所产生的应答文本,被包含的文件在逻辑和语法上独立于当前JSP页面,其优点是可以使用param子元素更加灵活的处理所需要的文件,缺点是执行速度慢一些。
< jsp:forward>:动作用于把请求转发到另一个页面,可以包含一个或几个< jsp:param>子动作,用于向所转向的目标资源传递参数。功能与Servlet的RequestDispatcher对象的forward方法类似,调用者与被调用者共享一个request对象。

语法:
<jsp:foward page = "relativeURLSpec"/>或
<jsp:param name ="name" value = "value"/>
……
< /jsp:foeward>

//page指定转发的相对地址;
//name:指定转向页面的传递的参数名称;
//value:指定向转向页面传递的参数名称对应的值。

JavaBean是一种特殊的Java类,以封装和重用为目的,优点:易于维护编写,封装了复杂的业务逻辑,可移植性,便于传输,用于本地和网络传输,分两种,有用户界面(UI)GUI组件,无用户界面,负责封装数据,业务处理JavaBean,JSP通常使用后一种。JSP+JavaBean与JSP+Servlet+JavaBean的组合设计模式成为开发JavaWeb的主流模式。
JavaBean规范:
JavaBean是一个public 类(外部访问),具有无参构造函数(外部实例化调用),提供setXxx()和getXxx()方法,被外部程序实例还使用。符合规范的Java类,都可以称为JavaBean。
setXxx()与getXxx()方法也被称为setter方法与getter方法,是针对JavaBean方法的一种命名方式,方法的名称为set+属性名和get+属性名构成,属性名是将JavaBean的属性名称首字母大写,JavaBean通过这种方法的命名 规范以及对类的访问权限和构造函数的要求,使得外部程序能够通过反射机制来实例化javaBean和查找到这些方法,从而调用这些方法来设置和获取JavBean对象的属性。
在javaBean中,对于属性的定义也不同于普通类中的属性定义,javaBean的属性是指setter和getter方法名中所包含的属性名,即使JavaBean类中没有定义此名称的实例变量,也可以成为JavaBean方法,即有方法就可以,这种定义方式扩展了属性的定义,融入了对javaBean所封装的业务功能状态的表示。
在JSP中使用JavaBean,在Java中可以向使用普通的类一样访问JavaBean,通过Java脚本实例化JavaBean,调用JavaBean对象的方法,使用动作元素访问JavaBean方法。
< jsp:useBean>:动作用于在某一指定名称的作用域范围内查找或者实例化一个JavaBenan,查找返回引用,不存在则实例化新的javBean对象,并将它指定的名称存储在指定的作用域范围内;JSP可以动态使用JavaBean组件来扩充JSP的功能。

语法:
<jsp:useBean id = "name" class = "className" scope= "page|request|session|application"/>或
<jsp:useBean id = "name" type = "typeName" scope = "page|request|session|application"/>

id:JavaBean对象的引用和其储存域名属性名,通过ID可以访问。
class:指定JavaBean的类名(全限定名),容器根据class指定的类调用其构造方法来创建这个类的实例;
scope:指定JavaBean的作用范围,可以使用page|request|session|application,默认page。
type:指定JAVBean对象的类型,通常在查找已存在的javaBean 时使用,这时使用type将不会产生新的对象。
JSP引擎首先在< jsp:useBean>元素scope属性所指向的作用域范围中查找id属性指定的JavBean对象,如果该域不存在此对象,则根据class指定的类名新创建一个对象。并将此对象以id属性指定的名称存储到scope属性指定的域范围。

<jsp:useBean id = "user" class ="com.qst.ch03.model.UserBean" scope = "request"/>
//在请求范围内创建或查找名为user的UserBean的对象。

< jsp:setProperty>;动作用于设置javaBean的属性;和< jsp:useBean>动作一起使用时,可实例化一个JavaBean对象,并对其属性初始化。

语法;
<jsp:setProperty name = "beanaName" property = "propertyName" value  ="propertyValue"/>或
<jsp:setProperty name = "beanaName" property = "propertyName" param  ="propertyName"/>
<jsp:setProperty name = "beanaName" property = "propertyName" />
<jsp:setProperty name = "beanaName" property = "*" />

//name:指定JavaBean的对象名,与useBean动作中id相对应;
//property:指定要为JavaBean中需要赋值的属性名;
//value:指定要为属性设置的值。可以为字符串,或者表达式,被自动转换为所要设置的JavaBean属性的类型,属性可选。
//param:指定请求中的参数名(如表单传值和URL传值),并将该参数字符串赋值给property所指定的属性。可选,不能与value同时使用。
// property = “*” :表示对JavaBean对象的多个属性进行赋值,此种形式将请求消息中的参数逐一与JavaBean对象中的属性进行比较,如果找到同名的属性,则将该请求参数赋给该属性。

<jsp:useBean id = "user" calss = "com.qst.ch3.UserBean" scope = "request"/>
<jsp:setProperty name = "user" property ="userName" param = "longinNane"/>
取出请求中名为longinName的参数值赋给user对象的userName属性。

由于嵌套在< jsp:useBean>元素中的< jsp:setProperty>元素只有在实例化JavaBean对象时才被执行,因此如果< jsp:useBean>元素所引用的JavaBean对象已经存在,嵌套的< jsp:setProperty>元素将不被执行。只有在JavaBean对象初始化时才执行。

< jsp:getProperty>:动作用于读取某个javabean的属性。不管什么类型都会被转换为String类型后输出到响应正文中。

语法:
< jsp:getProperty name ="beanName" property = "propertyName">

//name:指定JavaBean对象名,与useBean动作中的id相对应。
//property:指定JavaBean中需要访问的属性名。

JSP内置对象

JSP内置对象是指在JSP页面中,不用声明就可以在脚本和表达式中直接使用的对象,JSP内置对象也称隐含对象。特点:有Web容器自动载入,不需要实例化,通过Web容器;来实现和管理,在所有的JSP页面中,直接调用内置对象都是合法的。

对象名 类型 功能说明
request javax.servlet.http.HttpServletrequest 请求对象,提供客户端HTTP请求数据的访问
response javax.servlet.hhtp.HttpServletrequest 响应对象,用来向客户端输出响应
out javax.servlet.jsp.JspWriter 输出对象,提供对输出流的访问,由java.io.Writer类继承得
session javax.servlet.http.HttpSession 会话对象,用来保存服务器与每个客户端会话过程中的信息
application javax.servlet.ServletContext 应用程序对象,保存整个应用环境信息
pageContext javax.servlet.jsp.PageContext 页面上下文对象,用于存储当前JSP页面的相关信息
config javax.servlet.ServletConfig 页面配置对象,JSP页面的配置信息对象
page javax.servlet.jsp.HttpJsPage 当前JSP页面对象,即this
exception java.lang.Throwable 异常对象,用于处理JSP页面中的错误

与input/Putput有关的内置对象:request,response,out对象,主要用来作为客户端和服务器间通信的桥梁,request表示发送请求,response表示响应,out表示把处理结果输出。

request对象拥有HttpServletRequest的所有方法。request对象获取参数的方法即适用于URL查询字符串的GET请求,也适用于Form表单的POST请求。request对象通过setAttribute()和getAttribute()存取请求域属性,在实际开发中,多用于存储,传递本次请求的处理结果。

response对象即响应对象,将JSP处理的响应返回给客户端,有HttpServletresponse接口的所有方法。
out对象即输出对象,控制管理输出的缓存区(buffer)和输出流(output stream)向客户端页面输出数据。与getWriter()方法获取的PrintWriter功能相同。
数据的处理

print/printil() 输出一个基本数据类型的值
print/printil() 输出一的对象的引用地址
print/printil(String str) 输出一个字符串的值
newLine() 输出一个换行符

out对象的newLine()和println()在显示页面不会有换行,生成的HTML页面中,输出数据后换行。
缓存区处理

viod clear() 清除缓存区内容,若缓存区内容为空,则产生IOException异常
void clearBuffer() 清除输出缓存区的内容,若缓存区内容为空,不产生以上
void flust() 直接将目前暂存 于缓存区的数据刷新输出
void close() 关闭输出流,,流一旦关闭就无法使用out对象
int getBufferSize() 获取缓存区的大小(KB)
int getRemaining() 获取目前使用还剩下的缓存区的大小(KB)
booiean isAutoFlush() 返回true表示缓存区满时会自动刷新输出,false表示缓存区满时不会自动清除并产生异常处理

向out对象的输出流写入数据时,数据会先被存储在缓存区中,在JSP默认得配置下,会在满时自动刷新。

与Context(上下文)有关的内置对象,包括session,application和pageContext对象,其中session对象表示浏览器与服务器的会话上下文环境,application对象表示应用程序上下文环境,pagesContext表示当前JSP页面上下文环境。

session对象即会话对象,表示浏览器与服务器之间的一次会话,一次会话的含义是指从客户端浏览器连接服务器开始到服务器端会话过期或用户主动退出后结束,session对象具有HttpSession接口的所有方法。存储在session范围中的属性即使经过重定向的多次请求仍然有效,考虑到session本身的目的,通常只应该把与用户状态有关的的信息放入session范围内,

application对象即应用程序程序上下文对象,表示当前应用程序的运行环境,获取应用程序上下文中的环境,application在容器启动时实例化,在容器关闭时销毁,作用域为整个web容器的生命周期。application具有ServletContext接口的所有功能。

pageContext即页面上下文对象,表示当前页面的运行环境,用于获取当前JSP页面的相关信息,pageContext对象作用范围为当前的JSP页面。可以访问当前页面的所有内置对象。提供存取页面域属性的方法。

获取内置对象的方法
ServletRequest getRequest() 获取当前JSP页面的请求对象
ServletResponse getResponse() 获取当前JSP页面的响应对象
HttpSession getSession() 获取与当前页面有联系的会话对象
ServletConfig getServletConfig() 获取当前JSP页面的servletConfig对象
ServletContext getServletContext() 获取当前JSP页面的运行环境的application对象
Object getPage() 获取当前JSP页面的Servlet实体page对象
Exception getException() 获取当前JSP页面的异常exception对象,不过此页面的page指令的isErrorPage属性要设为true
JspWriter getOut() 获取当前JSP页面的输出流out对象
存取属性的方法
Object getAttribute(String name,int scope) 获取范围为scope,名为name的属性对象
void setAttribute(String name,Object value,int scope) 以名/值对的方式储存scope范围域的属性
void removeAttribute(String name,int scope) 从scope范围移除名为name的属性
Enumeration getAttributeNameScope(int scope) 从scope范围中获取所有属性的名称

scope参数被定义为4个常量,代表四种作用域范围:
PAGE_SCOPE =1(页面域),REQUEST_SCOPE =2(请求域),SESSION_SCOPE = 3(会话域),APPLICATION_SCOPE =4(应用域)。

与Servlet有关的内置对象:包括page对象和config对象,
page对象表示JSP翻译后的Servlet对象,即this,代表JSP本身,可以调用servlet 的所有的方法,
config对象表示JSP翻译后的Servlet 的ServletConfig对象。即页面配置对象,存储一些初始的数据结构,
与Error有关的内置对象
exception对象,当JSP网页有错误会产生异常,exception对象就用这个来对异常做处理。
如果JSP页面中要使用该对象,必须将page指令的isErrorPage属性设置为true。
JSP的四种作用域(对象的生命周期和可访问性):

  1. 页面域(page scope):页面域的生命周期是指页面执行期间,存储在页面域的对象只对它所在页面是可访问的。
  2. **请求域(request scope )**请求域的生命周期是指一次请求的过程,包括请求转发(forward)和被包含(include)的情况.存储在请求域中的对象只有在此次请求过程中才可以被访问,
  3. **会话域(session scope)**会话域的生命周期是指某个客户端与服务器所连接的时间,客户端在第一次访问服务器时创建会话,在会话过期或安全退出会话结束。存储在会话域的属性在整个会话期间可以被访问。
  4. **应用域(application scope)**应用域的生命周期是指从服务器开始执行服务到服务器被关闭为止,是4个域中最长的,存储在域中的对象可以被JSP和Servlet共享访问,要注意存储数据的大小和安全,可能会造成服务器负载过重。产生线程安全问题。
    JSP的4种作用域分别对应pageContext,request,session和application,4个内置对象,都可以通过setAttribute(String name,Object value):方法来存储属性,通过getAttribute(Stirng name,Object value):来获取属性。

表达式语言

EL(Expression Language,表达式语言)简介是一种简单的语言,方便处理应用程序数据,而无需要JSP脚本元素和JSP表达式,E最初是在标准标签库JSTL(JavaServlet Page Standard Tag Library )1.1中定义。后来分离出来,因此,只要支持Servlet2.4,JSP2.0 以上的版本Web容器,都可以在JSP网页中直接使用EL。EL在容器中默认配置下处于启动状态,JSP页面也可以通过Page指令isELgnored属性单独设置其状态。
< %@page isELIgnored= "true|false" %>
//如果属性取值为true,则EL表达式被当做字符串直接输出,默认情况下isELIgnored为false,由JSP引擎调用EL引擎来解释执行其中的表达式。
EL表达式语言最大的优势是可以方便的访问JSP的隐含对象的JavaBean组件,代替<%=%>,<% %>的功能,是JSP页面从HTML代码中嵌入Java代码的混乱结构得以改善,提高程的可读性和易维护性,(可以访问内置对象pageComtext,request,session,application),简化了对JavaBean,集合的访问方式。对数据进行自动类型转换,通过各种运算符进行运算,使用自定义函数实现更加复杂的业务功能)

1,EL语法

${ 表达式}//表达式可以为常量,变量,表达式中可以使用EL隐藏对象,EL运算符,合EL函数。
EL中的常量:布尔值,整形常量,浮点型常量,字符串常量,NULL常量。
EL中的变量:EL变量不同于JSP从当前页面中查找,而是由EL引擎调用PageContext.findAttribute(Stirng)方法从JSP作用域中按照page,request,session,application范围的顺序依次查找该变量。找到回传,停止。没有找到,回传null,一般指定查找范围。
EL中的保留字:and,or,not,empty,div,mod,instanceof,eq,ne,lt,gt,le,ge,true,false,null;
EL中的[]和 . 操作符:"."访问属性,[]也可以用来访问属性,[“属性名”];当属性名中有特殊字符时(.-等),要用[]。
[] :可以访问有序集合或数组中的指定索引位置的某个元素 ${attay[0]};可以访问Map对象的Key关键字的值, $ {map[“key”]};可以与点操作符结合使用 $ {users[0].username}。
EL 的错误处理机制:不提供警告,只提供默认值和错误,默认值为空字符串,错误是抛出一个异常,常见错误的处理方式:

  • 访问一个不存在的变量,表达式输出空字符串,而不是输出null;
  • 访问一个不存在的对象的属性时,表达式输出空字符串,不抛出NullPointerException异常。
  • 访问一个存在对象的不存在属性时,则表达式会抛出PropertyNotFoundException异常。
EL隐含对象:
  • 与范围有关的隐含对象:pageScope,requestScope,sessionScope,applicationScope.
pageScope 获取页面作用范围中的属性值=pageContext.getAttribute()
requestScope 获取请求作用范围中的属性值=request.getAttribute()
sessionScope 获取会话作用范围中的属性值=session.getAttribute()
applicantionScope 获取应用程序作用范围中的属性值=application.getAttribute()
  • 与请求参数有关的对象:param,paramValues。对post与Get请求都适用。
param 用于获取请求参数的单个值=request.getParameter()
paramValue 获得请求参数的一组值=request.getParameterValues()
  • 其它的隐含对象:pageConrext,header,headerValues,cookie,initParam。
pageContext 相当于JSP页面中的pageContext 对象,用于获取ServletContext,request,response和session等其他的JSP内置对象
header 用于获取HTTP请求头中的单个值=request.getHeader(String name)
headerValues 用于获得HTTP请求头中的一组值,相当于request.getHeaders(String name)
cookie 用于获取指定的Cookie
initParam 用于获取上下文初始化参数,相当于applicant。getParameter(String name)
EL运算符:

算术运算符:+,-,*,/(div),%(mod);
关系运算符:==(eq),!=(ne),<(lt),>(gt),<=(le),>=(ge);
逻辑运算符:&&(and),||(or),!(not);
条件运算符:A?B:C;
empty运算符:是一种前缀操作符,检测值是否为空或null,$( empty 操作数);
//当操作数指向的对象为null时,表达式为true;
//当操作数是空字符串时,返回true。
//当操作数是集合或数组时,如果操作数中没有任何元素,返回true。
//当操作数是java.util.Map对象中的一个关键字时,如果Map对象为空时,Map对象没有指定的关键字时,或Map对象的关键字对应的值为空时,表达式返回true。
运算符的优先级

从上到下 从左到右
[] ,"." < ,>,<=,>=,lt,gt,lege
() ++,!=,eq,ne
-,not,!,empty && ,and
*,/,div/%,mod || ,or
+,- ? :
EL自定义函数:提供一种语法允许在EL中调用某个java类的静态方法,EL自定义函数扩展了EL表达式的功能。通过方法调用实现一些复杂的业务逻辑。S{ns.func(a1,a2,a3)};
  • 前缀ns必须匹配包含了函数的。
  • func为函数的名称。
  • a1,a2……an为函数的参数。
EL自定义函数的开发与应用包括三个步骤:
  • 编写EL自定义函数的映射的Java类以及类中的静态方法。
  • 编写标签库描述符文件(TLD文件),在TLD文件中描述自定义函数。
  • 在JSP页面中导入和使用自定义函数。

标准标签库

JSTL简介(javaServer Pages Standard Tag Library,JSP 标准标签库)是由Apache和Jakarta项目组开发的一个通用型标签库,是JSP 2.0最重要的特性之一。
将下载的jar包放到项目的运行环境calsspath中,在Eclipse工具下,可将其复制到WebContent\WEB-INF\lib目录下。
JSTL主要提供给Java Web开发人员一个标准通用的标签函数库,标签库同时支持EL获取数据,Web开发人员能够利用此标签函数库取代直接在页面中嵌入Java程序的做法。
JSTL函数库的分类

标签库 前缀名 URI 示例
核心标签库 c http://java.sun.com/jsp/jstl/core <c:out>
I18N标签库 fmt http//:java.sun.com/jsp/jstl/fmt fmt:formatDate
SQL标签库 sql http//:java.sun.com/jsp/jstl/sql sql:query
XML标签库 x http://java.sun.com/jsp/jstl/xml <x:forBach>
函数标签库 fn http://java.sun.com/jsp/jstl/functions fn:split

核心标签库:包含Web应用的常用操作标签,在JSP中使用核心标签库,首先需要使用taglib指令导入,
<%@taglib prefix =“标签库前缀” uri = “http://java.sun.com/jsp/jstl/core”%>
//prefix:表示显示声明标签库的前缀名,可以为任意字符串,通常设置为c不能使用:以及保留的关键字,
//uri:表示核心标签库的URI,从而定位标签库描述文件(TLD);
在TSTL1.0的版本中,核心心标签库的URI属性值为:http://java.sun.com/jstl/core;

  • 通用标签,用于操作变量:<c:out/>,<c:set/>,<c:remove/>,<c:catch/>标签;
    1 输出数据(=<%=%>):<c:out value = “value” [escapeXml = “{true|false}”] [default = “defaultValue”]/>
    value:表示要输出的数据,可以是JSP表达式,EL表达式或静态值。
    escapeXml:表示是否将><&’“等特殊字符进行HTML字符实体转换在进行输出。默认值为true;
    default:表示如果value属性的值为null时所输出的默认值。
    常见的HTML字符实体转换:>(&gt;),<&lt;),&(&amp;),’(&#039),”(&#034),
    2设置范围与的属性:<c:set var =“varName” value =“value” [scope = “{page|request|session|application}”]/>
    var:指定要设置的范围域的属性名;
    value:指定var属性的属性值,
    scope:指定var属性所属的范围域,默认为page;
    3删除范围域属性:<c:remove var =“userNmae” [scope= “{page|request|session|aplication}”]>
    var:要删除的属性名;scope:所在的范围域;
    4捕获异常:<c:catch [var = “varName”] nested actions></c:catch>
    var:标识捕获的异常对象的名称,并将异常对象保存到page域中。
    若未指定var属性,则仅捕获异常而不再page域中保存异常对象。
    <c:catch var =" myexception">
    <%=5/0%>
    </c:catch>
    <c:out value = “myException"/>//java.lang.ArithmeticException:/byzero;<c:outvalue="{myException}"/> // java.lang.ArithmeticException:/by zero; <c:out value= "myException"/>//java.lang.ArithmeticException:/byzero;<c:outvalue="{myException.message}”/>// /by zero;
  • 条件标签,用于流程控制<c:if>,<c:choose>,<c:when>,<c:otherwise>;
    1条件判断:<c:if test = “condition”[var = “varName”] [scope = “{page|request|session|application}”]>
    //condition为true时执行代码;
    </c:if>
    test:用于指定条件表达式:返回Boolean型值;
    var:用于指定test属性的执行结果保存在某个范围作用域的属性名称;
    scope:指定将test属性的执行结果保存到指定范围域;
    2多条件选择<c:choose >没有属性,标签体内容只能有一个或多个<c:when>和0个或多个<c:otherwise>标签一起使用:
    <c:choose >
    //<c:when>或<c:otherwise>标签
    </c:choose>
    3<c:when test = “condition”>,必须以<c:choose>为父标签,且必须在<c:otherwise>标签之前,即条件分支if的意思
    //condititon为true时执行的代码;
    <c:when>
    4<c:otherwise>,即当前面所有的<c:when>标签条件都不符合的情况下的最后的选择
    //执行的代码
    <c:otherwise>
  • 迭代标签,用于循环变遍历集合<c:forEach>,<c:forTokens>;
    1用于遍历集合或迭代指定的次数:
    <c:forEach [var = “varName”] items = “collection” [varStatus = “varStatusName”][begin = “begin”][end = “end”][step = “step”]>
    //标签体内容;
    </c:forEach>
    var :指定当前迭代的元素保存到page域的属性名称。
    items:指定将要迭代的集合对象。
    varStatus:表示当前被迭代到对象的状态的信息对象,有四个属性,index(表示当前迭代成员的索引值),count(表示当前以迭代成员的数量),first(表示当前迭代到的成员是否为第一个)和last(表示当前迭代到的成员是否为最后一个);
    begin:表示遍历的起始索引,值为整数。
    end:表示遍历的结束索引,值为整数。
    step:表示迭代的步长,值为整数。
    2用于实现类似java.util.StringTokenizer类的迭代功能,按照指定的分隔符对字符串进行迭代
    <c:forTokens items = “stringOfTokens” delims = “delimitres” [var = “varName”][varStatus = “varStatusName”][begin = begin][end= end] [step=step]>
    //标签体内容
    </c:forTokens>
    items:用于指定将要迭代的字符串;
    delims:用于指定一个或多个分隔符;
    var:用于将当前迭代的子字符串保存到page域中的属性名称。
    varStatus:表示当前被迭代的状态的信息。
    begin:指定从第begin个子字符串开始迭代。索引值0开始。
    end:指定迭代到end个字符串,索引值0开始。
    step:指定迭代的步长。
  • URL标签,用于针对URL的相关操作<c:URL>,<c:import><c:redirect>
    1用于在JSP页面中构造一个URL地址:
    <c:irl value = “value”[var = “varName”][scope = “{page|request|session|application}”][context = “context”]>
    [<c:param name = “paramName” value = “paramValue”/>]
    </c:url>
    value:指定要构造的URL;
    var:指定构造出的URL结果保存到范围域的属性的名称。
    scope:指定属性存在的范围域;
    context:指定URL地址所属的同一容器下的Web应用上下文。当指定context属性时,value属性中的地址必须是以“/”开头的相对地址。
    <c:param>:标签指定URL地址传递的参数。可选;
    3用于执行response.sendRedirect()方法的功能。将当前访问请求重定向到其他资源:
    <c:redirect url = “value”[context=“context”]>
    [<c:param name = “paramName” value = “paramaValue”/>]
    </c:redirect>
    url:用于指向重定向的目标资源的URL地址;
    context:指定重定向地址所属的同一容器下的Web应用上下文;
    <c:param>:标签指定URL地址传递的参数,可选。
    4用于在JSP页面中导入一个URL地址指向的资源内容,可以是一个静态或动态文件,可以是当前应用或同一服务器下的其他应用中的资源。
    <c:import url = “url” [var = “varName”][scope = “{page|request|session|application}”][context = “context”][charEncoding = “charEncoding”]>
    [<c:param name = “paramName” value = “paramValue”/>]
    </c:import>
    url:指定要导入资源的URL地址;
    var:指定导入资源保存在范围域中的属性名称,可选;
    scope:指定导入资源所属的内容转换成字符串时所使用的字符集编码。
    context:指定重定向地址所属的同一容器下的Web应用上下文;
    charEncoding:指定将导入的资源文件传递的参数,可选。
    <c:include>标签与jsp:include动作指令功能相似,但jsp:include动作只能包含当前应用下的文件资源,而<c:import>标签可以包含任何其他应用或网站下的资源。例如<c:import url = “http://www.baidu.com”/>

l18N标签库

JSTL提供一个用于实现国际化和格式化功能的标签库———Internationlization标签库,简称为国际化标签库或l18N标签库,封装了java语言中java.util和java.text两个包中与国际化和格式化相关的API类的功能。提供对数字,日期时间等本地敏感的数据按本地化信息显示的功能。
使用I18N标签库,需要使用taglib指令导入:<%@taglib prefix =“fmt” uri= “http://java.sun.com/jsp/jstl/fmt”%>
国际化标签:
I18N中国际化标签主要包括< fmt:setLocale>,< fmt:bundle>,< fmt:setBundle>,< fmt:message>,< fmt:param>。
在使用国际化标签时,需要包含 有多个资源文件的资源包,资源包中的各个资源分别对应不同的的本地信息。
资源文件的创建:在资源包基名指定为messageResource,简体中文的资源名文件称为messageResponse_zh_CN.properties,,美国英语的资源文件为messageResponse_en_US.properties。
messageResponse_zh_CN.properties文件

title = JSTL\u6807\u7B7E
welcome = \u6B22\u8FCE\u60A8{0},\u65E5\u671F\u662F{1,date,full},\u65F6\u95F4\u662F{2,time,full}
organization = QST\u9752\u8F6F\u5B9E\u8BAD

< fmt:setLocale value = “locale” [scope = “{page|request|session|applicantion}”]/>:
用于在JSP页面中显示的设置用户的本地化语言环境,环境设置后,国际化标签库中的其他标签将使用该本地化信息,忽略客户端传过来的本地信息

<fmt:setLocale value="zh_CN"/>//设置页面语言环境为简体中文
<fmt:setLocale value="en"/>//设置页面语言环境为英文
//value用于指定语言和国家代码,可以为java.util.Locale或String实例。
//scope用于指定Locale环境变量的作用范围,默认page

< fmt:setBundle basename = “basename” [var = “varName”] [ scope = “{page|request|session|applicantion}”]/>
根据< fmt:setLocale >标签设置的本地化信息(绑定一个资源文件)创建一个资源包(ResourceBundle)对象,并可将其保存在范围域属性中。

<fmt:setLocale value = "zh_CN"/>//根据本地化信息,创建资源包对象
<fmt:setBundle basename = "messageResource" var = "messageResource"/>
//basename指定资源包的基名。
//var用于指定创建的资源包对象保存在范围域的属性名
//scope用于指定创建的资源包对象所属的范围域。
//该示例将会绑定名为messageResponse_zh_CN.properties的资源文件,创建相应的资源对象。

< fmt:bundle basename = “basename”[prefix = “prefix”]>
[< fmt: message key = “messageKey”>]
< /fmt:bundle>
与< fmt:setBundle>标签的功能类似,但其创建的资源包对象仅对其标签体有效。

<fmt:setLocale value = "zh_CN"/>
<fmt:bundle basename = "messageResource"><fmt message key = "title"/>
</fmt:bundle>
//对与资源文件中的Key名称较长的情况,可以把相同的前缀用属性prefix表示

< fmt:message key=“messageKey”[bundle=“resourceBundle”][var=“varName”][ scope = “{page|request|session|applicantion}”]/>
用于从资源包中查找一个指定的key的值,并进行格式化输出。

<fmt:setLocale value = "zh_CN"/>
<fmt:setBundle basename = "messageResource"/>
<fmt:message key = "title">
</fmt:message>
//重指定文件中查找key为title的value值显示,输出JSTL标签
//bundle指定使用的资源包名,若<fmt:setBundle>保存了资源文件,该属性就可以从保存的资源文件中
//var用于将显示信息保存为某个范围域的属性

< fmt:param value = “messageParameter”/>
标签仅有一个参数,用于在< fmt:message>中做参数置换

< fmt:setLocale value = "zh_CN"/>
< fmt:setBundle basename = "messageResource"/>
< fmt:message key = "welcome">
< fmt:param value = "${sessionScope.userName}"/}
< fmt:param value = "<%=new Date()%>"/>
< fmt:param value = "<%=new Date()%>">
< /fmt:message>
//对资源文件中的信息进行置换,对应{}中的信息。

格式化标签:I18N中的格式化标签包括< fmt:formatNumber>和< fmt: formaDate>
< fmt:formatDate value= “date”//指定要格式化的日期或时间
[type = “{time|date|both}”]//指定要输出日期或时间或者两者有之
[dateStyle = “{default|short|medium|long|full}”]//指定日期部分的输出格式。
[timeStyle = “{default|short|medium|long|full}”]//指定时间部分的输出格式。
[pattern = “customPattern”]//指定一个自定义的日期和时间输出格式;
[timeZone = “tiemZone”]//指定当时采用的时区
[var = “varName”]//指定格式化结果保存到某个范围域中某个属性的名称
[Scope = “[page|request|session|application]”]//指定保存的范围域
/>

<fmt:setLocale value = "zn_CN"/>
<fmt:formatDate value = "<% = new Date()%>"/>
<fmt:formatDate value = "<% = new Date()%>" pattern ="yyyy-MM-dd HH:mm:ss"/>
<fmt:formatDate value = "<% = new Date()%>" type = "both" dateStyle = "full"/>
<fmt:formatDate value = "<% = new Date()%>" type = "both" timeStyle = "medium"/>

fmt :formatNumber value = “numericValue”//指定需要格式化的字符串
[type = “{number|currency|percent}”]//指定值得类型,数字|货币|百分比
[pattern = “customPattern”]//指定自定义的格式化样式
[currencyCode=“currencycode” ]//指定货币编码,
[currencySymbol = “currencySymbol”]//指定货币编号
[groupingUsed = “{true|false}”]//指定格式化后的结果是否使用间隔符。
[var = “varName”]//指定保存在范围域的属性
[scope = “{page|request|session|application}”]//指定范围域
/>
用于将数值货币或百分比按本地化信息或自定义的格式进行格式化。

<fmt:setLocale value = "zn_CN"/>
<fmt:formatNumber value ="123.3" pattern = "#,#00.0#"/>//123.3
<fmt:formatNumber value ="0.12" type = "percent"/>//12%
<fmt:formatNumber value  ="1234567890" type = "currency"/>//¥1234567890.00
<fmt:formatNumber value  ="12.345" type  ="currern" pattern = "$#,##"/>//$12

格式化符号及其作用:0(表示一个数位),#(表示一个位数,前导零和尾追零不显示),.(表示小数点分割),,(表示分隔符的位置),-(负数前缀),%(用100乘,显示%号);
函数标签库
函数标签库是在JSTL定义的标准的EL函数集,函数标签库中定义的函数,基本上都是对字符串进行操作的函数。
使用taglib指令导入:
<%@raglib prefix = “标签库前缀” URL= “htttp://java.sun.com/jsp/jstl/function”%>
前缀通常设置为fu,uri定位当前标签库的描述文件(TLD 文件)

JSTL提供的EL函数标签库
contains(String string,String substring) 判断字符串string中是否包含字符串substring
containsIgnoreCase(String string,String string) 判断字符串string是否包含字符串substring,不区分大小写
endsWith(String string,String suffix) 判断字符串是否string是否以字符串suffix结尾
escapeXML(String string) 将字符串的XML/HTML等特殊字符转换为实体字符
indexOf(String string,String substring) 查找字符串string中字符串substring第一次出现的位置
join(Stirng []array,String separator) 将数组array中的每个字符串按给定的分隔符separator连接为一个字符串
length(Object item) 返回参数item中包含元素的数量,item的类型可以是集合,数组,和字符串
replace(String string,String before,String after) 用字符串after替换字符串string中的before,返回替换结果
split(String string,String separator) 以separator为分隔符对字符串string进行分割,将分割后的每部分内容存入数组中返回
startWith(String string,String prefix) 判断字符串string 是否是以prefix开头
substring(String string,int begin ,ine end) 截取字符串(前包后不包)
substringAfter(String string,String substring) 返回字符串substring在字符串string后面的内容
substringBefore(String string,String substring) 返回字符串substring在字符串string前面的内容
toUpperCase(String string) 转小写
toLowerCase(String string) 转大写
trim(String string) 去除String首尾的空格返回

EL函数在JSTL标签中的使用:${fu:函数名(参数列表)}
自定义标签库:
在jsp2.0中开发标签库需要步骤:

  • 开发自定义标签处理类;
  • 建立一个*.dlt文件对应的一个标签库,可以包换多个标签。
  • 在jSP中使用自定义标签。
    开发自定义标签类:需要继承一个父类:javax.serlvet.jsp.tagext.SimpleTagSupport,如果标签包含属性,要有对应的setter和getter方法。需要重写doTag()方法,负责生成页面内容
public class DateFormat extends SimpleTagSupport{Date data;String type;setter/getter方法省略
@Override
public viod doTag()throw JspException.IOException{SimpleDateFormat sdf = new SimpleDateFormat();if(type.equals("full")){sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");}if(type.equals("time")){sdf = new SimpleDateFormat("HH-mm—dd");}
JspWriter out= super.getJspContext().getOut();
out.print(sdf.format(date));
}

建立TDL文件:
TDL文件即标签库描述文件,每个TDL文件对应一个标签库,标签库的根元素是taglib,他可以包含多个tag子元素,每个tag元素都定义一个标签,

  • < tlib-version>元素:标签库的版本号
  • < jsp-version>元素:JSP版本号
  • < short-name>元素:标签库的默认前缀
  • < uri>元素:标签库的URI。
  • < tag>元素:当前标签库的一个标签
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE taglib PUBLIC "-//Sun Microsystems,Inc.//DTD JSP Tag Library 1.2//En""http://java.sun.com/j2ee/dtd/web-jsptaglibrary_1_2.dtd">
<taglib ><tlib-version>1.0</tlib-vresion><jsp-version>2.0</jsp-version><short-name>dateFormat</short-name><tag><name>dateFormat</name><tag-class>com.gst.chapter09.tag.DateFormat</tag-class><body-content>empty</body-content><descripttion>format date</descripttion><attribute><name>date</name><required>true</required><rtexprvalue>ttrue</rtexprvalue><rtexprvalue>true</rtexprvalue></attribute></tag>
</taglib>
<%@taglib prefix = "mydate" uri  ="/dateFormat"%>
<mydate:dateFormat date  ="<%=new Date()%>" type = "full">
<mydate:dateFormat date  ="<%=new Date()%>" type = "date">
<mydate:dateFormat date  ="<%=new Date()%>" type = "time">

第十章 Filter与Listener

过滤器(Filter):

也称之为拦截器,是Servlet2.3规范新增的功能,在Servlet2.4规范中的到增强。

过滤器运行原理:

当用户的请求到达所请求的资源之前。可以借助过滤器来改变这些请求的内容,此过程也称之为“预处理”,当执行结果要响应到用户之前,可以经过过滤器修改响应输出的内容,此过程称为"后处理",过滤器的运行步骤分如下几步:

  1. Web容器判断接受的请求资源是否有与之匹配的内容,有的话容器将请求交给相应过滤器进行处理。
  2. 在过滤器预处理过程中,可以改变请求的内容,或者重新设置请求报头,根据业务需求对请求进行拦截返回或者将请求转发给目标资源。
  3. 若请求被转发给目标资源,则由目标资源对请求进行处理后作出响应;
  4. 容器将响应转发给会过滤器,
  5. 在过滤器后处理过程中,可以根据需求对响应的内容 进行修改。
  6. Web容器将响应发送回过滤器。

在一个Web应用中,可以部署多个过滤器。组成一个过滤器链,客户端的请求可以在这些过滤器之间传递,直到到达目标资源。在客户端的请求响应过程中,并不需要经过所有的过滤器链,而是根据过滤器链中每个过滤器的过滤条件来匹配需要的过滤资源。

过滤器核心接口:
  • init(FilterConfig config):过滤器的初始化方法,容器在过滤器实例化后调用此方法对过滤器进行初始化,传递FilterConfig config 对象,用于获取Servlet相关的ServletContext对象。
  • doFilter(ServletRequest request,ServletResponse response,FilterChain chain):过滤器的功能实现,当用户请求经过时,容器调用此方法对请求和响应进行功能处理,参数对象并不依赖于具体的协议,
  • FilterChian对象的doFilter(request,response)方法负责将请求传递给下一个过滤器或目标资源。
  • destory():在过滤器生命周期结束前由Web容器调用,可用于使用资源的释放。

过滤器的生命周期分为四个阶段:

  1. 加载和实例化:Web容器启动时,会根据@WebFilter属性filterName所定义的类名的字符拼写顺序,或者web.xml中申明的Filter顺序依次实例化Filter。
  2. 初始化:Web容器调用init(FilterConfig config)方法来初始化过滤器。容器在调用该方法时,向过滤器传递FilterConfig对象,实例化和初始化的操作只会在容器启动时执行,并且只会执行一次。
  3. doFilter()方法的执行:当客户端请求目标资源的时候,容器会筛选出符合映射条件的Filter,并按照@WebFilter属性FilterName所定义的类名的字符顺序,或者web.xml中声明的filter-mapping的顺序依次调用这些过滤器的doFilter()方法,在这个链式调用过程中,可以调用FilterChain对象的doFilter(ServletRerquest,ServletResponse)(参数并不依赖于具体的协议)方法将请求传给下一个过滤器或目标资源,也可以直接给客户端返回响应信息,请求转发或者从定向等。以FilterChain对象的doFilter(ServletRerquest,ServletResponse)方法为界限,上面的为预处理,下面的为后处理。
  4. 销毁:Web容器调用destroy()方法指示过滤器的生命周期结束。释放过滤器资源。

FliterConfig接口:javax.servlter.FilterConfig接口由容器实现,容器将实例作为参数传入过滤器(Filter)对象的初始化方法init()中,来获取过滤器的初始化参数和Servlet的相关信息。

getFilterName() 获取配置信息中指定的过滤器的名字
getInitParameter(String name) 获取配置信息中指定的名为name的过滤器初始化参数值
getInitParameterNames() 获取过滤器的所有初始化参数的名字的枚举集合
getServletContext() 获取Servlet上下文对象

FilterChain接口
javax.servlet.FilterChain接口由容器实现,容器将其实例作为参数传入过滤器对象的doFilter()方法中,FilterChain对象用于调用过滤器链中的下一个过滤器。

doFilter(ServletRequest request,ServletResponse response) 使用下一个过滤器被调用

过滤器的开发

  1. 创建Filter接口实现类;
  2. 编写过滤器的功能代码; 对过滤器进行声明配置;
  3. 对过滤器的属性配置: Servlet 3.0 以上版本可以使用@WebFilter形式的Annotation对Filter进行声明配置,也可以在web.xml中配置。
属性名 类型 是否必须 说明
filterName String 用于指定Filter的名称,默认类名,默认按照@WebFilter的该属性类名的字符顺序作为多个过滤器的实例化和执行顺序
urlPatterns/value String[] 指定Filter所拦截的URL{}表示
servletNames String[] 指定该Filter对那种Servlet执行过滤,可指定多个Servlet的名称,值是@WebServlet中的name属性的取值或< servlet-name>的取值
dispatcherTypes DispatcherType 用于指定该Filter对那种模式的请求过滤,支持REQUEST,FORWARD,INCLUDE,ERROR和ASYNC这五个值得任意组合,默认值为REQUEST
initParam WebInitParam[] 指定该Filter的一组配置参数
asyncSupport boolean 指定该Filter是否支持异步操作模式
displayName String 指定该Filter的显示名称
description String 指定该Filter的描述信息

urlPatterns/value指定的URL匹配模式要求(不能混合使用):
路径匹配:/index.jsp或 / * (表示对所有请求拦截)
扩展名匹配:*.jsp
@WebFilter的属性dispatcherTypes的属性值:REQUEST(请求动作),FORWARD(请求转发),INCLUDE(合并资源),ERROR(异常跳转到异常界面),ASYNC(指异步处理的请求)。

    @WebServlet(description = "Filter描述信息" displayName = "Filter显示信息",filterName = "Filter名称",urlPatterns = {"映射地址"},ServletName = {"Servlet名称"},initParam = {WebinitParam(name = "参数名",value = "参数值")},dispatchertypes = { DispatcherTypes.REQUEST值},asyncSupported = 是否异步
)

除了在@WebFilter的Annotation方式进行配置,还可以在web.xml中配置

<filter><display-name>Filter信息描述</display-name><filter-name>Filter的名称</filter-name><filter-class>filter实现类的全限定名</filter-class><async-support>是否异步</async-support><init-param><description>请求字符编码方式</description><param-name>Encoding</param-name><param-value>UTF-8</param-value></init-param><init-param><description>响应字符编码方式</description><param-name>ContentType</param-name><param-value>text/html;charset=UTF-8</param-value></init-param></filter><filter-mapping><filter-name>ExampleFilter</filter-name><url-pattern>映射URL</url-pattern><servlet-name>过滤的Servlet(可以多个)</servlet-name><servlet-name>……</servlet-name><dispatcher>请求模式</dispatcher></filter-mapping>

< filter>元素的先后顺序决定Web容器对Filter过滤器的加载和实例化,
< filter-mapping>元素的先后顺序决定Web对具有相同映射条件的执行顺序。
完全基于Annotation的过滤器方式配置,由filterName的名称搜字符确定顺序。
完全基于web.xml的方式对过滤器链配置,相同映射条件下,< filter-mapping>元素的先后顺序决定。
使用Annotation和web.xml相结合的方式,web要早于Annotation声明的Filter。

package com.oracle.filter;import java.io.IOException;import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;public class FilterDemo1 implements Filter{/** @see javax.servlet.Filter#init(javax.servlet.FilterConfig)*/@Overridepublic void init(FilterConfig filterConfig) throws ServletException {// TODO Auto-generated method stub}@Overridepublic void doFilter(ServletRequest request, ServletResponse response,FilterChain chain) throws IOException, ServletException {// TODO Auto-generated method stubSystem.out.println("我是FilterDemo1,客户端向Servlet发送的请求被我拦截到了");//对请求放行,进入下一个过滤器FilterDemo2chain.doFilter(request, response);System.out.println("我是FilterDemo1,Servlet向客户端发送的响应被我拦截到了");}@Overridepublic void destroy() {// TODO Auto-generated method stub}}
package com.oracle.filter;import java.io.IOException;import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;public class FilterDemo2 implements Filter{@Overridepublic void init(FilterConfig filterConfig) throws ServletException {// TODO Auto-generated method stub}@Overridepublic void doFilter(ServletRequest request, ServletResponse response,FilterChain chain) throws IOException, ServletException {// TODO Auto-generated method stubSystem.out.println("我是FilterDemo2,客户端向Servlet发送的请求被我拦截到了");//对请求放行,进入Servletchain.doFilter(request, response);System.out.println("我是FilterDemo2,Servlet向客户端发送的响应被我拦截到了");}@Overridepublic void destroy() {// TODO Auto-generated method stub}}
<filter><filter-name>filterDemo1</filter-name><filter-class>com.oracle.filter.FilterDemo1</filter-class></filter><filter><filter-name>filterDemo2</filter-name><filter-class>com.oracle.filter.FilterDemo2</filter-class></filter><filter-mapping><filter-name>filterDemo1</filter-name><url-pattern>/*</url-pattern><!-- /*是对所有的文件进行拦截 --></filter-mapping><filter-mapping><filter-name>filterDemo2</filter-name><url-pattern>/*</url-pattern><!-- /*是对所有的文件进行拦截 --></filter-mapping>

分 析:当有多个过滤器对同一个请求进行拦截时,根据web.xml文件中的配置顺序,谁在前,先执行谁。当第 一过滤器拦截成功后,会执行doFilter方法,该方法中,调用chain.doFilter方法,会将该请求放行给下一个过滤器,依次执行,直到执行 到最后一个过滤器,当最后一个过滤器调用chain.doFilter方法时,请求会被放行给Servlet,当Servlet处理返回响应信息时,先返 回到最后执行的过滤器,继续执行该过滤器剩下的代码。依次返回,直到返回到第一个过滤器,最后返回给客户端。

过滤器的应用:

  • 做统一的认证处理。
  • 对用户的请求进行检查和更精确的记录,
  • 监视或对用户所传传递的参数做前置处理(防止数据注入攻击);
  • 改变图像文字的格式
  • 对响应做压缩处理
  • 对XML的输出使用XSLT来转换。
    控制用户的访问权限:在Web应用中,有很多操作是需要用户具有相关的操作权限才可以进行访问的,设置 较为全面的请求拦截映射地址,对于用户登录页面及处理登录操作页面的Servlet不能进行 访问限制,可以使用初始化参数灵活指定相关地址,通过判断会话对象中是否存在用户登录时的标识域属性,来决定用户是否具有访问的权限。
    压缩响应的结果:
    Filter结合GZIP压缩技术是解决Web应用中网络传输大数据量问题的常用方法,GZIP是HTTP协议中使用的一种压缩算法,压缩响应内容,减少网络传输数据量,提高响应速度,与过滤器结合,可以在现有代码的基础上引入功能。技术点:
  • 需要设置请求报头Accept-Encoding:gzip,deflated。
  • Filter通过Accept-Encoding请求头。来判断浏览器是否支持数据格式压缩,和支持那种格式的数据,如果支持GZIP压缩格式,创建一个包含压缩功能的自定义响应对象传递给目标资源,以便截获目标资源,压缩处理。
  • 要保证与HttpServletresponse接口的规范一致,Servlet API 提供了一个HttpServletResponseWrapper 来包装原始的response对象,自定义的响应对象可以继承此类,对输出响应消息的getOutputStream(),getWriter()和flushBuffer()方法进行重写。
  • Web服务器程序使用JDK提供的java.util.zip.GZIPOutputStream类将数据压缩为GZIP格式,GZIPOutputStream类通过其构造方法包装一个底层输出流对象,调用Writer()方法向底层输出流对象中写入压缩成GZIP格式的数据,最后关闭对象。
  • 在响应报文中添加报文头:Content-Encoding:gizp;//告诉实体主体适用的编码方式。

GZIP压缩一般只处理文本内容。

监听器:

Servlet API 提供了大量监听器接口实现对Web应用内特定的事件进行监听,当Web应用中特定事件发生时,回调监听器内的事件监听方法。

监听器实现通过两个步骤完成:

  • 1,定义监听器实现类,实现监听器的所有方法,
  • 2,通过Annotation或在web.xml文件中声明Listener。
在web.xml中申明配置< listener>< description>描述信息< /description>< listener-calss>指定Listener的全限定名< /listener-calss>在Annotation中声明配置@WebListener("描述信息");

常用的Web事件监听器接口可分为三类:

与Servlet上下文相关的监听器接口。

  • ServletContextListener接口:用于监听ServletContext对象的创建和销毁,触发会产生一个ServletContextEvent事件对象,然后执行事件处理方法:

    • contextInitialized(ServletContextEvent sce):创建ServletContext对象时触发,接受ServletContextEvent对象。
    • contextDestroyed(ServletContextEvent sce):销毁ServletContext对象时触发,接受ServletContextEvent对象。
    • ServletContextEvent为一个事件类,用于通过getServletContext()获取ServletContext对象。
  • ServletContextAttributeListener接口,用于监听范围内属性的创建,删除和修改,触发产生一个ServletContextAttributeEvent对象。然后调用相应的事件处理方法。
    • attributeAdded(ServletContextAttributeEvent event):存入application范围的属性时触发。传递ServletContextAttributeEvent对象。
    • attributeRemoved(ServletContextAttributeEvent event):删除时触发。
    • attributerReplaced(ServletContextAttributeEvent event):替换时触发。
    • ServletContextAttributeEvent 用于通知Web应用程序Servlet上下文属性改变。getName()和getValue()分别获取属性名的属性值。

与会话相关的监听器接口。

  • HttpSessionListener接口用于监听用户会话对象的HttpSession的创建和销毁事件。触发产生一个HttpSessionEvent对象,调用监器的处理方法。

    • sessionCreated(HttpSessionEvent se):创建HttpSession对象触发。传递事件对象。
    • sessionDestroyed(HttpSessionEvent se):销毁时触发,
    • HttpSessionEvent 事件对象getSession()用于获取改变前的HttpSession对象。
  • HttpSessionAttributeListener接口用于监听会话域属性的创建,删除和修改,触发产生一个HttpSessionAttributeEvent事件对象。
    • attributeAdded(HttpSessionAttributeEvent event):属性存入时触发,传递事件对象。
    • attributeRemoved(HttpSessionAttributeEvent event):属性删除时触发,传递事件对象。
    • attributeReplaced(HttpSessionAttributeEvent event):替换属性时触发,传递事件对象。
    • HttpSessionAttributeEvent 事件对象getName()/getValue()用于获取属性名/值。
与请求相关的监听器接口。
  • ServletRequestListener接口用于监听用户请求的产生和结束。触发产生ServletRequestEvent事件对象。即相应事件处理方法。

    • requestInitialized(ServletRequestEvent sre):创建时触发,接收对象。
    • requestDestroyed(ServletrequestEvent sre ):销毁时触发,接收对象。
  • ServletRequestAttributeListener接口用于监听ServletRequest(request)范围内的属性单独创建,删除和修改。触发产生一个ServletRequestAttributeEvent对象。调用事件处理方法。

    • attributeAdded(ServletRequestAttributeEvent event):存入request范围属性时触发,传递对象。
    • attributeRemoved(ServletRequestAttributeEvent event):删除属性时触发,传递对象。
    • attributeReplaced(ServletRequestAttributeEvent event):替换属性时触发,传递对象。
    • ServletRequestAttributeEvent 事件类对象getName()/getValue()用于获取属性名/值。

MVC模式

MVC(Model-View-Controller):模式是一种体系结构,有三个组成部分,Model(模型),View(视图)和Controller(控制器)。MVC结构的每个部分具有各自的功能,作用,并以最少的耦合协同工作,提高可扩展性和可维护性。
MVC模式是交互式应用程序最广泛使用的一种体积结构,能够有效的将界面显示,流程控制,和业务处理相分离,
MVC模式结构代表了软件结构的3个层次,模型层,视图层,控制层。
模型层(Model):是应用系统的核心层,负责封装数据和业务操作。模型层可以分为数据模型和业务模型。数据模型用来对用户请求的数据和数据库查询的数据进行封装,业务模型用来对业务处理逻辑进行封装,控制器(Controller)将用户请求数据和业务处理逻辑交给相应的模型,视图(View)从模型中获取数据,模型改变时通知视图数据更新,维护具有弹性。
视图层(View):视图层主要是指与用户交互的界面,即应用程序的外观。当做用户的操作接口,输入数据和显示数据处理后的结果,用户通过视图输入数据,转交给控制器,控制器根据用户的请求调用相应的数据模型和业务模型进行处理,选择合适的视图,视图调用模型对结果数据进行显示,同时当模型更新数据时,视图也随之更新。
控制层(Controller):控制整个系统的处理流程,介于视图层和模型层之间。进行数据传递和流程转向,控制层接受用户的请求和数据,做出判断将请求和数据交由那个模型来处理,最后将结果交由视图来显示模型返回的数据。
MVC最主要的精神就是Model和View的分离,这两者之间的分离可使网页设计和程序设计人员相互独立。提高开发效率和维护效率。
Java Web 开发模式:先后经历Model1和Model2两种应用结构模式。model1是以JSP为主的开发模式,Model2模式即Web应用的MVC模式,
Model1模式:即完全的JSP开发和JSP+JavaBean开发
JSP:优点:开发时间短,小幅度修改容易,缺点:可读性低,程序重复利用性低。
JSP+JavaBean:优点:可读性高,重复利用率高,缺点:缺乏流程控制。
Model2模式:基于MVC结构的设计模式,通过javaBean,EJB等组件实现MVC模型层,通过JSP实现MVC的视图层,通过Servlet实现控制层。通过这种设计模式把业务处理,流程控制,和界面显示分层不同的组件实现。
Model2:流程:

  1. 用户通过浏览器向Servlet发送请求。
  2. Servlet根据用户请求调用相应的JavaBean完成对请求数据,业务操作,结果数据的处理和封装.
  3. Servlet根据处理的结果选择相应的JSP页面。
  4. JSP页面调用JavaBean 获取页面所需要的数据结果,
  5. 包含数据结果的的JSP页面被响应返回客户端浏览器.
    优点:开发流程明确,使用model2设计模式可以完全切开显示端与商业逻辑端的开发,核心的程序控制,维护容易。
    缺点:学习时间长,开发时间较长。

嗯,这本书的笔记做完啦,但是掌握的不好,尤其最后部分,都没有实际的敲代码,哎,破事一大堆,没有一件如意的。依旧,摘一《瓦尔登湖》的句子,18.12.1大学教室

整理的面试题笔记:

1,动态网站技术有哪些?

2,一般的Web架构是指BS 还是CS,BS架构是什么咚咚?
3,Web应用程序的流程,即把一个URL串输入地址栏后发生写什么?
4,说一说Servlet生命周期?
5,在Web应用中,客户端向服务器请求数据的方式通常有啥?
6,讲一讲你对重定向与请求转发的认识?
7,ServletConfig对象有何作用,在Servlet中如何使用?
8,关于ServletContext对象你了解多少?
9,你知道HttpServletRequest,HTTPServletResponse对象吗?
10,ServletContext对象和ServletConfig对象的getInitParameter()方法有何区别?
11,ServletContext对象如何存取自定义属性,属性的访问范围是什么?
12,HttpServletRequest对象如何自定义属性,属性的访问范围是什么?
13,Servlet如何向页面输出数据?

  • 1,CGA,ASP,ASP.NET,PHP,servlet,JSP等
  • 2,是BS,即浏览器服务器的形式,是基于特定HTTP通信协议的CS架构,对CS的一种变化或者改进,
  • 3,浏览器请求-服务器处理请求-响应结果返回浏览器
    客户通过URL地址发送的请求转换为标准的HTTP请求,Web服务器首先需要检查请求的文件地址是否正确,若错误,返回错误信息,若正确,服务器将根据请求的GET或POST方法及文件的类型进行相应的处理,将结果以HTML或XML或着二进制文件等数据形式表示。并按照HTTP协议的响应消息格式反馈给浏览器,浏览器会根据消息附带的信息查看并显示该信息。
  • 4,Servlet生命周期是由Servlet容器负责管理的,Servlet 本身并不是直接运行的虚拟机上,Servlet生命周期是指Servlet实例从创建到响应客户端请求,直至销毁的过程,会经过创建,初始化,服务可用,服务不可用,处理请求,终止服务和销毁服务7种状态。
    涉及到三个方法:init(),Service(),destory()。

    • 加载和实例化:Servlet创建,在服务器运行中,客户机首次向Servlet发送请求,重新装入Servlet时,在为Servlet配置了自动装入选项(load-on-startup)时。
    • 初始化:Servlet容器调用Servlet的init(ServletConfig config)方法来对Servlet实例进行初始化。读取固定数据,初始化JDBC连接等资源连接,init()方法的参数ServletConfig对象由Servlet容器创建并传递给Servlet,一直存在,直到销毁。
    • 处理请求:服务器接受到客户端请求后,会为该请求创建一个请求对象和响应对象,并调用service()方法,service()方法在调用其他方法。
    • 销毁:当Servlet容器需要终止Servlet,它会先调用Servlet的destroy()方法.
  • 5,四种,
    *其一,通过超链接形式查询数据
    语法链接文本
    //即Web中以GET方式提交数据。数据部分和地址部分由?隔开,参数之间由&隔开,但安全性差,以明文方式显示。在发送的请求的URI地址可以是绝对地址,也可以是相对地址,开发中一般使用相对地址,便于开发移植。
    *其二,通过Form表单形式更新数据
    语法:
    其三,通过Ajax实现异步访问
$.ajax({url:'/ExampleServlet',type:'post',dataType:'json',success:function(data){alert('成功!');alert(data);},error:function(){alert('内部错误');}});
  • 其四,通过JS语句实现
<script type="text/javascript">location.assign("/ExampleServlet");       </script>
  • 6,重定性和请求转发是Servlet中对新的URL地址的转向的两种主要方式:

    • 1,重定向:指由原请求地址重新定位到某个新地址,原有的请求失效,客户端看到的是新的请求返回的响应结果,客户端浏览器地址栏变成了新的请求地址,在重定性过程中客户端和服务器会经过两次请求和两次响应,其中第二次请求由客户端发起。第一次请求到服务器后,由服务器响应指定重定向的第二请求(返回3开头的状态码),客户端第二请求发出,最后经过服务器发返回响应。
      重定向通过HttpServletResponse对象的sendRedirect()方法实现的,该方法会通知客户端去重新访问新指定的URL地址,
      public void sendRedirect(string location)throws java.io.IOExcetion
      //location为重定向的URL地址,可以是相对路劲或绝对路径,可以重定向到当前应用程序中的资源,还可以重定向到同一站点的其他资源,使用绝对URL可以定位到其他站点的资源。
    • 2,请求转发:指将请求转发到其他地址,使用同一个请求,转发后的浏览器地址内容不变,即经过一次请求响应,转发过程发生在服务器内部,服务器只能从当前应用内部查找相应的转发资源,而不能转发其他资源,
      使用RequesDispatcher接口中的forward()方法来实现,该方法可以把请求转发给另外一个资源,并让该资源对此请求进行响应RequestDispatcher接口还有一个include()//将其他资源并入到当前请求中。RequestDispatcher是一个接口,需要通过使用HttpResquest对象的getrequesDispatcher()方法获得该接口的实例对象。
     RequestDispatcher dispatcher =request.getrequestDispatcher(String path).forward(ServletRequeste request,Servletresponse response);
    

    请求转发与重定向的区别

转发只能将请求转发给同一个Web应用中的组件,重定向可以重定向到当前资源,同一个站点的其他资源,以及其他站点资源。
重定向访问后的URL会发生改变,请求转发URL地址保持不变。
重定向是由服务器告诉浏览器去重新请求一个URL,是客户端行为,请求转发是服务器程序内部发生转发行为,
请求转发服务器之间共享请求对象和响应对象,属于同一个访问请求过程,重定向调用者与被调用者使用各自的请求和转发对象。属于两个独立的访问请求和响应过程。

  • 7,
    容器在初始化一个Servlet时,会为这个Servlet创建一个ServletConfig对象,并将这个对象通过init(ServletConfig config)方法传递并保存在此Servlet对象中,使用ServletConfig接口中的方法主要可以访问两项内容:
    Servlet初始化参数和ServletContext对象,

    • 前者通过由容器从Servlet的配置属性中读取(在Servlet的init()方法中调用ServletConfig参数getInitParameter()方法来获取初始化参数的值,)
    • 后者为Servlet提供有关的容器信息(调用ServletConfig对象的getServletContext()方法来获取ServletContext对象。)
  • 8,
    ServletContext对象代表当前Servlet运行环境,Servlet容器在启动一个Web应用时,会为该应用创建一个唯一 的ServletContext对象供该应用中的所有Servlet对象共享,Servlet对象可以通过ServletContext来访问容器中的各种资源。
    ServletContext对象可以获得应用范围的初始化参数,在应用范围内存取共享数据,访问当前Web应用的信息,访问当前容器的信息和输出日志和访问服务器端的文件系统资源。
  • 9,
    HttpServletRequest接口用于封装HTTP请求信息,对象用于获取请求报文信息,获取网络连接信息和存取请求域属性。ServletContext对象,HttpServletRequest对象具有相同的存取域的方法。
    HttpServletResponse接口用于封装HTTP响应信息,创建响应报文。
  • 10,
    ServletContext对象的getInitParameter()方法用来访问整个应用范围内的初始化参数,参数通过web.xml的元素来指定,所有的servlet都可访问,
    ServletConfig对象对象的getInitParameter()方法用来访问当前Servlet的初始化参数,参数通过web.xml的来指定。仅当前配置的Servlet可访问。
  • 11,
    ServletContext对象通过setAttribute(name,value)方法来存取自定义属性,通过getAttribute(name)来取自定义属性值。
    ServletContext对象的自定义属性也被称为应用域属性,表示在web应用的整个生命周期内,可以被web应用范围内的所有组件所共享
  • 12,
    HttpServletrequest对象通过setAttribute(name,value)方法来自定义一个域属性,
    HttpServletRequest对象自定义属性也被称为请求域属性,表示在本次请求和响应的生命周期内供本次请求对象所访问,
    13,
    通过HttpServletResponse对象调用getOutputStream()方法获取字节输出流对象ServletOutputStream,用于创建包含二进制数据的响应正文,
    通过调用getWriter()方法获取字符输出流对象PrintWriter,用于创建包含字符数据的响应正文。
14,你知道Session和Cookie吗?说说它们的区别和联系?
15,你还知道哪些会话跟踪技术?
16,session的生命周期?
17,简述一下JSP执行原理:
18,JSP元素有哪些?
19,include指令元素与动作元素有啥区别?
20,JSP内置对象有哪些?
  • 14,
    Session和Cookie是两种会话跟踪技术,HTTP是一种无状态协议,利用Session和Cookie可以实现多次请求之间的数据共享。

    • Cookie 是由 Web 服务器保存在用户浏览器(客户端)上的小文本文件,cookie本身有一定的大小限制,,每个cookie所存放的数据不能超过4KB。cookie由一些键值对(cookieName–value)构成,根据cookieName来检索的cookie中的信息,它可以包含有关用户的信息。当cookie到达过期时间时,cookie就会被删除,默认情况下,当浏览器关闭时cookie立即失效,对于长期的Cookie,会保存在磁盘中,无论何时用户链接到服务器,Web 站点都可以访问 Cookie 信息。
    • Session技术是指使用HttpSession会话实现会话跟踪技术,HttpSession对象是Javax.servlet.http.HttpSession接口的实例,也称会话对象,该对象用来保存单个用户访问时的 一些信息,是服务器在无状态的Http协议下用来识别和维护具体某个用户的重要方式。
    • HttpSession对象会在用户第一次访问服务器时由容器创建(在访问JSP,Servlet,等程序才会创建,只访问HTML,IMAGE等静态资源并不会创建),当用户调用其失效方法(invalidate())或超过其最大不活动时间时会失效,在此期间,用户与服务器之间的多次请求都属于同一个会话。服务器在创建会话时,会分配一个唯一的会话标识:SessionId,以“JSESSIONID”的属性名保存在客户端Cookie中,在用户随后的请求的中,通过JSESSIONID属性来识别不同的用户。实现每个用户的会话跟踪。

联系:

session是通过cookie来工作的,session依赖于Cookie,服务器在创建会话时,会分配一个唯一的会话标识:SessionId,以“JSESSIONID”的属性名保存在客户端Cookie中,在用户随后的请求的中,通过Cookie中的JSESSIONID属性来识别不同的用户。实现每个用户的会话跟踪。

区别:
+ 1、cookie数据存放在客户的浏览器上,session数据放在服务器上。
+ 2、cookie不是很安全,别人可以分析存放在本地的COOKIE并进行COOKIE欺骗
考虑到安全应当使用session。
+ 3、session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能
考虑到减轻服务器性能方面,应当使用COOKIE。
+ 4、单个cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个cookie。
+ 5,对于Java Web来说,Cookie只能保存Sting类型的KV对,Session可以存放Object类型的KV。
+ 6,Session不区分访问路径,同一个用户在访问一个网站期间,所有的请求地址都可以访问到Session,而Cookie如果设置参数路径,那么同一网站中不同路径下的Cookie是相互访问不到的。

  • 15,

    • URL重写技术:在客户端浏览起完全禁用了Cookie后,通过在请求地址后附加会话标识的URL重写技术任可实现会话的跟踪技术。
    • 隐藏表单域:利用Form表单的隐藏表单域,可以在完全脱离浏览器对Cookie的使用权限以及在用户无法显示页面看到的隐藏标识的情况下,将标识随请求一起穿送给服务器处理。实现会话跟踪。
  • 16,
    HttpSession对象会在用户第一次访问服务器有容器创建,在用户调用其失效方法或超过最大不活动时间时失效。

  • 17,

    • 1,客户端向服务器发送JSP页面请求。
    • 2,容器检索请求的JSP页面,第一次请求,则将静态数据和动态数据转换为Java代码,将JSP文件翻译为一个Java文件。
    • 3,容器将翻译后的Servlet源代码编译为字节码文件,对于Tomcat而言,生成的字节码文件默认存放在<Tomcat安装目录>work目录下。
    • 4,编译后的字节码文件被加载到容器内存中执行,并根据用户的请求生成HTML格式的响应内容
    • 5,容器将响应内容返回客户端
      当同一个JSP页面再次被请求时,只要该JSP文件没有发生过改变,容器将直接调用已加载的字节码文件,而不会再执行翻译和编译的过程
  • 18,

    • 脚本元素:脚本<%%>,表达式<%=%>,声明<%!%>注释<%-- --%>
    • 指令元素:<%@page%>,<%@include%>,<%@taglib%>
    • 动作元素:< jsp:include>,< jsp:forward>,< jsp:param>,< jsp:userBean>’
  • 19,
    include指令元素和动作元素都是实现包含文件代码复用。
    对于包含文件的处理指令和方式不同,include指令元素在翻译阶段就引入所包含的文件,被处理的文件在逻辑上和语法上依赖于当前的JSP页面,优点是执行速度快。include动作元素是JSP页面在运行时才引入包含的文件所产生的应答文本,被包含的文件在逻辑和语法上独立于当前JSP页面,其优点是可以使用param子元素更加灵活的处理所需要的文件,缺点是执行速度慢一些。

  • 20,

对象 描述
request 请求对象,提供客户端HTTP请求数据的访问
response 响应对象,用来向客户端输出响应
out 输出对象,提供对输出流的访问,由java.io.Writer类继承得
session 会话对象,用来保存服务器与每个客户端会话过程中的信息
application 应用程序对象,保存整个应用环境信息
pageContext 页面上下文对象,用于存储当前JSP页面的相关信息
config 页面配置对象,JSP页面的配置信息对象
page 当前JSP页面对象,即this
exception 异常对象,用于处理JSP页面中的错误
21,你知道EL吗?EI的隐含对象有哪些?
22,你知道JSTL,日常开发哪里会用到呢?
23,你对Filter与Listener了解多少?
24,谈谈你对MVC模式的理解?
  • 21,
    EL即表达式语言,最大的优势是可以方便的访问JSP的隐含对象的JavaBean组件,
    EL隐含对象

    • 与范围有关的隐含对象:pageScope,requestScope,sessionScope,applicationScope.
    • 与请求参数有关的对象:param,paramValues。对post与Get请求都适用
    • 其它的隐含对象:pageConrext,header,headerValues,cookie,initParam。
  • 22,
    JSTL主要提供给Java Web开发人员一个标准通用的标签函数库,标签库同时支持EL获取数据,Web开发人员能够利用此标签函数库取代直接在页面中嵌入Java程序的做法。
    核心标签库:

    • 通用标签,用于操作变量:<c:out/>,<c:set/>,<c:remove/>,<c:catch/>标签
    • 条件标签,用于流程控制<c:if>,<c:choose>,<c:when>,<c:otherwise>;
    • 迭代标签,用于循环遍历集合<c:forEach>,<c:forTokens>
    • 函数标签库:是一些对String对象的操作。
  • 23,

    • 过滤器(Filter):也称之为拦截器,当用户的请求到达所请求的资源之前。可以借助过滤器来改变这些请求的内容,此过程也称之为“预处理”,当执行结果要响应到用户之前,可以经过过滤器修改响应输出的内容,此过程称为"后处理"
      +监听器(Listener):Servlet API 提供了大量监听器接口实现对Web应用内特定的事件进行监听,当Web应用中特定事件发生时,回调监听器内的事件监听方法。
  • 24,MVC(Model-View-Controller):模式是一种体系结构,
    有三个组成部分,Model(模型),View(视图)和Controller(控制器)。
    MVC结构的每个部分具有各自的功能,作用,并以最少的耦合协同工作,提高可扩展性和可维护性。
    MVC模式是交互式应用程序最广泛使用的一种体积结构,能够有效的将界面显示,流程控制,和业务处理相分离,

    • **模型层(Model)**
      是应用系统的核心层,负责封装数据和业务操作。模型层可以分为数据模型和业务模型。数据模型用来对用户请求的数据和数据库查询的数据进行封装,业务模型用来对业务处理逻辑进行封装,控制器(Controller)将用户请求数据和业务处理逻辑交给相应的模型,视图(View)从模型中获取数据,模型改变时通知视图数据更新,维护具有弹性。
      +**视图层(View)**
      视图层主要是指与用户交互的界面,即应用程序的外观。当做用户的操作接口,输入数据和显示数据处理后的结果,用户通过视图输入数据,转交给控制器,控制器根据用户的请求调用相应的数据模型和业务模型进行处理,选择合适的视图,视图调用模型对结果数据进行显示,同时当模型更新数据时,视图也随之更新。
    • **控制层(Controller)**
      控制整个系统的处理流程,介于视图层和模型层之间。进行数据传递和流程转向,控制层接受用户的请求和数据,做出判断将请求和数据交由那个模型来处理,最后将结果交由视图来显示模型返回的数据。

    嗯,某些原因,整理了这份Java Web的面试知识点。感觉这些技术有些旧了,不太会考太多。加油生活!^_^.
    2019.7.19

人的价值并不在于他外在的皮肤上,所以我们没必要去触碰彼此。

《JAVA Web技术及应用》读书笔记相关推荐

  1. 读书笔记 | 墨菲定律

    1. 有些事,你现在不做,永远也不会去做. 2. 能轻易实现的梦想都不叫梦想. 3.所有的事都会比你预计的时间长.(做事要有耐心,要经得起前期的枯燥.) 4. 当我们的才华还撑不起梦想时,更要耐下心来 ...

  2. 读书笔记 | 墨菲定律(一)

    1. 有些事,你现在不做,永远也不会去做. 2. 能轻易实现的梦想都不叫梦想. 3.所有的事都会比你预计的时间长.(做事要有耐心,要经得起前期的枯燥.) 4. 当我们的才华还撑不起梦想时,更要耐下心来 ...

  3. 洛克菲勒的38封信pdf下载_《洛克菲勒写给孩子的38封信》读书笔记

    <洛克菲勒写给孩子的38封信>读书笔记 洛克菲勒写给孩子的38封信 第1封信:起点不决定终点 人人生而平等,但这种平等是权利与法律意义上的平等,与经济和文化优势无关 第2封信:运气靠策划 ...

  4. 股神大家了解多少?深度剖析股神巴菲特

    股神巴菲特是金融界里的传奇,大家是否都对股神巴菲特感兴趣呢?大家对股神了解多少?小编最近在QR社区发现了<阿尔法狗与巴菲特>,里面记载了许多股神巴菲特的人生经历,今天小编简单说一说关于股神 ...

  5. 2014巴菲特股东大会及巴菲特创业分享

     沃伦·巴菲特,这位传奇人物.在美国,巴菲特被称为"先知".在中国,他更多的被喻为"股神",巴菲特在11岁时第一次购买股票以来,白手起家缔造了一个千亿规模的 ...

  6. 《成为沃伦·巴菲特》笔记与感想

    本文首发于微信公众帐号: 一界码农(The_hard_the_luckier) 无需授权即可转载: 甚至无需保留以上版权声明-- 沃伦·巴菲特传记的纪录片 http://www.bilibili.co ...

  7. 读书笔记002:托尼.巴赞之快速阅读

    读书笔记002:托尼.巴赞之快速阅读 托尼.巴赞是放射性思维与思维导图的提倡者.读完他的<快速阅读>之后,我们就可以可以快速提高阅读速度,保持并改善理解嗯嗯管理,通过增进了解眼睛和大脑功能 ...

  8. 读书笔记001:托尼.巴赞之开动大脑

    读书笔记001:托尼.巴赞之开动大脑 托尼.巴赞是放射性思维与思维导图的提倡者.读完他的<开动大脑>之后,我们就可以对我们的大脑有更多的了解:大脑可以进行比我们预期多得多的工作:我们可以最 ...

  9. 读书笔记003:托尼.巴赞之思维导图

    读书笔记003:托尼.巴赞之思维导图 托尼.巴赞的<思维导图>一书,详细的介绍了思维发展的新概念--放射性思维:如何利用思维导图实施你的放射性思维,实现你的创造性思维,从而给出一种深刻的智 ...

  10. 产品读书《滚雪球:巴菲特和他的财富人生》

    作者简介 艾丽斯.施罗德,曾经担任世界知名投行摩根士丹利的董事总经理,因为撰写研究报告与巴菲特相识.业务上的往来使得施罗德有更多的机会与巴菲特亲密接触,她不仅是巴菲特别的忘年交,她也是第一个向巴菲特建 ...

最新文章

  1. Nginx 502 bad gateway的解决方案
  2. [Struts]Token 使用及原理
  3. win32窗口机制之CreateWindow
  4. 六、jQuery 中的 AJAX 跨域问题
  5. bzoj4419 [Shoi2013]发微博 差分
  6. 微信小程序开发学习笔记001--认识微信小程序,第一个微信小程序
  7. python编写一个程序、计算字符串中子串出现的次数_急求。。。C语言实现,计算字符串中子串出现的次数,就是先输入一个字符串,再输入一个上面字符串中存在...
  8. sCMOS相机的读出噪声
  9. OpenStack手动制作CentOS 7 KVM镜像
  10. ArcGIS Server学习资料
  11. 802.11n 重新扬帆
  12. 一款强大的反编译工具luyten
  13. NES专题——一块带给无数人年少欢乐的CPU(6502)
  14. 天正电气图例_天正电气设计施工图中常用线路敷设方式
  15. web工程引用其他java工程_并读取spring配置文件_SpringBoot项目实战(8):四种读取properties文件的方式...
  16. 全基因组重测序数据分析
  17. 使用pip出现报错:Could not find a version that satisfies the...No matching distribution distributio...
  18. 18年美亚杯团体赛内存部分
  19. 一秒钟实现Andriod系统文件访问
  20. 2.前端性能优化-web性能指标

热门文章

  1. SQL Server 2005的身份验证模式修改步骤
  2. 用c语言完成流水灯控制的程序设计,单片机C语言程序设计之TIMER0控制流水灯
  3. 更改IP电话的IP地址
  4. 什么叫列满秩矩阵,为什么A是列满秩矩阵
  5. 8位阿里P8合著“Dubbo微服务进阶笔记”一经面世,Github上标星93K+
  6. c# printdialog 打印html,c# – ReportViewer.PrintDialog()在打印到Adobe PDF时抛出异常
  7. 图片资源检索,图片文件压缩、裁剪、存储、收藏网站汇总,宝藏呀
  8. 集训队每周一赛 2020-04-02(思维/模拟+贪心+二分)
  9. HTML期末大作业~基于HTML+CSS+JavaScript旅游网站设计与实现(6个页面)
  10. Origin 批量处理文件和数据