代码之家  ›  专栏  ›  技术社区  ›  Jonathan Allen

如何将Salesforce与Google地图集成?

  •  5
  • Jonathan Allen  · 技术社区  · 14 年前

    1. 在谷歌地图上画出来。
    3 回复  |  直到 14 年前
        1
  •  11
  •   Community CDub    7 年前

    编辑 :

    感谢 tggagne

    与此同时,创建了更多的mashup示例。其中最重要的一个是“SF总线雷达”( github youtube

    尽管如此,下面是我的更新示例,包括服务器端地理编码、类型地理位置的新字段和JSON解析器的使用。

    它尝试在联系人记录中缓存地理编码结果。请记住,它可能不是“生产就绪”(没有googlebusinessapi key=因为我们所有的请求都来自同一个Salesforce IP服务器池 there might be error messages


    在签出之前,您需要在环境中进行2项更改:

    1. “添加” Remote Site Setting “这说明 https://maps.googleapis.com
    2. 在设置中添加字段“位置”->自定义->联系人->领域。类型应为“地理位置”。我选择显示为小数和精度为6位小数。

      public with sharing class mapController {
      public String searchText {get;set;}
      public List<Contact> contacts{get; private set;}
      
      public static final String GEOCODING_URI_BASE = 'https://maps.googleapis.com/maps/api/geocode/json?sensor=false&address=';
      
      // For purposes of this demo I'll geocode only couple of addresses server-side. Real code can use the commented out value.
      public static final Integer MAX_CALLOUTS_FROM_APEX = 3; // Limits.getLimitCallouts()
      
      public mapController(){
          searchText = ApexPages.currentPage().getParameters().get('q');
      }
      
      public void find() {
          if(searchText != null && searchText.length() > 1){
              List<List<SObject>> results = [FIND :('*' + searchText + '*') IN ALL FIELDS RETURNING 
                  Contact (Id, Name, Email, Account.Name,
                      MailingStreet, MailingCity, MailingPostalCode, MailingState, MailingCountry, 
                      Location__Latitude__s, Location__Longitude__s)
                  ];
              contacts = (List<Contact>)results[0];
              if(contacts.isEmpty()){
                  ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.INFO, 'No matches for "' + searchText + '"'));
              } else {
                  serverSideGeocode();
              }
          } else {
              if(contacts != null) {
                  contacts.clear();
              }
              ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.INFO, 'Please provide at least 2 characters for the search.'));
          }
      }
      
      public void clearGeocodedData(){
          for(Contact c : contacts){
              c.Location__Latitude__s = c.Location__Longitude__s = null;
          }
          Database.update(contacts, false);
          contacts.clear();
      }
      
      public String getContactsJson(){
          return JSON.serialize(contacts);
      }
      public String getDebugContactsJson(){
          return JSON.serializePretty(contacts);
      }
      
      private void serverSideGeocode(){
          List<Contact> contactsToUpdate = new List<Contact>();
          Http h = new Http();  
          HttpRequest req = new HttpRequest();
          req.setMethod('GET'); 
          req.setTimeout(10000);
      
          for(Contact c : contacts){
              if((c.Location__Latitude__s == null || c.Location__Longitude__s == null)){
                  String address = c.MailingStreet != null ? c.MailingStreet + ' ' : '' +
                      c.MailingCity != null ? c.MailingCity + ' ' : '' +
                      c.MailingState != null ? c.MailingState + ' ' : '' +
                      c.MailingPostalCode != null ? c.MailingPostalCode + ' ' : '' +
                      c.MailingCountry != null ? c.MailingCountry : '';
                  if(address != ''){
                      req.setEndpoint(GEOCODING_URI_BASE + EncodingUtil.urlEncode(address, 'UTF-8'));
                      try{
                          HttpResponse res = h.send(req);
                          GResponse gr = (GResponse) JSON.deserialize(res.getBody(), mapController.GResponse.class);
                          if(gr.status == 'OK'){
                              LatLng ll = gr.results[0].geometry.location;
                              c.Location__Latitude__s = ll.lat;
                              c.Location__Longitude__s = ll.lng;
                              contactsToUpdate.add(c);
                          } else {
                              ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.ERROR, 'Geocoding of "' + address + '" failed:' + gr.status));
                          }
                      }catch(Exception e){
                          ApexPages.addMessages(e);
                      }
                  }
                  // Bail out if we've reached limit of callouts (not all contacts might have been processed).
                  if(Limits.getCallouts() == MAX_CALLOUTS_FROM_APEX) {
                      break;
                  }
              }
          }
          if(!contactsToUpdate.isEmpty()) {
              Database.update(contactsToUpdate, false); // some data in Developer editions is invalid (on purpose I think).
              // If update fails because "j.davis@expressl&amp;t.net" is not a valid Email, I want the rest to succeed
          }
      }
      
      // Helper class - template into which results of lookup will be parsed. Some fields are skipped!
      // Visit https://developers.google.com/maps/documentation/geocoding/#Results if you need to create full mapping.
      public class GResponse{
          public String status;
          public GComponents[] results;
      }
      public class GComponents{
         public String formatted_address;
         public GGeometry geometry;
      }
      public class GGeometry {
          public LatLng location;
      }
      public class LatLng{
          public Double lat, lng;
      }
      }
      

    <apex:page controller="mapController" tabStyle="Contact" action="{!find}" id="page">
        <head>
            <style>
                div #map_canvas { height: 400px; }
            </style>
            <script type="text/javascript" src="https://maps.googleapis.com/maps/api/js?sensor=false"></script>
        </head>
        <apex:sectionHeader title="Hello StackOverflow!" subtitle="Contact full text search + Google Maps integration" />
        <apex:pageMessages />
        <apex:form id="form">
            <apex:pageBlock id="searchBlock">
                <apex:inputText value="{!searchText}" />
                <apex:commandButton value="Search" action="{!find}"/>
                <p>Examples: <a href="/apex/{!$CurrentPage.Name}?q=USA">"USA"</a>, "Singapore", "Uni", "(336) 222-7000". If it works in the global search box, it will work here.</p>
            </apex:pageBlock>
            <apex:pageBlock title="Found {!contacts.size} Contact(s)..." rendered="{!NOT(ISNULL(contacts)) && contacts.size > 0}" id="resultsBlock">
                <apex:pageBlockButtons location="top">
                    <apex:commandButton value="Clear cached locations" title="Click if you want to set 'null' as geolocation info for all these contacts" action="{!clearGeocodedData}" />
                </apex:pageBlockButtons>
                <apex:pageBlockTable value="{!contacts}" var="c" id="contacts">
                    <apex:column headerValue="{!$ObjectType.Contact.fields.Name.label}">
                        <apex:outputLink value="../{!c.Id}">{!c.Name}</apex:outputLink>
                    </apex:column>
                    <apex:column headerValue="Address">
                        {!c.MailingStreet} {!c.MailingCity} {!c.MailingCountry}
                    </apex:column>
                    <apex:column value="{!c.Account.Name}"/>
                    <apex:column headerValue="Location (retrieved from DB or geocoded server-side)">
                        {!c.Location__Latitude__s}, {!c.Location__Longitude__s}
                    </apex:column>
                </apex:pageBlockTable>
                <apex:pageBlockSection columns="1" id="mapSection">
                    <div id="map_canvas" />
                </apex:pageBlockSection>
                <apex:pageBlockSection title="Click to show/hide what was geocoded server-side and passed to JS for further manipulation" columns="1" id="debugSection">
                    <pre>{!debugContactsJson}</pre>
                </apex:pageBlockSection>
                <pre id="log"></pre>
            </apex:pageBlock>
        </apex:form>
        <script type="text/javascript">
        twistSection(document.getElementById('page:form:resultsBlock:debugSection').childNodes[0].childNodes[0]); // initially hide the debug section
    
        var contacts = {!contactsJson};    // Array of contact data, some of them might have lat/long info, some we'll have to geocode client side
        var coords = [];                   // Just the latitude/longitude for each contact
        var requestCounter = 0;
    
        var markers = [];                  // Red things we pin to the map.
        var balloon = new google.maps.InfoWindow(); // Comic-like baloon that floats over markers.
    
        function geocodeClientSide() {
            for(var i = 0; i < contacts.length; i++) {
                if(contacts[i].Location__Latitude__s != null && contacts[i].Location__Longitude__s != null) {
                    coords.push(new google.maps.LatLng(contacts[i].Location__Latitude__s, contacts[i].Location__Longitude__s));
                } else {
                    ++requestCounter;
                    var address = contacts[i].MailingStreet + ' ' + contacts[i].MailingCity + ' ' + contacts[i].MailingCountry;
                    var geocoder = new google.maps.Geocoder();
                    if (geocoder) {
                        geocoder.geocode({'address':address}, function (results, status) {
                            if (status == google.maps.GeocoderStatus.OK) {
                                coords.push(results[0].geometry.location);
                            } else {
                                var pTag = document.createElement("p");
                                pTag.innerHTML = status;
                                document.getElementById('log').appendChild(pTag);
                            }
                            if(--requestCounter == 0) {
                                drawMap();
                            }
                        });
                    }
                }
            }
            // It could be the case that all was geocoded on server side (or simply retrieved from database).
            // So if we're lucky - just proceed to drawing the map.
            if(requestCounter == 0) {
                drawMap();
            }
        }
    
        function drawMap(){
            var mapOptions = {
                center: coords[0],
                zoom: 3,
                mapTypeId: google.maps.MapTypeId.ROADMAP
            };
            var map = new google.maps.Map(document.getElementById("map_canvas"),  mapOptions);
    
            for(var i = 0; i < coords.length; ++i){
                var marker = new google.maps.Marker({map: map, position: coords[i], title:contacts[i].Name, zIndex:i});
    
                google.maps.event.addListener(marker, 'click', function() {
                    var index = this.zIndex;
                    balloon.content = '<b>'+contacts[index].Name + '</b><br/>' + contacts[index].Account.Name + '<br/>' + contacts[index].Email;
                    balloon.open(map,this);
                });
                markers.push(marker);
            }
        }
    
        geocodeClientSide();
        </script>
    </apex:page>
    
        2
  •  1
  •   SnapShot    13 年前

    另一个地方是force.com平台的基础知识 book site 如果您没有开发人员帐户)。他们有一个非常好和详细的教程 here 展示如何将地图与Salesforce集成(他们使用Yahoo作为教程,但它与Google地图同样适用)。

        3
  •  1
  •   Jamie Smith    7 年前

    apex:map 没有额外的googleapi。 当在闪电中观看时也能工作——没有具体的个人经历,但这是我读到的。

    文档示例:

    <apex:map width="600px" height="400px" mapType="roadmap" center="{!Account.BillingStreet}, {!Account.BillingCity}, {!Account.BillingState}">
          <!-- Add a CUSTOM map marker for the account itself -->
          <apex:mapMarker title="{! Account.Name }" position="{!Account.BillingStreet}, {!Account.BillingCity}, {!Account.BillingState}" icon="{! URLFOR($Resource.MapMarkers, 'moderntower.png') }"/>
    
          <!-- Add STANDARD markers for the account's contacts -->
          <apex:repeat value="{! Account.Contacts }" var="ct">
    
            <apex:mapMarker title="{! ct.Name }" position="{! ct.MailingStreet }, {! ct.MailingCity }, {! ct.MailingState }"></apex:mapMarker>
    
          </apex:repeat>
    </apex:map>
    

    在这个例子中, {! Account.Contacts } apex:mapMarker {Account.Contacts} 示例中正在迭代的列表。

    文档: Docs that example was pulled from.