JavaWeb

Java Web

1.基本概念

1.1前言

web开发:

  • web,网页的意思,www.baidu.com
  • 静态Web
    • html,CSS
    • 提供给所有人看的数据始终不会发生变化!
  • 动态Web
    • 淘宝,几乎所有的网站都是动态;
    • 提供给所有人看的数据会发生变化!每个人在不同的时间,不同的点看到的信息各不相同
    • 技术栈:Servlet/JSP,ASP,PHP

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

1.2 Web应用程序

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

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

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

1.3、静态web

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

image

  • 静态web存在的缺点
    • Web页面无法动态更新,所有用户看到都是同一个页面
      • 轮播图,点击特效:伪动态
      • JavaScript【实际开发中,它用的最多】
      • VBScript
    • 它无法和数据库交互(数据无法持久化,用户无法交互)

1.4、动态web

页面会动态展示:“Web得页面展示得效果因人而异”

image

缺点:

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

优点:

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

image

2.web服务器

2.1技术讲解

ASP:

  • 微软:国内最早流行的就是ASP

  • 在HTML中嵌入了VB的脚本,ASP+COM

  • 在ASP开发中,基本一个页面都有几千行的业务代码,页面及其混乱

  • 维护成本高

  • C#

  • IIS

    <h1>
        <h1><h1>
            <h1>
                <h1>
                    <h1>
             <h1>
                 <%
                    System.out.println("hello");
                    %>
                    <h1>
                        <h1>
          <h1><h1>
    <h1>
    

PHP:

  • PHP开发速度很快,功能很强大,跨平台,代码很简单(70%,wp)
  • 无法承载大访问量的情况(局限性)

JSP/Servlet:

  • sun公司主推的B/S架构
  • 基于Java语言(所有的大公司,或者一些开源的组件,都是用Java写的)
  • 可以承载三高问题带来的影响
  • 语法像ASP,ASP–>JSP,加强市场强度
  • ……

2.2web服务器

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

IIS

微软的:ASP……Windows中自带的

Tomcat

image

Tomcat是Apache 软件基金会(Apache Software Foundation)的Jakarta 项目中的一个核心项目,由Apache、Sun 和其他一些公司及个人共同开发而成。由于有了Sun 的参与和支持,最新的Servlet 和JSP 规范总是能在Tomcat 中得到体现,Tomcat 5支持最新的Servlet 2.4 和JSP 2.0 规范。因为Tomcat 技术先进、性能稳定,而且免费,因而深受Java 爱好者的喜爱并得到了部分软件开发商的认可,成为比较流行的Web 应用服务器。
Tomcat 服务器是一个免费的开放源代码的Web 应用服务器,属于轻量级应用服务器,在中小型系统和并发访问用户不是很多的场合下被普遍使用,是开发和调试JSP 程序的首选。对于一个初学者来说,可以这样认为,当在一台机器上配置好Apache 服务器,可利用它响应HTML(标准通用标记语言下的一个应用)页面的访问请求。实际上Tomcat是Apache 服务器的扩展,但运行时它是独立运行的,所以当你运行tomcat 时,它实际上作为一个与Apache 独立的进程单独运行的。
诀窍是,当配置正确时,Apache 为HTML页面服务,而Tomcat 实际上运行JSP 页面和Servlet。另外,Tomcat和IIS等Web服务器一样,具有处理HTML页面的功能,另外它还是一个Servlet和JSP容器,独立的Servlet容器是Tomcat的默认模式。不过,Tomcat处理静态HTML的能力不如Apache服务器。

image

可以配置启动的端口号

  • tomcat的默认端口为8080
<Connector port="8080"protocol="HTTP/1.1"
           connectionTimerout+"20000"
           redirectProt="8443">

可以配置主机的名称

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

高难度面试题:

网站是如何访问的!

  1. 输入一个域名:回车

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

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

      127.0.0.1 localhost
      
    2. 没有:取DNS服务器找,找到得话就返回,找不到就返回找不到

    image

Tomcat发布网站

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

image-20220306153632563

image

image

网站应该有的结构

--webapps:Tomcat服务器的web目录
	-ROOT
	-test:网站的目录名
		—WEB—INF
			-Classes:java程序
			-lib:web应用程序依赖的jar包
			-web.xml:网站的配置文件
		-index.html 默认的首页
·		-static
			-CSS
				-style.css
			-js
			-img
		  - ……
  • tomcat10 在项目导入Servlet中的配置文件因为写为

        <dependency>
          <groupId>jakarta.servlet.jsp</groupId>
          <artifactId>jakarta.servlet.jsp-api</artifactId>
          <version>3.0.0</version>
          <scope>provided</scope>
        </dependency>
        <dependency>
          <groupId>jakarta.servlet</groupId>
          <artifactId>jakarta.servlet-api</artifactId>
          <version>5.0.0</version>
          <scope>provided</scope>
        </dependency>
    

3.HTTP

3.1什么是HTTP

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

​ 万维网WWW(World Wide Web)发源于欧洲日内瓦量子物理实验室CERN,正是WWW技术的出现使得因特网得以超乎想象的速度迅猛发展。这项基于TCP/IP的技术在短短的十年时间内迅速成为已经发展了几十年的Internet上的规模最大的信息系统,它的成功归结于它的简单、实用。在WWW的背后有一系列的协议和标准支持它完成如此宏大的工作,这就是Web协议族,其中就包括HTTP超文本传输协议。
​ 在1990年,HTTP就成为WWW的支撑协议。当时由其创始人WWW之父蒂姆·伯纳斯·李(Tim Berners-Lee)提出,随后WWW联盟(WWW Consortium)成立,组织了IETF(Internet Engineering Task Force)小组进一步完善和发布HTTP。
HTTP是应用层协议,同其他应用层协议一样,是为了实现某一类具体应用的协议,并由某一运行在用户空间的应用程序来实现其功能。HTTP是一种协议规范,这种规范记录在文档上,为真正通过HTTP进行通信的HTTP的实现程序。
​ HTTP是基于B/S架构进行通信的,而HTTP的服务器端实现程序有httpd、nginx等,其客户端的实现程序主要是Web浏览器,例如Firefox、Internet Explorer、Google Chrome、Safari、Opera等,此外,客户端的命令行工具还有elink、curl等。Web服务是基于TCP的,因此为了能够随时响应客户端的请求,Web服务器需要监听在80/TCP端口。这样客户端浏览器和Web服务器之间就可以通过HTTP进行通信了。

  • HTTP(超文本传输协议)是一个简单的请求-响应协议,它通常运行在TCP之上
    • 文本:html,字符串,……
    • 超文本:图片,音乐,视频,定位,地图……
    • 80
  • HTTPS:安全的
    • 443

3.2 两个时代

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

3.3 HTTP请求

* 客户端-发请求(Request)-服务器

Bing:

Request URL: https://cn.bing.com/fd/ls/lsp.aspx		//请求地址
Request Method: POST								//post方法
Status Code: 204 									//状态码
Remote Address: 202.89.233.100:443					//远程地址
Accept:text/html
Accept-Encoding:gzip,deflate,br
Accept-Language:zh-CN,zh;q=0   //语言
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:主机……/.

3.4 HTTP响应

  • 服务器-响应-客户端

Bing:

cache-control: private		//缓存控制
connection:keep-Alive		//连接
content-Encoding:gzip		//编码类型
content-type: text/css		//类型

1.响应体

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

2.响应状态栏

200:请求响应成功

3XX:请求重定向

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

4XX:找不到资源

  • 资源不存在

5XX:服务器代码错误 500 502网关错误

常见面试题:

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

作为客户端,浏览器接收到地址之后,首先会到windows系统文件hosts中查找是否有需要劫持的ip地址,若没有则需要询问DNS域名解析服务器该域名对应的ip地址。(DNS缓存)
浏览器缓存,系统缓存,路由器缓存,IPS服务器缓存,根域名服务器缓存,顶级域名服务器缓存,主域名服务器缓存

获取到正确的ip地址后,客户端会与服务器建立TCP连接(三次握手),(网络层、数据链路层、物理层)

客户端向服务端发送请求,包含请求行、请求头、请求正文。多种请求方式(GET,POST、PUT等)

服务端处理请求,并返回响应,包含状态码、响应头、响应体

浏览器收到响应,解析渲染页面,展示出来

断开连接(http1.0短连接,http1.1长连接)

4.Maven

我们为什么要学习这个技术

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

  2. 如何能够让一个东西自动帮我们导入和配置这个jar包。

    由此,Maven诞生了!

4.1Maven项目架构管理工具

我们目前用来就是方便导入jar包的!

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

  • 有约束,不要去违反

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

4.2下载和安装Maven

下载地址:https://maven.apache.org/download.cgi

下载解压后,放入自己特定的目录

4.3配置系统环境变量

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

image

image

成功:

image

4.4 阿里云镜像

  • 镜像:mirrors
    • 作用:加速我们的下载
  • 国内建议使用阿里云的镜像
<mirror>
	 <id>nexus-aliyun</id>
	 <mirrorOf>*</mirrorOf>
	 <name>Nexus aliyun</name>
	 <url>http://maven.aliyun.com/nexus/content/groups/public</url>
</mirror>

image

4.5 本地仓库

在本地的仓库。远程仓库

建立一个本地仓库:localRepository

image

image

4.6再IDEA中使用Maven

  1. 启动IDEA

  2. 创建一个Maven项目(模板webapps)

    image

  3. 观察仓库

    image

  4. IDEA中的Maven设置

    IDEA项目创建成功后,看一眼Maven配置

    image

    注意:经常再IDEA中会出现一个问题,就是项目自动创建完成后,它这个MavebHome会使用IDEA默认,我们如果发现了这个问题,手动改为本地的

    image

4.7 创建一个普通的Maven项目

  • 启动IDEA

  • 创建Maven项目(默认)

  • 观察项目结构

    image

<?xml version="1.0" encoding="UTF-8"?>
<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>

    <groupId>org.example</groupId>
    <artifactId>JavaWeb-Maven02</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
    </properties>

</project>

image

4.8 在IDEA中标记资源目录

image

或者:

image

4.9 IDEA中配置tomcat

image

image

4.10 pom文件

pom.xml事Maven的核心配置文件

image

<?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>org.example</groupId>
  <artifactId>JavaWeb-Maven01</artifactId>
  <version>1.0-SNAPSHOT</version>
<!--  Package:项目的打包方式
      jar:java应用
      war:Java web应用
      -->
  <packaging>war</packaging>

  <name>JavaWeb-Maven01 Maven Webapp</name>
  <!-- FIXME change it to the project's website -->
  <url>http://www.example.com</url>

