6

@GET我们将 JAX-RS 与一些相当基本的 POJO 实体一起使用,并且有许多带@POST注释的方法,它们@Produce@Consume MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML. 没什么了不起的。

我的问题是我应该如何最好地验证传入的数据?

我们没有 XML Schema,尽管我可以生成一个。我需要以某种方式将其挂钩,这看起来并不吸引人,而且我还没有找到一个简洁的例子。

我们可以使用“bean 验证”,但我再次不确定如何连接并调用它。

最后(我认为)我们可以例如isValidForXXX()向实体 POJO 添加一些方法,并在我们有实例提交给我们时调用它们。

有人推荐吗?

4

3 回答 3

2

如果您有 XML 模式,那么您可以在MessageBodyReader. 有关具体示例,请参阅我对类似问题的回答。

验证阅读器

下面是一个简单的实现,MessageBodyReader它做了四件事:1) Create a JAXBContext2) 创建 3) 的实例Schema4 Unmarshaller) 解组InputStream.

package org.example;

import java.io.*;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.net.URL;

import javax.ws.rs.*;
import javax.ws.rs.core.*;
import javax.ws.rs.ext.*;
import javax.xml.XMLConstants;
import javax.xml.bind.*;
import javax.xml.validation.*;

@Provider
@Consumes("application/xml")
public class ValidatingReader implements MessageBodyReader<Customer> {

    @Context
    protected Providers providers;

    private Schema schema;
    private JAXBContext jaxbContext;

    public ValidatingReader() {
        try {
            JAXBContext jc = JAXBContext.newInstance(Customer.class);
            SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
            URL schemaURL = null; // URL for your XML schema
            schema = sf.newSchema(schemaURL);
        } catch(Exception e) {
            throw new RuntimeException(e);
        }
    }

    public boolean isReadable(Class<?> arg0, Type arg1, Annotation[] arg2, MediaType arg3) {
        return arg0 == Customer.class;
    }

    public Customer readFrom(Class<Customer> arg0, Type arg1, Annotation[] arg2, MediaType arg3, MultivaluedMap<String, String> arg4, InputStream arg5)
            throws IOException, WebApplicationException {
        try {
            Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
            unmarshaller.setSchema(schema);
            return (Customer) unmarshaller.unmarshal(arg5);
        } catch(JAXBException e) {
            throw new RuntimeException(e);
        }
    }

}
于 2012-05-01T13:29:38.023 回答
1

正在寻求完成与原始海报相同的事情。由于似乎希望避免 aMessageBodyReader我想我会分享这个解决方案,它只是使用HttpServletRequest作为参数,然后使用该getInputStream方法直接处理数据。

@POST
@Path("/myPath")
@Consumes(MediaType.APPLICATION_XML)
public Response saveCustomerInteraction(@Context HttpServletRequest httpRequest) {

    Response response = null;
    try {
        CustomerInteraction ci = this.handleCustomerInteractionRequest(httpRequest);
        if (ci!=null){
            // save your data or whatever your app does
        }
        else {
            response = Response.status(Status.BAD_REQUEST).entity("invalid XML").build();               
        }
    }
    catch(Exception e){
        log.error(e.getMessage(),e);
        response = Response.serverError().entity(e.getMessage()).build();
    }
    return response;
}

然后该handleCustomerInteractionRequest方法将处理 servlet 流并验证 XML

protected CustomerInteraction handleCustomerInteractionRequest(HttpServletRequest request){

    CustomerInteraction ci = null;
    try {
        SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
        Schema schema = sf.newSchema(schemaUrl);
        JAXBContext jaxbContext = JAXBContext.newInstance(CustomerInteraction.class);
        Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
        unmarshaller.setSchema(schema);
        ci = (CustomerInteraction) unmarshaller.unmarshal(request.getInputStream());    
    }
    catch (Exception e){
        // log error and return a null (or whatever you want to do with the error)
    }

    return ci;
} 
于 2015-02-20T23:11:16.603 回答
0

使用 MessageBodyReader 作为优秀的@Blaise Doughan 建议可以为您提供很大的灵活性。显然,如果您已经拥有 @Consumes 注释和 JAXB 注释类,我可以看到这看起来很冗长。

这真的取决于您的舒适程度。我注意到您没有定义 XML 模式,因此您手动创建了 JAXB 类,在相同的类(或外部自定义验证器)中编写验证逻辑似乎是合乎逻辑的。

我个人会考虑编写 XML Schema,特别是如果您的验证规则很容易表达。这对您的项目来说可能是一笔不错的投资:您可以从那时起自动生成 JAXB 类,并自动获得验证,因此您应该有更好的可维护性。

于 2012-05-02T00:05:26.643 回答