IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> servlet笔记 -> 正文阅读

[Java知识库]servlet笔记

代码地址:https://github.com/Autunomy/webstudy

1.HttpServlet对象

在编写web程序的时候,我们都会让自己的servlet继承于Tomcat的HttpServlet类,重写其中的service方法。我们自己编写的Servlet的对象,在全局只创建一次,也就是说Servlet对象是单例的,Servlet对象的创建是第一次访问此Servlet时创建;

2.HttpServlet中,两种service方法的区别

在tomcat的HttpServlet对象中有两个service方法,他们的权限修饰符不同

protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
}
/*-------------------------------------------------------------------------------------------------*/
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
}

两种方法并没有本质的区别,查看源码

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ciQUpOTp-1655361136536)(servlet%E7%AC%94%E8%AE%B0.assets/image-20220524132724569.png)]

这里的this就是HttpServlet的protected的service方法,也就是说如果我们调用public的service方法,那么本质上还是调用的是protected的service方法

3.HttpServletRequest对象

HttpServletRequest对象是请求对象,这个对象不需要我们创建,是Tomcat创建并传递给我们的一个对象,这个对象里面封装了请求的所有数据,比如,请求头,请求体,请求方法等的内容

常用api

方法参数含义
getHeader()String 请求头参数的key获取请求头
getContextPath()获取上下文路径
getServletPath()获取servlet中的映射路径
getMethod()获取请求方式
getRequestURL()获取url
getRequestURI()获取uri
getParameter()String 请求参数的key获取请求的数据

案例

public class Servlet01 extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //获取请求头  这里我们获取的是主机和端口号
        String host = req.getHeader("host");
        System.out.println("请求头="+host);

        //获取上下文路径
        String contextPath = req.getContextPath();
        System.out.println("上下文路径="+contextPath);

        //获取servlet中的映射路径
        String servletPath = req.getServletPath();
        System.out.println("servlet中的映射路径="+servletPath);

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

        //获取url和uri
        StringBuffer url = req.getRequestURL();
        String uri = req.getRequestURI();
        System.out.println("url="+url);
        System.out.println("uri="+uri);

        //获取请求的数据 这里我们需要自己在浏览器地址栏加上参数
        //http://localhost:8080/servlet01?name=zhangsan&age=18
        String name = req.getParameter("name");
        String age = req.getParameter("age");
        System.out.println("name="+name+"  "+"age="+age);
    }
}

4.HttpServletResponse对象

HttpServletRequest对象是响应对象,这个对象不需要我们创建,是Tomcat创建并传递给我们的一个对象,这个对象里面封装了响应的所有数据,包括响应体,响应头等等

常用api

方法参数含义
setHeader()String Object 是一个key-value键值对给响应数据包设置响应头
setContentType()String 数据的格式设置数据类型
setCharacterEncoding()String 编码的类型设置响应实体编码
setStatus()给响应数据包设置状态码
getWriter()获取页面输出对象PrintWriter
write()Object 需要写入页面的数据向页面写数据

案例

public class Servlet02 extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //给响应数据包设置响应头
        resp.setHeader("mydata","data");
        //设置数据类型
        resp.setContentType("application/json");
        //设置响应实体编码(默认为)  另一种设置方式为resp.setContentType("application/json;charset=utf-8");
        resp.setCharacterEncoding("utf-8");
        //给响应数据包设置状态码,一般不用自己设置,由系统自动判断
        resp.setStatus(200);
        //设置页面输出的数据
        resp.getWriter().write("servlet02你好");
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1ZrlHRLS-1655361136537)(servlet%E7%AC%94%E8%AE%B0.assets/image-20220524133814517.png)]

5.Servlet的生命周期

Servlet是全局单例的,也就是说这个实例在第一次访问的时候被创建,之后就不再进行创建了

整个生命周期

  1. 第一次访问被创建,执行对象的创建回调构造方法
  2. 回调init()初始化方法,执行初始化操作
  3. 每次请求到达都会执行service()方法
  4. 程序停止的时候会自动回调destroy()函数来销毁servlet

案例

public class Servlet03 extends HttpServlet {
    public Servlet03() {
        System.out.println("servlet03被创建了");
    }

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.getWriter().write("servlet03");
    }

    @Override
    public void destroy() {
        System.out.println("servlet03被销毁了");
    }

    @Override
    public void init() throws ServletException {
        System.out.println("servlet03被初始化了");
    }
}

5.HttpServletConfig对象

在HttpServlet对象中,有两个init()方法其中一个方法是无参的一个方法是有参的,有参的方法的参数是HttpServletConfig,这个对象可以将我们在web.xml文件中提前配置的内容取出来

案例

