JavaWeb

JavaWeb

java web

一、基本概念

1.1前言

web开发:

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

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

1.2 web应用程序

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

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

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

1.3静态web

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

  • 静态web存在的缺点

    • web网页无法动态更新,所有的用户看到的都是一样的
      • 轮播图,点击特效:伪动态
      • javaScript 实际开发中,应用最多
      • VBScript
    • 它无法和数据库交互(数据无法持久化,数据无法交互)

1.4动态web

页面会动态展示:"Web的页面展示效果因人而异";

缺点:

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

优点:

  • web页面可以动态刷新,所有的用户看到的都不是同一个页面
  • 他可以与数据库交互(数据持久化:注册)

新手村:---魔鬼训练(分析原理,看源码)---》PK场

1.5javaweb项目结构

当然可以。JavaWeb项目通常由多个目录组成,每个目录都有其特定的作用。以下是JavaWeb项目中常见的一些目录及其用途的介绍:

  1. src目录:

    • 主要存放Java源代码,即你的Java类文件。这些类文件可以是Servlet、JSP、JavaBean、DAO(Data Access Object)、Service等。
    • 通常会根据功能或模块进一步划分子目录,如com.yourcompany.projectname.controller、com.yourcompany.projectname.model、com.yourcompany.projectname.dao等。
  2. web目录:

    • Web应用的根目录,存放Web应用的静态资源和动态页面。
    • WEB-INF目录 :这个目录下的文件对用户是不可见的 ,通常包含以下子目录和文件:
      • classes目录 :存放编译后的.class文件,即src目录下编译后生成的.class文件。
      • lib目录 :存放Web应用所需的第三方库文件,即.jar文件。
      • web.xml:Web应用的部署描述符,定义了Servlet、Filter、Listener等组件的配置信息。
    • 静态资源 :如css、js、images等目录,存放样式表、JavaScript文件和图片等。
    • JSP文件:Java Server Pages,通常存放在Web根目录或其子目录中,用于生成动态网页内容。
  3. META-INF目录:

    • 通常由开发工具自动生成和使用 ,存放项目的元数据信息,例如MANIFEST.MF文件。
  4. target目录(在Maven项目中常见):

    • 存放构建输出的文件 ,如编译后的.class文件、打包后的.jar或.war文件。
  5. test目录(在Maven项目中常见):

    • 存放测试代码,用于编写单元测试和集成测试。
  6. resources目录:

    • 存放项目的各种资源文件 ,如配置文件(application.properties、log4j.properties等)、SQL脚本、模板文件等。在Maven项目中,这个目录通常位于src/main/resources。

这些目录共同构成了一个完整的JavaWeb项目结构,帮助开发者组织和管理代码、资源和配置文件,使得项目更加清晰和易于维护。

二 、web服务器

2.1技术讲解

ASP,

  • 微软:国内最早的就是流行ASP;
  • 在HTML中嵌入了VB的脚本,ASP+COM;
  • 在ASP开发中,基本一个页面都有几千行的业务代码,页面混乱
  • 维护成本高
  • C#
html 复制代码
<h1>
  	<h1><h1>
      	<h1>
          	<h1>
              	<h1>	
        <h1>
          <%
             
           %>
            <h1>
              	<h1>


  <h1><h1>               
  <h1>

JSP/Servlet:

B/S:浏览器和服务器

C/S:客户端和服务器

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

PHP

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

2.2、web服务器

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

IIS

微软的;ASP...,Windows中自带的

Tomcat

面向百度编程;

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(标准通用标记语言下的一个应用)页面的访问请求。

诀窍是,当配置正确时,Apache 为HTML页面服务,而Tomcat 实际上运行JSP 页面和Servlet。Tomcat最新版本为10.0.5。

...

工作3-5年之后,可以尝试手写Tomcat服务器;

下载tomcat:

  1. 安装 or 解压
  2. 了解配置文件及目录结构
  3. 这个东西的作用

三、Tomcat

3.1、下载tomcat

3.2、Tomcat启动和配置

文件夹作用:

启动和关闭Tomcat

访问:http://localhost:8080/

可能遇到的问题:

  1. java环境变量没有配置
  2. 闪退问题:需要配置兼容
  3. 乱码问题:配置文件中配置

3.3、配置

可以配置启动的端口号:

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

可以配置主机的名称:

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

高难度面试题

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

  1. 输入一个域名;回车

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

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

      java 复制代码
      127.0.0.1  localhost
    2. 没有:去DNS服务器找,找到就返回,找不到就返回找不到

  3. 可以配置一下环境变量(可选性)

3.4、发布一个web网站

不会就模仿

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

网站应该有的结构

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

举个例子:

打开tomcat,访问localhost/zxystudy

html 复制代码
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>我的第一个网页</title>
</head>
<body>
<h1>欢迎来到我的网页</h1>
<p>这是一个段落。</p>
</body>
</html>

四、Http--不太好

4.1、什么是Http

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

  • 文本:html,字符串,~...
  • 超文本:图片,音乐,视频、定位、地图...(本质是一种带超链接的文本)
  • 默认端口:80

Https: 安全的(S:security)

  • 443

4.2、两个时代

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

4.3、Http请求

  • 客户端---发请求----服务器

百度:

java 复制代码
请求 URL: https://www.baidu.com/  			请求地址	
请求方法: GET								get方法/post方法	
状态代码: 200 OK					状态码:200
远程地址: 14.215.177.38:443				
引用站点策略: origin-when-cross-origin
java 复制代码
Accept:text/html
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6		语言
Cache-Control: max-age=0
Connection: keep-alive
1、请求行
  • 请求行中的请求方式:GET
  • 请求方式:GET,POST ,HEAD,DELETE,PUT,TRACT...
    • get:请求能够携带的参数比较少,大小有限制,会在浏览器的URL地址栏显示数据内容,相对不安全,高效
    • post:请求能够携带的参数没有限制,大小没有限制,不会在浏览器的URL地址栏显示数据内容,相对安全,但不高效
2、消息头
jva 复制代码
Accept:告诉服务器它所支持的数据类型 
Accept-Encoding: 支持哪种编码格式, GBK,UTF-8,GB2312,ISO8859-1
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6		告诉浏览器它的语言环境
Cache-Control: max-age=0		缓存控制
Connection: keep-alive	告诉服务器,请求完成是断开还是保持连接

4.4、Http响应

  • 客户端---发请求----服务器

百度:

java 复制代码
https: //www.baidu.com/?tn=68018901_16_pg  请求地址
Request Method: GET     get方法/post方法
状态代码: 200 OK         状态码:200
远程地址: 183.240.98.161:443

Cache-Control: private			缓存控制
Connection: keep-alive			b连接
Content-Encoding: gzip			编码
Content-Type: text/html;charset=utf-8		类型
    
1.响应体
java 复制代码
Accept:告诉浏览器它所支持的数据类型 
Accept-Encoding: 支持哪种编码格式, GBK,UTF-8,GB2312,ISO8859-1
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6		告诉浏览器它的语言环境
Cache-Control: max-age=0		缓存控制
Connection: keep-alive	告诉;浏览器,请求完成是断开还是保持连接
HOST: 主机...../.。
Refresh:告诉客户端,多久刷新一次
2.响应状态码

200:请求响应成功

3**:请求重定向

404:找不到资源

5**:服务器代码错误

五、Maven

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

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

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

    由此,Maven诞生

5.1、Maven架构管理工具

我们目前用他就是为了方便导入jar包

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

  • 有约束,不要去违反

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

5.2、Maven下载和安装

官网:点击此处

选择自己电脑的版本

下载完成后,解压即可

5.3、配置环境环境变量

在我们系统环境变量中

配置如下配置:

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

测试MAVEN是否安装成功,必须 保证配置完毕!

5.4阿里云镜像

我的文件位置:D:\Program Files (x86)\apache-maven-3.9.9\conf\settings.xml

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

5.5本地仓库

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

建立一个本地仓库:localRepository

xml 复制代码
<localRepository>E:\apache-maven-3.8.4\maven_repo</localRepository>

5.6、在IDEA中使用Maven

1.启动IDEA

2.创建一个Maven项目

3.因IDEA版本有差异

4.观察maven仓库多了什么东西

5.IDEA中的maven设置

IDEA项目创建成功后,看一下设置

6.源勾上会影响下载速度

5.7创建一个普通的maven项目

5.8标记文件功能


target是运行程序生成的文件夹

5.9在IDEA中配置Tomcat


5.10、pom文件

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

xml 复制代码
<!--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/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <!--配置的GAV-->
  <groupId>org.example</groupId>
  <artifactId>mavenproject</artifactId>
  <version>1.0-SNAPSHOT</version>
  <!--Package:项目打包方式
  jar:java应用
  war:Javaweb应用-->
  <packaging>war</packaging>
  <name>mavenproject Maven Webapp</name>
  <url>http://maven.apache.org</url>
  <!--依赖项-->
  <dependencies>
    <!--具体依赖的jar包配置文件-->
    <!--Maven的高级之处在于:它会帮你导入这个jar包的其他jar-->
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
  </dependencies>
  <!--项目构建用的东西-->
  <build>
    <finalName>mavenproject</finalName>
  </build>
</project>


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

xml 复制代码
    <build>
        <resources>
            <resource>
                <directory>src/main/resources</directory>
                <includes>
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                </includes>
                <filtering>true</filtering>
            </resource>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                </includes>
                <filtering>true</filtering>
            </resource>
        </resources>
    </build>

最终pom.xml的配置:

xml 复制代码
<!--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/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <!--配置的GAV-->
  <groupId>org.example</groupId>
  <artifactId>mavenproject</artifactId>
  <version>1.0-SNAPSHOT</version>
  <!--Package:项目打包方式
  jar:java应用
  war:Javaweb应用-->
  <packaging>war</packaging>
  <name>mavenproject Maven Webapp</name>
  <url>http://maven.apache.org</url>
  <!--依赖项-->
  <dependencies>
    <!--具体依赖的jar包配置文件-->
    <!--Maven的高级之处在于:它会帮你导入这个jar包的其他jar-->
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.13.2</version>
      <scope>test</scope>
    </dependency>


    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>5.3.17</version>
    </dependency>
  </dependencies>
  <!--项目构建用的东西-->
  <!--配置resources,来防止资源导出失败-->
  <build>
    <resources>
      <resource>
        <directory>src/main/resources</directory>
        <includes>
          <include>**/*.properties</include>
          <include>**/*.xml</include>
        </includes>
        <filtering>true</filtering>
      </resource>
      <resource>
        <directory>src/main/java</directory>
        <includes>
          <include>**/*.properties</include>
          <include>**/*.xml</include>
        </includes>
        <filtering>true</filtering>
      </resource>
    </resources>
  </build>
</project>

5.11、IDEA的操作

显示目录树:ctrl+alt+shift+U

六、Servlet

6.1、Servlet简介

  • Servlet就是Sun公司开发动态web的一门技术
  • 用于处理客户端(如浏览器)的请求并生成响应
  • Sun在这些API中提供了一个接口叫做:Servlet,如果你想要开发一个Servlet程序,只需要完成两个步骤:
    • 编写一个类,实现Servlet接口
    • 把开发好的java类部署到web服务器中

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

6.2、HelloServlet

Servlet接口在Sun公司有两个默认的实现类:HtppServlet,

1.构建一个Maven项目,删掉里面的无关东西比如src目录 ,然后在里面在构建新的module作为子项目;这个空的工程就是Maven主工程

注意这里存在Tomcat10的版本问题

参考如下:

https://www.cnblogs.com/sleepyhermit/p/15701302.html
注意!我用的是tomcat9,所以是javax.servlet-api

xml 复制代码
<!-- https://mvnrepository.com/artifact/jakarta.servlet/jakarta.servlet-api -->
<dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>4.0.1</version>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>javax.servlet.jsp</groupId>
      <artifactId>jsp-api</artifactId>
      <version>2.1</version>
    </dependency>

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

父项目有:

java 复制代码
  <modules>
    <module>servlet-01</module>
  </modules>

子项目有:

java 复制代码
    <parent>
        <groupId>org.example</groupId>
        <artifactId>javaweb-servlet</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>

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

java 复制代码
son extends father

接下来父项目就不用管了,接下来只要管子项目

3.MAVEN环境优化

1.修改web.xml为最新的(去Tomcat里面找)

我的电脑在D:\Program Files (x86)\apache-tomcat-9.0.98\webapps\ROOT\WEB-INF

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
                      http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0"
         metadata-complete="true">

</web-app>

2.将Maven的结构搭建完善

4.编写一个Servlet程序

  1. 编写一个普通类
  1. 实现Servlet类,这里直接继承HttpServlet
java 复制代码
package com.zxy.servlet;


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

public class HelloServlet extends HttpServlet {
//由于get或者post只是请求实现的不同方式,可以互相调用,业务逻辑都一样
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        PrintWriter writer = resp.getWriter();//响应流
        writer.println("Hello,Servlet");
    }

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

5.编写Servlet的映射

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

xml 复制代码
  <!--注册Servlet-->
<servlet>
   <servlet-name>hello</servlet-name>
   <servlet-class>com.zxy.servlet.HelloServlet</servlet-class>
</servlet>
  <!--客户端请求路径:http://localhost:8080/s1/hello1-->
    <!--Servlet的映射路径-->
    <!--Servlet 容器会将请求路径 /hello1 匹配到映射路径 /hello1,并调用对应的 Servlet 处理请求。-->
<servlet-mapping>
   <servlet-name>hello</servlet-name>
   <url-pattern>/hello</url-pattern>
</servlet-mapping>

6.配置Tomcat

注意:配置项目发布的路径

我的程序上下文是/s1

7.启动测试

6.3、Servlet原理

