JavaWeb完整笔记

1、基本概念

1.1、前言

web开发

  • web :网页的意思
  • 静态web(html,css):提供给所有人看的数据始终不会发生变化
  • 动态web(技术栈:Servlet/JSP,ASP,PHP):提供给所有人看的数据始终会发生变化,每个人在不同的时间,不同的地点看到的信息各不相同
  • 在java中,动态web资源开发的技术统称为JavaWeb
1.2、web应用程序

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

  • a.html、b.htm…多个web资源,这些web资源可以被外界访问,对外界提供服务;
  • 能访问到的任何一个页面或者资源,都存在于这个世界的某一个角落的计算机上。
  • URL
  • 这个统一的web资源会被放在同一个文件夹下,web应用程序–>Tomcat:服务器。
  • 一个web应用由多部分组成(静态web,动态web)
    • html,css,js
    • jsp, serxlet
    • Java程序
    • jar包
    • 配置文件(Properties)

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

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

  • 静态web存在的缺点

    • Web页面无法动态更新,所有用户看到都是同一个页面
      • 轮播图,点击特效:伪动态
      • JavaScript [实际开发中,它用的最多]
      • VBScript
    • 无法和数据库交互(数据无法持久化,用户无法交互)
1.4、动态web
  • 页面会动态展示:“Web的页面展示的效果因人而异”;

  • 缺点

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

    • Web页面可以动态更新,所有用户看到都不是同一个页面
    • 可以与数据库交互(数据持久化:注册,商品信息,用户信息……)

2、web服务器

2.1、技术讲解
  • ASP:
    • 微软:国内最早流行的就是ASP;
    • 在HTML中嵌入了VB的脚本,ASP+ COM;
    • 在ASP开发中,基本一个页面都有几千行的业务代码,页面极其换乱
    • 维护成本高!
    • C#
    • IIS服务器
  • PHP:
    • PHP开发速度很快,功能很强大,跨平台,代码很简单(70%中小型网站, WP)
    • 无法承载大访问量的情况(局限性)
  • JSP/Servlet:
    • sun公司主推的B/S架构
      • B/S:浏览器和服务器
      • C/S:客户端和服务器
    • 基于java语言的(所有的大公司或者一些开源的组件都是用java写的)
    • 可以承接三高问题(高并发、高可用、高性能)带来的影响
    • 语法像ASP,有利于ASP转JSP,加强市场竞争度
2.2、web服务器

服务器是一种被动的操作,用来处理用户的一些请求和给用户一些响应信息

  • IIS:微软的,ASP,Windows中自带的

  • Tomcat

    Tomcat是Apache软件基金会(Apache Software Foundation)的akarta项目中的一个核心项目,最新的Servlet和SP规范总是能在Tomcat中得到体现,因为Tomcat技术先进、性能稳定,而且免费,因而深受Java爱好者的喜爱并得到了部分软件开发商的认可,成为目前比较流行的Web应用服务器。

    Tomcat服务器是一个免费的开放源代码的Web应用服务器,属于轻量级应用服务器,在中小型系统和并发访问用户不是很多的场合下被普遍使用,是开发和调试LSP程序的首选。对于一个lava初学web的人来说,它是最佳的选择

    Tomcat 实际上运行ISP页面和Servlet。Tomcat最新版本为9.0。

3、Tomcat

3.1 、安装Tomcat

tomcat官网:http://tomcat.apache.org/

3.2、Tomcat启动和配置
  • 文件夹的作用:

  • 启动和关闭Tomcat

  • 访问测试:http://localhost:8080/

  • 可能遇到的问题:

    • Java环境变量没有配置
    • 闪退问题:需要配置兼容性
    • 乱码问题:配置文件中设置
3.3、配置

  • 可以配置启动的端口号

    <Connector port="8081" protoco1="HTTP/1.1"
    		   connectionTimeout="20000"
    		   redirectPort="8443"/>
    
    • tomcat的默认端口号为:8080
    • mysql:3306
    • http:80
    • https:443
  • 可以配置主机的名称

    <Host name="www.pqf.com" appBase="webapps"
    	unpackwARS="true" autoDeploy="true">
    
    • 默认的主机名为:localhost–>127.0.0.1
    • 默认网站应用存放的位置为:webapps
  • 面试题:请你谈谈网站是如何进行访问的

    • 输入一个域名;回车

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

      • 有:直接返回对应的ip地址,这个地址中有我们需要访问的web程序,可以直接访问

        127.0.0.1 www.pqf.com

      • 没有:去DNS服务器找,找到的话就返回,找不到就返回找不到

3.4、发布一个web网站
  • 将写的网站,放到服务器(Tomcat)中指定的web应用的文件夹(webapps)下,就可以访问了

  • 网站应该有的结构

    --webapps : Tomcat服务器的web目录
    	- ROOT
    	- kuangstudy : 网站的目录名
    		- WEB-INF
    			-classes : java程序
    			-lib: web应用所依赖的jar包
                -web.xml :网站配置文件
            - index.html默认的首页
            - static
    			-css
    				-style.css
                -js
    			-img
            -......
    

4、HTTP

4.1、什么是HTTP

HTTP(超文本传输协议)是一个简单的请求-响应协议,它通常运行在TCP之上。

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

Https:安全的

  • 默认端口:443
4.2、两个时代
  • http1.0
    • HTTP/1:客户端可以与web服务器连接后,只能获得一个web资源,断开连接
  • http2.0
    • HTTP/1.1:客户端可以与web服务器连接后,可以获得一个web资源
4.3、Http请求
  • 客户端—发请求(Request)—服务器

  • 例:百度

    Request URL:https://www.baidu.com/   请求地址
    Request Method:GET    get方法/post方法
    Status code:200 OK    状态码:200
    Remote(远程) Address : 14.215.177.39:443
    
    Accept:text/html
    Accept-Encoding:gzip,def1ate,br
    Accept-Language:zh-CN,zh;q=0.9    语言
    Cache-contro7:max-age=0
    Connection:keep-alive
    
  • 请求行

    • 请求行中的请求方式:GET
    • 请求方式:GetPost,HEAD,DELETE,PUT,TRACT…
      • get:请求能够携带的参数比较少,大小有限制,会在浏览器的URL地址栏显示数据内容,不安全,但高效
      • post:请求能够携带的参数没有限制,大小,没有限制,不会在浏览器的URL地址栏显示数据内容,安全,但不高效
  • 消息头

    Accept:告诉浏览器,它所支持的数据类型
    Accept-Encoding:支持哪种编码格式     GBK    UTF-8    GB2312    Is08859-1
    Accept-Language:告诉浏览器,它的语言环境
    cache-control:缓存控制
    connection:告诉浏览器,请求完成是断开还是保持连接
    HOST:主机..../.
    
