ServletJSP:上

#Servlet是什么?

sun公司制订的一种用来扩展web服务器功能的组件规范。

(1)扩展web服务器功能

早期的web服务器只能处理静态资源的请求,即需要事先将html文件准备好,并存放到web服务器上面。不能够处理动态资源的请求(需要计算,动态生成html)。早期使用CGI(CommonGatewayInterface)应用程序来扩展。CGI程序使用perl,c/c++等语言来编写,编写繁琐,不方便移值,性能也不是很好,现在用得很少了。浏览器将请求发送给webserver,如果是动态资源的请求,web server会将请求转交给servlet容器来处理,由容器来处理。

这里写图片描述

(2)组件规范

  1. 什么是组件?
    符合规范,实现部分功能,并且需要部署到相应的容器里面才能运行的软件模块。
    servlet就是一个组件,需要部署到servlet容器里面才能运行。
  2. 什么是容器?
    符合规范,提供组件运行环境的程序。
    servlet容器为servlet提供运行环境。

#手动部署Servlet

  • step1. 写一个java类,实现Servlet接口或者继承HttpServlet抽象类。
    注:建议继承HttpServlet抽象类。

  • step2.编译。

  • step3.打包。
    创建一个具有如下结构的文件夹:

          appname  (应用名)
              WEB-INF
                  classes   (.class文件) 
                  lib      (可选  .jar文件)
                  web.xml   (部署描述文件)  
    
  • step4.部署。
    将step3创建的文件夹拷贝到容器里面。
    可以使用jar命令将step3创建的文件夹压缩成 ".war"结尾的文件,然后再拷贝。

  • step5.启动容器,访问Servlet
    http://ip:port/appname/servlet-pattern
    注: servlet-pattern在web.xml当中定义。
    这里写图片描述
    #Servlet运行过程

比如,在浏览器地址栏输入 http://ip:port/servlet-day01/hello

  • step1.浏览器依据ip,port建立连接(即与web服务器之间建立网络连接)。

  • step2.浏览器需要将相关数据打包(即按照http协议要求,制作一个请求数据包,包含了一些数据,比如请求资源路径),并且将请求
    数据包发送出去。

  • step3.web服务器会将请求数据包中数据解析出来,并且将这些数据添加到request对象,同时,还会创建一个response对象。

  • step4.web服务器创建Servlet对象,然后调用该对象的service方法(会将request和response作为参数)。
    注:在service方法里面,通过使用request获得请求相关的数据,
    比如请求参数值,然后将处理结果写到response。

  • step5.web服务器将response中的数据取出来,制作响应数据包,然后发送给浏览器。

  • step6. 浏览器解析响应数据包,然后展现。

这里写图片描述

#常见的错误
##500
500是状态码,表示系统错误。
产生的原因:

  • web.xml文件配置错误。比如将类名写错。

  • 源代码写错。比如,没有继承HttpServlet。
    ##404
    404是状态码,表示依据请求路径找不到对应的资源。
    产生的原因

  • 没有部署应用

  • 访问地址写错

  • web.xml配置文件写错
    ##405
    405是状态码,表示找不到处理方法。
    产生的原因:service方法签名错误(方法名,参数类型,异常类型,返回类型写错)
    #HTTP协议
    ##什么是HTTP协议?

是一种网络应用层协议,规定了浏览器与web服务器之间如何通信以及数据包的结构。

##如何通信?
step1. 先建立连接。
step2. 发送请求数据包。
step3. 发送响应数据包。
step4. 关闭连接。
即 一次请求,一次连接。

这里写图片描述
##优点

web服务器可以利用有限的连接为尽可能多的客户请求服务。

##两种数据包的结构
###请求数据包

  • 请求行 (请求类型 请求资源路径 协议和版本)
GET      /hotelmanager/home     HTTP/1.1
  • 若干消息头:消息头是一些键值对(键和值之间使用": "分隔)
    浏览器和服务器之间可以利用消息头传递一些特殊的信息。
    比如,浏览器可以发送"user-agent"告诉服务器,浏览器的类型和版本。
  • 实体内容:如果请求类型是get,实体内容为空。

