Java Servlet

1. Servlet简介

Servlet 是运行在服务端tomcat的,从代码层面上来讲Servlet就是一个接口

  • 用来接收、处理客户端请求、响应给浏览器的动态资源。在整个Web应用中,Servlet主要负责接收处理请求、协同调度功能以及响应数据。可以把Servlet称为Web应用中的控制器
  • Servlet是运行在服务端的,Servlet必须在WEB项目中开发且在Tomcat服务容器中运行
    在这里插入图片描述

2. Servlet开发流程

2.1. 开发一个UserServlet

public class UserServlet extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 获取请求中的参数
        String username = req.getParameter("username");
        if("wyb".equals(username)){
            //通过响应对象响应信息
            resp.getWriter().write("NO");
        }else{
            resp.getWriter().write("YES");
        }
    }
}
  • 自定义一个类,继承HttpServlet类
  • 重写service方法,用于处理用户请求的服务方法
  • HttpServletRequest:请求对象,由请求报文经过tomcat转换而来的,通过该对象可以获取请求中的信息
  • HttpServletResponse:响应对象,会被tomcat转换为响应的报文,通过该对象可以设置响应中的信息
  • Servlet对象的生命周期(创建,初始化,处理服务,销毁)由tomcat管理的,无需new
  • HttpServletRequest和HttpServletResponse 两个对象也是由tomcat负责转换,在调用service方法时传入的

2.2. 在web.xml为UseServlet配置请求的映射路径

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd"
         version="5.0">
    <servlet>
        <!--给UserServlet起一个别名-->
        <servlet-name>userServlet</servlet-name>
        <servlet-class>com.wyb.servlet.UserServlet</servlet-class>
    </servlet>

    <servlet-mapping>
        <!--关联别名和映射路径-->
        <servlet-name>userServlet</servlet-name>
        <!--可以为一个Servlet匹配多个不同的映射路径,但是不同的Servlet不能使用相同的url-pattern-->
        <url-pattern>/userServlet</url-pattern>
       <!-- <url-pattern>/userServlet2</url-pattern>-->
        <!--
            /        表示通配所有资源,不包括jsp文件
            /*       表示通配所有资源,包括jsp文件
            /a/*     匹配所有以a前缀的映射路径
            *.action 匹配所有以action为后缀的映射路径
        -->
       <!-- <url-pattern>/*</url-pattern>-->
    </servlet-mapping>
</web-app>
  • Servlet并不是文件系统中实际存在的文件或者目录,所以为了能够请求到该资源,需要为其配置映射路径,配置在web.xml中
  • servlet-name:servlet的别名,定义要见名知意就好
  • url-pattern:定义Servlet的请求映射路径,一个servlet可以对应多个不同的url-pattern,多个servlet不能使用相同的url-pattern
  • url-pattern中可以使用一些通配写法
    • /:通配所有资源,不包括jsp文件
    • /*:通配所有资源,包括jsp文件
    • /a/* :匹配所有以a前缀的映射路径
    • *.action:匹配所有以action为后缀的映射路径

2.3. 开发一个form表单,向servlet发送一个get请求并携带username参数

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <form action="userServlet">
        请输入用户名:<input type="text" name="username" /> <br>
        <input type="submit" value="校验">
    </form>
</body>
</html>

2.4. 映射关系图

在这里插入图片描述

3. Servlet注解方式配置

3.1. @WebServlet注解源码

package jakarta.servlet.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @since Servlet 3.0
 */
@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface WebServlet {
    /**
     * The name of the servlet
     * 相当于 servlet-name
     * @return the name of the servlet
     */
    String name() default "";

    /**
     * The URL patterns of the servlet
     * 如果只配置一个url-pattern ,则通过该属性即可,和urlPatterns属性互斥
     * @return the URL patterns of the servlet
     */
    String[] value() default {};

    /**
     * The URL patterns of the servlet
     * 如果要配置多个url-pattern ,需要通过该属性,和value属性互斥
     * @return the URL patterns of the servlet
     */
    String[] urlPatterns() default {};

    /**
     * The load-on-startup order of the servlet
     * 配置Servlet是否在项目加载时实例化
     * @return the load-on-startup order of the servlet
     */
    int loadOnStartup() default -1;

    /**
     * The init parameters of the servlet
     * 配置初始化参数
     * @return the init parameters of the servlet
     */
    WebInitParam[] initParams() default {};

    /**
     * The description of the servlet
     *
     * @return the description of the servlet
     */
    String description() default "";
    ......
}

