07【Listener、Ajax、Json】

追求适度,才能走向成功;人在顶峰,迈步就是下坡;身在低谷,抬足既是登高;弦,绷得太紧会断;人,思虑过度会疯;水至清无鱼,人至真无友,山至高无树;适度,不是中庸,而是一种明智的生活态度。

导读:本篇文章讲解 07【Listener、Ajax、Json】,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com,来源:原文

文章目录

07【Listener、Ajax、Json】

一、监听器

监听器用于监听web应用中某些对象、信息的创建、销毁、增加,修改,删除等动作的发生,然后作出相应的响应处理。当范围对象的状态发生变化的时候,服务器自动调用监听器对象中的方法。常用于统计在线人数和在线用户,系统加载时进行信息初始化,统计网站的访问量等等。

1.1 监听器的类别

在JavaWEB中,监听器分为三大类,八大种,分别是监听域对象生命周期监听域对象的属性变化监听session的钝化与活化/监听session绑定与解绑

1.1.1 监听域对象

对象类型 对应的监听器 作用
ServletContext ServletContextListener 监听ServletContext的生命周期
HttpSession HttpSessionListener 监听Session的生命周期
HttpServletRequest ServletRequestListener 监听Request的生命周期

1.1.2 监听属性

对象类型 对应的监听器 作用
ServletContext ServletContextAttributeListener 监听ServletContext属性的变化
HttpSession HttpSessionAttributeListener 监听Session属性的变化
HttpServletRequest ServletRequestAttributeListener(监听移除) 监听Request属性的变化

1.3.3 监听session对象状态

对象类型 对应的监听器 作用
HttpSession HttpSessionBindingListener(绑定,解除绑定) 监听session的属性绑定与移除
HttpSession HttpSessionActivationListener(钝化和活化) 监听session中的属性钝化与活化

1.2 监听案例

1.2.1 监听域对象案例

  • servletContext:
    • 何时创建:服务器启动
    • 何时销毁:服务器关闭
  • session:
    • 何时创建:
      • 默认第一次获取
    • 何时销毁:
      • 30分钟
      • invildete()
      • 服务器关闭
  • Request:
    • 何时创建:每次请求都会创建一个新的request
    • 何时销毁:请求响应request销毁(服务器)

需求:编写三个监听类,分别监听ServletContextSessionRequest的生命周期

观察效果

  • Demo01ContextListener:监听ServletContext
package com.dfbz.listener;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;


/**
 * @author lscl
 * @version 1.0
 * @intro: 用于监听ServletContext的创建于销毁
 */
@WebListener
public class Demo01ContextListener implements ServletContextListener {
    @Override
    public void contextInitialized(ServletContextEvent servletContextEvent) {
        System.out.println("servletContext初始化啦!");
    }

    @Override
    public void contextDestroyed(ServletContextEvent servletContextEvent) {

        System.out.println("servletContext销毁啦!");
    }
}
  • Demo02SessionListener:监听Session
package com.dfbz.listener;

import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;

/**
 * @author lscl
 * @version 1.0
 * @intro: 用于监听session的创建于销毁
 */
@WebListener
public class Demo02SessionListener implements HttpSessionListener {

    @Override
    public void sessionCreated(HttpSessionEvent httpSessionEvent) {
        System.out.println("session初始化啦!");
    }

    @Override
    public void sessionDestroyed(HttpSessionEvent httpSessionEvent) {
        System.out.println("session销毁啦!");

    }
}
  • Demo03ServletListener:监听Request
package com.dfbz.listener;

import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;

/**
 * @author lscl
 * @version 1.0
 * @intro: 用于监听request的创建与销毁
 */
@WebListener
public class Demo03RequestListener implements ServletRequestListener {


    @Override
    public void requestDestroyed(ServletRequestEvent servletRequestEvent) {
        System.out.println("request销毁啦!");

    }

    @Override
    public void requestInitialized(ServletRequestEvent servletRequestEvent) {
        System.out.println("request初始化啦!");
    }
}
  • Demo01Servlet:
package com.dfbz.servlet;

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

/**
 * @author lscl
 * @version 1.0
 * @intro:
 */
@WebServlet(value = "/demo01")
public class Demo01Servlet extends HttpServlet  {

    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        HttpSession session = request.getSession();
        System.out.println("Demo01Servlet执行啦!");
    }
}
  • Demo02Servlet:
package com.dfbz.servlet;

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

/**
 * @author lscl
 * @version 1.0
 * @intro:
 */
@WebServlet("/demo02")
public class Demo02Servlet extends HttpServlet {

    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        HttpSession session = request.getSession();

        // 销毁session
        session.invalidate();

        // 响应客户端(request销毁)
        response.getWriter().println("session invalidated!");
    }
}

执行的结果:

1)服务器启动时ServletConext创建

2)当有任意的请求发送过来时,request都会创建,等待服务器响应时,request销毁;

3)当调用request.getSession()方法时,session创建

4)浏览器关闭session并没有销毁(只是sessionid丢失了),当再次打开浏览器访问/demo01时,session又创建了(返回一个新的sessionid)

5)关闭服务器ServletContext、session、request全部销毁(在控制台窗口中只能看到ServletContext的contextDestroyed方法执行,但其实所有的资源已经释放)

生命周期小结:

  • ServletConext生命周期?
    • 何时创建:服务器启动创建
    • 何时销毁:服务器关闭销毁
  • Session声明周期?
    • 何时创建:第一次调用session.getSession()时创建
    • 何时销毁:
      • 调用invalidate方法时
      • session过期时间到期(默认30分钟)
      • 服务器关闭(这种方法销毁,不会触发HttpSessionListener监听器的Destroyed方法)
  • Request的生命周期?
    • 何时创建:每次访问都会创建
    • 何时销毁:响应结束销毁

1.2.2 监听属性案例

需求:编写三个监听类,分别监听ServletContextSessionRequest的属性变化情况

  • Demo01ContextAttrListener:
package com.dfbz.listener2;

import javax.servlet.ServletContextAttributeEvent;
import javax.servlet.ServletContextAttributeListener;

/**
 * @author lscl
 * @version 1.0
 * @intro:
 */
@WebListener
public class Demo01ContextAttrListener implements ServletContextAttributeListener {
    @Override
    public void attributeAdded(ServletContextAttributeEvent servletContextAttributeEvent) {
        System.out.println("context中添加了一个属性!");
        System.out.println("name: "+servletContextAttributeEvent.getName());
        System.out.println("value: "+servletContextAttributeEvent.getValue());
        System.out.println("--------------------");
    }

    @Override
    public void attributeRemoved(ServletContextAttributeEvent servletContextAttributeEvent) {
        System.out.println("context中移除了一个属性!");
        System.out.println("name: "+servletContextAttributeEvent.getName());
        System.out.println("value: "+servletContextAttributeEvent.getValue());
        System.out.println("--------------------");
    }

    @Override
    public void attributeReplaced(ServletContextAttributeEvent servletContextAttributeEvent) {
        System.out.println("context中替换了一个属性!");
        System.out.println("name: "+servletContextAttributeEvent.getName());
        System.out.println("value: "+servletContextAttributeEvent.getValue());
        System.out.println("--------------------");
    }
}
  • Demo02SessionAttrListener:
package com.dfbz.listener2;

import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionBindingEvent;

/**
 * @author lscl
 * @version 1.0
 * @intro:
 */
@WebListener
public class Demo02SessionAttrListener implements HttpSessionAttributeListener {

    @Override
    public void attributeAdded(HttpSessionBindingEvent httpSessionBindingEvent) {
        System.out.println("session中添加了一个属性!");
        System.out.println("name: "+httpSessionBindingEvent.getName());
        System.out.println("value: "+httpSessionBindingEvent.getValue());
        System.out.println("--------------------");
    }

    @Override
    public void attributeRemoved(HttpSessionBindingEvent httpSessionBindingEvent) {
        System.out.println("session中移除了一个属性!");
        System.out.println("name: "+httpSessionBindingEvent.getName());
        System.out.println("value: "+httpSessionBindingEvent.getValue());
        System.out.println("--------------------");
    }

    @Override
    public void attributeReplaced(HttpSessionBindingEvent httpSessionBindingEvent) {
        System.out.println("session中替换了一个属性!");
        System.out.println("name: "+httpSessionBindingEvent.getName());
        System.out.println("value: "+httpSessionBindingEvent.getValue());
        System.out.println("--------------------");
    }
}
  • Demo03RequestAttrListener:
package com.dfbz.listener2;

import javax.servlet.ServletRequestAttributeEvent;
import javax.servlet.ServletRequestAttributeListener;

