Servlet是什么
Servlet(Server Applet),全称Java Servlet,未有中文译文。是用Java编写的服务端程序。其主要功能在于交互式地浏览和修改数据,生成动态Web内容。狭义的Servlet是指Java语言实现的一个接口,广义的Servlet是指任何实现了这个Servlet接口的类,一般情况下,人们将Servlet理解为后者。
简单的来说,Servlet就是实现了Servlet接口的类,作用就是用来接收浏览器请求并做出相应。
Servlet本身不能独立运行,需要在一个web应用中运行的,而一个web应用是部署在tomcat中的,所以开发一个Servlet需要如下几个步骤
- 创建web应用项目
- 编写Servlet代码
- 部署到tomcat中
Servlet的工作流程
- 浏览器发送请求到服务器
- 服务器调用Servlet,Servlet根据请求的内容作出响应,并传输回服务器
- 服务器将响应内容返回给浏览器
用户请求致使Servlet容器调用Servlet的Service方法,并传入一个ServletRequest对象和一个ServletResponse对象。ServletRequest对象和ServletResponse对象都是由Servlet容器(Tomcat)封装好的,可以直接使用。
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String method = req.getMethod();
long lastModified;
if (method.equals("GET")) {
lastModified = this.getLastModified(req);
if (lastModified == -1L) {
this.doGet(req, resp);
} else {
long ifModifiedSince = req.getDateHeader("If-Modified-Since");
if (ifModifiedSince < lastModified) {
this.maybeSetLastModified(resp, lastModified);
this.doGet(req, resp);
} else {
resp.setStatus(304);
}
}
} else if (method.equals("HEAD")) {
lastModified = this.getLastModified(req);
this.maybeSetLastModified(resp, lastModified);
this.doHead(req, resp);
} else if (method.equals("POST")) {
this.doPost(req, resp);
} else if (method.equals("PUT")) {
this.doPut(req, resp);
} else if (method.equals("DELETE")) {
this.doDelete(req, resp);
} else if (method.equals("OPTIONS")) {
this.doOptions(req, resp);
} else if (method.equals("TRACE")) {
this.doTrace(req, resp);
} else {
String errMsg = lStrings.getString("http.method_not_implemented");
Object[] errArgs = new Object[]{method};
errMsg = MessageFormat.format(errMsg, errArgs);
resp.sendError(501, errMsg);
}
}
这是我们平时写Servlet继承的HttpServlet类里的service方法的具体实现,主要做的就是判断请求的方式,根据请求的方式来执行相应的方法,而在HttpServlet对这些doGet方法有具体的实现,所以我们在写Servlet的时候要做的,就是根据需求重写这些处理请求的方法,给出响应的信息。
编写第一个Servlet类
package com.zwq.servlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
public class HelloServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
PrintWriter writer = response.getWriter();
writer.print("Hello Servlet");
}
}
新建一个类继承自HttpServlet,然后重写他的doGet方法,然后就可以在方法体内执行需要的业务需求了,这里做的是访问时在网页上显示Hello Servlet。
配置工作
我们写好了Servlet类,还需要对它进行一些配置,以便让Tomcat知道,在访问某个路径的时候,要读取哪个类底下的哪一个Servlet。
打开这个web.xml文件,添加两个标签,一个是<servlet>,另一个是<servlet-mapping>。
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0"
metadata-complete="true">
<servlet>
<servlet-name>HelloServlet</servlet-name>
<servlet-class>com.zwq.servlet.HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>HelloServlet</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
</web-app>
上下两个servlet-name 里的名字是可以随便取的,但要保持一致。servlet-class是指定编写的Servlet的路径,url-pattern里的/hello的意思是,当我们在浏览器里访问/hello时,会调用这个HelloServlet进行处理。
做完这些后,将项目部署到Tomcat上,运行Tomcat访问localhost:8080/hello,就能看到输出的结果了。
ServletContext对象
web容器在启动的时候,会为每一个web程序分配一个ServletContext对象,它代表着当前web程序,所有Servlet共享一个ServletContext对象,所以可以通过这个对象来实现Servlet之间的数据传输。
public class HelloServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext servletContext = this.getServletContext();
servletContext.setAttribute("name","芜湖");
}
}
修改HelloServlet,获取他的ServletContext对象,往里添加一个名字为name的属性。然后新建一个新的Servlet,做好上文最中的准备工作,继承HttpServlet,重写需要的方法,在XML里注册Servlet,这里重点介绍一下重写的doGet方法。
public class GetServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext servletContext = this.getServletContext();
String name = (String) servletContext.getAttribute("name");
resp.setContentType("text/html");
resp.setCharacterEncoding("utf-8");
resp.getWriter().print("通过ServletContext传输的数据:"+name);
}
}
首先先拿到了当前Servlet的ServletContext对象,这个ServletContext和HelloServlet类里的ServletContext是同一个对象,然后调用getAttribute,传入属性的名字,就能获得之前在HelloSe里传入的属性,最后还需要设置一下编码,否则中文会乱码。然后重启Tomcat,访问localhost:8080/get。
如果直接访问/get的话,会输出一个null,原因是name的值是在HelloServlet里传入的,直接访问/get的话,name属性里是没有值的,自然只能输出一个null,所以要先访问一次localhost:8080/hello,网页上什么都不会显示,但是会传一个值到ServletContext里,这样就能在GetServlet里获取到了。
RequestDispatcher请求转发
请求转发,顾名思义就是将请求转发到另一个另一个Servlet上,就可以在一次访问里同时调用多个Servlet,RequestDispatcher其实是一个接口,里面只定义了两个方法,分别是include和forward。
修改一下HelloServlet里的doGet方法,在HelloServlet里也输出一些文字,然后调用RequestDispatcher,以forward的方式将请求转发至/get。
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext servletContext = this.getServletContext();
servletContext.setAttribute("name","芜湖");
resp.setContentType("text/html");
resp.setCharacterEncoding("utf-8");
resp.getWriter().println("我是HelloServlet里的数据!!!!!!");
servletContext.getRequestDispatcher("/get").forward(req,resp);
}
重启Tomcat,访问localhost:8080/hello,会发现刚刚设置的文字并没有输出,显示的内容都是GetServlet里的,而且直接输出了具体的值,而不是null,这就是转发请求所导致的。
如果调用的是include方法,就会保留第一个Servlet里的内容。