servlet


1. Servlet

  • 是一组web应用程序编程接口
  • 可以来实现动态web应用

image-20220122093604200


2. 创建一个我们的动态web项目

image-20220122093922987

image-20220122094020057

image-20220122094055482

image-20220122094154493

image-20220122094222801

image-20220122094348928

image-20220122094418960


3. 给项目进行打包

image-20220122094604036

image-20220122094701037

image-20220122095501118

image-20220122095603204

启动tomcat

1
startup.bat

我们发现一个很神奇的地方:

web01.war被自动解压了,我们就可以通过浏览器来访问我们的应用程序了;

image-20220122095807942


4. 我们编写第一个Servlet

image-20220122102231953


5. 给IDEA集成Tomcat

image-20220122102303051

image-20220122102336870

集成好Tomcat之后需要配置servlet的访问路径:

1
2
3
4
5
6
7
8
9
10
<!--配置servlet的访问路径-->
<servlet>
<servlet-name>servlet01</servlet-name>
<servlet-class>com.xzy.web01.Servlet01</servlet-class>
</servlet>

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

浏览器访问:

image-20220122104038817


6. Servlet的访问原理(很重要)

image-20220122113840989


7. HttpServlet对象

  • 是一个Sun公司提供的一个JavaEE规范的抽象类

  • Tomcat中集成了Servlet抽象类

  • 我们只需要引入Tomcat中的servlet.jar就可以使用了

  • Servlet对象是Tomcat通过反射来创建的;

  • Tomcat创建的Servlet对象是单例的

  • Servlet中的常用的操作

    1
    2
    3
    this.doGet();
    this.doPost();
    ...
  • Servlet中的service方法帮我们做了什么事?

    image-20220122144505813

image-20220122144650418

所以: 我们如果想统一的处理请求,就用service方法;

如果想针对不同的请求做不同的处理,则重写对象的doXXX()方法;但是重写这些方法之后一定不能调用父类的此方法;

img


8. HttpServletRequest对象

  • 是由Tomcat服务器帮我们创建的

  • Tomcat在全局只创建唯一的一个HttpServletRequest对象

  • HttpServletRequest对象封装的是”请求数据包“中的内容

  • 由Tomcat给我们进行请求数据包的封装,封装成一个HttpServletRequest对象,然后调用Servlet中的service(req,resp)方法,通过传递参数的形式交给我们开发者;我们就可以使用此对象,获取请求数据包中的内容了;

  • Tomcat下一次请求过来的时候,并不会重新创建一个HttpServletRequest对象,而是把里面的属性都清空,再封装新的请求数据包中的数据,然后通过方法回调给我们传递;

  • HttpServletRequest中常用的操作

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    //获取请求携带的参数数据
    System.out.println("name=" + req.getParameter("name"));

    //获取请求的URI对象(统一资源标识符)
    System.out.println("URI=" + req.getRequestURI());

    //获取请求的URL对象
    System.out.println("URL=" + req.getRequestURL());

    //获取请求的会话对象
    System.out.println("会话对象=" + req.getSession());

    //获取请求头对象
    System.out.println("User-Agent=" + req.getHeader("User-Agent"));

    //获取请求方式
    System.out.println("请求方式=" + req.getMethod());

    //获取请求的查询字符串
    System.out.println("QueryString=" + req.getQueryString());

    //获取远程地址
    System.out.println("RemoteAddr=" + req.getRemoteAddr());
    System.out.println("RemoteHost=" + req.getRemoteHost());
    System.out.println("RemotePort=" + req.getRemotePort());

    //Servlet的上下文(Context)对象
    System.out.println("Context对象=" + req.getServletContext());
    }

9. HttpServletResponse对象

  • 由Tomcat创建的封装Http响应数据包的对象

  • 我们在开发的过程中调用HttpServletResponse对象提供的方法,然后把HttpServletResponse交给Tomcat,Tomcat把其中的属性拿出来,组装成响应数据包,返回给客户端(浏览器);

  • HttpServletResponse常用的操作

    1
    2
    3
    4
    5
    //设置响应头数据
    resp.setHeader("uname", "admin");

    //给响应数据包的响应实体设置内容
    resp.getWriter().println("hello");

10. 响应中字符串的编码问题

1
2
3
4
5
6
7
8
9
//设置响应头数据
resp.setHeader("uname", "admin");

