EL和JSTL和MVC思想

EL

EL:表达式语言

EL概述和基本使用

目的:获取作用域中的共享数据

EL的内置对象

JSTL

JSTL概述和准备

逻辑判断标签(if、choose)

循环迭代标签(foreach)

时间格式化标签(formateDate)

MVC思想

Model1

  • JSP + JavaBean开发也称作JSP模式一(以JSP为中心的设计模型)
  • 此方法适合于快速开发
  • JSP不仅仅负责输出页面,还处理请求,没有体现责任分离原则

Model2

  • 模式二又叫做以Servlet为中心的设计模型
  • 适合于团队开发,用此模式开发,速度相对较慢但可维护性高

体现出了责任分离思想:

JSP:界面输出
Servlet:

  • 接收请求参数
  • 调用业务方法,处理请求
  • 控制页面跳转

JavaBean:封装业务操作,可重复使用

MVC模式

目的:责任分离,把业务代码从视图中剥离出来

M(Model):模型对象(封装业务操作、算法、可重复使用、JavaBean)
V(View):视图(界面、JSP、HTML等)
C(Controler):控制器(控制页面跳转、Servlet)

Model1、2其实和MVC本质相同,MVC含义更广

在Web中,必须先有请求,而后才有响应

JSP技术和JavaBean规范

JSP

JSP概述

JSP:Java Server Pages(Java的服务网页)

Servlet的缺陷:

  • 输出动态网页,恶心
  • 没有体现责任分离思想(谁最擅长做什么,就应该最什么!)

实现动态网页的技术:

  • Servlet:Java代码(主) + html片段(辅)
  • JSP: Java代码(辅) + html页面(主)

责任分离思想:

Servlet擅长:

  • 接收请求参数,封装对象
  • 调用业务方法处理请求
  • 控制页面跳转 --> JSP/html

JSP擅长:页面输出

JSP原理

所有以.jsp作为后缀的请求都交给JspServlet处理;

JspServlet类负责把JSP翻译成Servlet。

因此,得出结论:JSP本质就是Servlet。

JSP基本语法;
JSP三大指令;
JSP九大内置对象;
JSP四大作用域;
JSP动作元素。

JavaBean规范

JavaBean概述

JavaBean是一种JAVA语言写的可重用组件(类),必须遵循一定的规范:

  • 类必须使用public修饰;
  • 必须保证有公共无参数的构造器;
  • 包含了属性的操作方法(设置属性值,获取属性值);、

JavaBean分类:

  • 复杂JavaBean:有用户界面,比如Button、Panel、Window类等
  • 简单JavaBean:没有用户界面,主要用于封装数据,操作数据库,逻辑运算等。
    一般的,我们说的JavaBean就指这一种,比如domain、dao、service组件等

JavaBean包含的成员:

  • 方法:Method
  • 事件:Event
  • 属性:property

getter()/setter/isXxx()

JDK的自省机制

内省机制(Introspector),操作(获取/设置)JavaBean中的方法/事件/属性。核心类:java.beans.Intrispector

企业中经常会把JavaBean转换为Map,或把Map转为JavaBean

Web组件跳转和数据共享

共享控制

请求转发(forward)

  • 一个Servlet接收到了请求,转发给另一个Servlet来负责部分或全部的请求处理
  • 对于请求转发来说这里强调的时Request对象,这两个Servlet使用的是同一个Request对象
  • Servlet使用javax.servlet.RequEstDispather.forward()方法来转发它所收到的HTTP请求。转发的目标Servlet负责生成响应结果,或将请求继续转发到另一个Servlet
  • 第一个Servlet生成的ServletRequst和ServletResponse对象被传递给下一个Servlet

请求转发可以访问到WEB-INF下的资源

URL重定向

URL重定向是第一次请求的响应码为302并且响应头中有Location,那么浏览器将根据Location的地址发出第二次请求。

请求转发和URL重定向的区别

转发 重定向
地址栏的变化 在地址栏内看不到路径的变化,在服务器端进行 在地址栏内可以看见路径的变化,在客户端进行
/ 的含义 表示当前WEB应用的根路径 WEB站点的服务器根路径, 重定向的页面不局限于当前的WEB应用,可以是外部的站点
可连接的资源 只能连接到当前WEB应用的资源 当前WEB应用的资源和外部的资源
访问WEB-INF下的资源 可以 不可以
向服务器发出的请求数 一次请求,共享页面的request对象 两次请求,不共享页面的request对象

提示:

  • 如果第二个Servlet不需要第一个Servlet接收到的请求数据,那么URL重定向和请求转发都可以用
  • 如果第二个Servlet要使用到第一个Servlet接收的请求数据,那么必须使用请求转发,保证两个Servlet共享一个Request对象

Include

Servlet类使用RequestDispatcher.inclide()方法包含其他的Web组件。对于包含来说这里强调的是Response对象,将响应输出的内容合并后输出。

