简体   繁体   English

使用HTTPURLConnection从HTTP Java客户端向Servlet发送XML数据时出现问题

[英]Problems when sending XML data from HTTP Java client to a servlet with HttpURLConnection

I have standalone java client sending xml data to http servlet using httpURLconnection class.but data appearing in non printable character format. 我有一个独立的Java客户端使用httpURLconnection类将xml数据发送到http servlet,但是数据以不可打印的字符格式显示。

For simulation i have been trying to send simple string but still it was appearing in non printable format. 为了进行模拟,我一直在尝试发送简单的字符串,但是它仍然以不可打印的格式出现。

I have written the following client code to communicate with servlet, 我已经编写了以下客户端代码来与Servlet进行通信,

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.ProtocolException;
import java.net.URL;

public class HttpClient implements IClient {

    private static IClient client = null;

    private HttpURLConnection httpConn = null;

    private OutputStream output = null;

    private InputStream input = null;

    private OutputStreamWriter out = null;

    private HttpClient() {
    }

    public static IClient getHttpClient() {
        if (client == null) {
            client = new HttpClient();
        }
        return client;
    }

    @Override
    public void connect(String urlString) throws IOException {
        URL url = new URL(urlString);
        httpConn = (HttpURLConnection) url.openConnection();
        initConnection();
        httpConn.connect();
        output = httpConn.getOutputStream();
        input = httpConn.getInputStream();
        System.out.println("Connection Response:" + httpConn.getResponseCode());
    }

    @Override
    public void sendFile(File file) throws IOException {
        // BufferedOutputStream bos = new BufferedOutputStream(output);
        // InputStream fis = new FileInputStream(file);
        // int bytesRead = 0;
        // byte[] buffer = new byte[8192];
        // while ((bytesRead = fis.read(buffer, 0, 8192)) != -1) {
        // bos.write(buffer, 0, bytesRead);
        // System.out.println("write:"+buffer);
        // }
        // bos.close();
        // fis.close();

        OutputStreamWriter out = new OutputStreamWriter(output, "UTF-16");
        out.write("test me");
    }

    @Override
    public boolean isConnected() {
        return httpConn != null ? true : false;
    }

    @Override
    public void close() {
        httpConn.disconnect();
    }

    private void initConnection() throws ProtocolException {
        httpConn.setDoOutput(true);
        httpConn.setDoInput(true);
        httpConn.setRequestMethod("POST");
        httpConn.setUseCaches(false);
        httpConn.setRequestProperty("Content-Type",
                "text/xml; charset=\"UTF-16\"");
        httpConn.setRequestProperty("Connection", "Keep-Alive");

    }

    private static byte[] getBytesFromFile(File file) throws IOException {

        InputStream is = new FileInputStream(file);
        System.out.println("\nDEBUG: FileInputStream is " + file);

        // Get the size of the file
        long length = file.length();
        System.out.println("DEBUG: Length of " + file + " is " + length + "\n");

        /*
         * You cannot create an array using a long type. It needs to be an int
         * type. Before converting to an int type, check to ensure that file is
         * not loarger than Integer.MAX_VALUE;
         */
        if (length > Integer.MAX_VALUE) {
            System.out.println("File is too large to process");
            return null;
        }

        // Create the byte array to hold the data
        byte[] bytes = new byte[(int) length];

        // Read in the bytes
        int offset = 0;
        int numRead = 0;
        while ((offset < bytes.length)
                && ((numRead = is.read(bytes, offset, bytes.length - offset)) >= 0)) {

            offset += numRead;

        }

        // Ensure all the bytes have been read in
        if (offset < bytes.length) {
            throw new IOException("Could not completely read file "
                    + file.getName());
        }

        return bytes;

    }

}

and servlet code is given below, 并在下面给出了servlet代码,

import java.io.BufferedInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class XMLServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        doPost(req, resp);
    }

    protected void doPost(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        System.out.println("=========inside doPost=========");
//      BufferedInputStream bis = new BufferedInputStream(req.getInputStream());
//      OutputStream fos = new FileOutputStream("test.xml");
//      int bytesRead = 0;
//      byte[] buffer = new byte[8192];
//      while ((bytesRead = bis.read(buffer, 0, 8192)) != -1) {
//          System.out.println("read:"+buffer);
//          fos.write(buffer, 0, bytesRead);
//      }
//      fos.close();
//      bis.close();
//      

        req.setCharacterEncoding("UTF-16");
        InputStreamReader isr = new InputStreamReader(req.getInputStream(),"UTF-16");
        char[] data = new char[10];
        isr.read(data);
        System.out.println(data);
        for (char c : data) {
            System.out.println(c);
        }
    }

}

Please any help me to get out of this problem. 请任何帮助我摆脱这个问题。

