当前位置: 首页 > news >正文

图片服务器

文章目录

  • 一、项目简介
  • 二、功能及场景
  • 三、业务设计
  • 四、数据库设计
    • 准备图片表
    • 准备实体类
  • 五、API设计
    • 常用功能封装
    • 文件上传
      • 文件上传
    • 获取图片列表接口
    • 获取图片内容
    • 删除图片接口
  • 六、项目优化
  • 七、测试
    • 自动化测试
    • 测试用例

一、项目简介

图片服务器:解决项目中插入图片的问题

在这里插入图片描述

二、功能及场景

1.功能/接口

  • 显示图片列表
  • 显示图片内容
  • 上传图片
  • 删除图片

模拟的html要展示的图片列表:

因为存在上传和删除操作,所以列表是动态变化=>需要是动态网页

(1) servlet返回Java字符串拼接的html内容
(2) 模板技术
(3) ajax 根据响应来动态生成html内容(本项目以此方式实现)

在这里插入图片描述

2.图片服务器的应用场景:

常见的:专门提供图片下载浏览的网站,图床
写博客文章,可以上传图片

三、业务设计

系统设计
数据库设计
接口设计:考虑请求方法,请求路径,请求数据(格式)﹔响应数据(json,图片格式)
基础设施搭建:
maven项目

前端技术: ajax,vue(前端js框架),jquery (只用了这个框架提供的ajax函数来发请求)
后端技术: Servlet, jdbc,commons-fileupload, commons–codec(唯一性验证的框架,通过上传的图片生成md5来验证), jackson,lombok

四、数据库设计

准备图片表

-- 准备表:
-- 注意:图片表的字段,转为实体类的成员变量(名称会关联前后端接口)
create table image_info (image_id int primary key auto_increment comment '主键id',image_name varchar(50) comment '图片名称',size bigint comment '图片大小',upload_time datetime comment '图片上传日期',md5 varchar(128) comment 'md5值,用于校验图片唯一',content_type varchar(50) comment '数据类型,上传图片时,请求数据就包含Content-Type',path varchar(1024) comment '图片的路径: 相对路径'
);

准备实体类

数据库jdbc操作(插入,修改,查询),返回http响应数据,都需要使用实体类。

把数据库的表转为类,字段转为成员变量。

import lombok.Getter;
import lombok.Setter;
import lombok.ToString;@Getter
@Setter
@ToString
public class ImageInfo {//主键idprivate Integer imageId;//图片名称private String imageName;//图片大小private Long size;//图片上传日期private java.util.Date uploadTime;//md5校验码:通过一段数据(字符串,数值,二进制)生成private String md5;//数据格式:http请求上传form-data数据格式时,图片字段还可以包含Content-Typeprivate String contentType;//图片路径:相对路径private String path;
}

五、API设计

常用功能封装

  • 封装数据库连接池
public class DBUtil {//封装数据库连接池(双重校验锁的线程安全的单例模式)private static volatile DataSource DS;private static DataSource getDataSource(){if(DS == null){synchronized (DBUtil.class){if(DS == null){MysqlDataSource dataSource = new MysqlDataSource();dataSource.setURL("jdbc:mysql://localhost:3306/image_system");dataSource.setUser("root");dataSource.setPassword("123456");dataSource.setUseSSL(false);dataSource.setCharacterEncoding("utf8");DS = dataSource;}}}return DS;}public static Connection getConnection(){try {return getDataSource().getConnection();} catch (SQLException e) {throw new RuntimeException("获取数据库连接失败", e);}}@Testpublic void testGetConnection(){System.out.println(getConnection());}public static void close(Connection c, Statement s, ResultSet rs){try {if(rs != null) rs.close();if(s != null) s.close();if(c != null) c.close();} catch (SQLException e) {throw new RuntimeException("释放数据库资源出错", e);}}
}
  • 序列化与反序列化
public class WebUtil {private static final ObjectMapper M = new ObjectMapper();static {//设置序列化的日期格式DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");M.setDateFormat(df);}//json序列化public static void serialize(HttpServletResponse resp, Object o){resp.setContentType("application/json");resp.setCharacterEncoding("UTF-8");try {String json = M.writeValueAsString(o);resp.getWriter().write(json);} catch (IOException e) {//这里是序列化就返回响应了,捕获到异常,就自行处理e.printStackTrace();resp.setStatus(500);}}//反序列化: 请求的json格式数据,转换为Java对象public static <T> T deserialize(HttpServletRequest req, Class<T> clazz){try {return M.readValue(req.getInputStream(), clazz);} catch (IOException e) {throw new RuntimeException("反序列化失败", e);}}
}

文件上传

上传需要考虑到的图片路径的问题:上传到数据库时,需要保存Path;图片本身是要保存在本地硬盘上,也涉及到路径;显示文件内容时,前端需要路径为< img src=“xxxx”>;因此需要分析这些路径该如何设置。