Servlet是由Web服务器调用,web服务器接收到浏览器请求之后,通过把请求和响应传送给Servlet里面的Service去调用方法对请求和响应进行处理。

这里图和方法参考至

https://www.cnblogs.com/wangjiming/p/10360327.html

步骤 1:客户端发起请求

客户端(如浏览器)通过 HTTP 协议向服务器发送请求。

例如:http://localhost:8080/s1/hello

步骤 2:Servlet 容器接收请求

Servlet 容器(如 Tomcat)接收到请求后,解析 URL,确定请求的上下文路径(Context Path)和请求路径(Request Path)。

例如:

上下文路径:/s1

请求路径:/hello

步骤 3:匹配 Servlet

Servlet 容器根据请求路径查找匹配的 Servlet。

匹配规则基于 web.xml 或注解(如 @WebServlet)中配置的 。

例如:

xml 复制代码
<servlet-mapping>
    <servlet-name>hello</servlet-name>
    <url-pattern>/hello</url-pattern>
</servlet-mapping>

运行 HTML

步骤 4:调用 Servlet 的生命周期方法

Servlet 容器根据请求调用 Servlet 的生命周期方法:

初始化: 调用 init() 方法(仅一次)。

处理请求: 调用 service() 方法(每次请求都会调用)。

对于 HTTP 请求,service() 方法会根据请求方法(GET、POST 等)调用对应的 doGet() 或 doPost() 方法。

销毁: 调用 destroy() 方法(Servlet 容器关闭或 Servlet 被移除时调用)。

步骤 5:生成响应

Servlet 通过 HttpServletResponse 对象生成响应内容(如 HTML、JSON)。

例如:

java 复制代码
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // Set the content type of the response to HTML
        response.setContentType("text/html");

        // Get the PrintWriter object to write the response
        PrintWriter out = response.getWriter();

        // Write the HTML content to the response
        out.println("<html>");
        out.println("<head><title>Hello Servlet</title></head>");
        out.println("<body>");
        out.println("<h1>Hello,World!</h1>");
        out.println("</body>");
        out.println("</html>");
    }

步骤 6:返回响应

Servlet 容器将生成的响应返回给客户端。

客户端(如浏览器)接收到响应后,渲染内容或执行其他操作。

6.4、Mapping问题

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

xml 复制代码
  <servlet-mapping>
    <servlet-name>hello</servlet-name>
    <url-pattern>/hello</url-pattern>
  </servlet-mapping>

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

xml 复制代码
  <servlet-mapping>
    <servlet-name>hello</servlet-name>
    <url-pattern>/hello1</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>hello</servlet-name>
    <url-pattern>/hello2</url-pattern>
  </servlet-mapping>  
  <servlet-mapping>
    <servlet-name>hello</servlet-name>
    <url-pattern>/hello3</url-pattern>
  </servlet-mapping>  
  <servlet-mapping>
    <servlet-name>hello</servlet-name>
    <url-pattern>/hello4</url-pattern>
  </servlet-mapping>

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

xml 复制代码
  <servlet-mapping>
    <servlet-name>hello</servlet-name>
    <url-pattern>/hello/*</url-pattern>
  </servlet-mapping>

4.默认请求路径

xml 复制代码
  <servlet-mapping>
    <servlet-name>hello</servlet-name>
    <url-pattern>/*</url-pattern>
  </servlet-mapping>

5.指定一些后缀或前缀等

xml 复制代码
  <servlet-mapping>
    <servlet-name>hello</servlet-name>
    <url-pattern>*.zxy</url-pattern>
  </servlet-mapping>

<!--这个地方表示,只要Url路径是.zxy,前面无论是什么都能访问到-->

6.优先级问题

固有的映射路径优先级高

通配符的优先级低

6.5、ServletContext

ServletContext 是 Java Servlet API 中的一个接口,它代表了整个 Web 应用程序的上下文环境。每个 Web 应用程序都有一个唯一的 ServletContext 对象(代表了当前的web应用),它在 Web 应用程序启动时由 Servlet 容器(如 Tomcat)创建,并在应用程序关闭时销毁。

web在请求的时候,它会为每个web程序都创建一个对应的ServletContext对象,它代表了当前的web应用:

1.共享数据

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

java 复制代码
package com.zxy.servlet;

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

public class HelloServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("Hello");
        //this.getInitParameter()初始化参数
        //this.getServletConfig();Servlet配置
        //this.getServletContext();Servlet上下文
        ServletContext servletContext = this.getServletContext();
        String username="小张";
        servletContext.setAttribute("username",username);//将一个数据保存在了ServletContext中,名字为:username(前者)--值为username(后者)
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.doPost(req, resp);
    }
}
java 复制代码
package com.zxy.servlet;

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

/**
 * @author zhangxuanyu
 * @version 17
 * @date
 */
public class GetServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    	/*ServletContext context = this.getServletContext();
        String username = (String) context.getAttribute("username");
        resp.getWriter().print("名字"+username);*/
        ServletContext servletContext = this.getServletContext();
        String username = servletContext.getAttribute("username").toString();
        resp.setContentType("text/html");
        resp.setCharacterEncoding("utf-8");
        resp.getWriter().print("名字:"+username);

    }

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

web.xml配置

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0"
         metadata-complete="true">
  <servlet>
    <servlet-name>hello</servlet-name>
    <servlet-class>com.zxy.servlet.HelloServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>hello</servlet-name>
    <url-pattern>/hello</url-pattern>
  </servlet-mapping>
  
  <servlet>
    <servlet-name>getc</servlet-name>
    <servlet-class>com.zxy.servlet.GetServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>getc</servlet-name>
    <url-pattern>/get</url-pattern>
  </servlet-mapping>

</web-app>

如上设置,如果不访问hello,直接访问get(使用的环境版本和我一样的话),将会得到如下

这里有一个问题,在于某些版本的Tomcat或者是IDEA的一些问题(目前不探究)或者使用的浏览器的问题,反正有很多种可能,将会有如下

2.获得初始化数据
xml 复制代码
  <!--配置一些web应用的初始化参数-->
  <context-param>
    <param-name>url</param-name>
    <param-value>jdbc:mysql://localhost:3306/mybatis</param-value>
  </context-param>
  <servlet>
    <servlet-name>gp</servlet-name>
    <servlet-class>com.zxy.servlet.ServletDemo03</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>gp</servlet-name>
    <url-pattern>/gp</url-pattern>
  </servlet-mapping>
java 复制代码
package com.zhong.wu;

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


public class ServletDemo03 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        ServletContext servletContext = this.getServletContext();

        String url = servletContext.getInitParameter("url");
        resp.getWriter().print(url);
    }

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

运行之后:

3.请求转发
xml 复制代码
  <servlet>
    <servlet-name>gp</servlet-name>
    <servlet-class>com.zxy.servlet.ServletDemo03</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>gp</servlet-name>
    <url-pattern>/gp</url-pattern>
  </servlet-mapping>

  <servlet>
    <servlet-name>sd4</servlet-name>
    <servlet-class>com.zxy.servlet.ServletDemo04</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>sd4</servlet-name>
    <url-pattern>/sd4</url-pattern>
  </servlet-mapping>
java 复制代码
package com.zxy.servlet;

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


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

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

}
java 复制代码
package com.zxy.servlet;

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


public class ServletDemo03 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        ServletContext servletContext = this.getServletContext();

        String url = servletContext.getInitParameter("url");
        resp.getWriter().print(url);
    }

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

转发是如图上半部分的关系,重定向是如图下半部分的关系。

A需要的资源由B去找C拿,再由B给A,这是转发。(即页面A的需要的资源由后台B去找另一个页面C获取,后台B在把这个资源交给页面A)

A需要的资源去找B要,B跟A说要去找C要,A找到C拿到资源,这是重定向。(即页面A需要的资源去询问后台B,后台B告诉页面A资源在页面C那里,然后页面A去找页面C要资源)

如果是转发,实际访问的页面路径还是原来的路径,本例子就是转发

而重定向,访问的路径会改变。

4.读取资源文件

Properties

  • 在JAVA目录下新建Properties。Properties properties = new Properties();
  • 在Resources目录下新建db.properties
properties 复制代码
username=root
password=123456

发现:都被打包在了同一目录下--classes

java 复制代码
package com.zxy.servlet;

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

public class ServletDemo05 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        InputStream resourceAsStream = this.getServletContext().getResourceAsStream("/WEB-INF/classes/db.properties");
        Properties properties = new Properties();
        properties.load(resourceAsStream);
        String user = properties.getProperty("username");
        String pwd = properties.getProperty("password");
        System.out.println(user);
        System.out.println(pwd);
        resp.getWriter().print(user+"----"+ pwd);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.doPost(req, resp);
    }
}
xml 复制代码
  <servlet>
    <servlet-name>sd5</servlet-name>
    <servlet-class>com.zxy.servlet.ServletDemo05</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>sd5</servlet-name>
    <url-pattern>/sd5</url-pattern>
  </servlet-mapping>

6.6、HttpServletResponse

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

  • 如果要获取客户端请求过来的参数,找HttpServletRequest
  • 如果要给客户端响应一些信息,找HttpServletResponse
1.简单分类

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

java 复制代码
public ServletOutputStream getOutputStream() throws IOException;
public PrintWriter getWriter() throws IOException;

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

java 复制代码
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);

//仅挑选了一部分

响应的状态码

java 复制代码
int SC_OK = 200;  //请求响应成功
int SC_NOT_FOUND = 404;  //找不到资源
int SC_INTERNAL_SERVER_ERROR = 500;  //服务器代码错误
2.常见应用

1.向浏览器输出消息

2.下载文件

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

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

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

        //1. 要获取下载的文件路径(绝对路径)
        String realPath = this.getServletContext().getRealPath("/WEB-INF/classes/img.jpg");
        System.out.println("下载的文件的路径:"+realPath);
        //  2. 下载的文件名
        String fileName = realPath.substring(realPath.lastIndexOf("\\") + 1);
        //  3. 设置想办法让浏览器支持下载我们需要的东西
        //需要中文的话,就进行编码设置
        resp.setHeader("Content-disposition","attachment;filename="+fileName);
        ///  4. 获取下载文件的输入流
        FileInputStream fis = new FileInputStream(realPath);
        //   5. 创建缓冲区
        /*buffer:用于临时存储文件数据的字节数组,大小为 1KB。
		len:记录每次读取的字节数。*/
        int len=0;
        byte[] buffer = new byte[1024];
        //   6. 获取OutputStream对象
        ServletOutputStream sos = resp.getOutputStream();
        //  7. 将FileOutputStream流写入到buffer缓冲区
        while((len=fis.read(buffer))!=-1){
            sos.write(buffer,0,len);
        }
        fis.close();
        sos.close();

        //   8. 使用OutputStream将缓冲区中的数据输出到客户端
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.doPost(req, resp);
    }
}
xml 复制代码
    <servlet>
        <servlet-name>fs</servlet-name>
        <servlet-class>com.zxy.servlet.FileServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>fs</servlet-name>
        <url-pattern>/fs</url-pattern>
    </servlet-mapping>
3.验证码功能

验证码怎么来?

  • 前端实现
  • 后端实现,需要用到JAVA的图片类,产生一个图片
java 复制代码
package com.zxy.servlet;


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

public class ImageServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //如何让浏览器五秒刷新一次
        resp.setHeader("refresh","5");
        //在内存中创建一个图片
        BufferedImage image = new BufferedImage(80,20,BufferedImage.TYPE_INT_RGB);
        //得到图片
        Graphics g =(Graphics2D) image.getGraphics();  //笔
        //设置图片背景颜色
        g.setColor(Color.white);
        g.fillRect(0,0,80,20);
        //给图片写数据
        g.setColor(Color.BLUE);
        g.setFont(new Font(null,Font.BOLD,20));
        g.drawString(makeNum(),0,20);
        //告诉浏览器这个请求用图片的方式打开
        resp.setContentType("image/jpg");
        //网站存在缓存,不让浏览器缓存
        resp.setDateHeader("expires",-1);
        resp.setHeader("Cache-Control","no-cache");
        resp.setHeader("Pragma","no-cache");
        //把图片写给浏览器
        boolean write = ImageIO.write(image,"jpg",resp.getOutputStream());

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

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}
xml 复制代码
<servlet>
    <servlet-name>is</servlet-name>
    <servlet-class>com.zxy.servlet.ImageServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>is</servlet-name>
    <url-pattern>/is</url-pattern>
  </servlet-mapping>
4.实现重定向

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

常见场景:

  • 用户登录:登录成功跳转到另一个页面
  • 表单提交后跳转到结果页

用resp.sendRedirect();实现

测试:

java 复制代码
package com.zxy.servlet;

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


public class RedirectServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.sendRedirect("img");
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.doPost(req, resp);
    }
}
xml 复制代码
    <servlet>
        <servlet-name>rs</servlet-name>
        <servlet-class>com.zxy.servlet.RedirectServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>rs</servlet-name>
        <url-pattern>/rs</url-pattern>
    </servlet-mapping>

代码运行之后输入/rs会跳转到/img

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

相同点:

  • 页面都会跳转

不同点:

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

测试2:

jsp 复制代码
//index.jsp:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>

<body>
<h2>Hello World!</h2>
<%--这里提交的路径,需要寻找到项目的路径 --%>
<%-- ${pageContext.request.contextPath}代表项目的路径--%>

<from action="${pageContext.request.contextPath}/rt" method="get">

    用户名:<input type="text" name="username">
    密码:<input type="text" name="password">
    <input type="submit">
</from>
</body>
</html>
jsp 复制代码
//sucess.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<h1>登陆成功</h1>
</body>
</html>
java 复制代码
package com.zxy.servlet;

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