4.4、Http响应
  • 服务器—响应—客户端

  • 例:百度

    Cache-contro1:private    缓存控制
    Connection:keep-Alive    连接
    Content-Encoding:gzip    编码
    Content-Type:text/htm1   类型
    
  • 响应体

    Accept:告诉浏览器,它所支持的数据类型
    Accept-Encoding:支持哪种编码格式     GBK    UTF-8    GB2312    Is08859-1
    Accept-Language:告诉浏览器,它的语言环境
    cache-control:缓存控制
    connection:告诉浏览器,请求完成是断开还是保持连接
    HOST:主机..../.
    Reflush:告诉客户端,多久刷新一次
    Location:让网页重新定位
    
  • 响应状态码

    200:请求响应成功

    3xx:请求重定向

    4xx:找不到资源 404

    5xx:服务器代码错误 500 502(网关错误)

5、Maven

5.1、Maven项目架构管理工具
  • 作用:目前是方便导入jar包

  • Maven的核心思想:约束大于配置(有约束,不要去违反)

  • Maven会规定好如何编写java代码,必须按照规范

5.2、下载安装Maven

官网:https://maven.apache.org/

5.3、配置环境变量

在的系统环境变量中
配置如下配置:

  • M2_HOME maven目录下的bin目录
  • MAVEN_HOME maven的目录
  • 在系统的path中配置 %MAVEN_HOME%/bin
5.4、阿里云镜像
  • 镜像:mirrors

    • 作用:加速下载
  • 国内建议使用阿里云的镜像(加下conf目录下setting.xml文件中的mirrors中)

    <mirror>
    	<id>nexus-aliyun</id>
    	<mirrorof>*,!jeecg,!jeecg-snapshots</mirrorof>
        <name>Nexus aliyun</name>
        <ur1>http://maven.aliyun.com/nexus/content/groups/public</ur1>
    </mirror>
    
5.5、本地仓库

建立一个本地仓库:localRepository

<1ocalRepository>D:\Environment\apache-maven-3.6.2\maven-repo</localRepository>
5.6、在IDEA中使用Maven
  1. 启动IDEA

  2. 创建一个MavenWeb项目

  3. 等待项目初始化完毕

  4. IDEA中配置Maven

  5. 新建目录

    (1)方法一

    (2)方法二

  6. 其他

  7. 创建一个简洁的Maven项目

5.7、pom文件
  1. pom.xml是Maven的核心配置文件

    <?xml version="1.0" encoding="UTF-8"?>
    
    <!--Maven版本和头文件 -->
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
      <modelVersion>4.0.0</modelVersion>
    
      <!--配置的GAV-->
      <groupId>com.ping</groupId>
      <artifactId>javaweb-01-maven</artifactId>
      <version>1.0-SNAPSHOT</version>
    
      <!--Package:项目的打包方式
      jar:java应用
      war:JavaWeb应用
      -->
      <packaging>war</packaging>
    
    
      <!--配置-->
      <properties>
      <!-- 项目的默认构建编码-->
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <!--编码版本-->
        <maven.compiler.source>1.7</maven.compiler.source>
        <maven.compiler.target>1.7</maven.compiler.target>
      </properties>
    
      <!--项目依赖-->
      <dependencies>
        <!--具体依赖的jar包配置文件-->
        <dependency>
          <groupId>junit</groupId>
          <artifactId>junit</artifactId>
          <version>4.11</version>
          <scope>test</scope>
        </dependency>
      </dependencies>
    
      <!--项目构建用的东西-->
      <build>
        <finalName>javaweb-01-maven</finalName>
        <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
          <plugins>
            <plugin>
              <artifactId>maven-clean-plugin</artifactId>
              <version>3.1.0</version>
            </plugin>
            <!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging -->
            <plugin>
              <artifactId>maven-resources-plugin</artifactId>
              <version>3.0.2</version>
            </plugin>
            <plugin>
              <artifactId>maven-compiler-plugin</artifactId>
              <version>3.8.0</version>
            </plugin>
            <plugin>
              <artifactId>maven-surefire-plugin</artifactId>
              <version>2.22.1</version>
            </plugin>
            <plugin>
              <artifactId>maven-war-plugin</artifactId>
              <version>3.2.2</version>
            </plugin>
            <plugin>
              <artifactId>maven-install-plugin</artifactId>
              <version>2.5.2</version>
            </plugin>
            <plugin>
              <artifactId>maven-deploy-plugin</artifactId>
              <version>2.8.2</version>
            </plugin>
          </plugins>
        </pluginManagement>
      </build>
    </project>
    
    
  2. maven由于约定大于配置,之后可能遇到我们写的配置文件,无法被导出或者生效的问题,解决方案:

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

6、Servlet

6.1、Servlet简介
  • Servlet就是sun公司开发动态web的一门技术
  • Sun在这些API中提供一个接口叫做:Servlet,如果你想开发一个Servlet程序,只需要完成两个小步骤:
    • 编写一个类,实现Servlet接口
    • 把开发好的Java类部署到web服务器中
  • 把实现了Servlet接口的Java程序叫做 Servlet
6.2、HelloServlet

Serlvet接口有两个默认的实现类:HttpServlet,GenericServlet

  1. 构建一个普通的Maven项目,删掉src目录,之后在这个项目中建立Module;这个空的工程就是Maven主工程

  2. Maven主工程导入的依赖

    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>4.0.1</version>
    </dependency>
    
    <dependency>
        <groupId>javax.servlet.jsp</groupId>
        <artifactId>javax.servlet.jsp-api</artifactId>
        <version>2.3.3</version>
    </dependency>
    
  3. 关于Maven父子工程的理解

    • 父项目中会新增

      <modules>
          <module>servlet-01</module>
      </modules>
      
    • 子项目会有(若没有,可手动添加)

      <parent>
          <artifactId>javaweb-02-servlet</artifactId>
          <groupId>com.ping</groupId>
          <version>1.0-SNAPSHOT</version>
      </parent>
      
    • 父项目中的java子项目可以直接使用

      son extends father 
      
  4. Maven环境优化

    • 修改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"
               metadata-complete="true">
      </web-app>
      
    • 将maven的结构搭建完整:在main目录下新建java和resources

  5. 编写一个Servlet程序

    • 编写一个普通类

    • 实现Servlet接口,继承HttpServlet

      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(); //响应流
              writer.print("Hello,Serlvet");
          }
      
          @Override
          protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
              doGet(req, resp);
          }
      }
      
  6. 编写Servlet的映射

    为什么需要映射︰写的是JAVA程序,但是要通过浏览器访问,而浏览器需要连接web服务器,所以需要在web服务中注册写的Servlet,还需给它一个浏览器能够访问的路径;

    <!--注册Servlet-->
    <servlet>
        <servlet-name>hello</servlet-name>
        <servlet-class>com.ping.servlet.HelloServlet</servlet-class>
    </servlet>
    <!--Servlet的请求路径-->
    <servlet-mapping>
        <servlet-name>hello</servlet-name>
        <url-pattern>/hello</url-pattern>
    </servlet-mapping>
    
  7. 配置Tomcat

  8. 启动测试

