openlayer开发&从Geoserver服务为wfs增加要素的源码分析

类似这样的例子应该是在很早之前就有接触了,同事当时展示了一个在app端绘制一个面,然后在web端能够展示出来,这过程不需要重新去发布地图服务,应该说这样的功能,在ogc服务中,就是wfs。而现在之所以回想到了之前的情景,是因为有小伙伴在openlayer中使用Geoserver发布的wfs要素服务,包了如下的错误。估计一时没有找到解决办法。

一开始,主要对了相应的参数进行检测。那么我们来看一下。我们的请求。在下面的这段代码中可以看到几个参数,需要细致的修改

     //创建feature
 var newFeature = new ol.Feature();
      newFeature.setGeometryName('the_geom');
      newFeature.setGeometry(new ol.geom.MultiPolygon([[[116.22,31.78],[117.23,31.78],[117.22,31.79],[116.22,31.78]]]));
      //newFeature.setGeometry(polygon);
      newFeature.set('OBJECTID',14);
      newFeature.set('wg', 'sswg14');
      newFeature.set('wgy', 'sswgy14');
      newFeature.set('bm', 'ssbm14');
      newFeature.set('wey', 'sswey14');
      newFeature.set('Id', 14);
      newFeature.set('SSWG', 'ssSSWG14');
      newFeature.set('SSJD', 'ssSSJD14');
      newFeature.set('SQMC', 'ssSQMC14');
      newFeature.set('FIRST_Id',14);
      newFeature.set('Shape_Leng', 14.14);
      newFeature.set('Shape_Area', 14.235);
    AddWfsFeature([newFeature]);

 AddWfsFeature([newFeature]);
    function AddWfsFeature(features) {
        var WFSTSerializer = new ol.format.WFS();
        var featObject = WFSTSerializer.writeTransaction(features,
            null, null, {
                featureType: 'lianhua',
                featureNS: 'http://localhost:8088/geoserver/',
                srsName: 'EPSG:4326'
            });
        var serializer = new XMLSerializer();
        var featString = serializer.serializeToString(featObject);
        var request = new XMLHttpRequest();
        request.open('POST', 'http://localhost:8088/geoserver/wfs?service=wfs');
        request.setRequestHeader('Content-Type', 'text/xml');
        request.send(featString);
    }

在Geoserver中,可以看到如下的发布图层。现在我们需要找到sde的工作空间。

切换到数据存储。如下图所示。

然后找到sde目录。下面的【命名】需要在上面请求代码的featurePrefix,【命名空间URL】则对应我们的featureNS

 

如果填写正确在这里,会报出空间信息错误。来看一下Geoserver是如何对工作空间进行检测的。

我们来看一下代码,对WFS工作空间查询类WFSWorkspaceQualifier类。特别需要注意的下面的qualifyRequest函数。

public class WFSWorkspaceQualifier extends WorkspaceQualifyingCallback {

    public WFSWorkspaceQualifier(Catalog catalog) {
        super(catalog);
    }

    @Override
    protected void qualifyRequest(
            WorkspaceInfo workspace, PublishedInfo layer, Service service, Request request) {
        if (request.getContext() != null) {
            // if a qualifying workspace exist, try to qualify the request typename
            // parameter, if present
            if (workspace != null && request.getKvp().containsKey("TYPENAME")) {
                Iterable typeNames = (Iterable) request.getKvp().get("TYPENAME");
                NamespaceInfo ns = catalog.getNamespaceByPrefix(workspace.getName());
                if (ns != null) {
                    List<QName> qualifiedNames = new ArrayList<QName>();
                    for (Object name : typeNames) {
                        if (name != null && name instanceof QName) {
                            QName typeName = (QName) name;
                            // no namespace specified, we can qualify
                            if (typeName.getNamespaceURI() == null
                                    || typeName.getNamespaceURI().equals("")) {
                                typeName = new QName(ns.getURI(), typeName.getLocalPart());
                            } else if (typeName.getNamespaceURI()
                                            .equals(catalog.getDefaultNamespace().getURI())
                                    || !typeName.getNamespaceURI().equals(ns.getURI())) {
                                // more complex case, if we have the default
                                // namespace, we have to check if it's been
                                // specified on the request, or assigned by parser
                                typeName = checkOriginallyUnqualified(request, ns, typeName);
                            }
                            qualifiedNames.add(typeName);
                        }
                    }
                    request.getKvp().put("TYPENAME", qualifiedNames);
                }
            }
        }
    }

