Servlet框架入门

Servlet

Servlet 是 java语言 中 JavaEE 的一个入门级 web框架, 是为了后期 SpringMVC , SpringBoot 框架 打下基础 。是一个 Web 服务、采用 B/S (浏览器/服务器) 架构

B/S架构

互联网中项目 主要 包含 B/S架构 和 C/S架构 , B/S 架构 是 基于 浏览器服务器的架构,是 JavaEE 最大的特点。 C/S架构 是基于 客户端服务器的架构, 安卓开发是 C/S架构。


网址URL的组成

https://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=1&rsv_idx=1&tn=baidu&wd=%E7%BE%8E%E5%A5%B3&fenlei=256

  • 协议: http 、https
  • 域名/主机: www.baidu.com , localhost , 127.0.0.1, 192.168.10.11
  • 端口号 : http协议默认端口号 80 , https 协议 默认端口号 443
  • 请求地址: /s , 是用来 定位 服务器的资源
  • 请求参数: ie=utf-8&f=8 , 浏览器 向 服务器 发送的数据。 请求参数 和 请求地址 以 ? 分割, 多个请求参数 使用 & 分割, 一个请求参数包含 2部分,键和值,且用 = 进行拼接
  • 锚点 : #hash

在浏览器中输入一个网址 、按下回车后会发生什么?


搭建 Servlet 项目

File -> new Project -> Maven -> 勾选 create from archetype -> 在下方的列表中 选中 maven-archetype-webapp -> 下一步 -> 输入 项目名 和 groupId -> 下一步 -> maven


JSP

是 SUN 推出的一款 在 服务端 进行 页面渲染的 技术 、可以用来 替代 静态页面 HTML , jsp 是一个 服务端的 语言。

JSP 是 Servlet 的 页面 表现形式 。 Servlet 是 JSP 的 底层实现 。

jsp中常见的脚本指令

  • <%! %> : 在 该脚本中, 可以 用来 定义 java 中的 类 、方法 、属性 等信息
  • <% %> : 该脚本中 可以 编写 java 语句 。
  • <%= %> : 将 等号 后面的 表达式 的 结果 输出到 浏览器中。

Tomcat 服务器

JSP 是后端服务语言,所以 不能直接通过浏览器访问、需要将项目部署到 服务器 上,才能正常访问 。 而 tomcat 是 Java语言 最受欢迎的 web 服务器,没有之一。

java 语言 常用的 web 服务器有 tomcat , jboss , weblogic 等


安装 tomcat

  1. 网址: https://tomcat.apache.org

Servlet 的生命周期方法

  • init() : 初始化方法、一个Servlet 只会被初始化 一次。 Servlet 默认是在 第一次 请求的时候调用, 也可以通过配置 将初始化的时间 提升到 随 tomcat 服务器的 启动 而初始化。
  • service() : 每次请求 都会 执行的方法 。
  • destroy() : 销毁、 一个 Servlet 只有在销毁的时候才会被调用, 随 tomcat 的关闭 而 销毁 。

编写一个 Servlet 程序的步骤

  1. 在 servlet 包下, 新建一个类 、继承 HttpServlet (需要添加 tomcat-servlet-api 依赖包)
  2. 重新 HttpServlet 中的 init , service , destory 方法 (按需引入,通常 init , destory 可以 不提供)
  3. 在 web.xml 中 中, 配置 servlet 和 请求地址的 映射关系 (关键步骤)
<servlet>
    <!-- 一个Servlet类在进行配置的时候,必须设置一个唯一的名字    -->
    <servlet-name>UserServlet</servlet-name>
    <!--   配置 Servlet 类的 全名     -->
    <servlet-class>com.qikux.servlet.UserServlet</servlet-class>
    <!--   配置 servlet 随 tomcat 的启动而进行初始化操作   -->
    <load-on-startup>1</load-on-startup>
    <!-- 给 servlet 传递格外的数据、设置字符集编码 -->
    <init-param>
      <param-name>encoding</param-name>
      <param-value>UTF-8</param-value>
    </init-param>
</servlet>

<servlet-mapping>
    <!--  必须和 servlet标签中的 名字 保持 完全一致    -->
    <servlet-name>UserServlet</servlet-name>
    <!--  配置一个 请求地址,用来访问 该 Servlet, 必须以 / 开头   -->
    <url-pattern>/user</url-pattern>
</servlet-mapping>
  1. 也可以使用 注解 @WebServlet 来 提供 上面的 XML 配置
@WebServlet(value="/user" , loadOnStartup = 1,  initParams = {@WebInitParam(name="encoding",  value="UTF-8")})
public  class UserServlet extends HttpServlet{
    ...
}

