Java_JavaWeb

不定期补充、修正、更新;欢迎大家讨论和指正

概述

Java Web,是用Java技术来解决相关web互联网领域的技术栈。web包括:web服务端和web客户端两部分。Java在客户端的应用有Java Applet,不过使用得很少,Java在服务器端的应用非常的丰富,比如Servlet,JSP、第三方框架等等。Java技术对Web领域的发展注入了强大的动力.

Internet上供外界访问的Web资源分为:

  • 静态web资源(如html 页面):指web页面中供人们浏览的数据始终是不变。
    静态web资源采用的开发技术:HTML、CSS、JavaSript(本文不涉及前端知识,但JavaWeb应该要知道的前端知识有HTML+CSS+JS、JQuery、AJAX、Json。

  • 动态web资源:指web页面中供人们浏览的数据是由程序产生的,不同用户、不同时间点访问web页面看到的内容各不相同。比如不同的用户登入自己淘宝,其购物车都是不同的。
    动态web资源开发技术:JSP/Servlet、ASP、PHP等。

在Java中,动态web资源开发技术统称为Java Web。了解过Java发展历史就知道,Java语言的前身Oak在当时消费品市场上并不算成功,但随着1995年互联网潮流的兴起,Oak迅速找到了最适合自己发展的市场定位并蜕变成为Java语言,成就了今天的Java,所以JavaWeb是Java极其重要的技术栈。

在访问互联网页面时,大致经过以下步骤

  1. 比如用户想要打开百度搜索,首先要在浏览器地址栏输入百度的网址(www.baidu.com),浏览器在B/S架构中作为客户端。

  2. (www.baidu.com)只是百度服务器的域名,而服务器是不能直接通过域名来访问的,而是通过IP地址来访问,所以中间还通过DNS(域名解析服务器)来解析域名,客户端会向域名服务器来询问(www.baidu.com)的IP地址,然后用IP地址来连接百度服务器。

  3. 客户端终于和百度服务器(常见的服务器有Apache、Nginx等)建立起了链接,用户在搜索框输入想搜索的东西,点击确认后,浏览器会向服务器通过Http/Https协议向百度服务器发送Request(请求),当然Http/Https协议只是计算机网络结构的应用层协议,往下还经过TCP/IP协议等,这里屏蔽细节。

  4. 百度服务器接受到请求,会分析请求的URL(uniform resource locator,统一资源定位系统),就是下面一长串的
    www.baidu.com/s?ie=utf-8&f=8&rsv_bp=1&rsv_idx=1&tn=baidu&wd=淘宝……
    因为光连上服务器不行啊,服务器还得知道你想访问什么资源。如果是静态资源,服务器找到相应资源经过处理就直接Response(响应)把浏览器需要的资源返回,如果是动态资源,服务器还得连接到数据库等更复杂的业务。

  5. 浏览器得到服务器Response的资源后,经过一系列处理渲染,呈现给用户。

下面博客比较详细些,Chrome浏览器中按F12可以进入开发者模式,可以看到从服务器请求到的资源,后面也会用得上。
用户访问网站详细流程
在这里插入图片描述
在这里插入图片描述
在后续IDEA来创建web工程,其目录结构应当如下图(约定大于配置)
在这里插入图片描述

  • java,存放项目的Java源代码
  • resources,存放相关的资源,比如数据库连接、Mybatis的配置信息
  • test,测试代码
  • web,存放前端资源,WEB-INF目录下的资源是不能直接通过路径访问的
  • web.xml,web工程的配置信息
  • index.jsp,web工程默认欢迎页

Servlet

Servlet(Server Applet)是Java Servlet的简称,是Sun公司主推的B/S架构,称为小服务程序或服务连接器,用Java编写的服务器端程序,具有独立于平台和协议的特性,主要功能在于交互式地浏览和生成数据,生成动态Web内容。除此之外还有ASP、PHP、JSP等其他动态生成技术。

Servlet是JavaWeb的三大组件(Servlet、Filter、Listener)中最重要的组件,其最主要的的作用是处理请求,服务器会把接收到的请求交给Servlet来处理,在Servlet中通常需要:接收请求数据Request;处理请求;完成响应Response。

下面来简单实现一个Servlet功能
导入Servlet相关依赖

 <!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>4.0.1</version>
            <scope>provided</scope>
        </dependency>

Servlet仅是一个接口,根据上面所说Servlet的主要功能是处理请求,所以以下方法比较符合的只有service()方法了
在这里插入图片描述
实现该方法,这段代码的作用是向浏览器屏幕打印消息
在这里插入图片描述

接下来就是让我们自定义的Servlet程序与URL作映射(在web.xml中作映射),这样当我们访问服务器的某个URL时,服务器会让相应的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类的位置,servlet-name可以任意,不过还是跟类名一致比较好 -->
	<servlet>
        <servlet-name>myServlet</servlet-name>
        <servlet-class>com.jojo.servlet.MyServlet</servlet-class>
    </servlet>
	
	<!-- 将URL和Servlet程序作映射,这里映射的是/1,也就是说当我们访问http://localhost:8080/web/1时,我们的请求会发送给
		com.jojo.servlet.MyServlet1这个类做处理,至于http://localhost:8080/web取决于你是如何自定义Tomcat部署路径的 -->
	<servlet-mapping>
        <servlet-name>myServlet</servlet-name>
        <!-- 1前面的/不能省略,它表示是当前Web项目部署的路径,可以把它等价为http://localhost:8080/web/ -->
        <url-pattern>/1</url-pattern>
    </servlet-mapping>

</web-app>

当然要实现该功能还需要服务器的支持,Tomcat是Javaweb中常用的服务器,现在我们只需要知道它是服务器,Servlet的容器就行,后面会提到。

启动Tomcat服务器,地址栏输入http://localhost:8080/web/1(因为是在本机测试,所以ip地址使用localhost或127.0.0.1,Tomcat服务器的默认端口号为8080,/web是我设置的整个web工程部署路径,直接访问该路径一般访问的是index.jsp的资源

http://localhost:8080/web 是该web工程的完整路径

接下来访问该工程下的/1路径的资源,可以看到浏览器打印了"Hello Servlet",说明该路径确实由相应的Servlet经过处理
在这里插入图片描述

doGet 和doPost

我们知道Http请求主要有两种Get和Post(OPTIONS, PUT, DELETE, TRACE ,CONNECT这些先不说)

Post相比于Get能携带的数据更多,更安全,一般来说Post用于修改和写入数据,Get一般用于搜索排序和筛选之类的操作(淘宝,支付宝的搜索查询都是get提交)。

那么如何对这两种请求分别作出不同的处理呢,我们先在index.jsp写一个表单,用于发送不同的请求
在这里插入图片描述
在这里插入图片描述
这里就不创建新的Servlet了,用刚才的MyServlet处理就行
如何得知请求的类型,很显然从两个参数之一ServletRequest做文章就行,但ServletRequest没有相关的方法,因此需要使用其子类HttpServletRequest
在这里插入图片描述
HttpServletRequest提供了获取请求方式的方法
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
修改表单提交方式为post
在这里插入图片描述
这样就可以对不同请求方式做出不同的处理了
在这里插入图片描述
不过自己来处理还是有些麻烦,事实上,在web项目中,更多的是继承Servlet下的子类HttpServlet来实现自己的Servlet的
在这里插入图片描述
该类在service()方法的基础上,提供了doGet()、doPost()、doHead()等所有Http请求的方法,我们只需要重写即可
在这里插入图片描述
在这里插入图片描述
以下为Servlet继承树,有兴趣的自己研究

在这里插入图片描述

ServletContext

Servlet中有三大作用域对象,主要用于以类似键值对的方式共享数据,作用域范围由小到大依次为

  • request:每一次请求都是一个新的 request 对象,如果在 web 组件之间需要共享同一个请求中的数据,只能使用请求转发。
  • session:每一次会话都是一个新的 session 对象,如果如果需要在一次会话中的多个请求之间需要共享数据,只能使用session。
  • application:应用级作用域,生命周期随着服务器的启动到销毁。,作用于整个 Web 应用,可以实现多次会话之间的数据共享在,一个应用中有且只有一个 application 对象。

application作用域具体的对象是ServletContext,在Web容器启动时,会为每个Web程序创建一个ServletContext对象,它代表当前Web应用。ServletContext是全局的,所以可以在不同的Servlet共享数据。

现在自定义两个Servlet,一个用于向应用作用域中存储数据,另一个从应用作用域取出数据,这就实现了Servlet间数据的共享

public class MyServlet1 extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        ServletContext servletContext = this.getServletContext();
        String m1 = "Can you see that?";
        servletContext.setAttribute("message",m1);//以键值对的形式向Context保存信息


    }
public class MyServlet2 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
        ServletContext servletContext = this.getServletContext();
        String message = (String)servletContext.getAttribute("message");//获取Context信息
		
		PrintWriter writer = resp.getWriter();//向浏览器输出信息
        writer.println(message);
    }
}

配置好映射,输入MyServlet2映射的URL(如果没出来效果可能是MyServlet1没执行就先执行MyServlet2,所以要先打开MyServlet1映射的URL)
在这里插入图片描述

Request

在前面已经大致了解Request一些具体实现类的作用了,只要有请求发送到Tomcat服务器,服务器就会把请求过来的Http协议信息解析好封装到Request实现类中。

以HttpServletRequest类为例,常用的API有

  • getSession()和getCookies(),Session和Cookie也是web中重要的知识点,后面单独讲

  • setCharacterEncoding(),设置字符集,避免乱码的情况,一般创建字符编码过滤器来处理

  • getContextPath(),获得当前web工程的路径,比如我的就是/web,这方法很多地方都有

  • getAttribute()/setAttribute()/removeAttribute(),前面说了Servlet有三大作用域,request就是其中一个,所以当然有共享数据的方法

  • getParameter(),获取请求中的参数,很重要的方法,比如在页面中输入账号密码,通过该方法就可以得到相关内容
    在这里插入图片描述
    在这里插入图片描述

    在这里插入图片描述
    在这里插入图片描述

  • getRequestDispatcher(),获取请求转发对象,跳转页面的一种方法,稍后和重定向一起讲

Response

当Servlet处理完数据后,就可以通过Response(响应)具体实现类返回给客户端数据了

  • setStatus()/getStatus(),设置状态码,这样客户端就知道服务器是否成功返回数据,或者是为什么没能接收到数据,比如很熟悉的404(所请求的页面不存在或已被删除,一般是URL错误),其他状态码自行了解(HTTP状态码)
  • setCharacterEncoding(),设置字符集
  • getWriter(),获取PrintWriter对象,字符流,常用于向浏览器屏幕输出信息
  • getOutputStream(),同上,返回字节流数据,常用于下载,两者在一个Servelt中只能使用一个
  • sendRedirect(),重定向,稍后讲

Java Response实现文件下载

请求转发和重定向

Servlet中页面的跳转有两种方法:请求转发和重定向

转发主要是将浏览器的请求交给另外一个servlet或jsp来处理,借助request对象完成,在服务器内部跳转,浏览器的地址并不发生改变,并且浏览器并不知道服务器内部发生了跳转,整个过程只会发生一次请求,转发的调用者和被调用者都可以共享request对象和response对象。
转发的优点一是安全性高,在内部发生跳转,浏览器地址不变;二是节省资源,转发只需要一次请求,就可以访问至少两个servlet或jsp页面。在实际开发中,转发用到的较多。
转发的局限性在于只能在同一web应用内使用,不能转发到外部的url地址。


public class MyServlet1 extends HttpServlet {


    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

       RequestDispatcher requestDispatcher = req.getRequestDispatcher("/2");
       //注意2前面的/不能省略,它表示是当前Web项目部署的路径,可以把它等价为http://localhost:8080/web/
       requestDispatcher.forward(req,resp);//相当于把当前的数据交给另一个Servlet处理,所以需要传递当前Request和Response

    }        
public class MyServlet2 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        PrintWriter writer = resp.getWriter();
        writer.println("Hello");
    }
}

如下图,访问的是/1路径,却是MyServlet2来处理请求,url的地址也没有变化,因为转发时传的是同一个请求,所以request作用域的数据可以共享
在这里插入图片描述

重定向是指服务器通知浏览器向一个新的地址发送请求,由response对象完成,可以重定向到新的servlet(服务器内部),也可以重定向到外部url(外部应用),浏览器地址发生改变,浏览器知道发生了跳转,整个过程会产生两次请求,重定向的调用者和被调用者不能共享request对象和response对象。
重定向的优点是不限制应用范围,可以重定向到服务器内部其他资源,也可以是外部的应用。
重定向的缺点是耗费请求资源,重定向整个过程发生了两次的请求,一个是资源消耗上比转发大,效率也比转发低;另外,因为浏览器的地址发生了变化,相对转发来讲,安全性没有转发高。
Servlet(四):转发与重定向、路径问题


public class MyServlet1 extends HttpServlet {


    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		
	   ServletContext servletContext = this.getServletContext();
       resp.sendRedirect(servletContext.getContextPath()+"/2");
       //重定向不同于转发,转发是在服务器内部,而重定向外内部都行,如果重定向的是内部,则需要加上应用名
       //比如http://localhost:8080/web/中http://localhost:8080是域名,/web是应用名
       //为了避免直接将应用名写在地址里面,可以使用request(servletContext也行).getContextPath()方法来替代。
       //直接加的话就是"/web/2"

    }        
public class MyServlet2 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        PrintWriter writer = resp.getWriter();
        writer.println("Hello");
    }

F12进入开发者模式,可以看到/1的状态码为302(可以简单的理解为该资源原本确实存在,但已经被临时改变了位置)
在这里插入图片描述

可以想象,请求转发是在银行办理业务,在前台填好资料给前台工作人员,然后前台工作人员交给后台人员处理,你所在的位置依然在银行的前台。而重定向就是拿着资料去某部门办理,该部门说这东西不归他们管,然后告诉你去其他部门办理,这时所在位置就应该是另一个部门了。

生命周期

在 Java 中,对象的生命周期被定义为该对象从创建直到销毁的整个过程。任何对象都有生命周期,Servlet 也不例外。
与 Servlet 生命周期有关的方法一般有以下三个:
在这里插入图片描述

  1. init() 方法
    init() 方法是在创建 Servlet 对象时被调用,而且只能被调用一次,用于 Servlet 对象在整个生命周期内的唯一一次初始化。只有在 init() 方法调用成功后,Servlet 才会处于服务状态,才能够去处理客户端的请求。
  2. service() 方法
    service() 方法是 Servlet 工作的核心方法。当客户端请求访问 Servlet 时,Servlet 容器就会调用 service() 方法去处理来自客户端的请求,并把处理后的响应返回给客户端。
  3. destroy() 方法
    destory() 方法是 Servlet 容器回收 Servlet 对象之前调用的,且只会调用一次,而此时的服务器处于停止状态或者访问资源已经被移除。

在这里插入图片描述

  1. 初始化阶段
    当用户第一次向 Servlet 容器发出 HTTP 请求要求访问某个 Servlet 时,Servlet 容器会在整个容器中搜索该 Servlet 对象,发现这个 Servlet 对象没有被实例化,于是创建这个 Servlet 对象,然后调用该对象的 init() 方法完成初始化。
    当用户第二次访问这个 Servlet 时,Servlet 容器仍然在容器中搜索该 Servlet 对象,结果找到了该对象的实例,则不去创建而直接使用该象。
    找到了对应的 Servlet 对象,随后 Servlet 进入到运行阶段。
    需要注意的是,在 Servlet 的整个生命周期内,它的 init() 方法只被调用一次。
  2. 运行阶段
    这是 Servlet 生命周期中最核心的阶段。在该阶段中,Servlet 容器会为当前的请求创建一个 ServletRequest 对象和一个 ServletResponse 对象(它们分别代表 HTTP 请求和 HTTP 响应),并将这两个对象作为参数传递给 Servlet 的 service() 方法。
    service() 方法从 ServletRequest 对象中获得用户的详细请求信息并处理该请求,通过 ServletResponse 对象生成响应结果。
    需要强调的是,在 Servlet 的整个生命周期内,用户每次请求访问 Servlet 时,Servlet 容器都会调用一次 Servlet 的 service() 方法,并且创建新的 ServletRequest 和 ServletResponse 对象。
  3. 销毁阶段
    当服务器停止时,Servlet 容器需要回收 Servlet 对象所占用的内存,在回收之前,会自动调用该对象的 destroy() 方法做好回收内存前的准备,辟如关闭后台线程。
    和 init() 方法类似,destroy() 方法也只会被调用一次。
    注意:Servlet 对象一旦创建就会驻留在内存中一直等待客户端的访问,直到服务器关闭或项目被移除出容器时,Servlet 对象才会被销毁。

原文:Servlet生命周期(图解)

文件上传

文件的上传和下载是互联网很常见的功能,现在来利用Javaweb来简单实现文件上传的功能。
文件上传主要分为两步:在前端写好传输功能、在后端接收文件并保存

在前端页面用form表单上传,其中

  • 提交方式以Post方式提交,因为Get请求携带的数据少且有限。
  • enctype=“multipart/form-data”(表示提交的数据以多段形式拼接,然后以二进制流发送给服务器)
  • input标签类型为file,且name属性需要设置,不然浏览器不会发送上传文件的数据

在这里插入图片描述
在这里插入图片描述

实现相关Servlet,先测试连通性
在这里插入图片描述
别忘了映射
在这里插入图片描述
URL绑定好Servlet后,就可以写接收文件的代码了
在这里插入图片描述
我们先试着接收流对象
在这里插入图片描述
成功接收到
在这里插入图片描述
尽管我们可以成功接收到流,但是因为分片的缘故,每个片段前面都会附加一些辅助的信息,所以还需要经过解析才能真正获取文件的内容。对于解析文件不仅繁琐而且目前也不会,所以要使用第三方来实现。
这里使用Apache提供的commons-fileupload

导入依赖

		<dependency>
            <groupId>commons-fileupload</groupId>
            <artifactId>commons-fileupload</artifactId>
            <version>1.3.3</version>
        </dependency>

个人对这些API也不是很熟,建议看尚硅谷的视频了解尚硅谷最新版JavaWeb全套教程,java web零基础入门完整版
在这里插入图片描述

在这里插入图片描述

文件下载

文件下载大致步骤如下:

  • 准备下载资源
  • 通过输入流获取提供的资源
  • 设置响应头
  • 通过响应头回传下载资源

这里以下载图片为例
在这里插入图片描述
在这里插入图片描述
第二步:通过输入流获取该资源的数据
客户端只需要向服务器发送下载请求,所以用Get请求就行
因为该资源的路径是web工程下,所以只能使用作用域最大的servletContext获取该资源
在这里插入图片描述
第三步:设置响应头信息
设置MIME类型,MIME是一种标准,用来表示文档、文件或字节流的性质和格式,就是告诉这个文件是什么类型的文件,比如之前的text/html,这里为image/jpeg, 自行了解。

设置响应头,告诉客户端应该怎么处理下载的资源,比如直接打开还是以附件存储。
这里要使用Content-disposition属性,Content-disposition 是 MIME 协议的扩展,MIME 协议指示 MIME 用户代理如何显示附加的文件。

其值disposition-type表示以什么方式下载,如attachment为以附件方式下载,disposition-parm为默认保存时的文件名服务端向客户端游览器发送文件时,如果是浏览器支持的文件类型,一般会默认使用浏览器打开,比如txt、jpg等,会直接在浏览器中显示,如果需要提示用户保存,就要利用Content-Disposition进行一下处理,关键在于一定要加上attachment。

这里以附件形式下载,"attachment; filename="后面可以自定义下载文件的名称
在这里插入图片描述
最后一步,通过响应的输出流将数据回传给客户端/
之前使用IO流时,一般是以创建缓冲区的形式,将输入流的数据复制到输出流
在文件上传时使用了第三方工具,这里也可以使用commons-fileupload第三方工具下的IOUtils.copy(),将输入流直接复制给输出流
在这里插入图片描述
完整代码如下

@Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        String downloadFile = "/img/wenming.jpg";
        ServletContext servletContext = getServletContext();
        InputStream is = servletContext.getResourceAsStream(downloadFile);

        String mimeType = servletContext.getMimeType(downloadFile);
        resp.setContentType(mimeType);
        resp.setHeader("Content-Disposition","attachment; filename=" + "civilizationVI.jpg");

        ServletOutputStream os = resp.getOutputStream();
        IOUtils.copy(is,os);
        
    }

剩下的就是Servlet的常规操作,映射之类的
成功下载
在这里插入图片描述

Tomcat

在这里插入图片描述

在写完相关的Servlet后,要知道IDEA本身只能执行Java代码,是没有让浏览器访问的功能,所以需要将写好的代码部署在相关的Web服务器上。

大家可能听过三大主流的Web服务器(Apache、 Nginx 、IIS),但Servlet用的服务器在广义上也是Web服务器(提供Web服务都可以叫Web服务器),所以很多地方也叫Web服务器,但作用有很大区别。具体点来说Servlet的是应用服务器,为了避免歧义,后序将这些服务器叫做应用服务器或者Servlet的容器。

前者具体来讲是Http服务器,因为当今Web在应用层使用的协议基本是HTTP协议,所以可以将Http服务器和Web服务器对等,这类服务器侧重于对静态资源的支持,有时也叫静态服务器。后者侧重动态资源,即动态服务器

Web服务器一般指网站服务器,是指驻留于因特网上某种类型计算机的程序,可以处理浏览器等Web客户端的请求并返回相应响应,也可以放置网站文件,让全世界浏览;可以放置数据文件,让全世界下载。目前最主流的三个Web服务器是Apache、 Nginx 、IIS。
Tomcat是Apache 软件基金会(Apache Software Foundation)的Jakarta 项目中的一个核心项目,Tomcat 服务器是一个免费的开放源代码的Web 应用服务器,属于轻量级应用服务器,在中小型系统和并发访问用户不是很多的场合下被普遍使用,是开发和调试JSP 程序的首选。一般来说Apache 为HTML页面服务,而Tomcat 实际上运行JSP 页面和Servlet。也就是说一般Apache适合静态页面,Tomcat适合动态页面。
——摘自百度百科

Apache与Tomcat有什么关系和区别
这里强烈推荐看看🐏哥的这个视频:服务器软件大科普!

Servlet最主流的容器是Tomcat,除此之外还有一些其他容器Web Logic、Jetty、JBoss、Resin、GlassFish等。

关于Tomcat的安装部署,以及如何整合到IDEA中,篇幅原因自行看下面文章。

  1. Tomcat 下载、安装、配置图文教程
  2. Tomcat 部署项目的三种方法
  3. IntelliJ IDEA整合Tomcat服务器

Cookie和Session

在浏览器访问服务器时,因为HTTP协议是无状态的,即服务器不知道用户上一次做了什么,这严重阻碍了交互式Web应用程序的实现。在典型的网上购物场景中,用户浏览了几个页面,买了一盒饼干和两饮料。最后结帐时,由于HTTP的无状态性,不通过额外的手段,服务器并不知道用户到底买了什么。为了追踪用户的信息,需要一些机制来实现,即Cookie和Session。

Cookie

Cookie(饼干),是一个保存在客户机中的简单的文本文件, 这个文件与特定的 Web 文档关联在一起, 保存了该客户机访问这个Web 文档时的信息, 当客户机再次访问这个 Web 文档时这些信息可供该文档使用。由于“Cookie”具有可以保存在客户机上的神奇特性, 因此它可以帮助我们实现记录用户个人信息的功能, 而这一切都不必使用复杂的CGI等程序

比如在浏览器打开控制台后,登入哔哩哔哩,可以看到以键值对存储信息的Cookie,只要这些Cookie存在并且没有过期,在之后再进入哔哩哔哩,就不需要输入账号密码了。
在这里插入图片描述
Cookie是一段不超过4KB的小型文本数据,由一个名称(Name)、一个值(Value)和其它几个用于控制Cookie有效期、安全性、使用范围的可选属性组成。其中 :

  1. Name/Value:设置Cookie的名称及相对应的值,对于认证Cookie,Value值包括Web服务器所提供的访问令牌
  2. Expires属性:设置Cookie的生存期。有两种存储类型的Cookie:会话性与持久性。Expires属性缺省时,为会话性Cookie,仅保存在客户端内存中,并在用户关闭浏览器时失效;持久性Cookie会保存在用户的硬盘中,直至生存期到或用户直接在网页中单击“注销”等按钮结束会话时才会失效 。
  3. Path属性:定义了Web站点上可以访问该Cookie的目录
  4. Domain属性:指定了可以访问该 Cookie 的 Web 站点或域。Cookie 机制并未遵循严格的同源策略,允许一个子域可以设置或获取其父域的 Cookie。当需要实现单点登录方案时,Cookie 的上述特性非常有用,然而也增加了 Cookie受攻击的危险,比如攻击者可以借此发动会话定置攻击。因而,浏览器禁止在 Domain 属性中设置.org、.com 等通用顶级域名、以及在国家及地区顶级域下注册的二级域名,以减小攻击发生的范围。
  5. Secure属性:指定是否使用HTTPS安全协议发送Cookie。使用HTTPS安全协议,可以保护Cookie在浏览器和Web服务器间的传输过程中不被窃取和篡改。该方法也可用于Web站点的身份鉴别,即在HTTPS的连接建立阶段,浏览器会检查Web网站的SSL证书的有效性。但是基于兼容性的原因(比如有些网站使用自签署的证书)在检测到SSL证书无效时,浏览器并不会立即终止用户的连接请求,而是显示安全风险信息,用户仍可以选择继续访问该站点。由于许多用户缺乏安全意识,因而仍可能连接到Pharming攻击所伪造的网站
  6. HTTPOnly 属性 :用于防止客户端脚本通过document.cookie属性访问Cookie,有助于保护Cookie不被跨站脚本攻击窃取或篡改。但是,HTTPOnly的应用仍存在局限性,一些浏览器可以阻止客户端脚本对Cookie的读操作,但允许写操作;此外大多数浏览器仍允许通过XMLHTTP对象读取HTTP响应中的Set-Cookie头

Cookie是服务器创建(第一次登录或登录信息过期)并返回给客户端的,在之后客户端每次访问该服务器时,在HTTP协议请求时都携带Cookie,这样服务器通过Cookie知道该用户的信息了。比如学校给每位学生办了学生证,这样学生就可以凭借学生证自由出入校园,而没有学生证的新生或学生证丢失过期的学生要自由出入校园就得向学校重新办理学生证。

我们可以分别在控制台查看某网站下登录过与没登录状态下的请求头

登录过
在这里插入图片描述
没登录
在这里插入图片描述
当用户第一次访问并登陆一个网站的时候,cookie的设置以及发送会经历以下4个步骤:
在这里插入图片描述
根据上图我们来用代码进行验证
在这里插入图片描述

第一次访问时,响应头返回了Cookie,但请求头没有相关Cookie
在这里插入图片描述
再次访问,请求头携带Cookie,服务器要获取请求中的Cookie,只需要调用req.getCookies()方法即可。
在这里插入图片描述
大致了解Cookie后,来看Cookie相关的API
在这里插入图片描述
其实也没什么好讲的,就是Cookie相关属性的Get/Set方法。相关属性如何设值,自行了解:Cookie的所有属性详解

需要注意的是因为响应和Cookie本身没有删除和修改Cookie的相关方法,只有resp.addCookie()方法,所以想要修改Cookie只能使用一个同名的Cookie来覆盖原先的Cookie。如果要删除某个Cookie,则只需要新建一个同名的Cookie,并将maxAge设置为0,并覆盖原来的Cookie即可(新建的Cookie,除了value、maxAge之外的属性,比如name、path、domain都必须与原来的一致才能达到修改或者删除的效果。否则,浏览器将视为两个不同的Cookie不予覆盖。)。

Session

Cookie虽然在一定程度上解决了“保持状态”的需求,但是由于Cookie本身最大支持4K字节,以及Cookie本身保存在客户端,可能被拦截或窃取,因此就需要有一种新的东西,它能支持更多的字节,并且保存在服务器,有较高的安全性。这就是Session。

Session:在计算机中,尤其是在网络应用中,称为“会话控制”。Session对象存储特定用户会话所需的属性及配置信息。这样,当用户在应用程序的Web页之间跳转时,存储在Session对象中的变量将不会丢失,而是在整个用户会话中一直存在下去。当用户请求来自应用程序的 Web页时,如果该用户还没有会话,则Web服务器将自动创建一个 Session对象。当会话过期或被放弃后,服务器将终止该会话。Session 对象最常见的一个用法就是存储用户的首选项。例如,如果用户指明不喜欢查看图形,就可以将该信息存储在Session对象中。

在Servlet中提到三大作用域,Session是其中一种,比request的作用域范围更大。Session 的作用范围为一段用户持续和服务器所连接的时间,但与服务器断线,这个属性就无效了。
Session 的开始时刻比较容易判断,它从浏览器发出第一个HTTP请求即可认为会话开始。但结束时刻就不好判断了,因为浏览器关闭时并不会通知服务器,所以只能通过如下这种方法判断:如果一定的时间内客户端没有反应,则认为会话结束。Tomcat的默认值为120分钟,但这个值也可以通过HttpSession的setMaxInactiveInterval()方法来设置。

Session的工作流程和Cookie很相似,只不过Session是保存在服务器内存中(Session也是以临时Cookie的形式存在)

  1. 用户第一次请求服务器时,服务器端会生成一个Session ID
  2. 服务器端将生成的Session ID通过set-cookie返回给客户端,
  3. 客户端收到Session ID会将它保存在cookie中,当客户端再次访问服务端时会带上这个Session ID
    当服务端再次接收到来自客户端的请求时,会先去检查是否存在Session ID,不存在就新建一个Session ID重复1,2的流程,如果存在就去服务端的session文件,找到与这个Session ID相对应的文件,文件中的键值便是Session ID,值为当前用户的一些信息
  4. 此后的请求都会交换这个 Session ID,进行有状态的会话。

Session一般是由服务器来自动创建的
在这里插入图片描述
第一次访问什么都没有
在这里插入图片描述
可以看到响应头以Cookie的形式返回了Session ID
在这里插入图片描述
在这里插入图片描述
当再次访问该网站,响应头就不再携带Session ID了,请求头带就行
在这里插入图片描述

现在看常用的API

  • req.getSession(),从请求中获取Session
  • getAttribute()/setAttribute(),session作为Servlet的作用域,理当有共享数据的方法
  • isNew(),
  • invalidate(),清空session对象里的东西,但不是清除这个session对象本身
  • getMaxInactiveInterval()/setMaxInactiveInterval(),session的有效时间,默认是1800秒,Tomcat服务器默认时间也是1800秒,即30分钟,如果想修改服务器下所有session的有效时间,可以在web.xml进行配置
    在这里插入图片描述

简单来说Session是服务端技术,用来保存用户的会话信息;Cookie是客户端技术;Session 的运行依赖 session id,而 session id 是存在 Cookie 中的,也就是说,如果浏览器禁用了 Cookie ,同时 Session 也会失效(但是可以通过其它方式实现,比如在 url 中传递 session_id)。
还是拿学生证举例,学生证相当于Cookie,学生证上因为空间限制只有学号、性名、学院等基础信息,学生证中的学号就像session id,学号通过学生证传递到学校管理系统(session通过cookie携带),学校方就可以通过学号验证该学生是否为本校学生,学生科目成绩等更加丰富的信息(会话信息)。

自行了解:
你真的了解 Cookie 和 Session 吗?
浅谈Session与Cookie的区别与联系
实现用户登录到底使用cookie还是session?
cookie安全性问题
正确理解 Session 的安全性
Session攻击(会话劫持+固定)与防御

JSP

在学习JSP前,我们先来看这样一个场景,我们接收到客户端的请求后动态地生成HTML页面并响应,这是很常用的功能
代码如下,向浏览器屏幕打印的这些代码因为HTML格式会转换为HTML页面
在这里插入图片描述
仅仅是向浏览器生成简单的HTML页面就要写如此繁琐的代码,因此需要别的技术来动态生成HTML页面。
在这里插入图片描述

JSP就是这么一种技术。虽然JSP在当前的技术栈中比较落后,但为了了解Web项目开发流程的发展,亦或者维护老项目还是很有学习的必要的。

JSP(Java Server Pages,Java服务器页面)是由Sun Microsystems公司主导创建的一种动态网页技术标准。JSP部署于网络服务器上,可以响应客户端发送的请求,并根据请求内容动态地生成HTML、XML或其他格式文档的Web网页,然后返回给请求者。JSP技术以Java语言作为脚本语言,为用户的HTTP请求提供服务,并能与服务器上的其它Java程序共同处理复杂的业务需求。JSP将Java代码和特定变动内容嵌入到静态的页面中,实现以静态页面为模板,动态生成其中的部分内容。HTML只能给用户提供静态的页面,而JSP页面可以嵌入Java代码,所以具有一定的动态性。

相比于普通的Servlet在Java代码中通过HttpServletResponse对象动态输出HTML内容,在Java源文件中通过字符串拼接的方式生成动态HTML内容会导致代码维护困难、可读性差。
而JSP在静态HTML内容中嵌入Java代码,Java代码被动态执行后生成HTML内容。

编写一个JSP页面(除了<%@ page …表明这是一个JSP页面,其他与HTML页面无异)
在这里插入图片描述
现在要做的只是在自定义的Servlet中将请求转发到写好的JSP中(为什么可以转发到JSP,这是因为JSP本质就是Servlet,后面可以看到)
在这里插入图片描述
这样,对于生成动态页面的职责就可以完全交付给JSP,而Servlet则注重业务逻辑
在这里插入图片描述

JSP本质是一个Servlet,我们可以查看其底层实现,我们找到Tomcat下JSP的工作目录(当然要访问该JSP才会编译,路径太绕了,看看就行,)
在这里插入图片描述

打开java文件,可以看到JSP导入了Servlet的包,直接继承的是HttpJspBase类,但是还不知道HttpJspBase是什么东西
在这里插入图片描述

搜了下HttpJspBase,发现继承了HttpServlet。所以JSP的底层还是Servlet,因为只要浏览器访问服务器,不管访问什么资源,其实都是访问Servlet
在这里插入图片描述
继续往下看,似曾相似的一幕,JSP的大致原理就是这样
在这里插入图片描述

四大作用域和九大内置对象

我们已经知道JSP本质上是Servlet,所以Servlet有的JSP也有,当然还有许多Servlet没有的东西。
Servlet有三大作用域,JSP在此基础上多了一个

  • page范围:只在一个页面保留数据(javax.servlet.jsp.PageContext(抽象类))
  • request范围:只在一个请求中保存数据(javax.servlet.httpServletRequest)
  • Session范围:在一次会话中保存数据,仅供单个用户使用(javax.servlet.http.HttpSession)
  • Application范围:在整个服务器中保存数据,全部用户共享(javax.servlet.ServletContext)

每个JSP编译后,都会内置九个对象,可以在编译后文件中找到
在这里插入图片描述
其中exception对象要在JSP页面开启isErrorPage="true"后才会出现
在这里插入图片描述
以下为九大内置对象的大致用途,详细点可以看这篇文章jsp四大作用域和九大内置对象

  • out对象:用于向客户端、浏览器输出数据。
  • request对象:封装了来自客户端、浏览器的各种信息。
  • response对象:封装了服务器的响应信息。
  • exception对象:封装了jsp程序执行过程中发生的异常和错误信息。
  • config对象:封装了应用程序的配置信息。
  • page对象:指向了当前jsp程序本身。
  • session对象:用来保存会话信息。也就是说,可以实现在同一用户的不同请求之间共享数
  • application对象:代表了当前应用程序的上下文。可以在不同的用户之间共享信息。
  • pageContext对象:提供了对jsp页面所有对象以及命名空间的访问。

关于out对象,有需要注意的地方,我们分别使用out对象和PrintWriter对象向浏览器传输数据,<%代码%> 为JSP语法,稍后就会学到,这里先忽略
在这里插入图片描述
然而输出结果却是PrintWriter对象先输出
在这里插入图片描述
这是因为out对象和response各自拥有自己的缓冲区。当JSP页面所有代码执行完成后会执行out.flush()方法将out缓冲区的数据追加到response的缓冲区,随后才会刷新response缓冲区将数据响应给浏览器
而PrintWriter的内容就存放在response缓冲区内,这就导致上面的情况

因此我们可以强制先将out缓冲区刷新,这样就会在PrintWriter前将数据写进response缓冲区
在这里插入图片描述

在这里插入图片描述
不过开发中不必担心这种情况,因为对于向浏览器传输数据,统一使用out对象就好

语法

JSP 语法

在使用JSP前需要导入JSP相关依赖

        <!-- https://mvnrepository.com/artifact/javax.servlet.jsp/javax.servlet.jsp-api -->
        <dependency>
            <groupId>javax.servlet.jsp</groupId>
            <artifactId>javax.servlet.jsp-api</artifactId>
            <version>2.3.3</version>
            <scope>provided</scope>
        </dependency>
JSP页面配置:<%@  代码  %>;JSP指令用来设置与整个JSP页面相关的属性。

比如我们要在页面正常显示中文,我们需要在 JSP 文件头部添加以下代码:
<%@ page language=“java” contentType="text/html; charset=UTF-8 pageEncoding=“UTF-8”%>
在这里插入图片描述
如下
在这里插入图片描述

除了page,还有include、taglib 自行了解
在这里插入图片描述

JSP脚本代码格式:<% 代码片段 %>:实现代码逻辑

在这里插入图片描述
在这里插入图片描述

还可以用循环打印多个HTML标签,就是语法有点奇葩
在这里插入图片描述
在这里插入图片描述

JSP注释格式:<%--  注释的东西 --%>

在这里插入图片描述

JSP表达式:<%= 代码 %>;

一个JSP表达式中包含的脚本语言表达式,先被转化成String,然后插入到表达式出现的地方。由于表达式的值会被转化成String,所以您可以在一个文本行中使用表达式而不用去管它是否是HTML标签。表达式元素中可以包含任何符合Java语言规范的表达式,但是不能使用分号来结束表达式。也就是说JSP表达式的内容直接显示在浏览器页面上,可以省略out。
在这里插入图片描述

在这里插入图片描述

JSP声明格式:<%! declaration; [ declaration; ]+ ... %>

一个声明语句可以声明一个或多个变量、方法,供后面的Java代码使用。在JSP文件中,您必须先声明这些变量和方法然后才能使用它们。
相当于声明了全局变量
在这里插入图片描述

查看JSP源码,发现声明的变量直接作为类的属性而不是在代码块中
在这里插入图片描述
在这里插入图片描述

JSP行为<jsp:action_name attribute="value" />

JSP行为标签使用XML语法结构来控制servlet引擎。它能够动态插入一个文件,重用JavaBean组件,引导用户去另一个页面,为Java插件产生相关的HTML等等。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

EL表达式

EL(Expression Language) 是为了使JSP写起来更加简单。表达式语言的灵感来自于 ECMAScript 和 XPath 表达式语言,它提供了在 JSP 中简化表达式的方法,让JSP的代码更加简化。

如下比较JSP表达式取值和EL表达式取值添加链接描述
在这里插入图片描述
可以看到EL表达式取值更方便些,此外当取的对象不存在时,普通取值会返回null,而EL表达式什么都不输出,展现效果更好
在这里插入图片描述
EL表达式没什么好讲的,自行了解JSP 表达式语言

JSTL

JSTL(JSP Standard Tag Library,核心标签库)是 JSP 标签的集合,它封装了 JSP 应用的通用核心功能。和EL表达式用于简化取值功能类似,JSTL也是为了简化其他JSP语法的使用。
JSP 标签是一组与 HTML 标签相似,但又比 HTML 标签强大的功能标签。JSTL 用来简化 JSP 开发,可以使我们不用嵌入 Java 代码就能够开发出复杂的 JSP 页面。
JSTL 包含 5 类标签库:core 标签库、fmt 标签库、fn 标签库、XML 标签库和 SQL 标签库。这 5 类标签库基本覆盖了 Web 开发中的所涉及的技术展示。

JSP 标准标签库(JSTL)

Filter和Listener

Filter(过滤器)实际上就是对web资源进行拦截,做一些处理后再交给下一个过滤器或servlet处理通常都是用来拦截request进行处理的,也可以对返回的response进行拦截处理。常见应用场景比如权限检查、日记操作、事务管理等…
在这里插入图片描述

例如Web常会遇到中文乱码的问题,我们可以在Servlet程序中添加req(resp).setCharacterEncoding(“utf-8”),但资源多之后这种方法无疑是很麻烦的,我们可以利用过滤器先将请求处理好字符编码再发送给Servlet或者处理好响应的字符编码再发回浏览器。
过滤器和后面的监听器使用大致流程和Servlet差不多——实现接口,在配置文件中作好映射

public class CharacterFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {//init会随着服务器启动而初始化
        System.out.println("Filter initialize successful");
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        request.setCharacterEncoding("utf-8");
        response.setCharacterEncoding("utf-8");
        System.out.println("character encoding successful");
        chain.doFilter(request, response);//doFilter必须要写,因为此过滤器处理完后要将工作传递给下一个过滤器或者Servlet
        								
    }

    @Override
    public void destroy() {//过滤器会随服务器关闭而销毁
        System.out.println("Filter destroy successful");

    }
}
	<filter>
        <filter-name>characterFilter</filter-name>
        <filter-class>com.jojo.filter.CharacterFilter</filter-class>
    </filter>
    
    <filter-mapping>
    	<!-- 要对哪些Servlet程序进行过滤 -->
        <filter-name>characterFilter</filter-name>
        <servlet-name>myServlet1</servlet-name>
        <servlet-name>myServlet2</servlet-name>
        <servlet-name>cookieServlet</servlet-name>
    </filter-mapping>

在这里插入图片描述
在这里插入图片描述

过滤器这方面还需要注意的就是配置拦截的路径问题
Filter过滤器的拦截路径配置
关于Spring-MVC中的过滤器请求路径/和/*的区别

过滤器链

如果有多个过滤器,那么过滤流程是怎么样的呢
在这里插入图片描述
举个简单的例子就理解了 想象我们经过三个检查口(1-2-3)办事,出来时的顺序应该为(3-2-1)
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
至于哪个检查口优先,那就看配置文件中过滤器的依次顺序了
在这里插入图片描述

Listener(监听器)就是用来监听各种事件的,比如我们点击程序右上角的关闭按钮,就是一个事件,系统根据事件关闭程序相关进程,点击鼠标也是一个事件等等,还有有些网站会记录访问量也可以用监听器来实现。监听器主要在图像化界面应用比较多,而且可以实现的接口繁多(因为什么操作都可以算作一个事件),所以了解就行。
javaweb之listener详解

MVC

将来我们的web项目会越来越庞大,大多情况下还需要连接数据库,添加日志、监控等功能,以我们当前的形式设计很难支撑一个正常web项目。
目前web项目的开发一般是使用MVC框架来开发,后续我们主要学习MVC框架为(Spring + SpringMVC + Mybatis)。
什么是MVC

项目推荐

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值