实现客户端与服务端的HTTP通讯
参考博客地址:http://www.cnblogs.com/menlsh/archive/2013/05/22/3091983.html
https://www.cnblogs.com/TankXiao/archive/2012/02/13/2342672.html
负责客户端与服务端之间的数据通讯任务。在询问了前辈以后,我得知Socket通讯往往是不稳定的,因此最终从学习HTTP通讯开始着手了。
在最终实现具体的项目要求之前,我首先决定尝试着写了一个用户登录的样例(包括客户端和服务端两部分的代码,没有使用数据库),也就是通过客户端将用户名和密码等信息发送给 服务端,而服务端则返回登录成功或登录失败的提示信息。我尝试着查找了资料,有关的资料非常之多,且确实用户登录往往被 作为入门项目实例,但是我也发现因为通过HTTP通讯实现客户端与服务端的数据通讯仿佛因为太过简单,前辈们都不愿意详细阐述,又或者是因为前辈们一般都是非常专业的人士,因此往往专攻前端或者是服务端,而导致基本上所有的blog对于其中一端的代码实现会简单略过,而相对仔细得阐释另一端的实现。譬如我所参考的博客中,非常详细得阐述了安卓端如何实现使用Post的方式提交数据,而服务端则是贴出了核心代码和有关测试界面而已。因此在此博客的基础上,我将对服务端的javaWeb程序进行补充记录,对Android的代码进行个人理解分析,好了,首先从服务端开始了。
服务端:
服务端主要涉及到的是Servlet服务,关于其具体是什么原理,我没有去深究,毕竟时间有限,当然,有必要还是应当好好了解一下的,目前我所获得的全部信息只是,Servlet是运行在Web服务器或者应用服务器上的程序,作为服务器上的数据库或应用 程序与HTTP请求之间的中介。简单来说,Servlet能够帮助服务器接收到HTTP请求。
根据我所参考的博客里提到,可以先尝试在浏览器中访问Web工程,查看其Servlet是否正常工作。
1)我首先创建了一个继承自HttpServlet的LoginServlet类。(身为一名菜鸟,我最开始甚至没发现有HttpServlet类,查看 许多博主的博文以后,才发现是我没有引入Tomcat的外部依赖库,添加一下就好了呢);
2)接着,我修改了我的写Web工程的“index.jsp”文件,实现了一个极其简单的登录界面。(千万千万要保证此处的aciton 的值和1)中创建的Servlet类的类名相同,像我偷懒,一开始Servlet的类直接跟参考博的博主一样命名了LoginAction,在这里 jsp文件里又偷懒复制了别的博主的登录界面,因此action写了LoginServlet,结果当然测试的时候出错了,当然,值得一提的 是,参考的博客的博主的LoginAction的类名命名方式其实是不够合理的,毕竟它是个Servlet而不是Action) ;
3)接下来就是实现我的LoginServlet类的doPost方法了,我就直接贴整份代码了,因为只是练习数据通讯,因此在判断是否登录成功的部分,也模仿了参考博的直接规定了账户名和密码的方式,而省去了数据库的操作(score变量是开发的安卓客户端传的一个数据,和username还有password的传递方式相同,因此网页端没有特地提出来了)。其实写(chao)完以后才发现,Servlet真的是很好用了,完全没有想象中那样需要很复杂的操作呢。
public class LoginServlet extends javax.servlet.http.HttpServlet {
protected void doPost(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
request.setCharacterEncoding("utf-8");
response.setCharacterEncoding("utf-8");
PrintWriter out = response.getWriter();
String username = "";
String password = "";
String score = "";
username = request.getParameter("username");
password = request.getParameter("password");
score = request.getParameter("score");
if (username.equals("admin") && password.equals("123")) {
out.print("Login succeeded!");
out.println();
out.print("username:" + username + " ; password:" + password + " ; score:" + score);
} else {
out.print("Login failed!");
out.println();
out.print("username:" + username + " ; password:" + password + " ; score:" + score);
}
out.flush();
out.close();
}
protected void doGet(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException {
}
}
4)测试,由于是在本地的Tomcat上运行Web程序,因此地址很简单,具体操作可以百度“Tomcat部署Web项目”关键字。
输入用户名和密码,点击登录后,得到提示信息。终于完成了参考博所说的服务端的准备工作!(因为没学过js,所以网页真的很丑陋,请原谅)
客户端:
客户端的实现,参考的博客里面其实写得非常详细了,我也就不再把相同的过程再阐述一遍了,不过因为参考博的博主只是针对客户端如何Post数据进行教学,数据也只是username和password两个,因此直接在MainActivity里面进行处理了,而我后续 究竟需要传递多少数据还不确定,因此创建了一个Data类,用于存放所以要传递的数据,并将封装函数放在了此类的方法中。但是核心代码类似,因此代码也就不贴出来了,就简单讲讲真正在实现的过程中碰到的几个问题吧。
1)参考博的博主在正文中并没有给出url地址的形式,大概是因为这个就是关于部署问题的问题了,没必要探讨吧。但是我确实在把服务端的程序部署到我2天前买的阿里云的服务器上的时候,碰到了不少(henduo)的问题,因此为了跟我一样有点菜菜的同学考虑,我会再新开一篇,用于记录我部署Web程序的血泪史。
2)在1)中所述的问题解决过程中,其实我多次碰到了安卓客户端发送数据没能够获得服务器返回数据的问题,当然,最终证明是阿里云服务器没有设置好防火墙的问题,但是在此过程中,我多次去确认了我的AndroidManifest.xml文件,是否进行了网络授权,再次特地提一下,如果没有正确收到返回数据,不妨去确认一下,是否写了这一行——
3)上述问题解决后,我通过本地访问服务器的地址,已经能够得到成功的反馈了,但是客户端却依旧失败了,查了好久,发现原来向服务端发送数据是要新开一个线程呢,于是创建线程,并把发送数据的函数放在了重写的Runable中。
private void postMsg(final Map
Thread postThread = new Thread(new Runnable() {
@Override
public void run() {
// resultTextView.setText(HttpUtils.submitPostData(params,"utf-8"));
resultString = HttpUtils.submitPostData(params,"utf-8");
handler.post(runnableUi);
}
});
postThread.start();
}
4)解决了一个问题,又出现了新的问题,报错是:
Only the original thread that created a view hierarchy can touch its views.
继续百度,查了好一会,发现原来是因为我直接在我新建的线程里动手修改了TextView的现实内容的问题,view和控件不是线程安全的,必须要单独处理。此处指路https://blog.csdn.net/djx123456/article/details/6325983,非常感人得立马解决了问题, 终于获得了我想要的结果,嘤嘤嘤。
至此,终于完成了超级简单的数据通讯的测试Demo,希望我的菜鸟教程能够帮助到和我一样看大牛的博客们十分迷茫的同学们!有任何建议和错误也欢迎大家指出,感谢!