HttpServletRequest (request) 常见的属性和方法

  • request.getMethod() : 获取 请求方式, 返回值 常见的有 GET , POST , PUT , DELETE , PATCH , OPTIONS
    • GET : 从 服务器 获取数据 、在 请求地址 中的表现是 以 ? (之后) 分割的 参数
    • POST : 表单提交 常用的常用 POST, 一般 做 新增 数据
    • PUT : 传统的 web请求不支持 、 PUT 通常 用来做 修改 数据
    • DELETE : 传统的 web 请求不支持 ,DELETE 通常做 删除数据
    • PATCH : 一般做 修改数据,和 PUT 区别在于 PUT 往往 是 整条数据更新, 而 Patch 通常是 部分数据更新
    • OPTIONS : 通常是 异步请求 自动发生的,用来检查 服务器是否支持 PUT , DELETE, PATH 或者 POST(JSON格式数据) 等请求的
  • request.getServletPath() : 获取 请求 路径地址 (从 项目名 后 获取的内容, 且不包含 请求的参数 ), 例如 /haredot/user?a=1&b=2, 如果项目名为 haredot ,那么 该方法返回 /user
  • request.getContextPath() : 获取 项目名 所对应的 地址 , 例如 /haredot/user?a=1&b=2 , 返回 /haredot , 如果 项目没有设置名字,则返回 “” 字符串
  • request.getRequestURI() : 获取 从 端口号 后面的内容 到 ? 前面的内容 ,例如 /haredot/user?a=1&b=2 , 返回 /haredot/user (会包含 项目名)
  • request.getRequestURL() : 获取 请求的完整例如 , 返回例如 http://localhost:8080/haredot/user , 注意 不带 请求参数
  • request.getSchema() : 获取 协议 , 例如 http , https
  • request.getServerName() : 获取 主机名 , 例如 localhost
  • request.getServerPort() : 获取端口号 , 例如 8080
  • request.getParameter(key) : 获取 表单(请求)参数中 key 对应的 值, 如果传入了多个值,则只能获取第 1 个
  • request.getParameterValues(key) : 获取 请求参数中 key 对应的值 ,返回一个 字符串数组
  • getParameterMap() : 获取 所有的 请求参数,返回一个 Map<String, String[]>
  • request.getHeader(key) :根据 指定的 请求头、 获取 请求的头信息 。
  • request.getCookies() : 获取所有的 Cookie , 如果没有任何Cookie , 返回 null , 否则 返回一个 数组
  • request.getSession() : 获取 session 会话 。
  • request.setAttribute(key , value) : 将 数据 存储到 request 作用域中 ,可以通过 forward 跳转的方式 将数据 传递到 .jsp 页面中
  • request.getAttribute(key) : 从 request 作用域中, 根据 key 获取 存储的值, 返回 Object 类型,使用的话可以需要强转 。
  • requestDispatcher(“/servletPath”).forward(request, response) : 转发跳转

Servlet 层主要的职责

Servlet 是 前端 ~ 后台的 一个 桥梁 。

  • 接收 前台 从 浏览器 传递过来 的数据 (头信息、参数、请求方式、路径 等信息)
  • 调用 业务逻辑层 处理 业务
  • 根据 业务逻辑层 执行的结果 进行 页面 跳转 、返回一个 合适的 资源给 浏览器

Servlet 中 常见的作用域对象

作用域对象 可以 进行 数据的存储 , 拥有 三个 方法 setAttribute(key, val) , getAttribte(key) , removeAttribute(key) ;

  • request : 和 请求 有关, 该作用域中存储的数据 ,只能在 一个请求中 使用, 不能 跨 请求访问 . 通常配合 转发 跳转 传递数据 使用
  • session : 和 浏览器 或者 用户 有关, 当浏览器关闭的时候, 会话就 结束 . 获取 会话超时 (默认 时间 30分钟), 可以 跨 请求 传递数据 , 通常配合 重定向 跳转 .
  • servletContext : 和 应用程序相关, 存储在 该作用域下的数据 被整个网站 共享 .

跳转方式

  • 转发
    request.getRequestDispatcher(servletPath).forward(request, response)
    

    servletPath 以 / 开头, / 指的是 从 项目 根 开始的地址 , 如果没有 / 代表 相对路径, Java web框架中 不建议使用 相对路径

    servletPath 只能传入 服务器的 内部 地址 .

  • 重定向
    response.sendRedirect(path) ;
    

path : 以 /开头 , / 指的是 从 端口号 后面 的 路径地址

path 支持 外部 网址 . 如果 要跳转到 外部 地址 , 地址 必须以 http 或者 https 开头


转发 VS 重定向

  • 转发 是 一次 请求 , 跳转由 服务器 内部完成 , 从 开始 请求 到 响应结果 地址栏的 地址 是 发送 请求的 地址 . 可以通过 request 作用域 传递 数据, 只能在服务器内部跳转
  • 重定向 是 二次 请求 , 地址栏 会 发生改变 , 不能 使用 request作用域传递数据, 可以跳转到 外部地址 中 .

重定向的原理

