Android显示系统(04)- OpenGL ES - Shader绘制三角形
一、前言:
OpenGL 1.0采用固定管线,OpenGL 2.0以上版本重要的改变就是采用了可编程管线,Shader 编程是指使用着色器(Shader)编写代码来控制图形渲染管线中特定阶段的处理过程。在图形渲染中,着色器是在 GPU 上执行的小型程序,用于定义图形渲染管线中不同阶段的处理逻辑,以实现各种视觉效果,那么渲染管线哪个阶段可编程呢?

就是上图的渲染管线蓝色部分。
二、Shader介绍:
1、Vertex Shader和Fragment Shader:
在现代的图形渲染中,通常会使用两种主要类型的着色器:顶点着色器(Vertex Shader)和片元着色器(Fragment Shader)。这两种着色器分别负责处理图形的顶点数据和片元(像素)数据,通过编写这些着色器程序,开发人员可以实现各种复杂的图形效果和渲染技术。
下面是对顶点着色器和片元着色器的简要介绍:
- 顶点着色器:
- 顶点着色器用于处理图形的顶点数据,如位置、颜色、法线等。
- 主要作用包括对顶点位置的变换(如模型变换、视图变换、投影变换)、法线变换、顶点着色等。
- 顶点着色器的输出通常是裁剪空间坐标或者屏幕空间坐标。
- 片元着色器:
- 片元着色器用于处理图元的片元(像素)数据,负责计算最终的颜色输出。
- 在片元着色器中,开发人员可以实现光照、纹理映射、阴影、透明度等效果。
- 片元着色器的输出通常是片元的颜色、深度值、法线等。
2、图元:
在Shader编程中,“图元”(Primitive)指的是基本的几何图形单元,通常是指在3D图形渲染中的基本几何形状,如点、线、三角形、四边形等。这些基本的几何图形单元是构成复杂场景的基础,它们通过渲染管线进行处理和转换,最终呈现在屏幕上。
在Shader编程中,图元是渲染管线处理的基本单位,Shader程序会对每个图元进行相应的处理,包括顶点变换、光照计算、纹理映射等操作,最终将图元渲染到屏幕上。常见的几何图元有以下几种:
- 点(Point):最简单的图元,通常用于表示粒子、光源等。
- 线(Line):由两个点组成的图元,可用于绘制线条、边缘等。
- 三角形(Triangle):由三个顶点组成的图元,是最基本的多边形,是3D图形学中最重要的图元之一,因为所有复杂的表面都可以由三角形网格构成。
- 四边形(Quadrilateral):由四个顶点组成的图元,通常被拆分为两个三角形处理。
Shader程序通过对这些基本图元进行处理和变换,最终形成了复杂的场景和图像。在Shader编程中,开发人员可以通过编写顶点着色器和片元着色器来对这些图元进行处理,实现各种视觉效果和渲染技术。处理图元是Shader程序中的一个重要任务,它直接影响着最终的渲染效果和性能。
3、三角形:
上面的四个图元中,其实最重要的是三角形,我们把大多数复杂的图形都可以用三角形拼起来,就像我小时候(不敢说你们00后小时候)糊灯笼一样。
比如,我之前文章提到的这个复杂的图,也都是由众多小三角形构成:

三、重要坐标系:
在 OpenGL ES 中,“标准设备坐标系”(Normalized Device Coordinates)和“屏幕坐标系”(Screen Coordinates)是两种不同的坐标系,它们在图形渲染过程中扮演不同的角色。
- 标准设备坐标系(Normalized Device Coordinates):
- 标准设备坐标系是一个抽象的坐标系,它是一个以屏幕空间的中心为原点,范围从 -1 到 1 的立方体空间。
- 在标准设备坐标系中,坐标 (0, 0) 表示屏幕中心,(-1, -1) 表示左下角,(1, 1) 表示右上角。
- 所有的顶点数据在通过
VertexShader处理后都会被映射到标准设备坐标系,这是 OpenGL ES 中进行图形变换和裁剪的标准坐标系。
- 屏幕坐标系(Screen Coordinates):
- 屏幕坐标系是实际显示设备的坐标系,它通常以左上角为原点,向右为 x 轴正方向,向下为 y 轴正方向。
- 屏幕坐标系的坐标值通常是以像素为单位的整数值,用来确定在屏幕上绘制图像和文本等元素的位置。
在 OpenGL ES 渲染过程中,顶点数据首先被定义在对象坐标系中,然后通过模型变换、视图变换和投影变换将其转换到标准设备坐标系中,最终在屏幕上绘制出来。