I think you are overcomplicating it. 我认为您太复杂了。 I JUST wrote something similar that takes any file and transfers it through HTTP to a servlet. 我只写了类似的东西,它可以接收任何文件并将其通过HTTP传输到servlet。 Just remember: All data is binary (including a text file)-- period. 只需记住:所有数据都是二进制(包括文本文件)-周期。 It's up to the given application to interpret that binary data. 由给定的应用程序来解释该二进制数据。 For example, notepad.exe simply reads a binary set of data and attempts to format it using ASCII standard. 例如,notepad.exe仅读取二进制数据集并尝试使用ASCII标准对其进行格式化。 So knowing that, simply read a file using a raw stream, set the mime-type of the connection to application/octet-stream and send it via "PUT" method. 因此,只需使用原始流读取文件,将连接的mime类型设置为application / octet-stream,然后通过“ PUT”方法将其发送即可。 The servlet code should be reading the file using the raw InputStream from the request and creating the corresponding file in its space. Servlet代码应使用请求中的原始InputStream读取文件,并在其空间中创建相应的文件。

From the client code: 从客户端代码:

URL url = new URL(urlString);
HttpURLConnection cnx = (HttpURLConnection)url.openConnection();
cnx.setRequestMethod("PUT");
cnx.setRequestProperty("Content-Type", "application/octet-stream");
// optional request property
cnx.setRequestProperty("filename", filename);
cnx.setDoOutput(true);
cnx.connect();
BufferedInputStream fileIn = 
       new BufferedInputStream(new FileInputStream(fileName), BUFFER_SIZE);
BufferedOutputStream out = 
       new BufferedOutputStream(cnx.getOutputStream(), BUFFER_SIZE);
byte[] bytes = new byte[BUFFER_SIZE];
int bytesRead;
while((bytesRead = fileIn.read(bytes)) != -1){
   out.write(bytes, 0, bytesRead);
}

That's it. 而已。

Now the servlet code.... 现在是servlet代码。

public void doPut(HttpServletRequest request, HttpServletResponse response){
    String filename = (String)request.getHeader("filename");
    StringBuilder fullPath = new StringBuilder(100);
    ServletContext ctxt = getServletContext();
    fullPath.append(ctxt.getRealPath(""))
      .append("uploads\\").append(filename);
    File f = new File(fullPath.toString());
    f.createNewFile();
    InputStream in = request.getInputStream();
    BufferedOutputStream fileOut = 
        new BufferedOutputStream(new FileOutputStream(f));
    byte[] bytes = new byte[BUFFER_SIZE];
    int bytesRead;
    while((bytesRead = in.read(bytes)) != -1){
       fileOut.write(bytes, 0, bytesRead);
    }
    fileOut.flush();
    fileOut.close();
    response.setStatus(HttpServletResponse.SC_CREATED);   
}

There are two major ways to upload a file on to server using http methods: 使用http方法将文件上传到服务器的方式主要有两种:

  1. Upload a file using PUT method. 使用PUT方法上传文件。 This allow you to put one file at a time on to server. 这使您可以一次将一个文件放到服务器上。 PUT method is easy to implement but you cannot upload a file from a html form (eg uploading form in your web browser) using PUT method. PUT方法易于实现,但是您不能使用PUT方法从html表单上载文件(例如,在Web浏览器中上载表单)。

  2. Upload files using POST method. 使用POST方法上传文件。 This is more complicated but most web site uses this to upload files on to server. 这比较复杂,但是大多数网站都使用它来将文件上传到服务器上。 You can do multiple file uploading per request. 您可以针对每个请求上传多个文件。 This is what I am going to talk about. 这就是我要谈的。

Note: GET is not used for file uploading unless you encode it somehow. 注意: GET不用于文件上传,除非您以某种方式对其进行编码。

Uploading files using URLConnection is not straight forwards and requires you to prepare your data in " multipart form ". 使用URLConnection上传文件不是直接的,需要您以“ 多部分形式 ”准备数据。 Of course, you shouldn't do it yourself. 当然,您不应该自己做。 There are a number of libraries to deal with this for you, eg HttpClient . 有许多库可以为您解决这个问题,例如HttpClient If you really want to use URLConnection , I shall refer to previous question on " How to use java.net.URLConnection to fire and handle HTTP requests " 如果您真的想使用URLConnection ,我将参考前面的问题“ 如何使用java.net.URLConnection来触发和处理HTTP请求

Below is the code for uploading your file using HttpClient. 以下是使用HttpClient上传文件的代码。 It is simplified from HttpClient example code. 它从HttpClient示例代码简化。

import java.io.File;


import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.multipart.FilePart;
import org.apache.commons.httpclient.methods.multipart.MultipartRequestEntity;
import org.apache.commons.httpclient.methods.multipart.Part;
import org.apache.commons.httpclient.params.HttpMethodParams;

public class MultipartFileUploadApp {

