一、什么是Servlet
servlet是java ee最早提出的web组件模型。Servlet只能运行在java ee的web容器中。
二、Servlet工作流程
1、初始化
每个servlet都对应一个url地址。当Web容器接受对url地址的请求信息后,根据url地址与servlet之间的映射关系将请求转发到指定的servlet来处理。如果该Web容器不存在此servlet的实例,web容器将动态装入并实例化servlet。
2、请求处理
针对客户端的请求,web容器将产生一个新的线程来调用servlet的service() 方法。service() 方法检查http请求类型(GETPOSTPUTDELETE等),然后调用相应的doGet()doPost()doPut()doDelete()等方法。最常见的请求类型是GET和POST。二者区别是:如果以GET请求方式传输,请求参数会直接附加在请求的url上;如果以POST请求方式传输,则参数会被打包在数据包中传送给服务器。
注意:一个servlet同时只有一个实例,并且它在servlet的使用期间将一直保留。当有多个请求发送到同一个servlet时,服务器将会为每个请求创建一个新的线程来处理客户端的请求。
3、退出
当处理完客户端请求后,servlet的实例并不会立即被web容器销毁。只有web应用程序关闭或servlet已经空闲很长时间,web容器才会将servlet视力从内存移除。移除之前web容器会调用servlet的destroy() 方法。
servlet可以使用这个方法关闭数据库连接、中断后台线程、向磁盘写入Cookie列表及执行其他清理动作。注:若web容器出现意外而被关闭,则无法保证destroy()方法被调用。
从上面servlet工作流可以看出,客户端和servlet并没有直接交互,无论客户机对servlet的请求还是servlet对客户端的相应,都是通过web容器来实现的,这确保了servlet组件的可移植性。
web容器的职责归纳为:
- 管理servlet组件的生命周期,负责servlet组建的初始化、销毁等;
- 将请求映射到对应的servlet,并将生成的响应返回给指定的 客户端。
Servlet的工作流充分体现了java ee“组件-容器”的核心编程思想。
三、Servlet API
- HttpServlet:基于web的servlet组件通常继承此接口,完成对客户端请求的处理。
- HttpServletRequest:代表发送到servlet组件的请求。
- HttpServletResponse:代表从servlet组件返回客户机的响应。
- HttpSession:代表在web应用运行过程中用来保存特定客户端状态信息的空间。
- ServletContext:代表servlet组件的运行环境信息。
- ServletConfig:代表servlet组件的配置信息。
- ServletException:代表servlet组件运行过程中抛出的意外对象。
- RequestDispatcher:请求转发器,可以将客户端请求从一个servlet转发到另外其他的服务器资源如其他servlet、静态html页面等。
四、第一个Servlet
编写servlet组件:
- 创建一个实现javax.servlet.http.HttpServlet接口的类。
- 重写doGet() 或doPost()方法,实现对HTTP请求信息的动态响应。
自Java EE5 规范以后,可使用注解代替复杂的配置文件。
下面是个例子:
@WebServlet("/servlet-first") public class Servlet extends HttpServlet { private static final long serialVersionUID = 1L; protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charest=UTF-8"); PrintWriter out = response.getWriter(); out.println("<html>"); out.println("<head>"); out.println("<title>Servlet First</title>"); out.println("</head>"); out.println("<body>"); out.println("<h1>Hello! This is first Servlet!</h1>"); out.println("</body>"); out.println("</html>"); out.close(); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { processRequest(request, response); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { processRequest(request, response); } }
运行tomcat,浏览器打开输入”http://localhost:8080/ServletDemo/servlet-first“即可。
注:在类前定义一个注解@WebServlet,它包含两个属性name和URLPattern,分别用来定义servlet组件的名称和URL模式。当部署此组件时,web容器会根据此注解自动完成对此servlet组件的部署配置。使用注解@WebServlet,需引用javax.servlet.annotation.WebServlet。
五、处理请求
下面是个例子:
<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>处理请求</title> </head> <body> <form name = "form1" method="post" action="getInf"> <table> <tr><td>姓名</td><td><input type="text" name="name"></td></tr> <tr><td>年龄</td><td><input type="text" name="age"></td></tr> <tr><td>出生日期(yyyy-mm-dd)</td><td><input type="text" name="birthday"></td></tr> <tr><td>爱好兴趣</td></tr><tr><td><input type="checkbox" name="checkbox1" value="阅读">阅读 <input type="checkbox" name="checkbox1" value="运动">运动 <input type="checkbox" name="checkbox1" value="音乐">音乐 <input type="checkbox" name="checkbox1" value="美食">美食 </td></tr> </table> <input type="submit" name="Submit" value="提交"> </form> </body> </html>
@WebServlet("/getInf") public class GetInf extends HttpServlet { private static final long serialVersionUID = 1L; protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=UTF-8"); request.setCharacterEncoding("UTF-8"); PrintWriter out = response.getWriter(); try { String name = request.getParameter("name"); String age = request.getParameter("age"); String dateString = request.getParameter("birthday"); SimpleDateFormat format = new SimpleDateFormat("yyyy-mm-dd"); java.util.Date birth = format.parse(dateString); String[] paraValues = request.getParameterValues("checkbox1"); String hobbies = new String(""); for(int i =0; i<paraValues.length;i++){ hobbies += paraValues[i]+""; } out.println("<html>"); out.println("<head>"); out.println("<title>Servlet GetInf</title>"); out.println("</head>"); out.println("<body>"); out.println("<h1>姓名"+ name +"</h1>"); out.println("<h1>年龄"+ age +"</h1>"); out.println("<h1>出生日期"+ birth +"</h1>"); out.println("<h1>爱好"+ hobbies +"</h1>"); out.println("</body>"); out.println("</html>"); } catch (ParseException e) { e.printStackTrace(); } finally{ out.close(); } } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
六、使用Filter过滤请求
除了利用servlet组件直接处理客户端请求外,java ee还提供一个组件来实现对请求信息的过滤处理,称为Filter。与servlet不同,他无法生成对客户端的响应,但filter能够拦截请求和响应,以便查看、提取或以某种方式操作正在客户机和服务器之间的交换数据。filter可以改变一个请求或者修改响应。filter与servlet的关联由web应用的配置文件或注解来明确。
用户发送请求给servlet时,在servlet处理请求前,首先由于此servlet关联的filter执行,然后才是servlet的执行。如果一个servlet有多个filter,则根据配置的前后次序执行。
Filter主要用于以下场景:
- 访问特定资源(web、jsp、servlet)时验证身份。
- 访问资源的记录跟踪。
- 访问资源的转换。
一个Filter必须实现javax.servlet.Filter接口,即实现以下三个方法:
- doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 。用来实现过滤行为的方法。引入的FilterChain对象提供了后续Filter所要调用的信息。
- init(FilterConfig fConfig)。由容器所调用的Filter出师方法。
- destroy() 。
下面是个例子:
@WebFilter(filterName="/IPFilter", urlPatterns={"/*"}) public class IPFilter implements Filter { private FilterConfig fConfig = null; public void destroy() { this.fConfig = null; } public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { String ipAddress = request.getRemoteAddr(); System.out.println("IP" + ipAddress +", Time" + new Date().toString()); chain.doFilter(request, response); } public void init(FilterConfig fConfig) throws ServletException { this.fConfig = fConfig; } }
注:
过滤器有两种映射模式:
- 对URL模式的映射,这也是默认的映射模式。在URL模式中可以试用通配符,如"/*"。
- 对servlet的映射。这时过滤器关联的是servlet的逻辑名称。
与servlet一样,新版本的java ee规范中,提供了注解@WebFilter来部署Filter组件,其属性filterName为Filter的逻辑名称, 属性urlPatterns为Filter的URL模式。
程序包含了Filter必须实现的三个接口方法:init()、destroy()和doFilter()。当容器第一次加载该过滤器时,init()方法被调用。该类这个方法包含了一个指向FilterConfig对象的引用。对请求和响应的过滤功能主要由doFilter()实现。web容器在垃圾收集之前调用destroy()方法,以便能够执行任何必须清理的代码。