问题描述
我有一个简单的应用程序通过异步任务与其 Servlet 后端通信.我在理解消息的包装方式以及如何操作这些消息的数据结构时遇到了一些麻烦.我想做的是接收多个对象,或者无论如何接收多个异构信息.我的代码:
I have a simple app communicating with its Servlet backend through an Async task. I have some trouble understanding how the messages are wrapped up and how to manipulate the data structures of these messages. What I want to do is to receive either multiple objects, or multiple heterogeneous information anyway. My code:
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:
The response message returns ArrayList as text:
Response: yay name received
packagename@objectkey1
packagename@objectkey2
packagename@objectkey3
...
packagename@objectkeyn
但相反,我想要的是将它按原样存储为 ArrayList.如何配置我的异步任务以接收我的 m_tours ArrayList 并将其存储在某处以供进一步使用?此外,如何配置它以接收多个对象?
But instead, what I want is to store it as it is, as an ArrayList. How can I configure my Async task to receive my m_tours ArrayList and store it somewhere for further use? Furthermore, how can I configure it to receive multiple objects?
* 编辑 *
我已经按照@orip 的建议尝试使用 Gson,将异步任务设置如下:
I've tried by using Gson as suggested by @orip, setting the Async task as follows:
@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 所建议的那样.谢谢!
The error: Caused by: com.google.gson.stream.MalformedJsonException: Use JsonReader.setLenient(true) to accept malformed JSON
was due to the fact that I was calling resp.getWriter().print()
two times, as suggested by @orip. Thank you!
推荐答案
将 servlet 的内容类型设置为 application/json
并返回一个 JSON 字符串(例如使用 Gson 或 Jackson 序列化结果.
Set the servlet's content type to application/json
and return a JSON string (e.g using Gson or Jackson to serialize the result.
在 Android 端,您可以使用 Android 的内置 JSON 类或(更好)使用您在 servlet 中使用的相同库来反序列化 JSON 字符串.
On the Android side you can deserialize the JSON string, either using Android's built-in JSON classes or (better) using the same libraries you used in your servlet.
例如,如果 Tour
类似于:
For example, if Tour
is something like:
public class Tour {
// some simple int/string/list fields
}
您可以构建一个响应类,例如:
You can build a response class like:
public class Tours {
private List<Tour> tours;
// ...
}
然后在服务器端(参见 这个问题,我在这里使用 Gson):
Then on the server side (see this question, I'm using Gson here):
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 代替 HttpClient
用于您的 HTTP 连接,您最终可能会得到更简单、更健壮的代码.
There are some optimizations to be made, but that could get you started.
Also, consider using OkHttp for your HTTP connections instead of using HttpClient
, you'll probably end up with simpler and more robust code.
这篇关于异步任务的消息与 Java Servlet 交换的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!