    public static void main(String[] args) {
        String targetURL = "http://localhost:8080/yourserver/upload";
        File targetFile = new File("/path/to/your/file.txt");

        PostMethod filePost = new PostMethod(targetURL);

        filePost.getParams().setBooleanParameter(HttpMethodParams.USE_EXPECT_CONTINUE, false);

        try {

            System.out.println("Uploading " + targetFile.getName() + " to " + targetURL);

            // add more parts you want to upload multiple files.
            Part[] parts = {new FilePart(targetFile.getName(), targetFile)};

            filePost.setRequestEntity(new MultipartRequestEntity(parts, filePost.getParams()));

            HttpClient client = new HttpClient();
            client.getHttpConnectionManager().getParams().setConnectionTimeout(5000);

            int status = client.executeMethod(filePost);

            if (status == HttpStatus.SC_OK) {
                System.out.println("Upload complete, response=" + filePost.getResponseBodyAsString());
            } else {
                System.out.println("Upload failed, response=" + HttpStatus.getStatusText(status));
            }
        } catch (Exception ex) {
            System.out.println("Error: " + ex.getMessage());
            ex.printStackTrace();
        } finally {
            filePost.releaseConnection();
        }


    }
}

For the server side, you have to parse multipart form request. 对于服务器端,您必须解析多部分表单请求。 Of course, there exists libraries to do that for you. 当然,存在可以为您执行此操作的库。 Here is the snipplet I am using 这是我正在使用的片段

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Iterator;
import java.util.List;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;

public class CommonsFileUploadServlet extends HttpServlet {

    private static final String TMP_DIR_PATH = "c:\\tmp";
    private File tmpDir;
    private static final String DESTINATION_DIR_PATH = "c:\\tmp\\files";
    private File destinationDir;

    public void init(ServletConfig config) throws ServletException {
        super.init(config);
        tmpDir = new File(TMP_DIR_PATH);
        if (!tmpDir.isDirectory()) {
            throw new ServletException(TMP_DIR_PATH + " is not a directory");
        }
        //String realPath = getServletContext().getRealPath(DESTINATION_DIR_PATH);
        destinationDir = new File(DESTINATION_DIR_PATH);
        if (!destinationDir.isDirectory()) {
            throw new ServletException(DESTINATION_DIR_PATH + " is not a directory");
        }

    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        PrintWriter out = response.getWriter();
        response.setContentType("text/plain");
        out.println("<h1>Servlet File Upload Example using Commons File Upload</h1>");
        out.println();

        DiskFileItemFactory fileItemFactory = new DiskFileItemFactory();
        /*
         *Set the size threshold, above which content will be stored on disk.
         */
        fileItemFactory.setSizeThreshold(1 * 1024 * 1024); //1 MB
        /*
         * Set the temporary directory to store the uploaded files of size above threshold.
         */
        fileItemFactory.setRepository(tmpDir);

        ServletFileUpload uploadHandler = new ServletFileUpload(fileItemFactory);
        try {
            /*
             * Parse the request
             */
            List items = uploadHandler.parseRequest(request);
            out.println("Count : " + items.size());
            Iterator itr = items.iterator();
            while (itr.hasNext()) {
                FileItem item = (FileItem) itr.next();
                /*
                 * Handle Form Fields.
                 */
                if (item.isFormField()) {
                    out.println("Field = " + item.getFieldName() + ", Value = " + item.getString());
                } else {
                    //Handle Uploaded files.
                    out.println("Field Name = " + item.getFieldName()
                            + ", File Name = " + item.getName()
                            + ", Content type = " + item.getContentType()
                            + ", File Size = " + item.getSize());
                    /*
                     * Write file to the ultimate location.
                     */
                    File file = new File(destinationDir, item.getName());
                    item.write(file);
                }
            }
            out.close();
        } catch (FileUploadException ex) {
            log("Error encountered while parsing the request", ex);
        } catch (Exception ex) {
            log("Error encountered while uploading file", ex);
        }

    }
}

I have standalone java client sending xml data to http servlet using httpURLconnection class.but data appearing in non printable character format. 我有一个独立的Java客户端使用httpURLconnection类将xml数据发送到http servlet,但是数据以不可打印的字符格式显示。

I can understand that. 我能理解 You're sending the data as UTF-16, but the XML file itself is likely not saved in UTF-16. 您以UTF-16的形式发送数据,但是XML文件本身可能未保存在UTF-16中。 You need to use the same character encoding as the XML file is saved in. That's usually UTF-8. 您需要使用与保存XML文件相同的字符编码。通常为UTF-8。

For simulation i have been trying to send simple string but still it was appearing in non printable format. 为了进行模拟,我一直在尝试发送简单的字符串,但是它仍然以不可打印的格式出现。

I don't understand that. 我不明白 It should work fine the way as you have in the code. 它应该可以像您在代码中那样很好地工作。 Probably you didn't test it properly. 可能您没有正确测试。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM