JavaWeb基础

七、JavaWeb基础

javaWeb:完整技术体系,掌握之后能够实现基于B/S架构的系统

1. C/S和B/S

1.1 C/S(Client/server)

  • C/S:客户端与服务器
  • 本质:本地上有代码(程序在本机上)
  • 优点:运行速度快(因为代码在本机上)
  • 缺点
    • 对本机有要求
    • 相对而言,不安全(因为本地有程序,所有的信息都在本地程序中记录着)
    • 不易维护

1.2 B/S(Brower/server)

  • B/S:浏览器与服务器
  • 本质
    • 本地上没有代码(程序在远程上)
    • 一次安装,到处运行
  • 优点
    • 对本机无要求(因为程序在服务器上运行)
    • 相对而言,较安全(因为代码在服务器上)
    • 相对而言,维护较容易
  • 缺点:运行速度慢(因为每次操作都要请求服务器)
  • B/S技术介绍
    • PHP
      • Hypertext Preprocessor(超文本预处理器)
      • php语言
    • JSP/SERVLET
      • JAVA语言
      • JSP/SERVLET是SUN制定的用Java开发web应用程序的规范技术
    • ASP.NET
      • C#语言

1.3 三方关系

  • 集体实现
    • 规范:SUN制定
    • 服务器:各容器供应商,如apache的tomcat等
    • 组件实现:程序员

2. Tomcat

2.1 目录结构

  • bin:存放启动和关闭脚本文件,存放命令
  • conf:存放各种配置文件
  • lib:所有的jar包
  • logs:所有的日志文件
  • temp:存放产生的临时文件
  • webapps:存放所有的部署的javaweb项目
  • work:存放编译后的jsp页面,存放JSP 生成的 Servlet 源文件和字节码文件

2.2 tomcat的运行、关闭和修改

  • tomcat运行:双击 bin 目录下的 startup.bat 文件

  • tomcat关闭:双击 bin 目录下的 shutdown.bat 文件关闭 Tomcat 服务器

  • 修改 Tomcat 默认的端口号

    • 打开 conf 目录下的 server.xml 文件
    • http默认端口:80
    • https默认端口:443

  • 修改cmd中乱码

    • 打开 conf 目录下的logging.properties文件
    • java.util.logging.ConsoleHandler.encoding = "UTF-8"换成GBK

2.3 web应用程序结构

2.4 web.xml

  • <servlet-mapping>:映射

  • <url-pattern>:访问路径

    xml 复制代码
    <servlet>
    	<servlet-name>myServlet</servlet-name>
    	<servlet-class>com.example.FirstServlet</servlet-class>
    </servlet>
    <servlet-mapping>
    	<servlet-name>myServlet</servlet-name>
    	<url-pattern>/myFirstServlet</url-pattern>
    </servlet-mapping>

3. Servlet详解

3.1 JavaWeb概述

  • Java Web应用由一组ServletHTML页、以及其它可以被绑定的资源构成
  • javaweb可以在各种供应商提供的实现Servlet规范的Servlet容器(Tomcat等)中运行
  • web应用包括
    • Servlet
      • 做控制,代表整个程序中的controller
      • 接受用户请求
      • 处理(响应)请求
    • JSP页面
      • JSP页面包括Java + DTML
    • 实用类:JDBC实体类
    • 静态文档:如HTML、图片等
    • 描述web应用的信息:如web . xml

3.2 Servlet概述

3.2.1 Servlet定义
  • 宏观定义:sun制定的用java编写web 应用程序的规范,技术
  • 微观定义:一个继承自HttpServlet,部署在webServer中可以处理客户端请求的Java类
  • 什么是Servlet?
    • Servlet 是一个用 Java 编写的程序,此程序在服务器上运行以处理客户端请求
    • 服务器:硬件服务器、软件服务器(Tomcat)等
      • 软件服务器在硬件服务器上运行
3.2.2 Servlet简介
  • Java Servlet是和平台无关的服务器端组件
  • Servlet运行在Servlet容器(服务器)
  • Servlet容器负责Servlet和客户的通信以及调用Servlet的方法
  • Servlet和客户的通信采用"请求/响应"的模式
  • 功能
    • (1)创建并返回基于客户请求的动态HTML页面
    • (2)创建可嵌入到现有HTML 页面中的部分HTML 页面(HTML 片段)
    • (3)与其它服务器资源(如数据库或基于Java的应用程序)进行通信
  • Servlet容器响应客户请求的过程
3.2.3 Servlet与Java类比较
3.2.4 Servlet容器
  • Servlet容器为JavaWeb应用提供运行时环境,它负责管理Servlet和JSP的生命周期,以及管理它们的共享数据
  • Servlet容器也称为JavaWeb应用容器(服务器),或者Servlet/JSP容器
  • Servlet容器软件
    • Tomcat
    • Resin
    • J2EE服务器(如Weblogic)中也提供了内置的Servlet容器
    • jboss
3.2.5 Servlet继承体系
3.2.6 Servlet生命周期
  • 在一个Servlet的生命期中
    • init()调用一次,一般第一次访问Servlet时调用
    • service()调用多次,每次访问时调用
      • 父类的service()会判断用户用的哪种请求并自动调用用户自己写的该请求的方法
      • 例如:使用Post请求时,service()会判断用的post请求并自动调用用户写的doPost方法
    • destroy()调用一次,服务器程序关闭时调用
    • <load-on-startup> 1 </load-on-startup>
      • 设置实例化、初始化的优先级
      • 0,1,2,3WEB应用程序启动
      • 0或1指在服务器启动时就将Servlet实例化并初始化
  • 生命周期的各个阶段

3.3 覆盖doGet与doPost方法

  • 因为doGetdoPost方法具体完成业务的功能,service在获取到请求之后会自动调用doGet和doPost方法,必须覆盖这两个方法,才能完成整个业务需求的开发
  • 重写doGet与doPost方法
    • HttpServlet与Servlet很相似,但实现了service()方法

3.4 Servlet映射

3.4.1 Servlet的注册和运行
3.4.1.1 Servlet的注册和启动
  • Servlet程序必须通过Servlet容器来启动运行
  • 储存目录有特殊要求,通常存储在<WEB应用程序目录>\WEB-INF\classes\(src)目录中
  • Servlet程序必须在WEB应用程序的web.xml文件中进行注册和映射其访问路径,才可以被Servlet引擎加载和被外界访问
3.4.1.2 <servlet>元素
  • 一个<servlet>元素用于注册一个Servlet

  • 包含有两个主要的子元素

    • <servlet-name>:用于设置Servlet的注册名称
    • <servlet-class>:用于设置Servlet的完整类名(包名+类名)
    xml 复制代码
    <servlet>
        <servlet-name>HelloServlet</servlet-name>
        <servlet-class>com.jinzhi.servlet.HelloServlet</servlet-class>
    </servlet>
3.4.1.3 <servlet-mapping>元素
  • 一个<servlet-mapping>元素用于映射一个已注册的Servlet的一个对外访问路径

  • 包含有两个子元素

    • <servlet-name>:用于指定Servlet的注册名称
    • <url-pattern>:用于指定Servlet的对外访问路径
    xml 复制代码
    <servlet-mapping>
        <servlet-name>HelloServlet</servlet-name>
        <url-pattern>/HelloServlet</url-pattern>
    </servlet-mapping>
3.4.1.4 示例
xml 复制代码
<!-- 定义一个Servlet -->
<servlet>
    <!-- Servlet的名称,用于在web.xml中引用 -->
    <servlet-name>HelloServlet</servlet-name>
    <!-- Servlet对应的Java类全路径 -->
    <servlet-class>com.jinzhi.servlet.HelloServlet</servlet-class>
</servlet>

<!-- 定义Servlet的URL映射 -->
<servlet-mapping>
    <!-- 与上面定义的Servlet名称对应 -->
    <servlet-name>HelloServlet</servlet-name>
    <!-- URL模式,当请求的URL匹配此模式时,将调用上述定义的Servlet -->
    <url-pattern>/HelloServlet</url-pattern>
</servlet-mapping>
3.4.2 Servlet映射的细节
  • 同一个Servlet可以被映射到多个URL
    • 多个<servlet-mapping>元素<servlet-name>子元素的设置值可以是同一个Servlet的注册名
xml 复制代码
<servlet>
    <servlet-name>MultiViewServlet</servlet-name>
    <servlet-class>com.example.servlet.MultiViewServlet</servlet-class>
</servlet>

<!-- 第一个URL映射 -->
<servlet-mapping>
    <servlet-name>MultiViewServlet</servlet-name>
    <!-- URL模式,当请求的URL匹配此模式时,将调用上述定义的Servlet -->
    <url-pattern>/url1</url-pattern>
</servlet-mapping>

<!-- 第二个URL映射 -->
<servlet-mapping>
    <servlet-name>MultiViewServlet</servlet-name>
    <!-- 另一个URL模式,当请求的URL匹配此模式时,同样会调用上述定义的Servlet -->
    <url-pattern>/url2</url-pattern>
</servlet-mapping>
  • Servlet映射到的URL中也可以使用*通配符
    • 一种格式是"*.扩展名",如:* . jsp
    • 一种格式是以正斜杠(/)开头并以"/*"结尾,如:/web01/

3.5 ServletConfig、HttpServletRequest、HttpServletReponse

3.5.1 ServletConfig
  • ServletConfig:获取Servlet的配置信息

  • 方法

    • ServletConfig.getInitParameter("name"):根据name获取初始化配置信息的value,返回值是获取到的元素值

      java 复制代码
      String name = config.getInitParameter("name");
      String age = config.getInitParameter("age");
  • <init-param>:用以设置初始化配置信息

    • 包含有两个子元素

      • <paraName>:用于指定初始化配置信息的name
      • <paraValue>:用于指定初始化配置信息的value
      xml 复制代码
      <init-param>
          <param-name>name</param-name>
          <param-value>张三</param-value>
      </init-param>
3.5.2 HttpServletRequest
  • 由Servlet容器生成,包装了客户端所有的请求信息

  • 方法

    方法 描述 示例
    request.getParameter("name") 根据 name 获取客户端的数据,返回值是获取到的值,获取客户端的数据
    request.getParameterValues("name") 根据 name 获取客户端数据,返回值是获取到值的数组,获取客户端的数据
    request.setCharacterEncoding("utf-8") 设置请求的字符编码格式,只对 post 请求有效, http 协议中请求编码 iso-8859-1
    request.setAttribute(name, value) request 对象设置属性值,获取服务器的数据
    request.getAttribute(name) 根据 name 获取到服务器端的数据,所有的返回值都是 Object 类型 ,获取服务器的数据
    request.getRequestDispatcher("路径").forward(request, response) 请求转发,跳转到该"路径"页面
3.5.3 HttpServletReponse
  • 由Servlet容器生成,包装了服务器对客户端的响应信息

  • 方法

    方法 描述 示例
    response.getWriter() 获取字符输出流对象,用于向页面输出数据,返回值是PrintWriter类型
    response.setContentType("text/html;charset=utf-8"); 设置响应的字符编码格式
3.5.4 Servlet间的通信
  • 一次请求可以访问多个Servlet
  • 多个servlet之间可以相互通信
3.5.5 Parameter与Attributer的区别

4. Web 程序结构

4.1 web应用程序

  • 一个 web 应用程序是由一组 ServletHTML 页面,以及其它的资源组成的运行在 web 服务器上的完整的应用程序,以一种结构化的有层次的目录形式存在
  • 组成 web 应用程序的这些文件要部署在相应的目录层次中,根目录代表整个 web 应用程序的"根"
  • 通常将 web 应用程序的目录放在 webapps 目录下
    • webapps 目录下的每一个子目录都是一个独立的 web 应用程序
    • 子目录的名字就是 web 应用程序的名字,也就是 web 应用程序的""
    • 用户通过 web 应用程序的""来访问 web 应用程序中的资源

