关闭

【一步一个脚印】Tomcat+MySQL为自己的APP打造服务器(2-2)Servlet的使用

标签: servletAndroid应用服务器servicedoGetdoPost详解
11043人阅读 评论(14) 收藏 举报
分类:

        在上一篇 【一步一个脚印】Tomcat+MySQL为自己的APP打造服务器(2-1)Servlet 的使用 中我们只是简单的对 Servlet 要做的任务、在服务器中的地位有了一个大概的了解,完成了在一个全新的 WorkSpace 中创建第一个 Dynamic Web Project ,并创建第一个 Servlet ,解决期间可能遇到的常见问题,还留了不少的内容重要内容没有完成,今天我们来继续解决这几个问题:

        一、怎么能访问到一个Servlet & URL中各部分的含义

        我们来回顾上一篇篇末时在浏览器中访问 FirstServlet 时用的地址 http://localhost:8080/ServletTest/Home/FirstServlet,我们还特地用不同颜色标注了这个URL的不同部分,下面我们来看看这各个部分都是什么:

http://localhost:8080/ServletTest/Home/FirstServlet

        http:// 是一种网络通信协议,HTTP是客户端浏览器或其他程序与Web服务器之间的应用层通信协议,比如还有 FTP ,HTTPS...等,你可以理解成就是网络通信的规则,你要用 http 就要遵循它下边指定的各种规则(这个具体我也不大懂,不妄加解释,以免误人子弟)。

        localhost:8080 是你访问的服务程序所在主机的地址及开放端口,即服务器的IP地址和对应的端口地址。这里我的服务器就是自己的电脑,直接用浏览器访问,所以我用的就是 localhost(默认的 localhost 是127.0.0.1,就是指本地);如果你经过网络(不管是局域网、或者是 Internet),就需要用真正的服务器 IP 地址了(命令行使用 ipconfig 命令即可查看电脑IP),*注意* 只有具有公网IP 的才能通过 Internet 访问到,否则只能通过局域网使用,关于这个问题,我们后边还会涉及到,到时候再详细解释。

/ServletTest/Home/FirstServlet 是你所访问的程序在服务器上部署的路径。其实这里这个路径是两个部分,/ServletTest/Home/FirstServlet 中/ServletTest 是工程项目名称(和自己的项目名称一致,你和我不一定一样),/Home/FirstServlet 是在创建Servlet的时候指定的 URL-mapping。项目名和url-mapping组合成你的 Servlet 路径。

当我们请求这样一个地址时(之前的例子是在浏览器中通过 GET 方式访问这个地址,之后我们加上 POST 请求的例子),根据 Http 协议的规则会去访问对应的 IP 的主机,启动后的 Tomcat 会监听设置的端口(如果没有更改,默认的端口号就是8080),监听到对本地主机这个端口的访问后根据路径——项目工程名 + url-mapping映射 来匹配所请求地址对应的 Servlet。这样,我们的请求就发送到了想要到达的位置,接下来看 Servlet 怎么响应这个请求。

        二、Servlet对请求的响应

        我们最常用的 Servlet 都是继承自HttpServlet,这种 Servlet 能够响应 GET、POST两种请求 。还记得我们上一篇中创建 FirstServlet 时候提醒你留意看一下的那个图吗,再贴一下:

        

        创建 Servlet 时 Eclipse 默认要重写父类方法 doGet、doPost。doGet 方法就是专门用来响应 GET 请求(从我们开始说 Servlet 开始,一直用的都是 GET 请求,POST 请求我们会在之后出现,并给出我的一个 Android 和服务器进行POST交互的完整例子);doPost 方法专门用来响应 POST 请求的。GET、POST是两种最常用的网络请求方式,只是使用的方法不同,各有优劣罢了,没有这方面基础知识的同学直接去百度,比较容易理解。

        由于还没有说到 POST,我们就先以 GET 请求为例来说说 Servlet 是怎么响应我们的请求的:

        在上边的问题中我们已经知道怎么请求到一个特定的 Servlet,下面我们来完成 Servlet 的响应。接着上一篇中的工程 ServletTest 继续,我们新创建的 FirstServlet 的原始doGet 方法如下:

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
	 *      response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
	}

        可以看到,doGet 方法有两个入参(doPost方法也一样):一个 HttpServletRequest 的实例对象、一个 HttpServletResponse 的实例对象。其中 HttpServletRequest 就是我们发到 Servlet 的 GET请求(同理,doPost 方法的入参 HttpServletRequest 对象就是发送的 POST 请求),从中可以获取我们发起请求时设置的参数;HttpServletResponse 就是将要返回给客户端或浏览器的响应(至于这个 response 怎么就从这里返回给了请求源,我们在这个问题完了再说),我们在 Servlet 中要做的就是从 request 中获取请求参数,根据业务逻辑进行计算处理,得出结论后把结果赋值到 response 中返回给客户端。至此,一次完整的网络交互就完成了,下面简单举个例子吧:

        在下面的代码中,我们模拟了一个最简单的登陆验证的处理过程:

/**
 * Servlet implementation class FirstServlet
 */
@WebServlet("/Home/FirstServlet")
public class FirstServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	/**
	 * Default constructor.
	 */
	public FirstServlet() {
		
	}

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
	 *      response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		String account = request.getParameter("account"); // 从 request 中获取名为 account 的参数的值
		String password = request.getParameter("password"); // 从 request 中获取名为 password 的参数的值
		System.out.println("account:" + account + "\npassword:" + password); // 打印出来看一看

		String result = "";
		if("abc".equals(account) 
				&& "123".equals(password)){ // 模拟登陆账号、密码验证
			result = "Login Success!";
		}else {
			result = "Sorry! Account or password error.";
		}
		/* 这里我们只是模拟了一个最简单的业务逻辑,当然,你的实际业务可以相当复杂 */
		
		PrintWriter pw = response.getWriter(); // 获取 response 的输出流
		pw.println(result); // 通过输出流把业务逻辑的结果输出
		pw.flush();
		
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
	 *      response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		doGet(request, response); // 默认的代码,意思就是说做doPost和doGet一样
								  // ***但实质上可行不可行呢?我们接下来或者下一篇就会说到
	}

}

           Run AS > Run on Server 运行在 Tomcat 中。

        接下来,我们在浏览器中拼接一个理想的 GET 请求:

        http://localhost:8080/ServletTest/Home/FirstServlet?account=abc&password=123

        运行结果:

        正确GET结果

        终端 Console 记录的请求参数:

        

        我们再来一个反例:

        反例

        终端记录:

        记录

        怎么样,你成功了吗?磨刀不误砍柴工,我们要认真践行标题上说的一步一个脚印,POST 方法放到这个话题完了再详细说。

        三、Servlet的工作流程

        如果你是一个完全的服务端的小白,做到这里是不是有点小激动呢?终于打通了任督二脉!但是作为一个需要不断学习不断思考的程序猿,你有没有想到 Servlet 怎么就能接收 GET 请求,怎么就能接收 POST 请求呢?怎么就能把 response 返回给请求源呢?下面我们就来看 Servlet 的工作流程。

        HttpServlet 中有一个极其重要的方法—— service(HttpServletRequest request, HttpServletResponse response),在 service 方法中获取 request 的请求方式,将 GET 、POST 不同的请求分发给对应的 doGet、doPost 方法,Servlet 的一般流程如下图:

        Servlet一般流程

        需要注意的是:两个参数HttpServletRequest request 和 HttpServletResponse response 都是 Server 持有的对象,doGet、doPost 方法都是在更改它的内容(所以这两个方法的返回类型都是 void),完成后 Server 将操作完成的 response 返回给请求源。这是 Servlet 的一般流程!

        不同的如下图:

        总流程

        Servlet 有一个创建过程,会激发其 init() (这个是 HttpServlet 父类 GenericServlet 的方法)进行初始化。有两个条件都可以激发,这个是我们可以自己设定的,默认是(2)第一次请求 Servlet 并且该 Servlet 还未有实例时进行 init(),也可以在在 web.xml 中 <servlet> 标签下配置 <load-on-startup> 标签,配置的值为整型,值越小 Servlet 的启动优先级越高。

        对于更多的客户端请求,Server 创建新的请求和响应对象,仍然激活此 Servlet 的 service() 方法,将这两个对象作为参数传递给它。如此重复以上的循环,但无需再次调用 init() 方法。一般 Servlet 只初始化一次(只有一个对象),当 Server 不再需要 Servlet 时(一般当 Server 关闭时),Server 调用 Servlet 的 destroy() 方法。

        四、乱码问题

        在上一篇最后的例子中,我们留了一个问题,就是中文乱码(如果你是处女座,不折腾你了,贴心的给你个链接,不用费劲找了)的问题,还记得吗?有没有发现本文在此之前都在避免用中文?下面我们就来搞搞这个问题:

        我们把 doGet 中账号密码加点中文,在响应中也加点中文;

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
	 *      response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		String account = request.getParameter("account"); // 从 request 中获取名为 account 的参数的值
		String password = request.getParameter("password"); // 从 request 中获取名为 password 的参数的值
		System.out.println("account:" + account + "\npassword:" + password); // 打印出来看一看

		String result = "";
		if("王x".equals(account) 
				&& "杰x".equals(password)){ // 添加中文
			result = "Login Success!" + "成功了!"; // 响应也加点中文
		}else {
			result = "Sorry! Account or password error." + "有点问题!"; // 响应也加点中文
		}
		/* 这里我们只是模拟了一个最简单的业务逻辑,当然,你的实际业务可以相当复杂 */
		
		PrintWriter pw = response.getWriter(); // 获取 response 的输出流
		pw.println(result); // 通过输出流把业务逻辑的结果输出
		pw.flush();
	}
        确保服务器程序更新(一般情况下第一次运行成功后,之后的代码更改在保存后会自动执行)后,在浏览器请求

        http://localhost:8080/ServletTest/Home/FirstServlet?account=王x&password=杰x

     带中文的请求和响应

        我们可以看到,相应结果英文部分是对的——判断的结果是 true,说明从请求到逻辑处理是理想的,作为辅证,我们看服务端收到的请求参数记录:

        中文请求参数记录

        到这里,我们就找出了乱码问题的根源——就是响应过程中出现问题,而中文乱码问题一般都是编码格式引发的。所以我们这里在添加一行:

		// ......之前的代码片就不用贴了
		
		response.setContentType("text/html;charset=utf-8"); // 设置响应报文的编码格式
		PrintWriter pw = response.getWriter(); // 获取 response 的输出流
		pw.println(result); // 通过输出流把业务逻辑的结果输出
		pw.flush();
        更改成功生效后,再次请求:

        

        

        *注意* 一般我们在正常使用中,都会直接设置 request、response 的编码格式,以防由于编码问题引发的不必要的麻烦,如下:

	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		/* 先设置请求、响应报文的编码格式  */
		request.setCharacterEncoding("utf-8");
		response.setContentType("text/html;charset=utf-8");
		
		// .....再进行我们的逻辑处理
	}
        是不是有同学会想到,如果每个 Servlet 都要这样写,doGet、doPost 都要手动写,是不是很麻烦也很烦人呐?是的!是挺烦人的。有没有什么好的办法解决这个问题呢?答案肯定是有的,那就是 Servlet 过滤器 Filter(包 javax.servlet.Filter 下),这个我们后边会说到。本篇先到这里啦!

        水平有限,如有不足和错误,敬请斧正,_程序猿大人_在此谢过!

