Java Web 学习

Java Web

概念

javaWeb 是指所有通过 java 语言编写可以通过浏览器访问的程序的总称。

javaWeb 是基于请求和响应来开发的

请求是什么?

请求是指客户端给服务器发送数据,叫请求 Request

响应是什么

响应是指服务端给客户端回传数据,叫响应 Response

请求和响应是成对出现的

Web 资源分类

web 资源按实现的技术和呈现的效果不同,又称为静态资源和动态资源两种。

静态资源html、css、js、txt、mp4视频、mp3音频、jpg图片

动态资源jsp 页面、Servlet 程序

常用的 Web 服务器

  1. Tomcat

    tomca 是由 Apache 组织提供的一种服务器,提供对 jspServlet 的支持,它是一种轻量级的 web 容器(即服务器),也是当前应用最广的 javaWeb 服务器(免费)

  2. Jboos

    是一个遵循 JavaEE 规范的、开放代码的、纯 Java 的 EJB 服务器,它支持所有的 JavaEE 规范(免费)

  3. GlassFish

    Oracle 公司开发的一款 javaWeb 服务器,是一款强健的商业服务器,达到产品级质量(应用很少)

  4. Resin

    CAUCHO 公司的产品,是一个非常流行的服务器,对 servlet 和 JSP 提供了良好的支持,性能也比较优良,resin 自身采用 Java 语言开发(收费,应用比较多)

  5. WebLogic

    Oracle 公司的产品,是目前应用最广泛的 web 服务器,支持 javaEE 规范,而且不断的完善以适应新的开发要求,适合大型项目(收费,用的不多,适合大公司)

Tomcat 服务器和 Servlet 版本关系

Servlet规格JSP规范EL规格WebSocket规范JASPIC规格Apache Tomcat版本最新发行版本支持的Java版本
4.02.33.01.11.19.0.x9.0.278及更高版本
3.12.33.01.11.18.5.x8.5.477及更高版本
3.12.33.01.1不适用8.0.x(已取代)8.0.53(已取代)7及更高版本
3.02.22.21.1不适用7.0.x7.0.966及更高版本 (WebSocket为7及更高版本)
2.52.12.1不适用不适用6.0.x(已归档)6.0.53(已归档)5及更高版本
2.42.0不适用不适用不适用5.5.x(已存档)5.5.36(存档)1.4及更高版本
2.31.2不适用不适用不适用4.1.x(已归档)4.1.40(已归档)1.3及更高版本
2.21.1不适用不适用不适用3.3.x(已存档)3.3.2(已存档)1.1及更高版本

Servlet 程序从 2.5 是现在使用最多的版本 (xml 配置)

到了 Servlet 3.0 之后,就是注解版本 Servlet 使用

Tomcat 的使用

Tomcat 安装

下载 tomcat zip 文件解压即可,并配置和 java 环境。

Tomcat 目录

  • bin

    专门用来存放 Tomcat 服务器的可执行程序

  • config

    专门用来存放 Tomcat 服务器的配置文件

  • lib

    专门用来存放 Tomcat 服务器的 jar 包

  • logs

    专门用来存放 Tomcat 服务器运行时输出的日志信息

  • temp

    专门用来存放 Tomcat 服务器运行时的临时数据

  • webapps

    专门用来存放部署的 web 工程

  • work

    是 Tomcat 的工作是的目录,用来存放 Tomcat 运行时 jsp 翻译为 Servlet 的源码,和 Session 钝化(序列化)的目录。

如何启动 Tomcat

点击 startup.bat 启动

找到 Tomcat 安装目录下的 bin 目录下的 startup.bat,双击点击即可启动 Tomcat。

打开浏览器在地址栏中输入 http://localhost:8080 来测试 Tomcat 是否成功启动。它是一个 Tomcat 的欢迎页面。

使用命令行启动

打开 cmd 窗口,cd 到 tomcat bin 目录(也可以把 tomcat bin 目录配置到 path 环境变量中),使用命令 catalina run 启动 tomcat

关闭 Tomcat

  1. 直接点击 Tomcat 窗口的 X 按钮。
  2. 在 Tomcat 窗口中使用 Ctrl + C
  3. 找到 Tomcat bin 目录的 showdown.bat 点击即可关闭

修改 Tomcat 端口号

找到 Tomcat conf 目录,找到 server.xml 中的 Connect 标签的 port 属性进行修改,修改完端口号一定要重启 Tomcat 才能生效。
如果修改 Tomcat 端口号为 80,在使用时可以不写 80 端口号

http 协议的默认端口号是 80,浏览器解析时会自动抹掉端口号 80

如何部署 web工程到 Tomcat

  1. 只需要把 web 工程的目录拷贝到 Tomcatwebapps 目录下即可。

  2. 找到 Tomcat 下的 conf\Catalina\localhost 目录,创建一个工程配置 xml 文件。

    <Context path="/abc" docBase="E:\\xxx\\xxx\\projectName">
    </Context>
    
    • <Context> 元素将本地文件系统中的一个目录映射成一个可供 Web 浏览器访问的虚拟目录。

    • path 指定在浏览器中的访问路径

    • docBase 指定项目实际路径

ROOT 的工程访问,以及默认 index.html 访问


当我们在浏览器中输入如下地址访问时:

http://ip:port ------ 没有工程名的时候,默认访问的是 ROOT 工程

当我们在浏览器中输入如下地址访问时:

http://ip:port/工程名 ------ 没有资源名,默认访问 index.html 页面

java Web 工程

idea 中创建 javaWeb工程

使用 idea 2022 为例创建 java web 工程为例

  1. 点击项目创建节目的 New Project,项目名称和包名取好后,点击 CREATE 按钮
  2. 右键点击创建的项目的文件夹,点击 Add Frameworks Support,勾选 Web Application后,再点击 ok

