用户登录实现流程
相关代码文件为:src/main/java/org/geoserver/security/filter/GeoServerUserNamePasswordAuthenticationFilter.java
package org.geoserver.security.filter;
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.geoserver.security.GeoServerSecurityFilterChain;
import org.geoserver.security.config.SecurityNamedServiceConfig;
import org.geoserver.security.config.UsernamePasswordAuthenticationFilterConfig;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
import org.springframework.security.web.authentication.RememberMeServices;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.session.ChangeSessionIdAuthenticationStrategy;
import org.springframework.security.web.authentication.session.SessionFixationProtectionStrategy;
/**
* User name / password authentication filter
*
* 核心功能:处理基于表单的用户名/密码认证流程
* 1. 拦截登录请求
* 2. 提取用户名/密码
* 3. 执行认证逻辑
* 4. 处理认证结果(成功/失败)
* 5. 提供认证入口点
*
* @author christian
*/
public class GeoServerUserNamePasswordAuthenticationFilter extends GeoServerCompositeFilter
implements GeoServerAuthenticationFilter {
// 登录处理相关URL常量
public static final String URL_LOGIN_SUCCCESS = "/web"; // 登录成功后的默认重定向地址
public static final String URL_LOGIN_FAILURE = // 登录失败重定向地址(带错误参数)
"/web/wicket/bookmarkable/org.geoserver.web.GeoServerLoginPage?error=true";
public static final String URL_LOGIN_FORM = // 登录表单地址(无错误状态)
"/web/wicket/bookmarkable/org.geoserver.web.GeoServerLoginPage?error=false";
private LoginUrlAuthenticationEntryPoint aep; // 认证入口点(处理未认证请求)
String[] pathInfos; // 需要启用认证的路径模式
/**
* 从配置初始化过滤器
* 核心配置方法:创建并配置Spring Security的认证过滤器链
*/
@Override
public void initializeFromConfig(SecurityNamedServiceConfig config) throws IOException {
super.initializeFromConfig(config);
// 获取需要认证的路径列表(逗号分隔)
pathInfos = GeoServerSecurityFilterChain.FORM_LOGIN_CHAIN.split(",");
// 转换为用户名密码过滤器的专用配置
UsernamePasswordAuthenticationFilterConfig upConfig =
(UsernamePasswordAuthenticationFilterConfig) config;
// 1. 配置认证入口点(当访问受保护资源时跳转到登录页)
aep = new LoginUrlAuthenticationEntryPoint(URL_LOGIN_FORM);
aep.setForceHttps(false); // 不强制HTTPS(生产环境应设为true)
try {
aep.afterPropertiesSet(); // Spring标准初始化方法
} catch (Exception e2) {
throw new IOException(e2);
}
// 2. 获取RememberMe服务(实现"记住我"功能)
RememberMeServices rms = securityManager.getRememberMeService();
// 3. 创建Spring Security的用户名密码认证过滤器
UsernamePasswordAuthenticationFilter filter = new UsernamePasswordAuthenticationFilter() {
/**
* 重写认证请求判断逻辑
* 只对特定路径的请求启用认证处理
*/
@Override
protected boolean requiresAuthentication(
HttpServletRequest request, HttpServletResponse response) {
// 检查当前请求路径是否在需要认证的路径列表中
for (String pathInfo : pathInfos) {
if (getRequestPath(request).startsWith(pathInfo))
return true;
}
return false;
}
};
// 4. 配置过滤器的基本参数
filter.setPasswordParameter(upConfig.getPasswordParameterName()); // 密码参数名(默认"password")
filter.setUsernameParameter(upConfig.getUsernameParameterName()); // 用户名参数名(默认"username")
filter.setAuthenticationManager(getSecurityManager().authenticationManager()); // 设置认证管理器
// 5. 配置附加服务
filter.setRememberMeServices(rms); // 集成RememberMe功能
GeoServerWebAuthenticationDetailsSource s = new GeoServerWebAuthenticationDetailsSource();
filter.setAuthenticationDetailsSource(s); // 自定义认证详情源(获取IP等信息)
// 6. 会话固定攻击防护
try {
// Servlet 3.1+ 使用会话ID变更策略(更安全)
filter.setSessionAuthenticationStrategy(new ChangeSessionIdAuthenticationStrategy());
} catch (IllegalStateException e) {
// 旧版Servlet使用会话迁移策略
filter.setSessionAuthenticationStrategy(new SessionFixationProtectionStrategy());
}
filter.setAllowSessionCreation(false); // 禁止随意创建会话
// 7. 配置认证结果处理器
// 7.1 认证成功处理器
SimpleUrlAuthenticationSuccessHandler successHandler =
new SimpleUrlAuthenticationSuccessHandler();
successHandler.setDefaultTargetUrl(URL_LOGIN_SUCCCESS); // 登录成功重定向到主页
filter.setAuthenticationSuccessHandler(successHandler);
// 7.2 认证失败处理器
SimpleUrlAuthenticationFailureHandler failureHandler =
new SimpleUrlAuthenticationFailureHandler();
failureHandler.setDefaultFailureUrl(URL_LOGIN_FAILURE); // 登录失败重定向回登录页(带错误标记)
filter.setAuthenticationFailureHandler(failureHandler);
// 8. 将配置好的过滤器添加到嵌套过滤器链
getNestedFilters().add(filter);
}
/**
* 获取认证入口点
* 当用户访问受保护资源时,此入口点负责引导到登录页
*/
@Override
public AuthenticationEntryPoint getAuthenticationEntryPoint() {
return aep;
}
/**
* 过滤器核心执行方法
* 将认证入口点存入请求属性,供后续流程使用
*/
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
// 在请求中存储认证入口点引用
req.setAttribute(GeoServerSecurityFilter.AUTHENTICATION_ENTRY_POINT_HEADER, aep);
// 继续执行过滤器链
super.doFilter(req, res, chain);
}
/** 标识此过滤器适用于HTML界面 */
@Override
public boolean applicableForHtml() {
return true; // 处理Web界面认证
}
/** 标识此过滤器不适用于服务端点 */
@Override
public boolean applicableForServices() {
return false; // 不处理WFS/WMS等OGC服务认证
}
}创建工作空间
src/main/java/org/geoserver/web/data/workspace/WorkspaceNewPage.java
WorkspaceNewPage 类继承自 GeoServerSecuredPage,确保该页面需要经过权限验证才能访问。
用户点击“提交”按钮时触发 submitLink.onSubmit() 方法,调用 handleOnSubmit() 方法进行实际处理。
private void handleOnSubmit() {
// Catalog 是 GeoServer 中管理所有数据(如工作区、命名空间等)的核心类。通过 getCatalog() 获取当前的目录实例,后续操作都依赖它。
Catalog catalog = getCatalog();
// 获取用户输入的工作区信息。model 是一个封装了用户表单数据的模型对象(CompoundPropertyModel<WorkspaceInfo>)。调用 getObject() 获取用户填写的工作区信息(如名称等)。
WorkspaceInfo workspace = model.getObject();
// 创建并设置命名空间信息 命名空间前缀(Prefix)使用工作区名称 命名空间 URI 从页面输入框中获取 是否隔离(Isolated)与工作区保持一致
NamespaceInfo namespace = catalog.getFactory().createNamespace();
namespace.setPrefix(workspace.getName());
namespace.setURI(nsUriTextField.getDefaultModelObjectAsString());
namespace.setIsolated(workspace.isIsolated());
// 验证工作区和命名空间是否合法
// 调用 catalog.validate(...) 检查工作区和命名空间是否符合规范(如名称是否合法、是否重复等)。使用 validateAndReport(...) 包装验证逻辑,自动显示错误提示。如果任一验证失败,终止流程并返回错误信息。
/* validateAndReport(...) 方法说明:
接收一个函数式参数(验证逻辑),执行校验。
如果验证失败,记录日志并提示错误。
返回布尔值表示验证是否通过。*/
if (!validateAndReport(() -> catalog.validate(workspace, true))
|| !validateAndReport(() -> catalog.validate(namespace, true))) {
// at least one validation fail
return;
}
// 保存工作区和命名空间若添加过程中发生异常(例如数据库写入失败),调用 cleanAndReport(...) 清理已保存的数据以保证一致性。
/*cleanAndReport(...) 方法说明:
判断是否只保存了工作区而未保存命名空间。
如果是,则删除已保存的工作区,确保两者要么都存在,要么都不存在。
记录异常信息并提示用户。*/
try {
catalog.add(workspace);
catalog.add(namespace);
} catch (Exception exception) {
LOGGER.log(Level.INFO, "Error storing workspace related objects.", exception);
cleanAndReport(exception);
}
// 设置默认工作区(如果勾选) 如果用户勾选了“设为默认工作区”,则更新目录中的默认工作区配置。
if (infoPanel.defaultWs) {
catalog.setDefaultWorkspace(workspace);
}
//如果用户有权限并且打开了“Security”选项卡,调用 accessdataPanel.save() 保存访问控制规则。成功后跳转回工作区管理页面。如果保存失败,记录日志并提示错误信息。
try {
if (accessdataPanel != null) accessdataPanel.save();
doReturn(WorkspacePage.class);
} catch (IOException e) {
LOGGER.log(Level.INFO, "Error saving access rules associated to workspace " + workspace.getName(), e);
error(e.getMessage() == null ? e.toString() : e.getMessage());
}
}添加工作空间和命名空间的代码详解
@Override
public void add(WorkspaceInfo workspace) {
//确保workspace对象不为null
workspace = resolve(workspace);
//校验workspace
validate(workspace, true);
// 检查是否已存在同名工作区
if (getWorkspaceByName(workspace.getName()) != null) {
throw new IllegalArgumentException("Workspace with name '" + workspace.getName() + "' already exists.");
}
// 调用 beforeadded(workspace) 方法,通知监听器即将添加一个工作区。
beforeadded(workspace);
// 获取当前默认工作区
WorkspaceInfo defaultWorkspace = getDefaultWorkspace();
WorkspaceInfo added;
/*如果当前没有默认工作区:
使用 synchronized 锁定 facade 对象,确保线程安全。
调用 facade.add(workspace) 将工作区添加进目录。
如果添加后仍然没有默认工作区,就将当前添加的工作区设为默认工作区:setDefaultWorkspace(workspace)
如果已有默认工作区:
直接调用 facade.add(workspace) 添加新工作区即可。*/
if (defaultWorkspace == null) {
synchronized (facade) {
added = facade.add(workspace);
// if there is no default workspace use this one as the default
if (getDefaultWorkspace() == null) {
setDefaultWorkspace(workspace);
}
}
} else {
added = facade.add(workspace);
}
added(added);
}添加工作空间的具体底层实现方法
将一个 CatalogInfo 类型的对象(如 WorkspaceInfo, NamespaceInfo, LayerInfo 等)添加到内存索引中
public T add(T value) {
//判断传入的 value 是否是一个 Java 动态代理对象(例如由 ModificationProxy.create(...) 创建的代理)。如果是,则通过反射获取其内部封装的真实对象(避免多次代理嵌套导致问题)。
if (Proxy.isProxyClass(value.getClass())) {
ModificationProxy h = (ModificationProxy) Proxy.getInvocationHandler(value);
value = (T) h.getProxyObject();
}
// 获取名称映射表(nameMap)
Map<Name, T> nameMap = getMapForValue(nameMultiMap, value);
// 生成对象名称(Name)
Name name = nameMapper.apply(value);
// 获取 ID 映射表(idMap)
Map<String, T> idMap = getMapForValue(idMultiMap, value);
// 加锁写入数据(线程安全)
writeLock.lock();
try {
nameMap.put(name, value);
return idMap.put(value.getId(), value);
} finally {
writeLock.unlock();
}
}添加命名空间
public void add(NamespaceInfo namespace) {
// 验证命名空间信息的有效性
validate(namespace, true);
NamespaceInfo added;
// 解析命名空间信息,以处理可能的命名空间冲突或重复
final NamespaceInfo resolved = resolve(namespace);
// 在添加命名空间之前执行的预处理步骤
beforeadded(namespace);
// 获取当前的默认命名空间
NamespaceInfo defaultNamespace = getDefaultNamespace();
if (defaultNamespace == null) {
// 如果当前没有默认命名空间,同步添加过程以避免并发问题
synchronized (facade) {
// 添加解析后的命名空间
added = facade.add(resolved);
// 如果系统中仍然没有默认命名空间,将新添加的命名空间设置为默认
if (getDefaultNamespace() == null) {
setDefaultNamespace(resolved);
}
}
} else {
// 如果已有默认命名空间,直接添加解析后的命名空间
added = facade.add(resolved);
}
// 添加完成后执行的后处理步骤
added(added);
}命名空间添加底层代码
public NamespaceInfo add(NamespaceInfo value) {
writeLock.lock();
try {
// 调用public T add(T value) 将传入的 NamespaceInfo 添加到其内部存储结构中
NamespaceInfo ns = super.add(value);
// 此方法用于更新当前类维护的 ConcurrentHashMap<String, List<NamespaceInfo>> index 索引。它会根据 NamespaceInfo 的 URI 将其加入对应的列表中,并保持列表按 ID 排序。
addInternal(value);
return ns;
} finally {
writeLock.unlock();
}
}存储仓库
Catalog
Catalog是 GeoServer 中用于访问元信息的核心接口,提供了对工作区(Workspace)、命名空间(Namespace)、样式(Style)、图层(Layer)、资源(Resource)等对象的统一访问方式。
关键方法:
add(StoreInfo store):添加一个存储仓库。
remove(StoreInfo store):移除一个存储仓库。
save(StoreInfo store):保存已修改的存储仓库。
getStore(String id, Class<T> clazz):根据 ID 获取特定类型的存储仓库。
getStoreByName(WorkspaceInfo workspace, String name, Class<T> clazz):根据名称和所属工作区获取特定类型的存储仓库。
getStoresByWorkspace(WorkspaceInfo workspace, Class<T> clazz):获取某个工作区下的所有指定类型的存储仓库。
CatalogFacade
CatalogFacade提供对持久化存储中 Catalog 对象的访问能力,封装了底层数据库或文件系统的具体实现细节。
关键方法:
add(StoreInfo store):向持久化存储中添加一个存储仓库。
remove(StoreInfo store):从持久化存储中移除一个存储仓库。
save(StoreInfo store):将对存储仓库的修改持久化。
getStore(String id, Class<T> clazz):根据 ID 和类型获取存储仓库。
getStoreByName(WorkspaceInfo workspace, String name, Class<T> clazz):根据工作区和名称获取存储仓库。
getStoresByWorkspace(WorkspaceInfo workspace, Class<T> clazz):获取某个工作区下的所有指定类型的存储仓库。
DefaultCatalogFacade
DefaultCatalogFacade是CatalogFacade 的默认实现类,基于内存中的结构进行管理
示例
添加存储仓库
catalog.add(store)
Catalog -> CatalogFacade -> DefaultCatalogFacade -> stores.add()
创建使用样式
创建样式页面代码地址/src/web/wms/src/main/java/org/geoserver/wms/web/data/StyleNewPage.java
用户提交后的执行代码
protected void onStyleFormSubmit() {
// 获取目录和模型对象
Catalog catalog = getCatalog();
StyleInfo model = styleForm.getModelObject();
// 使用目录工厂创建一个全新的 StyleInfo 对象,并通过 CatalogBuilder 把表单数据复制进去。
StyleInfo s = catalog.getFactory().createStyle();
CatalogBuilder builder = new CatalogBuilder(catalog);
builder.updateStyle(s, model);
StyleHandler styleHandler = styleHandler();
// 写入 SLD 文件如果图例为空或没有在线资源地址,则将图例设为 null
if (null == s.getLegend()
|| null == s.getLegend().getOnlineResource()
|| s.getLegend().getOnlineResource().isEmpty()) {
s.setLegend(null);
}
// 写入 SLD 文件,如果文件名为空,则根据样式名称生成文件名(如 mystyle.sld),然后把用户输入的原始样式内容(rawStyle)写入资源池中。
try {
if (s.getFilename() == null) {
// TODO: check that this does not override any existing files
s.setFilename(s.getName() + "." + styleHandler.getFileExtension());
}
catalog.getResourcePool().writeStyle(s, new ByteArrayInputStream(rawStyle.getBytes()));
} catch (IOException e) {
throw new WicketRuntimeException(e);
}
// 获取样式版本号,设置格式版本,然后调用 catalog.add(s) 将样式正式添加进目录。成功后提示“Style saved”。
try {
Version version = styleHandler.version(rawStyle);
s.setFormatVersion(version);
catalog.add(s);
styleForm.info("Style saved");
} catch (Exception e) {
LOGGER.log(Level.SEVERE, "Error occurred saving the style", e);
error(e.getMessage());
}
}catalog.add(s)执行过程类似于前面创建工作空间,存储仓库的代码,都是基于内存中的结构进行管理,代码逻辑相似。
服务发布
OGC 服务是通过 Web 访问和作地理空间数据的标准化接口。GeoServer 实施以下主要 OGC 服务规范:
Web Map Service (WMS) - 将地图渲染为图像(PNG、JPEG 等)
Web Feature Service (WFS) - 检索和作矢量要素数据
Web Coverage Service (WCS) - 提供对 coverage/栅格数据的访问
请求处理架构
所有 OGC 服务请求都遵循 GeoServer 中的通用模式。OWS Dispatcher 接收请求,OWS Dispatcher 确定服务类型和作,分析请求参数,并将请求路由到相应的服务实现。
主要组件与类说明
1. Dispatcher
位置: org.geoserver.ows.Dispatcher
作用:
OWS 请求的入口类
根据请求内容选择合适的服务实现类(Service)
调用对应的操作处理器(OperationHandler)
关键方法:
@Override
protected ModelAndView handleRequestInternal(HttpServletRequest httpRequest, HttpServletResponse httpResponse)
throws Exception {
// 对 HTTP 请求进行预处理,括设置编码
preprocessRequest(httpRequest);
// 初始化一个自定义的 Request 对象,用于封装整个请求过程中的上下文信息。
Request request = new Request();
// 将原始的 HTTP 请求和响应对象保存进 Request 中,便于后续使用。
request.setHttpRequest(httpRequest);
request.setHttpResponse(httpResponse);
Service service = null;
try {
// 调用 init() 方法对请求进行进一步初始化
/* 该函数 init 的主要功能是初始化一个 OWS 请求对象(Request),根据 HTTP 请求的方法和内容类型解析请求参数、处理不同类型的请求体(如 SOAP、multipart/form-data、XML POST),并设置相关字段以供后续处理使用。*/
request = init(request);
// 使用 ThreadLocal 存储当前线程的请求上下文,避免多线程间冲突。
REQUEST.set(request);
// 根据请求参数查找对应的 Service 实现类(如 WMS/WFS/WCS 等)。如果找不到服务或出错,会触发异常处理逻辑。
try {
service = service(request);
} catch (Throwable t) {
exception(t, null, request);
return null;
}
// 如果在初始化阶段就已经出现错误,直接抛出不再继续执行。
if (request.getError() != null) {
throw request.getError();
}
// 根据请求内容(如 GetFeature, GetMap)确定要执行的操作,并创建 Operation 对象。
Operation operation = dispatch(request, service);
request.setOperation(operation);
// 如果是 SOAP 请求,做一些特殊标记或处理。
if (request.isSOAP()) {
flagAsSOAP(operation);
}
// 调用具体服务的操作处理器,执行业务逻辑(如查询数据库、生成 GML 数据等)。
Object result = execute(request, operation);
// 如果有返回结果,构建响应内容并写入 HTTP 响应流中。
if (result != null) {
response(result, request, operation);
}
} catch (Throwable t) {
// 捕获所有异常,如果是安全相关的异常(如权限不足),重新抛出以便上层处理;否则调用 exception() 方法统一处理错误。
if (isSecurityException(t)) throw (Exception) t;
exception(t, service, request);
} finally {
// 触发完成后的回调(如日志记录、清理临时文件等)。移除线程局部变量中的请求对象,防止内存泄漏。
fireFinishedCallback(request);
REQUEST.remove();
}
return null;
}2. Request
位置: org.geoserver.ows.Request
作用:
封装整个请求过程中的上下文信息
包括原始 HTTP 请求、解析后的 KVP、请求服务类型、输出格式等
重要字段:
private HttpServletRequest httpRequest;
private Map<String, Object> kvp; // 解析后的键值对参数
private BufferedReader input; // POST 请求体输入流
private String service; // 服务类型(wms/wfs/wcs)
private String request; // 操作名称(GetMap/GetFeature)
private String version; // 协议版本号(1.3.0 / 2.0.0)
private Operation operation; // 当前执行的操作对象
private Service serviceDescriptor; // 当前调用的服务描述
3. Operation
位置: org.geoserver.platform.Operation
作用:
表示一个完整的 OGC 操作(如 GetFeature)
封装了操作名、服务描述、请求对象、响应对象
4. Service
位置: org.geoserver.platform.Service
作用:
抽象表示某个服务的实现(如 WMS/WFS/WCS)
包含该服务支持的所有操作及其处理器
5. KvpParser
位置: org.geoserver.ows.KvpParser
作用:
将 KVP 参数字符串解析为 Java 对象
支持多种数据类型(String、Integer、Double、Enum、Time、Elevation 等)
6. XmlRequestReader
位置: org.geoserver.ows.XmlRequestReader
作用:
解析 XML 格式的请求体(如 SOAP 请求)
使用 SAX 或 DOM 解析器读取 XML 并生成 Java 对象
7. Response
位置: org.geoserver.ows.Response
作用:
封装响应数据
支持不同输出格式(GML、GeoJSON、CSV、HTML 等)
WCS服务
架构流程