<servlet>
    <servlet-name>servlet03</servlet-name>
    <servlet-class>com.hty.web01.Servlet03</servlet-class>
    <init-param>
        <param-name>name</param-name>
        <param-value>zhangsan</param-value>
    </init-param>
    <init-param>
        <param-name>age</param-name>
        <param-value>18</param-value>
    </init-param>
</servlet>
public void init(ServletConfig config) throws ServletException {
    String name = config.getInitParameter("name");
    String age = config.getInitParameter("age");
    System.out.println("name="+name+"  "+"age="+age);
}

问题:如果我们将两个init方法都重写了,那么调用哪一个呢?

查看源码

public void init(ServletConfig config) throws ServletException {
    this.config = config;
    this.init();
}

public void init() throws ServletException {
}

在有参的init中调用了无参的init,说明了,如果我们重写之后没有调用父类的init方法,那么就只会执行有参的init方法,但是如果我们在有参的init方法中调用了父类的init方法,那么就会在调用有参的init方法之前先调用一次无参的init方法

@Override
public void init(ServletConfig config) throws ServletException {
    super.init(config);
    String name = config.getInitParameter("name");
    String age = config.getInitParameter("age");
    System.out.println("name="+name+"  "+"age="+age);
}

输出结果

servlet03被创建了
servlet03被初始化了
name=zhangsan age=18

6.请求转发

其实请求转发是服务器内部的请求转发,与浏览器没有任何关系,对于浏览器而言页面不会出现出现刷新,就是一个请求

案例

public class Servlet04 extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.getRequestDispatcher("/servlet01").forward(req,resp);
    }
}

这个案例转发到了servlet01中,ide的控制台就会展示出上面servlet01中的内容

7.请求重定向

浏览器发送一次请求,服务器返回302状态码+Location响应头,浏览器因为有一个机制(碰到响应码是302的就会去检查Location响应头,然后跳转访问Location响应头中携带的地址)

请求重定向之后,浏览器地址栏就会发生变化

案例

public class Servlet05 extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.sendRedirect("/servlet01");
    }
}

8.ServletContext对象

Tomcat在加载我们的应用程序的时候,会给我们的应用程序创建一个ServletContext对象,代表我们这个应用程序对象,我么可以通过Servlet中的api来获取此对象。这个对象相当于一个变量的保存区,可以将我们每一个servlet设置key-value键值对保存在里面,在任何一个servlet中都可以使用这些key-value键值对

案例

public class Servlet06 extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        ServletContext servletContext = this.getServletContext();
        //设置参数
        servletContext.setAttribute("name","zhangsan");
        servletContext.setAttribute("age","18");
    }
}
public class Servlet07 extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        ServletContext servletContext = this.getServletContext();
        //获取参数
        String name = (String) servletContext.getAttribute("name");
        String age = (String) servletContext.getAttribute("age");
        System.out.println(name + "  " + age);
    }
}

9.service()方法详解

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

在上面的程序中,我们直接调用了父类的service()方法,最后的执行结果为

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-c6g7Hk4r-1655361136538)(servlet%E7%AC%94%E8%AE%B0.assets/image-20220524204712421.png)]

原因:

阅读源码我们可以发现,service方法调用了HttpServlet中的doGet(),doPost()等一系列的方法,他是根据请求的方法来进行选择的,又由于浏览器只能发送get请求,所以service方法还是调用了doGet()方法,进入到doGet()方法就会发现,405错误时从这里来的。根据这个例子来看,我们重写service方法的时候,一定不能调用父类方法。

10.json与对象之间的转换

前后端交互的数据格式就是json格式

一种json字符串   {"author":"吴承恩","id":1,"name":"西游记"}

要拼接为这种字符串那么我们就要重写toString()方法,并利用反射机制获取到属性的值

