java web 处理response返回数据

工作的时候遇到一个需求,同样的接口返回给App端的json数据需要将数值型改成字符型,而之前传给网页端的比如一些分页数据、时间戳、id等是数值的。
于是打算加一个拦截器拦截请求,在controller执行完后,如果是传给App端就把json做一下转换。

看一下拦截器的postHandler方法

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object o, ModelAndView modelAndView) throws Exception {
    }

打断点运行到这个位置发行,由于使用@ResponseBody返回json数据,ModelAndView是null,而Object o似乎指的是controller而非返回数据。response中更是没有发现返回数据的踪迹。按理说拦截器可以访问action上下文,值栈里的对象,但是没找到可行的办法。

再试一下过滤器。
过滤器拦截器的执行顺序为过滤器、拦截器、过滤器、action、拦截器、过滤器。过滤器阶段获取request和response的访问数据是放在io流中的,从流中读取后需要再写回,否则数据无法再传到。
需要构造一个response的代理,放入过滤器中,等action执行完后,通过代理来获取response的io流数据,改写后再写入。具体代码如下。

**
 * @description: 返回代理
 * @author: WangJie
 * @create: 2018-07-19 10:36
 **/


public class MyHttpServletResponseWrapper extends HttpServletResponseWrapper
{

    private ByteArrayOutputStream buffer;

    private ServletOutputStream out;

    public MyHttpServletResponseWrapper(HttpServletResponse httpServletResponse)
    {
        super(httpServletResponse);
        buffer = new ByteArrayOutputStream();
        out = new WrapperOutputStream(buffer);
    }

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

    @Override
    public void flushBuffer()
            throws IOException
    {
        if (out != null)
        {
            out.flush();
        }
    }

    public byte[] getContent()
            throws IOException
    {
        flushBuffer();
        return buffer.toByteArray();
    }

    class WrapperOutputStream extends ServletOutputStream
    {
        private ByteArrayOutputStream bos;

        public WrapperOutputStream(ByteArrayOutputStream bos)
        {
            this.bos = bos;
        }

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

        @Override
        public boolean isReady()
        {

            // TODO Auto-generated method stub
            return false;

        }

        @Override
        public void setWriteListener(WriteListener arg0)
        {

            // TODO Auto-generated method stub

        }
    }

}

/**
 * @description: 返回值过滤器
 * @author: WangJie
 * @create: 2018-07-19 10:38
 **/
@Slf4j
@Component
public class ResponseFilter implements Filter {

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
            throws IOException, ServletException {


        MyHttpServletResponseWrapper wrapperResponse = new MyHttpServletResponseWrapper((HttpServletResponse) response);//转换成代理类

        // 这里只拦截返回,直接让请求过去,如果在请求前有处理,可以在这里处理

        filterChain.doFilter(request, wrapperResponse);

        log.info("进入返回值过滤器处理{}", ((HttpServletRequest) request).getRequestURI());

        byte[] content = wrapperResponse.getContent();//获取返回值
        //判断是否有值
        if (content.length > 0) {

            String str = new String(content, "UTF-8");
            log.info("处理前返回值{}", str);
            String expectStr = JsonUtil.jsonNumberToString(str);
            //把返回值输出到客户端
            ServletOutputStream out = response.getOutputStream();
            out.write(expectStr.getBytes());
            out.flush();
            log.info("处理后返回值{}", expectStr);
        }

    }

    @Override
    public void init(FilterConfig arg0)
            throws ServletException {

    }

    @Override
    public void destroy() {

    }

}

这样就做到了对返回数据的处理。测试了一下,正常的请求能达到理想效果,但在发生请求跳转的时候,这个方法总会报”getWriter() has already been called for this responsegetWriter() has already been called for this response”的错误,也是无法解决。换成重定向后就可以解决了。但是随之而来的问题是跨域出问题了。。。

又查了些资料后发现了第三种方法——使用@ControllerAdvice配合ResponseBodyAdvice 统一处理返回值/响应体。
ResponseBodyAdvice是spring4.1的新特性,其作用是在响应体写出之前做一些处理;比如,修改返回值、加密等。
完全契合我们的需求,代码如下。

/**
 * @description:
 * @author: WangJie
 * @create: 2018-07-20 14:30
 **/
@ControllerAdvice
public class MyResponseControllerAdvice implements ResponseBodyAdvice<Object> {

    @Value(("${token.client.app}"))
    private String appClient;

    @Override
    public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) {
        return true;
    }

    @Override
    public Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType, Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
        ServletServerHttpRequest req = (ServletServerHttpRequest) serverHttpRequest;
        HttpServletRequest httpReq = req.getServletRequest();
     //   Token token = (Token) httpReq.getAttribute("token");
        String client = httpReq.getHeader("client");
        if (client!=null && appClient.equals(client)) {
            String jsonStr = JSON.toJSONString(o);
            jsonStr=JsonUtil.jsonNumberToString(jsonStr);
            return JSON.parseObject(jsonStr);
        }
        return o;
    }
}
  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
要让 Java 接口返回 JSON 数据格式,你可以使用任何一个 JSON 库,比如 Jackson、Gson 或者 Fastjson。以下是使用 Jackson 库的示例代码: 首先,确保你的项目中已经引入了 Jackson 库的依赖。如果使用 Maven 管理项目依赖,可以在 pom.xml 文件中添加以下依赖: ```xml <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.12.3</version> </dependency> ``` 然后,在你的 Controller 中,可以按照如下方式编写代码: ```java import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class MyController { @Autowired private ObjectMapper objectMapper; @GetMapping("/my-api") public MyResponse myApi() { MyResponse response = new MyResponse(); response.setCode(200); response.setMessage("Success"); // 设置其它字段... return response; } public static class MyResponse { private int code; private String message; // 其它字段... // 省略 getter 和 setter 方法... public String toJson() { try { return objectMapper.writeValueAsString(this); } catch (Exception e) { throw new RuntimeException(e); } } } } ``` 以上代码中,我们使用 Jackson 库的 ObjectMapper 对象将 Java 对象转换为 JSON 字符串。在 MyResponse 类中,我们添加了 toJson() 方法,该方法将 MyResponse 对象转换为 JSON 字符串。 当客户端请求 /my-api 接口时,MyController 的 myApi() 方法返回 MyResponse 对象,并且 MyResponse 对象会被自动转换为 JSON 格式的数据返回给客户端。如果你想手动序列化对象为 JSON 字符串,可以调用 MyResponse.toJson() 方法。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值