7

我使用 Spring for Android 作为 Android 应用程序中远程调用的 REST 模板。

目前正在将图像上传到服务器。

我想出了类似的东西:

public Picture uploadPicture(String accessToken, String fileToUpload) throws RestClientException {
    RestTemplate rest = new RestTemplate();
    FormHttpMessageConverter formConverter = new FormHttpMessageConverter();
    formConverter.setCharset(Charset.forName("UTF8"));
    CustomGsonHttpMessageConverter jsonConverter = new CustomGsonHttpMessageConverter();
    rest.getMessageConverters().add(formConverter);
    rest.getMessageConverters().add(jsonConverter);
    String uploadUri = AppConfig.ROOT_URL.concat(AppConfig.ADD_PHOTO);

    HashMap<String, Object> urlVariables = new HashMap<String, Object>();
    urlVariables.put("accessToken", accessToken);

    HttpHeaders httpHeaders = new HttpHeaders();
    httpHeaders.setAccept(Collections.singletonList(MediaType.parseMediaType("application/json")));

    MultiValueMap<String, Object> parts = new LinkedMultiValueMap<String, Object>();
    parts.add("picture", new FileSystemResource(fileToUpload));
    Picture response = rest.postForObject(uploadUri, parts, Picture.class, urlVariables);
    return response;
}

这工作正常,但现在我想从中获取进度更新。

有谁知道这是否可能以及如何做到这一点?

提前致谢 :)

4

2 回答 2

3

所以我遇到了同样的问题,并决定查看 Spring-Android 源代码。经过大量挖掘,我发现了我需要扩展的内容。从这个链接中得到了一些灵​​感。

进度监听器

public interface ProgressListener {
  void transferred(long num);
}

计数输入流

public class CountingInputStream extends FileInputStream {

 private final ProgressListener listener;
 private long transferred;

 public CountingInputStream(File file, ProgressListener listener) throws FileNotFoundException {
    super(file);
    this.listener = listener;
    this.transferred = 0;
 }

 @Override
 public int read(byte[] buffer) throws IOException {
    int bytesRead = super.read(buffer);
    if (bytesRead != -1) {
        this.transferred += bytesRead;
    }
    this.listener.transferred(this.transferred);
    return bytesRead;
 }

}

侦听器文件系统资源

public class ListenerFileSystemResource extends FileSystemResource {

 private final ProgressListener listener;

 public ListenerFileSystemResource(File file, ProgressListener listener) {
     super(file);
     this.listener = listener;
 }

 @Override
 public InputStream getInputStream() throws IOException {
     return new CountingInputStream(super.getFile(), listener);
 }

}

发送文件任务

private class SendFileTask extends AsyncTask<String, Integer, Boolean> {
    private ProgressListener listener;
    private long totalSize;

    @Override
    protected Boolean doInBackground(String... params) {
        File file = new File(filePath);
        totalSize = file.length();
        listener = new ProgressListener() {
            @Override
            public void transferred(long num) {
                publishProgress((int) ((num / (float) totalSize) * 100));
            }
        };
        ListenerFileSystemResource resource = new ListenerFileSystemResource(file, listener);
        MyResult result = new MyService().uploadFile(resource);
    }

我的服务

public FileResult uploadFile(ListenerFileSystemResource resource, Long userId, FileType type) {
    String[] pathParams = {ConnectorConstants.FILE_RESOURCE };
    String[] headerKeys = {"manager_user_id"};
    String[] headerValues = {String.valueOf(userId)};
    String[] formKeys = {ConnectorConstants.FILE_FORM_PARAM};
    Object[] formValues = {resource};

    MultiValueMap<String, Object> body = createMultiValueMap(formKeys, formValues);

    HttpConnector<FileResult> connector = new HttpConnector<FileResult>(FileResult.class);
    return connector.path(pathParams).header(createValuePairs(headerKeys, headerValues)).multipart().body(body).post();
}

连接器

public final class HttpConnector<T> {

    public static String API_URL = "https://myapi.com";

    private UriComponentsBuilder builder;

    private RestTemplate template;

    private Class<T> generic;

    private HttpEntity<?> requestEntity;

    private HttpHeaders headers;

    /**
     * 
     * @param generic
     */
    protected HttpConnector(Class<T> generic)
    {
            this.builder = UriComponentsBuilder.fromUriString(API_URL);
            this.template = new RestTemplate();
    this.template.setRequestFactory(new HttpComponentsClientHttpRequestFactory());
            this.generic = generic;
            this.template.getMessageConverters().add(new GsonHttpMessageConverter(getGson()));
            this.headers = new HttpHeaders();
    }

    /**
     * 
     * @param pathSegments
     * @return
     */
    protected HttpConnector<T> path(String[] pathSegments)
    {
            this.builder = builder.pathSegment(pathSegments);
            return this;
    }

    /**
     * 
     * @param headerParams
     * @return
     */
    protected HttpConnector<T> header(List<NameValuePair> headerParams)
    {
            for (NameValuePair param : headerParams)
            {
                    headers.add(param.getName(), param.getValue());
            }
            return this;
    }

    /**
     * 
     * @param queryParams
     * @return
     */
    protected HttpConnector<T> query(List<NameValuePair> queryParams)
    {
            for (NameValuePair param : queryParams)
            {
                    this.builder = builder.queryParam(param.getName(), param.getValue());
            }
            return this;
    }

