07-Servlet

unit07-Servlet

Servlet概述

什么是Servlet?

Servlet是由SUN公司提供的一门动态Web资源开发技术

Servlet本质上是一段Java程序,和之前的Java程序不同的是,Servlet程序无法独立运行,需要将Servlet程序放在服务器中(比如tomcat服务器),由服务器调用才可以执行。

Servlet: 服务器端的Java程序.

Servlet是运行在服务器端的Java程序,其作用是什么?

其作用是对服务器接收过来的请求进行处理(作用为处理请求)

329ebdac1b25e0943488cf41428e6552

329ebdac1b25e0943488cf41428e6552

开发Servlet程序

开发Servlet程序的步骤

第一步: 写一个类,实现一个Servlet接口或者继承Servlet接口的子类(GenericServlet/HttpServlet),并实现其中的方法

1
2
3
Servlet接口
|-- GenericServlet类(抽象类)
|-- HttpServlet类

第二步: 在web应用的web.xml文件中配置Servlet程序对外访问的路径。

Eclipse在创建一个Servlet时,会在web.xml文件中生成Servlet配置,所以不需要我们手动配置。

使用Eclipse创建Web项目

22432d0ee6fe5616365ecb77f5748b37

22432d0ee6fe5616365ecb77f5748b37

46a097af287c3d455ace4644c98ad27b

46a097af287c3d455ace4644c98ad27b

以上是Web项目在工程视图(Project)和包视图(package)下结构,推荐使用包视图!

1、创建一个Web工程: 在左侧窗口中, 点击鼠标右键 —> New —>
Dynamic Web Project

22fa5f600a0bdd2206b028c42d7feab3

22fa5f600a0bdd2206b028c42d7feab3

2、接着会弹出如下窗口:

![创建Web项目](JAVAWEB-f534b2420e73dc56b14042eb95c91cc0

f534b2420e73dc56b14042eb95c91cc0

注意:

(1) 3.0版本不会创建web.xml文件,
并且创建Servlet时也不会在web.xml文件中生成Servlet相关的配置信息, 记得改为2.5。

(2) Target runtime选项中如果没有可选的服务器,可点击右侧的”New
Runtime…”进行配置。

详细操作步骤在《5.2配置Target runtime(Web项目运行环境)》

3、Eclipse中创建的Web工程的目录结构:

image-20200219170618551

image-20200219170618551

1
2
3
4
5
6
(1) day09: 工程名称/项目名称
(2) src: 源码目录, 创建的java源文件、配置文件(properties、xml文件等)都可以放在src源码目录下
(3) build/classes: 编译文件的输出目录, src源码目录中的文件编译后会输出到classes目录下。
其中的classes目录在发布时会放在WEB-INF目录下,随着项目一起发布到服务器中
(4) WebContent: 就是Web应用的目录,其中可以存放 html、css、js、jsp、图片以及编译后的class文件、jar包、web.xml文件等. 将来发布项目到服务器,其实就是将WebContent中的所有内容一起发布到服务器中。
(5) WebContent/WEB-INF/lib: 用于存放当前项目所依赖的jar包。比如要访问mysql数据库,需要导入mysql驱动包,直接将jar包拷贝到lib目录下即可!(也不用再去做 build path --> add to build path)

使用Eclipse创建Servlet

1、选中项目中的src目录,鼠标右键 —> New —> Servlet

b363459bbe88da812109f0863d80b552

b363459bbe88da812109f0863d80b552

2、在弹出的窗口中,根据提示填写内容:

4226a1514a967a42ec6d49e23b725939

4226a1514a967a42ec6d49e23b725939

3、点击finish即可完成Servlet创建过程, 创建好的Servlet如下:

3d2214e9146db1b26b6038f61c3a8014

3d2214e9146db1b26b6038f61c3a8014

通过Eclipse创建Servlet,默认继承HttpServlet。由于HttpServlet也是Servlet接口的子类,让HelloServlet继承HttpServlet,相当于间接实现了Servlet接口。

继承HttpServlet类,默认会覆盖doGet方法和doPost方法,两个方法的作用为:

*** doGet方法:**当浏览器发送请求的方式为GET提交时, 将会调用doGet方法来处理请求

*** doPost方法:**当浏览器发送请求的方式为POST提交时,
将会调用doPost方法来处理请求

提示:如果当GET提交和POST提交处理代码相同时,可以将代码写在其中一个方法里(例如写在doGet中),并在另外一个方法(例如doPost)中调这个方法。这样一来,不管是GET提交还是POST提交,最终doGet方法都会执行,都会对请求进行处理!!

Servlet在web.xml中的配置

在通过Eclipse创建Servlet时,会自动在web.xml文件中进行Servlet相关信息的配置

(注意:如果是复制Servlet类文件,但配置信息不会跟着复制,需要自己手动添加配置,否则复制的Servlet将无法访问!)

1
2
3
4
5
6
7
8
<servlet>
<servlet-name>HelloServlet</servlet-name>
<servlet-class>com.tedu.HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>HelloServlet</servlet-name>
<url-pattern>/HelloServlet</url-pattern>
</servlet-mapping>

关于上面的配置信息:

a) Eclipse每创建一个Servlet,
就会在web.xml文件中添加两个标签:标签(可以将这两个标签看成一个组的标签)

