【问题标题】:How to disable Jersey POJOMappingFeature for just one method or controller class如何仅为一种方法或控制器类禁用 Jersey POJOMappingFeature
【发布时间】:2014-09-10 18:13:01
【问题描述】:

我在 web.xml 中打开了 Jersey JSON POJOMappingFeature,如下所示将 POJO 转换为 JSON:

<init-param>
        <param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
        <param-value>true</param-value>
</init-param>

我在其中一个控制器中有一个方法来处理文件上传。它获取多部分表单数据,从表单中提取文件输入字段,将其转换为 InputStream 并将文件保存到磁盘:

@POST
@Path("/upload")
@Consumes(MediaType.MULTIPART_FORM_DATA)
@Produces("application/json")
public FileMetaData uploadFiles(FormDataMultiPart formDataMultiPart) {
    return new FileUploadHandler(SERVER_FILE_UPLOAD_LOCATION).upload(formDataMultiPart);
}

public FileMetaData upload(FormDataMultiPart formDataMultiPart) {
    FormDataBodyPart formFile = formDataMultiPart.getField("files");
    ContentDisposition contentDisposition = formFile.getContentDisposition();
    return saveFile(formFile.getValueAs(InputStream.class), contentDisposition.getFileName(), formFile.getMediaType().toString());
}

这适用于所有文件格式,但当我尝试上传 JSON 文件时,formFile.getValueAs(InputStream.class) 会引发错误,抱怨无法将字符串转换为 InputStream。我认为这是因为 Jersey 自动将 JSON 文件转换为字符串对象。 那么我怎样才能防止 Jersey 只为这个方法或控制器这样做呢?我的要求是我需要将 json 文件保存为文件本身。

我已经尝试在这方面进行了很多搜索,但我最终得到的只是关于如何启用 POJOMapping 而不是选择性地禁用它的文档。任何帮助将不胜感激!

更新: 我的自定义 MessageBodyReader 如下所示:

public class JSONMessageBodyReader implements MessageBodyReader<Object> {

private static final Logger log = LoggerFactory.getLogger(JSONMessageBodyReader.class);

@Override
public boolean isReadable(Class<?> type, Type genericType,
                          Annotation[] annotations, MediaType mediaType) {
    // return true;
    return mediaType.isCompatible(MediaType.APPLICATION_JSON_TYPE)
            || mediaType.isCompatible(MediaType.APPLICATION_OCTET_STREAM_TYPE);
            || mediaType.isCompatible(MediaType.TEXT_HTML_TYPE);
}

@Override
public Object readFrom(Class<Object> type, Type genericType,
                       Annotation[] annotations, MediaType mediaType,
                       MultivaluedMap<String, String> httpHeaders, InputStream entityStream)
        throws IOException, WebApplicationException {
    if (log.isTraceEnabled()) {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        byte[] chunk = new byte[256];
        int read = -1;
        while ((read = entityStream.read(chunk)) != -1) {
            baos.write(chunk, 0, read);
        }
        chunk = baos.toByteArray();
        String entity = new String(chunk);
        log.trace("the entity: " + entity);
        return ObjectMapperFactory.getInstance().readValue(chunk, 0, chunk.length, type);
    }

    return ObjectMapperFactory.getInstance().readValue(entityStream, type);
}

}

【问题讨论】:

    标签: java json rest jersey pojo


    【解决方案1】:

    我最终通过使用较低级别的 HttpServletRequest 而不是 Jersey 的 FormDataParams 处理上传的文件来解决我的要求,如下所示:

    @POST
    @Path("/upload")
    @Consumes("multipart/form-data")
    @Produces("application/json")
    public FileMetaData uploadFiles(@Context ServletContext servletContext, @Context HttpServletRequest request) {
        return fileUploadHandler.upload(request, servletContext);
    }
    
    
    public FileMetaData upload(HttpServletRequest request, ServletContext servletContext) {
        FileMetaData fileMetaData = null;
        boolean isMultipart = ServletFileUpload.isMultipartContent(request);
        if (isMultipart) {
            LOGGER.info("About to save file on the server : {}", this.SERVER_UPLOAD_DIRECTORY);
    
            DiskFileItemFactory diskFileItemFactory = new DiskFileItemFactory();
            File repository = (File) servletContext.getAttribute("javax.servlet.context.tempdir");
            diskFileItemFactory.setRepository(repository);
            ServletFileUpload servletFileUpload = new ServletFileUpload(diskFileItemFactory);
            try {
                List<FileItem> files = servletFileUpload.parseRequest(request);
                Iterator<FileItem> iter = files.iterator();
                while(iter.hasNext()) {
                    FileItem fileItem = iter.next();
                    String fileName = fileItem.getName();
                    if (fileName != null) {
                        fileName = FilenameUtils.getName(fileName);
                    }
                    String fileUploadDirectory = this.SERVER_UPLOAD_DIRECTORY;
                    File uploadDirectory = new File(fileUploadDirectory);
                    if(!uploadDirectory.exists()) {
                        uploadDirectory.mkdir();
                        LOGGER.info("creating directory {}", uploadDirectory.getAbsolutePath());
                    }
                    String fileUploadPath = fileUploadDirectory + File.separator + fileName;
                    File fileToStore = new File(fileUploadPath);
                    LOGGER.info("saved file {} on server", fileName);
    
                    fileItem.write(fileToStore);
                    long fileSize = fileToStore.length();
                    String size = (fileSize > 1024) ? (fileSize/1024) + "Kb" : fileSize + "b";
                    fileMetaData = new FileMetaData(fileName, size, true);
                }
            } catch (Exception e) {
                LOGGER.warn("error occurred while saving file to server : {}", e.getStackTrace());
                e.printStackTrace();
            }
        }
    
        else {
            LOGGER.info("No files to upload in request");
        }
    
        return fileMetaData;
    }
    

    这个解决方案对我来说非常有效,尽管我觉得它是对我最初问题的一种破解。如果这个解决方案也能帮助其他人,我会很高兴。 但是有人必须提供一种纯粹的 Jersey 方法来解决这个问题,而不涉及 HttpServletRequest 我很乐意尝试一下。 谢谢!

    【讨论】:

    • 问题解决了吗?我也需要纯运动衫解决方案。这是我的问题stackoverflow.com/q/31138727/660408
    • 就像我上面提到的,我只管理了一个涉及低级 HttpServletRequest 的解决方法。
    猜你喜欢
    • 2013-07-08
    • 2013-06-17
    • 1970-01-01
    • 1970-01-01
    • 2018-01-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多