共享信息

  • 在一个综合的web应用系统中,各个组件通过共享对象来交换数据,就叫web应用开发中的信息共享
  • 在JavaWeb应用中,通常使用四个共享对象(四个作用域):pageContext、request、session、servletContext

相同点:他们都有相同的存储方法

  • setAttribute(String name,Object value);
  • getAttribute(String name);
  • getAttributeNames();
  • removeAttribute(String name);

区别:共享范围

  • pageContext(PageContext):相同一个页面
  • request(HttpServletRequest):相同一次请求
  • session(HttpSession):相同一次会话
  • ServletContext(ServletContext):整个web应用的生命周期

ServletContext对象

Servlet容器在启动时会自动加载Web应用,并为每个Web应用创建唯一的ServletContext对象,可以把ServletContext看成是一个Web应用服务器端共享内存,在ServletContext中可以存放共享数据,它提供了4钟读取或设置共享数据的方法

  • setAttribute(String name,Object value);
  • getAttribute(String name);
  • getAttributeNames();
  • removeAttribute(String name);

获取ServletContext对象的四种方式:

//1.先得到servletCongig对象,然后在得到ServletContext
ServletContext servletContext = getServletConfig().getServletContext();
//2.直接得到
servletContext = getServletContext();
//3.从Session对象中得到
servletContext = request.getSession().getServletContext();
//4.可以直接从request上得到。只不过它是3.0的方法
servletContext = request.getServletContext();

ServletContext在服务器启动的时候被创建,那么可以提前通过web.xml配置一些全局初始化参数

<context-param>
    <param-name>xxxx</param-name>
    <param-value>XXXXXXXXXXXXXXXXXXXXXX</param-value>
</context-param>

ServletContext对象提供了以下两个获取初始化参数的方法:

  1. getInitParameter(String name)
  2. getInitParameterNames()

其他方法看API

Cookie和Session

Web应用中的会话及会话管理

  • HTTP协议时一个无状态的的协议,当一个客户向服务器发出请求,在服务器返回响应后,连接就关闭了。这时,在服务器端不保留连接的相关信息,因此当下一次请求连接时,服务器已没有以前的连接信息了,也就无法判断这一次连接和以前的连接是否属于同一客户,也就是说Web服务器无法跟踪客户状态。
  • 在Servlet规范中,常用以下两种机制完成会话跟踪
    1.使用持续的Cookie
    2.使用Servlet API中Session(会话)机制

Cookie

什么是Cookie

  • Cookie是一种在客户端保持HTTP状态信息的技术
  • Cookie是在浏览器访问Web服务器端的某个资源时,由WEB服务器在HTTP应答头中附带传送给浏览器的一个数据,WEB服务器传送给客户端浏览器的数据可以是各不相同的;
  • 一旦浏览器保存了某个Cookie,那么它以后每次访问服务端时,Cookie都应附加在请求头中传回给服务器
  • 一个Cookie只能记录一种信息,它至少含有一个标识信息的名称(NAME)和设置值(VALUE)(k-v);
  • 一个WEB站点可以给一个WEB浏览器发送多个Cookie,一个WEB浏览器也可以存储多个站点所提供的Cookie;
  • 浏览器一般最多能存入300个Cookie,每个站点最多可以存放20个Cookie,每个Cookie大小限制在4kb
  • Cookie只能送回给创建它的服务器,不可以送到其他的服务器;
  • Cookes的基本工作原理“
客户计算机                              服务器
           1.客户端请求                 
           2.服务器在响应头中设置Cookie  
 Cookies   3.客户端在请求文档           
           4.服务器读取Cookie           

创建Cookie

  • 创建Cookie对象new Cookie(name, value);
  • 设置最大时效 setMaxAge(int age);
  • 将Cookie 放入到HTTP响应报头(Set-Cookie:key=value)
String username = request.getParameter("username");
//创建一个Cookie
Cookie  cookie = new Cookie("usename", username);
//将cookie发送给浏览器
response.addCookie(cookie);

如果创建了一个Cookie,并将它发送到浏览器,默认情况下它是一个会话级别的cookie;存储在浏览器的内存中,用户推出浏览器之后被删除;

若希望浏览器将该cookie存储在磁盘上,则需要使用maxAge,并给出一个以秒为单位的时间。将最大时效设置为0则是命令浏览器删除该coolie;

发送cookie需要使用HttpServletResponse的addCookie方法,将cookie插入到一个Set-Cookie HTTP响应报头中

Cookie cookie = new Cookie("username", username);
//给一个cookie设置了一个预期时间,那么该cookie是一个持久化的cookie,该cookie
//将会保存在浏览器所在的硬盘上,浏览器关闭后不会消失,只有超过了这个期限,浏览器才不发送该cookie
cookie.setMaxAge(60*5);
response.addCookie(cookie);

读取Cookie

