1 該項目的主要功能是:後臺經過xml或者json格式返回後臺的視頻資訊,而後Android客戶端界面顯示出來html
首前後臺新創建一個java web後臺java
採用mvc的框架android
因此的servlet都放在servlet中,servlet想當於android中的controller層,android中的控制層下面能夠在分爲activity 、fragment和adapter 、serverce服務和broadcast廣播web
Service是業務層,按照面向接口編程的原則,控制層的數據不能直接和業務層的實現類打交道,只能和業務層的具體實現類打交道,這裏service就是業務層的業務接口,定義了業務操做的接口數據庫
Service.impl編程
這裏就是業務接口的具體實現類,在這裏經過調研數據庫model模型層的數據接口訪問數據庫,在這裏業務實現類也不能直接訪問數據量,而是經過model層提供的數據庫接口才能操做數據庫。json
Model數據庫模型層,裏面又能夠分爲db、dao,model層主要經過單例;提供一個數據庫訪問的接口提供給業務層的實現類調用。數組
例如:在這裏經過數據庫的接口操做數據庫 Model.getInstace().getVideoNewsDao(),經過這種方式經過model層提供一個接口讓業務庫實現類調用,最好不要使用直接new VideoNewsDao()的方式瀏覽器
bean服務器
就是存儲具體的java對象
咱們來看下後臺的代碼:
package com.videonews.bean; public class VideoNewsBean { private Integer videoId ;//電影id private String videoTitle ;// 電影標題 private Integer timeLength ;//電影時間長度 public VideoNewsBean() { super(); } public VideoNewsBean(Integer videoId, String videoTitle, Integer timeLength) { this.videoId = videoId; this.videoTitle = videoTitle; this.timeLength = timeLength; } public Integer getVideoId() { return videoId; } public void setVideoId(Integer videoId) { this.videoId = videoId; } public String getVideoTitle() { return videoTitle; } public void setVideoTitle(String videoTitle) { this.videoTitle = videoTitle; } public Integer getTimeLength() { return timeLength; } public void setTimeLength(Integer timeLength) { this.timeLength = timeLength; } @Override public String toString() { return "VideoNewsBean [videoId=" + videoId + ", videoTitle=" + videoTitle + ", timeLength=" + timeLength + "]"; } }
咱們來看業務的實現接口:
package com.videonews.service; import java.util.List; import com.videonews.bean.VideoNewsBean; public interface VideoNewsService { public List<VideoNewsBean> getAllNews(); }
咱們來看業務接口的實現類:
public class VideoNewsServiceImp implements VideoNewsService { @Override public List<VideoNewsBean> getAllNews() throws Exception{ // TODO Auto-generated method stub //在這裏經過數據庫的接口操做數據庫 Model.getInstace().getVideoNewsDao() //這裏咱們操做數據庫,咱們直接模擬數據 List<VideoNewsBean> datas = new ArrayList<VideoNewsBean>(); datas.add(new VideoNewsBean(1, "人民的利益", 100)); datas.add(new VideoNewsBean(2, "三生三世", 100)); datas.add(new VideoNewsBean(1, "光頭強", 100)); return datas; }
正常的業務操做中:業務實現類應該經過數據庫接口操做數據庫得到對象的數據,這裏咱們模擬該過程直接返回數據
咱們來看看
ListServlet:
public class ListServlet extends HttpServlet { VideoNewsService service = new VideoNewsServiceImp(); //採用面向接口的編程方式,控制層只能和業務類的接口打交道,最好不要寫成 public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException doPost(request, response); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //判斷是返回json,仍是返回xml格式的數據 String format = (String) request.getAttribute("format"); if(format == null || "json".equals(format)){ //進行業務操做得到數據 try { List<VideoNewsBean> news = service.getAllNews(); //封裝json字符串數據 //1 方法1 使用第三方的gson框架,這裏使用Gson,須要gson的jar包 Gson gson = new Gson(); String jsonString = gson.toJson(news); //方法2本身封裝json字符串數據,在實際的開發過程當中固然使用gson框架 //[{"videoId":1,"videoTitle":"人民的利益","timeLength":100},{"videoId":2,"videoTitle":"三生三世","timeLength":100}, //{"videoId":1,"videoTitle":"光頭強","timeLength":100}] // "使用轉義寫成\",{直接寫成"{" StringBuilder builder = new StringBuilder(); builder.append("["); for(VideoNewsBean videonew:news){ builder.append("{").append("\""); builder.append("videoId").append("\"").append(":").append(""+videonew.getVideoId()).append(";"); builder.append("videoTitle").append("\"").append(":").append(""+videonew.getVideoTitle()).append(";"); builder.append("timeLength").append("\"").append(":").append(""+videonew.getTimeLength()).append("}"); builder.append(","); } //遍歷以後最後多了一個builder.append(",");要記得去掉 builder.deleteCharAt(builder.length()-1); builder.append("]"); String jsonString2 = builder.toString(); request.setAttribute("json", jsonString); //重定向到jsp頁面 request.getRequestDispatcher("WEB-INF/page/json.jsp").forward(request, response); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); //業務操做失敗,須要在界面jsp上面提示用戶,或者對業務操做失敗作出其餘的處理 } }else{ //進行業務操做得到數據 try { List<VideoNewsBean> news = service.getAllNews(); request.setAttribute("videos", news); //重定向到jsp頁面 request.getRequestDispatcher("WEB-INF/page/videonews.jsp").forward(request, response); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); //業務操做失敗,須要在界面jsp上面提示用戶,或者對業務操做失敗作出其餘的處理 } } } }
上面有幾個地方須要注意的:
控制層和業務層採用面向接口的編程方式,控制層只和業務的接口類打交道
VideoNewsService service = new VideoNewsServiceImp();
而不是具體和業務的實現類打交道,最好不需寫成 VideoNewsServiceImp service = new VideoNewsServiceImp();
二、依據客戶端請求的客戶以爲是以xml的格式仍是json的格式返回數據給客戶端
三、同理業務庫實現類也不能直接操做數據庫,必須經過數據庫的接口操做數據庫Model.getInstance.getVideoNewsDao();經過model模型層提供一個操做數據庫的接口訪問數據庫,這就是面向接口的編程的思想。這裏模擬操做數據庫的過程直接將數據返回業務類
四、在進行業務操做的時候getAllNews()若是這個業務操做有異常,應該將異常拋出,不該該內存try catch進行處理,而應該拋出給控制層servlet。Servlet已經異常才知道該業務操做是成功仍是失敗,在jsp或者html中進行顯示。
五、咱們來看看web-inf/page/videonews.jsp的代碼:若是以xml的方法返回給客戶端
<%@ page language="java" contentType="text/xml; charset=UTF-8" pageEncoding="UTF-8"%><%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %><?xml version="1.0" encoding="UTF-8"?>
<videonews><c:forEach items="${videos}" var ="video">
<news id = "${video.videoId}">
<title>${video.videoTitle}</title>
<timelength>${video.timeLength}</timelength>
</news></c:forEach>
</videonews>
上面使用了jsp的c標籤進行遍歷,須要在java web工程的libs目錄下添加下面兩個jar包,而且
contentType="text/xml;必須是xml格式
咱們在瀏覽器上訪問:
如今咱們在瀏覽器訪問http://localhost:8080/lihuoming_25/ListServlet
若是是以json格式返回,videonews.jsp的代碼以下:
<%@ page language="java" contentType="text/plain; charset=utf-8" pageEncoding="utf-8"%> ${json}
咱們來看看整個java web工程的程序框架是:
咱們來看看Android端客戶端的代碼:
客戶端也是按照後臺同樣採用mvc的框架
也是採用控制層、模型層、業務層、工具類類型的四種方式
控制層包括activity 、fargment 、receiver等
業務層:主要進行業務操做,例如從服務器上或者接送數據,業務層的異常最好不要使用try catch內部處理,而已經將異常拋出,在控制層處理異常,若是控制層能夠經過異常知道業務操做是否成功,在界面上作出相應的顯示
業務層最好寫成業務接口類類和業務實現類:接口主要定義業務的具備方法,實現類主要實現該業務的具體操做
Model:主要操做數據庫,封裝數據庫操做的接口提供給業務層調用例如Model.getInstance.getDbDao()採用單例的模式提供一個數據庫接口給業務實現類調用,不清楚的能夠看尚硅谷硅谷社交項目。
Bean:封裝Javabean對象
Utils工具類主要工具類。
咱們首先來看業務的接口類:
package application.weiyuan.com.lihuoming_25.bussiness; import org.json.JSONException; import org.xmlpull.v1.XmlPullParserException; import java.io.IOException; import java.util.List; import application.weiyuan.com.lihuoming_25.model.bean.VideoNewsBean; /** * Created by wei.yuan on 2017/4/24. */ public interface VideoNewsService { public List<VideoNewsBean> getAllNews(String path) throws IOException, XmlPullParserException, JSONException; }
咱們來看業務的實現類:
import android.util.Log; import android.util.Xml; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import java.net.URLConnection; import java.util.ArrayList; import java.util.List; import javax.xml.datatype.XMLGregorianCalendar; import application.weiyuan.com.lihuoming_25.model.bean.VideoNewsBean; /** * Created by Administrator on 2017/4/18. * XmlPullParser.START_DOCUMENT對應文檔開始 XmlPullParser.END_DOCUMENT <videnews>是根元素、有三個<News>子元素 <標記名稱 屬性名1="屬性值1" 屬性名1="屬性值1" ……>內容</標記名稱> 起始標籤(外國語:starttag)表示一個特定區域的開始,例如<起始>; 結束標籤(外國語:end tag)定義了一個區域的結束,除了在小於號以後緊跟着一個斜線(/)外,和起始標籤基本同樣,例如</結束>; 其中標記名稱對應的事件是XmlPullParser.START_TAG ,<news>或者<title>都是一個開始tag </news>對應一個XmlPullParser.END_TAG <news id =」2」>其中id就是這個tag的屬性 <title>光頭強</title>這個tag標籤沒有屬性,可是存在內容,內容就是光頭強 注意根元素<videnews>也是一個tag標籤,咱們經過程序的代碼日誌打印就能夠看出來 04-19 00:19:06.508 10100-10138/? D/123456 start_tag: videonews 04-19 00:19:06.508 10100-10138/? D/123456 start_tag: news 04-19 00:19:06.508 10100-10138/? D/123456 start_tag: title 04-19 00:19:06.509 10100-10138/? D/123456 start_tag: timelength 04-19 00:19:06.509 10100-10138/? D/123456 end_tag: news 04-19 00:19:06.510 10100-10138/? D/123456 start_tag: news 04-19 00:19:06.510 10100-10138/? D/123456 start_tag: title 04-19 00:19:06.510 10100-10138/? D/123456 start_tag: timelength 04-19 00:19:06.510 10100-10138/? D/123456 end_tag: news 04-19 00:19:06.510 10100-10138/? D/123456 start_tag: news 04-19 00:19:06.510 10100-10138/? D/123456 start_tag: title 04-19 00:19:06.510 10100-10138/? D/123456 start_tag: timelength 04-19 00:19:06.510 10100-10138/? D/123456 end_tag: news 04-19 00:19:06.510 10100-10138/? D/123456 end_tag: videonews 04-19 00:19:11.492 10370-10387/? D/123456 start_tag: videonews 04-19 00:19:11.492 10370-10387/? D/123456 start_tag: news 04-19 00:19:11.492 10370-10387/? D/123456 start_tag: title 04-19 00:19:11.492 10370-10387/? D/123456 start_tag: timelength 04-19 00:19:11.492 10370-10387/? D/123456 end_tag: news 04-19 00:19:11.492 10370-10387/? D/123456 start_tag: news 04-19 00:19:11.492 10370-10387/? D/123456 start_tag: title 04-19 00:19:11.492 10370-10387/? D/123456 start_tag: timelength 04-19 00:19:11.492 10370-10387/? D/123456 end_tag: news 04-19 00:19:11.492 10370-10387/? D/123456 start_tag: news 04-19 00:19:11.492 10370-10387/? D/123456 start_tag: title 04-19 00:19:11.492 10370-10387/? D/123456 start_tag: timelength 04-19 00:19:11.492 10370-10387/? D/123456 end_tag: news 04-19 00:19:11.493 10370-10387/? D/123456 end_tag: videonews */ public class VideoNewsServiceImp implements VideoNewsService{ public List<VideoNewsBean> getAllNews(String path) throws IOException, XmlPullParserException, JSONException { List<VideoNewsBean> news = new ArrayList<>(); URL url = new URL(path); HttpURLConnection connection = (HttpURLConnection)url.openConnection(); connection.setRequestMethod("GET"); connection.setConnectTimeout(5000); connection.connect(); if(connection.getResponseCode() == 200){ InputStream inputStream = connection.getInputStream(); //news = pullXML(inputStream);//服務器返回的xml格式 news = pullJson(inputStream); //返回的json字符串 } return news; } //對xml文件進行解析 public List<VideoNewsBean> pullXML(InputStream in) throws XmlPullParserException, IOException { List<VideoNewsBean> datas = null; VideoNewsBean newsBean = null; XmlPullParser pullParser = Xml.newPullParser(); //得到一個xml的pull解析器 pullParser.setInput(in, "utf-8"); //設置解析的編碼格式,必須和服務器段的jsp中的xml編碼格式對象 int eventType = pullParser.getEventType(); //開啓一個解析事件 while (eventType != XmlPullParser.END_DOCUMENT){ //只要事件不是xml的文檔結束事件,就一直解析, //XmlPullParser.END_DOCUMENT表示xml已經解析完成了 switch (eventType){ case XmlPullParser.START_DOCUMENT: //開啓文檔解析事件 datas = new ArrayList<>(); break; case XmlPullParser.START_TAG: // 開始一個標籤的解析 Log.d("123456 start_tag",pullParser.getName()); if(pullParser.getName().equals("news")){ newsBean = new VideoNewsBean(); //得到標籤的屬性值 int id = Integer.parseInt(pullParser.getAttributeValue(0));//0表示第一個屬性,若是是1表示第二個屬性值 newsBean.setVideoId(id); break; }else if(pullParser.getName().equals("title")){ //得到titile的內容 // <title>人民的利益</title>,解析分爲三個事件<title>是標籤開始事件 人民的利益是標籤的內容爲第二個事件, // </title>爲第三個事件 //如今解析到了<title>,pullParser.next()就是到下一個事件 pullParser.nextText()下一個事件的文本值 String title = pullParser.nextText(); newsBean.setVideoTitle(title); break; }else if(pullParser.getName().equals("timelength")){ int timeLength = Integer.parseInt(pullParser.nextText()); newsBean.setTimeLength(timeLength); break; }else { break; } case XmlPullParser.END_TAG: //一個標籤解析完成 Log.d("123456 end_tag",pullParser.getName()); if(pullParser.getName().equals("news")){ datas.add(newsBean); newsBean = null; } break; case XmlPullParser.END_DOCUMENT: //結束文檔解析事件 return datas; } //解析下一個事件 eventType = pullParser.next(); } return datas; } //對服務器返回的json數據進行解析 public List<VideoNewsBean> pullJson(InputStream in) throws IOException, JSONException { List<VideoNewsBean> news = new ArrayList<>(); //第一步將InputStream轉化成byte[] byte[] buffer= new byte[1024]; ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); int len = -1; while ((len = in.read(buffer))!= -1){ outputStream.write(buffer,0,len); } byte[] bytes = outputStream.toByteArray(); String jsonString = new String(bytes,"utf-8");//編碼必須和服務器的同樣 //第二步將byte轉化成json數組 JSONArray jsonArray = new JSONArray(jsonString); //得到json數組中的jsonObject對象 for(int i = 0 ;i < jsonArray.length();i++){ JSONObject jsonObject = jsonArray.getJSONObject(i); VideoNewsBean bean = new VideoNewsBean(); bean.setVideoId(jsonObject.getInt("videoId")); bean.setVideoTitle(jsonObject.getString("videoTitle")); bean.setTimeLength(jsonObject.getInt("timeLength")); news.add(bean); } return news; } }
對xml解析比較複雜:
XML元素與HTML元素的格式基本相同,其格式以下:
<標記名稱 屬性名1="屬性值1" 屬性名1="屬性值1" ……>內容</標記名稱>
全部的數據內容都必須在某個標記的開始和結束標記內,而每一個標記又必須包含在另外一個標記的開始與結束標記內,造成嵌套式的分佈,只有最外層的標記沒必要被其餘的標記所包含。最外層的是根元素(Root),又稱文件(Document)元素,全部的元素都包含在根元素內。在前面的Flowers.xml文件中,根元素就是<Flowers>,根元素必須並且只能有一個,在該文件有三個<Flower>子元素,這樣的元素能夠有多個。
XmlPullParser.START_DOCUMENT對應文檔開始
XmlPullParser.END_DOCUMENT
<videnews>是根元素、有三個<News>子元素
<標記名稱 屬性名1="屬性值1" 屬性名1="屬性值1" ……>內容</標記名稱>
起始標籤(外國語:starttag)表示一個特定區域的開始,例如<起始>;
結束標籤(外國語:end tag)定義了一個區域的結束,除了在小於號以後緊跟着一個斜線(/)外,和起始標籤基本同樣,例如</結束>;
其中標記名稱對應的事件是XmlPullParser.START_TAG ,<news>或者<title>都是一個開始tag
</news>對應一個XmlPullParser.END_TAG
<news id =」2」>其中id就是這個tag的屬性
<title>光頭強</title>這個tag標籤沒有屬性,可是存在內容,內容就是光頭強
注意根元素<videnews>也是一個tag標籤,咱們經過程序的代碼日誌打印就能夠看出來
04-19 00:19:06.508 10100-10138/? D/123456 start_tag: videonews
04-19 00:19:06.508 10100-10138/? D/123456 start_tag: news
04-19 00:19:06.508 10100-10138/? D/123456 start_tag: title
04-19 00:19:06.509 10100-10138/? D/123456 start_tag: timelength
04-19 00:19:06.509 10100-10138/? D/123456 end_tag: news
04-19 00:19:06.510 10100-10138/? D/123456 start_tag: news
04-19 00:19:06.510 10100-10138/? D/123456 start_tag: title
04-19 00:19:06.510 10100-10138/? D/123456 start_tag: timelength
04-19 00:19:06.510 10100-10138/? D/123456 end_tag: news
04-19 00:19:06.510 10100-10138/? D/123456 start_tag: news
04-19 00:19:06.510 10100-10138/? D/123456 start_tag: title
04-19 00:19:06.510 10100-10138/? D/123456 start_tag: timelength
04-19 00:19:06.510 10100-10138/? D/123456 end_tag: news
04-19 00:19:06.510 10100-10138/? D/123456 end_tag: videonews
04-19 00:19:11.492 10370-10387/? D/123456 start_tag: videonews
04-19 00:19:11.492 10370-10387/? D/123456 start_tag: news
04-19 00:19:11.492 10370-10387/? D/123456 start_tag: title
04-19 00:19:11.492 10370-10387/? D/123456 start_tag: timelength
04-19 00:19:11.492 10370-10387/? D/123456 end_tag: news
04-19 00:19:11.492 10370-10387/? D/123456 start_tag: news
04-19 00:19:11.492 10370-10387/? D/123456 start_tag: title
04-19 00:19:11.492 10370-10387/? D/123456 start_tag: timelength
04-19 00:19:11.492 10370-10387/? D/123456 end_tag: news
04-19 00:19:11.492 10370-10387/? D/123456 start_tag: news
04-19 00:19:11.492 10370-10387/? D/123456 start_tag: title
04-19 00:19:11.492 10370-10387/? D/123456 start_tag: timelength
04-19 00:19:11.492 10370-10387/? D/123456 end_tag: news
04-19 00:19:11.493 10370-10387/? D/123456 end_tag: videonews
咱們來看activity的代碼:
public class MainActivity extends Activity { private ListView lv_main; private VideoNewsService service = null; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); initData(); } private void initData() { service = new VideoNewsServiceImp(); final String path = "http://192.168.1.103:8080/lihuoming_25/ListServlet"; ExecutorService executorService = Executors.newCachedThreadPool(); executorService.execute(new Runnable() { @Override public void run() { try { final List<VideoNewsBean> news = service.getAllNews(path); runOnUiThread(new Runnable() { @Override public void run() { Toast.makeText(MainActivity.this,"" + "得到數據成功"+news.size(),Toast.LENGTH_SHORT).show(); List<Map<String, String>> listems = new ArrayList<Map<String, String>>(); for (int i = 0; i < news.size(); i++) { VideoNewsBean newsBean = news.get(i); Map<String, String> listem = new HashMap<String, String>(); listem.put("id", newsBean.getVideoId()+""); listem.put("title", newsBean.getVideoTitle()+""); listem.put("timeLength", newsBean.getTimeLength()+""); listems.add(listem); } SimpleAdapter adapter = new SimpleAdapter(MainActivity.this, listems, R.layout.item_news, new String[] {"title", "timeLength" }, new int[] {R.id.name,R.id.desc}); lv_main.setAdapter(adapter); /*SimpleAdapter的參數說明 * 第一個參數 表示訪問整個android應用程序接口,基本上全部的組件都須要 * 第二個參數表示生成一個Map(String ,Object)列表選項 * 第三個參數表示界面佈局的id 表示該文件做爲列表項的組件 * 第四個參數表示該Map對象的哪些key對應value來生成列表項 * 第五個參數表示來填充的組件 Map對象key對應的資源一依次填充組件 順序有對應關係 * 注意的是map對象能夠key能夠找不到 但組件的必需要有資源填充 由於 找不到key也會返回null 其實就至關於給了一個null資源 * 下面的程序中若是 new String[] { "name", "head", "desc","name" } new int[] {R.id.name,R.id.head,R.id.desc,R.id.head} * 這個head的組件會被name資源覆蓋 * */ } }); } catch (final Exception e) { e.printStackTrace(); runOnUiThread(new Runnable() { @Override public void run() { Toast.makeText(MainActivity.this,"" + "得到數據失敗"+e.toString(),Toast.LENGTH_SHORT).show(); } }); } } }); } private void initView() { lv_main = (ListView) findViewById(R.id.lv_main); } }
咱們來看xml佈局文件:
activity_main.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="application.weiyuan.com.lihuoming_25.MainActivity"> <ListView android:id="@+id/lv_main" android:layout_width="match_parent" android:layout_height="match_parent"> </ListView> </RelativeLayout>
item_news.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal" > <TextView android:id="@+id/name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="20dp" android:textColor="#f0f" android:paddingLeft="10dp"/> <TextView android:id="@+id/desc" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="14dp" android:paddingLeft="10dp"/> </LinearLayout>