/**
 * @author lscl
 * @version 1.0
 * @intro:
 */
@WebListener
public class Demo03RequestAttrListener implements ServletRequestAttributeListener {


    @Override
    public void attributeAdded(ServletRequestAttributeEvent servletRequestAttributeEvent) {
        System.out.println("request中添加了一个属性!");
        System.out.println("name: "+servletRequestAttributeEvent.getName());
        System.out.println("value: "+servletRequestAttributeEvent.getValue());
        System.out.println("--------------------");
    }

    // request移除属性时并不会触发这个方法,request属性的删除只有在request销毁的时候才会真正的删除,removeAttribute只是被标记不可访问而已
    @Override
    public void attributeRemoved(ServletRequestAttributeEvent servletRequestAttributeEvent) {
        System.out.println("request中移除了一个属性!");
        System.out.println("name: "+servletRequestAttributeEvent.getName());
        System.out.println("value: "+servletRequestAttributeEvent.getValue());
        System.out.println("--------------------");
    }
    
    // 对于访问不支持异步的servlet,Tomcat每次都会在请求域中携带一个org.apache.catalina.ASYNC_SUPPORTED参数,表示是否不支持异步,因此每次请求后端时都会触发一次attributeReplaced
    @Override
    public void attributeReplaced(ServletRequestAttributeEvent servletRequestAttributeEvent) {
        System.out.println("request中替换了一个属性!");
        System.out.println("name: "+servletRequestAttributeEvent.getName());
        System.out.println("value: "+servletRequestAttributeEvent.getValue());
        System.out.println("--------------------");
    }
}
  • Demo03Servlet:
package com.dfbz.servlet;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;
import java.io.IOException;

/**
 * @author lscl
 * @version 1.0
 * @intro: 
 */
@WebServlet("/demo03")
public class Demo03Servlet extends HttpServlet {

    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        ServletContext context = getServletContext();
        HttpSession session = request.getSession();

        String contextVal = request.getParameter("context");
        String sessionVal = request.getParameter("session");
        String requestVal = request.getParameter("request");

        if(contextVal==null){
            contextVal="";
        }

        if(sessionVal==null){
            sessionVal="";
        }

        if(requestVal==null){
            requestVal="";
        }
        
        switch (contextVal) {
            case "1":
                context.setAttribute("user", "zhangsan");
                break;
            case "2":
                context.removeAttribute("user");
                break;
        }

        switch (sessionVal) {
            case "1":
                session.setAttribute("user", "zhangsan");
                break;
            case "2":
                session.removeAttribute("user");
                break;
        }

        switch (requestVal) {
            case "1":
                request.setAttribute("user", "zhangsan");
                break;
            case "2":
                request.removeAttribute("user");
                break;
        }

        response.getWriter().println("ok!");
    }
}

分别访问:

http://localhost:8080/demo03?context=1

http://localhost:8080/demo03?context=2

http://localhost:8080/demo03?session=1

http://localhost:8080/demo03?session=2

http://localhost:8080/demo03?reqeust=1

http://localhost:8080/demo03?request=2

查看执行效果:

当监听的对象添加了一个属性时会触发对应的attributeAdded方法,如果这个属性之前就存在,那么属于替换操作,触发attributeReplaced,如果移除域对象的某个属性,那么触发attributeRemoved方法

1.3 回顾session的持久化

我们都知道session是存储在服务器的内存中的,当服务器关闭之后,session就销毁了,session的持久化指的是将session的内容持久化到磁盘上,进行永久保存,想要session的内容能够持久化必须保证对象实现Serializable接口;

session的持久化也叫钝化与活化

  • 钝化:从内存到磁盘
  • 活化:从磁盘到内存

在这里插入图片描述

在web目录下创建META-INF目录,然后创建Context.xml文件:

<Context>
    <!-- maxIdleSwap:session中的对象多长时间不使用就钝化(单位为分钟) -->
    <!-- directory:钝化后的对象的文件写到磁盘的哪个目录下  配置钝化的对象文件默认在work/catalina/localhost/钝化文件 -->
    <Manager className="org.apache.catalina.session.PersistentManager" maxIdleSwap="1">
        <Store className="org.apache.catalina.session.FileStore" directory="d:/aaa" />
    </Manager>
</Context>

在这里插入图片描述

创建Person对象:

package com.dfbz.entity;

import java.io.Serializable;

/**
 * @author lscl
 * @version 1.0
 * @intro: 
 */
public class Person implements Serializable {        // 实现Serializable接口

    private String id;
    private String name;

}
  • CreateServlet:
package com.dfbz.servlet;

import com.dfbz.entity.Person;

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

/**
 * @author lscl
 * @version 1.0
 * @intro:
 */
@WebServlet("/create")
public class CreateServlet extends HttpServlet {

    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws IOException {

        response.setContentType("text/html;charset=utf8");

        Person person = new Person("1", "张三");

        // 将对象存入session
        request.getSession().setAttribute("person", person);

        response.getWriter().println("create访问成功...会话ID" + request.getSession().getId()+"<hr>");
        response.getWriter().println("person: " + person);
    }
}
  • QueryServlet:
package com.dfbz.servlet;

import com.dfbz.entity.Person;

import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

/**
 * @author lscl
 * @version 1.0
 * @intro:
 */
@WebServlet("/query")
public class QueryServlet extends HttpServlet {

    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws IOException {
        response.setContentType("text/html;charset=utf8");

        Person person = (Person) request.getSession().getAttribute("person");

        PrintWriter writer = response.getWriter();

        writer.println("query访问成功...会话ID"+request.getSession().getId()+"<hr>");
        writer.println("person: "+person+"<hr>");
    }
}

  • DeleteServlet:
package com.dfbz.servlet;

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

/**
 * @author lscl
 * @version 1.0
 * @intro:
 */
@WebServlet("/delete")
public class DeleteServlet extends HttpServlet {

    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        response.setContentType("text/html;charset=utf8");

        PrintWriter writer = response.getWriter();

        writer.println("delete访问成功..." + request.getSession().getId());

        // 销毁session(钝化的文件也会被删除)
        request.getSession().invalidate();
    }
}

访问:http://localhost:8080/create

等待一分钟,观察:D:/aaa目录下是否有xxx.session文件产生,等待文件生成后关闭服务器(session销毁)

再次访问:http://localhost:8080/query 发现session中保存的person依旧存在

1.4 钝化与活化监听

我们之前学习过session的持久化(钝化与活化),我们可以通过设置Context.xml来调整session持久化的时间,有个比较尴尬的情况就是,session持久化后并不会”通知”我们,我们只能大概的估计一下session已经持久化了;HttpSessionActivationListener监听器正是来帮我们监听session的钝化与活化的

HttpSessionActivationListener监听器中提供有两个方法:

  • sessionWillPassivate:钝化后执行的方法
  • sessionDidActivate:活化后执行的方法

我们可以修改Person,让Person实现HttpSessionActivationListener接口:

package com.dfbz.entity;

import javax.servlet.http.HttpSessionActivationListener;
import javax.servlet.http.HttpSessionEvent;
import java.io.Serializable;

/**
 * 实现Serializable、HttpSessionActivationListener接口
 */
public class Person implements HttpSessionActivationListener, Serializable {

    private String id;
    private String name;

    //钝化时执行的方法
    public void sessionWillPassivate(HttpSessionEvent se) {
        // TODO Auto-generated method stub
        System.out.println("Person钝化了");
    }

    //活化时执行的方法
    public void sessionDidActivate(HttpSessionEvent se) {
        // TODO Auto-generated method stub
        System.out.println("Person活化了");

    }
}

重启服务器:观察session钝化和活化后是否执行对应方法

1.6 Session绑定与解绑

到目前为止,我们就差HttpSessionBindingListener监听器没有学习了,那么这个监听器有什么作用呢?

HttpSessionBindingListener监听器监听的是单个session的绑定属性情况,如果绑定了监听器类,那么触发绑定方法,如果移除了监听器类,那么触发解绑方法

  • Demo01SessionBindingListener:
package com.dfbz.listener3;

import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSessionBindingEvent;
import javax.servlet.http.HttpSessionBindingListener;

/**
 * @author lscl
 * @version 1.0
 * @intro:
 */
@WebListener
public class Demo01SessionBindingListener implements HttpSessionBindingListener {
    @Override
    public void valueBound(HttpSessionBindingEvent httpSessionBindingEvent) {
        System.out.println("session绑定啦!");
    }

    @Override
    public void valueUnbound(HttpSessionBindingEvent httpSessionBindingEvent) {
        System.out.println("session解绑啦!");
    }
}
  • Demo04Servlet:
package com.dfbz.servlet;

import com.dfbz.listener3.Demo01SessionBindingListener;

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

/**
 * @author lscl
 * @version 1.0
 * @intro:
 */
@WebServlet("/demo04")
public class Demo04Servlet extends HttpServlet {

    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        HttpSession session = request.getSession();

        String flag = request.getParameter("flag");
        if ("1".equals(flag)) {
            // 触发绑定方法

            session.setAttribute("bindingListener", new Demo01SessionBindingListener());
            response.getWriter().println("binding ok!");
        } else if ("2".equals(flag)) {

            // 触发解绑方法
            session.removeAttribute("bindingListener");
            response.getWriter().println("unBinding ok!");
        }
        
    }
}

1.7 监听器小结

监听器分为三大类,共八种;分别是监听域对象生命周期监听域对象属性的添加与移除监听session对象的变化

  • 1)监听域对象
    • 1)ServletContextListener:监听ServletConext生命周期
    • 2)HttpSessionListener:监听session生命周期,如是服务器关闭,session是销毁了,但是不会触发destroty
    • 3)ServletRequestListener:监听request生命周期,如是服务器关闭,request是销毁了,但是不会触发destroty
  • 2)监听属性
    • 1)ServletContextAttributeListener:监听ServletConext属性变化情况,包括添加、移除、替换
    • 2)HttpSessionAttributeListener:监听Session属性变化情况,包括添加、移除、替换
    • 3)ServletRequestAttributeListener:监听Request属性变化情况,包括添加、移除、替换
  • 3)监听session对象的变化
    • 1)HttpSessionActivationListener:监听session属性对象的钝化与活化
    • 2)HttpSessionBindingListener:监听session属性对象的绑定与解绑

二、Ajax

2.1 Ajax简介

2.1.1 Ajax介绍

Ajax 即”Asynchronous Javascript And XML”(异步 JavaScript 和 XML),是指一种创建交互式网页应用的网页开发技术。通过在后台与服务器进行少量数据交换,Ajax可以使用网页实现异步更新。这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新(无刷新技术)。传统的网页(不使用Ajax)如果需要更新内容,必须重载整个网页页面。

  • 异步请求:无刷新,用户体验极高

  • 同步请求:有刷新,之前我们学习的所有客户端浏览器提交的请求全部都是有刷新的同步请求。

2.1.2 ajax的应用场景

ajax的应用场景很多,常见的应用场景如下:

1)异步校验

我们在注册账号的过程中,当鼠标移出输入框时,如果用户名存在那么则提示已经存在,这个过程页面没有刷新,但是依旧发送了请求访问了后台的数据库;

在这里插入图片描述

2)菜单联动

很多网站上都会有侧边菜单栏,当鼠标移入主菜单时,子菜单中的数据再发送请求到后台查询;这个过程页面是没有刷新的;

在这里插入图片描述

3)内容自动补全

各大网站上的搜索功能大致都会提供自动补全功能,实质上是获取当前输入框的内容当做参数发送请求到服务器端查询数据了,这个过程页面也没有刷新

百度的搜索补全功能:

在这里插入图片描述

淘宝的搜索补全功能:

在这里插入图片描述

2.2 JavaScript原生的ajax

JavaScript原生的Ajax开发步骤如下:

  • 1)创建Ajax引擎对象:XMLHttpRequest

  • 2)为Ajax引擎对象绑定监听

  • 3)绑定提交地址

  • 4)发送请求

  • 5)监听里面处理响应数据

2.2.1 Servlet代码

package com.dfbz.ajax;

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

/**
 * @author lscl
 * @version 1.0
 * @intro:
 */
@WebServlet("/demo01")
public class Demo01Servlet extends HttpServlet {

    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.getWriter().println("hello ajax!");
    }
}

2.2.2 ajax代码

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

</head>
<body>

<input type="button" onclick="request()" value="异步请求">

<script>
    function request() {
        // 创建一个ajax对象
        var ajax = new XMLHttpRequest()

        // 获取当前的ajax对象的状态值
        console.log(ajax.readyState);       // 0 请求还没有初始化(调用open方法之前)

        /*
            打开(封装一个请求)
            参数1: 请求的方式
            参数2: 请求的地址
            参数3: 是否异步
         */
        ajax.open("post", "demo01", true);

        console.log(ajax.readyState);       // 1 与服务器的连接已经建立(调用open方法之后)

        // 发送请求
        ajax.send();

        // 监听ajax状态变化(我只能监听服务器给我响应之后的状态(2,3,4)的状态值变化)
        ajax.onreadystatechange = function () {

            if (ajax.readyState == 4 && ajax.status == 200) {
                // 说明已经服务器已经成功响应客户端,并且是一个正确的响应
                console.log(ajax.responseText)
            }
        }
    }

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

2.2.3 ajax状态值

  • 0:请求未初始化(调用open方法之前)

  • 1:服务器连接已建立 (调用open方法之后)

  • 2:载入完成(send方法执行完毕,已经接受响应(后端逻辑已经执行完成))

  • 3:交互(正在解析响应内容,如果服务器没有响应内容则跳过这一状态)

  • 4:完成(响应内容解析完毕)

上面需要注意两点:

1)onreadystatechange方法监听readyState的变化只是在到达服务器端并且完全响应后之后的状态,也就是2、3、4

2)为状态值变为4的时候只能说明服务器已经成功响应了客户端,但并不能代表是一个正确的响应

2.2.4 ajax响应状态码

我们前面提到,如果通过监听readyState状态值变为4只能说明一次请求已经结束了(已经成功的响应),而不管响应是否是正确的(状态码为200)

1)测试404

我们如果请求的地址填写错误readystate的值也是可以正常从0变化到4的;因为这也是一次完整的请求和响应

在这里插入图片描述

2)测试500

修改Demo01Servlet代码:

@WebServlet("/demo01")
public class Demo01Servlet extends HttpServlet {

    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 触发异常  响应码:500
        int i = 1 / 0;
        response.getWriter().println("hello ajax!");
    }
}

在这里插入图片描述

3)ajax的status属性

通过上面的案例我们能够知道,即使是一次错误的响应,readyState的值也是会变化的,因此我们不能仅仅通过readyState的值变化到了4就断定这个请求已经正确响应了;也有可能是一个错误的响应;

那如何定义这个响应是正确的?响应状态码为200!我们在学习Http协议的时候了解到,响应状态码为200代表服务器正确处理请求并且正确的响应;ajax提供status属性来获取http响应的状态码

修改方法:

ajax.onreadystatechange = function () {

    if (ajax.readyState == 4 && ajax.status == 200) {
        // 服务器端完全响应了并且响应状态码为200
        
        alert("服务器端响应的内容: "+ajax.responseText)
    }
}

2.3 JQuery框架的ajax

我们刚刚学习了原生的JS操作ajax方法,过程难免有些繁琐,jquery对ajax进行了封装,免去了很多复杂的操作,让我们的开发更加便捷,在企业中,我们一般都是采用jquery来操作ajax;

请求方式 语法 说明
GET请求 $.get(url, [data], [callback], [type]) 简单的get请求
POST请求 $.post(url, [data], [callback], [type]) 简单的post请求
AJAX请求 $.ajax([settings]) 复杂的ajax请求(可以设更多的参数)
GET请求 $.get([settings]) 复杂的get请求(可以设更多的参数)
POST请求 $.post([settings]) 复杂的post请求(可以设更多的参数)

在线jquery手册:https://jquery.cuishifeng.cn/

2.3.1 GET请求方式

$.get(url, [data], [callback], [type]):简单的 GET 请求功能,如需复杂的ajax参数设置请使用$.ajax。

  • 参数说明如下:
参数名称 解释
url 请求的服务器端url地址
data 发送给服务器端的请求参数,格式可以是key=value,也可以是json对象
callback 当请求成功后的回掉函数,可以在函数体中编写我们的逻辑代码
type 预期的返回数据的类型,取值可以是 xml, html, script, json, text, _defaul等,一般不用我们自己设定

中括号([])中的参数代表是可选

  • demo02.html:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <!--引入jquery-->
    <script src="js/jquery-3.5.1.min.js"></script>
</head>
<body>
<input type="button" value="GET请求方式" onclick="fun1()">
<script>

    // GET请求方式
    function fun1() {
        $.get("demo02", "username=zhansan&password=123", function (res) {
            alert("服务器端响应的结果: " + res)
        },"html")

        /*// 也可以传递json字符串
        $.get("demo02", {"username": "zhangsan", "password": "123", "flag": "1"}, function (res) {
            alert("服务器端响应的结果: " + res)
        })*/
    }