    /**
     * Checks if the typeName default namespace is present in the original request, or it has been
     * overridden by parser. If it's been overridden we can qualify with the given namespace.
     *
     * @param request
     * @param ns
     * @param typeName
     */
    private QName checkOriginallyUnqualified(Request request, NamespaceInfo ns, QName typeName) {
        Map<String, String[]> originalParams = request.getHttpRequest().getParameterMap();
        for (String paramName : originalParams.keySet()) {
            if (paramName.equalsIgnoreCase("TYPENAME")) {
                for (String originalTypeName : originalParams.get(paramName)) {
                    if (originalTypeName.equals(typeName.getLocalPart())) {
                        // the original typeName was not
                        // qualified, we can qualify it
                        typeName = new QName(ns.getURI(), typeName.getLocalPart());
                    }
                }
            }
        }
        return typeName;
    }

    @Override
    protected void qualifyRequest(
            WorkspaceInfo workspace, PublishedInfo layer, Operation operation, Request request) {
        NamespaceInfo ns = catalog.getNamespaceByPrefix(workspace.getName());

        GetCapabilitiesRequest caps =
                GetCapabilitiesRequest.adapt(
                        OwsUtils.parameter(operation.getParameters(), EObject.class));
        if (caps != null) {
            caps.setNamespace(workspace.getName());
            return;
        }

        DescribeFeatureTypeRequest dft =
                DescribeFeatureTypeRequest.adapt(
                        OwsUtils.parameter(operation.getParameters(), EObject.class));
        if (dft != null) {
            qualifyTypeNames(dft.getTypeNames(), workspace, ns);
            return;
        }

        GetFeatureRequest gf =
                GetFeatureRequest.adapt(
                        OwsUtils.parameter(operation.getParameters(), EObject.class));
        if (gf != null) {
            for (Query q : gf.getQueries()) {
                // in case of stored query usage the typenames might be null
                if (q.getTypeNames() != null) {
                    qualifyTypeNames(q.getTypeNames(), workspace, ns);
                }
            }
            return;
        }

        LockFeatureRequest lf =
                LockFeatureRequest.adapt(
                        OwsUtils.parameter(operation.getParameters(), EObject.class));
        if (lf != null) {
            for (Lock lock : lf.getLocks()) {
                lock.setTypeName(qualifyTypeName(lock.getTypeName(), workspace, ns));
            }
            return;
        }

        TransactionRequest t =
                TransactionRequest.adapt(
                        OwsUtils.parameter(operation.getParameters(), EObject.class));
        if (t != null) {
            for (TransactionElement el : t.getElements()) {
                if (el instanceof Insert) {
                    Insert in = (Insert) el;
                    // in the insert case the objects are gt feature types which are not mutable
                    // so we just check them and throw an exception if a name does not match
                    List features = in.getFeatures();
                    ensureFeatureNamespaceUriMatches(features, ns, t);
                } else if (el instanceof Replace) {
                    Replace rep = (Replace) el;
                    // in the replace case the objects are gt feature types which are not mutable
                    // so we just check them and throw an exception if a name does not match
                    List features = rep.getFeatures();
                    ensureFeatureNamespaceUriMatches(features, ns, t);
                } else {
                    el.setTypeName(qualifyTypeName(el.getTypeName(), workspace, ns));
                }
            }
        }
    }

    /**
     * Iterates the given features and ensures their namespaceURI matches the given namespace
     *
     * @param features
     * @param ns
     * @param t
     */
    private void ensureFeatureNamespaceUriMatches(
            List features, NamespaceInfo ns, TransactionRequest t) {
        for (Iterator j = features.iterator(); j.hasNext(); ) {
            Object next = j.next();
            if (next instanceof Feature) {
                Feature f = (Feature) next;
                Name n = f.getType().getName();
                if (n.getNamespaceURI() != null && !ns.getURI().equals(n.getNamespaceURI())) {
                    throw new WFSException(t, "No such feature type " + n);
                }
            }
        }
    }

