Servlet

1、Servlet

Servlet 是 Server 与 Applet 的缩写,是服务端⼩程序的意思。使⽤ Java 语⾔编写的服务器端程序, 可以像⽣成动态的 WEB ⻚,Servlet 主要运⾏在服务器端,并由服务器调⽤执⾏, 是⼀种按照 Servlet 标准来开发的类。 是 SUN 公司提供的⼀⻔⽤于开发动态 Web 资源的技术。(⾔外之意:要实现 web 开发,需要实现 Servlet 标准)

Servlet 本质上也是 Java 类,但要遵循 Servlet 规范进⾏编写,没有 main()⽅法,它的创建、使⽤、 销毁都由 Servlet 容器进⾏管理(如 Tomcat)。(⾔外之意:写⾃⼰的类,不⽤写 main ⽅法,别⼈⾃动 调⽤)

Servlet 是和 HTTP 协议是紧密联系的,其可以处理 HTTP 协议相关的所有内容。这也是 Servlet 应⽤ ⼴泛的原因之⼀。 提供了 Servlet 功能的服务器,叫做 Servlet 容器,其常⻅容器有很多,如 Tomcat, Jetty, WebLogic Server, WebSphere, JBoss 等等。

2、Servlet的实现

1、继承HTTPServlet类

public class Servlet01 extends HttpServlet {

}

2、重写service方法

service放专门用来处理请求

public class Servlet01 extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 处理请求
    }
}

3、添加注解,设置访问路径

@WebServlet("/ser01")
public class Servlet01 extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 处理请求
    }
}

3、Servlet的生命周期

servlet中没有main方法,不能独立运行,servlet的运行完全由servlet引擎来控制调度。

1、实例和初始化

servlet只有在第一次访问的时候才会创建实例,而且只会执行一次

当请求到达时,查找该servlet对象是否存在,不存在则创建实例并初始化。

2、就绪

可以多次调用执行

请求到达,则自动调用service方法,该方法在servlet的生命周期中可以多次调用

3、销毁

只会执行一次

服务器关闭,会自动销毁servlet实例

@WebServlet("/ser05")
public class Servlet05  extends HttpServlet {
    /*
    就绪/服务方法(处理请求)
    系统方法,自动调用
    当请求到达Servlet容器的时候自动调用该方法
    可以重复调用
     */
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("Servlet05");
    }


    /*
    初始化方法
    系统方法,自动调用
    当请求到达Servlet容器的时候,Servlet容器判断是否有该对象存在,不存在则自动创建并实例化
    该方法只会被执行一次
     */

    @Override
    public void init(ServletConfig config) throws ServletException {
        System.out.println("Servlet创建");
    }

    /*
    销毁方法
    系统方法,自动调用
    当服务器关闭时或结束程序时自动调用该方法
    方法只会执行一次
     */
    @Override
    public void destroy() {
        System.out.println("Servlet销毁");
    }
}

4、Servlet的工作流程

在这里插入图片描述

  1. WebClient向Servlet容器发出请求
  2. Servlet容器接收WebClient的请求
  3. Servlet容器创建HttpServletRequest对象,把webClient的请求信息封装到这个对象中
  4. Servlet容器创建HttpServletResponet对象
  5. Servlet容器调用httpServlet的service方法,将request和respone两个对象当作参数传递给HttpServlet
  6. HttpServle调用HttpServletRequest对象的有关方法获取请求信息
  7. HttpServle调用HttpServletResponet对象的有关方法生成响应数据
  8. Servle容器把HttpServlet的响应结果传递给WebClient

5、HttpServletRequest

HttpServletRequest对象,使用该对象获取WebClient传来的数据

5.1、常用方法

1、获取请求的完整的URL

// 获取请求的完整的URL
String url = req.getRequestURL()+"";
System.out.println("请求的完整的URL:"+url);

2、获取请求的URI

// 获取请求的URI
String uri = req.getRequestURI();
System.out.println("请求的URI:"+uri);

3、获取请求的站点名