当 一个请求 结束后 , 响应 一个 301 / 302 的状态码 给 浏览器 , 浏览器 如果发现 状态为 301/302 , 那么 就会触发 重定向的操作, 浏览器 会从 响应的 头信息 中 找到 Location 并获取对应的值,

将 Location的值 作为 第二次 请求的 请求地址 继续 发送 . 整个 重定向的 动作 是由 浏览器完成 的 .


JSP 中的四大作用域

  • pageContext : 存储在该作用域的数据、只在当前页面中有效。不能跨页面,不能跨请求。 pageContext 有一个特殊的方法 findAttribute(key) , 会从四个作用域中依次查找对应的key
  • request
  • session
  • application (ServletContext)

EL 表达式 和 JSTL 标签库

EL 表达式

是 JSP 语言 特有的一种 在 页面上 进行 数据展示(数据输出)的 一种 有效手段 。语法格式为 ${ key } , key 支持 Java表达式 , 变量 来自于 作用域 中 存放的数据

EL 表达式 会 从 作用域 中 获取数据 。${key} 等价于 pageContext.findAttribute(key) 。

EL 表达式 默认 会从 pageContrext -> request -> session -> application 四个作用域中 依次找 满足条件的 key, 如果找到,则 停止查找

如果要从 指定的作用域 获取对应的值,则可以使用 pageScope , requestScope, sessionScope , applicationScope 强制 从指定的作用域中 获取数据

例如 ${sessionScope.a} 代表 从 session作用域中 获取存储的 a 对应的数据

对象获取属性
${obj.propertyName} 

propertyName 指的是 obj 对象中定义的 getter 方法, 去掉 get 首字母变小写 (如果去掉get后的属性名 前两个字母都是大写、则不做任何的改变)

Map 根据 键 获取对应的值

${obj.key}
${obj['key']} 

List / Array 获取 对应的数据

${list[0]}

隐式对象

  • 获取 请求参数
${param}  :  获取所有的请求参数,返回一个 Map<String, String> 

${param.key} 

${paramValues} :  获取所有的请求参数,返回一个 Map<String, String[]> 

${paramValues.key}
  • 获取请求头信息

    ${header}  :  获取所有的请求头信息 ,返回一个 Map<String, String> 
    
    ${headerValues} : 获取所有的请求头信息 ,返回一个 Map<String, String[]> 
    
  • 获取 Cookie 信息

    ${cookie}  : 获取所有Cookie,  返回一个 Map<String, Cookie> 
    
  • 使用 pageContext 获取 request, session , application 对象

    ${pageContext.request}    // 获取 request 对象
    
    ${pageContext.rquest.contextPath}  // 获取项目名
    
    ${pageContext.session}   // 获取 session 对象 
    
    ${pageContext.servletContext} // 获取 application 对象
    

JSTL 标签库

是 jsp 中 进行数据处理的 一套 标签库 、在使用的时候,需要引入 jstl 依赖包 。

<dependency>
    <groupId>jstl</groupId>
    <artifactId>jstl</artifactId>
    <version>1.2</version>
</dependency>
  • c 标签库 (最重要的)
  • fn 标签库 (比较重要的)
  • fmt 标签库 (内容较少)