3.2. @WebServlet注解使用

使用@WebServlet注解替换Servlet配置

@WebServlet(
        name = "userServlet",
        //value = "/user",
        urlPatterns = {"/userServlet1","/userServlet2","/userServlet"},
        initParams = {@WebInitParam(name = "encoding",value = "UTF-8")},
        loadOnStartup = 6
)
public class UserServlet  extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String encoding = getServletConfig().getInitParameter("encoding");
        System.out.println(encoding);
        // 获取请求中的参数
        String username = req.getParameter("username");
        if("wyb".equals(username)){
            //通过响应对象响应信息
            resp.getWriter().write("NO");
        }else{
            resp.getWriter().write("YES");
        }
    }
}

4. Servlet生命周期

生命周期对应方法执行时机执行次数
构造对象构造器第一次请求或者容器启动1
初始化init()构造完毕后1
处理服务service(HttpServletRequest req,HttpServletResponse resp)每次请求多次
销毁destory()容器关闭1

4.1. 声明周期测试

  1. servlet
package com.wyb.servlet;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;

public class ServletLifeCycle  extends HttpServlet {
    public ServletLifeCycle(){
        System.out.println("构造器");
    }
    @Override
    public void init() throws ServletException {
        System.out.println("初始化方法");
    }
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("service方法");
    }
    @Override
    public void destroy() {
        System.out.println("销毁方法");
    }
}
  1. 配置Servlet
    <servlet>
        <servlet-name>servletLifeCycle</servlet-name>
        <servlet-class>com.wyb.servlet.ServletLifeCycle</servlet-class>
        <!--load-on-startup
            如果配置的是正整数则表示容器在启动时就要实例化Servlet,
            数字表示的是实例化的顺序
        -->
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>servletLifeCycle</servlet-name>
        <url-pattern>/servletLiftCycle</url-pattern>
    </servlet-mapping>

4.2. 生命周期总结

  1. Servlet对象在容器中是单例的
  2. 容器是可以处理并发的用户请求的,每个请求在容器中都会开启一个线程
  3. 多个线程可能会使用相同的Servlet对象,所以在Servlet中,不要轻易定义一些容易经常发生修改的成员变量
  4. load-on-startup中定义的正整数表示实例化顺序,如果数字重复,容器会自行解决实例化顺序问题,但是应该避免重复
  5. Tomcat容器中已经定义了一些随系统启动实例化的servlet,我们自定义的servlet的load-on-startup尽量不要占用数字1-5

5. Servlet继承结构

5.1. Servlet接口

Servlet 规范接口,所有Servlet必须实现

  • public void init(ServletConfig config) throws ServletException;
    • 初始化方法,容器在构造servlet对象后自动调用的方法,容器负责实例化一个ServletConfig对象,并在调用该方法时传入
    • ServletConfig对象可以为Servlet 提供初始化参数
  • public ServletConfig getServletConfig();
    • 获取ServletConfig对象,后续可以通过该对象获取Servlet初始化参数
  • public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException;
    • 处理请求并做出响应的服务方法,每次请求产生由容器调用
    • 容器创建一个ServletRequest对象和ServletResponse对象,容器在调用service方法时,传入这两个对象
  • public String getServletInfo();
    • 获取ServletInfo信息的方法
  • public void destroy();
    • Servlet实例在销毁之前调用的方法

5.2. GenericServlet 抽象类

GenericServlet 抽象类是对Servlet接口一些固定功能的粗糙实现,以及对service方法的再次抽象声明并定义了一些其他相关功能方法

  • private transient ServletConfig config;
    • 初始化配置对象作为属性
  • public GenericServlet() { }
    • 构造器,为了满足继承而准备
  • public void destroy() { }
    • 销毁方法的平庸实现
  • public String getInitParameter(String name)
    • 获取初始参数的快捷方法
  • public Enumeration<String> getInitParameterNames()
    • 返回所有初始化参数名的方法
  • public ServletConfig getServletConfig()
    • 获取初始Servlet初始配置对象ServletConfig的方法
  • public ServletContext getServletContext()
    • 获取上下文对象ServletContext的方法
  • public String getServletInfo()
    • 获取Servlet信息的平庸实现
  • public void init(ServletConfig config) throws ServletException()
    • 初始化方法的实现,并在此调用了init的重载方法
  • public void init() throws ServletException
    • 重载init方法,为了让我们自己定义初始化功能的方法
  • public void log(String msg)
  • public void log(String message, Throwable t)
    • 打印日志的方法及重载
  • public abstract void service(ServletRequest req, ServletResponse res) throws ServletException, IOException;
    • 服务方法再次声明
  • public String getServletName()
    • 获取ServletName的方法