6.3、Servlet原理

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

6.4、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>
    
  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>*.ping</url-pattern>
    </servlet-mapping>
    
  6. 优先级问题

    指定了固有的映射路径优先级最高,如果找不到就会走默认的处理请求

    <!--404-->
    <servlet>
        <servlet-name>error</servlet-name>
        <servlet-class>com.ping.servlet.ErrorServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>error</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>
    
6.5、ServletContext

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

1、共享数据

在这个Servlet中保存的数据,可以在另外一个servlet中拿到;

  • 保存数据到ServletContext中

    public class HelloServlet extends HttpServlet {
    
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
            //this.getInitParameter();   初始化参数
            //this.getServletConfig();   Servlet配置
            //this.getServletContext();  Servlet上下文
    
            ServletContext context = this.getServletContext();
    
            String username = "用户名"; //数据
            context.setAttribute("username", username);//将一个数据保存在ServletContext中,名字为 username(前),值 username(后)
    
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            doGet(req, resp);
        }
    }
    
  • 从ServletContext中获取数据

    public class GetServlet extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            ServletContext context = this.getServletContext();
    
            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 {
            doGet(req, resp);
        }
    }
    
  • 配置web.xml

    <servlet>
        <servlet-name>hello</servlet-name>
        <servlet-class>com.ping.servlet.HelloServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>hello</servlet-name>
        <url-pattern>/hello</url-pattern>
    </servlet-mapping>
    
    <servlet>
        <servlet-name>getc</servlet-name>
        <servlet-class>com.ping.servlet.GetServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>getc</servlet-name>
        <url-pattern>/getc</url-pattern>
    </servlet-mapping>
    
  • 测试访问结果

2、获取初始化参数
public class ServletDemo03 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        ServletContext context = this.getServletContext();

        String url = context.getInitParameter("url");
        resp.getWriter().print(url);
    }
}
  • web.xml
<!--配置一些web应用初始化参数-->
<context-param>
    <param-name>url</param-name>
    <param-value>jdbc:mysql://localhost:3306/mybatis</param-value>
</context-param>

<servlet>
    <servlet-name>getp</servlet-name>
    <servlet-class>com.ping.servlet.ServletDemo03</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>getp</servlet-name>
    <url-pattern>/getp</url-pattern>
</servlet-mapping>

  • 测试结果:获取web.xml中context-param下的参数

3、请求转发
public class ServletDemo04 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        ServletContext context = this.getServletContext();

        RequestDispatcher requestDispatcher = context.getRequestDispatcher("/getp");//转发的请求路径
        requestDispatcher.forward(req,resp);//调用forward实现请求转发
        //context.getRequestDispatcher("/getp").forward(req,resp);

    }
}

  • web.xml
<servlet>
    <servlet-name>sd4</servlet-name>
    <servlet-class>com.ping.servlet.ServletDemo04</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>sd4</servlet-name>
    <url-pattern>/sd4</url-pattern>
</servlet-mapping>
  • 测试结果:转发到localhost:8080/s2/getp

4、读取资源文件

Properties

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

发现:都被打包到了同一个路径下:classes(俗称这个路径为classpath,即类路径)

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

        InputStream is = this.getServletContext().getResourceAsStream("/WEB-INF/classes/db.properties");

        Properties prop = new Properties();
        prop.load(is);
        String user = prop.getProperty("username");
        String pwd = prop.getProperty("password");

        resp.getWriter().print(user + "." + pwd);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}
  • db.properties
username=root
password=123456
  • web.xml
 <servlet>
        <servlet-name>sd5</servlet-name>
        <servlet-class>com.ping.servlet.ServletDemo05</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>sd5</servlet-name>
        <url-pattern>/sd5</url-pattern>
    </servlet-mapping>

  • 测试结果

6.6、HttpServletResponse

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

  • 如果要获取客户端请求过来的参数:找HttpServletRequest
  • 如果要给客户端响应一些信息:找HttpServletResponse
1、简单分类
  • 负责向浏览器发送数据的方法

    ServletOutputStream getOutputStream() throws IOException;
    PrintWriter getwriter() throws IOException;
    
  • 负责向浏览器发送响应头的方法

    void setCharacterEncoding(String var1);
    void setContentLength(int var1) ;
    void setContentLengthLong(long var1);
    void setContentType(String var1);
    
    void setDateHeader(String var1,long var2);
    void addDateHeader(String var1,long var2);
    void setHeader(String var1,String var2);
    void addHeader(String var1,String var2);
    void setIntHeader(string var1,int var2);
    void addIntHeader(string var1,int var2);
    
  • 响应的状态码

    int SC_CONTINUE = 100;
    int SC_SWITCHING_PROTOCOLS = 101;
    int SC_OK = 200;
    int SC_CREATED = 201;
    int SC_ACCEPTED = 202;
    int SC_NON_AUTHORITATIVE_INFORMATION = 203;
    int SC_NO_CONTENT = 204;
    int SC_RESET_CONTENT = 205;
    int SC_PARTIAL_CONTENT = 206;
    int SC_MULTIPLE_CHOICES = 300;
    int SC_MOVED_PERMANENTLY = 301;
    int SC_MOVED_TEMPORARILY = 302;
    int SC_FOUND = 302;
    int SC_SEE_OTHER = 303;
    int SC_NOT_MODIFIED = 304;
    int SC_USE_PROXY = 305;
    int SC_TEMPORARY_REDIRECT = 307;
    int SC_BAD_REQUEST = 400;
    int SC_UNAUTHORIZED = 401;
    int SC_PAYMENT_REQUIRED = 402;
    int SC_FORBIDDEN = 403;
    int SC_NOT_FOUND = 404;
    int SC_METHOD_NOT_ALLOWED = 405;
    int SC_NOT_ACCEPTABLE = 406;
    int SC_PROXY_AUTHENTICATION_REQUIRED = 407;
    int SC_REQUEST_TIMEOUT = 408;
    int SC_CONFLICT = 409;
    int SC_GONE = 410;
    int SC_LENGTH_REQUIRED = 411;
    int SC_PRECONDITION_FAILED = 412;
    int SC_REQUEST_ENTITY_TOO_LARGE = 413;
    int SC_REQUEST_URI_TOO_LONG = 414;
    int SC_UNSUPPORTED_MEDIA_TYPE = 415;
    int SC_REQUESTED_RANGE_NOT_SATISFIABLE = 416;
    int SC_EXPECTATION_FAILED = 417;
    int SC_INTERNAL_SERVER_ERROR = 500;
    int SC_NOT_IMPLEMENTED = 501;
    int SC_BAD_GATEWAY = 502;
    int SC_SERVICE_UNAVAILABLE = 503;
    int SC_GATEWAY_TIMEOUT = 504;
    int SC_HTTP_VERSION_NOT_SUPPORTED = 505;
    