public class RequestTest extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 设置请求编码
        req.setCharacterEncoding("UTF-8");

        // 设置响应编码
        resp.setCharacterEncoding("UTF-8");

        // 获取请求参数
        String username = req.getParameter("username");
        String password = req.getParameter("password");

        // 打印用户名和密码(用于测试)
        System.out.println("用户名: " + username);
        System.out.println("密码: " + password);

        // 重定向到 success.jsp
        resp.sendRedirect(req.getContextPath() + "/success.jsp");
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp); // 直接调用 doGet,避免重复代码
    }
}
xml 复制代码
    <servlet>
        <servlet-name>rt</servlet-name>
        <servlet-class>com.zxy.servlet.RequestTest</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>rt</servlet-name>
        <url-pattern>/rt</url-pattern>
    </servlet-mapping>

代码运行之后:

输入/rt跳转:

6.7、HttpServletRequest

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

1.获取前端传来的数据

使用 req.getParameter() 获取单个参数,使用 req.getParameterValues() 获取多个值(如复选框数据)

java 复制代码
package com.zxy.servlet;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.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 {
        req.setCharacterEncoding("utf-8");  //设置请求的字符编码为 UTF-8,解决中文乱码问题
        resp.setCharacterEncoding("utf-8");  //设置响应的字符编码为 UTF-8
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        String[] hobby = req.getParameterValues("hobby");
        //后台接受乱码问题

        System.out.println(username);
        System.out.println(password);
        System.out.println(Arrays.toString(hobby));

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

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req,resp);
    }
}
jsp 复制代码
//index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>登录</title>
</head>
<body>
<h1>登录</h1>
<div style="text-align: center">
    <%-- 这里以表单表示的意思是,以post的方式提交表单,提交到我们的Login请求--%>
    <form action="${pageContext.request.contextPath}/ls" method="post">
        用户:<input type="text" name="username"><br>
        密码:<input type="password" name="password"><br>
        爱好:
        <input type="checkbox" name="hobby" value="女孩">女孩
        <input type="checkbox" name="hobby" value="代码">代码
        <input type="checkbox" name="hobby" value="Terraria">Terraria
        <input type="checkbox" name="hobby" value="电影">电影

        <br>
        <input type="submit">
    </form>
</div>
</body>
</html>
jsp 复制代码
//success.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<h1>登陆成功</h1>
</body>
</html>
xml 复制代码
<servlet>
    <servlet-name>LoginServlet</servlet-name>
    <servlet-class>com.zxy.servlet.LoginServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>LoginServlet</servlet-name>
    <url-pattern>/ls</url-pattern>
  </servlet-mapping>

如出现控制台获取前端数据输出乱码问题,致谢参考如下

https://blog.csdn.net/a16310320524/article/details/104617520

2.请求转发

七、Cookie、Session

7.1会话

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

有状态会话:如果某个客户端访问过了一次,那么下一次他在访问的时候,服务器端知道,这个客户曾经访问过

7.2保存会话的两种技术

cookie

  • 客户端技术(响应,请求)
  • Cookie 是由服务器发送到浏览器并保存在客户端的一小块数据(通常是一个键值对)
  • 每次浏览器向服务器发送请求时,都会自动携带与该域名相关的 Cookie
  • Cookie 可以设置有效期,过期后会被浏览器删除。

session

  • 服务器技术,利用这个技术可以保存用户的会话信息

7.3、Cookie

1.从请求拿到cookie信息

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

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

cookie特点:

  • 存储在客户端:Cookie 保存在用户的浏览器中

  • 一个cookie只能保存一个信息

  • 一个web服务器站点可以给浏览器发送多个cookie,最多存放20个cookie

  • Cookie大小有限制4kb;

  • 300个浏览器cookie上限

cookie用途:

  • 用途

    • 记录用户偏好设置(如语言、主题)。

    • 记录用户的登录状态(如记住我功能)。

    • 跟踪用户行为(如广告推荐)。

cookie工作原理:

  • 服务器通过 HTTP 响应头的 Set-Cookie 字段将 Cookie 发送到浏览器。
  • 浏览器保存 Cookie,并在后续请求中通过 HTTP 请求头的 Cookie 字段将其发送回服务器。
  • 服务器读取 Cookie,并根据其中的信息做出响应

删除cookie

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

代码举例子

  • 在 Java 中创建 Cookie:

    java 复制代码
    // 创建一个 Cookie
    Cookie cookie = new Cookie("username", "zxy");
    // 设置有效期(单位:秒)
    cookie.setMaxAge(60 * 60 * 24); // 1 天
    // 将 Cookie 添加到响应中
    response.addCookie(cookie);
  • 在 Java 中读取 Cookie:

    java 复制代码
    // 获取所有 Cookie
    Cookie[] cookies = request.getCookies();
    if (cookies != null) {
        for (Cookie cookie : cookies) {
            if ("username".equals(cookie.getName())) {
                System.out.println("用户名:" + cookie.getValue());
            }
        }
    }
java 复制代码
package com.zxy.servlet;

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

public class CookieDemo01 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 设置请求和响应的字符编码
        req.setCharacterEncoding("utf-8");
        resp.setCharacterEncoding("utf-8");
        resp.setContentType("text/html;charset=UTF-8");

        PrintWriter writer = resp.getWriter();

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

        // 检查是否存在 Cookie
        if (cookies != null) {
            for (Cookie cookie : cookies) {
                // 检查是否有名为 "lastLoginTime" 的 Cookie
                if (cookie.getName().equals("lastLoginTime")) {
                    // 获取 Cookie 的值
                    String value = cookie.getValue();
                    long lastLoginTime = Long.parseLong(value);
                    Date date = new Date(lastLoginTime);
                    writer.write("你上一次访问的时间是:" + date.toLocaleString());
                    found = true;
                    break;
                }
            }
        }

        // 如果是第一次访问,或者没有找到 "lastLoginTime" Cookie
        if (!found) {
            writer.write("这是您第一次访问");
        }

        // 创建新的 Cookie,记录当前访问时间
        Cookie cookie = new Cookie("lastLoginTime", System.currentTimeMillis() + "");
        // 设置 Cookie 的有效期为 24 小时
        cookie.setMaxAge(24 * 60 * 60);
        // 将 Cookie 添加到响应中
        resp.addCookie(cookie);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp); // 通常 POST 请求可以调用 doGet 方法处理
    }
}
xml 复制代码
<servlet>
  <servlet-name>CookieDemo1</servlet-name>
  <servlet-class>com.zxy.servlet.CookieDemo01</servlet-class>
</servlet>
<servlet-mapping>
  <servlet-name>CookieDemo1</servlet-name>
  <url-pattern>/c1</url-pattern>
</servlet-mapping>

可以用URLEncode解决乱码问题

java 复制代码
package com.zxy.servlet;


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


public class CookieDemo02 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //创建一个Cookie,名字必须与被删除的一致
        Cookie cookie = new Cookie("lastLoginTime", System.currentTimeMillis() + "");

        //将cookie有效期设置为0
        cookie.setMaxAge(0);

        resp.addCookie(cookie);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.doPost(req, resp);
    }
}
java 复制代码
package com.zxy.servlet;

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


//中文数据传递
public class CookieDemo03 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setCharacterEncoding("utf-8");
        resp.setCharacterEncoding("utf-8");
        resp.setContentType("text/html;charset=UTF-8");

        PrintWriter writer = resp.getWriter();
        //Cookie,服务器端从客户端获取
        Cookie[] cookies = req.getCookies();//这里返回数组,说明cookie可能存在多个
        writer.write("你上一次访问的时间是");
        for (Cookie cookie : cookies) {
            //获得cookie的名字
            if (cookie.getName().equals("name")) {
                //获取cookie中的值

                String value = cookie.getValue();
                System.out.println(value);
                writer.write(value);
            }

        }

        //服务端给客户端响应一个cookie
        Cookie cookie = new Cookie("name", "小张");
        resp.addCookie(cookie);
    }

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

7.4、Session

什么是Session:

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

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

  • 用户登陆之后,整个网站它都可以访问 ------->保存用户信息

  • Session 是服务器端的一种机制,用于在多次请求之间保持用户的状态信息。

  • 每个用户会话都有一个唯一的 ID(Session ID),通常通过 Cookie 传递给客户端。

  • Session 数据存储在服务器端(服务器内存或数据库中)

Session特点:

  • 存储在服务器端:Session 数据保存在服务器中,客户端仅保存 Session ID。
  • 大小无限制:Session 可以存储较多的数据(但受服务器内存或数据库限制)。
  • 安全性较高:Session ID 是通过 Cookie 或 URL 传递的,数据本身不会暴露给客户端。
  • 用途
    • 记录用户的登录状态。
    • 存储用户的购物车信息。
    • 保存用户的临时数据(如表单提交)

Session 的工作原理

  1. 当用户第一次访问服务器时,服务器为其创建一个唯一的 Session ID,并存储在服务器内存或数据库中。
  2. 服务器通过 Set-Cookie 将 Session ID 发送到客户端。
  3. 客户端在后续请求中通过 Cookie 或 URL 将 Session ID 发送回服务器。
  4. 服务器根据 Session ID 找到对应的 Session 数据,并做出响应

代码举例子:

  • 在 Java 中创建和设置 Session 数据:

    java 复制代码
    // 获取 Session 对象(如果不存在则创建)
    HttpSession session = request.getSession();
    // 在 Session 中保存数据
    session.setAttribute("username", "zxy");
  • 在 Java 中读取 Session 数据:

    java 复制代码
    // 获取 Session 对象
    HttpSession session = request.getSession(false); // 如果不存在则返回 null
    if (session != null) {
        // 从 Session 中读取数据
        String username = (String) session.getAttribute("username");
        System.out.println("用户名:" + username);
    }
  • 销毁 Session:

    java 复制代码
    // 销毁当前 Session
    session.invalidate();

Session和Cookie

  • 打开浏览器的时候Session就存在了,而普通的Cookie需要访问指定页面创建
  • Session基于Cookie会话创建,但只存在在服务器,即服务器关闭则消失。而Cookie会保存在电脑。
  • Session跨Servlet共享数据
  • Cookie是把用户的数据写给用户的浏览器,浏览器保存(可以保存多个)
  • Session把用户的数据写到用户独占的Session,服务器端保存。(保存重要的信息,减少服务器资源的浪费)
  • Session对象由服务器创建
特性 Cookie Session
存储位置 客户端(浏览器) 服务器端
数据安全 不安全(容易被篡改或窃取) 较安全(数据存储在服务器)
存储大小 每个 Cookie 不超过 4KB,数量有限制 无限制(受服务器内存或数据库限制)
生命周期 可以设置有效期,过期后删除 默认在浏览器关闭后失效,或手动设置超时时间
用途 存储较小的、非敏感数据(如用户偏好) 存储较大的、敏感数据(如登录状态、购物车)
java 复制代码
package com.zxy.servlet;

import com.zxy.pojo.Person;

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


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

        //给Session中存东西
        session.setAttribute("name",new Person("小张",19));

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

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

        //Session创建的时候做了什么
        //Cookie jsessionid = new Cookie("JSESSIONID", id);
        // resp.addCookie(jsessionid);

    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.doPost(req, resp);
    }
}
java 复制代码
package com.zxy.servlet;

import com.zxy.pojo.Person;

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


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

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

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

手动注销

java 复制代码
package com.zxy.servlet;

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


public class SessionDemo03 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //手动注销Session
        HttpSession session = req.getSession();
        session.removeAttribute("name");
        session.invalidate();
    }

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

会话自动过期:配置xml

xml 复制代码
    <!--设置Session失效时间 -->
    <session-config>
        <!-- 设置1分钟后Session失效 -->
        <session-timeout>1</session-timeout>
    </session-config>
复制代码
 +-------------------+       +-------------------+       +-------------------+
 |    用户浏览器      |       |    服务器端         |        |   数据库/内存      |
 |-------------------|       |-------------------|       |-------------------|
 |                   |       |                   |       |                   |
 | 1. 用户访问网站     | ----> | 2. 服务器创建       |       |                   |
 |                   |       |    Session        | <---->| 存储 Session 数据  |
 |                   |       |                   |       |                   |
 | 3. 服务器发送       | <---- | 4. 服务器通过       |       |                   |
 |    Session ID     |       |    Set-Cookie 返回 |       |                   |
 |    (通过 Cookie)   |       |    Session ID     |       |                   |
 |                   |       |                   |       |                   |
 | 5. 浏览器保存       |       |                   |       |                   |
 |    Session ID     |       |                   |       |                   |
 |    (在 Cookie 中)  |       |                   |       |                   |
 |                   |       |                   |       |                   |
 | 6. 后续请求携带     | ----> | 7. 服务器根据       |       |                   |
 |    Session ID     |       |    Session ID     | <----> | 查找 Session 数据 |
 |    (通过 Cookie)   |       |   识别用户         |       |                   |
 |                   |       |                   |       |                   |
 +-------------------+       +-------------------+       +-------------------+

八、JSP

8.1、什么是JSP

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

最大的特点:

  • 写JSP像是在写html

  • 区别:

    • HTML只给用户提供静态的资源

    • JSP页面中可以嵌入JAVA代码,为用户提供动态数据

8.2、JSP原理

思路:JSP是怎样运行的

  • 代码层面没有问题

  • 服务器内部工作

    • tomcat中有一个work目录
    • IDEA中使用Tomcat的会在IDEA对应的tomcat产生一个work

我电脑上的地址

java 复制代码
C:\Users\ASUS\AppData\Local\JetBrains\IntelliJIdea2023.3\tomcat\aa0e3520-b813-4e2c-bc30-ab30aa36e8d6\work\Catalina\localhost\s2\org\apache\jsp

发现页面变成了Java程序

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

JSP最终也会被转换JAVA程序

JSP本质上就是一个Servlet

java 复制代码
//初始化
public void _jspInit() 
  
//销毁
public void _jspDestroy()