C 标签库 的使用
  • 使用 @taglib 指令 引入 标签库
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
  • 常见的 c 标签
    • c:out
      <c:out  value=""  default=""  escapeXml="true" />
      
      - value :  用来设置 输出的 内容, 支持 EL 表达式 
      - default :  当 value 中提供的  EL表达式 找不到对应的数据, 取 default 设置的值 
      - escapeXml :  是否转义 标签, 默认 是 true 转义, 如果设置为 false, 在表现上和 EL表达式 类似
      
    • c:set
      <c:set  var="a"  value="${b + 1}"  scope="page" />
      
      - var:  将存储的值 放到 指定的 变量中 
      - value : 要存储的数据、支持 EL 表达式 
      - scope : 存储的作用域,默认是 page , 支持的值用  page,  request,  session,  application
      
    • c:url
      <c:url  value="/a" />   :  类似于 c:out ,可以将结果输出到网页中, 会自动在地址前 添加 项目名 , 例如返回  /haredot/a
      
      <c:url value=""  var=""  scope="page" /> :  类似于 c:set , 支持 临时 存储值 
      
    • c:if 单分支条件
      <c:if  test="" />   
      
      -test : 定义 判断条件 ,支持 关系运算符 > , >= , < , <= , == , !=   支持 逻辑运算符  &&,  ||  ,  !
      
      - 关系运算符 还支持  
          - gt  :   大于  
          - ge  :   大于等于 
          - lt  :   小于 
          - le  :   小于等于 
          - eq  :   等于 
          - ne  :   不等于 
          
      - 逻辑运算符 还支持
          - and 
          - or 
          - not 
          
      - 空值 判断 
          -  empty 
      
    • c:choose 多分支条件判断
      <c:choose>
          <c:when test="${score >= 90}">优秀</c:when>
          <c:when test="${score >= 80}">良好</c:when>
          <c:when test="${score >= 70}">中等</c:when>
          <c:when test="${score >= 60}">及格</c:when>
          <c:otherwise>不及格</c:otherwise>
      </c:choose>
      
    • c:forTokens 对字符串进行按照指定的分隔符进行拆分后 遍历
      <!-- request.setAttribute("hobbies", "爬山、游泳、学Java"); -->
      
      <c:forTokens items="${hobbies}" delims="" var="hobby" varStatus="vs">
          ${hobby}
      </c:forTokens>
      
    • c:forEach 循环
      - 列表遍历
      <c:forEach items="${userList}" var="user" varStatus="vs">
          <p>
              <label>序号:${vs.last}</label>
              <label>用户名: ${user.username}</label>
              <label>性别: ${user.sex}</label>
          </p>
      </c:forEach>
      
       varStatus 中 常见的属性 
       
       - index :  获取 遍历的 数据的索引 ,从 0 开始 
       - count :  获取 遍历的 数据的 出库顺序, 从 1 开始 ,和 index 在同一条记录中永远相差 1 
       - first :  遍历的 当前数据 是否 是 第一条数据 
       - last  :  遍历的 当前数据 是否是 最后一条数据 
       
      - 数字遍历 
       <c:forEach var="m" begin="1" end="9" step="1">
      
          <c:forEach var="n" begin="1" end="${m}">
              <span>${n} * ${m} = ${ n * m }</span>
          </c:forEach>
          <br/>
      </c:forEach>
      
      - begin : 从 几 开始
      - end :  到 几 结束
      - step : 步长,每次增加多少 , step 值 必须 > 0 , 默认值是 1 
      

fn 标签库

对网页中 展示的 字符串 进行 处理 、例如 字符串 替换、截取、脱敏等操作。

  • 引入方式

    <%@taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
    
  • 常见的函数

    • contains 包含
    • startsWith 以 …开头
    • endsWith 以 … 结尾
    • indexOf 查找 某个子串 在字符串中出现的索引位置
    • join 按照指定的分隔符 拼接字符串
    • split 拆分字符串
    • length 获取 长度
    • replace 替换字符串
    • substring(str , start , end)
      • 截取字符串 , start 从哪里开始 , end 代表 截取到哪里,不包含 end 所在的位置 , -1 代表截取到尾部
    • toLowerCase 转小写
    • toUpperCase 转大写
    • trim 去除前后空格
fmt 标签库

对页面中要展示的数据 进行格式化 处理

  • 引入方式

    <%@taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
    
  • 常见的标签

    • fmt:locale : 设置 国际化语言 环境
      <fmt:locale  value="zh-CN" />
      <!--zh-CN : 中文 ,  en-US : 英文  -->
      
    • fmt:setBundle : 设置 国际化 配置文件 前缀
      <!-- 
        需要在该标签前使用 fmt:locale 确认语言环境,否则会读取浏览器默认语言环境 , 从 PageContext 中查找 javax.servlet.jsp.jstl.fmt.locale 对应的语言信息
        public static Object get(PageContext pc, String name, int scope) {
          	switch (scope) {
            	case PageContext.PAGE_SCOPE:  return pc.getAttribute(name + PAGE_SCOPE_SUFFIX, scope);
            	case PageContext.REQUEST_SCOPE: return pc.getAttribute(name + REQUEST_SCOPE_SUFFIX, scope);
            	case PageContext.SESSION_SCOPE:  return get(pc.getSession(), name);
            	case PageContext.APPLICATION_SCOPE: return pc.getAttribute(name + APPLICATION_SCOPE_SUFFIX, scope);
            	default: throw new IllegalArgumentException("unknown scope");
            }
        } 
      -->
      <fmt:setBundle  basename="message"/>   
      
      <!--message_zh_CN.properties : 中文配置文件 , message_en_US.properties : 英文配置文件 , 配置文件中的占位符使用 {n}   -->
      - message_zh_CN.properties 
      
      login = 登录
      msg = 你好,{0} 欢迎登录本系统
      
      - message_en_US.properties
      login = Sign In
      msg = Hello , {0} Welcome to My Site
      
    • fmt:message : 读取 国际化配置文件中的数据
      // 在 servlet 中读取国际化配置文件,并将其存储到对应的作用域中 (下面的代码写在servlet中后可以在 JSP 中 省略 fmt:locale 和 fmt:bundle 两个标签)
      
      Locale locale = new Locale("zh",  "CN") ;  // zh_CN
      // 读取 classpath 下的 message 国际化配置文件,并设置 语言环境 
      ResourceBundle resourceBundle = ResourceBundle.getBundle("message", locale);
      
      // ResourceBundle 获取国际化 中的数据
      //  String  message = bundle.getString(key);  // 获取 国际化配置文件中 对应键 对应的值 
      // MessageFormat formatter = new MessageFormat("");  // 获取 消息格式化对象,负责格式化数据 
      // formatter.applyPattern("你好,{0}欢迎登陆本系统") ;  // 设置要格式化的字符串
      // formatter.format(new String[]{"张三"}) ;  // 传入数据 
      
      // 构建一个上下文对象,目的是为了让 fmt:message 能够使用  
      LocalizationContext localizationContext = new LocalizationContext(resourceBundle, locale);
      // 将上下文对象存储到 对应的作用域中 
      // pageContext 作用域 添加 后缀 .page
      // request 作用域 添加 后缀 .request 
      // session 作用域 添加 后缀 .session 
      // application 作用域 添加 后缀 .application
      request.setAttribute(Config.FMT_LOCALIZATION_CONTEXT + ".request", localizationContext);  // javax.servlet.jsp.jstl.fmt.localizationContext
      
      
      <!-- JSP 中 获取 国际化消息 -->
      <fmt:message  key="login" />
      
      <fmt:message key="msg"> 
         <fmt:param value="${sessionScope.user.username}" />   <!-- 给第一个占位符 {0} 设置数据 -->
      <fmt:message>
      
    • fmt:fomratDate
      <fmt:formatDate value="${birth}" pattern="yyyy/MM/dd" />  <!-- 格式化 java.util.Date 日期对象 -->
      
    • fmt:formatNumber
      <fmt:formatNumber value="${23434323.5632}" pattern="#,###.##"/>  <!-- 整数部分 每三位逗号分隔、保留2位小数、四舍五入 -->
      

