Hello,今天给各位童鞋们分享Servlet简介,赶紧拿出小本子记下来吧!
1. Servlet 是什么?
web 项目想要在 Web 服务器(TomCat, JBoss等)上运行, 必须满足一套规则, Servlet 就是规则
这套规则由 SUN 公司制定(Servlet 规范的核心是 Servlet 接口), 属于 JavaEE 规范, 而我们 JAVA 程序员就是写 Servlet 的实现类
2. web 项目的角色以及作用
web服务器:
根据一定的规则管理 web 项目
根据浏览器的 URL 查找到对应的 web 项目
SUN公司:
SUN 公司是 web 服务器和 web 项目交互规则的制定者
它制定了 Servlet 接口, 如果程序员想让 web 服务器管理自己的资源, 必须实现这个接口
开发web项目的java程序员:
写 Servlet 接口的实现类, 写配置文件 XML (将用户的请求路径和底层的java程序绑定在一起)
下面三行模拟一个 XML 文件
/login=LoginServlet
/delete=DeleteServlet
/save=SaveServlet
web项目的XML文件都是以类似路径=资源(类名)的形式保存的
当用户输入一个资源时候, Web服务器可以根据路径(key)查找到对应的资源(value)
再根据类名(资源)通过反射机制new对象
3. Servlet规范介绍
1. Servlet宏观上讲是一种规范, 这个规范来自JavaEE规范中的一种
2. 作用:
在Servlet规范中, 指定”动态资源文件”开发步骤
在Servlet规范中, 指定web服务器调用动态资源文件规则
在Servlet规范中, 指定web服务器管理动态资源文件实例对象规则
4. Servlet接口实现类
1. Servlet接口来自于Servlet规范下一个接口, 这个接口存在于web服务器提供的jar包中
2. Tomcat服务器下lib文件有一个servlet-api.jar存放servlet接口(javax.servlet.Servlet接口)
3. Servlet规范中认为, web服务器能调用的动态资源文件必须是一个Servlet接口实现类
5. Servlet接口实现类开发步骤
第一步:创建一个java类, 让它实现Servlet接口
Servlet接口的子类关系如下
祖宗接口Servlet——爷爷类GenericServlet(抽象)——父类HttpServlet(抽象)——子类java程序员写的实现类
Servlet接口有五个抽象方法(最重要的是service)
GenericServlet类没有实现service, 别的都实现了
HttpServlet类实现了service方法, 在service中, 通过request.getMethod()获取请求端的方法名(get,post等), 不是反射(Method是request类里面的一个属性)
java程序员写的实现类需要重写具体的doXXX方法
根据这个例子可以看出抽象类的一种作用:
通过抽象类继承接口的方式(抽象类实现了接口中的部分抽象方法), 降低接口实现类对接口的依赖程度(接口实现类可以直接继承已经实现了部分方法的抽象类, 而不用继承什么都没有实现的接口)
所以不直接实现Servlet接口, 而要继承HttpServlet接口的原因, 主要是为了简化开发步骤
第二步:重写HttpServlet父类中的两个方法,doGet或者doPost
web服务器会根据会根据路径名找到对应的实现类, 通过反射创建对象, 在由web服务器主动调用这个对象的service方法
在实现类中又重写了doGet或者doPost方法, 而实现类又继承了HttPServlet类实现的service方法, 这里service方法的主要作用为,
通过反射获取请求端的方法名, 调用对应的doXXX方法
第三步:将Servlet接口实现类信息<注册>到web服务器
这样web服务器就可以根据路径找到对应的实现类, 完成相关操作了.
web.xml路径:web项目文件—-web—-WEB-INF—web.xml
找到文件后加入如下:
mm
oneServlet
mm
/one
这时候请求URL为: http://localhost:8081/web项目名/one , 访问的资源为oneServlet类 IDEA中项目名可以在 run—-edit—-Deployment最下面的Application context更改
6. servlet对象的生命周期(web服务器如何管理web项目)
1. 在一个网站(web项目)中所有servlet接口实现类对象必须由web服务器创建(反射)
2. 在默认情况下, web服务器收到当前Servlet接口实现类的第一次请求时, 会自动创建这个Servlet接口实现类的实例化对象
在手动配置的情况下, 可以要求web服务器在启动的时候就创建出类的实例化对象
在web.xml配置文件中手动设置
mm
oneServlet
30
3. 在web服务器运行期间, 一个Servlet接口实现类只能被创建出一个实例对象
4. 在web服务器关闭的时候, 自动的将网站中所有Servlet对象进行销毁
7. HttpServletResponse接口
1. 介绍
-
HttpServletResponse接口来自于Servlet规范中, 在Tomcat中存在于servlet-api.jar中
-
HttpServletResponse接口的实现类由web服务器提供
-
HttpServletResponse接口负责将doGet/doPost方法的执行结果写入到响应体中, 交给浏览器
-
开发人员习惯于将HttpServletResponse接口实例化的对象叫做响应对象
2. 主要功能
- 将执行结果以二进制的形式写入到响应体中(序列化和反序列化)
例:
2. 可以设置响应头content-type属性值, 从而控制浏览器使用对应的编译器将响应体的二进制数据编译成对应的文字,图片,视频等
例:
此时浏览器上显示的结果并不为50, 而为2
原因:
out.writer(), 可以将字符, 字符串, ASCII码写入到响应体中
当参数为int时, 会将其认为是ASCII码, 在浏览器显示的时候就是打印ASCII码对应的字符
ASCII码为50时候对应的字符为2
解决:
使用out.print();
所以, 今后的开发中一律使用out.print()方法, writer()
例:
浏览器上的结果为: java
JavaScript
C??
说明, 浏览器并没有把我们的响应包当做HTML, 而是当成了普通的文本
原因: 浏览器在接受到响应包之后, 根据响应头的content-type属性的值的不同采用不同的编译器编译响应体中二进制的内容
在默认的请求下, 我们content-type属性的值为”text”, 此时浏览器将采用文本编译器对二进制的值进行解析
解决: 要在得到输出流之前, 通过响应对象对响应头中的content-type属性进行重新赋值, 使浏览器采用对应的二进制编译器
现在解决了HTML的问题, 但是现在的结果中还是有?, 抓个包看看Content-type的值, Content-Type: text/html;charset=ISO-8859-1
改字符集
response.setContentType(“text/html;charset=UTF-8”);
显示结果一切正常, nice
此时的抓个包看看Content-type为:text/html;charset=UTF-8 3. 设置响应头的location属性, 将一个请求地址赋值给location, 从而控制浏览器向指定服务器发送请求
浏览器在接受到响应包之后, 如果发现响应头存在location属性, 自动通过地址栏向location指定的位置发送请求
sendRedirect方法作用为远程控制浏览器的行为
请求三要素为: 请求地址, 请求方式, 请求参数
请求参数可以用queryString的方式加在URL之后
例:
8. HttpServletRequest接口
1. 介绍
-
HttpServletRequest接口来自于Servlet规范中, 在Tomcat中存在于servlet-api.jar中
-
HttpServletRequest接口的实现类由web服务器提供
-
HttpServletRequest接口负责在doGet/doPost方法运行时读取Http请求协议包中的信息
-
开发人员习惯于将HttpServletRequest接口实例化的对象叫做请求对象
-
继承关系interface HTTPServletRequest extends ServletRequest{}
-
HTTPServletRequest封装了什么信息?
请求方法
URI
协议版本号
表单提交数据
……
- 一次请求对应一个HttPServletRequest
2. 作用
- 可以读取Http请求协议包中请求行(请求首行, 包括请求方法, URL, Http协议版本)中的信息
例:
在控制台上打印:
URL = http://localhost:8081/05/one
method = GET
也可以通过请求对象, 读取{请求行}中{URI}信息
request.getRequestURI(), 读取URI, 返回结果是一个字符串
URI: 资源文件精准定位地址, 在请求行中实际上没有这个属性, 实际上是根据URL截取的一个字符串
这个字符串的格式为”/web项目名/资源文件名”
URI用于让web服务器对被访问资源进行定位
例:
// 3. 通过请求对象, 读取{请求行}中{URI}信息
// request.getRequestURI(), 读取URI信息, 返回结果为一个String
String uri = request.getRequestURI();
System.out.println(“URI = ” + uri);
2. 可以读取保存在Http请求协议包中请求头或者请求体中的参数信息 例:在一个web项目中建立静态资源(HTML文件), 这个静态资源如下:
模拟访问某一个资源时带参数信息, 可见参数有username和password/two路径对应的Servlet接口实现类情况如下:
控制台上打印的结果为:userName=Tompassword=123上面的例子是从请求头中获取QueryString, 下面是从请求体中获取
用户名
这个表单提交路径的Servlet实现类如下:
public class ThreeServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 通过请求对象, 读取{请求体}的参数信息
// 方法和请求头中一模一样
String value = request.getParameter(“username”);
System.out.println(“username = ” + value);
}
}
在表单上打出 zhangsan
控制台上显示结果如下:
username = zhangsan
可见不管从请求头还是请求体中获取queryString的信息, 代码都是一样的
但是, 如果post方法的中queryString有中文时, 会出现乱码
原因: 浏览器以Get方式发送请求, 参数保存在请求头中, 当Http请求协议包到达web服务器之后(协议包中的内容是二进制), 第一件事情就是解码
请求头中的二进制内容是由Tomcat负责解码, 默认使用UTF-8
如果以Post方式发送请求, 参数保存在请求体中, 当Http请求协议包到达web服务器之后(协议包中的内容是二进制), 第一件事情就是解码
请求体中的二进制内容是由请求对象(request)负责解码, request默认使用[ISO-8859-1]字符集, 中文时候就会出现乱码
解决: 在读取请求体内容之前, 先通知请求对象使用UTF-8字符集解码
保险起见, 我们将在重写doGet和doPost方法中, 前两行加入如下代码指定解码方式
request.setCharacterEncoding(“UTF-8”);
response.setCharacterEncoding(“UTF-8”);
- 可以代替浏览器向Web服务器申请资源文件调用
就是重定向
3. 表单提交数据格式
例: username=admin&password=123&interest=sport&interest=music
上面的例子可以看出, 表单提交数据信息的格式是类似键值对的格式
键值对就可以抽象为Map, 但是我们发现interest对应了两个值(复选框中一个name可能对应多个value)
所以这个Map的格式为<String, String[]>
上面的例子Map格式如下:
Map<String, String[]>
—————————————-
key value
username {“admin”}
password {“123”}
interest {“sport”, “music”}
4. 常用方法
获取表单数据表单提交的数据, 会自动封装到request对象中, request对象中有一个Map<String, String[]>来存储这些数据
String getParameter(String name) // 通过key获取对应value(String[])的首元素, 这个方法使用最多
Map getParameterMap() // 获取整个Map集合
Enumeration getParameterNames() //获取整个Map集合的所有Key
String[] getParameterValues(String name) //通过Key获取对应的value(String[]), 这个方法适合获得复选框请求信息
获取路径地址
String getRemoteAddr() // 获取客户端的ip地址
String getContexPath() // 获取上下文路径(web项目根路径)
String getMethod() // 获取请求方式
String getRequestURI() // 获取URI
StringBuffer getRequestURL() // 获取URL
String getServletPath() // 获取Servlet路径, 这里的路径是指web.xml和这个Servlet实现类相关的路径(/xxx)
向request中存入信息,可以参考下面5. HttpServletRequest是一个怎样的范围
void setAttribute(String name, Object o) // 向request范围中存入数据, name为key, o为value, 类似于Map
Object getAttribute(String name) // 从request范围中读取数据
void removeAttribute(String name) // 移除request范围中的数据
获取请求转发器, 让转发器对象指向某个资源, 这里的参数为web.xml文件中配置的”/xxx”
具体可以参考下面5. HttpServletRequest是一个怎样的范围的解决
RequestDispatcher getRequestDispatcher(String path)
和会话有关方法
Cookie[] getCookies()
HttpSession getSession()
5. HttpServletRequest是一个怎样的范围
HttpServletRequest类型的对象通常命名为request, 代表本次请求
一次请求对应一个request对象, 请求范围是很小的, request只能完成在同一次请求中的数据传递
看下面一个例子:AServlet向request中存入对象, 之后又取出对象
此时浏览器上打印: User{usercode=’111′, username=’zhangsan’} 如果在上面操作执行完毕之后让BServlet从request取数据
BServlet类如下:
浏览器上打印结果为: null
这说明这两个Servlet的request不是一个对象 解决办法: 转发
AServlet改成如下, BServlet不变
此时浏览器上显示: User{usercode=’111′, username=’zhangsan’}
注意, AServlet里没有打印到浏览器, 而BServlet有, 说明通过转发BServlet取到了数据
我们抓个包看看, 发现只有一次请求, 这说明转发只有一次请求
9. 请求对象和响应对象的生命周期
-
在web服务器接受到浏览器发送的[Http请求协议包]之后, 自动为当前的[Http请求协议包]生成一个[请求对象]和一个[响应对象]
-
在web服务器去调用doGet或者doPost方法时, 负责将[请求对象]和[响应对象]当做实参传到这个方法中, 来确保doGet/doPost的正确执行
-
当doGet或者doPost运行完毕的时候, 意味着本次请求处理完毕, web服务器端生成了一个http响应协议包,
所以说[请求对象]和[响应对象]的生命周期贯穿一次请求处理的全过程
[请求对象]将[请求协议包]中的内容解析出来, [响应对象]负责将doGet/doPost方法的执行结果告诉[响应协议包]
所以[请求对象]和[响应对象]更像是web服务器和浏览器(或是用户)之间的捎话人
好啦,今天的文章就到这里,希望能帮助到屏幕前迷茫的你们