因为保存在浏览器上的cookie以请求头的形式发送,所以需要通过request获取客户端的cookie,如果没有cookie发送过来,requst.getCookie()返回null

修改Cookie

修改指定名字的cookie,就是再次向浏览器发送一个同名并且不同值的一个cookie,让其覆盖

删除Cookie

删除指定名字的cookie,就是再次向浏览器发送一个同名并且失效的cookie,让其覆盖

Cookie存储中文

因为Cookie数据传递是通过消息头的形式,而消息头中不能出现中文,所以在创建Cookie之前需要把数据编码成非中文。服务器接收浏览器发送的Cookie值时再解码出中文。

创建带有中文内容的Cookie:

//使用URLEncoder.encode方法把中文编码为application/x-www-form-urlencoded格式
Cookie cookie = new Cookie("username",URLEncoder.encode("中文","UTF-8"));
cookie.setMaxAge(60*5);
response.addCookie(cookie);

接收带有中文的Cookie:

Cookie[] cookies = request.getCookies();
if(cookies != null){
    for(Cookie cookie : cookies){
        if("username".equals(cookie.getName())){
            //使用URLDecoder把application/x-www-form-urlencoded格式反编码
            String value = URLDecoder.decode(cookie.getValue(), "UTF-8");
            break;
        }
    }
}

Session

什么是Session

  • Session机制采用的时在服务器端保持HTTP状态信息的方案;
  • 当程序需要为某个客户端的请求创建一个Session的时候,Servlet容器首先检查这个客户端的请求里是否已经包含了一个seesion id,如果已经包含一个seesion id则说明以前已经为次客户端创建过seesion,Servlet容器就按照session id把这个session检索出来使用(如果检索不到可能会创建一个),如果客户端请求不包含session id,则为此客户端创建一个session并且生成一个与此session相关联的session id。这个session id将会在本次响应中返回给客户端保存
  • 可以将Session看作是Map<String,Object>对象,session id靠cookie维护客户端和服务器之间的通信。

创建Session

在服务器上创建一个空间,并为该内存空间生成一个唯一的id,放在cookie中发送给客户端,通过request.getSession()方法得到该请求所在的会话。默认情况下,如果当前请求没有在一个存在的会话下,服务器会创建一个并返回

查询Session中的内容

通过request的getSessioin方法得到该请求所在的会话,通过session.getAttribute方法得到在session中对应key的值

HttpSession session = request.getSession();
User user = (User)session.getAttribute("user");

删除Session

HttpSession session = request.getSession();
//从session中删除user
httpSession.removeAttribute("user");
//或者让session失效
httpSession.invalidate();//让session失效

Session的超时管理

  • WEB服务器无法判断当前的客户端浏览器是否还会继续访问,也无法检测客户端浏览器是否关闭,所以,技术客户已经离开或关闭了浏览器,WEB服务器还要保留与之对应的HttpSession对象
  • 随着时间的推移而不断增加新的访问客户端,WEB服务器内存中将会因此积累起大量的不再被使用的HttpSession对象,并将最终导致服务器内存耗尽。
  • WEB服务器采用“超时限制”的办法来判断客户端是否还在继续访问,如果某个客户端在一定的时间之内没有发出后续请求,WEB服务器则认为客户端已经停止了活动,结束与该客户端的会话并将与之对应的HttpSession对象失效
  • 如果客户端浏览器超时之后再次发出访问请求,WEB服务器会认为这是一个新的会话的开始,将为之创建新的HttpSession对象和分配新的会话标识号。
  • 可以通过三种方式设置Session的超期时间:
    1.在web.xml中设置:
<!-- session-config包含一个子元素session-timeout,单位为分钟 -->
<session-config>
    <session-timeout>5</session-timeout>
</session-config>

2.使用session.setMaxInactiveInterval(秒)设置
3.优先级:

3.1:setMaxInactiveInterval优先级最高,如果setMaxInactiveInterval没有设置,则默认是session-config中设置的时间
3.2:setMaxInactiveInterval设置的是当前会话失效时间,不是整个web服务的。
3.3:setMaxInactiveInterval的参数是秒,session-config的是分钟
3.4:如果当前项目的web.xml中没有设置的话就使用tomcat/conf/web.xml中默认的配置

禁用Cookie的时候使用Session

由于cookie可以被认为的禁止,必须有其他机制以便在cookie被禁止时仍能够在服务器和客户端之间传递session id。经常被使用的一种技术叫URL重写,就是把seesion id直接附加在URL路径的后面

Servlet

Servlet概述

SUN公司提出了Servlet规范后Java在Web领域才有了一席之地。Servlet规范不仅规范了Servlet容器,还规范了JavaWeb应用结构和Servlet代码结构。

Servlet容器为JavaWeb应用提供运行时环境,它负责管理Servlet和JSP的声明周期,以及管理他们的共享数据。

Servlet容器也称为JavaWeb容器,或者Servlet容器。