2、下载文件
  • 要获取下载文件的路径

  • 下载的文件名

  • 设置想办法让浏览器能够支持下载我们需要的东西

  • 获取下载文件的输入流

  • 创建缓冲区

  • 获取OutputStream对象

  • 将FileOutputStream流写入到buffer缓冲区

  • 使用Outputstream将缓冲区中的数据输出到客户端!

    public class FileServlet extends HttpServlet {
    
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            // 1.要获取下载文件的路径
            //String realPath = "E:\\学习笔记\\JAVAWEB\\javaweb-02-servlet\\response\\target\\classes\\图片.png";
            String realPath = this.getServletContext().getRealPath("/WEB-INF/classes/图片.png");
    
            System.out.println("下载文件的路径:" + realPath); //下载文件的路径:D:\JAVAEE_DEV\apache-tomcat-9.0.43\webapps\r\WEB-INF\classes\图片.png
            // 2.下载的文件名
            String fileName = realPath.substring(realPath.lastIndexOf("\\") + 1);
            // 3.设置想办法让浏览器能够支持(Content-Disposition)下载我们需要的东西,中文文件名使用URLEncoder.encode编码,否则可能乱码
            resp.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
            // 4.获取下载文件的输入流
            FileInputStream in = new FileInputStream(realPath);
            // 5.创建缓冲区
            int len = 0;
            byte[] buffer = new byte[1024];
            // 6.获取OutputStream对象
            ServletOutputStream out = resp.getOutputStream();
            // 7.将FileOutputStream流写入到buffer缓冲区,使用Outputstream将缓冲区中的数据输出到客户端!
            while ((len = in.read(buffer)) != -1) {
                out.write(buffer, 0, len);
            }
            in.close();
            out.close();
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            doGet(req, resp);
        }
    }
    
  • web.xml

    <servlet>
        <servlet-name>filedown</servlet-name>
        <servlet-class>com.ping.servlet.FileServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>filedown</servlet-name>
        <url-pattern>/down</url-pattern>
    </servlet-mapping>
    
  • 测试结果:地址栏输入http://localhost:8080/r/down,浏览器下方提示下载

3、验证码功能

验证码怎么来的

  • 前端实现

  • 后端实现,需要用到Java的图片类,生成一张图片

    public class ImageServlet extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
            //如何让浏览器3秒自动刷新一次
            resp.setHeader("refresh","3");
    
            //在内存中创建一个图片
            BufferedImage image = new BufferedImage(50, 20, BufferedImage.TYPE_INT_RGB);
            //得到图片
            Graphics2D g = (Graphics2D) image.getGraphics(); //笔
            //设置图片背景颜色
            g.setColor(Color.white);
            g.fillRect(0,0,50,20);
            //给图片写数据
            g.setColor(Color.BLUE);
            g.setFont(new Font(null,Font.BOLD,20));
            g.drawString(makeNum(),0,20);
    
            //告诉浏览器,这个请求用图片的方式打开
            resp.setContentType("image/jpg");
            //网站存在缓存,不让浏览器缓存
            resp.setDateHeader("expires",-1);
            resp.setHeader("Cache.Control","no-cache");
            resp.setHeader("Pragma","no-cache");
    
            //把图片写给浏览器
            ImageIO.write(image, "jpg", resp.getOutputStream());
    
        }
        //生成随机数
        private 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"); //用0填充不满4位的数,保证最终返回的num一定是4位
            }
            num = sb.toString() + num;
            return num;
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            doGet(req, resp);
        }
    }
    
  • web.xml

    <servlet>
        <servlet-name>ImageServlet</servlet-name>
        <servlet-class>com.ping.servlet.ImageServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>ImageServlet</servlet-name>
        <url-pattern>/img</url-pattern>
    </servlet-mapping>
    
  • 测试结果

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

  • 常见场景

    • 用户登录
    void sendRedirect(String var1) throws IOException;
    
  • 示例

    public class RedirectServlet extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
            /*
            resp.setHeader("Location","/r/red");
            resp.setStatus(302);
             */
    
            resp.sendRedirect("/r/img"); //重定向
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            doGet(req, resp);
        }
    }
    
    
  • 面试题:请你聊聊重定向和转发的区别?

    • 相同点
      • 页面都会实现跳转
    • 不同点
      • 请求转发的时候,url不会产生变化;307
      • 重定向时候,url地址栏会发生变化;302

6.7、HttpServletRequest

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

1、获得前端传递的参数以及请求转发
  • LoginServlet类

    public class LoginServlet extends HttpServlet {
        @Override
        protected void doGet(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[] numbers = req.getParameterValues("number");
    
            System.out.println("=================================");
            
            System.out.println(username);
            System.out.println(password);
            System.out.println(Arrays.toString(numbers));
            System.out.println("=================================");
    
            //通过请求转发
            //这里的 / 代表当前的web应用
            req.getRequestDispatcher("/success.jsp").forward(req, resp);
    
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            doGet(req, resp);
        }
    }
    
    
  • web.xml

    <servlet>
        <servlet-name>LoginServlet</servlet-name>
        <servlet-class>com.ping.servlet.LoginServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>LoginServlet</servlet-name>
        <url-pattern>/login</url-pattern>
    </servlet-mapping>
    
  • index.jsp

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title>登录</title>
    </head>
    <body>
    <h1>登录</h1>
    <div>
        <%--这里表单的意思:以post方式提交表单,提交到login请求--%>
        <form action="${pageContext.request.contextPath}/login" method="post">
            用户名:<input type="text" name="username"><br>
            密码:<input type="password" name="password"><br>
            数字:
            <input type="checkbox" name="number" value=""><input type="checkbox" name="number" value=""><input type="checkbox" name="number" value=""><input type="checkbox" name="number" value=""><br>
            <input type="submit">
        </form>
    </div>
    
    </body>
    </html>
    
  • 新建success.jsp

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title>Title</title>
    </head>
    <body>
    <h1>登录成功</h1>
    
    </body>
    </html>
    
  • 测试结果

    • 首页输入信息

    • 点击提交转发到:http://localhost:8080/r/login

    • 控制台输出信息

7、Cookie,Session

7.1、会话

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

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

你能怎么证明你是西开的学生?
你 学校

  1. 发票 西开给你发票
  2. 学校登记 西开标记你来过了

一个网站,怎么证明你来过?
客户端 服务端

  1. 服务端给客户端一个信件,客户端下次访问服务端带上信件就可以了; cookie
  2. 服务器登记你来过了,下次你来的时候我来匹配你; session
7.2、保存会话的两种技术
  • cookie
    • 客户端技术(响应,请求)
  • session
    • 服务器技术,服务器技术,利用这个技术,可以保存用户的会话信息,可以把信息或者数据放在Session中
  • 网站登录之后,你下次不用再登录了,第二次访问直接就上去了
