Head first:servlet and jsp 笔记

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/l00149133/article/details/78617424
  1. 常用端口:HTTP在TCP的端口80上运行;telnet在端口23,FTP在端口21,SSH(secure shell 远程登录协议)在端口22

  2. CGI:CGI(Common Gateway Interface) 是WWW技术中最重要的技术之一,有着不可替代的重要地位。CGI是外部应用程序(CGI程序)与WEB服务器之间的接口标准,是在CGI程序和Web服务器之间传递信息的过程。CGI规范允许Web服务器执行外部程序,并将它们的输出发送给Web浏览器,CGI将Web的一组简单的静态超媒体文档变成一个完整的新的交互式媒体。
    Common Gateway Interface,简称CGI。在物理上是一段程序,运行在服务器上,提供同客户端HTML页面的接口。这样说大概还不好理解。那么我们看一个实际例子:现在的个人主页上大部分都有一个留言本。留言本的工作是这样的:
    先由用户在客户端输入一些信息,如评论之类的东西。接着用户按一下“发布或提交”(到目前为止工作都在客户端)
    浏览器把这些信息传送到服务器的CGI目录下特定的CGI程序中,于是CGI程序在服务器上按照预定的方法进行处理。在本例中就是把用户提交的信息存入指定的文件中。然后CGI程序给客户端发送一个信息,表示请求的任务已经结束。此时用户在浏览器里将看到“留言结束”的字样。整个过程结束。

  3. web服务器自己不做的两件事:不提供动态内容,不保存数据。这两件事都是通过web服务器辅助应用(可能是CGI或者servlet)来实现的

  4. JSP:把java放到html的解决方案,而不是把html放到java(println)

  5. 什么是容器:servlet没有main()方法,它们受控于另一个java应用,这个java应用称为容器。tomcat就是这样一个容器。如果web服务器应用(如Apache或Nignx)得到一个指向某servlet的请求(而不是其他请求,如请求一个普通的静态HTML页面),此时服务器不是把这个请求交给servlet本身,而是交给部署该servlet的容器。要由容器向servlet提供HTTP请求和响应,而且要由容器调用servlet的方法,如doPost()或者doGet()

  6. Apache,nginx和tomcat的关系和区别(https://www.zhihu.com/question/32212996
    Apache的全称应该叫做Apache HTTP Server,它跟nginx一样,都是一种HTTP Server。HTTP Server本质上也是一种应用程序——它通常运行在服务器之上,绑定服务器的IP地址并监听某一个tcp端口来接收并处理HTTP请求,这样客户端(一般来说是IE, Firefox,Chrome这样的浏览器)就能够通过HTTP协议来获取服务器上的网页(HTML格式)、文档(PDF格式)、音频(MP4格式)、视频(MOV格式)等等资源。
    一个 HTTP Server 关心的是 HTTP 协议层面的传输和访问控制,所以在 Apache/Nginx 上你可以看到代理、负载均衡等功能。客户端通过 HTTP Server 访问服务器上存储的资源(HTML 文件、图片文件等等)。通过 CGI 技术,也可以将处理过的内容通过 HTTP Server 分发,但是一个 HTTP Server 始终只是把服务器上的文件如实的通过 HTTP 协议传输给客户端。
    而tomcat是一个servlet/JSP的容器。是一个应用服务器(application server)。应用服务器,是一个应用执行的容器。它首先需要支持开发语言的 Runtime(对于 Tomcat 来说,就是 Java),保证应用能够在应用服务器上正常运行。其次,需要支持应用相关的规范,例如类库、安全方面的特性。对于 Tomcat 来说,就是需要提供 JSP/Sevlet 运行需要的标准类库、Interface 等。为了方便,应用服务器往往也会集成 HTTP Server 的功能,但是不如专业的 HTTP Server 那么强大,所以应用服务器往往是运行在 HTTP Server 的背后,执行应用,将动态的内容转化为静态的内容之后,通过 HTTP Server 分发到客户端。
    tomcat本身也有HTTP Server的功能。与HTTP Server相比,Tomcat能够动态的生成资源并返回到客户端。Apache HTTP Server和Nginx都能够将某一个文本文件的内容通过HTTP协议返回到客户端,但是这个文本文件的内容是固定的——也就是说无论何时、任何人访问它得到的内容都是完全相同的,这样的资源我们称之为静态资源。动态资源则与之相反,在不同的时间、不同的客户端访问得到的内容是不同的,例如:包含显示当前时间的页面显示当前IP地址的页面Apache HTTP Server和Nginx本身不支持生成动态页面(但它们可以通过其他模块来支持例如通过Shell、PHP、Python脚本程序来动态生成内容)。如果想要使用Java程序来动态生成资源内容,使用这一类HTTP服务器很难做到。Java Servlet技术以及衍生的Java Server Pages技术可以让Java程序也具有处理HTTP请求并且返回内容(由程序动态控制)的能力,Tomcat正是支持运行Servlet/JSP应用程序的容器(Container)
    Tomcat运行在JVM之上,它和HTTP服务器一样,绑定IP地址并监听TCP端口,同时还包含以下职责:管理Servlet程序的生命周期,将URL映射到指定的Servlet进行处理与Servlet程序合作处理HTTP请求——根据HTTP请求生成HttpServletResponse对象并传递给Servlet进行处理,将Servlet中的HttpServletResponse对象生成的内容返回给浏览器
    虽然Tomcat也可以认为是HTTP服务器,但通常它仍然会和Nginx配合在一起使用:动静态资源分离——运用Nginx的反向代理功能分发请求:所有动态资源的请求交给Tomcat,而静态资源的请求(例如图片、视频、CSS、JavaScript文件等)则直接由Nginx返回到浏览器,这样能大大减轻Tomcat的压力。
    负载均衡,当业务压力增大时,可能一个Tomcat的实例不足以处理,那么这时可以启动多个Tomcat实例进行水平扩展,而Nginx的负载均衡功能可以把请求通过算法分发到各个不同的实例进行处理

  7. 容器能提供什么?
    1)通信支持:利用容器提供的方法,你能轻松地让servlet跟web服务器对话。不需要自己建立serversocket,监听端口,创建流等。
    2)生命周期管理。容器会负责加载类,实例化和初始化servlet,调用servlet方法,垃圾回收servlet实例等等
    3)多线程支持:容器会自动为它接收的每个servlet请求创建一个新的java线程。针对客户的请求,如果servlet已经运行完相应的HTTP服务方法,这个线程就会结束。这并不是说不用考虑线程安全,还是会遇到同步问题的,但是这样确实能让你少做很多工作
    4)声明方式实现安全:利用容器,可以使用xml部署描述文件来配置和修改安全性,而不必将其硬编码写到servlet代码中
    5)JSP支持:容器负责把JSP翻译成真正的java

  8. 一个servlet可以有3个名字
    分别是:
    1)用户访问的URL名,用户用户访问,是个虚构的名字,完全为用户提供
    2)开发部署人员命名的内部名称,同样的,这也是个虚拟的名字,只用于部署servlet
    3)servlet实际的文件名,包括类名和包名
    显然,理论上来说,我们可以直接使用servlet的实际文件名,把它硬编码写到所有使用这个servlet的JSP和其他HTML页面中。比如webapp/shop/userServlet.class.
    但是这样会存在几个问题:可维护性和安全性
    实际使用中,是容器来调用servlet,我们配置部署描述文件将URL映射到servlet:

    <servlet>
    <servlet-name>Myservlet</servlet-name> <!-- Myservlet是开发部署人员命名的内部名称,只用于部署servlet -->
    <servlet-class>com.test.app.oneServlet</servlet-class> <!-- servlet的真实文件名,但是不需要加.class后缀 -->
    </servlet>
    <servlet-mapping>
    <servlet-name>Myservlet</servlet-name> <!-- 这里的Myservlet就是上面定义的Myservlet,这样servlet的真实文件就跟url组成了映射关系-->
    <url-pattern>/one</url-pattern>  <!-- /one就是用户访问的URL名,这里是个相对路径,全路径类似http://www.123.com/web/one,这样最终servlet就映射到了/one这个路径-->
  9. 容器会给每个请求(而不是每个servlet)创建一个新的线程,每个servlet都只有一个实例
  10. servlet的生命中期:init()–service()–doGet()/doPost()–destroy()
  11. 幂等(HTTP幂等方法,是指无论调用这个url多少次,都不会有不同的结果的HTTP方法):根据RESTful设计标准,取东西就要GET(GET就是安全的,幂等的,不会修改服务资源),新增就要POST(POST就是不安全的,非幂等的),修改就要PUT(PUT就要幂等),删除就是DELETE(DELETE就要幂等)
  12. forward和redirect的区别:forward不走客户端,地址栏没有变化;redirect走客户端,地址栏改变,客户端会收到301重定向请求
  13. servletConfig可以设定servlet的参数(通过web.xml配置),仅在这个servlet里面可被访问(通过方法:

    getServletConfig().getInitParameter("username")):

    配置:

    <web-app>
    <servlet>
    <servlet-name>Myservlet</servlet-name> 
    <servlet-class>com.test.app.oneServlet</servlet-class>
    <init-param>
    <param-name>username</param-name>
    <param-value>zhangsan</param-value>
    </init-param>
    </servlet>
    </web-app>

    另,spring里的配置:

    <servlet>
    <servlet-name>springmvc</servlet-name>
    <servlet-class>
        org.springframework.web.servlet.DispatcherServlet
    </servlet-class>
    <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/springmvc-servlet.xml</param-value>
        </init-param>
    </servlet>
  14. servletContext可以设定上下文参数(通过web.xml配置),在整个应用里面都可被访问(通过方法:

    getServletContext().getInitParameter("username")):

    配置:

    <web-app>
    <context-param>
    <param-name>username</param-name>
    <param-value>zhangsan</param-value>
    </context-param>
    </web-app>

    另,spring里的配置:

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            /WEB-INF/spring-*.xml
        </param-value>
    </context-param>
  15. ServletContextListener上下文监听者,这个接口有2个方法,分别是contextInittialized(用来监听
    servletContext的初始化)和contextDestroyed(用来监听servletContext的销毁),可以在应用为用户提供服务之前运行一些代码
    ServletContextListener通过web.xml来配置

    <listener>
    <listener-class>
    com.example.MyServletContextListener
    </listener-class>
    </listener>

    另,spring里的配置:

    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
  16. tomcat的热部署(已经在线上的服务不可能重启tomcat来更新)

  17. HTTP是一种无状态连接。浏览器与服务器端建立连接,发出请求,得到相应,最后关闭连接。
  18. 为了识别不同的用户(在不需要用户登录的情况下),容器会在response中发送一个cookie(比如带有唯一标示JSESSIONID)给客户端,客户端会保存这个cookie,然后每次发送请求的时候,在header里面带上这个cookie
  19. 如何让容器发送cookie:
    调用HttpSession session = request.getSession();
  20. 如果客户端禁用cookie:使用url重写,类似http://test.com/shop;jsessionid=00A321DB1
    对应的方法是:

    response.encodeURL("result") //result是你的URL

    对于重定向可以使用 :

    response.encodeRedirectURL("/result");

    只能通过上面的方法来进行url重写,这意味着静态HTML页面无法进行重写,除非你在代码中动态的生成HTML

  21. session的删除:
    1)超时
    2)手动调用invalidate()
    3)应用结束(崩溃or取消部署)
    可以在web.xml里面来配置session的超时时间:

    <web-app> <session-config>
    <session-timeout>15</session-timeout>  <!-- 这里的单位是分钟 --> 
    </session-config> </web-app>
  22. cookie实际上就是在客户端和服务器之间交换的一小段数据(一个键值对)。服务器把cookie发送给用户,用户做出下一个请求时再把cookie返回给服务器。
    默认的,cookie与session的寿命一样长,但是你也可以单独设置。通常我们也会把cookie设置的比较长,这样即便会话结束了,用户再次访问网站时,我们也可以得到用户的一些信息

  23. 对于集群环境(有多个JVM,这些JVM可以在相同的物理主机上–虚拟主机,或者在不同的物理主机上),每个JVM,都将有一个ServletContext,每个JVM上的每个servlet都有一个ServletConfig,但是对于每个web应用的一个给定的会话ID,只有一个HttpSession对象,而不论应用分布在多少个JVM上
    简单点说,对于集群环境,ServletContext和ServletConfig都会复制,而HttpSession只是移动(只有唯一的一份)
  24. 你的JSP最终会变成一个完整的servlet在web应用中运行。它与其他的servlet非常相似,只不过这个servlet类会由容器为你编写。
    容器拿到你在JSP中写的代码,把这些代码转换成为一个servlet类源文件(.java),然后再把这个源文件编译为Java servlet类。在此之后,这就是名副其实的servlet了,而且这个servlet的运行并无特别之处,就好像它的代码都是你自己编写和编译的一样。换句话说,容器会加载这个servlet类,实例化并初始化,为每个请求建立一个单独的线程,并调用servlet的service()方法
  25. 在用户第一次请求某个JSP,jsp文件会被转化成java文件,进而编译成一个class文件,在整个JSP的生命周期中,整个转化和编译步骤只发生一次。JSP一旦得到转换和编译,就跟其他的servlet一样了。
  26. jsp的内置对象(又叫隐含对象,有9个,不需要预先声明就可以在脚本代码和表达式中随意使用),分别是:

    request 请求对象  类型 javax.servlet.ServletRequest 作用域 Request
    response 响应对象 类型 javax.servlet.SrvletResponse 作用域 Page
    pageContext 页面上下文对象 类型 javax.servlet.jsp.PageContext 作用域 Page
    session 会话对象 类型 javax.servlet.http.HttpSession 作用域 Session
    application 应用程序对象 类型javax.servlet.ServletContext 作用域 Application
    out 输出对象 类型 javax.servlet.jsp.JspWriter 作用域 Page
    config 配置对象 类型 javax.servlet.ServletConfig 作用域 Page
    page 页面对象 类型 javax.lang.Object 作用域 Page
    exception 例外对象 类型 javax.lang.Throwable 作用域 page

  27. scriptlet是包含在<% %>之间的Java代码,写在JSP文件中,现在已经被EL(表达式语言,expression language)和JSTL(jsp标准标记库 JSP Standard Tag Library)替代

  28. EL语法:

    ${firstThing.secondThing} or ${firstThing["secondThing"]}

    其中,firstThing可以是EL隐式对象或者属性

  29. EL函数:
    1)使用TLD标记库描述文件(扩展名为.tld,放在/WEB-INF目录下,提供了定义函数的java类与调用函数的jsp之间的一个映射)
    2)使用taglib来引用对应的TLD文件
    3)使用EL调用函数
  30. JSTL常用标记:

    <c:out>
    <c:forEach>
    <c:if>
    <c:choose><c:when><c:otherwise>
    <c:set>
    <c:import> 类似<jsp:include>
    <c:url>
    <c:catch>
  31. EL提供的更多是一个对象或者一个函数,而JSTL提供的更多的是一个逻辑(比如if else)

  32. war文件:去掉web应用上下文目录,也就是把WEB-INF之上的一级目录去掉后,把整个web应用结构压缩起来。
    不过有个问题,如果没有包括特定的web应用目录(例如cnzzdata),容器怎么知道这个web应用的名称/上下文呢?
    这取决于你的容器。在tomcat中,war文件的文件名就会成为web应用的名字。
  33. 应用部署为war时,唯一的新东西是META-INF目录(在根目录下,其中包含一个MANIFEST.MF文件)。你自己可能不会在META-INF目录中放任何东西,所以不用关心应用是否部署为一个war,除非你确实需要在MANIFEST.MF文件中指定库依赖性
  34. WEB-INF下的html和jsp是不可以直接访问的(META-INF也是如此)
  35. dd配置默认页面:welcome-file-list.需要注意的是:
    1).welcome-file-list可以配置多个默认页面,比如:

    <web-app>
    <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>default.jsp</welcome-file>
    </welcome-file-list>
    </web-app>

