Server Integration — Java / Spring Boot
Spring Boot with io.pickpoint:pickpoint (jvm-sdk) — exposes PickPoint to your frontend. The API key lives in an environment variable and never reaches the client.
1
Dependencies (Maven)
<!-- pom.xml -->
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<dependency>
<groupId>io.pickpoint</groupId>
<artifactId>pickpoint</artifactId>
<version>2.0.0</version>
</dependency>
</dependencies>2
Configuration and SDK client bean
# application.properties
pickpoint.key=${PICKPOINT_KEY} # loaded from env var// PickPointConfig.java
import io.pickpoint.Client;
import io.pickpoint.Config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class PickPointConfig {
@Bean
public Client pickpointClient(@Value("${pickpoint.key}") String key) {
return Client.create(Config.builder().apiKey(key).build());
}
}3
Geocoding controller
// GeocodingController.java
import io.pickpoint.Client;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.Map;
@RestController
@RequestMapping("/geo")
public class GeocodingController {
private final Client pp;
public GeocodingController(Client pp) { this.pp = pp; }
// GET /geo/forward?q=Eiffel+Tower&limit=5
@GetMapping("/forward")
public Object forward(@RequestParam String q,
@RequestParam(defaultValue = "5") int limit,
@RequestParam(required = false) String countrycodes,
@RequestParam(required = false) String viewbox) {
Map<String, String> params = new HashMap<>();
params.put("q", q);
params.put("limit", String.valueOf(limit));
if (countrycodes != null) params.put("countrycodes", countrycodes);
if (viewbox != null) params.put("viewbox", viewbox);
return pp.forward(params);
}
// GET /geo/reverse?lat=48.85&lon=2.29&zoom=18
@GetMapping("/reverse")
public Object reverse(@RequestParam double lat,
@RequestParam double lon,
@RequestParam(defaultValue = "18") int zoom) {
return pp.reverse(Map.of(
"lat", String.valueOf(lat),
"lon", String.valueOf(lon),
"zoom", String.valueOf(zoom)
));
}
// GET /geo/search?q=Baker+St&viewbox=…
@GetMapping("/search")
public Object search(@RequestParam String q,
@RequestParam(required = false) String viewbox,
@RequestParam(defaultValue = "6") int limit) {
Map<String, String> params = new HashMap<>();
params.put("q", q);
params.put("limit", String.valueOf(limit));
if (viewbox != null) params.put("viewbox", viewbox);
return pp.search(params);
}
}4
Routing controller
// RoutingController.java
import io.pickpoint.Client;
import org.springframework.web.bind.annotation.*;
import java.util.Map;
@RestController
public class RoutingController {
private final Client pp;
public RoutingController(Client pp) { this.pp = pp; }
@PostMapping("/route")
public Object route(@RequestBody Map<String, Object> body) {
return pp.route(body);
}
@PostMapping("/route/optimized")
public Object routeOptimized(@RequestBody Map<String, Object> body) {
return pp.optimizedRoute(body);
}
}5
Device tracking - REST
// DeviceController.java
import io.pickpoint.Client;
import io.pickpoint.DeviceListQuery;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/devices")
public class DeviceController {
private final Client pp;
public DeviceController(Client pp) { this.pp = pp; }
@GetMapping
public Object list() {
return pp.getDevices().list(new DeviceListQuery());
}
}6
Device tracking - WebSocket relay
Mint a client token with mintClientTokens, subscribe with TrackingClient, fan out onLocation events to the browser session:
// TrackingRelayHandler.java — WebSocket subscriber relay
import io.pickpoint.MintKt;
import io.pickpoint.tracking.ListenerAuth;
import io.pickpoint.tracking.TrackingClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;
import java.util.List;
@Component
public class TrackingRelayHandler extends TextWebSocketHandler {
@Value("${pickpoint.key}")
private String apiKey;
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
String deviceUid = session.getUri().getQuery().split("deviceUid=")[1].split("&")[0];
var pair = MintKt.mintClientTokens(
io.pickpoint.Config.builder().apiKey(apiKey).build(),
List.of("devices"),
600L
);
var cfg = io.pickpoint.tracking.Config.builder()
.endpoint("wss://tracking.pickpoint.io")
.listener(ListenerAuth.builder().accessToken(pair.getAccessToken()).build())
.subscribe(List.of(deviceUid))
.build();
TrackingClient tracking = TrackingClient.connect(cfg);
tracking.onLocation(loc -> {
try {
var p = loc.getPoint();
session.sendMessage(new TextMessage(
"{\"lat\":" + p.getLatitude() + ",\"lon\":" + p.getLongitude() + "}"
));
} catch (Exception ignored) {}
});
}
}