<!--  配置-->
  <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-Maven01</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>

新的干净项目配置

<?xml version="1.0" encoding="UTF-8"?>
<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>

    <groupId>org.example</groupId>
    <artifactId>JavaWeb-Maven02</artifactId>
    <version>1.0-SNAPSHOT</version>
    <!--项目依赖-->
    <dependencies>
        <!--    具体依赖的的jar包配置文件-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
            <scope>test</scope>
        </dependency>
<!--        Maven的高级之处,它会帮你导入这个jar包所依赖的jar包-->
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-web -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.1.9.RELEASE</version>
        </dependency>
    </dependencies>
</project>

image

maven由于他的约定大于配置,我们之后可以能遇到我们写的配置文件,无法被导出或者生效的问题

4.11 IDEA操作

当前项目的Maven的结构体系 (IDEA侧边栏Maven-显示依赖项)

image

4.12 Maven仓库的使用

地址:https://mvnrepository.com/

下载:需要使用的jar包

image

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

导入到配置

image

4.13 测试

写一个HelloServlet类

package com.webapps;

import jakarta.servlet.http.HttpServlet;

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

public class HelloServlet extends HttpServlet {
    @Override
    protected void doGet(jakarta.servlet.http.HttpServletRequest req, jakarta.servlet.http.HttpServletResponse resp) throws jakarta.servlet.ServletException, IOException {
        resp.setContentType("text/html");
        resp.setCharacterEncoding("utf-8");
        PrintWriter out = resp.getWriter();
        out.println("<html>");
        out.println("<head>");
        out.println("<title>Hello World!</title>");
        out.println("</head>");
        out.println("<body>");
        out.println("<h1>Hello World!</h1>");
        out.println("</body>");
        out.println("</html>");
    }

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

web.xml中写入映射

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <display-name>Archetype Created Web Application</display-name>
<!--  web.xml中是配置我们web的核心应用-->
<!--  注册Servlet-->
  <servlet>
    <servlet-name>Hello Servlet</servlet-name>
    <servlet-class>com.webapps.HelloServlet</servlet-class>
  </servlet>
<!--  一个servlet对应一个Mopping:映射-->
  <servlet-mapping>
    <servlet-name>Hello Servlet</servlet-name>
<!--    请求路径-->
    <url-pattern>/xiang</url-pattern>
  </servlet-mapping>
</web-app>

webapps中写入hader.html文件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>我是导航栏</h1>
</body>
</html>

image

5.Servlet

5.1 Servlet简介

  • Servlet就是sun公司开发动态web的一名技术
  • Java Servlet 是运行在 Web 服务器或应用服务器上的程序,它是作为来自 Web 浏览器或其他 HTTP 客户端的请求和 HTTP 服务器上的数据库或应用程序之间的中间层。
  • sun公司在它的API中提供了一个接口叫做:Servlet,如果你想开发一个Servlet程序,只需要完成两个小步骤:
    • 编写一个类,实现Servlet接口
    • 把开发好的Java类部署到web服务器中

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

image

5.2 Hello_Servlet

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

  1. 创建一个普通的Maven项目,删除掉src ,以后我们的学习就在这个项目里面建立Moude;这个空的工程就是Maven的主工程

  2. 添加所需要用的Maven依赖

    <dependencies>
        <!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
        <dependency>
          <groupId>javax.servlet</groupId>
          <artifactId>javax.servlet-api</artifactId>
          <version>4.0.1</version>
          <scope>provided</scope>
        </dependency>
        <!-- https://mvnrepository.com/artifact/javax.servlet.jsp/javax.servlet.jsp-api -->
        <dependency>
          <groupId>javax.servlet.jsp</groupId>
          <artifactId>javax.servlet.jsp-api</artifactId>
          <version>2.3.3</version>
          <scope>provided</scope>
        </dependency>
      </dependencies>
    
  3. 关于Maven父子工程的理解:

    父项目中会有:

    <modules>
    	</modules>servlet-01<modules>
    </modules>
    

    子项目会有:

    <parent>
        <artifactID>javaweb-02-servlet</artifactID>
        <groupId>com.xxxx</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    

    父项目中的java子项目可以直接使用

    son extends father
    
  4. Maven环境优化

    1. 修改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">
      
      </web-app>
      
    2. 将maven的结构搭建完整

      image
      image

  5. 编写一个Servlet程序

    1. 编写一个普通类
    2. 实现Servlet接口,这里我们直接继承HttpServlet
      • 如果出现问题的话使用tomcat10的依赖
    package com.xiang;
    
    import jakarta.servlet.ServletException;
    import jakarta.servlet.ServletOutputStream;
    import jakarta.servlet.http.HttpServlet;
    import jakarta.servlet.http.HttpServletRequest;
    import jakarta.servlet.http.HttpServletResponse;
    
    import java.io.IOException;
    import java.io.PrintWriter;
    
    public class HelloServlet extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    //        ServletOutputStream outputStream = resp.getOutputStream();
            PrintWriter writer = resp.getWriter();
            writer.println("HelloServlet");
        }
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            doGet(req,resp);
        }
    }
    
  6. 编写Servlet的web.xml映射

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

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
                      http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <servlet>
        <servlet-name>helloServlet</servlet-name>
        <servlet-class>com.xiang.HelloServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>helloServlet</servlet-name>
        <url-pattern>hello</url-pattern>
    </servlet-mapping>
</web-app>
  1. 配置Tomcat
  2. 运行

5.3 原理

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

image

5.4 Mapping

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

    <!--  一个servlet对应一个Mopping:映射-->
      <servlet-mapping>
        <servlet-name>HelloServlet</servlet-name>
    <!--    请求路径-->
        <url-pattern>/xiang</url-pattern>
      </servlet-mapping>
    
  2. 一个Servlet可以指定多个映射路径

    <!--  一个servlet对应一个Mopping:映射-->
      <servlet-mapping>
        <servlet-name>HelloServlet</servlet-name>
    <!--    请求路径-->
        <url-pattern>/xiang</url-pattern>
      </servlet-mapping>
    <!--  一个servlet对应一个Mopping:映射-->
      <servlet-mapping>
        <servlet-name>HelloServlet</servlet-name>
    <!--    请求路径-->
        <url-pattern>/xiang1</url-pattern>
      </servlet-mapping>
    
  3. 一个Servlet可以通用路径

    <!--  一个servlet对应一个Mopping:映射-->
      <servlet-mapping>
        <servlet-name>HelloServlet</servlet-name>
    <!--    请求路径-->
        <url-pattern>/xiang/*</url-pattern>
      </servlet-mapping>
    
  4. 默认请求路径

    <!--  一个servlet对应一个Mopping:映射-->
      <servlet-mapping>
        <servlet-name>HelloServlet</servlet-name>
    <!--    请求路径-->
        <url-pattern>/*</url-pattern>
      </servlet-mapping>
    

    例如:404

    <?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">
    
    
      <display-name>Archetype Created Web Application</display-name>
    <!--  web.xml中是配置我们web的核心应用-->
    <!--  注册Servlet-->
      <servlet>
        <servlet-name>HelloServlet</servlet-name>
        <servlet-class>com.webapps.HelloServlet</servlet-class>
      </servlet>
    <!--  一个servlet对应一个Mopping:映射-->
      <servlet-mapping>
        <servlet-name>HelloServlet</servlet-name>
    <!--    请求路径-->
        <url-pattern>/xiang</url-pattern>
      </servlet-mapping>
    
  5. 指定一些后缀或者前缀等等……

    <!--  一个servlet对应一个Mopping:映射-->
    <!-- 注意*前面不能加‘/’-->
      <servlet-mapping>
        <servlet-name>HelloServlet</servlet-name>
    <!--    请求路径-->
        <url-pattern>*.xiang</url-pattern>
      </servlet-mapping>	
    

5.5 ServletContext

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

1.共享数据

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

//        this.getInitParameter();
        //初始化参数
//        this.getServletConfig();
        //Servlet配置
//        this.getServletContext();
        //Servlet上下文
        ServletContext servletContext = this.getServletContext();
        //数据
        String username = "xaing";
        //将一个数据保存在ServletContext中,名字为:username,值:username
        servletContext.setAttribute("username",username);


        System.out.println("hello world");
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    ServletContext servletContext = this.getServletContext();
    String username =(String) ((ServletContext) servletContext).getAttribute("username");
    resp.setContentType("text/html");
    resp.setCharacterEncoding("utf-8");

    resp.getWriter().print("名字:"+username);
}
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
                      http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
  <servlet>
    <servlet-name>hello</servlet-name>
    <servlet-class>com.xiang.HelloServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>hello</servlet-name>
    <url-pattern>/hello</url-pattern>
  </servlet-mapping>
<servlet>
  <servlet-name>get</servlet-name>
  <servlet-class>com.xiang.GetServlet</servlet-class>
</servlet>
  <servlet-mapping>
    <servlet-name>get</servlet-name>
    <url-pattern>/get</url-pattern>
  </servlet-mapping>
</web-app>

测试结果:

image

2.获取初始化参数

<!--配置一些web应用初始化参数-->
  <context-param>
    <param-name>url</param-name>
    <param-value>jdbc:mysql://localhost:3306/temp</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);
}

image

3.请求转发

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

image

image

4.读取资源文件

写一个Properties资源文件

username = root
passwrod = 123456

JavaSE读取方法

private  static  String username = null;
private  static  String password = null; 
InputStream input =JdbcUtils.class.getClassLoader().getResourceAsStream("db.properties");
Properties properties = new Properties();
properties.load(input);
 username=properties.getProperty("username");
password=properties.getProperty("password");

JavaWeb读取方法

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    resp.setContentType("text/html");
    resp.setCharacterEncoding("utf-8");
    InputStream resourceAsStream = this.getServletContext().getResourceAsStream("/WEB-INF/classes/db.properties");//路径具体看自己的target目录
    Properties properties = new Properties();
    properties.load(resourceAsStream);
    String username = properties.getProperty("username");
    String password = properties.getProperty("password");
    resp.getWriter().print("用户名:"+username);
    resp.getWriter().print("<br>");
    resp.getWriter().print("密码:"+password);
}

image

5.6 HttpServletResponse

web服务器接收到客户端的http请求,针对这个请求,分别创建一个代表请求的HttoServletrquest对象,代表响应的一个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 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. 将FileOutputSream流写入到buffer缓冲区
    8. 使用OutputStream将缓冲区中的数据输出到客户端

    下载案例

    package com.servlet;
    
    import jakarta.servlet.ServletException;
    import jakarta.servlet.ServletOutputStream;
    import jakarta.servlet.http.HttpServlet;
    import jakarta.servlet.http.HttpServletRequest;
    import jakarta.servlet.http.HttpServletResponse;
    import java.io.FileInputStream;
    import java.io.IOException;
    import java.io.PrintWriter;
    
    public class FileServlet extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            // 1. 要获取下载文件的路径
            String realPath = this.getServletContext().getRealPath("/WEB-INF/classes/img.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[] buffer = new byte[1024];
            // 6. 获取OutputStream对象
            ServletOutputStream out = resp.getOutputStream();
            // 7. 将FileOutputSream流写入到buffer缓冲区, 使用OutputStream将缓冲区中的数据输出到客户端
            while((len=in.read(buffer))>0){
                out.write(buffer,0,len);
            }
            in.close();
            out.close();
        }
        @Override
        protected long getLastModified(HttpServletRequest req) {
            return super.getLastModified(req);
        }
    }
    

3.验证码功能

验证怎么来的?

  • 前端实现

  • 后段实现,需要用到java的图片类,生产一个图片

    package com.servlet;
    import jakarta.servlet.ServletException;
    import jakarta.servlet.http.HttpServlet;
    import jakarta.servlet.http.HttpServletRequest;
    import jakarta.servlet.http.HttpServletResponse;
    
    import javax.imageio.ImageIO;
    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 {
            //如何让浏览器5秒自动刷新一次;
            resp.setHeader("refresh","3");
            //在内存中创建一个图片
            BufferedImage bufferedImage = new BufferedImage(80,20,BufferedImage.TYPE_INT_RGB);
            //得到图片
            Graphics2D graphics = (Graphics2D) bufferedImage.getGraphics();//笔
            //设置图片的背景颜色
            graphics.setColor(Color.white);
            graphics.fillRect(0,0,80,20);
            //给图片写数据
            graphics.setColor(Color.BLUE);
            graphics.setFont(new Font(null,Font.BOLD,20));
            graphics.drawString(makeNum(),0,20);
    
            //告诉浏览器,这个请求用图片的方式打开
            resp.setContentType("image/jpeg");
            //网站存在缓存,不让浏览器缓存
            resp.setDateHeader("expires",-1);
            resp.setHeader("Cache-Control","no-cache");
            resp.setHeader("Pragma","no-cache");
    
            //把图片写给浏览器
            ImageIO.write(bufferedImage,"jpg",resp.getOutputStream());
        }
        //生产随机数
        private String makeNum(){
            Random random = new Random();
            String num = random.nextInt(99999999) + "";
            StringBuffer stringBuffer = new StringBuffer();
            for (int i = 0; i < 7-num.length(); i++) {
                stringBuffer.append("0");
            }
            num=stringBuffer.toString() +num;
            return num;
        }
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            super.doPost(req, resp);
        }
    }
    

4.实现重定向

image

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

常见场景:

  • 用户登陆
void sendRedired(String var1)throws IOException

测试:

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    /**
     * resp.setHeader("Location","/webServlet01_war/Img");
     * resp.setStatus(302);
     * */
    resp.sendRedirect("/webServlet01_war/Img");
}

