JavaWeb

基础概念

web开发:

  • web:页面的意思,例如:www.baidu.com

  • 静态web:

    • html,css
    • 提供给所有人看的数据始终不会发生变化的
  • 动态web:

    • 淘宝,以及几乎所有的网站
    • 提供给所有人看的数据始终会发生变化,每个人在不同的时间,不同的地点看到的信息各不相同
    • 技术栈:Servlet/JSP,ASP,PHP

在Java中,动态web资源开发的技术统称为JavaWeb

web应用程序

web应用程序:可以提供浏览器访问的程序;

  • a.html、b.html 等多个web资源,这些web资源可以被外届访问,对外界提供服务;

  • 你们很访问到的任何一个页面或者资源,都存在于这个世界的某一个角落的计算机上。

  • URL:统一资源定位标志,就是指网络地址。

  • 这个统一的web资源会被放在同一个文件夹下,web应用程序 -->Tomcat:服务器

  • 一个web应用由多部分组成(静态web,动态web)

    • html,css,js
    • jsp,servlet
    • Java程序
    • jar包
    • 配置文件(Properties)

web应用程序编写完毕后,若想提供给外届访问:需要一个服务器来统一管理;

静态web

*.htm、*.html、这些都是网页的后缀,
如果服务器上一直存在这些东西,我们就可以直接进行读取。
通络;

在这里插入图片描述
静态web存在的缺点:

  • web页面无法动态更新,所有用户看到都是同一个页面

    • 轮播图、点击特效:伪动态
    • JavaScript [实际开发中,它用的最多]
    • VBScript
  • 它无法和数据库交互(数据无法持久化,用户无法交互)

动态web

页面会动态展示:“web的页面展示的效果因人而异”;
在这里插入图片描述
缺点:

  • 加入服务器的动态web资源出现了错误,我们需要重新编写我们的后台程序,重新发布;

    • 停机维护

优点:

  • web页面可以动态更新,所有用户看到都不是同一个页面
  • 它可以与数据库交互(数据持久化:注册,商品信息,用户信息…)
    在这里插入图片描述

Tomcat启动和配置

文件夹作用:

  • bin:启动、关闭的脚本文件
  • conf:配置文件
  • lib:依赖的jar包
  • logs:日志文件
  • webapps:存放网站的

可以配置启动的端口号

  • tomcat的默认端口号为:8080
  • mysql:3306
  • http:80
  • https:443
<Connector port="8080" redirectPort="8443"
 connectionTimeout="20000" protocol="HTTP/1.1"/>

可以配置主机名称

  • 默认的主机名为:localhost -> 127.0.0.1
  • 默认网站应用存放的位置为:webapps
<Host name="localhost" autoDeploy="true"
 unpackWARs="true" appBase="webapps">

请你谈谈网站是如何进行访问的

  • 1、输入一个域名;回车

  • 2、检查本机的 C:\Windows\System32\drivers\etc\hosts配置文件下有没有这个域名映射;

    • 有:直接返回对应的ip地址,这个地址中,有我们需要访问的web程序,可以直接访问
    • 没有:去DNS服务器找,找到的话就返回,找不到就返回找不到

在这里插入图片描述

发布一个web网站

不会就先模仿:将自己写的网站,放到服务器(Tomcat)中指定的web应用的文件夹(webapps)下,就可以访问了

网站应该有的结构:

  • webapps:Tomcat服务器的web目录

    • ROOT

    • zyaStudy:网站的目录名

      • WEB-INF

        • classes:Java程序
        • lib:web应用所依赖的jar包
        • web.xml:网站配置文件
      • index.html 默认的首页

      • static

        • css

          • style.css
        • js

        • img


HTTP

http:

超文本传输协议(Hyper Text Transfer Protocol,HTTP)是一个简单的请求-响应协议,它通常运行在TCP之上。它指定了客户端可能发送给服务器什么样的消息以及得到什么样的响应。请求和响应消息的头以ASCII形式给出;而消息内容则具有一个类似MIME的格式。这个简单模型是早期Web成功的有功之臣,因为它使开发和部署非常地直截了当。

  • 文本:html、字符串、…
  • 超文本:图片、音乐、视频、定位、地图、…
  • 端口号:80

https:

  • Hyper Text Transfer Protocol over SecureSocket Layer,是以安全为目标的 HTTP 通道
  • 端口号:443

两个时代:

http1.0 :

  • HTTP/1.0:客户端可以与web服务器连接后,只能获得一个web资源,断开连接

http2.0

  • HTTP/1.1:客户端可以与web服务器连接后,可以获得多个web资源

Http请求:

客户端 — 发请求(Request)— 服务端

百度:

Request URL: https://www.baidu.com/		请求地址
Request Method: GET					get方法/post方法
Status Code: 200 OK						状态码:200
Remote Address: 36.152.44.95:443		远程地址
引用站点策略: strict-origin-when-cross-origin

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
Cache-Control: max-age=0
Connection: keep-alive

1、请求行

  • 请求行中的请求方式:GET

  • 请求方式:Get、Post、HEAD、DELETE、PUT、TRACT、…

    • get:请求能够携带的参数较少,大小有限制,会在浏览器的URL地址栏显示数据内容,不安全,但高效。
    • post:请求能够携带的参数没有限制,大小没有限制,不会在浏览器的URL地址栏显示数据内容,安全,但不高效。

2、消息头

Accept: 告诉浏览器,它所支持的数据类型
Accept-Encoding: 支持哪种编码格式  GBK、UTF-8、GB2312、ISO8859-1
Accept-Language: 告诉浏览器,它的语言环境 
Cache-Control: 缓存控制
Connection: 告诉浏览器,请求完成是断开还是保持连接
HOST: 主机

Http响应

服务端 — 响应(Respones)— 客户端

百度:

Bdpagetype: 2
Bdqid: 0xa2d77d3d0000d469
Cache-Control: private		// 缓存控制
Connection: keep-alive		// 连接:保持活着
Content-Encoding: gzip		// 编码
Content-Type: text/html;charset=utf-8		// 类型
Date: Wed, 18 Aug 2021 13:33:25 GMT
Expires: Wed, 18 Aug 2021 13:33:24 GMT
Server: BWS/1.1
Set-Cookie: BDSVRTM=320; path=/
Set-Cookie: BD_HOME=1; path=/
Set-Cookie: H_PS_PSSID=34436_34370_34376_33848_34449_34092_34111_26350_34426_34289; path=/; domain=.baidu.com
Strict-Transport-Security: max-age=172800
Traceid: 1629293605019960986611733985055083648105
Transfer-Encoding: chunked
X-Frame-Options: sameorigin
X-Ua-Compatible: IE=Edge,chrome=1

响应体

Accept: 告诉浏览器,它所支持的数据类型
Accept-Encoding: 支持哪种编码格式  GBK、UTF-8、GB2312、ISO8859-1
Accept-Language: 告诉浏览器,它的语言环境 
Cache-Control: 缓存控制
Connection: 告诉浏览器,请求完成是断开还是保持连接
HOST: 主机
Refrush: 告诉客户端,多久刷新一次
Location: 让网页重新定位

响应状态码

200:请求响应成功 200
3xx:请求重定向

  • 重定向:你重新到我给你新位置去

4xx:找不到资源 404

  • 资源不存在;

5xx:服务器代码错误

  • 500
  • 502:网关错误

常用面试题:当你的浏览器中地址栏输入地址并回车的一瞬间到页面能够展示回来,经历了什么?

第一种https://blog.csdn.net/qq_44912064/article/details/114846888

  1. 域名解析
  2. 发起TCP的三次握手
  3. 建立起TCP连接后发起http请求
  4. 服务器响应http请求,浏览器得到html代码
  5. 浏览器解析html代码,并请求html代码中的资源(css JavaScript 图片)
  6. 浏览器对页面进行渲染呈现

第二种
https://zhuanlan.zhihu.com/p/95904514

  1. 用户在浏览器输入 URL
  2. 浏览器尝试读取 URL 的缓存
  3. 无缓存则开始查 URL 域名的 ip,也就是 DNS 查找
  4. 开始建立 TCP 链接,经过三次握手成功建立连接
  5. 客户端开始发送数据
  6. 服务端将用户所需的资源返回给客户端
  7. 若返回的是 HTML 文档的话,浏览器开始解析 HTML 文档
  8. 构建 DOM 树、构建 CSSOM 树
  9. 将解析步骤中创建的 CSSOM 树和 DOM 树合成为 Render 树,然后用于计算每个可见元素的布局,最后将其绘制到屏幕上

Maven

1、在JavaWeb开发中,需要使用大量的jar包,我们手动去导入;

2、Maven能够自动帮我们导入和配置这个jar包

Maven的核心思想:约定大于配置

  • 有约束,不要去违反。

Maven会规定好你该如何去编写我们的Java代码,必须要按照这个规范来;

配置环境变量

  • M2_HOME: maven目录下的bin目录
  • MAVEN_HOME:maven的目录
  • 在系统的path中配置:%MAVEN_HOME%\bin

在这里插入图片描述
在终端输入:mvn -version
得到这个结果:说明环境配置成功

阿里云镜像:

  • 镜像:mirrors

    • 作用:加速我们的下载
  • 国内建议使用阿里云的镜像

本地仓库

在本地的仓库,远程仓库:

建立一个仓库:


Servlet

Servlet就是sun公司开发动态web的一门技术

Sun在这些API中提供一个接口叫做:Servlet,如果你想开发一个Servlet程序,只需要完成两个小步骤:

  • 编写一个类,实现Servlet接口
  • 把开发好的Java类部署到web服务器

把实现了Servlet接口的Java程序叫做,Servlet

HelloServlet

Servlet接口Sun公司有两个默认的实现类:HttpServlet、

1、构建一个普通的Maven项目,删掉里面的src目录,以后我们的学习就在这个项目里面建立Module;这个空的工程就是Maven主工程。

2、关于Maven父子工程的理解:

  • 父项目中会有:

    <modules>
       <module>servlet-01</module>
    </modules>
    
  • 子项目会有:

    <parent>
        <artifactId>javaweb-02-servlet</artifactId>
        <groupId>org.example</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    
  • 父项目中的Java子项目可以直接使用:

    son extends father
    

3、Maven环境优化:

  1. 修改web.xml为最新的
  2. 将maven的结构搭建完整

4、编写一个Servlet程序:

  1. 编写一个普通类
  2. 实现Servlet接口,这里我们直接继承HttpServlet
package com.zhang.servlet;

import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

public class HelloServlet extends HttpServlet {
    // 由于get或者post只是请求实现的不同的方式,可以互相调用,业务逻辑都一样
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //        ServletOutputStream outputStream = resp.getOutputStream();
        PrintWriter writer = resp.getWriter();  // 响应流
        //        super.doGet(req, resp);
        writer.print("hello servlet");
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.doPost(req, resp);
    }
}

5、编写Servlet的映射:

为什么需要映射:我们写的是Java程序,但是要通过浏览器访问,而浏览器需要连接web服务器,所以我们需要再web服务器中注册我们写的Servelt,还需要给他一个浏览器能够访问的路径;

<servlet>
       <servlet-name>hello</servlet-name>
       <servlet-class>com.zhang.servlet.HelloServlet</servlet-class>
</servlet>

<servlet-mapping>
       <servlet-name>hello</servlet-name>
       <url-pattern>/hello</url-pattern>
</servlet-mapping>

6、配置Tomcat

在这里插入图片描述


Servlet原理

Servlet是由Web服务器调用,web服务器在收到浏览器请求之后,会

在这里插入图片描述

Mapping:请求映射的路径

1、一个Servlet可以指定一个映射路径:

<servlet-mapping>
        <servlet-name>hello</servlet-name>
        <url-pattern>/hello</url-pattern>
</servlet-mapping>

2、一个Servlet可以指定多个映射路径:

<servlet-mapping>
        <servlet-name>hello</servlet-name>
        <url-pattern>/hello</url-pattern>
</servlet-mapping>
<servlet-mapping>
        <servlet-name>hello</servlet-name>
        <url-pattern>/hello1</url-pattern>
</servlet-mapping>
<servlet-mapping>
        <servlet-name>hello</servlet-name>
        <url-pattern>/hello2</url-pattern>
</servlet-mapping>
<servlet-mapping>
        <servlet-name>hello</servlet-name>
        <url-pattern>/hello3</url-pattern>
</servlet-mapping>
<servlet-mapping>
        <servlet-name>hello</servlet-name>
        <url-pattern>/hello4</url-pattern>
</servlet-mapping>

3、一个Servlet可以指定通用映射路径:

<servlet-mapping>
        <servlet-name>hello</servlet-name>
        <url-pattern>/hello/*</url-pattern>
</servlet-mapping>

4、默认请求路径:

<servlet-mapping>
        <servlet-name>hello</servlet-name>
        <url-pattern>/*</url-pattern>
</servlet-mapping>

5、指定一些后缀或者前缀等等…(可以自定义后缀实现请求路径,注意点:*前面不能加项目映射的路径)

<servlet-mapping>
        <servlet-name>hello</servlet-name>
        <url-pattern>*.zhangyiang</url-pattern>
</servlet-mapping>

6、以下是一些错误情况

<servlet-mapping>
        <servlet-name>hello</servlet-name>
        <url-pattern>/*.zhangyiang</url-pattern>
</servlet-mapping>
// * 前面不能加项目映射的路径
<servlet-mapping>
        <servlet-name>hello</servlet-name>
        <url-pattern>/hello/*.zhangyiang</url-pattern>
</servlet-mapping>

7、优先级问题:

  • 指定了固有的映射路径优先级最高,如果找不到就会走默认的处理请求;
<!--注册Servlet-->
<servlet>
        <servlet-name>error</servlet-name>
        <servlet-class>com.zhang.servlet.ErrorServlet</servlet-class>
</servlet>
<!--Servlet的请求路径-->
<!--localhost:8080/s1/hello-->
<servlet-mapping>
        <servlet-name>error</servlet-name>
        <url-pattern>/*</url-pattern>
</servlet-mapping>

ServletContext

web容器在启动的时候,它会为每个web程序都创建一个对应的ServletContext对象,它代表了当前的web应用;

  • 共享数据

    我在这个Servlet中保存的数据,可以在另外一个Servlet中拿到;(也可以通过 IO流 的形式进行数据传输,但比较麻烦)

    • 是一个域对象(服务器在内存上创建的存储空间,用于在不同动态资源 servlet 之间传递与共享数据)
    • 可以读取全局配置参数
    • 可以搜索当前工程目录下面的资源文件
    • 可以获取当前工程名字
package com.zhang.servlet;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class HelloServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("Hello");
        // this.getInitParameter();     // 初始化参数
        // this.getServletConfig();     // Servlet配置
        // this.getServletContext();    // Servlet上下文(联系上下文)

        ServletContext servletContext = this.getServletContext();
        String username = "杯子";
        servletContext.setAttribute("username", username);  // 将一个数据保存在ServletContext中,名字为 username,值为 username

    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.doPost(req, resp);
    }
}

package com.zhang.servlet;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class GetServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 将HelloServlet类中的数据,读取到本类中
        ServletContext context = this.getServletContext();
        // 程序把它设定为Object类型,然后我们可以强转为 String类型
        String username = (String) context.getAttribute("username");
        // 设置内容类型
        resp.setContentType("text/html");
        // 设置编码格式
        resp.setCharacterEncoding("utf-8");
        // 在相关页面上打印数据
        resp.getWriter().print("名字: " + username);
    }

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

<!--注册Servlet-->
<servlet>
    <servlet-name>getc</servlet-name>
    <servlet-class>com.zhang.servlet.GetServlet</servlet-class>
</servlet>
<!--映射Servlet-->
<servlet-mapping>
    <servlet-name>getc</servlet-name>
    <url-pattern>/getc</url-pattern>
</servlet-mapping>

获取初始化参数

<!--配置一些web应用初始化参数-->
<context-param>
   <param-name>url</param-name>
   <param-value>jdbc:mysql://localhost:3306/mybatis</param-value>
</context-param>
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    ServletContext context = this.getServletContext();
    String url = context.getInitParameter("url");
    resp.getWriter().print(url);
}

请求转发(RequestDispatcher)

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
   ServletContext context = this.getServletContext();
//        RequestDispatcher requestDispatcher = context.getRequestDispatcher("/gp");  // 转发的请求路径
//        requestDispatcher.forward(req, resp);   // 调用forward实现请求转发:
   context.getRequestDispatcher("/gp").forward(req, resp);
}

请求转发原理:路径不会发生改变
在这里插入图片描述
重定向原理:路径会发生改变
在这里插入图片描述


读取资源文件

<!--在build中配置resources,来防止我们资源导出失败的问题-->
<build>
    <resources>
        <resource>
            <directory>src/main/resources</directory>
            <includes>
                <include>**/*.properties</include>
                <include>**/*.xml</include>
            </includes>
            <filtering>true</filtering>
        </resource>
        <resource>
            <directory>src/main/java</directory>
            <includes>
                <include>**/*.properties</include>
                <include>**/*.xml</include>
            </includes>
            <filtering>true</filtering>
        </resource>
    </resources>
</build>

Properties类:

  • 在Java目录下新建properties
  • 在resources目录下新建properties

发现:都被打包到了同一个路径下:classes,我们俗称这个路径为classpath;

思路:需要一个文件流

package com.zhang.servlet;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class ServletDemo04 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        InputStream is = this.getServletContext().getResourceAsStream("/WEB-INF/classes/com/zhang/servlet/aa.properties");
        Properties properties = new Properties();
        properties.load(is);
        String user = properties.getProperty("username");
        String pwd = properties.getProperty("password");
        resp.getWriter().print(user + ":" + pwd);
    }

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


HttpServletResponse

web服务器接收到客户端的http请求,针对这个请求,分别创建一个代表请求的 HttpServletRequest对象,代表响应的 HttpServletResponse;

  • 如果要获取客户端请求过来的参数:找 HttpServletRequest
  • 如果要给客户端响应一些信息:找 HttpServletResponse

1、简单分类:

负责向浏览器发送数据的方法:

public ServletOutputStream getOutputStream() throws IOException;

public PrintWriter getWriter() throws IOException;

负责向浏览器发送响应头的方法:

public void setCharacterEncoding(String charset);

public void setContentLength(int len);

public void setContentLengthLong(long len);

public void setContentType(String type);
public void setDateHeader(String name, long date);

public void addDateHeader(String name, long date);

public void setHeader(String name, String value);

public void addHeader(String name, String value);

public void setIntHeader(String name, int value);

public void addIntHeader(String name, int value);

响应的状态码:

public static final int SC_CONTINUE = 100;

public static final int SC_SWITCHING_PROTOCOLS = 101;

public static final int SC_OK = 200;

public static final int SC_CREATED = 201;

public static final int SC_ACCEPTED = 202;

public static final int SC_NON_AUTHORITATIVE_INFORMATION = 203;

public static final int SC_NO_CONTENT = 204;

public static final int SC_RESET_CONTENT = 205;

public static final int SC_PARTIAL_CONTENT = 206;

public static final int SC_MULTIPLE_CHOICES = 300;

public static final int SC_MOVED_PERMANENTLY = 301;

public static final int SC_MOVED_TEMPORARILY = 302;

public static final int SC_FOUND = 302;

public static final int SC_SEE_OTHER = 303;

public static final int SC_NOT_MODIFIED = 304;

public static final int SC_USE_PROXY = 305;

public static final int SC_TEMPORARY_REDIRECT = 307;

public static final int SC_BAD_REQUEST = 400;

public static final int SC_UNAUTHORIZED = 401;

public static final int SC_PAYMENT_REQUIRED = 402;

public static final int SC_FORBIDDEN = 403;

public static final int SC_NOT_FOUND = 404;

public static final int SC_METHOD_NOT_ALLOWED = 405;

public static final int SC_NOT_ACCEPTABLE = 406;

public static final int SC_PROXY_AUTHENTICATION_REQUIRED = 407;

public static final int SC_REQUEST_TIMEOUT = 408;

public static final int SC_CONFLICT = 409;

public static final int SC_GONE = 410;

public static final int SC_LENGTH_REQUIRED = 411;

public static final int SC_PRECONDITION_FAILED = 412;

public static final int SC_REQUEST_ENTITY_TOO_LARGE = 413;

public static final int SC_REQUEST_URI_TOO_LONG = 414;

public static final int SC_UNSUPPORTED_MEDIA_TYPE = 415;

public static final int SC_REQUESTED_RANGE_NOT_SATISFIABLE = 416;

public static final int SC_EXPECTATION_FAILED = 417;

public static final int SC_INTERNAL_SERVER_ERROR = 500;

public static final int SC_NOT_IMPLEMENTED = 501;

public static final int SC_BAD_GATEWAY = 502;

public static final int SC_SERVICE_UNAVAILABLE = 503;

public static final int SC_GATEWAY_TIMEOUT = 504;

public static final int SC_HTTP_VERSION_NOT_SUPPORTED = 505;

2、常见应用:

  1. 向浏览器输出消息

  2. 下载文件

    1. 要获取下载文件的路径
    2. 下载的文件名是啥?
    3. 设置想办法让浏览器能够支持下载我们需要的东西
    4. 获取下载文件的输入流
    5. 创建缓冲流
    6. 获取 OutputStream对象
    7. 将 FileOutputStream流写入到 buffer缓冲区
    8. 使用 OutputStream将缓冲区中的数据输出到客户端
package com.zhang.servlet;

import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.FileInputStream;
import java.io.IOException;

public class FileServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("1111");
        //        // 1、获取下载文件的路径
//        String realPath = this.getServletContext().getRealPath("/jt.png");
        String realPath = "E:\\idea project\\com.zya\\response1\\src\\main\\resources\\jt.png";
        System.out.println("下载文件的路径: " + realPath);
        // 2、下载的文件名是啥
        String fileName = realPath.substring(realPath.lastIndexOf("\\")+1);
        // 3、设置想办法让浏览器能够支持下载我们需要的东西
        resp.setHeader("Content-Disposition", "attachment;filename="+fileName);
        // 4、获取下载文件的输入流
        FileInputStream in = new FileInputStream(realPath);
        // 5、创建缓冲区
        int len = 0;
        byte[] bytes = new byte[1024];
        // 6、获取OutputStream对象
        ServletOutputStream out = resp.getOutputStream();
        // 7、将FileOutputStream流写入到buffer缓冲区,使用OuputStream将缓冲区中的数据输出到客户端
        while ((len = in.read(bytes))!=-1){
            out.write(bytes, 0, len);
        }
        // 8、关闭数据流
        out.close();
        in.close();
    }

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

验证码功能:

前端实现:用JavaScript

后端实现:可以用到 Java 的图片类,生成一个图片

package com.zhang.servlet;

import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Random;

public class ImageServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 如何让浏览器3秒自动刷新一次
        resp.setHeader("refresh", "3");

        // 在内存中创建一个图片
        BufferedImage bufferedImage = new BufferedImage(80, 20, BufferedImage.TYPE_INT_RGB);
        // 得到图片
        Graphics2D g = (Graphics2D) bufferedImage.getGraphics();   //笔
        // 设置图片的背景颜色
        g.setColor(Color.WHITE);
        g.fillRect(0,0,80,20);
        // 给图片写数据
        g.setColor(Color.BLUE);
        g.setFont(new Font(null, Font.BOLD,20));
        g.drawString(makeNum(), 0 ,20);

        // 告诉浏览器,这个请求用图片的方式打开
        resp.setContentType("image/png");
        // 网站存在缓存,不让浏览器缓存
        resp.setDateHeader("expires",-1);
        resp.setHeader("Cache-Control", "no-cache");
        resp.setHeader("Pragma", "no-cache");

        // 把图片写给浏览器
        boolean write = ImageIO.write(bufferedImage, "png",resp.getOutputStream());
    }

    // 生成随机数
    public String makeNum(){
        Random random = new Random();
        String num = random.nextInt(9999) + "";
        StringBuffer sb = new StringBuffer();
        for (int i = 0;i < 4 - num.length();i++){
            sb.append("0");
        }
        String s = sb.toString() + num;
        return num;
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.doPost(req, resp);
    }
}

实现重定向

在这里插入图片描述

B 一个 web资源收到客户端A请求后,B 他会通过 A 客户端去访问另一个web资源C,这个过程叫重定向

常用场景:

  • 用户登录
    void sendRedirect(String var1) throws IOException;
    
package com.zhang.servlet;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class RedirectServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        /*
        	原理:
            resp.setHeader("Location", "/img");
            resp.setStatus(302);
         */
        resp.sendRedirect("/ImageServlet"); // 重定向
    }

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

面试题:请你聊聊重定向和转发的区别?

相同点:

  • 页面都会实现跳转

不同点:

  • 请求转发的时候,url不会发生变化<---- 307
  • 重定向时候,url地址栏会发生变化 <---- 302

如果出现中文乱码,就加上这句编码转换:
<%@ page contentType=“text/html; charset=UTF-8” %>

<html>
<body>
<h2>Hello World!</h2>

<%--这里提交的路径,需要寻找项目的路径--%>
<%--${pageContext.request.contextPath}代表当前的项目--%>
<%@ page contentType="text/html; charset=UTF-8" %>
<form action="${pageContext.request.contextPath}/login" method="get">
    用户名: <input type="text" name="username"><br>
    密码: <input type="password" name="password"><br>
    <input type="submit">
</form>

</body>
</html>

package com.zhang.servlet;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class RequestTest extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 处理请求
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        System.out.println(username + ":" + password);

        // 重定向时候一定要注意路径问题,否则404
        resp.sendRedirect("/success.jsp");
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.doPost(req, resp);
    }
}

HttpServletRequest

HttpServletRequest代表客户端的请求,用户通过Http协议访问服务器,HTTP请求中的所有信息会被封装到 HttpServletRequest,通过这个 HttpServletRequest的方法,获得客户端的所有信息

1、获取前端传递的参数,请求转发:

  • req.getParameter(String s)
  • req.getParameterMap()
  • req.getParameterNames()
  • req.getParameterValues(String s)
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    req.setCharacterEncoding("utf-8");
    resp.setCharacterEncoding("utf-8");

	String username = req.getParameter("username");
    String password = req.getParameter("password");

	String[] hobbys = req.getParameterValues("hobbys");

	System.out.println("=============================");
	System.out.println(username);
	System.out.println(password);
	System.out.println(Arrays.toString(hobbys));
	System.out.println("=============================");

	System.out.println(req.getContextPath());
	// 通过请求转发
	// 这里的 / 代表当前的web应用
	req.getRequestDispatcher("/success.jsp").forward(req,resp);
}

7、Cookie和session

7.1、会话

会话:用户打开一个浏览器,点击了很多超链接,访问多个web资源,关闭浏览器,这个过程可以称之为会话。

有状态会话:一个同学来过教室,下次再来教室,我们会知道这个同学,曾经来过,称之为有状态会话;

你能怎么征明你是学校的学生(Java中的万物皆对象:你和学校)

  • 发票 ----- 学校给你发票
  • 学校登记 ----- 学校标记你来过了

一个网站,怎么征明你来过?

  • 客户端 <-----> 服务端
  • 服务端给客户端一个信件,客户端下次访问服务端带上信件就可以了; cookie
  • 服务器登记你来过了,下次你来的时候我来匹配你;session

7.2、保存会话的两种技术

cookie

  • 客户端技术(响应,请求)

session

  • 服务器技术,利用这个技术,可以保存用户的会话信息,我们可以把信息或者数据放在session中

7.3、Cookie

1、从请求中拿到cookie信息

2、服务器响应给客户端cookie

Cookie[] cookies = req.getCookies();	// 获得Cookie
cookie.getName();	// 获得cookie中的key
cookie.getValue();	// 获得cookie中的value
new Cookie("lastLoginTime", System.currentTimeMillis()+"");	// 新建一个cookie
cookie.setMaxAge(24*60*60);	// 设置cookie的有效期
resp.addCookie(cookie);	// 响应给客户端一个cookie
package com.zhang.servlet;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Date;

// 保存用户上一次访问的时间
public class CookieDemo01 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 服务器,告诉你,你来的时间,把这个时间封装成一个信件,你下带来,我就知道你来了

        // 解决中文乱码
        req.setCharacterEncoding("utf-16");
        resp.setCharacterEncoding("utf-16");

        PrintWriter out = resp.getWriter();

        // Cookie,服务器端从客户端获取
        Cookie[] cookies = req.getCookies(); // 这里返回数组,说明Cookie可能存在多个

        // 判断Cookie是否存在
        if (cookies!=null){
            // 如果存在怎么办
            out.write("你上一次访问的时间是:");
            for (Cookie cookie:cookies) {
                System.out.println(cookie);
            }

            for (int i = 0; i < cookies.length; i++) {
                Cookie cookie = cookies[i];
                // 获取cookie的名字
                if (cookie.getName().equals("lastLoginTime")){
                    // 获取cookie中的值
                    long lastLoginTime = Long.parseLong(cookie.getValue());
                    Date date = new Date(lastLoginTime);
                    out.write(date.toLocaleString());
                }
            }
        }else {
            out.write("这是你第一次访问本站");
        }

        // 服务器给客户端响应一个Cookie

        Cookie cookie = new Cookie("lastLoginTime", System.currentTimeMillis()+"");
        // cookie有效期为1天
        cookie.setMaxAge(24*60*60);
        resp.addCookie(cookie);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.doPost(req, resp);
    }
}

cookie:一般会保存在本地的 用户目录下 AppData

一个网站cookie是否存在上限?

  • 一个Cookie只能保存一个信息
  • 一个web站点可以给浏览器发送多个cookie,最多存放20个cookie
  • Cookie大小有限制 4KB
  • 300个浏览器上限

删除Cookie

  • 不设置有效期,关闭浏览器,自动失效
  • 设置有效期时间为0
package com.zhang.servlet;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Date;

// 保存用户上一次访问的时间
public class CookieDemo01 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 创建一个cookie,名字必须要和删除的名字一样
        Cookie cookie = new Cookie("lastLoginTime", System.currentTimeMillis()+"");

		// 将cookie有效期设置为0,立马过期
		cookie.setMaxAge(0);

		resp.addCookie(cookie);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.doPost(req, resp);
    }
}

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


7.4 Session(重点)

什么是Session:

  • 服务器会给每一个用户(浏览器)创建一个Session对象
  • 一个Session独占一个浏览器,只要浏览器没有关闭,这个Session就存在
  • 用户登录之后,整个网站它都可以访问(保存用户信息,保存购物车的信息…)
public interface HttpSession {
    long getCreationTime();

    String getId();

    long getLastAccessedTime();

    ServletContext getServletContext();

    void setMaxInactiveInterval(int var1);

    int getMaxInactiveInterval();

    /** @deprecated */
    @Deprecated
    HttpSessionContext getSessionContext();

    Object getAttribute(String var1);

    /** @deprecated */
    @Deprecated
    Object getValue(String var1);

    Enumeration<String> getAttributeNames();

    /** @deprecated */
    @Deprecated
    String[] getValueNames();

    void setAttribute(String var1, Object var2);

    /** @deprecated */
    @Deprecated
    void putValue(String var1, Object var2);

    void removeAttribute(String var1);

    /** @deprecated */
    @Deprecated
    void removeValue(String var1);

    void invalidate();

    boolean isNew();
}

Session和Cookie的区别:

  • Cookie是把用户的数据写给用户的浏览器,浏览器保存(可以保存多个)
  • Session把用户的数据写到用户独占Session中,服务器端保存(保存重要的信息,减少服务器资源的浪费)
  • Session对象由服务器创建

使用场景:

  • 保存一个登录用户的信息
  • 购物车信息
  • 在整个网站中,经常会使用的数据,我们将它保存在Session中

使用Session:

package com.blb.servlet.util;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;
import java.io.IOException;

@WebServlet("/s1")

public class SessionDemo01 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        // 解决乱码问题
        req.setCharacterEncoding("utf-16");
        resp.setCharacterEncoding("utf-16");
        resp.setContentType("text/html;charset=utf-8");

        // 得到Session
        HttpSession session = req.getSession();

        // 给Session中存东西
        session.setAttribute("name",new Person("张义昂", 1));

        // 获取Session的ID
        String id = session.getId();

        // 判断Session是不是新创建的
        if (session.isNew()){
            resp.getWriter().write("session创建成功, ID为"+id);
        }else {
            resp.getWriter().write("session已经在服务器中存在了, ID为"+id);
        }

        // session创建的时候做了什么事情
//        Cookie cookie = new Cookie("JSESSIONID", id);
//        resp.addCookie(cookie);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.doGet(req, resp);
    }
}

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

package com.blb.servlet.util;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;

@WebServlet("/s2")

public class SessionDemo02 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        // 解决乱码问题
        req.setCharacterEncoding("utf-16");
        resp.setCharacterEncoding("utf-16");
        resp.setContentType("text/html;charset=utf-8");

        // 得到Session
        HttpSession session = req.getSession();

        Person name = (Person) session.getAttribute("name");
        System.out.println(name.toString());
    }

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

手动注销Session

package com.blb.servlet.util;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;

@WebServlet("/s3")

public class SessionDemo03 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        HttpSession session = req.getSession();
        session.removeAttribute("name");
        // 手动注销session
        session.invalidate();
    }

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

会话自动过期:web.xml配置

<?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">
    
    <welcome-file-list>
        <welcome-file>work01</welcome-file>
    </welcome-file-list>

    <!-- 设置Session默认的失效时间   -->
    <session-config>
        <!--  15分钟后session失效了,以分钟为单位   -->
        <session-timeout>15</session-timeout>
    </session-config>
</web-app>

请添加图片描述


8、JSP

8.1、什么是JSP

Java Server Pages:Java服务器端页面,也和Servlet一样,用于动态Web技术

最大的特点:

  • 写JSP就像在写HTML
  • 区别:
    • HTML只给用户提供静态的数据
    • JSP页面中可以嵌入Java代码,为用户提供动态数据

8.2、JSP原理

思路:JSP怎么执行的?

  • 代码层面没有任何问题
  • 服务器内部工作
    • tomcat中有一个work目录
    • IDEA中使用Tomcat的会在IDEA的tomcat中生产一个work目录
  • 浏览器向服务器发送请求,不管访问什么资源,其实都是在访问Servlet!

JSP最终也会被转化成为一个Java类!

JSP本质上Servlet

// 初始化
public void _jspInit() {

}

// 销毁
public void _jspDestroy() {

}

// JSP的Service
public void _jspService(.HttpServletRequest request, HttpServletResponse response) {

}

1、判断请求
2、内置对象

final javax.servlet.jsp.PageContext pageContext;	// 页面上下文
javax.servlet.http.HttpSession session = null;	// session
final javax.servlet.ServletContext application;	// applicationContext
final javax.servlet.ServletConfig config;	// config
javax.servlet.jsp.JspWriter out = null;	// out
final java.lang.Object page = this;		// page 当前页
HttpServletRequest request		// 请求
HttpServletResponse response	// 响应

javax.servlet.jsp.JspWriter _jspx_out = null;	
javax.servlet.jsp.PageContext _jspx_page_context = null;

3、输出页面前增加的代码

response.setContentType("text/html");	// 设置响应的页面类型
pageContext = _jspxFactory.getPageContext(this, request, response, null, true, 8192, true);
_jspx_page_context = pageContext;
application = pageContext.getServletContext();
config = pageContext.getServletConfig();
session = pageContext.getSession();
out = pageContext.getOut();
_jspx_out = out;

4、以上的这些个对象我们可以在JSP页面中直接使用
在这里插入图片描述
在JSP页面中:

只要是Java代码就会原封不动的输出;

如果是HTML代码,就会转化为:

out.write("<html>\r\n");

这样的格式,输出到前端!


8.3、JSP基础语法

任何语言都有自己的语法,Java中有,JSP作为Java技术的一种应用,它拥有一些自己扩充的语法(了解,知道即可!),Java所有语法都支持

JSP表达式

作用:用来将程序的输出,输出到客户端

<%= 变量或者表达式 %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>$Title$</title>
  </head>
  <body>

  <%-- JSP表达式 --%>
  <%= new java.util.Date() %>

  </body>
</html>

JSP脚本片段

<%-- 分割线 --%>
<hr>

<%-- JSP脚本片段 --%>
<%
  int sum = 0;
  for (int i = 0; i <= 100 ; i++) {
    sum+=i;
  }
  out.println("<h1>"+sum+"</h1>");
%>

脚本片段的再实现

<%-- JSP脚本片段 --%>
  <%
    int sum = 0;
    for (int i = 0; i <= 100 ; i++) {
      sum+=i;
    }
    out.println("<h1>"+sum+"</h1>");
  %>

  <%
    int x = 10;
    out.println(x);
  %>
  <p>这是一个JSP文档</p>
  <%
    int y = 10;
    out.println(y);
  %>

  <%-- 在代码中嵌入HTML元素 --%>
  <%
    for (int i = 0; i < 5; i++) {
  %>
  <h1>hello world  <%= i%> </h1>
  <%
    }
  %>

JSP声明:会被编译到JSP生成Java的类中,其他的就会被生成到 _jspService方法中

<%!
    static {
      System.out.println("Loading Servlet!");
    }

    private int globalVar = 0;
    public void jspInit(){
      System.out.println("进入了方法!");
    }
  %>

在JSP,嵌入Java代码即可

<%%>
<%=%>
<%!%>

<%--注释--%>

JSP的注释,不会在客户端显示,HTML就会!


8.4、JSP指令

<%@ page contentType="text/html;charset=UTF-8" language="java" %>

<%--定制错误页面--%>

<%@ page errorPage="error/500.jsp" %>

<html>
  <head>
    <title>$Title$</title>
  </head>
  <body>
  	<%
		int x = 1/0;
	%>
  </body>
</html>

<%@page args.... %>
<%@include file="" %>

<%--@include会将两个页面合二为一--%>

<%@include file="common/header.jsp"%>
<h1>网页主体</h1>

<%@include file="common/footer.jsp"%>

<hr>


<%--jsp标签
	jsp : include: 拼接页面,本质还是三个
	--%>
<jsp:include page="/common/header.jsp" />
<h1>网页主体</h1>
<jsp:include page="/common/footer.jsp" />

8.5、9大内置对象

  • pageContext – 存东西
  • Request – 存东西
  • Response
  • Session – 存东西
  • Application 【ServletContext】-- 存东西
  • Config 【ServletConfig】
  • Out
  • Page
  • Exception

pageContext.setAttribute(“name1”,“Java1”); // 保存的数据只在一个页面中有效

request.setAttribute(“name2”,“Java2”); // 保存在数据只在一次请求中有效,请求转发会携带这个数据

application.setAttribute(“name3”,“Java3”); // 保存的数据只在服务器中有效,从打开服务器到关闭服务器

session.setAttribute(“name4”,“Java4”); // 保存的数据只在一次会话中有效,从打开浏览器到关闭浏览器

public static final int PAGE_SCOPE = 1;
    public static final int REQUEST_SCOPE = 2;
    public static final int SESSION_SCOPE = 3;
    public static final int APPLICATION = 4;
    // scope : 作用域
    public void setAttribute(String name, Object attribute, int scope) {
        switch(scope) {
            case 1:
                this.mPage.put(name, attribute);
                break;
            case 2:
                this.mRequest.put(name, attribute);
                break;
            case 3:
                this.mSession.put(name, attribute);
                break;
            case 4:
                this.mApp.put(name, attribute);
                break;
            default:
                throw new IllegalArgumentException("Bad scope " + scope);
        }
    }
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page isELIgnored="false" %>
<html>
<head>
    <title>Title</title>
</head>
<body>

<%--  内置对象  --%>

<%
    //    pageContext.include();
//    pageContext.forward();

    pageContext.setAttribute("name1","Java1");  // 保存的数据只在一个页面中有效
    request.setAttribute("name2","Java2");  // 保存在数据只在一次请求中有效,请求转发会携带这个数据
    application.setAttribute("name3","Java3");  // 保存的数据只在服务器中有效,从打开服务器到关闭服务器
    session.setAttribute("name4","Java4");  // 保存的数据只在一次会话中有效,从打开浏览器到关闭浏览器
%>

<%--
    脚本片段中的代码,会被原封不动生成到 JSP.java
    要求:这里面的代码:必须保证Java语法的正确性
--%>

<%
    //     通过pageContext取出我们保存的值
//     通过pageContext取出,我们通过寻找的方式来
    // 从底层到高层(作用域) : page --> request --> session --> application
    // JVM : 双亲委派机制 : 先找上级加载器,最上级没有才会从下级找
    String name1 = (String) pageContext.findAttribute("name1");
    String name2 = (String) pageContext.findAttribute("name2");
    String name3 = (String) pageContext.findAttribute("name3");
    String name4 = (String) pageContext.findAttribute("name4");
    String name5 = (String) pageContext.findAttribute("name5");
%>

<%--使用EL表达式输出--%>
    <h1>取出的值为: </h1>
    <h2>${name1}</h2>
    <h2>${name2}</h2>
    <h2>${name3}</h2>
    <h2>${name4}</h2>
<%--EL表达式会自动不在网页上显示null值--%>
    <h2>${name5}</h2>

</body>
</html>

request:客户端向服务器发送请求,产生数据,用户看完就没用了;比如:新闻,用户看完没用的;

session:客户端向服务器发送请求,产生的数据,用户用完一会还有用,比如:购物车;

application:客户端发服务器发送请求,产生的数据,一个用户用完了,其他用户还可能使用,比如:聊天数据;


8.6、JSP标签,JSTL标签,EL表达式

EL表达式:${}

  • 获取数据
  • 执行运算
  • 获取web开发的常用对象

JSP标签:

<%--jsp:include--%>
<%--
    http://localhost:8080/jsptag.jsp?name=kuangshen&age=12
--%>

    <jsp:forward page="/jsptag2.jsp">
        <jsp:param name="name" value="kuangshen"/>
        <jsp:param name="age" value="12"/>
    </jsp:forward>

JSTL表达式:

JSTL标签库的使用就是为了弥补HTML标签的不足;它自定义许多标签,可以供我们使用,标签的功能和Java代码一样!

格式化标签

SQL标签

XML标签

核心标签(掌握部分)
在这里插入图片描述

JSTL标签使用步骤:

  • 引入对应的taglib
  • 使用其中的方法
  • 在Tomecat也需要引入jstl的包,否则会报错;JSTL解析错误

if

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
    <title>Title</title>
</head>
<body>

    <h1>4</h1>

    <hr>

    <form action="coreif.jsp" method="get">
        <%--
            EL表达式获取表单中的数据
            ${param.参数名}
        --%>
        <input type="text" name="username" value="${param.username}">
        <input type="submit" value="登录">
    </form>

    <%--如果提交的用户名是管理员,则登陆成功--%>
    <%
        if (request.getParameter("username").equals("admin")){
            out.print("登陆成功");
        }
    %>

    <c:if test="${param.username == 'admin'}" var="isAdmin">
        <c:out value="管理员欢迎您" />
    </c:if>

    <%--自闭和标签--%>
    <c:out value="${isAdmin}"></c:out>

</body>
</html>

switch

<%--定义一个变量score,值为85--%>
<c:set var="score" value="85"></c:set>

<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:choose>

for

<%
    ArrayList<String> people = new ArrayList<>();
    people.add(0,"张三");
    people.add(1,"李四");
    people.add(2,"王五");
    people.add(3,"赵六");
    people.add(4,"田七");
    request.setAttribute("list",people);
%>

<%--
    var : 每一次遍历出来的变量
    items : 要遍历的对象
    begin : 从哪开始
    end : 到哪结束
    step : 步长
--%>

<c:forEach items="${list}" var="people">
    <c:out value="${people}" /><br>
</c:forEach>

<hr>

<c:forEach var="people" items="${list}" begin="1" end="3" step="2">
    <c:out value="${people}" /><br>
</c:forEach>

9、JavaBean

实体类

JavaBean有特定的写法:

  • 必须要有一个无参构造
  • 属性必须私有化
  • 必须有对应的get/set方法

一般用来和数据库的字段做映射

ORM(对象关系映射)

  • 表 -->类
  • 字段 --> 属性行
  • 行记录 --> 对象

people表

idnameageaddress
11号3中国
22号3中国
33号3中国
44号3中国
class People {
	private int id;
	private String name;
	private int age;
	private String address;
}

class A {
	new People(1, "1号", 3, "中国");
	new People(2, "2号", 3, "中国");
	new People(3, "3号", 3, "中国");
	new People(4, "4号", 3, "中国");
}

10、MVC三层架构

MVC:

  • Model:模型
  • View:视图
  • Controller:控制器

10.1、早些年的MVC架构

在这里插入图片描述

用户层直接访问控制层,控制层就可以直接操作数据库

servlet – CRUD --> 数据库

弊端:程序十分臃肿,不利于维护

servlet的代码中:处理请求、响应、试图跳转、处理业务代码、处理逻辑代码

架构:没什么是加一层解决不了的!!!

10.2、MVC三层架构

在这里插入图片描述
Model:

  • 业务处理:业务逻辑(Service)
  • 数据持久化:CRUD(Dao)

View:

  • 展示数据
  • 提供链接发起Servlet请求(a、form、img…)

Controller:

  • 接收用户的请求:(req:请求参数、Session信息)
  • 交给业务层处理对应的代码
  • 控制视图的跳转

11、Filter

Filter:过滤器,用来过滤网站的数据;

  • 处理中文乱码
  • 登录验证…

在这里插入图片描述
过滤器代码:

package com.blb.filter;

import javax.servlet.*;
import java.io.IOException;

public class CharacterEncodingFilter implements Filter {

    // 初始化: web服务器启动,就已经初始化,随时等待过滤对象出现!
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("CharacterEncodingFilter已经初始化");
    }

    // filterChain : 链
    /*
        1、过滤器的所有代码,在过滤特定请求的时候都会执行
        2、必须要让过滤器继续同行
            filterChain.doFilter(servletRequest, servletResponse);
     */
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        servletRequest.setCharacterEncoding("utf-16");
        servletResponse.setCharacterEncoding("utf-16");
        servletResponse.setContentType("text/html;charset=UTF-8");

        System.out.println("CharacterEncodingFilter执行前...");
        filterChain.doFilter(servletRequest, servletResponse);//让我们的请求继续走,如果不写,程序到这里就被拦截了
        System.out.println("CharacterEncodingFilter执行后...");
    }

    // 销毁
    public void destroy() {
        System.getenv();
        System.out.println("CharacterEncodingFilter已经销毁");
    }
}

配置路径的时候,一定要把过滤器的路径包括项目路径

<servlet>
        <servlet-name>ShowServlet</servlet-name>
        <servlet-class>com.blb.filter.servlet.ShowServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>ShowServlet</servlet-name>
        <url-pattern>/servlet/show</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>ShowServlet</servlet-name>
        <url-pattern>/show</url-pattern>
    </servlet-mapping>

    <!--过滤器-->
    <filter>
        <filter-name>CharacterEncodingFilter</filter-name>
        <filter-class>com.blb.filter.CharacterEncodingFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>CharacterEncodingFilter</filter-name>
        <!--只要是 /servlet的任何请求,都会经过这个过滤器-->
        <url-pattern>/servlet/*</url-pattern>
    </filter-mapping>

12、监听器

实现一个监听器的接口(有N种)

1、编写一个监听器:实现监听器的接口

// 统计网站在线人数: 统计session
public class onlineCountListener implements HttpSessionListener {

    // 创建session监听: 看你的一举一动
    // 一旦创建Session就会触发一次这个事件!
    public void sessionCreated(HttpSessionEvent httpSessionEvent) {
        ServletContext servletContext = httpSessionEvent.getSession().getServletContext();
        System.out.println(httpSessionEvent.getSession().getId());
        Integer onlineCount = (Integer) servletContext.getAttribute("onlineCount");

        if (onlineCount == null) {
            // 装箱
            onlineCount = new Integer(1);
        }else {
            // 开箱
            int count = onlineCount.intValue();
            onlineCount = new Integer(count+1);
        }

        servletContext.setAttribute("onlineCount", onlineCount);
    }

    // 销毁session监听
    // 一旦销毁Session就会触发一次这个事件!
    public void sessionDestroyed(HttpSessionEvent httpSessionEvent) {
        ServletContext servletContext = httpSessionEvent.getSession().getServletContext();
        Integer onlineCount = (Integer) servletContext.getAttribute("onlineCount");

        if (onlineCount == null) {
            // 装箱
            onlineCount = new Integer(0);
        }else {
            // 开箱
            int count = onlineCount.intValue();
            onlineCount = new Integer(count-1);
        }

        servletContext.setAttribute("onlineCount", onlineCount);
    }

    /*
        Sesssion销毁:
        1、手动销毁  getSession().invalidate();
        2、自动销毁  在web.xml配置销毁时间
     */
}

2、在web.xml中注册监听器

<!--注册一个监听器-->
<listener>
    <listener-class>com.blb.filter.listener.onlineCountListener</listener-class>
</listener>

3、看情况使用


13、过滤器和监听器常见应用

public class TestPandel {
    public static void main(String[] args) {
        Frame frame = new Frame("中秋节快乐");   // 新建一个窗体
        Panel panel = new Panel(null);  // 面板
        frame.setLayout(null);  // 设置窗体的布局

        frame.setBounds(300,300,500,500);
        frame.setBackground(new Color(0,0,255));    // 设置背景颜色

        panel.setBounds(50,50,300,300);
        panel.setBackground(new Color(0,255,0));    // 设置背景颜色

        frame.add(panel);

        frame.setVisible(true);

        // 监听事件: 监听关闭事件
        frame.addWindowFocusListener(new WindowAdapter() {
            @Override
            public void windowOpened(WindowEvent e) {
                System.out.println("打开");
            }

            @Override
            public void windowClosing(WindowEvent e) {
                System.out.println("关闭ing");
                System.exit(0);
            }

            @Override
            public void windowClosed(WindowEvent e) {
                System.out.println("关闭ed");
            }

            @Override
            public void windowIconified(WindowEvent e) {
                super.windowIconified(e);
            }

            @Override
            public void windowDeiconified(WindowEvent e) {
                super.windowDeiconified(e);
            }

            @Override
            public void windowActivated(WindowEvent e) {
                System.out.println("激活");
            }

            @Override
            public void windowDeactivated(WindowEvent e) {
                System.out.println("未激活");
            }

            @Override
            public void windowStateChanged(WindowEvent e) {
                super.windowStateChanged(e);
            }

            @Override
            public void windowGainedFocus(WindowEvent e) {
                super.windowGainedFocus(e);
            }

            @Override
            public void windowLostFocus(WindowEvent e) {
                super.windowLostFocus(e);
            }
        });
    }
}
  • 3
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值