GeoServer WMS Integration in Java: Complete Web Map Service Guide

GeoServer is an open-source server for sharing geospatial data that implements OGC standards like WMS (Web Map Service), WFS, and WCS. This guide demonstrates how to integrate GeoServer WMS services into Java applications for dynamic map generation and spatial data visualization.

Why Use GeoServer WMS with Java?

  • Standards Compliance: Full OGC WMS 1.1.1 and 1.3.0 support
  • Dynamic Map Generation: Create maps on-the-fly from various data sources
  • Multiple Output Formats: PNG, JPEG, SVG, PDF, and more
  • Styling Control: SLD-based styling and theming
  • Layer Management: Combine multiple data sources in single maps
  • Caching Support: Integrates with tile caching systems

Prerequisites

  • GeoServer instance running
  • Java 8+ with HTTP client capabilities
  • Maven/Gradle for dependency management

Step 1: Project Dependencies

Maven (pom.xml):

<dependencies>
<!-- HTTP Client -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.14</version>
</dependency>
<!-- Image Processing -->
<dependency>
<groupId>javax.media</groupId>
<artifactId>jai_core</artifactId>
<version>1.1.3</version>
</dependency>
<!-- GeoTools for spatial operations -->
<dependency>
<groupId>org.geotools</groupId>
<artifactId>gt-main</artifactId>
<version>28.2</version>
</dependency>
<dependency>
<groupId>org.geotools</groupId>
<artifactId>gt-wms</artifactId>
<version>28.2</version>
</dependency>
<!-- JSON Processing -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.15.2</version>
</dependency>
<!-- XML Binding -->
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.1</version>
</dependency>
<!-- Spring Boot (Optional) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.7.0</version>
</dependency>
<!-- Caching -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
<version>2.7.0</version>
</dependency>
<!-- Apache Commons IO -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.11.0</version>
</dependency>
</dependencies>

Step 2: Configuration Classes

@Configuration
@ConfigurationProperties(prefix = "geoserver")
@Data
public class GeoServerConfig {
private String baseUrl = "http://localhost:8080/geoserver";
private String username;
private String password;
private String workspace = "myworkspace";
private int timeout = 30000;
private boolean cacheEnabled = true;
private int cacheSize = 1000;
private long cacheExpiryMinutes = 60;
public String getWmsEndpoint() {
return baseUrl + "/wms";
}
public String getRestEndpoint() {
return baseUrl + "/rest";
}
}
@Component
@Slf4j
public class GeoServerHttpClient {
private final GeoServerConfig config;
private final CloseableHttpClient httpClient;
private final ObjectMapper objectMapper;
public GeoServerHttpClient(GeoServerConfig config) {
this.config = config;
this.objectMapper = new ObjectMapper();
// Configure HTTP client with basic auth
RequestConfig requestConfig = RequestConfig.custom()
.setConnectTimeout(config.getTimeout())
.setSocketTimeout(config.getTimeout())
.build();
CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(
AuthScope.ANY,
new UsernamePasswordCredentials(config.getUsername(), config.getPassword())
);
this.httpClient = HttpClients.custom()
.setDefaultRequestConfig(requestConfig)
.setDefaultCredentialsProvider(credentialsProvider)
.build();
}
public byte[] executeWmsRequest(Map<String, String> params) throws GeoServerException {
try {
String url = buildWmsUrl(params);
HttpGet request = new HttpGet(url);
log.debug("Executing WMS request: {}", url);
try (CloseableHttpResponse response = httpClient.execute(request)) {
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode != 200) {
throw new GeoServerException("WMS request failed with status: " + statusCode);
}
// Check content type to ensure we got an image
Header contentType = response.getFirstHeader("Content-Type");
if (contentType == null || !contentType.getValue().startsWith("image/")) {
String responseBody = EntityUtils.toString(response.getEntity());
throw new GeoServerException("WMS returned non-image response: " + responseBody);
}
return EntityUtils.toByteArray(response.getEntity());
}
} catch (Exception e) {
throw new GeoServerException("Error executing WMS request", e);
}
}
public String executeRestRequest(String endpoint) throws GeoServerException {
try {
String url = config.getRestEndpoint() + endpoint;
HttpGet request = new HttpGet(url);
request.setHeader("Accept", "application/json");
try (CloseableHttpResponse response = httpClient.execute(request)) {
String responseBody = EntityUtils.toString(response.getEntity());
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode != 200) {
throw new GeoServerException("REST request failed: " + responseBody);
}
return responseBody;
}
} catch (Exception e) {
throw new GeoServerException("Error executing REST request", e);
}
}
private String buildWmsUrl(Map<String, String> params) {
StringBuilder urlBuilder = new StringBuilder(config.getWmsEndpoint());
urlBuilder.append("?service=WMS");
urlBuilder.append("&version=1.1.1"); // or 1.3.0
for (Map.Entry<String, String> entry : params.entrySet()) {
urlBuilder.append("&")
.append(entry.getKey())
.append("=")
.append(URLEncoder.encode(entry.getValue(), StandardCharsets.UTF_8));
}
return urlBuilder.toString();
}
}