7.3、Cookie
  1. 从请求中拿到cookie信息

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

  3. cookie一般会保存在本地的用户目录下的appdata;

  4. 关于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
    
  5. 一个网站cookie是否存在上限(细节问题)

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

    • 不设置有效期,关闭浏览器,自动失效
    • 设置有效期时间为0
  7. 编码解码

    URLEncoder.encode("String类型的数据","utf-8")); //编码
    URLDecoder.decode("String类型的数据","UTF-8");  //解码
    
  8. 应用cookie保存用户上一次访问的时间

    • java类

      public class CookieDemo01 extends HttpServlet {
          @Override
          protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
              //服务器告诉你你来的时间,把这个时间封装为一个信件,你下次带来,就知道你来了
      
              //解决中文乱码
      
              resp.setContentType("text/html");
              req.setCharacterEncoding("utf-8");
              resp.setCharacterEncoding("utf-8");
      
              PrintWriter out = resp.getWriter();
      
              //Cookie,服务端从客户端获取
              Cookie[] cookies = req.getCookies();//这里返回数组,说明Cookie可能存在多个
      
              //判断Cookie是否存在
              if (cookies!=null) {
                  //如果存在怎么办
                  out.write("你上一次访问的时间是:");
      
                  for (int i = 0; i < cookies.length; i++) {
                      Cookie cookie = cookies[i];
                      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
      
              //cookie有效期为1天
              cookie.setMaxAge(24*60*60);//设置cookie的有效期,单位为秒
      
              resp.addCookie(cookie); //响应给客户端一个cookie
          }
      
          @Override
          protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
              doGet(req, resp);
          }
      }
      
      
    • web.xml

      <servlet>
          <servlet-name>CookieDemo01</servlet-name>
          <servlet-class>com.ping.servlet.CookieDemo01</servlet-class>
      </servlet>
      <servlet-mapping>
          <servlet-name>CookieDemo01</servlet-name>
          <url-pattern>/c1</url-pattern>
      </servlet-mapping>
      
    • 测试结果

7.4、Session(重点)
  1. 什么是Session:

    • 服务器会给每一个用户(浏览器)创建一个Seesion对象

    • 一个Session会独占一个浏览器,只要浏览器没有关闭,这个Session就会存在

    • 用户登录之后,整个网站都可以访问;

    • Session保护用户的信息;保存购物车的信息

  2. Session和Cookie的区别

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

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

    HttpSession session = req.getSession(); //得到Session
    
    session.setAttribute("name","小明"); //在Session中存数据
    
    String sessionId = session.getId(); //获取Session的ID
    
    //判断Session是不是新创建
    if (session.isNew()) {
        resp.getWriter().write("session创建成功,ID:"+sessionId);
    }else{
        resp.getWriter().write("session已经在服务器中存在了,ID:"+sessionId);
    }
    
    String name = (String) session.getAttribute("name"); //获取Session中的数据
    
    session.invalidate(); //手动注销Session
    
  5. 会话自动过期:配置web.xml

    <!--设置Session默认的失效时间-->
    <session-config>
        <!--15分钟后Session自动失效,以分钟为单位-->
        <session-timeout>15</session-timeout>
    </session-config>
    
  6. 应用Session保存和获取对象数据

    • pojo类

      public class Person {
          private String name;
          private int age;
      
          public Person() {
          }
      
          public Person(String name, int age) {
              this.name = name;
              this.age = age;
          }
      
          public String getName() {
              return name;
          }
      
          public void setName(String name) {
              this.name = name;
          }
      
          public int getAge() {
              return age;
          }
      
          public void setAge(int age) {
              this.age = age;
          }
      
          @Override
          public String toString() {
              return "Person{" +
                      "name='" + name + '\'' +
                      ", age=" + age +
                      '}';
          }
      }
      
    • SessionDemo01类:保存数据到session中

      public class SessionDemo01 extends HttpServlet {
          @Override
          protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
      
              //解决乱码问题
              resp.setCharacterEncoding("utf-8");
              req.setCharacterEncoding("utf-8");
              resp.setContentType("text/html;charset=utf-8");
      
              //得到Session
              HttpSession session = req.getSession();
      
              //在Session中存数据
              session.setAttribute("name", new Person("小明", 8));
      
              //获取Session的ID
              String sessionId = session.getId();
      
              //判断Session是不是新创建
              if (session.isNew()) {
                  resp.getWriter().write("session创建成功,ID:" + sessionId);
              } else {
                  resp.getWriter().write("session已经在服务器中存在了,ID:" + sessionId);
              }    
          }
      
          @Override
          protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
              doGet(req, resp);
          }
      }
      
      
    • SessionDemo02类:获取session中的数据

      public class SessionDemo02 extends HttpServlet {
      
          @Override
          protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
      
              //解决乱码问题
              req.setCharacterEncoding("utf-8");
              resp.setCharacterEncoding("utf-8");
              resp.setContentType("text/html;charset=utf-8");
      
              //得到Session
              HttpSession session = req.getSession();
      
              //获取Session中的数据
              Person person = (Person) session.getAttribute("name");
      
              resp.getWriter().write(person.toString());
          }
      
          @Override
          protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
              doGet(req, resp);
          }
      }
      
      
    • 配置web.xml

      <servlet>
          <servlet-name>SessionDemo01</servlet-name>
          <servlet-class>com.ping.servlet.SessionDemo01</servlet-class>
      </servlet>
      <servlet-mapping>
          <servlet-name>SessionDemo01</servlet-name>
          <url-pattern>/s1</url-pattern>
      </servlet-mapping>
      
      <servlet>
          <servlet-name>SessionDemo02</servlet-name>
          <servlet-class>com.ping.servlet.SessionDemo02</servlet-class>
      </servlet>
      <servlet-mapping>
          <servlet-name>SessionDemo02</servlet-name>
          <url-pattern>/s2</url-pattern>
      </servlet-mapping>
      
    • 测试结果:

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目录

    • 进入目录

      C:\Users\用户名\AppData\Local\JetBrains\IntelliJIdea2020.3\tomcat\f4559a8e-20ba-4cb5-abb8-05e0fbbc30bd\work\Catalina\localhost\ROOT\org\apache\jsp

    • 发现页面转变成了java程序

    • JSP最终也会被转换成为一个Java类

    • JSP本质上就是一个Servlet(从源码得出)

      • index_jsp 继承 HttpJspBase 继承 HttpServlet

      • 判断请求

      • 内置一些对象

        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               //响应
        
      • 输出页面前增加的代码

        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;
        
      • 以上的这些对象可以在JSP页面中直接使用

  • 流程图

  • 浏览器向服务器发送请求,不管访问什么资源,其实都是在访问Servlet!

  • 在JSP页面中;

    • 只要是JAVA代码就会原封不动的输出

    • 如果是HTML代码,就会被转换为

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

      这样的格式输出到前端

8.3、JSP基础语法

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

