Servlet

本文对Servlet的基础知识进行介绍,希望对您有所帮助

一.HTTP协议

1.1 介绍

​ 超文本传输协议,客户端请求和相应的标准协议,这个协议详细规定了浏览器和万维网服务器之间的互相通信规则。

请求协议 和 响应协议

1.2 书写格式

1.3 协议特点

  • 支持客户/服务器模式

  • 简单快捷

  • 灵活 允许传输任意类型的数据对象

  • 无连接 每次连接只处理一个请求 收到应答后即断开连接 节省时间

  • 无状态 没有记忆能力,如果后续处理需要前面的信息则它必须重新传

1.4 HTTP请求

​ 请求行 第一行

​ 请求方式 get/post

​ 请求地址

​ 请求版本

​ 请求头 键值对

​ Host 当前域名

​ Connection:keep-alive 保持存活状态

​ User-Agent 表明浏览器数据

​ Accept 接受类型

​ 请求正文 get请求时并到地址栏上

​ post请求时的Form Data

1.5 HTTP响应

​ 状态行

​ 协议版本 响应状态码 以及 其说明(OK)

​ 响应头

​ 响应正文

​ 浏览器中看到的

1.6 消息头

​ 每一个报头域 名字+”:”+空格+值

​ 请求头

Referer 说明请求从哪来 从一个页面到另一个页面会显示

​ 用处:百度设置广告 邀请用户链接 防盗链

​ 响应头

Location 重定向[更换域名操作]

Refresh 自动跳转

 **案例:定时跳转案例 webstorm_code/servlet/定时跳转.html**
1
<meta http-equiv="refresh" content="3;url=http://www.google.com">

二. Tomcat

2.1 介绍

​ 免费开源的轻量级web服务器

​ 性能稳定 中小型系统使用多

2.2 目录结构

2.3 部署方式

  • 直接将项目放在webapps里

  • 配置conf/server.xml

  • 在conf/Catalina/localhost创建任意名称的xml文件

三. servlet基础

3.1 介绍

​ servlet是server和applet的缩写 服务端小程序

​ servlet本质上也是java类,但要遵循他自己的规范,没有main方法,他的创建和,使用,销毁都由Servlet容器进行管理(如:tomcat)

​ 提供了servlet功能的服务器叫做servlet容器(Tomcat,jetty,weblogic server,jboss等)

3.2 规范

三种实现方式 案例实现01 02 03

  • 继承HttpServlet类
  • 继承GenericServlet类
  • 实现Servlet接口

3.3 重写service方法

​ 专门用来处理请求

​ 通过流输出数据到浏览器

3.4 设置注解

一次只用一种 切记路径中的斜杠记得写

1
2
3
@WebServlet("/ser01")
@WebServlet(name = "kai1",value = "/ser01")
@WebServlet(name = "kai1",value = {"/ser01","/ser02"})

3.5 工作流程

3.6 doGet和doPost

案例实现04

​ 实际上重写Service更方便,通过调用会自动根据请求方式处理

3.7 生命周期

案例实现05

​ init:系统方法 当请求到达servlet容器时,servlet容器会判断该 Servlet对象是否存在,不存在才会调用创建实例

​ service:当有请求到达时调用 可以被多次调用

​ destroy:当服务器关闭或应用程序停止时调用该方法,只调用一次

  • web客户端向servlet容器发出http请求
  • servlet容器接收web客户端的请求
  • servlet容器创建一个HttpServletRequest对象,将web客户端请求的信息封装到这个对象中
  • Servlet容器创建一个HttpServletResponse对象
  • Servlet容器调用HttpServlet对象Service方法,把Request与Response作为参数,传给HttpServlet
  • HttpServlet调用HttpServletRequest对象的有关方法,获取http请求信息
  • HttpServlet调用HttpServletResponse对象有关的方法,生成响应数据
  • Servlet容器把HttpServlet的响应结果传给web客户端

四. 常见对象

4.1 HttpServletRequest对象