在 module 中添加 web 支持也是一样,只是点击 module 文件夹,也是点击Add Frameworks Support,勾选 Web Application后,再点击 ok

目录

  1. src

    java 源代码

  2. web

    专门用来存放 web 工程的资源文件,比如 html、css、js 文件等等

    注意:web 文件夹上面有一个蓝色小点,说明 web 目录正确配置了

  3. WEB-INF

    是一个受服务器保护的目录,浏览器无法直接访问此目录的内容。

    位于 WEB-INF 目录下的 web.xml 文件,它是整个动态 web 工程的配置部署描述文件。可以在这里配置很多 web 工程的组件,比如 Servlet 程序、Filter、Listener、Session 超时等

idea 中 tomcat 实例和其他细节

  1. 修改模块的工程路径,在 Deployment中修改 Application context值即可完成访问路径修改

    可以修改为 /projectName

  2. 修改端口号,在 Server中修改 HTTP port 的值即可

  3. 修改启动浏览器,在 Server中修改 After launch 后面下拉框中的浏览器即可

  4. 配置点击运行按钮时的动作。在 Server中的 On 'Update' action 后面的下拉选项默认是 Restart server,表示重启 server。可以选择 Update classes and resources,来进行 热更新

Artifacts

项目的打包部署设置,这个是项目配置里面比较关键的地方

官方定义:

即编译后的 Java 类,Web 资源等的整合,用以测试、部署等工作。再白话一点,就是说某个 module 要如何打包,例如 war exploded、war、jar、ear 等等这种打包形式。某个 module 有了 Artifacts 就可以部署到应用服务器中了。

jar:Java ARchive,通常用于聚合大量的 Java 类文件、相关的元数据和资源(文本、图片等)文件到一个文件,以便分发Java平台应用软件或库;

war:Web application ARchive,一种 JAR 文件,其中包含用来分发的 JSP、Java Servlet、Java 类、XML 文件、标签库、静态网页(HTML 和相关文件),以及构成 Web 应用程序的其他资源;

exploded:在这里你可以理解为展开,不压缩的意思。也就是 war、jar 等产出物没压缩前的目录结构。建议在开发的时候使用这种模式,便于修改了文件的效果立刻显现出来。

默认情况下,IDEA 的 Modules 和 Artifacts 的 output 目录已经设置好了,不需要更改,打成 war 包的时候会自动在 WEB-INF 目录下生成 classes,然后把编译后的文件放进去。

其实,实际上,当你点击运行 tomcat 时,默认就开始做以下事情:

  • 编译,IDEA 在保存/自动保存后不会做编译,不像 Eclipse 的保存即编译,因此在运行 server 前会做一次编译。编译后 class 文件存放在指定的项目编译输出目录下;
  • 根据 artifact 中的设定对目录结构进行创建;
  • 拷贝 web 资源的根目录下的所有文件到 artifact 的目录下;
  • 拷贝编译输出目录下的 classes 目录到 artifact 下的 WEB-INF 目录下;
  • 拷贝 lib 目录下所需的 jar 包到 artifact 下的 WEB_INF 目录下;
  • 运行 server,运行成功后,如有需要,会自动打开浏览器访问指定 url

Facets

Facets: 英文翻译“(事物的)方面特征”,表述了在 module (项目/模块/组件)中使用的各种各样的框架、技术和语言。这些 Facets 让 IDEA 知道怎么对待 module 内容,并保证与相应的框架和语言保持一致。

使用 Facets 能让我们下载并配置 framework 所必须的组件,会自动生成各种各样的描述符,并存储在适当的位置,等等。

大多数 Facets 可以无冲突得添加到 Module 中。

也有一些 Facets 是继承其他 Facets 的,这些 Facets 的添加就必须先添加他们的父 Facets,这些 Facets 也要依赖Intellij IDEA 的相关插件是否开启.

例如 web 项目,他有一个很重要的作用是配置 web.xml 文件的访问路径和部署 root 的位置

Facets 可以增加某种组件支持,如 web 支持

Servlet

什么是 Servlet?

  1. servlet 是 JavaEE 规范之一,规范就是接口
  2. Servlet 是 JavaWeb 三大组件之一,三大组件分别是:Servlet程序、Filter过滤器、Listener监听器
  3. Servlet 是运行在服务器上的一个 java 小程序,它可以接收客户端发送过来的请求,并响应数据给客户端。

如何创建 Servlet 程序?

  1. 编写一个类去实现 Servlet 接口

  2. 实现 service 方法,处理请求,并响应数据

  3. 到 web.xml 中注册 Servlet 组件

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
             version="4.0">
        <!--servlet 标签给 Tomcat 配置 Servlet 程序-->
        <servlet>
            <!--Servlet 程序的名称,一般是类名-->
            <servlet-name>HelloServlet</servlet-name>
            <!--Servlet 程序的全类名-->
            <servlet-class>cn.xx.HelloServlet</servlet-class>
        </servlet>
    
        <!--给 Servlet 程序配置访问地址-->
        <servlet-mapping>
            <!--该标签的作用是告诉服务器,我当前配置的地址给哪个 Servlet 程序使用-->
            <servlet-name>HelloServlet</servlet-name>
            <!--配置访问地址
            1. 如果配置 / 服务器解析的时候,表示地址为:http://ip:port/工程名 
            2. 如果配置 /hello 服务器解析的时候,表示地址为:http://ip:port/工程名/hello
            -->
            <url-pattern>/hello</url-pattern>
        </servlet-mapping>
    </web-app>
    

Servlet 查找定位

浏览器资源位置去匹配 web.xml 中的 <servlet-mapping> 标签中的 <url-pattern> 中的值,找到后通过

<servlet-name>的值去找到对应 servlet处理类。

