AJAX基础+Axios快速入门+JSON使用+综合案例

news/2024/4/26 15:52:41/文章来源:https://www.cnblogs.com/dandelion-000-blog/p/16847281.html

目录
  • 1、 AJAX
    • 1.1 概述
      • 1.1.1 作用
      • 1.1.2 同步和异步
    • 1.2 快速入门
      • 1.2.1 服务端实现
      • 1.2.2 客户端实现
    • 1.3 案例
      • 1.3.1 需求
      • 1.3.2 分析
      • 1.3.2 后端实现
      • 1.3.3 前端实现
  • 2、 Axios异步框架
    • 2.1 基本使用
    • 2.2 快速入门
      • 2.2.1 后端实现
      • 2.2.2 前端实现
    • 2.3 请求方法别名
  • 3、 JSON
    • 3.1 概述
    • 3.2 JSON基础语法
      • 3.2.1 定义格式
      • 3.2.2 代码格式
      • 3.2.3 发送异步请求携带数据
    • 3.3 JSON串和Java对象的相互转换
      • 3.3.1 Fastjson 使用
      • 3.3.2 代码演示
  • 4、 案例
    • 4.1 需求和方案
    • 4.2 查询所有功能
      • 4.2.1 环境准备
      • 4.2.2 后端实现
      • 4.2.3 前端实现
    • 4.3 添加品牌功能
      • 4.3.1 后端实现
      • 4.3.2 前端实现

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 {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {// 响应数据resp.getWriter().write("hello ajax~");}@Overrideprotected 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, IE5xhttp = 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 configurationPUBLIC "-//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;}@Overridepublic 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) {// 获取SqlSessionSqlSession sqlSession = factory.openSession(true);// 获取UserMapperUserMapper mapper = sqlSession.getMapper(UserMapper.class);// 调用daoUser 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();@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {// 接收用户名String username = req.getParameter("username");// 调用Service查询Userboolean flag = service.selectUsername(username);// 响应标记resp.getWriter().write("" + flag);}@Overrideprotected 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 {@Overrideprotected 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);}@Overrideprotected 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, IE5xhttp = 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的nonedocument.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 {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {// 响应数据String username = req.getParameter("username");resp.getWriter().write("hello "+ username + " axios get~");}@Overrideprotected 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);// })// postaxios({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;}@Overridepublic 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 configurationPUBLIC "-//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 mapperPUBLIC "-//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();@Overrideprotected 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);}@Overrideprotected 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 {@Overrideprotected 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");}@Overrideprotected 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);// 判断响应数据是否为successif (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);// 判断响应数据是否为successif (resp.data == "success") {// 重定向到查询所有页面location.href = "http://localhost:8080//brand-demo-ajax/brand.html";}})}
    </script></body>
    </html>
    

额外说明:

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_410296.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

GAS技能系统

HUT -》 在\Intermediate\Build\Win64\UE4Editor\Inc\的目录下 找到generated 头文件和cpp文件 里面有HUT根据UCLASS 和 Generate Body 生成的 定义 以及声明宏(UFUNCTION 里的CustomThunk元可以让用户自己手动添加宏定义和宏声明) 将wildcard改为通配符然后手动将自定义的…

Terraform 华为云实践 项目初始化

这个架构就是DNS加上负载均衡加ecs&#xff0c;最后vpc的架构。网络这块是DNS和VPC&#xff0c;对象存储是用来做terraform的后端来配置。 项目的初始化 Terraform Registry 华为云的terraform链接如上所示。 先将项目的目录结构建好&#xff0c;modules是我们的模块&#xf…

来一场关于元宇宙的灵魂辩论|BOOK DAO内容共建招募

「 备选问题 」1. 你认为元宇宙最重要的特点是什么&#xff1f;用一句话描述你理解的 “元宇宙”2. 元宇宙是游戏2.0吗&#xff1f;它与游戏有什么不同&#xff1f;3. 元宇宙是否需要区块链&#xff1f;是否需要NFT&#xff1f;各扮演什么角色&#xff1f;4. 元宇宙是否需要经济…

大数据项目之电商数仓、电商业务简介、电商业务流程、电商常识、业务数据介绍、电商业务表、后台管理系统

文章目录5. 电商业务简介5.1 电商业务流程5.2 电商常识5.2.1 SKU和SPU5.2.2 平台属性和销售属性5.2.2.1 平台属性5.2.2.2 销售属性6. 业务数据介绍6.2 电商业务表6.2.1 收藏商品6.2.2 加购物车6.2.3 领用优惠券6.2.4 下单6.2.5 支付6.2.6 退单6.2.7 退款6.2.8 评价6.3 后台管理…

部署简易POD image自己定义镜像

k8s部署pod apiversion: 版本 kind: 类型 metadata: 字面意识&#xff0c;元素信息&#xff0c;POD信息 name: POD名字 labels: 字母意识&#xff0c;标签 通过拓扑 label 进行副本调度 label的使用无非就是增删改查 还有个重要的标签namespace&#xff08;命名空间&…

针对垃圾渗滤液中膜产水脱氮工艺的设计,除氨氮树脂

垃圾渗滤液是指来源于垃圾填埋场中垃圾本身含有的水分、进入填埋场的雨雪水及其他水分&#xff0c;扣除垃圾、覆土层的饱和持水量&#xff0c;并经历垃圾层和覆土层而形成的一种高浓度的有机废水&#xff0c;有堆积的准备用于焚烧的垃圾渗漏出的水分。为什么要处理垃圾渗滤液&a…

黑马点评-达人探店

摘要&#xff1a;达人探店业务&#xff1a; 本质是发表blog和点赞等功能。利用Redis的Set实现点赞与取消点赞&#xff0c;然后利用SortedSet对点赞功能进行改进实现点赞排行的功能。 在学习的过程中&#xff0c;我们不应该急于写代码&#xff0c;首先分析业务逻辑&#xff0c;…

SpringBoot项目启动执行任务的几种方式

经过整理后得到以下几种常用方式&#xff0c;供大家参考。 1. 使用过滤器 init() &#xff1a;该方法在tomcat容器启动初始化过滤器时被调用&#xff0c;它在 Filter 的整个生命周期只会被调用一次。可以在这个方法中补充想要执行的内容。 Component public class MyFilter …

vs2017 外网远程调试

外网远程调试:由于外网的目标电脑IP无法直接访问&#xff0c;则需要第三方内网穿透工具辅助&#xff0c;本文使用NATAPP进行 注册一个账号&#xff1a;NATAPP -注册完成&#xff0c;登录后&#xff0c;在购买隧道中选择Free免费购买一个 购买成功后&#xff0c;在我的隧道中可…

突破出行市场桎梏,需要高端出行的精神内核?

如果高端出行是一本书&#xff0c;那么豪车可能只是封面和封底。真正重要的&#xff0c;是隐藏其中的服务的精神与体验的内核。 这一点&#xff0c;国内高端出行市场的探索者们应当深有体会。从早期高端巡游出租车&#xff0c;到BBA豪华车势力曾经推动的高端出行网约车&#x…

「设计模式」工厂方法模式

文章目录一、概念二、用途三、实现方式四、工厂方法模式的利与弊为什么要使用工厂来创建对象&#xff1f;为什么每种对象要单独有一个工厂&#xff1f;五、工厂方法与简单工厂的区别六、总结参考资料一、概念 工厂方法模式(Factory Method Pattern)又称为工厂模式&#xff0c;…

前端工具——01-VS Code的使用

前言 文章标题&#xff1a;《第一次使用 VS Code 时你应该知道的一切配置》。本文的最新内容&#xff0c;更新于 2020-06-19。大家完全不用担心这篇文章会过时&#xff0c;因为随着 VS Code 的版本更新和插件更新&#xff0c;本文也会随之更新。 本文的最新内容&#xff0c;也会…

腾讯云centos7安装mysql5.7

昨天服务器上的数据库被勒索了&#xff0c;重装系统之后不得不再装一次数据库&#xff0c;踩了很多坑&#xff0c;在此记录安装过程。 首先把centos7自带的数据库mariadb卸载掉&#xff0c;把MySQL的相关文件夹都删掉。 查看组件服务 rpm -qa | grep -i mariadb rpm -qa | gr…

Mybatics-连接配置

1、mysql连接数_MySQL配置参数优化 1.1、优化最大连接数max_connections 是MySQL最大并发连接数默认值是151 MySQL允许的最大连接数上限是32767 实际连接数是最大连接数的85%较为合适 查询数据库目前设置的最大并发连接数是多少 查询数据库目前实际连接的并发数是多少 在MyS…

SpringBoot集成JWT(极简版):

文章目录1.JWT依赖2.JWT工具类TokenUtils.java3.token示例4.拦截器JwtInterceptor.java5.拦截器设置InterceptorConfig.java6.统一接口WebConfig.java7.设置自定义头配置 CorsConfig .java8.GlobalExceptionHandler.java9.ServiceException.java10.设置token:11.最终效果&#…

离线下IDEA打开拷贝的完整工程,解决工程代码大量报错的问题

一、背景 在日常工作中&#xff0c;代码工程的保存和协作开发一般是通过代码仓库实现的。但是对于正常的多人研究开发时&#xff0c;工程代码的物理拷贝也是需要的&#xff0c;这可以节省工程代码依赖环境的安装和配置&#xff0c;同时也能保证代码完整和版本一致。 在大部分企…

【测试沉思录】9. 数据工厂低代码平台探索与实践

欢迎订阅我的新专栏《现代命令行工具指南》&#xff0c;精讲目前最流行的开源命令行工具&#xff0c;大大提升你的工作效率。 作者&#xff1a;吴锺瑞、刘洪初 编辑&#xff1a;毕小烦 一. 需求背景 造数据可能是日常迭代中最频繁也是最耗时的工作。 我们在20年8月对部门内的…

HashSet实现类的使用

【1】放入Integer类型数据package com.msb.test06;import java.util.HashSet;/*** @author : liu* 日期:10:36:57* 描述:IntelliJ IDEA* 版本:1.0*/ public class TestInteger {//这是一个main方法:是程序的入口public static void main(String[] args) {//创建一个HashSet集合…

Cannon.js -- 3d物理引擎

文章目录前言一、关于Cannon.js二、Cannon.js的使用最后注意点&#xff1a;优化事件其他本文完整代码下载&#xff1a;相关链接&#xff1a;前言 本篇将介绍Cannon.js -- 3d物理引擎的基础使用&#xff0c;并用Cannon.js与three.js写一个简单的demo 一、关于Cannon.js Q&…

什么是轮廓阴影和圆角

目录 outline box-shadow 将元素设置为一个圆形 outline outline 用来设置元素的轮廓线&#xff0c;用法和border一模一样 轮廓和边框不同的点&#xff0c;就是轮廓不会影响到可见框的大小 <!DOCTYPE html> <html lang"en"> <head><meta ch…