@Override
public String toString() {
    StringBuffer sb = new StringBuffer();
    sb.append("{");

    Class<? extends Book> bookClass = this.getClass();
    //获取私有的属性
    Field[] fileds = bookClass.getDeclaredFields();
    for (int i = 0; i < fileds.length; i++) {
        String name = fileds[i].getName();
        sb.append("\"" + name + "\": ");
        try {
            sb.append("\"" + fileds[i].get(this) + "\",");
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }
    sb.replace(sb.length()-1,sb.length(),"");
    sb.append("}");

    return sb.toString();
}

通过拼接我们发现,这种方式非常的麻烦,那么我们就需要借用第三方的工具包来实现json的转换

11.fastjson

由于自行拼接json字符串很麻烦,于是我们就可以使用第三方的工具包来帮助我们拼接json字符串,fastjson就是阿里巴巴的一个工具包,专门用来处理json字符串的

public class json01 {
    public static void main(String[] args) {
        Book book = new Book();
        book.setId(1);
        book.setName("西游记");
        book.setAuthor("吴承恩");
        book.setDate(new Date(System.currentTimeMillis()));
		
        //json的序列化
        //不换行的格式显示
        String s = JSON.toJSONStringWithDateFormat(book,"yyyy-MM-dd HH:mm:ss", SerializerFeature.BrowserCompatible);
        //换行的格式显示
        String s1 = JSON.toJSONStringWithDateFormat(book,"yyyy-MM-dd HH:mm:ss", SerializerFeature.PrettyFormat);
        System.out.println(s);
        
        //json的反序列化
        Book book1 = JSON.parseObject(s, Book.class);
        System.out.println(book1);
    }
}

集合的转换

public class json02 {
    public static void main(String[] args) {
        List<Book> bookList = new ArrayList<>();

        Book book1 = new Book();
        book1.setId(1);
        book1.setName("西游记");
        book1.setAuthor("吴承恩");
        book1.setDate(new Date(System.currentTimeMillis()));

        Book book2 = new Book();
        book2.setId(2);
        book2.setName("三国演义");
        book2.setAuthor("罗贯中");
        book2.setDate(new Date(System.currentTimeMillis()));

        bookList.add(book1);
        bookList.add(book2);

        String s = JSON.toJSONStringWithDateFormat(bookList, "yyyy-MM-dd HH:mm:ss");
        System.out.println(s);
        /*
        结果
        [{"author":"吴承恩","date":"2022-05-24 21:51:29","id":1,"name":"西游记"},{"author":"罗贯中","date":"2022-05-24 21:51:29","id":2,"name":"三国演义"}]
        */
    }
}

详情请见:http://t.csdn.cn/8bPs1

12.Servlet返回json字符串给客户端

由于现在的开发都是前后端分离,所以前后端的数据交互主要都是靠json。

public class Servlet01 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        Book book = new Book();
        book.setId(1);
        book.setName("西游记");
        book.setAuthor("吴承恩");
        book.setDate(new Date());

        //将book序列化为json字符串
        String bookJson = JSON.toJSONString(book);
        resp.getWriter().write(bookJson);
    }
}

13.乱码的问题

只有在地址栏中携带数据才不会出现乱码,也就是说get请求永远不会出现乱码,post,put,delete等请求在请求体中携带的参数数会出现乱码问题

解决方法是

req.setCharacterEncoding("urf-8");//设置请求实体中的编码格式

在响应实体中出现乱码的解决方式

resp.setHeader("Content-Type","application/json;charset=utf-8");

14.MIME类型(Type)

在网络中传输数据,需要告诉客户端或者告诉服务器我们传输的数据的类型是什么,这些个类型是有一定规范的,我们常用的类型有以下这么一些:

text/plain(纯文本)
text/html (网页)
text/javascript(js的脚本文件)
text/css(css文件)
image/jpeg(JPEG图像)
image/png(PNG图像)
application/pdf(PDF文档)
application/json(json类型)
application/x-www-form-urlencoded(简单表单数据类型)
multipart/form-data(复合表单类型)
....

这些就是可以设置在Content-Type中的值

如果不指定MIME-TYPE类型,如果客户端是浏览器,那么浏览器就会尝试着去解析,所以在实际开发中,都会显示的指定MIME-TYPE;

15.服务器获取浏览器提交的表单数据

后端编写

public class Servlet01 extends HttpServlet {

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String name = req.getParameter("name");
        Integer age = Integer.valueOf(req.getParameter("age"));
        System.out.println(name);
        System.out.println(age);
    }
}

前端编写

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<!--
action:表单提交的服务器的地址
method:请求方式(默认为GET)
enctype:表单数据的编码方式:默认(application/x-www-form-urlencoded)
-->
<form action="/web03/servlet01" method="POST" enctype="application/x-www-form-urlencoded">
    <!--autocomplete  关闭浏览器自动补全提示-->
    <input type="text" name="name" placeholder="请输入姓名" autocomplete="off">
    <input type="text" name="age" placeholder="请输入年龄" autocomplete="off">
    <button>提交</button>
</form>
</body>
</html>

总结: 以上的这种方式提交表单数据的方式是同步的,在网络环境较差的情况下用户体验不好,所以在实际的开发过程中,尽量应该使用异步的方式提交表单数据;

16.异步请求

16.1.原生js的异步请求实现

异步请求的第一步就是先要将表单阻止提交,阻止的方式就是在form中加入onsubmit属性并return false;

<form onsubmit="return false;"></form>

编写前端

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<h1>提交表单数据</h1>
<form onsubmit="return false;" id="form">
    <input type="text" autocomplete="off" name="name" placeholder="请输入姓名"/>
    <br>
    <input type="text" autocomplete="off" name="age" placeholder="请输入年龄"/>
    <br>
    男: <input type="radio" name="sex" value=""> 女:<input type="radio" name="sex" value="">
    <br>
    java: <input type="checkbox" value="java" name="loves">
    python:<input type="checkbox" value="python" name="loves">
    大数据: <input type="checkbox" value="大数据" name="loves">
    <br>
    <select name="city">
        <option>西安市</option>
        <option>北京市</option>
        <option>宝鸡市</option>
    </select>
    <br>
    <button onclick="doSubmit()">提交数据给服务器</button>