​ 主要作用是接收客户端发送过来的请求信息,例如:请求的参数,发送的头信息等都属于是客户端发来的信息,service方法中的形参接受的是HttpServletRequest接口的实例化对象,表示该对象主要用在http协议上

4.1.1 方法介绍

案例实现06

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
//获取请求完整路径 http开始 参数前结束
String url = req.getRequestURL()+"";
resp.getWriter().write("获取请求完整路径"+url);
//获取请求时部分路径 从项目的站点名开始 到 参数结束
String uri = req.getRequestURI();
resp.getWriter().write("\n获取请求时部分路径"+uri);
//获取请求时的参数字符串 从?开始到最后的字符串
String queryString = req.getQueryString();
resp.getWriter().write("\n获取请求时的参数字符串"+queryString);
//获取请求方式 get/post
String method = req.getMethod();
resp.getWriter().write("\n获取请求方式"+method);
//获取协议版本 http/1.1
String protocol = req.getProtocol();
resp.getWriter().write("\n获取协议版本"+protocol);
//获取项目站点名 项目对外访问路径
String webapp = req.getContextPath();
resp.getWriter().write("\n获取项目站点名"+webapp);
//获取指定名称的参数值
String uname = req.getParameter("name");
String upwd = req.getParameter("password");
resp.getWriter().write("\n用户名"+uname);
resp.getWriter().write("\n密码"+upwd);
//获取指定名称所有参数值 返回字符串数组
String[] hobbys = req.getParameterValues("hobby");
//判断数组是否为空
if(hobbys!=null&&hobbys.length>0){
for(String hobby:hobbys){
resp.getWriter().write("\n爱好"+hobby);
}
}
4.1.2 乱码问题

get请求 8之后不会乱码

post请求 解决乱码

1
req.serCharacterEncoding("UTF-8")
4.1.3 请求转发

案例实现ser07+ser08

​ 是一种服务器行为,当客户端请求到达后,服务器进行转发,此时会将请求对象进行保存,地址栏中的URL地址不会改变,得到响应后,服务器端再响应发送给客户端,从始至终只有一个请求发出

​ 服务端行为

地址栏不发生改变

​ 从始至终只有一个请求

​ 数据可以共享

还可以跳转到jsp或html 后台页面跳到前台

1
2
req.getRequestDispatcher("index.jsp").forward(req,resp);
req.getRequestDispatcher("index.html").forward(req,resp);
4.1.4 作用域

案例实现ser09+ser10

也可以跳到jsp

1
2
3
req.setAttribute(String name,String value);
req.getAttribute(String name);
req.removeAttribute(String name);

4.2 HttpServletResponse对象

​ 主要功能是用于服务器端的请求进行响应,将Web服务器处理后的结果返回给客户端,service()方法中形参接受的是HttpServletResponse接口的实例化对象,这个对象封装了向客户端发送数据,发送响应头,发送响应状态码的方法

4.2.1 响应数据

案例实现ser11

字符流和字节流

两者不能一起使用

1
2
3
4
PrintWriter writer = resp.getWriter();
writer.write("hello printwriter");
ServletOutputStream out = resp.getOutputStream();
out.write("hello outputstreeam".getBytes("UTF-8"));
4.2.2 响应乱码

字节流乱码

字符流乱码

​ 服务端客户端编码不一致 不支持中文

两种解决方法一致

1
2
3
4
5
6
7
```java
//设置编码格式
resp.setCharacterEncoding("UTF-8");
//设置客户端编码模式
resp.setHeader("content-type","text/html;charset=UTF-8");
//同时设置两者
resp.setContentType("text/html;charset=UTF-8");
1
2
3
4
5
6
7
8
9
10
11
12
13
14
##### 4.2.3 重定向

**案例实现ser12+ser13**

服务端指导 客户端行为

存在两次请求

地址栏会改变

req对象不共享

```java
resp.sendRedirect("...")
4.2.4 req和resp对比
请求转发 重定向
地址栏不会改变 地址栏会发生改变
只有一次请求 两次请求
req对象可以共享 不共享
服务端行为 客户端行为
地址只能是当前站点下,不能跨域 任何可以访问到的地址,可以跨域