b)
标签内都会有一个标签,标签的内容可以更改,但要求更改后的这两个标签的内容也必须一致。

c) 标签用于配置Servlet类的全路径名(即包名+类名)

需要注意:如果在创建Servlet后修改了Servlet类的名称,这个地方也要一起更改,否则将会出现”ClassNotFoundException”
即类找不到异常

d)
标签用于配置浏览器以什么路径访问当前Servlet(即Servlet对外访问的路径),默认的路径是:/类名

例如:上面为HelloServlet配置的
/HelloServlet,因此我们在浏览器中的访问路径则为:

http://主机名/web项目访问路径**/HelloServlet**

运行Servlet程序、访问测试

1、访问Servlet方式一:

若是第一次运行,需要先创建tomcat服务器,即在Servers窗口中点击链接可创建一个tomcat服务器,且只需创建一次即可!

(1)发布项目到服务器:在服务器上右键 –> 点击 “add and remove” 将当前web项目发布到服务器中,并点击完成。

(2)启动tomcat服务器:在服务器上右键 Start 即可启动服务器

(3)通过浏览器访问Servlet:打开本地浏览器,通过路径访问,即可访问Servlet程序

http://localhost:8080/项目名称/HelloServlet

2、访问Servlet方式二:

(1) 在运行的Servlet上点击右键 –-> “Run As” —> “1 Run on Server”

329006b7629a8f0b0c9bddfc90fba675

329006b7629a8f0b0c9bddfc90fba675

(2) 在弹出的窗口中,直接点击完成即可!!!

6340e1bd76974184a91c55595864123b

6340e1bd76974184a91c55595864123b

(3) 运行结果如下:

f478e638564b90f44fdd1ef210c11f30

f478e638564b90f44fdd1ef210c11f30

或者打开浏览器,复制上图中的路径:

http://localhost:8080/Hello/HelloServlet,粘贴到浏览器的地址栏中,回车访问:

12910389bb2a950777329cc3568e8ec7

12910389bb2a950777329cc3568e8ec7

Eclipse默认发布Web应用的位置

Tomcat服务器中默认只有一台虚拟主机,叫做localhost主机

而localhost主机发布web应用的位置是webapps。

将day09发布到localhost主机中,但为什么day09项目没有在webapps目录下?

-——————————————————————————————————-

默认情况下,发布一个Web应用到localhost主机中,只需要将Web应用的目录拷贝到webapps目录下即可完成发布!

而将Eclipse和Tomcat整合之后,通过Eclipse发布一个web应用到tomcat服务器中,发布的路径默认被改成了:

[工作空间]\.metadata\.plugins\org.eclipse.wst.server.core\tmp0\wtpwebapps

如何修改Eclipse默认发布Web应用的目录位置:

(1)关闭服务器,将服务器中的所有应用移除

(2)在服务器上右键 –> clean

(3)双击tomcat服务器,在弹出窗口中找到 Server location, 选择第二个选项

并将下方的Deploy Path改为: webapps 改完后,Ctrl+s保存配置即可!!

Eclipse如何发布一个Web应用

当通过eclipse将day09项目发布到服务器中,是直接将day09拷贝到服务器中对应的目录下吗?

发布的过程如下:

66b1236906843df1bfc1d002a36a0ea7

66b1236906843df1bfc1d002a36a0ea7

Servlet调用过程

通过浏览器访问服务器中的一个Servlet程序,这个Servlet程序是如何执行的?又是如何被调用的?