1、JSP表达式
<%--JSP表达式
    作用:用来将程序的输出,输出到客户端
    模板:<%= 变量或者表达式%>
--%>
<%= new java.util.Date()%>
2、JSP脚本片段
  <%--JSP脚本片段--%>
  <%
    int sum = 0;
    for (int i = 1; i < 100; i++) {
      sum+=i;
    }
    out.println("<h1>Sum="+sum+"</h1>"); //4950
  %>
  • 脚本片段的再实现

      <%
        int x = 10;
        out.println(x);//10
      %>
      <p>这是一个JSP文档</p>
      <%
        int y = 20;
        out.println(x+y);//30
      %>
    
      <hr>
    
      <%--在代码嵌入HTML元素--%>
      <% for (int i = 0; i < 5; i++) { %>
        <h1>Hello,World <%=i%></h1>
      <% } %>
    
    
3、JSP声明
  <%--在方法外写代码--%>
  <%!
    static {
      System.out.println("Loading Servlet!");
    }

    private  int globalVar = 0;

    public void ping(){
      System.out.println("进入了方法ping");
    }
  %>

  <!--HTML的注释-->
  <%--JSP的注释--%>    
  • JSP声明:会被编译到JSP生成Java的类中;其他的就会被生成到_jspService方法中!
  • 在JSP中嵌入JAVA代码即可
  • JSP的注释,不会在客户端显示,HTML就会
8.4、JSP指令
<%--定制错误页面--%>
<%@ page errorPage="error/500.jsp" %>

<%--显示的声明这是一个错误页面--%>
<%@ page isErrorPage="true" %>

<%--编码--%>
<%@ page pageEncoding="UTF-8" %>

<%--@ include会将两个页面合二为一--%>
<%@ include file="***.jsp"%>


  • 定制错误页面方法二:配置web.xml

    <error-page>
        <error-code>500</error-code>
        <location>/error/500.jsp</location>
    </error-page>
    
8.5、9大内置对象
  • PageContext:保存数据

  • Request :保存数据

  • Response

  • Session:保存数据

  • Application【SerlvetContext】:保存数据

  • config【ServletConfig】

  • out

  • page:几乎不用

  • exception

  • 重点

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

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

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

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

8.6、JSP标签,JSTL标签,EL表达式
<!--JSTL表达式的依赖-->
<dependency>
    <groupId>javax.servlet.jsp.jstl</groupId>
    <artifactId>jstl-api</artifactId>
    <version>1.2</version>
</dependency>

<!-- standard标签库-->
<dependency>
    <groupId>taglibs</groupId>
    <artifactId>standard</artifactId>
    <version>1.1.2</version>
</dependency>
  
1、EL表示式:${}
  • 获取数据
  • 执行运算
  • 获取web开发的常用对象
2、JSP标签
<%--jsp:include:拼接页面,本质还是两个--%>
<jsp:include page="/***.jsp"/>
<h1>网页主体</h1>

<%--jsp:forward:请求转发--%>
<%--http://localhost:8080/jsptag.jsp?name=pqf&age=12--%>
<jsp:forward page="/jsptag2.jsp">
    <jsp:param name="name" value="pqf"/>
    <jsp:param name="age" value="20"/>
</jsp:forward>


<%--jsptag2.jsp页面可取出参数--%>
名字:<%=request.getParameter("name")%>
年龄:<%=request.getParameter("age")%>

3、JSTL表达式

JSTL标签库的使用就是为了弥补HTML标签的不足;

它定义许多标签可以使用,标签的功能和Java代码一样

  • 格式化标签

  • SQL标签

  • XML标签

  • 核心标签(掌握部分)

    • 引入核心标签库

      <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
      
    • 核心标签的描述

  • JSTL标签的使用步骤

    • 引入对应的taglib
    • 使用其中的方法
    • 在Tomcat也需要引入 jstl的包,否则会报错:JSTL解析错误
  • <c:if >标签的使用

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <%--引入JSTL核心标签库:c(核心标签) --%>
    <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
    
    <html>
    <head>
        <title>Title</title>
    </head>
    <body>
    
    <h4>if测试</h4>
    
    <form action="coreif.jsp" method="get">
        <%--
        EL表达式获取表单中的数据
        ${param.参数名}
        --%>
        <input type="text" name="username" value="${param.username}">
        <input type="submit" value="登录">
    </form>
    
    <%--判断如果提交的用户名是管理员,则登录成功--%>
    
    <%--<%
        //request.getParameter("username").equals("admin"):易空指针,应该为"admin".equals()
    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}"/>
    
    </body>
    </html>
    
    
  • <c:when >标签的使用

    <%--定义一个变量score,值为85--%>
    <c:set var="score" value="85"/>
    
    <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>
    
  • <c:when >标签的使用

    <%
    ArrayList<String> people = new ArrayList<>();
    people.add(0,"张三");
    people.add(1,"李四");
    people.add(2,"王五");
    people.add(3,"赵六");
    
    request.setAttribute("list",people);
    %>
    
    <%--
        var:每一次遍历出来的遍历
        items:要遍历的对象
        begin:开始的位置,默认为0
        end:结束的位置,默认为最后一位
        step:步长
        --%>
    <c:forEach var="people" items="${list}">
        <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

ORM:对象关系映射

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

people表

idnameageaddress
1张三18南京
2李四19苏州
3王五20无锡
class People{
    private int id;
    private String name;
    private int age;
    private String address;  
}

class A{
    new People(1,"张三",18,"南京")
}

10、MVC三层架构

10.1、早些年架构

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

servlet–CRUD–>数据库

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

serv1et的代码中:处理请求、响应、视图跳转、处理DBC、处理业务代码、处理逻辑代码

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

10.2、MVC三层架构

  • 什么是MVC: Model(模型)、 view(视图)、 Controller(控制器)

  • Model

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

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

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

    登录—>接收用户的登录请求—>处理用户的请求(获取用户登录的参数,username,password)---->交给业务层处理登录业务(判断用户名密码是否正确:事务)—>Dao层查询用户名和密码是否正确–>数据库

11、Filter过滤器(重点)

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

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

