win7 发布asp网站/广州外包网络推广公司
文章目录
文章目录
一、概要
二、前置知识点-FreeMarker
三、前置知识点-AbstractHttpMessageConverter
3.1 描述
3.2 应用
四、前置知识点-AbstractDecorator
4.1描述
4.2 应用
五、工作空间查询解读
5.1 模板解读
5.2 请求转换器解读
一、概要
关于geoserver的rest服务,其实官网有一个简单的描述,此处不多搬运详情可以查看它官网描述(点我),但是需要重点了解的是最新的GeoServer是使用SpringMVC来实现的REST服务,抛弃了Restlet。GeoServer扩展之REST_geoserver过时了-CSDN博客 从GeoServer2.12版(2017)开始采用的SpringMVC, 它的Wiki中也做了个简单描述,但是开发文档没有更新,重要的事情说两遍开发文档没有更新。所以官网描述看看就可以了,不用跟着它的指引做。 本文着重从源码角度梳理整个rest服务的流程
二、前置知识点-FreeMarker
在上一篇文章中看到geoserver的模板框架是FreeMarker
主体框架 | spring(不是spring boot) |
UI框架 | Wicket(类似jsp) |
通信框架(前后台交互) | Servlet |
地理处理框架 | GeoTools |
模板框架 | FreeMarker |
这个东西主要就是用于格式化REST接口的
用法的话参照下面的代码(AI生成的,可能细节上有问题,看看即可)
1.环境配置
Configuration cfg = new Configuration(Configuration.VERSION_2_3_31);
cfg.setDirectoryForTemplateLoading(new File("templates")); // 设置模板目录
cfg.setDefaultEncoding("UTF-8"); // 设置默认编码
2.加载模板
Template template = cfg.getTemplate("example.ftl");
3.数据模型
Map<String, Object> dataModel = new HashMap<>();
dataModel.put("title", "FreeMarker 示例");
dataModel.put("message", "这是一个 FreeMarker 模板!");
4.处理模板
StringWriter out = new StringWriter();
template.process(dataModel, out);
String result = out.toString();
System.out.println(result);
三、前置知识点-AbstractHttpMessageConverter
AbstractHttpMessageConverter
一般与rest 接口联合使用,用于根据前端需求返回不同格式的结果,就比如工作空间的三种请求方式
3.1 描述
下面是AI(智普清言)生成的,可能细节上有问题,看看即可
AbstractHttpMessageConverter
是 Spring 框架中用于处理 HTTP 请求和响应的转换的一个抽象类。它为具体的 HTTP 消息转换器提供了一种模板方法模式,用于将请求体或响应体转换为 Java 对象,或者将 Java 对象转换为响应体。
如果你需要自定义一个消息转换器,你可以扩展这个类,并实现其中的抽象方法。下面是扩展 AbstractHttpMessageConverter
的基本步骤:
-
确定支持的媒体类型:在构造函数中设置你的转换器将支持哪些媒体类型(例如
application/json
,text/xml
等)。 -
实现
supports
方法:这个方法需要判断传入的 Java 类型是否为你的转换器所支持的类型。 -
实现
read
方法:这个方法负责将请求体转换为 Java 对象。 -
实现
write
方法:这个方法负责将 Java 对象转换为响应体。
以下是一个简单的示例,展示了如何创建一个自定义的 AbstractHttpMessageConverter
:
import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
import org.springframework.http.converter.AbstractHttpMessageConverter;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;import java.io.IOException;
import java.nio.charset.Charset;public class CustomMessageConverter extends AbstractHttpMessageConverter<MyObject> {public CustomMessageConverter() {// 设置支持的媒体类型super(new MediaType("application", "custom", Charset.forName("UTF-8")));}@Overrideprotected boolean supports(Class<?> clazz) {// 判断传入的类型是否为 MyObject 或其子类return MyObject.class.isAssignableFrom(clazz);}@Overrideprotected MyObject readInternal(Class<? extends MyObject> clazz, HttpInputMessage inputMessage)throws IOException, HttpMessageNotReadableException {// 实现从请求体到 MyObject 的转换逻辑// ...return new MyObject();}@Overrideprotected void writeInternal(MyObject myObject, HttpOutputMessage outputMessage)throws IOException, HttpMessageNotWritableException {// 实现从 MyObject 到响应体的转换逻辑// ...}
}
在上述代码中,MyObject
是你希望转换的目标对象类型。你需要实现 readInternal
和 writeInternal
方法来完成具体的转换逻辑。
最后,不要忘记将你的自定义转换器注册到 Spring 的 HttpMessageConverter
列表中,这通常是通过配置一个 WebMvcConfigurer
来实现的:
@Configuration
public class WebConfig implements WebMvcConfigurer {@Overridepublic void configureMessageConverters(List<HttpMessageConverter<?>> converters) {converters.add(new CustomMessageConverter());}
}
这样,当 Spring MVC 处理请求和响应时,就会使用你的自定义转换器来处理 MyObject
类型的数据。
博客园里面有一篇文章写的也不错可以参考(点我)
3.2 应用
在geoserver中,设置转换器的配置代码在RestConfiguration中
src/rest/src/main/java/org/geoserver/rest/RestConfiguration.java
在applicationContext.xml中可以看到扫描的是整个包下面的类
<?xml version="1.0" encoding="UTF-8"?>
<beans><!-- <mvc:annotation-driven/> --><context:component-scan base-package="org.geoserver.rest"/>
</beans>
当扫描到RestConfiguration时就会自动注册消息转换器
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
/** Configure various aspects of Spring MVC, in particular message converters */
@Configuration
public class RestConfiguration extends WebMvcConfigurationSupport {/** 配置消息转换器 */@Overrideprotected void configureMessageConverters(List<HttpMessageConverter<?>> converters) {Catalog catalog = (Catalog) applicationContext.getBean("catalog");List<BaseMessageConverter> gsConverters =GeoServerExtensions.extensions(BaseMessageConverter.class);gsConverters.add(new FreemarkerHTMLMessageConverter("UTF-8"));gsConverters.add(new XStreamXMLMessageConverter());gsConverters.add(new XStreamJSONMessageConverter());gsConverters.add(new XStreamCatalogListConverter.XMLXStreamListConverter());gsConverters.add(new XStreamCatalogListConverter.JSONXStreamListConverter());gsConverters.add(new InputStreamConverter());EntityResolver entityResolver = catalog.getResourcePool().getEntityResolver();for (StyleHandler sh : Styles.handlers()) {for (Version ver : sh.getVersions()) {gsConverters.add(new StyleReaderConverter(sh.mimeType(ver), ver, sh, entityResolver));gsConverters.add(new StyleWriterConverter(sh.mimeType(ver), ver, sh));}}if (applicationContext.containsBean("gwcConverter")) {converters.add((HttpMessageConverter<?>) applicationContext.getBean("gwcConverter"));}gsConverters.sort(Comparator.comparingInt(BaseMessageConverter::getPriority));for (BaseMessageConverter converter : gsConverters) {converters.add(converter);}converters.removeIf(Jaxb2RootElementHttpMessageConverter.class::isInstance);converters.add(0, new Jaxb2RootElementHttpMessageConverter());super.addDefaultHttpMessageConverters(converters);}
}
上面的一对转换器都是针对geoserver一些特定对象的封装,像workspace、layer、datastore等,最下面那个比较特殊,也是比较常见的一个,它用于将java对象转换成json或者xml返回给前端
converters.add(0, new Jaxb2RootElementHttpMessageConverter());
比如果当请求工作空间时一般有下面的几种请求
http://localhost:8080/geoserver/rest/workspaces (浏览器预览居多)
或
http://localhost:8080/geoserver/rest/workspaces.json (作为前端调用的接口居多)
或
http://localhost:8080/geoserver/rest/workspaces.xml (作为前端调用的接口居多)
Jaxb2RootElementHttpMessageConverter 转换器,会根据前端请求的Accept请求头自动适配出前端需要的格式
其优先级是 格式拼接到请求地址上(http://localhost:8080/gisserver/rest/workspaces.json)大于 请求地址什么都不加 但是header有Accept参数
四、前置知识点-AbstractDecorator
4.1描述
org.geotools.util.decorate.AbstractDecorator
是 GeoTools 库中的一个类,它提供了一个基础实现,用于创建装饰者模式(Decorator Pattern)的装饰器。装饰者模式允许你动态地给一个对象添加额外的职责,而不需要修改其原有的代码。通俗来说就是子类定义一个delegate变量,在子类方法中直接代用父类的方法,并且这个变量一般是通过依赖注入的,不用单独的给赋值。
在 GeoTools 中,AbstractDecorator
类是一个抽象类,它实现了 Decorator
接口,并提供了一个构造函数,接受一个要装饰的对象作为参数。这个被装饰的对象通常是一个接口的实现,而 AbstractDecorator
类则负责将所有的调用委派给这个对象。
举例:
import org.geotools.util.decorate.AbstractDecorator;public class MyDecorator extends AbstractDecorator<MyInterface> {public MyDecorator(MyInterface delegate) {super(delegate);}@Overridepublic void doSomething() {// 在调用原有方法之前,可以添加一些额外的逻辑System.out.println("Before doing something");// 调用被装饰对象的方法delegate.doSomething();// 在调用原有方法之后,也可以添加一些额外的逻辑System.out.println("After doing something");}
}public interface MyInterface {void doSomething();
}public class MyImplementation implements MyInterface {@Overridepublic void doSomething() {System.out.println("Doing something");}
}public class Main {public static void main(String[] args) {MyInterface myImplementation = new MyImplementation();MyDecorator myDecorator = new MyDecorator(myImplementation);myDecorator.doSomething();}
}
4.2 应用
说AbstractDecorator
的目的主要是为了理解WorkspaceController类
从源码中可以看到
public class WorkspaceController extends AbstractCatalogController {private static final Logger LOGGER = Logging.getLogger(WorkspaceController.class);@Autowiredpublic WorkspaceController(@Qualifier("catalog") Catalog catalog) {super(catalog);}
}
扩展的说一下@Autowired是个依赖注入,
构造函数中有一个catalog,但是WorkspaceController是个servlet接口,没有实例化的地方,构造函数怎么能够传过来呢,查看applicationContext.xml可以看到
<alias name="localWorkspaceCatalog" alias="catalog"/>
<bean id="localWorkspaceCatalog" class="org.geoserver.catalog.impl.LocalWorkspaceCatalog"><constructor-arg ref="advertisedCatalog" />
</bean><bean id="advertisedCatalog" class="org.geoserver.catalog.impl.AdvertisedCatalog"><constructor-arg ref="secureCatalog" /><property name="layerGroupVisibilityPolicy"><bean id="org.geoserver.catalog.LayerGroupVisibilityPolicy.HIDE_NEVER" class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean"/></property>
</bean>
catalog就这通过applicationContext.xml的配置实现初始情况下就可以构造函数注入进去
再继续看LocalWorkspaceCatalog ,跟踪源码可以看到下面的代码
public class LocalWorkspaceCatalog extends AbstractCatalogDecorator implements Catalog {}public class AbstractCatalogDecorator extends AbstractDecorator<Catalog> implements Catalog {public AbstractCatalogDecorator(Catalog catalog) {super(catalog);}
}// 反编译的AbstractDecorator
public class AbstractDecorator<D> implements Wrapper, Serializable {protected D delegate;public AbstractDecorator(D delegate) {if (delegate == null) {throw new NullPointerException("Cannot delegate to a null object");} else {this.delegate = delegate;}}
}
通过一步步的查看父对象可以看到最终继承自 org.geotools.util.decorate.AbstractDecorator
,也就是说可以直接用delegate去操作父类的一些操作
五、工作空间查询解读
一般来说工作空间的查询地址是
http://localhost:8080/geoserver/rest/workspaces (浏览器预览居多)
或
http://localhost:8080/geoserver/rest/workspaces.json (作为前端调用的接口居多)
或
http://localhost:8080/geoserver/rest/workspaces.xml (作为前端调用的接口居多)
当浏览器访问http://localhost:8080/geoserver/rest/workspaces的servlet代码位置在如下位置(✈ 引申的说一下,geoserver的rest代码大多在 gs-restconfig 包下面)
src/restconfig/src/main/java/org/geoserver/rest/catalog/WorkspaceController.java
@GetMappingpublic RestWrapper workspacesGet() {List<WorkspaceInfo> wkspaces = catalog.getWorkspaces();return wrapList(wkspaces, WorkspaceInfo.class);}
从@GetMapping 能看出来它是个普通的spring servlet接口,RestWrapper是对返回结果的一个包装器,catalog是针对geoserver文件目录映射出来的一个方法类
查询结果是这样的
如果不用包装器的话返回结果是这样的
@GetMapping("/details")public List<WorkspaceInfo> getAllWorkspacesDetails() {List<WorkspaceInfo> workspaces = catalog.getWorkspaces();return workspaces;}
可以看出来如果不用包装器的话会把查出的数据原封不动的返回出来,而且兼容xml和json,实际不管使用不使用包装器时上面 三、前置知识点-AbstractHttpMessageConverter 讲到Jaxb2RootElementHttpMessageConverter 转换器都会生效,也就是说一直支持xml个json请求,而当使用包装器时就用到了另一个模板框架二、前置知识点-FreeMarker
5.1 模板解读
往下看wrapList源码
protected <T> RestWrapper<T> wrapList(Collection<T> list, Class<T> clazz) {return new RestListWrapper<>(list, clazz, this, getTemplate(list, clazz));}
这里面终于找到了一个跟模板相关的东西getTemplate(list, clazz)
在WorkspaceController的基类RestBaseController中找到下面获取模板的代码
protected Template getTemplate(Object o, Class<?> clazz) {Template template = null;Configuration configuration = createConfiguration(clazz);。。。。。。(此处省略n行代码)return tryLoadTemplate(configuration, templateName);}
里面的代码看着没啥营养我替你们看过了,跟着代码就能找到模板的位置,也就是这个地方
src/restconfig/src/main/java/org/geoserver/rest/catalog/ftl-templates/workspaces.ftl
<#include "head.ftl">
Workspaces
<ul>
<#list values as w><li><a href="${page.pageURI(w.properties.name + '.html')}">${w.properties.name}</a><#if w.properties.isDefault> [default] 哈哈 </#if></li>
</#list>
</ul>
<#include "tail.ftl">
最后那两个“哈哈”是我自己加的,浏览器访问可以看到下面效果
如果你那儿是乱码的可以在头部模板里面加个<meta charset="UTF-8" />
src/restconfig/src/main/java/org/geoserver/rest/catalog/ftl-templates/head.ftl
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head><title>GeoServer Configuration</title><meta charset="UTF-8" /><meta name="ROBOTS" content="NOINDEX, NOFOLLOW"/>
</head>
<body><#setting number_format="#0.0#">
但是访问的时候我还有一个疑问,直接访问是用的模板,但当我访问json的接口时儿返回结果貌似没有走这个模板
这是因为什么呢 ,再返回去查getTemplate方法,原因是默认是根据模板名查询模板的,也就是说根据workspace就能查到模板,换成workspace.json 就不行,如果想要用json类型的模板,就得再定义个workspace.json.flt文件,
if (template == null) template = tryLoadTemplate(configuration, templateName + ".ftl");
总的来说,如果不加干预的话直接请求
http://localhost:8080/geoserver/rest/workspaces
就会使用FreeMarker模板,然后经过转换器(此处是Jaxb2RootElementHttpMessageConverter 、FreemarkerHTMLMessageConverter、XStreamXMLMessageConverter、XStreamJSONMessageConverter。。。)传给前端,如果是访问
http://localhost:8080/geoserver/rest/workspaces.json
的话则会跳过模板直接经过转换器(此处是Jaxb2RootElementHttpMessageConverter )然后传给前端
到这里FreeMarker的框架算是基本上梳理完了 ,感觉就像是个放大版的StringBuilder。
5.2 请求转换器解读
看了前面描述的三、前置知识点-AbstractHttpMessageConverter 可以知道在查询完之后会执行一次查询结果的转换操作
再次看查询工作空间的代码
@GetMappingpublic RestWrapper workspacesGet() {List<WorkspaceInfo> wkspaces = catalog.getWorkspaces();return wrapList(wkspaces, WorkspaceInfo.class);}
🔎 下钻查看wrapList的代码如下
protected <T> RestWrapper<T> wrapList(Collection<T> list, Class<T> clazz) {return new RestListWrapper<>(list, clazz, this, getTemplate(list, clazz));}
🔎 继续下钻查看RestListWrapper以及它的基类RestWrapperAdapter
public void configurePersister(XStreamPersister persister, XStreamMessageConverter converter) {controller.configurePersister(persister, converter);}
从这里能看出来包装器有个关于转换器的配置的方法,而且类型是XStreamMessageConverter converter,继续跟踪代码,查找下它是在哪里被调用的
这里看到有几个继承类,但是只有里面的类型和RestListWrapper是一样的
public abstract class XStreamCatalogListConverterextends XStreamMessageConverter<RestListWrapper<?>>
根据spring mvc的自动根据参数类型适配的原则,它用的转换器就是XStreamCatalogListConverter,而且从注释中也能看出来
/*** A wrapper for all Collection type responses using the {@link XStreamCatalogListConverter} (XML* and JSON output). Also supports Collection type responses using the {@link* FreemarkerHTMLMessageConverter}, but is not required for such responses.** <p>In the previous rest API this wasn't needed because in each individual rest request the* Collections were aliased to*/
在XStreamCatalogListConverter.java中能够看到具体的转换方法
protected void configureXStream(XStream xstream, Class<?> clazz, RestListWrapper<?> wrapper) {XStreamPersister xp = xpf.createXMLPersister();wrapper.configurePersister(xp, this);final String name = getItemName(xp, clazz);xstream.alias(name, clazz);xstream.registerConverter(new CollectionConverter(xstream.getMapper()) {@Overridepublic boolean canConvert(@SuppressWarnings("rawtypes") Class type) {return Collection.class.isAssignableFrom(type);}@Overrideprotected void writeCompleteItem(Object item,MarshallingContext context,HierarchicalStreamWriter writer) {writer.startNode(name);context.convertAnother(item);writer.endNode();}});xstream.registerConverter(new Converter() {@Overridepublic boolean canConvert(Class type) {return clazz.isAssignableFrom(type);}@Overridepublic void marshal(Object source,HierarchicalStreamWriter writer,MarshallingContext context) {String ref;// Special case for layer list, to handle the non-workspace-specific// endpoint for layersif (clazz.equals(LayerInfo.class)&& OwsUtils.getter(clazz, "prefixedName", String.class) != null&& RequestInfo.get() != null&& !RequestInfo.get().getPagePath().contains("/workspaces/")) {ref = (String) OwsUtils.get(source, "prefixedName");} else if (OwsUtils.getter(clazz, "name", String.class) != null) {ref = (String) OwsUtils.get(source, "name");} else if (OwsUtils.getter(clazz, "id", String.class) != null) {ref = (String) OwsUtils.get(source, "id");} else if (OwsUtils.getter(clazz, "id", Long.class) != null) {// For some reason Importer objects have Long ids so this catches that// caseref = OwsUtils.get(source, "id").toString();} else {throw new RuntimeException("Could not determine identifier for: " + clazz.getName());}writer.startNode(wrapper.getItemAttributeName());writer.setValue(ref);writer.endNode();encodeLink(encode(ref), writer);}@Overridepublic Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {return null;}});}
我修改了上述代码中的
writer.startNode(wrapper.getItemAttributeName() +"test");
然后再次请求接口就能看到修改后的数据
写在最后,文章难免有写的不对或者不完善的地方,欢迎提出纠正意见
相关文章:

Geoserver源码解读四 REST服务
文章目录 文章目录 一、概要 二、前置知识点-FreeMarker 三、前置知识点-AbstractHttpMessageConverter 3.1 描述 3.2 应用 四、前置知识点-AbstractDecorator 4.1描述 4.2 应用 五、工作空间查询解读 5.1 模板解读 5.2 请求转换器解读 一、概要 关于geoserver的r…...

硬件开发笔记(二十一):外部搜索不到的元器件封装可尝试使用AD21软件的“ManufacturerPart Search”功能
若该文为原创文章,转载请注明原文出处 本文章博客地址:https://hpzwl.blog.csdn.net/article/details/139869584 长沙红胖子Qt(长沙创微智科)博文大全:开发技术集合(包含Qt实用技术、树莓派、三维、OpenCV…...

【AI大模型】GPTS 与 Assistants API
前言 2023 年 11 月 6 日,OpenAI DevDay 发表了一系列新能力,其中包括:GPT Store 和 Assistants API。 GPTs 和 Assistants API 本质是降低开发门槛 可操控性和易用性之间的权衡与折中: 更多技术路线选择:原生 API、…...

攻击者开始使用 XLL 文件进行攻击
近期,研究人员发现使用恶意 Microsoft Excel 加载项(XLL)文件发起攻击的行动有所增加,这项技术的 MITRE ATT&CK 技术项编号为 T1137.006。 这些加载项都是为了使用户能够利用高性能函数,为 Excel 工作表提供 API …...

Why RAG is slower than LLM?
I used RAG with LLAMA3 for AI bot. I find RAG with chromadb is much slower than call LLM itself. Following the test result, with just one simple web page about 1000 words, it takes more than 2 seconds for retrieving: 我使用RAG(可能是指某种特定的…...

Word页码设置,封面无页码,目录摘要阿拉伯数字I,II,III页码,正文开始123为页码
一、背景 使用Word写项目书或论文时,需要正确插入页码,比如封面无页码,目录摘要阿拉伯数字I,II,III为页码,正文开始以123为页码,下面介绍具体实施方法。 所用Word版本:2021 二、W…...

汽车汽配图纸管理、产品研发管理解决方案
汽车汽配图纸管理、产品研发管理解决方案 随着全球汽车市场的快速发展,中国汽车汽配行业迎来了前所未有的发展机遇。然而,在这一过程中,企业也面临着诸多挑战,如研发能力的提升、技术资料管理的复杂性、以及跨部门协作的困难等。为…...

小程序简单版音乐播放器
小程序简单版音乐播放器 结构 先来看看页面结构 <!-- wxml --><!-- 标签页标题 --> <view class"tab"><view class"tab-item {{tab0?active:}}" bindtap"changeItem" data-item"0">音乐推荐</view><…...

驾校预约管理系统
摘 要 随着驾驶技术的普及和交通安全意识的增强,越来越多的人选择参加驾校培训,以获取驾驶执照。然而,驾校管理面临着日益增长的学员数量和繁琐的预约管理工作。为了提高驾校的管理效率和服务质量,驾校预约管理系统成为了必不可少…...

C++ 左值右值 || std::move() || 浅拷贝,深拷贝 || 数据类型
数据类型: 作用:决定变量所占内存空间的字节大小,和布局方式基本数据类型: 算数类型: 整形(bool / char……扩展集 / int / long……)&& 浮点形(float/double……ÿ…...

发那科机器人IO 分配
IO 信号 也称为输入\输出信号,是机器人与外围设备通信的电信号...

ubuntu开机怎么进入、退出命令行界面
要在Ubuntu系统开机时进入命令行界面,可以按照以下步骤操作: 在开机过程中按下Ctrl Alt F1组合键,这将会切换到第一个虚拟控制台,即命令行界面。如果Ctrl Alt F1没有生效,也可以尝试Ctrl Alt F2、Ctrl Alt F3…...

『FPGA通信接口』LVDS接口(4)LVDS接收端设计
文章目录 1.LVDS接收端概述2逻辑框图3.xapp855训练代码解读4.接收端发送端联调5.传送门 1.LVDS接收端概述 接收端的传输模型各个属性应该与LVDS发送端各属性一致,例如,如果用于接收CMOS图像传感器的图像数据,则接收端程序的串化因子、通道个…...

面试题:HTTP的body是二进制还是文本
实际上,HTTP的body可以是二进制数据,也可以是文本。HTTP协议本身不对body内容的格式做限制,具体格式取决于Content-Type头字段的定义。 文本数据: 当Content-Type头字段指定为文本类型时(如text/plain、text/html、ap…...

5分钟带你部署一套Jenkins持续集成环境
5分钟带你部署一套Jenkins持续集成环境 Jenkins是开源CI&CD软件领导者, 提供超过1000个插件来支持构建、部署、自动化, 满足任何项目的需要。 Jenkins的优点 持续集成和持续交付 作为一个可扩展的自动化服务器,Jenkins 可以用作简单的 CI…...

OpenAI突然宣布停止向中国提供API服务!
标题 🌟 OpenAI突然宣布停止向中国提供API服务! 🌟摘要 📜引言 📢正文 📝1. OpenAI API的重要性2. 停止服务的原因分析3. 对中国市场的影响4. 应对措施代码案例 📂常见问题解答(QA)❓…...

Bootstrap 标签
Bootstrap 标签 引言 Bootstrap 是一个流行的前端框架,它提供了一套丰富的组件和工具,帮助开发者快速构建响应式和移动优先的网页。在 Bootstrap 中,标签(Badge)是一种小巧的组件,用于显示计数、提示或标…...

EtherCAT主站SOEM -- 37 -- win-soem-win10及win11系统QT-SOEM-1个电机转圈圈-周期同步速度模式(CSV模式)
EtherCAT主站SOEM -- 37 -- win-soem-win10及win11系统QT-SOEM-1个电机转圈圈-周期同步速度模式(CSV模式) 0 QT-SOEM及STM32F767-SOEM视频欣赏及源代码链接:0.1 Linux--Ubuntu系统之 QT-SOEM博客、视频欣赏及源代码链接0.2 STM32F767-SOEM 博客、视频欣赏及源代码链接0.3 wi…...

老板舍不得买库存管理软件❓一招解决
在当今快节奏的商业环境中,仓库管理是企业运作中不可或缺的一环。对于许多中小型企业而言,简易且高效的库存管理系统尤为重要。搭贝简易库存管理系统针对仓库的出入库进行有效管理,帮助企业实现库存的透明化和流程的自动化。 客户的痛点 1. …...

【MySQL数据库】:MySQL视图特性
目录 视图的概念 基本使用 准备测试表 创建视图 修改视图影响基表 修改基表影响视图 删除视图 视图规则和限制 视图的概念 视图是一个虚拟表,其内容由查询定义,同真实的表一样,视图包含一系列带有名称的列和行数据。视图中的数据…...

malloc、free和new delete的区别
malloc/free 和 new/delete 是在 C 中分配和释放内存的两种不同方法。它们主要有以下区别: 1. 语法和用法 malloc 和 free: malloc开辟空间时需要手动计算分配的空间大小 int* p (int*)malloc(sizeof(int) * 10); // 分配10个int类型的内存 // 使用内存 free(p); …...

如何有效地优化 Erlang 程序的内存使用,以应对大规模数据处理的需求?
要有效地优化Erlang程序的内存使用,以应对大规模数据处理的需求,可以考虑以下几个方面: 减少不必要的内存分配:避免过多的数据复制和不必要的数据结构创建。可以使用Erlang的二进制数据类型来避免数据复制,使用原子数据…...

vue3项目使用@antv/g6实现可视化流程功能
文章目录 项目需求一、需要解决的问题二、初步使用1.动态数据-组件封装(解决拖拽会留下痕迹的问题,引用图片,在节点右上角渲染图标,实现,事现旋转动画,达到loading效果)2.文本太长,超出部分显示(...),如下函…...

【Linux网络(一)初识计算机网络】
一、网络发展 1.发展背景 2.发展类型 二、网络协议 1.认识协议 2.协议分层 3.OSI七层模型 4.TCP/IP协议 三、网络传输 1.协议报头 2.局域网内的两台主机通信 3.跨网络的两台主机通信 四、网络地址 1.IP地址 2.MAC地址 一、网络发展 1.发展背景 计算机网络的发展…...

Vulhub——Log4j、solr
文章目录 一、Log4j1.1 Apache Log4j2 lookup JNDI 注入漏洞(CVE-2021-44228)1.2 Apache Log4j Server 反序列化命令执行漏洞(CVE-2017-5645) 二、Solr2.1 Apache Solr 远程命令执行漏洞(CVE-2017-12629)2.…...

linux 设置程序自启动
程序随系统开机自启动的方法有很多种, 这里介绍一种简单且常用的, 通过系统的systemd服务进行自启动。 第一步: 新建一个.service文件 sudo vim /etc/systemd/system/myservice.service[Unit] DescriptionMy Service #Afternetwork.target[…...

PostgreSQL 分区表与并行查询(十)
1. 分区表概述 1.1 什么是分区表 分区表是将大表分割成更小、更可管理的部分的技术。每个分区表都可以单独进行索引和查询,从而提高查询性能和管理效率。 1.2 分区策略 1.2.1 基于范围的分区 按照时间范围或者数值范围进行分区,如按月或按地区。 C…...

React Hooks使用规则:为什么不在条件语句和循环中使用它们
React Hooks为函数组件引入了状态和生命周期特性,极大地增强了其功能。然而,正确使用Hooks是确保组件稳定性和性能的关键。本文将探讨React Hooks的基本规则,以及为什么我们不应该在条件语句和循环中使用它们。 Hooks的基本规则 React团队为…...

【Docker】Consul 和API
目录 一、Consul 1. 拉取镜像 2. 启动第一个consul服务:consul1 3. 查看consul service1 的ip地址 4. 启动第二个consul服务:consul2, 并加入consul1(使用join命令) 5. 启动第三个consul服务:consul3&…...

Python polars学习-07 缺失值
背景 polars学习系列文章,第7篇 缺失值 该系列文章会分享到github,大家可以去下载jupyter文件,进行参考学习 仓库地址:https://github.com/DataShare-duo/polars_learn 小编运行环境 import sysprint(python 版本:…...