2).配置多个默认页面的意义在于,对于不同目录的请求,会在该目录下顺序查找默认页面列表里的页面
比如按照1中的配置,如果login目录中有index.html文件,也有default.jsp文件,当你请求:
http://localhost:8080/webtest/login的时候,会跳转到index.html
而如果search目录中只有default.jsp文件,当你请求:http://localhost:8080/webtest/search的时候,会跳转到default.jsp
36. 默认的,servlet会在每一个请求到来时初始化。但是可以通过在dd中配置来完成在部署时加载servlet:

<load-on-startup>1</load-on-startup> <!-- 只要这个值大于0,就表示“在部署或者服务器启动时初始化这个servlet”,而这个值的大小决定了它的启动顺序(与我们常识相反,1是最先加载的,数字越大越往后)-->

37. web应用安全:
假冒者,非法升级者和窃听者
认证,授权,机密性和数据完整性
38. tomcat有tomcat-users.xml文件,但是它并不在web应用的目录中,而是在tomcat的conf/目录下。而且它应用于tomcat下部署的所用应用。所以在生产阶段我们通常不会用tomcat自身的认证机制,其中一个原因是,如果不重启tomcat就无法修改认证内容
39. 过滤器Filter(面向切面)
请求过滤器可以:
完成安全检查
重新格式化请求首部或者请求体
建立请求审计或日志
相应过滤器可以:
压缩响应流
追加或修改响应流(比如增加水印)
创建一个完全不同的响应
40. 过滤器的生命周期:
1)首先要有一个init()来初始化
2)真正的工作在doFilter()中完成
3)最后是destroy()
41. doFilter的3个参数:
1)ServletRequest(而不是HttpServletRequest)
2)ServletResponse(而不是HttpServletResponse)
3)FilterChain(filter链,你可以理解为它是一个filter管理器或驱动。过滤器并不知道请求所涉及的其他过滤器,也就是说过滤器之间互相是不知道的,servlet更是不知道所有过滤器的存在,但是总有人要知道过滤器的执行顺序,这个人就是FilterChain。另外filterChain的doFilter()方法负责明确接下来调用那个filter的doFilter()方法)
引用doFilter()方法的代码:

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws

ServletException, IOException{
chain.doFilter(request, response); //顺序执行过滤器,最后调用servlet
}
42. 声明过滤器

<filter>
<filter-name>BeerRequest</filter-name>
<filter-class>com.example.wen.BeerRequestFilter</filter-class>
<init-param>
<param-name>LogFileName</param-name>
<param-value>UserLog.txt</param-value>
</init-param>
</filter>

声明对应URL模式的过滤器映射(有点类似servlet的声明和映射)

<filter-mapping>
<filter-name>BeerRequest</filter-name>
<url-pattern>*.do</url-pattern> <!-- 所有.do的资源都要使用这个过滤器-->
</filter-mapping>

也可以不对应URL,而是对应特定的servlet声明映射:

<filter-mapping>
<filter-name>BeerRequest</filter-name>
<url-pattern>*.do</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>INCLUDE</dispatcher>
<dispatcher>FORWARD</dispatcher>
<dispatcher>ERROR</dispatcher>
</filter-mapping>

还可以对转发,包含,请求分发或者错误处理进行声明过滤器映射(不是所有的请求都来自于客户,还可能来自于转发,或者程序跳转到错误页面,或者你在代码中应用了include等等非用户请求的所有资源):

<filter-mapping>
<filter-name>BeerRequest</filter-name>
<dispatcher>REQUEST</dispatcher> <!-- REQUEST表示对客户请求启用过滤器(其实默认就是启用的)-->
<dispatcher>INCLUDE</dispatcher> <!-- INCLUDE表示对由一个include()调用分发来的请求启用过滤器 -->
<dispatcher>FORWARD</dispatcher> <!-- FOWARWD表示对由一个forward()调用分发来的请求启用过滤器 -->
<dispatcher>ERROR</dispatcher> <!-- ERROR表示对错误处理器调用的资源启用过滤器 -->
</filter-mapping>