//resp.setHeader("Content-Type", "text/html;charset=UTF-8");
//下面的写法是上面的简写
resp.setContentType("text/html;charset=UTF-8");
//给响应数据包的响应实体设置内容(默认响应使用的编码为latin1-ISO8859-1)
resp.setCharacterEncoding("UTF-8");
resp.getWriter().println("<h1>hello你好</h1>");

11. Mime类型

1
2
3
4
5
6
7
8
text/html; 网页类型
application/json; json字符串类型
image/gif;
image/jpeg;
text/plain; 原生文本类型
application/x-javascript; js文件类型
text/css; css类型
....

12. ServletContext对象

  • 这是一个Servlet的上下文的对象

  • 由Tomcat创建的,Tomcat会为我们的应用创建一个唯一的ServletContext的对象,代表我们的应用上下文对象的获取

    1
    2
    //获取上下文对象
    ServletContext servletContext = this.getServletContext();

13. Tomcat中的静态资源的访问

image-20220122163054176


14. 练习

城市-学校(二级联动)

  • 获取城市列表接口
  • 根据城市id,列表获取学校列表接口
  • 根据城市id和学校id查询学校的详细信息的接口; 西安交通大学—西安市

使用技术:

  • html css js es6 vue axios
  • tomcat servlet request response
  • mysql
  • jdbc
  • dbutils
  • druid
  • fastjson

15. Servlet中的生命周期

image-20220601213937679

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
 /**
* 在整个应用程序的生命周期中只调用一次(在第一次访问该Servlet时由Tomcat进行调用)
*
* @param config 对Servlet配置的信息的封装对象
* @throws ServletException
*/
@Override
public void init(ServletConfig config) throws ServletException {
super.init(config);
System.out.println("servlet01......init()");
System.out.println("myname=" + config.getInitParameter("myname"));
System.out.println("myage=" + config.getInitParameter("myage"));
}

/**
* 在应用程序结束时由Tomcat调用(一般在这里编写清理资源的操作)
*/
@Override
public void destroy() {
System.out.println("servlet01....destory");
}

/**
* 每次请求都会调用
*
* @param req
* @param resp
* @throws ServletException
* @throws IOException
*/
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("servlet01.....service");
}

16. Servlet中的配置信息的获取

image-20220123111850260


17. 获取上下文中的配置信息

上下文对象是ServletContext对象;

image-20220123112542780


18. 请求转发与请求重定向

18.1 请求转发

image-20220123113037503

  • 请求转发是请求的服务器内部转发,对于客户端而言没有感知的
  • 地址栏不会发生变化
  • 服务器内部的请求转发用的是同一个请求对象(请求数据包)
1
2
//请求转发
req.getRequestDispatcher("/servlet04").forward(req, resp);

18.2 请求重定向

image-20220123113938245

  • 请求重定向其实是和服务器无关的
  • 浏览器如果遇到了302响应码+Location响应头就会自动的发生请求转跳转(是浏览器的一种机制)
  • 请求重定向,其实已经是两个请求了
  • 浏览器的地址栏会发生变化
1
2
3
4
5
//请求重定向
//resp.setStatus(302);
//resp.setHeader("Location", "/servlet04");
//一般不建议直接使用302+Location来写,我们可以使用现成的api
resp.sendRedirect("/servlet04");

19. Cookie

  • Cookie是浏览器存储数据的一种机制

  • 可以在服务器响应一个响应头(Set-Cookie:xxx),浏览器识别到Set-Cookie的响应头之后就能保存数据;

  • 可以在服务端设置响应头:目的为了让浏览器保存数据;

  • 浏览器访问某个域名下的服务的时候,会检查本地Cookie的存储域中在此域名下有无Cookie信息,如果有,则通过请求头 Cookie: xxx进行携带;

  • Cookie是可以设置有效期,设置了有效期的Cookie,即使浏览器关闭,但是有效期还没有失效的情况下,重新打开浏览器依然有效;

    1
    2
    3
    4
    5
    6
    //底层就是这么来干的,但是这种写法对开发者不友好
    //resp.setHeader("Set-Cookie", "myname=admin");
    Cookie cookie = new Cookie("myname", "admin");
    //setMxAge(有效期秒数) -1代表浏览器关闭时有效
    cookie.setMaxAge(1 * 60 * 60 * 24);
    resp.addCookie(cookie);

20. Mvc的架构

image-20220123153940242


21. Web程序的热部署

我们现在每修改一个地方都需要进行一次重启,这太费劲了;Idea中支持项目的热部署

首先打开idea自带的热编译功能(在web应用运行的过程中进行编译)