//JSPServic
public void _jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response)

1.判断请求

2.内置一些对象

java 复制代码
final javax.servlet.jsp.PageContext pageContext;	//页面上下文
javax.servlet.http.HttpSession session = null;	//Session
final javax.servlet.ServletContext application;	//applicationContext
final javax.servlet.ServletConfig config;		//config
javax.servlet.jsp.JspWriter out = null;		//out
final java.lang.Object page = this;			//page:当前
javax.servlet.jsp.JspWriter _jspx_out = null;		//请求
javax.servlet.jsp.PageContext _jspx_page_context = null;  //响应

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

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

4.以上的这些个对象我们可以在JSP页面中直接使用

在JSP页面中,只要是JAVA代码就会原封不动的输出

如果是html代码,就会被转换成为,类似

java 复制代码
 out.write("<html>\r\n");

的格式被输出到前端。

jsp 复制代码
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
hello
<%
String name="小张";

%>
name:<%=name%>


</body>
</html>

8.3、JSP基础语法

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

先在pom.xml中配置

xml 复制代码
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>servlet-api</artifactId>
      <version>2.5</version>
    </dependency>
<!--jsp依赖-->
    <dependency>
      <groupId>javax.servlet.jsp</groupId>
      <artifactId>javax.servlet.jsp-api</artifactId>
      <version>2.3.3</version>
    </dependency>
<!--jstl表达式的依赖-->
    <dependency>
      <groupId>javax.servlet.jsp.jstl</groupId>
      <artifactId>jstl-api</artifactId>
      <version>1.2</version>
    </dependency>
<!--standard标签库-->
    <dependency>
      <groupId>taglibs</groupId>
      <artifactId>standard</artifactId>
      <version>1.1.2</version>
    </dependency>

JSP表达式

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

JSP脚本片段

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

脚本片段的再实现

jsp 复制代码
<%
int x=10;
out.println(x);
%>

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

<%--   在代码里嵌入HTML元素 --%>
<%
    for (int i = 0; i < 5; i++) {
%>
<h1>Hello, World <%=i%></h1>
<%
    }
%>

EL表达式

jsp 复制代码
<%for (int i = 0; i < 5; i++) { %>
<h1>Hello,World</h1>
<% }%>

JSP声明

用于定义全局变量、方法或类

jsp 复制代码
<%!
    static {
        System.out.println("Loading Servlet!");
    }
    private int globalVar=0;
    public void zxy(){
        System.out.println("进入了方法zxy!");
    }
%>

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

在JSP中嵌入JAVA代码即可

jsp 复制代码
jsp基本语法
<%%>  代码片段
<%=%> 表达式
<%!%> 定义全局的方法
<%----%> 注释

在JSP页面中,JSP的注释不会在客户端源码中出现,但是HTML的注释会在客户端源码中出现

8.4、JSP指令

jsp 复制代码
<%--footer.jsp--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<h1>我是footer</h1>
<%
    int i=10;
    %>
jsp 复制代码
<%--header.jsp--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<h1>我是Header</h1>
jsp 复制代码
<%--hello.jsp--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>

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

<%-- JSP标签--%>
<%--在底层Servlet会将两个页面的代码写入当前JSP页面对应的Servlet页面 --%>
<%-- 这种写法本质还是三个页面--%>
<%-- 要注意变量的重复定义问题
在单独的一个页面内定义的变量是局部变量,而在总页面处定义的变量是全局变量
--%>
<jsp:include page="header.jsp"/>
<h1>网页主体</h1>
<%-- 在这里定义的变量如果出现重复将会直接报错--%>
<jsp:include page="footer.jsp"/>
</body>
</html>

8.5、九大内置对象

  • PageContext 存东西
  • Request 存东西
  • Response
  • Session 存东西
  • Application ServletContext 存东西
  • config SerlvetConfig
  • out
  • page ,几乎不用
  • excepetion

JSP 中的 九大内置对象 是 JSP 容器为开发者提供的可以直接使用的对象,无需显式声明或实例化。它们涵盖了 Web 开发中常用的功能,如请求、响应、会话管理、应用上下文等。以下是每个内置对象的详细介绍:


1. PageContext

  • 作用:

    • 提供了访问其他内置对象(如 request、response、session 等)的方法。
    • 用于在当前页面中存储数据(page 作用域)。
    • 支持属性的查找和设置(findAttribute、setAttribute 等)。
  • 示例:

    jsp 复制代码
    <%
        pageContext.setAttribute("name", "xiaozhang"); // 存储到 page 作用域
        String name = (String) pageContext.getAttribute("name"); // 从 page 作用域获取
    %>

2. Request

  • 作用:

    • 封装了客户端发送的 HTTP 请求信息。
    • 用于在一次请求中存储数据(request 作用域)。
    • 可以通过 getParameter() 获取请求参数,setAttribute() 设置属性,getAttribute() 获取属性。
  • 示例:

    jsp 复制代码
    <%
        String username = request.getParameter("username"); // 获取请求参数
        request.setAttribute("message", "Hello, World"); // 存储到 request 作用域
    %>

3. Response

  • 作用:

    • 封装了服务器对客户端的 HTTP 响应。
    • 用于设置响应头、状态码、重定向等。
  • 示例:

    jsp 复制代码
    <%
        response.setContentType("text/html"); // 设置响应内容类型
        response.sendRedirect("newPage.jsp"); // 重定向到新页面
    %>

4. Session

  • 作用:

    • 用于在一次会话中存储数据(session 作用域)。
    • 会话从用户打开浏览器开始,到关闭浏览器结束(或会话超时)。
    • 可以通过 setAttribute() 和 getAttribute() 管理会话数据。
  • 示例:

    jsp 复制代码
    <%
        session.setAttribute("user", "xiaozhang"); // 存储到 session 作用域
        String user = (String) session.getAttribute("user"); // 获取会话数据
    %>

5. Application(ServletContext)

  • 作用:

    • 代表了整个 Web 应用的上下文。
    • 用于在整个应用的生命周期中存储数据(application 作用域)。
    • 所有用户共享 application 中的数据。
  • 示例:

    jsp 复制代码
    <%
        application.setAttribute("counter", 100); // 存储到 application 作用域
        int counter = (Integer) application.getAttribute("counter"); // 获取应用数据
    %>

6. Config(ServletConfig)

  • 作用:

    • 封装了 Servlet 的配置信息。
    • 可以通过 getInitParameter() 获取初始化参数。
  • 示例:

    jsp 复制代码
    <%
        String value = config.getInitParameter("paramName"); // 获取初始化参数
    %>

7. Out

  • 作用:

    • 用于向客户端输出内容。
    • 是 JspWriter 的实例,类似于 Java 中的 PrintWriter。
  • 示例:

    jsp 复制代码
    <%
        out.println("Hello, World"); // 向客户端输出内容
    %>

8. Page

  • 作用:

    • 代表当前 JSP 页面的实例。
    • 实际是 this 的引用,指向当前 JSP 页面转换后的 Servlet 实例。
  • 注意:

    • page 对象在开发中几乎不使用。

9. Exception

  • 作用:

    • 仅在异常处理页面(isErrorPage="true")中可用。
    • 封装了异常信息。
  • 示例 :
    errorPage.jsp:

    jsp 复制代码
    <%@ page isErrorPage="true" %>
    <html>
    <body>
        <h1>Error Occurred</h1>
        <p><%= exception.getMessage() %></p> <!-- 输出异常信息 -->
    </body>
    </html>

    index.jsp:

    jsp 复制代码
    <%@ page errorPage="errorPage.jsp" %>
    <html>
    <body>
    <%
        int a = 10 / 0; // 触发异常
    %>
    </body>
    </html>

总结

内置对象 作用域 主要功能
PageContext page 管理页面范围内的属性,访问其他内置对象
Request request 封装 HTTP 请求,管理请求范围内的属性
Response 无 封装 HTTP 响应,设置响应头、重定向等
Session session 管理会话范围内的属性,存储用户会话数据
Application application 管理应用范围内的属性,存储全局数据
Config 无 获取 Servlet 配置信息
Out 无 向客户端输出内容
Page 无 代表当前 JSP 页面实例,几乎不使用
Exception 无 仅在异常处理页面中可用,封装异常信息

应用场景

  • PageContext:适用于仅在当前页面中使用的数据。
  • Request:适用于请求转发时携带的数据。
  • Session:适用于用户会话中的数据(如登录信息)。
  • Application:适用于全局共享的数据(如计数器)。
  • Exception:用于集中处理异常。

ctrl+?快速打出<%----%>

代码实战:

jsp 复制代码
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page isELIgnored="false" %>

<html>
<head>
    <title>Title</title>
</head>
<body>
<%
    pageContext.setAttribute("name1", "xiaozhang1"); // 数据仅在当前页面有效
    request.setAttribute("name2", "xiaozhang2");    // 数据在一次请求中有效,请求转发会携带这个数据
    session.setAttribute("name3", "xiaozhang3");    // 数据在一次会话中有效,从打开浏览器到关闭浏览器
    application.setAttribute("name4", "xiaozhang4"); // 数据在服务器运行期间有效,从打开服务器到关闭服务器
%>
<%--脚本片段里的代码会被原封不动生成到jsp.java中
要求:这里面的代码,必须保证java语法的正确性--%>
<%
    //通过pageContext取出我们保存的值
    //从底层到该高层(作用域):page->request->session->application,即从小范围到大范围
    //JVM:双亲委派机制
    String name1 = (String) pageContext.findAttribute("name1");
    String name2 = (String) pageContext.findAttribute("name2");
    String name3 = (String) pageContext.findAttribute("name3");
    String name4 = (String) pageContext.findAttribute("name4");
    String name5 = (String) pageContext.findAttribute("name5"); // name5 不存在,值为 null
%>

<%--使用EL表达式输出 ${}--%>
<h1>取出的值</h1>
<h3>${name1}</h3> <!-- 输出: xiaozhang1 -->
<h3>${name2}</h3> <!-- 输出: xiaozhang2 -->
<h3>${name3}</h3> <!-- 输出: xiaozhang3 -->
<h3>${name4}</h3> <!-- 输出: xiaozhang4 -->
<h3>${name5}</h3> <!-- 输出: 空字符串 -->
<h3><%=name5%></h3> <!-- 输出: null -->

</body>
</html>
jsp 复制代码
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page isELIgnored="false" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<%
  //从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");
  String name5 = (String)pageContext.findAttribute("name5");


%>

<%-- 使用EL表达式输出--%>
<h1>取出的值</h1>
<h3>${name1}</h3>
<h3>${name2}</h3>
<h3>${name3}</h3>
<h3>${name4}</h3>
<h3>${name5}</h3>
<%--EL表达式会过滤空值 --%>
<h3><%=name5%></h3>
</body>
</html>
java 复制代码
pageContext.setAttribute("name1","xiaozhang1");//保存的数据仅在一个页面有效
request.setAttribute("name2","xiaozhang2");//保存的数据只在一次请求中有效,请求转发可以携带这个数据
session.setAttribute("name3","xiaozhang3");//保存的数据只在一次会话中有效,从打开浏览器到关闭浏览器
application.setAttribute("name4","xiaozhang4");//保存的数据只在服务器中有效,从打开服务器到关闭服务器

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

session:客户端向服务器发送请求,产生的数据可能等下用户还会再次使用。如购物车

applicaiton:客户断向服务器发送请求,产生的数据,一个用户用完了,可以让另一个用户使用,如聊天信息

增加了转发到index.jsp

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

<%
    pageContext.forward("/index.jsp");
%>

</body>
</html>

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

EL表达式: ${}

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

确认IDEA开启了EL表达式使用:

jsp 复制代码
<%@ page isELIgnored="false" %>

JSP标签

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

jsp 复制代码
<%-- jsp:clude--%>
<jsp:forward page="/jsptag2.jsp">
    <jsp:param name="value1" value="value1"/>
    <jsp:param name="value2" value="value2"/>

举例子:

jsp 复制代码
<%--jsptag.jsp--%>
<%@ page isELIgnored="false" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>

<h1>tag1</h1>
<%--<jsp:include>--%>

<jsp:forward page="/jsptag2.jsp">
    <jsp:param name="name" value="zxy"></jsp:param>
    <jsp:param name="age" value="18"></jsp:param>
</jsp:forward>

</body>
</html>
jsp 复制代码
<%--jsptag2.jsp--%>
<%@ page isELIgnored="false" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>

<h1>tag2</h1>
姓名:<%=request.getParameter("name")%>
年龄:<%=request.getParameter("age")%>
</body>
</html>

JSTL标签

JSTL标签库的使用是为了弥补HTML标签的不足;它自定义了许多标签供用户使用,标签的功能和JAVA代码功能相同。

JSTL 提供了一系列功能强大的标签,可以处理常见的任务,如循环、条件判断、格式化、数据库操作等。

  • 核心标签(掌握部分)
jsp 复制代码
<%-- 引入JSTL标签库的核心标签--%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>

JSTL标签库的使用步骤

  1. 引入对应的taglib标签库
  2. 使用其中的方法
jsp 复制代码
<%--jstl.jsp--%>
<%@ page isELIgnored="false" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%-- 引入JSTL标签库的核心标签--%>
<%@ 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">
    <%-- EL表达式获取表单中的数据
    ${param.参数名}
    --%>
    <input type="text" name="username" value="${param.username}">
    <input type="submit" value="登录">
</form>
<%--判断如果提交的用户是管理员,则登陆成功
 --%>
<c:if test="${param.username=='admin'}" var="isAdimin">
    <c:out value="管理员欢迎您!"/>