一个Java Web应用程序是由一组Servlet、HTML页面、类,以及其他资源组成的运行在web服务器上的完整的应用程序,以一种结化的由层次的目录形式存在。组成Web应用程序的这些文件要部署在相应的目录层次中,根目录代表整个web应用程序的“根”。

通常将web应用程序的目录放在webapps目录下,在webapps目录下的每一个子目录都是一个独立的web应用程序,子目录的名字就是web应用程序的名字,也就是web应用程序的“根”。用户通过web应用程序的“根”来访问web应用程序中的资源。

Servlet规范中定义了web应用程序的目录层次:
应用程序的根目录(名字随便起):

WEB-INF(大写,并且是中划线)
    --classes(当前应用程序java文件编译出来的.class文件)
    --lib当前应用程序关联的jar文件
    --web.xml配置文件

第一个Servlet程序

1:搭建JavaWeb项目:

  1. 创建一个Java项目:HelloServletWeb;
  2. 在HelloServletWeb中创建一个文件夹webapp,表示web项目的根
  3. 在webapp中创建WEB-INF文件夹
  4. 在WEB-INF中创建文件夹:lib、classes
  5. 在WEB-INF中去Tomcat根/conf拷贝web.xml文件,只需要保留根元素。
  6. 把当前项目的classpath路径改成webapp/WEB-INF下的classes中

2:编写Servlet:

  1. 为该项目增加Servlet的支持
    1.1:把Tomcat根/lib中servlet-api.jar文件拷贝到项目WEB-INF下的lib中
    1.2:在项目中选择servlet-api.jar,鼠标右键,build path-->add to build path
  2. 开发Servlet程序:
    2.1:定义一个类HelloServlet,并让该类去实现javax.servlet.Serlet接口;
    2.2:实现Servlet接口 中的init,service,destory等方法

注意:若生成方法中的参数是arg0或者arg1等格式的,原因是还没有关联源代码:关联上:apache-tomcat-7.x.x-src.zip,并重新实现/覆写方法就OK;

3:配置Servlet:HelloServlet仅仅是一个普通的实现类而已,而我最终要运行在Tomcat服务器中,所以得告诉Tomcat,来帮我管理HelloServlet类:

  1. 找到项目根目录下的WEB-INF下的web.xml文件;
  2. 在根元素web-app中创建一个新的元素节点:servlet
  3. 在根元素web-app中创建一个新的元素节点:servlet-mapping

在web.xml中的配置:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
                      http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
  version="3.0">

    <servlet>
        <!-- 为Servlet起一个名字 -->
        <servlet-name>HelloServlet</servlet-name>
        <!-- Servlet类的全限定名称 -->
        <servlet-class>ee.coding.servlet.HelloServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <!-- 该限定名必须和上面servlet节点中的servle-tname一样 -->
        <servlet-name>HelloServlet</servlet-name>
        <!-- 给servlet映射的路径 -->
        <url-pattern>/hello</url-pattern>
    </servlet-mapping>

</web-app>

4:部署访问:

在Server.xml文件的Host元素中:

<Context docBase="D:\WorkSpace\HelloServlet\webapp" path=""/>

通过:http://localhost/hello 访问

Servlet的声明周期和执行流程

Servlet的生命周期

Servlet容器为JavaWeb应用提供运行时环境,它负责管理Servlet和JSP的生命周期,以及管理他们的共享数据。

Servlet生命周期方法

public class HelloServlet implements Servlet {
    
    /*
     *1.执行一次创建一个对象 
     */
    public HelloServlet() {
    }

    /*
     * 2.Servlet对象被创建后执行该方法,并且只执行一次
     */
    @Override
    public void init(ServletConfig config) throws ServletException {
    }

    /*
     *3.每次客户请求都执行 
     */
    @Override
    public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
        System.out.println("Hello!");
    }
    
    /*
     *4.正常关闭服务器并且该Servlet对象被销毁的时候执行 
     */
    @Override
    public void destroy() {
    }

    @Override
    public String getServletInfo() {
        return null;
    }

    @Override
    public ServletConfig getServletConfig() {
        return null;
    }
}

为该Servlet只当一个访问地址:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
                      http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
  version="3.0">
    
    <servlet>
        <!-- 为Servlet起一个名字 -->
        <servlet-name>HelloServlet</servlet-name>
        <!-- Servlet类的全限定名称 -->
        <servlet-class>ee.coding.servlet.HelloServlet</servlet-class>
        <!-- 服务器启动的时候就会创建该Servlet对象,并且执行init方法,数字越小越先加载执行 -->
        <load-on-startup>0</load-on-startup>
    </servlet>
    <servlet-mapping>
        <!-- 该限定名必须和上面servlet节点中的servle-tname一样 -->
        <servlet-name>HelloServlet</servlet-name>
        <!-- 给servlet映射的路径 -->
        <url-pattern>/hello</url-pattern>
    </servlet-mapping>