image-20220123154515779

22. Session会话技术

  • Cookie是浏览器存储数据的一种机制
  • Session是服务器存储数据的一种机制
1
2
//服务器会判断有无此session对象,有则获取并返回,无此对象则创建并返回,创建之后在内存中会有一个session对象,并且每一个session对象都有唯一的一个id,我们称为SessionId;
HttpSession session = req.getSession();

session.invalidate() 是将session设置为失效,一般在退出时使用,但要注意的是:session失效的同时浏览器会立即创建一个新的

session的,你第一个session已经失效了,所以调用它的getAttribute方法时候一定会抛出NullPointerException

23. 服务器是如何知道浏览器是否关闭窗口?

服务器是通过浏览器携带过来的Cookie信息进行判断的

响应头:

image-20220125105854947

请求头:

image-20220125105928380


24. Session对象什么时候失效?

  • 默认Session对象的失效时间为浏览器关闭时失效(底层是基于Cookie进行判断的)

  • 当然Session也可以设置有效期

    1
    2
    //设置session的有效期为10s,10s后失效
    session.setMaxInactiveInterval(10);

25. Session携带数据

1
2
3
HttpSession session = req.getSession();
//session携带数据
session.setAttribute("myname", "admin");
1
2
3
//session获取数据
HttpSession session = req.getSession();
System.out.println(session.getAttribute("myname"));

26. Servlet中的域对象

域: 作用域 范围

  • ServletContext: 整个应用的域对象
  • HttpSession: 一个会话的域对象
  • HttpServletRequest: 请求的域对象

27. IDEA集成了Tomcat的原理?

Idea集成了Tomcat,但是:

image-20220125114707187

Idea并不会污染我们自己安装的Tomcat,而会克隆一个副本;


28. Servlet接收请求参数

28.1 Servlet接收Get请求参数

image-20220126094646952

image-20220126094658090


28.2 Servlet接收Post请求参数

image-20220126095421495

image-20220126095433688


29. Get请求乱码问题

老版本中的Tomcat,发送Get请求,如果有中文参数,则会出现乱码问题,需要设置请求的编码方式

1
2
//设置查询参数中的编码方式
req.setCharacterEncoding("utf-8");

而在新版本中已经没有乱码问题了,无需理会;


30. Post请求的乱码问题

POST请求,如果在请求实体中携带数据,一定会出现乱码问题的;

POST请求实体中的编码,使用时IOS8859-1的编码方式,我们需要使用UTF-8重新编码;

Post请求乱码:先getBytes(StandardCharsets.ISO_8859_1)解码,再new String编码

1
name= new String(name.getBytes(StandardCharsets.ISO_8859_1),"UTF-8");

31. Servlet中的请求过滤器

image-20220126111318110

Servlet中的过滤器实现 Filter接口

Servlet中的过滤器都是基于Url的过滤

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class Filter01 implements Filter {
/**
* 应用程序启动时就会调用初始化方法
*
* @param filterConfig
* @throws ServletException
*/
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("Filter01初始化了....");
}

/**
* @param servletRequest 请求对象
* @param servletResponse 响应对象
* @param filterChain 过滤器链对象
* @throws IOException
* @throws ServletException
*/
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("filter01..");
filterChain.doFilter(servletRequest, servletResponse);
}

@Override
public void destroy() {
System.out.println("Filter01过滤器销毁了....");
}
}

web.xml

1
2
3
4
5
6
7
8
9
<filter>
<filter-name>filter01</filter-name>
<filter-class>com.xzy.web04.filter.Filter01</filter-class>
</filter>

<filter-mapping>
<filter-name>filter01</filter-name>
<url-pattern>/city/servlet01</url-pattern>
</filter-mapping>