</c:if>
<%--自闭合标签 --%>
<c:out value="${isAdimin}"/>
</body>
</html>
jsp 复制代码
<%--coreif.jsp--%>
<%@ page isELIgnored="false" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%--引入jstl核心标签库,我们才能使用jstl标签 core--%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<h4>if测试</h4>
<form action="coreIf.jsp" method="get">
    <%--
    el表达式获取表单中的数据
    ${param.参数名}
    --%>
    <input type="text" name="username" value="${param.username}">
    <input type="submit" value="登录">
</form>

<%--判断如果提交的用户名是管理员,则登录成功--%>
<c:if test="${param.username=='admin'}" var="isAdmin">
    <c:out value="管理员欢迎你!"></c:out>
</c:if>

<c:out value="${isAdmin}"></c:out>

</body>
</html>
jsp 复制代码
<%--coreWhen.jsp--%>
<%@ page isELIgnored="false" %>
<%@ 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>
<c:set var="score" value="100"/>
<c:choose>
    <c:when test="${score>90}">优秀</c:when>
    <c:when test="${score>80}">良好</c:when>
    <c:when test="${score>60}">一般</c:when>
    <c:otherwise>不及格</c:otherwise>
</c:choose>
</body>
</html>
jsp 复制代码
<%--coreForeach.jsp--%>
<%@ page isELIgnored="false" %>
<%@ page import="java.util.ArrayList" %>
<%@ page import="java.util.List" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>

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

<%--
var 每一次遍历出来的变量
item 要遍历的对象
begin 开始下标
end 结束下标
step  步长
--%>
<c:forEach var="person" items="${personList}">
    <c:out value="${person}"/><br/>
</c:forEach>
<hr/>
<c:forEach var="person" items="${personList}" begin="1" end="3" step="2">
    <c:out value="${person}"/><br/>
</c:forEach>

</body>
</html>
  • 格式化标签

  • SQL标签

运行SQL查询语句

  • XML标签

九、JavaBean

实体类

JavaBean有特定的写法

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

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

ORM:对象关系映射

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

person表

i name age adress
1 xiaozhang1 3 湖南
2 xiaozhang2 18 湖南
3 xiaozhang3 100 湖南
java 复制代码
//实体类都是和数据库中的表结构一一对应
class person{
  private int id;
  private String name;
  private int age;
  private String adress; 
  //...省了构造方法和get set 方法
}
jsp 复制代码
<%--javabean.jsp--%>
<%@ page import="pojo.Student" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>

<%
    //    Student student = new Student();
//    student.setAddress("深圳");
//    student.setAge(18);
//    student.setId(1);
//    student.setName("zxy");
%>

<jsp:useBean id="student" class="pojo.Student" scope="page"/>

<jsp:setProperty name="student" property="address" value="深圳"/>
<jsp:setProperty name="student" property="age" value="18"/>
<jsp:setProperty name="student" property="id" value="1"/>
<jsp:setProperty name="student" property="name" value="zyy"/>

<%--  <%=student.getAddress()%>   --%>
地址:<jsp:getProperty name="student" property="address"/>
年龄:<jsp:getProperty name="student" property="age"/>
id:<jsp:getProperty name="student" property="id"/>
姓名:<jsp:getProperty name="student" property="name"/>

</body>
</html>

十、MVC三层架构

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

10.1早些年的开发模式

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

java 复制代码
servlet--CRUD--->数据库
  弊端:程序十分臃肿,不利于维护
  servlet代码中:处理请求、响应、视图跳转、处理JDBC、处理逻辑代码、处理业务代码

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

调用

|

|

JDBC

|

|

Mysql Oracle Sqlserver

10.2、MOV的三层架构

模型(Model)

模型层负责处理应用程序的核心数据和业务逻辑。它直接与数据库或其他数据源交互,管理数据的存取、验证、更新和删除等操作。数据持久层:CRUD (DAO)

  • 主要职责:
    • 管理数据、业务规则和逻辑
    • 与数据库或其他持久化存储系统交互
    • 提供数据访问接口供控制器调用
  • 特点:
    • 与视图和控制器无关,独立于界面和用户交互逻辑。
    • 通常包含数据实体、数据访问对象(DAO)、服务层等。
  • 举例:
    • 在用户管理系统中,模型层可能包含用户数据的增删改查操作,以及用户权限验证等逻辑。

视图(View)

视图层负责呈现用户界面,是用户与应用程序交互的窗口。它从模型中获取数据并以可视化的形式展示给用户。

  • 主要职责:
    • 负责数据的展示和界面设计。
    • 从模型获取数据并渲染到界面上。
    • 不直接处理业务逻辑,只负责显示数据。
  • 特点:
    • 与模型和控制器解耦,只关注如何呈现数据。
    • 可以是HTML页面、图形用户界面(GUI)或其他形式的界面。
  • 举例:
    • 在Web应用中,视图通常是由HTML、CSS和JavaScript组成的页面,用于展示用户信息或操作界面。

控制器(Controller)

控制器层是模型和视图之间的桥梁,负责处理用户的输入和交互逻辑。它从视图接收用户请求,调用模型处理数据,并将结果返回给视图。

  • 主要职责 :
    • 接收用户输入(req:请求参数、Session信息...):如点击按钮、提交表单等
    • 交给业务层处理对应的代码
    • 调用模型处理业务逻辑
    • 将模型处理的结果传递给视图进行渲染,控制视图的跳转
  • 特点 :
    • 负责协调模型和视图之间的交互
    • 不直接处理数据或界面,只负责流程控制
  • 举例 :
    • 当用户在Web页面提交表单时,控制器接收表单数据,调用模型进行验证和存储,并将结果返回给视图进行显示

十一、Filter(过滤器)--重点

Filter:过滤器,用来过滤网站的数据。即用于拦截请求和响应,可以在请求到达目标资源之前或响应返回给客户端之前执行某些操作。常见的应用场景包括编码设置、权限验证、日志记录等。

  • 处理中文乱码
  • 登录验证
过滤器的生命周期
  1. 初始化 :
    • 过滤器实例化后会调用 init(FilterConfig config) 方法。
    • 可以在此方法中加载配置或初始化资源。
  2. 过滤 :
    • 每次请求时都会调用 doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 方法。
    • 在此方法中可以对请求和响应进行处理,然后通过 chain.doFilter(request, response) 将请求传递给下一个过滤器或目标资源。
  3. 销毁 :
    • 过滤器销毁时会调用 destroy() 方法。
    • 可以在此方法中释放资源。

Filter开发步骤:

1.导包

2.编写过滤器

java 复制代码
package com.zxy.filter;

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

//Chain:链,过滤中的所有代码,在过滤特定的请求时执行
public class CharacterEncodingFilter implements Filter {
    //初始化
    //在web服务器启动的时候就已经完成初始化
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("CharacterEncodingFilter已经初始化了");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        servletRequest.setCharacterEncoding("utf-8");
        servletResponse.setCharacterEncoding("utf-8");
        servletResponse.setContentType("text/html;charset=UTF-8");

        System.out.println("CharacterEncodingFilter执行前");
        filterChain.doFilter(servletRequest,servletResponse);//让请求继续走,如果不写,程序在这里就被拦截了,不会接着去走其他拦截器
        System.out.println("CharacterEncodingFilter执行后");
    }
    //销毁
    //在web服务器关闭的时候,过滤器会销毁
    @Override
    public void destroy() {
        System.out.println("CharacterEncodingFilter已经销毁了");
    }
}
java 复制代码
package com.zxy.filter;

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

@WebFilter(urlPatterns = "/*")
public class MyFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("过滤器初始化");
    }
    
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        System.out.println("执行过滤操作");
        chain.doFilter(request, response);
    }

    @Override
    public void destroy() {
        System.out.println("过滤器销毁");
    }
}

3.在web.xml中配置Filter

