Servlet 的三种创建方式、请求响应常用方法

Servlet

1. Servlet 的三种创建方式

1.1 Servlet 程序的整体代码逻辑结构
interface Servlet
	Java EE 规范规定的 Servlet 程序必须要求完成的方法,整个 Java WEB 中所有 servlet 程序的总接口。

abstract class GenericServlet implements Servlet, ServletConfig 
	完成了一部分 Servlet 接口规范的 abstract 修饰类,同时引入了 ServletConfig 规则、

abstract class HttpServlet extends GenericServlet
	引入了 HTTP 协议,符合 Servlet 标准的一个 abstract 修饰类

自定义类【遵从】 servlet 接口,请问算不算一个 Servlet 程序???
	算!!!
自定义类【继承】 GenericServlet 抽象类,请问算不算一个 Servlet 程序???
	算!!!
1.2 遵从 Servlet 接口实现 Servlet 程序
package com.qfedu.a_createServlet;

import javax.servlet.*;
import javax.servlet.annotation.WebServlet;
import java.io.IOException;

/**
 * 遵从 Servlet 接口实现 Servlet 程序
 *
 * public void init(ServletConfig config) throws ServletException
 *      初始化当前 Servlet 程序,所需参数是 ServletConfig 对象 servlet 配置对象
 *
 * public ServletConfig getServletConfig()
 *      获取 ServletConfig Servlet配置对象,可以认为 ServletConfig 是 Servlet 程序的一部分
 *
 * public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException
 *      【核心方法】
 *        对外提供数据服务的方法,所需参数是 Tomcat 在处理用户请求时对应创建的 ServletRequest 和 绑定的
 *        ServletResponse 对象
 *
 * public String getServletInfo()
 *      获取 Servlet 字符串描述信息
 *
 * public void destroy()
 *      销毁 Servlet 程序,Tomcat退出时自动调用
 *      业务逻辑考虑
 *          用户登陆 ==> 对应当前用户的 servlet 启动提供服务
 *          用户退出 ==> 对应当前用户的 servlet 调用 destroy 销毁
 *
 * @author Anonymous 2022/4/15 9:33
 */
@WebServlet("/cs1")
public class CreateServlet1 implements Servlet {

    public CreateServlet1() {
        System.out.println("CreateServlet1 Constructor called...");
    }

    @Override
    public void init(ServletConfig config) throws ServletException {
        System.out.println("init method called...");
    }

    @Override
    public ServletConfig getServletConfig() {
        System.out.println("getServletConfig method called...");
        return null;
    }

    @Override
    public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
        System.out.println("Service method called...");
        /*
        HttpServletRequest HttpServletResponse
        在原始的 ServletRequest ServletResponse 做了增强,满足适应 Http 协议规范!!!
         */
        res.getWriter().append("<h1>Implements Interface Servlet to Create Servlet Program</h1>");
    }

    @Override
    public String getServletInfo() {
        System.out.println("getServletInfo method called...");
        return null;
    }

    @Override
    public void destroy() {
        System.out.println("destroy method called...");
    }
}

1.3 继承 GenericServlet 抽象类实现 Servlet 程序
package com.qfedu.a_createServlet;

import javax.servlet.GenericServlet;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebServlet;
import java.io.IOException;

/**
 * 继承 abstract class GenericServlet
 *
 * public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException
 *      有且只需要实现 service 方法,因为其他 Servlet 接口中规定的方法,全部都已经实现。
 *      程序员在完成 Servlet 程序的过程中,更加专注的是业务逻辑相关内容
 *
 * Servlet 接口使用一个手动挡
 *      开车需要考虑离合,换挡,油门,刹车...
 * GenericServlet 抽象类是一个自动挡
 *      只需要考虑 D 挡,油门,刹车,专注于开车!!!
 * @author Anonymous 2022/4/15 9:33
 */
@WebServlet("/cs2")
public class CreateServlet2 extends GenericServlet {
    @Override
    public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
        System.out.println("Service method called...");
        /*
        HttpServletRequest HttpServletResponse
        在原始的 ServletRequest ServletResponse 做了增强,满足适应 Http 协议规范!!!
         */
        res.getWriter().append("<h1>Extend abstract class GenericServlet to Create Servlet Program</h1>");
    }
}
1.4 继承 HttpServlet 抽象类实现 Servlet 程序
package com.qfedu.a_createServlet;

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

/**
 * 继承 abstract class HttpServlet 完成 Servlet
 *
 * 继承之后虽然 HttpServlet 是一个 abstract 修饰类,但是没有任何一个强制方法需要实现
 * 在 HttpServlet 中继承 GenericServlet ,实现了 符合 Servlet 接口规范的 service 方法
 * 并且增强 service 方法,加入 HTTP 协议,按照 HTTP 协议规范根据用户请求的方式操作实现
 * 对应处理方法
 *      doGet ==> GET 请求
 *      doPOST ==> POST 请求
 *      程序员无需考虑 Servlet 整体的实现过程,初始化方法,资源销毁,数据配置,而且专注于
 *      针对用户请求数据方式的处理过程。
 *
 * 自动挡汽车
 *      不同的驾驶模式,有自动辅助驾驶。
 *
 * @author Anonymous 2022/4/15 9:33
 */
