You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PrimeFaces Gmap无整体刷新绘制多边形的实现方法

PrimeFaces Gmap 点击绘制多边形不重载组件实现方案

问题背景

使用JSF + PrimeFaces开发集成Gmap组件的应用时,需要实现两个核心需求:

  • 用户点击地图选取顶点即可实时绘制多边形,每次点击后能即时看到多边形构建效果
  • 所有选中的点位数据需要同步到Backing Bean,支持后续持久化存储到数据库

最初按照「每次点击后同步更新地图与Backing Bean模型」的逻辑实现,在<p:ajax>标签中配置了update="@this",但该配置会触发整个Gmap组件完全重载,导致当前地图的平移位置、缩放级别、中心点参数全部重置为初始值,用户每次点击后都要重新缩放、平移回目标绘制区域,操作体验极差。

已知要实现无整体重载的更新需要结合JavaScript,以下是最初的最小复现代码。

初始复现代码

技术栈版本

  • JSF 2.3(Mojarra实现)
  • PrimeFaces 10.0
  • Wildfly 26.1

JSF页面初始代码

<h:head>
    <script type="text/javascript" src="https://maps.google.com/maps/api/js?sensor=true"></script>
</h:head>
<h:body>
    <h:form id="frmMap2"> 
        <p:gmap center="41.381542, 2.122893" 
                zoom="15" 
                type="HYBRID" 
                style="width:100%;height:400px"
                model="#{testMapBean.polygonModel}">
               <p:ajax event="pointSelect" 
                       listener="#{testMapBean.onPointSelect}" 
                       update="@this"/>
        </p:gmap>
    </h:form>
</h:body>

Backing Bean初始代码(ViewScoped作用域)

@Named(value = "testMapBean")
@ViewScoped
public class TestMapBean implements Serializable {

    private MapModel polygonModel;
    
    private Polygon polygon;
    
    public TestMapBean() 
    {
        
    }

    @PostConstruct
    public void init()
    {
        polygonModel = new DefaultMapModel();
 
        polygon = new Polygon();
        polygon.setStrokeColor("#FF9900");
        polygon.setFillColor("#FF9900");
        polygon.setStrokeOpacity(0.7);
        polygon.setFillOpacity(0.7);

        polygonModel.addOverlay(polygon);
    }
     
    public void onPointSelect(PointSelectEvent event) 
    {
        LatLng latlng = event.getLatLng();
        polygon.getPaths().add(latlng);
        
    }
    // 省略公共getter与setter方法
}

最终实现方案

核心思路是彻底移除update="@this"配置,从根源上避免整个Gmap组件重载:前端提前初始化Google Maps原生多边形实例,用户点击选点后仅将坐标传到后端存储,后端拼接JS调用语句直接更新前端原生多边形的路径,全程不触发组件重渲染,地图的缩放级别、平移位置、中心点状态会完全保留。

视图层完整代码

<h:head>
    <script type="text/javascript" 
            src="https://maps.google.com/maps/api/js?sensor=true"></script>
    
    <script type="application/javascript">
        var map;
        var pl;
         
        function initbs()
        { 
            // 通过PrimeFaces widget变量获取地图原生实例
            map = PF('wmaptest').map;
             
            // 初始化原生谷歌地图多边形实例
            pl = new google.maps.Polygon({ 
                strokeColor: "#777777",
                strokeOpacity: 0.8,
                strokeWeight: 2,
                fillColor: "#FF0000",
                fillOpacity: 0.35,
            }); 
        }
            
        // 更新多边形路径的方法
        function drline(coords) 
        {  
            // 将多边形挂载到地图,设置最新坐标路径
            pl.setMap(map);  
            pl.setPath(coords);
        }
        
    </script>
</h:head>
<h:body>
    <h:form id="frmMap2"> 
        <p:gmap widgetVar="wmaptest"
                center="41.381542, 2.122893" 
                zoom="15" 
                type="ROADMAP" 
                style="width:100%;height:800px"> 
                 
                <p:ajax event="pointSelect" 
                        listener="#{testMapBean.onPointSelect}"/>  
        </p:gmap>
    </h:form> 
</h:body>

后端Bean完整代码

@Named(value = "testMapBean")
@ViewScoped
public class TestMapBean implements Serializable {

    // 存储所有选中的多边形顶点
    private Set<LatLng> latLngList = new HashSet<LatLng>();
     
    public TestMapBean() 
    {
    }

    @PostConstruct
    public void init()
    {
        // 页面初始化完成后执行JS初始化方法
        PrimeFaces.current().executeInitScript("initbs()");
    }
      
    /**
     * 拼接JS调用语句,触发前端多边形更新
     */
    public void drawLine()
    { 
        String scriptStr = latLngList.stream()
                        .map(this::toJavaScriptCoord)
                        .collect(Collectors.joining(",", "drline([", "])"));
        
        PrimeFaces.current().executeScript(scriptStr); 
    }

    /**
     * 将后端LatLng对象转为JS可识别的坐标对象字符串
     */
    private String toJavaScriptCoord(LatLng latLng) {
        return "{lat:" + latLng.getLat() + ",lng:" + latLng.getLng() + "}";
    }
    
    /**
     * 地图选点事件监听
     */
    public void onPointSelect(PointSelectEvent event) 
    {
        LatLng latlng = event.getLatLng();
        latLngList.add(latlng);
        // 选点完成后触发前端多边形更新
        drawLine();
    }
    
    // 公共getter与setter
    public Set<LatLng> getLatLngList() {
        return latLngList;
    }

    public void setLatLngList(Set<LatLng> latLngList) {
        this.latLngList = latLngList;
    }
}

内容的提问来源于stack exchange,提问作者Leandro Alsina

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 23:51:22