DubboX rest接口支持XML协议

DubboX的rest服务注册示例:

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

<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
       xmlns="http://www.springframework.org/schema/beans"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd">

    <dubbo:protocol name="rest" 
    				port="6666"
    				threads="500" 
    				contextpath="wyl" 
    				server="tomcat" 
    				accepts="500"
                    extension="com.alibaba.dubbo.rpc.protocol.rest.support.LoggingFilter"/>
	
    <dubbo:service interface="com.wyl.sys.module.client.rest.IDemoRestService" protocol="rest" ref="demoRestService" document="demo" />
</xml>

接口定义:

import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;

@Path("demo")
@Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
@Produces({ MediaType.APPLICATION_JSON + "; " + MediaType.CHARSET_PARAMETER + "=UTF-8",
        MediaType.TEXT_XML + "; " + MediaType.CHARSET_PARAMETER + "=UTF-8" })
public interface IDemoRestService {

    @POST
    @Path("xml")
    String xml(XmlDto dto);

}

Dto定义:

import lombok.Data;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import java.io.Serializable;

@Data
@XmlRootElement(name="wyl")
@XmlAccessorType(XmlAccessType.FIELD)
public class XmlDto implements Serializable {

    @XmlElement(name="name")
    private String name;

    @XmlElement(name="address")
    private String address;

}

请求参数示例:

<xml>
	<name>test</name>
	<address>chain</address>
</xml>

以上为使用javax的xml注解方式来实现XML协议的请求。

由于DubboX的Rest实现不支持使用XStream接收XML类型的入参,具体可查看:

org.jboss.resteasy.spi.ResteasyProviderFactory

各种协议的解析类映射关系可查看:

org.jboss.resteasy.core.MediaTypeMap

其内置支持的provider为:

org.jboss.resteasy.plugins.providers.jaxb.JAXBXmlSeeAlsoProvider
org.jboss.resteasy.plugins.providers.jaxb.JAXBXmlRootElementProvider
org.jboss.resteasy.plugins.providers.jaxb.JAXBXmlTypeProvider
org.jboss.resteasy.plugins.providers.jaxb.CollectionProvider
org.jboss.resteasy.plugins.providers.jaxb.MapProvider
com.alibaba.fastjson.support.jaxrs.FastJsonProvider
org.jboss.resteasy.plugins.providers.DocumentProvider
org.jboss.resteasy.plugins.providers.SourceProvider
org.jboss.resteasy.plugins.providers.jaxb.JAXBElementProvider
org.jboss.resteasy.plugins.providers.DataSourceProvider
org.jboss.resteasy.plugins.providers.StringTextStar
org.jboss.resteasy.plugins.providers.InputStreamProvider
org.jboss.resteasy.plugins.providers.ReaderProvider
org.jboss.resteasy.plugins.providers.ByteArrayProvider
org.jboss.resteasy.plugins.providers.FileProvider

如果要使用XStream,则需要自行对dubbo协议进行扩展。

首先增加XStream解析工具类:

import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.converters.basic.*;
import com.thoughtworks.xstream.converters.collections.CollectionConverter;
import com.thoughtworks.xstream.converters.reflection.PureJavaReflectionProvider;
import com.thoughtworks.xstream.converters.reflection.ReflectionConverter;
import com.thoughtworks.xstream.core.util.QuickWriter;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
import com.thoughtworks.xstream.io.xml.PrettyPrintWriter;
import com.thoughtworks.xstream.io.xml.XppDriver;
import com.thoughtworks.xstream.security.NoTypePermission;
import com.thoughtworks.xstream.security.WildcardTypePermission;

import java.io.Writer;

public class XStreamInitializer {

    public static ClassLoader classLoader;

    public static void setClassLoader(ClassLoader classLoaderInfo) {
        classLoader = classLoaderInfo;
    }