面实体:请你聊聊重定向和转发的区别

相同点:

  • 页面都会实现跳转

不同点

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

5.7 HttpServletRequest

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

1.获取前端传递的参数

req.getParameter();
req.getParameterValues()

2.请求转发

LoginServlet.java:

package com.servlet;

import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

import java.io.IOException;
import java.util.Arrays;

public class LoginServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        String[] hobbies = req.getParameterValues("hobbies");
        System.out.println("==========================");
        System.out.println(username);
        System.out.println(password);
        System.out.println(Arrays.toString(hobbies));
        System.out.println("==========================");
        //通过请求转发
        req.getRequestDispatcher("/success.jsp").forward(req,resp);
        resp.setCharacterEncoding("utf-8");
    }

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

index.jsp:

<%--
  Created by IntelliJ IDEA.
  User: xiangsir
  Date: 2022/5/11
  Time: 下午4:34
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>登陆</title>
</head>
<body>
<%@page pageEncoding="UTF-8" %>
<h1 style="text-align: center">登陆</h1>
    <div style="text-align: center">
<%--        表单已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="hobbies" value="女孩">女孩
            <input type="checkbox"  name="hobbies" value="唱歌">唱歌
            <input type="checkbox"  name="hobbies" value="代码">代码
            <input type="checkbox"  name="hobbies" value="电影">电影
            <br>

            <input type="submit" value="登陆">
        </form>
    </div>
</body>
</html>

success.jsp

<%--
  Created by IntelliJ IDEA.
  User: xiangsir
  Date: 2022/5/11
  Time: 下午5:09
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<h1>登陆成功</h1>
</body>
</html>

6. Cookie、Session

6.1 会话

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

有状态会话

一个网站,证明证明你来过?

客户端 服务端

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

6.2 保存会话的两种技术

cookie

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

session

  • 服务器技术,利用这个技术,可以保存用户的会话信息?我们可以把信息或者数据放在Session中!
  1. 从请求中拿到cookie信息
  2. 服务器响应给客户端cookie
Cookie[] cookies = req.getCookies();//获得cookie
cookie.getName();//获得Cookie的key
cookie.getValue();//获得Cookie的Value
new Cookie("lastLoginTime", String.valueOf(System.currentTimeMillis()));//新建一个cookie
cookie.setMaxAge(24*60*60); //设置cookie有效期为一天
resp.addCookie(cookie);//响应设置的cookie到浏览器

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

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

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

删除Cookie

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

传递中文cookie

//编码
Cookie cookie = new Cookie("name",URLEncoder.encoded("测试","utf-8"));
//解码
out.write(URLDecoder.decode(cookie.getValue,"UTF-8"));

测试:

package com.servlet;

import jakarta.servlet.ServletException;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.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 {
        //服务器告诉你,你来的时间把这个时间封装成一个信件,你下带来,我就知道你来了

        //解决中文乱码
        resp.setContentType("text/html;charset=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];
                //获取cookie的名字
               if(cookie.getName().equals("lastLoginTime")){
                   long lastLoginTime = Long.parseLong(cookie.getValue());
                   Date date = new Date(lastLoginTime);
                   out.write(date.toLocaleString());
               }
            }
        }else {
            out.write("这是你第一次访问本站");
        }

        //服务器给客户端响应一个cookie
        Cookie cookie = new Cookie("lastLoginTime", String.valueOf(System.currentTimeMillis()));
        //设置cookie有效期为一天
        cookie.setMaxAge(24*60*60);
        resp.addCookie(cookie);
    };

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

image

6.4 Session(重点)

什么是Session:

  • 服务器会给每个用户(浏览器)创建一个Session对象
  • 一个Session独占一个浏览器,只要浏览器没有关闭,这个Session就存在
  • 用户登录之后,整个网站它都没有访问–>保存用户的信息

Session和Cookie的区别:

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

使用场景

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

常用方法

方法名 功能描述
getId() 获取SessionID
isNew() Session是否是新的(如果客户端请求消息中返回了一个与Servlet程序当前获得的HttpSession对象的会话标识号相同,则认为这个HttpSession对象不是新建的)
setMaxInactiveInterval() 设置Session的最大时效
getMaxInactiveInterval() 获取Session的最大时效
getCreationTime() 获取Session的创建时间
getLastAccessedTime() 获取Session的最后访问时间
invalidate() 销毁Session对象
setAttribute() 设置数据,将数据保存在Session这个域对象中
getAttribute() 获取数据,将保存在Session这个域对象中的数据获取出来

使用

  1. 创建测试类Person
package com.Pojo;

public class Person {
    private String name;
    private int age;

    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 "Pojo.Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
  1. 创建测试Session类
package com.servlet;
import com.Pojo.*;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;

import java.io.IOException;

public class SessionDemo01 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //解决乱码问题
        resp.setContentType("text/html;charset=UTF-8");
        resp.setCharacterEncoding("utf-8");

        //得到Session
        HttpSession session = req.getSession();
        //给Seesion中存东西
        session.setAttribute("name", new Person("测试",1));
        //获取Session的ID
        String sessionId = session.getId();

        //判断Session是不是新创建的
        if (session.isNew()) {
            resp.getWriter().write("session创建成功:"+sessionId);
        }else {

            resp.getWriter().write("session已创建的ID:"+sessionId);
        }
        Person person= (Person) session.getAttribute("name");

        resp.getWriter().write("</br>");
        resp.getWriter().write(String.valueOf(person));
    }

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

image

  1. 新页面引用Session类
package com.servlet;

import com.Pojo.Person;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;

import java.io.IOException;

public class SessionDemo02 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //解决乱码问题
        resp.setContentType("text/html;charset=UTF-8");
        resp.setCharacterEncoding("utf-8");

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

        Person person = (Person) session.getAttribute("name");

        System.out.println(person);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req,resp);
    }
}
  1. 注销Session年

    1. 手动注销
    package com.servlet;
    
    import jakarta.servlet.ServletException;
    import jakarta.servlet.http.HttpServlet;
    import jakarta.servlet.http.HttpServletRequest;
    import jakarta.servlet.http.HttpServletResponse;
    import jakarta.servlet.http.HttpSession;
    
    import java.io.IOException;
    
    public class SessionDemo03 extends HttpServlet{
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            HttpSession session = req.getSession();
            session.removeAttribute("name");
            //手动注销
            session.invalidate();
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            doGet(req, resp);
        }
    }
    
    1. 自动注销

    web.xml中写入

    <!--    设置session默认的失效时间-->
        <session-config>
    <!--        十五分钟自动注销-->
            <session-timeout>15</session-timeout>
        </session-config>
    

7.JSP

7.1 什么是JSP

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

最大的特点:

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

7.2 JSP原理

思路:JSP到度怎么执行

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

img

7.3 JSP基础语法

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

JSP表达式

<%--  JSP表达式
作用:用来将程序的输出,输出到客户端
<%= 变量或者表达式%>
--%>
  <%= new java.util.Date()%>

JSP脚本片段

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

JSP声明

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

<%!
static {
  System.out.println("Loading Servlet!");
}
private int glovalVar = 0;
public  void  test(){
  System.out.println("进入年方法test()");
}
<%%>嵌入代码
<%=%>表达式输出值
<%!%>全局
<%--注释--%>(JSP的注释客户端不会显示,HTML注释会显示在客户端)

测试:(功能:不同时间段提示不同文字)