xml 复制代码
   <filter>
        <filter-name>CharacterEncodingFilter</filter-name>
        <filter-class>com.zxy.filter.CharacterEncodingFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>CharacterEncodingFilter</filter-name>
        <!-- 只要是/servlet的任何请求,都会经过这个过滤器-->
        <url-pattern>/servlet/*</url-pattern>
    </filter-mapping>
xml 复制代码
<filter>
    <filter-name>MyFilter</filter-name>
    <filter-class>com.zxy.filter.MyFilter</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>MyFilter</filter-name>
    <url-pattern>/MF</url-pattern>
  </filter-mapping>

十二、监听器

监听器用于监听 Web 应用中的特定事件,例如 ServletContext、HttpSession 和 ServletRequest 的生命周期事件,以及属性值的变化事件。监听器可以实现对应用状态的监控和处理

实现一个监听器的接口即可

1.1 ServletContext 监听器
  • ServletContextListener :
    • 监听 ServletContext 的创建和销毁。
    • 可以实现应用启动时初始化资源,应用关闭时释放资源。
    • 主要方法:
      • contextInitialized(ServletContextEvent sce):当 ServletContext 初始化时调用。
      • contextDestroyed(ServletContextEvent sce):当 ServletContext 销毁时调用。
  • ServletContextAttributeListener :
    • 监听 ServletContext 中属性的添加、删除和替换。
    • 主要方法:
      • attributeAdded(ServletContextAttributeEvent scab):添加属性时调用。
      • attributeRemoved(ServletContextAttributeEvent scab):删除属性时调用。
      • attributeReplaced(ServletContextAttributeEvent scab):替换属性时调用。
1.2 HttpSession 监听器
  • HttpSessionListener :
    • 监听 HttpSession 的创建和销毁。
    • 主要方法:
      • sessionCreated(HttpSessionEvent se):当 HttpSession 创建时调用。
      • sessionDestroyed(HttpSessionEvent se):当 HttpSession 销毁时调用。
  • HttpSessionAttributeListener :
    • 监听 HttpSession 中属性的添加、删除和替换。
    • 主要方法:
      • attributeAdded(HttpSessionBindingEvent se):添加属性时调用。
      • attributeRemoved(HttpSessionBindingEvent se):删除属性时调用。
      • attributeReplaced(HttpSessionBindingEvent se):替换属性时调用。
1.3 ServletRequest 监听器
  • ServletRequestListener :
    • 监听 ServletRequest 的创建和销毁。
    • 主要方法:
      • requestInitialized(ServletRequestEvent sre):当请求初始化时调用。
      • requestDestroyed(ServletRequestEvent sre):当请求销毁时调用。
  • ServletRequestAttributeListener :
    • 监听 ServletRequest 中属性的添加、删除和替换。
    • 主要方法:
      • attributeAdded(ServletRequestAttributeEvent srae):添加属性时调用。
      • attributeRemoved(ServletRequestAttributeEvent srae):删除属性时调用。
      • attributeReplaced(ServletRequestAttributeEvent srae):替换属性时调用。
1.4 其他监听器
  • HttpSessionBindingListener

    :

    • 监听某个对象绑定到 HttpSession 或从 HttpSession 中解绑的事件。
    • 主要方法:
      • valueBound(HttpSessionBindingEvent event):当对象绑定到 HttpSession 时调用。
      • valueUnbound(HttpSessionBindingEvent event):当对象从 HttpSession 中解绑时调用。

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

1.编写一个监听器

实现监听器的接口

java 复制代码
package com.zxy.listener;


import javax.servlet.ServletContext;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;


//统计网站在线人数: 即统计session
public class OnlineCountListener implements HttpSessionListener {
    //创建session监听:看你的一举一动
    //一旦创建Session就会触发这个事件
    @Override
    public void sessionCreated(HttpSessionEvent se) {
        ServletContext sc = se.getSession().getServletContext();
        Integer onlineCount = (Integer) sc.getAttribute("OnlineCount");
        if(onlineCount==null){
            onlineCount=new Integer(1);
        }else{
            int count=onlineCount.intValue();
            onlineCount=new Integer(count+1);
        }

        sc.setAttribute("OnlineCount",onlineCount);

    }
    //销毁session监听
    @Override
    public void sessionDestroyed(HttpSessionEvent se) {
        ServletContext sc = se.getSession().getServletContext();
        Integer onlineCount = (Integer) sc.getAttribute("OnlineCount");
        if(onlineCount==null){
            onlineCount=new Integer(0);
        }else{
            int count=onlineCount.intValue();
            onlineCount=new Integer(count-1);
        }

        sc.setAttribute("OnlineCount",onlineCount);
    }
}
java 复制代码
package com.zxy.listener;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;

@WebListener
public class MyContextListener implements ServletContextListener {
    @Override
    public void contextInitialized(ServletContextEvent sce) {
        System.out.println("ServletContext 初始化");
    }
    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        System.out.println("ServletContext 销毁");
    }
}

2.配置监听器

xml 复制代码
  <listener>
    <listener-class>com.zxy.listener.OnlineCountListener</listener-class>
  </listener>
xml 复制代码
<listener>
    <listener-class>com.zxy.listener.MyContextListener</listener-class>
</listener>

十三、过滤器和监听器的常见应用

特性 监听器 过滤器
作用 监听应用中的事件(如启动、销毁、属性变化等) 拦截请求和响应,执行额外的处理逻辑
适用场景 监听生命周期事件、属性变化 权限验证、编码设置、日志记录等
执行时机 事件发生时触发 请求到达目标资源之前或响应返回给客户端之前
主要接口 ServletContextListener、HttpSessionListener 等 Filter

监听器:GUI编程中经常用到;

java 复制代码
package com.zxy.listener;

import java.awt.*;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;

public class TestPanel {
    public static void main(String[] args) {
        Frame frame = new Frame();  //新建一个窗体
        Panel panel = new Panel();   //面板
        frame.setLayout(null);   //设置窗体布局

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

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

        frame.add(panel);

        frame.setVisible(true);

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

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

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

            @Override
            public void windowIconified(WindowEvent e) {

            }

            @Override
            public void windowDeiconified(WindowEvent e) {

            }

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

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


    }
}

用户登录后才能进入主页!用户注销后就不能进入主页

1.用户登录之后,向Session中放入用户的数据

2.进入主页的时候要判断用户是否已经登录,要求,在过滤器中实现

java 复制代码
package com.zxy.filter;


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

public class SysFilter implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        //
        HttpServletRequest request1 = (HttpServletRequest) request;
        HttpServletResponse response1 = (HttpServletResponse) response;
        Object user_session = request1.getSession().getAttribute("USER_SESSION");
        if(user_session==null){
            response1.sendRedirect("/error.jsp");
        }


        chain.doFilter(request,response);
    }

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

    @Override
    public void destroy() {
        Filter.super.destroy();
    }
}
xml 复制代码
  <filter>
    <filter-name>SysFilter</filter-name>
    <filter-class>com.zxy.filter.SysFilter</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>SysFilter</filter-name>
    <url-pattern>/sys/*</url-pattern>
  </filter-mapping>

十四、JDBC

JDBC复习

什么是jdbc:java连接数据库!

需要jar包的支持:

java.sql

javax.sql

mysql-connection-java...(连接驱动)

实验环境搭建:

sql 复制代码
DROP TABLE `users`;

CREATE TABLE `users`(
  `id` INT PRIMARY KEY,
  `name` VARCHAR(50) NOT NULL,
  `password` VARCHAR(40) NOT NULL,
  `email` VARCHAR(60) NOT NULL,
  `birthday` DATE
) ENGINE=INNODB DEFAULT CHARSET=utf8

INSERT INTO `users` (`id`, `name`, `password`, `email`, `birthday`) VALUES('1','张三','123456','zs@sina.com','2021-07-14');
INSERT INTO `users` (`id`, `name`, `password`, `email`, `birthday`) VALUES('2','李四','123456','lisi@sina.com','1981-12-04');
INSERT INTO `users` (`id`, `name`, `password`, `email`, `birthday`) VALUES('3','王五','123456','wangwu@sina.com','1982-12-04');
INSERT INTO `users` (`id`, `name`, `password`, `email`, `birthday`) VALUES('4','赵六','123456','zhaoliu@sina.com','1987-12-05');
INSERT INTO `users` (`id`, `name`, `password`, `email`, `birthday`) VALUES('5','钱七','123456','qianqi@sina.com','2021-07-19');
INSERT INTO `users` (`id`, `name`, `password`, `email`, `birthday`) VALUES('6','刘八','123456','liuba@sina.com','2021-07-19');

导入数据库依赖pom.xml

xml 复制代码
<?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>com.zxy</groupId>
    <artifactId>javaweb-jdbc</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.49</version>
        </dependency>
    </dependencies>
</project>

idea连接数据库

jdbc固定步骤:

加载驱动

连接数据库

创建Statement

编写sql

执行sql

关闭连接

java 复制代码
package com.zxy;

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

public class TestJdbc {
    public static void main(String[] args) {
        String url = "jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf-8";
        String user = "root";
        String pwd = "123456";
        try {

            //1. 加载驱动
            Class.forName("com.mysql.jdbc.Driver");
            //2. 连接数据库
            Connection con = DriverManager.getConnection(url, user, pwd);
            //3. 向数据库发送sql的对象Statement:crud
            Statement statement = con.createStatement();

            //4.编写sql
            String str = "select * from users";

            //5.执行sql
            ResultSet rs = statement.executeQuery(str);
            while (rs.next()) {
                System.out.println("id=" + rs.getInt("id"));
                System.out.println("name=" + rs.getString("name"));
                System.out.println("password=" + rs.getString("password"));
                System.out.println("email=" + rs.getString("email"));
                System.out.println("birthday=" + rs.getString("birthday"));
            }
            //6.关闭连接,释放资源
            rs.close();
            statement.close();
            con.close();

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

预编译

java 复制代码
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;

public class Test2Jdbc {
    public static void main(String[] args) {
        String url = "jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf-8";
        String user = "root";
        String pwd = "123456";
        try {
            // 1. 加载驱动(JDBC 4.0 之后可以省略)
            Class.forName("com.mysql.jdbc.Driver");

            // 2. 连接数据库
            Connection con = DriverManager.getConnection(url, user, pwd);

            // 3. SQL
            String str = "INSERT INTO users(id, name, password, email, birthday) VALUES (?,?,?,?,?)";

            // 4. 预编译
            PreparedStatement statement = con.prepareStatement(str);
            statement.setInt(1, 8);  //给第一个占位符的值赋值8
            statement.setString(2, "小红"); //给第二个占位符的值赋值小红
            statement.setString(3, "123456");
            statement.setString(4, "xiaohong@sina.com");
            statement.setDate(5, new java.sql.Date(System.currentTimeMillis()));

            // 5. 执行SQL
            int count = statement.executeUpdate();

            if (count > 0) {
                System.out.println("插入成功!");
            }

            // 6. 释放资源
            statement.close();
            con.close();

        } catch (ClassNotFoundException e) {
            System.err.println("加载数据库驱动失败: " + e.getMessage());
        } catch (SQLException e) {
            System.err.println("数据库操作失败: " + e.getMessage());
        }
    }
}

jdbc事务

要么都成功,要么都失败

ACID原则:保证数据的安全

复制代码
开启事务
事务提交  commit()
事务回滚  rollback()
关闭事务

转账:
A:1000
B:1000

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

Junit单元测试

依赖

xml 复制代码
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.13</version>
</dependency>

简单实用

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

java 复制代码
import org.junit.Test;

public class Test3Jdbc {

    @Test
    public void test() {
        System.out.println("hello");
    }
}
sql 复制代码
CREATE TABLE `account`(
  `id` INT PRIMARY KEY,
  `name` VARCHAR(50) NOT NULL,
  `money` FLOAT NOT NULL
) ENGINE=INNODB DEFAULT CHARSET=utf8

INSERT INTO `account` (`id`, `name`, `money`) VALUES(1,'A',1000);
INSERT INTO `account` (`id`, `name`, `money`) VALUES(2,'B',1000);
INSERT INTO `account` (`id`, `name`, `money`) VALUES(3,'C',1000);
sql 复制代码
#数据库里面试
# 开启事务
start transaction ;

# 模拟转账
update account set money=money-100 where name='A';
update account set money=money+100 where name='B';

# 回滚
rollback ;

# 提交
commit;
java 复制代码
import org.junit.Test;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

public class Test3Jdbc {

    @Test
    public void test() {

        String url = "jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf-8";
        String user = "root";
        String pwd = "123456";
        Connection con = null;
        try {

            Class.forName("com.mysql.jdbc.Driver");
            con = DriverManager.getConnection(url, user, pwd);


            //开启事务 这里不开启事务的话异常情况就会有问题   false是开启
            con.setAutoCommit(false);

            con.prepareStatement("update account set money=money-100 where name='A'").executeUpdate();

            //制造错误
//            int i = 1 / 0;

            con.prepareStatement("update account set money=money+100 where name='B'").executeUpdate();

            con.commit();

            System.out.println("success");

        } catch (Exception e) {
            System.out.println("error rollback");
            if (con != null) {
                try {
                    con.rollback();
                } catch (SQLException ex) {
                    ex.printStackTrace();
                }
            }


        } finally {
            if (con != null) {
                try {
                    con.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }

    }
}

十五、SMBMS

数据库:

15.1项目搭建

1.搭建一个Maven web项目

2.配置Tomcat

3.测试项目是否能运行

4.导入项目中所需要的包

jsp,servlet,mysql驱动,jstl,stand

5.创建项目包结构

6.编写实体类

ORM映射;表--类映射

7.编写基础公共类

  1. 数据库配置文件

    properties 复制代码
    driver=com.mysql.jdbc.Driver
    url=jdbc:mysql://localhost:3306?useUnicode=true&characterEncoding=tuf-8
    username=root
    password=123456
  2. 编写数据库的公共类

    java 复制代码
    package com.zxy.dao;
    
    import java.io.IOException;
    import java.io.InputStream;
    import java.sql.*;
    import java.util.Properties;
    
    
    //操作数据库的公共类
    public class BaseDao {
        private static String driver;
        private static String url;
        private static String username;
        private static String password;
    
        //静态代码块,类加载的时候即初始化
        static {
            Properties properties = new Properties();
            //通过类加载器读取对应的资源
            InputStream is = BaseDao.class.getClassLoader().getResourceAsStream("db.properties");
    
            try {
                properties.load(is);
    
    
            } catch (IOException e) {
                e.printStackTrace();
            }
            driver = properties.getProperty("driver");
            url=properties.getProperty("url");
            username=properties.getProperty("username");
            password=properties.getProperty("password");
    
            //获取数据库的连接
    
    
        }
        public static   Connection getConnection(){
            Connection connection=null;
            try {
                Class.forName(driver);
                connection= DriverManager.getConnection(url,username,password);
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
            }
            return  connection;
        }
        //编写查询公共类
        public  static ResultSet execute(Connection connection,PreparedStatement preparedStatement,ResultSet resultSet,String sql,Object[] params) throws SQLException {
            //预编译的SQL
            preparedStatement = connection.prepareStatement(sql);
            for (int i = 0; i < params.length; i++) {
                //setObject占位符从1开始,但是数组是从0开始
                preparedStatement.setObject(i+1,params[i]);
            }
            resultSet = preparedStatement.executeQuery();
    
            return  resultSet;
        }
        //编写CURD
        //更新
        public  static int execute(Connection connection,PreparedStatement preparedStatement,String sql,Object[] params) throws SQLException {
            preparedStatement = connection.prepareStatement(sql);
            for (int i = 0; i < params.length; i++) {
                //setObject占位符从1开始,但是数组是从0开始
                preparedStatement.setObject(i+1,params[i]);
            }
            int i = preparedStatement.executeUpdate();
    
            return i;
        }
    
        //释放资源
        public static boolean closeResource(Connection connection,ResultSet resultSet,PreparedStatement preparedStatement){
            boolean flag=true;
            if(resultSet!=null){
                try {
                    resultSet.close();
                    //GC回收
                    resultSet=null;
                } catch (SQLException e) {
                    e.printStackTrace();
                    flag=false;
                }
            }
            if(connection!=null){
                try {
                    connection.close();
                    //GC回收
                    connection=null;
                } catch (SQLException e) {
                    e.printStackTrace();
                    flag=false;
                }
            }
            if(preparedStatement!=null){
                try {
                    preparedStatement.close();
                    //GC回收
                    preparedStatement=null;
                } catch (SQLException e) {
                    e.printStackTrace();
                    flag=false;
                }
            }
            return flag;
        }
    }
  3. 编写字符编码过滤器

java 复制代码
package com.zxy.filter;

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


public class CharacterEncodingFilter implements Filter {

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        request.setCharacterEncoding("utf-8");
        response.setCharacterEncoding("utf-8");

        chain.doFilter(request,response );
    }

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

    @Override
    public void destroy() {
        Filter.super.destroy();
    }
}
xml 复制代码
    <!-- 字符编码过滤器-->
    <filter>
        <filter-name>CharacterEncodingFilter</filter-name>
        <filter-class>com.zxy.filter.CharacterEncodingFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>CharacterEncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

8.导入静态资源

15.2登录功能实现

1.编写前端页面

2.设置主页

xml 复制代码
    <!--设置欢迎页面 -->
    <welcome-file-list>
        <welcome-file>login.jsp</welcome-file>
    </welcome-file-list>

3.编写dao层登录用户登录的接口

java 复制代码
package com.zxy.dao.user;

import com.zxy.pojo.User;

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


public interface UserDao {
    //得到要登录的用户
    public User getLoginUser(Connection connection,String userCode) throws SQLException;
}

4.编写dao接口的实现类

java 复制代码
package com.zxy.dao.user;

import com.zxy.dao.BaseDao;
import com.zxy.pojo.User;

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

public class UserDaoImp implements UserDao{
    @Override
    public User getLoginUser(Connection connection, String userCode) throws SQLException {
        PreparedStatement pstm=null;
        ResultSet rs=null;
        User user=null;
        String sql="select * from smbms_user where userCode=?";
        Object[] params={userCode};
        if(connection!=null) {

            rs = BaseDao.execute(connection, pstm, rs, sql, params);
            if (rs.next()) {
                user = new User();
                user.setId(rs.getInt("id"));
                user.setUserCode(rs.getString("userCode"));
                user.setUserName(rs.getString("userName"));
                user.setUserPassword(rs.getString("userPassword"));
                user.setGender(rs.getInt("gender"));
                user.setBirthday(rs.getDate("birthday"));
                user.setPhone(rs.getString("phone"));
                user.setAddress(rs.getString("address"));
                user.setUserRole(rs.getInt("userRole"));
                user.setCreatedBy(rs.getInt("createBy"));
                user.setCreationDate(rs.getDate("creationDate"));
                user.setModifyBy(rs.getInt("modifyBy"));
                user.setModifyDate(rs.getDate("modifyDate"));
            }
            BaseDao.closeResource(null, rs, pstm);
        }

        return user;

    }
}

5.业务层接口

java 复制代码
package com.zxy.service;

import com.zxy.pojo.User;


public interface UserService {
    //用户登录
    public User login(String userCode,String password);
}

6.业务层实现

java 复制代码
package com.zxy.service;

import com.zxy.dao.BaseDao;
import com.zxy.dao.user.UserDao;
import com.zxy.dao.user.UserDaoImp;
import com.zxy.pojo.User;
import org.junit.Test;

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

public class UserServiceImpl implements UserService{
//业务层都会调用Dao层,所以我们要引入Dao
    private UserDao userDao;
public UserServiceImpl(){
    userDao=new UserDaoImp();
}

    @Override
    public User login(String userCode, String password) {
        Connection connection=null;
        User user=null;
        try {
            connection=BaseDao.getConnection();
            //通过业务层调用对应的具体数据库操作
            user=userDao.getLoginUser(connection,userCode);
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            BaseDao.closeResource(connection,null,null);
        }
        return user;
    }
    /*
    测试
    @Test
    public void test(){
        UserServiceImpl userService = new UserServiceImpl();
        User admin = userService.login("admin", "1234567");
        System.out.println(admin.getUserPassword());
    }

     */
}