localhost/Hello/HelloServlet

参考<<Servlet调用过程图>>

扩展:修改Servlet模版

通过Eclipse可以直接创建一个Servlet类,这相比通过记事本等文本编辑工具创建Servlet,可以节省配置Servlet的时间,提高了我们的开发效率。

但是通过Eclipse生成的Servlet类中包含了许多我们不需要的注释和默认实现代码,这些每次都删除也非常占用时间。

接下来可以通过添加模版代码的形式,来生成Servlet的内容,以便于提高我们的开发效率。

1、先创建一个Servlet,将其中的内容修改为自己期望的模版格式,并复制其中的内容,例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package ${enclosing_package};

import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
* author: bjzhangsz@tedu.cn
* datetime: ${date} ${time}
*/
public class ${primary_type_name} extends HttpServlet {
private static final long serialVersionUID = 1L;

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}

2、点击菜单栏中的window –> Preferences

61ff91aedf878c76b0e51b94ffdca92a

61ff91aedf878c76b0e51b94ffdca92a

3、在出现的窗口左侧依次点击:Java –> Editor –> templates
-->(在右边的窗口中) 点击New… :

35b3781ebd2acd7a178db29783dc5a6a

35b3781ebd2acd7a178db29783dc5a6a

4、在出现的新窗口中填写如下内容:

7dcab79636bff53d51b35d449adffebd

7dcab79636bff53d51b35d449adffebd

5、替换包路径和类名(作用是在新建Servlet生成的Servlet模版中使用当前类的包路径和类型)

cfc14076c3b3e9187afa6594a5ba08a8

cfc14076c3b3e9187afa6594a5ba08a8

效果如下:

82d8ec98345ff6e99c7caf7fce40c38f

82d8ec98345ff6e99c7caf7fce40c38f

3e4ab784b24d0682572a1d92ec58098e

3e4ab784b24d0682572a1d92ec58098e

效果如下:

a7026f1287e078eb5561ff5ff7ff2ebe

a7026f1287e078eb5561ff5ff7ff2ebe

6、点击OK保存,创建新的Servlet文件,测试

将Servlet中的所有内容全选删除,并输入”servlet”,接着按 “Alt+ /“
提示即可生成自己想要的Servlet模版内容!

0f1925b9e96b93a6e13e7aa674ec2e35

0f1925b9e96b93a6e13e7aa674ec2e35

效果如下:

a5ada366c84bcef88e797f7126db4433

a5ada366c84bcef88e797f7126db4433

request和response介绍

request是代表HTTP请求信息的对象,response是代表HTTP响应信息的对象。

当浏览器发请求访问服务器中的某一个Servlet时,服务器将会调用Servlet中的service方法来处理请求。在调用service方法之前会创建出request和response对象。

其中request对象中封装了浏览器发送给服务器的请求信息(请求行、请求头、请求实体等),response对象中将会封装服务器要发送给浏览器的响应信息(状态行、响应头、响应实体),在service方法执行完后,服务器再将response中的数据取出,按照HTTP协议的格式发送给浏览器。

每次浏览器访问服务器,服务器在调用service方法处理请求之前都会创建request和response对象。(即,服务器每次处理请求都会创建request和response对象)

在请求处理完,响应结束时,服务器会销毁request和response对象。

request对象

获取请求参数

问题1、什么是请求参数?

所谓的请求参数,就是浏览器发送给服务器的数据(不区分请求方式),例如:通过表单向服务器提交的用户名、密码等,或者在超链接后面通过问号提交的数据,都是请求参数。

1
http://localhost/day10/TestParam?user=zhangsan&pwd=123&like=篮球&like=足球

问题2、如何获取请求参数?

1
2
3
4
5
6
7
(1)request.getParameter(String paramName)
-- 根据请求参数的名字获取对应的参数值,返回值是一个字符串;
-- 如果一个参数有多个值,该方法只会返回第一个值。
-- 如果获取的是一个不存在的参数,返回值为null
(2)request.getParameterValues(String paramName)
-- 根据请求参数的名字获取该名字对应的所有参数值组成的数组,返回值是一个字符串数组,其中包含了这个参数名对应的所有参数值
-- 如果获取的是一个不存在的参数,返回值为null

代码示例:

1
2
3
4
5
6
7
//1.获取请求参数中的用户名(user)
String user = request.getParameter("user");
System.out.println( "user="+user );

