因为Adobe放弃了flash,所以原来基于flex的项目要用H5+js重写。原来的项目是前后端分离的,这次只迁移前端工程,API工程保留。客户要求前端JS通过JSON与API工程交互,而既存的API工程的参数和响应都是xml的。不得已只好在后端工程加拦截器修改request和response了。
修改request和response时,因为request只能读取一次,所以要将内容保存起来,采用装饰类HttpServletRequestWrapper和HttpServletResponseWrapper。json和xml的格式转换使用了 JSON-java 工具集。

此处约定好了前端只发送content-type为application/json的POST请求,如何有其他情况,请考虑是否需要覆盖getParameter getParameterMap getParameterNames getParameterValues等方法。并且filter中要对不同情况进行判断,格式转换也不宜再放到WrapRequest的构造方法里。

web.xml中配置拦截器

web.xml
<filter>
    <filter-name>XmlFilter</filter-name>
    <filter-class>XXX.filter.XmlFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>XmlFilter</filter-name>
    <servlet-name>XxxxServlet</servlet-name>
</filter-mapping>

拦截器代码

Xmlfilter.java
public void doFilter(ServletRequest request, ServletResponse response,
			FilterChain chain) throws IOException, ServletException {

        WrapRequest wreq = new WrapRequest((HttpServletRequest)request);
		WrapResponse wres = new WrapResponse((HttpServletResponse)response);

        chain.doFilter(wreq, wres);

        response.setContentType("application/json;charset=UTF-8");
        response.setCharacterEncoding("UTF-8");
        String xmlData = wres.getData();

        String jsonData = XML.toJSONObject(new String(xmlData)).toString();
        PrintWriter out = response.getWriter();
        out.write(jsonData);
        out.flush();
        out.close();

	}

修改request

WrapRequest.java
public class WrapRequest extends HttpServletRequestWrapper {

	private String _body;
    private HttpServletRequest _request;

    public WrapRequest(HttpServletRequest request) throws IOException
    {
        super(request);
        _request = request;

        StringBuffer jsonStr = new StringBuffer();
        BufferedReader bufferedReader = request.getReader();

        String line;
        while ((line = bufferedReader.readLine()) != null)
            jsonStr.append(line);
        JSONObject data = new JSONObject(jsonStr.toString());
        _body = XML.toString(data);
    }

    @Override
    public ServletInputStream getInputStream() throws IOException
    {
        final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(_body.getBytes());
        return new ServletInputStream()
        {
            public int read() throws IOException
            {
                return byteArrayInputStream.read();
            }
        };
    }

    @Override
    public BufferedReader getReader() throws IOException
    {
        return new BufferedReader(new InputStreamReader(this.getInputStream()));
    }

    @Override
    public String getHeader(String name) {
        String header = super.getHeader(name);
        if(null != name && "Content-Type".equals(name)){
        	return "application/xml";
        }
        return header;
    }

    @Override
    public Enumeration<String> getHeaders(String name) {
        List<String> headerVals = Collections.list(super.getHeaders(name));
        int index = 0;
        for (String value : headerVals) {
            if (null != name && "Content-Type".equalsIgnoreCase(name)) {
                headerVals.set(index, "application/xml");
            }

            index++;
        }

        return Collections.enumeration(headerVals);
    }

    @Override
    public String getContentType(){
    	return this.getHeader("Content-Type");
    }
}

修改response

WrapResponse.java
public class WrapResponse extends HttpServletResponseWrapper {

	private ByteArrayOutputStream out = null;
	private ServletOutputStream stream = null;
	private PrintWriter writer = null;

	public WrapResponse(HttpServletResponse response) throws IOException {
		super(response);
		out = new ByteArrayOutputStream();
		stream = new WrapOutputStream(out);
		writer = new PrintWriter(out);
	}

	@Override
	public ServletOutputStream getOutputStream() throws IOException {
		return stream;
	}

	@Override
	public PrintWriter getWriter() throws UnsupportedEncodingException {
		return writer;
	}

	public String getData() throws IOException {
		if (stream != null) {
			stream.flush();
		}
		if (writer != null) {
			writer.flush();
		}
		return out.toString();
	}
}
WrapOutputStream.java
public class WrapOutputStream extends ServletOutputStream {
	private ByteArrayOutputStream out = null;

	public WrapOutputStream(ByteArrayOutputStream stream)
			throws IOException {
		out = stream;
	}

	@Override
	public void write(int b) throws IOException {
		out.write(b);
	}
}

最后还是忍不住吐槽一下,虽然暂时实现了功能,但通过拦截器把请求类型和参数都改掉实在是奇葩,明明JS端几行代码的事。