7.编写Servlet

java 复制代码
package com.zxy.servlet;

import com.zxy.pojo.User;
import com.zxy.service.UserServiceImpl;
import com.zxy.util.Constants;

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


public class LoginServlet extends HttpServlet {
    //Servlet:控制层调用业务层代码

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("LoginServlet--start---");
        //获取用户名和密码
        String usercode = req.getParameter("userCode");
        String userPassword = req.getParameter("userPassword");

        //和数据库中的密码进行对比,调用业务层代码
        UserServiceImpl userService = new UserServiceImpl();
        User user = userService.login(usercode, userPassword);//这里已经把登录的人查出来了
        if(user!=null){
            //查有此人,可以登录
            //将用户的信息放到Session中
            req.getSession().setAttribute(Constants.USER_SESSION,user);
            //跳转到内部主页
            resp.sendRedirect("jsp/frame.jsp");
        }else{
            //查无此人
            //转发会登录页面,顺带提示提示用户名或者密码错误
            req.setAttribute("error","用户名或者密码不正确");
            req.getRequestDispatcher("login.jsp").forward(req,resp);
        }

    }

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

JSP的功能不多介绍,传入一个数值,这个数值被JSP页面中的如图语句接收

8.注册Servlet

xml 复制代码
    <!--登录的注册 -->
<servlet>
    <servlet-name>LoginServlet</servlet-name>
    <servlet-class>com.zxy.servlet.LoginServlet</servlet-class>
</servlet>
    <servlet-mapping>
        <servlet-name>LoginServlet</servlet-name>
        <url-pattern>/login.do</url-pattern>
    </servlet-mapping>

9.测试访问

15.3登录功能优化

注销功能:

思路:移除Session,返回登录页面

java 复制代码
package com.zxy.servlet;

import com.zxy.util.Constants;

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


public class LogoutServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //移除用户的Constants.USER_SESSION
        req.getSession().removeAttribute(Constants.USER_SESSION);
        resp.sendRedirect("/login.jsp");

    }

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

注册xml

xml 复制代码
   <servlet>
        <servlet-name>LogoutServlet</servlet-name>
        <servlet-class>com.zxy.servlet.LogoutServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>LogoutServlet</servlet-name>
        <url-pattern>/jsp/login.do</url-pattern>
    </servlet-mapping>

登录拦截优化

拦截器

java 复制代码

注册xml

xml 复制代码
 <!--用户登录过滤器-->
    <filter>
        <filter-name>SysFilter</filter-name>
        <filter-class>com.zxy.filter.SysFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>SysFilter</filter-name>
        <url-pattern>/jsp/*</url-pattern>
    </filter-mapping>

15.4密码修改

1.导入前端页面

2.UserDao接口

java 复制代码
package com.zxy.dao.user;

import com.zxy.pojo.User;

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

public interface UserDao {
    //得到要登录的用户
    public User getLoginUser(Connection connection,String userCode) throws SQLException;

    //修改当前用户密码
    public int updatePwd(Connection connection,int id,int password)throws  SQLException;
}

3.UserDaoImp

java 复制代码
package com.zxy.dao.user;

import com.zxy.dao.BaseDao;
import com.zxy.pojo.User;

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


public class UserDaoImp implements UserDao{

    @Override
    public int updatePwd(Connection connection, int id, int password) throws SQLException {
        PreparedStatement pstm=null;
        int execute=0;
        if (connection!=null) {
            String sql="update smbms_user set userPassword=? where id=?";
            Object[] params={password,id};
            execute = BaseDao.execute(connection, pstm, sql, params);
            BaseDao.closeResource(null, null, pstm);
        } 
        return execute;

    }

    @Override
    public User getLoginUser(Connection connection, String userCode) throws SQLException {
        PreparedStatement pstm=null;
        ResultSet rs=null;
        User user=null;
        String sql="select * from smbms_user where userCode=?";
        Object[] params={userCode};
        if(connection!=null) {

            rs = BaseDao.execute(connection, pstm, rs, sql, params);
            if (rs.next()) {
                user = new User();
                user.setId(rs.getInt("id"));
                user.setUserCode(rs.getString("userCode"));
                user.setUserName(rs.getString("userName"));
                user.setUserPassword(rs.getString("userPassword"));
                user.setGender(rs.getInt("gender"));
                user.setBirthday(rs.getDate("birthday"));
                user.setPhone(rs.getString("phone"));
                user.setAddress(rs.getString("address"));
                user.setUserRole(rs.getInt("userRole"));
                user.setCreatedBy(rs.getInt("createBy"));
                user.setCreationDate(rs.getDate("creationDate"));
                user.setModifyBy(rs.getInt("modifyBy"));
                user.setModifyDate(rs.getDate("modifyDate"));
            }
            BaseDao.closeResource(null, rs, pstm);
        }

        return user;

    }
}

5.User服务接口

6.User服务层实现类

java 复制代码
package com.zxy.service;

import com.zxy.dao.BaseDao;
import com.zxy.dao.user.UserDao;
import com.zxy.dao.user.UserDaoImp;
import com.zxy.pojo.User;
import org.junit.Test;

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


public class UserServiceImpl implements UserService{
//业务层都会调用Dao层,所以我们要引入Dao
    private UserDao userDao;

    @Override
    public boolean updatePwd(int id, int pwd) {
        Connection connection=null;
        connection=BaseDao.getConnection();
        boolean flag=false;
        //修改密码
        try {
            if(userDao.updatePwd(connection,id,pwd)>0){
    flag=true;
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            BaseDao.closeResource(connection,null,null);
        }

        return flag;
    }

    public UserServiceImpl(){
    userDao=new UserDaoImp();
}

    @Override
    public User login(String userCode, String password) {
        Connection connection=null;
        User user=null;
        try {
            connection=BaseDao.getConnection();
            //通过业务层调用对应的具体数据库操作
            user=userDao.getLoginUser(connection,userCode);
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            BaseDao.closeResource(connection,null,null);
        }
        return user;
    }
    /*
    测试
    @Test
    public void test(){
        UserServiceImpl userService = new UserServiceImpl();
        User admin = userService.login("admin", "1234567");
        System.out.println(admin.getUserPassword());
    }

     */
}

7.通过提出方法实现Servlet复用

java 复制代码
package com.zxy.servlet;

import com.mysql.jdbc.StringUtils;
import com.zhong.wuduan.pojo.User;
import com.zhong.wuduan.service.UserServiceImpl;
import com.zhong.wuduan.util.Constants;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;


//实现Servlet复用
public class UserServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String method = req.getParameter("method");
        if(method.equals("savepwd")&&method!=null){
            this.updatePwd(req,resp);
        }else{


        }
    }

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

    public void updatePwd(HttpServletRequest req,HttpServletResponse resp) throws ServletException, IOException {
        //从Session里面拿ID
        Object attribute = req.getSession().getAttribute(Constants.USER_SESSION);
        String newpassword = req.getParameter("newpassword");

        boolean flag=false;
        if(attribute!=null&& !StringUtils.isNullOrEmpty(newpassword)){
            UserServiceImpl userService = new UserServiceImpl();
            flag = userService.updatePwd(((User) attribute).getId(), newpassword);
            if(flag){
                req.setAttribute("message","修改密码成功,请退出,请使用新密码登录");
                //密码修改成功,移除当前Session
                req.getSession().removeAttribute(Constants.USER_SESSION);
            }else{
                req.setAttribute("message","修改密码失败");
                //密码修改失败,
            }
        }else{
            if(attribute==null){
                System.out.println("attribute");
            }
            if(!StringUtils.isNullOrEmpty(newpassword)){
                System.out.println("newpassword");
            }
            req.setAttribute("message","新密码有问题");
            //新密码有问题
        }
        req.getRequestDispatcher("pwdmodify.jsp").forward(req,resp);

    }
}

8.测试

优化密码修改使用Ajax

1.阿里巴巴的fastjson

xml 复制代码
<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.75</version>
</dependency>

2.后台代码修改

java 复制代码
package com.zxy.servlet;

import com.alibaba.fastjson.JSONArray;
import com.mysql.jdbc.StringUtils;
import com.zxy.pojo.User;
import com.zxy.service.UserServiceImpl;
import com.zxy.util.Constants;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;