    private static final XppDriver XPP_DRIVER = new XppDriver() {
        @Override
        public HierarchicalStreamWriter createWriter(Writer out) {
            return new PrettyPrintWriter(out, getNameCoder()) {
                private static final String PREFIX_CDATA = "<![CDATA[";
                private static final String SUFFIX_CDATA = "]]>";
                private static final String PREFIX_MEDIA_ID = "<MediaId>";
                private static final String SUFFIX_MEDIA_ID = "</MediaId>";
                private static final String PREFIX_REPLACE_NAME = "<ReplaceName>";
                private static final String SUFFIX_REPLACE_NAME = "</ReplaceName>";

                @Override
                protected void writeText(QuickWriter writer, String text) {
                    if (text.startsWith(PREFIX_CDATA) && text.endsWith(SUFFIX_CDATA)) {
                        writer.write(text);
                    } else if (text.startsWith(PREFIX_MEDIA_ID) && text.endsWith(SUFFIX_MEDIA_ID)) {
                        writer.write(text);
                    } else if (text.startsWith(PREFIX_REPLACE_NAME) && text.endsWith(SUFFIX_REPLACE_NAME)) {
                        writer.write(text);
                    } else {
                        super.writeText(writer, text);
                    }

                }

                @Override
                public String encodeNode(String name) {
                    //防止将_转换成__
                    return name;
                }
            };
        }
    };

    /**
     * Gets instance.
     *
     * @return the instance
     */
    public static XStream getInstance() {
        XStream xstream = new XStream(new PureJavaReflectionProvider(), XPP_DRIVER) {
            // only register the converters we need; other converters generate a private access warning in the console on Java9+...
            @Override
            protected void setupConverters() {
                registerConverter(new NullConverter(), PRIORITY_VERY_HIGH);
                registerConverter(new IntConverter(), PRIORITY_NORMAL);
                registerConverter(new FloatConverter(), PRIORITY_NORMAL);
                registerConverter(new DoubleConverter(), PRIORITY_NORMAL);
                registerConverter(new LongConverter(), PRIORITY_NORMAL);
                registerConverter(new ShortConverter(), PRIORITY_NORMAL);
                registerConverter(new BooleanConverter(), PRIORITY_NORMAL);
                registerConverter(new ByteConverter(), PRIORITY_NORMAL);
                registerConverter(new StringConverter(), PRIORITY_NORMAL);
                registerConverter(new DateConverter(), PRIORITY_NORMAL);
                registerConverter(new CollectionConverter(getMapper()), PRIORITY_NORMAL);
                registerConverter(new ReflectionConverter(getMapper(), getReflectionProvider()), PRIORITY_VERY_LOW);
            }
        };
        xstream.ignoreUnknownElements();
        xstream.setMode(XStream.NO_REFERENCES);
        xstream.autodetectAnnotations(true);
        xstream.addPermission(NoTypePermission.NONE);
        xstream.addPermission(new WildcardTypePermission(new String[]{"com.**"}));
        if (null == classLoader) {
            classLoader = Thread.currentThread().getContextClassLoader();
        }
        xstream.setClassLoader(classLoader);
        return xstream;
    }

}
import com.thoughtworks.xstream.XStream;

import java.util.*;

public class XmlTransformer {

    private static final Map<Class<?>, XStream> CLASS_2_XSTREAM_INSTANCE = new HashMap<>();

    static {
        registerClass(XmlDto.class);
    }

    /**
     * XML转POJO
     */
    @SuppressWarnings("unchecked")
    public static <T> T xmlToPojo(String xml, Class<T> clazz) {
        T object = (T) CLASS_2_XSTREAM_INSTANCE.get(clazz).fromXML(xml);
        return object;
    }

    /**
     * POJO转XML
     */
    public static <T> String pojoToXml(T object, Class<T> clazz) {
        return CLASS_2_XSTREAM_INSTANCE.get(clazz).toXML(object);
    }

