《Head First Servlet&JSP》读书笔记
自己最近在看《How Tomcat Works》这本书。Tomcat是Servlet容器,在这本书里面大量使用到了Servlet,但是自己对Servlet不是好清晰,所以花了2天时间读了这本书。
1. 概述
1.1 总结
总体的来说,《Head First Servelt&JSP》这本书还是非常不错的,对Servlet&Jsp介绍的挺细的且有主次区分,让人理解起来轻松。因为《Head First》系列都是通过半漫画形式讲解,所以书较厚,不过读起来轻松。因为自己之前就了解Servelt&Jsp,所以读起来挺快的。
1.2 目录
- 为什么使用Servlet&Jsp
- Web应用体系框架
- MVC迷你教程
- 作为Servlet
- 作为Web应用
- 会话状态
- 作为JSP
- 没有脚本的页面
- 强大的定制标记
- JSTL也有力不及的时候...
- 部署Web应用
- 要保密,要安全
- 过滤器的威力
- 企业设计模式
自己看了第1、2、3、4、5、6、7、11、13、14章。关于JSP方面自己看的较少,一来自己觉得现在流行前后端分离,使用JSP技术应该越来越少;二来自己就不喜欢类型View方面的东西,还是喜欢代码 ^ - ^
1.3 章节解释
第一章(为什么使用Servlet&Jsp):主要解释了Web客户端、服务器做了什么,以及它们之间的通信:HTTP协议。
第二、三章(Web应用体系框架、MVC迷你教程):个人觉得这一章讲的挺好的,也挺有用的。尤其对于知道怎么使用Servlet&Jsp或者使用Servlet框架(SpringMVC或Struts2),它将会让你了解整个Java Web的大体框架。如:一个HTTP请求的大体流程是什么样的;Web.xml的作用;为什么Web-INFO下是安全目录等等。
第四章(作为Servlet):主要讲了Servlet的生命周期、Servlet如何处理请求等等。
第五章(作为Web应用):主要讲了ServletConfig与ServletContext、8个监听器的使用、以及4个对象(ServletContext、ServletRequest 、ServletResponse、HttpSession)的生命周期、线程安全、作用域等等。
第六章(会话状态):主要讲了会话如何工作、如何创建、如何添加属性等等。
第七章(作为JSP):主要讲了JSP与Servlet的关系,一些JSP的基本用法等等。
第十一章(部署Web应用):主要讲了把Java Web项目部署到Servlet容器中使用(如Tomcat),与第一二章食用更佳。
第十三章(过滤器的威力):主要讲了Servlet中的Filter(过滤器)的使用。
第十四章(企业设计模式):讲了讲企业开发中的一些组件、以及Struts的MVC模式(有点老了,现在版本与它说的都不一样了)。
2. 一些总结吧
2.1 什么是容器?
容器是用来部署Servlet的容器,处理一切与Servelt相关的请求。如果Web服务器应用(如Apache)得到一个指向Servelt的请求(而不是其它请求,如请求静态资源),这时服务器会把该请求交给部署该Servlet的容器,由容器向Servlet提供请求与响应对象,调用Servlet的service()方法处理请求。注:Tomcat实际上Web服务器与Servlet容器的结合体,它既处理静态资源请求,也处理Servelt请求。
2.2 容器能提供什么?
- 通信支持:Servlet不直接与客户端通信,而是由容器与客户端进行通信。所以Servlet中只需要写业务逻辑(解耦)。
- Servlet生命周期的管理:注每个Servlet在容器中只有一个实例。
- 多线程的支持:容器会自动为每个请求分配一个线程,并处理它。
- JSP的支持:会把JSP自动编译为Servlet,并管理它。
2.3 容器如何管理Servlet
- 容器会加载web.xml文件初始化一些信息(如Servelt与URL的对应关系),信息保存在ServletContext对象中。也就是说一个web.xml对应一个ServeltContext对象。
- 容器会在请求到来之前实例化Servlet并初始化一些信息,可通过loadOnStartup字段配置什么时候实例化Servelt。
- 容器调用Servelt的init()方法处理化一些信息,如配置Servlet时的init-Param信息。这些信息在ServletConfig对象中。也就是说每个Servlet都有自己对应的ServletConfig对象。
- 容器会在请求到来时创建一个ServletRequest、ServletResponse对象,分配一个线程,调用对应的Servlet对象的service()方法进行处理。注意:Servlet只有一个对象实例,容器会为每个请求分配线程并调用Servlet的service(ServletReqeust req, ServletResponse resp)方法进行处理。
- 容器调用Servlet的destory()方法进行销毁Servlet。
2.4 ServletContext与ServletConfig
- ServeltContext应该叫做WebContext更好,它代表一个Web程序的上下文。我们可以在web.xml文件中context-param字段中初始化一些数据,但这些数据是线程不安全的。
- ServletConfig代表Servelt配置的一些信息。其在Servlet的init(ServletConfig config)方法中进行初始化。在SSM框架中,我们就会在DispatcherServlet配置中初始化所有的spring容器中的对象。如下:
1 <!-- 配置DispatcherServlet --> 2 <servlet> 3 <servlet-name>seckill-dispatcher</servlet-name> 4 <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> 5 <!-- 配置springMVC需要加载的配置文件 6 spring-dao.xml spring-service.xml spring-web.xml 7 mybatis -> spring -> springMVC--> 8 <init-param> 9 <param-name>contextConfigLocation</param-name> 10 <param-value>classpath:spring/spring-*.xml</param-value> 11 </init-param> 12 <load-on-startup>1</load-on-startup> 13 </servlet> 14 <servlet-mapping> 15 <servlet-name>seckill-dispatcher</servlet-name> 16 <!-- 默认匹配所有的请求 --> 17 <url-pattern>/</url-pattern> 18 </servlet-mapping>
2.5 Servlet
- Servlet的生命周期可以看上面的:容器如何管理Servlet。
- Servlet处理请求时,容器通过调用其service()方法来处理请求,而service()方法通过查询Http的请求方法来调用对于的Servlet方法,如GET-->doGet(),POST-->doPost()。所以我们写Servlet时,需要继承HttpServlet,然后重写其doGet()、doPost()或doDelete()等方法,具体要看该Servlet处理什么请求方法。
注:Servlet需要在web.xml中注册
2.6 请求与响应
- 容器会在HTTP请求到来时创建ServletRequest、ServletResponse对象。请求的所有信息都会保存在ServletRequest对象中,具体看它的API。响应的信息(包括响应头)都会写入ServletResponse对象。注:我们在使用ServletResponse对象直接发送给客户端消息时,必须设置Content-Type信息,否则客户端不能够解析该信息。