//实现Servlet复用
public class UserServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String method = req.getParameter("method");
        Object attribute = req.getSession().getAttribute(Constants.USER_SESSION);
        User user = (User) attribute;
        System.out.println(user.getUserPassword());
        if(method.equals("savepwd")&&method!=null){
            this.updatePwd(req,resp);
        }else if(method.equals("pwdmodify")&&method!=null){
        this.pwdModify(req, resp);

        }
    }

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

    public void updatePwd(HttpServletRequest req,HttpServletResponse resp) throws ServletException, IOException {
        //从Session里面拿ID
        Object attribute = req.getSession().getAttribute(Constants.USER_SESSION);
        String newpassword = req.getParameter("newpassword");

        boolean flag=false;
        if(attribute!=null&& !StringUtils.isNullOrEmpty(newpassword)){
            UserServiceImpl userService = new UserServiceImpl();
            flag = userService.updatePwd(((User) attribute).getId(), newpassword);
            if(flag){
                req.setAttribute("message","修改密码成功,请退出,请使用新密码登录");
                //密码修改成功,移除当前Session
                req.getSession().removeAttribute(Constants.USER_SESSION);
            }else{
                req.setAttribute("message","修改密码失败");
                //密码修改失败,
            }
        }else{
            if(attribute==null){
                System.out.println("attribute");
            }
            if(!StringUtils.isNullOrEmpty(newpassword)){
                System.out.println("newpassword");
            }
            req.setAttribute("message","新密码有问题");
            //新密码有问题
        }
        req.getRequestDispatcher("pwdmodify.jsp").forward(req,resp);

    }

    //验证旧密码
    public void pwdModify(HttpServletRequest req,HttpServletResponse resp){
        //从Session里面拿ID
        Object attribute = req.getSession().getAttribute(Constants.USER_SESSION);
        String oldpassword = req.getParameter("oldpassword");
        //万能的Map:结果集
        HashMap<String, String> resultMap = new HashMap<>();

        if(attribute==null){
            //Session失效了,Session过期了
            resultMap.put("result","sessionerror");

            System.out.println("sessionerror");
        }else if(StringUtils.isNullOrEmpty(oldpassword)){
            //输入的密码为空
            resultMap.put("result","error");
            System.out.println("error");
        }else{
            String userPassword = ((User) attribute).getUserPassword();//Session中用户的密码
            System.out.println(userPassword);
            if(oldpassword.equals(userPassword)){
                System.out.println("true");
                resultMap.put("result","true");
            }else {
                resultMap.put("result","false");
                System.out.println("false");
            }

        }
        try {
            resp.setContentType("application/json");
            PrintWriter writer = resp.getWriter();
            //JSONArray  阿里巴巴的工具类,转换格式
        /*
        resultMap=["result","sessionerror"]
         */
            writer.write(JSONArray.toJSONString(resultMap));
            writer.flush();
            writer.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

15.5用户管理实现

思路:

1.导入支持分页的工具类

2.用户列表页面导入

userlist.jsp

1、获取用户数量

1.UserDao

java 复制代码
package com.zxy.dao.user;

import com.zxy.pojo.User;

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


public interface UserDao {
    //得到要登录的用户
    public User getLoginUser(Connection connection,String userCode) throws SQLException;

    //修改当前用户密码
    public int updatePwd(Connection connection,int id,String password)throws  SQLException;
    
    //查询用户总数
    public int getUserCount(Connection connection,String username,int userRole) throws SQLException;
}

2.UserDaoImpl

java 复制代码
package com.zxy.dao.user;

import com.mysql.jdbc.StringUtils;
import com.zxy.dao.BaseDao;
import com.zxy.pojo.User;

import javax.swing.plaf.basic.BasicOptionPaneUI;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;


public class UserDaoImp implements UserDao{
    //根据用户名或者角色查询
    @Override
    public int getUserCount(Connection connection, String username, int userRole) throws SQLException {

        PreparedStatement pstm=null;
        ResultSet rs=null;

        int count=0;
        if(connection!=null){
            StringBuffer sql = new StringBuffer();
            sql.append("select count(1) as count from smbms_user u,smbms_role r where u.userRole=r.id");
            ArrayList<Object> list = new ArrayList<>();//存放我们的参数

            if(!StringUtils.isNullOrEmpty(username)){
                sql.append(" and u.userName list ?");
                list.add("%"+username+"%");//index:0
            }
            if(userRole>0){
                sql.append(" and u.userRole = ?");
                list.add(userRole);//index:1

            }
            //怎么把list转换为数组
            Object[] params = list.toArray();

            System.out.println("UserDaoImpl-->getUserCount:"+sql.toString());


            rs = BaseDao.execute(connection, pstm, rs, sql.toString(), params);

         if(rs.next()){
              count = rs.getInt("count");//从结果集中获取最终的数据

         }
         BaseDao.closeResource(null,rs,pstm);
        }
        return count;
    }

    @Override
    public int updatePwd(Connection connection, int id, String password) throws SQLException {
        PreparedStatement pstm=null;
        int execute=0;
        if (connection!=null) {
            String sql="update smbms_user set userPassword=? where id=?";
            Object[] params={password,id};
            execute = BaseDao.execute(connection, pstm, sql, params);
            BaseDao.closeResource(null, null, pstm);
        } 
        return execute;

    }

    @Override
    public User getLoginUser(Connection connection, String userCode) throws SQLException {
        PreparedStatement pstm=null;
        ResultSet rs=null;
        User user=null;
        String sql="select * from smbms_user where userCode=?";
        Object[] params={userCode};
        if(connection!=null) {

            rs = BaseDao.execute(connection, pstm, rs, sql, params);
            if (rs.next()) {
                user = new User();
                user.setId(rs.getInt("id"));
                user.setUserCode(rs.getString("userCode"));
                user.setUserName(rs.getString("userName"));
                user.setUserPassword(rs.getString("userPassword"));
                user.setGender(rs.getInt("gender"));
                user.setBirthday(rs.getDate("birthday"));
                user.setPhone(rs.getString("phone"));
                user.setAddress(rs.getString("address"));
                user.setUserRole(rs.getInt("userRole"));
                user.setCreatedBy(rs.getInt("createBy"));
                user.setCreationDate(rs.getDate("creationDate"));
                user.setModifyBy(rs.getInt("modifyBy"));
                user.setModifyDate(rs.getDate("modifyDate"));
            }
            BaseDao.closeResource(null, rs, pstm);
        }

        return user;

    }
}

3.UserService

java 复制代码
package com.zxy.service;

import com.zxy.pojo.User;


public interface UserService {
    //用户登录
    public User login(String userCode,String password);
    
    //根据用户ID修改密码
    public boolean updatePwd(int id,String pwd);

    //查询记录数
    public int getUserCount(String username,int userRole);
}

4.UserServiceImpl

java 复制代码
package com.zxy.service;

import com.zxy.dao.BaseDao;
import com.zxy.dao.user.UserDao;
import com.zxy.dao.user.UserDaoImp;
import com.zxy.pojo.User;
import org.junit.Test;

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


public class UserServiceImpl implements UserService{

//业务层都会调用Dao层,所以我们要引入Dao
    private UserDao userDao;

    @Override
    public int getUserCount(String username, int userRole) {
        Connection connection=null;
        int userCount=0;
        try {
             connection = BaseDao.getConnection();
             userCount = userDao.getUserCount(connection, username, userRole);
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            BaseDao.closeResource(connection,null,null);
        }
        return userCount;
    }
    @Test
    public void test1(){
        UserServiceImpl userService = new UserServiceImpl();
        int userCount = userService.getUserCount(null, 1);
        System.out.println(userCount);
    }
    @Override
    public boolean updatePwd(int id, String pwd) {
        Connection connection=null;
        connection=BaseDao.getConnection();
        boolean flag=false;
        //修改密码
        try {
            if(userDao.updatePwd(connection,id,pwd)>0){
    flag=true;
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            BaseDao.closeResource(connection,null,null);
        }

        return flag;
    }

    public UserServiceImpl(){
    userDao=new UserDaoImp();
}

    @Override
    public User login(String userCode, String password) {
        Connection connection=null;
        User user=null;
        try {
            connection=BaseDao.getConnection();
            //通过业务层调用对应的具体数据库操作
            user=userDao.getLoginUser(connection,userCode);
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            BaseDao.closeResource(connection,null,null);
        }
        return user;
    }
    /*
    测试
    @Test
    public void test(){
        UserServiceImpl userService = new UserServiceImpl();
        User admin = userService.login("admin", "1234567");
        System.out.println(admin.getUserPassword());
    }

     */
}
2.获取用户列表

1.userdao

java 复制代码
//获取用户列表
    public List<User> getUserlist(Connection connection,String userName,int userRole,int currentPageNo,int pageSize) throws SQLException;

2.userdaoimpl

java 复制代码
 @Override
    public List<User> getUserlist(Connection connection, String userName, int userRole, int currentPageNo, int pageSize) throws SQLException {
        PreparedStatement pstm = null;
        ResultSet rs = null;
        List<User> userList = null;

        if (connection != null) {
            // ==================这一部分与获取用户总数一致==================
            StringBuffer sql = new StringBuffer();
            ArrayList<Object> paramsList = new ArrayList<Object>();
            sql.append("SELECT * FROM smbms_user u, smbms_role r WHERE u.userRole=r.id");

            if (!StringUtils.isNullOrEmpty(userName)) {
                sql.append(" AND u.userName=?");
                paramsList.add("%" + userName + "%");
            }

            if (userRole > 0) {
                sql.append(" AND r.id=?");
                paramsList.add(userRole);
            }
            // ==================这一部分与获取用户总数一致==================
            // 实现分页功能 -- LIMIT startIndex, pageSize 比如第1页就是0,5 第2页就是5,5 第3页就是10,5
            //在数据库中,分页使用  limit startIndex,pageSize;

            sql.append(" ORDER BY u.creationDate DESC LIMIT ?,?");

            // startIndex 应当等于(第i页 - 1) * pageSize
            int startIndex = (currentPageNo - 1) * pageSize;

            // 把 startIndex 和 pageSize 加入到参数列表中
            paramsList.add(startIndex);
            paramsList.add(pageSize);

            // 把参数列表转成数组
            Object[] params = paramsList.toArray();
            System.out.println("SQL: UserDaoImpl.getUserList --> " + sql);
            rs =  BaseDao.execute(connection, pstm,rs,sql.toString(),params);

            // 遍历查询到的用户列表,加入到结果列表中
            userList = new ArrayList<User>();
            while (rs.next()) {
                // 实例化一个 User 对象,并给相关属性赋值
                User _user = new User();
                _user.setId(rs.getInt("id"));
                _user.setUserCode(rs.getString("userCode"));
                _user.setUserName(rs.getString("userName"));
                _user.setUserPassword(rs.getString("userPassword"));
                _user.setGender(rs.getInt("gender"));
                _user.setBirthday(rs.getDate("birthday"));
                _user.setPhone(rs.getString("phone"));
                _user.setAddress(rs.getString("address"));
                _user.setUserRole(rs.getInt("userRole"));
                _user.setCreatedBy(rs.getInt("createdBy"));
                _user.setCreationDate(rs.getTimestamp("creationDate"));
                _user.setModifyBy(rs.getInt("modifyBy"));
                _user.setModifyDate(rs.getTimestamp("modifyDate"));
                // 加入到结果列表中
                userList.add(_user);
            }
            BaseDao.closeResource(null, rs, pstm);
        }

        return userList;
    }

3.userService

java 复制代码
  /**
     * 通过条件查询用户列表
     *
     * @param userName      用户名
     * @param userRole      角色 id
     * @param currentPageNo 当前分页的页号
     * @param pageSize      分页的每页大小
     * @return 返回符合条件的用户列表
     */
    List<User> getUserList(String userName, int userRole, int currentPageNo, int pageSize);

4.userServeice

java 复制代码
  @Override
    public List<User> getUserList(String userName, int userRole, int currentPageNo, int pageSize) {
        Connection connection = BaseDao.getConnection();
        List<User> userList = null;

        try {
            userList = userDao.getUserlist(connection, userName, userRole, currentPageNo, pageSize);
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        } finally {
            BaseDao.closeResource(connection, null, null);
        }

        return userList;
    }
3.获取角色操作

1.RoleDao

java 复制代码
package com.zxy.dao.role;

import com.zxy.pojo.Role;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;

public interface RoleDao {

    /**
     * 获取用户角色列表
     *
     * @param connection 数据库连接对象
     * @return 返回用户角色列表
     * @throws SQLException SQL 执行出错时会抛出异常
     */
    List<Role> getUserRoleList(Connection connection) throws SQLException;
}

2.RoleDaolmpl

java 复制代码
package com.zxy.dao.role;


import com.zxy.dao.BaseDao;
import com.zxy.pojo.Role;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

public class RoleDaoImpl implements RoleDao {

    // 获取用户角色列表
    public List<Role> getUserRoleList(Connection connection) throws SQLException {

        ResultSet rs = null;
        PreparedStatement pstm = null;
        ArrayList<Role> roleList = new ArrayList<Role>();

        if (connection != null) {
            String sql = "SELECT * FROM smbms_role";
            Object[] params = {};
            rs = (ResultSet) BaseDao.execute(connection,pstm,rs,sql,params);

            // 遍历查询到的结果集
            while (rs.next()) {
                Role _role = new Role();
                _role.setId(rs.getInt("id"));
                _role.setRoleCode(rs.getString("roleCode"));
                _role.setRoleName(rs.getString("roleName"));

                roleList.add(_role);
            }
            BaseDao.closeResource(null, rs, pstm);
        }

        return roleList;
    }
}

3.RoleService

java 复制代码
package com.zxy.service.role;


import com.zxy.pojo.Role;

import java.util.List;

public interface RoleService {

    /**
     * 获取用户角色列表
     */
    List<Role> getUserRoleList();
}

4.RoleServiceImpl

java 复制代码
package com.zxy.service.role;


import com.zxy.dao.BaseDao;
import com.zxy.dao.role.RoleDaoImpl;
import com.zxy.pojo.Role;
import org.junit.Test;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;

public class RoleServiceImpl implements RoleService {

    private RoleDaoImpl roleDao;

    public RoleServiceImpl() {
        roleDao = new RoleDaoImpl();
    }

    // 获取用户角色列表
    public List<Role> getUserRoleList() {
        Connection connection = BaseDao.getConnection();
        List<Role> userRoleList = null;

        try {
            userRoleList = roleDao.getUserRoleList(connection);
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        } finally {
            BaseDao.closeResource(connection, null, null);
        }

        return userRoleList;
    }

    /**
     * 测试获取用户角色列表api
     */
    @Test
    public void testGetUserRoleList() {
        List<Role> userRoleList = getUserRoleList();
        for (Role role : userRoleList) {
            System.out.println(role.getRoleName());
        }
    }
}
4.用户显示的Servlet

1.获取用户前端的数据(查询)

2.判断请求是否执行,看参数的判断

3.为了实现分页,需要计算出当前页面和总页面,页面代销

4.用户列表展示

5.返回前端

java 复制代码
 //重点,难点
    public void query(HttpServletRequest req,HttpServletResponse resp){

        //从前端获取数据
        String queryUserName=req.getParameter("queryName");
        String temp = req.getParameter("queryUserRole");
        String pageIndex = req.getParameter("pageIndex");
        int queryUserRole=0;
        System.out.println(temp);
        //获取用户列表
        UserServiceImpl userService = new UserServiceImpl();


        //第一次走这个请求,一定是第一页,且页面大小固定
        int pageSize=2;//可以把这个写到配置文件内,方便后期修改
        int currenPageNo=1;//默认从第1页开始
        if(pageIndex!=null){
            currenPageNo=Integer.parseInt(pageIndex);
        }
        if(queryUserName==null){
            queryUserName="";
            //这里不手动赋空值会导致空指针异常
        }
        if(temp!=null&&!temp.equals("")){
            queryUserRole=Integer.parseInt(temp);//前端传过来的数值是对应角色对应的Id
        }

        //获取用户总数量(分页: 上一页,下一页的情况)
        int userCount = userService.getUserCount(queryUserName, queryUserRole);

        //总页数支持
        PageSupport pageSupport = new PageSupport();
        pageSupport.setCurrentPageNo(currenPageNo);
        pageSupport.setPageSize(pageSize);
        pageSupport.setTotalCount(userCount);

        //控制首页和尾页
        int totalPageCount = pageSupport.getTotalPageCount();//总共有几页
        //如果页面<1了,就显示第一页的东西
        if(totalPageCount<1){
            currenPageNo=1;
        }else if(currenPageNo>totalPageCount){
            //当前页面页数大于最后一页
            currenPageNo=totalPageCount;
        }

        //获取用户列表展示
        List<User> userList = userService.getUserList(queryUserName, queryUserRole, currenPageNo, pageSize);

        req.setAttribute("userList",userList);

        RoleServiceImpl roleService = new RoleServiceImpl();
        List<Role> userRoleList = roleService.getUserRoleList();
        req.setAttribute("roleList",userRoleList);

        req.setAttribute("totalCount",userCount);
        req.setAttribute("currentPageNo",currenPageNo);
        req.setAttribute("totalPageCount",totalPageCount);
        req.setAttribute("queryUserName",queryUserName);
        req.setAttribute("queryUserRole",queryUserRole);

        //返回前端
        try {
            req.getRequestDispatcher("userlist.jsp").forward(req,resp);
        } catch (ServletException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

十六、文件上传

十七、邮件发送

​

​

​

带附件邮件逻辑:

相关推荐
码事漫谈2 小时前
三步改掉 AI 味,附可直接复制的去 AI 味提示词
后端
IT_陈寒2 小时前
Redis卡顿的锅,这次真不是大key的错
前端·人工智能·后端
可乐鸡翅yeah_2 小时前
video.js 集成 hls.js 开发 M3U8 播放器,新手高频踩坑
开发语言·前端·javascript·后端·ecmascript·m3u8·音视频在线播放
程序猿_极客3 小时前
【免费】分享一套优质的基于SpringBoot的服装商城管理系统的设计与实现(带可视化图表、协同过滤功能),源码+文档+视频详解(讲解)
java·spring boot·后端·服装商城管理系统
明月_清风3 小时前
面对陌生的 GitHub 项目无从下手?这 4 个网站帮你快速读懂源码
前端·后端·github
bug菌3 小时前
🤔同事突然问我:Spring的注解 @Component 和 @Service 有何不同?
java·spring boot·后端
leobertlan4 小时前
痛苦系列 | DSP-02 频域切片:DTFT与DFT的探索
android·后端
加我攻城狮4 小时前
当大模型把「景区」定位到附近公共厕所:我的 AI 旅行小程序踩坑实录
后端·微信
Lonely丶墨轩4 小时前
用 Vue + Spring Boot + Python 做一个 AI 双人海龟汤游戏:从出题、联机到自动审稿等核心技术设计与实现
spring boot·后端·游戏
猪猪拆迁队4 小时前
跨电脑复制共享-WebRTC 打洞踩坑
前端·后端·go