1、 AJAX

1.1 概述

AJAX (Asynchronous JavaScript And XML):异步的 JavaScript 和 XML。

1.1.1 作用

  1. 与服务器进行数据交换

    • 使用JSP

      • 浏览器发送请求Servlet
      • Servlet调用完业务逻辑层之后,将数据存储到Request域对象
      • 转发到对应JSP进行展示(将JSP作为视图)
    • 使用AJAX:AJAX可以给服务器发送请求,并获取服务器响应的数据

      使用AJAX+HTML替换JSP

      • 浏览器发送请求Servlet
      • Servlet调用完业务逻辑层后将数据通过AJAX直接响应回给浏览器页面
      • 页面使用HTML来进行数据展示
  2. 异步交互

    • 可以在不重新加载整个页面的情况下,与服务器交换数据并更新部分网页的技术,如:搜索联想、用户名是否可用校验,点击关注,点击收藏,等等…

1.1.2 同步和异步

  • 同步发送请求的过程

    • 客户端访问服务器
    • 服务器处理客户端请求
    • 服务器返回处理结果到客户端
    • 客户端进行其他请求
  • 异步发送请求的过程:不用等待服务器端

    • 客户端访问服务器
    • 服务器处理客户端请求(期间客户端可进行其他操作)
    • 服务器返回处理结果到客户端
    • 客户端进行其他请求

1.2 快速入门

1.2.1 服务端实现

  • 编写Servlet

    package priv.dandelion.controller.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;
    
    @WebServlet("/ajaxDemo")
    public class AjaxDemo extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            // 响应数据
            resp.getWriter().write("hello ajax~");
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            this.doGet(req, resp);
        }
    }
    

1.2.2 客户端实现

  • 步骤说明

    1. 创建xhttp核心对象
    2. 建立连接
    3. 发送请求
    4. 获取响应
  • 完整代码

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>AJAX-demo1</title>
    </head>
    <body>
    
    <script>
    
        // 创建核心对象
        var xhttp;
        if (window.XMLHttpRequest) {
            xhttp = new XMLHttpRequest();
        } else {
            // code for IE6, IE5
            xhttp = new ActiveXObject("Microsoft.XMLHTTP");
        }
    
        // 建立连接(包含第三个参数,为true是异步,默认异步,此处省略)
        xhttp.open("GET", "http://localhost:8080/ajax-demo/ajaxDemo");
    
        // 发送请求
        xhttp.send();
    
        // 获取响应,监听到onreadystatechange就绪状态事件,事件发生变化时执行函数
        xhttp.onreadystatechange = function() {
            // this.readyState == 4 表示请求发送结束且响应就绪,this.status == 200表示成功收到响应
            if (this.readyState == 4 && this.status == 200) {
                // 通过 this.responseText 可以获取到服务端响应的数据
                alert(this.responseText);
            }
        };
    
    </script>
    
    </body>
    </html>
    

1.3 案例

1.3.1 需求

  • 用户注册功能

  • 在用户名输入框失去焦点时,校验该用户名是否存在,并在页面中给出提示

1.3.2 分析

  • 前端

    1. 给用户名输入框绑定光标失去焦点事件onblur
    2. 发送ajax请求,携带username参数
  • 后端

    1. 接收用户名
    2. 调用service查询User
    3. 返回标记