@WebServlet("/cs3")
public class CreateServlet3 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.getWriter().append("<h1>Extend abstract class HttpServlet to Create Servlet Program</h1>");
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}
1.5 三种方式对比和结构分析
	Servlet 接口规定了 Java EE 规范所有 Servlet 程序必须完成的方法内容,涉及到 Servlet 初始化,销毁,配置,数据信息获取,和【服务方法】,只考虑业务逻辑,需要完成的方法过多,使用不便。并且不支持 HTTP 协议
	
	GenericServlet 遵从 Servlet 接口,将和业务逻辑无关的方法内容,完成配套实现,留给用户的有且只有 service 方法,作为业务逻辑的实现。
	
	HttpServlet 继承 GenericServlet 引入  HTTP 协议支持,针对于不同的 HTTP 请求方式分门别类处理,同时引入了 HTTP 协议的其他规范,例如 Cookie Session Header... 对于用户而言可以专注于请求方式对应业务逻辑处理。 
	
	abstract 类在代码结构中【承上启下】

2. 请求响应常用方法

2.1 ServletRequest 常用方法
方法名 功能
String getMethod(); 获取当前用户请求方式 GET or POST
String getRequestURL(); 获取用户请求完整 URL http://localhost:8080/Day38/test
String getRequestURI(); 获取用户请求资源信息 /Day38/test
String getQueryString(); GET请求生效,可以获取URL参数 name=James&age=16
String getProtocol(); 获取当前请求的协议类型 HTTP/1.1
String getRemoteAddr(); 获取用户主机 IP 地址
String getRemoteHost(); 获取用户请求目标主机地址/域名/IP地址
int getRemotePort(); 请求资源的端口号
String getRemoteUser(); 请求对应的用户名
String getContextPath(); 获取虚拟路径名称 http://localhost:8080/Day38/test == /Day38
String getHeader(String headerName) 根据请求头的名称获取对应数据
setCharacterEncoding(); 请求数据编码集修改,可以处理乱码问题
package com.qfedu.b_method;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;

/**
 * 演示 Request 常用方法
 * <p>
 *
 *
 * @author Anonymous 2022/4/15 11:28
 */
@WebServlet("/rm1")
public class RequestMethod1 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 获取当前用户请求方式 GET or POST
        String method = req.getMethod();
        System.out.println("用户当前请求方式 : " + method);

        // 获取用户请求完整 URL
        StringBuffer requestUrl = req.getRequestURL();
        System.out.println("获取用户请求完整 URL : " + requestUrl);

        // 获取用户请求资源信息
        String requestUri = req.getRequestURI();
        System.out.println("获取用户请求资源信息 : " + requestUri);

        // GET请求生效,可以获取URL参数 name=James&age=16
        String queryString = req.getQueryString();
        System.out.println("用户通过 GET 请求提交的参数字符串 : " + queryString);

        // 获取当前请求的协议类型 HTTP/1.1
        String protocol = req.getProtocol();
        System.out.println("获取当前请求的协议类型 : " + protocol);

        // 获取用户主机 IP 地址
        String remoteAddr = req.getRemoteAddr();
        System.out.println("获取用户主机 IP 地址 : " + remoteAddr);

        // 获取用户请求目标主机地址/域名/IP地址
        String remoteHost = req.getRemoteHost();
        System.out.println("获取用户请求目标主机地址/域名/IP地址 : " + remoteHost);

        // 请求资源的端口号
        int remotePort = req.getRemotePort();
        System.out.println("请求资源的端口号 : " + remotePort);

        // 请求对应的用户名
        String remoteUser = req.getRemoteUser();
        System.out.println("请求对应的用户名 : " + remoteUser);

        // 【重点方法】获取虚拟路径名称  http://localhost:8080/Day38/test == /Day38
        String contextPath = req.getContextPath();
        System.out.println("获取虚拟路径名称 : " + contextPath);

        // 根据请求头的名称获取对应数据
        String header = req.getHeader("Cache-Control");
        System.out.println("Cache-Control header :" + header);

    }

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

2.2 ServletRequest 重要方法【VIP Method】
方法 功能
String getParameter(String name) 根据指定的参数名称获取对应数据,数据类型为 String
String[] getParameterValues(String name); 根据指定的参数名称获取对应数据,数据类型为String[] 字符串数组,可以用于多选框操作
Map<String, String[]> getParameterMap(); 获取当前 Request 请求中用户提交的所有参数和数据的 Map 双边队列,Map 对应 key 是参数名称 String 类型,参数值 value 为 String[] 【你会用的上瘾】
Enumeration getParameterNames(); 获取用户请求数据当中所有参数名称,可以讲Enumeration 看做是一个 Set 集合
// BeanUtils 工具类
BeanUtils.setProperty(Object bean, String name, Object value);
BeanUtils.copyProperties(Object dest, Object src);
String BeanUtils.getProperty(Object bean, String name);
BeanUtils.populate(Object bean, Map properties);
package com.qfedu.b_method;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.Map;

