博客连接:孟鑫菲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分 |