  • 对于上传到数据库中保存的路径信息字段名为path(是服务端自定义的,这里是一个md5值),但是数据库中并不保存完整路径——为自定义后缀,完整路径=本地路径前缀(服务端本地路径前缀)+自定义后缀
  • 前端显示的路径由 <img v-bind:src="'imageShow?imageId=' + image.imageId"> 决定
  • 后端servlet提供/imageShow的接口:通过解析imageId, 找到文件在服务端本地的路径(完整路径),然后把二进制数据写入响应体。其中解析方法是:1,通过Id在数据库中找到对应的数据(包含path字段)2.拼接上前缀就可以找到图片在本地的真实路径;

文件上传

文件上传接口请求如下:

在这里插入图片描述

针对接口的请求,后端servlet进行处理返回响应,整体步骤分为以下操作:

  • 获取请求数据:uploadImage=图片数据 。获取图片Part对象
  • 保存图片完整路径在服务端本地硬盘: 完整路径为路径前缀+后缀(/MD5值)
  • 保存图片信息在数据库
  • 返回响应: {ok: boolean, msg: String} ,是根据接口所需响应设置此两个字段
//图片上传接口@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {//请求数据:uploadImage=图片数据Part p = req.getPart("uploadImage");//1.保存在服务端本地硬盘: 完整路径为路径前缀+后缀(自己约定规则)//我们这里简单的,用md5值作为文件名(/md5值作为后缀)//md5操作,可以基于byte[],String,InputStream//先根据上传的图片,生成md5值String md5 = DigestUtils.md5Hex(p.getInputStream());//保存在服务端本地硬盘:路径前缀(常量)+后缀(/md5值)p.write(LOCAL_PATH_PREFIX+"/"+md5);//2.保存在数据库//先构造一个ImageInfo对象,来保存要插入数据库的数据ImageInfo image = new ImageInfo();//设置图片名称:上传的文件名image.setImageName(p.getSubmittedFileName());//设置图片大小:上传的文件大小image.setSize(p.getSize());//设置上传日期:当前日期image.setUploadTime(new java.util.Date());//设置md5image.setMd5(md5);//设置数据格式/类型: 上传的文件格式(注意,不是请求的数据格式,是form-data上传的图片字段的格式)image.setContentType(p.getContentType());//设置路径:设置为路径后缀(/md5值)image.setPath("/"+md5);//插入数据库图片数据 jdbc操作int n = ImageDao.insert(image);//返回响应: {ok: boolean, msg: String}Map<String, Object> data = new HashMap<>();data.put("ok", true);//我们不返回错误,出错就让tomcat返回500状态码WebUtil.serialize(resp, data);}

获取图片列表接口

返回:[{imageId: 1, imageName: “”}]
查询数据库所有图片,并返回(List),设置到响应体中

//获取图片列表接口:返回[{imageId: 1, imageName: ""}]@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {//查询数据库所有图片,并返回(List<ImageInfo>)List<ImageInfo> images = ImageDao.selectAll();//返回响应WebUtil.serialize(resp, images);}

此时运行后,图片列表展示效果如下:

在这里插入图片描述

获取图片内容

在这里插入图片描述

  • 请求:GET /imageShow?imageld=1
    其中, imageld是获取图片列表接口响应的数据,来填充进去的
  • 响应体为图片的二进制数据(响应的数据格式,可以设置,也可以不设置)

后端servlet处理get请求步骤如下

