Java Web03:Servlet


Servlet是开发动态Web的一门技术,提供一个接口Servlet,通常开发Servlet程序只需要两步:

  • 编写一个Java类,实现Servlet接口
  • 将类部署到Web服务器

把实现了Servle接口的Java程序叫做Servlet

GenericServlet类实现了Servlet接口,HttpServlet类继承了GenericServlet类,因此只需要继承HttpServlet类即可

第一个Servlet程序

1、构建一个Maven项目

  • 为了便于以后统一管理,创建一个干净的项目,删掉src目录
  • 统一配置pom.xml文件,将需要的依赖包导入进来
  • 这个空的项目称为Maven主项目,子项目放在单独创建的module里(也就是勾选"Create from archetype"创建Maven项目),就可以公用导入的依赖包了
<?xml version="1.0" encoding="UTF-8"?>

    4.0.0

    org.example
    ServletStudy
    1.0-SNAPSHOT

    
        8
        8
    

    
        
        
            javax.servlet
            javax.servlet-api
            4.0.1
        

        
        
            javax.servlet.jsp
            jsp-api
            2.2
        
    

2、创建子项目module(见上节)

  • 创建子项目以后,其pom.xml文件中会多出一个parent标签,而父项目的pom.xml文件则多出一个module标签
  • 子项目可以直接使用父项目导入的依赖包
  • 注意更换子项目的web.xml内容,创建java和resources目录

3、编写Java程序

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

/**
 * 继承HttpServlet类
 * HttpServlet继承了GenericServlet
 * GenericServlet实现了Servlet接口
 */
public class HelloServlet extends HttpServlet {

    /**
     * 重写doGet()和doPost()方法
     */
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse res) throws IOException {

        /**
         * 响应的类型:html
         * 编码:utf-8
         */
        res.setContentType("text/html;charset=utf-8");

        /**
         * 获取响应的输出流
         */
        PrintWriter out = res.getWriter();
        out.println("");
        out.println("");
        out.println("HelloServlet");
        out.println("");
        out.println("");
        out.println("

Servlet访问成功!

"); out.println(""); out.println(""); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { super.doPost(req, resp); } }

4、编写Servlet的映射

  • Java程序要通过浏览器访问
  • 而浏览器需要连接Web服务器,因此需要在服务器中注册Servlet(web.xml文件),还要给定一个浏览器可以访问的路径
<?xml version="1.0" encoding="UTF-8"?>


    
    
    
        HelloServlet
        HelloServlet
    
    
    
        HelloServlet
        /Hello
    

5、在webapp目录编写一个header.html文件,在Tomcat中配置项目路径为"localhost:8080/Servlet01",然后启动Tomcat

  • 访问"localhost:8080/Servlet01",读取的是index.jsp
  • 访问"localhost:8080/Servlet01/Hello",读取的是Servlet映射的Java程序
  • 访问"localhost:8080/Servlet01/header.html",读取的header.html



    
    Title


导航栏

Servlet原理

Servlet运行在Servlet容器中,它的运行需要容器的支持,由容器管理从创建到销毁的整个过程

而Tomcat 是最常用的JSP/Servlet 容器

Servlet的执行过程

  1. 浏览器向服务器发出GET/POST请求

  2. 服务器上的Servlet容器接收到该URL,根据该URL判断为Servlet请求,此时Servlet容器将产生两个对象:请求对象(HttpServletRequest)和响应对象(HttpServletResponce)

  3. Servlet容器根据URL检索与请求匹配的 Servlet 实例,并且创建一个线程;如果实例不存在就加载并实例化出该类Servlet

    的一个实例对象,接着Servlet容器调用该实例的 init() 方法来对实例做一些初始化工作(每个Servlet容器原则上只有一个实例

  4. Servlet容器将刚才创建的请求对象和响应对象传递给线程

  5. Servlet容器调用Servlet的service()方法

  6. service()方法根据请求类型调用doGet()/doPost()方法

  7. doGet()/doPost()执行完后,将结果返回给Servlet容器

  8. 线程销毁或放在线程池中等待回收

MVC架构

JSP充当页面角色Servlet扮演控制器角色,两者组合构建基本的MVC三层架构模式

Servlet的生命周期

  1. Servlet容器加载Servlet类
  2. Servlet容器实例化Servlet(Servlet无参构造函数执行)
  3. 执行init()方法(在Servlet生命周期中,只执行一次,且在service()方法执行前执行)
  4. 执行service()方法,处理客户请求,doPost()或doGet()
  5. 执行destroy(),销毁线程

ServletContext对象

Servlet容器在启动时,会为每个项目创建一个对应的ServletContext对象,它代表了当前的Web应用

因为每个Servlet容器只有一个实例,如果有多个Java程序实现Servlet接口,为了可以复用其他类的一些内容,可以将这些内容存储

在ServletContext对象中,这样同一个Servlet容器中的类可以公用这个ServletContext对象

应用:数据共享、获取初始化参数、请求转发

共享数据

A类设置属性

setAttribute()

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class A extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse res) {

        /**
         * getServletContext()方法访问ServletContext对象
         */
        ServletContext servletContext = this.getServletContext();
        String username = "ty";

        /**
         * setAttribute()方法添加属性,让其他类复用
         */
        servletContext.setAttribute("username", username);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.doPost(req, resp);
    }
}

B类获取属性

getAttribute()

注意:每个类都需要在web.xml文件中注册和映射Servlet

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class B extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse res) throws IOException {

        res.setContentType("text/html;charset=utf-8");
        
        /**
         * getServletContext()方法访问ServletContext对象
         */
        ServletContext servletContext = this.getServletContext();

        /**
         * getAttribute()方法获取其他类定义的属性
         */
        String username = (String) servletContext.getAttribute("username");
        res.getWriter().println(username);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.doPost(req, resp);
    }
}