25
0
查看评论

使用Servlet写app接口

  • 2015-08-23 15:00
  • 1.00MB
  • 下载

【一步一个脚印】Tomcat+MySQL为自己的APP打造服务器(2-1)Servlet的使用

服务器接收来自不同用户的不同的请求(当然是以该服务器作为请求目标的那些请求),分析不同的请求,控制模块将各自的请求分送至对应的 Servlet (如登陆请求,则将登陆数据送至LoginServlet),然后 Servlet 根据请求内容处理业务逻辑(如登陆请求则解析用户名密码,并和数据库中保存的用户...
  • a_running_wolf
  • a_running_wolf
  • 2016-05-31 11:52
  • 15549

【一步一个脚印】Tomcat+MySQL为自己的APP打造服务器(3-2)Android 和 Service 的交互之POST方式

今天是圣诞节,虽说我本人对这个西方节日没什么感觉,但毕竟还是有很多小年轻人(自认为已然脱离年轻人的航道)挺在意这个节日的,在这里祝大家圣诞快乐吧(要是凑巧你也没什么感觉,那就预祝元旦快乐)!         闲话少叙,继续我们的正题。得益于上一篇文章【一步一个...
  • a_running_wolf
  • a_running_wolf
  • 2016-12-27 16:45
  • 5200

【一步一个脚印】Tomcat+MySQL为自己的APP打造服务器(3-3)Json数据交互

这篇文章实在是耽搁了太久了,唉,人生呐,怎一个懒字了得!都不好意思扯会儿淡了,进入正题吧。上篇我们将 Android 和 Servlet 进行 POST 方式进行数据交互搞通了,但是在例子中传输的数据是以最简单的 String 类型来举例的,下边我们就来用现在流行的 JSON 格式跑一个。Json,...
  • a_running_wolf
  • a_running_wolf
  • 2017-04-24 22:18
  • 3778

【一步一个脚印】Tomcat+MySQL为自己的APP打造服务器(4)完结篇

在这个系列的前几篇文章中,从最初简单的服务器环境搭建、MySQL数据库的安装、Servlet 的原理及使用、数据库的连接及CURD操作、Android和服务器GET/POST数据交互,到最后JSon格式报文的使用,我们已经将这个过程完整的走完一遍,但是其中用的代码都是片段式的,没有一个清晰的结构,甚...
  • a_running_wolf
  • a_running_wolf
  • 2017-05-09 18:06
  • 3695

【一步一个脚印】Tomcat+MySQL为自己的APP打造服务器(3-1)Android 和 Service 的交互之GET方式

好久没更新了,罪过罪过。最对不起的人莫过于那些支持和等待在下拙文的诸位,在此道一声抱歉。管窥之见,侥幸博得各位认同,给了我莫大的鼓励。         话休絮烦,文接前章。         到【一步一个脚印】Tomcat...
  • a_running_wolf
  • a_running_wolf
  • 2016-12-20 20:36
  • 11847

【一步一个脚印】Tomcat+MySQL为自己的APP打造服务器(2-3)Servlet连接MySQL数据库

在【一步一个脚印】Tomcat+MySQL为自己的APP打造服务器(1)服务器环境搭建中我们搭建了完整的服务器开发环境,但是接下来的两篇介绍 Servlet 的并没有用到 MySQL数据库,因为仅有的验证登录业务也是模拟的,今天我们就来说说 Servlet 中使用 MySQL 的方法。
  • a_running_wolf
  • a_running_wolf
  • 2016-07-31 01:44
  • 11830

【一步一个脚印】Tomcat+MySQL为自己的APP打造服务器(1)服务器环境搭建

做 Android 开发一年多了,虽然不敢说有多精通,但也相对熟悉。做久了就会发现 Android 在行外人眼中是多么高深(包括 IOS 也一样),但是我们自己知道其实 Android 和 Web 前端其实本质上是没有多大的区别,只不过一个是显示在浏览器中,一个是显示在手机上而已。慢慢地,你会发现移...
  • a_running_wolf
  • a_running_wolf
  • 2016-04-17 20:03
  • 24376

Tomcat+MySQL为自己的APP打造服务器(2-1)Servlet的使用

Tomcat+MySQL为自己的APP打造服务器(1)服务器环境搭建中已经配好了JDK,这次直接找一个JavaEE版本的Eclipse解压到我们想安装的目录下即可,用过 Eclipse+ADT 开发 Android 的同学都知道 Eclipse 是免安装的,在 /eclipse 下直接打开 ec...
  • qq_35112637
  • qq_35112637
  • 2017-02-20 22:09
  • 67

Tomcat+MySQL为自己的APP打造服务器(3-1)Android 和 Service 的交互之GET方式

^_^ 尊重原创,共享知识,转载请注明"_程序猿大人_"http://blog.csdn.net/a_running_wolf 声明一下:以下是 Windows 平台下 Tomcat + MySQL 搭建服务器。     ...
  • monkey_study
  • monkey_study
  • 2017-05-09 11:05
  • 169
    个人资料
    • 访问:277298次
    • 积分:2387
    • 等级:
    • 排名:第18338名
    • 原创:28篇
    • 转载:1篇
    • 译文:0篇
    • 评论:326条
    博客专栏
    最新评论