Servlet 生命周期

  1. Servlet 构造器 (仅在第一次访问时调用)

  2. init 方法(仅在第一次访问时调用)

  3. service 方法(每次访问都会调用)

  4. destroy 方法(在 web 工程停止时调用)

GET POST 请求分发

在 service 中进行 GET、POST 分发

public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
    HttpServletRequest request = (HttpServletRequest)servletRequest;
    String method = request.getMethod();
    if ("GET".equals(method)) {
        System.out.println("GET METHOD");
    }else if ("POST".equals(method)){
        System.out.println("POST METHOD");
    }
}

继承 HttpServlet

实际使用中,一般继承 HttpServlet 来进行开发

public class BuyServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("request get: "+ req.getQueryString());
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("request post: "+req.getParameter("username")+" "+req.getParameter("stu_class"));
    }
}

idea 创建 Servlet 程序

  1. 在项目包目录上点击右键,再点击 new,再选择 Servlet
  2. 填写类名,可选是否使用基于 servlet3 的注解的配置。(我这里使用 xml 配置)
  3. 在 web.xml 中配置 <servlet-mapping>请求映射路径。

Servlert 继承关系

Interface Servlet <------------ Class GenericServlet <----------------- Class HttpServlet

在这里插入图片描述

各自的作用

  1. Servlet

    只是负责定义 Servlet 程序的访问规范

  2. GenericServlet

    实现了 Servlet 接口,做了很多空实现。并持有一个 ServletConfig 类的引用,并对 ServletConfig 的使用做了一些方法。

    public ServletConfig getServletConfig()
    public ServletContext getServletContext()
    
  3. HttpServlet

    继承了抽象类 GenericServlet 的 service 方法,并实现了请求的分发。在分发的 doGet、doPost 等方法中只是做了抛异常的处理。

ServletConfig

在继承的 Servlet 类中可以在 init 方法中直接使用 servletConfig 对象

@Override
public void init(ServletConfig servletConfig) throws ServletException {
    System.out.println("init");
}

在继承 HttpServlet 类中可以使用下面的代码获取

ServletConfig servletConfig = getServletConfig();

ServletConfig 的作用

  1. 可以获取 Servlet 程序的别名,也就是 web.xml 中 <servlet-name>标签中的值

    String servletName = servletConfig.getServletName();
    
  2. 可以获取初始化参数的值,在 web.xml 的 <servlet> 的 <init-param> 中的键值对

    String username = servletConfig.getInitParameter("username");
    
  3. 可以获取 ServletContext 对象

    ServletContext servletContext = servletConfig.getServletContext();
    
 <servlet>
     <!--Servlet 程序的名称,一般是类名-->
     <servlet-name>HelloServlet</servlet-name>
     <!--Servlet 程序的全类名-->
     <servlet-class>cn.xx.HelloServlet</servlet-class>
     <!--初始化的数据-->
     <init-param>
         <param-name>username</param-name>
         <param-value>root</param-value>
     </init-param>
</servlet>

ServletContext

  1. Servlet 是一个接口,它表示 Servlet 上下文对象
  2. 一个 web 工程,只有一个 ServletContext 对象实例
  3. ServletContext 对象是一个域对象
  4. ServletContext 是在 web 工程部署启动的时候创建。在 web 工程停止的时候销毁。

域对象

可以在不同的 Servlet 中进行数据传递的对象称为域对象。

域对象必须有的方法

void setAttribute(name,value);//存储数据的方法
Object getAttribute(name);//根据 name 获取对应数据值
void removeAttribute(name);//删除数据