    void qualifyTypeNames(List names, WorkspaceInfo ws, NamespaceInfo ns) {
        if (names != null) {
            for (int i = 0; i < names.size(); i++) {
                QName name = (QName) names.get(i);
                names.set(i, qualifyTypeName(name, ws, ns));
            }
        }
    }

    QName qualifyTypeName(QName name, WorkspaceInfo ws, NamespaceInfo ns) {
        if (name != null) {
            return new QName(ns.getURI(), name.getLocalPart(), ws.getName());
        }
        return null;
    }
}

在qualifyRequest函数中,我们可以看到正确的工作空间和表。

我们再来看一下,使用到的函数。从这里可以看得出使用features进行了遍历,然后取出相应的工作空间来比对。

    private void ensureFeatureNamespaceUriMatches(
            List features, NamespaceInfo ns, TransactionRequest t) {
        for (Iterator j = features.iterator(); j.hasNext(); ) {
            Object next = j.next();
            if (next instanceof Feature) {
                Feature f = (Feature) next;
                Name n = f.getType().getName();
                if (n.getNamespaceURI() != null && !ns.getURI().equals(n.getNamespaceURI())) {
                    throw new WFSException(t, "No such feature type " + n);
                }
            }
        }
    }

而我们这里填写的是这样的工作空间。如下,显然是不对的。因为匹配不到发布的WFS要素服务的命名空间。

好了,修改好上面的工作空间后,我们再来看一下其他的参数请求。根据上面报错信息,进入到错误的提示位置。在visit方法中,出现了报错信息,大意是不能为空的字符进行数据的转换。

    public void visit(Binding binding) {
        Class bindingClass;
        if (!(binding instanceof InstanceBinding)) {
            bindingClass = binding.getClass();
            QName bindingTarget = binding.getTarget();
            binding = (Binding)this.context.getComponentInstanceOfType(binding.getClass());
            if (binding == null) {
                binding = this.parser.getBindingLoader().loadBinding(bindingTarget, this.context);
                if (binding == null) {
                    binding = this.parser.getBindingLoader().loadBinding(bindingTarget, bindingClass, this.context);
                }

                if (binding.getClass() != bindingClass) {
                    throw new IllegalStateException("Reloaded binding resulted in different type, from " + bindingClass + " to " + binding.getClass());
                }
            }
        }

        try {
            if (this.result == null) {
                bindingClass = null;
                XSDTypeDefinition type;
                if (Schemas.nameMatches(this.instance.getDeclaration(), binding.getTarget())) {
                    type = this.instance.getTypeDefinition();
                } else {
                    type = Schemas.getBaseTypeDefinition(this.instance.getTypeDefinition(), binding.getTarget());
                }

                if (this.value == null) {
                    this.value = this.preParse(this.instance);
                    if (type != null && (type instanceof XSDSimpleTypeDefinition || ((XSDComplexTypeDefinition)type).isMixed())) {
                        this.result = this.value;
                    } else if (this.value != null && this.value instanceof String) {
                        if ("".equals(((String)this.value).trim())) {
                            this.result = null;
                        } else {
                            this.result = this.value;
                        }
                    } else {
                        this.result = this.value;
                    }
                }
            }

            if (binding instanceof SimpleBinding) {
                this.result = ((SimpleBinding)binding).parse(this.instance, this.result);
            } else {
                this.result = ((ComplexBinding)binding).parse((ElementInstance)this.instance, this.node, this.result);
            }

            if (this.result != null) {
                this.value = this.result;
            }

        } catch (Throwable var4) {
            String msg = "Parsing failed for " + this.instance.getName() + ": " + var4.toString();
            throw new RuntimeException(msg, var4);
        }
    }

