改造springboot支持application/xml请求

改造springboot支持application/xml请求,并同时处理json和xml入参

需求说明:
由于对接,涉及到请求方使用xml做入参,特在前人的基础上进行整理,如下:

资料来源
1.导包

<dependency>
    <groupId>com.fasterxml.jackson.dataformat</groupId>
    <artifactId>jackson-dataformat-xml</artifactId>
    <version>2.9.7</version>
</dependency>
  1. 配置转换器
@Configuration
public class WebConfig implements WebMvcConfigurer {
    //省略部分代码
    .
    .
    .

    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
            Jackson2ObjectMapperBuilder builder = Jackson2ObjectMapperBuilder.xml();
            builder.indentOutput(true);
            converters.add(new MappingJackson2XmlHttpMessageConverter(builder.build()));

    }

注意:参考资料中使用的是实现WebMvcConfigurationSupport ,但会导致WebMvcConfigurer 的实现被覆盖,同时接口层面入参必须使用@RequestParam才能接收,固此处改成单一实现WebMvcConfigurer
3.封装实体 示例如下(这里的xml没有固定格式开头<?xml……>)

//根节点
@JacksonXmlRootElement(localName = "document")
@Data
@NoArgsConstructor
@AllArgsConstructor
//自定义xml入参
public class CreditLoanApproveAckNotifyDto {
    //包含的子节点 使用内部类接收
    @JacksonXmlElementWrapper(localName ="request")
    private Request request;
    @JacksonXmlProperty(localName = "signature")
    private String signature;

    @Data
    //自定义子节点
    @NoArgsConstructor
    @AllArgsConstructor
    public static class Request {
        @JacksonXmlElementWrapper(localName ="head")
        private Header head;
        @JacksonXmlElementWrapper(localName ="body")
        private NotifyDomain body;
    }
}

资料来源
注意:这里的自定义子节点内部类,必须使用static并加上构造方法才能被jackson实例化,完成解析,否则会提示:can only instantiate non-static inner class by using default, no-argument constructor

4.接口改造

 @PostMapping(value = "/test",
            consumes = MediaType.APPLICATION_XML_VALUE,
            produces = MediaType.APPLICATION_XML_VALUE)
    @ResponseBody
    public void getCameraImageTest(@RequestBody CreditLoanApproveAckNotifyDto dto) {

这样就完成了对xml入参的支持.
后续:因为是跟设备供应商对接,更操蛋的出现了,参数类型是application/xml,一个接口有两个请求体,分别是不同的功能被设备供应商整合在一起(其中一个是应我们要求后加的),之前版本的设备用的是一个请求体,有一个参数类型可以区分,且是json的,这一版本用xml,后加的功能请求体内部格式是json(直接拿上一版本的请求体,tm都不改一下),供应商说,“你们拦截一下,自己解析不就行了”,*了狗了,改造如下:(仅适用于自行提取的参数较少的场景,如果需要的参数较多和复杂,建议还是让对方改请求比较合适)
1.过滤器+配置类拦截该接口,其中过滤器主要代码如下

private static final String XML_PREFIX = "<";

private static final String JSON_PREFIX = "{";
@Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest request = null;
        if (servletRequest instanceof HttpServletRequest) {
            request = new BodyReaderHttpServletRequestWrapper((HttpServletRequest) servletRequest);
        }
        if (request == null) {
            chain.doFilter(servletRequest, servletResponse);
            return;
        }
        String contentType = request.getContentType();
        //获取请求参数
        String body = getValue(request);
        if (StringLocalUtil.isEmpty(body)) {
            chain.doFilter(servletRequest, servletResponse);
            return;
        }
        body = body.trim();
        Long timeStamp = System.currentTimeMillis() / 1000;
        //接收自己解析后的参数
        CustomParam customerParam =null;
        //转换请求参数为map
        Map parameterMap = new HashMap(request.getParameterMap());
        if (MediaType.APPLICATION_XML_VALUE.equals(contentType)) {
            //人脸请求
            if (body.startsWith(XML_PREFIX)) {
                parameterMap.put("type", new String[]{"1"});
                //自定义解析xml  readStringXml()就是一个解析xml的方法
                customerParam = readStringXml(body);
            } else if (body.startsWith(JSON_PREFIX)) {
                body = body.replace("\t", "");
                //自定义解析json getCameraByJson()就是一个jackson解析的方法
                customerParam = getCameraByJson(body);
                parameterMap.put("type", new String[]{"3"});
            }
        }
        if (customerParam != null&&customerParam .getTime()!=null) {
            //获取解析后的参数 这是示例而已
            timeStamp = customerParam .getTime;
        }
        //放入参数并重装成新的请求
        parameterMap.put("timeStamp", new String[]{timeStamp.toString()});
        ParameterRequestWrapper newRequest = new ParameterRequestWrapper(request, parameterMap);
        //把请求传递下去
        chain.doFilter(newRequest, servletResponse);
    }
    
     private static String getValue(HttpServletRequest request) {
        String valueStr = "";

        try {
            StringBuffer sb = new StringBuffer();
            InputStream is = request.getInputStream();
            InputStreamReader isr = new InputStreamReader(is);
            BufferedReader br = new BufferedReader(isr);
            String s = "";
            while ((s = br.readLine()) != null) {
                sb.append(s);
            }
            valueStr = sb.toString();
        } catch (IOException e) {
            e.printStackTrace();
            valueStr = "";
        }
        return valueStr;
    }

辅助的参数解析:

public class ParameterRequestWrapper extends HttpServletRequestWrapper {

    private Map params;
    public ParameterRequestWrapper(HttpServletRequest request, Map newParams) {
        super(request);
        this.params = newParams;
    }
    @Override
    public Map getParameterMap() {  return params;    }


    @Override
    public Enumeration getParameterNames() {
        Vector l = new Vector(params.keySet());
        return l.elements();
    }


    @Override
    public String[] getParameterValues(String name) {
        Object v = params.get(name);
        if (v == null) {
            return null;
        } else if (v instanceof String[]) {
            return (String[]) v;
        } else if (v instanceof String) {
            return new String[]{(String) v};
        } else {
            return new String[]{v.toString()};
        }
    }


    @Override
    public String getParameter(String name) {
        Object v = params.get(name);
        if (v == null) {
            return null;
        } else if (v instanceof String[]) {
            String[] strArr = (String[]) v;
            if (strArr.length > 0) {
                return strArr[0];
            } else {
                return null;
            }
        } else if (v instanceof String) {
            return (String) v;
        } else {
            return v.toString();
        }
    }
}

原来的接口:(上面的依赖也都去掉了)

@PostMapping(value = "/test")
public void getCameraImageTest(String timeStamp) {……}

结束了……

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值