    private static void registerClass(Class<?> clz) {
        XStream xstream = XStreamInitializer.getInstance();
        xstream.processAnnotations(clz);
        xstream.processAnnotations(getInnerClasses(clz));
        register(clz, xstream);
    }

    private static Class<?>[] getInnerClasses(Class<?> clz) {
        Class<?>[] innerClasses = clz.getClasses();
        if (innerClasses == null) {
            return null;
        }
        List<Class<?>> result = new ArrayList<>();
        result.addAll(Arrays.asList(innerClasses));
        for (Class<?> inner : innerClasses) {
            Class<?>[] innerClz = getInnerClasses(inner);
            if (innerClz == null) {
                continue;
            }

            result.addAll(Arrays.asList(innerClz));
        }
        return result.toArray(new Class<?>[0]);
    }

    public static void register(Class<?> clz, XStream xStream) {
        CLASS_2_XSTREAM_INSTANCE.put(clz, xStream);
    }

    /**
     * 注册第三方的该类及其子类.
     * 便利第三方类使用 XStreamTransformer进行序列化, 以及支持XStream 1.4.18 以上增加安全许可
     *
     * @param clz 要注册的类
     */
    public static void registerExtendClass(Class<?> clz) {
        XStream xstream = XStreamInitializer.getInstance();

        Class<?>[] innerClz = getInnerClasses(clz);
        xstream.processAnnotations(clz);
        xstream.processAnnotations(innerClz);
        xstream.allowTypes(new Class[]{clz});
        xstream.allowTypes(innerClz);

        register(clz, xstream);
    }

}

新增Dubbo provider(仅为示例)


import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import org.jboss.resteasy.plugins.providers.AbstractEntityProvider;
import javax.ws.rs.Consumes;
import javax.ws.rs.Produces;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.ext.Provider;
import javax.xml.bind.annotation.XmlElement;
import java.io.*;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.nio.charset.StandardCharsets;

@Provider
@Consumes({MediaType.APPLICATION_XML, MediaType.TEXT_XML})
@Produces({MediaType.APPLICATION_XML, MediaType.TEXT_XML})
public class XStreamProvider extends AbstractEntityProvider {

    @Override
    public boolean isReadable(Class type, Type genericType, Annotation[] annotations, MediaType mediaType) {
        return type.isAnnotationPresent(XStreamAlias.class);
    }

    @Override
    public Object readFrom(Class type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap httpHeaders, InputStream entityStream) throws IOException, WebApplicationException {
        StringBuilder sb = new StringBuilder();
        try(BufferedReader reader = new BufferedReader(new InputStreamReader(entityStream))) {
            String line;
            while((line = reader.readLine()) != null) {
                sb.append(line);
            }
        }
        return XmlTransformer.xmlToPojo(sb.toString(), type);
    }

    @Override
    public boolean isWriteable(Class type, Type genericType, Annotation[] annotations, MediaType mediaType) {
        return false;
    }

    @Override
    public void writeTo(Object o, Class type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap httpHeaders, OutputStream entityStream) throws IOException, WebApplicationException {

    }


}

修改DTO上的注解,使用XStream的注解:

import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.Data;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import java.io.Serializable;

@Data
@XStreamAlias("xml")
@XmlAccessorType(XmlAccessType.FIELD)
public class XmlDto implements Serializable {

    @XmlElement(name="name")
    @XStreamAlias("name")
    private String name;

    @XmlElement(name="address")
    @XStreamAlias("address")
    private String address;

}

最后在dubbo的REST服务注册中,添加该扩展:

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

<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
       xmlns="http://www.springframework.org/schema/beans"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
    <dubbo:protocol name="rest" 
    				port="7777"
    				threads="500" 
    				contextpath="eoswpc" 
    				server="tomcat" 
    				accepts="500" 
                   
extension="com.wyl.service.base.provider.XStreamProvider"/>


</xml>

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值