// 获取请求的站点名
String webName = req.getContextPath();
System.out.println("请求的站点名:"+webName);

4、获取请求方式

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

5、获取请求的所有参数

// 获取请求的所有参数
String queryString = req.getQueryString();
System.out.println("请求的所有参数:"+queryString);

6、获取请求协议

// 获取请求协议
String protocol = req.getProtocol();
System.out.println("请求协议:"+protocol);

5.2、获取请求参数

不管前台传来什么数据,在servlet中都是字符串

1、getParameter

获取指定name的一个数据

String uname = req.getParameter("uname");

2、getParameterValues

获取指定name的多个数据,返回字符串数组

String[] hobbys = req.getParameterValues("hobby");

5.3、请求乱码问题

由于现在的 request 属于接收客户端的参数,所以必然有其默认的语⾔编码,主要是由于在解析过程 中默认使⽤的编码⽅式为 ISO-8859-1(此编码不⽀持中⽂),所以解析时⼀定会出现乱码。有两种方式。

1、setCharacterEncoding

设置前台传来的数据的编码

该方式只针对POST请求有效

//设置请求的编码格式UTF-8格式
req.setCharacterEncoding("UTF-8");

2、编码转换

这种方式对任何类型的请求都是有效的。

Tomcat8及其以上,Get请求不会乱码

String uname = new String(req.getParameter("uname").getBytes("ISo-8859-1"),"UTF-8");

5.4、请求转发

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

req.getRequestDispatcher("index.html").forward(req,resp);

5.5、request作用域

可以该对象可以在**一次请求**中传递数据

第一个参数为名字,第二个为要传递的值,值可以时任意类型

// 添加内容
req.setAttribute("name","zhangsan");
// 删除内容
req.removeAttribute("name");
// 获取内容
req.getAttribute("name")

6、HttpServletResponse

HttpServletResponse对象,使用该对象像前台相应数据

6.1、相应数据

在服务器接收到请求数据后,进行处理。需要将处理结果响应给前台

1、字符流

只能相应字符数据

Writer writer = resp.getWriter();
writer.write("Hello World!");

2、字节流

可以相应任意类型的数据

ServletOutputStream sos = resp.getOutputStream();
sos.write("ahh".getBytes());

两种相应方式只能选择其中的一个,不能同时使用

6.2、相应乱码问题

在响应中,如果响应的数据中有中文,就有可能会乱码。这是因为服务器响应的的数据,会经过网络传输,服务器有一种编码格式,在客户端(浏览器)也会有一种编码格式。如果两者编码不一样,就会出现乱码。

6.2.1、字符流

因为服务器默认编码格式是ISO-8859-1,所以相应中文,一定会出现乱码

处理方案1

// 设置服务器相应给浏览器的数据的编码格式
resp.setCharacterEncoding("utf-8");
// 添加响应头,告知浏览器要响应的数据类型和编码
resp.setHeader("content-type","text/html;charset=UTF-8");
resp.getWriter().write("<h1>啊哈哈</h1>");

处理方案2

// 设置相应类型和编码格式
resp.setContentType("text/html;charset=UTF-8");
resp.getWriter().write("<h1>啊哈哈</h1>");

6.2.2、字节流

对于字节流,由于是传输的字节,所有可以会乱码。如果客户端和服务器使用的是一种编码格式就不会乱码,如果不是一种编码格式就会乱码

处理方案1

// 添加响应头,告知浏览器要响应的数据类型和编码
resp.setHeader("content-type","text/html;charset=UTF-8");
resp.getOutputStream().write("<h1>啊哈哈</h1>".getBytes("UTF-8"));

处理方案2

// 设置相应类型和编码格式
resp.setContentType("text/html;charset=UTF-8");
resp.getOutputStream().write("<h1>啊哈哈</h1>".getBytes("UTF-8"));

6.3、重定向

重定向是客户端行为,在客户端访问服务器后,服务器接收数据后,进行相应,在相应的同时会给客户端一个地址,当客户端接收到服务器的相应后,会马上回服务器给的地址发起新的相应。重定向会发生两次请求。

