如何将 Salesforce 与 Google 地图集成? [英] How do I integrate Salesforce with Google Maps?

查看:31
本文介绍了如何将 Salesforce 与 Google 地图集成?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何将 Salesforce 与 Google 地图集成?我只是在寻找有关如何...的信息

  1. 在 Salesforce 中搜索联系人
  2. 在谷歌地图上绘制它们.

解决方案

编辑:

感谢

<小时>

在检查之前,您需要对环境进行 2 次更改:

  1. 添加指向远程站点设置""https://maps.googleapis.com" rel="nofollow noreferrer">https://maps.googleapis.com 以启用来自 Apex 的标注
  2. 在设置 -> 自定义 -> 联系人 -> 字段中添加字段位置".类型应为地理位置".我选择了显示为小数和 6 个小数位的精度.

    public with share class mapController {公共字符串 searchText {get;set;}公共列表<联系方式>联系人{得到;私人集;}public static final String GEOCODING_URI_BASE = 'https://maps.googleapis.com/maps/api/geocode/json?sensor=false&address=';//出于此演示的目的,我将仅对服务器端的几个地址进行地理编码.真正的代码可以使用注释掉的值.公共静态最终整数 MAX_CALLOUTS_FROM_APEX = 3;//Limits.getLimitCallouts()公共地图控制器(){searchText = ApexPages.currentPage().getParameters().get('q');}公共无效查找(){if(searchText != null && searchText.length() > 1){列表<列表>结果 = [FIND :('*' + searchText + '*') 在所有字段中返回联系人(ID、姓名、电子邮件、帐户名称、MailingStreet、MailingCity、MailingPostalCode、MailingState、MailingCountry、位置__纬度__s,位置__经度__s)];联系人 = (List)results[0];如果(contacts.isEmpty()){ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.INFO, '没有匹配的 "' + searchText + '"'));} 别的 {serverSideGeocode();}} 别的 {如果(联系人!= null){联系人.清除();}ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.INFO, '请提供至少 2 个字符用于搜索.'));}}public void clearGeocodedData(){for(联系人 c : 联系人){c.Location__Latitude__s = c.Location__Longitude__s = null;}Database.update(联系人,假);联系人.清除();}公共字符串 getContactsJson(){返回 JSON.serialize(contacts);}公共字符串 getDebugContactsJson(){返回 JSON.serializePretty(contacts);}私有无效 serverSideGeocode(){列出<联系方式>contactsToUpdate = new List();Http h = new Http();HttpRequest req = new HttpRequest();req.setMethod('GET');req.setTimeout(10000);for(联系人 c : 联系人){if((c.Location__Latitude__s == null || c.Location__Longitude__s == null)){字符串地址 = c.MailingStreet != null ?c.MailingStreet + ' ' : '' +c.MailingCity != null ?c.MailingCity + ' ' : '' +c.MailingState != null ?c.MailingState + ' ' : '' +c.MailingPostalCode != null ?c.MailingPostalCode + ' ' : '' +c.MailingCountry != null ?c.邮寄国家:'';如果(地址!= ''){req.setEndpoint(GEOCODING_URI_BASE + EncodingUtil.urlEncode(address, 'UTF-8'));尝试{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);} 别的 {ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.ERROR, ''+地址+''的地理编码失败:'+ gr.status));}}catch(异常e){ApexPages.addMessages(e);}}//如果我们已达到调用限制(并非所有联系人都可能已被处理),则退出.if(Limits.getCallouts() == MAX_CALLOUTS_FROM_APEX) {休息;}}}if(!contactsToUpdate.isEmpty()) {Database.update(contactsToUpdate, false);//开发人员版本中的某些数据无效(我认为是故意的).//如果更新失败,因为j.davis@expressl&amp;t.net"不是有效的电子邮件,我希望其余的成功}}//Helper 类 - 将解析查找结果的模板.一些字段被跳过!//如果您需要创建完整的映射,请访问 https://developers.google.com/maps/documentation/geocoding/#Results.公共类 GResponse{公共字符串状态;公共 GComponents[] 结果;}公共类 GComponents{公共字符串 formatted_address;公共 GGeometry 几何;}公共类 GGeometry {公共纬度位置;}公开课经纬度{公共双纬度,lng;}}

<小时>

<头><风格>div #map_canvas { 高度:400 像素;}</风格><script type="text/javascript" src="https://maps.googleapis.com/maps/api/js?sensor=false"></script><apex:sectionHeader title="你好 StackOverflow!"副标题="联系全文搜索+谷歌地图集成"/><apex:pageMes​​sages/><apex:form id="form"><apex:pageBlock id="searchBlock"><apex:inputText value="{!searchText}"/><apex:commandButton value="Search" action="{!find}"/><p>示例:<a href="/apex/{!$CurrentPage.Name}?q=USA">"USA"</a>, "Singapore", "Uni", "(336)222-7000".如果它在全局搜索框中工作,它就会在此处工作.</p></apex:pageBlock><apex:pageBlock title="Found {!contacts.size} Contact(s)..." render="{!NOT(ISNULL(contacts)) &&contacts.size > 0}" id="结果块"><apex:pageBlockButtons location="top"><apex:commandButton value="清除缓存位置" title="如果您想为所有这些联系人设置 'null' 作为地理位置信息,请单击" 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="地址">{!c.MailingStreet} {!c.MailingCity} {!c.MailingCountry}</apex:column><apex:column value="{!c.Account.Name}"/><apex:column headerValue="位置(从数据库或地理编码服务器端检索)">{!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="单击以显示/隐藏经过地理编码的服务器端并传递给 JS 以供进一步操作的内容" columns="1" id="debugSection"><pre>{!debugContactsJson}</pre></apex:pageBlockSection><pre id="日志"></pre></apex:pageBlock></apex:form><script type="text/javascript">twinSection(document.getElementById('page:form:resultsBlock:debugSection').childNodes[0].childNodes[0]);//最初隐藏调试部分var 联系人 = {!contactsJson};//联系人数据数组,其中一些可能有经纬度信息,有些我们必须对客户端进行地理编码var 坐标 = [];//只是每个联系人的纬度/经度var requestCounter = 0;var 标记 = [];//我们固定在地图上的红色东西.var 气球 = 新 google.maps.InfoWindow();//漂浮在标记上的漫画式气球.函数 geocodeClientSide() {for(var i = 0; i </apex:page>

How do I integrate Salesforce with Google Maps? I'm just looking for information on how to...

  1. Search for contacts in Salesforce
  2. Plot those on a google map.

解决方案

EDIT:

Thanks to tggagne's comment I've realized that people still see this answer. The code that was here is over 2.5 years old. If you want to see it - check the history of edits.

A lot has changed in the meantime, more mashup examples were created. Not the least of them being "SF Bus Radar" (github, youtube) app by Cory Cowgill (created on Dreamforce'11 I think).

Nonetheless - here's my updated example with server-side geocoding, new field of type Geolocation and usage of JSON parsers.

It tries to cache the geocoding results in the contact records. Bear in mind it might not be 'production-ready' (no Google Business API key = as all our requests come out from same pool of Salesforce IP servers there might be error messages). That's why I've left the client-side geocoding too.


You'll need to make 2 changes in your environment before checking it out:

  1. Add "Remote Site Setting" that points to https://maps.googleapis.com to enable callouts from Apex
  2. Add field "Location" in Setup -> Customize -> Contacts -> fields. Type should be "Geolocation". I've selected display as decimals and precision of 6 decimal places.

    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>

这篇关于如何将 Salesforce 与 Google 地图集成?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