公共模块 (wcs)
位于 src/wcs 目录下,包含多个 WCS 版本共享的基础类和接口。
核心类与功能:
1. WCSFactoryExtension.java
功能:用于扩展 WCS 的工厂类,支持插件机制动态创建不同类型的 WCS 实例。
使用场景:当需要根据配置或运行时条件生成特定实现时使用。
2. WCSInfo.java / WCSInfoImpl.java
功能:表示 WCS 服务的全局配置信息,如启用状态、支持的操作等。
结构:
定义了 WCS 服务的基本属性(如是否启用、支持的格式)。
提供持久化能力(通常由 Spring 配置管理)。
3. WCSCoverageClipCallback.java
功能:处理覆盖数据裁剪的回调逻辑。
场景:在响应客户端请求时,对输出图像进行边界裁剪(如子集裁剪)。
4. CoverageEncoder.java
功能:编码器基类,负责将 Coverage 数据转换为最终输出格式(如 GeoTIFF、PNG 等)。
子类包括:
GeoTIFFCoverageResponseDelegate
IMGCoverageResponseDelegate
5. CoverageResponseDelegate.java
功能:响应委托接口,定义如何将 Coverage 数据写入 HTTP 响应流中。
实现类:
GeoTIFFCoverageResponseDelegate:处理 GeoTIFF 格式输出。
IMGCoverageResponseDelegate:处理 PNG/JPG 等图像格式。
6. WCSXStreamLoader.java
功能:加载和保存 WCS 配置文件(如 XML),通常用于持久化存储服务配置。
使用方式:通过 XStream 序列化/反序列化对象模型。
7. WCSUtils.java
功能:工具类,提供一些通用方法(如坐标系处理、时间维度处理等)。
示例方法:CRS 转换、时间范围解析等。
8. WcsException.java
功能:异常类,封装 WCS 请求过程中可能抛出的错误信息(如参数非法、不支持的操作等)。
使用方式:统一抛出标准化错误码和描述,便于客户端识别。
WCS 1.0 模块 (wcs1_0)
位于 src/wcs1_0 目录下,实现了 OGC WCS 1.0.0 规范。
核心类与功能:
1. 请求解析 (kvp 包)
Wcs10KvpParser.java
功能:解析 KVP(Key-Value Pair)格式的请求参数。
子类包括:
BBoxKvpParser:解析 BBOX 参数。
TimeKvpParser:解析 TIME 维度参数。
ElevationKvpParser:解析 ELEVATION 维度参数。
InterpolationMethodKvpParser:解析 INTERPOLATION 方法。
Wcs10GetCoverageRequestReader.java
功能:读取并构建 GetCoverage 请求对象,调用相应的解析器处理参数。
输出:构造完整的 GetCoverageRequest 对象供后续处理。
2. 响应处理 (response 包)
Wcs10GetCoverageResponse.java
功能:处理 GetCoverage 请求,生成对应格式的响应(如 GeoTIFF)。
流程:
获取 Coverage 数据
调用 CoverageEncoder 编码器完成数据输出
Wcs10DescribeCoverageResponse.java
功能:返回 Coverage 描述信息(如元数据、维度范围等)。
Wcs10CapsTransformer.java
功能:将服务能力描述(Capabilities)转换为 XML 输出。
3. XML 处理 (xml/v1_0_0 包)
WcsXmlReader.java
功能:XML 请求解析器,用于处理 XML 格式的请求(如 DescribeCoverage)。
WCSParserDelegate.java
功能:解析器委托类,协调不同 XML 元素的解析逻辑。
4. 服务类
DefaultWebCoverageService100.java
功能:WCS 1.0 的默认实现类,处理所有操作(GetCapabilities、GetCoverage、DescribeCoverage)。
实现接口:WebCoverageService100
WebCoverageService100.java
功能:接口,定义 WCS 1.0 所需的所有操作(GetCapabilities、GetCoverage、DescribeCoverage)。
WCS10WorkspaceQualifier.java
功能:限定工作区逻辑,决定某个 Coverage 是否属于当前请求的工作空间。
WCS10ServiceExceptionHandler.java
功能:异常处理器,统一处理 WCS 1.0 请求中的异常并返回标准错误信息。
WCS 1.1 模块 (wcs1_1)
位于 src/wcs1_1 目录下,实现了 OGC WCS 1.1.1 规范。
核心类与功能:
1. 请求解析 (kvp 包)
BoundingBoxKvpParser.java
功能:解析 bbox 参数,支持更复杂的子集裁剪(如多边形区域)。
RangeSubsetKvpParser.java
功能:解析 range-subset 参数,用于选择波段或变量子集。
2. 响应处理 (response 包)
3. XML 处理 (xml 包)
DescribeCoverageXmlParserTest.java(略去测试部分)
功能:测试类,验证 XML 格式的 DescribeCoverage 请求解析逻辑。
4. 服务类
WebCoverageService111.java
功能:WCS 1.1 的主服务接口,定义所有操作(GetCapabilities、GetCoverage、DescribeCoverage、GetCoverageMultipart 等)。
DefaultWebCoverageService111.java
功能:WCS 1.1 的默认实现类,继承并实现 WebCoverageService111 接口。
支持特性:
多维 Coverage
分片响应(multipart response)
WCS11ServiceExceptionHandler.java
功能:异常处理类,统一处理 WCS 1.1 请求的错误。
WCS11WorkspaceQualifier.java
功能:工作区限定逻辑,确保访问权限控制。
WCS 2.0 模块 (wcs2_0)
位于 src/wcs2_0 目录下,实现了 OGC WCS 2.0 Core 及扩展规范。
核心类与功能:
1. 请求处理 (kvp 包)
CRSExtentionKVPTest.java(略去测试部分)
功能:测试 CRS 扩展参数的解析。
ScaleKvpTest.java(略去测试部分)
功能:测试 Scale 参数的解析逻辑。
SubsetKvpParserTest.java(略去测试部分)
功能:测试 Subset 参数的解析过程。
2. XML 请求处理 (xml 包)
CRSExtentionTest.java(略去测试部分)
功能:测试 XML 格式的 CRS 扩展参数处理。
ScalingExtentionTest.java(略去测试部分)
功能:测试 XML 格式的 Scaling 扩展参数处理。
RangeSubsetExtentionTest.java(略去测试部分)
功能:测试 XML 格式的 RangeSubset 扩展参数处理。
3. 响应处理 (response 包)
4. 服务类
DefaultWebCoverageService20.java
功能:WCS 2.0 的默认实现类,处理所有操作(GetCapabilities、GetCoverage、DescribeCoverage)。
新增特性:
支持分片(Trimming)
支持波段子集(RangeSubset)
支持缩放(Scaling)
WCS20ServiceExceptionHandler.java
功能:异常处理类,处理 WCS 2.0 请求的错误。
WCS20WorkspaceQualifier.java
功能:工作区限定类,控制 Coverage 访问权限。
WMS 服务
服务架构