4.3HttpSession对象

4.3.1 介绍

​ HttpSession 对象是servlet.http.HttpSession的实例,该接口只是一个纯粹接口,这是因为session本身就是属于HTTP协议的范畴

​ session的作用是标识了一次会话,或者说确认一个用户,并且一次会话(一个用户的多次请求)期间共享数据,我们可以通过req.getSession()方法,获取session对象.如果重新打开一个新的浏览器则无法获取之前设置的session

4.3.2 标识符等数据

标识符:唯一标识一次会话,每当请求到达服务器,如果开启了会话,服务器第一步会查看是否从客户端回传一个JSESSIONID的cookie,如果没有则创建一个新的session对象。

这里的JSESSIONID是一个特殊的cookie,添加到resp对象,响应给客户端,有效时间为关闭浏览器。

1
2
3
4
5
String id = session.getID();
String time = session.getCreationTime(); 创建时间
session.getLastAccessedTime(); 最后一次访问时间
session.isNew();
...
4.3.3 域对象

​ 请求转发 一次请求 session和req都能拿到

​ 重定向 两次请求 session能拿到 req失效

4.3.4 session销毁
  • 默认到期时间

    tomcat是30min 一旦有操作 session会重新计时

    修改默认时间需要到tomcat conf web.xml中修改

    1
    2
    3
    <session-config>
    <session-timeout>30</session-timeout>
    </session-config>
  • 自己设定到期时间

    1
    2
    session.setMaxInactiveInterval(...);
    session.getMaxInactiveInterval(...);
  • 立即销毁

    1
    session.invalidate();
  • 关闭浏览器失效

    底层cookie 默认关闭失效

  • 关闭服务器失效

4.4 ServletContext对象

4.4.1 介绍

每一个web项目只有一个 又称application对象

作用

  • 作为域对象来共享数据

  • 该对象保存了当前应用程序的相关信息

    例如:getServerInfo()获取当前服务信息

    ​ getRealPath(String path)获取资源的真实路径

4.4.2 获取和常用方法

案例实现con1

1
2
3
4
5
6
7
8
9
10
11
12
13
//通过req获取
ServletContext servletContext1 = req.getServletContext();
//通过session对象获取
ServletContext servletContext2 = req.getSession().getServletContext();
//通过ServletConfig对象获取
ServletContext servletContext3 = getServletConfig().getServletContext();
//直接获取
ServletContext servletContext4 = getServletContext();
//常用方法
//1.获取版本信息
String serverInfo = req.getServletContext().getServerInfo();
//2.获取项目真实路径
String realPath = req.getServletContext().getRealPath("/");
4.4.3 域对象

三大域对象

  • req域对象 用的最多

    在一次请求中有效 请求转发有效

  • session域对象

    一次会话有效 请求转发和重定向都有效

  • servletContext域对象

    整个应用程序都有效 服务器关闭失效

五. 文件上传和下载

5.1 上传

案例实现wen1+shangchuan.html

5.2 下载

​ 使用超链接时,如果遇到浏览器能够识别的资源,则会显示内容,如果遇到浏览器不能识别的资源,则会进行下载

案例实现shangchuan.html

1
2
<a href="download/1.txt">起的是查看效果</a>
<a href="download/1.txt" download="文档.txt">起的是下载效果</a>

download属性代表下载的名字

5.3 后台代码下载

案例实现wen2+shangchuan.html

6.1 介绍

​ 是浏览器提供的一种技术,通过服务器的程序能将一些只须保存在客户端,或者在客户端进行处理的数据,放在本地的计算机上,不需要通过网络传输,因而提高网页处理的效率,并且能够减少服务器的负载,但是由于cookie是服务器端保存在客户端的信息,所以安全性很差,例如保存密码

6.2 创建发送

