【问题标题】:How to serialize Java object into JSON and return it in servlet filter?如何将 Java 对象序列化为 JSON 并在 servlet 过滤器中返回?
【发布时间】:2015-12-11 15:09:06
【问题描述】:

我有这个javax.servlet.Filter 来检查是否允许客户端访问 API REST 资源。

@Component
public class AuthorizationRequestFilter implements Filter {

    public static final String AUTHORIZATION_TOKEN = "X-Access-Token";

    @Autowired
    @Qualifier("loginService")
    private ILoginService loginService;

    private void throwUnauthorized(ServletResponse res) throws IOException {

        HttpServletResponse response = (HttpServletResponse) res;

        response.reset();
        response.setHeader("Content-Type", "application/json;charset=UTF-8");
        response.sendError(HttpServletResponse.SC_UNAUTHORIZED);

    }

    private void throwForbidden(ServletResponse res) throws IOException {

        HttpServletResponse response = (HttpServletResponse) res;

        response.reset();
        response.setHeader("Content-Type", "application/json;charset=UTF-8");
        response.sendError(HttpServletResponse.SC_FORBIDDEN);

    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {

        HttpServletRequest request = (HttpServletRequest) req;

        String accessToken = request.getHeader(AUTHORIZATION_TOKEN);

        if (StringUtils.isEmpty(accessToken)) {
            throwUnauthorized(res);
        } else {
            AccountLoginData account = loginService.find(accessToken);
            if (account == null) {
                throwForbidden(res);
            }
        }

        chain.doFilter(req, res);

    }

    @Override
    public void destroy() {
    }

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

}

它有效,但我想在这两个throw*() 方法中使用适当的信息写入客户端 JSON。在这个应用程序的另一部分,我使用这些响应消息对象来通知客户端发生了什么。

例如,当没有找到记录时:

public class NotFoundResponseMessage extends ResponseMessage {

    public NotFoundResponseMessage(String message) {
        super(HttpStatus.NOT_FOUND, 1, message);
    }

}

public class ResponseMessage {

    private int status;
    private int code;
    private String message;
    private String reason;

    public ResponseMessage(int status, int code, String message, String reason) {

        Assert.notNull(reason, "Reason must not be null.");
        Assert.isTrue(status > 0, "Status must not be empty.");

        this.status = status;
        this.code = code;
        this.message = message;
        this.reason = reason;

    }

}

我的问题

我想在我的javax.servlet.Filter 授权/身份验证过滤器中返回带有序列化对象(UnauthorizedResponseMessageForbiddenResponseMessage)的 JSON。我使用 Spring Boot 和 Jackson 库。

  1. 如何手动ResponseMessage 序列化为 JSON 表示形式?
  2. 如何在我的过滤器类中将此 JSON 写回客户端?

编辑 1:

private void throwUnauthorized(ServletResponse res) throws IOException {

    HttpServletResponse response = (HttpServletResponse) res;

    response.reset();
    response.setHeader("Content-Type", "application/json;charset=UTF-8");
    response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
    response.getWriter().write("{\"foo\":\"boo\"}");

}

现在我可以写出 JSON 但返回 HTTP 500,因为:

java.lang.IllegalStateException: getWriter() has already been called for this response
    at org.apache.catalina.connector.Response.getOutputStream(Response.java:544)

【问题讨论】:

  • afaik 你只会在经过身份验证的情况下使用chain.doFilter(req, res);。否则,链下的事情会尝试添加常规(重复)响应:stackoverflow.com/a/8445927/995891

标签: java json spring servlets


【解决方案1】:

只需从过滤器中抛出您的异常并使用@ResponseStatus 注释抛出的异常。这样,它会自动转换为给定的 http 错误代码。 (也可以定义错误信息)

代码示例:

@ResponseStatus(value = HttpStatus.BAD_REQUEST, reason = "Error while trying to add the feed.")
public class AddFeedException extends Exception {

    private static final long serialVersionUID = 290724913968202592L;

    public AddFeedException(Throwable throwable) {
        super(throwable);
    }
}

【讨论】:

  • 是的,这是我在控制器中使用的,但 javax.servlet.Filter 中的异常处理不起作用,因为它在 Springs servletDispatcher 之外...
【解决方案2】:

使用JacksonObject转换为JSON,下面是一个例子

ObjectMapper mapper = new ObjectMapper();
String Json =  mapper.writeValueAsString(object);  

【讨论】:

  • 为什么它的回答被否决了?它有什么问题(它有效)。
【解决方案3】:

我遇到了同样的问题,完整的解决方案如下:

try {
    restResponse = service.validate(httpReq);
} catch (ForbiddenException e) {

    ObjectMapper mapper = new ObjectMapper();
    ResponseObject object = new ResponseObject();
    object.setStatus(HttpServletResponse.SC_FORBIDDEN);
    object.setMessage(e.getMessage());
    object.setError("Forbidden");
    object.setTimestamp(String.valueOf(new Date().getTime()));
    HttpServletResponse httpResp = (HttpServletResponse) response;
    httpResp.reset();
    httpResp.setHeader("Content-Type","application/json;charset=UTF-8");
    httpResp.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
    String json =  mapper.writeValueAsString(object);
    response.getWriter().write(json);
    return;
}

结果是:

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-01
    • 1970-01-01
    • 2015-02-02
    • 1970-01-01
    • 1970-01-01
    • 2021-05-21
    相关资源
    最近更新 更多