</web-app>

Servlet执行流程

  1. 在浏览器上请求:http://localhost:8080/hello
  2. 浏览器发送请求信息:
    GET /life HTTP/1.1
    Host: localhost:8080
  3. Tomcat接收到浏览器发送的请求信息,根据请求信息中的Host的值找虚拟主机
  4. 解析请求中的资源路径,并到项目的web.xml中去匹配<url-pattern>,假如没有匹配到则返回404错误,如果匹配到,寻找对应servlet-name
  5. 根据<servlet-name>的名字到Servlet对象缓存池中查询。若找到执行第7步;
  6. 根据<servlet-name>找到<servlet-class>值,使用反射创建Servlet实例,并放到Servlet对象缓存池中;
  7. Servlet容器调用该Servlet对象上的init方法,并传入封装web.xml配置信息的ServletConfig对象;
  8. Servlet容器调用该Servlet对象上的service执行,并且传入封装了客户端请求信息的request对象和向客户端返回响应信息的response对象;
  9. 如果tomcat关闭,当Servlet要被销毁的时候,Servlet容器就会调用destroy方法。

ServletConfig接口

Servlet容器会将解析出的Servlet相关信息封装在ServletConfig对象中,当Servlet初始化时将ServletConfig对象传入init方法中。

可以在Servlet中通过Servlet对象获取servlet相关的配置信息,ServletConfig的方法看API。

为HelloServlet配置一些初始化参数:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
                      http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
  version="3.0">

    <servlet>
        <servlet-name>HelloServlet</servlet-name>
        <servlet-class>ee.coding.servlet.HelloServlet</servlet-class>
        <!-- 为HelloServlet提供一些初始化参数 -->
        <init-param>
            <param-name>encoding</param-name>
            <param-value>utf-8</param-value>
        </init-param>
        <init-param>
            <param-name>language</param-name>
            <param-value>en</param-value>
        </init-param>
    </servlet>
    <servlet-mapping>
        <servlet-name>HelloServlet</servlet-name>
        <url-pattern>/hello</url-pattern>
    </servlet-mapping>

</web-app>

Servlet继承体系

GenericServlet实现了Servlet接口和ServletConfig接口,里面提供了一些简便的访问ServletConfig对象中信息的方法。

HttpServlet

HttpServlet中主要是处理HTTP请求,它根据客户的请求方式在service方法中将请求处理分为几种方式。最常使用GET和POST,分别覆盖doGet和doPost方法即可。也可以直接通过覆盖service(HttpServletResponse,HttpServletResponse)方法来统一处理所有请求方式的请求。

HttpServletRequest

HttpServletRequest是ServletRequest接口的子接口,表示HTTP协议的请求对象。既然HttpServletRequest是HTTP的请求对象,那么该接口中包含了获取各种请求信息的方法。

常用方法:

String getContextPath():获取上下文路径,<Context path="上下文路径".../>
String getHeader(String headName):根据指定的请求头获取对应的请求头的值
String getRequestURL():返回当前请求的资源名称。上下文路径/资源名称
StringBuffer getRequestURL():返回浏览器地址栏的内容
String getRemoteAddr():返回请求服务器的客户端的IP

获取请求参数的方法:

String getParameter(String name):根据参数名称,获取对应参数的值
String[] getParameterValues(String name):根据参数名称,获取该参数的多个值
Enumeration<String> getParameterNames():获取所有请求参数的名字
Map<String,String[]> getParameterMap():返回请求参数组成的Map集合

中文乱码问题

Tomcat接收请求的时候,默认使用的是ISO-8859-1编码,而该编码只占一个字节,不支持中午(两个字节)

解决方案:

  1. 对乱码使用ISO-8859-1解码 ---> byte数组
  2. 对byte数组重新使用UTF-8编码
//使用ISO-8859-1解码,恢复为二进制
byte[] data = username.getBytew("ISO-8859-1");
//重新使用UTF-8编码
username = new String(data, "UTF-8");

POST方式:

request.setCharacterEncoding("UTF-8");//设置  请求参数的编码方式

注意:必须在获取第一个参数之前设置,只对POST方式有效

GET方式:可以修改Tomcat对GET方式的编码(不建议修改)

71    <Connector port="80" protocol="HTTP/1.1"
72               connectionTimeout="20000"
73               redirectPort="8443" />

等价于:

71    <Connector port="80" protocol="HTTP/1.1"
72               connectionTimeout="20000"
73               redirectPort="8443" 
74               URLEncoding="ISO-8859-1"
75               />

改成:UTF-8:

71    <Connector port="80" protocol="HTTP/1.1"
72               connectionTimeout="20000"
73               redirectPort="8443" 
74               URLEncoding="UTF-8"
75               />

HttpServletResponse

HttpServletResponse是ServletResponse的子接口,表示HTTP协议的响应对象。该接口中包含了处理响应的方法。

常用方法:

OutputStream getOutputStream():获取字节输出流,文件下载
Writer getWriter():获取字符输出流,输出内容

注意:以上两个方法不能共存,只能使用其中一个。

设置响应的编码:

response.setCharacterEncoding("UTF-8")

设置响应的MIME类型:

response.setContentType("text/html");//不要写错了

上述两个操作可以合并为:

response.setContentType("text/html;character=utf-8");

如果向客户端输出中文内容,为了防止乱码必须指定编码:

response.setContentType("text/html;character=utf-8");
PrintWriter printWriter = response.getWriter();
printWriter.println("这是返回给客户端的内容");

设置响应头和响应编码:

response.setHeader("Locatioin","http://localhost/docs");
response.setStatus(307);

Servlet映射细节

1.同一个Servlet可以配置多个url-pattern
2.资源同通配符配置:*(任意个数的任意字符)

第一种:/*或者 /system/*
    /*:随便一个字符,都可以访问当前Servlet
    /system/*:所有以/system/打头的资源名才可以访问该Servlet(登陆验证)
第二种:*.拓展名
    *.do:资源名必须以.do结尾才可以访问当前Servlet

3.配置Servlet的时候,<servlet-name>不能起名为default:在Tomcat中,主web.xml文件规定了:访问静态资源都得通过default的Servlet
4.Servlet对象的生命周期:

第一次访问的:
    构造器 ---> init ---> service
第N次:
    service
在框架中,我们习惯给Servlet配置:<load-on-startup>来决定其构建和初始化顺序

学习Struts1/SpringMVC的时候,优先启动该Servlet(该Servlet主要负责加载资源和初始化操作)
5.从Tomcat7开始支持Servllet的注解映射:首先保证:web-app的metagata-complete属性为false,缺省值就是false

<web-app xmlns="http://java.sun.com/xml/ns/javaee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
                      http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
  version="3.0" metadata-complete="false">

</web-app>

Servlet线程安全

Servlet体系结构是建立在Java多线程机制之上的,它的生命周期是由web容器负责的。在Servlet对象缓冲池中,同一个Servlet只会存在一个实例。这样,当两个或多个线程同时访问同一个Servlet时,会发生多个线程同时访问同一资源的情况,数据可能变得不一致。所以在用Servlet构建的Web应用时如果不注意线程安全的问题,会使所写的Servlet程序有难以发现的错误。

解决方案:

  • 让Servlet实现 javax.servlet.SingleThreadModel接口:同时只能让一个线程来访问资源,若是多个资源,进入等待(不推荐);
  • 在service()中不要使用成员变量。Struts1,SpringMVC也是线程不安全的,Struts2是线程安全的。

Tomcat和HTTP

CS和BS

CS和BS

CS和BS是软件架构模式:
C/S:Client/Server:客户端/服务端架构
B/S:Browser/Server:Browser/Server:浏览器/服务器架构

C/S架构

特点:在服务端主要就是一个数据库,把所有业务逻辑以及界面的渲染操作交给客户端完成,运行在电脑桌面。

开发语言:VB、Delphi、BC++、C#、Java awt/swing等:比如桌面QQ,扫雷,印象笔记等

优点:较安全,用户界面很丰富,用户体验不错等

缺点:每次升级都需要重新安装,针对不同的操作系统开发,可移植性差

B/S架构

特点:通过浏览器访问,BS是特殊的CS,此时浏览器充当了客户端,基于HTTP协议。

开发语言:JSP,ASP,PHP等,基于浏览器访问的应用,把业务逻辑交给服务端完成,客户端仅仅只是做页面渲染和数据交换

优点:只开发服务端,可以跨平台,移植性很强等。

缺点:安全性较低,用户体验较差等

现在的应用综合了BS和CS的有点:部分应用不再是单纯BS:

富客户端技术:RIA,客户端会处理部分的业务逻辑,也会做界面的渲染和数据交互,界面丰富好比是CS。EasyUI,Flex,Ext js,Java FX等

瘦客户端技术:基于传统的html界面,客户端只是界面的渲染和数据交互(传统的BS)

Tomcat服务器

Web应用

Web应用就是基于HTTP协议在B/S架构中的服务端的应用程序,它接收客户端浏览器的请求并返回应答结果(通常是以界面的形式)

如果使用:https://coding.ee访问,浏览器按照以下过程去访问服务器:

  1. 浏览器先到:C:\Windows\ststem32\drivers\etc\hosts文件中找是否有映射的IP;
  2. 如果没有就会到DNS服务器上找域名对于的IP;
  3. 根据IP找到应用的服务器;
  4. 根据端口号找到在服务器上面安装的web服务器软件;
  5. 服务器软件中根目录文件夹下面的index.html文件

Tomcat简介

JavaWeb应用是由一组Servlet、HTML页面、JSP页面、工具类以及其他可以绑定的资源构成,它可以在各种供应商提供的实现Servlet规范的Servlet容器中运行。

Tomcat是一个免费的开放源码的Servlet容器,他是Apache软件基金会的一个顶级项目,由Apache、Oracle和其他一些公司及个人共同开发而成。Tomcat8支持最新的Servlet3.1和JSP2.3规范。

Tomcat用Java语言开发,是一个符合JavaEE标准的Web服务器,但JavaEE中的EJB程序无法在此处运行。

Tomcat安装和运行

Tomcat根目录下的文件和文件夹:

bin:存放了启动/关闭Tomcat等的工具
conf:存放了Tomcat软件的一些配置文件
lib:存放了Tomcat软件启动运行的依赖jar文件
logs:存放了Tomcat日志记录(成功、失败等
temp:临时目录,比如把上传的大文件存放于临时目录
webapps:里面存放需要部署的javaweb项目
work:工作目录,存放了jsp翻译成Servlet的java文件及字节码文件

Tomcat直接解压后就可以使用,前提是必须配置JAVA_HOME或JRE_HOME

运行Tomcat:点击Tomcat根目录/bin/startup.bat文件

如果Tomcat启动成功,就是要访问到Tomcat软件。通过以下方式访问:

http://Tomcat所在电脑的IP:Tomcat运行的端口/资源名称

在本机上访问地址如下:

http://localhost:8080
http://127.0.0.1:8080

Tomcat常见问题

还没启动Tomcat或者Tomcat启动失败就去访问地址

Tocam启动成功,但是出现404:资源路径写错了
注意:出错之后要习惯去查看日志信息:Tomcat根/logs/catalina.2016-10-1.log

Tomcat下的配置文件的结构不能乱改

要保证XML内容编码和文件本身的编码相同,若有中午,建议使用UTF-8,否则不能使用中文

Tomcat的配置

添加tomcat管理用户:
在conf/tomcat-users.xml中添加:

<role rolename="manager-gui"/>
<user username="root" password="admin" roles="manager-gui"/>

再次启动Tomcat后,就可以访问首页的Server Status和Manager App
与Host Manager

Tomcat默认的端口为8080,可以在conf/server.xml中将其端口号改为80,71行左右

注意:修改完server.xml后要重启tomcat才能生效

部署Web项目

直接给Tomcat指定一个项目的路径(重点)

<Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true">
    <--
        Context中的C和docBase中的B是大写的
        path是指当前项目的虚拟路径,并且该虚拟路径可以是空或者必须以/开头
        如果path是一个""表示当前项目是一个默认的项目
    -->
    <Context path="" docBase="E:\projects\baidu" />
    <Context path="/sina" docBase="E:\projects\sina" />
    <Context path="/google" docBase="E:\projects\google" />
</Host>

在tomcat\conf\Catalina\localhost文件夹下创建一个XML文件用于配置项目路径,如在tomcat\conf\Catalina\localhost下创建google.xml:

<Context docBase="E:\projects\google" />

不用在该内容中指定path,该文件的名字就是当前项目的虚拟路径。可以通过http://localhost:8080/google访问到docBase指向的项目目录

配置虚拟主机

主要解决的问题:可以给一台服务器增加多个默认的虚拟项目路径

增加在server.xml中host节点:

<Host name"www.google.cim" appBase="webapps" unpackWARS="true" autoDeploy="true">
    <Context path="google" docBase="E:\projects\google" />
</Host>

让Host中的name属性的值映射到本机上面,需要修改Hosts文件中内容

C:\Windows\ststem32\drivers\etc\hosts

127.0.0.1 localhost
127.0.0.1 www.baidu.com
127.0.0.1 www.google.com

为的是通过上面的地址访问的时候,将这些域名映射到本机上。

通过域名访问到指定服务器的时候,浏览器会将该域名通过请求头Host的值发送给Tomcat服务器,Tomcat服务器就可以根据Host值在server.xml中找到具体的虚拟主机。一个项目可能有多个域名,那么可以通过给虚拟主机增加别名来增加多个域名。

<Host name"www.google.cim" appBase="webapps" unpackWARS="true" autoDeploy="true">
    <Alias>www.g.cn</Alias><!--别名-->
    <Context path="google" docBase="E:\projects\google" />
</Host>

搭建基于Eclpse的纯的JavaWeb项目

操作步骤:

  1. 搭建一个Java项目
  2. 在该项目下新建一个文件夹,表示根,名为:webapp(名字随意)
  3. 在webapp下新建一个文件夹,名字为WEB-INF
  4. 在WEB-INF中新建一个文件夹,名为classes
  5. 在WEB-INF中新建一个文件夹,名为lib
  6. 去Tomcat根/webappa/ROOT/WEB-INF目录下拷贝一个web.xml文件到WEB-INF下(只保留头和根元素)
  7. 改变项目的输出目录:也就是改变classes的路径,从默认的bin目录改变成webapp/WEB-INF/classes中;
  8. 搞定:以后要把项目给别人,只给webapp目录

给Eclipse安装Tomcat的插件

//待补充

HTTP协议

HTTP概述

WEB浏览器与WEB服务器之间的一问一答的交互过程必须遵循一定的规则,这个规则就是HTTP协议。

HTTP是htpertext transfer protocol(超文本传输协议)的简写,它是TCP/IP协议集中的一个应用层协议,用于 定义WEB浏览器与WEB服务器之间数据交换的过程以及数据本身的格式。HTTP协议的版本:HTTP/1.0、HTTP/1.1、HTTPS2.0

HTTP1.0的特点:浏览器与WEB服务器的连接过程是短暂的,每次连接只处理一个请求和响应。对一个页面的访问,浏览器与WEB服务器都要建立一次单独的连接。浏览器到WEB服务器之间的所有通讯都是完全独立分开的请求和相应对。

HTTP1.1的特点:在一个TCP连接上可以传送多个HTTP请求和响应;多个请求和响应过程可以重叠进行;增加了更多的请求和响应头。

体验HTTP协议

HTTP协议的信息分为请求头消息和响应头消息。用来规定服务器和客户浏览器端信息交互的格式。可以安装httpwatch或firebug来查看这些交互数据。

在浏览器上输入 http://localhost:8080后,向服务器发送的请求信息:

Host    
127.0.0.1:8080
User-Agent  
Mozilla/5.0 (Windows NT 10.0; …) Gecko/20100101 Firefox/55.0
Accept  
text/html,application/xhtml+xm…plication/xml;q=0.9,*/*;q=0.8
Accept-Language 
zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding 
gzip, deflate
Connection  
keep-alive

