Servlet字面意思即服务端小程序
Servlet是一组接口、一组规范、一个协议;用于开发Web项目
一个工程的搭建通常由各模块组成;各个模块分工协作、相互配合可以高效率地构建大型项目。各个模块之间需要一组规范来连接,Servlet就是这样一组规范
B/S架构中涉及到的协议、标准、规范:
每一个url都对应着互联网中的一个资源,分为静态资源和动态资源,例如:
这段程序就是Servlet程序,当浏览器发送某个请求时,服务器找到该请求对应的servlet程序并执行servlet对象的service()方法。请求路径与servlet程序的对应信息配置在web.xml文件中,如图:
javax.servlet.Servlet接口
public interface Servlet {
/**
初始化方法,servlet对象创建之后会执行该方法;servlet对象为单例对象,故该方法只执行一次
*/
void init(ServletConfig config) throws ServletException;
/**
获取servletConfig对象,该对象由服务器创建并传入
*/
ServletConfig getServletConfig();
/**
主体方法,用于处理业务逻辑,服务器通过请求路径找到对应的servlet对象并执行该方法;由服务器传入请求和响应对象
*/
void service(ServletRequest request, ServletResponse response) throws ServletException, IOException;
/**
返回有关servlet的信息,例如作者,版本和版权
*/
String getServletInfo();
/**
销毁前的准备,servlet对象销毁前会执行该方法
*/
void destroy();
}
Servlet对象从最初的创建,方法的调用,到最后被销毁,都是由web容器来管理的,javaweb程序员无权干涉
具体过程:
注意:servlet对象是单例,web容器为每个Servlet类只创建一个servlet对象
org.apache.catalina.core.StandardWrapperFacade
标签中的所有内容,例如:void init(ServletConfig servletConfig) throws ServletException;
public interface ServletConfig {
//获取servletName: servletName
String getServletName();
//获取ServletContext对象,ServletContext为Servlet的上下文环境,下章节讲
ServletContext getServletContext();
/**
获取初始化参数name对应的value
driver
com.mysql.jdbc.driver
*/
String getInitParameter(String paranmae);
/**
获取初始化参数的name集合的枚举(类似迭代器):
Enumeration initParameterNames = servletConfig.getInitParameterNames();
通过name集合循环遍历拿出name,通过name获取value
while (initParameterNames.hasMoreElements()) {
String name = initParameterNames.nextElement();
String value = servletConfig.getInitParameter(name);
}
*/
Enumeration<String> getInitParameterNames();
}
ServletContext指javax.servlet.ServletConfig接口
ServletContext对象由服务器创建,Tomcat服务器对ServletContext接口的实现类完整类名是:org.apache.catalina.core.ApplicationContextFacade
ServletContext意为servlet的上下文环境,servletContext对象对应着整个项目,该对象只有一个且被所有servlet共享,servletContext对象对应着web.xml文件,例如:
web.xml文件服务器启动阶段被解析,servletContext对象在服务器启动阶段被创建,在服务器关闭时被销毁
/**
根据参数的名称获取value,均为字符串
driver
com.mysql.jdbc.driver
*/
String getInitParameter(String paraname);
//与ServletConfig中的方法作用相同
Enumeration<String> getInitParameterNames();
//向ServletContext对象中添加数据
void setAttribute(String name, Object obj);
//根据name从ServletContext对象中获取数据
Object getAttribute(String name);
//从ServletContext对象中移除数据
void removeAttribute(String name);
//获取文件绝对路径
String getRealPath(String path);
由于所有的servlet共同对应着一个servletContext,不同的servlet、不同的用户可以通过一下两个方法共享数据
//向ServletContext对象中添加数据
void setAttribute(String name, Object obj);
//根据name从ServletContext对象中获取数据
Object getAttribute(String name);
GenericServlet即通用Servlet,是一个抽象类,实现了Servlet接口
init()
方法public String getInitParameter(String name);
、public ServletContext getServletContext();
子类继承之后,可以在子类中直接使用,方便编程HttpServlet是一个模板类、抽象类,继承于GenericServlet
service(ServletRequest req, ServletResponse res)
方法将两个参数转化为HttpServletRequest和HttpServletResponse类型的service(HttpServletRequest request, HttpServletResponse response)
方法获取请求方法;判断,如果是Get请求就执行doGet()方法,如果是Post请求就执行doPost()方法注意:HttpServlet提供的doGet()方法和doPost()方法是用来报错的、是用来让我们重写的
所以,我们编写的的Servlet类继承HttpServlet后,后端需要的是什么请求,那么我们就重写对应的doPost()/doGet()方法,方法内是我们的业务代码,并不需要重写service()方法
doPost()
/doGet()
方法doPost()
/doGet()
方法内就是我们的业务代码,doXXX()
可以看作main()
方法service()
内编写了,不需要重写service()
方法service()
方法并不需要也没有理由去重写这两个方法模版方法设计模式属于行为行设计模式
模版方法有一个特点:doXXX()
模板方法设计模式的主要作用:
模板方法设计模式的例子:
请求协议包括四部分:
1,请求行
2,消息报头
3,空白行
4,请求体
请求行包括:请求方式 URI 协议版本号
空白行:专门用来分离消息报头和请求体的
响应协议包括四部分:状态行、响应报头、空白行、响应体
状态行:协议版本号 状态码
空白行:是用来分离响应报头和响应体的
响应协议中重点掌握状态码:
(1), 什么情况下浏览器发送的请求是GET请求,什么情况下浏览器发送的请求是POST请求?
只有当使用表单form,并且讲form的标签的method属性设置为method=“post”,才是POST请求方式,其余剩下的所有请求都是基于GET请求
(2), GET请求和POST请求有什么区别?
uri?name=value&name=value
,这种提交方式最终提交的数据会显示在浏览器地址栏上name=value&name=value
,这种提交方式最终不会显示在浏览器地址栏上(3),GET请求和POST请求应该如何选择?
浏览器将资源缓存后,缓存的资源是和某个特定的路径绑定在一起的,只要浏览器再发送这个相同的请求路径,这个时候浏览器就会去缓存中获取资源,不再访问服务器,以这种方式降低服务器的压力,提高用户体验。
但是有的时候我们并不希望走缓存,希望每一次后哦访问服务器,可以在请求路径后面添加时间戳,例如:http://ip:port/oa/system/logout?timetamp=1234564635423
表单提交的数据会封装在request对象的Map集合中,key是name,value是字符串类型的一个一维数组,如下:
/*获取浏览器提交的数据*/
String getParameter(String name) //获取name对应的一维数组的首元素
Map getParameterMap() //获取request对象中的Map集合
Enumeration getParameterNames() //返回name集合的枚举,与ServletConfig、ServletContext中的getInitParameterNames()作用相同
String[] getParameterValues(String name) //返回String数组,数组包含name对应的多个value值
/*获取路径、URL、URI、IP*/
String getContextPath() //获取上下文路径(web项目根路径),资源的根路径
String getMethod() //获取浏览器请求方式
String getRequestURI() //获取请求的URI
StringBuffer getRequestURL() //获取请求的URL
String getServletPath() //获取请求的ServletPath,即servlet对应的请求路径
String getRemoteAddr() //获取客户端IP地址
/*从一次请求对应的HttpServletRequest对象范围中增删查数据*/
Object getAttribute(String name) //从此次请求对应的request对象范围中获取数据
void setAttribute(String name, Object o) //从此次请求对应的request对象范围中存储数据
void removeAttribute(String name) //从此次请求对应的request对象范围中删除数据
/*请求转发器*/
RequestDispatcher getRequestDispatcher(String path) //获取请求转发器,用于请求转发
/*编码*/
void setCharacterEncoding(String env) //覆盖此请求正文中使用的字符编码的名称(针对post请求才起作⽤)
/**/
HttpSession getSession() //返回与此请求关联的当前会话,如果该请求没有会话,则创建一个并返回。
HttpSession session=request.getSession(true);//获取session对象,若没有获取到则新建session对象并返回;与getSession()作用相同
HttpSession session=request.getSession(false);//获取session对象,若没有获取到则返回null
Cookie[] getCookies() //返回一个Cookie数组,其中包含浏览器端发送过来的包含在请求中的所有cookie
//Cookie和Session下面章节讲
void addCookie(Cookie cookie) //给这个响应添加⼀个cookie
void sendRedirect(String s) //重定向,发送⼀条响应码,将浏览器跳转到指定的位置
PrintWriter getWriter() //获得字符输出流,通过字符流的write(String s)⽅法可以将字符串输出到response缓冲区中,随后Tomcat会将response缓冲区中的内容组装成Http响应返回给浏览器端。
void setContentType(String s) //设置响应内容的类型,例如:response.setContentType("text/html;charset=UTF-8");
步骤:
forward()
方法即可完成转发例如:
//请求转发到/b对应的Servlet
request.getRequestDispatcher("/b").forward(request,response);
特点: 在浏览器端进行一次请求,服务器端将请求从一个Servlet转发给另一个Servlet…,浏览器端的地址不变,但是实际上可能后台是好几个Servlet依次处理浏览器的请求,并响应给浏览器。请求转发可以使不同的servlet共享同一个request中的数据,通过以下方法:
Object getAttribute(String name) //从此次请求对应的request对象范围中获取数据
void setAttribute(String name, Object o) //从此次请求对应的request对象范围中存储数据
void removeAttribute(String name) //从此次请求对应的request对象范围中删除数据
服务器将请求路径反馈给浏览器,浏览器又向web服务器发送了一次全新的请求;例如:
response.sendRedirect(request.getContextPath() + "/b");
https://www.baidu.com
大部分情况下都使用重定向
假设现在浏览器端发送向数据库中插入一条数据的请求,插入成功后跳转到成功页面
使用转发:
使用重定向:
服务器创建Cookie并发送给浏览器
//创建cookie
Cookie cookie = new Cookie(String name, String value);
//设置Cookie有效期
cookie.setMaxAge(60*60*60);
//设置Cookie绑定的路径
cookie.setPath("/webapp/user");
//将cookie发送给浏览器
response.addCookie(cookie);
Cookie未绑定路径时默认绑定的路径:
在默认情况下,未设置Cookie绑定路径的Cookie,会绑定当前访问路径的上一层路径(带"/"),如:
/webapp/test/a
路径时,服务器发送的Cookie(此Cookie未人为设置绑定路径),那么此Cookie默认绑定的路径未/webapp/test
/,所以访问/webapp/test/、/webapp/test/···时都会将此Cookie发送给服务器Cookie绑定路径:
cookie.setPath();
来设置此Cookie绑定的访问路径;当设置此Cookie绑定的路径时,浏览器只有访问此路径,以及此路径下的其他资源时,浏览器才会将此Cookie发送到服务器
如下:那么此Cookie只有浏览器访问/webapp19/user路径,以及/webapp/user/···等等其他此路径下的其他资源时,浏览器才会将此Cookie发送到服务器
cookie.setPath("/webapp/user");
只有当浏览器访问Cookie绑定的路径以及此路径下的其他资源时,浏览器才会将Cookie发送给服务器
通过方法cookie.setMaxAge(int expiry)
例如:以下设置Cookie有效期为24小时
cookie.setMaxAge(60*60*24);
例如:实现十天内免登录,将用户名和密码保存在cookie中,每当访问登录页面时发送给服务器,服务器验证
HttpSession session=request.getSession();//与getSession(true)作用相同
HttpSession session=request.getSession(true);//获取session对象,若没有获取到则新建session对象并返回;(无参数默认为true)
HttpSession session=request.getSession(false);//获取session对象,若没有获取到则返回null
1,浏览器发送请求,服务器对应的Servlet首次调用request.getSession(true);
方法时获取Session对象:
2, 浏览器再次发送请求,会自动提交Cookie(前提是同一个绑定路径下)
request.getSession();
方法时获取Session对象web系统中引入了session超时的概念,当很长一段时间(这个时间可以配置)没有用户再访问session对象,此时session对象超时,web服务器自动回收session对象
设置Session对象失效时间(两次请求之间的最大时间间隔),优先级 1 > 2 > 3
void setAttribute(String name, Object value) //向会话范围中存储数据
Object getAttribute(String name) //从会话范围中获取数据
void removeAttribute(String name) //从会话范围中移除某个数据
void invalidate() //销毁session对象
void setMaxInactiveInterval(int interval) //设置session对象失效时间(浏览器向服务器两次请求之间最大时间间隔,超过最大设置时间间隔则销毁此session)
例如:报存用户登录状态,验证用户是否已登录
void setAttribute(String name, Object value) 和 Object getAttribute(String name)
方法共享数据浏览器对请求数据的编码方式和服务器对请求数据的解码方式不同。Get请求的数据在URL中,属于URL编码;Post请求数据的编码方法即页面的编码方式
(1)适用于Post请求和Get请求
//获取乱码字符
String value = request.getParameter("name");
//将乱码字符通过错误的ISO-8859-1编码方式重新还原回去
byte[] bytes = value.getBytes("ISO-8859-1");
//再通过正确的编码方式进行解码
value = new String(bytes, "UTF-8");
(2)仅支持Post请求
//设置字符编码方式
request.setCharacterEncoding("UTF-8");
//获取正确的字符
String value = request.getParameter("name");
(3)仅支持Get请求
注:Tomcat8之后针对于Get请求服务器会在程序中解决字符编码的问题;所以我们只需要处理Post请求的乱码问题即可
在获取输出流对象之前设置输出内容的类型和字符集,例如:
response.setContentType("text/html;charset=UTF-8");
PrintWriter writer = response.getWriter();
web工程servlet中反斜杠"/"的表示含义:
如果路径是在浏览器端被解析,则"/“表示"http://ip地址:port/”
如果路径是在服务器端被解析,则"/“表示"http://ip地址:port/项目名/”
下面罗列了一些web工程中"/"的使用场景:
1,浏览器端被解析的场景:
response.sendRedirect("/项目名/资源路径");
cookie.setPath("/项目名/资源路径");
2,服务器端被解析的场景:
请求转发:request.getRequestDispatcher("/资源路径").forward(request,response);
获取资源的真实绝对路径:context.getRealPath("/资源路径");
从Servlet3.0开始,配置Servlet⽀持注解⽅式,同时保留了配置web.xml的⽅式。这降低了配置xml所花费的时间和精力。
服务器会在启动时读取注解
@WebServlet常⽤属性
例如:
注意:根元素web.xml中不能配置属性metadata-complete=“true”,否则⽆法加载Servlet。metadata-complete属性表示通知Web容器是否寻找注解,默认不写或者设置false,容器会扫描注解,为Web应⽤程序构建有效的元数据;如果设置metadata-complete=“true”,会在启动时不扫描注解(annotation)。如果不扫描注解的话,⽤注解进⾏的配置就⽆法⽣效,例如:@WebServlet