总结来说,标准设备坐标系是为了方便进行图形变换和裁剪而定义的坐标系,而屏幕坐标系则是实际显示设备上的坐标系,用于确定最终图像的位置。OpenGL ES 中的渲染过程涉及将顶点数据从对象坐标系转换到标准设备坐标系,最终映射到屏幕坐标系进行显示。
四、GLSL语言:
1、概念:
着色器是使用一种叫GLSL的类C语言写成的。GLSL是为图形计算量身定制的,它包含一些针对向量和矩阵操作的有用特性。
着色器的开头总是要声明版本,接着是输入和输出变量、uniform和main函数。每个着色器的入口点都是main函数,在这个函数中我们处理所有的输入变量,并将结果输出到输出变量中。
一个典型的着色器有下面的结构:
#version version_number
in type in_variable_name;
in type in_variable_name;out type out_variable_name;uniform type uniform_name;void main()
{// 处理输入并进行一些图形操作...// 输出处理过的结果到输出变量out_variable_name = weird_stuff_we_processed;
}
当我们特别谈论到顶点着色器的时候,每个输入变量也叫顶点属性(Vertex Attribute)。我们能声明的顶点属性是有上限的,它一般由硬件来决定。OpenGL确保至少有16个包含4分量的顶点属性可用,但是有些硬件或许允许更多的顶点属性,你可以查询GL_MAX_VERTEX_ATTRIBS来获取具体的上限:
int nrAttributes;
glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &nrAttributes);
std::cout << "Maximum nr of vertex attributes supported: " << nrAttributes << std::endl;
通常情况下它至少会返回16个,大部分情况下是够用了。
2、数据传递:

- 可以将Prog想象成一个芯片,有很多的引脚,比如这儿的1绑定的是VertextShader,2绑定的是FragmentShader。
- 顶点着色器Vertex负责确定3D图形的三个顶点,片元着色器Fragment负责确定每个像素的颜色;
- 数据传给1的时候,就会自动传给
vPosition;看看具体怎么传递的:- 通过
glGetAttribLocation获取vPositon的引脚; glEnableVertextAttribArray传入的参数就是上一步获取的ID,这样,就可以打开这个引脚;- 通过
glVertexAttribPointer将准备好的顶点数据Vertex Buffer Object传递给引脚1,这样vPosition就收到了;
- 通过
- 数据传给2的时候,就会自动传给
vColor;- 通过
glGetUniformLocation获取引脚; - 通过
glUniform4fv传递给vColor即可;
- 通过
3、变量:
1)vertex shader变量:

- 输入变量有:Attribute类型、Uniforms类型(unform变量相当于全局变量)、Samplers类型;
- 输出变量有:Varying类型(Vertex Shader的输出,可以作为后续的Shader的输入)
- 内部变量有:gl_Position(这个最重要);
- 以gl开头的变量都是内部变量;
- vertex shader需要给gl_Position赋值来确定顶点的位置;
- 渲染管线会根据gl_Position进行图元装配;
2)fragment shader变量:

- Varying类型:作为Fragment Shader的输入,和Vertex Shader的输出一一对应;
- gl_FragColor:内部变量,是Fragment Shader的输出,保存每个像素的颜色;
- 确定每个像素的最终颜色;
- 可以和纹理结合,实现纹理的映射;
- 还可以通过它实现光照、高亮等颜色特效;
五、绘制一个三角形:
1、步骤:
-
使用
GLSurfaceView创建OpenGL ES环境; -
定义顶点着色器和片元着色器以及OpenGL ES程序;
-
编译顶点着色器和片元着色器;
- 使用
GLES30.glCreateShader()创建Shader对象; - 使用
GLES30.glShaderSource()绑定Shader和其源代码; - 使用
GLES30.glCompileShader()编译Shader;
- 使用
-
链接OpenGL ES程序;
- 使用
GLES30.glCreateProgram()创建OpenGL ES程序; - 使用
GLES30.glAttachShader()绑定Shader到OpenGL ES程序; - 使用
GLES30.glLinkProgram()链接整个OpenGL ES程序;
- 使用
-
使用OpenGL ES程序;
- 调用
GLES30.glUseProgram()使用OpenGL ES程序; - 传递顶点数据和片元数据
- 调用
2、创建OpenGL ES环境:
定义GLSurfaceView:
// 文件路径:com/example/glsurfaceviewdemo/GLSurfaceViewTest.java
public class GLSurfaceViewTest extends GLSurfaceView {public GLSurfaceViewTest(Context context) {super(context);// 设置OpenGL ES版本(由于3.0兼容2.0,我们使用3.0)setEGLContextClientVersion(3);// 设置渲染器Renderer,函数调用后,里面会启动一个新线程构造EGL环境setRenderer(new GLRenderTest());}
}
MainActivity使用GLSurfaceView:
// 文件路径:com/example/glsurfaceviewdemo/MainActivity.java
public class MainActivity extends AppCompatActivity {private GLSurfaceViewTest mGlSurfaceViewTest;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);mGlSurfaceViewTest = new GLSurfaceViewTest(this);setContentView(mGlSurfaceViewTest);}
}
3、定义顶点着色器和片元着色器:
// 文件路径:com/example/glsurfaceviewdemo/Triangle.java
// 定义的顶点着色器代码private final String mVertexShaderCode ="attribute vec4 vPosition;" +"void main() {" +" gl_Position = vPosition;" +"}";// 定义的片段着色器代码private final String mFragmentShaderCode ="precision mediump float;" +"uniform vec4 vColor;" +"void main() {" +" gl_FragColor = vColor;" +"}";// 定义的三角形顶点坐标数组private final float[] mTriangleCoords = new float[]{0.0f, 0.2f, 0.0f, // 顶部-0.5f, -0.5f, 0.0f, // 左下角0.5f, -0.5f, 0.0f // 右下角};// 定义的fragment的颜色数组,表示每个像素的颜色private final float[] mColor = new float[]{0.0f, 1.0f, 0.0f, 1.0f};
4、定义OpenGL ES程序:
// 文件路径:com/example/glsurfaceviewdemo/Triangle.java
private int mProgram;
mProgram = GLES30.glCreateProgram();
5、编译着色器:
// 文件路径:com/example/glsurfaceviewdemo/Triangle.javapublic Triangle() {// ...// 2.加载并编译vertexShader和fragmentShaderint vertexShader = Companion.compileShader(GLES30.GL_VERTEX_SHADER, mVertexShaderCode);int fragmentShader = Companion.compileShader(GLES30.GL_FRAGMENT_SHADER, mFragmentShaderCode);// ...}// 定义静态内部类public static class Companion {// 创建并编译着色器public static int compileShader(int type, String shaderCode) {// 创建一个着色器int shader = GLES30.glCreateShader(type);// 将着色器代码设置到着色器对象中GLES30.glShaderSource(shader, shaderCode);// 编译着色器GLES30.glCompileShader(shader);return shader;}}
6、链接OpenGL ES程序:
// 文件路径:com/example/glsurfaceviewdemo/Triangle.javapublic Triangle() {// ...// 4.attach两个编译好的着色器到program当中GLES30.glAttachShader(mProgram, vertexShader);GLES30.glAttachShader(mProgram, fragmentShader);// 5.链接整个programGLES30.glLinkProgram(mProgram);}
7、使用OpenGL ES程序:
// 文件路径:com/example/glsurfaceviewdemo/Triangle.javapublic void draw() {// 使用programGLES30.glUseProgram(mProgram);// 获取顶点着色器的位置句柄mPositionHandle = GLES30.glGetAttribLocation(mProgram, "vPosition");// 启用顶点属性数组GLES30.glEnableVertexAttribArray(mPositionHandle);// 准备三角形坐标数据// 重置缓冲区位置mVertexBuffer.position(0);// 指定顶点属性数据的格式和位置GLES30.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX, GLES30.GL_FLOAT, false, 0, mVertexBuffer);// 获取片元着色器的颜色句柄mColorHandle = GLES30.glGetUniformLocation(mProgram, "vColor");// 设置绘制三角形的颜色GLES30.glUniform4fv(mColorHandle, 1, mColor, 0);// 绘制三角形GLES30.glDrawArrays(GLES30.GL_TRIANGLES, 0, mTriangleCoords.length / COORDS_PER_VERTEX);// 禁用顶点属性数组GLES30.glDisableVertexAttribArray(mPositionHandle);}
这就是一个绘制三角形的函数;
8、渲染器调用:
在渲染器中周期性地调用上面的绘制函数。
// 文件路径:com/example/glsurfaceviewdemo/GLRenderTest.java
public class GLRenderTest implements GLSurfaceView.Renderer {private Triangle mTriangle;@Overridepublic void onSurfaceCreated(GL10 gl, EGLConfig config) {GLES30.glClearColor(1.0f, 1.0f, 1.0f, 1.0f);mTriangle = new Triangle();}@Overridepublic void onSurfaceChanged(GL10 gl, int width, int height) {GLES30.glViewport(0, 0, width, height);}@Overridepublic void onDrawFrame(GL10 gl){GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT);mTriangle.draw();}
}
9、运行结果:

10、附:全部代码:
文件路径:com/example/glsurfaceviewdemo/MainActivity.java
package com.example.glsurfaceviewdemo;import androidx.appcompat.app.AppCompatActivity;import android.os.Bundle;public class MainActivity extends AppCompatActivity {private GLSurfaceViewTest mGlSurfaceViewTest;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);mGlSurfaceViewTest = new GLSurfaceViewTest(this);setContentView(mGlSurfaceViewTest);}
}
文件路径:com/example/glsurfaceviewdemo/GLSurfaceViewTest.java
package com.example.glsurfaceviewdemo;import android.content.Context;
import android.opengl.GLSurfaceView;
import android.util.AttributeSet;public class GLSurfaceViewTest extends GLSurfaceView {public GLSurfaceViewTest(Context context) {super(context);// 设置OpenGL ES版本(由于3.0兼容2.0,我们使用3.0)setEGLContextClientVersion(3);// 设置渲染器Renderer,函数调用后,里面会启动一个新线程构造EGL环境setRenderer(new GLRenderTest());}
}
文件路径:com/example/glsurfaceviewdemo/GLRenderTest.java
package com.example.glsurfaceviewdemo;import android.opengl.GLES30;
import android.opengl.GLSurfaceView;import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;public class GLRenderTest implements GLSurfaceView.Renderer {private Triangle mTriangle;@Overridepublic void onSurfaceCreated(GL10 gl, EGLConfig config) {GLES30.glClearColor(1.0f, 1.0f, 1.0f, 1.0f);mTriangle = new Triangle();}@Overridepublic void onSurfaceChanged(GL10 gl, int width, int height) {GLES30.glViewport(0, 0, width, height);}@Overridepublic void onDrawFrame(GL10 gl){GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT);mTriangle.draw();}
}
文件路径:com/example/glsurfaceviewdemo/Triangle.java
package com.example.glsurfaceviewdemo;import android.opengl.GLES30;import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;import javax.microedition.khronos.opengles.GL;public class Triangle {public Triangle() {// 1.初始化顶点缓冲区,存储三角形坐标// 为顶点坐标分配DMA内存空间ByteBuffer byteBuffer = ByteBuffer.allocateDirect(mTriangleCoords.length * 4);// 设置字节顺序为本地字节顺序(会根据硬件架构自适应大小端)byteBuffer.order(ByteOrder.nativeOrder());// 将字节缓冲区转换为浮点缓冲区mVertexBuffer = byteBuffer.asFloatBuffer();// 将顶点三角形坐标放入缓冲区mVertexBuffer.put(mTriangleCoords);// 设置缓冲区的位置指针到起始位置mVertexBuffer.position(0);// 2.加载并编译vertexShader和fragmentShaderint vertexShader = Companion.compileShader(GLES30.GL_VERTEX_SHADER, mVertexShaderCode);int fragmentShader = Companion.compileShader(GLES30.GL_FRAGMENT_SHADER, mFragmentShaderCode);// 3.创建一个OpenGL程序mProgram = GLES30.glCreateProgram();// 4.attach两个编译好的着色器到program当中GLES30.glAttachShader(mProgram, vertexShader);GLES30.glAttachShader(mProgram, fragmentShader);// 5.链接整个programGLES30.glLinkProgram(mProgram);}// 顶点数据是float类型,因此,使用这个存储private FloatBuffer mVertexBuffer;private int mProgram;// 定义的顶点着色器代码private final String mVertexShaderCode ="attribute vec4 vPosition;" +"void main() {" +" gl_Position = vPosition;" +"}";// 定义的片段着色器代码private final String mFragmentShaderCode ="precision mediump float;" +"uniform vec4 vColor;" +"void main() {" +" gl_FragColor = vColor;" +"}";// 定义的三角形顶点坐标数组private final float[] mTriangleCoords = new float[]{0.0f, 0.2f, 0.0f, // 顶部-0.5f, -0.5f, 0.0f, // 左下角0.5f, -0.5f, 0.0f // 右下角};// 定义的fragment的颜色数组,表示每个像素的颜色private final float[] mColor = new float[]{0.0f, 1.0f, 0.0f, 1.0f};// 顶点着色器的位置句柄private int mPositionHandle = 0;// 片元着色器的位置句柄private int mColorHandle = 0;private final int COORDS_PER_VERTEX = 3;// 定义静态内部类public static class Companion {// 创建并编译着色器public static int compileShader(int type, String shaderCode) {// 创建一个着色器int shader = GLES30.glCreateShader(type);// 将着色器代码设置到着色器对象中GLES30.glShaderSource(shader, shaderCode);// 编译着色器GLES30.glCompileShader(shader);return shader;}}public void draw() {// 使用programGLES30.glUseProgram(mProgram);// 获取顶点着色器的位置句柄mPositionHandle = GLES30.glGetAttribLocation(mProgram, "vPosition");// 启用顶点属性数组GLES30.glEnableVertexAttribArray(mPositionHandle);// 准备三角形坐标数据// 重置缓冲区位置mVertexBuffer.position(0);// 指定顶点属性数据的格式和位置GLES30.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX, GLES30.GL_FLOAT, false, 0, mVertexBuffer);// 获取片元着色器的颜色句柄mColorHandle = GLES30.glGetUniformLocation(mProgram, "vColor");// 设置绘制三角形的颜色GLES30.glUniform4fv(mColorHandle, 1, mColor, 0);// 绘制三角形GLES30.glDrawArrays(GLES30.GL_TRIANGLES, 0, mTriangleCoords.length / COORDS_PER_VERTEX);// 禁用顶点属性数组GLES30.glDisableVertexAttribArray(mPositionHandle);}
}
六、总结:
本文主要介绍了Shader以及GLSL语言,同时画出了一个三角形,但是一般工程中GLSL语言会用单独的文件写,后续我们改进下!
相关文章:
Android显示系统(04)- OpenGL ES - Shader绘制三角形
一、前言: OpenGL 1.0采用固定管线,OpenGL 2.0以上版本重要的改变就是采用了可编程管线,Shader 编程是指使用着色器(Shader)编写代码来控制图形渲染管线中特定阶段的处理过程。在图形渲染中,着色器是在 GP…...
微信 创建小程序码-有数量限制
获取小程序码:小程序码为圆图,有数量限制。 目录 文档 接口地址 功能描述 注意事项 请求参数 对接 获取小程序码 调用获取 小程序码示例 总结 文档 接口地址 https://api.weixin.qq.com/wxa/getwxacode?access_tokenaccess_token 功能描述 …...
重生之我在异世界学编程之C语言:操作符篇
大家好,这里是小编的博客频道 小编的博客:就爱学编程 很高兴在CSDN这个大家庭与大家相识,希望能在这里与大家共同进步,共同收获更好的自己!!! 本文目录 引言正文1. 算术操作符2. 关系࿰…...
365天深度学习训练营-第P7周:马铃薯病害识别(VGG-16复现)
文为「365天深度学习训练营」内部文章 参考本文所写记录性文章,请在文章开头带上「👉声明」 🍺 要求: 自己搭建VGG-16网络框架【达成√】调用官方的VGG-16网络框架【达成√】如何查看模型的参数量以及相关指标【达成√】 &#…...
解密时序数据库的未来:TDengine Open Day技术沙龙精彩回顾
在数字化时代,开源已成为推动技术创新和知识共享的核心力量,尤其在数据领域,开源技术的涌现不仅促进了行业的快速发展,也让更多的开发者和技术爱好者得以参与其中。随着物联网、工业互联网等技术的广泛应用,时序数据库…...
Kubernetes 告警标签规范与最佳实践
1. 前言 在现代化的 Kubernetes 运维环境中,规范的告警标签系统对于快速定位和解决问题至关重要。本文将详细介绍告警标签的设计规范和最佳实践,帮助团队建立高效的告警处理流程。 © ivwdcwso (ID: u012172506) 2. 标签体系设计 2.1 基本概念 告警标签(Labels)是一…...
前端开发 之 15个页面加载特效中【附完整源码】
前端开发 之 15个页面加载特效中【附完整源码】 文章目录 前端开发 之 15个页面加载特效中【附完整源码】八:圆环百分比加载特效1.效果展示2.HTML完整代码 九:毒药罐加载特效1.效果展示2.HTML完整代码 十:无限圆环加载特效1.效果展示2.HTML完…...
rsync+nfs+lrsync服务部署流程
rsyncnfslrsync服务 主机信息 主机角色外网IP内网IP主机名nfs、lsync10.0.0.31176.16.1.31nfs客户端10.0.0.7176.16.1.7web01rsync、nfs10.0.0.41172.16.1.41backup 部署流程 1.backup服务器部署rsync --下载rsync服务 [rootbackup ~]# yum install -y rsync --配置rsync服…...
基于SpringBoot+Vue的宠物咖啡馆系统-无偿分享 (附源码+LW+调试)
目录 1. 项目技术 2. 功能菜单 3. 部分功能截图 4. 研究背景 5. 研究目的 6. 可行性分析 6.1 技术可行性 6.2 经济可行性 6.3 操作可行性 7. 系统设计 7.1 概述 7.2 系统流程和逻辑 7.3 系统结构 8. 数据库设计 8.1 数据库ER图 (1)宠物订…...
SQLServer 服务器只接受 TLS1.0,但是客户端给的是 TLS1.2
Caused by: javax.net.ssl.SSLHandshakeException: the server selected protocol version TLS10 is not accepted by client preferences [TLS12] 原因描述:SQLServer 服务器只接受 TLS1.0,但是客户端给的是 TLS1.2 解决方法如下: 打开文件…...
Golang内存模型总结1(mspan、mcache、mcentral、mheap)
1.内存模型 1.1 操作系统存储模型 从上到下分别是寄存器、高速缓存、内存、磁盘,其中越往上速度越快,空间越小,价格越高。 关键词是多级模型和动态切换 1.2 虚拟内存与物理内存 虚拟内存是一种内存管理技术,允许计算机使用比…...
lobeChat安装
一、安装Node.js version > v18.17.0 二、下载 cd F:\AITOOLS\LobeChat git clone https://github.com/lobehub/lobe-chat.git (下载要是失败就手动下:https://codeload.github.com/lobehub/lobe-chat/zip/refs/heads/main) npm install …...
Android学习8 -- NDK2--练习2(Opencv)
以下是一个简单的安卓项目示例,通过NDK调用OpenCV来处理图像(例如,将彩色图像转换为灰度图像)。 开发环境 安装 Android Studio(支持NDK开发)。配置NDK和CMake(通过Android Studio的SDK Manage…...
nodejs循环导出多个word表格文档
文章目录 nodejs循环导出多个word表格文档一、文档模板编辑二、安装依赖三、创建导出工具类exportWord.js四、调用五、效果图nodejs循环导出多个word表格文档 结果案例: 一、文档模板编辑 二、安装依赖 // 实现word下载的主要依赖 npm install docxtemplater pizzip --save/…...
elasticsearch-如何给文档新增/更新的字段
文章目录 前言elasticsearch-如何给文档新增/更新的字段1. 如何给某些文档新增/更新的字段2. 给所有文档添加/更新一个新的字段3. 测试 前言 如果您觉得有用的话,记得给博主点个赞,评论,收藏一键三连啊,写作不易啊^ _ ^。 而且…...
https/http访问接口工具类,附带ssl忽略证书验证,以及head头部的添加-java版
复制即用 package utils;import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component;import javax.net.ssl.*; import java.io.BufferedReader; import java.io.IOException; impo…...
node.js基础学习-express框架-静态资源中间件express.static(十一)
前言 在 Node.js 应用中,静态资源是指那些不需要服务器动态处理,直接发送给客户端的文件。常见的静态资源包括 HTML 文件、CSS 样式表、JavaScript 脚本、图片(如 JPEG、PNG 等)、字体文件和音频、视频文件等。这些文件在服务器端…...
Python语法基础---正则表达式
🌈个人主页:羽晨同学 💫个人格言:“成为自己未来的主人~” 我们这个文章所讲述的,也是数据分析的基础文章,正则表达式 首先,我们在开始之前,引出一个问题。也是我们接下来想要解决的问题。…...
Uniapp 微信小程序分享 - 自定义绘制分享图片
技术栈: Uniapp Vue3 简介 因实际业务需求,需要实现微信小程序自定义分享,根据当前数据动态生成(绘制)分享卡片的图片。 基础分享使用 配置此处不在赘述,可查看上篇博客:Uniapp 微信小程序分…...
鸿蒙技术分享:Navigation页面容器封装-鸿蒙@fw/router框架源码解析(三)
本文是系列文章,其他文章见:鸿蒙fw/router框架源码解析(一)-router页面管理鸿蒙fw/router框架源码解析(二)-Navigation页面管理鸿蒙fw/router框架源码解析(四)-路由Hvigor插件实现原…...
KubeSphere 容器平台高可用:环境搭建与可视化操作指南
Linux_k8s篇 欢迎来到Linux的世界,看笔记好好学多敲多打,每个人都是大神! 题目:KubeSphere 容器平台高可用:环境搭建与可视化操作指南 版本号: 1.0,0 作者: 老王要学习 日期: 2025.06.05 适用环境: Ubuntu22 文档说…...
接口测试中缓存处理策略
在接口测试中,缓存处理策略是一个关键环节,直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性,避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明: 一、缓存处理的核…...
DockerHub与私有镜像仓库在容器化中的应用与管理
哈喽,大家好,我是左手python! Docker Hub的应用与管理 Docker Hub的基本概念与使用方法 Docker Hub是Docker官方提供的一个公共镜像仓库,用户可以在其中找到各种操作系统、软件和应用的镜像。开发者可以通过Docker Hub轻松获取所…...
遍历 Map 类型集合的方法汇总
1 方法一 先用方法 keySet() 获取集合中的所有键。再通过 gey(key) 方法用对应键获取值 import java.util.HashMap; import java.util.Set;public class Test {public static void main(String[] args) {HashMap hashMap new HashMap();hashMap.put("语文",99);has…...
微服务商城-商品微服务
数据表 CREATE TABLE product (id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 商品id,cateid smallint(6) UNSIGNED NOT NULL DEFAULT 0 COMMENT 类别Id,name varchar(100) NOT NULL DEFAULT COMMENT 商品名称,subtitle varchar(200) NOT NULL DEFAULT COMMENT 商…...
深度学习水论文:mamba+图像增强
🧀当前视觉领域对高效长序列建模需求激增,对Mamba图像增强这方向的研究自然也逐渐火热。原因在于其高效长程建模,以及动态计算优势,在图像质量提升和细节恢复方面有难以替代的作用。 🧀因此短时间内,就有不…...
NPOI Excel用OLE对象的形式插入文件附件以及插入图片
static void Main(string[] args) {XlsWithObjData();Console.WriteLine("输出完成"); }static void XlsWithObjData() {// 创建工作簿和单元格,只有HSSFWorkbook,XSSFWorkbook不可以HSSFWorkbook workbook new HSSFWorkbook();HSSFSheet sheet (HSSFSheet)workboo…...
NPOI操作EXCEL文件 ——CAD C# 二次开发
缺点:dll.版本容易加载错误。CAD加载插件时,没有加载所有类库。插件运行过程中用到某个类库,会从CAD的安装目录找,找不到就报错了。 【方案2】让CAD在加载过程中把类库加载到内存 【方案3】是发现缺少了哪个库,就用插件程序加载进…...
上位机开发过程中的设计模式体会(1):工厂方法模式、单例模式和生成器模式
简介 在我的 QT/C 开发工作中,合理运用设计模式极大地提高了代码的可维护性和可扩展性。本文将分享我在实际项目中应用的三种创造型模式:工厂方法模式、单例模式和生成器模式。 1. 工厂模式 (Factory Pattern) 应用场景 在我的 QT 项目中曾经有一个需…...
ubuntu22.04有线网络无法连接,图标也没了
今天突然无法有线网络无法连接任何设备,并且图标都没了 错误案例 往上一顿搜索,试了很多博客都不行,比如 Ubuntu22.04右上角网络图标消失 最后解决的办法 下载网卡驱动,重新安装 操作步骤 查看自己网卡的型号 lspci | gre…...
