zoukankan      html  css  js  c++  java
  • 让isis支持高德地图

    概述

    由于项目需要用到地图,虽然isis的插件库里有个现成的地图实现,不过用的google地图,虽然google地图可以不用注册Appkey,但完全打不开。所以打算改成国产地图。

    效果

    先看下运行效果。

    列表中的效果:

    整体效果:

    详细效果:

    实现思路

    高德地图的API跟Google地图类似,编程模型也相同,甚至很多类的命名都一样的。所以,从Google迁到高德还是比较容易的。

    高德跟Google一样,用一个DIV来渲染地图。根据Vicket的编程方式,这个Div使用一个组件来表示,这个组件包含了相应的属性和呈现出来的模板及脚本。

    先看下Google的模板,很简单在Panel里放了一个Div:

    <html xmlns:wicket>
        <body>
        <wicket:panel>
            <div wicket:id="map" style="100%; height:100%"></div>
        </wicket:panel>
    </body>
    </html>
    

     Google的客户端对应的初始化脚本:

    /*
     * Licensed to the Apache Software Foundation (ASF) under one or more
     * contributor license agreements.  See the NOTICE file distributed with
     * this work for additional information regarding copyright ownership.
     * The ASF licenses this file to You under the Apache License, Version 2.0
     * (the "License"); you may not use this file except in compliance with
     * the License.  You may obtain a copy of the License at
     *
     *      http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */
    /*
     * Wicket GMap3
     *
     * @author Tilman M�ller
     * @author Joachim F. Rohde
     */
    // Wicket Namespace
    if (typeof(Wicket) === 'undefined') {
        window.Wicket = {};
    }
    else if (typeof(Wicket) !== "object") {
        throw new Error("Wicket already exists but is not an object");
    }
    
    function WicketClientGeocoder() {
    
        try {
            this.coder = new google.maps.Geocoder();
        } catch (e) {
            if( !Wicket.maps['_failSilently'] ) {
                throw e;
            }
        }
    
        this.getLatLng = function(callBack, addressId){
    
            var address = Wicket.$(addressId).value;
    
            this.coder.geocode({
                'address': address
            }, function(results, status){
    
                if (status === google.maps.GeocoderStatus.OK) {
                    callBack = callBack + '&address=' + results[0].formatted_address;
                    callBack = callBack + '&coordinates=' + results[0].geometry.location;
                }
                callBack = callBack + '&status=' + status;
    
                Wicket.Ajax.ajax({
                    'u':callBack
                });
            });
        }
    }
    
    Wicket.maps = {}
    
    function WicketMap(id, failSilently) {
        Wicket.maps[id] = this;
    
        if(failSilently) {
            Wicket.maps['_failSilently'] = failSilently;
        }
    
        this.options = {};
        try {
            this.map = new google.maps.Map(Wicket.$(id));
        } catch (e) {
            if(!failSilently) {
                throw e;
            }
        }
        this.overlays = {};
    
        this.onEvent = function(callBack, params) {
            params['center'] = this.map.getCenter();
            params['bounds'] = this.map.getBounds();
            params['zoom'] = this.map.getZoom();
            params['currentMapType'] = this.getMapTypeString(this.map.getMapTypeId());
    
            for ( var key in params) {
                callBack = callBack + '&' + key + '=' + params[key];
            }
    
            Wicket.Ajax.ajax({
                'u':callBack
            });
        }
    
        this.addListener = function(event, callBack) {
            var self = this;
    
            google.maps.event.addListener(this.map, event, function() {
                var params = {};
                for ( var p = 0; p < arguments.length; p++) {
    
                    if (arguments[p] != null) {
                        if (arguments[p].latLng != null)
                        {
                            params['lat'] = arguments[0].latLng.lat();
                            params['lng'] = arguments[0].latLng.lng();
                        }
                    }
                }
    
                self.onEvent(callBack, params);
            });
        }
    
    
        this.addOverlayListener = function(overlayID, event) {
            var self = this;
            var overlay = this.overlays[overlayID];
    
            google.maps.event.addListener(overlay, event, function() {
                var params = {};
                for ( var p = 0; p < arguments.length; p++) {
                    if (arguments[p] != null) {
                        params['argument' + p] = arguments[p];
                    }
                }
    
                if (overlay.getPosition) {
                    params['overlay.latLng'] = overlay.getPosition();
                }
                else if (overlay.getCenter) {
                    // Circle uses #getCenter() instead
                    params['overlay.latLng'] = overlay.getCenter();
                }
    
                if (overlay.getRadius) {
                    // Circle
                    params['overlay.radius'] = overlay.getRadius();
                }
    
                if (overlay.getBounds) {
                    params['overlay.bounds'] = overlay.getBounds();
                }
    
                params['overlay.overlayId'] = overlay.overlayId;
                params['overlay.event'] = event;
    
                self.onEvent(self.overlayListenerCallbackUrl, params);
            });
        }
    
        this.clearOverlayListeners = function(overlayID, event) {
            var overlay = this.overlays[overlayID];
    
            google.maps.event.clearListeners(overlay, event);
        }
    
        this.setDraggingEnabled = function(enabled) {
            this.options.draggable = enabled;
            this.map.setOptions(this.options);
        }
    
        this.setDoubleClickZoomEnabled = function(enabled) {
            this.options.disableDoubleClickZoom = enabled;
            this.map.setOptions(this.options);
        }
    
        this.setScrollWheelZoomEnabled = function(enabled) {
            this.options.scrollwheel = enabled;
            this.map.setOptions(this.options);
        }
    
        this.setScaleControlEnabled = function(enabled) {
            this.options.scaleControl = enabled;
            this.map.setOptions(this.options);
        }
    
        this.setZoomControlEnabled = function(enabled) {
            this.options.zoomControl = enabled;
            this.map.setOptions(this.options);
        }
    
        this.setMapTypeControlEnabled = function(enabled) {
            this.options.mapTypeControl = enabled;
            this.map.setOptions(this.options);
        }
    
        this.setStreetViewControlEnabled = function(enabled) {
            this.options.streetViewControl = enabled;
            this.map.setOptions(this.options);
        }
    
        this.setPanControlEnabled = function(enabled) {
            this.options.panControl = enabled;
            this.map.setOptions(this.options);
        }
        
        this.fitBounds = function(bounds) {
            this.options.bounds = bounds;
            this.map.setOptions(this.options);
            this.map.fitBounds(bounds);
        }
        
        this.panToBounds = function(bounds) {
            this.options.bounds = bounds;
            this.map.setOptions(this.options);
            this.map.panToBounds(bounds);
        }
    	
        this.setMinZoom = function(minZoom) {
            this.options.minZoom = minZoom;
            this.map.setOptions(this.options);
        }
    	
        this.setMaxZoom = function(maxZoom) {
            this.options.maxZoom = maxZoom;
            this.map.setOptions(this.options);
        }
    
        this.getMapTypeString = function(mapType) {
            switch (mapType) {
                case google.maps.MapTypeId.ROADMAP:
                    return 'ROADMAP';
                    break;
                case google.maps.MapTypeId.SATELLITE:
                    return 'SATELLITE';
                    break;
                case google.maps.MapTypeId.HYBRID:
                    return 'HYBRID';
                    break;
                case google.maps.MapTypeId.TERRAIN:
                    return 'TERRAIN';
                    break;
                default:
                    return 'unknown';
                    break;
            }
        }
    
        this.setMapType = function(mapType) {
            this.map.setMapTypeId(mapType);
        }
    
        this.setZoom = function(level) {
            this.map.setZoom(level);
        }
    
        this.setCenter = function(center) {
        //设置地图中心 this.map.setCenter(center); } this.setCenterFailSafe = function(lat, lng, unbounded) { try { this.map.setCenter( new google.maps.LatLng(lat, lng, unbounded) ); } catch (e) { // do nothing } } this.panTo = function(center) { this.map.panTo(center); } this.panDirection = function(dx, dy) { this.map.panBy(dx, dy); } this.zoomOut = function() { this.map.setZoom(this.map.getZoom()-1) } this.zoomIn = function() { this.map.setZoom(this.map.getZoom()+1) } this.addOverlay = function(overlayId, overlay) { this.overlays[overlayId] = overlay; overlay.overlayId = overlayId; overlay.setMap(this.map); overlay.toString = function() { return overlayId; }; } this.removeOverlay = function(overlayId) { if (this.overlays[overlayId] != null) { this.overlays[overlayId].setMap(null); this.overlays[overlayId] = null; } } this.clearOverlays = function() { if (this.overlays) { for (i in this.overlays) { this.overlays[i].setMap(null); } } this.overlays = {}; } this.triggerEvent = function(event) { google.maps.event.trigger(this.map, event); } this.triggerResize = function() { this.triggerEvent('resize'); } } Wicket.Event.add(window, "load", function(event){ if(typeof(Wicket.geocoder) === 'undefined') Wicket.geocoder = new WicketClientGeocoder(); });

     Java部分的实现,可以看出其属性与客户端的JS是一一对应的,这是Vicket的一种机制,将服务端的对象映射到客户端,这样在服务端设置属性就跟在客户端设置一样:

    /*
     *
     * ==============================================================================
     * Licensed under the Apache License, Version 2.0 (the "License"); you may not
     * use this file except in compliance with the License. You may obtain a copy of
     * the License at
     *
     * http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
     * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
     * License for the specific language governing permissions and limitations under
     * the License.
     */
    package org.wicketstuff.gmap;
    
    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    import org.apache.wicket.Component;
    import org.apache.wicket.ajax.AbstractDefaultAjaxBehavior;
    import org.apache.wicket.ajax.AjaxRequestTarget;
    import org.apache.wicket.behavior.Behavior;
    import org.apache.wicket.markup.ComponentTag;
    import org.apache.wicket.markup.head.IHeaderResponse;
    import org.apache.wicket.markup.head.OnDomReadyHeaderItem;
    import org.apache.wicket.markup.html.WebMarkupContainer;
    import org.apache.wicket.markup.html.panel.Panel;
    import org.apache.wicket.request.IRequestParameters;
    import org.apache.wicket.request.Request;
    import org.apache.wicket.request.cycle.RequestCycle;
    import org.apache.wicket.util.string.Strings;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.wicketstuff.gmap.api.GEvent;
    import org.wicketstuff.gmap.api.GLatLng;
    import org.wicketstuff.gmap.api.GLatLngBounds;
    import org.wicketstuff.gmap.api.GMapType;
    import org.wicketstuff.gmap.api.GMarker;
    import org.wicketstuff.gmap.api.GMarkerCluster;
    import org.wicketstuff.gmap.api.GMarkerOptions;
    import org.wicketstuff.gmap.api.GOverlay;
    import org.wicketstuff.gmap.event.GEventListenerBehavior;
    
    /**
     * Wicket component to embed <a href="http://maps.google.com">Google Maps</a> into your pages.
     * <p>
     */
    public class GMap extends Panel implements GOverlayContainer
    {
    
        /** log. */
        private static final Logger log = LoggerFactory.getLogger(GMap.class);
        private static final long serialVersionUID = 1L;
        // Center is Palo Alto
        private GLatLng center = new GLatLng(37.4419, -122.1419);
        private boolean draggingEnabled = true;
        private boolean doubleClickZoomEnabled = false;
        private boolean scrollWheelZoomEnabled = false;
        private boolean streetViewControlEnabled = false;
        private boolean zoomControlEnabled = true;
        private boolean mapTypeControlEnabled = true;
        private boolean scaleControlEnabled = false;
        private boolean panControlEnabled = true;
        private GMapType mapType = GMapType.ROADMAP;
        private int zoom = 13;
        private int minZoom = 0;
        private int maxZoom = 0;
        private final Map<String, GOverlay> overlays = new HashMap<String, GOverlay>();
        protected final WebMarkupContainer map;
        private GLatLngBounds bounds;
        private OverlayListener overlayListener = null;
        private List<GLatLng> markersToShow = new ArrayList<GLatLng>();
        
        /**
         * If set to true map loading will not produce any JavaScript errors in case
         * google maps API cannot be found (e.g. no Internet connection)
         */
        private boolean failSilently = false;
        private GMarkerCluster markerCluster;
    
        /**
         * Constructor.
         *
         * Default the header contributor of the component will added and the gmap
         * will be initiated directly on rendering of the map.
         *
         * @param id wicket id
         * @param apiKey your Google API key
         */
        public GMap(final String id, String apiKey)
        {
            this(id, new GMapHeaderContributor("http", apiKey));
        }
    
        /**
         * Constructor.
         *
         * Default the header contributor of the component will added and the gmap
         * will be initiated directly on rendering of the map.
         *
         * @param id wicket id
         * @param scheme the scheme ("http" or "https") which should be used
         * @param apiKey your Google API key
         */
        public GMap(final String id, String apiKey, String scheme)
        {
            this(id, new GMapHeaderContributor(scheme, apiKey));
        }
    
        /**
         * Construct.
         *
         * Default the header contributor of the component will added and the gmap
         * will be initiated directly on rendering of the map.
         *
         * @param id wicket id
         * @deprecated since 22th June 2016 Google Maps requires an API-key,
         * therefore you should use
         * {@link #GMap(java.lang.String, java.lang.String) } or {@link #GMap(java.lang.String, java.lang.String, java.lang.String)
         * }
         * instead of this constructor
         * @see
         * http://googlegeodevelopers.blogspot.de/2016/06/building-for-scale-updates-to-google.html
         */
        public GMap(final String id)
        {
            this(id, new GMapHeaderContributor());
        }
    
        /**
         * @deprecated Since the sensor-parameter is no longer required from Google
         * {@link #GMap(java.lang.String, java.lang.String) } or {@link #GMap(java.lang.String, java.lang.String, java.lang.String)
         * }
         * instead of this constructor
         */
        public GMap(final String id, final boolean sensor)
        {
            this(id, new GMapHeaderContributor(sensor));
        }
    
        /**
         * Construct.
         *
         * @param id
         * @param headerContrib
         */
        public GMap(final String id, final GMapHeaderContributor headerContrib)
        {
            super(id);
    
            if (headerContrib != null)
            {
                add(headerContrib);
            }
    
            map = new WebMarkupContainer("map");
            map.setOutputMarkupId(true);
            add(map);
    
            overlayListener = getOverlayListener();
            add(overlayListener);
    
        }
        
        protected OverlayListener getOverlayListener()
        {
        	return new OverlayListener();
        }
    
        /**
         * @return the markup-id of the container
         */
        public String getMapId()
        {
            return map.getMarkupId();
        }
    
        @Override
        protected void onBeforeRender()
        {
            super.onBeforeRender();
    
            if (getApplication().usesDevelopmentConfig()
                    && !getApplication().getMarkupSettings().getStripWicketTags())
            {
                log.warn("Application is in DEVELOPMENT mode && Wicket tags are not stripped,"
                        + "Some Chrome Versions will not render the GMap."
                        + " Change to DEPLOYMENT mode  || turn on Wicket tags stripping." + " See:"
                        + " http://www.nabble.com/Gmap2-problem-with-Firefox-3.0-to18137475.html.");
            }
        }
    
        @Override
        public void renderHead(IHeaderResponse response)
        {
            response.render(OnDomReadyHeaderItem.forScript(getJSinit()));
        }
    
        /**
         * Add an overlay.
         *
         * @see GOverlayContainer#addOverlay(GOverlay)
         * @param overlay
         * overlay to add
         * @return This
         */
        @Override
        public GMap addOverlay(final GOverlay overlay)
        {
            overlays.put(overlay.getId(), overlay);
            overlay.setParent(this);
    
            AjaxRequestTarget target = getRequestCycle().find(AjaxRequestTarget.class);
            if (target != null && findPage() != null)
            {
                target.appendJavaScript(overlay.getJS());
            }
    
            return this;
        }
    
        /**
         * Remove an overlay.
         *
         * @see GOverlayContainer#removeOverlay(GOverlay)
         * @param overlay
         * overlay to remove
         * @return This
         */
        @Override
        public GMap removeOverlay(final GOverlay overlay)
        {
            while (overlays.containsKey(overlay.getId()))
            {
                overlays.remove(overlay.getId());
            }
    
            AjaxRequestTarget target = RequestCycle.get().find(AjaxRequestTarget.class);
            if (target != null && findPage() != null)
            {
                target.appendJavaScript(overlay.getJSremove());
            }
    
            overlay.setParent(null);
    
            return this;
        }
    
        /**
         * Clear all overlays.
         *
         * @see GOverlayContainer#removeAllOverlays()
         * @return This
         */
        @Override
        public GMap removeAllOverlays()
        {
            for (final GOverlay overlay : overlays.values())
            {
                overlay.setParent(null);
            }
            overlays.clear();
            AjaxRequestTarget target = getRequestCycle().find(AjaxRequestTarget.class);
            if (target != null && findPage() != null)
            {
                target.appendJavaScript(getJSinvoke("clearOverlays()"));
            }
            return this;
        }
    
        /**
         * @see GOverlayContainer#getOverlays()
         */
        @Override
        public List<GOverlay> getOverlays()
        {
            return Collections.unmodifiableList(new ArrayList<GOverlay>(overlays.values()));
        }
    
        public GLatLngBounds getBounds()
        {
            return bounds;
        }
    
        public void setBounds(GLatLngBounds bounds)
        {
    		this.bounds = bounds;
    	}
    
        /**
         * Returns the script for triggering an event on map.
         *
         * @param event
         * @return
         */
        public CharSequence getTriggerEventScript(String event) {
    		return "Wicket.maps['"+getMapId()+ "'].triggerEvent('"+event+"')";
    	}
    
        /**
         * @return returns the script to make map re-paint after resize.
         */
    	public CharSequence getTriggerResizeScript() {
    		return "Wicket.maps['"+getMapId()+ "'].triggerResize();";
    	}
    
        /**
         * Sets if dragging should be allowed or not.
         * @param enabled true if dragging should be allowed, false otherwise
         */
        public void setDraggingEnabled(final boolean enabled)
        {
            if (this.draggingEnabled != enabled)
            {
                draggingEnabled = enabled;
    
                AjaxRequestTarget target = getRequestCycle().find(AjaxRequestTarget.class);
                if (target != null && findPage() != null)
                {
                    target.appendJavaScript(getJSsetDraggingEnabled(enabled));
                }
            }
        }
    
        /**
         * Is dragging allowed? Enabled by default.
         *
         * @return true if it's allowed, false if not
         */
        public boolean isDraggingEnabled()
        {
            return draggingEnabled;
        }
    
        /**
         * Sets if zooming-by-doubleclicking should be allowed or not.
         * @param enabled true if zooming-by-doubleclicking should be allowed, false otherwise
         */
        public void setDoubleClickZoomEnabled(final boolean enabled)
        {
            if (this.doubleClickZoomEnabled != enabled)
            {
                doubleClickZoomEnabled = enabled;
    
                AjaxRequestTarget target = RequestCycle.get().find(AjaxRequestTarget.class);
                if (target != null && findPage() != null)
                {
                    target.appendJavaScript(getJSsetDoubleClickZoomEnabled(enabled));
                }
            }
        }
    
        /**
         * Is the function zooming-by-doubleclick enabled?
         * Disabled by default.
         *
         * @return true if enabled, false if disabled
         */
        public boolean isDoubleClickZoomEnabled()
        {
            return doubleClickZoomEnabled;
        }
    
        /**
         * Sets if zooming-by-mousewheel should be allowed or not.
         * @param enabled true if zooming-by-mousewheel should be allowed, false otherwise
         */
        public void setScrollWheelZoomEnabled(final boolean enabled)
        {
            if (this.scrollWheelZoomEnabled != enabled)
            {
                scrollWheelZoomEnabled = enabled;
    
                AjaxRequestTarget target = getRequestCycle().find(AjaxRequestTarget.class);
                if (target != null && findPage() != null)
                {
                    target.appendJavaScript(getJSsetScrollWheelZoomEnabled(enabled));
                }
            }
        }
    
        /**
         * Is the function zooming-by-mousewheel enabled?
         * Disabled by default.
         *
         * @return true if enabled, false if disabled
         */
        public boolean isScrollWheelZoomEnabled()
        {
            return scrollWheelZoomEnabled;
        }
    
        /**
         * Is the StreetView control enabled?
         * Disabled by default.
         *
         * @return true if enabled, false if disabled
         */
        public boolean isStreetViewControlEnabled()
        {
            return streetViewControlEnabled;
        }
    
        /**
         * Sets if the StreeView control should be visible or not.
         * @param enabled true if StreetView should be allowed, false otherwise
         */
        public void setStreetViewControlEnabled(boolean enabled)
        {
            if (this.streetViewControlEnabled != enabled)
            {
                streetViewControlEnabled = enabled;
    
                AjaxRequestTarget target = getRequestCycle().find(AjaxRequestTarget.class);
                if (target != null && findPage() != null)
                {
                    target.appendJavaScript(getJSsetStreetViewControlEnabled(enabled));
                }
            }
        }
    
        /**
         * Is the zoom control enabled?
         * Enabled by default.
         *
         * @return true if enabled, false if disabled
         */
        public boolean isZoomControlEnabled()
        {
            return zoomControlEnabled;
        }
    
        /**
         * Sets if the zoom control should be visible or not.
         * @param enabled true if the zoom-control should be enabled, false otherwise
         */
        public void setZoomControlEnabled(boolean enabled)
        {
            if (this.zoomControlEnabled != enabled)
            {
                this.zoomControlEnabled = enabled;
    
                AjaxRequestTarget target = getRequestCycle().find(AjaxRequestTarget.class);
                if (target != null && findPage() != null)
                {
                    target.appendJavaScript(getJSsetZoomControlEnabled(enabled));
                }
            }
        }
    
        /**
         * Is the map type control enabled?
         * Enabled by default.
         *
         * @return true if enabled, false if disabled
         */
        public boolean isMapTypeControlEnabled()
        {
            return mapTypeControlEnabled;
        }
    
        /**
         * Sets if the map type control should be visible or not.
         * @param enabled true if you want the user to have the possibility to
         * change the map type, false otherwise
         */
        public void setMapTypeControlEnabled(boolean enabled)
        {
    
            if (this.mapTypeControlEnabled != enabled)
            {
                this.mapTypeControlEnabled = enabled;
    
                AjaxRequestTarget target = getRequestCycle().find(AjaxRequestTarget.class);
                if (target != null && findPage() != null)
                {
                    target.appendJavaScript(getJSsetMapTypeControlEnabled(enabled));
                }
            }
        }
    
        /**
         * Is the scale control enabled?
         * Disabled by default.
         *
         * @return true if enabled, false if disabled
         */
        public boolean isScaleControlEnabled()
        {
            return scaleControlEnabled;
        }
    
        /**
         * Sets if the scale control should be visible or not.
         * @param enabled true if the scale-control should be enabled, false otherwise
         */
        public void setScaleControlEnabled(boolean enabled)
        {
            if (this.scaleControlEnabled != enabled)
            {
                this.scaleControlEnabled = enabled;
    
                AjaxRequestTarget target = getRequestCycle().find(AjaxRequestTarget.class);
                if (target != null && findPage() != null)
                {
                    target.appendJavaScript(getJSsetScaleControlEnabled(enabled));
                }
            }
        }
    
        /**
         * Is the pan control enabled?
         * Enabled by default.
         *
         * @return true if enabled, false if disabled
         */
        public boolean isPanControlEnabled()
        {
            return panControlEnabled;
        }
    
        /**
         * Sets if the pan control should be visible or not.
         * @param enabled true if the pan-control should be enabled, false otherwise
         */
        public void setPanControlEnabled(boolean enabled)
        {
            if (this.panControlEnabled != enabled)
            {
                this.panControlEnabled = enabled;
    
                AjaxRequestTarget target = getRequestCycle().find(AjaxRequestTarget.class);
                if (target != null && findPage() != null)
                {
                    target.appendJavaScript(getJSsetPanControlEnabled(enabled));
                }
            }
        }
    
        /**
         * @return the current map type.
         * @see GMapType
         */
        public GMapType getMapType()
        {
            return mapType;
        }
    
        /**
         * Sets the map type which should be used.
         * @param mapType the map type
         * @see GMapType
         */
        public void setMapType(final GMapType mapType)
        {
            if (this.mapType != mapType)
            {
                this.mapType = mapType;
    
                AjaxRequestTarget target = RequestCycle.get().find(AjaxRequestTarget.class);
                if (target != null && findPage() != null)
                {
                    target.appendJavaScript(mapType.getJSsetMapType(GMap.this));
                }
            }
        }
    
        /**
         * @return the current zoom level
         */
        public int getZoom()
        {
            return zoom;
        }
    	
        /**
         * @return the minZoom level
         */
        public int getMinZoom()
        {
            return minZoom;
        }
    	
        /**
         * @return the maxZoom level
         */
        public int getMaxZoom()
        {
            return maxZoom;
        }
    
        /**
         * Sets a new zoom level.
         * @param level the new zoom level
         */
        public void setZoom(final int level)
        {
            if (this.zoom != level)
            {
                this.zoom = level;
    
                AjaxRequestTarget target = getRequestCycle().find(AjaxRequestTarget.class);
                if (target != null && findPage() != null)
                {
                    target.appendJavaScript(getJSsetZoom(zoom));
                }
            }
        }
    	
        /**
         * Sets a new minZoom limit.
         * @param level the new minZoom level
         */
        public void setMinZoom(final int level)
        {
            if (this.minZoom != level)
            {
                this.minZoom = level >= 0 ? level : 0;
    
                AjaxRequestTarget target = getRequestCycle().find(AjaxRequestTarget.class);
                if (target != null && findPage() != null)
                {
                    target.appendJavaScript(getJSsetMinZoom(minZoom));
                }
            }
        }
    	
        /**
         * Sets a new maxZoom limit.
         * @param level the new maxZoom level
         */
        public void setMaxZoom(final int level)
        {
            if (this.maxZoom != level)
            {
                this.maxZoom = level >= 0 ? level : 0;
    
                AjaxRequestTarget target = getRequestCycle().find(AjaxRequestTarget.class);
                if (target != null && findPage() != null)
                {
                    target.appendJavaScript(getJSsetMaxZoom(maxZoom));
                }
            }
        }
    
        /**
         * @return the current center point
         */
        public GLatLng getCenter()
        {
            return center;
        }
    
        /**
         * Set the center.
         *
         * @param center
         * center to set
         */
        public void setCenter(final GLatLng center)
        {
            if (!this.center.equals(center))
            {
                this.center = center;
    
                AjaxRequestTarget target = RequestCycle.get().find(AjaxRequestTarget.class);
                if (target != null && findPage() != null)
                {
                    target.appendJavaScript(getJSsetCenter(center));
                }
            }
        }
    
        /**
         * Changes the center point of the map to the given point. If the point is already visible in the current map view,
         * change the center in a smooth animation.
         *
         * @param center
         * the new center of the map
         */
        public void panTo(final GLatLng center)
        {
            if (!this.center.equals(center))
            {
                this.center = center;
    
                AjaxRequestTarget target = getRequestCycle().find(AjaxRequestTarget.class);
                if (target != null && findPage() != null)
                {
                    target.appendJavaScript(getJSpanTo(center));
                }
            }
        }
        
        public void setMarkerCluster(GMarkerCluster markerCluster)
        {
            if(markerCluster == null)
                throw new IllegalArgumentException("GMarkerCluster argument should not be null.");
            this.markerCluster = markerCluster;
            if (getBehaviors(GMapMarkerClustererHeaderContributor.class).isEmpty()) 
            {
                add(new GMapMarkerClustererHeaderContributor());
            }
        }
    
        public boolean isMarkerClusterEnabled()
        {
            return markerCluster != null;
        }
        
        /**
         * Generates the JavaScript used to instantiate this GMap3 as an JavaScript class on the client side.
         *
         * @return The generated JavaScript
         */
        public String getJSinit()
        {
            final StringBuilder js = new StringBuilder("new WicketMap('" + getMapId() + "', "+isFailSilently() +");
    ");
    
            js.append(getJSinvoke("clearOverlays()"));
            js.append(overlayListener.getJSinit());
            js.append(getJSsetCenter(getCenter()));
            js.append(getJSsetZoom(getZoom()));
            js.append(getJSsetMinZoom(getMinZoom()));
            js.append(getJSsetMaxZoom(getMaxZoom()));
            js.append(getJSfitBounds());
            js.append(getJSsetDraggingEnabled(draggingEnabled));
            js.append(getJSsetDoubleClickZoomEnabled(doubleClickZoomEnabled));
            js.append(getJSsetScrollWheelZoomEnabled(scrollWheelZoomEnabled));
            js.append(getJSsetStreetViewControlEnabled(streetViewControlEnabled));
            js.append(getJSsetZoomControlEnabled(zoomControlEnabled));
            js.append(getJSsetScaleControlEnabled(scaleControlEnabled));
            js.append(getJSsetMapTypeControlEnabled(mapTypeControlEnabled));
            js.append(getJSsetPanControlEnabled(panControlEnabled));
            js.append(getJSFitMarkers());
            js.append(mapType.getJSsetMapType(this));
    
            // Add the overlays.
            for (final GOverlay overlay : overlays.values())
            {
                js.append(overlay.getJS());
            }
            for (final Object behavior : getBehaviors(GEventListenerBehavior.class))
            {
                js.append(((GEventListenerBehavior) behavior).getJSaddListener());
            }
            
            js.append(getJSMarkerCluster());
    
            return js.toString();
        }
    
        /**
         * Convenience method for generating a JavaScript call on this GMap with the given invocation.
         *
         * @param invocation
         * The JavaScript call to invoke on this GMap.
         * @return The generated JavaScript.
         */
        public String getJSinvoke(final String invocation)
        {
            return getJsReference() + "." + invocation + ";
    ";
        }
    
        /**
         * Build a reference in JS-Scope.
         */
        public String getJsReference()
        {
            return "Wicket.maps['" + getMapId() + "']";
        }
    
        /**
         * @see #fitMarkers(List, boolean, double)
         */
        public void fitMarkers(final List<GLatLng> markersToShow)
        {
            fitMarkers(markersToShow, false, 0.0);
        }
    
        /**
         * @see #fitMarkers(List, boolean, double)
         */
        public void fitMarkers(final List<GLatLng> markersToShow, final boolean showMarkersForPoints)
        {
            fitMarkers(markersToShow, showMarkersForPoints, 0.0);
        }
    
        /**
         * <p>
         * Makes the map zoom out and centre around all the GLatLng points in markersToShow.
         * <p>
         * Big ups to Doug Leeper for the code.
         *
         * @see <a href= "http://www.nabble.com/Re%3A-initial-GMap2-bounds-question-p19886673.html" >Doug's Nabble post</a>
         * @param markersToShow
         * the points to centre around.
         * @param showMarkersForPoints
         * if true, will also add basic markers to the map for each point focused on. Just a simple convenience
         * method - you will probably want to turn this off so that you can show more information with each
         * marker when clicked etc.
         */
        public void fitMarkers(final List<GLatLng> markersToShow, final boolean showMarkersForPoints,
                final double zoomAdjustment)
        {
            this.markersToShow = markersToShow;
            
            // show the markers
            if (showMarkersForPoints)
            {
                for (final GLatLng location : markersToShow)
                {
                    this.addOverlay(new GMarker(new GMarkerOptions(this, location)));
                }
            }
        }
        
        private String getJSFitMarkers() {
            if (markersToShow.isEmpty())
            {
                return "";
            }
            
            final StringBuilder buf = new StringBuilder();
            buf.append("var bounds = new google.maps.LatLngBounds();
    ");
            // Ask google maps to keep extending the bounds to include each point
            for (final GLatLng point : markersToShow)
            {
                buf.append("bounds.extend( ").append(point.getJSconstructor()).append(" );
    ");
            }
            
            buf.append(getJSinvoke("fitBounds(bounds)"));
            buf.append(getJSinvoke("panToBounds(bounds)"));
            
            return buf.toString();
        }
        
        private String getJSsetDraggingEnabled(final boolean enabled)
        {
            return getJSinvoke("setDraggingEnabled(" + enabled + ")");
        }
    
        private String getJSsetDoubleClickZoomEnabled(final boolean enabled)
        {
            return getJSinvoke("setDoubleClickZoomEnabled(" + enabled + ")");
        }
    
        private String getJSsetScrollWheelZoomEnabled(final boolean enabled)
        {
            return getJSinvoke("setScrollWheelZoomEnabled(" + enabled + ")");
        }
    
        private String getJSsetStreetViewControlEnabled(final boolean enabled)
        {
            return getJSinvoke("setStreetViewControlEnabled(" + enabled + ")");
        }
    
        private String getJSsetZoomControlEnabled(final boolean enabled)
        {
            return getJSinvoke("setZoomControlEnabled(" + enabled + ")");
        }
    
        private String getJSsetScaleControlEnabled(final boolean enabled)
        {
            return getJSinvoke("setScaleControlEnabled(" + enabled + ")");
        }
    
        private String getJSsetMapTypeControlEnabled(final boolean enabled)
        {
            return getJSinvoke("setMapTypeControlEnabled(" + enabled + ")");
        }
    
        private String getJSsetPanControlEnabled(final boolean enabled)
        {
            return getJSinvoke("setPanControlEnabled(" + enabled + ")");
        }
    
        private String getJSsetZoom(final int zoom)
        {
            return getJSinvoke("setZoom(" + zoom + ")");
        }
    	
        private String getJSsetMinZoom(final int minZoom)
        {
            return getJSinvoke("setMinZoom(" + minZoom + ")");
        }
    	
        private String getJSsetMaxZoom(final int maxZoom)
        {
            return getJSinvoke("setMaxZoom(" + maxZoom + ")");
        }
    
        /**
         * Build the JavaScript for fitBounds() with the bounds property
         * 
         * @return JavaScript for the fitBounds-Function
         */
    	private String getJSfitBounds() {
    		if (null == bounds || Strings.isEmpty(bounds.getJSconstructor())) {
    			return "";
    		} // else
    		return getJSinvoke("fitBounds(" + bounds.getJSconstructor() + ")");
    	}
    
    
        private String getJSsetCenter(final GLatLng center)
        {
            if (center != null)
            {
            	if( !failSilently )
            	{
            		return getJSinvoke("setCenter(" + center.getJSconstructor() + ")");
            	} else {
            		return getJSinvoke("setCenterFailSafe(" + center.getArguments() + ")");
            	}
            }
            return "";
        }
    
        private String getJSpanDirection(final int dx, final int dy)
        {
            return getJSinvoke("panDirection(" + dx + "," + dy + ")");
        }
    
        private String getJSpanTo(final GLatLng center)
        {
            return getJSinvoke("panTo(" + center.getJSconstructor() + ")");
        }
    
        private String getJSzoomOut()
        {
            return getJSinvoke("zoomOut()");
        }
    
        private String getJSzoomIn()
        {
            return getJSinvoke("zoomIn()");
        }
        
        private String getJSMarkerCluster()
        {
        	if(markerCluster != null)
        	{
        		
        		return markerCluster.getJSconstructor();
        	}
        	return "";
        }
        
        
    
        /**
         * Update state from a request to an AJAX target.
         * You need to call this method explictly if you want to have up-to-date values.
         */
        public void update()
        {
            // Attention: don't use setters as this will result in an endless
            // AJAX request loop
            IRequestParameters requestParameters = getRequest().getRequestParameters();
            bounds = GLatLngBounds.parse(requestParameters.getParameterValue("bounds").toString());
            center = GLatLng.parse(requestParameters.getParameterValue("center").toString());
            zoom = requestParameters.getParameterValue("zoom").toInt(zoom);
            String requestMapType = requestParameters.getParameterValue("currentMapType").toString();
            mapType = requestMapType != null ? GMapType.valueOf(requestParameters.getParameterValue("currentMapType").toString()) : mapType;
        }
    
        public void setOverlays(final List<GOverlay> overlays)
        {
            removeAllOverlays();
            for (final GOverlay overlay : overlays)
            {
                addOverlay(overlay);
            }
        }
    
        private static abstract class JSMethodBehavior extends Behavior
        {
            private static final long serialVersionUID = 1L;
            private final String attribute;
    
            public JSMethodBehavior(final String attribute)
            {
                this.attribute = attribute;
            }
    
            @Override
            public void onComponentTag(final Component component, final ComponentTag tag)
            {
                String invoke = getJSinvoke();
    
                if (attribute.equalsIgnoreCase("href"))
                {
                    invoke = "javascript:" + invoke;
                }
    
                tag.put(attribute, invoke);
            }
    
            protected abstract String getJSinvoke();
        }
    
        public class ZoomOutBehavior extends JSMethodBehavior
        {
            private static final long serialVersionUID = 1L;
    
            public ZoomOutBehavior(final String event)
            {
                super(event);
            }
    
            @Override
            protected String getJSinvoke()
            {
                return getJSzoomOut();
            }
        }
    
        public class ZoomInBehavior extends JSMethodBehavior
        {
            private static final long serialVersionUID = 1L;
    
            public ZoomInBehavior(final String event)
            {
                super(event);
            }
    
            @Override
            protected String getJSinvoke()
            {
                return getJSzoomIn();
            }
        }
    
        public class PanDirectionBehavior extends JSMethodBehavior
        {
            private static final long serialVersionUID = 1L;
            private final int dx;
            private final int dy;
    
            public PanDirectionBehavior(final String event, final int dx, final int dy)
            {
                super(event);
                this.dx = dx;
                this.dy = dy;
            }
    
            @Override
            protected String getJSinvoke()
            {
                return getJSpanDirection(dx, dy);
            }
        }
    
        public class SetZoomBehavior extends JSMethodBehavior
        {
            private static final long serialVersionUID = 1L;
            private final int zoomBehavior;
    
            public SetZoomBehavior(final String event, final int zoom)
            {
                super(event);
                zoomBehavior = zoom;
            }
    
            @Override
            protected String getJSinvoke()
            {
                return getJSsetZoom(zoomBehavior);
            }
        }
    
        public class SetCenterBehavior extends JSMethodBehavior
        {
            private static final long serialVersionUID = 1L;
            private final GLatLng gLatLng;
    
            public SetCenterBehavior(final String event, final GLatLng gLatLng)
            {
                super(event);
                this.gLatLng = gLatLng;
            }
    
            @Override
            protected String getJSinvoke()
            {
                return getJSsetCenter(gLatLng);
            }
        }
    
        public class SetMapTypeBehavior extends JSMethodBehavior
        {
            private static final long serialVersionUID = 1L;
            private final GMapType mapTypeBehavior;
    
            public SetMapTypeBehavior(final String event, final GMapType mapType)
            {
                super(event);
                mapTypeBehavior = mapType;
            }
    
            @Override
            protected String getJSinvoke()
            {
                return mapTypeBehavior.getJSsetMapType(GMap.this);
            }
        }
    
        public class OverlayListener extends AbstractDefaultAjaxBehavior
        {
            private static final long serialVersionUID = 1L;
    
            @Override
            protected void respond(final AjaxRequestTarget target)
            {
                final Request request = RequestCycle.get().getRequest();
    
                final String overlayId = request.getRequestParameters().getParameterValue("overlay.overlayId").toString().replace("overlay", "");
                final String event = request.getRequestParameters().getParameterValue("overlay.event").toString();
                final GOverlay overlay = overlays.get(overlayId);
                if (overlay != null)
                {
                    overlay.onEvent(target, GEvent.valueOf(event));
                }
            }
    
            public Object getJSinit()
            {
                return GMap.this.getJSinvoke("overlayListenerCallbackUrl = '" + this.getCallbackUrl() + "'");
    
            }
        }
    
    	public boolean isFailSilently() {
    		return failSilently;
    	}
    
    	public void setFailSilently(boolean failSilently) {
    		this.failSilently = failSilently;
    	}
    }
    

     看下怎么往地图上添加标记,可以看到我们不用直接在客户端写JS,服务端操作即可:

    	private GMap buildGui() {
    
    		final EntityModel model = getModel();
    		final ObjectAdapter adapter = model.getObject();
    		Location l = (Location) adapter.getObject();
    		GLatLng latLng = new GLatLng(l.getLatitude(), l.getLongitude());
    
    		final boolean visible = latLng != null;
    
    		final GMap map = new GMap(ID_MAP, apiKey);
    		// map.setStreetViewControlEnabled(true);
    		map.setScaleControlEnabled(false);
    		map.setPanControlEnabled(false);
    		map.setDoubleClickZoomEnabled(false);
    		map.setZoom(17);
    
    		if (visible) {
    
    			// centre the map on the first object that has a location.
    			map.setCenter(latLng);
    		}
    
    		addOrReplace(map);
    
    		addMarker(map, adapter);
    
    		return map;
    	}
    
    	private void addMarker(final GMap map, ObjectAdapter adapter) {
    
    		ObjectAdapter dereferencedAdapter = dereference(adapter);
    
    		final GMarker gMarker = createGMarker(map, adapter, dereferencedAdapter);
    		if (gMarker != null) {
    			map.addOverlay(gMarker);
    			// addClickListener(gMarker, dereferencedAdapter);
    		}
    		List<GLatLng> glatLngsToShow = Lists.newArrayList();
    		map.fitMarkers(glatLngsToShow);
    	}
    

    下边开始尝试替换相应的内容:

    GMapHeaderContributor类,改成高德的接口

    public class GMapHeaderContributor extends Behavior {
    
    	private static final long serialVersionUID = 1L;
    	// URL for Google Maps' API endpoint.
    	private static final String GMAP_API_URL = "%s://webapi.amap.com/maps?v=1.3&key=%s";
    	private static final String HTTP = "http";
    	// We have some custom Javascript.
    	private static final ResourceReference WICKET_GMAP_JS = new JavaScriptResourceReference(GMap.class,
    			"wicket-gmap.js");
    
    //...
    }
    

    wicket-gmap.js

    //...
    //地图对象的实例化
    function WicketClientGeocoder() {
    
        this.coder = new AMap.Geocoder();
    
        this.getLatLng = function(callBack, addressId){
        
            var address = Wicket.$(addressId).value;
            
            this.coder.geocode({
                'address': address
            }, function(results, status){
            
                var params = {};
                if (status == AMap.GeocoderStatus.OK) {
                    params['address'] = results[0].formatted_address;
                    params['coordinates'] = results[0].geometry.location;
                    params['status'] = status;
                }
                
                for ( var key in params) {
                    callBack = callBack + '&' + key + '=' + params[key];
                }
                
                Wicket.Ajax.ajax({
                    'u':callBack, 
                    'ep': params
                });
            });
        }
    }
    
    //其它API有差异的地方也相应的改一下,此处略
    //...
    

    实现集合页UI适配工厂:

    /*
     *  Copyright 2013~2014 Dan Haywood
     *
     *  Licensed under the Apache License, Version 2.0 (the
     *  "License"); you may not use this file except in compliance
     *  with the License.  You may obtain a copy of the License at
     *
     *        http://www.apache.org/licenses/LICENSE-2.0
     *
     *  Unless required by applicable law or agreed to in writing,
     *  software distributed under the License is distributed on an
     *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
     *  KIND, either express or implied.  See the License for the
     *  specific language governing permissions and limitations
     *  under the License.
     */
    package com.itisys.map.ui;
    
    import java.io.IOException;
    import java.net.HttpURLConnection;
    import java.net.URL;
    import java.net.UnknownHostException;
    
    import org.apache.isis.core.commons.config.IsisConfiguration;
    import org.apache.isis.core.metamodel.spec.ObjectSpecification;
    import org.apache.isis.core.metamodel.specloader.SpecificationLoader;
    import org.apache.isis.core.runtime.system.context.IsisContext;
    import org.apache.isis.viewer.wicket.model.models.EntityCollectionModel;
    import org.apache.isis.viewer.wicket.ui.CollectionContentsAsFactory;
    import org.apache.isis.viewer.wicket.ui.ComponentFactoryAbstract;
    import org.apache.isis.viewer.wicket.ui.ComponentType;
    import org.apache.wicket.Component;
    import org.apache.wicket.model.IModel;
    import org.apache.wicket.model.Model;
    
    import com.itisys.map.applib.AmapApplibConstants;
    import com.itisys.map.applib.Locatable;
    
    public class CollectionOfEntitiesAsLocatablesFactory extends ComponentFactoryAbstract implements CollectionContentsAsFactory {
    
        private static final long serialVersionUID = 1L;
    
        private static final String ID_MAP = "map";
    
        private boolean determinedWhetherInternetReachable;
        private boolean internetReachable;
    
        public CollectionOfEntitiesAsLocatablesFactory() {
            super(ComponentType.COLLECTION_CONTENTS, ID_MAP);
        }
    
        @Override
        public ApplicationAdvice appliesTo(IModel<?> model) {
    
            final String apiKey = getConfiguration().getString(AmapApplibConstants.API_KEY);
            if(apiKey == null) {
                return ApplicationAdvice.DOES_NOT_APPLY;
            }
    
            if(!internetReachable()) {
                return ApplicationAdvice.DOES_NOT_APPLY;
            }
            
            if (!(model instanceof EntityCollectionModel)) {
                return ApplicationAdvice.DOES_NOT_APPLY;
            }
    
            EntityCollectionModel entityCollectionModel = (EntityCollectionModel) model;
    
            ObjectSpecification typeOfSpec = entityCollectionModel.getTypeOfSpecification();
            ObjectSpecification locatableSpec = getSpecificationLoader().loadSpecification(Locatable.class);
            return appliesIf(typeOfSpec.isOfType(locatableSpec));
        }
    
        private boolean internetReachable() {
            if(!determinedWhetherInternetReachable) {
                internetReachable = isInternetReachable();
                determinedWhetherInternetReachable = true;
            }
            return internetReachable;
        }
        
        /**
         * Tries to retrieve some content, 1 second timeout.
         */
        private static boolean isInternetReachable()
        {
            try {
                final URL url = new URL("http://www.amap.com");
                final HttpURLConnection urlConnect = (HttpURLConnection)url.openConnection();
                urlConnect.setConnectTimeout(1000);
                urlConnect.getContent();
                urlConnect.disconnect();
            } catch (UnknownHostException e) {
                return false;
            } catch (IOException e) {
                return false;
            }
            return true;
        }
    
        public Component createComponent(String id, IModel<?> model) {
    
            final String apiKey = getConfiguration().getString(AmapApplibConstants.API_KEY);
    
            EntityCollectionModel collectionModel = (EntityCollectionModel) model;
            return new CollectionOfEntitiesAsLocatables(id, apiKey, collectionModel);
        }
    
        protected SpecificationLoader getSpecificationLoader() {
            return IsisContext.getSessionFactory().getSpecificationLoader();
        }
    
        protected IsisConfiguration getConfiguration() {
            return IsisContext.getSessionFactory().getConfiguration();
        }
    
        @Override
        public IModel<String> getTitleLabel() {
            return Model.of("Map");
        }
    
        @Override
        public IModel<String> getCssClass() {
            return Model.of("fa fa-map-marker");
        }
    
    }
    

    实现实体属性UI适配:

    /*
     *  Copyright 2013~2014 Dan Haywood
     *
     *  Licensed under the Apache License, Version 2.0 (the
     *  "License"); you may not use this file except in compliance
     *  with the License.  You may obtain a copy of the License at
     *
     *        http://www.apache.org/licenses/LICENSE-2.0
     *
     *  Unless required by applicable law or agreed to in writing,
     *  software distributed under the License is distributed on an
     *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
     *  KIND, either express or implied.  See the License for the
     *  specific language governing permissions and limitations
     *  under the License.
     */
    package com.itisys.map.ui;
    
    import org.apache.isis.core.commons.config.IsisConfiguration;
    import org.apache.isis.core.metamodel.specloader.SpecificationLoader;
    import org.apache.isis.core.runtime.system.context.IsisContext;
    import org.apache.isis.viewer.wicket.model.models.ScalarModel;
    import org.apache.isis.viewer.wicket.ui.components.scalars.ComponentFactoryScalarAbstract;
    import org.apache.wicket.Component;
    
    import com.itisys.map.applib.AmapApplibConstants;
    import com.itisys.map.applib.Location;
    
    public class EntityAsLocatablesFactory extends ComponentFactoryScalarAbstract {
    
    	private static final long serialVersionUID = 1L;
    
    	private static final String ID_MAP = "map";
    
    	public EntityAsLocatablesFactory() {
    		super(EntityAsLocatables.class, Location.class);
    	}
    
    	protected SpecificationLoader getSpecificationLoader() {
    		return IsisContext.getSessionFactory().getSpecificationLoader();
    	}
    
    	protected IsisConfiguration getConfiguration() {
    		return IsisContext.getSessionFactory().getConfiguration();
    	}
    
    	@Override
    	protected Component createComponent(String id, ScalarModel scalarModel) {
            final String apiKey = getConfiguration().getString(AmapApplibConstants.API_KEY);
    		return new EntityAsLocatables(id,apiKey, scalarModel);
    	}
    
    }
    
  • 相关阅读:
    一些我遇到前端方面的问题和解决方法
    Effective Objective-C 2.0学习记录(二)
    Effective Objective-C 2.0学习(一)
    加快Xcode运行速度
    JPA CriteriaBuilder的简单使用
    日志切分
    iOS并发,串行,异步,同步
    服务重启脚本
    简述http/https加密和认证方式
    nohup的使用
  • 原文地址:https://www.cnblogs.com/icoolno1/p/7354349.html
Copyright © 2011-2022 走看看