我有一个简单的应用程序通过Async任务与其Servlet后端通信。 我在理解消息如何被包装以及如何操纵这些消息的数据结构方面遇到了一些麻烦。 我想要做的是接收多个对象或多个异构信息。 我的代码:
public class MyServlet extends HttpServlet {
ArrayList<Tour> m_tours;
@Override
public void doGet(HttpServletRequest req, HttpServletResponse resp)
throws IOException {
resp.setContentType("text/plain");
resp.getWriter().println("Please use the form to POST to this url");
}
@Override
public void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {
String order = req.getParameter("order");
resp.setContentType("text/plain");
if (order == null) {
resp.getWriter().println("Please enter a name");
}
resp.getWriter().println("yay name received");
ArrayList<Tour> m_tours = getTours(); //returns a populated ArrayList of custom Tour objects
resp.getWriter().print(m_tours);
}
private void getTours(){
//some code here
}
}`
我的异步任务类:
class ServletPostAsyncTask extends AsyncTask<Pair<Context, String>, Void, String> {
private Context context;
@Override
protected String doInBackground(Pair<Context, String>... params) {
context = params[0].first;
String order = params[0].second;
String[] url = new String[3];
url[0] = "http://192.168.169.85:8080/hello";
url[1] = "http://10.0.2.2:8080/hello";
url[2] = "http://192.168.1.102:8080/hello";
HttpClient httpClient = new DefaultHttpClient();
HttpPost httpPost = new HttpPost(url[2]);
List<NameValuePair> nameValuePairs = new ArrayList<>(1);
nameValuePairs.add(new BasicNameValuePair("order", order));
try {
// Add name data to request
httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
// Execute HTTP Post Request
HttpResponse response = httpClient.execute(httpPost);
HttpEntity entity = response.getEntity();
if (response.getStatusLine().getStatusCode() == 200) {
return EntityUtils.toString(entity);
}
return "Error: " + response
.getStatusLine()
.getStatusCode() + " " + response
.getStatusLine().getReasonPhrase();
} catch (ClientProtocolException e) {
return e.getMessage();
} catch (IOException e) {
return e.getMessage();
}
}
@Override
protected void onPostExecute(String result) {
String result1 = "Response: "+result;
Toast.makeText(context, result1, Toast.LENGTH_LONG).show();
}
}
响应消息将ArrayList作为text:
返回 Response: yay name received
packagename@objectkey1
packagename@objectkey2
packagename@objectkey3
...
packagename@objectkeyn
但相反,我想要的是将它原样存储为ArrayList。 如何配置我的异步任务以接收我的m_tours ArrayList并将其存储在某处以供进一步使用? 此外,如何配置它以接收多个对象?
*编辑*
我按照@orip的建议尝试使用Gson,设置Async任务如下:
@Override
protected String doInBackground(Pair<Context, String>... params) {
context = params[0].first;
String order = params[0].second;
String[] url = new String[3];
url[0] = "http://192.168.169.85:8080/hello";
url[1] = "http://10.0.2.2:8080/hello";
url[2] = "http://192.168.1.102:8080/hello";
// HttpPost httpPost = new HttpPost("http://semiotic-art-88319.appspot.com/hello");
HttpClient httpClient = new DefaultHttpClient(); //127.0.0.1 - 10.201.19.153
HttpPost httpPost = new HttpPost(url[2]);
List<NameValuePair> nameValuePairs = new ArrayList<>(1);
nameValuePairs.add(new BasicNameValuePair("order", order));
try {
// Add name data to request
httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
// Execute HTTP Post Request
HttpResponse response = httpClient.execute(httpPost);
if (response.getStatusLine().getStatusCode() == 200) {
HttpEntity entity = response.getEntity();
return EntityUtils.toString(entity);
}
return "Error: " + response
.getStatusLine()
.getStatusCode() + " " + response
.getStatusLine().getReasonPhrase();
} catch (ClientProtocolException e) {
return e.getMessage();
} catch (IOException e) {
return e.getMessage();
}
}
@Override
protected void onPostExecute(String jsonResponse) {
Gson gson = new Gson();
tours = (gson.fromJson(jsonResponse, Tours.class));
Toast.makeText(context, jsonResponse, Toast.LENGTH_LONG).show();
}
并在服务器端:
@Override
public void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {
String asyncMessage = req.getParameter("order");
if(asyncMessage.equals("tours")){
m_tours = getTours(); //ArrayList<Tour> m_tours;
Tours tours = new Tours(m_tours);
resp.setContentType("application/json");
PrintWriter out = resp.getWriter();
out.print(new Gson().toJson(tours));
out.flush();
resp.getWriter().print(m_tours);
}
}
但是我收到了错误:
03-23 13:27:09.523 32387-32387/madapps.bicitourbo E/AndroidRuntime﹕ FATAL EXCEPTION: main
Process: madapps.bicitourbo, PID: 32387
com.google.gson.JsonSyntaxException: com.google.gson.stream.MalformedJsonException: Use JsonReader.setLenient(true) to accept malformed JSON at line 1 column 692 path $
at com.google.gson.Gson.assertFullConsumption(Gson.java:786)
at com.google.gson.Gson.fromJson(Gson.java:776)
at com.google.gson.Gson.fromJson(Gson.java:724)
at com.google.gson.Gson.fromJson(Gson.java:696)
at madapps.bicitourbo.ServletPostAsyncTask.onPostExecute(ServletPostAsyncTask.java:92)
at madapps.bicitourbo.ServletPostAsyncTask.onPostExecute(ServletPostAsyncTask.java:36)
at android.os.AsyncTask.finish(AsyncTask.java:632)
at android.os.AsyncTask.access$600(AsyncTask.java:177)
at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:645)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:149)
at android.app.ActivityThread.main(ActivityThread.java:5257)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:609)
at dalvik.system.NativeStart.main(Native Method)
Caused by: com.google.gson.stream.MalformedJsonException: Use JsonReader.setLenient(true) to accept malformed JSON at line 1 column 692 path $
该行发生此错误:
Tour tours = (gson.fromJson(jsonResponse, Tours.class));
我做错了什么?
* EDIT2 * 解决:
错误:Caused by: com.google.gson.stream.MalformedJsonException: Use JsonReader.setLenient(true) to accept malformed JSON
是因为我正在调用resp.getWriter().print()
两次,正如@orip所建议的那样。谢谢!
答案 0 :(得分:2)
将servlet的内容类型设置为application/json
并返回JSON字符串(例如,使用Gson或Jackson来序列化结果。
在Android方面,您可以使用Android的内置JSON类或(更好)使用您在servlet中使用的相同库来反序列化JSON字符串。
例如,如果Tour
类似于:
public class Tour {
// some simple int/string/list fields
}
您可以构建一个响应类,如:
public class Tours {
private List<Tour> tours;
// ...
}
然后在服务器端(请参阅this question,我在这里使用Gson):
List<Tour> listOfTours = ...;
Tours tours = new Tours(listOfTours);
response.setContentType("application/json");
PrintWriter out = response.getWriter();
out.print((new Gson()).toJson(tours));
out.flush();
在客户端:
String jsonResponse = ...;
Tours tours = (new Gson()).fromJson(jsonResponse, Tours.class);
有一些优化要做,但这可以让你开始。
另外,考虑将OkHttp用于HTTP连接,而不是使用HttpClient
,您可能最终会得到更简单,更健壮的代码。