Spring:根据 XSD 架构验证 REST 控制器 [英] Spring: Validate REST controller against XSD schema

查看:21
本文介绍了Spring:根据 XSD 架构验证 REST 控制器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

目前我有带有以下代码的 RestController

At the moment I have RestController with the following code

package be.smartask.api;

import be.smartask.api.model.NumberValue;
import be.smartask.api.model.TextValue;
import be.smartask.api.model.Translations;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;


/**
 * @author Glenn Van Schil
 *         Created on 21/01/2016
 */
@CrossOrigin
@RestController
@RequestMapping(path = "/values")
public class Controller {

    @RequestMapping(method = RequestMethod.POST, headers = "Value-Type=text")
    ResponseEntity<?> createAttribute(@RequestBody TextValue value) {
        System.out.println(value.getCode());
        for (Translations.Translation translation : value.getTranslations().getTranslation()) {
            System.out.println(translation.getLang());
            System.out.println(translation.getValue());
        }
        return new ResponseEntity<>(HttpStatus.CREATED);
    }

    @RequestMapping(method = RequestMethod.POST, headers = "Value-Type=number")
    ResponseEntity<?> createAttribute(@RequestBody NumberValue value) {
        System.out.println(value.getMinValue());
        System.out.println(value.getMaxValue());
        return new ResponseEntity<>(HttpStatus.CREATED);
    }
}

这很好用,我可以像这样发布一个 NumberValue:

This works great, I can post a NumberValue like this:

<numberValue id="id" minValue="0" maxValue="10"/>

但是当我将 TextValue 发布到 NumberValue 方法时

But when I post a TextValue to NumberValue method

<textvalue code="LUXE">
    <translations>
        <translation lang="en">luxury car</translation>
    </translations>
</textvalue>

它仍然有效.它只是将 minValue 和 maxValue 保留为 0,0.

It still works. It just leaves the minValue and maxValue to 0,0.

我的问题是:当正文与我的 xsd 文件中定义的不完全相同时,我如何强制执行 400: Bad Request(或类似的请求)?通过定义,我的意思是 xml 标记的名称不相同或缺少所需的 xs:attribute,...

我的 xsd 文件:

<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified"
           xmlns:xs="http://www.w3.org/2001/XMLSchema">

            <!-- ValueVO -->
    <xs:complexType name="geopoint">
        <xs:attribute type="xs:double" name="lat"/>
        <xs:attribute type="xs:double" name="lon"/>
    </xs:complexType>

    <xs:complexType name="translations">
        <xs:sequence>
            <xs:element name="translation" minOccurs="0" maxOccurs="unbounded">
                <xs:complexType>
                    <xs:simpleContent>
                        <xs:extension base="xs:string">
                            <xs:attribute type="xs:string" name="lang" use="required"/>
                        </xs:extension>
                    </xs:simpleContent>
                </xs:complexType>
            </xs:element>
        </xs:sequence>
    </xs:complexType>

    <xs:complexType name="value">
        <xs:attribute type="xs:string" name="id" use="required"/>
    </xs:complexType>

    <xs:complexType name="textValue">
        <xs:complexContent>
            <xs:extension base="value">
                <xs:sequence>
                    <xs:element type="translations" name="translations"/>
                </xs:sequence>
                <xs:attribute type="xs:string" name="code" use="required"/>
            </xs:extension>
        </xs:complexContent>
    </xs:complexType>

    <xs:complexType name="numberValue">
        <xs:complexContent>
            <xs:extension base="value">
                <xs:attribute type="xs:double" name="minValue" use="required"/>
                <xs:attribute type="xs:double" name="maxValue" use="required"/>
            </xs:extension>
        </xs:complexContent>
    </xs:complexType>

    <xs:complexType name="dateValue">
        <xs:complexContent>
            <xs:extension base="value">
                <xs:attribute type="xs:date" name="minValue" use="required"/>
                <xs:attribute type="xs:date" name="maxValue" use="required"/>
            </xs:extension>
        </xs:complexContent>
    </xs:complexType>

    <xs:complexType name="cityValue">
        <xs:complexContent>
            <xs:extension base="value">
                <xs:sequence>
                    <xs:element type="geopoint" name="geopoint"/>
                    <xs:element type="translations" name="translations"/>
                </xs:sequence>
            </xs:extension>
        </xs:complexContent>
    </xs:complexType>

    <xs:complexType name="timeValue">
        <xs:complexContent>
            <xs:extension base="value"/>
        </xs:complexContent>
    </xs:complexType>

    <xs:element name="value" type="value"/>
    <xs:element name="textValue" type="textValue"/>
    <xs:element name="numberValue" type="numberValue"/>
    <xs:element name="dateValue" type="dateValue"/>
    <xs:element name="cityValue" type="cityValue"/>
    <xs:element name="timeValue" type="timeValue"/>

    <xs:element name="values">
        <xs:complexType>
            <xs:sequence>
                <xs:element ref="value" maxOccurs="unbounded" minOccurs="0"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
    <!-- END ValueVO --> 