1
2
3
4
//cookie 创建
Cookie cookie = new Cookie("name","kai");
//发送cookie对象
resp.addCookie(cookie);

6.3 cookie获取

1
2
3
4
5
6
7
8
9
//cookie获取 返回的是数组 需要遍历
Cookie[] cookies = req.getCookies();
if(cookies!=null && cookies.length>0){
for(Cookie cookie:cookies){
String name = cookie.getName();
String value = cookie.getValue();
System.out.println("名称:"+name+" "+"value:"+value);
}
}

6.4 到期时间

取值

  • 负数 默认-1 关闭浏览器失效
  • 0 表示删除cookie
  • 正整数 存储的秒数 就算重启客户端电脑也会存活 实际存在在硬盘上
1
2
3
Cookie cookie = new Cookie("name","kai");
cookie.setMaxAge(-1);
resp.addCookie(cookie);

6.5 注意点

  • 保持于当前浏览器中

  • 存中文会产生问题

    需要将中文URLEncoder进行编码

    获取时 URLDecoder进行解码

  • 同名问题 会覆盖原有

  • 存放数量问题 有上限

6.6 路径问题

  • 当前服务器下任何项目的任意资源都可获取cookie对象

    setPath(“/“)

  • 当前项目下的资源可获取Cookie对象

    setPath(“/s01”) 写当前项目或不写

  • 指定项目下的资源可获取cookie对象

    setPath(“/s02”)

  • 指定目录下的资源可获取Cookie对象

    setPath(“/s01/coo01”)

​ 当访问路径包含了cookie的路径时,则该请求将带上该cookie

​ 当路径设为s01,那么s01/coo01 也可以访问到

七. 其他实例

7.1 处理日期

使用SimpleDateFormat对象来格式化Date对象

案例实现time1

1
2
3
SimpleDateFormat ft = new SimpleDateFormat ("yyyy.MM.dd  hh:mm:ss E a ");
Date dNow = new Date();
ft.format(dNow);

7.2 点击计数

  • 在 init() 方法中初始化一个全局变量。
  • 每次调用 Service方法时,都++。
  • 如果需要,可以使用一个数据库表来存储全局变量的值在 destroy() 中。在下次初始化 Servlet 时,该值可在 init() 方法内被读取
  • 如果只想对一个 session 会话计数一次页面点击,使用 isNew() 方法来检查该 session 会话是否已点击过相同页面。
  • 可以通过显示全局计数器的值,来在网站上展示页面的总点击量。

案例实现

7.3 连接数据库

导jar包问题 官网下载

个人认为

启动mysql 管理员方式运行cmd net start mysql

navicat

这里我们直接实现点击计数的数存放到数据库中

连接数据库一般方法

  • 注册JDBC驱动器

    1
    Class.forName("com.mysql.cj.jdbc.Driver");
  • 打开连接

    1
    Connection con = DriverManager.getConnection(数据库路径,用户名,密码);
  • 执行sql语句

    1
    2
    3
    String sql = "SELECT shu FROM jishu";
    PreparedStatement sta = con.prepareStatement(sql);
    ResultSet rs = sta.executeQuery();
  • 获取处理数据

  • 关闭

    1
    2
    rs.close();
    sta.close();

7.4 登录

建表 2.sql 点击访问

架构

​ dao层

​ impl > UserDaoImpl

​ domain层 User类

​ util层 jdbcUtil类 连接数据库

​ servlet层 login register

案例实现+注册

思路:

  • servlet层获取到提交的数据

  • 执行查询数据库逻辑

    dao层

    • 初始化数据库
    • 执行sql语言
    • 得到匹配的数据
    • 返回User对象
  • 根据返回值判断是否登陆成功

  • 请求转发到success.jsp页面或者error.jsp页面

7.5 注册

​ 思路与登陆相似。。。


Servlet
http://kaikai12321.github.io/2022/10/02/Servlet/
作者
Hou Kai
发布于
2022年10月2日
许可协议