</form>

<script type="text/javascript">
    function doSubmit() {
        //获取name
        let name = document.querySelector("input[name='name']");
        //获取age
        let age = document.querySelector("input[name='age']");
        //由于多个input的name=sex所以需要遍历,选择出来被选择的值
        let sex = document.querySelectorAll("input[name='sex']");
        //最后获取到的被选择的sex
        let sexVal = null;
        for (let sexKey in sex) {
            if (sex[sexKey].checked) {
                sexVal = sex[sexKey].value;
            }
        }
        //获取loves
        let lovesInputs = document.querySelectorAll("input[name='loves']");
        let loves = [];
        lovesInputs.forEach(lovesInput=>{
            if(lovesInput.checked){
                loves.push(lovesInput.value);
            }
        })

        //获取city
        let city = document.querySelector("select[name='city']").value;

        const userObj={
            name,
            age,
            sex,
            loves,
            city
        }

        //异步请求对象
        let xhr = new XMLHttpRequest();
        //由于这里的前后端都是一个服务器,所以我们不需要写ip和端口号
        xhr.open("POST","/web03/servlet01");
        //这里必须指定表单类型,不然会无法提交到服务器
        xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded")
        xhr.send("name=zhangsan&age=18&sex=男&loves=java&loves=大数据&city=西安市");
        xhr.onreadystatechange = function(){
            if(xhr.readyState == 4){
                const responseJsonText = xhr.responseText;
                //把json类型的文本转换成js中的对象(js中对象的反序列化)
                const jsonObj = JSON.parse(responseJsonText);

                //把对象转换成字符串(js中的对象的序列化)
                console.log(JSON.stringify(jsonObj));
            }
        }
    }
</script>
</body>
</html>

编写后端

public class Servlet01 extends HttpServlet {

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setCharacterEncoding("utf-8");
        String name = req.getParameter("name");
        Integer age = Integer.valueOf(req.getParameter("age"));
        String sex = req.getParameter("sex");
        String[] loves = req.getParameterValues("loves");
        String city = req.getParameter("city");
        User user = new User(name,age,sex,loves,city);
        resp.setContentType("application/json;charset=utf-8");
        resp.getWriter().write(JSON.toJSONString(user));
    }
}

这个Uers实体类

package com.hty.web03.pojo;

public class User {
    private String name;
    private Integer age;
    private String sex;
    private String[] loves;
    private String city;

    public User() {
    }

    public User(String name, Integer age, String sex, String[] loves, String city) {
        this.name = name;
        this.age = age;
        this.sex = sex;
        this.loves = loves;
        this.city = city;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public String[] getLoves() {
        return loves;
    }

    public void setLoves(String[] loves) {
        this.loves = loves;
    }

    public String getCity() {
        return city;
    }

    public void setCity(String city) {
        this.city = city;
    }
}

16.2.基于jQuery的异步请求

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>基于jQuery的异步请求实现</title>
    <script src="jquery-1.9.1.js"></script>
</head>
<body>

<form onsubmit="return false;" id="form">
    <input type="text" autocomplete="off" name="name" placeholder="请输入姓名"/>
    <br>
    <input type="text" autocomplete="off" name="age" placeholder="请输入年龄"/>
    <br>
    男: <input type="radio" name="sex" value=""> 女:<input type="radio" name="sex" value="">
    <br>
    java: <input type="checkbox" value="java" name="loves">
    python:<input type="checkbox" value="python" name="loves">
    大数据: <input type="checkbox" value="大数据" name="loves">
    <br>
    <select name="city">
        <option>西安市</option>
        <option>北京市</option>
        <option>宝鸡市</option>
    </select>
    <br>
    <button onclick="doSubmit()">提交数据给服务器</button>
</form>
<script>
    function doSubmit(){
        //将提交的表单信息序列化为一个字符串
        let dataform = $("#form").serialize();

        //使用jQuery中提供的异步请求的api
        $.ajax({
            url:"/web03/servlet01",//请求地址
            type:"POST",//默认为get
            data:dataform,//请求的数据
            //args就是响应的数据
            success:function (...args){//成功的回调函数
                console.log("成功响应",args);
            },
            fail:function (){//失败的回调函数
                console.log("失败响应");
            }
        })
    }

</script>
</body>
</html>

17.Servlet中的域对象

域就是作用域(范围)

  • ServletContext(全局域对象)
  • ServletRequest(请求域对象)
  • HttpSession

18.ServletContext对象

ServletContext域对象是在全局作用域都是同一个对象

要测试这个对象,我们需要先创建两个servlet,一个用来存,一个用来获取

//域对象
public class Servlet03 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //给全局域对象设置值
        ServletContext servletContext = this.getServletContext();
        servletContext.setAttribute("name","zhangsan");
        System.out.println("servlet03");
    }
}
//域对象
public class Servlet04 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //获取全局域对象的值
        ServletContext servletContext = this.getServletContext();
        String name = servletContext.getAttribute("name").toString();
        System.out.println(name);
        System.out.println("servlet04");
    }
}

请求重定向和请求转发都可以获取到ServletContext对象中的数据

19.ServletRequest对象

ServletRequest对象只在一次请求中有效;

我们仍然需要两个类来进行测试,用一个servlet请求转发到另一个servlet中,就可以测试请求作用域对象

//域对象
public class Servlet03 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //请求转发
        req.setAttribute("name","张三");
        System.out.println("servlet03");
        req.getRequestDispatcher("/web03/servlet04").forward(req,resp);

    }
}
//域对象
public class Servlet04 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String name = req.getAttribute("name").toString();
        System.out.println(name);

        System.out.println("servlet04");
    }
}

在请求重定向中不能访问到请求作用域对象

20.Filter过滤器

过滤器的本质还是一个Servlet,对Servlet的访问的前后做一些处理

  • 过滤器就是Servlet规范中,对servlet前后做处理的一个组件
  • 过滤器是对多个请求的前后都可以进行处理
  • 过滤器可以有多个,多个过滤器组成了一条过滤链
  • 过滤器编写完成后需要注册
  • 过滤器中需要配置过滤器到底过滤哪些请求

执行步骤

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jhevM039-1655361136539)(servlet%E7%AC%94%E8%AE%B0.assets/image-20220530204204054.png)]

21.Filter过滤器的生命周期

首先在web.xml中对filter进行注册

<!--注册filter-->
<filter>
    <filter-name>myfilter01</filter-name>
    <filter-class>com.hty.web03.filter.MyFilter01</filter-class>
</filter>
<filter-mapping>
    <filter-name>myfilter01</filter-name>
    <url-pattern>*.do</url-pattern>
</filter-mapping>
public class MyFilter01 implements Filter {
    //init方法在tomcat容器启动后,加载应用时调用  只调用一次
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("过滤器MyFilter01被初始化");
    }
	
    //每个能被过滤器过滤的请求都要执行一次
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("执行MyFilter01过滤器------------");
        filterChain.doFilter(servletRequest,servletResponse);//放行
    }
	
    //destory方法在应用被停止时调用
    @Override
    public void destroy() {
        System.out.println("过滤器MyFilter01被销毁");
    }
}

22.过滤链

当有多个过滤器的时候,那么这些过滤器就会组成一个过滤链,过滤链中,配置在前面的过滤器会先执行,回调的时候,顺序是相反的

23.数据库连接池

  • dbcp
  • c3p0
  • druid(阿里巴巴开源数据连接池)
  • hikari

24.servlet访问数据库

首先创建数据库和数据

SET FOREIGN_KEY_CHECKS=0;

-- ----------------------------
-- Table structure for book
-- ----------------------------
DROP TABLE IF EXISTS `book`;
CREATE TABLE `book` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键id',
  `name` varchar(64) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '图书名称',
  `author` char(4) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '图书作者',
  `release_date` date DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;

-- ----------------------------
-- Records of book
-- ----------------------------
INSERT INTO `book` VALUES ('1', '西游记', '吴承恩', '2022-05-17');
INSERT INTO `book` VALUES ('2', '三国演义', '罗贯中', '2022-05-30');
INSERT INTO `book` VALUES ('3', '水浒传', '施耐庵', '2022-05-30');
INSERT INTO `book` VALUES ('4', '红楼梦', '曹雪芹', '2022-05-30');

在项目根目录下创建一个resources的目录,并标记为resources目录,创建一个db.properties的文件

# 写入自己的配置
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://10.10.10.134:3306/java21?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
username=root
password=123456

使用数据库连接池

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import com.alibaba.fastjson.JSON;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.MapHandler;
import org.apache.commons.dbutils.handlers.MapListHandler;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.sql.DataSource;
import java.io.IOException;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;
import java.util.Properties;

//根据书籍id查询书名
public class Servlet07 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        try {
            //获取页面传递的书籍的id
            Integer id = Integer.valueOf(req.getParameter("id"));
            //数据库连接池
            Properties prop = new Properties();
            prop.load(this.getClass().getClassLoader().getResourceAsStream("db.properties"));
            DataSource druidDataSource = DruidDataSourceFactory.createDataSource(prop);
            QueryRunner queryRunner = new QueryRunner(druidDataSource);
            Map result = (Map)queryRunner.query("select * from book where id = ?", id, new MapHandler());