自定义标签

  • 添加依赖包

    <dependency>
        <groupId>org.apache.tomcat</groupId>
        <artifactId>tomcat-jsp-api</artifactId>
        <version>9.0.75</version>
        <scope>provided</scope>
    </dependency>
    
  • 在 WEB-INF 下 新建一个 tld (可任意)文件夹、在 文件夹下 新建一个 haredot.tld 文件 (文件名可自定义), 并添加如下内容

    <?xml version="1.0" encoding="UTF-8" ?>
    
    <taglib xmlns="http://java.sun.com/xml/ns/j2ee"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee 
                http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd" version="2.0">
        <tlib-version>1.1</tlib-version>
        <!--  标签库的简写名称  -->
        <short-name>h</short-name>
        <!--  引入标签库的 网址,自定义即可  -->
        <uri>http://www.haredot.com/jsp/haredot</uri>
    
        <tag>
            <name>jdk8time</name>
            <tag-class>com.qikux.taglib.TemporalTag</tag-class>
            <!--  empty 代表 该标签是 单标签,没有标签体,  JSP 代表是 双标签,允许定义标签体   -->
            <body-content>empty</body-content> 
            <attribute>
                <name>value</name>
                <required>true</required>
                <!--    是否支持 EL表达式    -->
                <rtexprvalue>true</rtexprvalue>
            </attribute>
            <attribute>
                <name>pattern</name>
                <required>false</required>
            </attribute>
        </tag>
    </taglib>
    
  • 编写 LocalDateTag 类 并 继承 TagSupport 类

  • doStartTag

  • doAfterBody

  • doEndTag

上述三个方法 为 编写 自定义标签 的核心方法, 均返回 int 类型 ,返回的常量值 有 SKIP_BODY , EVAL_BODY_INCLUDE , SKIP_PAGE , EVAL_PAGE , EVAL_BODY_AGAIN

  • SKIP_BODY : 该值 可以作为 doStartTag 的返回值 ,代表 跳过 标签体中的内容, 意味着 写在 标签体中的内容 不会渲染在页面上 , 在 doAfterBody中使用,代表执行执行 doEndTag
  • EVAL_BODY_INCLUDE : 该值 可以作为 doStartTag 的返回值, 代表 渲染 标签体 中定义的内容
  • SKIP_PAGE : 该值 可以作为 doEndTag 返回值 , 代表 跳过 标签 后面所有的内容
  • EVAL_PAGE : 该值 可以作为 doEndTag 返回值, 代表 正常 结束 标签, 允许 后面的内容 进行渲染
  • EVAL_BODY_AGAIN : 该值 主要在 doAfterBody 中 作为返回值 , 可以实现 循环的效果 。
public class TemporalTag extends TagSupport {

    private Temporal value ;

    private String pattern ;

    public void setValue(Temporal value) {
        this.value = value;
    }

    public void setPattern(String pattern) {
        this.pattern = pattern;
    }

    @Override
    public int doEndTag() throws JspException {
        // 根据用户指定的 pattern 进行格式化
        String format = DateTimeFormatter.ofPattern(pattern).format(value);
        // 将数据写入 到浏览器
        try {
            this.pageContext.getOut().write(format);
            return EVAL_PAGE;
        } catch (IOException e) {
            throw new JspTagException(e.getMessage(), e);
        }
    }

}
  • 在 web.xml 中, 配置 自定义标签库
    <jsp-config>
        <taglib>
            <taglib-uri>http://www.haredot.com/jsp/haredot</taglib-uri>
            <taglib-location>/WEB-INF/tld/haredot.tld</taglib-location>
        </taglib>
    </jsp-config>
    

