android客户端+JAVA WEB服务器实现json数据解析
首先,项目中使用javaweb作为后台服务器,源码地址:服务器和客户端源码地址。
接下来进入正题。
一、java web服务器
这里就多说了,不太了解j2ee的请查阅相关书籍。
项目结构如下:
News类定义了之后解析的JSON对象的内容;
NewsServer则是定义了一个获取最新新闻News的接口;
NewsServer则是实现了这个接口,定义了获取最新新闻的方法;
NewsListServlet则是一个实现客户端get和post请求的servlet,用于实现网络请求时的业务逻辑处理,主要返回含有News内容的json字符串;
jsonnewslist.jsp是一个jsp文件用于测试服务器是否正常运行。
服务器部分就不啰嗦了,直接贴代码和截图
(1)News类
- <span style="font-size:18px;"> public class News {
- private Integer id;
- private String title;
- private Integer timelength;
- public News(Integer id, String title, Integer timelength) {
- this.id = id;
- this.title = title;
- this.timelength = timelength;
- }
- public Integer getId() {
- return id;
- }
- public void setId(Integer id) {
- this.id = id;
- }
- public String getTitle() {
- return title;
- }
- public void setTitle(String title) {
- this.title = title;
- }
- public Integer getTimelength() {
- return timelength;
- }
- public void setTimelength(Integer timelength) {
- this.timelength = timelength;
- }
- }</span>
- <span style="font-size:18px;">public interface NewsServer {
- /*
- * 获取最新的新闻News
- */
- public java.util.List<News> getLastNews();
- }</span>
- <span style="font-size:18px;">import java.util.ArrayList;
- import java.util.List;
- public class NewsServerBean implements NewsServer {
- @Override
- public List<News> getLastNews() {
- // TODO Auto-generated method stub
- List<News> news = new ArrayList<>();
- news.add(new News(10, "吕文健", 20));
- news.add(new News(45, "李昱喜", 10));
- news.add(new News(89, "android is amazing", 50));
- return news;
- }
- }</span>
- <span style="font-size:18px;">import java.io.IOException;
- import java.util.List;
- import javax.servlet.ServletException;
- import javax.servlet.annotation.WebServlet;
- import javax.servlet.http.HttpServlet;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- @WebServlet(name="newslist",
- urlPatterns={"/newslist"}
- )//配置Servlet
- public class NewsListServlet extends HttpServlet {
- /**
- *
- */
- private static final long serialVersionUID = 1L;
- NewsServerBean serverbean =new NewsServerBean();
- @Override
- protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
- // TODO Auto-generated method stub
- doPost(req, resp);
- }
- @Override
- protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
- // TODO Auto-generated method stub
- req.setCharacterEncoding("GBK");</span>
- <span style="font-size:18px;"> resp.setCharacterEncoding("GBK");//这里设置成gbk防止手机端显示乱码,之前设置为utf-8总是乱码
- List<News> news = serverbean.getLastNews();</span>
- <span style="font-size:18px;"> StringBuilder json = new StringBuilder();
- json.append("[");
- for(News news2:news){
- json.append('{').append("\"id\":").append(news2.getId()).append(",");
- json.append("\"title\":").append("\""+news2.getTitle()+"\"").append(",");
- json.append("\"timelength\":").append(news2.getTimelength());
- json.append('}').append(",");
- }
- json.deleteCharAt(json.length()-1);//?
- json.append("]");
- req.setAttribute("json", json.toString());
- req.getRequestDispatcher("/jsonnewslist.jsp").forward(req, resp);
- }
- }</span>
(5)jsonnewslist.jsp(在服务端测试服务器是否布置成功)
- <span style="font-size:18px;"><%@ page language="java" contentType="text/plain; charset=GBK"
- pageEncoding="GBK"%>
- ${json}</span>
OK,运行成功,服务器解决了,楼主把它打包成war,放在阿里云服务器上,省去了用电脑做服务器的各种麻烦。 接下来进入正题,客户端解析Json
二、android客户端
客户端部分主要是一个简单的listview显示获取的news,运行结果如下:
![](https://i-blog.csdnimg.cn/blog_migrate/6a70988a22818fbbd84606efee44c0dd.png)
接下来,开始贴代码:
1、布局文件:
(1)activity_main.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/activity_main" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context="wf.com.getnewsinjson.MainActivity"> <Button android:id="@+id/btn_refresh" android:layout_width="match_parent" android:layout_height="50dp" android:text="刷新" /> <ListView android:id="@+id/listview" android:layout_width="match_parent" android:layout_height="wrap_content" /> </LinearLayout>(2)item.xml(ListView中每一个item的布局)
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="match_parent" > <TextView android:id="@+id/title" android:layout_width="0dp" android:layout_height="50dp" android:layout_weight="1" android:gravity="center" /> <TextView android:layout_marginLeft="10dp" android:id="@+id/timelength" android:layout_width="0dp" android:layout_weight="1" android:layout_height="50dp" android:gravity="center" /> </LinearLayout>2、主要代码
(1)、News类(和之前服务器中的一样,用于解析)
(2)、NewsServer类(用于连接服务器并解析JSON字符串)
import android.util.Log; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.List; import Util.StreamTool; /** * Created by wangfeng on 2016/12/8. */ public class NewsService { public static List<News> getJsonLastNews() { List<News> list = null; InputStream in = null; String path = "http://*****";//这里输入自己的服务器地址 try { list = new ArrayList<>(); URL url = new URL(path); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setConnectTimeout(5000); conn.setRequestMethod("GET"); if (conn.getResponseCode()==200){ in = conn.getInputStream(); list = parseJSON(in); } } catch (MalformedURLException e) { e.printStackTrace(); System.out.println("客户端未连接到服务器"); } catch (IOException e) { e.printStackTrace(); System.out.println("客户端未连接到服务器"); } return list; }
/*
*解析json字符串并返回一个List
*/
public static List<News> parseJSON(InputStream in){ List<News> list = null; try { list = new ArrayList<>(); // String str = StreamTool.streamToString(in); // System.out.println(str); byte[] bytes = StreamTool.stream2Byte(in);//这里用到了StreamTool工具类,自己到CSDN上下载一个,这里是把 //输入流转化为字节数组
String str = new String (bytes,"GBK");//因为服务器设置了返回编码为GBK,这里也设置编码方式为GBK System.out.println("解析成功"+str); JSONArray jsonArray = new JSONArray(str);//将json字符串转化为JSONArray for(int i =0;i< jsonArray.length();i++){ JSONObject jsonObject = jsonArray.getJSONObject(i);//循环JSONArray获得每一个JSONObject对象 int id = jsonObject.getInt("id"); String title = jsonObject.getString("title"); int timelength = jsonObject.getInt("timelength"); list.add(new News(id,title,timelength)); } } catch (IOException e) { e.printStackTrace(); Log.e("io","输入流读取错误"); } catch (JSONException e) { e.printStackTrace(); Log.e("json","json数组转换错误"); } catch (Exception e) { e.printStackTrace(); } return list; } }
(3)MainActivity类
import android.os.Handler; import android.os.Message; import android.support.v7.app.AppCompatActivity; import android.view.View; import android.widget.Button; import android.widget.ListView; import android.widget.SimpleAdapter; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import butterknife.BindView; import butterknife.ButterKnife; import butterknife.OnClick; public class MainActivity extends AppCompatActivity implements Runnable { List<HashMap<String,Object>> data; private static final int TAG =0X1;//用于Handler中的异步处理标志 Thread thread = null;//声明线程,用于执行NewsServer中的网络访问 Handler handler = new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); switch (msg.what){ case TAG: SimpleAdapter simpleAdapter = new SimpleAdapter(MainActivity.this,data,R.layout.item,new String[]{"title","timelength"},new int[]{R.id.title,R.id.timelength}); listview.setAdapter(simpleAdapter); break; } } }; @BindView(R.id.btn_refresh) Button btnRefresh; @BindView(R.id.listview) ListView listview; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ButterKnife.bind(this);//这里使用了ButterKnife组件来初始化组件和绑定id,不懂得自行百度 } @OnClick(R.id.btn_refresh) public void onClick(View view) { switch (view.getId()) { case R.id.btn_refresh: thread = new Thread(this); thread.start(); break; } } @Override public void run() { String length = getResources().getString(R.string.timelength); List<News> news = NewsService.getJsonLastNews();//这里必须另起一个线程访问,不能在主线程中访问 data = new ArrayList<>(); for(News news1:news){ HashMap<String,Object> item = new HashMap<>(); item.put("id",news1.getId()); item.put("title",news1.getTitile()); item.put("timelength",length+": "+news1.getTimelength()); data.add(item); } Message msg = new Message(); msg.what=TAG; handler.sendMessage(msg);//通知组件更新界面 } }
三、后记
作为一只菜鸟不得不承认在这次练习中,犯了不少低级错误,比如,服务器端,没有设置返回的编码方式,json字符串忘记加“ ”;在客户端,在非UI线程中更新UI组件,在解析json时没有设置编码方式,在设置请求方式时将GET写成Get,哎,吃一堑长一智。
- private String title;
- private Integer timelength;
- public News(Integer id, String title, Integer timelength) {
- this.id = id;
- this.title = title;
- this.timelength = timelength;
- }
- public Integer getId() {
- return id;
- }
- public void setId(Integer id) {
- this.id = id;
- }
- public String getTitle() {
- return title;
- }
- public void setTitle(String title) {
- this.title = title;
- }
- public Integer getTimelength() {
- return timelength;
- }
- public void setTimelength(Integer timelength) {
- this.timelength = timelength;
- }
- }</span>
- <span style="font-size:18px;">public interface NewsServer {
- /*
- * 获取最新的新闻News
- */
- public java.util.List<News> getLastNews();
- }</span>
- <span style="font-size:18px;">import java.util.ArrayList;
- import java.util.List;
- public class NewsServerBean implements NewsServer {
- @Override
- public List<News> getLastNews() {
- // TODO Auto-generated method stub
- List<News> news = new ArrayList<>();
- news.add(new News(10, "吕文健", 20));
- news.add(new News(45, "李昱喜", 10));
- news.add(new News(89, "android is amazing", 50));
- return news;
- }
- }</span>
- <span style="font-size:18px;">import java.io.IOException;
- import java.util.List;
- import javax.servlet.ServletException;
- import javax.servlet.annotation.WebServlet;
- import javax.servlet.http.HttpServlet;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- @WebServlet(name="newslist",
- urlPatterns={"/newslist"}
- )//配置Servlet
- public class NewsListServlet extends HttpServlet {
- /**
- *
- */
- private static final long serialVersionUID = 1L;
- NewsServerBean serverbean =new NewsServerBean();
- @Override
- protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
- // TODO Auto-generated method stub
- doPost(req, resp);
- }
- @Override
- protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
- // TODO Auto-generated method stub
- req.setCharacterEncoding("GBK");</span>
- <span style="font-size:18px;"> resp.setCharacterEncoding("GBK");//这里设置成gbk防止手机端显示乱码,之前设置为utf-8总是乱码
- List<News> news = serverbean.getLastNews();</span>
- <span style="font-size:18px;"> StringBuilder json = new StringBuilder();
- json.append("[");
- for(News news2:news){
- json.append('{').append("\"id\":").append(news2.getId()).append(",");
- json.append("\"title\":").append("\""+news2.getTitle()+"\"").append(",");
- json.append("\"timelength\":").append(news2.getTimelength());
- json.append('}').append(",");
- }
- json.deleteCharAt(json.length()-1);//?
- json.append("]");
- req.setAttribute("json", json.toString());
- req.getRequestDispatcher("/jsonnewslist.jsp").forward(req, resp);
- }
- }</span>
(5)jsonnewslist.jsp(在服务端测试服务器是否布置成功)
- <span style="font-size:18px;"><%@ page language="java" contentType="text/plain; charset=GBK"
- pageEncoding="GBK"%>
- ${json}</span>
OK,运行成功,服务器解决了,楼主把它打包成war,放在阿里云服务器上,省去了用电脑做服务器的各种麻烦。 接下来进入正题,客户端解析Json
二、android客户端
客户端部分主要是一个简单的listview显示获取的news,运行结果如下:
![](https://i-blog.csdnimg.cn/blog_migrate/6a70988a22818fbbd84606efee44c0dd.png)
接下来,开始贴代码:
1、布局文件:
(1)activity_main.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/activity_main" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context="wf.com.getnewsinjson.MainActivity"> <Button android:id="@+id/btn_refresh" android:layout_width="match_parent" android:layout_height="50dp" android:text="刷新" /> <ListView android:id="@+id/listview" android:layout_width="match_parent" android:layout_height="wrap_content" /> </LinearLayout>(2)item.xml(ListView中每一个item的布局)
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="match_parent" > <TextView android:id="@+id/title" android:layout_width="0dp" android:layout_height="50dp" android:layout_weight="1" android:gravity="center" /> <TextView android:layout_marginLeft="10dp" android:id="@+id/timelength" android:layout_width="0dp" android:layout_weight="1" android:layout_height="50dp" android:gravity="center" /> </LinearLayout>2、主要代码
(1)、News类(和之前服务器中的一样,用于解析)
(2)、NewsServer类(用于连接服务器并解析JSON字符串)
import android.util.Log; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.List; import Util.StreamTool; /** * Created by wangfeng on 2016/12/8. */ public class NewsService { public static List<News> getJsonLastNews() { List<News> list = null; InputStream in = null; String path = "http://*****";//这里输入自己的服务器地址 try { list = new ArrayList<>(); URL url = new URL(path); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setConnectTimeout(5000); conn.setRequestMethod("GET"); if (conn.getResponseCode()==200){ in = conn.getInputStream(); list = parseJSON(in); } } catch (MalformedURLException e) { e.printStackTrace(); System.out.println("客户端未连接到服务器"); } catch (IOException e) { e.printStackTrace(); System.out.println("客户端未连接到服务器"); } return list; }
/*
*解析json字符串并返回一个List
*/
public static List<News> parseJSON(InputStream in){ List<News> list = null; try { list = new ArrayList<>(); // String str = StreamTool.streamToString(in); // System.out.println(str); byte[] bytes = StreamTool.stream2Byte(in);//这里用到了StreamTool工具类,自己到CSDN上下载一个,这里是把 //输入流转化为字节数组
String str = new String (bytes,"GBK");//因为服务器设置了返回编码为GBK,这里也设置编码方式为GBK System.out.println("解析成功"+str); JSONArray jsonArray = new JSONArray(str);//将json字符串转化为JSONArray for(int i =0;i< jsonArray.length();i++){ JSONObject jsonObject = jsonArray.getJSONObject(i);//循环JSONArray获得每一个JSONObject对象 int id = jsonObject.getInt("id"); String title = jsonObject.getString("title"); int timelength = jsonObject.getInt("timelength"); list.add(new News(id,title,timelength)); } } catch (IOException e) { e.printStackTrace(); Log.e("io","输入流读取错误"); } catch (JSONException e) { e.printStackTrace(); Log.e("json","json数组转换错误"); } catch (Exception e) { e.printStackTrace(); } return list; } }
(3)MainActivity类
import android.os.Handler; import android.os.Message; import android.support.v7.app.AppCompatActivity; import android.view.View; import android.widget.Button; import android.widget.ListView; import android.widget.SimpleAdapter; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import butterknife.BindView; import butterknife.ButterKnife; import butterknife.OnClick; public class MainActivity extends AppCompatActivity implements Runnable { List<HashMap<String,Object>> data; private static final int TAG =0X1;//用于Handler中的异步处理标志 Thread thread = null;//声明线程,用于执行NewsServer中的网络访问 Handler handler = new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); switch (msg.what){ case TAG: SimpleAdapter simpleAdapter = new SimpleAdapter(MainActivity.this,data,R.layout.item,new String[]{"title","timelength"},new int[]{R.id.title,R.id.timelength}); listview.setAdapter(simpleAdapter); break; } } }; @BindView(R.id.btn_refresh) Button btnRefresh; @BindView(R.id.listview) ListView listview; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ButterKnife.bind(this);//这里使用了ButterKnife组件来初始化组件和绑定id,不懂得自行百度 } @OnClick(R.id.btn_refresh) public void onClick(View view) { switch (view.getId()) { case R.id.btn_refresh: thread = new Thread(this); thread.start(); break; } } @Override public void run() { String length = getResources().getString(R.string.timelength); List<News> news = NewsService.getJsonLastNews();//这里必须另起一个线程访问,不能在主线程中访问 data = new ArrayList<>(); for(News news1:news){ HashMap<String,Object> item = new HashMap<>(); item.put("id",news1.getId()); item.put("title",news1.getTitile()); item.put("timelength",length+": "+news1.getTimelength()); data.add(item); } Message msg = new Message(); msg.what=TAG; handler.sendMessage(msg);//通知组件更新界面 } }
三、后记
作为一只菜鸟不得不承认在这次练习中,犯了不少低级错误,比如,服务器端,没有设置返回的编码方式,json字符串忘记加“ ”;在客户端,在非UI线程中更新UI组件,在解析json时没有设置编码方式,在设置请求方式时将GET写成Get,哎,吃一堑长一智。