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-eks1rhYP-1653982682072)(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-WhqaDTHi-1653982682074)(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-50ePocVI-1653982682074)(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-GpCATDsQ-1653982682075)(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();
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值