提问者:小点点

接受作为camel restlet或cxfrsendpoint的Multipart文件上载


我希望实现一个路由,其中reslet/cxfrsendpoint将接受文件作为多部分请求和进程。(请求也可能有一些JSON数据。

提前感谢。问候。[编辑]尝试了以下代码。还尝试使用curl发送文件。我可以在标头和调试输出中看到文件相关信息,但无法检索附件。

from("servlet:///hello").process(new Processor() {
   @Override
   public void process(Exchange exchange) throws Exception {
      Message in = exchange.getIn();
      StringBuffer v = new StringBuffer();
       HttpServletRequest request = (HttpServletRequest) in
          .getHeaders().get(Exchange.HTTP_SERVLET_REQUEST);

       DiskFileItemFactory diskFile = new DiskFileItemFactory();
       FileItemFactory factory = diskFile;
       ServletFileUpload upload = new ServletFileUpload(factory);
       List items = upload.parseRequest(request);
..... 

curl : curl -vvv -i -x post -h “Content-Type: multipart/form-data” -F “image=@/Users/navaltiger/1.jpg;类型=图像/JPG“ http://:8080/JettySample/camel/hello

以下代码有效(但不能使用,因为它嵌入了jetty,我们想将其部署在tomcat/weblogic上)

public void configure() throws Exception {
        // getContext().getProperties().put("CamelJettyTempDir", "target");
        getContext().setStreamCaching(true);
        getContext().setTracing(true);

         from("jetty:///test").process(new Processor() {
//      from("servlet:///hello").process(new Processor() {
            public void process(Exchange exchange) throws Exception {

                String body = exchange.getIn().getBody(String.class);
                HttpServletRequest request = exchange.getIn().getBody(
                        HttpServletRequest.class);

                StringBuffer v = new StringBuffer();
                // byte[] picture = (request.getParameter("image")).getBytes();

                v.append("\n Printing All Request Parameters From HttpSerlvetRequest: \n+"+body +" \n\n");

                Enumeration<String> requestParameters = request
                        .getParameterNames();
                while (requestParameters.hasMoreElements()) {
                    String paramName = (String) requestParameters.nextElement();
                    v.append("\n Request Paramter Name: " + paramName
                            + ", Value - " + request.getParameter(paramName));
                }

共3个答案

匿名用户

我有一个类似的问题,并在布伦托斯的回答的启发下设法解决了。在我的例子中,restendpoint是通过xml定义的:

<restContext id="UploaderServices"  xmlns="http://camel.apache.org/schema/spring">

    <rest path="/uploader">
        <post bindingMode="off" uri="/upload"  produces="application/json">
            <to uri="bean:UploaderService?method=uploadData"/>
        </post>
    </rest>

</restContext>

我不得不使用bindingmode=off来禁用xml/json解组,因为HttpRequest正文包含多部分数据(json/text文件),显然标准解组过程无法处理请求,因为它期望正文中有一个字符串,而不是多部分有效负载。

文件和其他参数从使用文件上传角模块的前端发送:https://github.com/danialfarid/ng-file-upload

为了解决CORS问题,我不得不在web.xml中添加一个CORSFilter过滤器,如下所示:

public class CORSFilter implements Filter {

@Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException,
        ServletException {
    HttpServletResponse httpResp = (HttpServletResponse) resp;
    HttpServletRequest httpReq = (HttpServletRequest) req;

    httpResp.setHeader("Access-Control-Allow-Methods", "GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS, CONNECT, PATCH");
    httpResp.setHeader("Access-Control-Allow-Origin", "*");
    if (httpReq.getMethod().equalsIgnoreCase("OPTIONS")) {
        httpResp.setHeader("Access-Control-Allow-Headers",
                httpReq.getHeader("Access-Control-Request-Headers"));
    }
    chain.doFilter(req, resp);
}

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

@Override
public void destroy() {
}
}

另外,我不得不稍微修改一下解组部分:

public String uploadData(Message exchange) {
    String contentType=(String) exchange.getIn().getHeader(Exchange.CONTENT_TYPE);
    MediaType mediaType = MediaType.valueOf(contentType); //otherwise the boundary parameter is lost
    InputRepresentation representation = new InputRepresentation(exchange
            .getBody(InputStream.class), mediaType);

    try {
        List<FileItem> items = new RestletFileUpload(
                new DiskFileItemFactory())
                .parseRepresentation(representation);

        for (FileItem item : items) {
            if (!item.isFormField()) {
                InputStream inputStream = item.getInputStream();
                // Path destination = Paths.get("MyFile.jpg");
                // Files.copy(inputStream, destination,
                // StandardCopyOption.REPLACE_EXISTING);
                System.out.println("found file in request:" + item);
            }else{
                System.out.println("found string in request:" + new String(item.get(), "UTF-8"));
            }
        }
    } catch (Exception e) {
        e.printStackTrace();
    }

    return "200";
}

匿名用户

我将Camel REST DSL与Replet一起使用,并且能够使用以下代码进行文件上传。

rest("/images").description("Image Upload Service")
.consumes("multipart/form-data").produces("application/json")
.post().description("Uploads image")
        .to("direct:uploadImage");

from("direct:uploadImage")
.process(new Processor() {

    @Override
    public void process(Exchange exchange) throws Exception {

        MediaType mediaType = 
            exchange.getIn().getHeader(Exchange.CONTENT_TYPE, MediaType.class);
        InputRepresentation representation =
            new InputRepresentation(
                exchange.getIn().getBody(InputStream.class), mediaType);

        try {
            List<FileItem> items = 
                new RestletFileUpload(
                    new DiskFileItemFactory()).parseRepresentation(representation);

            for (FileItem item : items) {
                if (!item.isFormField()) {
                    InputStream inputStream = item.getInputStream();
                    Path destination = Paths.get("MyFile.jpg");
                    Files.copy(inputStream, destination,
                                StandardCopyOption.REPLACE_EXISTING);
                }
            }
        } catch (FileUploadException | IOException e) {
            e.printStackTrace();
        }


    }

});

匿名用户

您可以使用 restdsl 执行此操作,即使您没有将 restlet(示例 jetty)用于 restdsl 组件。

您需要为该路由打开restdinding of first,并创建两个类来处理您体内的多部分。

您需要两个类:

  • DW请求上下文
  • DW文件上传

然后在您的定制处理器中使用它们

这是代码:

DWRequestContext.java

    import org.apache.camel.Exchange;
    import org.apache.commons.fileupload.RequestContext;

    import java.io.IOException;
    import java.io.InputStream;
    import java.nio.charset.StandardCharsets;

    public class DWRequestContext implements RequestContext {

        private Exchange exchange;

        public DWRequestContext(Exchange exchange) {
            this.exchange = exchange;
        }

        public String getCharacterEncoding() {
            return StandardCharsets.UTF_8.toString();
        }

        //could compute here (we have stream cache enabled)
        public int getContentLength() {
            return (int) -1;
        }

        public String getContentType() {
            return exchange.getIn().getHeader("Content-Type").toString();
        }

        public InputStream getInputStream() throws IOException {
            return this.exchange.getIn().getBody(InputStream.class);
        }
    }

DWFile上传.java

    import org.apache.camel.Exchange;
    import org.apache.commons.fileupload.FileItem;
    import org.apache.commons.fileupload.FileItemFactory;
    import org.apache.commons.fileupload.FileUpload;
    import org.apache.commons.fileupload.FileUploadException;

    import java.util.List;

    public class DWFileUpload extends
            FileUpload {

        public DWFileUpload() {
            super();
        }

        public DWFileUpload(FileItemFactory fileItemFactory) {
            super(fileItemFactory);
        }

        public List<FileItem> parseInputStream(Exchange exchange)
                throws FileUploadException {
            return parseRequest(new DWRequestContext(exchange));
        }
    }

您可以这样定义您的处理器:

    routeDefinition.process(new Processor() {
                    @Override
                    public void process(Exchange exchange) throws Exception {
                        // Create a factory for disk-based file items
                        DiskFileItemFactory factory = new DiskFileItemFactory();
                        factory.setRepository(new File(System.getProperty("java.io.tmpdir")));

                        DWFileUpload upload = new DWFileUpload(factory);

                        java.util.List<FileItem> items = upload.parseInputStream(exchange);

                        //here I assume I have only one, but I could split it here somehow and link them to camel properties...
                        //with this, the first file sended with your multipart replaces the body
                        // of the exchange for the next processor to handle it
                        exchange.getIn().setBody(items.get(0).getInputStream());
                    }
                });