管理系统总结(前端:Vue-cli, 后端Jdbc连接mysql数据库,项目部署tomcat里)

news2024/11/28 7:36:35

根据所学的知识, 写一个管理系统, 顺便总结一些知识点

准备:

前端用vue-cli的框架, 后端用jdbc连接数据库, 项目部署tomcat服务器来完成交互

●前端的vue-cli框架搭建可以看 点击跳转 的第二小结
●后端的tomcat在idea里的相关的配置与集成,可以看 点击跳跃

文章目录

  • 一、 前段搭建
    • 1. 登录组件
    • 2. 管理页面
    • 3.异步请求发送后端, 验证账号
    • 4.异步请求发送后端 数据转化json
    • 5.防止通过浏览器地址恶意访问
    • sessionStorage
    • 具体操作
    • 提高安全性(session不安全), 使用token来验证
    • 具体操作
    • 添加请求拦截器
    • 响应拦截器
  • 二、后端搭建
    • 1. 项目构建
    • 2. 封装连接数据库的代码
    • 3. 登录判断账号
    • 4. 解决跨域问题
    • 5. 后端对返回结果进行封装
    • 6. 后端对返回结果进行转化json格式后进行响应

一、 前段搭建

在完成点击跳转Vue-cli 项目的搭建之后, 咱去组件官网直接 顺组件 (复制组件), 这里我用的是Element-ui官网的组件,官网点击右边: 点击完成跳转

1. 登录组件

在这里插入图片描述

2. 管理页面

在这里插入图片描述

3.异步请求发送后端, 验证账号

首先使用xios来发送, 因为原生态的ajax代码繁琐
<1>首先要引入axios.js文件或者安装axios的脚手架

$ npm install axios
这里就引入xios.js的组件来使用axios发送请求

<2>下载完成后, 在node_moudules里导入到main.js的全局配置文件里面
在这里插入图片描述

<3>导入后就能直接用axios语法来发送请求
发送get请求

				this.$http.get("http://localhost:8080/webBack_5.14/login?account=jwq&password=111").then(function(resp){
					//业务逻辑代码
				})

发送post请求

				this.$http.post("http://localhost:8080/webBack_5.14/login",this.account).then((resp){
				//业务逻辑代码
				})

4.异步请求发送后端 数据转化json

由于json是一种轻量级的数据格式, 所以前后端传输数据时候, 经常用json格式来传输

在前端可以写一个方法来转化数据格式:

在这里插入图片描述

请求里做参数转json格式,直接发送json的请求
在这里插入图片描述

5.防止通过浏览器地址恶意访问

如果仅仅是通过登录框验证密码还是不够安全, 还可以通过URL地址来直接进行访问, 就会跳过登录的页面

如下:
在这里插入图片描述

直接输入了网站URL的地址, 就直接访问进来了, 根本没有通过账户密码的验证

所以要将一个验证信息放到浏览器里—>(sessionStorage)

sessionStorage

他是浏览器里可以存储数据的容器, 在关闭浏览器时就会清除

因此将用户信息存储到sessionStorage(会话储存) 里 , 在进入具体操作的网页网页时候可以先进行判断, 如果有会话存储里有账号, 那么就可以进行访问, 不然那就回到登录的页面, 这样验证就更加符合需求,

在这里插入图片描述

而且此时的sessionStorage还可以将登录人的信息, 账号放到页面上显示, 就好像京东这些购物软件, 将用户人的登录信息展示到我的这一页面,就可以将操作人的信息放到sessionStorage里面, 随后在哪个页面想要获取渲染在前端时, 就可以随时获取, 非常方便

如下:
在这里插入图片描述
在这里插入图片描述

具体操作

在登录成功后, 将account的数据放入到sessionStorage里面,
在之后每一次请求处理访问登录的请求外的其他请求, 都要验证account

<1>放入account
在这里插入图片描述
在这里插入图片描述
<2>添加web会话跟踪技术
这是在router对象的那个index.js文件里配置
在这里插入图片描述
这样每一次请求的跳转就有了条件, 经过验证, 满足条件才会跳转, 让浏览器的安全性有了基础保障
在这里插入图片描述

提高安全性(session不安全), 使用token来验证