重定向方式1

// 客户端接收到相应就会马上向index.jsp发起新的请求
resp.sendRedirect("index.jsp");

重定向方式2

// 设置响应码,307或者302都可以
resp.setStatus(307);    // 302
// 添加响应头
resp.setHeader("location","ser05");

请求转发和重定向的区别

请求转发重定向
一次请求,request域的数据共享两次请求,request域的数据不共享
服务端行为客户端行为
地址栏不会改变地址栏发生改变
只可以转发到本站单可以重定向到任何地方

7、Cookie

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

7.1、Cookie的创建和发送

new Cookie(“name”,“admin”):第一个参数是Cookie的Name,第二个参数是Value

// 创建cookie
Cookie cookie = new Cookie("name","admin");
//发送Cookie
resp.addCookie(cookie);

可以在客户端F12查看

7.2、Cookei的获取

cookie不能获取指定的一个,只能获取所有,然后循环遍历

// 获取Cookie,返回的是一个Cookie数组
Cookie[] cookies = req.getCookies();
// 非空判断
if (cookies!=null && cookies.length>0){
    // 遍历Cookie
    for (Cookie cookie:cookies){
        System.out.println("name:"+cookie.getName()+"---value:"+cookie.getValue());
    }
}

7.3、设置Cookie的到期时间

Cookie是有有效期的,默认关闭浏览器失效。可以通过setMaxAge方法设置有效期

1、负整数

负整数表示关闭浏览器就失效,默认也是关闭浏览器失效

// 负整数 关闭浏览器失效,默认值-1
Cookie cookie = new Cookie("name1","zhangsan");
cookie.setMaxAge(-1); // 关闭浏览器就失效
resp.addCookie(cookie);

2、正整数

正整数表示存活时间,单位是秒

// 正整数 存活时间 单位秒
Cookie cookie1 = new Cookie("name2","lisi");
// 存活30秒,30秒后就失效
cookie1.setMaxAge(30);
resp.addCookie(cookie1);

3、零

零表示删除一个Cookie,存活时间为0,也就自动失效了

// 零 删除Cookie
Cookie cookie2 = new Cookie("name3","wanger");
cookie2.setMaxAge(0);
resp.addCookie(cookie2);

7.4、Cookie的路径问题

可以给Cookie设置路径,设置哪些路径可以访问Cookie

1、当前服务器下的任何资源都能访问cookie

Cookie cookie1 = new Cookie("cookie1","cookie1");
cookie1.setPath("/");
resp.addCookie(cookie1);

2、当前项目下的任何资源都能访问cookie

Cookie cookie2 = new Cookie("cookie2","cookie2");
cookie2.setPath("/s04");
resp.addCookie(cookie2);

3、指定项目下的任何资源都能访问cookie

Cookie cookie3 = new Cookie("cookie3","cookie3");
cookie3.setPath("/s03");
resp.addCookie(cookie3);

4、指定项目下指定目录下的任何资源都能访问cookie

Cookie cookie4 = new Cookie("cookie4","cookie4");
cookie4.setPath("/s04/ser02");
resp.addCookie(cookie4);

7.5、Cookie的注意点

1、Cookie如果换了浏览器或者换了电脑将会失效

2、Cookie中name不能为中文

如果要使用中文,需要进行编码

name = URLEncoder.encode(name,"UTF-8");// 编码转换

3、Cookie的数量和大小是有限的,大小一般在4kb左右

4、Cookie中如果出现重名的将会覆盖掉之前的

8、HttpSession

对于服务器而言,每一个连接到它的客户端都是一个 session,servlet 容器使用此接口创建 HTTP 客户端和 HTTP 服务器之间的会话。会话将保留指定的时间段,跨多个连接或来自用户的页面请求。一个会话通常对应于一个用户,该用户可能多次访问一个站点。可以通过此接口查看和操作有关某个会话的信息,比如会话标识符、创建时间和最后一次访问时间。在整个 session 中,最重要的就是属性的操作。