###响应数据包

  • 状态行 (协议和版本 状态码 状态描述):状态码是一个三位数字,表示服务器处理请求的状态。
      HTTP/1.1     200    OK
  • 消息头
    服务器同样也可以将一些消息头发送给浏览器。
    如可以通过设置content-type消息头,告诉浏览器,服务器返回的数据类型。
  • 实体内容
    程序处理的结果。浏览器会解析实体内容中的数据,然后展现。

#两种请求类型
##get请求

  • 哪一些情况下,浏览器会发送get请求?
    • 直接输入某个地址
    • 点击链接,例如:pricemodify.jsp?roomtype="单人间"&price=199
    • 表单默认提交方式
  • 特点
    • 会将请求参数放到请求行里面,只能提交少量的数据。
    • 因为请求行大约只能存放2k左右的数据。
    • 会将请求参数显示在浏览器地址栏,不安全。
    • 如有些网络设备(路由器)会记录这些地址。
      ##post请求
  • 哪一些情况下,浏览器会发送post请求,设置表单的method=“post”
  • 特点
    • 不会将请求参数显示在浏览器地址栏,相对安全,但并不会对请求参数加密
    • 会将请求参数添加到实体内容里面,所以,可以提交大量数据给服务器
      #Servlet输出乱码问题
  1. 为什么会乱码?
    out在输出时,默认使用iso-8859-1来编码。
  2. 如何解决?
    response.setContentType(“text/html;charset=utf-8”);
    这行代码的作用:
  • 作用1.返回content-type消息头,告诉浏览器,服务器返回的数据类型。
  • 作用2:另外,out在输出时,会使用指定的字符集来编码。
    #表单中文参数乱码问题
  1. 为什么会有乱码?
    表单提交时,浏览器会对中文参数值进行编码。服务器端默认会使用iso-8859-1来解码。
    会使用表单所在的页面打开时使用的字符集来编码。
  2. 如何解决?
  1. 情形1 表单提交方式为post
    request.setCharacterEncoding(“utf-8”);
    注:要加到所有的request.getParameter方法前面。
  2. 情形2 表单提交方式为get
    设置 <Connector URIEncoding="utf-8"/>此参数在tomcat- service.xml文件中
    只针对get请求有效。
    #读取请求参数值

form表单post提交,表单控件中都有name值

(1) request提供的getParameter方法。

String getParameter(String paramName);
如果请求参数名写错,会返回null值。
如果不填写任何数据,会获得空字符串。

(2) request提供的getParameterValues

String[] getParameterValues(String paramName);
当有多个请求参数名相同时,用该方法。
多选框,如果不选择任何选项,浏览器不会发送任何数据给服务器。

#重定向
(1) 什么是重定向?

服务器通知浏览器,向一个新地址发送请求。
服务器可以发送一个302状态码以及一个location消息头(值是一个地址,称之为重定向地址)给浏览器,浏览器收到之后,会立即向重定向地址发送请求。

这里写图片描述

(2)如何重定向?

  • response.sendRedirect(String url);:url就是重定向地址。
    重定向之前,容器会清空response对象上存放的所有数据。 也就是说,
    实体内容里面是没有任何数据的。

(3)特点

  • 重定向地址是任意的。
  • 重定向之后浏览器地址会发生变化。

