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

ImageCombiner设计源码详解

前言

在前面的博客中介绍了一款Java的海报生成器ImageCombiner,原文地址:拿来就用的Java海报生成器ImageCombiner(一),在博文中简单介绍了一下代码以及一个真实的生成案例。但是对源码的介绍不多,本文就针对源码进行深入的讲解,便于用户在使用的过程当中可以知其然,知其所以然,了解它的内部架构,程序设计理念,相关类的具体实现,现有的不足,再此基础上可以扩展出符合自己业务的逻辑,进行二次开发改造。

一、源码分析

1、整体设计

ImageCombiner的源码比较简洁,主要包含以下三个包,element 海报组合要素,enums 海报样式、输出格式枚举,painter 具体的绘制器。

包图说明

整体类图

2、绘制器设计

从上面的类图可以清晰得看到,兑现绘制器和绘制工厂共同完成图像、文本、矩形绘制器三种。

图片绘制器与文本绘制器和矩形绘制器不一样的是多了两个make的方法,一个是用于对图片进行高斯模糊处理的方法。高斯模糊的源码如下:

/*** 高斯模糊(毛玻璃效果)** @param srcImage* @param radius* @return*/private BufferedImage makeBlur(BufferedImage srcImage, int radius) {if (radius < 1) {return srcImage;}int w = srcImage.getWidth();int h = srcImage.getHeight();int[] pix = new int[w * h];srcImage.getRGB(0, 0, w, h, pix, 0, w);int wm = w - 1;int hm = h - 1;int wh = w * h;int div = radius + radius + 1;int r[] = new int[wh];int g[] = new int[wh];int b[] = new int[wh];int rsum, gsum, bsum, x, y, i, p, yp, yi, yw;int vmin[] = new int[Math.max(w, h)];int divsum = (div + 1) >> 1;divsum *= divsum;int dv[] = new int[256 * divsum];for (i = 0; i < 256 * divsum; i++) {dv[i] = (i / divsum);}yw = yi = 0;int[][] stack = new int[div][3];int stackpointer;int stackstart;int[] sir;int rbs;int r1 = radius + 1;int routsum, goutsum, boutsum;int rinsum, ginsum, binsum;for (y = 0; y < h; y++) {rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0;for (i = -radius; i <= radius; i++) {p = pix[yi + Math.min(wm, Math.max(i, 0))];sir = stack[i + radius];sir[0] = (p & 0xff0000) >> 16;sir[1] = (p & 0x00ff00) >> 8;sir[2] = (p & 0x0000ff);rbs = r1 - Math.abs(i);rsum += sir[0] * rbs;gsum += sir[1] * rbs;bsum += sir[2] * rbs;if (i > 0) {rinsum += sir[0];ginsum += sir[1];binsum += sir[2];} else {routsum += sir[0];goutsum += sir[1];boutsum += sir[2];}}stackpointer = radius;for (x = 0; x < w; x++) {r[yi] = dv[rsum];g[yi] = dv[gsum];b[yi] = dv[bsum];rsum -= routsum;gsum -= goutsum;bsum -= boutsum;stackstart = stackpointer - radius + div;sir = stack[stackstart % div];routsum -= sir[0];goutsum -= sir[1];boutsum -= sir[2];if (y == 0) {vmin[x] = Math.min(x + radius + 1, wm);}p = pix[yw + vmin[x]];sir[0] = (p & 0xff0000) >> 16;sir[1] = (p & 0x00ff00) >> 8;sir[2] = (p & 0x0000ff);rinsum += sir[0];ginsum += sir[1];binsum += sir[2];rsum += rinsum;gsum += ginsum;bsum += binsum;stackpointer = (stackpointer + 1) % div;sir = stack[(stackpointer) % div];routsum += sir[0];goutsum += sir[1];boutsum += sir[2];rinsum -= sir[0];ginsum -= sir[1];binsum -= sir[2];yi++;}yw += w;}for (x = 0; x < w; x++) {rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0;yp = -radius * w;for (i = -radius; i <= radius; i++) {yi = Math.max(0, yp) + x;sir = stack[i + radius];sir[0] = r[yi];sir[1] = g[yi];sir[2] = b[yi];rbs = r1 - Math.abs(i);rsum += r[yi] * rbs;gsum += g[yi] * rbs;bsum += b[yi] * rbs;if (i > 0) {rinsum += sir[0];ginsum += sir[1];binsum += sir[2];} else {routsum += sir[0];goutsum += sir[1];boutsum += sir[2];}if (i < hm) {yp += w;}}yi = x;stackpointer = radius;for (y = 0; y < h; y++) {pix[yi] = (0xff000000 & pix[yi]) | (dv[rsum] << 16) | (dv[gsum] << 8) | dv[bsum];rsum -= routsum;gsum -= goutsum;bsum -= boutsum;stackstart = stackpointer - radius + div;sir = stack[stackstart % div];routsum -= sir[0];goutsum -= sir[1];boutsum -= sir[2];if (x == 0) {vmin[y] = Math.min(y + r1, hm) * w;}p = x + vmin[y];sir[0] = r[p];sir[1] = g[p];sir[2] = b[p];rinsum += sir[0];ginsum += sir[1];binsum += sir[2];rsum += rinsum;gsum += ginsum;bsum += binsum;stackpointer = (stackpointer + 1) % div;sir = stack[stackpointer];routsum += sir[0];goutsum += sir[1];boutsum += sir[2];rinsum -= sir[0];ginsum -= sir[1];binsum -= sir[2];yi += w;}}srcImage.setRGB(0, 0, w, h, pix, 0, w);return srcImage;}