            resp.setContentType("application/json;charset=utf-8");
            resp.getWriter().write(JSON.toJSONString(result));

        } catch (SQLException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

25.案例-下拉菜单二级联动

前端页面的编写

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>homework</title>
    <script src="jquery-1.9.1.js"></script>
</head>
<body>
<button onclick="getCity()">获取城市信息</button>
<br>
<select name="city" id="city" class="city" onchange="changeCity(this)">

</select>


<select name="school" id="school">

</select>

<script>
    function getCity(){
        let city = [];
        $.ajax({
            url:"/web04/homeworkservlet01",
            method:"POST",
            success:function (...args){
                for(let i=0;i<args[0].length;++i){
                    city.push(args[0][i][0]);
                }
                const citySelecter = document.querySelector("#city");
                citySelecter.length = 0;
                for(let i = 0;i<city.length;++i){
                    let option = document.createElement("option");
                    let text = document.createTextNode(city[i]);
                    option.append(text);
                    citySelecter.append(option);
                }
            },
            fail:function(){

            }
        })
    }

    function changeCity(city){
        let dataMsg = city.value;
        console.log(dataMsg);
        let school = [];
        // console.log(jsonStr);
        $.ajax({
            url:"/web04/homeworkservlet02",
            method:"POST",
            //在ajax中不能直接指定dataType为json,不然后端无法接收到数据
            data:{"city":dataMsg},
            success:function(...args){
                console.log(args);
                for(let i=0;i<args[0].length;++i){
                    school.push(args[0][i][0]);
                }
                const schoolSelecter = document.querySelector("#school");
                schoolSelecter.length = 0;
                for(let i = 0;i<city.length;++i){
                    let option = document.createElement("option");
                    let text = document.createTextNode(school[i]);
                    option.append(text);
                    schoolSelecter.append(option);
                }
            },
            fail:function(){

            }
        })

    }

</script>
</body>
</html>

两个Servlet

HomeWorkServlet01

package com.hty.web04;

import com.alibaba.druid.pool.DruidDataSourceFactory;
import com.alibaba.fastjson.JSON;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.ArrayListHandler;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.sql.DataSource;
import java.io.IOException;
import java.sql.SQLException;
import java.util.List;
import java.util.Properties;

public class HomeWorkServlet01 extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        try {
            req.setCharacterEncoding("utf-8");

            Properties pro = new Properties();
            pro.load(this.getClass().getClassLoader().getResourceAsStream("db.properties"));

            DataSource druidDataSource = DruidDataSourceFactory.createDataSource(pro);
            QueryRunner queryRunner = new QueryRunner(druidDataSource);
            List<String> result = (List<String>)queryRunner.query("select name from city",new ArrayListHandler());

//            System.out.println(JSON.toJSONString(result));
            resp.setContentType("application/json;charset=utf-8");
            resp.getWriter().write(JSON.toJSONString(result));
        } catch (SQLException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

HomeWorkServlet02

package com.hty.web04;

import com.alibaba.druid.pool.DruidDataSourceFactory;
import com.alibaba.fastjson.JSON;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.ArrayListHandler;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.sql.DataSource;
import java.io.IOException;
import java.sql.SQLException;
import java.util.List;
import java.util.Properties;

public class HomeWorkServlet02 extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        try {
            req.setCharacterEncoding("utf-8");
            String city = req.getParameter("city");
            System.out.println(city);
            Properties pro = new Properties();
            pro.load(this.getClass().getClassLoader().getResourceAsStream("db.properties"));

            DataSource druidDataSource = DruidDataSourceFactory.createDataSource(pro);
            QueryRunner queryRunner = new QueryRunner(druidDataSource);
            List<String> result = (List<String>)queryRunner.query("select name from school where city = ?",city,new ArrayListHandler());
//            System.out.println(JSON.toJSONString(result));
            resp.setContentType("application/json;charset=utf-8");
            resp.getWriter().write(JSON.toJSONString(result));
        } catch (SQLException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

26.Servlet中的会话技术

26.1.Cookie技术

Cookie是浏览器存储数据的一种机制,也就是说Cookie技术其实是浏览器的一个功能,浏览器可以在本地存储数据;

测试

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    Cookie cookie = new Cookie("name","admin");
    resp.addCookie(cookie);
}

response中的内容

HTTP/1.1 200
//设置了一个cookie
Set-Cookie: name=admin
Content-Length: 0
Date: Wed, 08 Jun 2022 13:36:25 GMT

cookie中的api

//触发浏览器的存储Cookie数据的功能
Cookie cookie = new Cookie("name", "admin");
//设置注释
cookie.setComment("我是Comment注释");
//设置Cookie的主机域名(一般不需要设置,默认就是此服务部署的服务器的域名)
cookie.setDomain("localhost");
//Cookie的作用域(/:代表当前服务下的所有子服务都有效),一般都会设置为/
cookie.setPath("/");
cookie.setMaxAge(60 * 60 * 24 * 7);//设置Cookie的有效期,单位为s,默认为-1,-1代表浏览器关闭之后失效
resp.addCookie(cookie);

总结:

Cookie是浏览器的一个机制:

  • 存储数据(检查到响应头中有Set-Cookie: xxx,则会把数据进行存储)
  • 携带数据:每次发送请求的时候都会进行检查,如果有符合条件的Cookie数据,则会在请求头中进行携带(Cookie: xxx)

26.2.Session技术

创建两个Servlet:

public class Servlet03 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        /**
         * 1. 检查请求头中时候有Cookie:xxxx
         * 1.1 没有: 创建一个新的Session对象
         * 1.2 有: 获取到Cookie中携带的sessionId,在内存中找到这个SessionId对应的session对象进行返回
         */
        HttpSession session = req.getSession();
        System.out.println("servlet03:" + session);
        resp.getWriter().write("hello");
    }
}
public class Servlet04 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        HttpSession session = req.getSession();
        System.out.println("servlet04:" + session);
    }
}