</xs:schema>

更新

我根据 Sheetal Mohan Sharma 的回答在我的 spring 配置中添加了以下内容

UPDATE

I added the following to my spring config based on Sheetal Mohan Sharma's answer

<?xml version="1.0" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd


http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">

    <context:component-scan base-package="be.smartask.api"/>

    <mvc:annotation-driven/>

    <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>

    <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
        <property name="messageConverters">
            <list>
                <ref bean="marshallingHttpMessageConverter"/>
                <bean class="org.springframework.http.converter.StringHttpMessageConverter"/>
            </list>
        </property>
    </bean>

    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
    </bean>
    <bean id="marshallingHttpMessageConverter"
          class="org.springframework.http.converter.xml.MarshallingHttpMessageConverter"
          p:marshaller-ref="jaxb2Marshaller" p:unmarshaller-ref="jaxb2Marshaller"/>

    <bean id="jaxb2Marshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
        <property name="schema" value="classpath:schema/xsd/smartaskRead.xsd"/>
        <property name="classesToBeBound">
            <list>
                <value>be.smartask.api.model.NumberValue</value>
                <value>be.smartask.api.model.TextValue</value>
            </list>
        </property>
    </bean>
</beans>

但 NumberValue 仍然接受 TextValue...

But NumberValue still accepts TextValue...

推荐答案

通过在 XSD 文件中提供命名空间,即使使用 API 版本控制,我们也设法做到了这一点

We managed to do this even with API versioning by providing the namespace inside the XSD files

配置文件

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
        http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.2.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd">

    <context:component-scan base-package="be.smartask.api"/>

    <context:annotation-config/>

    <mvc:cors>
        <mvc:mapping path="/**"/>
    </mvc:cors>

    <mvc:annotation-driven>
        <mvc:message-converters>
            <bean id="marshallingHttpMessageConverter"
                  class="org.springframework.http.converter.xml.MarshallingHttpMessageConverter">
                <property name="marshaller" ref="jaxb2Marshaller"/>
                <property name="unmarshaller" ref="jaxb2Marshaller"/>
            </bean>
        </mvc:message-converters>
    </mvc:annotation-driven>

    <bean id="jaxb2Marshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
        <property name="schemas">
          <list>
            <value>classpath:/schema/xsd/v1/smartAsk.xsd</value>
            <value>classpath:/schema/xsd/v2/smartAsk.xsd</value>
          </list>
        </property>
        <property name="packagesToScan">
          <list>
            <value>be.smartask.api.model.smartask.v1</value>
            <value>be.smartask.api.model.smartask.v2</value>
          </list>
        </property>
    </bean>

    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/view/"/>
        <property name="suffix" value=".jsp"/>
    </bean>
</beans>

首先提供架构位置,然后生成 xsd 对象的包位置,最后使用新创建的 Jaxb2Marshaller 覆盖 marshallingHttpMessageConverter

First you provide the schema locations, second the the package location of the xsd objects will be generated and last override the marshallingHttpMessageConverter with your newly created Jaxb2Marshaller

如果您打算在 API 中进行一些版本控制,最好提供一个命名空间,以便编组器知道哪个 xsd 文件用于哪个包

If you plan on doing some versioning in your API it's best to supply a namespace so the marshaller know which xsd file to use for which package

<xs:schema xmlns="smartask:v1"
       xmlns:xs="http://www.w3.org/2001/XMLSchema"
       xmlns:xsd="http://www.w3.org/2001/XMLSchema"
       xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
       xmlns:annox="http://annox.dev.java.net"
       attributeFormDefault="unqualified"
       elementFormDefault="qualified"
       targetNamespace="smartask:v1"
       jaxb:version="2.1"
       jaxb:extensionBindingPrefixes="annox">

<xs:schema xmlns="smartask:v2"
       xmlns:xs="http://www.w3.org/2001/XMLSchema"
       xmlns:xsd="http://www.w3.org/2001/XMLSchema"
       xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
       xmlns:annox="http://annox.dev.java.net"
       attributeFormDefault="unqualified"
       elementFormDefault="qualified"
       targetNamespace="smartask:v2"
       jaxb:version="2.1"
       jaxb:extensionBindingPrefixes="annox">

在我们的例子中是smartask:v1"和smartask:v2"

in our case it was "smartask:v1" and "smartask:v2"

这篇关于Spring:根据 XSD 架构验证 REST 控制器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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