У меня есть проект Spring Boot, который использует Google Maps JavaScript API
и Google Places API
для получения информации о следах в зависимости от местоположения. Я пытаюсь отобразить список событий, а также список трасс на карте, так как оба имеют местоположение. Класс EventDTO выглядит следующим образом:
package com.trailfinder.dto;
import java.io.Serializable;
import java.time.LocalDateTime;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Transient;
/**
* @author LookItsCashew
* DTO for Events posted on application
*/
@SuppressWarnings("serial")
@Entity
@Table(name="events")
public class EventDTO implements Serializable {
@Id
@GeneratedValue
@Column(name="EventID")
private int eventId;
@Column(name="Distance")
private double distance;
@Column(name="EventStart")
private LocalDateTime eventStart;
@Column(name="EventEnd")
private LocalDateTime eventEnd;
@Column(name="Latitude")
private String Latitude;
@Column(name="Longitude")
private String Longitude;
@Transient
private EventCreatorDTO eventCreator;
/**
* Create and initialize a new instance of the EventDTO
*
* @param eventId
* @param distance
* @param eventStart
* @param eventEnd
* @param latitude
* @param longitude
* @param eventCreator
*/
public EventDTO(double distance, LocalDateTime eventStart, LocalDateTime eventEnd, String latitude,
String longitude, EventCreatorDTO eventCreator)
{
this.distance = distance;
this.eventStart = eventStart;
this.eventEnd = eventEnd;
this.Latitude = latitude;
this.Longitude = longitude;
this.eventCreator = eventCreator;
}
/**
* Create an instance of EventDTO
*/
public EventDTO() {
}
/**
* @return the eventId
*/
public int getEventId() {
return eventId;
}
/**
* @param eventId the eventId to set
*/
public void setEventId(int eventId) {
this.eventId = eventId;
}
/**
* @return the distance
*/
public double getDistance() {
return distance;
}
/**
* @param distance the distance to set
*/
public void setDistance(double distance) {
this.distance = distance;
}
/**
* @return the eventStart
*/
public LocalDateTime getEventStart() {
return eventStart;
}
/**
* @param eventStart the eventStart to set
*/
public void setEventStart(LocalDateTime eventStart) {
this.eventStart = eventStart;
}
/**
* @return the eventEnd
*/
public LocalDateTime getEventEnd() {
return eventEnd;
}
/**
* @param eventEnd the eventEnd to set
*/
public void setEventEnd(LocalDateTime eventEnd) {
this.eventEnd = eventEnd;
}
/**
* @return the latitude
*/
public String getLatitude() {
return Latitude;
}
/**
* @param latitude the latitude to set
*/
public void setLatitude(String latitude) {
Latitude = latitude;
}
/**
* @return the longitude
*/
public String getLongitude() {
return Longitude;
}
/**
* @param longitude the longitude to set
*/
public void setLongitude(String longitude) {
Longitude = longitude;
}
/**
* @return the eventCreator
*/
public EventCreatorDTO getEventCreator() {
return eventCreator;
}
/**
* @param eventCreator the eventCreator to set
*/
public void setEventCreator(EventCreatorDTO eventCreator) {
this.eventCreator = eventCreator;
}
public String toString() {
return eventCreator.getCreatorFirstName() + "'s hiking event";
}
}
И мой TrailDTO выглядит примерно так:
package com.trailfinder.dto;
/**
* @author LookItsCashew
* Represents a trail Place that is nearby from Google Places library
* Will be separate entities from Events, which are user created and custom
*/
public class TrailDTO {
// Private fields
private String id;
private String placeId;
private String name;
private double latitude;
private double longitude;
//Adds an interesting bit to the trail
private String hotSpot;
/**
* @return the id
*/
public String getId() {
return id;
}
/**
* @param id the id to set
*/
public void setId(String id) {
this.id = id;
}
/**
* @return the placeId
*/
public String getPlaceId() {
return placeId;
}
/**
* @param placeId the placeId to set
*/
public void setPlaceId(String placeId) {
this.placeId = placeId;
}
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @param name the name to set
*/
public void setName(String name) {
this.name = name;
}
/**
* @return the latitude
*/
public double getLatitude() {
return latitude;
}
/**
* @param latitude the latitude to set
*/
public void setLatitude(double latitude) {
this.latitude = latitude;
}
/**
* @return the longitude
*/
public double getLongitude() {
return longitude;
}
/**
* @param longitude the longitude to set
*/
public void setLongitude(double longitude) {
this.longitude = longitude;
}
public String gethotSpot(){
return hotSpot;
}
public String sedhotSpot(String hotSpot){
return hotSpot;
}
}
Моя страница указателя - это то место, где карта живет и использует JQuery
для запроса List
трасс и событий от контроллера как JSON
, которые затем будут повторяться и создаваться маркеры там, где находятся TrailDTO
местоположения, и то же самое для событий. Мой контроллер пропускает List
следов или событий, и только следы отображаются на карте. Вот мой Controller
:
package com.trailfinder;
import java.util.ArrayList;
import java.util.List;
import org.json.JSONArray;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import com.trailfinder.dto.EventAttendeeDTO;
import com.trailfinder.dto.EventDTO;
import com.trailfinder.dto.TrailDTO;
import com.trailfinder.service.IHikeService;
/**
* @author LookItsCashew
* Controller for the TrailFinder UI layer
*/
@Controller
public class TrailFinderController {
@Autowired
private IHikeService hikeService;
/**
* Handles return of home screen view and index end point
* @return index
*/
@RequestMapping("/index")
public String index() {
return "index";
}
/**
* Handles return of home screen view and / end point
* @return index
* @throws Exception
*/
@RequestMapping(value="/", method=RequestMethod.GET)
public String base(Model model) {
Iterable<EventDTO> events = null;
try {
events = hikeService.getEvents();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
model.addAttribute("events", events);
return "index";
}
@RequestMapping(value="/Event", method=RequestMethod.GET)
public String evt(@RequestParam(value="eventId") int eventId, Model model) {
EventDTO eventDTO;
List<EventAttendeeDTO> attendees=null;
try {
eventDTO = hikeService.fetchEventById(eventId);
attendees = hikeService.getAttendees(eventDTO);
model.addAttribute("event", eventDTO);
model.addAttribute("attendees", attendees);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return "eventdetails";
}
@RequestMapping(value="/Event/Attend", method=RequestMethod.POST)
public String attendEvent(@RequestParam(value="eventId", required=true) int eventId, EventAttendeeDTO attendee, Model model) {
boolean isEventAttended;
try {
// fetch the event user is attending
EventDTO eventAttending = hikeService.fetchEventById(attendee.getEventId());
attendee.setEvent(eventAttending);
// Persist the attendee
isEventAttended = hikeService.attendEvent(attendee);
if (isEventAttended) {
model.addAttribute("event", eventAttending);
return "eventdetails";
}
} catch (Exception e) {
e.printStackTrace();
}
return "index";
}
@RequestMapping(value="/profile", method=RequestMethod.GET)
public String prof(Model model) {
//ProfileDTO profile = hikeService.getProfile(0);
//model.addAttribute("ProfileDTO", profile);
return "profile";
}
/**
* Needs to return the JSON of all trails from Google Places
* @param lat the latitiude of the user's current location
* @param lng the longitude of the user's current location
* @return trails the trails to be returned to the view
*/
@RequestMapping(value="/fetchTrailList", method=RequestMethod.GET, produces = "application/json; charset=UTF-8")
@ResponseBody
public List<TrailDTO> fetchTrailList(@RequestParam(value="lat") double lat, @RequestParam(value="lng") double lng) {
// List of trails to return
List<TrailDTO> trails = new ArrayList<>();
try {
trails = hikeService.getNearbyTrails(lat, lng);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return trails;
}
/**
* Needs to return the JSON of all events from persistence
* @return events the events to be returned to the view
*/
@RequestMapping(value="/getEventsJSON", method=RequestMethod.GET, produces = "application/json; charset=UTF-8")
@ResponseBody
public List<EventDTO> getEventsJSON() {
// List of trails to return
List<EventDTO> events = new ArrayList<>();
try {
events = (List<EventDTO>) hikeService.getEvents();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return events;
}
}
Вот мой index.html
:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="ISO-8859-1"/>
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css">
<!-- jQuery library -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<!-- Popper JS -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.16.0/umd/popper.min.js"></script>
<!-- Latest compiled JavaScript -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js"></script>
<style>
/* Set the size of the div element that contains the map */
#map {
height: 400px; /* The height is 400 pixels */
width: 100%; /* The width is the width of the web page */
}
</style>
<title>TrailFinder | Home</title>
</head>
<body>
<div id="main" class="container">
<div th:replace = "fragments/headbar :: navbar"></div>
<br>
<div id="content">
<div class="row">
<div class="col-lg-8">
<div id="map" class="container container-fluid">
</div>
</div>
<div class="col-lg-4">
<h3>Events Near You</h3>
<!--list event attributes here -->
<div class="list-group list-group-action" th:each="event : ${events}">
<a th:href="@{/Event(eventId=${event.eventId})}" class="list-group-item">
<p th:text="${event}"/>
</a>
</div>
</div>
</div>
</div>
</div>
<script>
function initMap() {
var map;
var trailMarker = {
path: 'M0-48c-9.8 0-17.7 7.8-17.7 17.4 0 15.5 17.7 30.6 17.7 30.6s17.7-15.4 17.7-30.6c0-9.6-7.9-17.4-17.7-17.4z',
fillColor: '#019730',
fillOpacity: 0.95,
scale: 0.8,
strokeColor: '#01AD37',
strokeWeight: 0.5
};
//Geolocation
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(function(position) {
var pos = {
lat: position.coords.latitude,
lng: position.coords.longitude
};
// Map options
var options = {
zoom:12,
center:pos
}
// The map, centered at current location
map = new google.maps.Map(
document.getElementById('map'), options);
var infoWindow = new google.maps.InfoWindow;
infoWindow.setPosition(pos);
infoWindow.setContent('You are here!');
infoWindow.open(map);
//map.setCenter(pos); // center map to user cordinates
// Creates trails in map
createTrails(pos);
}, function() {
handleLocationError(true, infoWindow, map.getCenter());
});
} else {
// Browser doesn't support Geolocation
handleLocationError(false, infoWindow, map.getCenter());
}
createEventsInMap();
function handleLocationError(browserHasGeolocation, infoWindow, pos) {
infoWindow.setPosition(pos);
infoWindow.setContent(browserHasGeolocation ?
'Error: The Geolocation service failed.' :
'Error: Your browser doesn\'t support geolocation.');
infoWindow.open(map);
}
function createTrails(pos) {
$.getJSON("/fetchTrailList", { lat: pos.lat, lng: pos.lng }, function (data) {
$.each(data, function (key, value) {
//console.log(data[key]);
var infoWindow = new google.maps.InfoWindow;
var marker = new google.maps.Marker({position: {lat: value.latitude, lng: value.longitude}, map: map, icon: trailMarker});
infoWindow.setPosition({ lat: value.latitude, lng: value.longitude });
infoWindow.setContent('<h3>' + value.name + '</h3>' + '<p>Coords: ' + value.latitude + ', '
+ value.longitude + '</p>' + '<a href="#"><p>Create Event...</p></a>');
marker.addListener('click', function() {
infoWindow.open(map, marker);
});
});
});
}
function createEventsInMap() {
$.getJSON("/getEventsJSON", function (data) {
$.each(data, function (key, value) {
console.log(data[key]);
var infoWindow = new google.maps.InfoWindow;
var marker = new google.maps.Marker({position: {lat: value.Latitude, lng: value.Longitude}, map: map});
infoWindow.setPosition({ lat: value.Latitude, lng: value.Longitude });
infoWindow.setContent('<h3>' + value.eventCreator.creatorFirstName + '</h3>'
+ '<p>Distance: ' + value.distance + ' km' + '</p>' + '<a href="@{/Event(eventId=' + value.eventId + '}"><p>View Event</p></a>');
marker.addListener('click', function() {
infoWindow.open(map, marker);
});
});
});
}
}
</script>
<script async="true" defer
src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCmC6Uco6nl8sRYwKBa8Xnjll3olfbYGKM&callback=initMap">
</script>
</body>
</html>
Обе функции для возврата JSON
почти идентичны по структуре, но отправляют разные типы Lists
вернуться на страницу index.html
. Не знаете, почему один тип списка работает, а другой нет? Любые ответы или помощь будут оценены.