好了,到上面的这一步就很是奇怪。因通过下面的代码可以看到能够解析到坐标系epsg:4326。

    public void startElement(QName qName, Attributes attributes) throws SAXException {
        List atts = new ArrayList();

        int i;
        for(i = 0; i < attributes.getLength(); ++i) {
            String rawAttQName = attributes.getQName(i);
            String prefix;
            String uri;
            if (rawAttQName != null) {
                if (rawAttQName.startsWith("xmlns:")) {
                    continue;
                }

                if (rawAttQName.endsWith("schemaLocation")) {
                    prefix = "";
                    if (rawAttQName.indexOf(58) != -1) {
                        prefix = rawAttQName.substring(0, rawAttQName.indexOf(58));
                    }

                    uri = this.parser.getNamespaceSupport().getURI(prefix);
                    if (uri != null && uri.equals("http://www.w3.org/2001/XMLSchema-instance")) {
                        continue;
                    }
                }
            }

            prefix = attributes.getURI(i);
            uri = attributes.getLocalName(i);
            QName attQName = new QName(prefix, uri);
            XSDAttributeDeclaration decl = Schemas.getAttributeDeclaration(this.content, attQName);
            if (decl == null && !this.parser.isStrict()) {
                if (this.parser.getLogger().isLoggable(Level.FINE)) {
                    this.parser.getLogger().fine("Parsing unknown attribute: " + attQName);
                }

                decl = XSDFactory.eINSTANCE.createXSDAttributeDeclaration();
                decl.setName(attQName.getLocalPart());
                decl.setTargetNamespace(attQName.getNamespaceURI());
                XSDSimpleTypeDefinition type = (XSDSimpleTypeDefinition)XSDUtil.getSchemaForSchema("http://www.w3.org/2001/XMLSchema").getSimpleTypeIdMap().get("string");
                decl.setTypeDefinition(type);
            }

            if (decl != null) {
                AttributeInstance att = new AttributeImpl(decl);
                att.setNamespace(decl.getTargetNamespace());
                att.setName(decl.getName());
                att.setText(attributes.getValue(i));
                atts.add(att);
            } else {
                this.parser.getLogger().warning("Could not find attribute declaration: " + attQName);
            }
        }

        this.element = new ElementImpl(this.content);
        this.element.setNamespace(qName.getNamespaceURI());
        this.element.setName(qName.getLocalPart());
        this.element.setAttributes((AttributeInstance[])((AttributeInstance[])atts.toArray(new AttributeInstance[atts.size()])));
        this.node = new NodeImpl(this.element);

        for(i = 0; i < this.element.getAttributes().length; ++i) {
            AttributeInstance attribute = this.element.getAttributes()[i];
            ParseExecutor executor = new ParseExecutor(attribute, (Node)null, this.parent.getContext(), this.parser);
            this.parser.getBindingWalker().walk(attribute.getAttributeDeclaration(), executor, this.parent.getContext());
            Object parsed = executor.getValue();
            this.node.addAttribute(new NodeImpl(attribute, parsed));
        }

        ElementInitializer initer = new ElementInitializer(this.element, this.node, this.parent.getContext());
        this.parser.getBindingWalker().walk(this.element.getElementDeclaration(), initer, this.container(), this.parent.getContext());
        this.setContext(new DefaultPicoContainer(this.parent.getContext()));
        ((BindingFactoryImpl)this.parser.getBindingFactory()).setContext(this.getContext());
        this.parent.startChildHandler(this);
    }

来看一下请求的结果。

走到这一步后,我们来看一下我们的请求。

对应的xml文件为。解析到epsg:4326就出错了。不过很是奇怪的是,这个请求中居然没有坐标信息,那么我们会不是我们的构建geometry对象出现了问题。

来看一下构建的geometry,其是一个MultiPolygon,而我们写的代码为:

newFeature.setGeometry(new ol.geom.MultiPolygon([[[116.22,31.78],[117.23,31.78],[117.22,31.79],[116.22,31.78]]]));

后面经过反复比较,哦,找到了问题了。由于小伙伴的粗心,没有正确的构造出geometry。正确的方式为。注意外部多一组中括号。

newFeature.setGeometry(new ol.geom.MultiPolygon([[[[116.22,31.78],[117.23,31.78],[117.22,31.79],[116.22,31.78]]]]));

 

这下我们再次来看一下请求信息。

但是,没有正确,在上面的请求中范围中,排布的方式为纬度、经度的方式。相应的,我们要做调整。最后经过请求后,

http://localhost:8080/geoserver/sde/wfs?service=WFS&version=1.0.0&request=GetFeature&typeName=sde:lianhua

我们可以看到这样的数据。下面的这条即为我们新填的数据。

好了,我们来看一下新添加的wfs服务吧



                                  更多内容,请微信扫二维码关注公众号,或者加入Geoserver技术交流群:1019869405

                                                                                  

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

yGIS

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值