- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
通过混合使用相关答案中的代码,我成功地通过 multipart 进行了调用。但是,我无法使用正确的参数名称发送它。
请求必须如何(从 iOS 应用程序中获取):
我的请求看起来如何:
代码:
MultipartRequest 应该是一个基本的多部分请求。
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.graphics.RectF;
import android.util.Log;
import com.android.volley.Request;
import com.android.volley.Response;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.File;
import com.android.volley.AuthFailureError;
import com.android.volley.toolbox.StringRequest;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
public class MultipartRequest extends StringRequest {
private final int maxImageWidth = 200;
private final int maxImageHeight = 200;
static String mimeType;
private final File file;
DataOutputStream dos = null;
String lineEnd = "\r\n";
static String boundary = "apiclient-" + System.currentTimeMillis();
String twoHyphens = "--";
int bytesRead, bytesAvailable, bufferSize;
byte[] buffer;
int maxBufferSize = 124 * 124;
public static MultipartRequest newInstance(final PlayEarnAPIImpl.OnPlayEarnAPIResponse listener, File file, Response.Listener<String> responseListener, Response.ErrorListener errorListener, String serviceURL) {
mimeType = "multipart/form-data;boundary=" + boundary;
return new MultipartRequest(Request.Method.PUT, serviceURL, responseListener, errorListener, file, serviceURL);
}
public MultipartRequest(int method, String url, Response.Listener<String> listener, Response.ErrorListener errorListener, File file, String serviceURL) {
super(method, url, listener, errorListener);
this.file = file;
}
private byte[] decodeFile(File file) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
options.inSampleSize = calculateInSampleSize(options, 400, 400);
Bitmap bitmap = BitmapFactory.decodeFile(file.getAbsolutePath(), options);
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 100, byteArrayOutputStream);
return byteArrayOutputStream.toByteArray();
}
public static int calculateInSampleSize(
BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
final int halfHeight = height / 2;
final int halfWidth = width / 2;
// Calculate the largest inSampleSize value that is a power of 2 and keeps both
// height and width larger than the requested height and width.
while ((halfHeight / inSampleSize) > reqHeight
&& (halfWidth / inSampleSize) > reqWidth) {
inSampleSize *= 2;
}
}
return inSampleSize;
}
//solution 2
private byte[] shrinkImage(File file) {
try {
int inWidth = 0;
int inHeight = 0;
InputStream in = new FileInputStream(file.getAbsolutePath());
// decode image size (decode metadata only, not the whole image)
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeStream(in, null, options);
in.close();
in = null;
// save width and height
inWidth = options.outWidth;
inHeight = options.outHeight;
// decode full image pre-resized
in = new FileInputStream(file.getAbsolutePath());
options = new BitmapFactory.Options();
// calc rought re-size (this is no exact resize)
options.inSampleSize = Math.max(inWidth / maxImageWidth, inHeight / maxImageHeight);
// decode full image
Bitmap roughBitmap = BitmapFactory.decodeStream(in, null, options);
// calc exact destination size
Matrix m = new Matrix();
RectF inRect = new RectF(0, 0, roughBitmap.getWidth(), roughBitmap.getHeight());
RectF outRect = new RectF(0, 0, maxImageWidth, maxImageHeight);
m.setRectToRect(inRect, outRect, Matrix.ScaleToFit.CENTER);
float[] values = new float[9];
m.getValues(values);
// resize bitmap
Bitmap resizedBitmap = Bitmap.createScaledBitmap(roughBitmap, (int) (roughBitmap.getWidth() * values[0]), (int) (roughBitmap.getHeight() * values[4]), true);
// save image
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
resizedBitmap.compress(Bitmap.CompressFormat.PNG, 100, byteArrayOutputStream);
return byteArrayOutputStream.toByteArray();
} catch (IOException e) {
Log.e("Image", e.getMessage(), e);
}
return null;
}
@Override
public String getBodyContentType() {
return mimeType;
}
@Override
public byte[] getBody() throws AuthFailureError {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
dos = new DataOutputStream(bos);
byte[] bitmapData = null;
try {
//dos.writeBytes(twoHyphens + boundary + lineEnd);
dos.writeBytes(lineEnd);
dos.writeBytes(" ------------------12345");
dos.writeBytes(lineEnd);
dos.writeBytes("Content-Disposition: form-data; name=\"picture\"; filename=\"file.png\"");
dos.writeBytes(lineEnd);
dos.writeBytes("Content-Type: image/png");
//dos.writeBytes("Content-Disposition: form-data; name=\"picture\";filename=\""
// + file.getName() + "\"" + lineEnd);
dos.writeBytes(lineEnd);
bitmapData = shrinkImage(this.file);
ByteArrayInputStream fileInputStream = new ByteArrayInputStream(bitmapData);
bytesAvailable = fileInputStream.available();
bufferSize = Math.min(bytesAvailable, maxBufferSize);
Log.d("MultipartRequest", "bufferSize:" + bufferSize);
buffer = new byte[bufferSize];
// read file and write it into form...
bytesRead = fileInputStream.read(buffer, 0, bufferSize);
while (bytesRead > 0) {
dos.write(buffer, 0, bufferSize);
bytesAvailable = fileInputStream.available();
bufferSize = Math.min(bytesAvailable, maxBufferSize);
bytesRead = fileInputStream.read(buffer, 0, bufferSize);
}
// send multipart form data necesssary after file data...
dos.writeBytes(lineEnd);
dos.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd);
return bos.toByteArray();
} catch (IOException e) {
e.printStackTrace();
}
return bitmapData;
}
这是我正在使用的请求:
import com.android.volley.AuthFailureError;
import com.android.volley.Request;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.google.gson.Gson;
import java.io.File;
import java.util.Map;
public class ChangeProfileImageRequest extends MultipartRequest {
private static final String UPDATE_PATH = "users/update";
String serviceURL = APIImpl.API_URL + UPDATE_PATH;
public static ChangeProfileImageRequest newInstance(final APIImpl.OnAPIResponse listener, File file) {
String serviceURL = APIImpl.API_URL + UPDATE_PATH;
return new ChangeProfileImageRequest(Request.Method.PUT, serviceURL, new ResponseListener(listener), new ErrorListener(listener), file, serviceURL);
}
public ChangeProfileImageRequest(int method, String url, Response.Listener<String> listener, Response.ErrorListener errorListener, File file, String serviceURL) {
super(method, url, listener, errorListener, file, serviceURL);
}
@Override
public Map<String, String> getHeaders() throws AuthFailureError {
Map<String, String> headers = new APIImpl().getTokenHeader();
//headers.put("Accept", "*/*");
headers.put("Content-Type", "multipart/form-data;boundary=----------------12345");
AppController.getInstance().addSessionCookie(headers);
return headers;
}
所以我猜这与“无法解码多部分正文”的屏幕截图有关,但我不知 Prop 体问题是什么。同样从服务器端未收到图片参数。
最佳答案
我设法让它工作,将 com.squareup.okhttp 添加到 gradle,并更改 this class一点点。
基本多部分请求:
import com.android.volley.AuthFailureError;
import com.android.volley.DefaultRetryPolicy;
import com.android.volley.NetworkResponse;
import com.android.volley.Request;
import com.android.volley.Response;
import com.android.volley.RetryPolicy;
import com.android.volley.VolleyLog;
import com.android.volley.toolbox.HttpHeaderParser;
import com.squareup.okhttp.Headers;
import com.squareup.okhttp.MediaType;
import com.squareup.okhttp.MultipartBuilder;
import com.squareup.okhttp.RequestBody;
import android.util.Log;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Map;
import okio.Buffer;
/**
* Multipart request for Google's Volley using Square's OkHttp.
*
* @author Hussain Al-Derry
* @version 1.0
*/
public class VolleyMultipartRequest extends Request<String> {
/* Used for debugging */
private static final String TAG = VolleyMultipartRequest.class.getSimpleName();
/* MediaTypes */
public static final MediaType MEDIA_TYPE_JPEG = MediaType.parse("image/jpeg");
public static final MediaType MEDIA_TYPE_PNG = MediaType.parse("image/png");
public static final MediaType MEDIA_TYPE_TEXT_PLAIN = MediaType.parse("text/plain");
private MultipartBuilder mBuilder = new MultipartBuilder();
private final Response.Listener<String> mListener;
private RequestBody mRequestBody;
public VolleyMultipartRequest(int method, String url,
Response.ErrorListener errorListener,
Response.Listener<String> listener) {
super(method, url, errorListener);
mListener = listener;
mBuilder.type(MultipartBuilder.FORM);
}
/**
* Adds a collection of string values to the request.
*
* @param mParams {@link HashMap} collection of values to be added to the request.
*/
public void addStringParams(HashMap<String, String> mParams) {
for (Map.Entry<String, String> entry : mParams.entrySet()) {
mBuilder.addPart(
Headers.of("Content-Disposition", "form-data; name=\"" + entry.getKey() + "\""),
RequestBody.create(MEDIA_TYPE_TEXT_PLAIN, entry.getValue()));
}
}
/**
* Adds a single value to the request.
*
* @param key String - the field name.
* @param value String - the field's value.
*/
public void addStringParam(String key, String value) {
mBuilder.addPart(
Headers.of("Content-Disposition", "form-data; name=\"" + key + "\""),
RequestBody.create(MEDIA_TYPE_TEXT_PLAIN, value));
}
/**
* Adds a binary attachment to the request.
*
* @param content_type {@link MediaType} - the type of the attachment.
* @param fileName String - the attachment field name.
* @param value {@link File} - the file to be attached.
*/
public void addAttachment(MediaType content_type, String paramName, String fileName, File value) {
mBuilder.addFormDataPart(paramName, fileName, RequestBody.create(content_type, value));
}
/**
* Builds the request.
* Must be called before adding the request to the Volley request queue.
*/
public void buildRequest() {
mRequestBody = mBuilder.build();
}
@Override
public String getBodyContentType() {
return mRequestBody.contentType().toString();
}
@Override
public byte[] getBody() throws AuthFailureError {
Buffer buffer = new Buffer();
try {
mRequestBody.writeTo(buffer);
} catch (IOException e) {
Log.e(TAG, e.toString());
VolleyLog.e("IOException writing to ByteArrayOutputStream");
}
return buffer.readByteArray();
}
@Override
protected Response<String> parseNetworkResponse(NetworkResponse response) {
String parsed;
try {
parsed = new String(response.data, HttpHeaderParser.parseCharset(response.headers));
} catch (UnsupportedEncodingException e) {
parsed = new String(response.data);
}
return Response.success(parsed, HttpHeaderParser.parseCacheHeaders(response));
}
@Override
public Request<?> setRetryPolicy(RetryPolicy retryPolicy) {
return super.setRetryPolicy(retryPolicy);
}
@Override
protected void deliverResponse(String response) {
if (mListener != null) {
mListener.onResponse(response);
}
}
}
并根据我的特定要求对其进行子类化:
public class ChangeProfileImageRequest extends VolleyMultipartRequest {
private static final String UPDATE_PATH = "users/update";
public static ChangeProfileImageRequest newInstance(final APIImpl.OnAPIResponse listener, File file) {
String serviceURL = APIImpl.API_URL + UPDATE_PATH;
//return new ChangeProfileImageRequest(Request.Method.PUT, serviceURL, new ResponseListener(listener), new ErrorListener(listener), file, serviceURL);
ChangeProfileImageRequest request = new ChangeProfileImageRequest(Method.PUT, serviceURL, new ErrorListener(listener), new ResponseListener(listener));
request.addAttachment(MEDIA_TYPE_PNG, "picture", "file.png", file);
return request;
}
public ChangeProfileImageRequest(int method, String url, Response.ErrorListener errorListener, Response.Listener<String> listener) {
super(method, url, errorListener, listener);
}
@Override
public Map<String, String> getHeaders() throws AuthFailureError {
Map<String, String> headers = new APIImpl().getTokenHeader();
headers.put("Accept", "*/*");
AppController.getInstance().addSessionCookie(headers);
return headers;
}
//ErrorListener and ResponseListener classes
并将其添加到 Volley 中:
public void updateProfileImage(APIImpl.OnAPIResponse listener, File image) {
ChangeProfileImageRequest request = ChangeProfileImageRequest.newInstance(listener, image);
request.buildRequest();
// Access the RequestQueue through your singleton class.
request.setRetryPolicy(new DefaultRetryPolicy(
0,
DefaultRetryPolicy.DEFAULT_MAX_RETRIES,
DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
VolleySingleton.getInstance().addToRequestQueue(request);
}
不过,我会接受一个只使用 Volley 的答案。我想仅仅因为一个请求不起作用就使用 Volley 和 OkHttp 并不理想。
关于java - Android Volley 多部分参数名称,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36183571/
我正在尝试做这样的事情:Name[i] = "Name"+ (i+1) 在 forloop 中,这样数组的值将是:Name[0] = Name1,Name[1] = Name2,Name[2] = N
我读了here,在GSP中我们可以这样写: ${params.action} 从GSP中,我们可以使用${params.action}作为参数调用Javascript函数(请参阅here)。 是否有其
我的问题:非常具体。我正在尝试想出解析以下文本的最简单方法: ^^domain=domain_value^^version=version_value^^account_type=account_ty
我创建了一条与此类似的路线: Router::connect("/backend/:controller/:action/*"); 现在我想将符合此模式的每个 Controller 路由重命名为类似
我在 Visual Studio 2013 项目中收到以下警告: SQL71502 - Procedure has an unresolved reference to object 最佳答案 这可以
任何人都可以指导我使用名称/值 .NET 集合或 .NET 名称/值字典以获得最佳性能吗?请问最好的方法是什么?我的应用程序是 ASP.NET、WCF/WF Web 应用程序。每个集合应该有 10 到
我在 Zend Framework 2 中有一个默认模块: namespace Application\Controller; use Zend\Mvc\Controller\AbstractActi
这是表格: 关于javascript - 在 javascript 中,这是一个有效的结构吗? : document. 名称.名称.值?,我们在Stack Overflow上找到一个类似的
HtmlHelper.ActionLink(htmlhelper,string linktext,string action) 如何找出正确的路线? 如果我有这个=> HtmlHelper.Actio
我需要一些有关如何将 Controller 定义传递给嵌套在 outer 指令中的 inner 指令的帮助。请参阅http://plnkr.co/edit/Om2vKdvEty9euGXJ5qan一个
请提出一个数据结构来表示内存中的记录列表。每条记录由以下部分组成: 用户名 积分 排名(基于积分)- 可选字段- 可以存储在记录中或可以动态计算 数据结构应该支持高效实现以下操作: Insert(re
错误 : 联合只能在具有兼容列类型的表上执行。 结构(层:字符串,skyward_number:字符串,skyward_points:字符串)<> 结构(skyward_number:字符串,层:字符
我想要一个包含可变数量函数的函数,但我希望在实际使用它们之前不要对它们求值。我可以使用 () => type 语法,但我更愿意使用 => type 语法,因为它似乎是为延迟评估而定制的。 当我尝试这样
我正在编写一个 elisp 函数,它将给定键永久绑定(bind)到当前主要模式的键盘映射中的给定命令。例如, (define-key python-mode-map [C-f1] 'pytho
卡在R中的错误上。 Error in names(x) <- value : 'names' attribute must be the same length as the ve
我有字符串,其中包含名称,有时在字符串中包含用户名,后跟日期时间戳: GN1RLWFH0546-2020-04-10-18-09-52-563945.txt JOHN-DOE-2020-04-10-1
有人知道为什么我会收到此错误吗?这显示将我的项目升级到新版本的Unity3d之后。 Error CS0103: The name `Array' does not exist in the curre
由于 Embarcadero 的 NNTP 服务器从昨天开始就停止响应,我想我可以在这里问:我使用非数据库感知网格,我需要循环遍历数据集以提取列数、它们的名称、数量行数以及每行中每个字段的值。 我知道
在构建Android应用程序的子项目中,我试图根据根build.gradle中的变量设置版本代码/名称。 子项目build.gradle: apply plugin: 'com.android.app
示例用例: 我有一个带有属性“myProperty”的对象,具有 getter 和 setter(自 EcmaScript 5 起支持“Property Getters 和 Setters”:http
我是一名优秀的程序员,十分优秀!