session缺点

  1. 浏览器里的数据时可以随时改的, 就会让一些不法分子走漏洞, 所以在前端验证并不是万全之策
  2. 用户认证之后,服务端做认证记录,如果认证的记录被保存在内存
    中的话,这意味着用户下次请求还必须要请求在这台服务器上,这样才能拿到授权的资源,这样在分布式的应用上,相应的限制了负载均衡器的能力。
    因此要引入另一种安全的高效的验证操作, token 验证方式

不了解token的可以看这里 点击跳转

具体操作

首先在登录成功之后, 要在后端生成token, 再将token连随响应数据一并发送给前端, 前端得到token之后, 在接下来的每一次发送请求都会将token携带到请求里, 到后端来验证token是否正确, 正确就继续执行操作, 不正确就要返回 token不对的异常信息

生成token:
首先要导入jar包
在这里插入图片描述
由JWT的方式生成token
想了解JWT的可以 点击去看看JWT

JWT的工具类

public class JWTUtil {

    /**
     * jwt 生成 token
     */
    public static String token (Admin admin){
        String token = "";
        try {
             //过期时间 为 1970.1.1 0:0:0 至 过期时间 当前的毫秒值 + 有效时间
            Date expireDate = new Date(new Date().getTime() +3600*1000);
             //秘钥及加密算法
            Algorithm algorithm = Algorithm.HMAC256("ZCEQIUBFKSJBFJH2020BQWE");
           //设置头部信息
            Map<String,Object> header = new HashMap<>();
            header.put("typ","JWT");
            header.put("alg","HS256");
            //携带 id,账号信息,生成签名
            token = JWT.create()
                    .withHeader(header)
                    .withClaim("id",admin.getId())
                    .withClaim("account",admin.getAccount())
                    .withExpiresAt(expireDate)
                    .sign(algorithm);
        }catch (Exception e){
            e.printStackTrace(); return null;
        }
        return token;
    }

    /**
     * 验证 token 的方法
     * @param token
     * @return
     */
    public static boolean verify(String token){
        try {
         //验签
            Algorithm algorithm = Algorithm.HMAC256("ZCEQIUBFKSJBFJH2020BQWE");
            JWTVerifier verifier = JWT.require(algorithm).build();
            DecodedJWT jwt = verifier.verify(token);
            return true;
        } catch (Exception e) {//当传过来的 token 如果有问题,抛出异常
            return false;
        }
    }

    /**
     * 获得 token 中 playload 部分数据,按需使用
     * @param token
     * @return
     */
    public static DecodedJWT getTokenInfo(String token){
        return JWT.require(Algorithm.HMAC256("ZCEQIUBFKSJBFJH2020BQWE")).build().verify(token);
    }
}

将token信息封装到admin对象里, 一并返回前端
在这里插入图片描述
前端将信息放入浏览器的会话存储里
在这里插入图片描述
请求发送时,后端验证token

先想想, 后端在接到前端请求时, 要验证token,可以写在一个过滤器里面, 除了登录请求外都要走这个过滤器, 那么问题来了, 如何使得这个过滤器除了登录请求外都走这个过滤器呢?
<1>过滤器的配置

我们可以通过给走这个过滤器的请求添加一层级的路径, 具体如下图
在这里插入图片描述
在这里插入图片描述

这样就可以区分经过验证token过滤器与不验证token过滤器的请求了, 不验证就直接写请求地址, 验证就加上一层级的/token

添加请求拦截器

由于我们的每一次请求都要将token信息发送给后端, 索性就放在响请求对象里的请求头的区域
那我们是不是每次请求都要设置请求头啊, 麻烦不麻烦
后端有没有将每次请求拦截下来的东西, 再设置请求头的内容, 你还别说还真有, 响应拦截器
这是

这是在每次请求时,将token放在请求的请求头区域里, 到后端浏览器调用
在这里插入图片描述

响应拦截器

在前端处理后端响应回来的状态码时, 每一个组件对相同部分状态码总是同一个业务流程, 如: 500 状态码时候, 就会弹出服务器异常的信息, 那这样会繁琐很多, 使得代码冗余

在每次接收响应时, 可以根据状态码来做统一给用户做出响应结果, 可以将那些状态码放入响应拦截器里

在这里插入图片描述

二、后端搭建

后端使用的是idea写代码工具, 集成了tomcat服务器

1. 项目构建

后端结构: 如下
在这里插入图片描述

2. 封装连接数据库的代码

