#Servlethtml
- 编写一个Java类,实现servlet接口
- 把开发好的Java类部署到web服务器中
###demo:使用servlet给浏览器输出“Hello World!~”java
使用UML描述Servlet的调用过程web
###Servlet的生命周期 Servlet会在第一次被访问的时候建立出相应的Servlet对象,为了方便后续请求的访问,Web容器建立一个Servlet对象后,会一直将其保存在容器中,之后关于该Servlet的请求,都使用该对象处理,一直不会被销毁,直到web容器关闭。也就是说,在一个Servlet运行的过程当中,web容器中有且只有一个该Servlet对象存在,多个请求使用多线程来分别处理,一个请求对应一个线程,多个请求多个线程(Tomcat会给每一个线程建立对应的request对象和response对象,一块儿交给Servlet对象),这些线程共享Servlet对象!能够得出一个结论:Servlet是非线程安全的,可是request对象和response对象是线程安全的数据库
Servlet的生命周期演示(init方法与destroy方法)设计模式
###使用Eclipse开发Servletapi
###HttpServlet HttpServlet指得是可以处理HTTP请求的serlvet,它在原有的Servlet接口上添加了一些HTTP协议处理的方法,它更增强大,在开发中一般继承这个类。 HttpServlet在实现Servlet接口时,重写了service方法,该方法内部会自动判断用户的请求方式,好比是get请求,则会调用HttpServlet的doGet方法,post请求,调用doPost方法。 在开发中,直接覆盖doGet和doPost方法,不用覆盖service方法。浏览器
阅读HttpServlet文档,查看HttpServlet源码(ctrl+shift+T) 使用Eclipse建立一个新的Servlet,继承HttpServlet,直接建立Servlet,自动生成配置(一个Servlet能够配置多个映射)缓存
#Servlet细节总结安全
**Servlet若是想要外部访问,必须把Servlet程序映射到一个URL地址上,在web.xml中使用`<servlet>`元素和`<servlet-mapping>`元素完成** >`<servlet>`元素用于注册Servlet,它包含两个子元素:`<servlet-name>`和`<servlet-class>`,分别用于注册Servlet的注册名称和Servlet的完整类名 >`<servlet-mapping>`元素用于映射一个已经注册的Servet对外访问路径,它包含两个子元素:`<servlet-name>`和`<url-pattern>`,分别用于指定注册名和对外访问路径
用一个Servlet能够被映射到多个URL上服务器
在Servlet映射到的URL,可使用通配符来配置,可是只能有两种固定的格式: > *
“ * . 扩展名”,如: *.do,*.html(伪静态)
> *"/* ",如:/action/*
使用了通配符后,就会产生一些新的问题,以下:
那么当这样通配后,对于类似的URL请求会怎么去处理呢?举例来讲明: * `/abc/a.html,/abc/* 和 /* 都匹配,Servlet引擎将会调用Servlet1` * `/abc,/abc/* 和 /abc 都匹配,Servlet引擎将会调用Servlet3` * `/abc/a.do,/abc/* 和 *.do 都匹配,Serlvet引擎将会调用Servlet1` * `/a.do,/* 和 *.do 都匹配,Servlet引擎将会调用Servlet2` * `/xxx/yyy/a.do,/* 和 *.do 都匹配,Servlet引擎将会调用Servlet2` \*号开头的优先级最低!不以\*开头的话,哪一个最像选择哪一个
Servlet是不能独立运行的,它的运行彻底是由Servlet引擎来控制和调度的。一个Servlet若是被访问,无论访问多少次,Web容器中以后一个Servlet对象,被多个请求(线程)共享,可是每次执行service方法,都是根据此次请求从新建立的请求对象和响应对象。当本次请求完成,请求对象和响应对象都会被销毁(响应对象的销毁在建立了标准的Http响应以后)。
<serlvet>
元素能够配置随着web容器的启动而建立该Servlet对象。使用<load-on-startup>
元素来完成,在建立过程当中,就会调用Servlet的init方法。若是有一些操做须要在服务 器启动的时候就完成,就可使用这种方式来完成(初始化数据库链接池等)。
若是某个Servlet的映射路径为 "/",那么这个Servlet就是当前web应用的默认Servlet。凡是在web.xml中找不到映射的URL,它们的访问请求都将交给这个默认的Servlet处理,也就是说,默认的Servlet用于处理全部其它Servlet都不处理的请求。
其实对于Tomcat来讲,咱们全部的请求都不能直接到达web资源,都会通过一个Servlet。如:http://localhost:8080/testweb/1.html ,若是项目根目录有一个 1.html 文件 是能够请求的到的,但其实,并非直接访问了该资源,Tomcat有一个默认的Servlet,由这个默认的Servlet读取了这个资源,而后返回给客户端。若是没有,就是404 若是你自定义了默认的Servlet,将会覆盖掉系统的默认Servlet,因此不建议这么作。(查看Tomcat的web.xml,其实全部的静态资源,都由该Servlet处理)
线程安全
Servlet存在线程安全问题,在实际开发中,要根据具体状况来编写解决同步的代码 在Servlet中编写程序时,要注意对象的静态属性的处理,否则会引起内容溢出的问题(对象的静态集合属性处理) 标准解决方案:同步代码块。非标准解决方案:SingleThreadModel(已经被废弃) 对于Servlet的线程安全问题,的确是一个比较灵活的问题,那么有如下几条开发建议,能够避免Servlet的线程安全问题: 1. 尽可能避免使用成员变量,若是万不得已使用了,就须要同步,可是注意同步可用性最小的代码路径 2. 要清楚request是线程安全的,HttpSession,ServletContext都不会线程安全的 3. 使用同步的集合类 4. 不要在Servlet中建立本身的线程来完成某个功能(增长了复杂度) 5. 在多个servlet中对外部对象(好比文件)进行修改操做时,必定要加锁,作到互斥的访问效果
#ServletConfig对象
<init-param>
标签为servlet配置一些初始化参数#ServletContext对象(重点)
getServletContext()
来获取ServletContext对象)###MVC简单介绍 到目前为止,对于客户端的请求,咱们都是使用对应的Servlet来作简单处理,可是问题是,通常的,不可能就简单在返回一个字符串或者在控制台打印一个语句,应该给客户返回一个html页面,那么这个html页面哪里来?若是这个html是个静态资源,那么很简单,可是咱们开发的是动态web资源,该怎么办呢?其实很简单,使用Servlet的response对象发送html的字符流给客户端。这种方法表面上看起来是没有什么问题,可是实际操做你就会发现,这个作法至关麻烦,并且开发效率很低,应该专门有一种特殊能力的Servlet来处理html的绘制,这种具备特殊能力的Servlet就是JSP。
JSP其实就是一个特殊的Servlet,它能很好的处理html的问题,使得页面的渲染与程序逻辑的处理能够得以分离。(demo,在Servlet中传值并转发给一个JSP)
#在Servlet中获取各类资源文件(重点)
在实际开发中,不少时候须要获取服务器上的一些别的资源来帮助开发,这些资源的获取方式都不太同样。
若是在开发中,须要的文件存储在WebContent(项目目录)中,那就使用ServletContext来读取,相关的方法有:
getRealPath(String path),返回一个虚拟路径对应资源的真实路径
getResource(String path),返回一个虚拟路径对应资源的URL对象
getRescourceAsStream(String path),返回一个虚拟路径对应资源的输入流
getResoucePaths(String path),返回一个虚拟路径下的全部对应资源的集合
这些方法中的参数都不该该是资源的绝对路径或相对路径,应该是一个针对当前应用的虚拟路径,应该以 “/” 开头,这个 "/" 就表示web应用所在目录,也成为项目根目录,而后按照资源在应用的目录结构来指定资源的虚拟路径。
在不少时候,咱们的资源文件并不在Web资源目录中,而是在类目录中,这个时候怎么读取呢?
使用类加载器来获取类路径中的资源:getSystemResource(String path),getResource(String path)
使用类自己来获取类路径中的资源:getResource(String path)
使用ServletContext获取项目根目录,而后按照项目层级去读取文件(WEB-INF/classes/a.txt)
- 根据类加载器来获取资源时,不要添加 "/",类加载器会从该加载器的类路径根目录来查找 path 指定的资源,加了 "/",反而找不到。
- 使用类自己来获取资源时,加 "/" ,意味着从类路径的根目录来查找,不加 "/",意味着,从当前类所在的文件夹来查找资源
- web应用和本地方法运行的效果是不同的,有关于System的资源获取,在web应用中是不起做用的
- 还有 getResourceAsStream(String path)系列的方法,跟上述的 getResource(String path)方法特色是一致的,只不过一个是返回URL对象,一个是返回流对象
- 使用类加载器的 getResourceAsStream(String path) 方法来获取资源的输入流时,不能实现动态读取文件变动,应该用类加载器来获取路径,而后用传统的读取文件的方式再次读取文件,这样就能实现实时更新数据了
- 若是资源文件过大,不要使用类加载器的方式来直接获取,由于这种方式会直接把资源所有加载进内存,容易内存溢出,使用类加载器获取地址,用传统方式的流而后缓冲读取
- 关于System与no-System的方法有什么区别,我已经总结好了,若是须要进一步了解,参看官方关于Resources的解释
#在客户端缓存Servlet的输出 对于不常常变化的数据,在Servlet中能够为其设置合理的缓存时间值,以免浏览器频繁得向服务器发送请求,提高服务器的性能。
String data = "aaaaaaaaaaaaaaaaaaaaaa"; long time = System.currentTimeMillis() + 1 * 24 * 60 * 60 * 1000; System.out.println("hehe"); response.setDateHeader("expires", time); response.getWriter().write(data);