获取初始化参数

getInitParameter()

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class HelloServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse res) throws IOException {

        res.setContentType("text/html;charset=utf-8");

        ServletContext servletContext = this.getServletContext();
        
        /**
         * getInitParameter()方法获取初始化信息
         */
        String url = servletContext.getInitParameter("url");
        res.getWriter().println(url);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.doPost(req, resp);
    }
}


    url
    jdbc:mysql://localhost:3306/mybatis

请求转发

转发访问时URL不会变

getRequestDispatcher()、forward()

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class HelloServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse res) throws IOException, ServletException {

        res.setContentType("text/html;charset=utf-8");

        ServletContext servletContext = this.getServletContext();

        /**
         * getRequestDispatcher()设置要转发的路径,访问当前路径时会变成访问那个路径
         */
        RequestDispatcher requestDispatcher = servletContext.getRequestDispatcher("/其他路径");

        /**
         * forward()方法实现请求转发
         */
        requestDispatcher.forward(req, res);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.doPost(req, resp);
    }
}

读取资源文件

配置文件,放在resources目录下,打包后的相对路径,也就是classpath为"/WEB-INF/classes/db.properties"

因为资源文件需要经常读取,不能放在本地,所以需要放在打包好的Web文件中

/**
 * db.properties
 */
username=root
password=123456
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

public class HelloServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse res) throws IOException, ServletException {

        res.setContentType("text/html;charset=utf-8");

        ServletContext servletContext = this.getServletContext();

        /**
         * getResourceAsStream()方法将资源转换为文件流
         */
        InputStream resourceAsStream = servletContext.getResourceAsStream("/WEB-INF/classes/db.properties");

        /**
         * Properties类读取文件流
         */
        Properties properties = new Properties();
        properties.load(resourceAsStream);
        String username = properties.getProperty("username");
        String password = properties.getProperty("password");

        /**
         * 发送到网页
         */
        res.getWriter().println("用户名:" + username);
        res.getWriter().println("密码:" + password);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.doPost(req, resp);
    }
}

注:如果配置文件放在java目录,则导出配置文件会失败,需要在子项目的pom.xml文件的build标签中配置resources


    
        
            src/main/resources
            
                **/*.properties
                **/*.xml
            
            true
        
        
            src/main/java
            
                **/*.properties
                **/*.xml
            
            true