//2.获取请求参数中的爱好(like)
String[] like = request.getParameterValues( "like" );
System.out.println( "like="+Arrays.toString( like ) );

问题3、获取请求参数时的中文乱码问题?

在获取中文的请求参数时,可能会出现乱码问题(和请求方式、tomcat服务器版本有关),具体可以分为以下三种情况:

(1)如果请求是GET提交,并且tomcat是8.0及以后的版本,GET提交的中文参数,在获取时不会出现乱码问题!(8.0以后的tomcat包括8.0在获取GET提交的中文参数时,已经处理中文乱码问题。)

(2)如果请求是POST提交,不管是哪个版本的tomcat服务器,在获取中文参数时,都会出现乱码问题。因为tomcat底层在接收POST提交的参数时,默认会使用iso8859-1编码接收,而这个编码中没有中文字符,所以在接收中文参数时,一定会出现中文乱码问题!

解决方法是:通知服务器在接收POST提交的参数时,使用utf-8编码来接收!

1
request.setCharacterEncoding("utf-8");

注意:这行代码不会影响GET提交,只对POST提交有效!

这行代码要放在任何获取参数的代码之前执行!

(3)如果请求是GET提交,并且tomcat是7.0及以前的版本,GET提交的中文参数,在获取时会出现乱码问题!

解决方法:在[tomcat安装目录]/ conf/server.xml文件的(修改端口的)Connector标签上,添加一个 URIEncoding=”utf-8” 属性,如下:

1
2
3
4
<Connector port="80" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443"
URIEncoding="utf-8" />

同时在[Eclipse]/Servers/[当前tomcat服务器对应的配置目录]/server.xml文件中,在Connector标签上,添加一个 URIEncoding=”utf-8” 属性,同上!

实现请求转发

请求转发是服务器内部资源的一种跳转方式,即当浏览器发送请求访问服务器中的某一个资源(A)时,该资源将请求转交给另外一个资源(B)进行处理并且由资源B做出响应的过程,就叫做请求转发。

请求转发和重定向都是资源的跳转方式,但是跳转的过程有所不同。

image-20200304232156159

image-20200304232156159

请求转发的特点:

1
2
3
4
(1)转发是一次请求,一次响应
(2)请求转发前后,浏览器的地址栏地址不会发生变化。(浏览器--访问--> A --转发--> B,地址栏地址始终指向A的地址)
(3)请求转发前后的request对象是同一个(转发前在A中的request和转发到B后,B中的request对象和A中的request对象是同一个。基于这一点,可以通过request从A带数据到B)
(4)请求转发前后的两个资源必须属于同一个Web应用,否则将无法进行转发。(A--转发-->B,A和B必须属于同一个Web应用!)

请求转发实现:

1
request.getRequestDispatcher(url地址/转发到资源的地址).forward(req, res);

代码示例:

1
2
3
//从当前Servlet转发到 index.jsp(http://localhost/day10/index.jsp)
//request.getRequestDispatcher("/index.jsp").forward(request, response);
request.getRequestDispatcher("index.jsp").forward(request, response);

image-20200221171059404

image-20200221171059404

作为域对象使用

request在实现转发时,通过request.setAttribute方法和request.getAttribute方法带数据到目的地时,就是通过request对象中的map集合带数据,这个request对象上的map集合以及request对象所在的范围即称之为是一个域对象。

如果一个对象具备可以被访问的范围,通过这个对象上的map集合可以在整个范围内实现数据的共享。这样的对象就叫做域对象。

在request对象上提供了往域对象(map)中存数据的方法以及取数据的方法:

1
2
3
4
request.setAttribute(String attrName, Object attrValue);
-- 往request域中存入一个域属性,属性名(key)只能是字符串,属性值(value)可以是任意类型。
request.getAttribute(String attrName);
-- 根据属性名(key)获取对应的属性值(value)。返回的是一个Object类型的对象。

request域对象所具备的三大特征:

**生命周期:**在服务器调用Servlet程序的service方法之前,会创建代表请求的request对象,在请求处理完,响应结束时,会销毁request对象。

**作用范围:**在一次请求范围内,都可以获取到同一个request对象。

**主要功能:**和请求转发配合使用,从Servlet带数据到JSP(带数据到目的地)

