一个Servlet就可以直接处理一个Http请求
在没有框架的时代,Http请求到达Tomcat应用服务器,服务器更具web.xml中配置的servletmapping,也就是关于哪些请求应该找那个servlet来处理。然后直接将这个Http请求交个对应的Servlet类。所以这些负责哪个请求的servlet配置必须得由程序员在xml文件中配置好才行。
请求处理方式:
1.去掉项目前缀URL,只剩下login
2.根据url匹配找到应该由名为LoginServlet的Servlet来处理
而名为LoginServlet真实对应的类是demo.servlet.LoginServlet
然后就new一个该Servlet来处理这个Http请求,保证了线程安全。
Spring MVC封装Servlet
Spring主要是通过DispatcherServlet实现了Servlet这个接口,又叫前端控制器,来自前端的请求会先到达这里,它负责去后台匹配合适的Handler(也就是真正的执行逻辑(相当于Servlet中的doGet))
比于之前的servlet,它一定程度上简化了开发人员的工作,使用servlet的话需要每个请求都去在web.xml中配置一个servlet节点,而Spring 中的DispatcherServlet他会拦截所有的请求,进一步去查找有没有合适的处理器,一个前端控制器就可以
HttpServlet
Servlet是一个接口,由Servlet容器直接来创建实现了该接口的实例
Servlet有五个方法:
1.init()只初始化一次
2.getServletConfig()
3.service(ServletRequest,ServletResponse):真正的执行
4.getServletInfo()
5.destory():在tomcat关闭或者该web项目被移出时调用
因为Servlet是Java服务端为了实现动态交互的一个接口,而基本上现在交互使用的都是HTTP协议,所以设计了基于HTTP协议的新接口,继承了Servlet接口的HttpServlet抽象类
然后将原来的service方法直接拆分成6个方法,来适应HTTP的六种不同的请求
• doGet
• doPost
• doPut
• doDelete
• doOptions
• doTrace
开发者只要根据请求方式来重写不同的方法即可
1、HttpServletRequest
HttpServletRequest接口继承自ServletRequest
因为Request代表请求,所以我们可以通过该对象分别获得HTTP请求的请求行,请求头和请求体
在service中使用的编码解码方式默认为 :ISO-8859-1编码,但此编码并不支持中文,因此会出现乱码问题,所以我们需要手动修改编码方式为UTF-8编码,才能解决中文乱码问题,下面是发生乱码的具体细节:
2、HttpServletResponse
HttpServletResponse接口继承自ServletResponse
在Service API中,定义了一HttpServletResponse接口,它继承自ServletResponse接口,专门用来封装HTTP响应消息。
由于HTTP请求消息分为状态行,响应消息头,响应消息体三部分,因此,在HttpServletResponse接口中定义了向客户端发送响应状态码,响应消息头,响应消息体的方法。
我们如何自己手写一个servlet
实现Servlet的三种方式:
- 实现javax.servlet.Servlet接口,重写接口中的5个方法
public MyServlet implements Servlet {
// 生命周期的4个方法:构造方法、init、service、destroy, service方法每次请求都会被调用,其他三个方法 // 只会调用一次
// 生命周期流程:实例化(构造方法) --> 初始化(init) --> 服务(service) --> 销毁(destroy)
// 第一次访问Servlet就创建,单实例
public MyServle() {
...
}
@Override
// 第一次访问Servlet就初始化
// ServletConfig接口实例用于获取Servlet配置信息,该接口提供了4个方法:
// getServletName()
// getInitParameter(String name)
// getInitParameterNames()
// getServletContext() 注:GenericServlet中有getServletConfig()和getServletContext()方法
public void init(ServletConfig config) {
...
}
@Override
public void service(ServletRequest request, ServletResponse response) {
...
}
@Override
// 应用卸载了就销毁
public void destroy() {
...
}
@Override
public String getServletInfo() {
...
}
@Override
public ServletConfig getServletConfig() {
...
}
}
- 继承抽象类javax.servlet.GenericServlet,重写service方法
该抽象类实现了除service方法以外的4个方法,service方法为抽象方法
- 继承抽象类javax.servlet.http.HttpServlet,重写doGet和doPost方法 (开发中最常用)
抽象类HttpServlet实现了全部5个方法,在service方法的实现service(ServletRequest request, ServletResponse response)
中,将ServletRequest对象
和ServletResponse
对象分别强转成了HttpServletRequest对象
和HttpServletResponse对象
,然后调用本地的service(HttpServletRequest request, HttpServletResponse response)
方法,在本地的service方法中,根据请求方式的不同调用doGet、doPost、doDelete等方法,并且自身也实现了这些方法,但是自己实现的doGet、doPost等方法是返回错误响应码405(不允许此方法 HTTP 1.1)或者400(请求出错 非HTTP 1.1),所以我们选择这种Servlet实现方式时,必须重写doGet和doPost方法
public MyServlet extends HttpServlet {
@Override
public void doGet(HttpServletRequest request, HttpServletReposne response) {
...
}
@Override
public void doPost(HttpServletRequest request, HttpServletResponse response) {
...
}
}
实现了Servlet之后必须在web.xml中注册
<servlet>
<servlet-name>Servlet名字</servlet-name>
<servlet-class>你编写的Servlet所在的路径</servlet-class>
<!-- 这个标签中的值必须为整数,当值>=0时表示在服务器启动时就创建该Servlet,并且值越小,该Servlet启 动的优先级越高;当值<0时或者没有指定该标签时,则该Servlet在被选择时才加载 -->
<load-on-startup>1</load-on-startup>
<init-param>
<param-name>参数1</param-name>
<param-value>参数值1</param-value>
</init-param>
<init-param>
<param-name>参数2</param-name>
<param-value>参数值2</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>跟上面servlet节点中的servlet名字一致</servlet-name>
<url-pattern>路径匹配模式</url-pattern>
</servlet-mapping>
如何在服务器启动时就创建Servlet?<load-on-startup>
标签
Servlet的url-pattern匹配模式与Filter相同,但是匹配是有顺序的:先精确匹配,再路径匹配,最后后缀匹配,一次请求只会匹配一个Servlet。
context全局参数配置方式:
<context-param>
<param-name>参数1</param-name>
<param-value>参数值1</param-value>
</context-param>
<context-param>
<param-name>参数2</param-name>
<param-value>参数值2</param-value>
</context-param>
可以通过ServletContext的getInitParameter(String name)
方法来获取全局参数值
Servlet三大域对象:
ServletContext:代表整个应用(WEB项目),一个应用只有一个ServletContext对象,单实例
HttpSession:会话范围
ServletRequest:请求范围
// 往ServletContext、HttpSession、ServletRequest中设置属性、更新属性、删除属性
void setAttribute(String name, Object value)
Object getAttribute(String name)
void removeAttribute(String name)
Servlet中请求转发和请求包含
ServletContext application = this.getServletContext();
RequestDispatcher rd = application.getRequestDispatcher("/contextDemo2");
// 请求转发: 由当前Servlet设置响应头,下一个Servlet设置响应头和响应体
// 设置响应头:response.setHeader("aaa", "bbb")
// 设置响应体:response.getWritter().print("Hello World!")
rd.forward(request, response);
// 请求包含: 当前Servlet和下一个Servlet都可以设置响应头和响应体
rd.include(request, response);
请求转发和重定向的区别:
请求转发:一次请求一次响应,地址栏不变,只能转发到本项目其他的Servlet,服务端的行为
重定向:二次请求两次响应,地址栏变化,不只能重定向到本项目的其它Servlet,还能定向到其它项目,浏览器端的行为。重定向用法:response.sendRedirect("url地址")