4.2 web 应用程序的目录层次

4.3 Web-INF说明

  • WEB-INF目录下的classeslib目录都可以存放Java的类文件
    • 在Servlet容器运行时,Web应用程序的类加载器首先加载classes目录下的,其次才是lib目录下的类
    • 如果这两个目录下存在同名的类,起作用的将是classes目录下的类
  • WEB-INF 是一个特殊的目录(所有字母都要大写),安全目录
    • 这个目录并不属于Web应用程序可以访问的上下文路径的一部分,对客户端来说,这个目录是不可见的
    • 但该目录下的内容对于Servlet代码是可见的,因此可以通过请求转发跳转到该目录下的页面

5. Http协议

5.1 HTTP简介

  • HTTP协议:WEB浏览器与WEB服务器之间的一问一答的交互过程必须遵循一定的规则
  • HTTP:hypertext transfer protocol(超文本传输协议
  • Http是 TCP/IP 协议集中的一个应用层协议
  • Http用于定义WEB浏览器与WEB服务器之间交换数据的过程以及数据本身的格式

5.2 HTTP会话方式

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

5.3 HTTP请求消息

  • 请求消息的结构
    • 一个请求行
    • 若干消息头
    • 实体内容
  • 消息头和实体内容都是可选的
  • 消息头和实体内容之间要用空行隔开

5.4 HTTP响应消息

  • 响应消息的结构
    • 一个状态行
    • 若干消息头
    • 实体内容
  • 消息头和实体内容都是可选的
  • 消息头和实体内容之间要用空行隔开

5.5 HTTP响应报文详解

  • 响应状态吗
    • 响应状态码以2开头的通常表示成功
    • 响应状态码以3开头的通常表示转移
    • 响应状态码以4开头的通常表示无法访问,其中包括找不到资源或没有权限等
      响应状态码以5开头的通常表示服务器端程序运行出错

5.6 响应内容类型MIME

  • 需要指出的是在浏览器和服务器之间传输的数据类型并非都是文本类型,还包括图片、视频、音频等多媒体类型
  • 多媒体类型是使用MIME类型定义的
  • MIME:Multipurpose Internet Mail Extensions,多功能Internet 邮件扩充服务
  • MIME类型的格式是"大类型/小类型",并与某一种文件的扩展名相对应
  • 常见mime类型

6. get和post请求

6.1 HTTP请求方法

  • HTTP协议的请求方法有GETPOST、HEAD、PUT、DELETE、OPTIONS、TRACE、CONNECT

6.2 get请求

  • get的使用情况
    • 当客户端要从服务器中读取文档时
    • 当点击网页上的链接
    • 通过在浏览器的地址栏输入网址来浏览网页的
  • get方法要求服务器将URL定位的资源放在响应报文数据部分,回送给客户端
  • get请求时的参数与值
    • 使用GET方法时,请求参数和对应的值附加在URL后面,利用一个问号("?")代表URL的结尾与请求参数的开始,传递参数长度受限制
    • 如:/index.jsp?id=100&op=bind
  • 使用GET方式传送的数据量一般限制在1KB以下

6.3 post请求

  • post方法可以允许客户端给服务器提供信息较多
  • post请求时的参数与值
    • post方法将请求参数封装在HTTP请求数据中,以名称/值的形式出现
  • post方式对传送的数据大小没有限制,而且也不会显示在URL中
  • post请求方式主要用于向WEB服务器端程序提交form表单中的数据

6.4 GET和POST区别

7. 请求域属性

  • 存储在ServletRequest对象中的对象称之为请求域属性
  • 属于同一个请求的多个处理模块之间可以通过请求域属性来传递对象数据
  • 与请求域属性相关的方法
    • setAttribute方法
    • getAttribute方法
    • removeAttribute方法
    • getAttributeNames方法
  • Parameter与Attributer的区别

8. 请求转发与重定向

8.1 请求转发

需要发送数据到前台页面用转发,一般查询显示数据用转发

  • RequestDispatcher实例对象是由Servlet引擎创建的

  • 获取RequestDispatcher对象的方法

    • ServletContext.getRequestDispatcher (参数只能是以"/"开头的路径)
  • RequestDispatcher实例对象用于包装一个要被其他资源调用的资源(例如,Servlet、HTML文件、JSP文件等),并可以通过其中的方法将客户端的请求转发给所包装的资源

  • 结论

    1. 转发地址栏显示的是转发前的地址
    2. 转发可以携带request作用域数据
    3. 转发只能转发项目内部
    4. RequestDispatcher对象的forward进行转发
    5. 转发是看转发前请求,是get就是get,是post就是post
    java 复制代码
    request.getRequestDispatcher("Servlet03").forward(request, response);

8.2 重定向

  • sendRedirect 方法

    • 可以重定向到当前应用程序中的其他资源
    • 还可以重定向到同一个站点上的其他应用程序中的资源
    • 也可以使用绝对URL重定向到其他站点的资源
  • 如果传递给sendRedirect 方法的相对URL以"/"开头,则是相对于整个WEB站点的根目录,而不是相对于当前WEB应用程序的根目录

  • 结论

    • 重定向地址栏显示跳转后地址
    • 不能携带request作用域数据
    • 可以重定向到外部地址
    • 重定向后所有的请求都是get
    java 复制代码
    response.sendRedirect("http://baidu.com");

8.3 请求转发和重定向的比较

9. JSP详解

9.1 JSP简介

9.1.1 JSP概念
  • JSP(Java Server Page):sun制定的用java编写web 应用程序的规范、技术,建立在servlet规范之上
  • JSP
    • JSP:Java Server Page
    • JSP转译完是Servlet
    • JSP != JAVA+DHTML
    • JSP页面=JAVA+DHTML
  • JSP是简化Servlet编写的一种技术
    • 将Java代码和HTML语句混合在同一个文件中编写,只对网页中的要动态产生的内容采用Java代码来编写,而对固定不变的静态内容采用普通静态HTML页面的方式编写
9.1.2 JSP页面
  • JSP页面是由HTML语句和嵌套在其中的Java代码组成的一个普通文本文件
  • JSP 页面的文件扩展名必须为.jsp
  • 在JSP页面中编写的Java代码需要嵌套在<%%>
    • 脚本片段:嵌套在<%%>之间的Java代码
    • 模版元素:没有嵌套在<%%>之间的内容
  • JSP文件路径
    • JSP文件可以放置在WEB应用程序中的除了WEB-INF及其子目录外的其他任何目录中
    • JSP页面的访问路径与普通HTML页面的访问路径形式也完全一样
  • JSP表达式
    • 将要输出的变量或表达式直接封装在<%= %>之中
    • 在JSP表达式中嵌套的变量或表达式后面不能有分号
9.1.3 JSP执行原理
  • JSP首次执行时,会先将 .jsp文件翻译成 .java文件,然后将 .java文件编译成 .class,然后执行
  • JSP第二次以及以后执行时,会直接访问 .class文件,然后执行
  • .jsp文件翻译成 .java文件是通过JSP引擎在该java的_jspServic方法中将html的标签自动的out.print()输出的
  • 通过部署路径同级目录的.metadata\.plugins\org.eclipse.wst.server.core\tmp0\work\Catalina\localhost\web04_01\org\apache\jsp可以查询翻译后的 .java文件和 .class文件
9.1.4 JSP的运行原理
  • WEB容器(Servlet引擎)接收到以.jsp为扩展名的URL的访问请求时,它会将该访问请求交给JSP引擎去处理
  • 每个JSP 页面在第一次被访问时
    • JSP引擎将它翻译成一个Servlet源程序
    • 再把这个Servlet源程序编译成Servlet的class类文件
    • 再由WEB容器(Servlet引擎)来装载和解释执行该Servlet程序
  • JSP中的脚本程序代码可以采用其他脚本语言来编写,但是,JSP页面最终必须转换成Java Servlet程序

9.2 JSP页面组成

9.2.1 注释
  • HTML注释

    • 语法:<!- 注释内容 ->

    • html的注释客户端、.java源程序中都可见

      java 复制代码
      <!-html注释 ->
  • Java注释

    • 语法://注释内容

    • java的注释客户端不可见,.java源程序可见

      java 复制代码
      <%//java注释%>
  • JSP注释

    • 语法:<% -- 注释内容-- %>

    • 会被WEB容器容器忽略,客户端和 .java源程序都不可见

      java 复制代码
      <%--JSP注释 --%>
9.2.2 元素
9.2.2.1 脚本元素
  • JSP表达式:<%=a%>

    • 相当于<%out.print(a);%>

    • 语法要求每句后面不能有分号

      java 复制代码
      <%=100 %>
  • <%! %>声明变量是全局的,语法要求每句后面有分号

    java 复制代码
    <%!int j = 100; %>
  • <% %>声明变量是局部的,语法要求每句后面有分号

    java 复制代码
    <%int i = 1;%>
9.2.2.2 指令元素
  • JSP 指令的语法
    • <%@ 指令名称 属性1="属性值1"属性2="属性值2" ... 属性n="属性值n"%>
    • 指令以<%@ 开始,而以%> 终止
    • @表示这是一个指令
  • JSP指令
    1. page

      • page可以出现多次,但是pageEncoding属性(页面编码)只能出现一次
      • page指令用于定义JSP页面的各种属性,无论page指令出现在JSP页面中的什么地方,它作用的都是整个JSP页面
      • page指令最好是放在整个JSP页面的起始位置
      • page指令属性
      java 复制代码
      //page指令说明这是一个用java写的html页面
      <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
    2. include

      • include指令用于将其他文件中的内容合并进当前JSP页面

      • 静态引入

        先复制再编译,不能有相同变量

        • 概念

          • JSP引擎在翻译当前JSP页面时将其他文件中的内容合并进当前JSP页面转换成的Servlet源文件中
          • 这种在源文件级别进行引入的方式称之为静态引入
          • 当前JSP页面与静态引入的页面紧密结合为一个Servlet
        • 语法:<%@ include file="relativeURL"%>

          • file属性用于指定被引入文件的相对路径
          jsp 复制代码
          <%@include file="top.jsp" %>
        • 静态引入是先将其他文件的内容复制进当前文件,然后再将当前文件编译成 .class文件,因此在运行之后并没有其他文件的 .class.Java文件

        • 静态引入中不能有相同的变量名

        • 在将JSP文件翻译成Servlet源文件时,JSP引擎将合并被引入的文件与当前JSP页面中的指令元素

          • 设置pageEncoding属性的page指令除外
          • 除了importpageEncoding属性之外,page指令的其他属性不能在这两个页面中有不同的设置值
      • 动态引入

        先编译再引入,可以有相同变量

        • 概念

          • JSP引擎在翻译当前JSP页面时将其他文件先编译成 .class文件,然后引入进当前JSP页面转换成的Servlet源文件
          • 这种在引入编译后文件的方式称之为动态引入
          • 当前JSP页面引入的是其他文件编译后的文件
        • 语法:<jsp:include page="..."/>

          • page属性用于指定被引入文件的相对路径
          jsp 复制代码
          <jsp:include page="top02.jsp"></jsp:include>
        • 动态引入是先将其他文件编译成 .class文件,然后再将编译后的文件引进当前页面,所以在运行之后有其他文件的.java.class文件

        • 动态引入中可以有相同的变量名

        • 动态引入还可以通过子标签<jsp:param>来传递属性和值

        jsp 复制代码
        <jsp:include page="top02.jsp">
        	<jsp:param value="zhangsan" name="myname"/>
        </jsp:include>
      • 指令(静态)与动作(动态)区别

    3. taglib

9.2.2.3 动作元素
  • JSP标签
    • <jsp:include>标签
      • <jsp:include>标签用于把另外一个资源的输出内容插入进当前JSP页面的输出内容之中(动态引入
      • 语法:
        <jsp:include page="relativeURL | <%=expression%>" flush="true|false" />
        • page属性用于指定被引入资源的相对路径,它也可以通过执行一个表达式来获得
        • flush属性指定在插入其他资源的输出内容时,是否先将当前JSP页面的已输出的内容刷新到客户端
    • <jsp:forward>标签
      • <jsp:forward>标签用于把请求转发给另外一个资源
      • 语法:<jsp:forward page="relativeURL" />
        • page属性用于指定请求转发到的资源的相对路径,它也可以通过执行一个表达式来获得。
    • <jsp:param>标签
      • <jsp:param>标签用于传递参数信息
      • 语法:
        <jsp:include page="relativeURL | <%=expression%>">
        <jsp:param name="parameterName" value="parameterValue|<%= expression %>" />
        </jsp:include>
        • name属性用于指定参数名
        • value属性用于指定参数值
      • <jsp:include><jsp:forward>标签中可以使用多个<jsp:param>标签来传递多个参数
9.2.3 注册与配置JSP页面的访问路径

9.3 JSP隐式对象

9.3.1 隐式对象
  • 隐式对象:在将 .jsp文件转译成 .java文件时,JSP引擎会自动的在该 .java文件中创建的对象
  • 不需要使用者声明创建,由容器维护和管理
9.3.2 九大内置对象
隐式对象 类型 描述 获取方法 返回对象
request javax.servlet.http.HttpServletRequest 得到用户请求信息 getRequest() 返回request隐式对象
response javax.servlet.http.HttpServletResponse 服务器向客户端的响应信息 pageContext.getResponse() 返回response隐式对象
pageContext javax.servlet.jsp.PageContext JSP的页面容器,该页面的所有东西都存放在该容器中,可以获取其他隐式对象 - -
session javax.servlet.http.HttpSession 用于保存用户信息 pageContext.getSession() 返回session隐式对象
application javax.servlet.ServletContext 所有用户的共享信息 pageContext.getServletContext() 返回application隐式对象
config javax.servlet.ServletConfig 服务器配置,可以获得初始化参数 pageContext.getServletConfig() 返回config隐式对象
out javax.servlet.jsp.JspWriter 用于页面输出 pageContext.getOut() 返回out隐式对象
page java.lang.Object 指当前页面转换后的Servlet类的实例 pageContext.getPage() 返回page隐式对象
exception java.lang.Throwable 表示JSP页面发生的异常,在错误页面才起作用 pageContext.getException() 返回exception隐式对象
9.3.3 pageContext对象
  • pageContext对象封装了当前JSP页面的运行信息,它提供了返回JSP页面的其他隐式对象的方法

  • setAttribute方法:setAttribute方法将对象存储进pageContext对象内部的一个HashMap对象中

  • getAttribute方法:来检索存储在该HashMap对象中的对象

  • PageContext类还定义了可以存储和检索其他域范围内的属性对象的方法

    java 复制代码
    pageContext.getRequest().setAttribute("age", 36);
  • pageContext对象可以获得其他隐式对象

10. 中文乱码

10.1 何时出现乱码?

  • 数据交互、语言不一致
  • Servlet相关
    • 页面输出内容
    • out.print()
    • 获取数据
      • request.getParameter()
  • JSP相关
    • 本质由转译的servlet out对象输出
    • 接受后台的数据可能会发生乱码
    • JSP设置的编码有问题可能会发生乱码

10.2 为何出现乱码?

  • 编码不一致

  • JSP不是中文开发的,开始只支持英文(iso-8859-1

10.3 如何解决乱码?

  • 使用一致编码
10.3.1 编码方式及解决
  1. 编码方式
    • GBK:中文
    • GB2312:简体中文
    • ISO-8859-1:英文
    • UTF-8:国际
  2. 代码解决
    • Servlet:response.setContentType("text/html;charset=utf-8")
    • JSP:<%@ page contentType="text/html; charset=utf-8"%>
    • IE:<meta http-equiv="Content-Type"content="text/html; charset= utf-8">
    • Tomcat 7.0及以前:需要在conf/server.xml文件Connector标签中添加 URIEncoding="utf-8" (只对get请求有用)
10.3.2 JSP乱码
  • JSP乱码问题
    1. JSP读取或输出数据时乱码
      • 输出响应正文时出现的中文乱码问题
      • 读取浏览器传递的参数信息时出现的中文乱码问题
    2. JSP页面翻译成Servlet源文件时乱码
      • JSP引擎将JSP源文件翻译的Servlet源文件默认采用UTF-8编码
      • 而JSP开发人员可以采用各种字符集编码来编写JSP源文件
      • JSP引擎将JSP源文件翻译成Servlet源文件时,需要进行字符编码转换
      • JSP引擎默认ISO8859-1字符集编码
  • JSP解决途径
    1. 读取或输出数据时
      • 设置request.setCharacterEncoding("UTF-8")
      • 设置response.setContentType("text/html;charset=utf-8")
    2. JSP页面翻译成Servlet源文件时乱码
      • contentType属性说明JSP源文件的字符集编码
      • pageEncoding属性说明JSP源文件的字符集编码
      • <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
10.3.3 请求参数乱码
  1. 只对post有效
    • request.setCharacterEncoding("UTF-8"):获取到请求参数并进行转码
  2. 只对get有效(server.xml)
    • <Connector port="8080" .............. URIEncoding="UTF-8"/>:在Tomcat 8以上版本默认添加了Connector URIEncoding="UTF-8"
  3. 即对post又对get有效
    • new String(x.getBytes("iso-8859-1"), "UTF-8")`

      java 复制代码
      new String(bookName.getBytes("iso-8859-1"),"utf-8")

11. MVC

11.1 MVC概念

11.1.1 MVC介绍
  • MVC:Model-View-Controller,即模型-视图-控制器
  • 优点
    • 实现了功能模块(Servlet)和显示模块(JSP)的分离
    • 提高了应用系统的可维护性、可扩展性、可移植性和组件的可复用性
11.1.2 模型(model

核心,封装存储数据

  • 模型
    • 模型是应用程序的主体部分,模型表示业务数据和业务逻辑
    • 一个模型能为多个视图提供数据
  • 分类
    1. 实体数据模型
      • 数据库的每个表对应java的每个实体类(数据载体),如:Entiry
    2. 业务数据模型
      • 实现增删改查,以及对数据库的操作,如:Dao、Service
  • 实体
    • 数据Bean,对应数据库的bean,如:Entiry
    • 业务Bean,如:Dao、Service
12.1.3 视图(View

外观,与用户交互

  • 视图
    • 视图是用户看到并与之交互的界面
  • 作用
    • 视图向用户显示相关的数据
    • 接受用户的输入
    • 不进行任何实际的业务处理
  • JSP显示模型中的数据,接受用户输入的数据,如:JSP
11.1.4 控制器(Controller

枢纽,响应请求,处理跳转,使模型与视图保持一致

  • 控制器
    • 控制器接受用户的输入并调用模型和视图去完成用户的需求
    • 控制器接收请求并决定调用哪个模型组件去处理请求,然后决定调用哪个视图来显示模型处理返回的数据
  • Servlet负责流程控制,根据请求类别调用DAO处理业务逻辑,根据不同结果调用JSP给客户反馈结果,如:Servlet

11.2 模型(Model)

11.2.1 JavaBean
  • JavaBean == Java类
  • 分类
    1. 数据Bean
      • 有状态,数据在变,即属性对应的属性值每次可能不一样
      • 数据库的每个表对应java的每个实体类(数据载体),如:Entiry
    2. 业务Bean
      • 无状态,即没有具体的属性值,只执行dao操作
      • 实现增删改查,以及对数据库的操作,如:Dao、Service
11.2.2 Model1
  • 模型要点
    • 客户端每次请求jsp页面
    • JSP页面负责表现逻辑、控制逻辑
    • JavaBean负责业务实现、持久化逻辑
  • 优点
    • 对部分业务逻辑(javabean)进行了封装
  • 缺点
    • 缺乏对控制逻辑的封装
    • jsp即负责表现逻辑,又负责控制逻辑
    • jsp较多,难以维护,代码冗余
11.2.3 Model2
  • 模型要点
    • JSP页面仅负责表现逻辑
    • JavaBean负责业务实现、持久化逻辑
    • Servlet负责流程控制
  • 优点
    • 彻底分离了业务逻辑与表现逻辑,进一步简化了JSP页面
  • 缺点
    • Servlet难以维护

11.3 MVC处理过程


不能跨层访问

只能自上向下依赖,而不能自下向上依赖

  1. ViewJSP
    • 呈现数据:从 request 中获取 Servlet 放入的属性
    • 接收用户的输入
    • 编写 JS 代码给出对应的提示
  2. Controller:Servlet
    • 获取请求信息:获取请求参数
    • 验证请求参数的合法性:验证失败,需要返回页面,并给出提示信息
    • 把请求参数封装为一个 JavaBean
    • 调用 DAO 的方法获取返回的结果
    • 把返回的结果放入到 request
    • 响应页面:转发、重定向
  3. Model:DAO
    • 获取数据库连接
    • 执行 CRUD 操作
    • 返回结果
  4. Model:SQL 用于存储数据

12. 分页

  1. 获取总记录数
    • sumRow总记录数
    • sql语句:select count(id) from tab
  2. 获取每页显示多少条
    • pageSize:为用户自己设定的
  3. 获取总页数
    • sumPage:总页数=总记录数/每页显示多少条
    • 三元表达式:
      sumRow%pageSize==0?sumRow/pageSize:(sumRow/pageSize)+1
  4. 获取当前页
    • nowPage
      • 第一次访问时指定nowPage为1
      • 其余都是根据请求传递的参数获取
  5. 获取当前页的数据
    • List
    • sql语句:
      select top " + pageSize + " * from tab where id not in
      (select top " + (nowPage - 1) * pageSize + " id from tab order by id desc)
      order by id desc

13. 会话

13.1 会话

  1. 提出问题
    • Http问题
      • HTTP协议是一种无状态的协议
      • WEB服务器本身并不能识别出哪些请求是同一个浏览器发出的
      • 浏览器的每一次请求都是完全孤立的
      • 作为 web 服务器,必须能够采用一种机制来唯一地标识一个用户,同时记录该用户的状态
    • 会话问题
      • 业务完成需要多次请求,如:购物车
      • 无连接的Http协议是无状态的,不能保存每个客户端私有信息
      • 如何保存客户端私有信息
  2. 会话
    • 会话是对某个web应用程序的一次整体访问过程
    • 一次会话包含多次请求
    • WEB应用中的会话是指一个客户端浏览器与WEB服务器之间连续发生的一系列请求和响应过程
  3. 会话状态
    • WEB应用的会话状态是指WEB服务器与浏览器在会话过程中产生的状态信息
    • 借助会话状态,WEB服务器能够把属于同一会话中的一系列的请求和响应过程关联起来
  4. 会话跟踪
    • 解决同一时刻不同客户端会话私有数据保存问题
  5. 会话跟踪如何实现有状态的会话?
    • WEB服务器端程序要从大量的请求消息中区分出哪些请求消息属于同一个会话
    • 即能识别出来自同一个浏览器的访问请求
    • 因此这需要浏览器对其发出的每个请求消息都进行标识
  6. 会话ID(SessionID)
    • 属于同一个会话中的请求消息都附带同样的标识号
    • 属于不同会话的请求消息总是附带不同的标识号
    • 这个标识号就称之为会话ID(SessionID)

13.2 Session

13.2.1 Session介绍
  • 不同环境下的不同含义
    • 中文翻译
      • session,中文翻译为会话
      • 含义是指有始有终的一系列动作/消息
      • 如打电话:从拿起电话拨号到挂断电话这中间的一系列过程称之为一个session
    • Web开发环境下
      • session在Web开发环境下是指一类用来在客户端与服务器端之间保持状态的解决方案
      • Session也用来指这种解决方案的存储结构
  • session
    • Session:服务器分配的保存客户端私有信息的一块内存空间
    • Session面向无链接无状态的Http协议而言是实现有状态会话的有益补充
    • SessionId是session的唯一标识
    • Session存储在服务器端
    • 服务器通过SessionID将客户端与Session数据对应起来
13.2.2 Session会话机制
  • 请求和响应
    • 客户端向服务端发出首次请求,服务器为此客户端产生session对象,并将生成的一个sessionId
    • 服务器应答时将该sessionId返回到客户端,客户端保存此sessionId(利用Cookie进行保存)
  • 当同一个客户端向服务器发出新的请求时,要将上次得到的sessionId一同发出,服务器检查用户的sessionId,根据该sessionId获得对应session对象
13.2.3 保存SessionId
  • Cookie
    • 浏览器自动发送
    • 默认方式,采用Cookie来保存sessionId
    • 在交互过程中浏览器可以自动的按照规则把sessionId发送给服务器
  • url重写
    • 使用情况:cookie被人为的禁用时,必须仍然能够把session id传递回服务器
    • 给每个超链接后增加请求参数,值为sessionId
    • URL重写:把session id附加在URL路径的后面
    • 两种附加方式
      • 一:作为URL路径的附加信息
      • 二:作为查询字符串附加在URL后面
13.2.4 获取Session
  1. Servlet中获得
    • request.getSession(boolean)
      • false:有session时返回该session,没有时返回null
      • true:有session时返回该session,没有时创建该session
    • request.getSession():与传true等价
  2. JSP访问
    • JSP通过内置对象session直接访问
13.2.5 删除Session与设置过期Session

注意:关闭浏览器只会使存储在客户端浏览器内存中的session cookie失效,不会使服务器端的session对象失效,但会标记为不可用,等到超过时间时,才会被垃圾回收机制回收

  1. session删除
    • 程序调用HttpSession.invalidate()

      java 复制代码
      HttpSession session = request.getSession();
      session.invalidate();
    • 距离上一次收到客户端发送的session id时间间隔超过了session的最大有效时间

    • 服务器进程被停止

  2. session过期
    • 访问的间隔过了最大过期时间
    • 调用session的invalidate方法
    • WebServer停止运行
13.2.6 Session常用方法
  • 设置超时时间

    • web.xml文件中控制session过期时间
    java 复制代码
    <session-config>
      <session-timeout>15</session-timeout>//单位是:分钟
    </session-config>
13.2.7 HttpSession 生命周期
  1. session对象的创建时期
    • 若当前的 JSP(或 Servlet) 是客户端访问的当前 WEB 应用的第一个资源,且 JSP 的 page 指定的 session 属性值为 false, 则服务器就不会为 JSP 创建一个 HttpSession 对象
    • 若当前 JSP 不是客户端访问的当前 WEB 应用的第一个资源,且其他页面已经创建一个 HttpSession 对象,则当前 JSP 页面会返回一个会话的 HttpSession 对象,而不会创建一个新的 HttpSession 对象
  2. session="false"
    • 当前 JSP 页面禁用 session 隐含变量!但可以使用其他的显式的 HttpSession 对象
  3. 对于 Serlvet 而言:若 Serlvet 是客户端访问的第一个 WEB 应用的资源,则只有调用了 request.getSession()request.getSession(true)才会创建 HttpSession 对象
  4. 会话结束session销毁
13.3.1 Cookie机制
  • Cookie机制是在客户端保存 HTTP 状态信息

  • 一旦WEB浏览器保存了某个Cookie,那么它在以后每次访问该WEB服务器时,都会在HTTP请求头中将这个Cookie回传给WEB服务器

  • 底层的实现原理

    浏览器自动实现

    • WEB服务器通过在HTTP响应消息中增加Set-Cookie响应头字段将Cookie信息发送给浏览器
    • 浏览器则通过在HTTP请求消息中增加Cookie请求头字段将Cookie回传给WEB服务器
  • 一个Cookie只能标识一种信息,它至少含有一个标识该信息的名称(NAME)和设置值(VALUE)。

  • 一个WEB站点可以给一个WEB浏览器发送多个Cookie

  • 一个WEB浏览器也可以存储多个WEB站点提供的Cookie

13.3.2 Servlet程序中使用Cookie
  • javax.servlet.http.Cookie类来封装Cookie信息
  • Cookie类的方法
    • 构造方法:public Cookie(String name,String value)

    • getName方法

    • setValue与getValue方法

    • setMaxAge与getMaxAge方法

    • setPath与getPath方法

    • addCookie方法

      • HttpServletResponse接口中定义了一个addCookie方法
      • 用于在发送给浏览器的HTTP响应消息中增加一个Set-Cookie响应头字段
      java 复制代码
      Cookie ageCookie = new Cookie("age", "25");
      response.addCookie(ageCookie);
    • getCookies方法

      • HttpServletRequest接口中定义了一个getCookies方法
      • 用于从HTTP请求消息的Cookie请求头字段中读取所有的Cookie
      java 复制代码
      Cookie[] cookies = request.getCookies();
13.3.3 发送Cookie
  1. 创建Cookie对象
  2. 设置最大时效
  3. 将Cookie放入到HTTP响应报头
  • 如果创建了一个cookie,并将他发送到浏览器,默认情况下它是一个会话级别的cookie; 存储在浏览器的内存中,用户退出浏览器之后被删除
  • 若希望浏览器将该cookie存储在磁盘上,则需要使用maxAge,并给出一个以为单位的时间
  • 最大时效设为0则是命令浏览器删除该cookie
  • 发送cookie需要使用HttpServletResponse的addCookie方法,将cookie插入到一个 Set-Cookie HTTP响应报头
  • 由于这个方法并不修改任何之前指定的Set-Cookie报头,而是创建新的报头,因此将这个方法称为是addCookie,而非setCookie
13.3.4 会话cookie和持久cookie的区别
  1. 会话cookie
    • 生命期为浏览器会话期的cookie被称为会话cookie
    • 如果不设置过期时间,则表示这个cookie生命周期为浏览器会话期间,只要关闭浏览器窗口,cookie就消失了
    • 会话cookie一般不保存在硬盘上而是保存在内存
  2. 持久cookie
    • 如果设置了过期时间,浏览器就会把cookie保存到硬盘上,关闭后再次打开浏览器,这些cookie依然有效直到超过设定的过期时间
    • 存储在硬盘上的cookie可以在不同的浏览器进程间共享,对于保存在内存的cookie,不同的浏览器有不同的处理方式
13.3.5 读取Cookie
  1. 调用request.getCookies

    • 要获取浏览器发送来的cookie,需要调用HttpServletRequest的getCookies方法,这个调用返回Cookie对象的数组,对应由HTTP请求中Cookie报头输入的值

      java 复制代码
      Cookie[] cookies = request.getCookies();
  2. 对数组进行循环

    • 调用每个cookie的getName方法,直到找到获取的cookie数据为止

      java 复制代码
      for(Cookie cookie : cookies) {
      	out.print(cookie.getName() + cookie.getValue() + "<br>");
      }

14. ServletContext

14.1 ServletContext

  • 启动时创建,停止时消亡
  • 只有一份,单态类
  • application对象的实例接口

14.2 application域

  • application域范围的属性
    • application对象的属性
      • application 对象(ServletContext对象)内部有一个哈希表集合对象,存储进application对象内的哈希表集合对象中的每对关键字/值被称为application对象的属性
    • application域范围的属性
      • 存储在application对象中的属性称之为application域范围的属性
      • application域范围的属性被当作该WEB应用程序范围内的全局变量使用
  • 四大用于application域范围的属性方法
    • getAttributeNames方法
    • getAttribute方法
    • removeAttribute方法
    • setAttribute方法

14.3 内置对象

14.4 获得其他隐式对象

  • getException方法返回exception隐式对象
  • getPage方法返回page隐式对象
  • getRequest方法返回request隐式对象
  • getResponse方法返回response隐式对象
  • getServletConfig方法返回config隐式对象
  • getServletContext方法返回application隐式对象
  • getSession方法返回session隐式对象
  • getOut方法返回out隐式对象

14.5 四个域对象

  • pageContext:当前页面起作用
  • request:当前请求起作用
  • session:当前会话起作用
  • application:应用程序的上下文起作用

15. 文件上传和下载

15.1 表单文件上传

15.1.1 <input type="file"/>
  • 浏览器会自动生成一个输入框和按钮
    • 输入框让用户填写本地文件的文件名和路径名
    • 按钮让浏览器打开一个文件选择框让用户选择文件
  • 需要将文件传送到服务器的某个目录中,而且还要修改文件名称(为了避免名字重复,进行名字的统一命名管理)
15.1.2 Enctype 属性
  • 表单上传文件时,必须指定表单 enctype属性的值为 multipart/form-data
  • 在form表单中,enctype 属性指定将数据发送到服务器时浏览器使用的编码类型
  • enctype 的属性值
    • application/x-www-form-urlencoded

      • 表单 enctype 属性的默认值,表示使用有限的字符集
      • 当使用了非字母和数字时,必须用"%HH"代替(H 代表十六进制数字)
      • 不满足大容量的二进制数据或包含非 ASCII 字符的文本
      html 复制代码
      <form action="/submit" method="post" enctype="application/x-www-form-urlencoded">
        <input type="text" name="username" value="John Doe">
        <input type="submit" value="Submit">
      </form> 
    • multipart/form-data

      • 表示表单以二进制传输数据
      html 复制代码
      <form action="/upload" method="post" enctype="multipart/form-data">
        <input type="text" name="username" value="John Doe">
        <input type="file" name="file">
        <input type="submit" value="Upload">
      </form> 
15.1.3 Commons-fileupload 组件
  • Apache 开源代码组织用来处理表单文件上传的一个子项目,可以支持任意大小的文件的上传
  • 从 1.1 版本开始依赖 Apache 的另一个项目:commons-io
  • 使用到的三个接口和类
    • ServletFileUpload:负责处理上传的文件数据,并将每部分的数据封装到一个FileItem对象中
    • DiskFileItemFactory: 是创建 FileItem 对象的工厂,该工厂类中可以配置内存缓冲区大小和存放临时文件的目录
  • ServletFileUpload 在接收上传文件数据时,会将内容保存到内存缓存区
    • 如果文件内容超过了 DiskFileItemFactory 指定的缓冲区的大小,那么文件将被保存到磁盘上,存储为 DiskFileItemFactory 指定目录中的临时文件
    • 等文件数据都接收完毕后,ServletUpload 在从文件中将数据写入到上传文件目录下的文件中
15.1.4 fileupload 上传基本原理
  • FileUpload组件将页面提交的所有元素(普通form表单域,如text和文件域file)都看作一样的FileItem
  • 因此上传页面提交的 request请求也就是一个FileItem的有序组合,FileUpload组件可以解析该request,并返回一个FileItem
  • 对于每一个FileItem,FileUpload组件可以判断出它是普通form表单域还是文件file域,从而根据不同的类型,采取不同的操作
    • 如果是表单域,就读出其
    • 如果是文件域,就保存文件到服务器硬盘上或者内存中
15.1.5 具体步骤
  1. 设置页面formenctypemultipart/form-data

  2. 需要创建要上传文件的接受路径文件(即要将文件存储到服务器的某个目录中)

    • 文件的真实保存路径并不在源代码的upload中,而是在Tomcat的发布路径的upload
  3. 需要将上传文件进行处理,获取表单提交的文本数据和文件数据(通过该form提交的既有文件也有正常数据)

    • 3.1 获取存储上传的文件的地址路径

      • String path = request . getServletContext() . getRealPath("服务器存储文件的路径");
    • 3.2 创建磁盘上传文件工厂(DisKFileItemFactory

      • DiskFileItemFactory: 是创建 FileItem 对象的工厂,该工厂类中可以配置内存缓冲区大小和存放临时文件的目录
      • 两种创建方法
        • DiskFileItemFactory dff = new DiskFileItemFactory("临时存放路径的位置","临时存放路径的大小");
        • DiskFileItemFactory dff = new DiskFileItemFactory()
    • 3.3 创建文件临时上传的handler

      • ServletFileUpload:负责处理上传的文件数据,并将每部分的数据封装到一个FileItem对象中
      • ServletFileUpload sf = new ServletFileUpload(dff);
    • 3.4 获取到所有表单请求的数据并将其存放进容器中,将request转化为DiskFileItem

      • List<DiskFileItem> lst = sf . parseRequest(request)
      • 会报异常
      • 会根据表单提交的request请求,将所有请求的数据放到list集合
    • 3.5 遍历获取到的容器中的数据,判断是纯文本数据还是文件

      java 复制代码
      for(FileItem  fileItem ; lst) {
           if(fileItem . isFormFiled()) {
                 //判断代表纯文本
           } else {
                 //代表是文件
           }
      }  
      • fileItem.isFormFiled()用于判断该fileItem 是不是纯文本
      • 如果是纯文本
        • fileItem.getFileName()
          - fileItem.getFileName()获取文本的name的属性值,相当于表单中的name属性
        • fileItem.getString("utf-8")
          • fileItem.getString()获取文本value的属性值,相当于表单中的value属性
          • getString可以获取表单中的任意一个的值,因此必须先getFileName()判断name,再获取value
          • 不写参数"utf-8"可能会出现乱码问题,因为对request设置的编码在 sf . parseRequest(request)时就将request转化了
        • 一般先判断name属性值是不是自己想要的属性值,是再getString()获取其对应的属性值;不是则不获取
      • 如果是文件
        • 3.5.1 先获取文件的上传名称
          • String fileName = fileItem . getName()
        • 3.5.2 判断文件是否为空
          • 若文件不为空
            • 1.统一管理上传文件的名称
              • fileName = System.currentTimeMillis() + fileName.substring(fileName . lastIndexOf(" . "));
              • System.currentTimeMillis()表示当前的时间戳
            • 2.构建该文件
              • File file = new File(path + File.separator + fileName );
              • File.separator 用于动态构建目录路径,并使用 File 类的 mkdirs 方法创建目录
            • 3.将fileItem文件写入file文件中(将文件保存中Tomcat发布路径下的upload文件中)
              • fileItem.write(file);
            • 4.持久化file文件(即将fileName存入数据库)
      java 复制代码
      //1.获取存储上传的文件的地址路径
      String path = request.getServletContext().getRealPath("/upload");
      //2.创建磁盘上传文件工厂(DisKFileItemFactory)
      DiskFileItemFactory dff = new DiskFileItemFactory();
      //3.创建文件临时上传的handler
      ServletFileUpload sf = new ServletFileUpload(dff);
      //4.获取到所有表单请求的数据并将其存放进容器中,将request转化为DiskFileItem
      try {
      	List<FileItem> list = sf.parseRequest(request);
      	for(FileItem fileItem : list) {
      		//判断是不是纯文本
      		if(fileItem.isFormField()) {
      			//纯文本
      			//获取表单的文本信息并将其持久化(添加数据载体BookInfo中)
      			if("bookName".equals(fileItem.getFieldName())) {
      				bookInfo.setBookName(fileItem.getString("utf-8"));
      			}	
      			if("author".equals(fileItem.getFieldName())) {
      				bookInfo.setAuthor(fileItem.getString("utf-8"));
      			}
      			if("pbName".equals(fileItem.getFieldName())) {
      				bookInfo.setPbName(fileItem.getString("utf-8"));
      			}
      			if("bookTypeId".equals(fileItem.getFieldName())) {
      				bookInfo.setBookTypeId(Integer.parseInt(fileItem.getString("utf-8")));
      			}
      			DateFormat dateFormat = new SimpleDateFormat("yyyy-mm-dd");
      			if("pbdate".equals(fileItem.getFieldName())) {
      				bookInfo.setPbdate(dateFormat.parse(fileItem.getString("utf-8")));
      			}
      			if("sjdate".equals(fileItem.getFieldName())) {
      				bookInfo.setSjdate(dateFormat.parse(fileItem.getString("utf-8")));
      			}
      			if("price".equals(fileItem.getFieldName())) {
      				bookInfo.setPrice(Float.parseFloat(fileItem.getString("utf-8")));
      			}
      			if("hyprice".equals(fileItem.getFieldName())) {
      				bookInfo.setHyprice(Float.parseFloat(fileItem.getString("utf-8")));
      			}
      			if("bookStates".equals(fileItem.getFieldName())) {
      				bookInfo.setBookStates(Integer.parseInt(fileItem.getString("utf-8")));
      			}
      			if("num".equals(fileItem.getFieldName())) {
      				bookInfo.setNum(Integer.parseInt(fileItem.getString("utf-8")));
      			}
      			if("context".equals(fileItem.getFieldName())) {
      				bookInfo.setContext(fileItem.getString("utf-8"));
      			}
      		} else {
      			//文件
      			//1.先获取文件的上传名称
      			String fileName = fileItem.getName();
      			//2.判断文件是否为空
      			if(!fileName.equals("")) {
      				//2.1 统一管理上传文件的名称
      				fileName = System.currentTimeMillis() + 
      						fileName.substring(fileName.lastIndexOf("."));
      				//2.2 构建该文件
      				File file = new File(path + File.separator + fileName);
      				//2.3 将fileItem文件写入file文件中
      				fileItem.write(file);
      				//2.4 持久化file文件(即将fileName存入数据库)
      				bookInfo.setBigImg(fileName);
      			}
      		}
      	}
      
      } catch (FileUploadException e1) {
      	// TODO Auto-generated catch block
      	e1.printStackTrace();
      } catch (ParseException e) {
      	// TODO Auto-generated catch block
      	e.printStackTrace();
      } catch (Exception e) {
      	// TODO Auto-generated catch block
      	e.printStackTrace();
      }

15.2 文件下载

  • 必设报头(两个)
    1. Content-Type:application/x-msdownload
      • Web 服务器需要告诉浏览器其所输出的内容的类型
      • 其类型不是普通的文本文件或 HTML 文件,而是一个要保存到本地的下载文件
    2. 设置 Content-Disposition 报头
      • Web 服务器希望浏览器不处理相应的文件内容,而是由用户选择将相应的文件内容保存到一个文件中
      • 该报头指定了接收程序处理数据内容的方式
        • HTTP 应用中只有 attachment 是标准方式
        • attachment 表示要求用户干预
        • attachment 后面还可以指定 filename参数
        • 该参数是服务器建议浏览器将实体内容保存到文件中的文件名称
      • 注意:在设置 Content-Dispostion 之前一定要指定 Content-Type
  • 下载需要将服务器的数据写到客户端
  • 文件内容的写入
    • 因为要下载的文件可以是各种类型的文件,所以将文件传送给客户端时,其相应内容应该被当做二进制来处理
    • 应该调用方法返回 ServeltOutputStream 对象来向客户端写入文件内容

16. 富文本编辑器(KindEditor)

  • KindEditor 是一套开源的在线HTML编辑器
    • 主要用于让用户在网站上获得所见即所得编辑效果
  • 开发人员可以用 KindEditor 把传统的多行文本输入框(textarea)替换为可视化的富文本输入框
  • KindEditor 使用 JavaScript 编写,可以无缝地与 Java、.NET、PHP、ASP 等程序集成
  • kindeditor替换文本域
    • 参考kindeditor文件夹下jsp文件夹下的demo.jsp文件里面怎么使用kindeditor替换文本域
    • 使用kindeditor完成项目中所有文本域的替换
    • 使用kindeditor完成文件上传
    • kindeditor文件上传所依赖的jar包
      • commons-io.jar
      • fileupload.jar
      • json-simple.jar
javascript 复制代码
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%
request.setCharacterEncoding("UTF-8");
String htmlData = request.getParameter("content1") != null ? request.getParameter("content1") : "";
%>
<!doctype html>
<html>
<head>
	<meta charset="utf-8" />
	<title>KindEditor JSP</title>
	<link rel="stylesheet" href="../themes/default/default.css" />
	<link rel="stylesheet" href="../plugins/code/prettify.css" />
	<script charset="utf-8" src="../kindeditor.js"></script>
	<script charset="utf-8" src="../lang/zh-CN.js"></script>
	<script charset="utf-8" src="../plugins/code/prettify.js"></script>
	<script>
		KindEditor.ready(function(K) {
			var editor1 = K.create('textarea[name="content1"]', {
				cssPath : '../plugins/code/prettify.css',
				uploadJson : '../jsp/upload_json.jsp',
				fileManagerJson : '../jsp/file_manager_json.jsp',
				allowFileManager : true,
				afterCreate : function() {
					var self = this;
					K.ctrl(document, 13, function() {
						self.sync();
						document.forms['example'].submit();
					});
					K.ctrl(self.edit.doc, 13, function() {
						self.sync();
						document.forms['example'].submit();
					});
				}
			});
			prettyPrint();
		});
	</script>
</head>
<body>
	<%=htmlData%>
	<form name="example" method="post" action="demo.jsp">
		<textarea name="content1" cols="100" rows="8" style="width:700px;height:200px;visibility:hidden;"><%=htmlspecialchars(htmlData)%></textarea>
		<br />
		<input type="submit" name="button" value="提交内容" /> (提交快捷键: Ctrl + Enter)
	</form>
</body>
</html>
<%!
private String htmlspecialchars(String str) {
	str = str.replaceAll("&", "&amp;");
	str = str.replaceAll("<", "&lt;");
	str = str.replaceAll(">", "&gt;");
	str = str.replaceAll("\"", "&quot;");
	return str;
}
%>

17. 过滤器(Filter)

17.1 过滤器Filter

17.1.1 Filter简介
  • Filter 是对 Servlet 容器调用 Servlet 的过程进行拦截,从而在 Servlet 进行响应处理的前后实现一些特殊的功能
  • 三个接口类
    • Filter:过滤器
    • FilterChain:过滤器链
    • FilterConfig:过滤器的配置信息
  • Filter 程序是一个实现了 Filter 接口的 Java 类,由 Servlet 容器进行调用和执行
  • Filter 程序需要在 web.xml 文件中进行注册和设置它所能拦截的资源
  • 只要是http访问的路径地址,过滤器都可以拦截,如: Jsp, Servlet, 静态图片文件和静态 html 文件
17.1.2 Filter 的过滤过程
  • 过滤器是向Web应用程序在请求前和响应后添加新功能的组件
17.1.3 过滤器实现
  1. init()
  2. destroy()
  3. doFilter()
17.1.4 过滤器生命周期
  • 过滤器在服务器启动的时候就被实例化、初始化了
17.1.5 过滤器工作原理
  • Filter 可以对 请求和响应进行拦截
  • 可以决定是否将请求继续传递给 Servlet 程序,以及对请求和响应信息是否进行修改
  • 一个 web 应用程序中可以注册多个 Filter 程序,每个 Filter 程序都可以对一个或一组 Servlet 程序进行拦截
  • 若有多个 Filter 程序对某个 Servlet 程序的访问过程进行拦截,web 容器将把这多个 Filter 程序组合成一个 Filter 链(过滤器链)
  • Filter 链中各个 Filter 的拦截顺序与它们在应用程序的 web.xml 中映射的顺序一致

17.2 三个接口

17.2.1 Filter 接口

使用过滤器,必须实现Filter接口

  • init()
    • 在 web 应用程序启动时,服务器根据 web.xml 文件中的配置信息来创建每个注册的 Filter 实例对象,并将其保存在服务器的内存中
    • Web容器创建 Filter 对象实例后,将立即调用该 Filter 对象的 init 方法
    • Init 方法在 Filter 生命周期中仅执行一次
    • web 容器在调用 init 方法时,会传递一个包含 Filter 的配置和运行环境的FilterConfig 对象
  • destroy()
    • 在Web容器卸载 Filter 对象之前被调用
    • destroy方法在Filter的生命周期中仅执行一次
  • doFilter()
    • 当客户端请求目标资源的时候,容器就会调用与这个目标资源相关联的过滤器的doFilter()方法
    • 参数 request(ServletRequest), response (ServletResponse)为 web 容器或 Filter 链的上一个 Filter 传递过来的请求和相应对象
    • 调用 chain.doFilter()方法才能把请求交付给 Filter 链中的下一个 Filter 或者目标 Servlet 程序去处理
    • 该方法的请求和响应参数的类型是ServletRequest和ServletResponse,因此过滤器的使用并不依赖于具体的协议
17.2.2 FilterChain接口
  • FilterChain接口:代表当前 Filter 链的对象
  • 由容器实现,容器将其实例作为参数传入过滤器对象的doFilter()方法中
  • 过滤器对象使用FilterChain对象调用过滤器链中的下一个过滤器或目标资源
  • doFilter(ServletRequest request,ServletResponse response):该方法用于调用过滤器链中的下一个过滤器或目标资源
  • 过滤器链
17.2.3 FilterConfig接口
  • FilterConfig接口:可以获取ServletContext对象,以及部署描述符中配置的过滤器的初始化参数
  • web 容器在调用 init 方法时,会传递一个包含 Filter 的配置和运行环境的 FilterConfig 对象
  • 初始化参数
    • <init-param>标签
      • <init-param>标签用于在web.xml文件中定义初始化参数
      • <param-name>用于定义初始化参数的名字
      • <param-value>用于定义初始化参数的值
    • fConfig.getInitParameter("name"):用于获取初始化配置参数的值

17.3 过滤器的部署

实现过滤器后,需要使用和元素在 web.xml 中进行注册和设置它所能拦截的资源

17.3.1 <filter> 元素
  • <filter>元素用于在Web应用程序中注册一个过滤器
  • <filter-name>:用于为过滤器指定一个名字,该元素的内容不能为空
  • <filter-class>:用于指定过滤器的完整的限定类名
  • <init-param>:用于为过滤器指定初始化参数
    • <param-name>:用于指定参数的名字
    • <param-value>:用于指定参数的值
    • 可以使用FilterConfig接口对象来访问初始化参数
17.3.2 <filter-mapping>元素
  • 用于设置一个 Filter 所负责拦截的资源
  • <filter-name>子元素
    • 用于设置filter的注册名称
    • 该值必须是在元素中声明过的过滤器的名字
  • <url-pattern>子元素
    • 设置 filter 所拦截的请求路径(即过滤器要过滤的目标地址)
    • 如果有多个过滤器同时拦截该资源,那么写在前面的过滤器先拦截,写在后面的后拦截
    • 请求路径
      • /*:表示拦截所有
      • /admin/*:表示拦截admin下的所有
      • /admin/index.jsp:表示拦截admin下的index.jsp
  • <dispatcher>
    • 指定过滤器所拦截的资源被 Servlet 容器调用的方式
    • 可以是request,include,forward和error之一,默认request.
    • 可以设置多个 子元素用来指定 Filter 对资源的多种调用方式进行拦截
17.3.3 过滤器部署

若一个 Filter 链中多次出现了同一个 Filter 程序,这个 Filter 程序的拦截处理过程将被多次执行

  • 可以通过元素为多个应用程序进行拦截
  • 可以为一个应用程序设置多个过滤器
    • Filter 链中各个 Filter 的拦截顺序与它们在应用程序的 web.xml 中映射的顺序一致

18. EL表达式

18.1 EL简介

  • EL:Expression Language 表达式语言
  • EL是JSP内置的表达式语言,用来访问页面上下文以及不同作用域对象
  • EL表达式相当于替代了JSP中的 "<%= %> "
  • 注意
    • EL表达式只能读取数据,不能修改数据
    • 使用EL表达式输出数据时,输出数据存在则输出,不存在(为null)则不输出,但是不会报错
  • EL作用
    • EL主要做输出显示
    • EL与JSTL代替JSP页面中的脚本元素与动作元素

18.2 EL基本语法

  • 注意:属性名是getXx和setXx方法对象的属性值,而不是对象中的变量名
    • 如:变量名为myName,但是EL是${user.name},那么该user对象中的get方法必定为getName()
    • ${对象.属性名} 中的属性名对应的是getXxx方法中的Xxx,而不是变量名
18.2.1 基础语法
  • 基本语法:${EL表达式}
18.2.2 获取域中的对象时
  • 直接使用对象名获取
    如:获取域中name为"user"的对象:${user}
18.2.3 获取对象的属性时
  • 方法一
    • 使用"${对象 . 属性名}"获取
    • 如:获取name为user的user对象的年龄:${user . age}
  • 方法二
    • 使用" ${对象 [ "属性名" ] }" 获取
    • 如:获取name为user的user对象的年龄:${user["age"]}
  • 注意:EL在反射时,会自己在属性名前面加上get,然后去寻找该对象中与之对应的get方法
    • 如:${user . age},EL会自动的在age前面加上get,变成getAge,然后去user对象中寻找getAge()方法
18.2.4 获取Map中属性时
  • 方法一
    • 直接通过key获取value:${map . key}
    • 如:获取map集合中key为1的值:${map . }
  • 方法二
    • 直接通过key获取value:${map[ key ]}
    • 如:获取map集合中key为1的值:${map . }
18.2.5 获取List中属性时
  • 直接通过下标获取:${list[ index ]}
  • 如:获取list集合中下标为1的学生对象的姓名:${list[1].studentName }
18.2.6 指定域中获取属性
  • 默认获取
    • 在EL表达式中直接使用属性名时会在四大作用域中按照从下到大依次查找
    • 四大域从小到大顺序为:pageScope、requestScope、sessionScope、applicationScope
  • 指定域获取
    • 当前页面作用域获取:${ pageScope .name}
    • 当前请求作用域获取:${requestScope.name}
    • 当前会话作用域获取:${sessionScope.name}
    • 应用程序上下文获取:${applicationScope.name}

18.3 禁用EL

<%@ page isELIgnored ="true|false" %>

18.4 EL隐式对象

  • 在EL中要使用request、response等jap其他八大内置对象时需要通过pageContext中获取
  • 如:${pageContext.request.servletPath }

18.5 empty运算符

  • empty 运算符主要用来判断值是否为null 或空的
  • 如:${ empty param . name }

19. JSTL

19.1 JSTL简介

  • JSTL:JavaServer Pages Standard Tag Library,JSP 标准标签函数库
  • JSTL和EL配合使用可以JSP页面中的脚本元素与动作元素

19.2 JSTL标签库

19.3 核心标签库

  • jstl.jar包
    • 必须在项目中导入jstl.jar包
    • 在JSP页面中通过taglib标签引入标签库
    • taglib标签
      • <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
      • prefix:用来指定前缀名,通过该名来使用JSTL,可以自定义,默认为 c
      • uri:相当于库的唯一标识,该属性指定要导入哪个库

19.4 <c:out>输出

  • 参数
    • value:需要显示出来的值
    • default:value值为null时,则显示default的值
    • escapeXml:是否转换特殊字符

19.5 <c:set>设置

  • 参数
    • value:要被储存的值
    • var:存入的变量名称
    • scope:var变量的jsp范围
    • target:为javaBean或Map对象
    • property:指定target对象的属性

19.6 <c:remove>移除

  • 参数
    • var:移除变量的名称
    • scope:var变量的JSP范围

19.7 流程控制

  • 参数
    • test:如果表达式为true,则执行;false则不执行
    • var:储存test运算的结果,即true或false
    • scope:var变量的JSP范围
19.7.1 <c:if>
  • 该标签只有if,没有else
19.7.2 <c:choose>
  • 只当做 <c:when> 和<c:otherwise> 的父标签
  • 子标签
    • <c:when>
    • <c:otherwise>
19.7.3 <c:forEach>循环
  • 参数
    • items:指被迭代的集合对象(为EL表达式)
    • var:代表循环的每个变量名
    • varStatus:表示用来存放现在指向的相关成员信息
      • varStatus . index:获取下标
      • varStatus . count:获取数量
    • begin:开始的位置
    • end:结束的位置
    • step:每次迭代的间隔数

19.8 <c:redirect>跳转

  • 参数
    • url:表示要跳转的路径

19. 监听器

19.1 监听器简介

  • 监听器是专门用于对其他对象身上发生的事件或状态改变进行监听和处理的对象
  • 当被监视的对象发生情况时,立即采取相应的行动
  • 定义
    • 一个实现监听器接口的类
    • 一个要在web.xml配置的类
  • 一句话定义监听器
    • 监听器就是可以在application、session、request三个对象创建、消亡或者往其中添加、修改、删除属性时能自动执行代码的组件
  • Servlet监听器
    • 用于监听web应用程序中的ServletContext、HttpSession、ServletRequest等域对象的创建与销毁以及属性发生改变的事件
  • 何时监听
    • 创建时候监听
    • 消亡时候监听
    • 属性改变的时候监听:添加、修改、删除属性

19.2 监听器接口

  • request
    • ServletRequestListener:监听ServletRequest对象的创建和消毁
    • ServletRequestAttributeListener:监听ServletRequest对象中属性的增加、删除和修改
  • session
    • HttpSessionListener:监听HttpSession对象的创建和销毁
    • HttpSessionAttributeListener:监听HttpSession对象中属性的增加、删除和修改
  • application
    • ServletContextListener:监听ServletContext对象的创建和销毁
    • ServletContextAttributeListener:监听ServletContext对象中属性的增加、删除和修改

19.3 Servlet监听器

19.3.1 分类

按监听的事件类型分类

  • 监听域对象的创建和销毁的事件监听器
  • 监听域对象中属性的增加和删除的事件监听器
  • 监听绑定到HttpSession域中某个对象状态的事件监听器
19.3.2 监听域对象的创建和销毁
  • ServletContextListener 接口
    • 用于监听 ServletContext 对象的创建和销毁事件
    • 被创建时
      • 激发contextInitialized (ServletContextEvent sce)方法
    • 被销毁时
      • 激发contextDestroyed(ServletContextEvent sce)方法
  • HttpSessionListener 接口
    • 用于监听HttpSession对象的创建和销毁
    • 被创建时
      • 激发sessionCreated(HttpSessionEvent se) 方法
    • 被销毁时
      • 激发sessionDestroyed (HttpSessionEvent se) 方法
  • ServletRequestListener接口
    • 用于监听ServletRequest 对象的创建和销毁
    • 被创建时
      • 激发requestInitialized(ServletRequestEvent sre)方法
    • 被销毁时
      • 激发requestDestroyed(ServletRequestEvent sre)方法
19.3.3 监听域对象属性的增加、删除和修改
  • 接口
    • ServletContextAttributeListener接口
      • 用于监听ServletContext域对象属性的增加、删除和修改
    • HttpSessionAttributeListener接口
      • 用于监听HttpSession域对象属性的增加、删除和修改
    • ServletRequestAttributeListener接口
      • 用于监听ServletRequest域对象属性的增加、删除和修改
  • 方法
    • 同一个事件在这三个接口中对应的方法名称完全相同,只是接受的参数类型不同
    • attributeAdded 方法
      • 当向被监听器对象中增加属性时,web容器就调用该方法进行相应
      • 该方法接受一个事件类型的参数,监听器通过该参数获得增加属性的域对象和被保存到域中的属性对象
      • 三大域属性监听器
        • getName():获取新添加域对象的属性名
        • getValue():获取新添加域对象的属性值
    • attributeRemoved 方法
      • 当删除被监听对象中的属性时,web 容器调用该方法进行相应
      • 三大域属性监听器
        • getName():获取要移除域对象的属性名
        • getValue():获取要移除域对象的属性值
    • attributeReplaced 方法
      • 当监听器的域对象中的属性被替换时,web容器调用该方法进行相应
      • 三大域属性监听器
        • getName():获取替换前域对象的属性名
        • getValue():获取替换前域对象的属性值

19.4 web.xml

19.4.1 标签
  • 用于告诉web应用程序在哪个xml中加载监听器
  • 子标签:指定参数名
  • 子标签:指定参数值
19.4.2 标签
  • 子标签:用于指定监听器的完整类名

20. 一个Servlet处理多个请求

20.1 方法一:if判断

  • 在一个Servlet类中写多个方法,获取页面传递来的方法名称,用if语句判断对应哪个方法,直接调用

20.2 方法二:反射机制

  1. 先写一个servlet,并重写里面的service方法,然后让实现业务的servlet继承该servlet
  2. 书写service方法。该service方法虽然写在该servlet中,但本质是实现业务的servlet的service方法
    • 2.1 先获取到页面请求的方法名称。(注:页面的请求方法名称必须与实现业务Servlet类里的方法名称一样)

    • 2.2 根据获取到的方法名称以及形参查找对应类中的方法并返回查找到的方法

      • this.getClass():用于获取当前对象的运行时类信息,返回值是一个Class对象
      • getMethod(String name, Class<?>... parameterTypes):用于获取指定名称和参数类型的公共方法,返回值是个Method
      • name: 参数是要获取的方法的名称。
      • parameterTypes :参数是一个 Class 对象数组,表示方法的参数类型
    • 2.3 利用实参动态调用获取到对应类中的方法

      • Method . invoke(Object obj, Object... args):用于动态调用由 Method 对象表示的方法,返回值是目标方法的返回值
      • 第一个参数 obj:表示要在哪个对象实例上执行该方法
      • 后续参数 args:表示传递给方法的实际参数。
    • 2.4 判断invoke方法捕获的返回值

      • 1:以"redirect:"开头的则为重定向
      • 2:否则就是请求转发
java 复制代码
String methodName = req.getParameter("method");

try {
    Method returnMethod = this.getClass().getMethod(methodName, HttpServletRequest.class, HttpServletResponse.class);
    String str = (String) returnMethod.invoke(this, req, resp);
    if (str.startsWith("redirect:")) {
        resp.sendRedirect(str.substring(str.lastIndexOf(":") + 1));
    } else {
        req.getRequestDispatcher(str).forward(req, resp);
    }
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
    // Handle exceptions appropriately
}

21. Servlet 3详解

21.1 Servlet 3新特性

  • Servlet、Filter、Listener等无需在web.xml中进行配置,可以通过Annotation(注解)进行配置
  • 使用注解的缺点:先将本地代码改完、编译完,才能将其放到服务器中(服务器存放的是class文件)
  • 模块化编程:将各个Servlet模块化,将配置文件也分开配置

21.2 @WebServlet

  • 用于在Web应用中定义Servlet
  • 必须指定注解的urlPatterns或value属性
  • 一般情况:@WebServlet("/WebServletText")
    • 省略了name和value,直接指定了访问的url
  • Servlet类前面加上:@WebServlet(name="",urlPatterns={""},initParams={@WebInitParam(name="",value=""),loadOnStartup=1})
属性 类型 说明 相当于 web.xml 中的 举例
name String 用于指定 Servlet 名称(Servlet 的唯一标识符) <servlet-name></servlet-name> name = "WebServletText"
urlPatterns/value String[ ] 用于指定访问 Servlet 的 URL <url-pattern></url-pattern> value = {"/WebServlet", "/WebServletText"}
loadOnStartup int 用于标记容器是否在应用程序启动时加载这个 Servlet <load-on-startup></load-on-startup> loadOnStartup = 1
initParams WebInitParam[ ] 用于配置初始化参数 <init-param><param-name></param-name><param-value></param-value></init-param> initParams = {@WebInitParam(name="name", value="zhangsan"), @WebInitParam(name="age", value="35")}
displayName String 指定 Servlet 的显示名称,用于描述该 Servlet,帮助管理员和开发人员更容易识别和理解 Servlet 的功能 <display-name></display-name> displayName = "this is a WebServletText"
asyncSupported boolean 指定 Servlet 是否支持异步操作 <async-supported></async-supported> asyncSupported = true

21.3 @WebFilter

  • 用于在Web应用中定义Filter
  • 如果没有指定Filter名字则默认是全限定类名
  • 注解的urlPatterns属性、servletNames 属性 或 value 属性必须被指定
  • 一般情况:@WebFilter("/*")
    • 省略了name和value,直接指定过滤所有路径
  • Filter类前面加上:@WebFilter(filterName="",urlPattern={"/*"})
属性 类型 说明 相当于 web.xml 中的配置 举例
filterName String 类型 指定过滤器的 name <filter-name></filter-name> filterName = "WebFilterText"
value/urlPatterns String[ ] 类型 指定要过滤的路径 <url-pattern></url-pattern> value = {"/admin/", "/demo/"}
servletNames String[ ] 类型 指定过滤器将具体过滤哪些 Servlet。取值是 @WebServlet 中的 name 属性,或者是 web.xml 中 <servlet-name>(webServlet 与 xml 中的 name 属性省略时默认是全类名) <servlet-name></servlet-name> servletNames = {"DemoServlet", "AddServlet"}
initParams WebInitParam[ ] 类型 用于配置过滤器的初始化参数 <init-param><param-name></param-name><param-value></param-value></init-param> initParams = {@WebInitParam(name="name", value = "zhangsan"), @WebInitParam(name="age", value = "39")}
asyncSupported boolean 类型 指定过滤器是否支持异步操作 <async-supported></async-supported> asyncSupported = true
dispatcherTypes DispatcherType 类型 指定过滤器的转发模式。具体取值包括: ASYNC、ERROR、FORWARD、INCLUDE、REQUEST 无直接对应标签,通常在 <filter-mapping> 中配置 dispatcherTypes = {DispatcherType.REQUEST, DispatcherType.FORWARD}

21.4 @WebInitParam

  • 用于配置初始化参数
  • @WebInitParam是WebServlet和WebFilter注解的一个属性
  • 类前面加上:@WebInitParam(name="", value = "")
属性 类型 说明 相当于 web.xml 中的
name String 指定初始化参数的名称 <param-name></param-name>
value String 指定初始化参数的值 <param-value></param-value>
description String 关于参数的描述 <description></description>

21.5 @WebListener

  • 用来获得特定web应用上下文中的各种操作事件的监听器
  • @WebListener注解的类必须实现的接口
    • javax.servlet.ServletContextListener
    • javax.servlet.ServletContextAttributeListener
    • javax.servlet.ServletRequestListener
    • javax.servlet.ServletRequestAttributeListener
    • javax.servlet.http.HttpSessionListener
    • javax.servlet.http.HttpSessionAttributeListener
  • 在Listener类前面加上@WebListener
    • 相当于<listener> <listener-class></listener-class> </listener>

21.6 @MultipartConfig

21.6.1 @MultipartConfig注解
  • 指定在Servlet上时,表示请求期望是mime/multipart类型
  • 相应servlet的HttpServletRequest对象必须使用getParts和getPart方法遍历各个mime附件以获取mime附件
属性 类型 说明
fileSizeThreshold int 当数据量大于该值时,内容将被写入文件。
location String 存放生成的文件地址。
maxFileSize long 允许上传的文件最大值。默认值为-1,表示没有限制。
maxRequestSize long 针对该 multipart/form-data 请求的最大数据量,默认值为-1,表示没有限制。
21.6.2 基于注解实现文件上传
  1. html中 表示文件上传控件

  2. form的 enctype="multipart/form-data"

  3. Servlet类的书写

    • 3.1 在Servlet类前加上 @MultipartConfig
    • 3.2 创建个保存上传文件的文件
    • 3.3 通过.request.getPart("name")获取Part(Part代表上传的文件),参数name是前端文件的name
      • Part part = request.getPart("img");
    • 3.4 获取上传文件的名称
      • String fileName = part.getSubmittedFileName();
    • 3.5 获取存储的路径
      • String uploadPath = request.getServletContext().getRealPath("/upload");
    • 3.6 调用Part.write(文件存储路径),将上传文件保存在后端的存储文件中
      • part.write(uploadPath + File.separator + fileName);
    java 复制代码
    import javax.servlet.ServletException;
    import javax.servlet.annotation.MultipartConfig;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import javax.servlet.http.Part;
    import java.io.File;
    import java.io.IOException;
    
    @WebServlet("/upload")
    @MultipartConfig(
        fileSizeThreshold = 1024 * 1024, // 1 MB
        maxFileSize = 1024 * 1024 * 50,  // 50 MB
        maxRequestSize = 1024 * 1024 * 100 // 100 MB
    )
    public class FileUploadServlet extends HttpServlet {
    
        private static final String UPLOAD_DIRECTORY = "upload";
    
        @Override
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            // 获取上传目录的真实路径
            String uploadPath = getServletContext().getRealPath("") + File.separator + UPLOAD_DIRECTORY;
        
            // 创建上传目录(如果不存在)
            File uploadDir = new File(uploadPath);
            if (!uploadDir.exists()) {
                uploadDir.mkdir();
            }
    
            try {
                // 获取上传的文件部分
                Part filePart = request.getPart("img");
                String fileName = filePart.getSubmittedFileName();
    
                // 将文件写入到指定位置
                filePart.write(uploadPath + File.separator + fileName);
    
                // 响应给客户端
                response.getWriter().println("文件上传成功: " + fileName);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

22. 数据库连接池

22.1 数据库连接池原理

  • 数据库连接池负责分配、管理和释放数据库连接,允许应用程序重复使用现有的数据库连接,而不是重新建立一个
  • 释放空闲时间超过最大空闲时间的数据库连接来避免因为没有释放数据库连接而引起的数据库连接遗漏
  • 原理
    • 在系统初始化的时候,将数据库连接作为对象存储在内存中,当用户需要访问数据库时,并非建立一个新的连接,而是从连接池中取出一个已建立的空闲连接对象
    • 使用完毕后,用户也并非将连接关闭,而是将连接放回连接池中,以供下一个请求访问使用
    • 连接的建立、断开都由连接池自身来管理

22.2 Druid连接池

java 复制代码
InputStream in = new  FileInputStream("db.properties");
Properties pro = new Properties();
pro.load(in);//将文件中的键值对存储在Properties对象中
DataSource ds = DruidDataSourceFactory.createDataSource(pro);//根据Properties中的配置创建DataSource数据源对象
Connection conn = ds.getConnection();//从数据源中获取一个数据库连接对象
22.2.1 Druid简介
  • Druid是一个JDBC组件
  • 包含
    • DruidDriver:代理Driver,能够提供基于Filter-Chain模式的插件体系
    • DruidDataSource:高效可管理的数据库连接池
    • SQLParser
  • 作用
    • 监控数据库访问性能
      • Druid内置提供了一个功能强大的StatFilter插件,能够详细统计SQL的执行性能
    • Druid提供了一个高效、功能强大、可扩展性好的数据库连接池
    • 数据库密码加密
    • SQL执行日志
      • Druid提供了不同的LogFilter,可以按需要选择相应的LogFilter,监控数据库的访问情况
    • 扩展JDBC
      • 通过Druid提供的Filter-Chain机制,很方便编写JDBC层的扩展插件
  • 优势
    • 监控SQL的执行时间、ResultSet持有时间、返回行数、更新行数、错误次数、错误堆栈信息
    • SQL执行的耗时区间分布。通过耗时区间分布,能够知道SQL的执行耗时情况
    • 监控连接池的物理连接创建和销毁次数、逻辑连接的申请和关闭次数、非空等待次数、PSCache命中率
22.2.2 Properties 对象
  • 继承自 Hashtable<Object, Object>,专门用于处理键值对的集合
  • Properties 对象通常用于读取配置文件中的属性
  • 方法
    • load(InputStream inStream)
      • 用于从输入流中加载属性列表
      • load方法会读取文件中的键值对,并将其存储在 Properties 对象中
    • getProperty(String key):返回指定键的属性值
    • setProperty(String key, String value):设置指定键的属性值
22.2.3 DruidDataSourceFactory 类
  • DruidDataSourceFactory 是 Druid 库中的一个类,用于根据配置创建 DataSource 实例
  • 方法
    • createDataSource(Properties properties):根据 Properties 对象中的配置创建一个 DataSource 实例
22.2.4 DataSource接口
  • 位于 javax.sql 包中
  • 代表一个数据源,提供了一种管理和获取数据库连接的标准化方式
  • 数据源可以用于连接池管理,提供更好的性能和资源管理
  • 方法
    • getConnection()
      • 用于从数据源中获取一个数据库连接
      • 如果连接池中有可用的连接,会直接返回;如果没有可用的连接,会根据配置创建新的连接
22.2.5 Druid的使用
  1. 导入Druid的jar包

  2. 将数据库配置信息写入配置文件中,如:db.properties

    • 配置信息不用记,用时百度就行
  3. 利用I/O流读取配置文件

    • InputStream in = DBUtil.class.getResourceAsStream("/db.properties");

    • getResourceAsStream():用于从类路径中加载资源文件

  4. 创建Properties对象,用于存储从配置文件中读取的键值对

    • Properties pro = new Properties();
  5. 调用Properties对象的load(in),将读取到的内容加载到Properties对象中

    • pro.load(in);
  6. 调用DruidDataSourceFactory.createDataSource(pro),根据Properties对象中的配置创建一个 DataSource 实例

    • DataSource ds = DruidDataSourceFactory.createDataSource(pro);
  7. 调用 DataSource 的 getConnection 方法,从连接池中获取一个可用的数据库连接

    • this.conn = ds.getConnection();
    java 复制代码
    import java.io.InputStream;
    import java.sql.Connection;
    import java.util.Properties;
    
    public class DBUtil {
    
        private static Connection conn = null;
    
        public static Connection getConnection() {
            // 获取当前类并从当前类的路径中加载资源文件,并用字节流进行读取
            InputStream in = DBUtil.class.getResourceAsStream("/db.properties");
        
     	   	// 创建Properties对象,用于存储从配置文件中读取的键值对
      	  	Properties pro = new Properties();
        
      	 	 try {
                 // 将InputStream中的内容加载到Properties对象中。
               	 // load方法会读取文件中的键值对,并将其存储在Properties对象中
                 pro.load(in);
            
             	// 根据Properties对象中的配置创建一个DataSource实例
     	       	DruidDataSourceFactory ds = DruidDataSourceFactory.createDataSource(pro);
            
      	      	// 调用DataSource的getConnection方法,从连接池中获取一个可用的数据库连接
      	      	// 如果连接池中有可用的连接,会直接返回;如果没有可用的连接,会根据配置创建新的连接。
       	     	conn = ds.getConnection();
     	   	} catch (IOException e) {
       	     	// 处理IO异常
            	e.printStackTrace();
        	} catch (Exception e) {
            	// 处理其他异常
            	e.printStackTrace();
        	}
        	return conn;
    	}
    }
  • 如果想要监控SQL的执行情况,则需要再web.xml中添加如下代码

    • DruidStatView:是 Druid 连接池提供的一个内置的监控和统计页面。它允许你通过 Web 界面查看和管理数据库连接池的状态和性能指标
    • 除了Servlet标签之外的都是过滤器,只有先进入过滤器才能记录sql的信息

23. kaptcha验证码

  • 使用过程
    1. 下载kaptcha的jar包放在lib中
    2. 在xml中进行配置
    3. 在前端表单中显示验证码
      • 如:<img alt="验证码" src="${pageContext.request.contextPath }/kaptcha">
    4. 在后端通过获取前台用户输入的验证码与session域中的验证码进行比较
      • 如:String sessionCode = (String)request.getSession().getAttribute(Constants.KAPTCHA_SESSION_KEY);
  • kaptcha生成的验证码将其放在session域中,其中name=KAPTCHA_SESSION_KEY,通过Session().getAttribute(Constants.KAPTCHA_SESSION_KEY)可以获取其生成的验证码
  • 本质:是随机数的拼接,然后添加了高度、干扰线之类的,最后输出成图片给前端

24. UUID帮助类

  • 数据库中不能存储明文密码,应该进行加密,此时就可以利用MD5加密类(hutool工具有)
  • UUID帮助类
    • java自带的UUID帮助类可以作为数据库的主键
    • 数据量大时,用int类型就会不够,因此就用UUID帮助生成唯一ID

25. 事务

25.1 事务简介

  • "事务"(Transaction)是指一系列操作,这些操作被视为一个单一的工作单元,要么全部成功完成,要么全部失败回滚
  • 事务管理确保了数据的一致性和完整性,可以防止并发操作导致的数据不一致问题

25.2 事务的四个特性

  • 原子性(Atomicity):事务是一个不可分割的工作单位,事务中的所有操作要么全部完成,要么全部不完成
  • 一致性(Consistency)
    • 事务必须保证数据库从一个一致状态转变为另一个一致状态
    • 事务执行前后,数据库的完整性约束不能被破坏
  • 隔离性(Isolation):多个事务并发执行时,每个事务的执行不应相互干扰
  • 持久性(Durability):一旦事务提交,其对数据库的更改将是永久性的,即使系统发生故障也不会丢失

25.3 常用方法

  • Connection.setAutoCommit(boolean):设置事务的提交方式
    • 参数
      • true:自动提交
      • false:手动提交
  • Connection.commit():提交事务
  • Connection.rollback():事务的回滚
    • 一般写在异常处理中
    • 对于异常的捕获,底层(DB、DAO层)应该向上抛出,一般在控制层或者service中进行捕获处理

26. 日志

26.1 日志介绍

  • 日志文件(logfile)是一个记录了发生在运行中的操作系统或其他软件中的事件文件,或者记录了在网络聊天软件的用户之间发送的消息
  • 日志记录(Logging):是指保存日志的行为

26.2 日志级别

ERROR和FATAL都属于服务器自己的异常,是需要马上得到人工介入并处理的

  • 日志级别优先级
    • ALL < TRACE < DEBUG < INFO < WARN < ERROR < FATAL < OFF
  • 分类
    1. FATAL:表示需要立即被处理的系统级错误
    2. ERROR:该级别的错误也需要马上被处理,但是紧急程度要低于FATAL级别
    3. WARN:该日志表示系统可能出现问题,也可能没有,这种情况如网络的波动等
    4. INFO:该种日志记录系统的正常运行状态
    5. DEBUG or TRACE:该日志规范由项目组自己定义,主要作用是对系统每一步的运行状态进行精确的记录

26.3 日志框架类别

  • Slf4j 是一套简易Java日志门面(接口),本身并无日志的实现
  • Logback 一套日志组件的实现(Slf4j阵营)
  • Log4j 2 是apache开发的一款Log4j的升级产品
  • 常用的组合
    • Slf4j与Logback组合使用
    • Commons Logging与Log4j组合使用

26.4 三大日志

26.4.1 Slf4j
  • Slf4j本身只提供了一个slf4j-api-version.jar包,主要是日志的抽象接口,jar中本身并没有对抽象出来的接口做实现
  • 对于不同的日志实现方案(例如Logback,Log4j...),封装出不同的桥接组件,可以灵活的选取自己项目里的日志实现
26.4.2 logback
  • logback使用需要和slf4j一起使用
  • 所需jar包
    • slf4j-api.jar
    • logback-core.jar
    • logback-classic.jar
    • logback-access.jar
26.4.3 log4j 2
  • 三个主要的组件
    • Loggers(记录器):日志类别
    • Appenders(输出源):日志要输出的地方
    • Layouts(布局):日志以何种形式输出
  • 三个核心概念
    • Logger:公共类,负责处理日志记录的大部分操作
    • Appender:公共接口,负责控制日志记录的输出
    • Layout:公共抽象类,负责格式化Appender的输出
  • Log4j日志系统允许把日志输出到不同的地方
    • org.apache.log4j.ConsoleAppender(控制台)
    • org.apache.log4j.FileAppender(文件)
    • org.apache.log4j.DailyRollingFileAppender(每天产生一个日志文件)
    • org.apache.log4j.RollingFileAppender(文件大小到达指定尺寸的时候产生一个新的文件)
    • org.apache.log4j.WriterAppender(将日志信息以流格式发送到任意指定的地方)
  • 配置文件
    • 不用记,直接百度

26.5 日志的使用

  • 获取日志类

    • public static final Logger log = LoggerFactory.getLogger(BookInfoDao.class);
    • Logger:org.slf4j.Logger中的;
    • LoggerFactory:org.slf4j.LoggerFactory中的;
  • 调用日志方法

    • 如:log.error(e.getMessage());
    • 如:log.info("图书保存成功!");
相关推荐
野犬寒鸦20 分钟前
MySQL索引详解(下)(SQL性能分析,索引使用)
数据库·后端·sql·mysql
.生产的驴5 小时前
SpringBoot 集成滑块验证码AJ-Captcha行为验证码 Redis分布式 接口限流 防爬虫
java·spring boot·redis·分布式·后端·爬虫·tomcat
野犬寒鸦6 小时前
MySQL索引使用规则详解:从设计到优化的完整指南
java·数据库·后端·sql·mysql
思考的橙子6 小时前
Springboot之会话技术
java·spring boot·后端
兆。9 小时前
电子商城后台管理平台-Flask Vue项目开发
前端·vue.js·后端·python·flask
weixin_437398219 小时前
RabbitMQ深入学习
java·分布式·后端·spring·spring cloud·微服务·rabbitmq
西京刀客14 小时前
Go多服务项目结构优化:为何每个服务单独设置internal目录?
开发语言·后端·golang
李匠202414 小时前
C++GO语言微服务之gorm框架操作MySQL
开发语言·c++·后端·golang
源码云商15 小时前
基于Spring Boot + Vue的高校心理教育辅导系统
java·spring boot·后端
黄俊懿16 小时前
【深入理解SpringCloud微服务】手写实现一个微服务分布式事务组件
java·分布式·后端·spring·spring cloud·微服务·架构师