1. 核心类与接口
WMS 类:
主要职责:作为 WMS 服务的入口点,提供获取样式、生成地图等功能。
GetMapRequest 类:
主要职责:封装 WMS GetMap 请求的所有参数。
关键属性:bbox, layers, styles, time, elevation.
GetMap 类:
主要职责:根据 GetMapRequest 生成地图内容。
示例方法:run, executeInternal, addLayer.
GetMapKvpRequestReader 类:
主要职责:解析 KVP 格式的请求参数,生成 GetMapRequest.
示例方法:read, parseCRS, processSLDBody.
2. 请求处理流程
请求解析:
使用 GetMapKvpRequestReader 解析 HTTP 请求中的 KVP 参数。
构建 GetMapRequest 对象,包含所有必要的参数如 bbox, layers, styles.
地图生成:
调用 GetMap 类的 run 方法,传入 GetMapRequest.
创建 WMSMapContent 对象,设置视图范围、背景色等。
添加图层(矢量、栅格、WMS/WMTS)到地图内容中。
响应生成:
使用 GetMapOutputFormat 生成最终的地图图像。
设置 HTTP 响应头,返回图像数据。
3. 样式处理
本地样式:
通过 getStyleByName 获取本地存储的样式。
应用于指定图层。
远程样式:
支持通过 STYLE_URL 或 STYLE_BODY 指定远程样式。
使用 SLDXmlRequestReader 解析 SLD 文档。
动态样式:
支持运行时动态生成样式。
通过 DynamicStyling 配置控制是否启用。
4. 缓存与性能优化
HTTP 缓存:
使用 CachingHttpClientBuilder 构建支持缓存的 HTTP 客户端。
配置最大缓存条目数和单个条目大小。
连接池:
使用 HttpClientConnectionManager 管理 HTTP 连接池,提高并发性能。
5. 扩展机制
回调接口:
GetMapCallback 允许插件在地图生成前后执行自定义逻辑。
插件支持:
通过 GeoServerExtensions 加载和管理插件。
请求处理流程