当服务器接收到这些请求的信息头的时候,将会做相应的处理然后发回响应信息:

Server  
Apache-Coyote/1.1
Accept-Ranges   
bytes
ETag    
W/"5931-1489038592000"
Last-Modified   
Thu, 09 Mar 2017 05:49:52 GMT
Content-Type    
text/css
Content-Length  
5931
Date    
Wed, 27 Sep 2017 14:30:14 GMT
.........

上面的信息格式就是HTTP协议定义的数据交互格式,要使用HTTP协议通信,客户端和服务器端必须符合这种格式。

HTTP请求消息的结构

HTTP协议请求消息由一个请求头、若干消息头、以及实体内容构成。其中的一些消息头和实体内容都是可选的,消息头和实体内容之间要用空行隔开。

在请求信息中第一行为请求行:

格式:请求方式 资源路径 HTTP版本号
请求方式:GET\POST、HEAD、OPTIONS、DELETE、TEACE、PUT

以不同的请求方式传递参数也不同:

  • 如果以GET方式提交的话,请求参数在资源路径的后面
  • 如果以POST方式发送请求的话,请求参数将会通过实体内容传递给服务器

HTTP响应消息的结构

HTTP协议响应消息由一个状态行、若干消息头、以及实体内容构成。其中的一些消息头和实体内容都是可选的,消息头和实体内容之间要用空行隔开。