在上述的代码,尤其是绘制器工厂的实现,信心的朋友通过阅读代码可以看到,工厂实现方式还是可以进行改造,由于目前的绘制对象也不多,不是有代码洁癖的也能接受。

package com.freewayso.image.combiner.painter;import com.freewayso.image.combiner.element.CombineElement;
import com.freewayso.image.combiner.element.ImageElement;
import com.freewayso.image.combiner.element.RectangleElement;
import com.freewayso.image.combiner.element.TextElement;/*** @Author zhaoqing.chen* @Date 2020/8/21* @Description*/
public class PainterFactory {private static ImagePainter imagePainter;               //图片绘制器private static TextPainter textPainter;                 //文本绘制器private static RectanglePainter rectanglePainter;       //矩形绘制器public static IPainter createInstance(CombineElement element) throws Exception {//考虑到性能,这里用单件,先不lock了if (element instanceof ImageElement) {if (imagePainter == null) {imagePainter = new ImagePainter();}return imagePainter;} else if (element instanceof TextElement) {if (textPainter == null) {textPainter = new TextPainter();}return textPainter;} else if (element instanceof RectangleElement) {if (rectanglePainter == null) {rectanglePainter = new RectanglePainter();}return rectanglePainter;} else {throw new Exception("不支持的Painter类型");}}
}

在上述的代码中,通过if循环来进行具体的绘制图形实例生成,可以想象一下,针对上述的代码,如果未来要扩展一种新的绘制对象,该怎么进行代码优化。

3、海报元素类设计

海报元素可以分为三种元素,与绘制器一一对应,分别是图片元素、文本元素、矩形元素。这几个类都是CombineElement的子类。后面结合时序图来说明具体的元素绑定与注册及绘制过程。

4、海报生成器

ImageCombiner是最重要的海报生成器类,在ImageCombiner中,定义了一个海报元素类的集合用来保存需要在海报中添加的元素。同时定义了很多的以add开头的添加海报元素的方法,用以往List集合中添加新的元素对象。

/*** 添加图片元素** @param imgUrl   图片rul* @param x        x坐标* @param y        y坐标* @param width    宽度* @param height   高度* @param zoomMode 缩放模式* @return*/public ImageElement addImageElement(String imgUrl, int x, int y, int width, int height, ZoomMode zoomMode) {ImageElement imageElement = new ImageElement(imgUrl, x, y, width, height, zoomMode);this.combineElements.add(imageElement);return imageElement;}

二、生成时序解析

1、海报组装