JSP 中的 九大内置对象

在 JSP 页面中,提供了 9个 内置对象,可以 直接 在 <% %> 中 。

  • pageContext
  • request
  • session
  • application
  • response
  • page : 代表当前页
  • config : 和 Servlet中的 ServletConfig 是等价的 , 可以 获取 Servlet 中的一些配置信息。
  • out : 输出内容
  • exception : 异常对象, 该对象 只能在 错误页面中 使用 。 配合 <%@page isErrorPage=“true” %> 使用

JSP 中 包含 include

将一个 网站中的 多个 相同 或者 相似 的内容 抽取 出来,存放到一个单独的文件中, 通过 include 的技术 将 抽取出来的内容 引入到 需要的文件中 。

  • 静态包含
    <%@include file="/WEB-INF/pages/common/nav.jsp"%>
    
  • 动态包含
    <jsp:include page="/WEB-INF/pages/common/nav.jsp">
        <jsp:param  name="a"  value="1" />
    </jsp:include>
    
动态包含 和 静态包含的区别
  1. 静态包含 是 将 需要包含的 页面 内容 直接 加载 到 页面中 ,构成一个 大的 完整的页面 后 同意进行 解析 并渲染 。 而 动态包含 是 将 需要 包含的 页面 渲染后的内容 加载到 页面中。
  2. 静态包含 不能传递 数据 、 而 动态包含 可以通过 jsp:param 传递 数据 , 在 公共页面中,通过 ${param} 来获取对应的参数。

文件上传

从 客户端 中 将 资源 通过 网络 传输的 方式 上传到 资源服务器的 过程

  • FileUpload : apache 的子项目 apache-fileupload 实现的。
  • Servlet 3.0 文件上传

Servlet 3.0 文件上传 实现 流程

  1. 在 Servlet 中 ,通过 配置 让 Servlet 支持 文件上传
  • 使用注解 允许 Servlet 文件上传
    @MultipartConfig(maxRequestSize = -1, maxFileSize = -1)
    
  • XML 配置 Servlet 允许 文件上传

<servlet>
  <servlet-name>UserServlet</servlet-name>
  <servlet-class>com.qikux.servlet.UserServlet</servlet-class>
  <multipart-config>
      <!--  上传资源在服务器中存储的临时位置,默认 window 在 C: 盘    -->
      <location>D:/temp</location>
      <!--  允许 请求传递的参数的最大字节数,如果设置为 -1 , 代表没有限制   -->
      <max-request-size></max-request-size>
      <!--  允许 单文件的 最大字节数、如果设置为 -1 , 代表没有限制      -->
      <max-file-size></max-file-size>      
  </multipart-config>
</servlet>

<servlet-mapping>
  <servlet-name>UserServlet</servlet-name>
  <url-pattern>/user</user-pattern>
</servlet-mapping>
  1. 使用 request.getPart(key) 方法 接收 上传的 文件
  • Part 类 常见的 属性 或 方法
    • getSubmittedFileName() : 获取 上传的文件名, 例如 img.jpg
    • photo.getContentType() : 获取 文件的媒体类型
    • getSize() : 获取 上传的文件 大小,单位是 字节, 返回 long
    • getInputStream() : 获取上传文件的 文件 输入流,可以通过该流 获取 上传的 文件对象
    • write(file) : 将 上传的 文件 写入 到 指定的 位置 。
  1. form 表单 在上传的时候 需要满足2个条件
  • 请求方式 必须是 POST
  • form 表单的 enctype 属性的 值 必须为 mutipart/form-data
    enctype 可用的值:
    a) application/x-www-form-urlencoded (默认值):  以表单的形式(键值对)提交数据
    b) multipart/form-data : 主要应用于文件上传,表示 以 流的形式 提交数据
    c) application/json    : 将数据 以 JSON 格式提交到 服务器
    

上传的文件 存放的方式

  • 存数据库 (不推荐)
  • 存 服务器 磁盘中 (以后 不推荐中…)
  • a) 存储的路径可以任意,但需要在 配置文件中进行管理,以方便后期迁移
    b) 存储到 当前项目中 (不需要配置文件)、 但是 项目在开发阶段一旦 mvn clear ,那么存储的文件全部就丢失了。
    
  • 文件服务器 (公司自己搭建的服务器)
  • oss 云存储服务器 (公司推荐使用的)
  • a) 阿里云 OSS
    b) 腾讯云 OSS
    c) 七牛云 OSS
    

文件下载