ServletContext 的作用

  1. 获取 web.xml 中配置的上下文参数 context-param

    context-param 是上下文参数(属于整个 web 工程,可以配置多个 context-param

    ServletContext servletContext = getServletConfig().getServletContext();
    String password = servletContext.getInitParameter("password");
    
    <!--context-param是上下文参数(属于整个web工程,可以配置多个context-param)-->
    <context-param>
        <param-name>password</param-name>
        <param-value>123456</param-value>
    </context-param>
    
  2. 获取当前的工程路径,格式为:/工程路径

    ServletContext servletContext = getServletConfig().getServletContext();
    String contextPath = servletContext.getContextPath();
    System.out.println("contextPath: "+ contextPath);
    
  3. 获取部署到服务器上的工程绝对路径,映射到 idea 代码中的 web 目录

    ServletContext servletContext = getServletConfig().getServletContext();
    String realPath = servletContext.getRealPath("/");
    

    path 必须以 / 开始, / 表示当前 Web 应用的根目录。

  4. 像 Map 一样存储数据。

ServletContext 存放数据

context.setAttribute("key1","value1");
String val = context.getAttribute("key1");
context.removeAttribute("key1");

HTTP 协议

GET 请求

  1. 请求行

    • 请求方式 GET
    • 请求的资源路径 [+?+请求参数]
    • 请求的协议版本 HTTP/1.1
  2. 请求头

    由 key : value 组成,不同的键值对,表示不同的含义

    Accept:告诉服务器,客户端可以接收的数据类型

    Accept-Language:告诉服务器,客户端可以接收的语言类型

    User-Agent:浏览器的信息

    Accept-Encoding:告诉服务器,客户端可以接收的数据编码(压缩)格式

    Host:表示请求的服务器的 ip 和端口号

    Connection:告诉服务器请求连接如何处理。Keep-Alive 告诉服务器回传数据不要马上关闭,保持一小段时间的连接。Closed 马上关闭。

POST 请求

  1. 请求行

    • 请求方式 POST
    • 请求的资源路径 [+?+请求参数]
    • 请求的协议版本 HTTP/1.1
  2. 请求头

    由 key : value 组成,不同的键值对,表示不同的含义

    Referer : 表示请求时,浏览器地址中的地址(从哪来)

    Content-Type : 表示发送的数据的类型。application/x-www-form-urlencoded 表示提交的数据格式是:name=value&name=value,然后对其进行 url 编码。url 编码是把非英文的内容转换为 %xx%xx

    multipart/form-data 表示以多段的形式提交数据给服务器(以流的形式提交,用于上传)

    Content-Length : 表示发送数据的长度

    Cache-Control 表示如何控制缓存,no-cache 表示无缓存。

  3. 空行

  4. 请求体

    发送给服务器的数据

常用的请求头

Accept:告诉服务器,客户端可以接收的数据类型

Accept-Language:告诉服务器,客户端可以接收的语言类型

User-Agent:浏览器的信息

Host:表示请求的服务器的 ip 和端口号

GET 和 POST 请求分类

GET 请求

  1. form 标签 method 为 get
  2. a 标签
  3. link 标签引入 css
  4. script 标签引入 js
  5. img 标签引入图片
  6. iframe 引入 html 页面
  7. 在浏览器地址栏中输入地址按回车

POST 请求

  1. form 标签 method 为 post

响应 HTTP 协议格式

  1. 响应行

    • 响应的协议
    • 响应状态码
    • 响应状态描述
  2. 响应头

    由 key : value 组成,不同的键值对,表示不同的含义

    Server : 表示服务器的信息

    Content-Type : 表示响应的数据的类型。

    Content-Length : 表示响应数据的长度

    Date : 请求响应的时间。(格林时间)

  3. 空行

  4. 响应体

    回传给客户端的数据

常用的响应码

  • 200

    请求成功

  • 302

    请求重定向

  • 404

    请求服务器已收到,但请求的数据不存在

  • 500

    请求服务器已收到,服务器内部错误

MIME

MIME 是 HTTP 协议中的数据类型

MIME (Multipurpose Internet Mail Extensions) 是描述消息内容类型的标准,用来表示文档、文件或字节流的性质和格式。

MIME 消息能包含文本、图像、音频、视频以及其他应用程序专用的数据。

浏览器通常使用 MIME 类型(而不是文件扩展名)来确定如何处理 URL,因此 Web 服务器在响应头中添加正确的 MIME 类型非常重要。如果配置不正确,浏览器可能会无法解析文件内容,网站将无法正常工作,并且下载的文件也会被错误处理。

语法

MIME 类型通用结构:type/subtype

MIME类型对大小写不敏感,但是传统写法都是小写。

两种主要的 MIME 类型在默认类型中扮演了重要的角色:

  • text/plain 表示文本文件的默认值。

  • application/octet-stream 表示所有其他情况的默认值。

常见的 MIME 类型

  • 超文本标记语言文本 .html、.htmltext/html
  • 普通文本 .txttext/plain
  • RTF 文本 .rtfapplication/rtf
  • GIF 图形 .gifimage/gif
  • JPEG 图形 .jpeg、.jpgimage/jpeg
  • au 声音文件 .auaudio/basic
  • MIDI 音乐文件 mid、.midiaudio/midi、audio/x-midi
  • RealAudio 音乐文件 .ra、.ramaudio/x-pn-realaudio
  • MPEG 文件 .mpg、.mpegvideo/mpeg
  • AVI 文件 .avivideo/x-msvideo
  • GZIP 文件 .gzapplication/x-gzip
  • TAR 文件 .tarapplication/x-tar

详细请参考 MIME 类型 | 菜鸟教程 (runoob.com)

HttpServletRequest

每次只要有请求进入 Tomcat 服务器,Tomcat 服务器就会把请求过来的 HTTP 协议信息解析好封装到 Request 对象中,然后传递到 service 方法 (doGet、doPost) 中给我们使用。我们可以通过 HttpServletRequst 对象,获取到所有的请求信息。

HttpServletRequest 常用方法

  • String getRequestURI();
    

    获取请求的资源路径

  • StringBuffer getRequestURL();
    

    获取请求资源的绝对路径

  • String getRemoteHost();
    

    获取客户端的 ip 地址

  • String getHeader(String var1);
    

    获取指定请求头

  • String getMethod();
    

    获取请求方法

  • String getParameter(String var1);
    

    获取请求的参数(一个 key 对应一个值)

  • String[] getParameterValues(String var1);
    

    获取多个值的请求参数(一个 key 对应多个值)

POST 请求的乱码问题

设置请求的编码解决请求乱码问题,一般设置为 UTF-8

void setCharacterEncoding(String var1) throws UnsupportedEncodingException;

注意:必须在获取请求参数前设置请求编码才能生效

请求转发

请求收到后,从一个资源跳到另一个资源。

//向请求域中传递数据
req.setAttribute("param1","value6666");
//获取请求调度器,设置好请求路径
RequestDispatcher requestDispatcher = req.getRequestDispatcher("/save");
//请求转发
requestDispatcher.forward(req,resp);

请求转发的特点

  1. 浏览器的地址没有变化
  2. 它们是一次请求
  3. 它们共享 Request 域中的数据
  4. 可以转发到 WEB-INF目录下
  5. 无法访问工程以外的资源

请求包含

请求包含是指使用 RequestDispatcher 的 include 方法将 当前的 Servlet 请求和其他的 Web 资源进行处理。改响应头既包含当前 Servlet 的响应内容也包含其他 Servlet 的响应内容。

//获取请求调度器,设置好请求路径
RequestDispatcher requestDispatcher = req.getRequestDispatcher("/save2");
//请求包含
requestDispatcher.include(req,resp);

html 的 base 标签

base 标签设置页面相对路径工作是的参照的地址,href 属性就是参照的值

<base href="http://xxx/xxx/"/>

所有相对路径在工作的时候都会参照当前浏览器地址中的地址来进行跳转

javaweb 中的相对路径和绝对路径

相对路径

  • . 表示当前目录
  • …(两个点) 表示上一级目录
  • 资源名 表示当前目录/资源名

绝对路径

http://ip:port/工程路径/资源路径

web 中斜杠的不同意义

在 web 中 / 是一种绝对路径

/ 被浏览器解析,得到的地址是 http://ip:port

/ 被服务器解析,得到的地址是 http://ip:port/工程路径

绝对路径的使用:

  1. <url-pattern>/test</url-pattern>
  2. servletContext.getRealPath(“/”);
  3. request.getRequestDispacher(“/”);

特殊情况

把 / 发送给服务器解析,得到 http://ip:port

response.sendRediect("/");

referer 请求头

Referer 请求头包含了当前请求页面的来源页面的地址,即表示当前页面是通过此来源页面里的链接进入的。 服务端一般使用 Referer 请求头识别访问来源,可能会以此进行统计分析、日志记录以及缓存优化等。

HttpServletResponse

每次只要有请求进入 Tomcat 服务器,Tomcat 服务器都会创建一个 Response 对象,然后传递到 service 方法 (doGet、doPost) 中给我们使用。我们可以通过 HttpServletResponse 对象,返回数据给客户端。

添加响应头

 void setHeader(String var1, String var2);
 void addHeader(String var1, String var2);
 void setContentLength(int length)

addHeader 方法可以添加同名的响应头。而 setHeader 方法会覆盖同名的响应头。
setContentLength 方法设置 Content-Length 响应头字段的值

响应流

字节流,用于下载(传递二进制数据)

ServletOutputStream getOutputStream() throws IOException;

字符流,常用语传递字符串。响应的默认字符集是 ISO-8859-1,不支持中文

PrintWriter getWriter() throws IOException;

往客户端回传数据

使用流写入数据给客户端

response.getOutputStream().write("hello world 好伐好伐".getBytes(StandardCharsets.UTF_8));
response.getWriter().write("111111");

响应的乱码问题

设置响应的字符集可以防止响应内容乱码

//设置服务器使用 UTF-8 字符集
response.setCharacterEncoding("UTF-8");
//设置浏览器也使用 UTF-8 字符集
response.setHeader("Content-Type", "text/html; charset=UTF-8");

它会同时设置服务器和浏览器都使用 UTF-8 字符集,还设置了响应头

注意:此方法需要在获取流对象之前调用才会生效

response.setContentType("text/html; charset=UTF-8");

两种流只能使用一种,否则会报错

禁止浏览器缓存页面

通过设置响应的响应头来禁止浏览器缓存页面

response.setDateHeader("Expires", 0);
response.setHeader("Cache-Control", "no-cache");
response.setHeader("Pragma", "no-cache");

请求重定向

请求重定向,是指客户端给服务器发请求,然后服务器告诉客户端去请求新的地址(因为之前的地址可能失效了)

请求重定向的第一种方法

请求重定向,第一次请求响应码 为 302,响应头中 Location 会携带新的地址。第二次请求会请求新的地址。

//第一次重定向的请求的响应
response.setStatus(302);
response.setHeader("Location", "http://localhost:8080/webmodule01/redirect2");

请求重定向的第二种方法 (推荐使用)

response.sendRedirect("http://localhost:8080/module01/redirect2");

请求重定向特点

  1. 浏览器地址栏会发生变化
  2. 两次请求
  3. 不共享 Request 域中的数据
  4. 不能访问 WEB-INF 下的资源
  5. 可以访问工程以外的资源

JavaEE 三层架构

1. Web 层

Web 层的作用有:

  1. 获取请求参数,封装成 Bean

  2. 调用 Service 层,处理业务

  3. 响应数据给客户端、请求转发、重定向

Servlet 程序,对应技术有 SpringMvc

Web 层对应 java 的 controller

2. Service 层

Service 层的作用有:

  1. 处理业务逻辑
  2. 调用持久层保存数据到数据库

Spring 框架

Service 层对应 java 的 service 接口和 service.impl 接口实现类

3. Dao 层

只负责跟数据库进行交互,执行 CRUD 操作。

JDBC,对应有 Mybatis、JPA 等等

Dao 层对应 java 的 Dao 接口和 dao.impl Dao 接口实现类

javaEE 对应的其他类有 javaBean 和 测试类

文件上传和下载

文件上传

文件上传步骤:

  1. 要有一个 form标签,method = post
  2. form 标签的 encType 属性值必须为 multipart/form-data
  3. 在 form 标签中使用 <input type='file' name='file'> 添加上传的文件
  4. 编写服务器代码接收,处理上传的数据

encType = multipart/form-data 表示提交的数据,以多段的形式进行拼接,然后以二进制的形式发送给服务器

请求头中的关键数据

Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryVMxBfKK3iE7W6FSO

Content-Type : 表示提交的数据类型。

boundary : 表示每段数据的分割符,它的值由浏览器每次随机生成。

----WebKitFormBoundaryVMxBfKK3iE7W6FSO 表示每段数据的开始

----WebKitFormBoundaryVMxBfKK3iE7W6FSO-- 后面多了两个减号,表示数据的结束标记

commons-fileupload.jar 的使用

commons-fileupload.jar 依赖 commons-io.jar,所以需要导入这两个 jar 包

ServletFileUpload用于解析上传数据

FileItem表示每个表单项

ServletFileUpload常用方法

  • public static final boolean isMultipartContent(HttpServletRequest request)
    

    判断当前上传的数据格式是否是多段上传

  • public List<FileItem> parseRequest(HttpServletRequest request)
    

    解析上传数据

FileItem常用方法

  • boolean isFormField()
    

    判断当前这个表单项是普通表单项还是上传的文件类型

    true 表示普通表单项

    false 表示上传的文件类型

  • String getFieldName()
    

    获取表单项的 name 属性值

  • String getString()
    

    获取当前表单项的值

  • String getName()
    

    获取上传的文件名

  • void write(File var1) throws Exception
    

    将上传的文件写入到参数 var1 指向的位置

@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
	//先判断上传的数据是否是多段数据
	if(ServletFileUpload.isMultipartContent(request)){
		FileItemFactory fileItemFactory = new DiskFileItemFactory();
		ServletFileUpload servletFileUpload = new ServletFileUpload(fileItemFactory);
		List<FileItem> list = servletFileUpload.parseRequest(req); 
		for(FileItem item:list){
			if(item.isFormField()){
				//普通表单项
			}else{
				//上传的文件
				item.write(new File("d"\\"+item.getName()));
			}
		}
	}
}

文件下载

文件下载步骤:

  1. 获取需要下载的文件名
  2. 读取要下载的文件内容
  3. 通过响应头高速客户端返回的数据类型
  4. 还要告诉客户端收到的数据是用于下载使用
  5. 把下载的内容回传给客户端
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
   //1.获取需要下载的文件名
   String name = request.getParameter("name");
   System.out.println("name: " + name);
   ServletContext context = getServletContext();
   //2.读取要下载的文件内容
   InputStream inputStream = context.getResourceAsStream(path);
   String path = "/file/" + name;
   System.out.println("path: " + path);
   //获取文件的类型
   String mimeType = context.getMimeType(path);
   //3.通过响应头高速客户端返回的数据类型
   response.setContentType(mimeType);
   //4.告诉客户端收到的数据是用于下载使用
   response.setHeader("Content-Disposition", "attachment; filename="+name);
   System.out.println("mimeType: " + mimeType);
   //5.把下载的内容回传给客户端
   IOUtils.copy(inputStream, response.getOutputStream());
}

Content-Disposition 响应头,表示收到的数据怎样处理

attachment 表示附件,表示 用于下载。

filename= 表示指定下载的文件名

注意: Google 浏览器中如果文件名有中文,需要使用 URL 编码,再替换到 filename=右边的值

String encode = URLEncoder.encode("你好.jpg", "utf-8");

注意: 火狐浏览器中如果文件名有中文,需要使用 BASE64 编码,header 格式为 attachment; filename==?charset?B?xxx?=

response.setHeader("Content-Disposition", "attachment; filename==?UTF-8?B?"+
                   new BASE64Encoder().encode("你好.jpg".getBytes("UTF-8"))+"?=");
  • =? 表示编码内容开始
  • charset 表示字符集
  • B 表示 BASE64 编码
  • xxx 表示编码后的内容
  • ?= 表示编码内容结束

使用 User-Agent 请求头判断浏览器类型

req.getHeader("User-Agent").contains("FireFox");//返回 true 表示是火狐浏览器

Cookie

Cookie 是在客户端

  1. Cookie 是服务器通知客户端保存键值对的一种技术。
  2. 客户端有了 Cookie 后,每次请求都会发送给服务器
  3. 每个 Cookie 的大小不超过 4K。

注意: Cookie 不支持中文以及特殊符号。可以对内容使用 BASE64 编码后,在进行使用

服务器向浏览器发送 Cookie 使用步骤

  1. 创建 Cookie 对象

  2. 通知客户端保存 Cookie,通过响应头 Set-Cookie 通知客户端保存 cookie。

    Set-Cookie: key1=value1

private void createCookie(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    Cookie cookie = new Cookie("key1","value1");
    response.addCookie(cookie);
    response.setContentType("text/html; charset=UTF-8");
    response.getWriter().write("cookie 创建成功");
}

浏览器向服务器发送 Cookie 步骤

  1. 通过请求头 Cookie 把 Cookie 信息发送给服务器

    Cookie: key1=value1; Idea-8296eef3=99ae362b-2ac2-4692-a6e7-469bd0e47a3a

  2. 服务器通过 request.getCookies() 方法获取到浏览器发送过来的所有 Cookie,它返回一个 Cookie 数组。

Cookie[] cookies = request.getCookies();
if (cookies != null) {
    for (Cookie cookie : cookies) {
        System.out.println("received cookie: " + cookie.getName() + "=" + cookie.getValue());
    }
}

Cookie 的修改

第一种方式:

  1. 在构造器中创建一个相同 name 的 Cookie 对象,同时 value 设置为一个新值
  2. 调用 response.addCookie(cookie)通知浏览器保存修改

第二种方式

  1. 先查询到需要修改的 cookie对象
  2. 通过 cookie.setValue(newVal) 赋予新的值
  3. 调用 response.addCookie(cookie)通知浏览器保存修改

Cookie 的生命控制

Cookie 的生命控制是指如何管理 Cookie 什么时候被删除

void setMaxAge(int expiry)

参数情况:

  1. 参数为正数,表示经过 expiry 秒就删除
  2. 参数为负数,表示浏览器一关,Cookie 就会被删除。默认就是 -1。浏览器上Expires/Max-Age显示为 Seesion级别
  3. 参数为 0,表示马上删除该 Cookie

Cookie 的 Path 属性

可以通过 cookie.setPath(path)来设置 cookie 的 path 属性。

path 属性可以有效的过滤哪些 Cookie 可以发送给服务器,哪些不发。

path 属性是通过请求的地址来进行有效的过滤

例如:

  1. Cookie1 path=/工程名称

  2. Cookie2 path=/工程名称/aaa

请求地址如下:

  • http://ip:port/工程名称/a.html

    Cookie1 发送,Cookie2 不发送

  • http://ip:port/工程名称/aaa/a.html

    Cookie1 发送,Cookie2 发送

Seesion

Seesion 是一种将会话数据保存在服务器端的技术。数据是存放在服务端

  1. seesion 是一个接口(HttpSeesion)
  2. seesion 是一个会话,它是用来维护一个客户端和服务端之间关联的一种技术
  3. 每个客户端都有自己的一个 Seesion 会话
  4. Seesion 会话中,我经常用来保存用户登录之后的信息

使用 HttpServletRequest getSession() 方法创建 Seesion

HttpSession getSession()

第一次调用该方法表示创建 Seesion 会话

之后调用该方法表示获取前面创建好的 Seesion 会话

使用HttpSession isNew() 方法判断 seesion 是否是新创建的

boolean isNew()

true 表示新创建的

false 表示之前创建的

每个会话都有唯一的 id 值

Seesion 的 getId() 方法

String getId()

Seesion 域存取数据

取数据

HttpSession session = request.getSession();
Object val1 = session.getAttribute("key1");

存数据

HttpSession session = request.getSession();
session.setAttribute("key1","value1");

Seesion 设置超时时间

void setMaxInactiveInterval(int var1)

设置 seesion 的存活时间,单位为秒。默认存活时间为 30 分钟。(在 Tomcat 的 web.xml 配置文件中配置了 seesion-timeout 时间是 30 分钟)

当参数为正数时,表示 seesion 存活时长为 var1 秒

当参数为负数时,表示 seesion 永不过期(极少使用)

可以在自己项目的 web.xml 中配置该属性

<seesion-config>
	<seesion-timeout>20</seesion-timeout>
</seesion-config>

获取 Seesion 超时时间

int getMaxInactiveInterval()

设置 Seesion 会话马上超时

void invalidate()

浏览器与 Seesion 的关系

服务器每次创建 Seesion 会话的时候,都会创建一个 Cookie 对象,这个 Cookie 对象的 key 永远是 JSEESIONID,值是新创建出来的 Seesion 的 id 值。

通过响应把创建出来的 Seesion 的 id 返回给 客户端。在 Set-Cookie 响应头中的中会有该 Seesion 的 id 数据。

Set-Cookie: JSESSIONID=E75CB401E7763AC94007887ACFA1E77B; Path=/fmjw; HttpOnly

客户端将此 Cookie 存起来,客户端在下次请求服务器时,会将此 Cookie 发送给服务器,服务器根据此 Cookie 的JSEESIONID 去内存中找出该 Seesion 对象。

Seesion 技术底层技术是基于 Cookie 技术来实现的,存放 Seesion 的 id 的 Cookie 的存活时间是 Seesion 级别的,所以当浏览器关闭时,该 Cookie 就被删除了。同时 Seesion 由于没有了 Cookie 中的 JSEESIONID ,所以会创建新的 Seesion

这就是浏览器打开时,Seesion 就存在,关闭浏览器 Seesion 就销毁了

使用 kaptcha Google 验证码

  1. 导入 kaptcha jar 包
  2. 注册 KaptchaServlet 程序(可以使用 kaptcha jar 包中自带的 KaptchaServlet)
  3. 在 KaptchaServlet 中创建随机验证码
  4. 将验证码存放在 Seesion 中,方便服务器验证客户端发送过来的验证码。
  5. 生成验证码图片,并返回给客户端。
//验证码配置属性
private Producer kaptchaProducer(){
    Properties properties=new Properties();
    //图片的宽度
    properties.setProperty("kaptcha.image.width","100");
    //图片的高度
    properties.setProperty("kaptcha.image.height","40");
    //字体大小
    properties.setProperty("kaptcha.textproducer.font.size","32");
    //字体颜色(RGB)
    properties.setProperty("kaptcha.textproducer.font.color","0,0,0");
    //验证码字符的集合
    properties.setProperty("kaptcha.textproducer.char.string","123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ");
    //验证码长度(即在上面集合中随机选取几位作为验证码)
    properties.setProperty("kaptcha.textproducer.char.length","4");
    //图片的干扰样式
    properties.setProperty("kaptcha.noise.impl","com.google.code.kaptcha.impl.NoNoise");

    DefaultKaptcha Kaptcha = new DefaultKaptcha();
    Config config=new Config(properties);
    Kaptcha.setConfig(config);
    return Kaptcha;
}

@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    Producer producer = kaptchaProducer();
    //创建随机验证码
    String text = producer.createText();
    System.out.println("text=" + text);
    HttpSession session = request.getSession();
    //存放验证码到 Seesion 中
    session.setAttribute("kaptcha",text);
    //生成验证码并返回给客户端
    BufferedImage image = producer.createImage(text);
    ImageIO.write(image,"jpg",response.getOutputStream());
}