Step 3: WMS Service Classes

Core WMS Service
@Service
@Slf4j
public class WmsService {
private final GeoServerHttpClient geoServerClient;
private final GeoServerConfig config;
public WmsService(GeoServerHttpClient geoServerClient, GeoServerConfig config) {
this.geoServerClient = geoServerClient;
this.config = config;
}
@Cacheable(value = "wmsMaps", key = "#request.hashCode()")
public byte[] getMap(WmsMapRequest request) throws GeoServerException {
try {
Map<String, String> params = buildGetMapParams(request);
return geoServerClient.executeWmsRequest(params);
} catch (Exception e) {
throw new GeoServerException("Error getting WMS map", e);
}
}
public WmsCapabilities getCapabilities() throws GeoServerException {
try {
Map<String, String> params = new HashMap<>();
params.put("request", "GetCapabilities");
params.put("service", "WMS");
// This would require XML parsing for full capabilities
// For simplicity, we'll use REST API for layer information
String restResponse = geoServerClient.executeRestRequest("/layers.json");
return parseCapabilitiesFromRest(restResponse);
} catch (Exception e) {
throw new GeoServerException("Error getting WMS capabilities", e);
}
}
public Map<String, String> getLayerInfo(String layerName) throws GeoServerException {
try {
String restResponse = geoServerClient.executeRestRequest(
"/workspaces/" + config.getWorkspace() + "/layers/" + layerName + ".json");
return parseLayerInfo(restResponse);
} catch (Exception e) {
throw new GeoServerException("Error getting layer info: " + layerName, e);
}
}
public List<WmsLayer> getAvailableLayers() throws GeoServerException {
try {
String restResponse = geoServerClient.executeRestRequest("/layers.json");
return parseLayersFromRest(restResponse);
} catch (Exception e) {
throw new GeoServerException("Error getting available layers", e);
}
}
public byte[] getLegendGraphic(String layerName, String style, int width, int height) 
throws GeoServerException {
try {
Map<String, String> params = new HashMap<>();
params.put("request", "GetLegendGraphic");
params.put("format", "image/png");
params.put("layer", config.getWorkspace() + ":" + layerName);
params.put("width", String.valueOf(width));
params.put("height", String.valueOf(height));
if (style != null) {
params.put("style", style);
}
return geoServerClient.executeWmsRequest(params);
} catch (Exception e) {
throw new GeoServerException("Error getting legend graphic", e);
}
}
public FeatureInfoResponse getFeatureInfo(FeatureInfoRequest request) throws GeoServerException {
try {
Map<String, String> params = buildFeatureInfoParams(request);
String response = new String(geoServerClient.executeWmsRequest(params));
return parseFeatureInfoResponse(response);
} catch (Exception e) {
throw new GeoServerException("Error getting feature info", e);
}
}
private Map<String, String> buildGetMapParams(WmsMapRequest request) {
Map<String, String> params = new HashMap<>();
params.put("request", "GetMap");
params.put("layers", String.join(",", request.getLayers()));
params.put("styles", String.join(",", request.getStyles()));
params.put("format", request.getFormat());
params.put("width", String.valueOf(request.getWidth()));
params.put("height", String.valueOf(request.getHeight()));
params.put("srs", request.getSrs());
params.put("bbox", request.getBbox());
params.put("transparent", request.isTransparent() ? "true" : "false");
if (request.getBgcolor() != null) {
params.put("bgcolor", request.getBgcolor());
}
if (request.getExceptions() != null) {
params.put("exceptions", request.getExceptions());
}
if (request.getTime() != null) {
params.put("time", request.getTime());
}
if (request.getElevation() != null) {
params.put("elevation", request.getElevation());
}
return params;
}
private Map<String, String> buildFeatureInfoParams(FeatureInfoRequest request) {
Map<String, String> params = buildGetMapParams(request.getMapRequest());
params.put("request", "GetFeatureInfo");
params.put("query_layers", String.join(",", request.getQueryLayers()));
params.put("info_format", request.getInfoFormat());
params.put("x", String.valueOf(request.getX()));
params.put("y", String.valueOf(request.getY()));
params.put("feature_count", String.valueOf(request.getFeatureCount()));
return params;
}
private WmsCapabilities parseCapabilitiesFromRest(String jsonResponse) throws Exception {
// Parse REST response to build capabilities object
JsonNode root = objectMapper.readTree(jsonResponse);
WmsCapabilities capabilities = new WmsCapabilities();
// Extract layer information from REST response
if (root.has("layers")) {
JsonNode layersNode = root.get("layers").get("layer");
List<WmsLayer> layers = new ArrayList<>();
for (JsonNode layerNode : layersNode) {
WmsLayer layer = new WmsLayer();
layer.setName(layerNode.get("name").asText());
layer.setTitle(layerNode.has("title") ? layerNode.get("title").asText() : "");
layer.setAbstract(layerNode.has("abstract") ? layerNode.get("abstract").asText() : "");
layers.add(layer);
}
capabilities.setLayers(layers);
}
return capabilities;
}
private List<WmsLayer> parseLayersFromRest(String jsonResponse) throws Exception {
JsonNode root = objectMapper.readTree(jsonResponse);
List<WmsLayer> layers = new ArrayList<>();
if (root.has("layers")) {
JsonNode layersNode = root.get("layers").get("layer");
for (JsonNode layerNode : layersNode) {
WmsLayer layer = new WmsLayer();
layer.setName(layerNode.get("name").asText());
layer.setTitle(layerNode.has("title") ? layerNode.get("title").asText() : "");
layer.setAbstract(layerNode.has("abstract") ? layerNode.get("abstract").asText() : "");
// Extract bounding box if available
if (layerNode.has("latlonBoundingBox")) {
JsonNode bboxNode = layerNode.get("latlonBoundingBox");
BoundingBox bbox = new BoundingBox(
bboxNode.get("minx").asDouble(),
bboxNode.get("miny").asDouble(),
bboxNode.get("maxx").asDouble(),
bboxNode.get("maxy").asDouble()
);
layer.setBoundingBox(bbox);
}
layers.add(layer);
}
}
return layers;
}
private FeatureInfoResponse parseFeatureInfoResponse(String xmlResponse) {
// Parse GML or other format feature info response
// This is a simplified implementation
FeatureInfoResponse response = new FeatureInfoResponse();
response.setRawResponse(xmlResponse);
response.setFeatures(parseFeaturesFromXml(xmlResponse));
return response;
}
private List<Map<String, Object>> parseFeaturesFromXml(String xml) {
// Implement XML parsing for feature information
// This would typically use JAXB or similar for GML parsing
return new ArrayList<>();
}
}
Advanced WMS Operations Service
@Service
public class AdvancedWmsService {
private final WmsService wmsService;
private final GeoServerConfig config;
public AdvancedWmsService(WmsService wmsService, GeoServerConfig config) {
this.wmsService = wmsService;
this.config = config;
}
public byte[] createTiledMap(TiledMapRequest request) throws GeoServerException {
List<byte[]> tileImages = new ArrayList<>();
for (Tile tile : request.getTiles()) {
WmsMapRequest wmsRequest = buildWmsRequestForTile(request, tile);
byte[] tileData = wmsService.getMap(wmsRequest);
tileImages.add(tileData);
}
return mergeTiles(tileImages, request.getGridLayout());
}
public byte[] createMultiLayerMap(MultiLayerMapRequest request) throws GeoServerException {
WmsMapRequest wmsRequest = new WmsMapRequest();
wmsRequest.setLayers(request.getLayerNames());
wmsRequest.setStyles(request.getStyles());
wmsRequest.setFormat(request.getFormat());
wmsRequest.setWidth(request.getWidth());
wmsRequest.setHeight(request.getHeight());
wmsRequest.setSrs(request.getSrs());
wmsRequest.setBbox(request.getBbox());
wmsRequest.setTransparent(true);
return wmsService.getMap(wmsRequest);
}
public Map<String, byte[]> batchGetMaps(List<WmsMapRequest> requests) throws GeoServerException {
Map<String, byte[]> results = new ConcurrentHashMap<>();
requests.parallelStream().forEach(request -> {
try {
byte[] mapData = wmsService.getMap(request);
results.put(request.getRequestId(), mapData);
} catch (GeoServerException e) {
log.error("Failed to get map for request: {}", request.getRequestId(), e);
}
});
return results;
}
public MapComparisonResult compareMaps(WmsMapRequest request1, WmsMapRequest request2) 
throws GeoServerException {
byte[] map1 = wmsService.getMap(request1);
byte[] map2 = wmsService.getMap(request2);
MapComparisonResult result = new MapComparisonResult();
result.setMap1Size(map1.length);
result.setMap2Size(map2.length);
result.setSizeDifference(Math.abs(map1.length - map2.length));
// Basic comparison - in practice, you'd use image processing libraries
result.setIdentical(Arrays.equals(map1, map2));
return result;
}
private WmsMapRequest buildWmsRequestForTile(TiledMapRequest baseRequest, Tile tile) {
WmsMapRequest wmsRequest = new WmsMapRequest();
wmsRequest.setLayers(baseRequest.getLayers());
wmsRequest.setStyles(baseRequest.getStyles());
wmsRequest.setFormat(baseRequest.getFormat());
wmsRequest.setWidth(tile.getWidth());
wmsRequest.setHeight(tile.getHeight());
wmsRequest.setSrs(baseRequest.getSrs());
wmsRequest.setBbox(tile.getBbox());
wmsRequest.setTransparent(baseRequest.isTransparent());
return wmsRequest;
}
private byte[] mergeTiles(List<byte[]> tileImages, GridLayout layout) {
// Implement tile merging logic
// This would typically use Java2D or image processing libraries
// For simplicity, return first tile
return tileImages.get(0);
}
}