将 服务器 中的 资源 通过 网络 传输 下载 到 客户端 的过程

  • 将 下载 的 资源 通过 流 的 技术 写入 到 响应 中

    try(FileInputStream in = new FileInputStream(file);
        // 通过 response 对象 将要下载的 资源 进行写入到 浏览器
        ServletOutputStream out = resp.getOutputStream()) {
        // 边读  边写
        int len = -1;  // 一次性读取 8K 
        byte[] bytes = new byte[8 << 10];
        while ((len = in.read(bytes)) != -1) {
            // 将读取到的数据 ,通过 输出流写入到 浏览器
            out.write(bytes, 0, len);
        }
    }
    
  • 设置 下载 资源的 媒体类型 头信息 (目的是为了让浏览器知道资源的类型)

response.setHeader("Content-Type",  "image/png");   // 文件的媒体类型 可以自行百度有那些
  • 设置 下载 资源的 附件 (主要包含 文件名 和 编码方式 等信息)
    String encode = URLEncoder.encode(filename, "UTF-8");  // 解决文件名中文乱码问题
    response.setHeader("Content-Disposition", "attachment;filename=" + encode);  // 以附件的方式下载文件
    
    - attachement  // 附件 
    - inline       //  预览 (文件必须支持预览才有效)
    

Servlet 响应 JSON格式数据

  • 添加 处理 JSON的 依赖库
    <!-- 添加 fastjson 依赖库, 处理JSON格式的数据 -->
    <dependency>
        <groupId>com.alibaba.fastjson2</groupId>
        <artifactId>fastjson2</artifactId>
        <version>2.0.32</version>
    </dependency>
    
  • 响应 JSON格式的数据
    ResultVo  resultVo = .... ;
    // 将 业务层返回的结果转换成 JSON 字符串, 
    String  json = JSONArray.toJSONString(resultVo) ; 
    
    // 设置响应头 类型为 JSON
    response.setHeader("Content-Type",  "application/json") ;
    
    // 通过 字符流 向 浏览器写入JSON 数据
    response.getWriter().print(json) ;
    

axios 异步请求 官方文档

  • GET 请求

  • POST 请求

    axios 库 默认 在 POST , PUT ,DELETE 请求中, 发送的是 JSON 格式的数据、需要服务器支持, Servlet 默认不能处理 JSON 参数,如果需要,服务器需要做特殊的处理。

    • json 格式传递数据
      axios.post('/user', {
          firstName: 'Fred',
          lastName: 'Flintstone'
        })
        .then(function (response) {
          console.log(response);
        })
        .catch(function (error) {
          console.log(error);
        });
        
      // 如果使用 json 格式提交数据,那么 Servlet 服务器 需要 通过  request.getInputStream() 获取 json数据 (需要通过流得到数据) 
      // request.getInputStream()  只能读取 一次,一旦读取过,该流 就无法获取数据。
      
    • 表单格式(键值对)传递数据
      // 方式一 
      let param = new URLSearchParams();
      param.append("name", "张三");
      param.append("sex", "男");
      
      axios.post("/user", param)
          .then(res=> console.log(res.data))
          
          
      // 方式二 (传递的参数必须是一个对象)
      let param = {name: "张三",  sex: "男"} ;
      axios.post("/user", param, {
            headers: {
                "content-type": "application/x-www-form-urlencoded"
            }
        }).then(res=> console.log(res.data))
      
    • 文件上传
      // 方式一 
      let formData = new FormData(); 
      formData.append("username", "xxx");
      formData.append("photo",  photo);   // photo 是一个文件对象
      
      axios.post("/user",  formData).then(res=> {
        console.log(res.data);
      })
      
      // 方式二 
      let param = {name: "张三",  sex: "男",  photo: photo} ;  // photo 是一个文件对象
      axios.postForm("/user", param).then(res=> {
        console.log(res.data)
      });
      
      
  • PUT 请求

    传统的 表单提交不支持 PUT, DELETE 请求 , 而异步请求是 支持 PUT, DELETE 等操作的。

    PUT 请求 通过 表单 发送的 数据, 不能直接通过 request.getParamter(key) 获取到,只能通过 request.getInputStream() 得到数据。

    PUT 请求 通过 json 发送的数据, 也不能通过 request.getParamter(key) 获取到,只能通过 request.getInputStream() 得到数据。

    解决方案: 自定义过滤器

  • DELETE 请求

    用法完全参考PUT请求
    

跨域

浏览器 具备 同源策略机制, 是一种保护机制, JavaScript 从一个源 向 另一个源 发送 http 请求的时候,就会 发生 跨域。 同源策略会对这种情况进行限制。

同源策略 指的是 协议、域名、端口必须完全相同。

CORS 跨域资源共享

在 请求 响应前 设置 头信息,解决 JS 跨域问题

response.setHeader("Access-Control-Allow-Origin", "*");  // 支持传入 http://localhost:8888  等网址
response.addHeader("Access-Control-Allow-Methods", "*");  // 允许访问的 请求方法
response.addHeader("Access-Control-Allow-Headers", "*");  // 允许访问的 请求头信息