<%@ page import="java.util.*" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<%
    Date date = new Date();
    int hour = date.getHours();
    if(hour>=0&&hour<4)
    {
        out.println("夜深了,注意休息啊!");
    }
    else if(hour>=4&&hour<7)
    {
        out.println("清晨好,您可真早呀!熬夜可要注意身体……");
    }
    else if(hour>=7&&hour<11)
    {
        out.println("上午好,相信今天肯定有收获!");
    }
    else if(hour>=11&&hour<14)
    {
        out.println("中午好,适当休息很有必要哦!");
    }
    else if(hour>=14&&hour<18)
    {
        out.println("下午好,困了就喝杯咖啡休息一下吧!");
    }
    else if(hour>=18&&hour<23)
    {
        out.println("晚上好,您真是分秒必争呀!");
    }
%>
</body>
</html>

7.4 JSP指令

指令 描述
<%@ page … %> 定义网页依赖属性,比如脚本语言,error页面、缓存需求等等
<%@ include … %> 包含其他文件
<%@ taglib … %> 引入标签库的定义

page指令

属性名称 取值 or 范围 描述
pageEncoding 当前页面 指定页面的编码格式
contentType 有效的文档类型 客户端浏览器根据该属性判断文档类型,例如: HTML格式为 text/html 纯文本格式为 text/plain JPG图像为 image/jpeg GIF图像为 image/gif Word文档为 application/msword
buffer 8kb jsp缓存大小
autoFlush true / false 是否自动刷新
errorPage 某个JSP页面的相对路径 指定一个错误页面,如果该JSP程序抛出一个未捕捉的异常,则转到errorPage指定的页面。eooroPage指定页面的isErrorPage属性为true,且内置的exception对象为未捕捉的异常。
isErrorPage true / false 指定该页面是否为错误处理页面,如果为true,则该JSP内置有一个Exception对象的exception,可直接使用。默认情况下,isErrorPage的值为false
import 任何包名、类名 指定在JSP页面翻译成的Servlet源文件中导入的包或类。import是唯一可以声明多次的page指令属性。一个import属性可以引用多个类,中间用英文逗号隔开
language java 指明解释该JSP文件时采用的语言,默认为Java
session true / false 指明该JSP内是否内置Session对象,如果为true,则说明内置Session对象,可以直接使用,否则没有内置Session对象。默认情况下,sessiion属性为true。需要注意的是,JSP引擎自动导入以下4个包: java.lang.* javax.servlet.* javax.servlet.jsp.* javax.servlet.http.*

include指令

include指令的具体语法格式如下所示:

  • 静态包含(jsp include指令)
<%@ include file="被包含的文件相对url地址" %>

  • 动态包含(jsp include动作)
<jsp:include page="被包含的文件相对url地址" flush="true/false" %>

区别:

  • 静态包含,两个jsp文件会编译成一个java文件,两个jsp文件中可以共享同一个变量,但不能定义重名变量。
  • 动态包含,两个jsp文件会生成两个java文件,两个jsp文件中不可以共享同一个变量,可以定义重名的变量。

指定错误界面

  1. 编写错误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;
    out.write(x/0);
%>
</body>
</html>
  1. 编写500.jsp文件
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page isErrorPage="true" %>
<html>
<head>
    <title>自定义500错误</title>
</head>
<body>
<img src="${pageContext.request.contextPath}/img/img.png" alt="500">
</body>
</html>

另外可以通过web.xml文件实现

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd"
         version="5.0">
    <error-page>
        <error-code>404</error-code>
        <location>/error/404.jsp</location>
    </error-page>
    <error-page>
        <error-code>500</error-code>
        <location>/error/500.jsp</location>
    </error-page>
</web-app>

7. 5 九大内置对象

对 象 类型 说 明
request javax.servlet.http.HttpServletRequest 获取用户请求信息
response javax.servlet.http.HttpServletResponse 响应客户端请求,并将处理信息返回到客户端
out javax.servlet.jsp.JspWriter 输出内容到 HTML 中
session javax.servlet.http.HttpSession 用来保存用户信息
application javax.servlet.ServletContext 所有用户共享信息【ServletContext】
config javax.servlet.ServletConfig 这是一个 Servlet 配置对象,用于 Servlet 和页面的初始化参数【ServletConfig】
pageContext javax.servlet.jsp.PageContext JSP 的页面容器,用于访问 page、request、application 和 session 的属性
page javax.servlet.jsp.HttpJspPage 类似于 Java 类的 this 关键字,表示当前 JSP 页面
exception java.lang.Throwable 该对象用于处理 JSP 文件执行时发生的错误和异常;只有在 JSP 页面的 page 指令中指定 isErrorPage 的取值 true 时,才可以在本页面使用 exception 对象。

pageContext读取

image

<%--
  Created by IntelliJ IDEA.
  User: xiangsir
  Date: 2022/5/13
  Time: 下午2:25
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<%--    内置对象--%>
<%
    pageContext.setAttribute("name1","1号");//保存的数据只有在一个页面中有效
    request.setAttribute("name2","2号");//保存的数据只有在一次请求中有效,请求转发会有效
    session.setAttribute("name3","3号");//保存的数据只在一次会话中有效,从打开到浏览器关闭
    application.setAttribute("name4","4号");//保存的数据只在服务器中有效,从哦i打开服务器到关闭服务器
%>
<%--脚本片段中的代码,会被原封不动的生成到.jsp.ava--%>
<%
    //从 pageContext取出,我们通过寻找的方式来
    String name1 = (String) pageContext.findAttribute("name1");
    String name2 = (String) pageContext.findAttribute("name2");
    String name3 = (String) pageContext.findAttribute("name3");
    String name4 = (String) pageContext.findAttribute("name4");
%>

<%--使用EL表达式输出${}--%>
<h1>取出的值为</h1>
<h3>${name1}</h3>
<h3>${name2}</h3>
<h3>${name3}</h3>
<h3>${name4}</h3>

</body>
</html>

由此知道:

pageContext.setAttribute(“name1″,”1号”);//保存的数据只有在一个页面中有效(可以采用请求转发有效)
request.setAttribute(“name2″,”2号”);//保存的数据只有在一次请求中有效,请求转发会有效
session.setAttribute(“name3″,”3号”);//保存的数据只在一次会话中有效,从打开到浏览器关闭
application.setAttribute(“name4″,”4号”);//保存的数据只在服务器中有效,从哦i打开服务器到关闭服务器

双亲委派机制*

了解双亲委派,需要先了解下JAVA的类加载器ClassLoader,java的类加载器主要有以下几种

img

什么是类加载器?

类加载器是jre的一部分,负责动态将类添加到Java虚拟机。

类加载分类

1、启动类加载器 bootstrap classloader :加载jre/lib/rt.jar