#Servlet容器处理请求资源路径
比如 http://ip:port/servlet-day03/abc.html
“/servlet-day03/abc.html”

  • step1. 容器默认会认为访问的是一个servlet即查找和"/abc.html"匹配的servlet。
    • 匹配规则:
	a.精确匹配:
            <url-pattern>/abc.html</url-pattern>
    b.通配符匹配:
            <url-pattern>/*</url-pattern>
            <url-pattern>/demo/*</url-pattern>
        *:匹配零个或者多个任意的字符。
    c.后缀匹配:
            <url-pattern>*.do</url-pattern>
        *.do  匹配所有以.do结尾的请求。
        此方法可以让一个servlet处理多个请求
  • step2.如果找不到匹配的servlet,则访问对应的文件。

#Servlet的生命周期
容器如何创建servlet对象,如何对其进行初始化处理,如果调用其方法来处理请求,以及如何销毁该对象的整个过程。
即容器如何管理servlet。

  • 生命周期
  1. 实例化一个Servlet对象,即new一个:执行一次
  2. 实例化的同时new一个ServletConfig对象
  3. 调用init()函数初始化对象:执行一次
  4. 将ServletConfig对象传给init()方法
  5. 通信组件调用Servlet的service()方法:执行多次
  6. Tomcat关闭时,销毁Servlet对象:执行一次

注意:Servlet在Tomcat内是单例(单个实例)的默认是首次访问Servlet时实例化它可以通过设置,使得Tomcat启动时实例化。
在web.xml servlet标签中加入

    <!-- 配置启动加载 -->
  	<!-- 	值越小,优先级越高(即先被实例化)-->
  	<load-on-startup>1</load-on-startup></servlet>

##service方法和doGet()&doPost()
容器收到请求之后,会调用servlet实例的service方法。HttpServlet的service方法是如何实现的?依据请求类型,分别调用对应的doXXX方法(比如,get请求就调用doGet方法)。

这里写图片描述

##相关的几个接口和类

  1. Servlet接口
  • init(ServletConfig config)
  • service(ServletRequest req,ServletResponse res)ServletRequest是一个接口,HttpServletRequest是其子接口。ServletResponse与之类似。
  • destroy()
  1. GenericServlet抽象类实现了Servlet接口的init和destroy方法。
  2. HttpServlet抽象类继承了GenericServlet,实现了service方法。
    #ServletConfig对象
    为此Servlet预置数据,即初始化参数。
    该数据在Tomcat创建ServletConfig后,由Config自动读取config与Servlet是1对1的关系

预置数据标签:web.xml的servlet标签内加入

    <init-param>
    <param-name>city</param-name>
    <param-value>北京</param-value>
    </init-param>
  • 获取预置数据
    ServletConfig cfg=getServletConfig();
    System.out.println(cfg.getInitParameter(“city”));
    #Servlet上下文

容器启动之后,会为每一个web应用创建一个实现了ServletContext接口要求的对象
该对象可以称之为Servlet上下文。

  • 特点
    • 唯一性:一个web应用对应一个Servlet上下文。
    • 一直存在: 只要容器没有关闭,应用没有被卸载,Servlet上下文就会一直存在。
  • 如何获取Servlet上下文?
    GenericServlet,ServletConfig,HttpSession,FilterConfig
    都提供了一个方法(getServletContext)来 获得Servlet上下文。
    ServletContext sc = getServletContext();
  • 作用
  • 绑订数据
    setAttribute,removeAttribute,getAttribute
    在满足使用条件的情况下,优先使用生命周期短的
    (request < session < Servlet上下文)。
  • 读取全局的初始化参数
<!-- 配置全局的初始化参数 -->
  <context-param>
  		<param-name>company</param-name>
  		<param-value>这而有一个名称</param-value>
  </context-param>
  
        //使用继承自GenericServlet的方法来获得上下文
		ServletContext sc = getServletContext();
		sc.setAttribute("username", "Sally");		
		
		//读取全局的初始化参数
		String company = sc.getInitParameter("company");

#Servlet线程安全问题

  • 为什么说Servlet会有线程安全问题?
  • 容器默认情况下,对于某个Servlet,只会创建一个实例。
  • 容器收到请求,就会启动一个线程来处理,就有可能有多个线程同时访问同一个Servlet实例(比如,这些线程去修改Servlet的属性值),就有可能产生线程安全问题。

这里写图片描述

  • 如何解决?
    a.加锁使用synchronized对有线程安全问题的代码加锁。
    b.尽量避免修改属性值
public void service(HttpServletRequest request,HttpServletResponse response)
throws ServletException, IOException {
		synchronized(this){
			count ++;
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println(
					Thread.currentThread()
					.getName() + ": " + count);
		}
	}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值