    /**
     * 
     * @param body
     * @return
     */
    protected HttpConnector<T> body(MultiValueMap<String, ? extends Object> body)
    {
            this.requestEntity = new HttpEntity<Object>(body, headers);
            return this;
    }

    /**
     * 
     * @param body
     * @return
     */
    protected HttpConnector<T> body(Object body)
    {
            this.requestEntity = new HttpEntity<Object>(body, headers);
            headers.setContentType(MediaType.APPLICATION_JSON);
            return this;
    }

    /**
     * 
     * @return
     */
    protected HttpConnector<T> form()
    {
            headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
            return addFormConverter();
    }

    /**
     * 
     * @return
     */
    protected HttpConnector<T> multipart()
    {
            headers.setContentType(MediaType.MULTIPART_FORM_DATA);
            return addFormConverter();
    }

    /**
     * 
     * @return
     */
    private HttpConnector<T> addFormConverter()
    {
            this.template.getMessageConverters().add(new FormHttpMessageConverter());
            return this;
    }

    /**
     * 
     * @return
     * @throws MeplisNotFoundException 
     */
    protected T post() throws MeplisNotFoundException
    {
            return sendRequest(HttpMethod.POST);
    }

    /**
     * 
     * @return
     * @throws MeplisNotFoundException 
     */
    protected T put() throws MeplisNotFoundException
    {
            return sendRequest(HttpMethod.PUT);
    }

    /**
     * 
     * @return
     * @throws MeplisNotFoundException 
     */
    protected T get() throws MeplisNotFoundException
    {
            return sendRequest(HttpMethod.GET);
    }

    /**
     * 
     * @param method
     * @return
     * @throws MeplisNotFoundException 
     */
    private T sendRequest(HttpMethod method) throws MyServiceNotFoundException
    {
            HttpStatus status = null;
            ResponseEntity<T> response;
            try
            {
                    response = template.exchange(toUri(), method, getRequestEntity(), generic);
                    status = response.getStatusCode();
                    if (HttpStatus.OK.equals(status))
                    {
                            return response.getBody();
                    }
            } catch (HttpClientErrorException e)
            {
                    if (HttpStatus.NOT_FOUND.equals(e.getStatusCode()))
                    {
                            throw new MyServiceNotFoundException();
                    }
                    else
                    {
                            Log.e(getClass().toString(), String.format("Error %s request, status[%s]", method.toString(), e.getStatusCode()), e);
                    }
            } catch (Exception e)
            {
                    Log.e(getClass().toString(), String.format("Error %s request, status: %s", method.toString(), status), e);
            }
            return null;
    }

    /**
     * 
     * @return
     */
    private HttpEntity<?> getRequestEntity()
    {
            if (this.requestEntity == null)
            {
                    this.requestEntity = new HttpEntity<Object>(headers);
            }
            return requestEntity;
    }

    /**
     * 
     * @return
     */
    private URI toUri()
    {
            return this.builder.build().toUri();
    }

    /**
     * 
     * @return
     */
    private Gson getGson()
    {
            return new GsonBuilder().create();
    }

    /**
     * 
     * @return
     */
    public HttpHeaders getHeaders()
    {
            return headers;
    }

}

我使用ListenerFileSystemResource而不是FileSystemResource并且可以工作。希望这对将来的某人有所帮助,因为我没有找到有关 Spring 框架的任何信息。

于 2013-08-09T23:39:19.657 回答
0

您需要覆盖 FormHttpMessageConverter 和 ResourceHttpMessageConverter :

public class ProgressFormHttpMessageConverter extends FormHttpMessageConverter {

    OnProgressListener mOnProgressListener;

    public ProgressFormHttpMessageConverter() {
        super();

        List<HttpMessageConverter<?>> partConverters = new ArrayList<HttpMessageConverter<?>>();
        partConverters.add(new ByteArrayHttpMessageConverter());
        StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter();
        stringHttpMessageConverter.setWriteAcceptCharset(false);
        partConverters.add(stringHttpMessageConverter);
        partConverters.add(new ProgressResourceHttpMessageConverter();
        setPartConverters(partConverters);
    }

    public ProgressFormHttpMessageConverter setOnProgressListener(OnProgressListener listener) {
        mOnProgressListener = listener;
        return this;
    }

    class ProgressResourceHttpMessageConverter extends ResourceHttpMessageConverter {

        @Override
        protected void writeInternal(Resource resource, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {
            InputStream inputStream = resource.getInputStream();
            OutputStream outputStream = outputMessage.getBody();

            byte[] buffer = new byte[StreamUtils.BUFFER_SIZE];
            long contentLength = resource.contentLength();
            int byteCount = 0;
            int bytesRead = -1;
            while ((bytesRead = inputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, bytesRead);
                byteCount += bytesRead;

                if(mOnProgressListener != null) {
                    mOnProgressListener.onProgress(resource, byteCount, contentLength);
                }
            }
            outputStream.flush();
        }
    }

    public interface OnProgressListener {
        void onProgress(Resource resource, int downloaded, int downloadSize);
    }
}
于 2015-06-08T10:49:12.537 回答