1.3.2 后端实现

  • 环境准备

    • 依赖

      <?xml version="1.0" encoding="UTF-8"?>
      
      <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
          <modelVersion>4.0.0</modelVersion>
      
          <groupId>priv.dandelion</groupId>
          <artifactId>ajax-demo</artifactId>
          <version>1.0-SNAPSHOT</version>
          <packaging>war</packaging>
      
          <properties>
              <maven.compiler.source>8</maven.compiler.source>
              <maven.compiler.target>8</maven.compiler.target>
          </properties>
      
          <dependencies>
              <!-- junit单元测试依赖 -->
              <dependency>
                  <groupId>junit</groupId>
                  <artifactId>junit</artifactId>
                  <version>4.11</version>
                  <scope>test</scope>
              </dependency>
              <!--mybatis 依赖-->
              <dependency>
                  <groupId>org.mybatis</groupId>
                  <artifactId>mybatis</artifactId>
                  <version>3.5.5</version>
              </dependency>
              <!--mysql 驱动-->
              <dependency>
                  <groupId>mysql</groupId>
                  <artifactId>mysql-connector-java</artifactId>
                  <version>5.1.46</version>
              </dependency>
              <!-- 添加slf4j日志api -->
              <dependency>
                  <groupId>org.slf4j</groupId>
                  <artifactId>slf4j-api</artifactId>
                  <version>1.7.20</version>
              </dependency>
              <!-- 添加logback-classic依赖 -->
              <dependency>
                  <groupId>ch.qos.logback</groupId>
                  <artifactId>logback-classic</artifactId>
                  <version>1.2.3</version>
              </dependency>
              <!-- 添加logback-core依赖 -->
              <dependency>
                  <groupId>ch.qos.logback</groupId>
                  <artifactId>logback-core</artifactId>
                  <version>1.2.3</version>
              </dependency>
              <!-- servlet依赖 -->
              <dependency>
                  <groupId>javax.servlet</groupId>
                  <artifactId>javax.servlet-api</artifactId>
                  <version>3.1.0</version>
                  <scope>provided</scope>
              </dependency>
              <!-- JSP依赖 -->
              <dependency>
                  <groupId>javax.servlet.jsp</groupId>
                  <artifactId>jsp-api</artifactId>
                  <version>2.2</version>
                  <scope>provided</scope>
              </dependency>
              <!-- JSTL依赖 -->
              <dependency>
                  <groupId>jstl</groupId>
                  <artifactId>jstl</artifactId>
                  <version>1.2</version>
              </dependency>
              <!-- JSTL标准标签库依赖 -->
              <dependency>
                  <groupId>taglibs</groupId>
                  <artifactId>standard</artifactId>
                  <version>1.1.2</version>
              </dependency>
          </dependencies>
      
          <build>
              <plugins>
                  <plugin>
                      <!-- tomcat插件 -->
                      <groupId>org.apache.tomcat.maven</groupId>
                      <artifactId>tomcat7-maven-plugin</artifactId>
                      <version>2.2</version>
                  </plugin>
              </plugins>
          </build>
      
      </project>
      
      
    • SQL

      -- 删除tb_user表
      drop table if exists tb_user;
      -- 创建用户表
      CREATE TABLE tb_user(
      	id int primary key auto_increment,
      	username varchar(20) unique,
      	password varchar(32)
      );
      
      -- 添加数据
      INSERT INTO tb_user(username,password) values('zhangsan','123'),('lisi','234');
      
      SELECT * FROM tb_user;
      
      
    • 静态页面

      • CSS

        * {
            margin: 0;
            padding: 0;
            list-style-type: none;
        }
        .reg-content{
            padding: 30px;
            margin: 3px;
        }
        a, img {
            border: 0;
        }
        
        body {
            background-image: url("../imgs/reg_bg_min.jpg") ;
            text-align: center;
        }
        
        table {
            border-collapse: collapse;
            border-spacing: 0;
        }
        
        td, th {
            padding: 0;
            height: 90px;
        
        }
        .inputs{
            vertical-align: top;
        }
        
        .clear {
            clear: both;
        }
        
        .clear:before, .clear:after {
            content: "";
            display: table;
        }
        
        .clear:after {
            clear: both;
        }
        
        .form-div {
            background-color: rgba(255, 255, 255, 0.27);
            border-radius: 10px;
            border: 1px solid #aaa;
            width: 424px;
            margin-top: 150px;
            margin-left:1050px;
            padding: 30px 0 20px 0px;
            font-size: 16px;
            box-shadow: inset 0px 0px 10px rgba(255, 255, 255, 0.5), 0px 0px 15px rgba(75, 75, 75, 0.3);
            text-align: left;
        }
        
        .form-div input[type="text"], .form-div input[type="password"], .form-div input[type="email"] {
            width: 268px;
            margin: 10px;
            line-height: 20px;
            font-size: 16px;
        }
        
        .form-div input[type="checkbox"] {
            margin: 20px 0 20px 10px;
        }
        
        .form-div input[type="button"], .form-div input[type="submit"] {
            margin: 10px 20px 0 0;
        }
        
        .form-div table {
            margin: 0 auto;
            text-align: right;
            color: rgba(64, 64, 64, 1.00);
        }
        
        .form-div table img {
            vertical-align: middle;
            margin: 0 0 5px 0;
        }
        
        .footer {
            color: rgba(64, 64, 64, 1.00);
            font-size: 12px;
            margin-top: 30px;
        }
        
        .form-div .buttons {
            float: right;
        }
        
        input[type="text"], input[type="password"], input[type="email"] {
            border-radius: 8px;
            box-shadow: inset 0 2px 5px #eee;
            padding: 10px;
            border: 1px solid #D4D4D4;
            color: #333333;
            margin-top: 5px;
        }
        
        input[type="text"]:focus, input[type="password"]:focus, input[type="email"]:focus {
            border: 1px solid #50afeb;
            outline: none;
        }
        
        input[type="button"], input[type="submit"] {
            padding: 7px 15px;
            background-color: #3c6db0;
            text-align: center;
            border-radius: 5px;
            overflow: hidden;
            min-width: 80px;
            border: none;
            color: #FFF;
            box-shadow: 1px 1px 1px rgba(75, 75, 75, 0.3);
        }
        
        input[type="button"]:hover, input[type="submit"]:hover {
            background-color: #5a88c8;
        }
        
        input[type="button"]:active, input[type="submit"]:active {
            background-color: #5a88c8;
        }
        .err_msg{
            color: red;
            padding-right: 170px;
        }
        #password_err,#tel_err{
            padding-right: 195px;
        }
        
        #reg_btn{
            margin-right:50px; width: 285px; height: 45px; margin-top:20px;
        }
        
        #checkCode{
            width: 100px;
        }
        
        #changeImg{
            color: aqua;
        }
        
      • HTML

        <!DOCTYPE html>
        <html lang="en">
        <head>
            <meta charset="UTF-8">
            <title>欢迎注册</title>
            <link href="css/register.css" rel="stylesheet">
        </head>
        <body>
        
        <div class="form-div">
            <div class="reg-content">
                <h1>欢迎注册</h1>
                <span>已有帐号?</span> <a href="login.html">登录</a>
            </div>
            <form id="reg-form" action="#" method="get">
        
                <table>
        
                    <tr>
                        <td>用户名</td>
                        <td class="inputs">
                            <input name="username" type="text" id="username">
                            <br>
                            <span id="username_err" class="err_msg" style="display: none">用户名不太受欢迎</span>
                        </td>
        
                    </tr>
        
                    <tr>
                        <td>密码</td>
                        <td class="inputs">
                            <input name="password" type="password" id="password">
                            <br>
                            <span id="password_err" class="err_msg" style="display: none">密码格式有误</span>
                        </td>
                    </tr>
        
        
                    <tr>
                        <td>验证码</td>
                        <td class="inputs">
                            <input name="checkCode" type="text" id="checkCode">
                            <img src="imgs/a.jpg">
                            <a href="#" id="changeImg">看不清?</a>
                        </td>
                    </tr>
        
                </table>
        
                <div class="buttons">
                    <input value="注 册" type="submit" id="reg_btn">
                </div>
                <br class="clear">
            </form>
        
        </div>
        </body>
        </html>
        
    • 数据库

      • 核心配置文件

        <?xml version="1.0" encoding="UTF-8" ?>
        <!DOCTYPE configuration
                PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
                "http://mybatis.org/dtd/mybatis-3-config.dtd">
        <configuration>
            <!--起别名-->
            <typeAliases>
                <package name="priv.dandelion.entity"/>
            </typeAliases>
        
            <environments default="development">
                <environment id="development">
                    <!-- 采用JDBC的事务管理方式 -->
                    <transactionManager type="JDBC"/>
                    <!-- 数据库连接信息 -->
                    <dataSource type="POOLED">
                        <property name="driver" value="com.mysql.jdbc.Driver"/>
                        <!-- value的值一定不能换行,一定!一定!不能换行 -->
                        <property name="url" value="jdbc:mysql:///db1?useSSL=false&amp;useUnicode=true&amp;characterEncoding=utf-8&amp;useServerPrepStmts=true"/>
                        <property name="username" value="root"/>
                        <property name="password" value="123456"/>
                    </dataSource>
                </environment>
            </environments>
            <!-- 扫描mapper,加载SQL映射文件 -->
            <mappers>
                <package name="priv.dandelion.dao"/>
            </mappers>
        </configuration>
        
      • Mapper映射文件

        <?xml version="1.0" encoding="UTF-8" ?>
        <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
        <mapper namespace="priv.dandelion.dao.UserMapper">
        </mapper>
        
    • 工具类

      • 获取SqlSessionFactory

        package priv.dandelion.utils;
        
        import org.apache.ibatis.io.Resources;
        import org.apache.ibatis.session.SqlSessionFactory;
        import org.apache.ibatis.session.SqlSessionFactoryBuilder;
        
        import java.io.IOException;
        import java.io.InputStream;
        
        public class SqlSessionFactoryUtils {
        
            // 提升作用域,用于再方法内进行返回
            private static SqlSessionFactory sqlSessionFactory;
        
            // 静态代码块会随着类的加载自动执行且只执行一次
            static {
                String resource = "mybatis-config.xml";
                InputStream inputStream = null;
                try {
                    inputStream = Resources.getResourceAsStream(resource);
                } catch (IOException e) {
                    e.printStackTrace();
                }
                sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
            }
        
            public static SqlSessionFactory getSqlSessionFactory() {
                return sqlSessionFactory;
            }
        
        }
        
      • 重编码ISO-8859-1为UTF-8

        package priv.dandelion.utils;
        
        import java.nio.charset.StandardCharsets;
        
        public class ReEncoding {
        
            public static String reEncodingToUtf8(String str) {
                // 使用ISO-8859-1编码将乱码字符编回二进制码,得到其字节数组
                byte[] bytes = str.getBytes(StandardCharsets.ISO_8859_1);
                // 将字节数组使用UTF-8重新编码
                return new String(bytes, StandardCharsets.UTF_8);
            }
        }
        
      • 验证码生成

        package priv.dandelion.utils;
        
        import javax.imageio.ImageIO;
        import java.awt.*;
        import java.awt.geom.AffineTransform;
        import java.awt.image.BufferedImage;
        import java.io.File;
        import java.io.FileOutputStream;
        import java.io.IOException;
        import java.io.OutputStream;
        import java.util.Arrays;
        import java.util.Random;
        
        /**
         * 生成验证码工具类
         */
        public class CheckCodeUtil {
        
            public static final String VERIFY_CODES = "123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
            private static Random random = new Random();
        
        
        
            /**
             * 输出随机验证码图片流,并返回验证码值(一般传入输出流,响应response页面端,Web项目用的较多)
             *
             * @param width 图片宽度
             * @param height 图片高度
             * @param os 输出流
             * @param verifySize 验证码长度
             * @return String
             * @throws IOException
             */
            public static String outputVerifyImage(int width, int height, OutputStream os, int verifySize) throws IOException {
                String verifyCode = generateVerifyCode(verifySize);
                outputImage(width, height, os, verifyCode);
                return verifyCode;
            }
        
            /**
             * 使用系统默认字符源生成验证码
             *
             * @param verifySize 验证码长度
             * @return
             */
            public static String generateVerifyCode(int verifySize) {
                return generateVerifyCode(verifySize, VERIFY_CODES);
            }
        
            /**
             * 使用指定源生成验证码
             *
             * @param verifySize 验证码长度
             * @param sources    验证码字符源
             * @return
             */
            public static String generateVerifyCode(int verifySize, String sources) {
                // 未设定展示源的字码,赋默认值大写字母+数字
                if (sources == null || sources.length() == 0) {
                    sources = VERIFY_CODES;
                }
                int codesLen = sources.length();
                Random rand = new Random(System.currentTimeMillis());
                StringBuilder verifyCode = new StringBuilder(verifySize);
                for (int i = 0; i < verifySize; i++) {
                    verifyCode.append(sources.charAt(rand.nextInt(codesLen - 1)));
                }
                return verifyCode.toString();
            }
        
            /**
             * 生成随机验证码文件,并返回验证码值 (生成图片形式,用的较少)
             *
             * @param w
             * @param h
             * @param outputFile
             * @param verifySize
             * @return
             * @throws IOException
             */
            public static String outputVerifyImage(int w, int h, File outputFile, int verifySize) throws IOException {
                String verifyCode = generateVerifyCode(verifySize);
                outputImage(w, h, outputFile, verifyCode);
                return verifyCode;
            }
        
        
        
            /**
             * 生成指定验证码图像文件
             *
             * @param w
             * @param h
             * @param outputFile
             * @param code
             * @throws IOException
             */
            public static void outputImage(int w, int h, File outputFile, String code) throws IOException {
                if (outputFile == null) {
                    return;
                }
                File dir = outputFile.getParentFile();
                //文件不存在
                if (!dir.exists()) {
                    //创建
                    dir.mkdirs();
                }
                try {
                    outputFile.createNewFile();
                    FileOutputStream fos = new FileOutputStream(outputFile);
                    outputImage(w, h, fos, code);
                    fos.close();
                } catch (IOException e) {
                    throw e;
                }
            }
        
            /**
             * 输出指定验证码图片流
             *
             * @param w
             * @param h
             * @param os
             * @param code
             * @throws IOException
             */
            public static void outputImage(int w, int h, OutputStream os, String code) throws IOException {
                int verifySize = code.length();
                BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
                Random rand = new Random();
                Graphics2D g2 = image.createGraphics();
                g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        
                // 创建颜色集合,使用java.awt包下的类
                Color[] colors = new Color[5];
                Color[] colorSpaces = new Color[]{Color.WHITE, Color.CYAN,
                        Color.GRAY, Color.LIGHT_GRAY, Color.MAGENTA, Color.ORANGE,
                        Color.PINK, Color.YELLOW};
                float[] fractions = new float[colors.length];
                for (int i = 0; i < colors.length; i++) {
                    colors[i] = colorSpaces[rand.nextInt(colorSpaces.length)];
                    fractions[i] = rand.nextFloat();
                }
                Arrays.sort(fractions);
                // 设置边框色
                g2.setColor(Color.GRAY);
                g2.fillRect(0, 0, w, h);
        
                Color c = getRandColor(200, 250);
                // 设置背景色
                g2.setColor(c);
                g2.fillRect(0, 2, w, h - 4);
        
                // 绘制干扰线
                Random random = new Random();
                // 设置线条的颜色
                g2.setColor(getRandColor(160, 200));
                for (int i = 0; i < 20; i++) {
                    int x = random.nextInt(w - 1);
                    int y = random.nextInt(h - 1);
                    int xl = random.nextInt(6) + 1;
                    int yl = random.nextInt(12) + 1;
                    g2.drawLine(x, y, x + xl + 40, y + yl + 20);
                }
        
                // 添加噪点
                // 噪声率
                float yawpRate = 0.05f;
                int area = (int) (yawpRate * w * h);
                for (int i = 0; i < area; i++) {
                    int x = random.nextInt(w);
                    int y = random.nextInt(h);
                    // 获取随机颜色
                    int rgb = getRandomIntColor();
                    image.setRGB(x, y, rgb);
                }
                // 添加图片扭曲
                shear(g2, w, h, c);
        
                g2.setColor(getRandColor(100, 160));
                int fontSize = h - 4;
                Font font = new Font("Algerian", Font.ITALIC, fontSize);
                g2.setFont(font);
                char[] chars = code.toCharArray();
                for (int i = 0; i < verifySize; i++) {
                    AffineTransform affine = new AffineTransform();
                    affine.setToRotation(Math.PI / 4 * rand.nextDouble() * (rand.nextBoolean() ? 1 : -1), (w / verifySize) * i + fontSize / 2, h / 2);
                    g2.setTransform(affine);
                    g2.drawChars(chars, i, 1, ((w - 10) / verifySize) * i + 5, h / 2 + fontSize / 2 - 10);
                }
        
                g2.dispose();
                ImageIO.write(image, "jpg", os);
            }
        
            /**
             * 随机颜色
             *
             * @param fc
             * @param bc
             * @return
             */
            private static Color getRandColor(int fc, int bc) {
                if (fc > 255) {
                    fc = 255;
                }
                if (bc > 255) {
                    bc = 255;
                }
                int r = fc + random.nextInt(bc - fc);
                int g = fc + random.nextInt(bc - fc);
                int b = fc + random.nextInt(bc - fc);
                return new Color(r, g, b);
            }
        
            private static int getRandomIntColor() {
                int[] rgb = getRandomRgb();
                int color = 0;
                for (int c : rgb) {
                    color = color << 8;
                    color = color | c;
                }
                return color;
            }
        
            private static int[] getRandomRgb() {
                int[] rgb = new int[3];
                for (int i = 0; i < 3; i++) {
                    rgb[i] = random.nextInt(255);
                }
                return rgb;
            }
        
            private static void shear(Graphics g, int w1, int h1, Color color) {
                shearX(g, w1, h1, color);
                shearY(g, w1, h1, color);
            }
        
            private static void shearX(Graphics g, int w1, int h1, Color color) {
        
                int period = random.nextInt(2);
        
                boolean borderGap = true;
                int frames = 1;
                int phase = random.nextInt(2);
        
                for (int i = 0; i < h1; i++) {
                    double d = (double) (period >> 1)
                            * Math.sin((double) i / (double) period
                            + (6.2831853071795862D * (double) phase)
                            / (double) frames);
                    g.copyArea(0, i, w1, 1, (int) d, 0);
                    if (borderGap) {
                        g.setColor(color);
                        g.drawLine((int) d, i, 0, i);
                        g.drawLine((int) d + w1, i, w1, i);
                    }
                }
        
            }
        
            private static void shearY(Graphics g, int w1, int h1, Color color) {
        
                int period = random.nextInt(40) + 10; // 50;
        
                boolean borderGap = true;
                int frames = 20;
                int phase = 7;
                for (int i = 0; i < w1; i++) {
                    double d = (double) (period >> 1)
                            * Math.sin((double) i / (double) period
                            + (6.2831853071795862D * (double) phase)
                            / (double) frames);
                    g.copyArea(i, 0, 1, h1, 0, (int) d);
                    if (borderGap) {
                        g.setColor(color);
                        g.drawLine(i, (int) d, i, 0);
                        g.drawLine(i, (int) d + h1, i, h1);
                    }
        
                }
        
            }
        }
        
    • 实体类

      • User

        package priv.dandelion.entity;
        
        public class User {
            private Integer id;
            private String username;
            private String password;
        
            public User(Integer id, String username, String password) {
                this.id = id;
                this.username = username;
                this.password = password;
            }
        
            public User() {
            }
        
            public Integer getId() {
                return id;
            }
        
            public void setId(Integer id) {
                this.id = id;
            }
        
            public String getUsername() {
                return username;
            }
        
            public void setUsername(String username) {
                this.username = username;
            }
        
            public String getPassword() {
                return password;
            }
        
            public void setPassword(String password) {
                this.password = password;
            }
        
            @Override
            public String toString() {
                return "User{" +
                        "id=" + id +
                        ", username='" + username + '\'' +
                        ", password='" + password + '\'' +
                        '}';
            }
        }
        
  • 编码

    • Dao

      • UserMapper

        package priv.dandelion.dao;
        
        import org.apache.ibatis.annotations.Param;
        import org.apache.ibatis.annotations.Select;
        import priv.dandelion.entity.User;
        
        import java.util.List;
        
        public interface UserMapper {
            @Select("select * from tb_user where username = #{name}")
            public User selectByName(@Param("name") String name);
        }
        
    • Service

      • UserService

        package priv.dandelion.service;
        
        import org.apache.ibatis.session.SqlSession;
        import org.apache.ibatis.session.SqlSessionFactory;
        import priv.dandelion.dao.UserMapper;
        import priv.dandelion.entity.User;
        import priv.dandelion.utils.SqlSessionFactoryUtils;
        
        public class UserService {
        
            private SqlSessionFactory factory = SqlSessionFactoryUtils.getSqlSessionFactory();
        
            public boolean selectUsername(String username) {
                // 获取SqlSession
                SqlSession sqlSession = factory.openSession(true);
                // 获取UserMapper
                UserMapper mapper = sqlSession.getMapper(UserMapper.class);
                // 调用dao
                User user = mapper.selectByName(username);
                // 释放资源
                sqlSession.close();
                return user != null;
            }
        
        }
        
    • Controller - Servlet

      • 用户名是否存在

        package priv.dandelion.controller.servlet;
        
        import priv.dandelion.service.UserService;
        import priv.dandelion.utils.ReEncoding;
        
        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;
        
        @WebServlet("/selectUsername")
        public class SelectUsernameServlet extends HttpServlet {
        
            UserService service = new UserService();
        
            @Override
            protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
                // 接收用户名
                String username = req.getParameter("username");
                // 调用Service查询User
                boolean flag = service.selectUsername(username);
                // 响应标记
                resp.getWriter().write("" + flag);
            }
        
            @Override
            protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
                this.doGet(req, resp);
            }
        }
        
        
      • 展示验证码

        package priv.dandelion.controller.servlet;
        
        import priv.dandelion.utils.CheckCodeUtil;
        
        import javax.servlet.ServletException;
        import javax.servlet.ServletOutputStream;
        import javax.servlet.annotation.WebServlet;
        import javax.servlet.http.HttpServlet;
        import javax.servlet.http.HttpServletRequest;
        import javax.servlet.http.HttpServletResponse;
        import javax.servlet.http.HttpSession;
        import java.io.IOException;
        
        /**
         * 验证码展示,并存储到Session
         */
        @WebServlet("/checkCode")
        public class CheckCodeServlet extends HttpServlet {
        
            @Override
            protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
                // 存储验证码图片到本地
                // OutputStream fos = new FileOutputStream("d://check-code.jpg");
        
                // 使用Response字节输出流获取验证码
                ServletOutputStream outputStream = resp.getOutputStream();
                String checkCode = CheckCodeUtil.outputVerifyImage(100, 50, outputStream, 4);
        
                // 将验证码存储到Session中
                HttpSession session = req.getSession();
                session.setAttribute("checkCodeGenerate", checkCode);
            }
        
            @Override
            protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
                this.doGet(req, resp);
            }
        }
        
        

1.3.3 前端实现

  • 步骤说明

    1. 给用户名输入框绑定光标失去事件onblur
    2. 发送Ajax请求,携带username参数
    3. 处理响应
  • JS代码

    • 检验用户名是否存在

      // 给用户名输入框绑定发失去焦点事件
      document.getElementById("username").onblur = function () {
          // 发送ajax请求
          // 获取用户名的值
          var username = this.value;
      
          // 创建核心对象
          var xhttp;
          if (window.XMLHttpRequest) {
              xhttp = new XMLHttpRequest();
          } else {
              // code for IE6, IE5
              xhttp = new ActiveXObject("Microsoft.XMLHTTP");
          }
          // 建立连接
          xhttp.open("GET", "http://localhost:8080/ajax-demo/selectUsername?username="+username);
          // 发送请求
          xhttp.send();
      
          // 获取响应
          xhttp.onreadystatechange = function() {
              if (this.readyState == 4 && this.status == 200) {
                  //判断
                  if(this.responseText == "true"){
                      //用户名存在,显示提示信息,清除style中的display的none
                      document.getElementById("username_err").style.display = '';
                  }else {
                      //用户名不存在,清除提示信息,设置style中的display为none,不显示
                      document.getElementById("username_err").style.display = 'none';
                  }
              }
          };
      }
      
    • 验证码刷新

      // 验证码刷新
      document.getElementById("changeImg").onclick = function () {
          // 图片路径已经被缓存,需要在后面加参数进行刷新,为保证多次刷新,可以以时间毫秒数作为参数
          document.getElementById("checkCodeImg").src = "/filter_demo/checkCode?"+new Date().getMilliseconds();
      }
      

2、 Axios异步框架

Axios 对原生的AJAX进行封装,简化书写。

Axios官网是:https://www.axios-http.cn

2.1 基本使用

  • 引入Axios 的JavaScript文件

    <script src="js/axios-0.18.0.js"></script>
    
  • 发送请求并获取响应

    axios({})为发送请求部分,.then(function (resp){});为回调函数,使用resp.data可以获取到返回的结果

    • get

      axios({
          method:"get",
          url:"http://localhost:8080/ajax-demo1/aJAXDemo1?username=zhangsan"
      }).then(function (resp){
          alert(resp.data);
      })
      
    • post

      axios({
          method:"post",
          url:"http://localhost:8080/ajax-demo1/aJAXDemo1",
          data:"username=zhangsan"
      }).then(function (resp){
          alert(resp.data);
      });
      

2.2 快速入门

2.2.1 后端实现

package priv.dandelion.controller.servlet;

import priv.dandelion.utils.ReEncoding;

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;

@WebServlet("/axiosDemo")
public class AxiosDemo extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 响应数据
        String username = req.getParameter("username");
        resp.getWriter().write("hello "+ username + " axios get~");
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String username = req.getParameter("username");
        resp.getWriter().write("hello "+ username + " axios post~");
    }
}

2.2.2 前端实现

<script src="js/axios-0.18.0.js"></script>

<script>
    // // get
    // axios({
    //     method: "get",
    //     url: "http://localhost:8080/ajax-demo/axiosDemo?username=zhangsan"
    // }).then(function (resp) {
    //     alert(resp.data);
    // })

    // post
    axios({
        method: "post",
        url: "http://localhost:8080/ajax-demo/axiosDemo",
        data:"username=zhangsan"
    }).then(function (resp) {
        alert(resp.data);
    })
</script>

2.3 请求方法别名

  • 为了方便起见, Axios 已经为所有支持的请求方法提供了别名。如下:

    • get 请求 : axios.get(url[,config])

    • delete 请求 : axios.delete(url[,config])

    • head 请求 : axios.head(url[,config])

    • options 请求 : axios.option(url[,config])

    • post 请求:axios.post(url[,data[,config])

    • put 请求:axios.put(url[,data[,config])

    • patch 请求:axios.patch(url[,data[,config])

  • get举例

    axios.get("http://localhost:8080/ajax-demo/axiosServlet?username=zhangsan").then(function (resp) {
        alert(resp.data);
    })
    
  • post举例

    axios.post("http://localhost:8080/ajax-demo/axiosServlet","username=zhangsan").then(function (resp) {
        alert(resp.data);
    })
    

3、 JSON

概念:JavaScript Object Notation。JavaScript 对象表示法

3.1 概述

  • JSON和JS定义对象格式的区别

    • JavaScript

      {
      	name:"zhangsan",
      	age:23,
      	city:"北京"
      }
      
    • JSON

      {
      	"name":"zhangsan",
      	"age":23,
      	"city":"北京"
      }
      

3.2 JSON基础语法

3.2.1 定义格式

  • 基本定义格式

    var 变量名 = '{"key":value,"key":value,...}';
    
  • value的数据类型

    • 数字(整数或浮点数)
    • 字符串(使用双引号括起来)
    • 逻辑值(true或者false)
    • 数组(在方括号中)
    • 对象(在花括号中)
    • null
  • value的数据类型示例

    var jsonStr = '{"name":"zhangsan","age":23,"addr":["北京","上海","西安"]}'
    

3.2.2 代码格式

  • 将JSON和JavaScript对象的相互转化

    • parse(str) :将 JSON串转换为 js 对象。使用方式是: var jsObject = JSON.parse(jsonStr);
    • stringify(obj) :将 js 对象转换为 JSON 串。使用方式是:var jsonStr = JSON.stringify(jsObject)
  • 代码演示

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>JSON-demo</title>
    </head>
    <body>
    <script>
        // 定义JSON字符串
        var jsonStr = '{"name":"zhangsan","age":23,"addr":["北京","上海","西安"]}'
        alert(jsonStr);
    
        // 将 JSON 字符串转为 JS 对象
        let jsObject = JSON.parse(jsonStr);
        alert(jsObject)
        alert(jsObject.name)
        // 将 JS 对象转换为 JSON 字符串
        let jsonStr2 = JSON.stringify(jsObject);
        alert(jsonStr2)
    </script>
    </body>
    </html>
    

3.2.3 发送异步请求携带数据

  • js 提供的 JSON 对象我们只需要了解一下即可。因为 axios 会自动对 js 对象和 JSON 串进行想换转换。
  • 发送异步请求时,如果请求参数是 JSON 格式,那请求方式必须是 POST。因为 JSON 串需要放在请求体中。
  • 使用 axios 发送请求时,如果要携带复杂的数据时都会以 JSON 格式进行传递

    提前定义一个 js 对象,用来封装需要提交的参数,然后使用 JSON.stringify(js对象) 转换为 JSON 串,再将该 JSON 串作为 axiosdata 属性值进行请求参数的提交

    var jsObject = {name:"张三"};
    
    axios({
        method:"post",
        url:"http://localhost:8080/ajax-demo/axiosServlet",
        data: JSON.stringify(jsObject)
    }).then(function (resp) {
        alert(resp.data);
    })
    
  • axios 会自动将 js 对象转换为 JSON 串进行提交

var jsObject = {name:"张三"};

axios({
    method:"post",
    url:"http://localhost:8080/ajax-demo/axiosServlet",
    data:jsObject  //这里 axios 会将该js对象转换为 json 串的
}).then(function (resp) {
    alert(resp.data);
})

3.3 JSON串和Java对象的相互转换

Fastjson 是阿里巴巴提供的一个Java语言编写的高性能功能完善的 JSON 库,是目前Java语言中最快的 JSON 库,可以实现 Java 对象和 JSON 字符串的相互转换。

3.3.1 Fastjson 使用

  • 依赖

    <!-- JSON串和Java对象的相互转换 -->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>1.2.62</version>
    </dependency>
    
  • Java对象转JSON

    String jsonStr = JSON.toJSONString(obj);
    
  • JSON转Java对象

    User user = JSON.parseObject(jsonStr, User.class);
    

3.3.2 代码演示

public class FastJsonDemo {

    public static void main(String[] args) {
        // 将Java对象转为JSON字符串
        User user = new User();
        user.setId(1);
        user.setUsername("zhangsan");
        user.setPassword("123");

        String jsonString = JSON.toJSONString(user);
        System.out.println(jsonString);//{"id":1,"password":"123","username":"zhangsan"}


        // 将JSON字符串转为Java对象
        User u = JSON.parseObject("{\"id\":1,\"password\":\"123\",\"username\":\"zhangsan\"}", User.class);
        System.out.println(u);
    }
}

4、 案例

4.1 需求和方案

  • 需求

    • 使用AJAX+JSON完成品牌数据的查询和添加
  • 方案

    • 查询所有

      1. 页面加载完成后发送异步请求,获取数据列表
      2. controller调用service进行查询
      3. service查询到List集合,返回给controller
      4. controller将List转换为JSON
      5. 将JSON串使用Response写回页面
      6. 遍历字符串数据,展示表格
    • 添加数据

      1. 点击添加按钮跳转到添加信息页面

      2. 输入内容点击提交,将数据封装为JSON格式,使用AJAX发送异步请求到后端

      3. 后端接收数据后反序列化JSON数据

        由于前端提交的是 json 格式的数据,所以我们不能使用 request.getParameter() 方法获取请求参数

        • 如果提交的数据格式是 username=zhangsan&age=23 ,后端就可以使用 request.getParameter() 方法获取
        • 如果提交的数据格式是 json,后端就需要通过 request 对象获取输入流,再通过输入流读取数据
      4. 将获取到的JSON对象转换为Brand对象

      5. 调用Service的add()发明合法添加数据

      6. 将JSON数据返回给浏览器

4.2 查询所有功能

4.2.1 环境准备

  • SQL

    -- 删除tb_brand表
    drop table if exists tb_brand;
    -- 创建tb_brand表
    create table tb_brand
    (
        -- id 主键
        id           int primary key auto_increment,
        -- 品牌名称
        brand_name   varchar(20),
        -- 企业名称
        company_name varchar(20),
        -- 排序字段
        ordered      int,
        -- 描述信息
        description  varchar(100),
        -- 状态:0:禁用  1:启用
        status       int
    );
    -- 添加数据
    insert into tb_brand (brand_name, company_name, ordered, description, status)
    values ('三只松鼠', '三只松鼠股份有限公司', 5, '好吃不上火', 0),
           ('华为', '华为技术有限公司', 100, '华为致力于把数字世界带入每个人、每个家庭、每个组织,构建万物互联的智能世界', 1),
           ('小米', '小米科技有限公司', 50, 'are you ok', 1);
    
  • 实体类

    package priv.dandelion.entity;
    
    public class Brand {
        // id 主键
        private Integer id;
        // 品牌名称
        private String brandName;
        // 企业名称
        private String companyName;
        // 排序字段
        private Integer ordered;
        // 描述信息
        private String description;
        // 状态:0:禁用  1:启用
        private Integer status;
    
        public Brand() {
        }
    
        public Brand(Integer id, String brandName, String companyName, Integer ordered, String description, Integer status) {
            this.id = id;
            this.brandName = brandName;
            this.companyName = companyName;
            this.ordered = ordered;
            this.description = description;
            this.status = status;
        }
    
        public Integer getId() {
            return id;
        }
    
        public void setId(Integer id) {
            this.id = id;
        }
    
        public String getBrandName() {
            return brandName;
        }
    
        public void setBrandName(String brandName) {
            this.brandName = brandName;
        }
    
        public String getCompanyName() {
            return companyName;
        }
    
        public void setCompanyName(String companyName) {
            this.companyName = companyName;
        }
    
        public Integer getOrdered() {
            return ordered;
        }
    
        public void setOrdered(Integer ordered) {
            this.ordered = ordered;
        }
    
        public String getDescription() {
            return description;
        }
    
        public void setDescription(String description) {
            this.description = description;
        }
    
        public Integer getStatus() {
            return status;
        }
    
        public void setStatus(Integer status) {
            this.status = status;
        }
    
        @Override
        public String toString() {
            return "Brand{" +
                    "id=" + id +
                    ", brand_name='" + brandName + '\'' +
                    ", company_name='" + companyName + '\'' +
                    ", ordered=" + ordered +
                    ", description='" + description + '\'' +
                    ", status=" + status +
                    '}';
        }
    }
    
  • MyBatis核心配置文件

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE configuration
            PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-config.dtd">
    <configuration>
        <!--起别名-->
        <typeAliases>
            <package name="priv.dandelion.entity"/>
        </typeAliases>
    
        <environments default="development">
            <environment id="development">
                <!-- 采用JDBC的事务管理方式 -->
                <transactionManager type="JDBC"/>
                <!-- 数据库连接信息 -->
                <dataSource type="POOLED">
                    <property name="driver" value="com.mysql.jdbc.Driver"/>
                    <!-- value的值一定不能换行,一定!一定!不能换行 -->
                    <property name="url" value="jdbc:mysql:///db1?useSSL=false&amp;useUnicode=true&amp;characterEncoding=utf-8&amp;useServerPrepStmts=true"/>
                    <property name="username" value="root"/>
                    <property name="password" value="123456"/>
                </dataSource>
            </environment>
        </environments>
        <!-- 扫描mapper,加载SQL映射文件 -->
        <mappers>
            <package name="priv.dandelion.dao"/>
        </mappers>
    </configuration>
    
  • Mapper映射文件

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper
            PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="priv.dandelion.dao.BrandMapper">
    
        <!-- 解决数据库与实体类命名不一致问题 -->
        <resultMap id="brandResultMap" type="brand">
            <result column="brand_name" property="brandName"></result>
            <result column="company_name" property="companyName"></result>
        </resultMap>
    
    </mapper>
    
  • Mapper接口

    package priv.dandelion.dao;
    
    import org.apache.ibatis.annotations.Insert;
    import org.apache.ibatis.annotations.ResultMap;
    import org.apache.ibatis.annotations.Select;
    import priv.dandelion.entity.Brand;
    
    import java.util.List;
    
    
    public interface BrandMapper {
    
        @ResultMap("brandResultMap")
        @Select("select * from tb_brand")
        List<Brand> selectAll();
    
        @Insert("insert into tb_brand " +
                "values(null, #{brandName}, #{companyName}, " +
                "#{ordered}, #{description}, #{status})")
        void addBrand(Brand brand);
    }
    
    
  • 工具类 - 获取SqlSession工厂

    package priv.dandelion.utils;
    
    import org.apache.ibatis.io.Resources;
    import org.apache.ibatis.session.SqlSessionFactory;
    import org.apache.ibatis.session.SqlSessionFactoryBuilder;
    
    import java.io.IOException;
    import java.io.InputStream;
    
    public class SqlSessionFactoryUtils {
    
        // 提升作用域,用于再方法内进行返回
        private static SqlSessionFactory sqlSessionFactory;
    
        // 静态代码块会随着类的加载自动执行且只执行一次
        static {
            String resource = "mybatis-config.xml";
            InputStream inputStream = null;
            try {
                inputStream = Resources.getResourceAsStream(resource);
            } catch (IOException e) {
                e.printStackTrace();
            }
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        }
    
        public static SqlSessionFactory getSqlSessionFactory() {
            return sqlSessionFactory;
        }
    
    }
    
  • Service

    package priv.dandelion.service;
    
    import org.apache.ibatis.session.SqlSession;
    import org.apache.ibatis.session.SqlSessionFactory;
    import priv.dandelion.dao.BrandMapper;
    import priv.dandelion.entity.Brand;
    import priv.dandelion.utils.SqlSessionFactoryUtils;
    
    import java.util.List;
    
    public class BrandService {
        SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtils.getSqlSessionFactory();
    
        public List<Brand> selectAll() {
            SqlSession sqlSession = sqlSessionFactory.openSession();
            BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);
            List<Brand> brands = mapper.selectAll();
            sqlSession.close();
            return brands;
        }
    
        public void addBrand(Brand brand) {
            SqlSession sqlSession = sqlSessionFactory.openSession(true);
            BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);
            mapper.addBrand(brand);
            sqlSession.close();
        }
    }
    
    

4.2.2 后端实现

  • Servlet

    package priv.dandelion.controller.servlet;
    
    import com.alibaba.fastjson.JSON;
    import priv.dandelion.entity.Brand;
    import priv.dandelion.service.BrandService;
    
    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("/selectAll")
    public class SelectAllServlet extends HttpServlet {
    
        BrandService service = new BrandService();
    
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            // 调用service 查询
            List<Brand> brands = service.selectAll();
            // 将集合序列化为JSON数据
            String jsonString = JSON.toJSONString(brands);
            // 响应数据
            // 处理中文数据
            resp.setContentType("text/json;charset=utf-8");
            resp.getWriter().write(jsonString);
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            this.doGet(req, resp);
        }
    }
    

4.2.3 前端实现

  • 引入JS文件

    <script src="js/axios-0.18.0.js"></script>
    
  • 监听监听页面加载完成事件,在页面加载完成后发送AJAX异步请求

    // 当页面加载完成后发送AJAX请求
    window.onload = function () {
        // 发送AJAX请求
        axios({
            method:"get",
            url:"http://localhost:8080//brand-demo-ajax/selectAll"
        }).then(function (resp) {
            // 获取数据
            let brands = resp.data;
    
            // 表格数据
            let tableData = "<tr>\n" +
                "        <th>序号</th>\n" +
                "        <th>品牌名称</th>\n" +
                "        <th>企业名称</th>\n" +
                "        <th>排序</th>\n" +
                "        <th>品牌介绍</th>\n" +
                "        <th>状态</th>\n" +
                "        <th>操作</th>\n" +
                "    </tr>";
    
            for (let i = 0; i < brands.length; i++) {
                let brand = brands[i];
                // 对表格数据进行拼接
                tableData += "<tr align=\"center\">\n" +
                    "        <td>" + (i + 1) + "</td>\n" +
                    "        <td>" + brand.brandName + "</td>\n" +
                    "        <td>" + brand.companyName + "</td>\n" +
                    "        <td>" + brand.ordered + "</td>\n" +
                    "        <td>" + brand.destination + "</td>\n" +
                    "        <td>" + brand.status + "</td>\n" +
                    "\n" +
                    "        <td><a href=\"#\">修改</a> <a href=\"#\">删除</a></td>\n" +
                    "    </tr>"
            }
    
            // 设置表格对象
            document.getElementById("brandTable").innerHTML = tableData;
        })
    }
    
  • 整体页面

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <a href="addBrand.html"><input type="button" value="新增"></a><br>
    <hr>
    <table id="brandTable" border="1" cellspacing="0" width="100%">
    
    </table>
    
    <script src="js/axios-0.18.0.js"></script>
    
    <script>
        // 当页面加载完成后发送AJAX请求
        window.onload = function () {
            // 发送AJAX请求
            axios({
                method:"get",
                url:"http://localhost:8080//brand-demo-ajax/selectAll"
            }).then(function (resp) {
                // 获取数据
                let brands = resp.data;
    
                // 表格数据
                let tableData = "<tr>\n" +
                    "        <th>序号</th>\n" +
                    "        <th>品牌名称</th>\n" +
                    "        <th>企业名称</th>\n" +
                    "        <th>排序</th>\n" +
                    "        <th>品牌介绍</th>\n" +
                    "        <th>状态</th>\n" +
                    "        <th>操作</th>\n" +
                    "    </tr>";
    
                for (let i = 0; i < brands.length; i++) {
                    let brand = brands[i];
                    // 对表格数据进行拼接
                    tableData += "<tr align=\"center\">\n" +
                        "        <td>" + (i + 1) + "</td>\n" +
                        "        <td>" + brand.brandName + "</td>\n" +
                        "        <td>" + brand.companyName + "</td>\n" +
                        "        <td>" + brand.ordered + "</td>\n" +
                        "        <td>" + brand.destination + "</td>\n" +
                        "        <td>" + brand.status + "</td>\n" +
                        "\n" +
                        "        <td><a href=\"#\">修改</a> <a href=\"#\">删除</a></td>\n" +
                        "    </tr>"
                }
    
                // 设置表格对象
                document.getElementById("brandTable").innerHTML = tableData;
            })
        }
    </script>
    
    </body>
    </html>
    

4.3 添加品牌功能

4.3.1 后端实现

  • Servlet部分

    package priv.dandelion.controller.servlet;
    
    import com.alibaba.fastjson.JSON;
    import priv.dandelion.entity.Brand;
    import priv.dandelion.service.BrandService;
    
    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.BufferedReader;
    import java.io.IOException;
    
    @WebServlet("/add")
    public class AddBrandServlet extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
            BrandService service = new BrandService();
    
            // 前端发送为JSON数据,不能使用request.getParameter接收数据
    
            // 接收前端发送的JSON数据
            BufferedReader reader = req.getReader();
            String params = reader.readLine();
    
            // 将JSON字符串反序列化为Java对象
            Brand brand = JSON.parseObject(params, Brand.class);
    
            // 调用Service进行添加
            service.addBrand(brand);
            
            // 响应成功标识
            resp.getWriter().write("success");
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            this.doGet(req, resp);
        }
    }
    

4.3.2 前端实现

  • 导入JS

    <script src="js/axios-0.18.0.js"></script>
    
  • 给提交按钮绑定单击事件,并发送AJAX异步请求到服务器

    // 给按钮绑定单击事件
    document.getElementById("btn").onclick = function () {
        // 将表单转换为JSON串
        var formData = {
            brandName:"",
            companyName:"",
            ordered:"",
            description:"",
            status:"",
        };
    
        // 获取表单数据
        formData.brandName = document.getElementById("brandName").value;
        formData.companyName = document.getElementById("companyName").value;
        formData.description = document.getElementById("description").value;
        formData.ordered = document.getElementById("ordered").value;
    
        // 获取单选的较为特殊,和单选的性质有关
        let status = document.getElementsByName("status");
        for (let i = 0;i < status.length; i++) {
            if (status[i].checked) {
                formData = status[i].value;
            }
        }
        alert(formData);
    
        // 发送AJAX请求
        axios({
            method:"post",
            url:"http://localhost:8080//brand-demo-ajax/add",
            data:formData
        }).then(function (resp) {
            alert(resp.data);
            // 判断响应数据是否为success
            if (resp.data == "success") {
                // 重定向到查询所有页面
                location.href = "http://localhost:8080//brand-demo-ajax/brand.html";
            }
        })
    }
    
  • 完整代码

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
        <meta charset="UTF-8">
        <title>添加品牌</title>
    </head>
    <body>
    <h3>添加品牌</h3>
    <form action="" method="post">
        品牌名称:<input id="brandName" name="brandName"><br>
        企业名称:<input id="companyName" name="companyName"><br>
        排序:<input id="ordered" name="ordered"><br>
        描述信息:<textarea rows="5" cols="20" id="description" name="description"></textarea><br>
        状态:
        <input type="radio" name="status" value="0">禁用
        <input type="radio" name="status" value="1">启用<br>
    
        <input type="button" id="btn" value="提交">
    </form>
    
    <script src="js/axios-0.18.0.js"></script>
    
    <script>
        // 给按钮绑定单击事件
        document.getElementById("btn").onclick = function () {
            // 将表单转换为JSON串
            var formData = {
              brandName:"",
              companyName:"",
              ordered:"",
              description:"",
              status:"",
            };
    
            // 获取表单数据
            formData.brandName = document.getElementById("brandName").value;
            formData.companyName = document.getElementById("companyName").value;
            formData.description = document.getElementById("description").value;
            formData.ordered = document.getElementById("ordered").value;
    
            // 获取单选的较为特殊,和单选的性质有关
            let status = document.getElementsByName("status");
            for (let i = 0;i < status.length; i++) {
                if (status[i].checked) {
                    formData = status[i].value;
                }
            }
            alert(formData);
    
            // 发送AJAX请求
            axios({
                method:"post",
                url:"http://localhost:8080//brand-demo-ajax/add",
                data:formData
            }).then(function (resp) {
                alert(resp.data);
                // 判断响应数据是否为success
                if (resp.data == "success") {
                    // 重定向到查询所有页面
                    location.href = "http://localhost:8080//brand-demo-ajax/brand.html";
                }
            })
        }
    </script>
    
    </body>
    </html>
    

额外说明:

该部分代码略显臃肿,但是该示例的目的主要是对AJAX、Axios以及JSON相关知识点的整理和演示,后续通过前端框架可以大大简化该部分代码。