5.3. HttpServlet 抽象类

abstract class HttpServlet extends GenericServlet ,HttpServlet抽象类,除了基本的实现以外,增加了更多的基础功能

  • private static final String METHOD_DELETE = "DELETE";
  • private static final String METHOD_HEAD = "HEAD";
  • private static final String METHOD_GET = "GET";
  • private static final String METHOD_OPTIONS = "OPTIONS";
  • private static final String METHOD_POST = "POST";
  • private static final String METHOD_PUT = "PUT";
  • private static final String METHOD_TRACE = "TRACE";
    • 上述属性用于定义常见请求方式名常量值
  • public HttpServlet() {}
    • 构造器,用于处理继承
  • public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException
    • 对服务方法的实现
    • 在该方法中,将请求和响应对象转换成对应HTTP协议的HttpServletRequest HttpServletResponse对象
    • 调用重载的service方法
  • public void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException
    • 重载的service方法,被重写的service方法所调用
    • 在该方法中,通过请求方式判断调用具体的do***方法完成请求的处理
  • protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
  • protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
  • protected void doHead(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
  • protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
  • protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
  • protected void doOptions(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
  • protected void doTrace(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
    • 对应不同请求方式的处理方法
    • 除了doOptions和doTrace方法,其他的do*** 方法都在故意响应错误信息

5.4. 自定义Servlet

继承关系图解
在这里插入图片描述
自定义Servlet中,必须要对处理请求的方法进行重写

  • 要么重写service方法
  • 要么重写doGet/doPost方法

6. ServletConfig和ServletContext

6.1. ServletConfig

  • 为Servlet提供初始配置参数的一种对象,每个Servlet都有自己独立唯一的ServletConfig对象
  • 容器会为每个Servlet实例化一个ServletConfig对象,并通过Servlet生命周期的init方法传入给Servlet作为属性
    在这里插入图片描述
    ServletConfig是一个接口
package jakarta.servlet;
import java.util.Enumeration;
public interface ServletConfig {
    String getServletName();
    ServletContext getServletContext();
    String getInitParameter(String var1);
    Enumeration<String> getInitParameterNames();
}
方法名作用
getServletName()获取<servlet-name>HelloServlet</servlet-name>定义的Servlet名称
getServletContext()获取ServletContext对象
getInitParameter()获取配置Servlet时设置的『初始化参数』,根据名字获取值
getInitParameterNames()获取所有初始化参数名组成的Enumeration对象
  • 定义Servlet
public class ServletA extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        ServletConfig servletConfig = this.getServletConfig();
        // 根据参数名获取单个参数
        String value = servletConfig.getInitParameter("param1");
        System.out.println("param1:"+value);
        // 获取所有参数名
        Enumeration<String> parameterNames = servletConfig.getInitParameterNames();
        // 迭代并获取参数名
        while (parameterNames.hasMoreElements()) {
            String paramaterName = parameterNames.nextElement();
            System.out.println(paramaterName + ":" + servletConfig.getInitParameter(paramaterName));
        }
    }
}
  • 配置Servlet
  <servlet>
       <servlet-name>ServletA</servlet-name>
       <servlet-class>com.wyb.servlet.ServletA</servlet-class>
       <!--配置ServletA的初始参数-->
       <init-param>
           <param-name>param1</param-name>
           <param-value>value1</param-value>
       </init-param>
       <init-param>
           <param-name>param2</param-name>
           <param-value>value2</param-value>
       </init-param>
   </servlet>
   <servlet-mapping>
       <servlet-name>ServletA</servlet-name>
       <url-pattern>/servletA</url-pattern>
   </servlet-mapping>

6.2. ServletContext

  • ServletContext对象又称为上下文对象,应用域对象
  • 容器会为每个app创建一个独立唯一的ServletContext对象
  • ServletContext对象为所有的Servlet共享
  • ServletContext为所有的Servlet提供初始配置参数
    在这里插入图片描述
  • 配置ServletContext参数
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd"
         version="5.0">

    <context-param>
        <param-name>paramA</param-name>
        <param-value>valueA</param-value>
    </context-param>
    <context-param>
        <param-name>paramB</param-name>
        <param-value>valueB</param-value>
    </context-param>
</web-app>
  • 在Servlet中获取ServletContext并获取参数
package com.wyb.servlet;
import jakarta.servlet.ServletConfig;
import jakarta.servlet.ServletContext;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Enumeration;

public class ServletA extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 从ServletContext中获取为所有的Servlet准备的参数
        ServletContext servletContext = this.getServletContext();
        String valueA = servletContext.getInitParameter("paramA");
        System.out.println("paramA:"+valueA);
        // 获取所有参数名
        Enumeration<String> initParameterNames = servletContext.getInitParameterNames();
        // 迭代并获取参数名
        while (initParameterNames.hasMoreElements()) {
            String paramaterName = initParameterNames.nextElement();
            System.out.println(paramaterName + ":" + servletContext.getInitParameter(paramaterName));
        }
    }
}
  • 其他API
    • 获取资源真实路径:无论项目的部署路径发生什么变化,都会动态获取项目运行时的实际路径: String realPath = servletContext.getRealPath("资源在web目录中的路径");
    • 获取项目的上下文路径:在部署进入tomcat时所使用的路径,可以解决一些后端页面渲染技术或者请求转发和响应重定向中的路径问题String contextPath = servletContext.getContextPath();
    • 域对象API
      • 域对象: 用于存储和传递数据的对象,传递数据不同的范围,称之为不同的域,不同的域对象代表不同的域,共享数据的范围也不同
      • ServletContext:应用,ServletContext域:应用域,是webapp中最大的域,可以在本应用内实现数据的共享和传递
      • webapp中的三大域对象:应用域,会话域,请求域
        |
API功能解释
void setAttribute(String key,Object value);向域中存储/修改数据
Object getAttribute(String key);获得域中的数据
void removeAttribute(String key);移除域中的数据

7. HttpServletRequest

  • HttpServletRequest是一个接口,父接口是ServletRequest
  • HttpServletRequest是Tomcat将请求报文转换封装而来的对象,在Tomcat调用service方法时传入
  • HttpServletRequest代表客户端发来的请求,所有请求中的信息都可以通过该对象获得
    在这里插入图片描述

7.1. 常见API

  • 获取请求行信息相关(方式,请求的url,协议及版本)
API功能解释
StringBuffer getRequestURL();获取客户端请求的url
String getRequestURI();获取客户端请求项目中的具体资源
int getServerPort();获取客户端发送请求时的端口
int getLocalPort();获取本应用在所在容器的端口
int getRemotePort();获取客户端程序的端口
String getScheme();获取请求协议
String getProtocol();获取请求协议及版本号
String getMethod();获取请求方式
  • 获得请求头信息相关
API功能解释
String getHeader(String headerName);根据头名称获取请求头
Enumeration getHeaderNames();获取所有的请求头名字
String getContentType();获取content-type请求头
  • 获得请求参数相关
API功能解释
String getParameter(String parameterName);根据请求参数名获取请求单个参数值
String[] getParameterValues(String parameterName);根据请求参数名获取请求多个参数值数组
Enumeration getParameterNames();获取所有请求参数名
Map<String, String[]> getParameterMap();获取所有请求参数的键值对集合
BufferedReader getReader() throws IOException;获取读取请求体的字符输入流
ServletInputStream getInputStream() throws IOException;获取读取请求体的字节输入流
int getContentLength();获得请求体长度的字节数
  • 其他API
API功能解释
String getServletPath();获取请求的Servlet的映射路径
ServletContext getServletContext();获取ServletContext对象
Cookie[] getCookies();获取请求中的所有cookie
HttpSession getSession();获取Session对象
void setCharacterEncoding(String encoding) ;设置请求体字符集

8. HttpServletResponse

  • HttpServletResponse是一个接口,父接口是ServletResponse
  • HttpServletResponse是Tomcat预先创建的,在Tomcat调用service方法时传入
  • HttpServletResponse代表对客户端的响应,该对象会被转换成响应的报文发送给客户端,可以设置响应信息
    在这里插入图片描述

8.1. 常见API

  • 设置响应行相关
API功能解释
void setStatus(int code);设置响应状态码
  • 设置响应头相关
API功能解释
void setHeader(String headerName, String headerValue);设置/修改响应头键值对
void setContentType(String contentType);设置content-type响应头及响应字符集(设置MIME类型)
  • 设置响应体相关
API功能解释
PrintWriter getWriter() throws IOException;获得向响应体放入信息的字符输出流
ServletOutputStream getOutputStream() throws IOException;获得向响应体放入信息的字节输出流
void setContentLength(int length);设置响应体的字节长度,其实就是在设置content-length响应头
  • 其他API
API功能解释
void sendError(int code, String message) throws IOException;向客户端响应错误信息的方法,需要指定响应码和响应信息
void addCookie(Cookie cookie);向响应体中增加cookie
void setCharacterEncoding(String encoding);设置响应体字符集

9. 请求转发和响应重定向

  • 请求转发和响应重定向是web应用中,间接访问项目资源的两种手段,也是Servlet控制页面跳转的两种手段
  • 请求转发通过HttpServletRequest实现,响应重定向通过HttpServletResponse实现

9.1. 请求转发

在这里插入图片描述

9.2. 请求转发特点(面试题)

  • 通过HttpServletRequest对象获取请求转发器实现
  • 请求转发是服务器内部的行为,对客户端是屏蔽的
  • 客户端只发送了一次请求,客户端地址栏不变
  • 服务端只产生了一对请求和响应对象,这一对请求和响应对象会继续传递给下一个资源
  • 因为全程只有一个HttpServletRequset对象,所以请求参数和请求域中的数据可以传递
  • 请求转发可以转发给其他Servlet动态资源,也可以转发给一些静态资源以实现页面跳转
  • 请求转发可以转发给WEB-INF下受保护的资源
  • 请求转发不能转发到本项目以外的外部资源
  • ServletA
@WebServlet("/servletA")
public class ServletA extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //  获取请求转发器
        RequestDispatcher requestDispatcher = req.getRequestDispatcher("servletB");
        // 转发给一个视图资源 ok
        // RequestDispatcher requestDispatcher = req.getRequestDispatcher("welcome.html");
        // 转发给WEB-INF下的资源  ok
        // RequestDispatcher requestDispatcher = req.getRequestDispatcher("WEB-INF/views/view1.html");
        // 转发给外部资源   no
        // RequestDispatcher requestDispatcher = req.getRequestDispatcher("http://www.baidu.com");
        // 获取请求参数
        String username = req.getParameter("username");
        System.out.println(username);
        // 向请求域中添加数据
        req.setAttribute("reqKey","requestMessage");
        // 做出转发动作
        requestDispatcher.forward(req,resp);
    }
}
  • ServletB
@WebServlet("/servletB")
public class ServletB extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 获取请求参数
        String username = req.getParameter("username");
        System.out.println(username);
        // 获取请求域中的数据
        String reqMessage = (String)req.getAttribute("reqKey");
        System.out.println(reqMessage);
        // 做出响应
        resp.getWriter().write("servletB response");        
    }
}

9.3. 响应重定向

在这里插入图片描述

9.4. 响应重定向特点(面试题)

  • 响应重定向通过HttpServletResponse对象的sendRedirect方法实现
  • 响应重定向是服务端通过302响应码和路径,告诉客户端自己去找其他资源,是在服务端提示下的客户端的行为
  • 客户端至少发送了两次请求,客户端地址栏是要变化的
  • 服务端产生了多对请求和响应对象,且请求和响应对象不会传递给下一个资源
  • 因为全程产生了多个HttpServletRequset对象,所以请求参数和请求域中的数据不可以传递
  • 重定向可以是其他Servlet动态资源,也可以是一些静态资源以实现页面跳转
  • 重定向不可以到给WEB-INF下受保护的资源
  • 重定向可以到本项目以外的外部资源
  • ServletA
@WebServlet("/servletA")
public class ServletA extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 获取请求参数
        String username = req.getParameter("username");
        System.out.println(username);
        // 向请求域中添加数据
        req.setAttribute("reqKey","requestMessage");
        // 响应重定向
        // 重定向到servlet动态资源 OK
        resp.sendRedirect("servletB");
        // 重定向到视图静态资源 OK
        // resp.sendRedirect("welcome.html");
        // 重定向到WEB-INF下的资源 NO
        // resp.sendRedirect("WEB-INF/views/view1");
        // 重定向到外部资源 OK
        // resp.sendRedirect("http://www.baidu.com");
    }
}
  • ServletB
@WebServlet("/servletB")
public class ServletB extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 获取请求参数
        String username = req.getParameter("username");
        System.out.println(username);
        // 获取请求域中的数据
        String reqMessage = (String)req.getAttribute("reqKey");
        System.out.println(reqMessage);
        // 做出响应
        resp.getWriter().write("servletB response");
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Qi妙代码

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值