public void test1() throws Exception {try {String bgImageUrl = "https://img.thebeastshop.com/combine_image/funny_topic/resource/bg_3x4.png";                       //背景图(测试url形式)String qrCodeUrl = "http://imgtest.thebeastshop.com/file/combine_image/qrcodef3d132b46b474fe7a9cc6e76a511dfd5.jpg";     //二维码String productImageUrl = "https://img.thebeastshop.com/combine_image/funny_topic/resource/product_3x4.png";             //商品图BufferedImage waterMark = ImageIO.read(new URL("https://img.thebeastshop.com/combine_image/funny_topic/resource/water_mark.png"));  //水印图(测试BufferedImage形式)BufferedImage avatar = ImageIO.read(new URL("https://img.thebeastshop.com/member/privilege/level-icon/level-three.jpg"));           //头像String title = "# 最爱的家居";                                       //标题文本String content = "苏格拉底说:“如果没有那个桌子,可能就没有那个水壶”";  //内容文本//合成器和背景图(整个图片的宽高和相关计算依赖于背景图,所以背景图的大小是个基准)ImageCombiner combiner = new ImageCombiner(bgImageUrl, OutputFormat.PNG);combiner.setBackgroundBlur(30);     //设置背景高斯模糊(毛玻璃效果)combiner.setCanvasRoundCorner(100); //设置整图圆角(输出格式必须为PNG)//商品图(设置坐标、宽高和缩放模式,若按宽度缩放,则高度按比例自动计算)combiner.addImageElement(productImageUrl, 0, 160, 837, 0, ZoomMode.Width).setRoundCorner(46)     //设置圆角.setCenter(true);       //居中绘制,会忽略x坐标参数,改为自动计算//标题(默认字体为“阿里巴巴普惠体”,也可以自己指定字体名称或Font对象)combiner.addTextElement(title, 55, 150, 1400);//内容(设置文本自动换行,需要指定最大宽度(超出则换行)、最大行数(超出则丢弃)、行高)combiner.addTextElement(content, "微软雅黑", 40, 150, 1480).setAutoBreakLine(837, 2, 60);//头像(圆角设置一定的大小,可以把头像变成圆的)combiner.addImageElement(avatar, 200, 1200, 130, 130, ZoomMode.WidthHeight).setRoundCorner(200).setBlur(5);       //高斯模糊,毛玻璃效果//水印(设置透明度,0.0~1.0)combiner.addImageElement(waterMark, 630, 1200).setAlpha(.8f)      //透明度,0.0~1.0.setRotate(15);     //旋转,0~360,按中心点旋转//二维码(强制按指定宽度、高度缩放)combiner.addImageElement(qrCodeUrl, 138, 1707, 186, 186, ZoomMode.WidthHeight);//元素对象也可以直接new,然后手动加入待绘制列表TextElement textPrice = new TextElement("¥1290", 40, 600, 1400);textPrice.setStrikeThrough(true);       //删除线combiner.addElement(textPrice);         //加入待绘制集合//动态计算位置int offsetPrice = textPrice.getX() + textPrice.getWidth() + 10;combiner.addTextElement("¥999", 60, offsetPrice, 1400).setColor(Color.red);//执行图片合并combiner.combine();//保存文件combiner.save("d://fullTest.png");System.out.println(1/0);System.out.println("end...");//或者获取流(并上传oss等)//InputStream is = combiner.getCombinedImageStream();//String url = ossUtil.upload(is);} catch (Exception e) {e.printStackTrace();}}

通过以上的时序图可以清晰的看到系统的调用过程,一共包含了24个步骤。通过时序图和代码,相信您可以很直观的看到相关的调用方式,这里不做过多的赘述。

2、combine海报合成

/*** 合成图片,返回图片对象** @throws Exception*/public BufferedImage combine() throws Exception {combinedImage = new BufferedImage(canvasWidth, canvasHeight, BufferedImage.TYPE_INT_RGB);Graphics2D g = combinedImage.createGraphics();//PNG要做透明度处理,否则背景图透明部分会变黑if (outputFormat == OutputFormat.PNG) {combinedImage = g.getDeviceConfiguration().createCompatibleImage(canvasWidth, canvasHeight, Transparency.TRANSLUCENT);g = combinedImage.createGraphics();}//抗锯齿g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);g.setColor(Color.white);//循环绘制各元素for (CombineElement element : combineElements) {IPainter painter = PainterFactory.createInstance(element);if (element.isRepeat()) {//平铺绘制painter.drawRepeat(g, element, canvasWidth, canvasHeight);} else {//正常绘制painter.draw(g, element, canvasWidth);}}g.dispose();//处理整图圆角if (roundCorner != null) {combinedImage = this.makeRoundCorner(combinedImage, canvasWidth, canvasHeight, roundCorner);}return combinedImage;}

combine方法是最核心的生成方法,在第6步进入循环,将页面设置的不同的海报元素添加到生成器中,并调用绘制器工程生成相应的绘制器,通过Graphics2D来进行海报的生成。至此,海报生成器的相关类就全部讲解完毕,工具虽小,五脏俱全。

//循环绘制各元素
for (CombineElement element : combineElements) {IPainter painter = PainterFactory.createInstance(element);if (element.isRepeat()) {//平铺绘制painter.drawRepeat(g, element, canvasWidth, canvasHeight);} else {//正常绘制painter.draw(g, element, canvasWidth);}}

三、总结

以上就是本文的主要内容,本文主要从海报生成器的源码和生成时序解析两个方面进行深度解析,使用UML的分析方法对类图、时序图结合源码进行说明,将海报生成器的核心代码做完整的剖析,想研究的朋友可以深入的学习,对于源码中不合理的地方可以进行修改。

相关文章:

ImageCombiner设计源码详解

前言在前面的博客中介绍了一款Java的海报生成器ImageCombiner,原文地址&#xff1a;拿来就用的Java海报生成器ImageCombiner&#xff08;一&#xff09;&#xff0c;在博文中简单介绍了一下代码以及一个真实的生成案例。但是对源码的介绍不多&#xff0c;本文就针对源码进行深入…...

python基础 | python基础语法

文章目录&#x1f4da;基础语法&#x1f407;输入和输出&#x1f955;print()输出&#x1f955;input()输入&#x1f407; 变量的命名&#x1f407;条件判断&#x1f955;单向判断&#x1f955;双向判断&#x1f955;多向判断&#x1f955;if嵌套&#x1f955;三元表达式&#…...

YOLOv6-3.0-目标检测论文解读

文章目录摘要算法2.1网络设计2.2Anchor辅助训练2.3自蒸馏实验消融实验结论论文&#xff1a; 《YOLOv6 v3.0: A Full-Scale Reloading 》github&#xff1a; https://github.com/meituan/YOLOv6上版本参考 YOLOv6摘要 YOLOv6 v3.0中YOLOv6-N达到37.5AP&#xff0c;1187FPS&…...

JAVA集合之Map >>HashMap/Hashtable/TreeMap/LinkedHashMap结构

Map 是一种键-值对&#xff08;key-value&#xff09;集合&#xff0c;键不可以重复&#xff0c;值可以重复。常见的实现类有&#xff1a;HashMap、Hashtable、TreeMap、LinkedHashMap等。 HashMap&Hashtable HashMap&#xff1a;数据结构为哈希表&#xff0c;允许使用 n…...

JavaScript从零开始 学习记录(一)

前言 选择视频课程之前&#xff0c;不仅查阅了资料&#xff0c;还询问了网友&#xff0c;最终敲定了学习黑马前端的视频教程&#xff0c;学了5小节&#xff0c;发现挺对自己口味的且从反响来看&#xff0c;还是相当不错的&#xff0c;便打算利用这个寒假学完 笔记范围 从这节…...

C++项目——高并发内存池(3)--central cache整体设计

1.central cache的介绍 1.1框架思想 1.1.1哈希映射 centralcache其实也是哈希桶结构的&#xff0c;并且central cache和thread cacha的哈希映射关系是一致的。目的为了&#xff0c;当thread cache某一个哈希桶下没有内存块时&#xff0c;可以利用之前编写的SizeClass::Index…...

Spring Boot 整合 MyBatis 配置等案例教程

运行环境&#xff1a;JDK 7 或 8、Maven 3.0 技术栈&#xff1a;SpringBoot 1.5、SpringBoot Mybatis Starter 1.2 、MyBatis 3.4 前言 距离第一篇 Spring Boot 系列的博文 3 个月了。《Springboot 整合 Mybatis 的完整 Web 案例》第一篇出来是 XML 配置 SQL 的形式。虽然 XM…...

比特数据结构与算法(第三章_下)队列的概念和实现(力扣:225+232+622)

一、队列&#xff08;Queue&#xff09;队列的概念&#xff1a;① 队列只允许在一端进行插入数据操作&#xff0c;在另一端进行删除数据操作的特殊线性表。② 入队列&#xff0c;进行插入操作的一端称为 队尾。出队列&#xff0c;进行删除操作的一端称为 队头。③ 队列中的元素…...

c++提高篇——STL容器实现打分系统

一、案例说明 有5名选手:选手ABCDE&#xff0c;10个评委分别对每一名选手打分&#xff0c;去除最高分&#xff0c;去除评委中最低分&#xff0c;取平均分。 二、案例实现 在实现这个系统时&#xff0c;我们规划一下实现的步骤以及细节&#xff1a; 1、创建一个选手类&#x…...

【图片上传记录三】element-ui组件详解与封装(自定义上传、限制文件大小、格式以及图片尺寸)

业务上有需求是前端上传 jpg/png/gif 格式, 并且 尺寸为 150px * 150px,300px*300px,428*428px 的图片 同时在上传的同时需要携带用户的个人信息以及其他额外信息 因此在 element-upload 基础之上 实现这个需求需要在上传前检查图片的大小&#xff0c;格式以及尺寸如何上传也成…...

一个golang版本管理工具

GitHub - moqsien/gvc: GVC is a productive tool to manage your dev environment for multi platforms and machines. | GVC 是一个用于快速配置和管理多机器跨平台的开发环境的生产力工具。 目前&#xff0c;gvc拥有以下功能或特点&#xff1a; go编译器自动安装和添加环…...

SpringBoot整合Spring Security过滤器链加载执行流程源码分析

文章目录1.引言2.Spring Security过滤器链加载1.2.注册名为 springSecurityFilterChain的过滤器2、查看 DelegatingFilterProxy类3.查看 FilterChainProxy类3.1 查看 doFilterInternal方法。3.2 查看 getFilters方法。4 查看 SecurityFilterChain接口5 查看 SpringBootWebSecur…...

Jest使用

一、测试到底测什么 提到测试的时候&#xff0c;即使是最简单的一个代码块可能都让初学者不知所措。最常问的问题的是“我怎么知道要测试什么&#xff1f;”。如果你正在写一个 Web 应用&#xff0c;那么你每个页面每个页面的测试用户交互的方式&#xff0c;就是一个很好的开端…...

定位于企业数字化底座,开箱可用(spring cloud+Vue)基础框架,赶紧收藏!

项目介绍&#xff1a;JVS是什么&#xff1f;JVS是企业级应用构建的基础脚手架&#xff0c;提供开箱即用的基础功能集成&#xff0c;其中集成了账户管理、租户管理、用户权限体系、三方登录、环境配置、各种业务日志等功能&#xff0c;还提供了对接低代码、数据中台的能力。JVS能…...

java字符统计

问题描述 给定一个只包含大写字母的字符串 &#xfffd; S, 请你输出其中出现次数最多的字符。 如果有多个字母均出现了最多次, 按字母表顺序依次输出所有这些字母。 输入格式 一个只包含大写字母的字符串 &#xfffd; S. 输出格式 若干个大写字母&#xff0c;代表答案。 …...

C#:Krypton控件使用方法详解(第八讲) ——kryptonBreadCrumb

今天介绍的Krypton控件中的kryptonBreadCrumb&#xff0c;下面开始介绍这个控件的属性&#xff1a;首先要介绍的是RootItem属性和外观属性&#xff1a;RootItem属性组中包含属性如下&#xff1a;image属性&#xff1a;代表在文字对象的前方插入一个图片&#xff0c;属性值如下图…...

2023从0开始学性能(1) —— 性能测试基础【持续更新】

背景 不知道各位大佬有没遇到上面的情况&#xff0c;性能这个东西到底是什么&#xff0c;还是以前的358原则吗&#xff1f;明显并不是适用于现在了。多次想踏入性能测试门槛都以失败告终&#xff0c;这次就以系列的方式来督促自己真正踏进性能测试的门槛。 什么是性能测试 通…...

如何通过一台 iPhone 申请一个 icloud 邮箱账号 后缀为 @icloud.com

总目录 iOS开发笔记目录 从一无所知到入门 文章目录需求关键步骤步骤后续需求 在 iPhone 自带的邮箱软件中添加账号&#xff0c;排第一位的是 iCloud 邮箱&#xff1a; 选 iCloud 之后&#xff1a; 提示信息是exampleicloud.com&#xff0c;也就是说是有icloud.com为域的邮箱…...

SQL89 计算总和

描述OrderItems表代表订单信息&#xff0c;包括字段&#xff1a;订单号order_num和item_price商品售出价格、quantity商品数量。order_numitem_pricequantitya110105a211100a21200a421121a5510a2119a775【问题】编写 SQL 语句&#xff0c;根据订单号聚合&#xff0c;返回订单总…...

Netty高级应用之:编解码器与群聊天室开发

Netty高级应用之&#xff1a;编解码器与群聊天室开发 文章目录Netty高级应用之&#xff1a;编解码器与群聊天室开发Netty编解码器Java的编解码Netty编解码器概念解码器(Decoder)编码器(Encoder)编码解码器CodecNetty案例-群聊天室聊天室服务端编写聊天室客户端编写Netty编解码器…...

Flask RESTful 示例

目录 1. 环境准备2. 安装依赖3. 修改main.py4. 运行应用5. API使用示例获取所有任务获取单个任务创建新任务更新任务删除任务 中文乱码问题&#xff1a; 下面创建一个简单的Flask RESTful API示例。首先&#xff0c;我们需要创建环境&#xff0c;安装必要的依赖&#xff0c;然后…...

【JavaEE】-- HTTP

1. HTTP是什么&#xff1f; HTTP&#xff08;全称为"超文本传输协议"&#xff09;是一种应用非常广泛的应用层协议&#xff0c;HTTP是基于TCP协议的一种应用层协议。 应用层协议&#xff1a;是计算机网络协议栈中最高层的协议&#xff0c;它定义了运行在不同主机上…...

FFmpeg 低延迟同屏方案

引言 在实时互动需求激增的当下&#xff0c;无论是在线教育中的师生同屏演示、远程办公的屏幕共享协作&#xff0c;还是游戏直播的画面实时传输&#xff0c;低延迟同屏已成为保障用户体验的核心指标。FFmpeg 作为一款功能强大的多媒体框架&#xff0c;凭借其灵活的编解码、数据…...

Java - Mysql数据类型对应

Mysql数据类型java数据类型备注整型INT/INTEGERint / java.lang.Integer–BIGINTlong/java.lang.Long–––浮点型FLOATfloat/java.lang.FloatDOUBLEdouble/java.lang.Double–DECIMAL/NUMERICjava.math.BigDecimal字符串型CHARjava.lang.String固定长度字符串VARCHARjava.lang…...

sqlserver 根据指定字符 解析拼接字符串

DECLARE LotNo NVARCHAR(50)A,B,C DECLARE xml XML ( SELECT <x> REPLACE(LotNo, ,, </x><x>) </x> ) DECLARE ErrorCode NVARCHAR(50) -- 提取 XML 中的值 SELECT value x.value(., VARCHAR(MAX))…...

解决本地部署 SmolVLM2 大语言模型运行 flash-attn 报错

出现的问题 安装 flash-attn 会一直卡在 build 那一步或者运行报错 解决办法 是因为你安装的 flash-attn 版本没有对应上&#xff0c;所以报错&#xff0c;到 https://github.com/Dao-AILab/flash-attention/releases 下载对应版本&#xff0c;cu、torch、cp 的版本一定要对…...

佰力博科技与您探讨热释电测量的几种方法

热释电的测量主要涉及热释电系数的测定&#xff0c;这是表征热释电材料性能的重要参数。热释电系数的测量方法主要包括静态法、动态法和积分电荷法。其中&#xff0c;积分电荷法最为常用&#xff0c;其原理是通过测量在电容器上积累的热释电电荷&#xff0c;从而确定热释电系数…...

iOS性能调优实战:借助克魔(KeyMob)与常用工具深度洞察App瓶颈

在日常iOS开发过程中&#xff0c;性能问题往往是最令人头疼的一类Bug。尤其是在App上线前的压测阶段或是处理用户反馈的高发期&#xff0c;开发者往往需要面对卡顿、崩溃、能耗异常、日志混乱等一系列问题。这些问题表面上看似偶发&#xff0c;但背后往往隐藏着系统资源调度不当…...

【Linux】Linux 系统默认的目录及作用说明

博主介绍&#xff1a;✌全网粉丝23W&#xff0c;CSDN博客专家、Java领域优质创作者&#xff0c;掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域✌ 技术范围&#xff1a;SpringBoot、SpringCloud、Vue、SSM、HTML、Nodejs、Python、MySQL、PostgreSQL、大数据、物…...

pikachu靶场通关笔记19 SQL注入02-字符型注入(GET)

目录 一、SQL注入 二、字符型SQL注入 三、字符型注入与数字型注入 四、源码分析 五、渗透实战 1、渗透准备 2、SQL注入探测 &#xff08;1&#xff09;输入单引号 &#xff08;2&#xff09;万能注入语句 3、获取回显列orderby 4、获取数据库名database 5、获取表名…...