</script>
</body>
</html>
  • Demo02Servlet:
package com.dfbz.ajax;

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

/**
 * @author lscl
 * @version 1.0
 * @intro:
 */
@WebServlet("/demo02")
public class Demo02Servlet extends HttpServlet {

    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        // 获取前端请求的方式
        String method = request.getMethod();

        response.setContentType("text/html;charset=utf8");
        response.getWriter().println("请求成功!请求的方式: " + method + "");

        // 获取前端提交的参数
        Map<String, String[]> parameterMap = request.getParameterMap();

        for (String key : parameterMap.keySet()) {
            response.getWriter().println("key: " + key + "---> val: " + Arrays.toString(parameterMap.get(key)));
        }
    }
}

响应如下:

在这里插入图片描述

2.3.2 POST请求方式

jQuery.post(url, [data], [callback], [type]):一个简单的 POST 请求功能,如需复杂的ajax参数设置请使用$.ajax。

  • 参数说明如下:
参数名称 解释
url 请求的服务器端url地址
data 发送给服务器端的请求参数,格式可以是key=value,也可以是json对象
callback 当请求成功后的回掉函数,可以在函数体中编写我们的逻辑代码
type 预期的返回数据的类型,取值可以是 xml, html, script, json, text, _defaul等
  • 新增按钮:
<input type="button" value="POST请求方式" onclick="fun2()">
  • JS代码:
// POST请求方式
function fun2() {
    $.post("demo02","username=zhansan&password=123",function (res) {
        alert("服务器端响应的结果: "+res)
    })
}

2.3.3 AJAX请求方式

jQuery.ajax([settings]):简单易用的高层实现见get和post方法。$.ajax()方法可以更加详细的设置底层的参数。

  • 参数说明如下:
属性名称 解释
url 请求的服务器端url地址
async (默认: true) 默认设置下,所有请求均为异步请求。如果需要发送同步请求,请将此选项设置为 false
data 发送到服务器的数据,可以是键值对形式,也可以是json对象形式
type (默认: “GET”) 请求方式 (“POST” 或 “GET”), 默认为 “GET”
dataType 预期的返回数据的类型,取值可以是 xml, html, script, json, text, _defaul等,一般不用我们设置(根据响应头的Content-Type)
success 请求成功后的回调函数
error 请求失败时调用此函数
  • 修改Demo02Servlet:
package com.dfbz.ajax;

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

/**
 * @author lscl
 * @version 1.0
 * @intro:
 */
@WebServlet("/demo02")
public class Demo02Servlet extends HttpServlet {

    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        // 根据前端传递的参数来决定要不要出现异常
        if ("0".equals(request.getParameter("flag"))) {
            // 模拟异常
            int i = 1 / 0;
        }

        // 获取前端请求的方式
        String method = request.getMethod();

        response.setContentType("text/html;charset=utf-8");
        response.getWriter().println("请求成功!请求的方式: " + method + "");

        // 获取前端提交的参数
        Map<String, String[]> parameterMap = request.getParameterMap();

        for (String key : parameterMap.keySet()) {
            response.getWriter().println("key: " + key + "---> val: " + Arrays.toString(parameterMap.get(key)));
        }
    }
}
  • 新增按钮:
<input type="button" value="POST请求方式" onclick="fun3()">
  • JS代码:
// Ajax请求方式
function fun3() {

    $.ajax({
        url:"demo02",               // 请求的路径
        async:true,                 // 是否异步
       // data:"username=zhangsan&password=123&flag=1",           // 请求的参数
        data:{"username":"zhangsna","password":"123","flag":"1"},           // 也可以传递json对象
        type:"post",                                            // 提交的方式
        success:function(res){                                  // 成功响应的回调函数
            alert("服务器端响应的结果: " + res)
        },
        error:function(res){                                    // 失败响应的回调函数
            // res:封装了失败的信息
            alert("服务器端响应的结果: " + JSON.stringify(res))
        }
    })
}

成功的信息:

在这里插入图片描述

失败的信息:

在这里插入图片描述

3.3.4 jQuery3.0 的GET新增签名方式

jQuery3版本之后为jQuery.get()jQuery.post()这两个工具函数增加了新签名,从而使得它们和$.ajax()的接口风格保持一致。

语法:jQuery.get([settings])

参数和$.ajax([settings])一致

属性名称 解释
url 请求的服务器端url地址
async (默认: true) 默认设置下,所有请求均为异步请求。如果需要发送同步请求,请将此选项设置为 false
data 发送到服务器的数据,可以是键值对形式,也可以是json对象形式
type (默认: “GET”) 请求方式 (“POST” 或 “GET”), 默认为 “GET”,但也可以发送POST
dataType 预期的返回数据的类型,取值可以是 xml, html, script, json, text, _defaul等
success 请求成功后的回调函数
error 请求失败时调用此函数
  • 新增按钮:
<input type="button" value="3.0之后的GET方式" onclick="fun4()">
  • JS代码:
function fun4() {

    $.get({
        url: "demo02",               // 请求的路径
        async: true,                 // 是否异步
        data: "username=zhangsan&password=123&flag=1",           // 请求的参数
        type: "get",                                            // 提交的方式默认为get,也可以改为post
        success: function (res) {                                  // 成功响应的回调函数
            alert("服务器端响应的结果: " + res)
        },
        error: function (res) {                                    // 失败响应的回调函数
            // res:封装了失败的信息
            alert("服务器端响应的结果: " + JSON.stringify(res))
        }
    })
}

2.3.5 jQuery3.0 的POST新增签名方式

语法:jQuery.post([settings])

属性名称 解释
url 请求的服务器端url地址
async (默认: true) 默认设置下,所有请求均为异步请求。如果需要发送同步请求,请将此选项设置为 false
data 发送到服务器的数据,可以是键值对形式,也可以是json对象形式
type (默认: “GET”) 请求方式 (“POST” 或 “GET”), 默认为 “POST”,也可以改为GET
dataType 预期的返回数据的类型,取值可以是 xml, html, script, json, text, _defaul等
success 请求成功后的回调函数
error 请求失败时调用此函数
  • 新增按钮:
<input type="button" value="3.0之后的POST方式" onclick="fun5()">
  • JS代码:
function fun5() {

    $.post({
        url: "demo02",               // 请求的路径
        async: true,                 // 是否异步
        data: "username=zhangsan&password=123&flag=1",           // 请求的参数
        type: "post",                                            // 提交的方式默认为post,也可以改为get
        success: function (res) {                                  // 成功响应的回调函数
            alert("服务器端响应的结果: " + res)
        },
        error: function (res) {                                    // 失败响应的回调函数
            // res:封装了失败的信息
            alert("服务器端响应的结果: " + JSON.stringify(res))
        }
    })
}

2.4 测试异步和同步

同步方式与异步方式的区别:

  • 同步方式发送请求:发送一个请求,需要等待响应返回,然后才能够发送下一个请求,如果该请求没有响应,不能发送下一个请求,客户端会处于一直等待过程中。
  • 异步方式发送请求:发送一个请求,不需要等待响应返回,随时可以再发送下一个请求,即不需要等待。

  • 准备测试Servlet:
package com.dfbz.ajax;

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

/**
 * @author lscl
 * @version 1.0
 * @intro:
 */
@WebServlet("/demo03")
public class Demo03Servlet extends HttpServlet {

    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        String flag = request.getParameter("flag");

        // 根据前端传递的参数来选择是否要睡眠
        if("1".equals(flag)){
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();

            }
        }

        response.getWriter().write("hello !");
    }
}
  • 测试页面:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<button id="btn1">不阻塞</button>
<button id="btn2">阻塞</button>
<script src="js/jquery-3.5.1.min.js"></script>
<script>

    $("#btn1").click(function () {

        $.get({
            async: false,				// 同步方式发送请求
            url: "/demo03",
            success: function (res) {
                console.log(res)
            }
        })
    })


    $("#btn2").click(function () {

        $.get({
            async: true,			// 异步方式发送请求
            url: "/demo03?flag=1",
            success: function (res) {
                console.log(res)
            }
        })
    })

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

三、综合案例 :注册校验

3.1. 需求

在用户注册页面,输入用户名,当用户名输入框失去焦点时,发送异步请求,将输入框的用户名传递给服务器端进行是否存在的校验。服务器返回json字符串数据。

3.2 代码效果

  • 示例一:

在这里插入图片描述

  • 示例二:

在这里插入图片描述

3.3 完成案例功能

3.3.1 搭建项目

1)执行SQL语句:

-- ----------------------------
-- Table structure for user
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user`  (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'ID',
  `username` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '用户名',
  `password` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '密码',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 5 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO `user` VALUES (1, 'admin', '111');
INSERT INTO `user` VALUES (2, 'root', '222');
INSERT INTO `user` VALUES (3, 'zhangsan', '333');
INSERT INTO `user` VALUES (4, 'lisi', '444');

2)拷贝项目资源

jdbc.properties、DataSourceUtils等

User实体:

/**
 * @author lscl
 * @version 1.0
 * @intro:
 */
public class User {
    private Integer id;
    private String username;
    private String password;
}

在这里插入图片描述

3.3.2 完成注册校验

1)register.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>用户注册</title>
    <script src="js/jquery-3.5.1.min.js"></script>
</head>
<body>

<form id="registerForm" action="/register" method="post">
    用户名:
    <input type="text" id="username" name="username" placeholder="请输入用户名"> 
    <span id="info"></span>
    <hr>
    密码:
    <input type="password" name="password" placeholder="请输入用户名">
    <hr>
    <input type="submit">
</form>

<script>

    $("#username").blur(function () {
        $.get("check", "username=" + $(this).val(), function (res) {
            if (res == 1) {
                // 数据库已经有了这个用户
                $("#info").css("color","red")
                $("#info").text("用户名已经存在!");
                
                // 如果存在就给标签上面添加一个标识符
            	$("#info").attr("flag", "true")
            }else {
                // 数据库还没有这个用户
                
            	// 如果不存在则移除标识符
           		$("#info").removeAttr("flag")
                $("#info").css("color","green")
                $("#info").text("用户名可用!");
            }
        })
    })

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

2)CheckServlet

package com.dfbz.controller;

import com.dfbz.service.UserService;

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

/**
 * @author lscl
 * @version 1.0
 * @intro:
 */
@WebServlet("/check")
public class CheckServlet extends HttpServlet {

    private UserService userService = new UserService();

    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        String username = request.getParameter("username");

        // 根据用户名查询数据库中有几条数据
        Integer count = userService.countByUsername(username);

        if (count > 0) {

            // 代表数据库已经有了这个用户

            // 给前端写个标识
            response.getWriter().write("1");
        }else{
            response.getWriter().write("0");
        }
    }
}

3)UserService

package com.dfbz.service;

import com.dfbz.dao.UserDao;

/**
 * @author lscl
 * @version 1.0
 * @intro:
 */
public class UserService {

    private UserDao userDao = new UserDao();

    /**
     * 根据用户名查询条数
     *
     * @param username
     * @return
     */
    public Integer countByUsername(String username) {

        Integer count=userDao.countByUsername(username);

        return count;
    }
}

4)UserDao

package com.dfbz.dao;

import com.dfbz.utils.DataSourceUtils;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

/**
 * @author lscl
 * @version 1.0
 * @intro:
 */
public class UserDao {
    public Integer countByUsername(String username) {

        try {
            // 获取数据库连接
            Connection connection = DataSourceUtils.getConnection();

            PreparedStatement ps = connection.prepareStatement("select count(id) from user where username=?;");

            // 设置占位符的值
            ps.setString(1,username);

            // 执行查询
            ResultSet rs = ps.executeQuery();
            
            // 默认查询到的条数为0
            Integer count = 0;

            if (rs.next()) {
                count = rs.getInt(1);
            }
            
            // 释放资源
            DataSourceUtils.close(connection,ps,rs);
            
            return count;
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }

        return 0;
    }
}

3.3.3 完成用户注册

1)修改前端页面:

// 表单提交前的校验
$("#registerForm").submit(function () {

    var flag = $("#info").attr("flag");

    // 假设表达可以提交
    var returnVal = true;

    if (flag == 'true') {

        // 代表用户名已经存在
        returnVal = false;			// 组织表单提交
    }

    return returnVal;
})

$("#username").blur(function () {
    $.get("check", "username=" + $(this).val(), function (res) {
        if (res == 1) {
            // 数据库已经有了这个用户
            $("#info").css("color", "red")

            // 如果存在就给标签上面添加一个标识符
            $("#info").attr("flag", "true")
            $("#info").text("用户名已经存在!");
        } else {
            // 数据库还没有这个用户

            $("#info").css("color", "green")

            // 如果不存在则移除标识符
            $("#info").removeAttribute("flag")
            $("#info").text("用户名可用!");
        }
    })
})

测试:用户名已经存在则提交不了表单,用户名不存在则可以提交表单

2)RegisterServlet

package com.dfbz.controller;

import com.dfbz.entity.User;
import com.dfbz.service.UserService;

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

/**
 * @author lscl
 * @version 1.0
 * @intro:
 */
@WebServlet("/register")
public class RegisterServlet extends HttpServlet {

    private UserService userService = new UserService();

    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        String username = request.getParameter("username");
        String password = request.getParameter("password");

        User user=new User();
        user.setUsername(username);
        user.setPassword(password);

        // 用户注册
        userService.register(user);

        response.setContentType("text/html;charset=utf8");
        writer.println("<h1><a href='register.html'>重新注册</a></h1>");
    }
}

3)UserService

package com.dfbz.service;

import com.dfbz.dao.UserDao;
import com.dfbz.entity.User;

/**
 * @author lscl
 * @version 1.0
 * @intro:
 */
public class UserService {

    private UserDao userDao = new UserDao();

    /**
     * 根据用户名查询条数
     *
     * @param username
     * @return
     */
    public Integer countByUsername(String username) {

        Integer count=userDao.countByUsername(username);

        return count;
    }

    /**
     * 用户注册
     * @param user
     */
    public void register(User user) {
        userDao.save(user);
    }
}

4)UserDao

/**
 * 用户保存
 * @param user
 */
public void save(User user) {
    try {
        // 获取数据库连接
        Connection connection = DataSourceUtils.getConnection();

        PreparedStatement ps = connection.prepareStatement("insert into user values(null,?,?)");

        // 设置占位符的值
        ps.setString(1,user.getUsername());
        ps.setString(2,user.getPassword());

        // 执行插入
        ps.executeUpdate();
        
        // 释放资源
        DataSourceUtils.close(connection,ps,rs);

    } catch (SQLException throwables) {
        throwables.printStackTrace();
    }
}

四、Json

4.1 Json概述

4.4.1 什么是Json

JSON(JavaScript Object Notation, JS 对象标记)是一种轻量级的数据交换格式。采用完全独立于编程语言的文本格式来存储和表示数据。简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言。易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率。

Json是一种纯字符数据格式,不属于编程语言

4.4.2 Json的应用场景

Json由于阅读/编写方便,同时也易于机器解析和生成,所以Json数据格式常用于网络上的数据交换;

公共服务API:https://www.nowapi.com/api

  • 访问天气API:http://api.k780.com/?app=weather.today&weaId=237&appkey=10003&sign=b59bc3ef6191eb9f747dd4e83c99f2a4&format=json

在这里插入图片描述

  • 查询IP归属API接口:http://api.k780.com/?app=ip.get&ip=182.101.29.127&appkey=10003&sign=b59bc3ef6191eb9f747dd4e83c99f2a4&format=json

在这里插入图片描述

  • 全国省市区API接口:http://api.k780.com/?app=weather.city&areaType=cn&appkey=10003&sign=b59bc3ef6191eb9f747dd4e83c99f2a4&format=json

在这里插入图片描述

4.2 Json语法

  • Json数据格式一般有以下三种:
类型 语法 解释
对象类型 {“username”:“zhangsan”} 其中name是字符串类型,而value是任意类型
数组/集合类型 [value,value,value…]或[{},{},[]… …] 其中value是任何类型(比如js对象,或数组)
混合类型 {name:[],name:val…} 合理包裹嵌套对象类型和数组类型

4.2.1 简单数据

存储简单类型数据:{name:value,name:value...}

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<script>
    //json的定义
    var person = {"id": 1, "name": "小明", "address": "广西南宁"}

    //json解析
    console.log(person.id+","+person.name+","+person.address)
</script>
</body>
</html

4.2.2 集合数据

存储集合类型数据:[value,value,value...]或[{},{}... ...]

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<script>
    var persons = [
        {"id": 1, "name": "小明", "address": "广西南宁"},
        {"id": 2, "name": "小红", "address": "云南大理"},
        {"id": 3, "name": "小龙", "address": "浙江杭州"}
    ];

    for (var i = 0; i < persons.length; i++) {
        console.log(persons[i].id + "," + persons[i].name + "," + persons[i].address)
    }
</script>
</body>
</html>

4.4.3 混合数据

1)混合存储1

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<script>
    var person = {
        "id": 1,
        "name": "小龙",
        "hobby": ["唱", "跳", "rap", "篮球"]
    }

    console.log(person.id+","+person.name+","+person.hobby)
</script>
</body>
</html>

2)混合存储2

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<script>
    var schools = {
        "Java01": [
            {"id": 1, "name": "小龙", "hobby": ["唱", "篮球"]},
            {"id": 2, "name": "小红", "hobby": ["rap", "篮球"]},
        ],
        "Java02": [
            {"id": 3, "name": "小龙", "hobby": ["跳", "rap"]},
            {"id": 4, "name": "小军", "hobby": ["唱"]},
        ]
    }

    // 取小龙
    console.log(schools.Java02[0].name);

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

4.3 Json的解析

我们刚刚在学习Json的数据格式时,会发现Json在很大程度上与我们Java中的实体类非常像,在开发过程中,我们在前端通常传递Json数据到后端,后端通过JavaBean来封装Json中的数据

在这里插入图片描述

4.3.1 常见的Json解析包

工具名称 介绍
Jsonlib Java 类库,需要导入的jar包较多
Gson google提供的一个简单的json转换工具
fastjson alibaba技术团队提供的一个高性能的json转换工具
Jackson 开源免费的json转换工具,springmvc转换默认使用jackson

4.3.2 FastJson解析包

Fastjson 是一个 Java 库,可以将 Java 对象转换为 JSON 格式(序列化),当然它也可以将 JSON 字符串转换为 Java 对象(反序列化)。Fastjson 可以操作任何 Java 对象,即使是一些预先存在的没有源码的对象。

JSON类的相关方法:

  • public static String toJSONString(Object object):Java对象转Json字符串
  • public static <T> T parseObject(String text, Class<T> clazz):Json字符串转Java对象
  • public static <T> List<T> parseArray(String text, Class<T> clazz) :Json字符串转换为集合对象,并指定集合的泛型;

实体类:

public class User {
    private Integer id;
    private String username;
    private Integer age;
    private String address;
}

1)对象与Json转换

package com.dfbz.json;

import com.alibaba.fastjson.JSON;
import com.dfbz.entity.User;
import org.junit.Test;

/**
 * @author lscl
 * @version 1.0
 * @intro:
 */
public class Demo01_FastJson_Obj_Str {
    // 对象转JSON
    @Test
    public void test1() {
        User user = new User(1, "张三", 20, "山东青岛");

        String jsonUser = JSON.toJSONString(user);

        System.out.println(jsonUser);
    }

    // JSON转对象
    @Test
    public void test2() {
        String json = "{\"address\":\"山东青岛\",\"age\":20,\"id\":1,\"username\":\"张三\"}";
        User user = JSON.parseObject(json, User.class);
        System.out.println(user);
    }
    
    // Map--->Json
    @Test
    public void test31(){

        Map map=new HashMap();
        map.put("id",1);
        map.put("username","李四");
        map.put("age",30);
        map.put("address","广西贵港");

        String jsonStr = JSON.toJSONString(map);

        System.out.println(jsonStr);
    }

    // Json---->Map
    @Test
    public void test4(){
        String jsonStr ="{\"address\":\"广西贵港\",\"id\":1,\"age\":30,\"username\":\"李四\"}";

        Map map = JSON.parseObject(jsonStr, Map.class);

        System.out.println(map);
    }
}

2)集合与Json的转换

package com.dfbz.json;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.dfbz.entity.User;
import org.junit.Test;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @author lscl
 * @version 1.0
 * @intro:
 */
public class Demo02_FastJson_Array_Json {
    // List<User>转Json
    @Test
    public void test1() {
        List<User> userList = new ArrayList<>();
        userList.add(new User(1, "张三", 20, "辽宁葫芦岛"));
        userList.add(new User(2, "李四", 26, "云南昆明"));
        userList.add(new User(3, "王五", 28, "云南昆明"));
        userList.add(new User(4, "王五", 28, "西藏阿里"));

        String jsonList = JSON.toJSONString(userList);
        System.out.println(jsonList);
    }


    // JSON转List<User>
    @Test
    public void test2() {
        String json = "[{\"address\":\"辽宁葫芦岛\",\"age\":20,\"id\":1,\"username\":\"张三\"},{\"address\":\"云南昆明\",\"age\":26,\"id\":2,\"username\":\"李四\"},{\"address\":\"云南昆明\",\"age\":28,\"id\":3,\"username\":\"王五\"},{\"address\":\"西藏阿里\",\"age\":28,\"id\":4,\"username\":\"王五\"}]";

        // 使用parseObject方法也支持Json字符串转集合类型,但是泛型类型必须是JSONObject
//        List<JSONObject> userList = JSON.parseObject(json, List.class);       

        // TypeReference来完成泛型的转换
//        List<User> userList = JSON.parseObject(json, new TypeReference<List<User>>(){});

        // 或者使用parseArray来转换
        List<User> userList = JSON.parseArray(json, User.class);        // 第二个参数写的是集合中泛型的类型
        System.out.println(userList);
    }

    // parseArray和parseObject
    @Test
    public void test3() {
        String json = "[{\"demo\":\"123\"}]";

        // parseArray不支持泛型中还要指定泛型的行为(编译不通过)
//        List<Map<String,Object>> list=JSON.parseArray(json,Map.class);

        // 使用parseObject直接转换为List(会有检查提示)
//        List<Map<String,Object>> list=JSON.parseObject(json,List.class);

        // 使用TypeReference来指定泛型中的泛型
        List<Map<String,Object>> list= JSON.parseObject(json, new TypeReference<List<Map<String,Object>>>(){});
        System.out.println(list);
    }
}

3)JSONObject对象

JSONObject是FastJson包提供的用来描述一个JSON字符串的对象,实现与Map接口,并且是JSON类的子类,本质上就是一个Map集合;JSONObject可以转换为Java对象,也可以转换为Json字符串;功能强大灵活

  • JSON类的方法:

    • public static JSONObject parseObject(String text):Json字符串转换为JSONObject对象
    • public static Object toJSON(Object javaObject):将Java对象转换为JSONObject对象;
  • JSONObject类的方法:

    • public <T> T toJavaObject(Class<T> clazz):将JSONObject对象转换为对应的Java对象;
    • public String toJSONString():将JSONObject转换为Json字符串;

示例代码:

package com.dfbz.json;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.dfbz.entity.User;
import org.junit.Test;

/**
 * @author lscl
 * @version 1.0
 * @intro:
 */
public class Demo03_JSONObject {

    // Java对象转JSONObject
    @Test
    public void test1() throws Exception{
        User user = new User(1, "王五", 28, "云南昆明");

        JSONObject jsonObject = (JSONObject) JSON.toJSON(user);
        System.out.println(jsonObject);
    }

    // JSON字符串转JSONObject
    @Test
    public void test2() throws Exception{
        String jsonStr="{\"address\":\"云南昆明\",\"id\":1,\"age\":28,\"username\":\"王五\"}";

        JSONObject jsonObject = JSON.parseObject(jsonStr);

        System.out.println(jsonObject);
    }


    // JSONObject转Java对象
    @Test
    public void test3() throws Exception{
        String jsonStr="{\"address\":\"云南昆明\",\"id\":1,\"age\":28,\"username\":\"王五\"}";

        JSONObject jsonObject = JSON.parseObject(jsonStr);

        User user = jsonObject.toJavaObject(User.class);

        System.out.println(user);
    }

    // JSONObject转Json字符串
    @Test
    public void test4() throws Exception{
        String jsonStr="{\"address\":\"云南昆明\",\"id\":1,\"age\":28,\"username\":\"王五\"}";

        JSONObject jsonObject = JSON.parseObject(jsonStr);

        String str = jsonObject.toJSONString();
        System.out.println(str);
    }
}

4)SerializerFeature

SerializerFeature是一个枚举类,用于设置Json转换时相关的参数

  • SerializerFeature类中的枚举项:
属性 介绍
QuoteFieldNames 输出key时是否使用双引号,默认为true
UseSingleQuotes 使用单引号而不是双引号,默认为false
WriteMapNullValue 是否输出值为null的字段,默认为false
WriteEnumUsingToString Enum输出name()或者original,默认为false
UseISO8601DateFormat Date使用ISO8601格式输出,默认为false
WriteNullListAsEmpty List字段如果为null,输出为[],而非null
WriteNullStringAsEmpty 字符类型字段如果为null,输出为”“,而非null
WriteNullNumberAsZero 数值字段如果为null,输出为0,而非null
WriteNullBooleanAsFalse Boolean字段如果为null,输出为false,而非null
SkipTransientField 如果是true,类中的Get方法对应的Field是transient,序列化时将会被忽略。默认为true
SortField 按字段名称排序后输出,默认为false
WriteTabAsSpecial 把\t做转义输出,默认为false 不推荐
PrettyFormat 结果是否格式化,默认为false
WriteClassName 序列化时写入类型信息,默认为false。反序列化是需用到
DisableCircularReferenceDetect 消除对同一对象循环引用的问题,默认为false
WriteSlashAsSpecial 对斜杠’/’进行转义
BrowserCompatible 将中文都会序列化为\uXXXX格式,字节数会多一些,但是能兼容IE 6,默认为false
WriteDateUseDateFormat 全局修改日期格式,默认为false。JSON.DEFFAULT_DATE_FORMAT = “yyyy-MM-dd”;JSON.toJSONString(obj, SerializerFeature.WriteDateUseDateFormat);
DisableCheckSpecialChar 一个对象的字符串属性中如果有特殊字符如双引号,将会在转成json时带有反斜杠转移符。
如果不需要转义,可以使用这个属性,默认为false
BeanToArray 将对象转为array输出
  • 准备一个实体类:
public class TestEntity {
    private String id;
    private String name;
    private Integer age;
    private Boolean flag;
    private Date date;
    private User user;
}
  • 测试代码:
package com.dfbz.json;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.dfbz.entity.TestEntity;
import com.dfbz.entity.User;
import org.junit.Test;

import java.util.Date;

/**
 * @author lscl
 * @version 1.0
 * @intro:
 */
public class Demo04_FastJson_SerializerFeature {

    @Test
    public void test() {
        User user = new User(1, "老王", null, "江西新余");
        TestEntity testEntity = new TestEntity("1", null, null, null, new Date(), user);

        // {"date":1651822673004,"id":"1","user":{"address":"江西新余","id":1,"username":"老王"}}
        String jsonStr = JSON.toJSONString(testEntity);
        System.out.println(jsonStr);

        // 修改默认日期格式(默认是yyyy-MM-dd HH:mm:ss)
        JSON.DEFFAULT_DATE_FORMAT = "yyyy年MM月dd日";

        String jsonStr2 = JSON.toJSONString(
                testEntity,
                SerializerFeature.UseSingleQuotes,                      // 使用单引号
                SerializerFeature.WriteMapNullValue,                    // 保留null字段
                SerializerFeature.WriteNullStringAsEmpty,               // String的null值转换为""
                SerializerFeature.WriteNullNumberAsZero,                // 数值的null值转换为0
                SerializerFeature.WriteNullBooleanAsFalse,              // 布尔的的null值转换为false
                SerializerFeature.WriteDateUseDateFormat,               // 使用默认的格式来格式化日期
                SerializerFeature.BeanToArray,                          // Java对象转换为数组(只保留值)
                SerializerFeature.PrettyFormat                          // 格式化JSON
        );
        System.out.println(jsonStr2);
    }
}

5)FastJson常用注解

  • @JSONField
    • ordinal:序列化时的顺序,数值越小越靠前;
    • name:序列化时的名称
    • format:指定转换日期时的格式
    • serialize:是否要序列化,默认true
    • deserialize:是否要反序列化,默认true
    • serialzeFeatures:指定序列化时的一些特性

  • 编写测试实体类:
public class Emp {

    // Java对象--->Json字符串(序列化)
    // Json字符串--->Java对象(反序列化)
    @JSONField(name = "empId", ordinal = 1,defaultValue = "100")
    private Integer id;

    @JSONField(ordinal = 3,deserialize = false)
    private String username;

    @JSONField(ordinal = 2,  serialize = false)
    private Integer age;

    @JSONField(ordinal = 4, format = "yyyy-MM-dd HH:mm:ss")
    private Date birthday;
    
    @JSONField(ordinal = 5,serialzeFeatures = SerializerFeature.WriteNullBooleanAsFalse)
    private Boolean flag;
    
    // 省略get/set/toString
}
  • 测试类:
package com.dfbz.json;

import com.alibaba.fastjson.JSON;
import com.dfbz.entity.Emp;
import org.junit.Test;

import java.util.Date;

/**
 * @author lscl
 * @version 1.0
 * @intro:
 */
public class Demo05_FastJson_Annotation {

    @Test
    public void test() {
        Emp emp = new Emp(1, "张三", 20, new Date(),null);

        String jsonStr = JSON.toJSONString(emp);

        // age没有序列化,id变成了empId,日期格式化了,flag默认为false
        // {"empId":1,"username":"张三","birthday":"2022-05-06 16:50:10","flag":false}
        System.out.println(jsonStr);

        Emp emp2 = JSON.parseObject(jsonStr, Emp.class);

        // username没有反序列化
        // Emp{id=1, username='null', age=null, birthday=Fri May 06 16:50:10 CST 2022, flag=false}
        System.out.println(emp2);
    }
}
  • @JSONType
    • orders:序列化时的顺序
    • includes:只序列化那些字段
    • ignores:不序列化那些字段

  • 测试实体类:
@JSONType(
        orders = {"flag","id","username","age","birthday"},         // 序列化时的顺序
//        includes =  {"flag","id","username","age"}     // 只序列化那些字段
        ignores = {"age","birthday"}           // 不序列化那些字段
)
public class Account {

    private Integer id;

    private String username;

    private Integer age;

    private Date birthday;

    private Boolean flag;
}
  • 测试代码:
@Test
public void test2() {
    Account account = new Account(1, "张三", 20, new Date(),null);

    String jsonStr = JSON.toJSONString(account);

    // {"id":1,"username":"张三"}
    System.out.println(jsonStr);
}

4.3.3 Jackson转换工具

1)Jackson转换工具的基本使用

  • public <T> T readValue(String var1, Class<T> var2):将Json字符串转换为Java对象;
  • public String writeValueAsString(Object var1):将Java对象转换为Json字符串;
package com.dfbz.json;

import com.dfbz.entity.User;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.Test;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author lscl
 * @version 1.0
 * @intro:
 */
public class Demo01_Jackson_Obj_Json {

    // jackson转换类
    private ObjectMapper om=new ObjectMapper();

    // 对象转JSON
    @Test
    public void test1() throws JsonProcessingException {
        User user=new User(1,"张三",20,"山东青岛");

        String jsonUser = om.writeValueAsString(user);

        System.out.println(jsonUser);

    }

    // JSON转对象
    @Test
    public void test2() throws IOException {
        String json="{\"address\":\"山东青岛\",\"age\":20,\"id\":1,\"username\":\"张三\"}";

        User user = om.readValue(json, User.class);

        System.out.println(user);
    }


    // Map转JSON
    @Test
    public void test3() throws JsonProcessingException {

        Map<String,Object> map=new HashMap<>();
        map.put("id",1);
        map.put("username","李四");
        map.put("age",25);
        map.put("address","甘肃酒泉");

        String jsonMap = om.writeValueAsString(map);
        System.out.println(jsonMap);
    }


    // JSON转Map
    @Test
    public void test4() throws IOException {

        String json="{\"address\":\"甘肃酒泉\",\"id\":1,\"age\":25,\"username\":\"李四\"}";

        Map map = om.readValue(json, Map.class);
        System.out.println(map);
    }


    // List<User>转Json
    @Test
    public void test5() throws JsonProcessingException {
        List<User> userList=new ArrayList<>();
        userList.add(new User(1,"张三",20,"辽宁葫芦岛"));
        userList.add(new User(2,"李四",26,"云南昆明"));
        userList.add(new User(3,"王五",28,"云南昆明"));
        userList.add(new User(4,"王五",28,"西藏阿里"));

        String jsonList = om.writeValueAsString(userList);
        System.out.println(jsonList);
    }


    // JSON转List<User>
    @Test
    public void test6() throws IOException {
        String json="[{\"address\":\"辽宁葫芦岛\",\"age\":20,\"id\":1,\"username\":\"张三\"},{\"address\":\"云南昆明\",\"age\":26,\"id\":2,\"username\":\"李四\"},{\"address\":\"云南昆明\",\"age\":28,\"id\":3,\"username\":\"王五\"},{\"address\":\"西藏阿里\",\"age\":28,\"id\":4,\"username\":\"王五\"}]";

        // java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to com.dfbz.entity.User
//        List<User> list =  om.readValue(userListJson, List.class);        // 默认情况下Jackson会把集合中的泛型都转换为LinkedHashMap类型
        
        // JSON转集合时,如果要确定集合中的泛型类则需要使用TypeReference来处理
        List<User> list =  om.readValue(userListJson, new TypeReference<List<User>>(){});

        for (User user : list) {
            System.out.println(user);
        }
    }
}

2)Jackson常用注解

  • 测试实体类:
// 序列化时忽略age,flag
@JsonIgnoreProperties({"age","flag"})
public class Emp {

    // 序列化时时使用empId
    @JsonProperty("empId")
    private Integer id;

    // 序列化时忽略username
    @JsonIgnore
    private String username;

    private Integer age;

    // 格式化日期
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private Date birthday;

    private Boolean flag;
}
  • 测试类:
package com.dfbz.json;

import com.dfbz.entity.Emp;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.Test;

import java.util.Date;

/**
 * @author lscl
 * @version 1.0
 * @intro:
 */
public class Demo02_Jackson_Annotation {

    // jackson转换类
    private ObjectMapper om=new ObjectMapper();

    @Test
    public void test1() throws Exception {
        Emp emp = new Emp(1,"张三",20,new Date(), true);

        String jsonStr = om.writeValueAsString(emp);

        // {"birthday":"2022-05-06 12:58:24","empId":1}
        System.out.println(jsonStr);
    }
}

五、综合案例:自动补全案例

案例效果:

在这里插入图片描述

思路:监听键盘输入框的键盘抬起事件,当键盘抬起时,带上用户输入的值,发送ajax请求来到后端模糊查询数据库,最终将数据发送给前端进行渲染

5.1 搭建项目

SQL语句:

-- ----------------------------
-- Table structure for goods
-- ----------------------------
DROP TABLE IF EXISTS `goods`;
CREATE TABLE `goods`  (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `title` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `content` varchar(2550) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 7 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of goods
-- ----------------------------
INSERT INTO `goods` VALUES (1, 'vivo游戏手机', 'vivo iQOO Neo3 5G 8GB+128GB 夜幕黑 高通骁龙865 144Hz竞速屏 立体双扬 44W闪充 双模5G全网通手机');
INSERT INTO `goods` VALUES (2, '小米游戏笔记本', 'RedmiBook 14 二代 超轻薄全金属(第十代英特尔酷睿i5-1035G1 16G 512G MX350 100%sRGB高色域)银 笔记本电脑');
INSERT INTO `goods` VALUES (3, '神舟战神笔记本', '神舟战神Z7/Z8系列十代酷睿六核i5/i7/GTX1650Ti/RTX3060独显游戏笔记本电脑 Z7-CU5高配版:16G+512G/1650Ti');
INSERT INTO `goods` VALUES (4, '神舟游戏笔记本', '\r\n神舟(HASEE)战神ZX6TI-CU5DA 英特尔酷睿i5-10400 GTX1650TI 4G 15.6英寸144Hz游戏笔记本(8G 512G SSD IPS)神舟(HASEE)战神ZX6TI-CU5DA 英特尔酷睿i5-10400 GTX1650TI 4G 15.6英寸144Hz游戏笔记本(8G 512G SSD IPS)神舟(HASEE)战神ZX6TI-CU5DA 英特尔酷睿i5-10400 GTX1650TI 4G 15.6英寸144Hz游戏笔记本(8G 512G SSD IPS)神舟(HASEE)战神ZX6TI-CU5DA 英特尔酷睿i5-10400 GTX1650TI 4G 15.6英寸144Hz游戏笔记本(8G 512G SSD IPS)神舟(HASEE)战神ZX6TI-CU5DA 英特尔酷睿i5-10400 GTX1650TI 4G 15.6英寸144Hz游戏笔记本(8G 512G SSD IPS)\r\n关注 分享 对比举报\r\n企业购更优惠\r\n神舟(HASEE)战神ZX6TI-CU5DA 英特尔酷睿i5-10400 GTX1650TI 4G 15.6英寸144Hz游戏笔记本(8G 512G SSD IPS)');
INSERT INTO `goods` VALUES (5, 'vivoiQOO Z1手机', 'vivo iQOO Z1 8GB+128GB 星河银 天玑1000Plus旗舰芯片 144Hz竞速屏 44W超快闪充 双模5G全网通手机 iqooz1');
INSERT INTO `goods` VALUES (6, '小米拍照手机', 'Redmi 9A 5000mAh大电量 大屏幕大字体大音量 1300万AI相机 八核处理器 人脸解锁 4GB+64GB 晴空蓝 游戏智能手机 小米 红米');

Goods实体类:

package com.dfbz.entity;

public class Goods {
    private Integer id;
    private String title;
    private String content;
}

jdbc.properties:

username=root
password=admin
url=jdbc:mysql://localhost:3306/test
driverClassName=com.mysql.jdbc.Driver
# 最大连接数
maxActive=50
# 初始化连接数
initialSize=10

5.2 SearchServlet:

package com.dfbz.controller;

import com.alibaba.fastjson.JSON;
import com.dfbz.entity.Goods;
import com.dfbz.service.GoodsService;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;

@WebServlet("/search")
public class SearchServlet extends HttpServlet {

    private GoodsService goodsService=new GoodsService();
    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        request.setCharacterEncoding("UTF-8");

        // 响应类型改为json
        response.setContentType("application/json;charset=utf8");

        // 接收前端传递的参数
        String title = request.getParameter("title");

        // 根据商品标题模糊查询商品
        List<Goods> goodsList = goodsService.findByTitleLike(title);

        // 在后台打印出来
        System.out.println(goodsList);
        // 把商品集合转成json字符串
        String jsonGoodsList = JSON.toJSONString(goodsList);

        // 写回给前端
        response.getWriter().write(jsonGoodsList);
    }
}

5.3 GoodsService:

package com.dfbz.service;

import com.dfbz.dao.GoodsDao;
import com.dfbz.entity.Goods;

import java.util.List;

public class GoodsService {
    private GoodsDao goodsDao=new GoodsDao();

    /**
     * 根据商品标题模糊查询商品
     * @param title
     * @return
     */
    public List<Goods> findByTitleLike(String title){
        return goodsDao.findByTitleLike(title);
    }
}

5.4 GoodsDao:

package com.dfbz.dao;

import com.dfbz.entity.Goods;
import com.dfbz.utils.DataSourceUtils;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

public class GoodsDao {

    /**
     * 根据商品标题模糊查询商品
     * @param title
     * @return
     */
    public List<Goods> findByTitleLike(String title) {

        try {
            Connection connection = DataSourceUtils.getConnection();
            PreparedStatement ps = connection.prepareStatement("select * from goods where title like ?");

            // 设置占位符的值(注意要拼接 %%,模糊查询)
            ps.setString(1, "%" + title + "%");

            List<Goods> goodsList = new ArrayList<>();
            ResultSet rs = ps.executeQuery();

            while (rs.next()) {

                int id = rs.getInt("id");
                String dbTitle = rs.getString("title");
                String content = rs.getString("content");
                goodsList.add(new Goods(id, dbTitle, content));
            }

            return goodsList;

        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }

        return null;

    }
}

5.5 前端页面

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

    <style>
        #content {
            width: 800px;
            padding: 20px;
            border: 2px solid #6622ff
        }
    </style>
    <script src="js/jquery-3.5.1.min.js"></script>
</head>
<body>
<h3>请输入您要购买的商品</h3>
<input type="text" placeholder="请输入您要购买的商品" id="title">
<hr>
<div id="content">
    <div>
        <h4>小米5G游戏手机</h4>
        <p>一亿像素夜景相机 / 120Hz六档变速高刷屏 / 国内首发骁龙750G / 6.67"小孔径全面屏 / 立体声双扬声器 </p>
        <hr>
    </div>
    <div>
        <h4>华为4G拍照手机</h4>
        <p>骁龙888|2K AMOLED 四曲面柔性屏|1亿像素三摄|时尚轻薄机身 </p>
        <hr>
    </div>
    <div>
        <h4>联想笔记本</h4>
        <p>
            联想(Lenovo)小新Air15 2021锐龙版全面屏办公轻薄笔记本电脑(8核R7-4800U 16G 512G 100%sRGB 高色域)深空灰联想(Lenovo)
        </p>
        <hr>
    </div>
</div>

<script>

    // 监听键盘抬起
    $("#title").keyup(function () {

        $.ajax({
            url:"search",
            data:{title: $(this).val()},
            success:function (res) {

                var contentHtml = "";
                // 循环拼接字符串
                for (let i = 0; i < res.length; i++) {

                    contentHtml += "<div>\n" +
                        "        <h4>" + res[i].title + "</h4>\n" +
                        "        <p>" + res[i].content + "</p>\n" +
                        "        <hr>\n" +
                        "    </div>";
                }

                // 将内容填充到div中
                $("#content").html(contentHtml);
            }
        })
    })

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

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/131638.html

(0)
飞熊的头像飞熊bm

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!