首先访问servlet03:

发现请求头中没有携带任何数据,那么servlet03中就会创建一个新的HttpSession对象,并且生成一个ID,把id称为SessionID,并且响应的时候通过响应头: Set-Cookie: JSESSIONID=XXXX,浏览器收到响应之后,发现触发了Cookie的机制(功能),把Sessionid进行了存储(Cookie的形式);有效期为-1;

再次访问servlet04(浏览器没有关闭): 浏览器会把JSESSIONID通过请求头 Cookie:xxx携带给服务器,服务器收到请求之后,根据JSESSIONID找到Session对象;

总结:

HttpSession浏览器只要不关闭就是一次会话,使用的就是同一个HttpSession对象;

27.监听器

监听对象的数据变化

需要在web.xml中进行注册

27.1.ServletContextListener

可以监听ServletContext对象的创建与销毁

初始化: 在Tomcat启动时(当程序加载到Tomcat中)就会初始化
销毁: 在Tomcat关闭时(从容器中卸载程序)就会销毁

public class MyListener implements ServletContextListener {
    // 当ServletContext对象初始化时调用
    @Override
    public void contextInitialized(ServletContextEvent servletContextEvent) {
        System.out.println("servletcontext初始化");
    }

    // 当ServletContext对象销毁时调用
    @Override
    public void contextDestroyed(ServletContextEvent servletContextEvent) {
        System.out.println("servletcontext销毁");
    }
}

27.2.ServletContextAttributeListener

可以监听ServletContext对象的数据的添加,修改和删除

给ServletContext域对象添加数据—>attributeAdded
修改ServletContext域对象中的数据—>attributeReplaced
移除ServletContext域对象中的数据—>attributeRemoved

public class MyListener implements ServletContextAttributeListener {
    //监听对象的添加
    @Override
    public void attributeAdded(ServletContextAttributeEvent servletContextAttributeEvent) {

    }
	//监听对象的修改
    @Override
    public void attributeRemoved(ServletContextAttributeEvent servletContextAttributeEvent) {

    }
	//监听对象的删除
    @Override
    public void attributeReplaced(ServletContextAttributeEvent servletContextAttributeEvent) {

    }
}

27.3.HttpSessionListener

监听session的创建与销毁

初始化: 会话建立的时候初始化
销毁: session对象被销毁时或者手动触发 session.invalidate();

public class MyListener implements HttpSessionListener {
    @Override
    public void sessionCreated(HttpSessionEvent httpSessionEvent) {

    }

    @Override
    public void sessionDestroyed(HttpSessionEvent httpSessionEvent) {

    }
}

27.4.HttpSessionAttributeListener

监听session中数据的添加,删除和修改

给HttpSession域对象添加数据—>attributeAdded
修改HttpSession域对象中的数据—>attributeReplaced
移除HttpSession域对象中的数据—>attributeRemoved

public class MyListener implements HttpSessionAttributeListener {

    @Override
    public void attributeAdded(HttpSessionBindingEvent httpSessionBindingEvent) {

    }

    @Override
    public void attributeRemoved(HttpSessionBindingEvent httpSessionBindingEvent) {

    }

    @Override
    public void attributeReplaced(HttpSessionBindingEvent httpSessionBindingEvent) {

    }
}

27.5.ServletRequestListener

监听请求作用域对象的创建和销毁

初始化: 请求到达服务器的时候创建(初始化)
销毁: 请求响应结束会进行销毁

public class MyListener implements ServletRequestListener {

    @Override
    public void requestDestroyed(ServletRequestEvent servletRequestEvent) {

    }

    @Override
    public void requestInitialized(ServletRequestEvent servletRequestEvent) {

    }
}

