JDBC【封装工具类、SQL注入问题】
day54
JDBC
封装工具类01
创建配置文件
DBConfig.properties
driverName=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/qnz01?characterEncoding=utf8&serverTimezone=UTC
username=root
password=root
新建配置文件,不用写后缀名
创建工具类
- 将变化的配置信息搬到配置文件中
- 工具类提供获取连接的方法
- 工具类提供关闭资源的方法
package com.qf.utils;/*** 数据库工具类*/
public class DBUtil {private static String url;private static String username;private static String password;static{//负责加载配置文件,只加载一次Properties properties = new Properties();try {properties.load(DBUtil.class.getClassLoader().getResourceAsStream("DBConfig.properties"));} catch (IOException e) {throw new RuntimeException(e);}String driverName = properties.getProperty("driverName");url = properties.getProperty("url");username = properties.getProperty("username");password = properties.getProperty("password");try {//加载驱动只加载一次Class.forName(driverName);} catch (ClassNotFoundException e) {throw new RuntimeException(e);}}/*** 获取连接对象*/public static Connection getConnection() throws SQLException {Connection connection = DriverManager.getConnection(url,username,password);return connection;}/*** 关闭资源*/public static void close(Connection connection, Statement statement, ResultSet resultSet){if(resultSet != null){try {resultSet.close();} catch (SQLException e) {throw new RuntimeException(e);}}if(statement != null){try {statement.close();} catch (SQLException e) {throw new RuntimeException(e);}}if(connection != null){try {connection.close();} catch (SQLException e) {throw new RuntimeException(e);}}}}
理解
(1)新建配置文件
把导入驱动包和获取连接对象的参数url、root、password写入配置文件
(2)将获取连接对象方法封装到工具类DBUtil
01:加载配置文件
new 一个配置文件对象,配置文件对象调用加载方法加载进来【报异常先用try-catch】
之后就可以配置文件对象调用方法拿到配置信息【注意要与配置文件的名字相同,否则找不到就是null】
02:导入驱动包03:在获取连接对象方法里,调用方法获取连接对象,返回连接对象
04:对于关闭资源,不用每次都写,直接在工具类写个关闭资源方法传入可能关的资源,里面非空判断哪些要关就行了
注意:
通常会把加载配置文件和导入驱动包放在静态代码块里,提高效率,不用获取一次连接加载一次,加载一次就行
对于重复使用的属性先静态定义【注意静态代码块只能初始化静态的属性】基本操作报错try-catch【例如类这里的forName类未找到异常就要么资源文件没导入,要么配置文件对应的名称没写对】,对于需要对应不同业务处理异常就需要抛异常,在外面处理
现在对于先前的增删改查就不用那么麻烦,每个都写导入驱动包和获取连接对象的一大坨代码,当然这里就涉及封装工具类
直接用工具类调用获取连接对象的方法,关闭资源方法
测试类
对day53的增删改查进行进一步优化
package com.qf.jdbc01;import com.qf.utils.DBUtil;
import org.junit.Test;import java.sql.*;public class Test01 {/*** 知识点:封装DBUtil - v1.0*///添加数据@Testpublic void test01() throws SQLException {//获取连接对象Connection connection = DBUtil.getConnection();//获取发送指令对象Statement statement = connection.createStatement();//发送SQL指令String sql = "INSERT INTO student(name,sex,age,salary,course) VALUES('柳如烟','女',28,6000,'HTML');";int num = statement.executeUpdate(sql);System.out.println("对于" + num + "行造成了影响");//关闭资源DBUtil.close(connection,statement,null);}//删除数据@Testpublic void test02() throws SQLException {//获取连接对象Connection connection = DBUtil.getConnection();//获取发送指令对象Statement statement = connection.createStatement();//发送SQL指令String sql = "DELETE FROM student WHERE id>10;";int num = statement.executeUpdate(sql);System.out.println("对于" + num + "行造成了影响");//关闭资源DBUtil.close(connection,statement,null);}//修改数据@Testpublic void test03() throws SQLException {//获取连接对象Connection connection = DBUtil.getConnection();//获取发送指令对象Statement statement = connection.createStatement();//发送SQL指令String sql = "UPDATE student SET age=21,salary=50000 WHERE id=3;";int num = statement.executeUpdate(sql);System.out.println("对于" + num + "行造成了影响");//关闭资源DBUtil.close(connection,statement,null);}//查询数据@Testpublic void test04() throws SQLException {//获取连接对象Connection connection = DBUtil.getConnection();//获取发送指令对象Statement statement = connection.createStatement();//发送SQL指令,并获取结果集对象String sql = "select * from student";ResultSet resultSet = statement.executeQuery(sql);//遍历结果集while(resultSet.next()){//判断是否有可迭代的数据行int id = resultSet.getInt("id");String name = resultSet.getString("name");String sex = resultSet.getString("sex");int age = resultSet.getInt("age");float salary = resultSet.getFloat("salary");String course = resultSet.getString("course");System.out.println(id + " -- " + name + " -- " + sex + " -- " + age + " -- " + salary + " -- " + course);}//关闭资源DBUtil.close(connection,statement,resultSet);}}
SQL注入问题
理解
ps:select * from student where name=‘’ or 1=1 #’ and passwd=‘111111’;
当输入用户名和密码
’ or 1=1 # '【对于它分不清sql命令和数据,就会or 1=1判断为true,#后面理解为注释,就直接登录进去了】
package com.qf.jdbc02;import com.qf.utils.DBUtil;public class Test01 {/*** 知识点:SQL注入问题** 出现原因:数据库分不清哪些是sql命令,哪些是数据** 需求:模拟登录功能*/public static void main(String[] args) throws SQLException {Connection connection = DBUtil.getConnection();Statement statement = connection.createStatement();Scanner scan = new Scanner(System.in);System.out.println("请输入账号:");String usernameVal = scan.nextLine();System.out.println("请输入密码:");String passwordVal = scan.nextLine();//select * from user where username='' or 1=1 #' and password='12312345'String sql = "select * from user where username='"+usernameVal+"' and password='"+passwordVal+"'";ResultSet resultSet = statement.executeQuery(sql);if(resultSet.next()){String username = resultSet.getString("username");String password = resultSet.getString("password");String nikeName = resultSet.getString("nike_name");System.out.println("登录成功");System.out.println(username);System.out.println(password);System.out.println(nikeName);}else{System.out.println("登录失败");}DBUtil.close(connection,statement,resultSet);}
}
解决
采用预编译对象来编程:告诉他,使用prepareStatement
sql命令中用?表示数据
注意:prepareStatement继承于statement
现在用prepareStatement拿到的sql是没有数据的,得到它的对象
再将输入的数据设置给这个对象,注意方法SetString的两个参数(下标,值)【注意下标从1开始】
- 安全性,避免了SQL注入
- 性能,预编译,语句-编译-执行
package com.qf.jdbc02;import com.qf.utils.DBUtil;public class Test02 {/*** 知识点:SQL注入问题** 出现原因:数据库分不清哪些是sql命令,哪些是数据* 解决方案:告诉数据库哪些是sql命令,哪些是数据** 需求:模拟登录功能*/public static void main(String[] args) throws SQLException {Connection connection = DBUtil.getConnection();String sql = "select * from user where username=? and password=?";PreparedStatement statement = connection.prepareStatement(sql);//输入数据后,将数据设置给statement对象Scanner scan = new Scanner(System.in);System.out.println("请输入账号:");String usernameVal = scan.nextLine();System.out.println("请输入密码:");String passwordVal = scan.nextLine();statement.setString(1,usernameVal);statement.setString(2,passwordVal);ResultSet resultSet = statement.executeQuery();if(resultSet.next()){String username = resultSet.getString("username");String password = resultSet.getString("password");String nikeName = resultSet.getString("nike_name");System.out.println("登录成功");System.out.println(username);System.out.println(password);System.out.println(nikeName);}else{System.out.println("登录失败");}DBUtil.close(connection,statement,resultSet);}
}
封装工具类02
更新数据(添加、删除、修改):
01方法传的参数(一个sql命令,另一个数据不确定用可变参数)
02由于不知道下标和值用setObject设置给statement,但有多个参数需要遍历处理就写个方法来专门处理【处理statement对象参数数据的处理器,注意setObject下标从1开始】直接调用处理
03添加操作返回影响行数
04而考虑到关闭资源,处理异常就不会关闭资源,对代码进行try-finally,考虑作用域把定义对象放在之外
添加–主键回填:
就是添加数据后,不再是返回影响的行数,加一个查询返回主键
主键回填理解:
查询:
以前查询就打印出来结果,现在查询的数据封装成对象,不同表封装不同的对象
01学生类:有参无参自动生成时,window+alt+回车快速生成,生成时涉及属性选择ctrl+1全选
02方法返回值设置成list集合,类型用泛型;传的参数(哪个类的对象clazz【反射创建】,一个sql,一个可变参数)
03对于拿到的结果集,需要遍历, 一个数据创建一个对象
先泛型创建对象【无数据】,获取数据字段名才可以利用反射去设置对象的属性
怎么获取:先用结果集对象调用方法获取表数据对象,再表数据对象调用方法获取字段个数,再在遍历中通过字段个数循环获取字段名,字段值反射获取类的属性对象和设置对象的属性【对于反射设置属性回顾以前反射讲到的方法】
04然后将封装的对象添加到对象集合再返回
05而考虑到关闭资源,处理异常就不会关闭资源,对代码进行try-finally,考虑作用域把定义对象放在之外
package com.qf.utils;/*** 数据库工具类*/
public class DBUtil {private static String url;private static String username;private static String password;static{//负责加载配置文件,只加载一次Properties properties = new Properties();try {properties.load(DBUtil.class.getClassLoader().getResourceAsStream("DBConfig.properties"));} catch (IOException e) {throw new RuntimeException(e);}String driverName = properties.getProperty("driverName");url = properties.getProperty("url");username = properties.getProperty("username");password = properties.getProperty("password");try {//加载驱动只加载一次Class.forName(driverName);} catch (ClassNotFoundException e) {throw new RuntimeException(e);}}/*** 获取连接对象*/public static Connection getConnection() throws SQLException {Connection connection = DriverManager.getConnection(url,username,password);return connection;}/*** 关闭资源*/public static void close(Connection connection, Statement statement, ResultSet resultSet){if(resultSet != null){try {resultSet.close();} catch (SQLException e) {throw new RuntimeException(e);}}if(statement != null){try {statement.close();} catch (SQLException e) {throw new RuntimeException(e);}}if(connection != null){try {connection.close();} catch (SQLException e) {throw new RuntimeException(e);}}}/*** 更新数据(添加、删除、修改)*/public static int commonUpdate(String sql,Object... params) throws SQLException {Connection connection = null;PreparedStatement statement = null;try {connection = getConnection();statement = connection.prepareStatement(sql);paramHandler(statement,params);int num = statement.executeUpdate();return num;}finally {close(connection,statement,null);}}/*** 添加数据 - 主键回填(主键是int类型可以返回)*/public static int commonInsert(String sql,Object... params) throws SQLException {Connection connection = null;PreparedStatement statement = null;ResultSet resultSet = null;try {connection = getConnection();statement = connection.prepareStatement(sql,PreparedStatement.RETURN_GENERATED_KEYS);paramHandler(statement,params);statement.executeUpdate();resultSet = statement.getGeneratedKeys();int primaryKey = 0;if(resultSet.next()){primaryKey = resultSet.getInt(1);}return primaryKey;}finally {close(connection,statement,resultSet);}}/*** 查询数据*/public static <T> List<T> commonQuery(Class<T> clazz,String sql, Object... params) throws SQLException, InstantiationException, IllegalAccessException {Connection connection = null;PreparedStatement statement = null;ResultSet resultSet = null;try {connection = getConnection();statement = connection.prepareStatement(sql);paramHandler(statement,params);resultSet = statement.executeQuery();//获取表数据对象ResultSetMetaData metaData = resultSet.getMetaData();//获取字段个数int count = metaData.getColumnCount();List<T> list = new ArrayList<>();while(resultSet.next()){T t = clazz.newInstance();//获取字段名及数据for (int i = 1; i <= count; i++) {String fieldName = metaData.getColumnName(i);Object fieldVal = resultSet.getObject(fieldName);setField(t,fieldName,fieldVal);}list.add(t);}return list;} finally {DBUtil.close(connection,statement,resultSet);}}/*** 处理statement对象参数数据的处理器*/private static void paramHandler(PreparedStatement statement,Object... params) throws SQLException {for (int i = 0; i < params.length; i++) {statement.setObject(i+1,params[i]);}}/*** 获取当前类及其父类的属性对象* @param clazz class对象* @param name 属性名* @return 属性对象*/private static Field getField(Class<?> clazz,String name){for(Class<?> c = clazz;c != null;c = c.getSuperclass()){try {Field field = c.getDeclaredField(name);return field;} catch (NoSuchFieldException e) {} catch (SecurityException e) {}}return null;}/*** 设置对象中的属性* @param obj 对象* @param name 属性名* @param value 属性值*/private static void setField(Object obj,String name,Object value){Field field = getField(obj.getClass(), name);if(field != null){field.setAccessible(true);try {field.set(obj, value);} catch (IllegalArgumentException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();}}}
}
调用工具类的方法实现增删改查
package com.qf.jdbc03;import com.qf.utils.DBUtil;public class Test01 {/*** 知识点:封装数据库 - v2.0*///添加数据@Testpublic void test01() throws SQLException {String sql = "INSERT INTO student(name,sex,age,salary,course) VALUES(?,?,?,?,?)";int num = DBUtil.commonUpdate(sql, "天使萌", "女", 23, 10000, "HTML");System.out.println("对于" + num + "行造成了影响");}//删除数据@Testpublic void test02() throws SQLException {String sql = "delete from student where id=?";int num = DBUtil.commonUpdate(sql, 3);System.out.println("对于" + num + "行造成了影响");}//修改数据@Testpublic void test03() throws SQLException {String sql = "update student set salary=? where id=?";int num = DBUtil.commonUpdate(sql, 15000,1);System.out.println("对于" + num + "行造成了影响");}//添加数据 - 主键回填@Testpublic void test04() throws SQLException {String sql = "INSERT INTO student(name,sex,age,salary,course) VALUES(?,?,?,?,?)";int primaryKey = DBUtil.commonInsert(sql, "铃原爱蜜莉", "女", 23, 10000, "HTML");System.out.println("返回的主键是:" + primaryKey);}//查询数据@Testpublic void test05() throws SQLException, InstantiationException, IllegalAccessException {String sql = "select * from student where id<?";List<Student> list = DBUtil.commonQuery(Student.class, sql, 8);for (Student stu : list) {System.out.println(stu);}}
}
学生类
package com.qf.jdbc03;public class Student {private int id;private String name;private String sex;private int age;private float salary;private String course;public Student() {}public Student(int id, String name, String sex, int age, float salary, String course) {this.id = id;this.name = name;this.sex = sex;this.age = age;this.salary = salary;this.course = course;}public int getId() {return id;}public void setId(int id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getSex() {return sex;}public void setSex(String sex) {this.sex = sex;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public float getSalary() {return salary;}public void setSalary(float salary) {this.salary = salary;}public String getCourse() {return course;}public void setCourse(String course) {this.course = course;}@Overridepublic String toString() {return "Student{" +"id=" + id +", name='" + name + '\'' +", sex='" + sex + '\'' +", age=" + age +", salary=" + salary +", course='" + course + '\'' +'}';}
}
小结:
JDBC:封装工具类,对增删改查优化,SQL注入问题
相关文章:

JDBC【封装工具类、SQL注入问题】
day54 JDBC 封装工具类01 创建配置文件 DBConfig.properties driverNamecom.mysql.cj.jdbc.Driver urljdbc:mysql://localhost:3306/qnz01?characterEncodingutf8&serverTimezoneUTC usernameroot passwordroot新建配置文件,不用写后缀名 创建工具类 将变…...

Windows打开redis以及Springboot整合redis
目录 前言Windows系统打开redisSpringboot整合redis依赖实体类yml配置文件config配置各个数据存储类型分别说明记录string数据写入redis,并查询通过命令行查询 list插入数据到redis中从redis中读取命令读取数据 hash向redis中逐个添加map键值对获取key对应的map中所…...
MySQL使用LIKE索引是否失效的验证
1、简单的示例展示 在MySQL中,LIKE查询可以通过一些方法来使得LIKE查询能够使用索引。以下是一些可以使用的方法: 使用前导通配符(%),但确保它紧跟着一个固定的字符。 避免使用后置通配符(%)&…...

封装日历uniapp,只显示年月不显示日
默认展示最新日期 子组件 <template><view class"date-picker"><picker mode"date" fields"month" change"onDateChange" :value"selectedDate"><view class"picker">{{ selectedDate…...

golang线程池ants-实现架构
1、总体架构 ants协程池,在使用上有多种方式(使用方式参考这篇文章:golang线程池ants-四种使用方法),但是在实现的核心就一个,如下架构图: 总的来说,就是三个数据结构: Pool、WorkerStack、goW…...

Mysql面试合集
概念 是一个开源的关系型数据库。 数据库事务及其特性 事务:是一系列的数据库操作,是数据库应用的基本逻辑单位。 事务特性: (1)原子性:即不可分割性,事务要么全部被执行,要么就…...
Android Gradle 开发与应用 (五): 构建变体与自定义任务
目录 1. 概述 2. 构建变体 2.1 构建变体的概念 2.2 构建类型 2.3 产品风味 2.4 构建变体的使用 3. 自定义任务 3.1 自定义任务的概念 3.2 创建自定义任务 3.3 配置任务依赖 3.4 任务类型 3.5 动态任务 3.6 自定义任务执行顺序 4. 案例 4.1 多渠道打包 4.2 自动…...

Django学习第六天
启动项目命令 python manage.py runserver 取消模态框功能 js实现列表数据删除 第二种实现思路 使用jquery修改模态框标题 编辑页面拿到数据库数据显示默认数据功能实现 想要去数据库中获取数据时:对象/字典 三种不同的数据类型 使用Ajax传入数据实现表单编辑&…...

docker部署mycat,连接上面一篇的一主二从mysql
一、docker下载mycat镜像 查看安装结果 这个名称太长,在安装容器时不方便操作,设置标签为mycat docker tag longhronshens/mycat-docker mycat 二、安装容器 先安装一个,主要目的是获得配置文件 docker run -it -d --name mycat -p 8066:…...
VUE2拖拽组件:vue-draggable-resizable-gorkys
vue-draggable-resizable-gorkys组件基于vue-draggable-resizable进行二次开发, 用于可调整大小和可拖动元素的组件并支持冲突检测、元素吸附、元素对齐、辅助线 安装: npm install --save vue-draggable-resizable-gorkys 全局引用: import Vue from vue import vdr fro…...

容器:stack
以下是关于stack容器的一些总结: stack容器比较简单,主要包括: 1、构造函数:stack [staName] 2、添加、删除元素: push() 、pop() 3、获取栈顶元素:top() 4、获取栈的大小:size() 5、判断栈是否为空&#x…...

跨平台Ribbon UI组件QtitanRibbon全新发布v6.7.0——支持Qt 6.6.3
没有Microsoft在其办公解决方案中提供的界面,就无法想象现代应用程序,这个概念称为Ribbon UI,目前它是使应用程序与时俱进的主要属性。QtitanRibbon是一款遵循Microsoft Ribbon UI Paradigm for Qt技术的Ribbon UI组件,QtitanRibb…...
(6) 深入探索Python-Pandas库的核心数据结构:DataFrame全面解析
目录 前言1. DataFrame 简介2. DataFrame的特点3. DataFrame的创建3.1 使用字典创建DataFrame3.2 使用列表的列表(或元组)创建DataFrame3.3 使用NumPy数组创建DataFrame3.4 使用Series构成的字典创建DataFrame3.5 使用字典构成的字典创建DataFrame 4. 从…...

在 Azure 云中开始使用适用于 Ubuntu 的 Grafana
介绍 Grafana 是一款开源工具,可用于可视化和分析数据。它特别适合跟踪计算机系统的运行情况。在构建微服务或其他类型的应用程序时,您可能需要分析日志数据、轻松可视化数据或设置特殊警报以接收有关系统中发生的某些事件的通知。 这就是为什么你可能…...

1.Python学习笔记
一、环境配置 1.Python解释器 把程序员用编程语言编写的程序,翻译成计算机可以执行的机器语言 安装: 双击Python3.7.0-选择自定义安装【Customize installation】-勾选配置环境变量 如果没有勾选配置环境变量,输入python就会提示找不到命令…...

中英双语介绍百老汇著名歌剧:《猫》(Cats)和《剧院魅影》(The Phantom of the Opera)
中文版 百老汇著名歌剧 百老汇(Broadway)是世界著名的剧院区,位于美国纽约市曼哈顿。这里汇集了许多著名的音乐剧和歌剧,吸引了全球各地的观众。以下是两部百老汇的经典音乐剧:《猫》和《剧院魅影》的详细介绍。 1.…...

RpcChannel的调用过程
目录 1. RPC调用方(caller)的调用(消费)过程 2.在caller下创建文件:calluserservice.cc 3.在src的include下创建文件:mprpcchannel.h 4.在src下创建mprpcchannel.cc 1. RPC调用方(caller)的调用(消费)过…...

东芝TB6560AHQ/AFG步进电机驱动IC:解锁卓越的电机控制性能
作为一名工程师,一直在寻找可靠且高效的组件来应用于你的项目中。东芝的TB6560AHQ/AFG步进电机驱动IC能够提供精准且多功能的电机控制,完全符合现代应用的高要求,保证高性能和易用性。在这篇文章中,我们将探讨TB6560AHQ/AFG的主要…...

免杀笔记 ----> DLL注入
这段时间我们暂时没什么事情干的话我们就继续更新我们的免杀笔记力!!! :今天我们讲DLL注入 目录 1.DLL注入 2.直接加载DLL? 3.远程线程注入 获取Handle 远程申请内存空间 将我们的CS的DLL加载入内存 创建远程线…...

奇迹MU 骷髅战士在哪
BOSS分布图介绍 我为大家带来各地区怪物分布图。在游戏前期,很多玩家可能会不知道该去哪里寻找怪物,也不知道哪些怪物值得打。如果选择了太强的怪物,弱小的玩家可能会无法抵御攻击。如果选择了低等级的boss,收益可能并不理想。所…...
2024年赣州旅游投资集团社会招聘笔试真
2024年赣州旅游投资集团社会招聘笔试真 题 ( 满 分 1 0 0 分 时 间 1 2 0 分 钟 ) 一、单选题(每题只有一个正确答案,答错、不答或多答均不得分) 1.纪要的特点不包括()。 A.概括重点 B.指导传达 C. 客观纪实 D.有言必录 【答案】: D 2.1864年,()预言了电磁波的存在,并指出…...
Axios请求超时重发机制
Axios 超时重新请求实现方案 在 Axios 中实现超时重新请求可以通过以下几种方式: 1. 使用拦截器实现自动重试 import axios from axios;// 创建axios实例 const instance axios.create();// 设置超时时间 instance.defaults.timeout 5000;// 最大重试次数 cons…...
鱼香ros docker配置镜像报错:https://registry-1.docker.io/v2/
使用鱼香ros一件安装docker时的https://registry-1.docker.io/v2/问题 一键安装指令 wget http://fishros.com/install -O fishros && . fishros出现问题:docker pull 失败 网络不同,需要使用镜像源 按照如下步骤操作 sudo vi /etc/docker/dae…...
聊一聊接口测试的意义有哪些?
目录 一、隔离性 & 早期测试 二、保障系统集成质量 三、验证业务逻辑的核心层 四、提升测试效率与覆盖度 五、系统稳定性的守护者 六、驱动团队协作与契约管理 七、性能与扩展性的前置评估 八、持续交付的核心支撑 接口测试的意义可以从四个维度展开,首…...
【Java学习笔记】BigInteger 和 BigDecimal 类
BigInteger 和 BigDecimal 类 二者共有的常见方法 方法功能add加subtract减multiply乘divide除 注意点:传参类型必须是类对象 一、BigInteger 1. 作用:适合保存比较大的整型数 2. 使用说明 创建BigInteger对象 传入字符串 3. 代码示例 import j…...

JVM虚拟机:内存结构、垃圾回收、性能优化
1、JVM虚拟机的简介 Java 虚拟机(Java Virtual Machine 简称:JVM)是运行所有 Java 程序的抽象计算机,是 Java 语言的运行环境,实现了 Java 程序的跨平台特性。JVM 屏蔽了与具体操作系统平台相关的信息,使得 Java 程序只需生成在 JVM 上运行的目标代码(字节码),就可以…...

浪潮交换机配置track检测实现高速公路收费网络主备切换NQA
浪潮交换机track配置 项目背景高速网络拓扑网络情况分析通信线路收费网络路由 收费汇聚交换机相应配置收费汇聚track配置 项目背景 在实施省内一条高速公路时遇到的需求,本次涉及的主要是收费汇聚交换机的配置,浪潮网络设备在高速项目很少,通…...

基于 TAPD 进行项目管理
起因 自己写了个小工具,仓库用的Github。之前在用markdown进行需求管理,现在随着功能的增加,感觉有点难以管理了,所以用TAPD这个工具进行需求、Bug管理。 操作流程 注册 TAPD,需要提供一个企业名新建一个项目&#…...
uniapp 实现腾讯云IM群文件上传下载功能
UniApp 集成腾讯云IM实现群文件上传下载功能全攻略 一、功能背景与技术选型 在团队协作场景中,群文件共享是核心需求之一。本文将介绍如何基于腾讯云IMCOS,在uniapp中实现: 群内文件上传/下载文件元数据管理下载进度追踪跨平台文件预览 二…...
Spring Boot + MyBatis 集成支付宝支付流程
Spring Boot MyBatis 集成支付宝支付流程 核心流程 商户系统生成订单调用支付宝创建预支付订单用户跳转支付宝完成支付支付宝异步通知支付结果商户处理支付结果更新订单状态支付宝同步跳转回商户页面 代码实现示例(电脑网站支付) 1. 添加依赖 <!…...