博客連接:孟鑫菲html
拍賣會apk:APK前端
安卓端:安卓端代碼
服務器端:服務器端代碼
數據庫:數據庫文件
說明文檔:點擊這裏mysql
本項目分爲服務器端和安卓端,缺一不可。服務器端採用Tomcat7.0.9進行本地服務器搭建,使用MySQL做爲數據庫存儲數據,使用Eclipse和VS Code進行代碼編輯,使用谷歌瀏覽器進行調試。安卓端採用Android Studio開發。
在這裏,咱們把手機端、平板端和網頁端統稱爲安卓端(因它們具備相同的功能),安卓端主要負責向服務器請求數據和處理服務器相應的json數據,服務器端負責處理安卓端請求以及和數據庫交互並把交互數據封裝成json數據返回給安卓端。android
輸入數據庫中已經存在的用戶「mysql」,密碼也是「mysql」,能夠進行成功登陸:
git
再點擊其中存在的物品,能夠看到相關信息:
sql
其中點擊右上角的加號按鈕能夠添加物品的種類,在這裏好比添加一個新的種類「TV」:
數據庫
點擊其中的正在拍賣的物品,能夠查看信息:
點擊右上角的加號能夠添加拍賣物品,並未拍賣物品定義拍賣信息:
編程
點擊其中任何一項均可以跳轉到相應種類的物品清單下,好比點擊「電腦硬件」:json
點擊「顯卡」,便可跳轉到競價頁面:
在這張頁面上,你能夠對該商品進行競價。
7.點擊「查看參與的競標」,會跳轉到用戶參與競標的物品清單界面:
點擊其中的物品一樣會顯示物品信息:
瀏覽器
bnLogin.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { if (validate()) { if (loginPro()) { Intent intent = new Intent(Login.this, AuctionClientActivity.class); startActivity(intent); finish(); } else { DialogUtil.showDialog(Login.this, "用戶名稱或者密碼錯誤,請從新輸入!", false); } } } });
validate()函數:
private boolean validate() { String username = etName.getText().toString().trim(); if (username.equals("")) { DialogUtil.showDialog(this, "用戶密碼是必填項!", false); return false; } String pwd = etPass.getText().toString().trim(); if (pwd.equals("")) { DialogUtil.showDialog(this, "用戶名是必填項!", false); return false; } return true; }
loginPro()函數:
private boolean loginPro() { String username = etName.getText().toString(); String pwd = etPass.getText().toString(); JSONObject jsonObj; try { jsonObj = query(username, pwd); if (jsonObj.getInt("userId") > 0) { return true; } } catch (Exception e) { DialogUtil.showDialog(this , "服務器響應異常,請稍後再試!", false); e.printStackTrace(); } return false; }
因爲動態碎片的引入,所以會存在view重複利用的狀況,這一功能界面就存在view重複利用,所以判斷服務器請求的路徑就是判斷該界面最終呈現的效果的前提條件,所以在代碼中的「action」即爲服務器請求路徑,若返回路徑爲「viewFail.jsp」即表明觸發的事件爲查看流拍物品。函數viewItemDetail實現的功能爲點擊流拍物品界面上listview後使相應物品的信息以對話框的形式彈出:
public class ViewItemFragment extends Fragment { Button bnHome; ListView succList; TextView viewTitle; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View rootView = inflater.inflate(R.layout.view_item, container , false); bnHome = (Button) rootView.findViewById(R.id.bn_home); succList = (ListView) rootView.findViewById(R.id.succList); viewTitle = (TextView) rootView.findViewById(R.id.view_titile); bnHome.setOnClickListener(new HomeListener(getActivity())); String action = getArguments().getString("action"); String url = HttpUtil.BASE_URL + action; if (action.equals("viewFail.jsp")) { viewTitle.setText(R.string.view_fail); } try { JSONArray jsonArray = new JSONArray(HttpUtil.getRequest(url)); JSONArrayAdapter adapter = new JSONArrayAdapter(getActivity(), jsonArray, "name", true); succList.setAdapter(adapter); } catch (Exception e) { DialogUtil.showDialog(getActivity(), "服務器響應異常,請稍後再試!", false); e.printStackTrace(); } succList.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { viewItemDetail(position); } }); return rootView; } private void viewItemDetail(int position) { View detailView = getActivity().getLayoutInflater().inflate(R.layout.detail, null); TextView itemName = (TextView) detailView.findViewById(R.id.itemName); TextView itemKind = (TextView) detailView.findViewById(R.id.itemKind); TextView maxPrice = (TextView) detailView.findViewById(R.id.maxPrice); TextView itemRemark = (TextView) detailView.findViewById(R.id.itemRemark); JSONObject jsonObj = (JSONObject) succList.getAdapter().getItem(position); try { itemName.setText(jsonObj.getString("name")); itemKind.setText(jsonObj.getString("kind")); maxPrice.setText(jsonObj.getString("maxPrice")); itemRemark.setText(jsonObj.getString("desc")); } catch (JSONException e) { e.printStackTrace(); } DialogUtil.showDialog(getActivity(), detailView); } }
顯示物品種類,和上一功能代碼內容相似:
bnHome.setOnClickListener(new HomeListener(getActivity())); bnAdd.setOnClickListener(new OnClickListener() { @Override public void onClick(View source) { mCallbacks.onItemSelected(ADD_KIND , null); } }); String url = HttpUtil.BASE_URL + "viewKind.jsp"; try { final JSONArray jsonArray = new JSONArray(HttpUtil.getRequest(url)); kindList.setAdapter(new KindArrayAdapter(jsonArray, getActivity())); } catch (Exception e) { DialogUtil.showDialog(getActivity(), "服務器響應異常,請稍後再試!" ,false); e.printStackTrace(); } return rootView;
添加物品種類:
其中validate()是判斷關於添加的種類的信息用戶是否輸入,若是輸入,addKind函數實現和服務器的交互,將物品信息插入數據庫。
bnCancel.setOnClickListener(new HomeListener(getActivity())); bnAdd.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { if (validate()) { String name = kindName.getText().toString(); String desc = kindDesc.getText().toString(); try { String result = addKind(name, desc); DialogUtil.showDialog(getActivity(), result , true); } catch (Exception e) { DialogUtil.showDialog(getActivity(), "服務器響應異常,請稍後再試!" , false); e.printStackTrace(); } } } }); return rootView; validate()函數: private boolean validate() { String name = kindName.getText().toString().trim(); if (name.equals("")) { DialogUtil.showDialog(getActivity() , "種類名稱是必填項!" , false); return false; } return true; } addKind函數: private String addKind(String name, String desc) throws Exception { Map<String , String> map = new HashMap<String, String>(); map.put("kindName" , name); map.put("kindDesc" , desc); String url = HttpUtil.BASE_URL + "addKind.jsp"; return HttpUtil.postRequest(url , map); }
查看拍賣物品:
bnHome.setOnClickListener(new HomeListener(getActivity())); bnAdd.setOnClickListener(new OnClickListener() { @Override public void onClick(View source) { mCallbacks.onItemSelected(ADD_ITEM , null); } }); String url = HttpUtil.BASE_URL + "viewOwnerItem.jsp"; try { JSONArray jsonArray = new JSONArray(HttpUtil.getRequest(url)); JSONArrayAdapter adapter = new JSONArrayAdapter(getActivity(), jsonArray, "name", true); itemList.setAdapter(adapter); } catch (Exception e) { DialogUtil.showDialog(getActivity() , "服務器響應異常,請稍後再試!", false); e.printStackTrace(); } itemList.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { viewItemInBid(position); } }); return rootView;
其中的 mCallbacks.onItemSelected是實現了 定義的Callbacks接口,當Callbacks被調用時就會在相應的activity中實現接口函數onItemSelected,此碎片的activity中的函數實現以下:
public void onItemSelected(Integer id, Bundle bundle) { Intent i = new Intent(this , AddItem.class); startActivity(i); }
添加拍賣物品,其中的validate()函數仍然是判斷用戶是否輸入信息,addItem是添加信息功能:
String url = HttpUtil.BASE_URL + "viewKind.jsp"; JSONArray jsonArray = null; try { jsonArray = new JSONArray(HttpUtil.getRequest(url)); } catch (Exception e1) { e1.printStackTrace(); } JSONArrayAdapter adapter = new JSONArrayAdapter(getActivity() , jsonArray , "kindName" , false); itemKind.setAdapter(adapter); bnAdd = (Button) rootView.findViewById(R.id.bnAdd); bnCancel = (Button) rootView.findViewById(R.id.bnCancel); bnCancel.setOnClickListener(new HomeListener(getActivity())); bnAdd.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { if (validate()) { String name = itemName.getText().toString(); String desc = itemDesc.getText().toString(); String remark = itemRemark.getText().toString(); String price = initPrice.getText().toString(); JSONObject kind = (JSONObject) itemKind.getSelectedItem(); int avail = availTime.getSelectedItemPosition(); switch(avail) { case 5 : avail = 7; break; case 6 : avail = 30; break; default : avail += 1; break; } try { String result = addItem(name, desc, remark , price , kind.getInt("id") , avail); DialogUtil.showDialog(getActivity(), result , true); } catch (Exception e) { DialogUtil.showDialog(getActivity(), "服務器響應異常,請稍後再試!" , false); e.printStackTrace(); } } } }); return rootView;
選擇物品種類,和上邊的有關從數據庫查找信息的功能原理類似:
long kindId = getArguments().getLong("kindId"); String url = HttpUtil.BASE_URL + "itemList.jsp?kindId=" + kindId; try { JSONArray jsonArray = new JSONArray(HttpUtil.getRequest(url)); JSONArrayAdapter adapter = new JSONArrayAdapter(getActivity() , jsonArray , "name" , true); succList.setAdapter(adapter); } catch (Exception e1) { DialogUtil.showDialog(getActivity() , "服務器響應異常,請稍後再試!" , false); e1.printStackTrace(); } viewTitle.setText(R.string.item_list); succList.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { JSONObject jsonObj = (JSONObject) succList.getAdapter().getItem(position); Bundle bundle = new Bundle(); try { bundle.putInt("itemId" , jsonObj.getInt("id")); } catch (JSONException e) { e.printStackTrace(); } mCallbacks.onItemSelected(ADD_BID, bundle); } }); return rootView;
參與競價:
bidPrice = (EditText)rootView.findViewById(R.id.bidPrice); bnAdd = (Button)rootView.findViewById(R.id.bnAdd); bnCancel = (Button)rootView.findViewById(R.id.bnCancel); bnCancel.setOnClickListener(new HomeListener(getActivity())); String url = HttpUtil.BASE_URL + "getItem.jsp?itemId=" + getArguments().getInt("itemId"); try { jsonObj = new JSONObject(HttpUtil.getRequest(url)); itemName.setText(jsonObj.getString("name")); itemDesc.setText(jsonObj.getString("desc")); itemRemark.setText(jsonObj.getString("remark")); itemKind.setText(jsonObj.getString("kind")); initPrice.setText(jsonObj.getString("initPrice")); maxPrice.setText(jsonObj.getString("maxPrice")); endTime.setText(jsonObj.getString("endTime")); } catch (Exception e1) { DialogUtil.showDialog(getActivity(), "服務器響應出現異常!", false); e1.printStackTrace(); } bnAdd.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { try { double curPrice = Double.parseDouble(bidPrice.getText().toString()); if( curPrice < jsonObj.getDouble("maxPrice")) { DialogUtil.showDialog(getActivity(), "您輸入的競價必須高於當前競價", false); } else { String result = addBid(jsonObj.getString("id"), curPrice + ""); DialogUtil.showDialog(getActivity(), result , true); } } catch(NumberFormatException ne) { DialogUtil.showDialog(getActivity(), "您輸入的競價必須是數值", false); } catch(Exception e) { e.printStackTrace(); DialogUtil.showDialog(getActivity(), "服務器響應出現異常,請重試!", false); } } }); return rootView;
其中的addBid函數實現了講競價插入數據庫的功能:
private String addBid(String itemId , String bidPrice) throws Exception { Map<String , String> map = new HashMap<String, String>(); map.put("itemId" , itemId); map.put("bidPrice" , bidPrice); String url = HttpUtil.BASE_URL + "addBid.jsp"; return HttpUtil.postRequest(url , map); }
一句話描述:這個組作的是一個旅遊類app,實現了景區、酒店、美食、路線等旅遊必備物品外,還實現了登陸註冊時向手機發送驗證功能。
優勢:最令我佩服得地方有,註冊用戶手機驗證碼功能,底部導航作的也比較好,我的信息查看和修改以及支持評論等功能;前端界面也相對完善。相對於用戶來講,這些功能都是旅遊須要用到的,具備很高的實用性。
缺點:缺點在於沒有特點功能,目前該軟件所實現的功能與市場上已存在旅遊軟件相比,沒有特點的主打功能。若是真的發佈,可能難以在市場上存活。
若是我來作:一是加入更多功能,二是,若是真要向市場發展,前期要有必定促銷策略。
一句話描述:這個組作的是一個爲專業人士或編程興趣愛好者開發的一個代碼學習的軟件,其中涵蓋多種代碼語言,而且有不少和編程相關的功能實現。
優勢:在「代碼闖關」這一功能上,代碼語言的覆蓋面很廣,種類不少;我的簡介的界面設計的比較好,貼近現實的使用習慣;還有一個亮點功能就是添加好友,能夠實現經過多種第三方軟件來添加。
缺點:查詢功能只能查詢軟件自帶的內容,比較侷限,其次運行會有閃退現象。
若是我來作:會更加優化部分界面,使得總體界面設計更加協調,好比代碼交流界面。
一句話描述:這個組作的是一個乒乓球愛好者交流app,該軟件不只能夠查看最新乒乓球類信息,還實現了世界排名,球員,視頻等等。
優勢:站在用戶角度來講,若是該軟件數據信息沒有問題,確實是一個瞭解乒乓球賽事的比較好的app。除了查看運動員信息外,還支持好比賽事賽程等功能也作的比較有吸引力。
缺點:這個軟件還能夠作的更好,實現登陸,評論功能等等。該軟件UI也能夠進一步升級改造。
若是我來作:第一步優化UI,第二步,加入一些新奇功能。
一句話描述:這個組作的是一個二手交易的app,能夠實現查看二手交易物品的信息,經過留言來使得出手者和購買者進行溝通。
優勢:成品軟件實現了登陸,查看出售物品,留言,評論,查看我的信息並修改密碼的功能,功能均可以較好地實現。修改密碼是一個較好的功能,在實際應用中更有實用性。
缺點:此軟件爲二手交易軟件,應該要有明確的設計目的,就是實現交易,可是此組設計的交易軟件是經過留言來使得買家和賣家聯繫的,這樣就大大下降了軟件設計出來的使用度,從長遠來看,實際應用性不強。
若是我來作:咱們會增長一些使得買家和賣家直接交易通話的功能,不會設計成留言的形式,而且還會增長交易的種類。
一句話描述:這個組作的是一個音樂播放器app,除了實現上一首下一首播放暫停等基本功能之外,還實現了歌曲進度條和圖片的旋轉。
優勢:功能相對齊全,界面也比較美觀。實現了歌曲和歌曲進度條的綁定,不只支持實時查看歌曲進度,並且還支持經過進度條調整音樂,站在用戶的角度來看,這是一個比較實用的功能。
缺點:站在用戶的角度來看,對於音樂最不能缺乏的就是「歌詞」,和現有的酷狗音樂或qq音樂軟件相比,功能相對侷限。
若是我來作:在時間充裕的狀況下,會更加着重於更加功能的實現。例如:歌詞功能,歌單功能,用戶登陸頭像等等。
以上排名不分前後。
問題描述: 使用服務器和數據庫進行通訊時,理論上來說,採用insert, delete, update語句執行,可是,在本次做業中,屢次調試一直沒有報錯,沒有結果。
解決方法: 在查閱資料後,嘗試經過採用把SQL語句換成HQL語句執行,問題終於獲得解決。有關HQL語句和數據庫交互代碼,參考這篇:HQL操做數據庫。
好比,採用HQL語句修改以後代碼以下:(這段代碼功能:查找kindId這一物品下的全部已拍賣物品)
public List<Item> findItemByKind(Integer kindId) { return find("from Item as i where i.kind.id=?0 and i.itemState.id=1", kindId); }
問題描述: 確保數據庫中存儲中文,服務器響應設置編碼gbk,安卓端代碼設置編碼gbk,代碼中中文適配沒問題,服務器返回json數據格式中文也ok,但響應就是亂碼。模擬器界面截圖以下:
解決方法: 在從新確保數據庫中文正常,服務器響應的json數據正常後,仍是沒有進展。懷疑是ASjson數據解碼有問題或是自己編碼有問題。因而,採用將AS中編碼有原來的UTF-8改成GBK,仍是不行。再改,將改爲GBK的代碼在改回UTF-8。終於,搞定。解決後界面請往上翻!
在AuctionClientActivity,一個關於主界面的Activity的程序代碼中,有關於將Frangment替換而後從新加載的語句「replace(R.id.auction_detail_container, fragment)」,關於replace的使用必定要先將替換的程序放入返回棧,即「addToBackStack(null)」,而後必定要加「commit()」來從新提交和執行。單獨使用replace會得不到替換的效果。
因爲在程序設計時會有不少的Fragment的編寫以及顯示,若是每寫一次不一樣界面下的Fragment,而後使之顯示,會形成不少沒必要要的程序重複,所以就用了FragmentActivity來實現Fragment的顯示功能,其中設置了顯示Fragment的抽象函數,只要繼承此類,便可從新編寫抽象函數的具體實現代碼,從而獲得不一樣的顯示效果,也獲得了程序上的統一。
姓名 | 分工 | 分工比例 | 分數 |
---|---|---|---|
劉宇瑩 | 服務器端設計、安卓端設計、報告撰寫 | 50% | 10分 |
孟鑫菲 | 服務器端設計、安卓端設計、博客撰寫 | 50% | 10分 |