27.6.ServletRequestAttributeListener

监听请求作用域对象的数据的添加,修改和删除

给ServletRequest域对象添加数据—>attributeAdded
修改ServletRequest域对象中的数据—>attributeReplaced
移除ServletRequest域对象中的数据—>attributeRemoved

public class MyListener implements ServletRequestAttributeListener {

    @Override
    public void attributeAdded(ServletRequestAttributeEvent servletRequestAttributeEvent) {

    }

    @Override
    public void attributeRemoved(ServletRequestAttributeEvent servletRequestAttributeEvent) {

    }

    @Override
    public void attributeReplaced(ServletRequestAttributeEvent servletRequestAttributeEvent) {

    }
}

28.使用注解开发

在Servlet3.x的版本中已经添加了对注解的支持,我们可以不使用web.xml,只使用注解开发;

//把当前注解作用的Servlet交给Tomcat来识别
@WebServlet(urlPatterns = "/servlet04")

//注册Filter
@WebFilter(urlPatterns = "/*")

//注册Listener监听器
@WebListener

29.文件上传

//接收GET请求的普通参数
String name = req.getParameter("name");

但是: 我们在实际的开发过程中有可能会使用到文件上传,而我们在前面学过的表单提交其实都是简单的表单提交,但是如果一个表单中包含了文件上传的组件,那么就不能使用简单的表单提交了;

简单的表单提交既可以使用GET请求也可以使用POST请求,但是在一般情况下,我们提交表单数据都是使用POST请求;

<form action="/servlet05"  method="post" enctype="application/x-www-form-urlencoded" >
POST /servlet05 HTTP/1.1
Host: 192.168.3.136:8080
Connection: keep-alive
Content-Length: 32
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: http://192.168.3.136:8080
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.5005.61 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Referer: http://192.168.3.136:8080/ops1.html
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8

username=admin&password=admin123

我们接下来看复合表单的数据提交:

复合表单绝对不能使用GET请求进行提交的,一定要使用POST请求;

复合表单的提交enctype就不能使用application/x-www-form-urlencoded,我们就得指定支持复合表单的编码格式enctype="multipart/form-data"

POST /servlet05 HTTP/1.1
Host: 192.168.3.136:8080
Connection: keep-alive
Content-Length: 391
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: http://192.168.3.136:8080
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary0U1mMgBO6VA5fYQk
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.5005.61 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Referer: http://192.168.3.136:8080/ops1.html
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8

------WebKitFormBoundary0U1mMgBO6VA5fYQk
Content-Disposition: form-data; name="username"

admin
------WebKitFormBoundary0U1mMgBO6VA5fYQk
Content-Disposition: form-data; name="password"

admin123
------WebKitFormBoundary0U1mMgBO6VA5fYQk
Content-Disposition: form-data; name="mPic"; filename=""
Content-Type: image/png

xxxx文件的二进制数据xxxx

------WebKitFormBoundary0U1mMgBO6VA5fYQk--

在老版本的Servlet中并没有提供对文件上传的支持,需要我们自己进行解析,但是Servlet3.x之后官方也发现很多人有这样的需求,官方替我们解析了,给我们直接提供了使用方式;我们直接获取复合表单数据即可,只需要注意在页面提交表单数据时的两个属性: method="post" enctype="multipart/form-data"

案例

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<form action="/web06/servlet03" method="post" enctype="multipart/form-data">
    <input type="text" name="username" placeholder="用户名" autocomplete="none">
    <input type="password" name="password" placeholder="密码" autocomplete="none">
    <input type="file" name="pic">
    <button>提交</button>
</form>
</body>
</html>
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;

@WebServlet(urlPatterns = "/web06/servlet03")

@MultipartConfig//注意 必须要这个注解才能使用
public class Servlet03 extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String username = req.getParameter("username");
        String password = req.getParameter("password");

        System.out.println(username);
        System.out.println(password);

        Part part = req.getPart("pic");
        System.out.println(part);
        System.out.println(part.getName());
        System.out.println(part.getSize());
        System.out.println(part.getSubmittedFileName());
        System.out.println(part.getContentType());
        part.write("D:\\pic.jpg");
    }
}

ead>

Title

提交 ```
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;

@WebServlet(urlPatterns = "/web06/servlet03")

@MultipartConfig//注意 必须要这个注解才能使用
public class Servlet03 extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String username = req.getParameter("username");
        String password = req.getParameter("password");

        System.out.println(username);
        System.out.println(password);

        Part part = req.getPart("pic");
        System.out.println(part);
        System.out.println(part.getName());
        System.out.println(part.getSize());
        System.out.println(part.getSubmittedFileName());
        System.out.println(part.getContentType());
        part.write("D:\\pic.jpg");
    }
}
  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-06-18 23:18:09  更:2022-06-18 23:18:47 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 18:48:11-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码