Servlet

Servlet使用来接受、处理、反馈用户请求的

类似于SpringBoot中的 Controller

虽然,现在写 SSM,SpringBoot,SpringCloud,都看不到Servlet了,但是 SpringMVC的底层,就是封装了Servlet,所以,如果想了解SpringMVC的作用原理,那对Servlet的学习,是必不可少的!

这里提个醒,要想学号Servlet,一定要对http协议,有一个比较深入的了解,推荐去看《图解http》,就是一本小册子,几个小时就能看完。Servlet中的很多操作,都是对 http 的封装,如果对 http 不了解的话,那学起来,会感到云里雾里的!(第一次学习)

Maven依赖

<!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>3.1.0</version>
    <scope>provided</scope>
</dependency>

使用

1. 继承 HttpServlet

public class HelloServlet extends HttpServlet 

2. 重写 doGet 和 doPost方法

public class HelloServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.doGet(req, resp);
    }

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

3. 在Web.xml中,写访问地址和Servlet的映射

前端访问到我们定义的URL后,后端会使用反射的形式,创建Servlet对象,从而让我们能够使用Servlet

<servlet>
        <servlet-name>HelloServlet</servlet-name>
        <servlet-class>top.faroz.servlet.HelloServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>HelloServlet</servlet-name>
        <url-pattern>/hello</url-pattern>
    </servlet-mapping>

4. 测试

  • 我们写一个前端页面,执行get 和 post

要注意,前端的访问路径,不能加 /

<body>
    <h1>这是首页</h1>

    <a href="hello">执行get</a>

    <form action="hello" method="post">
        <button type="submit">执行post</button>
    </form>
</body>
  • 修改Servlet类,接受我们的请求
public class HelloServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("执行了doGet方法");
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("执行了doPost方法");
    }
}
  • 点击按钮,执行请求

image-20210513144435830

Servlet API讲解

image-20210513153322266

Servlet全局对象

ServletContext

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

        /**
         * 这是一个Servlet的全局对象
         * 无论是长连接还是短连接,都可以获取存储在这个全部对象中的信息
         */
        ServletContext servletContext = req.getServletContext();
    }

Servlet 生命周期(重要

下面,给出一张流程图

image-20210513153616308

何时创建?

当我们第一次向这个Servlet发送请求的时候,创建

这个Servlet是单例模式,在服务器一次执行的过程中,只会创建一次

我们看不到其显示的创建过程,因为,Servlet的创建,是通过反射实现的

何时销毁?

当我们关闭服务器(Tomcat)的时候,才会销毁

Servlet常用方法

请求

常用方法
  1. String getParameter(String name)

    根据表单组件名称获取提交数据,返回值是String 注:服务器在接收数据时使用字符串统一接收

  2. String[ ] getParameterValues(String name)

    获取表单组件对应多个值时的请求数据

  3. void setCharacterEncoding(String charset)

    指定每个请求的编码(针对post请求才起作用)

    post 在传输中文的时候,会出现乱码问题

    但是有趣的是,用 get 方法,向服务器传值,不会出现乱码问题

    示例:

    @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            req.setCharacterEncoding("utf-8");
            Map<String, String[]> params = req.getParameterMap();
            System.out.println("doPost-->"+params.get("name")[0]+"  "+params.get("password")[0]);
        }
    

    image-20210513161851008

  4. RequestDispatcher getRequestDispatcher(String path)

    –跳转⻚面
    返回一个RequestDispatcher对象,该对象的forward( )方法用于转发请求

    关于转发和重定向的区别,后面会讲

    因为转发是在服务器端进行的,所以,肯定是要在 resp 给客户端前进行的,所以,这个方法,只有 req 才有

    示例:

    request.getRequestDispatcher("../success.jsp").forward(request,response);
    
  5. 存值 request.setAttribute(“key”,value)

    前端给后端传值: req.getParameter()

    后端给前端传值: req.setAttribute(“key”,value)

    request 存值,是单次请求有效的

/**
	* 前端给后端传值: req.getParameter()
	* 后端给前端传值: req.setAttribute("key",value)
	*
	* request 存值,是单次请求有效的
	*/
String haha="呵呵呵呵呵";
req.setAttribute("haha",haha);
  1. 取值 request.getAttribute("key”); //取值后需要向下转型

    注意,我们之前提到,request 存值,是单次请求有效的,那又怎么能通过 req 获取值?

    这是因为,这个方法,是在转发中,才有效的

    示例:

    String a1=(String)request.getAttribute("uname");
    
补充

方式1:

通过表单 get/post提交(一般我们都用post)

方式2:

通过a标签发送数据(get提交)
这里的key值=表单元素的控件名,value值=表单中控件的value属性值 注:第一个参数使用?拼接,之后的参数使用&拼接,获取数据还是通过 String
name=request.getParameter(“name”);

方式3:

通过地址栏直接拼接-get请求

方式4:

js提交数据-get请求
location.href=“目标请求?key=value&key=value”

注:方式2/3都属于get提交方式,表单提交可以使用get、post提交方式

get 和 post 的区别(重点
  1. 传输方式:

get,一般是用url拼接参数的方式,传递参数,所以,会在地址栏显示的展示用户输入的数据,而且 url 中的字符,是使用的ascii编码,而非 unicode 的,所以非ASCII字符都要编码之后再传输。

post,会把请求的数据,放在 http 数据包中,所以,在地址栏是看不到的,因此,安全性也比 get 高

  1. 传输数据大小

get, 是通过 url 传值的,url 并没有设置长度上限。但是,各个浏览器,都会对 url 有自己的长度上限,所以,get 传输的数据大小,取决于浏览器给的 url 长度上限

post,理论上没有数据传输上限,但是,各个服务器会规定对POST提交数 据大小进行限制,Apache、IIS都有各自的配置。

  1. 安全性

POST的安全性比GET的高。这里的安全是指真正的安全,而不同于上面GET提到的安全方法中的安全, 上面提到的安全仅仅是不修改服务器的数据。比如,在进行登录操作,通过GET请求,用户名和密码都 会暴露再URL上,因为登录⻚面有可能被浏览器缓存以及其他人查看浏览器的历史记录的原因,此时的 用户名和密码就很容易被他人拿到了。除此之外,GET请求提交的数据还可能会造成Cross-site request frogery攻击

乱码问题

get 是不会有乱码问题的,Tomcat 8 以后,都是自动对 get 进行编码转换

所以,我们只要关注 post 的乱码问题即可

响应

  1. void addCookie(Cookie var1)

    给这个响应添加一个cookie

  2. void sendRedirect(String var1)

    发送一条响应码,将浏览器跳转到指定的位置

  3. PrintWriter getWriter()

    获得字符流,通过字符流的write(String s)方法可以将字符串设置到response 缓冲区中,随后Tomcat会将response缓冲区中的内容组装成Http响应返回给浏览器端。

    这个,可以用来传送序列化后的对象信息

  4. setContentType()

    设置响应内容的类型

Session

概念

关于Session,我之前写了一个 cookie 和 session 的对比,里面详细阐明了二者的内容和区别,这里,只介绍 Servlet 中 Session 的操作

对于是在不知道 session 是什么的,只要记住,session 是服务器为用户分配的,服务器中的一小片空间。我放一个图,大伙就清楚了:

image-20210422162950918

常用方法

//获取session对象
HttpSession session = req.getSession();
//在session中设置值
session.setAttribute("haha","ha");
//获取session值
session.getAttribute("haha");
//移除session值
session.removeAttribute("haha");
//获取sessionId
String id = session.getId();
System.out.println("sessionId:"+id);

要是看过我写的Session和cookie相关的博客,就知道,这里的SessionID,是和浏览器(客户端相关的),不同的客户端,有不同的SessionId

image-20210513230034915

Session失效方式

方式1:

session.setMaxInactiveInterval(10*60);//设置有效时间为10分钟

方式2:

修改web.xml

<session-config>
	<session-timeout>10</session-timeout>//单位:分钟 
</session-config>

小结:

(1)invalidate() (2)removeAttribute(“key”) (3)直接关闭浏览器。

获得初始化参数

我们之前解决乱码问题,是使用request.setCharacterEncoding("utf-8");,但是request.setCharacterEncoding("utf-8");代码的耦合度太高,不便于后期维护修改。可以通过初始化参数实现

其实,初始化参数,和配置文件的使用有点类似。

我们如果要使用,要在Servlet重写的 init()方法中,获取初始化参数,这样,在这个Servlet的整个生命周期中,就可以一直使用这个初始化参数了

当前Servlet中有效

  1. web.xml定义
 <servlet>
    <servlet-name></servlet-name>
    <servlet-class></servlet-class>
    <init-param>
       <param-name>encoding</param-name>
       <param-value>utf-8</param-value>
    </init-param>
</servlet>
  1. servlet中获得初始化参数,重写init()方法
 public void init(ServletConfig config) throws ServletException {
      encoding= config.getInitParameter("encoding");
}

全局有效

  1. 定义,context-param是和servlet标签同级别
 <context-param>
   <param-name>encoding</param-name>
   <param-value>utf-8</param-value>
  </context-param>
  1. 获得数据
 @Override // 请求->init()->service()->doget/dopost->destory();
public void init(ServletConfig config) throws ServletException {
  //
  encoding=config.getServletContext().getInitParameter("encoding");
}

有什么用

设置初始化参数后,我们的Servlet就可以在任意位置获取

这样,如果我们希望修改编码方式,只要修改 web.xml文件即可

注解

注解,只有在 Servlet 3 以上可以用

Servlet 设置的话,无非就是 请求地址、别名(可有可无)、初始化参数、和启动优先级

@WebServlet(name = "student", urlPatterns = "/stu",initParams = {
        @WebInitParam(name = "name",value = "faro_z"),
        @WebInitParam(name = "name",value = "dio"),
},loadOnStartup = 1)
public class StudentServlet extends HttpServlet {

    @Override
    public void init(ServletConfig config) throws ServletException {
        System.out.println("我想看看,加注解的Servlet,会不会自动加载");
        config.getInitParameter("name");
    }

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

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

注意:

  1. loadOnStartup属性:

    标记容器是否在启动应用时就加载Servlet,默认不配置或数值为负数时表示客 户端第一次请求Servlet时再加载;0或正数表示启动应用就加载,正数情况下,数值越小,加载该 Servlet的优先级越高;

Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