WFS 服务
服务流程
.png)
核心接口与实现类
a. WebFeatureService
作用:定义 WFS 所有标准操作的接口。
关键方法:
getCapabilities: 获取服务能力文档。
describeFeatureType: 返回要素类型定义。
getFeature: 查询并返回要素集合。
transaction: 处理事务操作。
lockFeature: 锁定要素资源。
b. DefaultWebFeatureService
继承关系:实现 WebFeatureService 接口,并集成 Spring 上下文支持。
构造函数:接收 GeoServer 实例,初始化 Catalog。
方法实现:调用对应的操作类执行具体业务逻辑。
核心操作类
a. GetFeature
作用:执行 WFS GetFeature 请求,生成要素集合响应。
流程:
解析请求参数(如 bbox、filter、typeName)。
构建查询语句。
调用 DataStore 获取数据。
返回 FeatureCollectionResponse。
b. DescribeFeatureType
作用:根据请求中的 typeName 获取要素类型描述信息(Schema)。
流程:
解析 typeName。
从 Catalog 中获取 FeatureTypeInfo。
返回 XML 或 JSON 格式的 Schema。
c. Transaction
作用:处理 WFS Transaction 请求,执行 insert、update、delete 操作。
流程:
解析 Transaction 操作列表。
针对每个操作调用对应的处理器(InsertElementHandler、UpdateElementHandler 等)。
提交事务并返回结果。
存储查询(Stored Query)
a. StoredQuery
作用:支持预定义的查询模板,可复用。
核心方法:
compile():将查询表达式中的参数替换为实际值,并解析为 Query 对象。
validate():验证查询中引用的类型名是否在返回类型列表中。
b. StoredQueryProvider
作用:管理 StoredQuery 的注册与查找。
命名空间与 XML 解析支持
a. CatalogNamespaceSupport
作用:支持从 Catalog 中动态获取命名空间映射。
使用场景:XML 解析时自动识别命名空间前缀。
b. QNameKvpParser
作用:将 KVP 参数中的 QName 字符串解析为 QName 对象
配置与上下文支持
a. WFSInfo
作用:表示 WFS 服务的全局配置(版本、输出格式、最大要素数等)。
来源:通过 GeoServer.getService(WFSInfo.class) 获取。
b. ApplicationContextAware
作用:Spring 注入上下文,用于加载插件、监听器等扩展组件。
GeoServer源码学习记录
https://blog.mykele.asia/archives/geoserveryuan-ma-xue-xi-ji-lu
Comments