Servlet快速开发记忆笔记

1.什么是Servlet

Servlet是一个JavaEE的组件,也是JavaEE中的一个规范.

Servlet是JavaEE中的一个规范:服务器其实是对Servlet的实现.
Servlet是一个JavaEE的组件:Servlet是一个程序(类),只不过必须要遵循Servlet的规范.

要求类:必须实现javax.servlet.Servlet接口.

2.如何搭建JavaWeb项目

搭建标准的JavaWeb的项目结构::

1.创建一个Java项目:HelloServletWeb;
2.在HelloServletWeb中创建一个文件夹webapp,表示Web项目的根;
3.在webapp中创建WEB-INF文件夹,
4.在WEB-IN中创建文件夹:lib,classes
5.在WEB-IN中去Tomcat根/conf拷贝web.xml文件,只需要保留根元素.
6.把当前项目的classpath路径改成webapp/WEB-IN下的classes中.

|-HelloServletWeb
|--webapp(这里可以写任何文件夹名,以后只需要将这个文件夹拷贝到服务器即可)
|---WEB-INF
|-----classes
|-----lib
|-----web.xml

3.开发第一个Servlet

Servlet属于JavaEE的范畴,得依赖JavaEE的jar.

Servlet的第一个程序编写步骤:
1):拷贝Tomcat根/lib/servlet-api.jar到项目的WEB-INF/lib目录中,并做build path.
2):编写Servlet程序,使之实现javax.servlet.Servlet接口,并覆盖接口中的方法.

    public class HelloServlet implements javax.servlet.Servlet{...实现方法...}

3):发现方法中参数出现arg0,arg1的情况是因为没有关联Servlet的源代码.
是否关联源代码和程序最终的运行没有关系,只是在开发阶段参数美观,可阅读源代码.
Tomcat的源代码程序:apache-tomcat-7.0.57-src.zip

4):在service(ServletRequest req, ServletResponse res)方法,打印一句话.

5):此时HelloServlet类,和Tomcat一点关系都没有:我们需要告诉Tomcat来帮我们管理HelloServlet类.在server.xml中部署项目:

<Context docBase="D:\JavaApps\Servlet\webapp" path="day3"/>

6):为资源配置路径

这里写图片描述

访问:

http://ip:port/contextPath/资源名
http://localhost:80/day3/hello

4.Servlet的生命周期

  1. 生命周期:从出生—>死亡,中间的过程.
  2. Servlet的生命周期:创建对象,初始化操作,运行操作,销毁操作.
  3. Tomcat管理了Servlet对象的生命周期,Servlet对象整个过程都是由Tomcat来管理的.Servlet的创建,初始化,运行,销毁的行为都是Tomcat来负责调用的.

  4. javax.servlet.Servlet接口中的方法:

    String getServletInfo():获取Servlet的信息(Servlet的作者,版本,版权相关).
    ServletConfig getServletConfig():获取Servlet的配置信息对象.
    
    void init(ServletConfig config):初始化Servlet对象方法
    
    void service(ServletRequest req, ServletResponse resp):服务方法,Web动态网页的操作就编写在该方法.
    
    void destroy():销毁Servlet对象方法.
    
  5. 在Web的生命周期中(Tomcat启动->Tomcat关闭),Servlet是单例的.

    构造器:在服务端程序第一次被请求的时候,调用,只被调用一次.
    
    void init(ServletConfig config):在构造器执行完毕之后,调用init方法,也只会执行一次.
    
    void service(ServletRequest req, ServletResponse resp):每一次请求都会执行该方法.
    
    void destroy():正常关闭Tomcat才会执行(该方法不一定会被执行,我们没必要在其中编写扫尾的操作).
    
  6. 总结:

      构造器--->init方法---->[ service方法 ]循环 ---->destory方法
    

5.Servlet的请求流程

1:浏览器先发送请求:http://localhost:80/day3/hello.
2:DNS解析域名(忽略)
3:Tomcat解析请求:/day3/hello.
上下文路径:/day3
资源的名称:/hello
4:解析Tomcat根/conf/server.xml文件,获取其中所有的元素,并找到path属性为/day3的元素.

  <Context docBase="D:\JavaApps\Servlet\webapp" path="day3"/>

再读取该元素,再获取docBase属性值,该属性值就是当前访问的WEB项目的根路径.

5:从该web的根路径/WEB-INF下找到web.xml文件.
6:读取web.xml文件,获取所有的元素,并判断哪一个的文本内容为:/hello.

  找不到: 报404错误.
  找  到: GOTO 7.

7:通过/hello,找到当前Servlet的全限定名.

 com._520it._01_hello.HelloServlet.