响应消息头的第一行为状态行:

格式:HTTP版本号 状态码 原因叙述

响应消息的实体内容就是网页文件的内容,也就是在浏览器中使用查看源文件的方式所看到的内容。

常用响应状态码

200(正常):表示一切正常,返回的是正常请求结果
206(部分正常):客户发送了一个带有Range(要求服务器只返回文档中的部分内容)的GET请求,服务器按要求完成了这个请求
302/307(临时重定向):指出被请求的文档已经被临时移到别处,此文档的新的URL在Location响应头中给出
304(未修改):表示客户机缓存的版本是最新的,客户机应该继续使用它
401(未经授权):表示客户机访问的是一个受口令和密码保护的页面,结合使用一个WWW-Authentication响应头提示客户机应重发一个带有Authorizatioin头的请求消息
404(找不到):服务器上不存在客户机所请求的资源
500(内部服务器错误):服务器端的CGI、ASP、JSP等程序发生错误

Get和Post请求的区别

GET方式:

浏览器地址栏:http://localhost/from.index?name=lanyue&age=17
请求行:GET /from.html?name=lanyue&age=17 HTTP/1.1
请求方式是:GET
请求资源是: /from.html?name=lanyue&age=17
请求资源包括请求参数:第一个参数使用?和资源连接,其他的参数使用&符号连接
缺点:保留请求信息,不安全。请求信息不超过1kb,这样就限定了GET方式不能做图片上传
超链接的请求都属于GET方式 
表单中的method=get

POST方式:

浏览器地址栏:http://localhost/from.index#
不再有请求信息:
请求行:POST /from.html HTTP/1.1
POST方式的参数全部在请求的实体中
隐藏了请求信息,较安全:POST方式没有限制请求的数据大小,可以做图片上传。

目前HTTP的请求方式只有两种:GET/POST,分别使用doPost/doGet方法来处理。