基于url的过滤器的url-pattern的写法:

  • 过滤具体的url请求

    1
    <url-pattern>/city/servlet01</url-pattern>
  • 基于 * 通配符的过滤

    1
    <url-pattern>/city/*</url-pattern>
  • 基于固定后缀的过滤

    1
    <url-pattern>*.do</url-pattern>

32. 一个请求多个过滤器过滤

多个过滤器过滤到同一个请求:

image-20220126142419247

1
2
3
4
5
6
7
8
9
10
11
12
<filter-mapping>
<filter-name>filter02</filter-name>
<url-pattern>*.do</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>filter01</filter-name>
<url-pattern>/city/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>filter03</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

以上的这三个过滤器,能过滤到同一个请求,那么这三个过滤器就组成了一个过滤器链,FilterChain对象,调用FilterChain对象的doFilter()方法,能放行请求,让请求进入

下一个过滤器,知道执行到过滤器链的尾部,放行的话则执行目标的Servlet;

doFilter之后的业务,等doFilter放行之后,访问到目标的servlet之后,再逆着执行一遍;


33. 编写一个字符集处理的过滤器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package com.xzy.web04.filter;


import javax.servlet.*;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.charset.StandardCharsets;

public class NameHandlerFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
String name = servletRequest.getParameter("name");
//解码操作
byte[] bytes = name.getBytes(StandardCharsets.ISO_8859_1);
//编码操作
name = new String(bytes, 0, bytes.length, StandardCharsets.UTF_8);
//给request域对象设置数据
servletRequest.setAttribute("name", name);
// servletResponse.setCharacterEncoding("UTF-8"); 等同于下面直接在MIME类型之后跟上字符集作用是等同的;
//以json的形式返回
servletResponse.setContentType("application/json;charset=utf-8");
filterChain.doFilter(servletRequest, servletResponse);
}

@Override
public void destroy() {

}
}

34. Servlet中的监听器

Servlet中的监听器主要是监听三个域对象的创建销毁,和其中的数据的变化:

  • ServletContext

  • HttpSession

  • HttpServletRequest

image-20220126153933115

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
package com.xzy.web04.listener;

import javax.servlet.*;
import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionBindingEvent;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;

/**
* 监听Context的创建和销毁
*/
public class MyListener implements ServletContextListener, ServletContextAttributeListener, HttpSessionListener, HttpSessionAttributeListener, ServletRequestListener, ServletRequestAttributeListener {
@Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
System.out.println("context的创建");
}

@Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {
System.out.println("context的销毁");
}


@Override
public void attributeAdded(ServletContextAttributeEvent servletContextAttributeEvent) {
System.out.println(servletContextAttributeEvent.getName() + "属性被添加了===>" + servletContextAttributeEvent.getValue());
}

@Override
public void attributeRemoved(ServletContextAttributeEvent servletContextAttributeEvent) {
System.out.println(servletContextAttributeEvent.getName() + "属性被移除了===>" + servletContextAttributeEvent.getValue());
}

@Override
public void attributeReplaced(ServletContextAttributeEvent servletContextAttributeEvent) {
System.out.println(servletContextAttributeEvent.getName() + "属性被替换了===>" + servletContextAttributeEvent.getValue());
}

@Override
public void sessionCreated(HttpSessionEvent httpSessionEvent) {
System.out.println("session被创建了");
}

@Override
public void sessionDestroyed(HttpSessionEvent httpSessionEvent) {
System.out.println("session对象被销毁了");
}

@Override
public void attributeAdded(HttpSessionBindingEvent httpSessionBindingEvent) {
System.out.println("session中添加了属性");
}

@Override
public void attributeRemoved(HttpSessionBindingEvent httpSessionBindingEvent) {
System.out.println("session中移除了属性");
}

@Override
public void attributeReplaced(HttpSessionBindingEvent httpSessionBindingEvent) {
System.out.println("session中替换了属性");
}

@Override
public void attributeAdded(ServletRequestAttributeEvent servletRequestAttributeEvent) {
System.out.println("reqeuest中添加了属性");
}

@Override
public void attributeRemoved(ServletRequestAttributeEvent servletRequestAttributeEvent) {
System.out.println("reqeuest中移除了属性");
}

@Override
public void attributeReplaced(ServletRequestAttributeEvent servletRequestAttributeEvent) {
System.out.println("reqeuest中替换了属性"+servletRequestAttributeEvent.getName()+"==="+servletRequestAttributeEvent.getValue());
}

@Override
public void requestDestroyed(ServletRequestEvent servletRequestEvent) {
System.out.println("请求销毁");
}

@Override
public void requestInitialized(ServletRequestEvent servletRequestEvent) {
System.out.println("请求创建");
}
}

35. 新版本servlet3.x之后的注解开发

注册Servlet:

1
2
3
@WebServlet("/servlet10")
@WebServlet(value = "/servlet10")
@WebServlet(urlPatterns = "/servlet10")

注册Filter:

1
2
3
@WebFilter("/*")
@WebFilter(value ="/*")
@WebFilter(urlPatterns ="/*")

注册Listener:

1
@WebListener

文章作者: Yang Shiyu
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Yang Shiyu !
  目录