8:从Servlet的实例缓冲池中去获取com._520it._01_hello.HelloServlet对应的对象.

  Map<String,Servlet> cache = .....;
  Servlet obj = cache.get("com._520it._01_hello.HelloServlet");
  if(obj == null{
       //第一次请求:GOTO 9.
  }else{
       //非第一次请求:GOTO 12;
  }

9:使用反射创建Servlet对象.

  Servlet obj = Class.forName("com._520it._01_hello.HelloServlet").newInstance();

10.把创建的Servlet对象,存储到Servlet实例缓存池中,供下一次请求使用.

    cache.put("com._520it._01_hello.HelloServlet",obj);

11:容器创建ServletConfig对象,并调用init方法,来完成初始化操作.

   obj.init(config);

12:容器创建ServletRequest和ServletResponse对象,并调用service方法,处理请求.

   obj.service(req,resp);

13:在service方法中,对当前请求的客户端做相应.

6.Servlet初始化参数

ServletConfig接口:表示Servlet的信息配置对象(web.xml中,当前Servlet的配置信息).

其中的方法:

String getServletName():获取当前Servlet的名字,<servlet-name>元素的文本内容.

ServletContext getServletContext():获取当前的Servlet上下文,其实表示当前应用对象.

String getInitParameter(String paramName):根据当前Servlet的指定的参数名获取初始化参数值.

Enumeration<String> getInitParameterNames():获取当前Servlet的所有初始化参数的名字.

配置信息如下:

<servlet>
    <servlet-name>ServletDemo2</servlet-name>
    <servlet-class>com._520it.servlet.ServletDemo2</servlet-class>
    <!-- 单个servlet的初始化数据 -->
    <init-param>
        <param-name>encoding</param-name>
        <param-value>GBK</param-value>
    </init-param>
    <init-param>
        <param-name>person</param-name>
        <param-value>lean</param-value>
    </init-param>
</servlet>
<servlet-mapping>
    <servlet-name>ServletDemo2</servlet-name>
    <url-pattern>/servletdemo2</url-pattern>        
</servlet-mapping>

获取初始化参数:

这里写图片描述

7.Servlet继承体系

以下模拟Servlet继承体系,首先Servlet是一个接口规范,Tomcat对于实现了2个子类GenericSevlet和HttpSevlet。

MyGenericSevlet.java

/**
 * 该类主要封装了ServletConfig对象的业务逻辑
 */
public abstract class MyGenericSevlet 
    implements Servlet,ServletConfig,Serializable{

    private static final long serialVersionUID = 1L;
    protected ServletConfig config;

    @Override
    public void init(ServletConfig config) throws ServletException {
        this.config=config;
        init();
    }

    public void init() {
        //NO OP
    }

    @Override
    public ServletConfig getServletConfig() {
        return config;
    }

    @Override
    public String getServletInfo() {
        return "";
    }

    @Override
    public void destroy() {

    }

    //---------如下就是ServletConfig 接口对应的方法--------
    @Override
    public String getServletName() {
        return config.getServletName();
    }

    @Override
    public ServletContext getServletContext() {
        return config.getServletContext();
    }

    @Override
    public String getInitParameter(String name) {
        return config.getInitParameter(name);
    }

    @Override
    public Enumeration<String> getInitParameterNames() {
        return config.getInitParameterNames();
    }

}

MyHttpSevlet.java:

/**
 * 该类主要封装了Http对象相关的请求方法
 */
public abstract class MyHttpSevlet  extends MyGenericSevlet{

    @Override
    public void service(ServletRequest req, ServletResponse res) 
            throws ServletException, IOException {
        HttpServletRequest request=(HttpServletRequest) req;
        HttpServletResponse response=(HttpServletResponse) res;
        service(request, response);
    }

    public void service(HttpServletRequest req, HttpServletResponse res) 
            throws ServletException, IOException {
        String method = req.getMethod();
        if (method.equals("GET")) {
            doGet(req, res);
        }else {
            doPost(req, res);
        }
    }

    private void doPost(HttpServletRequest req, HttpServletResponse res) {
        //DEFAULT IMPL
    }

    private void doGet(HttpServletRequest req, HttpServletResponse res) {
        //DEFAULT IMPL
    }

}

总结:

这里写图片描述

8.HttpServletRequest常用方法

ServletRequest接口: 请求对象,封装了获取所有请求信息(请求行,请求头,请求实体)的方法.
HttpServletRequest接口:是ServletRequest的子接口,处理HTTP协议请求的方法.
常用方法:

01.String getMethod():返回请求方式:如GET/POST
02.String getRequestURI():返回请求行中的资源名字部分:如/test/index.html

03.StringBuffer getRequestURL():返回浏览器地址栏中所有的信息
04.String getContextPath():返回当前项目的上下文路径(<Context/>元素的path属性值.)
05.String getRemoteAddr():返回发出请求的客户机的IP地址
06.String getHeader(String name):返回指定名称的请求头的值。

获取请求参数的方法:

01.String getParameter(String name):返回指定名字参数的值。

02.String[] getParameterValues(String name):返回指定名字参数的多个参数值。

03.Enumeration<String> getParameterNames():返回所有参数名的Enumeration对象。

04.Map<String,String[]> getParameterMap():返回所有的参数和值所组成的Map对象。

9.HttpServletResponse常用方法

ServletResponse接口: 响应对象.封装了获取响应信息的方法.
HttpServletResponse接口:ServletResponse的子接口,可以处理HTTP响应的方法.

常用方法:

OutputStream getOutputStream():获取字节输出流对象.  文件下载.
PrintWriter  getWriter():获取字符输出流对象
注意:上述方法,不能共存,否则报错.

设置输出的MIME类型(内容的类型):
response.setContentType(“text/html”);//不能写错
设置输出数据的编码方式:
response.setCharacterEncoding(“UTF-8”);
可以将上述两行代码合并成一行代码:
response.setContentType(“text/html;charset=utf-8”);

注意:必须先设置MIME类型和编码,再获取输出流,否则没有效果.

10.Servlet映射细节

1):一个Servlet程序(Web组件),可以配置多个,表示一个Servlet有多个资源名称.
2):一个Servlet程序,可以配置多个.
3):必须保证唯一性,而且必须使用/打头.
4):Servlet的映射支持通配符映射(*:表示任意字符):

 第一种写法:   /*,任意的资源都可以访问该Servlet. /system/*:请求的资源必须以/system/打头才可以访问.
                Servlet中,权限控制:
  第二种写法:   *.拓展名, 比如: *.do,请求的资源必须以.do作为结尾才可以访问该Servlet.

5):在映射Servlet的时候,元素的文本内容不能是default.因为,在Tomcat中存在一个叫做default的Servlet,专门用于处理请求静态资源(html,css,js,图片等).
在Tomcat根/conf/web.xml文件:

<servlet>
    <servlet-name>default</servlet-name>
    <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
    <init-param>
        ...
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>

11.Servlet3.0新特性-注解配置

Servlet3.0对应着JavaEE6的规范,Tomcat7.*.

问题:传统的使用XML做Servlet配置,如果Servlet有N个,就得配置 10*N 行代码,web.xml文件,臃肿,不利于维护,开发效率低.

从Tomcat7开始,可以使用注解(WebServlet)来取代XML配置.
使用注意:在web.xml文件的根元素中,存在属性,表示是否忽略扫描Web组件注解:
metadata-complete=”true” : 要忽略
metadata-complete=”false”: 不忽略
不要改属性: 缺省情况等价于metadata-complete=”false”.

开发步骤:

1.修改web.xml

<web-app xmlns="http://java.sun.com/xml/ns/javaee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
  version="3.0" metadata-complete="false">
  ...

 </web-app>

2.在Servlet中,对其进行配置:

@WebServlet(value="/mapping",loadOnStartup=1,
    initParams= {@WebInitParam(name="encoding",value="GBK"),
            @WebInitParam(name="username",value="lean")})
public class MappingServlet extends HttpServlet{

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("mapping service !");
        String encoding = getInitParameter("encoding");
        String username = getInitParameter("username");
        System.out.println(encoding+"  "+username);
    }

}

12.启动初始化Servlet

回顾Servlet生命周期方法的执行流程:
在启动Tomcat服务器的时候,没有对Servlet创建和初始化操作.
在第一次服务端请求的时候:
1):创建Servlet对象.
2):调用init方法做初始化.
3):调用service方法,处理请求.

如果某一天,某一个Servlet(核心Servlet:初始化全局的信息)需要在启动服务器的时候就创建出来,我们可以使用loadOnStartup配置。

配置后启动Tomcat,会发现init被调用了,但是不代表service被调用,因为我们只是创建了该对象,并没有调用该对象的组件。

13.Servlet线程安全问题

Servlet的线程不安全问题:

造成的根本原因是:Servlet是单例的,Servlet中的非static的成员变量只有一份,多个客户端好比是多个线程,都访问的是同一个空间.
解决方案:

     1:让当前Servlet实现javax.servlet.SingleThreadModel接口.
       包装只有一个线程放Servlet,如果有多个线程就排队,如此的话,性能超低(已过时).
     2:在Servlet中不要使用成员变量,使用局部变量.
       每一个用户,每一个请求都会调用service方法,而局部变量在service方法中,每一次都是新的空间.

Struts1,Spring MVC都是线程不安全的,都是单例的和Servlet类似.
Struts2是线程安全的,因为每一个线程(请求)都是一个新的Action对象.

猜你喜欢

转载自blog.csdn.net/qq285016127/article/details/78166293
今日推荐