服务器验证验证码

 @Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    HttpSession session = request.getSession();
    //从 seesion 中获取验证码
    String token = (String)session.getAttribute(Constants.KAPTCHA_SESSION_KEY);
    //获取完成后,从 seesion 中移除验证码
    session.removeAttribute(Constants.KAPTCHA_SESSION_KEY);
    //从 request中获取 验证码 参数的值
    String code = request.getParameter("code");
    // 比较验证码
    if (token != null && token.equalsIgnoreCase(code)){
        System.out.println("验证成功");
    }
}

前端更新图片验证码

$(function () {
    // 刷新验证码
    $("#verification").bind("click", function () {
        $(this).hide().attr('src', '/verification?random=' + Math.random()).fadeIn();
    });
});

Filter

  1. Filter 过滤器是 JavaWeb 的三大组件之一。
  2. Filter 过滤器它是 JavaEE 的规范,也就是接口。
  3. Filter 过滤器它的作用是 拦截请求、过滤响应

拦截请求的场景

  1. 权限检查
  2. 日志操作
  3. 事务操作

Filter

Filter 过滤器的使用步骤

  1. 编写一个类去实现 Filter 接口
  2. 实现过滤方法 doFilter()
  3. web.xml 中配置 Filter 以及它的拦截路径

Fillter 生命周期

  1. 构造器初始化 (在 web 工程启动的时候就已经执行。)
  2. init 方法(在 web 工程启动的时候就已经执行。)
  3. doFilter 方法(每次拦截到请求,就会执行。)
  4. destroy 方法(在 web 工程停止的时候执行。)