session 无论客户端还是服务器端都可以感知到,若重新打开一个新的浏览器,则无法取得之前设置的 session,因为每一个 session 只保存在当前的浏览器当中,并在相关的页面取得。

Session 的作用就是为了标识一次会话,或者说确认一个用户;并且在一次会话(一个用户的多次请求)期间共享数据。我们可以通过 request.getSession()方法,来获取当前会话的 session 对象。

sessio的底层是依赖Cookie实现的

8.1、Session对象的创建和获取

如果这一次会话中存在session,则获取session对象,反之创建一个新的session对象

// 获取session
HttpSession session = req.getSession();

8.2、Session的常用方法

// 获得SessionID
String id = session.getId();
System.out.println(id);
// 获取session的创建时间,返回的是一个时间戳
System.out.println(session.getCreationTime());
// 获取session的最后一次访问时间,返回的是一个时间戳
System.out.println(session.getLastAccessedTime());
// 是不是新创建的session
System.out.println(session.isNew());

8.3、Session域

1、添加Session数据

HttpSession session = req.getSession();
session.setAttribute("uname","ahh");
session.setAttribute("upwd","123456");

2、移除Session数据

session.removeAttribute("upwd");

3、获取session数据

返回的是一个Object

HttpSession session = req.getSession();
System.out.println(session.getAttribute("name"));

8.4、Session对象的销毁

session对象的销毁有五种情况

1、默认事件到期

session的默认事件是30分钟,如果30分钟内没有发起新的请求,就会失效,当然,时间可以修改。

可以在 Tomcat 中的 conf 目录下的 web.xml 文件中进行修改。

<!-- session 默认的最大不活动时间。单位:分钟。 -->
<session-config>
	<session-timeout>30</session-timeout>
</session-config>

2、自己设置到期时间

setMaxInactiveInterval:这是到期时间,单位是秒

当然有设置也有获取,getMaxInactiveInterval获取失效时间

HttpSession session = req.getSession();
// 设置失效时间
session.setMaxInactiveInterval(15);

3、立即失效

session.invalidate();

4、关闭浏览器失效

session底层是依赖域cookie的,cookie默认就是关闭就浏览器就失效,所以session也是关闭浏览器就失效

5、关闭服务器失效

session是服务器端的对象,服务器关闭了,session也就失效了

9、ServletContext

每一个 web 应用都有且仅有一个ServletContext 对象,又称 Application 对象,从名称中可知,该对象是与应用程序相关的。在 WEB 容器启动的时候,会为每一个 WEB 应用程序创建一个对应的 ServletContext 对象。

该对象有两大作用,第一、作为域对象用来共享数据,此时数据在整个应用程序中共享; 第二、该对象中保存了当前应用程序相关信息。例如可以通过 getServerInfo() 方法获取当前服务器信息 ,getRealPath(String path) 获取资源的真实路径等。

9.1、获取ServletContext

context的获取方式有很多,比如以下几种常用的

1、通过request获取

// 通过req获取
ServletContext context1 = req.getServletContext();

2、通过session获取

// 通过session获取
ServletContext context2 = req.getSession().getServletContext();

3、通过ServletConfig获取

// 通过ServletConfig获取
ServletContext context3 = getServletConfig().getServletContext();

4、直接获取,只能在Servlet中使用

// 直接获取,只能在Servlet中使用
ServletContext context4 = getServletContext();

9.2、常用方法

// 获取当前服务器信息
System.out.println(context1.getServerInfo());
// 获取项目的真实路径
System.out.println(context1.getRealPath("/"));

9.2、Context域

该域对象储存的数据只要服务器不关闭不手动移除,就会一直有效。

ServletContext context = req.getServletContext();

1、添加

// 添加
context.setAttribute("uname","zhangsan");
context.setAttribute("upwd","123");
context.setAttribute("uage","20");

2、删除

// 删除
context.removeAttribute("uage");

3、获取

ServletContext context = request.getServletContext();
String name = (String) context.getAttribute("uname");