2、Filter开发步骤

  • 导包

  • 编写过滤器:实现Filter接口,重写对应的方法即可

    package com.ping.filter;
    
    import javax.servlet.*;
    import java.io.IOException;
    
    public class CharacterEncodingFilter implements Filter {
    
        @Override
        //初始化:web服务器启动,就可以初始化了,随时等待过滤对象出现
        public void init(FilterConfig filterConfig) throws ServletException {
            System.out.println("CharacterEncodingFilter初始化");
        }
    
    
        @Override
        //Chain:链
        /*
        1.过滤器中的所有代码,在过滤特定请求的时候都会执行
        2.必须要让过滤器继续通行:chain.doFilter(request,response);
        */
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
            request.setCharacterEncoding("utf-8");
            response.setCharacterEncoding("utf-8");
            response.setContentType("text/html;charset=UTF-8");
    
            System.out.println("CharacterEncodingFilter执行前...");
            chain.doFilter(request, response); //让用户的请求继续走,如果不写,程序到这里就被拦截停止
            System.out.println("CharacterEncodingFilter执行后...");
        }
    
    
        @Override
        //销毁:web服务器关闭的时候,过滤器会销毁
        public void destroy() {
            System.out.println("CharacterEncodingFilter销毁");
        }
    }
    
    
  • 在web.xml中配置Filter

    <servlet>
        <servlet-name>ShowServlet</servlet-name>
        <servlet-class>com.ping.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.ping.filter.CharacterEncodingFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>CharacterEncodingFilter</filter-name>
        
        <!--只要是 /servlet/的任何请求,都会经过这个过滤器-->
        
        <url-pattern>/servlet/*</url-pattern>
        <!--<url-pattern>/*</url-pattern>-->
    </filter-mapping>
    
  • 测试

    public class ShowServlet extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            resp.getWriter().write("你好,世界");
        }
    }
    

12、监听器

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

  1. 编写一个监听器统计网站在线人数,实现监听器的接口

    package com.ping.listener;
    
    import javax.servlet.ServletContext;
    import javax.servlet.http.HttpSessionEvent;
    import javax.servlet.http.HttpSessionListener;
    
    //统计网站在线人数:统计session
    public class OnlineCountListener implements HttpSessionListener {
    
        @Override
        //创建session监听
        //一旦创建session就会触发一次这个事件
        public void sessionCreated(HttpSessionEvent se) {
            ServletContext ctx = se.getSession().getServletContext();
    
            System.out.println(se.getSession().getId());
            Integer onlineCount = (Integer) ctx.getAttribute("OnlineCount");
    
            if (onlineCount==null){
                onlineCount = new Integer(1);
            }else{
                int count = onlineCount.intValue();
    
                onlineCount = new Integer(count+1);
            }
    
            ctx.setAttribute("OnlineCount",onlineCount);
        }
    
        @Override
        //销毁session监听
        //一旦销毁session就会触发一次这个事件
        public void sessionDestroyed(HttpSessionEvent se) {
            ServletContext ctx = se.getSession().getServletContext();
            se.getSession().invalidate();
            Integer onlineCount = (Integer) ctx.getAttribute("OnlineCount");
    
            if (onlineCount==null){
                onlineCount = new Integer(0);
            }else{
                int count = onlineCount.intValue();
    
                onlineCount = new Integer(count-1);
            }
    
            ctx.setAttribute("OnlineCount",onlineCount);
        }
    
        /*
        Session销毁
        1.手动销毁:se.getSession().invalidate();
        2.自动销毁
        */
    }
    
  2. web.xml中注册监听器

    <!--注册监听器-->
    <listener>
        <listener-class>com.ping.listener.OnlineCountListener</listener-class>
    </listener>
    
    <!--session自动销毁,单位为分钟-->
    <session-config>
        <session-timeout>1</session-timeout>
    </session-config>
    
  3. index.jsp:获得在线的人数

    <h1>当前有
        <span style="color:red"><%=this.getServletConfig().getServletContext().getAttribute("OnlineCount")%>
        </span> 
    人在线</h1>
    
  4. 测试

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

  1. 监听器在GUI中的应用(在GUI编程中经常使用)

    public class TestPane1 {
        public static void main(String[] args) {
            Frame frame = new Frame("窗口标题"); //新建一个窗体
            Panel panel = new Panel(null); //面板(布局方式:null)
            frame.setLayout(null); //设置窗体的布局
    
            frame.setBounds(300,300,500,500);
            frame.setBackground(new Color(0,0,225)); //设置背景颜色
    
            panel.setBounds(50,50,300,300);
            panel.setBackground(new Color(0,255,0));//设置背景颜色
    
            frame.add(panel);
    
            frame.setVisible(true);
    
            //监听事件:监听关闭事件
            frame.addWindowListener(new WindowListener() {
                @Override
                public void windowOpened(WindowEvent e) {
                    System.out.println("打开");
                }
    
                @Override
                public void windowClosing(WindowEvent e) {
                    System.out.println("关闭ing");
                    System.exit(0); //0:正常终止
                    //System.exit(1); //1:非正常终止
                }
    
                @Override
                public void windowClosed(WindowEvent e) {
                    System.out.println("关闭ed");
                }
    
                @Override
                public void windowIconified(WindowEvent e) {
    
                }
    
                @Override
                public void windowDeiconified(WindowEvent e) {
    
                }
    
                @Override
                public void windowActivated(WindowEvent e) {
                    System.out.println("激活");
                }
    
                @Override
                public void windowDeactivated(WindowEvent e) {
                    System.out.println("未激活");
                }
            });
            
            frame.addWindowListener(new WindowAdapter() {
                @Override
                public void windowClosing(WindowEvent e) {
                   
                }
            });
        }
    }
    
  2. 过滤器的应用(用户登录之后才能进入主页,用户未登录就不能进入主页)

    • 用户登录之后,将用户的数据放入向Sesison中

      public class LoginServlet extends HttpServlet {
          @Override
          protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
              //获取前端请求的参数
              String username = req.getParameter("username");
      
              if (username.equals("admin")) {//登录成功
                  req.getSession().setAttribute(Constant.USER_SESSION,req.getSession().getId());
                  resp.sendRedirect("/sys/success.jsp");
              }else{ //登录失败
                  resp.sendRedirect("/error.jsp");
              }
          }
      
          @Override
          protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
              doGet(req, resp);
          }
      }
      
    • 进入主页的时候要判断用户是否已经登录,在过滤器中实现

      public class SysFilter implements Filter {
          @Override
          public void init(FilterConfig filterConfig) throws ServletException {
          }
      
          @Override
          public void doFilter(ServletRequest ServletRequest, ServletResponse ServletResponse, FilterChain chain) throws IOException, ServletException {
              //ServletRequest 强转为 HttpServletRequest
              HttpServletRequest request = (HttpServletRequest) ServletRequest;
              HttpServletResponse response = (HttpServletResponse) ServletResponse;
      
              if (request.getSession().getAttribute(Constant.USER_SESSION)==null) {
                  response.sendRedirect("/error.jsp");
              }
      
              chain.doFilter(request,response);
          }
      
          @Override
          public void destroy() {
          }
      }
      
    • 配置web.xml

      <servlet>
          <servlet-name>LoginServlet</servlet-name>
          <servlet-class>com.ping.servlet.LoginServlet</servlet-class>
      </servlet>
      <servlet-mapping>
          <servlet-name>LoginServlet</servlet-name>
          <url-pattern>/servlet/login</url-pattern>
      </servlet-mapping>
      
      <filter>
          <filter-name>SysFiler</filter-name>
          <filter-class>com.ping.filter.SysFilter</filter-class>
      </filter>
      <filter-mapping>
          <filter-name>SysFiler</filter-name>
          <url-pattern>/sys/*</url-pattern>
      </filter-mapping>
      
      

14、JDBC

  • JDBC:Java连接数据库

  • 需要的jar包

    • java.sql
    • javax.sql
    • mysql-connetor-java :连接驱动(必须导入)
  • 实验环境搭建

  • 新建数据库

    CREATE TABLE users(
    id INT PRIMARY KEY ,
    `name` VARCHAR(40),
    `password` VARCHAR(60),
    email VARCHAR(60),
    birthday DATE
    );
    
    INSERT INTO users(id,`name`,`password`,email,birthday)
    VALUES(1,'张三','1234','zs@qq.com','2000-11-14');
    INSERT INTO users(id,`name`,`password`,email,birthday)
    VALUES(2,'李四','12345','ls@qq.com','2000-05-1');
    INSERT INTO users(id,`name`,`password`,email,birthday)
    VALUES(3,'王五','123456','ww@qq.com','2000-02-4');
    
    SELECT * FROM users;
    
  • 导入数据库依赖

    <!--mysql的驱动-->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.47</version>
    </dependency>
    
  • IDEA中连接数据库

  • JDBC固定步骤

    1. 加载驱动
    2. 连接数据库,代表数据库
    3. 向数据库发送SQL的对象Statement : CRUD1
    4. 编写SQL(根据业务,不同的SQL)
    5. 执行SQL
    6. 关闭连接
    public class TestJdbc {
        public static void main(String[] args) throws ClassNotFoundException, SQLException {
            //配置信息
            //useUnicode=true&characterEncoding=utf-8 解决中文乱码
            String url = "jdbc:mysql://localhost:3306/jdbc?useUnicode=true&characterEncoding=utf-8&useSSL=false";
            String username = "root";
            String password = "123456";
    
            //1.加载驱动
            Class.forName("com.mysql.jdbc.Driver");
    
            //2.连接数据库,代表数据库
            Connection connection = DriverManager.getConnection(url, username, password);
    
            //3.向数据库发送SQL的对象Statement,PreparedStatement:CRUD
            Statement statement = connection.createStatement();//普通的
            //PreparedStatement pre = connection.prepareStatement(sql); //预编译(安全)
    
            //4.编写SQL
            String sql = "select * from users";
    
            String sqldelete = "delete from users where id = 2";
    
            //受影响的行数,增删改都使用executeUpdate即可
            int i = statement.executeUpdate(sqldelete);
    
            //5.执行查询SQL,返回一个ResultSet(结果集)
            ResultSet rs= statement.executeQuery(sql);
    
    
            while (rs.next()) {
                System.out.println("id="+rs.getObject("id"));
                System.out.println("name="+rs.getObject("name"));
                System.out.println("password="+rs.getObject("password"));
                System.out.println("email="+rs.getObject("email"));
                System.out.println("birthday="+rs.getObject("birthday"));
            }
    
            //6.关闭连接,释放资源(一定要做) 先开后关
            rs.close();
            statement.close();
            connection.close();
    
        }
    }
    
    
  • 预编译SQL

    public class TestJdbc2 {
        public static void main(String[] args) throws Exception {
            //配置信息
            //useUnicode=true&characterEncoding=utf-8 解决中文乱码
            String url = "jdbc:mysql://localhost:3306/jdbc?useUnicode=true&characterEncoding=utf-8&useSSL=false";
            String username = "root";
            String password = "123456";
    
            //1.加载驱动
            Class.forName("com.mysql.jdbc.Driver");
    
            //2.连接数据库,代表数据库
            Connection connection = DriverManager.getConnection(url, username, password);
    
            //3.编写SQL
            String sql = "insert into users(id,name,password,email,birthday) values (?,?,?,?,?)";
    
            //3.预编译:PreparedStatement:CRUD
            PreparedStatement preparedStatement = connection.prepareStatement(sql); //预编译(安全)
    
            preparedStatement.setInt(1,4); //给第一个站位符? 的值赋值为4;
            preparedStatement.setString(2,"小明"); //给第二个站位符? 的值赋值为"小明";
            preparedStatement.setString(3,"12345"); //给第三个站位符? 的值赋值为"12345";
            preparedStatement.setString(4,"123@qq.com"); //给第四个站位符? 的值赋值为"123@qq.com";
            preparedStatement.setDate(5,new Date(new java.util.Date().getTime())); //给第五个站位符? 的值赋值为new Date(new java.util.Date().getTime());
    
            //5.执行SQL
            int i = preparedStatement.executeUpdate();
    
            if (i>0) {
                System.out.println("插入成功");
            }
    
            //6.关闭连接,释放资源(一定要做) 先开后关
            preparedStatement.close();
            connection.close();
    
        }
    
    }
    
  • 事务

    • 特征:要么都成功,要么都失败
    • ACID原则(原子性,一致性,隔离性):保证数据的安全

    1.开启事务

    2.事务提交 commit()

    3.事务回滚 rollback()

    4.关闭事务

    eg:转账

    A:1000

    B:1000

    A(900) --> 100 --> B(1100)

    转账和到账要么同时发生,要么同时不发生,避免系统崩溃导致只转账而没到账

    • JDBC
    public class TestJdbc3 {
        @Test
        public void test() {
            //配置信息
            //useUnicode=true&characterEncoding=utf-8 解决中文乱码
            String url = "jdbc:mysql://localhost:3306/jdbc?useUnicode=true&characterEncoding=utf-8&useSSL=false";
            String username = "root";
            String password = "123456";
    
            Connection connection = null;
            try {
                //1.加载驱动
                Class.forName("com.mysql.jdbc.Driver");
    
                //2.连接数据库,代表数据库
                connection = DriverManager.getConnection(url, username, password);
    
                //3.通知数据库开启事务,false是开启
                connection.setAutoCommit(false);
                String sql = "update  account set money = money-100 where name = 'A'";
                connection.prepareStatement(sql).executeUpdate();
    
                //制造错误
                //int i = 1/0;
    
                String sql2 = "update  account set money = money+100 where name = 'B'";
                connection.prepareStatement(sql2).executeUpdate();
    
                connection.commit(); //以上两条SQL都执行成功了,就提交事务
                System.out.println("success");
            } catch (Exception e) {
                try {
                    //如果出现异常,就通知数据库回滚事务
                    connection.rollback();
                } catch (SQLException exception) {
                    exception.printStackTrace();
                }finally{
                    try {
                        connection.close();
                    } catch (SQLException throwables) {
                        throwables.printStackTrace();
                    }
                }
            }
        }
    }
    
    
  • Junit单元测试

    • 依赖
    <!--单元测试-->
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
    </dependency>
    <!--mysql的驱动-->
    
    • 简单使用

      @Test注解只有在方法上有效,只要加了这个注解的方法,就可以直接运行

    import org.junit.Test;
    public class Test {
        @Test
        public void test(){
            System.out.println("Hello");
        }
    }
    
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Fly-ping

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值