1 @WebServlet(loadOnStartup=1, urlPatterns={"/test"}) 2 public class TestServlet extends HttpServlet { 3 @Override 4 protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 5 HttpSession session = req.getSession(); 6 Map<String, String[]> map = req.getParameterMap(); 7 System.out.println("HTTP Query String:"); 8 for (Map.Entry<String, String[]> entry : map.entrySet()) { 9 System.out.print("key: " + Arrays.toString(entry.getValue())); 10 System.out.println(" value: " + Arrays.toString(entry.getValue())); 11 } 12 String content = "<html> " + 13 "<head> " + 14 "</head> " + 15 "<body> " + 16 "Hello World" + 17 "</body> " + 18 "</html>"; 19 PrintWriter writer = resp.getWriter(); 20 resp.setContentType("text/html"); 21 writer.write(content); 22 writer.flush(); 23 writer.close(); 24 } 25 } 26 ----------萌萌的分割线--------- 27 Request: 28 GET /test?id=10086&name=kanyuxia HTTP/1.1 29 Host: localhost:8080 30 Connection: keep-alive 31 Cache-Control: max-age=0 32 Upgrade-Insecure-Requests: 1 33 User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.110 Safari/537.36 34 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8 35 Accept-Encoding: gzip, deflate, sdch, br 36 Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.6,en;q=0.4 37 Cookie: JSESSIONID=jp3o7r8iufda1c2dykdfzlk5t 38 39 ----------萌萌的分割线-------- 40 Response: 41 HTTP/1.1 200 OK 42 Date: Wed, 19 Apr 2017 07:39:58 GMT 43 Content-Type: text/html;charset=ISO-8859-1 44 Transfer-Encoding: chunked 45 Server: Jetty(8.1.14.v20131031) 46 Request Headers 47 view parsed 48 49 <html> 50 <head> 51 </head> 52 <body> 53 Hello World</body> 54 </html> 55 ----------萌萌的分割线--------- 56 server console: 57 HTTP Query String: 58 key: [kanyuxia] value: [kanyuxia] 59 key: [10086] value: [10086]
2.7 重定向与转发
- Servelt中的重定向可以使用HttpServletResponse的sendRedirect()方法,该方法相当于在响应头部中设置响应码301、响应头中的Location字段为重定向字段。
- Servlet转发通过HttpServletRequest的getReqeustDispatcher()方法获得RequestDispatcher对象,然后通过该对象转发请求与响应对象。
具体使用可以看:《Spring实战》读书笔记--SpringMVC之forward与redirect
2.7 监听器
Servlet中有8下监听器,如下:
监听器接口 | 事件类型 |
---|---|
ServletContextListener | ServletContextListener |
ServletContextAttributeListener | ServletContextAttributeEvent |
HttpSessionListener | HttpSessionEvent |
HttpSessionBindingListener | HttpSessionBindingEvent |
HttpSessionAttributeListener | HttpSessionBindingEvent |
HttpSessionAcctivatioinListener | HttpSessionEvent |
ServletRequestListener | ServletRequestEvent |
ServletRequestAttributeListener | ServletRequestAttributeEvent |
具体使用看API吧。注:监听器需要在web.xml中注册
1 @WebListener(value="TestListener") 2 public class TestListener implements HttpSessionListener { 3 public void sessionCreated(HttpSessionEvent se) { 4 HttpSession session = se.getSession(); 5 System.out.println("服务器创建了HttpSession, Session Id 为:" + session.getId()); 6 } 7 public void sessionDestroyed(HttpSessionEvent se) { 8 HttpSession session = se.getSession(); 9 System.out.println("服务器销毁了HttpSession, Session Id 为:" + session.getId()); 10 } 11 } 12 ----------萌萌的分割线--------- 13 response: 14 Content-Type:text/html;charset=ISO-8859-1 15 Date:Wed, 19 Apr 2017 07:44:56 GMT 16 Expires:Thu, 01 Jan 1970 00:00:00 GMT 17 Server:Jetty(8.1.14.v20131031) 18 Set-Cookie:JSESSIONID=km2ogboi1e8i184272wq13myz;Path=/ 19 Transfer-Encoding:chunked 20 21 ----------萌萌的分割线--------- 22 server console: 23 服务器创建了HttpSession, Session Id 为:1ttrgbo9io8gs11o9vwic1zvwx
2.8 Session与Cookies
Http协议是无状态协议,不能都保存相关信息。所以创建了Cookies、Session来保存相关信息。
- Cookies是保存在保存在客户端的信息,每次Http请求都会把该URL下的所有Cookies发给服务器,服务器可以访问。但其不安全,因为保存在客户端,用户可以自行删除。服务器可以在响应头的Set-Cookies字段中设置Cookies。
- Session可以对同一个客户在一定时间内保存一些信息。Session信息保存在服务器上面的,所以安全。Session是基于Cookies的,服务器第一下使用Session时,会给客户端发送Set-Cookies: JSESSIONID=***,设置一个SessionId。以后每次客户端发送请求都会发送该Cookies该服务器,所以服务器就知道该请求是谁的请求。
- Servlet中HttpSession对象表示会话对象,我们可以HttpServletRequest对象的getSession()方法获得HttpSession对象,然后可以使用其方法处理相关逻辑。具体可以查看HttpSession的API。
- HttpSession可以设置时间来控制其生命周期,也可以在web.xml中配置默认的HttpSession生命周期长度。
2.9 JSP
- JSP会被容器自动转换、编译为Servlet类,所以其与Servlet类没有多大的区别。
3.0 过滤器 Filter
我们可以配置Filter拦截请求,Filter与Struts2中的Intercept原理一样。注:需要在web.xml中注册
- FilterChain类型于栈。Filter在调用FilterChain的doFilter()方法之前拦截请求,之后拦截响应。
- 如果直接给Servlet传递ServletResponse对象,Servlet响应会直接返回给客户端,不会经过Filter。所以如果要拦截响应,则需要FilterChain的doFilter()方法传递HttpServletResponseWrapper对象,最后响应才会进过Filter。其中:HttpServletWrapper使用了装饰器设计模式。
1 @WebFilter(urlPatterns = "/*") 2 public class EncodeFilter implements Filter { 3 public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)throws IOException, ServletException { 4 request.setCharacterEncoding("UTF-8"); 5 chain.doFilter(request, response); 6 } 7 public void destroy() { 8 } 9 public void init(FilterConfig arg0) throws ServletException { 10 } 11 }