9.3、Servlet中的三大域对象

域对象描述
request在一次请求中有效,请求转发有效,重定向失效。
session在一次会话中有效,请求转发和重定向都有效
context整个项目中有效

10、文件的上传与下载

10.1、文件上传

前台页面

<%--
  Created by IntelliJ IDEA.
  User: 2025
  Date: 2020/3/24
  Time: 16:07
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>文件上传</title>
</head>
<body>
    <!--
        multipart/form-data:设置这是一个要提交文件的表单
    -->
    <form action="uploadServlet" method="post" enctype="multipart/form-data">
        姓名:<input type="text" name="uname" placeholder="请输入姓名" autocomplete="off"><br>
        文件:<input type="file" name="myfile"><br>
        <button>提交</button>
    </form>
</body>
</html>

后端实现

package cn.yanghuisen.servlet;

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

/**
 * @Version 1.0
 * @Author
 * @Date 2020/3/24 16:44
 * @Desc MultipartConfig 标识该Servlet支持文件上传
 *  servlet将multipart/form-data的POST请求数据封装成part对象,通过part对上传的文件进行操作
 */
@WebServlet("/uploadServlet")
@MultipartConfig // 上传文件必须设置该注解
public class Servlet07 extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 设置请求数据编码
        req.setCharacterEncoding("UTF-8");
        // 获取普通表单
        String uname = req.getParameter("uname");
        System.out.println(uname);
        // 获取文件 servlet将multipart/form-data的POST请求数据封装成part对象
        Part part = req.getPart("myfile");
        String fileName = part.getSubmittedFileName();
        System.out.println("文件名:"+fileName);
        // 获取文件存放路径
        String path = getServletContext().getRealPath("/");
        System.out.println(path);
        // 把文件保存到指定目录
        part.write(path+"/"+fileName);
    }
}

10.2、下载

1、前台超链接下载

当浏览器识别不出文件时就会自动调用下载

<a href="download/01-Servlet.zip">压缩包文件</a>

2、指定download下载

通过添加downlaod属性下载

<a href="download/abc.txt" download>文本文件</a>
<a href="download/download.jpg" download="abc.png">图片文件</a>

3、后台实现下载

前台页面

<%--
  Created by IntelliJ IDEA.
  User: 2025
  Date: 2020/3/24
  Time: 17:09
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <form action="downloadServlet">
        <input type="text" name="filename" placeholder="请输入要下载的文件的名字" autocomplete="off">
        <button>下载</button>
    </form>
</body>
</html>

后端代码

package cn.yanghuisen.servlet;

import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.Arrays;

/**
 * @Version 1.0
 * @Author
 * @Date 2020/3/24 18:28
 * @Desc
 */

@WebServlet("/downloadServlet")
public class DownloadServlet extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 设置请求编码
        req.setCharacterEncoding("UTF-8");
        resp.setContentType("text/html;charset=UTF-8");
        String fileName = req.getParameter("filename");
        if (fileName==null || "".equals(fileName.trim())){
            Writer writer = resp.getWriter();
            writer.write("文件名不能为空");
            writer.close();
            return;
        }

        // 获取路径
        String path = req.getServletContext().getRealPath("/download/");
        File file = new File(path+fileName);
        // 文件是否存在,并且是一个文件
        if (file.exists() && file.isFile()){
            // 设置一个浏览器不识别的相应格式
            resp.setContentType("application/octet-stream");
            // 设置响应头信息
            resp.setHeader("Content-Disposition","attachment;filename="+fileName);
            // 获取输入流
            InputStream is = new FileInputStream(file);
            // 获取输出流
            ServletOutputStream sos = resp.getOutputStream();
            int len = 0;
            byte[] bytes = new byte[1024];
            while ((len = is.read(bytes))!=-1){
                sos.write(bytes,0,len);
            }
            sos.close();
            is.close();
        }else {
            Writer writer = resp.getWriter();
            writer.write("文件不存在");
            writer.close();
        }
    }
}

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值