2、扩展类加载器 extension classloader :加载jre/lib/ext/*.jar

3、应用程序类加载器 application classloader:加载classpath上指定的类库

双亲委派机制双亲委派机制是指当一个类加载器收到一个类加载请求时,该类加载器首先会把请求委派给父类加载器。每个类加载器都是如此。

​ 当一个Hello.class这样的文件要被加载时。不考虑我们自定义类加载器,首先会在AppClassLoader中检查是否加载过,如果有那就无需再加载了。如果没有,那么会拿到父加载器,然后调用父加载器的loadClass方法。父类中同理会先检查自己是否已经加载过,如果没有再往上。注意这个过程,直到到达Bootstrap classLoader之前,都是没有哪个加载器自己选择加载的。如果父加载器无法加载,会下沉到子加载器去加载,一直到最底层,如果没有任何加载器能加载,就会抛出ClassNotFoundException。

7.6 JSP标签、JSTL标签、EL表达式

1 EL表达式:

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

2 jsp标签

<%--jsp:include--%>
<%--<jsp:forward page="Error.jsp">--%>
<%--    <jsp:param name="value1" value="value1"/>--%>
<%--    <jsp:param name="value2" value="value2"/>--%>
<%--</jsp:forward>--%>

3 JSTL(JSP标准标签库)

首先使用Maven导入包(Tomcat10)

<dependency>
    <groupId>org.glassfish.web</groupId>
    <artifactId>jakarta.servlet.jsp.jstl</artifactId>
    <version>2.0.0</version>
</dependency>
<dependency>
    <groupId>org.apache.taglibs</groupId>
    <artifactId>taglibs-standard-spec</artifactId>
    <version>1.2.5</version>
</dependency>
<dependency>
    <groupId>org.apache.taglibs</groupId>
    <artifactId>taglibs-standard-impl</artifactId>
    <version>1.2.5</version>
</dependency>

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

核心标签

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
标签 描述
<c:out> 用于在JSP中显示数据,就像<%= … >
<c:set> 用于保存数据
<c:remove> 用于删除数据
<c:catch> 用来处理产生错误的异常状况,并且将错误信息储存起来
<c:if> 与我们在一般程序中用的if一样
<c:choose> 本身只当做<c:when>和<c:otherwise>的父标签
<c:when> <c:choose>的子标签,用来判断条件是否成立
<c:otherwise> <c:choose>的子标签,接在<c:when>标签后,当<c:when>标签判断为false时被执行
<c:import> 检索一个绝对或相对 URL,然后将其内容暴露给页面
<c:forEach> 基础迭代标签,接受多种集合类型
<c:forTokens> 根据指定的分隔符来分隔内容并迭代输出
<c:param> 用来给包含或重定向的页面传递参数
<c:redirect> 重定向至一个新的URL.
<c:url> 使用可选的查询参数来创造一个URL

格式化标签

<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>

SQL标签

<%@ taglib prefix="sql" uri="http://java.sun.com/jsp/jstl/sql" %>

XML标签

<%@ taglib prefix="x"  uri="http://java.sun.com/jsp/jstl/xml" %>

在使用xml标签前,你必须将XML 和 XPath 的相关包拷贝至你的<Tomcat 安装目录>\lib下:

JSTL标签使用步骤

  • 引入对于的taglib
  • 引用其中的方法
  • 在Tomcat中也需要引入jar包,否则会报错

测试1:c: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>
<h4>IF测试</h4>
<hr>
<form action="coreif.jsp" method="get">
    <input type="text" name="username" value="${param.username}">
    <input  type="submit"   value="登陆">
</form>
<%--判断如果提交的用户是管理员,则登陆成功--%>
<c:if test="${param.username=='admin'}" var="isadmin" scope="session">
    <c:out value="管理员"></c:out>
</c:if>
</body>
</html>

image

测试2:c:choose c:when

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<%--定义一个变量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>=60}">
        你的成绩为及格
    </c:when>
    <c:when test="${score<60}">
        你的成绩为不及格
    </c:when>
</c:choose>
</body>
</html>

image

测试3:c:forEach

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<%
    ArrayList<String> people = new ArrayList<>();
    people.add(0,"张三");
    people.add(1,"李四");
    people.add(2,"王五");
    people.add(3,"赵六");
    people.add(4,"田七");
    people.add(5,"吴八");
    people.add(6,"华九");
    people.add(7,"向十");
    request.setAttribute("list",people);
%>
<%--
var:每一次遍历的变量
items:要遍历的对象
begin:开始
end:结束
step:步长
--%>
<c:forEach var="people" items="${list}">
    <c:out value="${people}"></c:out>
    <br>
</c:forEach>
<hr>
<c:forEach var="people" items="${list}" begin="0" end="3" step="2">
    <c:out value="${people}"></c:out>
</c:forEach>
</body>
</html>

image

8.JavaBean

8.1什么是JavaBean

​ JavaBean 是一种JAVA语言写成的可重用组件。为写成JavaBean,类必须是具体的和公共的,并且具有无参数的构造器。JavaBean 通过提供符合一致性设计模式的公共方法将内部域暴露成员属性,set和get方法获取。众所周知,属性名称符合这种模式,其他Java 类可以通过自省机制(反射机制)发现和操作这些JavaBean 的属性。

​ 它可以被Applet、Servlet、JSP等Java应用程序调用.也可以可视化地被Java开发工具使用。它包含属性(Properties)、方法(Methods)、事件(Events)等特性。

实体类

JavaBean有特定的写法

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

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

ORM:对象关系映射

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

People表

id name age address
1 一号 3 北京
2 二号 18 上海
3 三号 100 武汉

写一个javabean

package com.pojo;

//实体类 我们一般都是和数据库的表结构一一对应

public class People {
    private  int id;
    private  String name;
    private  int age;
    private  String address;

    public People() {
    }

    public People(int id, String name, int age, String address) {
        this.id = id;
        this.name = name;
        this.age = age;
        this.address = address;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    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;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return "People{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                ", address='" + address + '\'' +
                '}';
    }
}

JSP中引入

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<%
//    People people = new People();
//    people.setId(1);
//    people.setName("一号");
//    people.setAge(3);
//    people.setAddress("北京");
%>
<jsp:useBean id="people" class="com.pojo.People" scope="page"></jsp:useBean>
<jsp:setProperty name="people" property="id" value="1"></jsp:setProperty>
<jsp:setProperty name="people" property="name" value="一号"></jsp:setProperty>
<jsp:setProperty name="people" property="age" value="3"></jsp:setProperty>
<jsp:setProperty name="people" property="address" value="北京"></jsp:setProperty>

id:<jsp:getProperty name="people" property="id"></jsp:getProperty>
姓名:<jsp:getProperty name="people" property="name" ></jsp:getProperty>
年龄:<jsp:getProperty name="people" property="age" ></jsp:getProperty>
地址:<jsp:getProperty name="people" property="address" ></jsp:getProperty>
</body>
</html>

可见与俩个代码功能一样

 People people = new People();
 people.setId(1);
 people.setName("一号");
 people.setAge(3);
 people.setAddress("北京");


<jsp:useBean id="people" class="com.pojo.People" scope="page"></jsp:useBean>
<jsp:setProperty name="people" property="id" value="1"></jsp:setProperty>
<jsp:setProperty name="people" property="name" value="一号"></jsp:setProperty>
<jsp:setProperty name="people" property="age" value="3"></jsp:setProperty>
<jsp:setProperty name="people" property="address" value="北京"></jsp:setProperty>

结果

image

8.2 练习

1.创建数据库

SET FOREIGN_KEY_CHECKS=0;

-- ----------------------------
-- Table structure for smbms_address
-- ----------------------------
DROP TABLE IF EXISTS `smbms_address`;
CREATE TABLE `smbms_address` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `contact` varchar(15) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '联系人姓名',
  `addressDesc` varchar(50) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '收货地址明细',
  `postCode` varchar(15) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '邮编',
  `tel` varchar(20) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '联系人电话',
  `createdBy` bigint(20) DEFAULT NULL COMMENT '创建者',
  `creationDate` datetime DEFAULT NULL COMMENT '创建时间',
  `modifyBy` bigint(20) DEFAULT NULL COMMENT '修改者',
  `modifyDate` datetime DEFAULT NULL COMMENT '修改时间',
  `userId` bigint(20) DEFAULT NULL COMMENT '用户ID',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

-- ----------------------------
-- Records of smbms_address
-- ----------------------------
INSERT INTO `smbms_address` VALUES ('1', '王丽', '北京市东城区东交民巷44号', '100010', '13678789999', '1', '2016-04-13 00:00:00', null, null, '1');
INSERT INTO `smbms_address` VALUES ('2', '张红丽', '北京市海淀区丹棱街3号', '100000', '18567672312', '1', '2016-04-13 00:00:00', null, null, '1');
INSERT INTO `smbms_address` VALUES ('3', '任志强', '北京市东城区美术馆后街23号', '100021', '13387906742', '1', '2016-04-13 00:00:00', null, null, '1');
INSERT INTO `smbms_address` VALUES ('4', '曹颖', '北京市朝阳区朝阳门南大街14号', '100053', '13568902323', '1', '2016-04-13 00:00:00', null, null, '2');
INSERT INTO `smbms_address` VALUES ('5', '李慧', '北京市西城区三里河路南三巷3号', '100032', '18032356666', '1', '2016-04-13 00:00:00', null, null, '3');
INSERT INTO `smbms_address` VALUES ('6', '王国强', '北京市顺义区高丽营镇金马工业区18号', '100061', '13787882222', '1', '2016-04-13 00:00:00', null, null, '3');

-- ----------------------------
-- Table structure for smbms_bill
-- ----------------------------
DROP TABLE IF EXISTS `smbms_bill`;
CREATE TABLE `smbms_bill` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `billCode` varchar(20) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '账单编码',
  `productName` varchar(20) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '商品名称',
  `productDesc` varchar(50) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '商品描述',
  `productUnit` varchar(10) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '商品单位',
  `productCount` decimal(20,2) DEFAULT NULL COMMENT '商品数量',
  `totalPrice` decimal(20,2) DEFAULT NULL COMMENT '商品总额',
  `isPayment` int(10) DEFAULT NULL COMMENT '是否支付(1:未支付 2:已支付)',
  `createdBy` bigint(20) DEFAULT NULL COMMENT '创建者(userId)',
  `creationDate` datetime DEFAULT NULL COMMENT '创建时间',
  `modifyBy` bigint(20) DEFAULT NULL COMMENT '更新者(userId)',
  `modifyDate` datetime DEFAULT NULL COMMENT '更新时间',
  `providerId` int(20) DEFAULT NULL COMMENT '供应商ID',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=18 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

-- ----------------------------
-- Records of smbms_bill
-- ----------------------------
INSERT INTO `smbms_bill` VALUES ('1', 'BILL2016_001', '洗发水、护发素', '日用品-洗发、护发', '瓶', '500.00', '25000.00', '2', '1', '2014-12-14 13:02:03', '15', '2019-04-16 21:43:12', '13');
INSERT INTO `smbms_bill` VALUES ('2', 'BILL2016_002', '香皂、肥皂、药皂', '日用品-皂类', '块', '1000.00', '10000.00', '2', '1', '2016-03-23 04:20:40', null, null, '13');
INSERT INTO `smbms_bill` VALUES ('3', 'BILL2016_003', '大豆油', '食品-食用油', '斤', '300.00', '5890.00', '2', '1', '2014-12-14 13:02:03', null, null, '6');
INSERT INTO `smbms_bill` VALUES ('4', 'BILL2016_004', '橄榄油', '食品-进口食用油', '斤', '200.00', '9800.00', '2', '1', '2013-10-10 03:12:13', null, null, '7');
INSERT INTO `smbms_bill` VALUES ('5', 'BILL2016_005', '洗洁精', '日用品-厨房清洁', '瓶', '500.00', '7000.00', '2', '1', '2014-12-14 13:02:03', null, null, '9');
INSERT INTO `smbms_bill` VALUES ('6', 'BILL2016_006', '美国大杏仁', '食品-坚果', '袋', '300.00', '5000.00', '2', '1', '2016-04-14 06:08:09', null, null, '4');
INSERT INTO `smbms_bill` VALUES ('7', 'BILL2016_007', '沐浴液、精油', '日用品-沐浴类', '瓶', '500.00', '23000.00', '1', '1', '2016-07-22 10:10:22', null, null, '14');
INSERT INTO `smbms_bill` VALUES ('8', 'BILL2016_008', '不锈钢盘碗', '日用品-厨房用具', '个', '600.00', '6000.00', '2', '1', '2016-04-14 05:12:13', null, null, '14');
INSERT INTO `smbms_bill` VALUES ('9', 'BILL2016_009', '塑料杯', '日用品-杯子', '个', '350.00', '1750.00', '2', '1', '2016-02-04 11:40:20', null, null, '14');
INSERT INTO `smbms_bill` VALUES ('10', 'BILL2016_010', '豆瓣酱', '食品-调料', '瓶', '200.00', '2000.00', '2', '1', '2013-10-29 05:07:03', null, null, '8');
INSERT INTO `smbms_bill` VALUES ('11', 'BILL2016_011', '海之蓝', '饮料-国酒', '瓶', '50.00', '10000.00', '1', '1', '2016-04-14 16:16:00', null, null, '1');
INSERT INTO `smbms_bill` VALUES ('12', 'BILL2016_012', '芝华士', '饮料-洋酒', '瓶', '20.00', '6000.00', '1', '1', '2016-09-09 17:00:00', null, null, '1');
INSERT INTO `smbms_bill` VALUES ('13', 'BILL2016_013', '长城红葡萄酒', '饮料-红酒', '瓶', '60.00', '800.00', '2', '1', '2016-11-14 15:23:00', null, null, '1');
INSERT INTO `smbms_bill` VALUES ('14', 'BILL2016_014', '泰国香米', '食品-大米', '斤', '400.00', '5000.00', '2', '1', '2016-10-09 15:20:00', null, null, '3');
INSERT INTO `smbms_bill` VALUES ('15', 'BILL2016_015', '东北大米', '食品-大米', '斤', '600.00', '4000.00', '2', '1', '2016-11-14 14:00:00', null, null, '3');
INSERT INTO `smbms_bill` VALUES ('16', 'BILL2016_016', '可口可乐', '饮料', '瓶', '2000.00', '6000.00', '2', '1', '2012-03-27 13:03:01', null, null, '2');
INSERT INTO `smbms_bill` VALUES ('17', 'BILL2016_017', '脉动', '饮料', '瓶', '1500.00', '4500.00', '2', '1', '2016-05-10 12:00:00', null, null, '2');

-- ----------------------------
-- Table structure for smbms_provider
-- ----------------------------
DROP TABLE IF EXISTS `smbms_provider`;
CREATE TABLE `smbms_provider` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `proCode` varchar(20) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '供应商编码',
  `proName` varchar(20) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '供应商名称',
  `proDesc` varchar(50) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '供应商详细描述',
  `proContact` varchar(20) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '供应商联系人',
  `proPhone` varchar(20) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '联系电话',
  `proAddress` varchar(50) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '地址',
  `proFax` varchar(20) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '传真',
  `createdBy` bigint(20) DEFAULT NULL COMMENT '创建者(userId)',
  `creationDate` datetime DEFAULT NULL COMMENT '创建时间',
  `modifyDate` datetime DEFAULT NULL COMMENT '更新时间',
  `modifyBy` bigint(20) DEFAULT NULL COMMENT '更新者(userId)',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=14 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

-- ----------------------------
-- Records of smbms_provider
-- ----------------------------
INSERT INTO `smbms_provider` VALUES ('1', 'BJ_GYS001', '北京三木堂商贸有限公司', '长期合作伙伴,主营产品:茅台、五粮液、郎酒、酒鬼酒、泸州老窖、赖茅酒、法国红酒等', '张国强', '13566669999', '北京市丰台区育芳园北路', '010-58858787', '1', '2013-03-21 16:52:07', '2019-04-12 16:44:03', '10');
INSERT INTO `smbms_provider` VALUES ('2', 'HB_GYS001', '石家庄帅益食品贸易有限公司', '长期合作伙伴,主营产品:饮料、水饮料、植物蛋白饮料、休闲食品、果汁饮料、功能饮料等', '王军', '13309094212', '河北省石家庄新华区', '0311-67738876', '1', '2016-04-13 04:20:40', null, null);
INSERT INTO `smbms_provider` VALUES ('3', 'GZ_GYS001', '深圳市泰香米业有限公司', '初次合作伙伴,主营产品:良记金轮米,龙轮香米等', '郑程瀚', '13402013312', '广东省深圳市福田区深南大道6006华丰大厦', '0755-67776212', '1', '2014-03-21 16:56:07', null, null);
INSERT INTO `smbms_provider` VALUES ('4', 'GZ_GYS002', '深圳市喜来客商贸有限公司', '长期合作伙伴,主营产品:坚果炒货.果脯蜜饯.天然花茶.营养豆豆.特色美食.进口食品.海味零食.肉脯肉', '林妮', '18599897645', '广东省深圳市福龙工业区B2栋3楼西', '0755-67772341', '1', '2013-03-22 16:52:07', null, null);
INSERT INTO `smbms_provider` VALUES ('5', 'JS_GYS001', '兴化佳美调味品厂', '长期合作伙伴,主营产品:天然香辛料、鸡精、复合调味料', '徐国洋', '13754444221', '江苏省兴化市林湖工业区', '0523-21299098', '1', '2015-11-22 16:52:07', null, null);
INSERT INTO `smbms_provider` VALUES ('6', 'BJ_GYS002', '北京纳福尔食用油有限公司', '长期合作伙伴,主营产品:山茶油、大豆油、花生油、橄榄油等', '马莺', '13422235678', '北京市朝阳区珠江帝景1号楼', '010-588634233', '1', '2012-03-21 17:52:07', null, null);
INSERT INTO `smbms_provider` VALUES ('7', 'BJ_GYS003', '北京国粮食用油有限公司', '初次合作伙伴,主营产品:花生油、大豆油、小磨油等', '王驰', '13344441135', '北京大兴青云店开发区', '010-588134111', '1', '2016-04-13 00:00:00', null, null);
INSERT INTO `smbms_provider` VALUES ('8', 'ZJ_GYS001', '慈溪市广和绿色食品厂', '长期合作伙伴,主营产品:豆瓣酱、黄豆酱、甜面酱,辣椒,大蒜等农产品', '薛圣丹', '18099953223', '浙江省宁波市慈溪周巷小安村', '0574-34449090', '1', '2013-11-21 06:02:07', null, null);
INSERT INTO `smbms_provider` VALUES ('9', 'GX_GYS001', '优百商贸有限公司', '长期合作伙伴,主营产品:日化产品', '李立国', '13323566543', '广西南宁市秀厢大道42-1号', '0771-98861134', '1', '2013-03-21 19:52:07', null, null);
INSERT INTO `smbms_provider` VALUES ('10', 'JS_GYS002', '南京火头军信息技术有限公司', '长期合作伙伴,主营产品:不锈钢厨具等', '陈女士', '13098992113', '江苏省南京市浦口区浦口大道1号新城总部大厦A座903室', '025-86223345', '1', '2013-03-25 16:52:07', null, null);
INSERT INTO `smbms_provider` VALUES ('11', 'GZ_GYS003', '广州市白云区美星五金制品厂', '长期合作伙伴,主营产品:海绵床垫、坐垫、靠垫、海绵枕头、头枕等', '梁天', '13562276775', '广州市白云区钟落潭镇福龙路20号', '020-85542231', '1', '2016-12-21 06:12:17', null, null);
INSERT INTO `smbms_provider` VALUES ('12', 'BJ_GYS004', '北京隆盛日化科技', '长期合作伙伴,主营产品:日化环保清洗剂,家居洗涤专卖、洗涤用品网、墙体除霉剂、墙面霉菌清除剂等', '孙欣', '13689865678', '北京市大兴区旧宫', '010-35576786', '1', '2014-11-21 12:51:11', null, null);
INSERT INTO `smbms_provider` VALUES ('13', 'SD_GYS001', '山东豪克华光联合发展有限公司', '长期合作伙伴,主营产品:洗衣皂、洗衣粉、洗衣液、洗洁精、消杀类、香皂等', '吴洪转', '13245468787', '山东济阳济北工业区仁和街21号', '0531-53362445', '1', '2015-01-28 10:52:07', null, null);

-- ----------------------------
-- Table structure for smbms_role
-- ----------------------------
DROP TABLE IF EXISTS `smbms_role`;
CREATE TABLE `smbms_role` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `roleCode` varchar(15) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '角色编码',
  `roleName` varchar(15) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '角色名称',
  `createdBy` bigint(20) DEFAULT NULL COMMENT '创建者',
  `creationDate` datetime DEFAULT NULL COMMENT '创建时间',
  `modifyBy` bigint(20) DEFAULT NULL COMMENT '修改者',
  `modifyDate` datetime DEFAULT NULL COMMENT '修改时间',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

-- ----------------------------
-- Records of smbms_role
-- ----------------------------
INSERT INTO `smbms_role` VALUES ('1', 'SMBMS_ADMIN', '系统管理员', '1', '2016-04-13 00:00:00', null, null);
INSERT INTO `smbms_role` VALUES ('2', 'SMBMS_MANAGER', '经理', '1', '2016-04-13 00:00:00', null, null);
INSERT INTO `smbms_role` VALUES ('3', 'SMBMS_EMPLOYEE', '普通员工', '1', '2016-04-13 00:00:00', null, null);

-- ----------------------------
-- Table structure for smbms_user
-- ----------------------------
DROP TABLE IF EXISTS `smbms_user`;
CREATE TABLE `smbms_user` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `userCode` varchar(15) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '用户编码',
  `userName` varchar(15) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '用户名称',
  `userPassword` varchar(15) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '用户密码',
  `gender` int(10) DEFAULT NULL COMMENT '性别(1:女、 2:男)',
  `birthday` date DEFAULT NULL COMMENT '出生日期',
  `phone` varchar(15) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '手机',
  `address` varchar(30) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '地址',
  `userRole` int(10) DEFAULT NULL COMMENT '用户角色(取自角色表-角色id)',
  `createdBy` bigint(20) DEFAULT NULL COMMENT '创建者(userId)',
  `creationDate` datetime DEFAULT NULL COMMENT '创建时间',
  `modifyBy` bigint(20) DEFAULT NULL COMMENT '更新者(userId)',
  `modifyDate` datetime DEFAULT NULL COMMENT '更新时间',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

-- ----------------------------
-- Records of smbms_user
-- ----------------------------
INSERT INTO `smbms_user` VALUES ('1', 'wen', '系统管理员', '123', '1', '1997-01-01', '15200981234', '湖南省衡阳市蒸湘区南华大学', '1', '1', '2019-04-07 10:15:55', null, null);
INSERT INTO `smbms_user` VALUES ('5', 'hanlubiao', '韩路彪', '0000000', '2', '1984-06-05', '18567542321', '北京市朝阳区北辰中心12号', '2', '1', '2014-12-31 19:52:09', null, null);
INSERT INTO `smbms_user` VALUES ('6', 'zhanghua', '张华', '0000000', '1', '1983-06-15', '13544561111', '北京市海淀区学院路61号', '3', '1', '2013-02-11 10:51:17', null, null);
INSERT INTO `smbms_user` VALUES ('7', 'wangyang', '王洋', '0000000', '2', '1982-12-31', '13444561124', '北京市海淀区西二旗辉煌国际16层', '3', '1', '2014-06-11 19:09:07', null, null);
INSERT INTO `smbms_user` VALUES ('8', 'zhaoyan', '赵燕', '0000000', '1', '1986-03-07', '18098764545', '北京市海淀区回龙观小区10号楼', '3', '1', '2016-04-21 13:54:07', null, null);
INSERT INTO `smbms_user` VALUES ('10', 'sunlei', '孙磊', '0000000', '2', '1981-01-04', '13387676765', '北京市朝阳区管庄新月小区12楼', '3', '1', '2015-05-06 10:52:07', null, null);
INSERT INTO `smbms_user` VALUES ('11', 'sunxing', '孙兴', '0000000', '2', '1978-03-12', '13367890900', '北京市朝阳区建国门南大街10号', '3', '1', '2016-11-09 16:51:17', null, null);
INSERT INTO `smbms_user` VALUES ('12', 'zhangchen', '张晨', '0000000', '1', '1986-03-28', '18098765434', '朝阳区管庄路口北柏林爱乐三期13号楼', '3', '1', '2016-08-09 05:52:37', '1', '2016-04-14 14:15:36');
INSERT INTO `smbms_user` VALUES ('13', 'dengchao', '邓超', '0000000', '2', '1981-11-04', '13689674534', '北京市海淀区北航家属院10号楼', '3', '1', '2016-07-11 08:02:47', null, null);
INSERT INTO `smbms_user` VALUES ('14', 'yangguo', '杨过', '0000000', '2', '1980-01-01', '13388886623', '北京市朝阳区北苑家园茉莉园20号楼', '3', '1', '2015-02-01 03:52:07', null, null);
INSERT INTO `smbms_user` VALUES ('15', 'test', 'test', '111', '1', '2019-04-16', '123456789', '南华大学', '1', '1', '2019-04-16 19:52:37', null, null);

9.MVC三层架构

什么是MVC:Model iew Controller 模型、视图、控制器

img

  • M即model模型是指模型表示业务规则。在MVC的三个部件中,模型拥有最多的处理任务。被模型返回的数据是中立的,模型与数据格式无关,这样一个模型能为多个视图提供数据,由于应用于模型的代码只需写一次就可以被多个视图重用,所以减少了代码的重复性。

    • 业务处理:业务逻辑(Service)
    • 数据持久层:CRUD(Dao)
  • V即View视图是指用户看到并与之交互的界面。比如由html元素组成的网页界面,或者软件的客户端界面。MVC的好处之一在于它能为应用程序处理很多不同的视图。在视图中其实没有真正的处理发生,它只是作为一种输出数据并允许用户操作的方式。

    • 展示数据
    • 提供链接发起Servlet请求(a,form.img……)
  • C即controller控制器是指控制器接受用户的输入并调用模型和视图去完成用户的需求,控制器本身不输出任何东西和做任何处理。它只是接收请求并决定调用哪个模型构件去处理请求,然后再确定用哪个视图来显示返回的数据。

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

10.Filter

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

  • 处理中文乱码
  • 登陆验证

这里写图片描述

Filter开发步骤:

  1. 导包

  2. 编写过滤器

    1. 导包不要导错了,注意tomcat版本

    2. 编写过滤器

      public class CharacterEncodingFilter implements Filter {
          //初始化
          @Override
          public void init(FilterConfig filterConfig) throws ServletException {
              System.out.println("CharacterEncodingFilter初始化");
          }
          //Chain:链
          /**
           * 1.过滤器中的所有代码,在过滤特定请求的时候都会执行
           * 2,必须要让过滤器教学同行
           * */
          @Override
          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
          public void destroy() {
              System.out.println("CharacterEncodingFilter销毁");
          }
      }
      
    3. 编写映射

      <?xml version="1.0" encoding="UTF-8"?>
      <web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd"
               version="5.0">
          <servlet>
              <servlet-name>ShowServlet</servlet-name>
              <servlet-class>com.servlet.ShowServlet</servlet-class>
          </servlet>
          <servlet-mapping>
              <servlet-name>ShowServlet</servlet-name>
              <url-pattern>/ss</url-pattern>
          </servlet-mapping>
          <filter>
              <filter-name>filter</filter-name>
              <filter-class>com.filter.CharacterEncodingFilter</filter-class>
          </filter>
          <filter-mapping>
              <filter-name>filter</filter-name>
      <!--        只要是/servlet的任何请求,会经过这个过滤器-->
              <url-pattern>/servlet/*</url-pattern>
          </filter-mapping>
      </web-app>
      

Filter应用测试

dmeo:用户登陆登陆之后才能进入主页!用户注销后就不能进入主页

Login.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<h1>用户登陆</h1>
<form action="${pageContext.request.contextPath}/login" method="post">
    <input type="text" name="username">
    <input type="submit">
</form>
</body>
</html>

login的Servlet

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

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("doPost");
        //获取前端请求的参数
        String username = req.getParameter("username");
        if(username.equals("admin")){
            //登陆成功
            req.getSession().setAttribute(USER_SESSION,req.getSession().getId());
            resp.sendRedirect("Sys/success.jsp");
        }else {
            //登陆失败
            resp.sendRedirect("error.jsp");
        }
    }
}

编写Session常量工具类

public class Constant {
    public  final  static String USER_SESSION="USER_SESSION";
}

编写主页

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

    Object userSession = request.getSession().getAttribute(USER_SESSION);
    if(userSession==null){
        response.sendRedirect("/Filter_war_exploded/Login.jsp");
    }
%>
<h1>主页</h1>
<p>
    <a href="${pageContext.request.contextPath}/logout">注销</a>
</p>
</body>
</html>

编写错误页

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<h1>错误页面</h1>
<p>
    <a href="${pageContext.request.contextPath}/logout">返回登陆页面</a>
</p>
</body>
</html>

编写注销代码

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

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        Object user_session = req.getSession().getAttribute(USER_SESSION);
        if(user_session!=null){
            req.getSession().removeAttribute(USER_SESSION);
            resp.sendRedirect("Login.jsp");
        }else {
            resp.sendRedirect("Login.jsp");
        }
    }
}

此时以及可以实现Dmeo,但是结构不清晰

写过滤器代码

public class SysFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        Filter.super.init(filterConfig);
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse)  servletResponse;
        if (request.getSession().getAttribute(USER_SESSION) == null) {
            response.sendRedirect("/Filter_war_exploded/error.jsp");
        }
        filterChain.doFilter(servletRequest,servletResponse);
    }

    @Override
    public void destroy() {
        Filter.super.destroy();
    }
}

修改主页JSP文件

<h1>主页</h1>
<p>
    <a href="${pageContext.request.contextPath}/logout">注销</a>
</p>
</body>
</html>

最后写映射

<servlet>
    <servlet-name>LoginServlet</servlet-name>
    <servlet-class>com.servlet.LoginServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>LoginServlet</servlet-name>
    <url-pattern>/login</url-pattern>
</servlet-mapping>
<servlet>
    <servlet-name>logout</servlet-name>
    <servlet-class>com.servlet.LogoutServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>logout</servlet-name>
    <url-pattern>/logout</url-pattern>
</servlet-mapping>
<filter>
    <filter-name>SysFilter</filter-name>
    <filter-class>com.filter.SysFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>SysFilter</filter-name>
    <url-pattern>/Sys/*</url-pattern>
</filter-mapping>

11.监听器(重点)

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

  1. 编写一个监听器

    实现监听器的接口

    public class OnlineCountLister implements HttpSessionListener {
        //创建session监听
        //一旦创建session就会触发这个事件
        @Override
        public void sessionCreated(HttpSessionEvent se) {
            ServletContext servletContext = se.getSession().getServletContext();
    
            Integer onlineCount = (Integer) servletContext.getAttribute("OnlineCount");
            if (onlineCount == null) {
                onlineCount= 1;
            }else {
                int count=onlineCount.intValue();
                onlineCount= count + 1;
            }
            servletContext.setAttribute("OnlineCount",onlineCount);
            System.out.println(se.getSession().getId());
        }
        //销毁session监听
        //一旦销毁session就会触发这个事件
        @Override
        public void sessionDestroyed(HttpSessionEvent se) {
            ServletContext servletContext = se.getSession().getServletContext();
            Integer onlineCount = (Integer) servletContext.getAttribute("OnlineCount");
            if (onlineCount == null) {
                onlineCount= 0;
            }else {
                int count=onlineCount.intValue();
                onlineCount= count - 1;
            }
            servletContext.setAttribute("OnlineCount",onlineCount);
        }
    }
    
  2. 配置注册监听器

    <!--    注册监听器-->
        <listener>
            <listener-class>com.listener.OnlineCountLister</listener-class>
        </listener>
    

12.JDBC

12.1 什么是JDBC

JDBC 指 Java 数据库连接,是一种标准Java应用编程接口( JAVA API),用来连接 Java 编程语言和广泛的数据库。

JDBC API 库包含下面提到的每个任务,都是与数据库相关的常用用法。

  • 制作到数据库的连接。
  • 创建 SQL 或 MySQL 语句。
  • 执行 SQL 或 MySQL 查询数据库。
  • 查看和修改所产生的记录。

从根本上来说,JDBC 是一种规范,它提供了一套完整的接口,允许便携式访问到底层数据库,因此可以用 Java 编写不同类型的可执行文件,例如:

  • Java 应用程序
  • Java Applets
  • Java Servlets
  • Java ServerPages (JSPs)
  • Enterprise JavaBeans (EJBs)

所有这些不同的可执行文件就可以使用 JDBC 驱动程序来访问数据库,这样可以方便的访问数据。

JDBC 具有 ODBC 一样的性能,允许 Java 程序包含与数据库无关的代码。

注意:使用JDBC前需要导入jar包

12.2 JDBC测试

测试:创建数据库表

CREATE TABLE `users`(
 `id` INT PRIMARY KEY,
 `NAME` VARCHAR(40),
 `PASSWORD` VARCHAR(40),
 `email` VARCHAR(60),
 birthday DATE
);

 INSERT INTO `users`(`id`,`NAME`,`PASSWORD`,`email`,`birthday`)
VALUES('1','zhangsan','123456','zs@sina.com','1980-12-04'),
('2','lisi','123456','lisi@sina.com','1981-12-04'),
('3','wangwu','123456','wangwu@sina.com','1979-12-04')

测试简单JDBC代码

  1. 加载驱动
  2. .用户信息
  3. 连接成功,数据库对象 connection 代表数据库
  4. 执行sql的对象 statement 执行sql的对象
  5. 执行sql的对象 去执行sql。可能存在结果,查看返回结果
  6. .释放连接
package com.JDBC.Demo01;

import com.mysql.jdbc.Driver;

import java.sql.*;

public class jdbcFirstDemo {
    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        //1.加载驱动
        Class.forName("com.mysql.cj.jdbc.Driver");//固定写法

        //2.用户信息
        String url  = "jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true&serverTimezone=UTC";
        String username = "root";
        String password = "admin";

        //3.连接成功,数据库对象 connection 代表数据库
        Connection connection = DriverManager.getConnection(url, username, password);
        //4.执行sql的对象  statement 执行sql的对象
        Statement statement = connection.createStatement();
        //5.执行sql的对象  去执行sql。可能存在结果,查看返回结果
        String sql ="SELECT * FROM `users`";

        ResultSet resultSet = statement.executeQuery(sql);//返回的结果集

        while (resultSet.next()){
            System.out.println("id="+resultSet.getObject("id"));
            System.out.println("name="+resultSet.getObject("NAME"));
            System.out.println("pwd="+resultSet.getObject("PASSWORD"));
            System.out.println("email="+resultSet.getObject("email"));
            System.out.println("birth="+resultSet.getObject("birthday"));
        }
        //6.释放连接
        resultSet.close();
        statement.close();
        connection.close();
    }
}

CRUD操作-create

使用executUpdate(string sql)方法完成数据库添加操作,实例操作

  Statement statement = connection.createStatement();
        //5.执行sql的对象  去执行sql。可能存在结果,查看返回结果
        String sql ="insert into user(...) value (..)";
        int num= statement.executeUpdate(sql);//返回的结果集
        if(num>0){
            System.out.println("插入成功");
        }

CRUD操作-delete

使用executUpdate(string sql)方法完成数据库添加操作,实例操作

Statement statement = connection.createStatement();
       //5.执行sql的对象  去执行sql。可能存在结果,查看返回结果
       String sql ="delete from user where id = 1";
       int num= statement.executeUpdate(sql);//返回的结果集
       if(num>0){
           System.out.println(删除成功");
       }

CRUD操作-update

使用executUpdate(string sql)方法完成数据库添加操作,实例操作

Statement statement = connection.createStatement();
      //5.执行sql的对象  去执行sql。可能存在结果,查看返回结果
      String sql ="update user set name ='' where name='';
      int num= statement.executeUpdate(sql);//返回的结果集
      if(num>0){
          System.out.println(更新成功");
      }

CRUD操作-delete

使用executeQuery(string sql)方法完成数据库添加操作,实例操作

String sql ="SELECT * FROM `users`";

       ResultSet resultSet = statement.executeQuery(sql);//返回的结果集

       while (resultSet.next()){
           System.out.println("id="+resultSet.getObject("id"));
           System.out.println("name="+resultSet.getObject("NAME"));
           System.out.println("pwd="+resultSet.getObject("PASSWORD"));
           System.out.println("email="+resultSet.getObject("email"));
           System.out.println("birth="+resultSet.getObject("birthday"));
       }

12.3 编写工具类

编写配置文件

driver = com.mysql.cj.jdbc.Driver
url = jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true&serverTimezone=UTC
username = root
password = admin

编写工具类

package com.JDBC.Demo02.utils;

import com.mysql.cj.protocol.Resultset;

import java.io.InputStream;
import java.sql.*;
import java.util.Properties;
public class JdbcUtils {
    private  static  String driver = null;
    private  static  String url = null;
    private  static  String username = null;
    private  static  String password = null;
    static {
        try{
            InputStream input = JdbcUtils.class.getClassLoader().getResourceAsStream("db.properties");
            Properties properties = new Properties();
            properties.load(input);
            driver=properties.getProperty("driver");
            url=properties.getProperty("url");
            username=properties.getProperty("username");
            password=properties.getProperty("password");


            //1.驱动只用加载一次
            Class.forName(driver);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    //获取链接
    public  static Connection getConnection() throws SQLException {
        return DriverManager.getConnection(url,username,password);
    }
    //释放资源
    public  static  void release(Connection connection, Statement statement, ResultSet resultSet) throws SQLException {
        if(resultSet!=null){
            resultSet.close();
        }
        if(statement!=null){
            statement.close();
        }
        if(connection!=null){
            connection.close();
        }
    }
}

测试

编写插入数据

package com.JDBC.Demo02.test;

import com.JDBC.Demo02.utils.JdbcUtils;
import com.mysql.cj.protocol.Resultset;

import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;

public class TestInsert {
    public static void main(String[] args) throws SQLException {
        Connection connection= null;
        Statement statement = null;
        Resultset resultset = null;
        try {
            connection = JdbcUtils.getConnection();//获取数据库链接
            statement = connection.createStatement();
            String sql  = " INSERT INTO `users`(`id`,`NAME`,`PASSWORD`,`email`,`birthday`)\n" +
                    "VALUES('4','zhangsan','123456','zs@sina.com','1220-12-04');";
            int i = statement.executeUpdate(sql);
            if(i>0){
                System.out.println("插入成功");
            }

        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            JdbcUtils.release(connection,statement,null);
        }
    }
}

编写查询数据

package com.JDBC.Demo02.test;

import com.JDBC.Demo02.utils.JdbcUtils;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class TestQuery {
    public static void main(String[] args) throws SQLException {
        Connection connection=null;
        Statement statement = null;
        ResultSet resultSet=null;
        try {
            connection = JdbcUtils.getConnection();
            statement = connection.createStatement();
            String sql = "select * from users where id=1";
            resultSet  = statement.executeQuery(sql);
            if(resultSet.next()){
                System.out.println("id="+resultSet.getObject("id"));
                System.out.println("name="+resultSet.getObject("NAME"));
                System.out.println("pwd="+resultSet.getObject("PASSWORD"));
                System.out.println("email="+resultSet.getObject("email"));
                System.out.println("birth="+resultSet.getObject("birthday"));
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            JdbcUtils.release(connection,statement,resultSet);
        }
    }
}

12.4 SQL注入问题

sql存在漏洞会被攻击导致数据泄露 SQL会被拼接

普通常见登录

package com.JDBC.Demo02.test;

import com.JDBC.Demo02.utils.JdbcUtils;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class SQL注入 {
    public static void main(String[] args) throws SQLException {
        //正常登录
        login("zhangsan","123456");
    }
    // 登录业务
    public  static  void login(String username,String password) throws SQLException {
        Connection connection=null;
        Statement statement = null;
        ResultSet resultSet=null;
        try {
            connection = JdbcUtils.getConnection();
            statement = connection.createStatement();
            String sql = "select * from users where `NAME` ='"+username+"' AND `PASSWORD`='"+password+"' ";
            resultSet  = statement.executeQuery(sql);
            if(resultSet.next()){
                System.out.println("id="+resultSet.getObject("id"));
                System.out.println("name="+resultSet.getObject("NAME"));
                System.out.println("pwd="+resultSet.getObject("PASSWORD"));
                System.out.println("email="+resultSet.getObject("email"));
                System.out.println("birth="+resultSet.getObject("birthday"));
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            JdbcUtils.release(connection,statement,resultSet);
        }
    }
}

PreparedStatement对象

PreparedStatement可以防止SQL注入,而且效率更好

使用PreparedStatement插入数据:

package com.JDBC.Demo03;

import com.JDBC.Demo02.utils.JdbcUtils;

import java.util.Date;
import java.sql.*;

public class TestInsert {
    public static void main(String[] args) throws SQLException {
        Connection connection=null;
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;

        try {
            connection = JdbcUtils.getConnection();

            //区别
            //使用?占位符代替参数
            String sql = " INSERT INTO `users`(`id`,`NAME`,`PASSWORD`,`email`,`birthday`)\n" +
                    "VALUES(?,?,?,?,?)";
            preparedStatement = connection.prepareStatement(sql);//预编译sql,先写sql ,然后不执行

            //手动参数赋值
            preparedStatement.setInt(1,5);
            preparedStatement.setString(2,"xiang");
            preparedStatement.setString(3,"123456");
            preparedStatement.setString(4,"xsadas@dsh.com");
            //注意点  sql.Date 数据库
            //   util.Date  Java  new Date().getTime()获得时间戳
            preparedStatement.setDate(5,new java.sql.Date(new Date().getTime()));

            int i = preparedStatement.executeUpdate();
            if(i>0){
                System.out.println("插入成功");
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            JdbcUtils.release(connection,preparedStatement,resultSet);
        }
    }
}

使用PreparedStatement查询数据:

package com.JDBC.Demo03;

import com.JDBC.Demo02.utils.JdbcUtils;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class TestQuery {
    public static void main(String[] args) throws SQLException {
        Connection connection=null;
        PreparedStatement preparedStatement= null;
        ResultSet resultSet = null;
        try {
            connection = JdbcUtils.getConnection();

            String sql = "select * from users where id=?";//编写sql

            preparedStatement = connection.prepareStatement(sql);//预编译

            preparedStatement.setInt(1,1);//传递参数

            resultSet=preparedStatement.executeQuery();//执行查询

            if(resultSet.next()){
                System.out.println("id="+resultSet.getObject("id"));
                System.out.println("name="+resultSet.getObject("NAME"));
                System.out.println("pwd="+resultSet.getObject("PASSWORD"));
                System.out.println("email="+resultSet.getObject("email"));
                System.out.println("birth="+resultSet.getObject("birthday"));
            }

        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            JdbcUtils.release(connection,preparedStatement,resultSet);
        }
    }
}

优化:

package com.JDBC.Demo03;

import com.JDBC.Demo02.utils.JdbcUtils;

import java.sql.*;
import java.util.Scanner;

public class SQL注入 {
    public static void main(String[] args) throws SQLException {
        System.out.print("输入查询用户ID:");
        try {
            Scanner scanner = new Scanner(System.in);
            int id = scanner.nextInt();
            login(id);
        }catch (Exception e){
            e.printStackTrace();
            System.out.println("数据异常!");
        }
    }
    // 登录业务
    public  static  void login(int id) throws SQLException {   Connection connection=null;
        PreparedStatement preparedStatement= null;
        ResultSet resultSet = null;
        try {
            connection = JdbcUtils.getConnection();

            String sql = "select * from users where id=?";//编写sql

            preparedStatement = connection.prepareStatement(sql);//预编译

            preparedStatement.setInt(1,id);//传递参数

            resultSet=preparedStatement.executeQuery();//执行查询

            if(resultSet.next()){
                System.out.println("id="+resultSet.getObject("id"));
                System.out.println("name="+resultSet.getObject("NAME"));
                System.out.println("pwd="+resultSet.getObject("PASSWORD"));
                System.out.println("email="+resultSet.getObject("email"));
                System.out.println("birth="+resultSet.getObject("birthday"));
            }

        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            JdbcUtils.release(connection,preparedStatement,resultSet);
        }
    }
}

12.5 事物

  1. 开启事务connection.setAutoCommit(false);
  2. 提交事务 connection.commit();
  3. 可以在catch语句中显示定义回滚语句,但默认失败就会回滚connection.rollback();
package com.JDBC.Demo05;

import com.JDBC.Demo02.utils.JdbcUtils;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Date;

public class TestTransaction {
    public static void main(String[] args) throws SQLException {
        Connection connection=null;
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;

        try {
            connection = JdbcUtils.getConnection();
            //关闭数据库的自动提交,自动会开启事务
            connection.setAutoCommit(false);//开启事物
            //区别
            //使用?占位符代替参数
            String sql = " INSERT INTO `users`(`id`,`NAME`,`PASSWORD`,`email`,`birthday`)\n" +
                    "VALUES(?,?,?,?,?)";
            preparedStatement = connection.prepareStatement(sql);//预编译sql,先写sql ,然后不执行

            //手动参数赋值
            preparedStatement.setInt(1,6);
            preparedStatement.setString(2,"xiang");
            preparedStatement.setString(3,"123456");
            preparedStatement.setString(4,"xsadas@dsh.com");
            //注意点  sql.Date 数据库
            //   util.Date  Java  new Date().getTime()获得时间戳
            preparedStatement.setDate(5,new java.sql.Date(new Date().getTime()));

            int i = preparedStatement.executeUpdate();
            connection.commit();
            if(i>0){
                System.out.println("插入成功");
            }
        } catch (SQLException e) {
            //异常回滚
            connection.rollback();
            e.printStackTrace();
        }finally {
            JdbcUtils.release(connection,preparedStatement,resultSet);
        }
    }
}

版权声明:本文为项sir原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/xiangsir/p/16282537.html