Servlet是在服务器上运行的小程序,也就是一个Java类,但比较特殊,不须要new,自动就能够运行。也有建立、垃圾回收和销毁过程。Servlet是JavaWeb的三大组件之一(Servlet、Filter、Listener),它属于动态资源。Servlet的做用是处理请求,服务器会把接收到的请求交给Servlet来处理,在Servlet中一般须要:html
例如客户端发出登陆请求,或者输出注册请求,这些请求都应该由Servlet来完成处理。Servlet须要咱们本身来编写,每一个Servlet必须实现javax.servlet.Servlet接口。Servlet对象驻留在服务器内存中。java
写一个java类,实现Servlet接口,实现了该接口,该类就不是普通的类了。web
package servletdemo; import javax.servlet.*; import javax.servlet.annotation.WebServlet; import java.io.IOException; @WebServlet("/servlet") public class servletDemo implements Servlet { @Override public void init(ServletConfig servletConfig) throws ServletException { System.out.println("Hello Servlet"); } @Override public ServletConfig getServletConfig() { return null; } @Override public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException { } @Override public String getServletInfo() { return null; } @Override public void destroy() { } }
部署应用到tomcat服务器。小程序
实例化-->初始化-->服务->销毁设计模式
出生:(实例化-->初始化)第一次访问Servlet就出生了(默认状况下)。(说明我能够改变它的出生时机,好比让servlet在服务器启动时就建立)数组
活着:(服务)应用活着,servlet就活着。(Servlet是单实例,其中的service()方法是多线程的。)浏览器
死亡:(销毁)应用被卸载了,servlet就销毁了。tomcat
package servletdemo; import javax.servlet.*; import javax.servlet.annotation.WebServlet; import java.io.IOException; @WebServlet("/servlet") public class servletDemo implements Servlet { //Servlet生命周期的方法:实例化方法(new 对象,无参构造) //在servlet第一次被访问时调用 public servletDemo() { System.out.println("*******servletDemo执行了"); } //Servlet生命周期的方法:初始化方法 //在servlet第一次被访问时调用 @Override public void init(ServletConfig servletConfig) throws ServletException { System.out.println("*********init执行了"); } @Override public ServletConfig getServletConfig() { return null; } //Servlet生命周期的方法:服务方法 //每次访问时都会被调用 @Override public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException { System.out.println("*******service执行了"); } @Override public String getServletInfo() { return null; } //Servlet生命周期的方法:销毁方法 //当应用被卸载时调用 @Override public void destroy() { System.out.println("*******destroy执行了"); } }
实现Servlet有三种方式:安全
自定义Servlet类的继承结构,以下图:服务器
package servletdemo; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @WebServlet("/servlet1") public class servlet extends HttpServlet { //具体实现1 @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("******MydoGet*******"); System.out.println(req.getRemoteAddr()); } //具体实现2 @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("*******MydoPost******"); } }
注意: 不要重写父类Httpservlet中的service()方法,由于该方法会调用Httpservlet中私有的service()方法,
咱们去重写这些不一样的表单提交的方法便可。
此故事纯属本人脑洞虚构
故事内容:草原上有一头公牛喜欢一头母牛,可是公牛不敢直接向母牛表白,有一天公牛找到一头小牛,想让小牛把他想对母牛说的话说给母牛听,小牛答应了,剧情很鸡血,就这样,看我用servlet实现
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <body> <h2>公牛表白准备</h2> <a href="/servlet2">去表白</a> </body> </html>
package com.demo.servlet; import javax.servlet.*; import javax.servlet.annotation.WebServlet; import java.io.IOException; @WebServlet("/servlet2") public class ServletDemo2 extends GenericServlet { @Override public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException { System.out.println("我是草原上的公牛"); System.out.println("我让小牛把我对母牛的爱传给她"); System.out.println("该说的话我给小牛说了,小牛听到了给我回复收到,并把我说的话传给母牛"); ServletContext application = this.getServletContext(); application.setAttribute("name","母牛"); application.getRequestDispatcher("/servlet3").forward(req,res); } }
package com.demo.servlet; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter; @WebServlet("/servlet3") public class ServletDemo3 extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doPost(req,resp); System.out.println("我是小牛"); //设置输出格式和字符编码 resp.setContentType("text/html;charset=utf-8"); //向页面输出内容 PrintWriter out = resp.getWriter(); out.println("<h1>我是小牛</h1>"); ServletContext application = this.getServletContext(); String name = (String) application.getAttribute("name"); System.out.println("收到的名字:"+name); out.println("收到的名字:"+name); System.out.println("小牛收到"); application.setAttribute("love","公牛说他爱你"); application.getRequestDispatcher("/servlet4").forward(req,resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("我是dopost"); resp.setContentType("text/html;charset=utf-8"); PrintWriter out = resp.getWriter(); out.println("<h1>我是servlet33</h1>"); } @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { super.service(req, resp); System.out.println("我是service333"); resp.setContentType("text/html;charset=utf-8"); PrintWriter out = resp.getWriter(); out.println("<h1>我是servlet333</h1>"); } }
package com.demo.servlet; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter; @WebServlet("/servlet4") public class Servlet4 extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doPost(req,resp); System.out.println("我是母牛"); String love = (String) this.getServletContext().getAttribute("love"); System.out.println(love); resp.setContentType("text/html;charset=utf-8"); //向页面输出内容 PrintWriter out = resp.getWriter(); out.println("收到的表白:"+love); System.out.println("母牛收到"); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { } }
一个servlet能够配置多个映射路径(或者说:多个映射路径能够指向同一个servlet),只要是name是同样的就行
通配符* 表明任意字符串
url-pattern:*.xxx 以.xxx结尾的请求均可以访问 注:不要加/
url-pattern:/* 以任意字符串结尾的请求均可以访问
在servlet类的上面写入注解@WebServlet("/hello")
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd" > <web-app> <display-name>Archetype Created Web Application</display-name> <servlet> <servlet-name>Servletdemo1</servlet-name> <servlet-class>com.demo.servlet.Servletdemo1</servlet-class> <init-param> <param-name>name</param-name> <param-value>tom</param-value> </init-param> <init-param> <param-name>password</param-name> <param-value>1234</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>Servletdemo1</servlet-name> <url-pattern>/servlet</url-pattern> </servlet-mapping> <context-param> <param-name>k</param-name> <param-value>xxxxxxxx</param-value> </context-param> </web-app>
package com.demo.servlet; import javax.servlet.*; import java.io.IOException; import java.io.PrintWriter; import java.util.Enumeration; public class Servletdemo1 implements Servlet { private ServletConfig servletConfig; @Override public void init(ServletConfig config) throws ServletException { servletConfig=config; System.out.println("init调用了"); } @Override public ServletConfig getServletConfig() { return servletConfig; } @Override public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException { //设置输出格式和字符编码 res.setContentType("text/html;charset=utf-8"); //向页面输出内容 PrintWriter out = res.getWriter(); out.println("我是service"+"<br>"); System.out.println("我是service"); //方法一 String name = servletConfig.getInitParameter("name"); String password = servletConfig.getInitParameter("password"); System.out.println("在控制台输出信息:"); System.out.println("name:"+name+"password:"+password); out.println("name:"+name+" "+"password:"+password+"<br>"); //方法二 Enumeration<String> en = servletConfig.getInitParameterNames(); while (en.hasMoreElements()){ String names = en.nextElement(); String values = servletConfig.getInitParameter(names); System.out.println("在控制台输出信息:"); System.out.println(names+" "+values); out.println(names+" "+values+"<br>"); } String k = servletConfig.getServletContext().getInitParameter("k"); System.out.println("在控制台输出信息:"); System.out.println("k:"+k+"<br>"); out.println("k"+k); } @Override public String getServletInfo() { return null; } @Override public void destroy() { } }
package com.demo.servlet; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter; @WebServlet("/hello") public class Servlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doPost(req,resp); ServletContext servletContext = this.getServletContext(); servletContext.setAttribute("user","Tom"); String user = (String)servletContext.getAttribute("user"); //从请求的地址栏或表单中获取信息 String user2 = req.getParameter("user"); System.out.println("获取Context容器中的信息:"+user); System.out.println("在控制台输出从访问的地址栏获取的信息:"+user2); resp.setContentType("text/html"); resp.setCharacterEncoding("utf-8"); PrintWriter out = resp.getWriter(); out.append("<!DOCTYPE html>") .append("<html><head></head><body>") .append("用户是"+user) .append("</body></html>"); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { } }
整个生命周期是单实例,但每次访问时为多线程。
一:单实例变成多实例,但过期了,由于耗费资源多,服务器压力大。
二:加线程锁,但数据会重复出现(没有同步机制),且运行效率低。
ServletContext: 表明的是整个应用。一个应用只有一个ServletContext对象。单实例。
一个项目只有一个ServletContext对象,服务器会为每一个应用建立一个ServletContext对象,咱们能够在N多个Servlet中来获取这个惟一的对象,使用它能够给多个Servlet传递数据,与Tomcat同生同死。
ServletContext对象的做用是在整个Web应用的动态资源直接共享数据。例如在AServlet中向ServletContext对象中保存一个值,而后在BServlet中就能够获取这个值,这就是数据共享。
在Servlet中获取ServletContext对象:
ServletContext context = config.getServletContext();
public class DemoServlet implements Servlet { public void init(ServletConfig config) throws ServletException { ServletContext context = config.getServletContext(); } }
public class HttpServletDemo extends HttpServlet { @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { ServletContext context = this.getServletContext(); } }
ServletContext是JavaWeb四大域对象之一:
全部域对象都是有存取数据的功能,由于域对象内部有一个Map,用来存储数据,下面是ServletContext对象用来操做数据的方法:
方法:public String getInitParamenter(String name) // 根据配置文件中的key获得value
方法:public String getRealPath(String path)// 根据资源名称获得资源的绝对路径,能够获得当前应用任何位置的任何资源。
public class AServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //获取带有盘符的路径 String path = this.getServletContext().getRealPath("/a.txt"); //获取资源路径后,再获取输入流对象 InputStream is = this.getServletContext().getResourceAsStream("/a.txt"); //获取当前路径下的全部资源路径 Set<String> paths = this.getServletContext().getResourcePaths("/WEB-INF"); } }
转发和重定向都能让浏览器得到另一个URL所指向的资源,但二者的内部运行机制有着很大的区别。
一、转发:有两种方式得到转发对象(RequestDispatcher):一种是经过HttpServletRequest的getRequestDispatcher()方法得到,一种是经过ServletContext的getRequestDispatcher()方法得到;
之前的request范围中存放的变量不会失效,就像把两个页面拼到了一块儿。 例如:
request.getRequestDispatcher (“demo.jsp"). forward(request, response);//转发到demo.jsp
详解:假设浏览器访问servlet1,而servlet1想让servlet2为客户端服务。此时servlet1调用forward()方法,将请求转发给servlet2。可是调用forward()方法,对于浏览器来讲是透明的,浏览器并不知道为其服务的Servlet已经换成Servlet2,它只知道发出了一个请求,得到了一个响应。浏览器URL的地址栏不变。
二、重定向:HttpServletResponse的sendRedirect()方法。
服务器根据此请求寻找资源并发送给客户,它能够重定向到任意URL,不能共享request范围内的数据。例如:response.sendRedirect(“demo.jsp");//重定向到demo.jsp
详解:假设浏览器访问servlet1,而servlet1想让servlet2为客户端服务。此时servlet1调用sendRedirect()方法,将客户端的请求从新定向到Servlet2。接着浏览器访问servlet2,servlet2对客户端请求做出反应。浏览器URL的地址栏改变。
三、主要区别:
(1)sendRedirect()方法不但能够在位于同一个主机上的不一样Web应用程序之间进行重定向,并且能够将客户端重定向到其余服务器上的Web应用程序资源。而forward()方法只能将请求转发给同一Web应用的组件。
(2)sendRedirect()方法不能转发到“/WEB-INF/”路径下的jsp页面资源,而getRequestDispatcher().forword()能够重定向到“/WEB-INF/”路径下的jsp页面资源。如 request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request, response);
(3)转发:浏览器URL的地址栏不变。
重定向:浏览器URL的地址栏改变。
方法:public RequestDispatcher getRequestDispatcher(String path) //参数表示要跳转到哪去
若是是经过参数传过来的对象,就叫依赖。
经过方法获得的对象,就叫关联。
Cookie[] getCookies()
返回一个数组,包含客户端发送该请求的全部的 Cookie 对象。
Enumeration getAttributeNames()
返回一个枚举,包含提供给该请求可用的属性名称。
HttpSession getSession()
返回与该请求关联的当前 session 会话,或者若是请求没有 session 会话,则建立一个。
HttpSession getSession(boolean create)
返回与该请求关联的当前 HttpSession,或者若是没有当前会话,且建立是真的,则返回一个新的 session 会话。
String getRequestedSessionId()
返回由客户端指定的 session 会话 ID。
Object getAttribute(String name)
以对象形式返回已命名属性的值,若是没有给定名称的属性存在,则返回 null。
String getCharacterEncoding()
返回请求主体中使用的字符编码的名称。
String getContentType()
返回请求主体的 MIME 类型,若是不知道类型则返回 null。
String getContextPath()
返回指示请求上下文的请求 URI 部分。
String getQueryString()
返回包含在路径后的请求 URL 中的查询字符串。
String getRemoteUser()
若是用户已经过身份验证,则返回发出请求的登陆用户,或者若是用户未经过身份验证,则返回 null。
int getParameterMap()
将参数封装成 Map 类型。
void reset()
清除缓冲区中存在的任何数据,包括状态码和头。
void resetBuffer()
清除响应中基础缓冲区的内容,不清除状态码和头。
void setCharacterEncoding(String charset)
设置被发送到客户端的响应的字符编码(MIME 字符集)例如,UTF-8。
void setStatus(int sc)
为该响应设置状态码。
void setIntHeader(String name, int value)
设置一个带有给定的名称和整数值的响应报头。
HTTP Header 响应实例:
//导入必需的 java 库 import java.io.IOException; import java.io.PrintWriter; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @WebServlet("/Refresh") //扩展 HttpServlet 类 public class Refresh extends HttpServlet { // 处理 GET 方法请求的方法 public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 设置刷新自动加载时间为 5 秒 response.setIntHeader("Refresh", 5); // 设置响应内容类型 response.setContentType("text/html;charset=UTF-8"); //使用默认时区和语言环境得到一个日历 Calendar cale = Calendar.getInstance(); //将Calendar类型转换成Date类型 Date tasktime=cale.getTime(); //设置日期输出的格式 SimpleDateFormat df=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); //格式化输出 String nowTime = df.format(tasktime); PrintWriter out = response.getWriter(); String title = "自动刷新 Header 设置 - 菜鸟教程实例"; String docType = "<!DOCTYPE html>\n"; out.println(docType + "<html>\n" + "<head><title>" + title + "</title></head>\n"+ "<body bgcolor=\"#f0f0f0\">\n" + "<h1 align=\"center\">" + title + "</h1>\n" + "<p>当前时间是:" + nowTime + "</p>\n"); } // 处理 POST 方法请求的方法 public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
以上测试实例是位于 TomcatTest 项目下,对应的 web.xml 配置为:
<?xml version="1.0" encoding="UTF-8"?> <web-app> <servlet> <!-- 类名 --> <servlet-name>Refresh</servlet-name> <!-- 所在的包 --> <servlet-class>com.runoob.test.Refresh</servlet-class> </servlet> <servlet-mapping> <servlet-name>Refresh</servlet-name> 同上面的类名 <!-- 访问的网址 --> <url-pattern>/TomcatTest/Refresh</url-pattern> </servlet-mapping> </web-app>
如今,调用上面的 Servlet,每隔 5 秒会显示当前系统时间。
404:服务器没法找到所请求的页面。
403:禁止访问所请求的页面。
401:所请求的页面须要用户名和密码。
405:在请求中指定的方法是不容许的。
307:所请求的页面已经临时转移到一个新的 URL。
500:未完成的请求。服务器遇到了一个意外的状况。
下面的方法可用于在 Servlet 程序中设置 HTTP 状态码。这些方法经过 HttpServletResponse 对象可用。
public void setStatus ( int statusCode )
该方法设置一个任意的状态码。setStatus 方法接受一个 int(状态码)做为参数。若是您的反应包含了一个特殊的状态码和文档,请确保在使用 PrintWriter 实际返回任何内容以前调用 setStatus。
public void sendError(int code, String message)
该方法发送一个状态码(一般为 404),连同一个在 HTML 文档内部自动格式化并发送到客户端的短消息。
// 设置错误代码和缘由 response.sendError(407, "Need authentication!!!" );
Servlet是实现了javax.servlet.Servlet接口的类,这个接口规定了特定的方法来处理特定的请求,咱们只须要实现Servlet相关的方法,Servlet规范是创建在HTTP协议上的,http1.1规范支持OPTIONS/GET/POST/HEAD/PUT/DELETE/TRACE等7种访问方式。下面咱们重点介绍Get/Post。
一、GET:表示查询信息,URL中附带少许参数信息,URL总长度不超过255个字符,参数还会在浏览器的地址栏中显示
二、POST:表示提交信息,通常用于提交大数据信息或者文件,提交的内容不收长度限制,也不会在地址栏中显示。
三、HEAD:表示查询文档头信息,服务器返回的文件类型,长度,最后修改时间等等,该方式较少使用。
四、OPTIONS /PUT /DELETE /TRACE:是被声明了但尚未被使用web访问方式,几乎不用。