  • 获取请求数据:图片id
  • 根据图片id,在数据库查询图片数据(path字段)
  • 根据图片完整路径,读取本地图片,把二进制数据设置到响应体
//获取图片内容接口:GET /imageShow?imageId=1@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {//1.获取请求数据:获取图片id,获取queryString,是getParameter获取String imageId = req.getParameter("imageId");//2.根据图片id,在数据库查询图片数据(包含path字段:路径后缀)ImageInfo imageInfo = ImageDao.selectOne(Integer.parseInt(imageId));//3.返回响应:读取本地图片文件,把二进制数据设置到响应体//读取本地图片:完整路径=路径前缀+路径后缀(path字段)String path = ImageServlet.LOCAL_PATH_PREFIX+imageInfo.getPath();//读取这个路径的文件//读取方式一:通过FileInputStream文件输入字节流来读取(参考io操作的代码)//读取方式二:byte[] b = Files.readAllBytes(path) 是工具方法,读取一个路径的所有数据,//Path对象,可以通过File对象转换File pic = new File(path);byte[] data = Files.readAllBytes(pic.toPath());//把图片二进制数据,写入到响应正文//严格来说要设置响应数据格式Content-Type,但前端是<img>使用,所以没有也可以resp.getOutputStream().write(data);}

删除图片接口

在这里插入图片描述

后端处理delete请求步骤如下

  • 获取请求数据: 获取图片id
  • 根据图片id查询到数据(包含path),拼接完整路径在本地删除
  • 删除数据库图片数据
  • 返回响应数据

六、项目优化

目前存在的问题:
1.重复图片上传:目前还是会接收并保存(降低效率)
解决方法:使用md5值,在数据库查询是否存在,如果存在就返回报错信息:上传重复图片

//md5操作,可以基于byte[],String,InputStream//先根据上传的图片,生成md5值String md5 = DigestUtils.md5Hex(p.getInputStream());// 可以先验证md5值,如果存在,就说明是已经存在(重复),不保存//先根据md5值,在数据库查询是否存在,如果存在就返回报错信息:上传重复图片ImageInfo imageInfo = ImageDao.selectByMd5(md5);if(imageInfo != null){//已经存在这个图片,说明重复Map<String, Object> data = new HashMap<>();data.put("ok", false);data.put("msg", "上传图片重复");WebUtil.serialize(resp, data);return;}

2.图片防盗链
只提供给授权(允许)的网站使用=>防盗链
解决方法:通过http请求报文中,Referer这个请求头,可以知道,当前这个http请求,是从哪个页面发起的(上一个页面是哪个)。我们就可以根据Referer的值,来判断是否允许访问。

白名单:提供一个数组/列表,在范围内的,才允许访问

/白名单列表:本机访问本机时,是以下路径,如果放在云服务器,需要改private static final List<String> WHITE_LIST = Arrays.asList("http://localhost:8080/java_image_server/","http://localhost:8080/java_image_server/index.html","http://localhost:8080/java_image_server/index2.html");

获取图片内容接口,先校验Referer请求头,在白名单列表中,才允许访问:

 //获取图片内容接口:GET /imageShow?imageId=1@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {//防盗链:先获取Referer请求头,在白名单列表中,才允许访问,否则返回403String referer = req.getHeader("Referer");//不在白名单中if(!WHITE_LIST.contains(referer)){//返回403resp.setStatus(403);return;}

七、测试

自动化测试

采用selenium和unittest框架完成了自动化测试,对项目中图片上传功能和删除图片部分编写简单的脚本,并生成测试报告。

from HTMLTestRunner import HTMLTestRunnerfrom selenium import webdriver
from selenium.webdriver.common.by import By
import time
import unittest
import testImageServer1
from ddt import ddt@ddt
class testImageServer(unittest.TestCase):def setUp(self):self.driver = webdriver.Chrome()self.url = "http://localhost:8080/java_image_server"self.driver.get(self.url)self.driver.maximize_window()time.sleep(3)def tearDown(self):self.driver.quit()# 上传图片def test_upload(self):driver = self.driverdriver.get(self.url)time.sleep(3)driver.find_element(By.XPATH, "//*[@id='blog-collapse']/form/div[1]/input").send_keys(r"C:\Users\xyy\Pictures\zhinengxinxi\Denoised.jpg")time.sleep(3)driver.find_element(By.XPATH, "//*[@id='blog-collapse']/form/div[2]/input").click()time.sleep(20)# 删除图片def test_delete(self):driver = self.driverdriver.get(self.url)time.sleep(3)driver.find_element(By.XPATH, "//*[@id='container']/div[1]/button").click()time.sleep(3)driver.switch_to.alert.accept()time.sleep(3)if __name__ == '__main__':unittest.main(verbosity=0)
import os
import sys
import time
import unittest
from HTMLTestRunner import HTMLTestRunnerimport testImageServer1
def createsuit():testima = unittest.TestSuite()# 向测试套件添加测试用例# testima.addTest(TestBaiDu("test_search_set"))# testima.addTest(TestBaiDu("test_baidu_search"))# 把一个类里面所有测试用例添加进去unittest.makeSuite(testbaidu1.Baidu1)testima.addTest(unittest.makeSuite(testImageServer1.testImageServer))return testimaif __name__ == '__main__':# 1.创建一个文件夹# 当前路径curpath = sys.path[0]# 当前路径下resultreport 文件夹不存在就创建一个if not os.path.exists(curpath+'/resultreport'):os.mkdir(curpath+'/resultreport')# 2.解决重复命名的问题 当前时间命名now = time.strftime("%Y-%m-%d-%H %M %S", time.localtime(time.time()))print(time.time())print(time.localtime(time.time()))# 准备HTML报告输出的文件filename = curpath+'/resultreport/'+now+'resultreport.html'# 创建测试报告 HTML格式的测试执行报告fp = open(filename, "wb")# 创建执行对象runner = HTMLTestRunner(stream=fp, title="图片服务器测试上传删除", description="用例执行情况:", verbosity=2)suit = createsuit()runner.run(suit)fp.close()

测试报告

测试用例

在这里插入图片描述

相关文章:

图片服务器

文章目录一、项目简介二、功能及场景三、业务设计四、数据库设计准备图片表准备实体类五、API设计常用功能封装文件上传文件上传获取图片列表接口获取图片内容删除图片接口六、项目优化七、测试自动化测试测试用例一、项目简介 图片服务器&#xff1a;解决项目中插入图片的问题…...

【JAVA程序设计】【C00110】基于SSM(非maven)的车辆维修管理系统

基于SSM&#xff08;非maven&#xff09;的车辆维修管理系统项目简介项目获取开发环境项目技术运行截图项目简介 基于ssm框架非maven开发的车辆维修管理系统共分为三个角色&#xff1a;管理员、用户 管理员角色包含以下功能&#xff1a; 查看用户、添加用户、查看车辆信息、故…...

微积分小课堂:用动态的眼光去找问题的最优解(最大值/最小值)【中学里的解题技巧】

文章目录 引言I 最优化问题1.1 不同形式的最优化1.2 用动态的眼光去找问题的最优解引言 把比较数大小的问题,变成了寻找函数变化拐点的问题,将这两个问题等同起来,需要发明一种工具,叫做导数。有了导数这个工具,求最大值问题就变成了解方程的问题。 用变化的眼光找到最优…...

网络爬虫和相关工具

在理想的状态下&#xff0c;所有ICP&#xff08;Internet Content Provider&#xff09;都应该为自己的网站提供API接口来共享它们允许其他程序获取的数据&#xff0c;在这种情况下爬虫就不是必需品&#xff0c;国内比较有名的电商平台&#xff08;如淘宝、京东等&#xff09;、…...

OSSFs挂载工具简介

OSSFs挂载工具 OSSFs挂载工具简介 ​ ossfs允许您在Linux系统中将对象存储OSS的存储空间&#xff08;Bucket&#xff09;挂载到本地文件系统。挂载完成后&#xff0c;您能够像操作本地文件一样操作OSS的对象&#xff08;Object&#xff09;&#xff0c;从而实现数据共享。 ​…...

Spring 容器创建初始化,获取bean流程分析

Spring 容器创建初始化&#xff0c;获取bean流程分析 Spring 容器创建初始化 流程分析 1、首先读取bean.xml 文件 2、扫描指定的包 com.hspedu.spring.component 2.1、扫描包&#xff0c;得到bean的class对象&#xff0c;排除包下不是bean的 2.2、扫描将bean信息封装BeanDef…...

无聊小知识.03 Springboot starter配置自动提示

1、前言Springboot项目配置properties或yaml文件时候&#xff0c;会有很多spring相关的配置提示。这个是如何实现的&#xff1f;如果我们自己的配置属性&#xff0c;能否也自动提示&#xff1f;2、Springboot配置自动提示其实IDE是通过读取配置信息的元数据而实现自动提示的。S…...

2023-03-03 mysql-join类别-分析

目录 摘要: mysql版本: DDL: 表结构: 插入数据: JOIN: 一. SELECT 二. INNER JOIN...

Saleen 系列来袭!

由 Ghostopunch 创作&#x1f47b;&#x1f94a; Ghostpunch 将 Saleen Automotive 带入 The Sandbox 元宇宙&#xff01; 是 Saleen Automotive 于 1984 年由汽车界的梦想家 Steve Saleen 创立&#xff0c;目标是将经过比赛验证的性能带入大街小巷和元宇宙……&#x1f609; 5…...

如何优雅地处理Java中的null值?使用Optional类来实现!

当我们在Java编程时&#xff0c;经常会遇到处理null值的问题。在Java 8中&#xff0c;引入了一个Optional类来解决这个问题。Optional类可以看作是一个容器&#xff0c;用于包装一个可能为null的值。它提供了一些方便的方法&#xff0c;以优雅地处理null值的情况。 下面我将详…...

巾帼绽芬芳 一起向未来(中篇)

编者按&#xff1a;为了隆重纪念纪念“三八”国际妇女节113周年&#xff0c;快来与你全方位、多层次分享交流“三八”国际妇女节的前世今生。分上篇&#xff08;节日简介、节日发展和节日意义&#xff09;、中篇&#xff08;节日活动宗旨和世界各国庆祝方式&#xff09;和下篇&…...

espnet training

from:ESPnet2 — ESPnet 202301 documentation from :Change the configuration for training — ESPnet 202301 documentation 训练完之后微调的命令: ./run.sh --stage 11 --ngpu 1 --asr_args "--max_epoch 205 --optim_conf lr=0.1 --resume true" --asr_exp…...

qsort函数的应用以及模拟实现

前言 &#x1f388;个人主页:&#x1f388; :✨✨✨初阶牛✨✨✨ &#x1f43b;推荐专栏: &#x1f354;&#x1f35f;&#x1f32f; c语言进阶 &#x1f511;个人信条: &#x1f335;知行合一 &#x1f349;本篇简介:>:介绍库函数qsort函数的模拟实现和应用 金句分享: ✨追…...

【iobit 软件】家族系列 - 正版激活码

装机必备iobit系列软件 - 激活码获取看最后 第一款、Advanced SystemCare 16 您需要的人工智能驱动的PC优化器&#xff0c;以释放磁盘空间&#xff0c;加速PC并保护在线隐私。 功能特点&#xff1a; 1. 系统清理与优化&#xff1a;通过清除系统垃圾文件、注册表信息、无用文…...

ACM-大一训练第三周(Floyd算法+并查集算法专题训练)

&#x1f680;write in front&#x1f680; &#x1f4dd;个人主页&#xff1a;认真写博客的夏目浅石.CSDN &#x1f381;欢迎各位→点赞&#x1f44d; 收藏⭐️ 留言&#x1f4dd;​ &#x1f4e3;系列专栏&#xff1a;ACM周训练题目合集.CSDN &#x1f4ac;总结&#xff1a…...

taobao.item.sku.update( 更新SKU信息 )

&#xffe5;开放平台免费API必须用户授权 *更新一个sku的数据 *需要更新的sku通过属性properties进行匹配查找 *商品的数量和价格必须大于等于0 *sku记录会更新到指定的num_iid对应的商品中 *num_iid对应的商品必须属于当前的会话用户 公共参数 请求地址: HTTP地址 http://gw.…...

ros2创建一个工程

第一步&#xff1a;创建src目录 $ mkdir ros2-demo $ cd ros2-demo/ $ mkdir src $ cd src/第二步&#xff1a;创建功能包cd src$ ros2 pkg create --build-type ament_cmake ros2_demo --dependencies rclcpp std_msgsros2 pkg create --build-type ament_python learning_pkg…...

【力扣】stack容器的探索之有效的括号

作者&#xff1a;狮子也疯狂 专栏&#xff1a;《算法详解》 愿你生如夏花之绚烂&#xff0c;幸运永远与你相伴&#xff0c;疯狂常在。 目录一. &#x1f981; Stack容器的来历1.1 操作栈的方法二. &#x1f981; Stack的使用2.1 题目2.2 分析2.3 详细算法实现2.4 力扣AC截图三…...

【Elsevier出版社】中科院2区,SCIEEI 双检,已有发表案例,3个月左右录用

1区智能传感器类SCIE&EI 【期刊简介】IF&#xff1a;5.0-6.0&#xff0c;JCR1区&#xff0c;中科院2区&#xff0c;SCI&EI 双检&#xff0c;正刊 【参考周期】3个月左右录用 【截稿日期】2023.5.30 【征稿领域】有关人工智能与传感器的相关研究均可 包括但不限于&#…...

基于明道云平台重建医院管理流程

一、龙华区医疗信息化建设情况 首先&#xff0c;给大家介绍一下龙华区医疗信息化建设的情况&#xff0c;龙华区位于深圳市的中部&#xff0c;目前下属3家公立医院&#xff0c;2家公共卫生机构。2017年&#xff0c;龙华区提出了建设智慧龙华总体框架方案&#xff0c;龙华区卫生…...

华为云AI开发平台ModelArts

华为云ModelArts&#xff1a;重塑AI开发流程的“智能引擎”与“创新加速器”&#xff01; 在人工智能浪潮席卷全球的2025年&#xff0c;企业拥抱AI的意愿空前高涨&#xff0c;但技术门槛高、流程复杂、资源投入巨大的现实&#xff0c;却让许多创新构想止步于实验室。数据科学家…...

Cursor实现用excel数据填充word模版的方法

cursor主页&#xff1a;https://www.cursor.com/ 任务目标&#xff1a;把excel格式的数据里的单元格&#xff0c;按照某一个固定模版填充到word中 文章目录 注意事项逐步生成程序1. 确定格式2. 调试程序 注意事项 直接给一个excel文件和最终呈现的word文件的示例&#xff0c;…...

oracle与MySQL数据库之间数据同步的技术要点

Oracle与MySQL数据库之间的数据同步是一个涉及多个技术要点的复杂任务。由于Oracle和MySQL的架构差异&#xff0c;它们的数据同步要求既要保持数据的准确性和一致性&#xff0c;又要处理好性能问题。以下是一些主要的技术要点&#xff1a; 数据结构差异 数据类型差异&#xff…...

【RockeMQ】第2节|RocketMQ快速实战以及核⼼概念详解(二)

升级Dledger高可用集群 一、主从架构的不足与Dledger的定位 主从架构缺陷 数据备份依赖Slave节点&#xff0c;但无自动故障转移能力&#xff0c;Master宕机后需人工切换&#xff0c;期间消息可能无法读取。Slave仅存储数据&#xff0c;无法主动升级为Master响应请求&#xff…...

HashMap中的put方法执行流程(流程图)

1 put操作整体流程 HashMap 的 put 操作是其最核心的功能之一。在 JDK 1.8 及以后版本中&#xff0c;其主要逻辑封装在 putVal 这个内部方法中。整个过程大致如下&#xff1a; 初始判断与哈希计算&#xff1a; 首先&#xff0c;putVal 方法会检查当前的 table&#xff08;也就…...

安宝特方案丨船舶智造的“AR+AI+作业标准化管理解决方案”(装配)

船舶制造装配管理现状&#xff1a;装配工作依赖人工经验&#xff0c;装配工人凭借长期实践积累的操作技巧完成零部件组装。企业通常制定了装配作业指导书&#xff0c;但在实际执行中&#xff0c;工人对指导书的理解和遵循程度参差不齐。 船舶装配过程中的挑战与需求 挑战 (1…...

云原生安全实战:API网关Kong的鉴权与限流详解

&#x1f525;「炎码工坊」技术弹药已装填&#xff01; 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 一、基础概念 1. API网关&#xff08;API Gateway&#xff09; API网关是微服务架构中的核心组件&#xff0c;负责统一管理所有API的流量入口。它像一座…...

腾讯云V3签名

想要接入腾讯云的Api&#xff0c;必然先按其文档计算出所要求的签名。 之前也调用过腾讯云的接口&#xff0c;但总是卡在签名这一步&#xff0c;最后放弃选择SDK&#xff0c;这次终于自己代码实现。 可能腾讯云翻新了接口文档&#xff0c;现在阅读起来&#xff0c;清晰了很多&…...

CSS | transition 和 transform的用处和区别

省流总结&#xff1a; transform用于变换/变形&#xff0c;transition是动画控制器 transform 用来对元素进行变形&#xff0c;常见的操作如下&#xff0c;它是立即生效的样式变形属性。 旋转 rotate(角度deg)、平移 translateX(像素px)、缩放 scale(倍数)、倾斜 skewX(角度…...

Golang——6、指针和结构体

指针和结构体 1、指针1.1、指针地址和指针类型1.2、指针取值1.3、new和make 2、结构体2.1、type关键字的使用2.2、结构体的定义和初始化2.3、结构体方法和接收者2.4、给任意类型添加方法2.5、结构体的匿名字段2.6、嵌套结构体2.7、嵌套匿名结构体2.8、结构体的继承 3、结构体与…...