**扩展内容:**request对象的getParameter和getAttribute方法有什么区别?

  • getParameter()方法是用于获取(从浏览器发送过来的)请求参数的,请求参数不能设置,只能是浏览器发送给服务器,在服务器端再通过getParameter方法获取请求中的参数
  • getAttribute()方法是用于从request域中获取域属性时用的,域属性得先存入到域中(即得先通过setAttribute方法将数据存入request域中),再通过getAttribute()方法从域中获取。

案例:模拟查询所有门店功能

1、创建一个Servlet程序,用于处理查询所有门店信息请求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class DoorListServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse
response)
throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
//1.模拟查询数据库, 查询所有门店集合
List<String> doorList = new ArrayList();
doorList.add("01, 永和北三环西路店, 010-67676767");
doorList.add("02, 永和西直门店, 010-68976347");
doorList.add("03, 永和东直门店, 010-78397647");
doorList.add("04, 永和北京西店, 010-78764397");
doorList.add("05, 永和天安门店, 010-78769743");
//2.将数据存入request域中
request.setAttribute( "list", doorList );
//3.将请求转发到 door_list.jsp 中, 取出所有门店显示在页面中
request.getRequestDispatcher("door_list.jsp")
.forward(request, response);
}
}

2、创建一个JSP,用于显示所有门店信息

1
2
3
4
5
6
7
8
9
10
11
<body>
<h3>显示所有门店信息</h3>
<%
//获取request域中的门店信息集合
List<String> list =(List<String>)request.getAttribute("list");
//遍历门店集合, 将门店信息输出在网页上
for( String door : list ){
out.write( door +"<br/>");
}
%>
</body>

response对象

response是代表HTTP响应信息的对象。

向客户端发送数据

PrintWriter out = response.getWriter();

由于服务器在通过response获取的流发送数据时,默认使用iso8859-1编码,而这个编码中没有中文字符,所以在通过response获取的流发送中文数据时,会出现乱码问题。

解决方法是:在响应数据之前,通知服务器使用utf-8发送数据。

1
2
3
4
5
/*  通知服务器在响应数据时,使用utf-8编码
* 也能通知浏览器使用utf-8接收服务器发送的数据 */
response.setContentType( "text/html;charset=utf-8" );
PrintWriter out = response.getWriter();
out.write( "你好" );

实现重定向

当浏览器向服务器发请求访问某一个资源A,资源A在响应时通知浏览器需要再进一步请求才能获取到对应的资源,浏览器再次发请求访问服务器中的资源B,最终由资源B响应浏览器要获取的资源,这个过程叫做重定向。

image-20200304232136926

image-20200304232136926

重定向的特点:

1
2
3
4
(1)重定向是两次请求、两次响应
(2)重定向前后,浏览器的地址栏地址会发生变化。(因为两次请求都是通过浏览器发起,浏览器知道这个跳转的过程,因此地址栏地址会变化)
(3)重定向前后的request对象不是同一个(因为重定向是两次请求,服务器会根据两次请求创建两个不同的request对象,request对象不是同一个,也就不能在重定向时通过request带数据到目的地。)
(4)重定向前后的两个资源可以是来自不同的web应用,甚至可以是来自不同的服务器。(进行跳转的两个资源之间没有限制)

实现代码:

1
response.sendRedirect(所重定向到资源的URL地址);

代码示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
//测试1: 从当前Servlet(day10/TestRedirect)重定向到day10/index.jsp
// http://localhost/day10/TestRedirect
// http://localhost/day10/index.jsp
response.sendRedirect( "http://localhost/day10/index.jsp" );
response.sendRedirect( "/day10/index.jsp" );
response.sendRedirect( "/index.jsp" ); //错误路径
response.sendRedirect( "index.jsp" ); //正确路径

//测试2: 从当前Servlet重定向到day09/index.jsp
response.sendRedirect( "http://localhost/day09/index.jsp" );

//测试3: 从当前Servlet重定向到百度首页
response.sendRedirect( "http://www.baidu.com" );

总结:什么时候用转发(forward)?什么时候用重定向(redirect)?

1
2
3
(1)如果希望跳转前后地址栏地址不会发生变化, 只能使用转发; 如果希望跳转前后地址栏地址会发生变化, 只能使用重定向
(2)如果希望在跳转前后, 能够通过request对象带数据到目的地, 只能使用转发
(3)如果仅仅是做一个跳转,没有其他要求,此时推荐使用转发(转发是一次请求,一次响应,可以减少访问服务器的次数,降低服务器的压力)

javaweb servlet