过滤器 Filter

是一种切面技术,可以对 请求 和 响应 进行拦截 。在 请求前 进行 逻辑 处理, 在 响应后 进行逻辑处理 。

  • 编写一个类 、实现 一个 Filter 接口

    public class CharacterEncodingFilter implements Filter {
    
        private String encoding ;
    
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
            encoding = filterConfig.getInitParameter("encoding");
    
            if (encoding == null || "".equals(encoding)) {
                encoding = "UTF-8" ;
            }
        }
    
        @Override
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
            request.setCharacterEncoding(encoding);
            response.setCharacterEncoding(encoding);
    
            System.out.println("Servlet 执行前 执行的代码");
    
            // 继续 执行请求, 进入下一个过滤器,如果没有下一个过滤器,则 进入 Servlet
            chain.doFilter(request, response);
    
            // 在 此 书写的代码 就是 响应后 执行的代码。。。
            System.out.println("Servlet 执行完后 执行的代码");
        }
    }
    
  • 在 web.xml 中 配置过滤器

    <filter>
        <filter-name>encodingFilter</filter-name>
        <filter-class>com.qikux.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
    </filter>
    
    <filter-mapping>
        <filter-name>encodingFilter</filter-name>
        <!--  /* 拦截所有请求      -->
        <url-pattern>/*</url-pattern>
        <!--<dispatcher>REQUEST</dispatcher> -->
    </filter-mapping>
    
  • dispatcher 的类型

    • REQUEST : 默认值, 过滤 的请求 为 普通 请求 (由浏览器发出的请求)
    • FORWARD : 过滤的请求 为 转发 forward 请求 , 拦截 request.getDispatcher(“/xxxx”).forward(request, response) ;
    • INCLUDE : 过滤的请求为 包含 请求, (动态包含的请求)
    • ERROR : 拦截的请求为 错误 请求, 当请求发生异常的时候,被拦截
    • ASYNC : 拦截 异步 Servlet 对应的请求, 例如 @WebServlet(asyncSupported=true, …)

监听器 Listener

Servlet 监听器 可以 监听 request 、 session 、 ServletContext(application)

监听器 对应的 类 构建的对象 会随 tomcat的启动而启动, 随 tomcat 的关闭 而 销毁。

  • ServletRequestListener : 监听 请求 的 创建 和 销毁

  • ServletRequestAttributeListener : 监听 向 request 作用域中 添加数据 、 移除数据、 替换数据 三个动作 。

  • HttpSessionListener : 负责监听 session的创建和销毁

  • HttpSessionAttributeListener : 负责 监听 向 session 中 添加数据、移除数据、替换数据 三个动作

  • ServletContextListener : 负责监听 application 的创建和销毁

  • ServletContextAttributeListener 负责 监听 向 application 中 添加数据、移除数据、替换数据 三个动作

@WebListener
public class ClassLoaderListener implements ServletContextListener {

    @Override
    public void contextInitialized(ServletContextEvent sce) {
        ApplicationContext ctx = new ClasspathApplicationContext();
        // 将 构建出来的应用上下问 存储 到 ServletContext 作用域中
        sce.getServletContext().setAttribute(SysConst.APPLICATION_CONTEXT, ctx);
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        // 当销毁 ServletContext 的时候,将 ctx 移除即可
        sce.getServletContext().removeAttribute(SysConst.APPLICATION_CONTEXT);
    }
}

向 浏览器 写入 Cookie

Cookie  cookie  = new Cookie(name ,  value) ; 

cookie.setPath("/");  // 设置 Cookie 的访问路径, 如果没有提供,默认是 当前项目 路径  

cookie.setDomain("")  ;  // 设置 Cookie 在 哪一个域 中使用,例如 可以设置为  baid.com , 就代表 www.baidu.com ,  wenku.baidu.com  可以访问 该 Cookie , 如果不设置,默认为 当前域

cookie.setMaxAge(n)  ;  //  设置 Cookie 的存活时间,单位是 秒 , 如果 大于 0 代表 存活时间,  如果 等于 0 代表 删除 Cookie , 如果设置为 小于 0 , 代表是一个 会话 Cookie (随浏览器关闭而销毁)  

cookie.setHttpOnly(boolean) ; // 设置 Cookie 是否是只读的

response.addCookie(cookie) ;

MVC 设计模式

M : Model (模型) , 完成数据的处理 (实体层 、 持久层、业务逻辑层)

V : View (视图) , 负责 进行页面处理 (主要由 JSP 来完成)

C : Controller (控制器) 、 沟通 前后端 、通常由 Servlet 充当


MVC 设计思想 要求 所有的请求 拥有 同一个 入口 , 由该入口 负责 进行 请求 的 分发、该入口完成 对 响应信息的 统一处理 。

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值