Step 4: Data Models and DTOs

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class WmsMapRequest {
private String requestId = UUID.randomUUID().toString();
@NotEmpty
private List<String> layers;
private List<String> styles = Collections.emptyList();
@NotBlank
private String format = "image/png";
@Min(1)
@Max(4096)
private int width = 800;
@Min(1)
@Max(4096)
private int height = 600;
@NotBlank
private String srs = "EPSG:4326"; // or CRS:84 for WMS 1.3.0
@NotBlank
private String bbox; // "minx,miny,maxx,maxy"
private boolean transparent = true;
private String bgcolor;
private String exceptions = "application/vnd.ogc.se_xml";
private String time; // Time dimension
private String elevation; // Elevation dimension
// Helper methods
public void setBoundingBox(double minX, double minY, double maxX, double maxY) {
this.bbox = minX + "," + minY + "," + maxX + "," + maxY;
}
public BoundingBox getBoundingBox() {
if (bbox != null) {
String[] parts = bbox.split(",");
if (parts.length == 4) {
return new BoundingBox(
Double.parseDouble(parts[0]),
Double.parseDouble(parts[1]),
Double.parseDouble(parts[2]),
Double.parseDouble(parts[3])
);
}
}
return null;
}
}
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class FeatureInfoRequest {
private WmsMapRequest mapRequest;
@NotEmpty
private List<String> queryLayers;
@NotBlank
private String infoFormat = "text/xml"; // or "application/vnd.ogc.gml"
@Min(0)
private int x;
@Min(0)
private int y;
@Min(1)
private int featureCount = 10;
}
@Data
public class WmsCapabilities {
private String version;
private String service;
private List<WmsLayer> layers;
private List<String> formats;
private List<String> srsList;
}
@Data
public class WmsLayer {
private String name;
private String title;
private String abstract;
private List<String> styles;
private BoundingBox boundingBox;
private List<String> crs;
private boolean queryable;
private boolean opaque;
private String attribution;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class BoundingBox {
private double minX;
private double minY;
private double maxX;
private double maxY;
public String toString() {
return minX + "," + minY + "," + maxX + "," + maxY;
}
public double getWidth() {
return maxX - minX;
}
public double getHeight() {
return maxY - minY;
}
}
@Data
public class FeatureInfoResponse {
private String rawResponse;
private List<Map<String, Object>> features;
private int featureCount;
}
@Data
public class TiledMapRequest {
private List<String> layers;
private List<String> styles;
private String format = "image/png";
private String srs = "EPSG:4326";
private boolean transparent = true;
private GridLayout gridLayout;
private List<Tile> tiles;
}
@Data
public class Tile {
private int row;
private int column;
private int width = 256;
private int height = 256;
private String bbox;
}
@Data
public class GridLayout {
private int rows;
private int columns;
private double tileWidth; // in geographic units
private double tileHeight; // in geographic units
}
@Data
public class MapComparisonResult {
private int map1Size;
private int map2Size;
private int sizeDifference;
private boolean identical;
private double similarityScore;
}

Step 5: REST API Controllers

@RestController
@RequestMapping("/api/wms")
@Validated
@Slf4j
public class WmsController {
@Autowired
private WmsService wmsService;
@Autowired
private AdvancedWmsService advancedWmsService;
@PostMapping("/map")
public ResponseEntity<?> getMap(@Valid @RequestBody WmsMapRequest request) {
try {
byte[] mapImage = wmsService.getMap(request);
// Determine content type from format
String contentType = getContentType(request.getFormat());
return ResponseEntity.ok()
.contentType(MediaType.parseMediaType(contentType))
.header("Content-Disposition", "inline; filename=\"map." + getFileExtension(request.getFormat()) + "\"")
.body(mapImage);
} catch (GeoServerException e) {
log.error("Error generating WMS map", e);
return ResponseEntity.badRequest().body(new ErrorResponse("MAP_GENERATION_ERROR", e.getMessage()));
}
}
@GetMapping("/capabilities")
public ResponseEntity<?> getCapabilities() {
try {
WmsCapabilities capabilities = wmsService.getCapabilities();
return ResponseEntity.ok(capabilities);
} catch (GeoServerException e) {
return ResponseEntity.badRequest().body(new ErrorResponse("CAPABILITIES_ERROR", e.getMessage()));
}
}
@GetMapping("/layers")
public ResponseEntity<?> getLayers() {
try {
List<WmsLayer> layers = wmsService.getAvailableLayers();
return ResponseEntity.ok(layers);
} catch (GeoServerException e) {
return ResponseEntity.badRequest().body(new ErrorResponse("LAYERS_ERROR", e.getMessage()));
}
}
@GetMapping("/legend/{layerName}")
public ResponseEntity<?> getLegend(
@PathVariable String layerName,
@RequestParam(defaultValue = "16") int width,
@RequestParam(defaultValue = "16") int height,
@RequestParam(required = false) String style) {
try {
byte[] legend = wmsService.getLegendGraphic(layerName, style, width, height);
return ResponseEntity.ok()
.contentType(MediaType.IMAGE_PNG)
.body(legend);
} catch (GeoServerException e) {
return ResponseEntity.badRequest().body(new ErrorResponse("LEGEND_ERROR", e.getMessage()));
}
}
@PostMapping("/feature-info")
public ResponseEntity<?> getFeatureInfo(@Valid @RequestBody FeatureInfoRequest request) {
try {
FeatureInfoResponse response = wmsService.getFeatureInfo(request);
return ResponseEntity.ok(response);
} catch (GeoServerException e) {
return ResponseEntity.badRequest().body(new ErrorResponse("FEATURE_INFO_ERROR", e.getMessage()));
}
}
@PostMapping("/map/batch")
public ResponseEntity<?> batchGetMaps(@Valid @RequestBody List<WmsMapRequest> requests) {
try {
Map<String, byte[]> results = advancedWmsService.batchGetMaps(requests);
return ResponseEntity.ok(results);
} catch (GeoServerException e) {
return ResponseEntity.badRequest().body(new ErrorResponse("BATCH_MAP_ERROR", e.getMessage()));
}
}
@PostMapping("/map/compare")
public ResponseEntity<?> compareMaps(@Valid @RequestBody MapComparisonRequest request) {
try {
MapComparisonResult result = advancedWmsService.compareMaps(
request.getRequest1(), request.getRequest2());
return ResponseEntity.ok(result);
} catch (GeoServerException e) {
return ResponseEntity.badRequest().body(new ErrorResponse("COMPARISON_ERROR", e.getMessage()));
}
}
// Helper methods
private String getContentType(String format) {
switch (format.toLowerCase()) {
case "image/png": return "image/png";
case "image/jpeg": return "image/jpeg";
case "image/gif": return "image/gif";
case "image/svg+xml": return "image/svg+xml";
case "application/pdf": return "application/pdf";
default: return "image/png";
}
}
private String getFileExtension(String format) {
switch (format.toLowerCase()) {
case "image/png": return "png";
case "image/jpeg": return "jpg";
case "image/gif": return "gif";
case "image/svg+xml": return "svg";
case "application/pdf": return "pdf";
default: return "png";
}
}
}
@Data
class MapComparisonRequest {
@Valid
private WmsMapRequest request1;
@Valid
private WmsMapRequest request2;
}
@Data
@AllArgsConstructor
class ErrorResponse {
private String errorCode;
private String message;
private LocalDateTime timestamp;
public ErrorResponse(String errorCode, String message) {
this.errorCode = errorCode;
this.message = message;
this.timestamp = LocalDateTime.now();
}
}

Step 6: Caching Configuration

@Configuration
@EnableCaching
public class CacheConfig {
@Bean
public CacheManager cacheManager(GeoServerConfig geoServerConfig) {
CaffeineCacheManager cacheManager = new CaffeineCacheManager();
cacheManager.setCaffeine(Caffeine.newBuilder()
.expireAfterWrite(geoServerConfig.getCacheExpiryMinutes(), TimeUnit.MINUTES)
.maximumSize(geoServerConfig.getCacheSize())
.recordStats());
return cacheManager;
}
}
@Service
public class WmsCacheService {
@CacheEvict(value = "wmsMaps", allEntries = true)
public void clearMapCache() {
log.info("Cleared WMS map cache");
}
@CacheEvict(value = "wmsMaps", key = "#request.hashCode()")
public void evictMapCache(WmsMapRequest request) {
log.debug("Evicted cache for map request: {}", request.getRequestId());
}
}

Step 7: Exception Handling

public class GeoServerException extends Exception {
public GeoServerException(String message) {
super(message);
}
public GeoServerException(String message, Throwable cause) {
super(message, cause);
}
}
@ControllerAdvice
public class GeoServerExceptionHandler {
@ExceptionHandler(GeoServerException.class)
public ResponseEntity<ErrorResponse> handleGeoServerException(GeoServerException ex) {
ErrorResponse error = new ErrorResponse("GEOSERVER_ERROR", ex.getMessage());
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(error);
}
@ExceptionHandler(ConstraintViolationException.class)
public ResponseEntity<ErrorResponse> handleValidationException(ConstraintViolationException ex) {
String message = ex.getConstraintViolations().stream()
.map(ConstraintViolation::getMessage)
.collect(Collectors.joining(", "));
ErrorResponse error = new ErrorResponse("VALIDATION_ERROR", message);
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(error);
}
}

Step 8: Configuration File

application.yml:

geoserver:
base-url: "http://localhost:8080/geoserver"
username: ${GEOSERVER_USERNAME:admin}
password: ${GEOSERVER_PASSWORD:geoserver}
workspace: "myworkspace"
timeout: 30000
cache-enabled: true
cache-size: 1000
cache-expiry-minutes: 60
spring:
cache:
type: caffeine
logging:
level:
com.yourcompany.geoserver: DEBUG

Step 9: Usage Examples

@Service
public class WmsExampleService {
@Autowired
private WmsService wmsService;
public void demonstrateUsage() {
try {
// Create a basic map request
WmsMapRequest request = WmsMapRequest.builder()
.layers(List.of("roads", "buildings"))
.format("image/png")
.width(800)
.height(600)
.srs("EPSG:4326")
.transparent(true)
.build();
request.setBoundingBox(-180, -90, 180, 90); // Worldwide
// Get map image
byte[] mapImage = wmsService.getMap(request);
// Get layer information
List<WmsLayer> layers = wmsService.getAvailableLayers();
// Get legend graphic
byte[] legend = wmsService.getLegendGraphic("roads", null, 32, 32);
} catch (GeoServerException e) {
// Handle exception
}
}
}

Key WMS Operations Supported

  1. GetMap: Generate map images with specified layers and styles
  2. GetCapabilities: Discover available layers and services
  3. GetFeatureInfo: Query feature information at specific locations
  4. GetLegendGraphic: Generate legend images for layers
  5. Batch Operations: Process multiple map requests efficiently
  6. Tiled Maps: Create and merge map tiles
  7. Map Comparison: Compare different map configurations

Best Practices

  1. Caching: Cache map images to reduce server load
  2. Error Handling: Comprehensive error handling for WMS failures
  3. Parameter Validation: Validate all WMS request parameters
  4. Connection Pooling: Use HTTP connection pooling for performance
  5. Authentication: Secure GeoServer credentials
  6. Format Selection: Choose appropriate image formats (PNG for transparency, JPEG for photos)
  7. Bounding Box Optimization: Use appropriate bounding boxes for your use case

This comprehensive GeoServer WMS integration provides a robust foundation for building mapping applications in Java, enabling dynamic map generation, spatial data visualization, and advanced WMS operations.

Leave a Reply

Your email address will not be published. Required fields are marked *


Macro Nepal Helper