/**
 *
 *
 * @author Anonymous 2022/4/15 14:54
 */
@WebServlet("/rm2")
public class RequestMethod2 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // getParameter 根据指定的参数名称获取对应数据,数据类型为 String
        String name = req.getParameter("name");
        String age = req.getParameter("age");
        String gender = req.getParameter("gender");

        // 根据指定的参数名称获取对应数据,数据类型为String[] 字符串数组,可以用于多选框操作
        String[] hobbies = req.getParameterValues("hobby");

        System.out.println(name);
        System.out.println(age);
        System.out.println(gender);
        System.out.println(Arrays.toString(hobbies));
        System.out.println();

        // 获取当前 Request 请求中用户提交的所有参数和数据的 Map 双边队列,
        // name=王乾&age=80&gender=0&hobby=0&hobby=3 ==>
        //          Map<String, String[]> = {"name"={"王乾"}, "age"={"80"}, "gender"={"0"}, "hobby"={"0", "3"}}
        // Map 对应 key 是参数名称 String 类型,参数值 value 为 String[] 【你会用的上瘾】
        Map<String, String[]> parameterMap = req.getParameterMap();

        parameterMap.forEach((key, value) -> System.out.println(key + ":" + Arrays.toString(value)));

        System.out.println();
        // 获取用户请求数据当中所有参数名称,可以将 Enumeration 看做是一个 Set 集合
        // TODO Enumeration
        Enumeration<String> parameterNames = req.getParameterNames();
        while (parameterNames.hasMoreElements()) {
            System.out.println(parameterNames.nextElement());
        }
    }

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

2.3 ServletResponse 常用方法
方法 功能
setContentType() 设置当前响应数据类型 setContentType("text/html;charset=utf-8")
PrintWriter getWriter(); 获取可以发送数据到前端的【字符流】 PrintWriter 常用 append(String)
package com.qfedu.b_method;

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

/**
 * @author Anonymous 2022/4/15 15:38
 */
@WebServlet("/respMethod")
public class ResponseMethod extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // "text/html;charset=utf-8"
        // 设定当前对外数据形式为可视化文本 HTML 类型数据,编码集采用 UTF-8 中文可见
        resp.setContentType("text/html;charset=utf-8");
        resp.getWriter().append("<h1>路见不平一声吼,大哥没有男朋友</h1>");
    }

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

3. Servlet 案例

3.1 前端提交数据到后台,后台保存到数据库

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>注册</title>
</head>
<body>
<form action="register" method="post">
    <span>姓名 : </span><input type="text" name="name"> <br>
    <span>年龄 : </span><input type="text" name="age"> <br>
    <span>性别 : </span><input type="radio" name="gender" value="0">男  <input type="radio" name="gender" value="1">女  <br>
    <input type="submit" value="提交">
</form>
</body>
</html>
package com.qfedu.c_demo;

import org.apache.commons.beanutils.BeanUtils;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.Map;

/**
 * @author Anonymous 2022/4/15 16:14
 */
@WebServlet("/register")
public class RegisterServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setCharacterEncoding("utf-8");
        // 直接获取用户提交数据的 Map 双边队列
        Map<String, String[]> map = req.getParameterMap();

        // 实例化 Person 对象
        Person person = new Person();
        try {
            // 利用 BeanUtils 工具类中 populate 方法使用
            // map 双边队列给予 JavaBean 规范对象赋值操作
            BeanUtils.populate(person, map);
        } catch (IllegalAccessException | InvocationTargetException e) {
            e.printStackTrace();
        }

        // 实例化 PersonDao 对象
        PersonDao personDao = new PersonDao();
        // Person 对象 通过 registerPerson 方法存储到数据库中
        if (1 == personDao.registerPerson(person)) {
            System.out.println("添加成功");
        } else {
            System.out.println("添加失败");
        }
    }

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

package com.qfedu.c_demo;

import util.BaseDao;

import java.sql.SQLException;

/**
 * 业务逻辑相关 Dao 首先继承 BaseDao
 *
 * @author Anonymous 2022/4/15 16:15
 */
public class PersonDao extends BaseDao {
    /**
     * 保存 Person 数据到数据中
     *
     * @param person Person 对象
     * @return SQL 语句运行对数据表的影响行数
     */
    public int registerPerson(Person person) {
        String sql = "insert into javaee_2203.user(name, age, gender) VALUES (?, ?, ?)";

        int i = 0;

        try {
            i = super.update(sql, person.getName(), person.getAge(), person.getGender());
        } catch (SQLException e) {
            e.printStackTrace();
        }

        return i;
    }
}

posted @ 2022-05-17 00:09  qtyanan  阅读(195)  评论(0编辑  收藏  举报