Как интегрировать Salesforce с Google Maps? - PullRequest
5 голосов
/ 26 июня 2010

Как мне интегрировать Salesforce с Google Maps?Я просто ищу информацию о том, как ...

  1. Поиск контактов в Salesforce
  2. Отображение контактов на карте Google.

Ответы [ 3 ]

11 голосов
/ 29 июня 2010

РЕДАКТИРОВАТЬ :

Благодаря комментарию tggagne я понял, что люди все еще видят этот ответ.Код, который был здесь, более 2,5 лет.Если вы хотите это увидеть - проверьте историю изменений.

За это время изменился лот , было создано больше примеров гибридных приложений.Не в последнюю очередь это приложение "SF Bus Radar" ( github , youtube ) от Cory Cowgill (созданное на Dreamforce'11, я думаю).

Тем не менее -Вот мой обновленный пример с геокодированием на стороне сервера, новым полем типа Geolocation и использованием анализаторов JSON.

Он пытается кэшировать результаты геокодирования в записях контактов.Помните, что он может быть не готов к работе (без ключа Google Business API =, поскольку все наши запросы поступают из одного пула IP-серверов Salesforce , могут быть сообщения об ошибках ).Вот почему я также оставил геокодирование на стороне клиента.

image image


Вам понадобитсячтобы сделать 2 изменения в вашей среде перед проверкой:

  1. Добавьте « Настройка удаленного сайта », которая указывает на https://maps.googleapis.com, чтобы включить выноски из Apex
  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;
    }
    }
    

<code><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}
var marker = new google.maps.Marker ({карта: карта, позиция: координаты [i], заголовок: контакты [i]. Имя, zIndex: i});google.maps.event.addListener (маркер, 'click', function () {var index = this.zIndex; balloon.content = '' + contacts [index] .Name + ''+ contacts [index] .Account.Name +''+ контакты [индекс] .Email;balloon.open (карта, это);});markers.push (маркер);}} geocodeClientSide ();
1 голос
/ 01 июня 2017

Начиная с Spring '15, мы также можем использовать apex:map без дополнительного Google API.Также работает при просмотре в Lightning - нет личного опыта специально, но это то, что я прочитал.

Пример из документов:

<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 для сопоставления всех контактов в списке.Несмотря на то, что OP устарела, «результаты поиска» могут в основном заменить список {Account.Contacts}, который повторяется в примере.

Документация: Документы, из которых был извлечен этот пример.

(я знаю, что это старое, но было обновлено из-за обновления, поэтому было бы неплохо подумать, что обновление без API.)

1 голос
/ 01 апреля 2011

Еще одно место, где можно ознакомиться с основными принципами платформы force.com книга (или сайт , если у вас нет учетной записи разработчика).У них есть очень хорошее и подробное руководство здесь , показывающее, как интегрировать карты с Salesforce (они используют Yahoo для обучения, но оно будет работать так же хорошо с Google Maps).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...