web.xml 中配置 Filter 过滤器

<!--filter 标签用于配置一个 Filter 过滤器-->
<filter>
    <!--给 Filter 过滤器取别名-->
    <filter-name>MyFilter</filter-name>
     <!--Filter 过滤器全类名-->
    <filter-class>cn.xx.web.MyFilter</filter-class>
    
    <!--配置 filter 的初始化数据,可以配置多组,和 servlet 一样-->
    <init-param>
      <param-name>test</param-name>
      <param-value>123456</param-value>
    </init-param>
    
    <init-param>
      <param-name>test2</param-name>
      <param-value>66666</param-value>
    </init-param>
    
  </filter>

 <!--filter-mapping 配置 Filter 过滤器的拦截路径-->
<filter-mapping>
    <!--filter-name 指定当前拦截路径给哪个 filter 使用-->
    <filter-name>MyFilter</filter-name>
    <!--url-pattern 配置拦截路径-->
    <!-- / 表示http:ip:port/工程路径-->
    <url-pattern>/*</url-pattern>
</filter-mapping>

FilterConifg 类

Filter 过滤器的配置文件类。Tomcat 每次创建 Filter 的时候,也同时创建一个 FilterConfig 类,这里包含了 Filter 配置文件的配置信息。

FilterConfig 类的作用是获取 filter 过滤器的配置内容

  1. 获取 filter 的名称,<filter-name> 标签中的值
  2. 获取在 filter 中配置的 <init-param>初始化的值
  3. 获取 ServletContext 的值
public void init(FilterConfig config) throws ServletException {
    //获取 filter-name 标签的值
    String filterName = config.getFilterName();
    //获取 filter 中配置的初始化数据
    String test = config.getInitParameter("test");
    //获取 ServletContext 的值
    ServletContext servletContext = config.getServletContext();
    System.out.println("filterName: "+filterName);
    System.out.println("test: "+test);
    System.out.println("servletContext: "+servletContext);
}

FilterChain

FilterChain.doFilter() 方法的作用

  1. 执行下一个 Filter 过滤器 (如果有下一个 Filter)
  2. 执行目标资源 (如果没有 Filter)

在多个 Filter 过滤器执行的时候,它们执行的优先顺序是由它们在 web.xml 中配置的顺序决定的!

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AkEFYgid-1687073342237)(D:\self\notebook\java\javaweb\filter_order.png)]在这里插入图片描述

多个 Filter 过滤器的执行的特点

  1. 所有 Filter 和目标资源默认都执行在同一个线程中
  2. 多个 Filter 共同执行的时候,它们都使用同一个 Request 对象

Filter 拦截路径

拦截路径可以配置多个

  1. 精确匹配

    <url-pattern> /target.html </url-pattern>

    匹配的地址为 http://ip:port/工程名称/target.html

  2. 目录匹配

    <url-pattern> /res/* </url-pattern>

    匹配的地址为 http://ip:port/工程名称/res/*

  3. 后缀名匹配

    <url-pattern> *.jpg </url-pattern>

    表示请求的地址必须以 .jpg 结尾才会拦截到

    注意:后缀名匹配的不能带有 / ,如 / *.jgp (两种通配方式不能同时使用)

Filter 过滤器只关心请求的地址是否匹配,不关心请求的资源是否存在 !!!

可以通过 Filter 中的后置代码来给 Servlet 中的 Service 逻辑增加事务的提交和回滚

@Override
public void doFilter(HttpServletRequest req, HttpServletResponse res, FilterChain chain)
    throws IOException, ServletException {
    // 获得Connection对象
    Connection connection = JDBCUtils.getConnection();
    try {
        // 开启事务,将默认的自动提交改为false
        connection.setAutoCommit(false);
        // 放行,执行相应代码
        chain.doFilter(req, res);
        // 如果无异常的话,执行到这一步就都成功了,所以提交事务
        connection.commit();
    } catch (Exception e) {
        // 处理异常
        try {
            // 若有异常则回滚数据
            connection.rollback();
        } catch (SQLException e1) {
            e1.printStackTrace();
        }
        e.printStackTrace();
    } finally {
        // 关闭事务
        JDBCUtils.releaseConnection();
    }
}

Listener

概念

Listener 表示监听器,是 JavaWeb 三大组件之一。

监听器可以监听就是在 application、session、request 三个对象创建、销毁或者往其中添加修改删除属性时自动执行代码的功能组件

分类

监听器分类监听器名称作用
ServletContext监听ServletContextListener用于对ServletContext对象进行监听(创建、销毁)
ServletContextAttributeListener用于对ServletContext对象中属性的监听(增删改属性)
Seesion监听HttpSeesionListener对Seesion对象的整体状态的监听(创建、销毁)
HttpSeesionAttributeListener用于对Seesion对象中属性的监听(增删改属性)
HttpSeesionBindingListener监听对象与Seesion的绑定和解除
HttpSeesionActivationListener对Seesion数据的钝化和活化的监听
Request监听ServletRequestListener对Request对象进行监听(创建、销毁)
ServletRequestAttributeListener对Request对象中的属性的监听(增删改属性)

使用

public class MyListener implements ServletContextListener{

    public MyListener() {
    }

    @Override
    public void contextInitialized(ServletContextEvent sce) {
        /* This method is called when the servlet context is initialized(when the Web application is deployed). */
        //加载资源
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        /* This method is called when the servlet Context is undeployed or Application Server shuts down. */
    }
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值