43. 响应过滤器:
原理:修改chain.doFilter(request, response)中,传递给servlet的response,而得到预期内的响应
修改response可以通过包装器(wrapper):

//包装器,继承自HttpServletResponseWrapper系统自带包装器
class TestResponseWrapper extends HttpServletResponseWrapper{
//覆盖你想定制的方法
}
class MyFilter implements Filter{
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain){
TestResponseWrapper warpper = new TestResponseWrapper(response); //用包装器包装响应
chain.doFilter(request, warpper);
}
44. 包装器的一个例子(实现压缩器)
class TestResponseWrapper extends HttpServletResponseWrapper{
public ServletOutputSteam getOutputStream() throws…{
servletGzupOS = new GzipSOS(resp.getOutputStream()); //这里resp.getOutputStream()是原本response的输出流,我们替换成自己的GZIP流,来改变响应,达到响应过滤的目的
return servletGzupOS;
}
}
45. JNDI:java命名和目录接口(java naming and directory interface),这是一个访问命名和目录服务的API。基于JNDI,可以在网络中的一个集中位置上完成查找。如果你有一些对象,而且希望网络上的其他程序找到并访问这些对象,就要向JNDI注册这些对象。其他程序想使用你的对象时,则可以使用JNDI来查找
46. RMI:远程方法调用(remote method invocation)
47. 所谓远程调用,指的是你要调用的对象在另一个JVM中

猜你喜欢

转载自blog.csdn.net/l00149133/article/details/78617424