zoukankan      html  css  js  c++  java
  • Servlet入门笔记

    一、一个简单的Servlet

    在servlet 3.0之前,下面是基本步骤:

    1.新建一个class名为FirstServlet,让它继承javax.servlet.http.HttpServlet;

    2.重写doGet和doPost方法:

    public void doGet(HttpServletRequest request, HttpServletResponse response){
            this.log("以GET方式访问");
    }
        
    public void doPost(HttpServletRequest request, HttpServletResponse response){
            this.log("以POST方式访问");
    }

    3.在web.xml中配置servlet:

    首先,一个servlet的基本信息配置在一个<servlet>标签中,

    <servlet>
        <servlet-name>FirstServlet</servlet-name>
        <servlet-class>com.levice.servlet.FirstServlet</servlet-class>
    </servlet>

    <servlet-name>代表servlet名称,可以取任意字符串,用于唯一标识某个servlet,一般和类名相同;<servlet-class>代表该servlet所指向的Servlet类。

    然后,servlet的访问方式(地址)配置在<servlet-mapping>标签中,

    <servlet-mapping>
          <servlet-name>FirstServlet</servlet-name>
          <url-pattern>/FirstServlet</url-pattern>
    </servlet-mapping>

    <servlet-name>代表servlet名称,<url-pattern>配置了该servlet的访问方式。上面的配置表示整个项目中可以使用“./FirstServlet”这个链接来访问这个servlet。

    到这里,一个简单的servlet就编写和配置完毕了,在/FirstServlet前面加上主机域名、端口号和项目名就可以访问这个servlet了。比如,服务器就是本机,端口号是8080,项目名称是Test,那么在将项目部署到tomcat并启动tomcat服务后,在浏览器上输入http://localhost:8080/Test/FirstServlet就能访问刚才写的那个servlet了,控制台会输出“以GET方式访问”这句话。

    二、在servlet中,还可以定义初始化参数

    在servlet标签内,还可以使用init-param标签定义初始化参数,

    <servlet>
          <servlet-name>FirstServlet</servlet-name>
          <servlet-class>com.levice.servlet.FirstServlet</servlet-class>
          <init-param>
              <param-name>ProjectName</param-name>
              <param-value>Traditional</param-value>
          </init-param>
      </servlet>

    param-name定义参数名,param-value定义参数值,在Servlet中使用getInitParameter(String paramName)来访问参数。

    三、servlet中的资源注射

    在servlet中使用@Resource修饰变量时,变量的值会在servlet运行时动态注入,例如

    @Resource(name="TestResource")
    private String message;

    上面表示message的值会在servlet运行时动态注入,此时只需要在web.xml配置一个名为TestResource的参数就可以了,如下:

    <env-entry>
       <env-entry-name>TestResource</env-entry-name>
       <env-entry-type>java.lang.String</env-entry-type>
       <env-entry-value>this is a test message</env-entry-value>
    </env-entry>

     在使用@Resource的时候,要注意import javax.annotation.Resource;同时,@Resource可以和变量使用在同一行中:

    private @Resource(name="TestResource") String message;

    四、servlet的生命周期

    Servlet会在服务器启动或第一次请求该Servlet时开始生命周期,在服务器结束时结束生命周期。无论多少次请求Servlet,最多只有一个Servlet实例。多个客户端并发请求Servlet时,服务器会启动多个线程分别执行该Servlet的service()方法。

    在Servlet对象的生命周期中,init(ServletConfig conf)方法与destroy()均只会被服务器执行一次,而service()在每次客户端请求Servlet时都会被执行。Servlet中有时会用到一些需要初始化与销毁的资源,因此可以把初始化资源的代码放入init()方法内,把销毁该资源的代码放入到destroy()方法内,而不需要每次处理请求都要初始化与销毁资源。

    对于Servlet的init(ServletConfig conf)方法,HttpServlet提供了一个更简单的不带参数的替代方法init()。HttpServlet加载时会执行这个不带参数的init()方法,因此只需把代码放置在init()中就可以了。对于原来的ServletConfig参数,仍然可以通过getServletConfig()方法获取到。

    从Java EE 5规范开始,Servlet中增加了两个影响Servlet生命周期的注解:@PostConstruct和@PreDestroy。这两个注解被用来修饰非静态的void()方法,而且该方法不能抛出异常声明。该注解同样可以写在方法前或返回类型void前面,如下:

    @PostConstruct
    public void someMethod(){
      ...
    }
    
    public @PreDestroy void anotherMethod(){
      ...
    }

    被@PostConstruct修饰的方法会在服务器加载Servlet时运行,并且只会被服务器调用一次,类似于init()方法。事实上,@PostConstruct修饰的方法构造函数之后、init()方法之前被运行。

    被@PreDestroy修饰的方法会在服务器卸载Servlet时运行,并且只会被服务器调用一次,类似于destroy()方法。被@PreDestroy修饰的方法会在destroy()之后(注意,不是之前),Servlet被彻底卸载之前运行。

    五、servlet之间的跳转

    Servlet之间的跳转通过RequestDispatcher对象的forward(HeetServletResquest req, HttpSevletResponse res)来实现,例如,跳转到另一个servlet:

    RequestDispatcher dispatcher = request.getRequestDispatcher("/servlet/SecondServlet");
    dispatcher.forward(request, response);

    getRequestDispatcher()方法的参数必须以“/”开始,“/”表示Web应用程序的根目录。

    Forward不仅可以跳转到Servlet,还可以跳转到另外一个文件,甚至WEB-INF文件夹下的文件,其中跳转到Servlet和JSP页面是最常见的。

    六、servlet与线程安全

    线程安全问题是指在多线程并发执行时,会不会出现问题。如果不出现问题,则是线程安全的;如果会出现问题,则是线程不安全的。

    Servlet只会有一个实例,多个用户同时请求Servlet时,Tomcat会派生出多条线程执行Servlet代码,因此Servlet有线程不安全的隐患。看下面一个例子:

    public class TestServlet extends HttpServlet {
      private String name;
    
      public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException,IOException{
      name=request.getParameter("name");
      try{
        Thread.sleep(10000);
      }catch(InterruptedException e) {}
      response.getWriter().println("Hello," + name);
    }

    这段代码让线程沉睡了10秒。10秒内分别用两个浏览器访问TestServlet?name=jack和TestServlet?name=tom,显示的结果均为“Hello,tom”,这就意味着程序出了问题。在前一个线程输出之前,后一个线程已将name修改成了tom。解决的办法是尽量不要像这样定义name,而把name定义在doGet和doPost里面。使用synchronized(name){}语句块也可以解决问题,但会造成线程等待,这样并不科学。

    七、servlet 3.0

     前面介绍了3.0之前的servlet,当servlet到了3.0,就变得高大上了许多,再也不需要配置web.xml了,所有配置都通过注解完成。我们看一个servlet 3.0的例子:

    package com.levice.servlet;
    
    import java.io.IOException;
    import javax.servlet.ServletException;
    import javax.servlet.annotation.WebInitParam;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    /**
     * Servlet implementation class MethodServlet
     */
    @WebServlet(
            description = "show the using of different nethod", 
            urlPatterns = { "/MethodServlet" }, 
            initParams = { 
                    @WebInitParam(name = "ProjectName", value = "Levice"),
                    @WebInitParam(name = "ServletName", value = "MethodServlet")
            })
    public class MethodServlet extends HttpServlet {
        private static final long serialVersionUID = 1L;
           
        /**
         * @see HttpServlet#HttpServlet()
         */
        public MethodServlet() {
            super();
            // TODO Auto-generated constructor stub
        }
    
        /**
         * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
         */
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            // TODO Auto-generated method stub
            response.getWriter().append("Served at: ").append(request.getContextPath());
            this.log("Hello World! again");
            this.log(getInitParameter("ProjectName"));
        }
    
        /**
         * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
         */
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            // TODO Auto-generated method stub
            doGet(request, response);
        }
    
    }

    如上,使用@WebServlet注释该Servlet后,就不需要web.xml中配置了,在description、urlPatterns和initParams这几个参数中只有urlPatterns是必须的。当然,要使用这些注解,下面两句是必不可少的:

    import javax.servlet.annotation.WebInitParam;
    
    import javax.servlet.annotation.WebServlet;
  • 相关阅读:
    两个半成品的ORM
    Mayberry小镇的管理 | 三种截然不同的领导风格 3M
    敏捷的目的(方向)错了以后……
    Error:java: Compilation failed: internal java compiler error
    java: -source 1.5 中不支持 diamond 运算符 (请使用 -source 7 或更高版本以启用 diamond 运算符)
    看mybatis日志模块时涉及的动态代理
    看的顺眼的却Destination Unreachable
    如何下载钉钉回放视频
    不想学习时看一看会有帮助的,“但行好事,莫问前程”
    守护线程
  • 原文地址:https://www.cnblogs.com/dige1993/p/5384957.html
Copyright © 2011-2022 走看看