由于要有许多的增删改查, 与数据库相关的操作, 所以就封装一下, 以后跟方便用
<1>首先先在src目录下新建一个. properties的文件
在这里插入图片描述
<2>新建一个工具类
工具类将加载驱动, 获取Connection连接对象, 释放资源一些操作封装成静态方法, 用的时候直接拿

就叫做JdbcUtil的类

public class JdbcUtil {

    private static String dirver = null;
    private static String url = null;
    private static String username = null;
    private  static String password = null;

    //获取数据库的外部文件
    //这里放在静态代码块里, 在第一次new对象时候, 就需要加载驱动
    static {
        try {
        //通过字节输入流来读取对应的properties文件
        InputStream in = JdbcUtil.class.getClassLoader().getResourceAsStream("db.properties");
        //再将读取到的文件放入到jdk里的properties对象里
        Properties pop = new Properties();
        //来获取外部的db.properties数据
        pop.load(in);

        //对应属性赋对象方法
        dirver = pop.getProperty("driver");
        url = pop.getProperty("url");
        username = pop.getProperty("username");
        password = pop.getProperty("password");

        //加载驱动
            Class.forName(dirver);
        } catch (IOException | ClassNotFoundException e) {
            System.out.println("java获取Connection对象错误");
            e.printStackTrace();
        }
    }
    //获取连接对象
    public static Connection getConnection() throws SQLException {
        return DriverManager.getConnection(url, username, password);
    }
    //释放连接对象的资源
    public void relese(Connection con, Statement sta, ResultSet res){
        if (res!=null){
            try {
                res.close();
            } catch (SQLException throwables) {
                System.out.println("sql接收数据集合ResultSet关闭异常");
                throwables.printStackTrace();
            }
        }
        if (sta!=null){
            try {
                sta.close();
            } catch (SQLException throwables) {
                System.out.println("sql接收数据集合ResultSet关闭异常");

                throwables.printStackTrace();
            }
        }
        if (con!=null){
            try {
                res.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
    }
}

3. 登录判断账号

<1>与数据库交互的Dao层代码展示


LoginDao

public class LoginDao {
    public Admin checkAccount(String account,String passWord) throws SQLException {
        Connection connection = null;
        PreparedStatement ps =null;
        ResultSet resultSet = null;
        Admin admin = null;
        JdbcUtil jdbcUtil = new JdbcUtil();

		//直接通过类调取方法来获取连接对象
        connection = jdbcUtil.getConnection();
    	//  ps = connection.prepareStatement("select account password from admin where account="+"\'"+account+"\'");
        ps = connection.prepareStatement("select id, account from admin where account=? and password=?");
        ps.setObject(1, account);
        ps.setObject(2, passWord);
        resultSet = ps.executeQuery();

        //如果有结果, 说明有该账号
        while(resultSet.next()){
            admin = new Admin();
            admin.setId(resultSet.getInt("id"));
            admin.setAccount(resultSet.getString("account"));
            break;
        }
        //释放连接数据库资源
        jdbcUtil.relese(connection,ps,resultSet);

        return admin;
    }
}

在这里插入图片描述

这三个地方需要注意一下
<1>第一部分 在判断登录这个Dao里, 此方法不能仅仅判断账号密码是否正确, 还要获取返回的那个admin对象

在实际项目中, 难道后天不需要账户信息吗?
就拿淘宝例子来说把, 是不是当你买个东西之后,再次登录时候就给你推类似的一些东西, 这里就是后天已经记录了你买的东西, 所以登录时候就知道给你推相似的商品了

<2>不能直接将用户的账号注入到SQL里查找

 ps = connection.prepareStatement("select account password from admin where account="+"\'"+account+"\'");

这一行代码, 可能会让一些 偷奸耍滑 的人钻空子, 你想想, 直接获取到的账号信息放入sql语句查找,

如果有一个用户输入account: 1==1, 那你此处sql的where条件不就形同虚设了嘛, 随便进入管理系统, 那你就等着被炒鱿鱼把

所以要用格式占位控制符来代替

        ps = connection.prepareStatement("select id, account from admin where account=? and password=?");
        ps.setObject(1, account);
        ps.setObject(2, passWord);

这不就肥肠完美么


<2>业务处理层LoginService

public class LoginServlet extends HttpServlet {

    @Override
    public void service(ServletRequest req, ServletResponse resp) throws ServletException, IOException {
        String account = req.getParameter("account");
        String password = req.getParameter("password");
        CommonRes commonRes = null;
        try{
            LoginDao loginDao = new LoginDao();
            Admin admin = loginDao.checkAccount(account, password);
            System.out.println(admin);
            if (admin!=null){
                //生成token
                String token = JWTUtil.token(admin);
                admin.setToken(token);
                commonRes = new CommonRes(200,admin,"登录成功");
            }else{
                commonRes = new CommonRes(201,"账号或密码错误");
            }
        }catch(Exception e){
            e.printStackTrace();
            commonRes = new CommonRes(500,"服务器异常");
        }
        //将common结果转化成jason格式返回
        resp.setContentType("text/html;charset=UTF-8");
        Writer writer = resp.getWriter();
        ObjectMapper mapper = new ObjectMapper();
        String jsonstr = mapper.writeValueAsString(commonRes);
        writer.write(jsonstr);
    }

代码解读
在这里插入图片描述
由于前端用的是axios的请求发送框架, 所以数据格式在经过服务器内部的一系列处理之后, 就会变成json的键值对格式,
所以后端可以直接 用 req.getParameter(“account”);获取对应参数值

        String account = req.getParameter("account");
        String password = req.getParameter("password");

4. 解决跨域问题

跨域是指从一个域名的网页去请求另一个域名的资源。比如从www.baidu.com 页面去请求 www.google.com 的资源。但是一般情况下不能这么做,它是由浏览器的同源策略造成

所以可以告诉浏览器可以访问, 可以在响应头里设置

我从后端来解决这个问题

由此我们可以写过一个过滤器来实现

public class CorsFilter implements Filter {
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
            throws IOException, ServletException {
        HttpServletResponse httpResponse = (HttpServletResponse) servletResponse;
        HttpServletRequest httpRequest = (HttpServletRequest) servletRequest;
        //允许携带Cookie时不能设置为* 否则前端报错
        httpResponse.setHeader("Access-Control-Allow-Origin", httpRequest.getHeader("origin"));//允许所有请求跨域
        httpResponse.setHeader("Access-Control-Allow-Methods", "*");//允许跨域的请求方法GET, POST, HEAD 等
        httpResponse.setHeader("Access-Control-Allow-Headers", "*");//允许跨域的请求头
        httpResponse.setHeader("Access-Control-Allow-Credentials", "true");//是否携带cookie

        filterChain.doFilter(servletRequest, servletResponse);
    }
}

并且在web.xml里配置哪些业务经过 过滤器

    <filter>
    <filter-name>corsFilter</filter-name>
    <filter-class>com.jwq.webback.filter.CorsFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>corsFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

5. 后端对返回结果进行封装

由于每次对后端结果进行返回时候,只能一个一个返回, 所以此时可以封装一个返回的结果集

commonRes

public class CommonRes {
    private int code;
    private Object data;
    private String message;

    public CommonRes(int code, Object data, String message) {
        this.code = code;
        this.data = data;
        this.message = message;
    }

    public CommonRes(int code, String message) {
        this.code = code;
        this.message = message;
    }

    //在转化json格式要通过反射机制用set, get方法来取值
    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public Object getData() {
        return data;
    }

    public void setData(Object data) {
        this.data = data;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}

代码解析
在这里插入图片描述
注意: 这里必须是有set,get方法, 因为在后面的json返回格式, 必须要通过反射机制转化json格式

6. 后端对返回结果进行转化json格式后进行响应

<1>首先要导入jar包
在这里插入图片描述
<2>在使用mapper对象里的writeValuesAsString()对响应结果进行json格式的处理

        Writer writer = resp.getWriter();
        ObjectMapper mapper = new ObjectMapper();
        //commonRes这是上面说的返回结果集对象,放入mapper对象的
        //方法里,转json格式
        String jsonstr = mapper.writeValueAsString(commonRes);
        writer.write(jsonstr);

<3>json响应结果查看

在这里插入图片描述
注意: 这里的message响应的是中文, 所以要设置响应头编码

可以设置一个过滤器, 将请求编码与响应编码一起设置了

public class EncodFilter implements Filter {
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        servletRequest.setCharacterEncoding("utf-8");
        HttpServletResponse response = (HttpServletResponse)servletResponse;
        response.setContentType("text/html;charset=UTF-8");
        //让进入到过滤器里的请求, 离开当前的过滤器, 继续向后执行, 后一个可能是过滤器,也可以是servlet
        filterChain.doFilter(servletRequest,servletResponse);
    }
}


在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

机智云物联网低功耗转接板GE211+机智云APP遥控灯

要实现硬件的智能化&#xff0c;除了硬件本身外&#xff0c;还需要实现&#xff1a;智能云平台、手机 APP、联网模块&#xff0c;每 一个领域都需要专业的团队来支撑。机智云提供完整的解决方案&#xff0c;让厂商或开发者只需要专 注于自身产品硬件。以最小的成本和风险实现硬…

【网络】路由器和无线路由器就这么配置

目录 &#x1f352;常见的接入互联网方式 &#x1f353;WAN配置 &#x1f353;LAN口配置 &#x1f353;WLAN配置 &#x1f353;WLAN安全 &#x1f352;路由设备管理 &#x1f353;路由器内部组件 &#x1f353;Cisco路由器的启动过程 &#x1f353;基础命令 &#x1f34e;show …

数据库中的DDL、DQL、DML、DCL 和 TCL 命令

数据库中的DDL、DQL、DML、DCL 和 TCL 命令 SQLDDL&#xff08;Data Definition Language&#xff09;数据库定义语言DML&#xff08;Data Manipulation Language&#xff09;数据操纵语言TCL&#xff08;Transaction Control Language&#xff09;事务控制语言DQL (Data Query…

UEFI开发环境搭建(Windows)

重拾UEFI学习。 第一步是搭建开发环境&#xff0c;记录如下&#xff1a; 1. 安装开发工具 Visual Studio 2017 python/ASL/NASM 安装到如下目录&#xff1a; c:\Python310 c:\ASL c:\NASM 更新系统变量Path: 新建系统变量PYTHON_HOME 下载EDK2 创建工作目录&#xff…

一个技巧,让ChatGPT学会复杂编程,编程水平逼近人类程序员!

夕小瑶科技说 原创 作者 | 智商掉了一地、Python 随着 AIGC 技术迈出了一大步&#xff0c;ChatGPT 等聊天机器人被频繁地使用在生活和工作中的各个场景。想象一下&#xff0c;当你写代码陷入没有头绪的境地或者无法解决 Bug 时&#xff0c;这种基于大型语言模型&#xff08;LL…

ROS:发布者Publisher的编程实现(C++)

目录 一、话题模型二、创建功能包三、创建Publisher代码四、编译代码五、运行 一、话题模型 图中&#xff0c;我们使用ROS Master管理节点。 有两个主要节点&#xff1a; Publisher&#xff0c;名为Turtle Velocity&#xff08;即海龟的速度&#xff09; Subscriber&#xff0c…

STM32H723ZGT6 LAN8720A LWIP

Stm32CubeMX 版本&#xff1a;6.8.1 硬件库版本&#xff1a;STM32Cube FW_H7 V1.11.0 usart.c#include <stdio.h> #if 1//标准库需要的支持函数 struct __FILE { int handle; }; FILE __stdout; //定义_sys_exit()以避免使用半主机模式 void _…

设计模式(二):创建型之工厂方法和抽象工厂模式

设计模式系列文章 设计模式(一)&#xff1a;创建型之单例模式 设计模式(二)&#xff1a;创建型之工厂模式 目录 一、设计模式分类二、概述三、简单工厂模式1、结构2、实现3、扩展&#xff1a;静态工厂 四、工厂方法模式1、结构2、 实现3、优缺点 五、抽象工厂模式1、结构2、实…

牛客网2018吉比特校招技术开发类试题分析

最近做了两套笔试题&#xff0c;复习一下错题&#xff0c;有很多地方需要查缺补漏&#xff0c;再谈一下感受总结一下。 2018届吉比特校招技术类笔试B卷 吉比特2018届提前批校园招聘-开发类试卷 一、基础题 1.已知 a 6789x 6789、b 6789x 6790、c 6789x 6791&#xff0c…

GIT | 浅析原理篇

此篇文章主要是讲讲 一些 git 操作发生的时候 , .git 文件如何变化&#xff0c;git 背后发生了什么。磨刀不误砍柴工嘛&#xff01;算是一篇视频观后笔记&#xff08;文末取视频地址&#xff09; 基础概念 Git 是一个代码版本管控的工具&#xff0c;是一个内容寻址文件系统&am…

剑指 Offer 14- I. 剪绳子解题思路

文章目录 题目解题思路优化 题目 给你一根长度为 n 的绳子&#xff0c;请把绳子剪成整数长度的 m 段&#xff08;m、n都是整数&#xff0c;n>1并且m>1&#xff09;&#xff0c;每段绳子的长度记为 k[0],k[1]…k[m-1] 。请问 k[0]k[1]…*k[m-1] 可能的最大乘积是多少&…

Spring Boot + vue-element 开发个人博客项目实战教程(二十六、前端首页统计完善及完结)

⭐ 作者简介&#xff1a;码上言 ⭐ 代表教程&#xff1a;Spring Boot vue-element 开发个人博客项目实战教程 ⭐专栏内容&#xff1a;个人博客系统 ⭐我的文档网站&#xff1a;http://xyhwh-nav.cn/ 后端代码gitee地址&#xff1a;https://gitee.com/whxyh/personal_blog …

设计模式六大原则的理解

本文参考&#xff1a; 设计模式简介 | 菜鸟教程 (runoob.com) 六大设计原则之依赖倒置原则&#xff08;DIP&#xff09; - 简书 (jianshu.com) 设计模式的六大原则有&#xff1a; 1、开闭原则&#xff08;Open Close Principle&#xff09; 开闭原则的意思是&#xff1a;对扩…

设计模式之~桥接模式

桥接模式&#xff1a; 将抽象部分与它的实现部分分离&#xff0c;使他们都可以独立地变化。这种类型的设计模式属于结构型模式&#xff0c;它通过提供抽象化和实现化之间的桥接结构&#xff0c;来实现二者的解耦。 什么叫抽象与它的实现分离&#xff0c;这并不是说&#xff0c;…

图解系列 图解Spring Boot 最大连接数及最大并发数

文章目录 概序架构图TCP的3次握手4次挥手时序图核心参数AcceptCountMaxConnectionsMinSpareThread/MaxThreadMaxKeepAliveRequestsConnectionTimeoutKeepAliveTimeout 内部线程AcceptorPollerTomcatThreadPoolExecutor 测试参考 每个Spring Boot版本和内置容器不同&#xff0c;…

树状数组学习总结

今天本初中生蒟蒻学习了一下 树状数组 \color{red}{树状数组} 树状数组&#xff0c;总结一下~~~ 树状数组的实现 功能简介 快速求前缀和&#xff08; O ( l o g 2 n ) \color{purple}{O(log_2n)} O(log2​n)&#xff09;修改某一个数&#xff08; O ( l o g 2 n ) \color{gr…

SpringBoot+原生awt,实现花花绿绿的图形验证码

图形验证码是用于验证用户身份的一种方式&#xff0c;通常在网站注册、登录或进行某些敏感操作时会使用。它通过展示一个包含随机字符或数字的图形&#xff0c;要求用户输入相应的字符或数字来证明其为真人而非机器人。图形验证码能有效地防止机器人攻击和恶意注册行为&#xf…

Excel·VBA自动生成日记账的对方科目

如图&#xff1a;根据日记账/序时账的日期、凭证号为一组&#xff0c;按借贷方向生成相反的科目&#xff0c;并写入H列。可能存在一对一、一对多、多对多等情况的账目 目录 数组法遍历、判断、写入测试结果 多对多问题处理测试结果 数组法遍历、判断、写入 适用日期凭证号连续…

HTTPS的加密流程——巨详细!

文章目录 前言HTTPS的工作过程引入对称加密引入非对称加密引入证书完整的加密流程总结 前言 HTTPS 也是一个应用层协议. 是在 HTTP 协议的基础上引入了一个加密层. HTTP 协议内容都是按照文本的方式明文传输的. 这就导致在传输过程中出现一些被篡改的情况. 比如&#xff1a;臭…

民宿预订系统的设计与实现(ASP.NET,SQLServer)

这个民宿预订系统是由第三方的运营公司来运营&#xff0c;他提供了一个民宿和客户都使用的一个信息平台&#xff0c;民宿注册之后把自己的民宿信息发布到网站平台上&#xff0c;然后发布自己的房间信息&#xff0c;打折信息等供客户查看和选择。客户可以在网站平台上查看民宿信…