狂神说学习笔记:JavaWeb

JavaWeb

1、基本概念

1.1、前言

web开发:

  • web,网页的意思 www.baidu.com

  • 静态web

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

    • 淘宝,几乎所有的网站

    • 提供给所有人看到数据始终会发生变化,每个人在不同的时间,不同的地点看到的信息各不相同!

    • 技术栈:Servlet/JSP,ASP,PHP

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

1.2、Web应用程序

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

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

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

1.3、静态web

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

image-20220123185256457

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

1.4、动态web

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

image-20220123185920973

缺点:

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

优点:

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

image-20220123190359984

2、Web服务器

2.1、技术讲解

ASP

  • 微软:国内最早流行的ASP;
  • 在HTML中嵌入了VB的脚本,ASP+COM
  • 在ASP开发中,基本一个页面都有几千行业务代码,页面及其混乱
  • 维护成本高!
  • 主要用于C#

PHP

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

JSP/Servlet

B/S:浏览器和服务器

C/S:客户端和服务器

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

2.2、Web服务器

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

IIS

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

Tomcat

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

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

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

...

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

下载tomcat:

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

3、Tomcat

3.1、安装Tomcat

Tomcat官网:https://tomcat.apache.org/

image-20220124173959520

image-20220124175429588

3.2、Tomcat启动和配置

文件夹的作用:

image-20220124180114585启动、关闭Tomcat

image-20220124184224168

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

可能遇到的问题:

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

3.3、 配置

image-20220124184723649

可以配置启动的端口号

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

可以配置主机的名称

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

高难度面试题:

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

  1. 输入一个域名;回车

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

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

      127.0.0.1	www.xxx.com
      
    • 没有:去DNS服务器上找,找到的话就返回,找不到就返回找不到

    image-20220124203107122

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

3.4、发布一个web网站

不会就先模仿

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

网站应该有的结构:

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

4、HTTP

4.1、什么是HTTP

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

  • 文本:html,字符串,~....
  • 超文本:图片,音乐,视频,定位,地图....
  • 80

HTTPS:安全的

  • 443

4.2、两个时代

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

4.3、HTTP请求

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

百度为例:

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

1.请求行

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

2.请求头

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

4.4、HTTP响应

  • 服务器 -- 响应(Respond) -- 客户端

百度为例:

Cache-Control: private		//缓存控制
Connection: keep-alive		//连接
Content-Encoding: gzip		//编码
Content-Type: text/html;charset=utf-8	//类型

1.响应体

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

2.响应状态码(重点)

200:请求响应成功

3xx:请求重定向 例:303

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

4xx:找不到资源 例:404

  • 资源不存在

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

常见面试题

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

5、Maven

我为什么要学习这个技术

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

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

    由此,Maven诞生了!

5.1、Maven项目架构管理工具

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

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

  • 有约束,不要去违反

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

5.2、下载安装Maven

image-20220126002129627

下载完成后,解压即可;

5.3、配置环境变量

在我们的系统环境变量中

配置如下配置:

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

image-20220126010058728

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

5.4、阿里云镜像

  • 镜像:mirrors

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

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

    image-20220126012552699

5.5、本地仓库

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

建立一个本地仓库:localRepository

  1. 现在maven文件夹里建一个名为maven-repo的文件夹
  2. 然后在maven文件夹下的confsettings.xml里添加如下语句,如图
  <localRepository>D:\Environment\apache-maven-3.8.4\maven-repo</localRepository>

image-20220126011611733

5.6、在IDEA中使用Maven

  1. 启动IDEA

  2. 创建一个Maven项目

    image-20220126225924953

    image-20220126230744002

    image-20220126231928534

    image-20220126232140596

  3. 等待项目初始化完毕

    image-20220126232759464

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

    image-20220126233343197

  5. IDEA中的Maven设置

    注意:IDEA项目创建成功后,看一眼Maven的配置

    image-20220126234051619

    image-20220126234527181

  6. 到这里,Maven在IDEA中的配置和使用就OK了

5.7、 创建一个普通的Maven项目

image-20220126235332263

  • 干净的项目

    image-20220127000102266

  • 不干净的项目

    image-20220127000820216

5.8、在IDEA中标记文件夹

  • 第一种方式:选中文件夹右键,选择Mark Directory as

    image-20220127001318380

  • 第二种方式:File-Project Structure-Modules

    image-20220127002147892

    image-20220127002438514

5.9、在IDEA中配置Tomcat

image-20220127002922561

image-20220127002941104

image-20220127003208549

image-20220127004237217

必须要的配置:我们访问一个网站,需要指定一个文件夹的名字

image-20220127005221206

image-20220127005250084

image-20220127005807040

image-20220127010038667

image-20220127010410677

5.10、pom文件

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

image-20220127011144429

<?xml version="1.0" encoding="UTF-8"?>
<!--Maven版本和头文件-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
<!--这里就是配置的GAV-->
  <groupId>com.dt</groupId>
  <artifactId>javaweb-01-maven</artifactId>
  <version>1.0-SNAPSHOT</version>
<!--packaging:项目的打包方式
jar:Java应用
war:JavaWeb应用
-->
  <packaging>war</packaging>


<!--配置-->
  <properties>
<!--项目的默认构建编码-->
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<!--编码版本-->
    <maven.compiler.source>1.7</maven.compiler.source>
    <maven.compiler.target>1.7</maven.compiler.target>
  </properties>
<!--项目依赖-->
  <dependencies>
<!--具体依赖的jar包配置文件-->
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
    </dependency>
  </dependencies>
<!--项目构建用的东西-->
  <build>
    <finalName>javaweb-01-maven</finalName>
    <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
      <plugins>
        <plugin>
          <artifactId>maven-clean-plugin</artifactId>
          <version>3.1.0</version>
        </plugin>
        <!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging -->
        <plugin>
          <artifactId>maven-resources-plugin</artifactId>
          <version>3.0.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-compiler-plugin</artifactId>
          <version>3.8.0</version>
        </plugin>
        <plugin>
          <artifactId>maven-surefire-plugin</artifactId>
          <version>2.22.1</version>
        </plugin>
        <plugin>
          <artifactId>maven-war-plugin</artifactId>
          <version>3.2.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-install-plugin</artifactId>
          <version>2.5.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-deploy-plugin</artifactId>
          <version>2.8.2</version>
        </plugin>
      </plugins>
    </pluginManagement>
  </build>
</project>

image-20220127015230396

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

解决方案

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

5.11、IDEA操作

image-20220127020258032

image-20220127020552285

5.12、解决遇到的问题

  1. Maven 3.6.2

    image-20220129210110442

    解决方法:降级为3.6.1

  2. Tomcat闪退

    解决方法:检查Java的环境配置

  3. IDEA中每次都需要重复配置Maven

    解决方法:在IDEA中的全局默认配置中去配置

    image-20220129214715086

    image-20220129215815194

    image-20220129215126538

  4. Maven项目中Tomcat无法配置

  5. Maven默认web项目中的web.xml版本问题

    image-20220129220839341

  6. 替换为webapp4.0版本和tomcat一致

    <?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>
    
  7. Maven仓库的使用

    地址:https://mvnrepository.com

    例子:

    仿写 http://localhost:8080/examples/servlets/helloworld.htmlhelloworld时,发现 HttpServlet所属的jar包在本地仓库中没有,这时就需要到 https://mvnrepository.com 寻找jar包。通过Tomcat能直接运行Helloworld知道Tomcat中存在能使用HttpServlet的jar包

    image-20220129224304501

    发现有个servlet-api.jar,所以在 https://mvnrepository.com 的搜索框中搜索 servlet-api。通过对比所属jar和下载人数发现,第一个就是我们要找的jar包

    image-20220129223617494

    image-20220129224719063

    image-20220129224853133

    依赖写在pom.xml的`dependencies里,然后点右边的加载,即可下载jar包,如下:

    image-20220129225425158

6、Servlet

6.1、Servlet简介

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

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

6.2、HelloServlet

Servlet接口sun公司有两个默认的实现类:HttpServlet,GenericServlet

image-20220130204015327

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

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

    父项目中会有

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

    子项目中会有

    	<parent>
            <artifactId>javaweb-02-servlet</artifactId>
            <groupId>com.dt</groupId>
            <version>1.0-SNAPSHOT</version>
        </parent>
    

    父项目中的jar包子项目能直接使用

    son extends father
    
  3. Maven环境优化

    1. 修改web.xml为最新的(直接复制Tomcat路径下的D:\Environment\apache-tomcat-9.0.58\webapps\ROOT\WEB-INF\web.xml里的)
    2. 将Maven的结构搭配完整(main路径下添加javaresources文件夹并标记,参考[IDEA文件标记](### 5.8、在IDEA中标记文件夹))
  4. 编写一个Servlet程序

    1. 编写一个普通类

    2. 实现Servlet接口,这里我们直接继承HttpServlet

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

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

    添加到web.xml

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

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

  7. 启动测试

6.3、Servlet原理

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

image-20220130211259144

6.4、Mapping问题

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

        <servlet-mapping>
            <servlet-name>hello</servlet-name>
            <url-pattern>/hello</url-pattern>
        </servlet-mapping>
    
  2. 一个Servlet可以指定多个映射路径

    	<servlet-mapping>
            <servlet-name>hello</servlet-name>
            <url-pattern>/hello</url-pattern>
        </servlet-mapping>
        <servlet-mapping>
            <servlet-name>hello</servlet-name>
            <url-pattern>/hello1</url-pattern>
        </servlet-mapping>
        <servlet-mapping>
            <servlet-name>hello</servlet-name>
            <url-pattern>/hello2</url-pattern>
        </servlet-mapping>
    
  3. 一个Servlet可以指定一个映射路径

    	<servlet-mapping>
            <servlet-name>hello</servlet-name>
            <url-pattern>/hello/*</url-pattern>
        </servlet-mapping>
    
  4. 默认请求路径

    	<servlet-mapping>
            <servlet-name>hello</servlet-name>
            <url-pattern>/*</url-pattern>
        </servlet-mapping>
    
  5. 指定一些后缀或者前缀等等

    <!--可以自定义后缀实现请求映射
    注意点:*之前不能加映射的路径-->
        <servlet-mapping>
            <servlet-name>hello</servlet-name>
            <url-pattern>*.dt</url-pattern>
        </servlet-mapping>
    
  6. 优先级问题

    指定了固有的映射路径优先级最高,如果找不到就会走默认的请求(例如如下:/hello会走第一个)

        <servlet>
            <servlet-name>hello</servlet-name>
            <servlet-class>com.dt.servlet.HelloServlet</servlet-class>
        </servlet>
    <!--Servlet的请求-->
        <servlet-mapping>
            <servlet-name>hello</servlet-name>
            <url-pattern>/hello</url-pattern>
        </servlet-mapping>
    
    <!--404-->
        <servlet>
            <servlet-name>error</servlet-name>
            <servlet-class>com.dt.servlet.ErrorServlet</servlet-class>
        </servlet>
        <servlet-mapping>
            <servlet-name>error</servlet-name>
            <url-pattern>/*</url-pattern>
        </servlet-mapping>
    

6.5、ServletContext

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

image-20220131200202016

1、共享数据

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

HelloServlet.java

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

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

        System.out.println("Hello,Servlet");
    }

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

GetServlet.java

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

        resp.setContentType("text/html");
        resp.setCharacterEncoding("utf-8");
        resp.getWriter().print("名字"+username);
    }

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

在web.xml加入

    <servlet>
        <servlet-name>hello</servlet-name>
        <servlet-class>com.dt.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.dt.servlet.GetServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>getc</servlet-name>
        <url-pattern>/getc</url-pattern>
    </servlet-mapping>

测试访问结果(先访问/hello再访问/getc):

image-20220131193534088

2、获取初始化参数

ServletDemo03:

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 {
        doGet(req, resp);
    }
}

在web.xml加入

    <servlet>
        <servlet-name>gp</servlet-name>
        <servlet-class>com.dt.servlet.ServletDemo03</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>gp</servlet-name>
        <url-pattern>/gp</url-pattern>
    </servlet-mapping>

测试访问结果:

image-20220131202708459

3、请求转发

ServletDemo03:

public class ServletDemo04 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        ServletContext servletContext = this.getServletContext();
//        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 {
        doGet(req, resp);
    }
}

在web.xml加入

    <servlet>
        <servlet-name>sd4</servlet-name>
        <servlet-class>com.dt.servlet.ServletDemo04</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>sd4</servlet-name>
        <url-pattern>/sd4</url-pattern>
    </servlet-mapping>

测试访问结果:

image-20220131202800444

转发与重定向原理图:

image-20220131202446573

4、读取资源文件

Properties

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

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

思路:需要一个文件流:

ServletDemo05.java

public class ServletDemo05 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        InputStream is = this.getServletContext().getResourceAsStream("/WEB-INF/classes/com/dt/servlet/db.properties");

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

        resp.setHeader("content-type","text/html;charset=UTF-8");
        resp.getWriter().print(user+":"+pwd);
    }

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

db.properties:

username=root
password=123456

在web.xml加入

    <servlet>
        <servlet-name>sd5</servlet-name>
        <servlet-class>com.dt.servlet.ServletDemo05</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>sd5</servlet-name>
        <url-pattern>/sd5</url-pattern>
    </servlet-mapping>

测试访问结果:

image-20220131220336276

6.6、HttpServletResponse

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

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

1、简单分类

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

    ServletOutputStream getOutputStream() throws IOException;
    PrintWriter getWriter() throws IOException;

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

    void setCharacterEncoding(String var1);

    void setContentLength(int var1);

    void setContentLengthLong(long var1);

    void setContentType(String var1);

    void setDateHeader(String var1, long var2);

    void addDateHeader(String var1, long var2);

    void setHeader(String var1, String var2);

    void addHeader(String var1, String var2);

    void setIntHeader(String var1, int var2);

    void addIntHeader(String var1, int var2);

响应的状态码:

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

2、常见应用

  1. 向浏览器输出消息

  2. 下载文件

    1. 要获取下载文件的路径
    2. 下载的文件名是啥?
    3. 设置想办法让浏览器能够支持下载我们需要的东西
    4. 获取下载文件的输入流
    5. 创建缓冲区
    6. 获取OutputStream对象
    7. 将FileOutputStream流写入到buffer缓冲区
    8. 使用OutputStream将缓冲区中的数据输出到客户端
    public class FileServlet extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    //        1. 要获取下载文件的路径
            String realPath = "E:\\code\\javaweb-02-servlet\\response\\target\\response\\WEB-INF\\classes\\漂亮mm.png";
    //        2. 下载的文件名是啥?
            String fileName = realPath.substring(realPath.lastIndexOf("\\"));
    //        3. 设置想办法让浏览器能够支持(Content-Disposition)下载我们需要的东西,文件名有中文的用 URLEncoder.encode 编码,不然乱码
            resp.setHeader("Content-Disposition","attachment;filename="+ URLEncoder.encode(fileName,"utf-8"));
    //        4. 获取下载文件的输入流
            FileInputStream in = new FileInputStream(realPath);
    //        5. 创建缓冲区
            int len = 0;
            byte[] buffer = new byte[1024];
    //        6. 获取OutputStream对象
            ServletOutputStream out = resp.getOutputStream();
    //        7. 将FileOutputStream流写入到buffer缓冲区
            while ((len = in.read(buffer)) > 0){
                out.write(buffer,0,len);
            }
            in.close();
            out.close();
    
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            doGet(req, resp);
        }
    }
    

3、验证码功能

验证怎么来的?

  • 前端实现

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

    public class ImageServlet extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
            //如何让浏览器5秒自动刷新一次
            resp.setHeader("refresh","3");
    
            //在内存中创建一个图片
            BufferedImage image = new BufferedImage(80,20,BufferedImage.TYPE_INT_RGB);
            //得到图片
            Graphics2D 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/jpeg");
            //网站存在缓存,不让浏览器缓存
            resp.setDateHeader("expires",-1);
            resp.setHeader("Cache-Control","no-cache");
            resp.setHeader("Pragma","no-cache");
    
            //把图片写给浏览器
            ImageIO.write(image,"jpg",resp.getOutputStream());
    
        }
    
        //生成随机数
        private String makeNum() {
            Random random = new Random();
            String num = random.nextInt(9999999) + "";
            StringBuffer sb = new StringBuffer();
            for (int i = 0; i < 7 - num.length(); i++) {
                sb.append("0");
            }
            num = sb.toString() + num;
            return num;
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            doGet(req, resp);
        }
    }
    

4、实现重定向

image-20220203203755222

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

常见场景:

  • 用户登录

    void sendRedirect(String var1) throws IOException;
    

    测试:

    public class RedirectServlet extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
            /* 重定向做了以下这两步
            resp.setHeader("Location","/r/img");
            resp.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY);
            //resp.setStatus(302);//等价于上一句
            */
            resp.sendRedirect("/r/img");//重定向
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            doGet(req, resp);
        }
    }
    

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

相同点

  • 页面都会实现跳转

不同点

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

image-20220203210109853

6.7、HttpServletRequest

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

image-20220206204937159

获取前端传递的参数,以及请求转发

image-20220206223715593

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

        req.setCharacterEncoding("utf-8");
        resp.setCharacterEncoding("utf-8");

        String username = req.getParameter("username");
        String password = req.getParameter("password");
        String[] hobbies = req.getParameterValues("hobbies");

        System.out.println("=".repeat(100));
        //后台接收中文乱码问题

        System.out.println(username);
        System.out.println(password);
        System.out.println(Arrays.toString(hobbies));
        System.out.println("=".repeat(100));

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

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

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

相同点

  • 页面都会实现跳转

不同点

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

7、Cookie、Session

7.1、会话

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

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

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

你 西开

1.发票 西开给你发票

2.学校登记 西开标记你来过了

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

客户端 服务端

1.服务端给客户端一个信件,客户端下次访问服务端带上信件就可以;cookie

2.服务器登记你来过了,下次你来的时候我来匹配你;session

7.2、保存会话的两种技术

cookie

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

session

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

常见场景:网站登录之后,你下次不用再登录,第二次访问直接就上去了!

7.3、Cookie

image-20220208225531678

  1. 从请求在拿到cookie信息
  2. 服务器响应给客户端cookie
Cookie[] cookies = req.getCookies();//获得cookie
cookie.getName();//获得cookie中的key
cookie.getValue();//获得cookie中的value
new Cookie("lastLoginTime", System.currentTimeMillis()+"");//新建一个cookie
cookie.setMaxAge(24*60*60);//设置cookie有效期
resp.addCookie(cookie);//响应给客户端一个cookie

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

一个网站cookie是否会存在上限?细节问题

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

删除cookie

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

编码解码:

URLEncoder.encode("鳄鱼","utf-8")//编码
URLDecoder.decode(cookie.getValue(),"utf-8")//解码

7.4、Session(重点)

image-20220208230029590

什么是Session:

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

image-20220208213205669

Session和Cookie的区别:

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

使用场景:

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

使用Session:

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.setHeader("Content-type","text/html;charset=utf-8");

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

        //给Session中存东西
        session.setAttribute("name",new Person("鳄鱼",1));

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

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

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

    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}
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.setHeader("Content-type","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 {
        doGet(req, resp);
    }
}
public class SessionDemo03 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

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

    }

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

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

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

ServletContext与Session的不同:

image-20220208230946717

8、JSP

8.1、什么是JSP

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

最大的特点:

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

8.2、JSP原理

思路:JSP到底怎么执行的

  • 代码层面没有任何问题
  • 服务器内部工作

​ tomcat中有一个work目录

​ IDEA中使用Tomcat会在IDEA中产生一个work目录

image-20220217221038116

​ 我电脑的地址:

C:\Users\Administrator\AppData\Local\JetBrains\IntelliJIdea2021.3\tomcat\c2ac0ae4-27bb-42fb-8e34-fd87b8242315\work\Catalina\localhost\ROOT\org\apache\jsp

发现页面转变成了Java程序

image-20220217222502648

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

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

JSP本质上就是一个Servlet

//初始化
  public void _jspInit() {
  }
//销毁
  public void _jspDestroy() {
  }
//JSPService
  public void _jspService(HttpServletRequest request, HttpServletResponse response)
  1. 判断请求

  2. 内置了一些对象

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

          response.setContentType("text/html");		//设置响应的页面类型
          pageContext = _jspxFactory.getPageContext(this, request, response,
          			null, true, 8192, true);
          _jspx_page_context = pageContext;
          application = pageContext.getServletContext();
          config = pageContext.getServletConfig();
          session = pageContext.getSession();
          out = pageContext.getOut();
          _jspx_out = out;
    
  4. 以上的这些对象我们可以在JSP页面中直接使用!

    image-20220217233420950

在JSP页面中:

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

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

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

这样的格式,输出到前端

8.3、JSP基础语法

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

JSP表达式

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

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

JSP声明

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

   private int globalVar = 0;

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

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

在JSP中嵌入JAVA代码即可!

<%%>
<%=%>
<%!%>
<%--注释--%>

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

8.4、JSP指令

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


    <%--@ include会将两个页面合二为一--%>
    <%@ include file="common/header.jsp"%>
    <h1>网页主体</h1>
    <%@ include file="common/footer.jsp"%>

    <hr>

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

8.5、9大内置对象

  • PageContext 存东西
  • Requset 存东西
  • Response
  • Session 存东西
  • Application【ServletContext】存东西
  • config【ServletConfig】
  • out
  • page 不用了解
  • exception
    pageContext.setAttribute("name1","1号");//保存的数据只在一个页面中生效
    request.setAttribute("name2","2号");//保存的数据只在一次请求中有效,请求转发也会携带这个数据
    session.setAttribute("name3","3号");//保存的数据只在一次会话中有效,从打开浏览器到关闭浏览器
    application.setAttribute("name4","4号");//保存的数据只在服务器中有效,从打开服务器到关闭服务器

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

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

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

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

        <!--JSTL表达式的依赖-->
        <dependency>
            <groupId>javax.servlet.jsp.jstl</groupId>
            <artifactId>jstl-api</artifactId>
            <version>1.2</version>
        </dependency>
        <!--standard标签-->
        <dependency>
            <groupId>taglibs</groupId>
            <artifactId>standard</artifactId>
            <version>1.1.2</version>
        </dependency>

EL表达式: ${}

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

JSP标签:

<%--jsp:include--%>

<jsp:forward page="/jspTag2.jsp">
    <jsp:param name="name" value="dt"/>
    <jsp:param name="age" value="18"/>
</jsp:forward>

JSTL表达式:

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

核心标签(掌握部分)

标签 描述
<c:out> 用于在JSP中显示数据,就像<%= ... >
<c:set> 用于保存数据
<c:remove> 用于删除数据
<c:if> 与我们在一般程序中用的if一样
<c:choose> 本身只当做<c:when><c:otherwise>的父标签
<c:when> <c:choose>的子标签,用来判断条件是否成立
<c:otherwise> <c:choose>的子标签,接在<c:when>标签后,当<c:when>标签判断为false时被执行
<c:forEach> 基础迭代标签,接受多种集合类型
<c:url> 使用可选的查询参数来创造一个URL

格式化标签

SQL标签

XML标签

JSTL标签库使用步骤

  • 引入对应的taglib

    <%--引入JSTL核心标签库,我们才能使用JSTL标签--%>
    <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
    
  • 使用其中的方法

  • 在Tomcat也需要引入JSTL的包,否则会报错:JSTL解析错误

<c:if><c:out>使用:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%--引入JSTL核心标签库,我们才能使用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="isAdmin">
    <c:out value="管理员您好!"></c:out>
</c:if>
<c:out value="${isAdmin}"></c:out>

</body>
</html>

<c:when>使用:

<%@ 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>

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

<c:choose>
    <c:when test="${score>=90}">
        <c:out value="你的成绩为优秀"></c:out>
    </c:when>
    <c:when test="${score>=80}">
        <c:out value="你的成绩为一般"></c:out>
    </c:when>
    <c:when test="${score<80}">
        <c:out value="菜鸡多练练吧"></c:out>
    </c:when>
</c:choose>

</body>
</html>

<c:forEach>使用:

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

<%
    ArrayList<String> people = new ArrayList<>();
    people.add(0,"张三");
    people.add(1,"李四");
    people.add(2,"王五");
    people.add(3,"赵六");
    people.add(4,"钱七");
    request.setAttribute("list",people);
%>
<%--
var,每一次遍历出来的变量
item,要遍历的对象
begin,开始
end,结束
step,步长
--%>
<c:forEach var="people" items="${list}">
    <c:out value="${people}"></c:out> <br>
</c:forEach>

<hr>

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

</body>
</html>

9、JavaBean

实体类

JavaBean有特定的写法:

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

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

ORM:对象关系映射

  • 表-->类
  • 字段-->属性
  • 行记录-->对象
id name age address
1 one 18 海南
2 two 18 海南
3 three 18 海南
class People {
    private int id;
    private String name;
    private int age;
    private String address;
}
class A {
    new People(1,"one",18,"海南");
    new People(2,"two",18,"海南");
    new People(3,"three",18,"海南");
}

10、MVC三层架构

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

10.1、早期架构

image-20220224231622355

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

servlet-->CRUD-->数据库

弊端:程序臃肿,不利于维护 servlet的代码中:处理请求、响应、视图跳转、处理JDBC、处理业务代码、处理逻辑代码

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

程序员调用

||

JDBC

||

MySQL Oracle SQLServer...

10.2、三层架构

image-20220224233713459

Model

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

View

  • 展示数据
  • 提供数据发起Servlet请求

Controller

  • 接收用户的请求:(req:请求参数、Session信息...)
  • 交给业务层处理对应的代码
  • 控制视图的跳转
登录--->接收用户的登录信息--->处理用户的请求(获取用登录的参数,username,password)--->交给业务层处理登录业务(判断用户名密码是否正确:事务)--->Dao层查询用户名和密码是否正确

11、Filter

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

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

image-20220228223412198

Filter开发步骤:

  1. 导包

    porn.xml

    	<dependencies>
            <dependency>
                <groupId>javax.servlet</groupId>
                <artifactId>servlet-api</artifactId>
                <version>2.5</version>
            </dependency>
            <dependency>
                <groupId>javax.servlet.jsp</groupId>
                <artifactId>javax.servlet.jsp-api</artifactId>
                <version>2.3.3</version>
            </dependency>
            <dependency>
                <groupId>javax.servlet.jsp.jstl</groupId>
                <artifactId>jstl-api</artifactId>
                <version>1.2</version>
            </dependency>
            <dependency>
                <groupId>taglibs</groupId>
                <artifactId>standard</artifactId>
                <version>1.1.2</version>
            </dependency>
            <!--连接数据库-->
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>5.1.47</version>
            </dependency>
        </dependencies>
    
  2. 编写过滤器

    1. 导包不要错

      image-20220228225352142

    2. 实现Filter接口,重写对应的方法即可

      public class CharacterEncodingFilter implements Filter {
      
          //初始化:web服务器启动就已经初始化了,随时等待过滤对象出现!
          @Override
          public void init(FilterConfig filterConfig) throws ServletException {
              System.out.println("CharacterEncodingFilter初始化");
          }
      
          /*
          1.过滤中的所有代码,在过滤特点请求的时候都会执行
          2.必须要让过滤器继续通行
              filterChain.doFilter(servletRequest,servletResponse);
           */
          @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销毁");
          }
      }
      
    3. 在web.xml中配置Filter

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

12、监听器

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

  1. 编写一个监听器

    实现监听器的接口

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

        <!--注册监听器-->
        <listener>
            <listener-class>com.dt.listener.OnlineCountListener</listener-class>
        </listener>
    
  3. 看情况是否使用

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

监听器:GUI编程中经常使用

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

        frame.setBounds(300,300,500,500);
        frame.setBackground(new Color(0,0,255));
        panel.setBounds(50,50,300,300);
        panel.setBackground(new Color(0,255,0));

        frame.add(panel);
        frame.setVisible(true);

        //监听事件,监听关闭事件
        frame.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }
        });
    }
}

14、JDBC

什么是JDBC:Java 连接数据库!

需要Java包的支持:

  • java.sql
  • javax.sql
  • mysql-connector-java 连接驱动(必须导入)

实验环境搭建

在SQLyog中创建 jdbc 数据库并运行以下SQL语句

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

INSERT INTO users(id,`name`,`password`,email,birthday)
VALUES(1,'张三','123456','zs@qq.com','2000-01-01');
INSERT INTO users(id,`name`,`password`,email,birthday)
VALUES(2,'李四','123456','ls@qq.com','2001-01-01');
INSERT INTO users(id,`name`,`password`,email,birthday)
VALUES(3,'王五','123456','ww@qq.com','2002-01-01');

SELECT * FROM users;

在porn.xml导入数据库依赖

<dependencies>
    <!--mysql的驱动-->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.47</version>
    </dependency>
</dependencies>

IDEA中连接数据库

image-20220325213156855

image-20220325213637652

JDBC固定步骤:

  1. 加载驱动
  2. 连接数据库
  3. 向数据库发送SQL的对象statement:CRUD
  4. 编写SQL(根据业务,不同的SQL)
  5. 执行SQL
  6. 关闭连接
package com.dt.test;

import java.sql.*;

/**
 * Created with IntelliJ IDEA.
 *
 * @author Dt
 * @Project javaweb-jdbc
 * @Title: TestJdbc
 * @Package com.dt.test
 * @Description: TODO
 * @date 2022/3/25 20:41
 */
public class TestJdbc {
    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        //配置信息
        //useUnicode=true&characterEncoding=utf-8   解决中文乱码
        String url = "jdbc:mysql://localhost:3306/jdbc?useUnicode=true&characterEncoding=utf-8&useSSL=false";
        String username = "root";
        String password = "123456";

        //1.加载驱动
        Class.forName("com.mysql.jdbc.Driver");
        //2.连接数据库
        Connection connection = DriverManager.getConnection(url, username, password);

        //3.向数据库发送SQL的对象statement,PreparedStatement:CRUD
        Statement statement = connection.createStatement();


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

        //5.执行查询SQl
        ResultSet resultSet = statement.executeQuery(sql);
        while (resultSet.next()) {
            System.out.println("id="+resultSet.getInt("id"));
            System.out.println("name="+resultSet.getString("name"));
            System.out.println("password="+resultSet.getString("password"));
            System.out.println("email="+resultSet.getString("email"));
            System.out.println("birthday="+resultSet.getString("birthday"));
        }

        //6.关闭连接,释放资源(一定要做)
        resultSet.close();
        statement.close();
        connection.close();
    }
}

预编译SQL

package com.dt.test;

import java.sql.*;

/**
 * Created with IntelliJ IDEA.
 *
 * @author Dt
 * @Project javaweb-jdbc
 * @Title: TestJdbc2
 * @Package com.dt.test
 * @Description: TODO
 * @date 2022/3/25 22:01
 */
public class TestJdbc2 {
    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        //配置信息
        //useUnicode=true&characterEncoding=utf-8   解决中文乱码
        String url = "jdbc:mysql://localhost:3306/jdbc?useUnicode=true&characterEncoding=utf-8&useSSL=false";
        String username = "root";
        String password = "123456";

        //1.加载驱动
        Class.forName("com.mysql.jdbc.Driver");
        //2.连接数据库
        Connection connection = DriverManager.getConnection(url, username, password);

        //3.编写SQL
        String sql = "insert into jdbc.users (id, name, password, email, birthday) values (?,?,?,?,?);";

        //4.预编译
        PreparedStatement statement = connection.prepareStatement(sql);
        statement.setInt(1, 4);//给第一个占位符?的值赋为4
        statement.setString(2, "赵六");
        statement.setString(3, "123456");
        statement.setString(4, "zl@qq.com");
        statement.setDate(5, new Date(new java.util.Date().getTime()));

        //5.执行查询SQl
        int i = statement.executeUpdate();
        if (i > 0) {
            System.out.println("插入成功");
        }

        //6.关闭连接,释放资源(一定要做)
        statement.close();
        connection.close();
    }
}

事务

要么都成功,要么都失败!

ACID原则:保证数据的安全

开启事务
事务提交 commit()
事务回滚 rollback()
关闭事务

例子:转账
A:1000
B:1000

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

Junit单元测试

依赖

<!--单元测试-->
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
</dependency>

简单使用

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

@Test
public void test() {
    System.out.println("Hello");
}

image-20220325224204013

失败的时候是红色:

image-20220325224329313

搭建一个环境


SMBMS

image-20220326141550682

数据库:

image-20220326143412463

项目如何搭建?

考虑使用不使用Maven?依赖,jar

项目搭建 准备工作

  1. 搭建一个Maven Web项目

  2. 配置Tomcat

  3. 测试项目是否能够跑起来

  4. 导入项目中会遇到的jar包:

    <dependencies>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>4.0.1</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet.jsp</groupId>
            <artifactId>javax.servlet.jsp-api</artifactId>
            <version>2.3.3</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>
        <dependency>
          <groupId>javax.servlet.jsp.jstl</groupId>
          <artifactId>jstl-api</artifactId>
          <version>1.2</version>
        </dependency>
        <dependency>
          <groupId>taglibs</groupId>
          <artifactId>standard</artifactId>
          <version>1.1.2</version>
        </dependency>
    </dependencies>
    
  5. 创建项目包结构

    image-20220326150618751

  6. 编写实体类

    ORM映射:表-类映射

  7. 编写基础公共类

    1. 数据库配置文件

      driver=com.mysql.jdbc.Driver
      url=jdbc:mysql://localhost:3306/smbms?useUnicode=true&characterEncoding=utf-8&useSSL=false
      username=root
      password=123456
      
    2. 编写数据库的公共类

      package com.dt.dao;
      
      
      import java.io.IOException;
      import java.io.InputStream;
      import java.sql.*;
      import java.util.Properties;
      
      /**
       * Created with IntelliJ IDEA.
       *
       * @author Dt
       * @Project smbms
       * @Title: BaseDao
       * @Package com.dt.dao
       * @Description: TODO
       * @date 2022/3/26 16:22
       */
      //操作数据库的公共类
      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();
              }
              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;
          }
      
          //编写增删改公共方法
          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 updateRow = preparedStatement.executeUpdate();
              return updateRow;
          }
      
          //释放资源
          public static boolean closeResource(Connection connection, PreparedStatement preparedStatement, ResultSet resultSet) {
              boolean flag = true;
      
              if (resultSet!=null) {
                  try {
                      resultSet.close();
                      //GC回收
                      resultSet = null;
                  } catch (SQLException e) {
                      e.printStackTrace();
                      flag = false;
                  }
              }
              if (preparedStatement!=null) {
                  try {
                      preparedStatement.close();
                      //GC回收
                      preparedStatement = null;
                  } catch (SQLException e) {
                      e.printStackTrace();
                      flag = false;
                  }
              }
              if (connection!=null) {
                  try {
                      connection.close();
                      //GC回收
                      connection = null;
                  } catch (SQLException e) {
                      e.printStackTrace();
                      flag = false;
                  }
              }
              return flag;
          }
      }
      
      
    3. 编写字符编码过滤器

      web.xml

      <!--字符编码过滤器-->
      <filter>
          <filter-name>CharacterEncodingFilter</filter-name>
          <filter-class>com.dt.filter.CharacterEcodingFilter</filter-class>
      </filter>
      <filter-mapping>
          <filter-name>CharacterEncodingFilter</filter-name>
          <url-pattern>/*</url-pattern>
      </filter-mapping>
      
  8. 导入静态资源

    image-20220327104354738

登录功能实现

  1. 编写前端页面

  2. 设置首页

    <!--设置欢迎页面-->
    <welcome-file-list>
        <welcome-file>login.jsp</welcome-file>
    </welcome-file-list>
    
  3. 编写dao层得到用户登录的接口

    package com.dt.dao.user;
    
    import com.dt.pojo.User;
    
    import java.sql.Connection;
    import java.sql.SQLException;
    
    /**
     * Created with IntelliJ IDEA.
     *
     * @author Dt
     * @Project smbms
     * @Title: UserDao
     * @Package com.dt.dao.user
     * @Description: TODO
     * @date 2022/3/27 11:19
     */
    public interface UserDao {
    
        //得到登录的用户
        public User getLoginUser(Connection connection, String userCode) throws SQLException;
    
    }
    
  4. 编写dao接口的实现类

    package com.dt.dao.user;
    
    import com.dt.dao.BaseDao;
    import com.dt.pojo.User;
    
    import java.sql.Connection;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    
    /**
     * Created with IntelliJ IDEA.
     *
     * @author Dt
     * @Project smbms
     * @Title: UserDaoImpl
     * @Package com.dt.dao.user
     * @Description: TODO
     * @date 2022/3/27 11:22
     */
    public class UserDaoImpl implements UserDao {
        //得到登录的用户
        @Override
        public User getLoginUser(Connection connection, String userCode) throws SQLException {
            PreparedStatement pstm = null;
            ResultSet rs = null;
            User user = null;
    
            if (connection != null) {
                String sql = "select * from smbms_user where userCode=?";
                Object[] params = {userCode};
    
                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("createdBy"));
                    user.setCreationDate(rs.getTimestamp("creationDate"));
                    user.setModifyBy(rs.getInt("modifyBy"));
                    user.setModifyDate(rs.getTimestamp("modifyDate"));
                }
                BaseDao.closeResource(null, pstm, rs);
            }
            return user;
        }
    }
    
  5. 业务层接口

    package com.dt.service.user;
    
    import com.dt.pojo.User;
    
    /**
     * Created with IntelliJ IDEA.
     *
     * @author Dt
     * @Project smbms
     * @Title: UserService
     * @Package com.dt.service.user
     * @Description: TODO
     * @date 2022/3/27 15:26
     */
    public interface UserService {
        //用户登录
        public User login(String userCode, String password);
    }
    
  6. 业务层实现类

    package com.dt.service.user;
    
    import com.dt.dao.BaseDao;
    import com.dt.dao.user.UserDao;
    import com.dt.dao.user.UserDaoImpl;
    import com.dt.pojo.User;
    import org.junit.Test;
    
    import java.sql.Connection;
    import java.sql.SQLException;
    
    /**
     * Created with IntelliJ IDEA.
     *
     * @author Dt
     * @Project smbms
     * @Title: UserServiceImpl
     * @Package com.dt.service.user
     * @Description: TODO
     * @date 2022/3/27 15:35
     */
    public class UserServiceImpl implements UserService {
        //业务层都会调用dao层,所以我们要引入dao层
        private UserDao userDao;
    
        public UserServiceImpl() {
            userDao = new UserDaoImpl();
        }
    
        @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);
            }
            //匹配密码
            if (user != null) {
                if (!user.getUserPassword().equals(password)) {
                    user = null;
                }
            }
            return user;
        }
    
    }
    
  7. 编写Servlet

    package com.dt.servlet.user;
    
    import com.dt.pojo.User;
    import com.dt.service.user.UserService;
    import com.dt.service.user.UserServiceImpl;
    import com.dt.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;
    
    /**
     * Created with IntelliJ IDEA.
     *
     * @author Dt
     * @Project smbms
     * @Title: LoginServlet
     * @Package com.dt.servlet.user
     * @Description: TODO
     * @date 2022/3/27 16:22
     */
    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");
    
            //和数据库中的密码进行对比,调用业务层
            UserService 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);
        }
    }
    
  8. 注册Servlet

    <!--Servlet-->
    <servlet>
        <servlet-name>LoginServlet</servlet-name>
        <servlet-class>com.dt.servlet.user.LoginServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>LoginServlet</servlet-name>
        <url-pattern>/login.do</url-pattern>
    </servlet-mapping>
    
  9. 测试访问,确保以上功能成功!

登录功能优化

注销功能:

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

package com.dt.servlet.user;

import com.dt.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;

/**
 * Created with IntelliJ IDEA.
 *
 * @author Dt
 * @Project smbms
 * @Title: LogoutServlet
 * @Package com.dt.servlet.user
 * @Description: TODO
 * @date 2022/3/27 22:29
 */
public class LogoutServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //清楚Session
        req.getSession().removeAttribute(Constants.USER_SESSION);
        //返回登录页面
        resp.sendRedirect(req.getContextPath()+"/Login.jsp");
    }

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

注册xml

<servlet>
    <servlet-name>LogoutServlet</servlet-name>
    <servlet-class>com.dt.servlet.user.LogoutServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>LogoutServlet</servlet-name>
    <url-pattern>/jsp/logout.do</url-pattern>
</servlet-mapping>

登录拦截优化

编写一个过滤器,并注册

package com.dt.filter;

import com.dt.pojo.User;
import com.dt.util.Constants;

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

/**
 * Created with IntelliJ IDEA.
 *
 * @author Dt
 * @Project smbms
 * @Title: SysFilter
 * @Package com.dt.filter
 * @Description: TODO
 * @date 2022/3/27 22:46
 */
public class SysFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) resp;

        //过滤器,从Session中获取用户
        User user = (User) request.getSession().getAttribute(Constants.USER_SESSION);

        if (user == null) {//已经被移除或者注销了,或者未登录
            response.sendRedirect(request.getContextPath()+"/error.jsp");
        } else {
            filterChain.doFilter(req,resp);
        }
    }

    @Override
    public void destroy() {

    }
}

<!--用户登录过滤器-->
<filter>
    <filter-name>SysFilter</filter-name>
    <filter-class>com.dt.filter.SysFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>SysFilter</filter-name>
    <url-pattern>/jsp/*</url-pattern>
</filter-mapping>

密码修改

  1. 导入前端素材

  2. 写项目,建议从底层向上写

  3. UserDao接口

    //修改当前用户密码
    public int updatePwd(Connection connection, int id, String password) throws SQLException;
    
  4. UserDao接口实现类

    //修改当前用户密码
    @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,pstm,null);
        }
        return execute;
    }
    
  5. UserService层

    //根据用户ID修改密码
    public boolean updatePwd(int id, String pwd);
    
  6. UserService实现类

    @Override
    public boolean updatePwd(int id, String pwd) {
        Connection connection = null;
        boolean flag = false;
        try {
            connection = BaseDao.getConnection();
            //修改密码
            if (userDao.updatePwd(connection, id, pwd) > 0) {
                flag = true;
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            BaseDao.closeResource(connection, null, null);
        }
        return flag; 
    }
    
  7. Servlet记得实现复用,需要提取出方法!

    <servlet>
        <servlet-name>UserServlet</servlet-name>
        <servlet-class>com.dt.servlet.user.UserServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>UserServlet</servlet-name>
        <url-pattern>/jsp/user.do</url-pattern>
    </servlet-mapping>
    
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String method = req.getParameter("method");
        if (method != null && method.equals("savepwd")) {
            this.updatePwd(req,resp);
        }
    }
    
    public void updatePwd(HttpServletRequest req, HttpServletResponse resp) {
        //从Session里获取ID
        Object o = req.getSession().getAttribute(Constants.USER_SESSION);
        String newpassword = req.getParameter("newpassword");
    
        boolean flag = false;
        if (o != null && !StringUtils.isNullOrEmpty(newpassword)) {
            UserService userService = new UserServiceImpl();
            flag = userService.updatePwd(((User) o).getId(), newpassword);
            if (flag) {
                req.setAttribute("message", "修改密码成功,请退出,使用新密码登录");
                //密码修改成功,移除当前Session
                req.getSession().removeAttribute(Constants.USER_SESSION);
            } else {
                req.setAttribute("message", "密码修改失败");
            }
        } else {
            req.setAttribute("message", "新密码有问题");
        }
        try {
            req.getRequestDispatcher("pwdmodify.jsp").forward(req,resp);
        } catch (ServletException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
  8. 测试

优化密码修改使用Ajax

  1. 阿里巴巴的fastjson

    <!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>1.2.75</version>
    </dependency>
    </dependencies>
    
  2. 后台代码修改

    //验证旧密码,Session中有用户的密码
    public void pwdModify(HttpServletRequest req, HttpServletResponse resp) {
        Object o = req.getSession().getAttribute(Constants.USER_SESSION);
        String oldpassword = req.getParameter("oldpassword");
    
        //万能的Map:结果集
        Map<String, String> resultMap = new HashMap<String, String>();
        if (o == null) {    //Session失效/过期了
            resultMap.put("result", "sessionerror");
        } else if (StringUtils.isNullOrEmpty(oldpassword)) { //输入的密码为空
            resultMap.put("result", "error");
        } else {
            //Session中用户的密码
            String userPassword = ((User) o).getUserPassword();
            if (oldpassword.equals(userPassword)) {
                resultMap.put("result", "true");
            } else {
                resultMap.put("result", "false");
            }
        }
    
        try {
            resp.setContentType("application/json");
            PrintWriter writer = resp.getWriter();
            //JSONArray:阿里巴巴的JSON工具类,转换格式
            /*
                resultMap = ["result":"sessionerror","result":"error"]
                Json格式 = {key:value}
                 */
            writer.write(JSONArray.toJSONString(resultMap));
            writer.flush();
            writer.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
  3. 测试

用户管理实现

思路:

image-20220329200536002

  1. 导入分页的工具类:PageSupport.java
  2. 用户列表页面导入
    • userlist.jsp
    • rollpage.jsp
    • useradd.jsp
    • usermodify.jsp
    • userview.jsp

1、获取用户数量

  1. UserDao

    //根据用户名或角色查询用户总数
    public int getUserCount(Connection connection, String userName, int userRole) throws SQLException;
    
  2. UserDaoImpl

    //根据用户名或角色查询用户总数
    @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<Object>();//存放我们的参数
    
            if (!StringUtils.isNullOrEmpty(userName)) {
                sql.append(" and u.userName like ?");
                list.add("%"+userName+"%");//index=0
            }
            if (userRole > 0) {
                sql.append(" and u.userRole like ?");
                list.add(userRole);
            }
            //怎么把list转换为数组
            Object[] params = list.toArray();
    
            rs = BaseDao.execute(connection, pstm, rs, sql.toString(), params);
    
            if (rs.next()) {
                count = rs.getInt("count");//从结果集中获取最终的数量
            }
            BaseDao.closeResource(null, pstm, rs);
        }
        return count;
    }
    
  3. UserService

    //查询记录数
    public int getUserCount(String userName, int userRole);
    
  4. UserServiceImpl

    @Override
    public int getUserCount(String userName, int userRole) {
        Connection connection = null;
        int count = 0;
    
        try {
            connection = BaseDao.getConnection();
            count = userDao.getUserCount(connection, userName, userRole);
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            BaseDao.closeResource(connection, null, null);
        }
        return count;
    }
    

2、获取用户列表

  1. UserDao

    //通过条件查询-userList
    public List<User> getUserList(Connection connection, String userName, int userRole, int currentPageNo, int pageSize) throws SQLException;
    
  2. UserDaoImpl

    //通过条件查询-userList
    @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 = new ArrayList<User>();
    
        if (connection != null) {
            StringBuffer sql = new StringBuffer();
            sql.append("select u.*,r.roleName as userRoleName from smbms_user u,smbms_role r where u.userRole = r.id");
            ArrayList<Object> list = new ArrayList<Object>();//存放我们的参数
    
            if (!StringUtils.isNullOrEmpty(userName)) {
                sql.append(" and u.userName like ?");
                list.add("%"+userName+"%");//index=0
            }
            if (userRole > 0) {
                sql.append(" and u.userRole like ?");
                list.add(userRole);
            }
    
            sql.append(" order by creationDate DESC list ?,?");
            currentPageNo = (currentPageNo-1)*pageSize;
            list.add(currentPageNo);
            list.add(pageSize);
    
            //怎么把list转换为数组
            Object[] params = list.toArray();
    
            rs = BaseDao.execute(connection, pstm, rs, sql.toString(), params);
    
            if (rs.next()) {
                User user = new User();
                user.setId(rs.getInt("id"));
                user.setUserCode(rs.getString("userCode"));
                user.setUserName(rs.getString("userName"));
                user.setGender(rs.getInt("gender"));
                user.setBirthday(rs.getDate("birthday"));
                user.setPhone(rs.getString("phone"));
                user.setUserRole(rs.getInt("userRole"));
                user.setUserRoleName(rs.getString("userRoleName"));
                userList.add(user);
            }
            BaseDao.closeResource(null, pstm, rs);
        }
        return userList;
    }
    
  3. UserService

    //根据条目查询用户列表
    public List<User> getUserList(String queryUserName, int queryUserRole, int currentPageNo, int pageSize);
    
  4. UserServiceImpl

    @Override
    public List<User> getUserList(String queryUserName, int queryUserRole, int currentPageNo, int pageSize) {
        Connection connection = null;
        List<User> userList = null;
    
        try {
            connection = BaseDao.getConnection();
            userList = userDao.getUserList(connection, queryUserName, queryUserRole, currentPageNo, pageSize);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            BaseDao.closeResource(connection, null, null);
        }
        return userList;
    }
    

3、获取角色操作!

为了我们职责统一,可以把角色的操作单独放在一个包中,和POJO类对应

  1. RoleDao

    package com.dt.dao.role;
    
    import com.dt.pojo.Role;
    
    import java.sql.Connection;
    import java.sql.SQLException;
    import java.util.List;
    
    /**
     * Created with IntelliJ IDEA.
     *
     * @author Dt
     * @Project smbms
     * @Title: RoleDao
     * @Package com.dt.dao.role
     * @Description: TODO
     * @date 2022/3/30 15:35
     */
    public interface RoleDao {
        //获取角色列表
        public List<Role> getRoleList(Connection connection) throws SQLException;
    }
    
  2. RoleDaoImpl

    package com.dt.dao.role;
    
    import com.dt.dao.BaseDao;
    import com.dt.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;
    
    /**
     * Created with IntelliJ IDEA.
     *
     * @author Dt
     * @Project smbms
     * @Title: RoleDaoImpl
     * @Package com.dt.dao.role
     * @Description: TODO
     * @date 2022/3/30 15:36
     */
    public class RoleDaoImpl implements RoleDao {
        //获取角色列表
        @Override
        public List<Role> getRoleList(Connection connection) throws SQLException {
            PreparedStatement pstm = null;
            ResultSet rs = null;
            List<Role> roleList = new ArrayList<Role>();
            if (connection != null) {
                String sql = "select * from smbms_role";
                Object[] params = {};
                rs = 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, pstm, rs);
            }
            return  roleList;
        }
    }
    
  3. RoleService

    package com.dt.service.role;
    
    import com.dt.pojo.Role;
    
    import java.util.List;
    
    /**
     * Created with IntelliJ IDEA.
     *
     * @author Dt
     * @Project smbms
     * @Title: RoleService
     * @Package com.dt.service.role
     * @Description: TODO
     * @date 2022/3/30 15:39
     */
    public interface RoleService {
        public List<Role> getRoleList();
    }
    
  4. RoleServiceImpl

    package com.dt.service.role;
    
    import com.dt.dao.BaseDao;
    import com.dt.dao.role.RoleDao;
    import com.dt.dao.role.RoleDaoImpl;
    import com.dt.pojo.Role;
    
    import java.sql.Connection;
    import java.sql.SQLException;
    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * Created with IntelliJ IDEA.
     *
     * @author Dt
     * @Project smbms
     * @Title: RoleServiceImpl
     * @Package com.dt.service.role
     * @Description: TODO
     * @date 2022/3/30 15:41
     */
    public class RoleServiceImpl implements  RoleService {
    
        //引入dao
        private RoleDao roleDao;
        public RoleServiceImpl(RoleDao roleDao) {
            this.roleDao = new RoleDaoImpl();
        }
    
        @Override
        public List<Role> getRoleList() {
            Connection connection = null;
            List<Role> roleList = new ArrayList<Role>();
            try {
                connection = BaseDao.getConnection();
                roleList = roleDao.getRoleList(connection);
            } catch (SQLException e) {
                e.printStackTrace();
            } finally {
                BaseDao.closeResource(connection, null, null);
            }
            return roleList;
        }
    }
    

4、用户显示的Servlet

  1. 获取用户前端的数据(查询)
  2. 判断请求是否需要执行,看参数得知判断
  3. 为了实现分页,需要计算出当前页面和总页面,页面大小
  4. 用户列表展示
  5. 返回前端
    //重点,难点
    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;

        //获取用户列表
        UserService userService = new UserServiceImpl();
        List<User> userList = null;

        //第一次走这个请求,一定是第一页,并且页面大小固定
        int pageSize = 5;//可以把这个放到配置文件中,方便后期修改
        int currentPageNo = 1;

        if (queryUserName == null) {
            queryUserName = "";
        }
        if (temp != null && !temp.equals("")) {
            queryUserRole = Integer.parseInt(temp); //给查询赋值
        }
        if (pageIndex != null) {
           currentPageNo = Integer.parseInt(pageIndex);
        }

        //获取用户的总数(分页:上一页,下一页的情况)
        int totalCount = userService.getUserCount(queryUserName, queryUserRole);
        //总页数支持
        PageSupport pageSupport = new PageSupport();
        pageSupport.setCurrentPageNo(currentPageNo);
        pageSupport.setPageSize(pageSize);
        pageSupport.setTotalCount(totalCount);

        int totalPageCount = pageSupport.getTotalPageCount();
        pageSupport.setTotalPageCount(totalPageCount);
        //控制首页和尾页
        //如果页面小于1了,就显示第一页的东西
        if (currentPageNo < 1) {
            currentPageNo = 1;
        } else if (currentPageNo > totalPageCount) {
            currentPageNo = totalPageCount;
        }

        //获取用户列表展示
        userList = userService.getUserList(queryUserName, queryUserRole, currentPageNo, pageSize);
        req.setAttribute("userList",userList);

        //获取角色列表
        RoleService roleService = new RoleServiceImpl();
        List<Role> roleList = roleService.getRoleList();
        req.setAttribute("roleList",roleList);

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

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

5、管理用户

一、添加用户(还需要查看用户是否存在)

  1. UserDao

    //添加用户
    public int add(Connection connection, User user) throws SQLException;
    
  2. UserDaoImpl

    //添加用户
    @Override
    public int add(Connection connection, User user) throws SQLException {
        PreparedStatement pstm = null;
        int updateRows = 0;
        if (connection != null) {
            String sql = "insert into smbms_user (userCode,userName,userPassword," +
                "userRole,gender,birthday,phone,address,creationDate,createdBy) " +
                "values (?,?,?,?,?,?,?,?,?,?);";
            Object[] params = {user.getUserCode(), user.getUserName(), user.getUserPassword(),
                               user.getUserRole(), user.getGender(), user.getBirthday(), user.getPhone(), user.getAddress(),
                               user.getCreationDate(), user.getCreatedBy()};
    
            updateRows = BaseDao.execute(connection, pstm, sql, params);
            BaseDao.closeResource(null, pstm, null);
        }
        return updateRows;
    }
    
  3. UserService

    //添加用户
    public boolean add(User user);
    
    //根据用户编码查询是否存在
    public User selectUserCodeExist(String userCode);
    
  4. UserServiceImpl

    @Override
    public boolean add(User user) {
        boolean flag = false;
        Connection connection = null;
    
        try {
            connection = BaseDao.getConnection();
            connection.setAutoCommit(false);//开启JDBC事务管理
            int updateRows = userDao.add(connection, user);
            connection.commit();
            if (updateRows > 0) {
                flag = true;
            }
        } catch (SQLException e) {
            try {
                connection.rollback();
            } catch (SQLException ex) {
                ex.printStackTrace();
            }
        } finally {
            BaseDao.closeResource(connection, null, null);
        }
        return flag;
    }
    
    @Override
    public User selectUserCodeExist(String userCode) {
        Connection connection = null;
        User user = null;
        try {
            connection = BaseDao.getConnection();
            user = userDao.getLoginUser(connection, userCode);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            BaseDao.closeResource(connection, null, null);
        }
        return user;
    }
    
  5. UserServlet

    //添加用户
    private void add(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException {
        String userCode = req.getParameter("userCode");
        String userName = req.getParameter("userName");
        String userRole = req.getParameter("userRole");
        String userPassword = req.getParameter("userPassword");
        String gender = req.getParameter("gender");
        String birthday = req.getParameter("birthday");
        String phone = req.getParameter("phone");
        String address = req.getParameter("address");
    
        User user = new User();
        user.setUserCode(userCode);
        user.setUserName(userName);
        user.setUserRole(Integer.valueOf(userRole));
        user.setUserPassword(userPassword);
        user.setGender(Integer.valueOf(gender));
        try {
            user.setBirthday(new SimpleDateFormat("yyyy-MM-dd").parse(birthday));
        } catch (ParseException e) {
            e.printStackTrace();
        }
        user.setPhone(phone);
        user.setAddress(address);
        user.setCreationDate(new Date());
        user.setCreatedBy(((User)req.getSession().getAttribute(Constants.USER_SESSION)).getId());
    
        UserService userService = new UserServiceImpl();
        if (userService.add(user)) {
            resp.sendRedirect(req.getContextPath()+"/jsp/user.do?method=query");
        } else {
            req.getRequestDispatcher("useradd.jsp").forward(req,resp);
        }
    }
    
    //判断用户账户是否可用
    private void userCodeExist(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        String userCode = req.getParameter("userCode");
        HashMap<String, String> resultMap = new HashMap<String, String>();
        if (StringUtils.isNullOrEmpty(userCode)) {
            resultMap.put("userCode", "exist");
        } else {
            UserService userService = new UserServiceImpl();
            User user = userService.selectUserCodeExist(userCode);
            if (user != null) {
                resultMap.put("userCode", "exist");
            } else {
                resultMap.put("userCode", "notexist");
            }
        }
        resp.setContentType("application/json");
        PrintWriter writer = resp.getWriter();
        writer.write(JSONArray.toJSONString(resultMap));
        writer.flush();
        writer.close();
    }
    

二、删除用户

  1. UserDao

    //删除用户
    public int deleteUserById(Connection connection, Integer delId) throws SQLException;
    
  2. UserDaoImpl

    //删除用户
    @Override
    public int deleteUserById(Connection connection, Integer delId) throws SQLException {
        PreparedStatement pstm = null;
        int flag = 0;
        if (connection != null) {
            String sql = "delete from smbms_user where id = ?";
            Object[] params = {delId};
            flag = BaseDao.execute(connection, pstm, sql, params);
            BaseDao.closeResource(null, pstm, null);
        }
        return flag;
    }
    
  3. UserService

    //根据id删除用户
    public boolean deleteUserById(Integer delId);
    
  4. UserServiceImpl

    @Override
    public boolean deleteUserById(Integer delId) {
        Connection connection =null;
        boolean flag = false;
        try {
            connection = BaseDao.getConnection();
            connection.setAutoCommit(false);
            int updateRows = userDao.deleteUserById(connection, delId);
            connection.commit();
            if (updateRows > 0) {
                flag = true;
            }
        } catch (Exception e) {
            try {
                connection.rollback();
            } catch (SQLException ex) {
                ex.printStackTrace();
            }
        } finally {
            BaseDao.closeResource(connection, null, null);
        }
        return flag;
    }
    
  5. UserServlet

    //删除用户
    private void delUser(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        String id = req.getParameter("uid");
        Integer delId = 0;
        try {
            delId = Integer.parseInt(id);
        } catch (NumberFormatException e) {
            delId = 0;
        }
        HashMap<String, String> resultMap = new HashMap<String, String>();
        if (delId <= 0) {
            resultMap.put("delResult","notexist");
        } else {
            UserService userService = new UserServiceImpl();
            if (userService.deleteUserById(delId)) {
                resultMap.put("delResult", "true");
            } else {
                resultMap.put("delResult", "false");
            }
        }
    
        resp.setContentType("application/json");
        PrintWriter writer = resp.getWriter();
        writer.write(JSONArray.toJSONString(resultMap));
        writer.flush();
        writer.close();
    }
    

三、修改用户(需要先获取用户信息)

  1. UserDao

    //根据id获取用户
    public User getUserById(Connection connection, String id) throws SQLException;
    
    //修改用户
    public int modify(Connection connection, User user) throws SQLException;
    
  2. UserDaoImpl

    //根据id获取用户
    @Override
    public User getUserById(Connection connection, String id) throws SQLException {
        PreparedStatement pstm = null;
        User user = null;
        ResultSet rs = null;
        if (connection != null) {
            String sql = "select u.*,r.roleName as userRoleName from smbms_user u,smbms_role r " +
                "where u.id=? and u.userRole = r.id";
            Object[] params = {id};
            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("createdBy"));
                user.setCreationDate(rs.getTimestamp("creationDate"));
                user.setModifyBy(rs.getInt("modifyBy"));
                user.setModifyDate(rs.getTimestamp("modifyDate"));
                user.setUserRoleName(rs.getString("userRoleName"));
            }
            BaseDao.closeResource(null, pstm, rs);
        }
        return user;
    }
    
    //修改用户
    @Override
    public int modify(Connection connection, User user) throws SQLException {
        PreparedStatement pstm = null;
        int flag = 0;
        if (connection != null) {
            String sql = "update smbms_user set userName=?," +
                "gender=?,birthday=?,phone=?,address=?,userRole=?,modifyBy=?,modifyDate=? where id = ? ";
            Object[] params = {user.getUserName(), user.getGender(), user.getBirthday(), user.getPhone(),
                               user.getAddress(), user.getUserRole(), user.getModifyBy(), user.getModifyDate(), user.getId()};
            flag = BaseDao.execute(connection, pstm, sql, params);
            BaseDao.closeResource(null, pstm, null);
        }
        return flag;
    }
    
  3. UserService

    //根据id获取用户信息
    public User getUserById(String id);
    
    //修改用户信息
    public boolean modify(User user);
    
  4. UserServiceImpl

    @Override
    public User getUserById(String id) {
        Connection connection = null;
        User user = null;
        try {
            connection = BaseDao.getConnection();
            user = userDao.getUserById(connection, id);
        } catch (Exception e) {
            e.printStackTrace();
            user = null;
        } finally {
            BaseDao.closeResource(connection, null, null);
        }
        return user;
    }
    
    @Override
    public boolean modify(User user) {
        Connection connection = null;
        boolean flag = false;
        try {
            connection = BaseDao.getConnection();
            connection.setAutoCommit(false);
            int updateRows = userDao.modify(connection, user);
            connection.commit();
            if (updateRows > 0) {
                flag = true;
            }
        } catch (Exception e) {
            try {
                connection.rollback();
            } catch (SQLException ex) {
                ex.printStackTrace();
            }
        } finally {
            BaseDao.closeResource(connection, null, null);
        }
        return flag;
    }
    
  5. UserServlet

    //根据id获取用户
    private void getUserById(HttpServletRequest req, HttpServletResponse resp, String url) throws ServletException, IOException {
        String id = req.getParameter("uid");
        if (!StringUtils.isNullOrEmpty(id)) {
            UserService userService = new UserServiceImpl();
            User user = userService.getUserById(id);
            req.setAttribute("user", user);
            req.getRequestDispatcher(url).forward(req,resp);
        }
    }
    
    //修改用户
    private void modify(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException {
        String id = req.getParameter("uid");
        String userName = req.getParameter("userName");
        String gender = req.getParameter("gender");
        String birthday = req.getParameter("birthday");
        String phone = req.getParameter("phone");
        String address = req.getParameter("address");
        String userRole = req.getParameter("userRole");
    
        User user = new User();
        user.setId(Integer.valueOf(id));
        user.setUserName(userName);
        user.setGender(Integer.valueOf(gender));
        try {
            user.setBirthday(new SimpleDateFormat("yyyy-MM-dd").parse(birthday));
        } catch (ParseException e) {
            e.printStackTrace();
        }
        user.setPhone(phone);
        user.setAddress(address);
        user.setUserRole(Integer.valueOf(userRole));
        user.setModifyBy(((User)req.getSession().getAttribute(Constants.USER_SESSION)).getId());
        user.setModifyDate(new Date());
    
        UserService userService = new UserServiceImpl();
        if (userService.modify(user)) {
            resp.sendRedirect(req.getContextPath()+"/jsp/user.do?method=query");
        } else {
            req.getRequestDispatcher("usermodify.jsp").forward(req,resp);
        }
    }
    

四、查看用户

  1. UserDao

    //根据id获取用户
    public User getUserById(Connection connection, String id) throws SQLException;
    
  2. UserDaoImpl

    //根据id获取用户
    @Override
    public User getUserById(Connection connection, String id) throws SQLException {
        PreparedStatement pstm = null;
        User user = null;
        ResultSet rs = null;
        if (connection != null) {
            String sql = "select u.*,r.roleName as userRoleName from smbms_user u,smbms_role r " +
                "where u.id=? and u.userRole = r.id";
            Object[] params = {id};
            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("createdBy"));
                user.setCreationDate(rs.getTimestamp("creationDate"));
                user.setModifyBy(rs.getInt("modifyBy"));
                user.setModifyDate(rs.getTimestamp("modifyDate"));
                user.setUserRoleName(rs.getString("userRoleName"));
            }
            BaseDao.closeResource(null, pstm, rs);
        }
        return user;
    }
    
  3. UserService

    //根据id获取用户信息
    public User getUserById(String id);
    
  4. UserServiceImpl

    @Override
    public User getUserById(String id) {
        Connection connection = null;
        User user = null;
        try {
            connection = BaseDao.getConnection();
            user = userDao.getUserById(connection, id);
        } catch (Exception e) {
            e.printStackTrace();
            user = null;
        } finally {
            BaseDao.closeResource(connection, null, null);
        }
        return user;
    }
    
  5. UserServlet

    //根据id获取用户
    private void getUserById(HttpServletRequest req, HttpServletResponse resp, String url) throws ServletException, IOException {
        String id = req.getParameter("uid");
        if (!StringUtils.isNullOrEmpty(id)) {
            UserService userService = new UserServiceImpl();
            User user = userService.getUserById(id);
            req.setAttribute("user", user);
            req.getRequestDispatcher(url).forward(req,resp);
        }
    }
    

6、最终UserServlet

package com.dt.servlet.user;

import com.alibaba.fastjson.JSONArray;
import com.dt.pojo.Role;
import com.dt.pojo.User;
import com.dt.service.role.RoleService;
import com.dt.service.role.RoleServiceImpl;
import com.dt.service.user.UserService;
import com.dt.service.user.UserServiceImpl;
import com.dt.util.Constants;
import com.dt.util.PageSupport;
import com.mysql.jdbc.StringUtils;

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.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created with IntelliJ IDEA.
 *
 * @author Dt
 * @Project smbms
 * @Title: UserServlet
 * @Package com.dt.servlet.user
 * @Description: TODO
 * @date 2022/3/28 12:19
 */

//实现Servlet复用
public class UserServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String method = req.getParameter("method");
        if (method != null && method.equals("savepwd")) {
            this.updatePwd(req,resp);
        } else if (method != null && method.equals("pwdmodify")) {
            this.pwdModify(req,resp);
        } else if (method != null && method.equals("query")) {
            this.query(req,resp);
        } else if (method != null && method.equals("add")) {
            this.add(req,resp);
        } else if (method != null && method.equals("getrolelist")) {
            this.getRoleList(req,resp);
        } else if (method != null && method.equals("ucexist")) {
            this.userCodeExist(req, resp);
        } else if (method != null && method.equals("deluser")) {
            this.delUser(req, resp);
        } else if (method != null && method.equals("view")) {
            this.getUserById(req, resp, "userview.jsp");
        } else if (method != null && method.equals("modify")) {
            this.getUserById(req, resp, "usermodify.jsp");
        } else if (method != null && method.equals("modifyexe")) {
            this.modify(req, resp);
        }
    }

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

    //添加用户
    private void add(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException {...}

    //重点,难点
    private void query(HttpServletRequest req, HttpServletResponse resp) {...}

    //获取角色列表
    private void getRoleList(HttpServletRequest req, HttpServletResponse resp) throws IOException {...}

    //判断用户账户是否可用
    private void userCodeExist(HttpServletRequest req, HttpServletResponse resp) throws IOException {...}

    //删除用户
    private void delUser(HttpServletRequest req, HttpServletResponse resp) throws IOException {...}
    //根据id获取用户
    private void getUserById(HttpServletRequest req, HttpServletResponse resp, String url) throws ServletException, IOException {...}

    //修改用户
    private void modify(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException {...}

    //修改密码
    private void updatePwd(HttpServletRequest req, HttpServletResponse resp) {...}
    //验证旧密码,Session中有用户的密码
    private void pwdModify(HttpServletRequest req, HttpServletResponse resp) {...}
}

拓展功能

文件上传

web.xml

<servlet>
    <servlet-name>FileServlet</servlet-name>
    <servlet-class>com.dt.servlet.FileServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>FileServlet</servlet-name>
    <url-pattern>/upload.do</url-pattern>
</servlet-mapping>

info.jsp

<%--
  Created by IntelliJ IDEA.
  User: Administrator
  Date: 2022/4/1
  Time: 14:57
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>$Title$</title>
</head>
<body>

<%--通过表单上传文件
    get:上传文件大小有限制
    post:上传文件大小没有限制
--%>
<form action="${pageContext.request.contextPath}/upload.do" method="post" enctype="multipart/form-data">
    上传用户:<input type="text" name="username"><br>
    <p><input type="file" name="file1"></p>
    <p><input type="file" name="file2"></p>
    <p><input type="submit"> | <input type="reset"></p>
</form>

</body>
</html>

FileServlet

package com.dt.servlet; 
/**
 * Created with IntelliJ IDEA.
 *
 * @Project 功能拓展
 * @Title: ${NAME}
 * @Package ${PACKAGE_NAME}
 * @Description: TODO
 * @author Dt
 * @date 2022/4/1 21:09
 */

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.ProgressListener;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;

import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.UUID;

@WebServlet(name = "FileServlet", value = "/FileServlet")
public class FileServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        //判断上传的文件是普通表单还是带文件的表单
        if (!ServletFileUpload.isMultipartContent(request)) {
            return;//终止方法运行,说明这是一个普通的表单,直接返回
        }

        //创建上传文件的保存路径,建议在WEB-INF路径下,安全,用户无法直接访问上传的文件
        String uploadPath = this.getServletContext().getRealPath("/WEB-INF/upload");
        File uploadFile = new File(uploadPath);
        if (!uploadFile.exists()) {
            uploadFile.mkdir();//创建这个目录
        }

        //缓存,临时文件
        //临时路径,如果文件超过了预期的大小,我们就把他放到一个临时文件里,过几天自动删除,或者提醒用户转存为永久
        String tmpdPath = this.getServletContext().getRealPath("/WEB-INF/tmp");
        File tmpFile = new File(tmpdPath);
        if (!tmpFile.exists()) {
            tmpFile.mkdir();//创建这个临时目录
        }

        //处理上传的文件,一般都需要通过流来获取,我们可以使用request.getInputStream(), 原生态的文件上传流获取,十分麻烦
        //但是我们都建议使用Apache的文件上传组件来实现,common-fileupload,它需要依赖于 common-io组件

        try {
            //1.创建DiskFileItemFactory对象,处理文件上传路径或者大小限制的
            DiskFileItemFactory factory = getDiskFileItemFactory(tmpFile);
            //2.获取ServletFileUpload
            ServletFileUpload upload = getServletFileUpload(factory);
            //3.处理上传的文件
            String msg = uploadParseRequest(upload, request, uploadPath);


            request.setAttribute("msg", msg);
            request.getRequestDispatcher("info.jsp").forward(request,response);
        } catch (FileUploadException e) {
            e.printStackTrace();
        }

    }


    public static DiskFileItemFactory getDiskFileItemFactory(File tmpFile) {
        DiskFileItemFactory factory = new DiskFileItemFactory();
        //通过这个工厂设置一个缓存区,当上传的文件大于这个缓存区的时候,将他放到临时文件中
        //缓存区大小为1M
        factory.setSizeThreshold(1024 * 1024);
        //临时目录的保存目录,需要一个File
        factory.setRepository(tmpFile);
        return factory;
    }

    public static ServletFileUpload getServletFileUpload(DiskFileItemFactory factory) {
        ServletFileUpload upload = new ServletFileUpload(factory);

        //监听文件上传进度
        upload.setProgressListener(new ProgressListener() {
            @Override
            //pBytesRead:已经读取到的文件大小
            //pContentLength:文件大小
            public void update(long pBytesRead, long pContentLength, int pItems) {
                System.out.println("总大小:" + pContentLength + "已上传:" + pBytesRead);
            }
        });

        //处理乱码问题
        upload.setHeaderEncoding("UTF-8");
        //设置单个文件的最大值
        upload.setFileSizeMax(1024 * 1024 * 10);
        //设置总共能上传文件的大小
        //1024 = 1kb * 1024 = 1M * 10 = 10M
        upload.setSizeMax(1024 * 1024 * 10);

        return upload;
    }

    public static String uploadParseRequest(ServletFileUpload upload, HttpServletRequest request, String uploadPath)
            throws FileUploadException, IOException {
        String msg = "";

        //把前端请求解析,封装成一个FileItem对象,需要从ServletFileUpload
        List<FileItem> fileItems = upload.parseRequest(request);
        //fileItem:每一个表单对象
        for (FileItem fileItem : fileItems) {
            //判断上传的文件是普通的表单还是带文件的表单
            if (fileItem.isFormField()) {
                //getFileName指的是前端表单控件的name
                String name = fileItem.getFieldName();
                //处理乱码
                String value = fileItem.getString("UTF-8");
                System.out.println(name + ":" + value);
            } else {
                //判断它是上传的文件

                //-------------------处理文件------------------//
                String uploadFileName = fileItem.getName();
                //可能存在文件名不合法的情况
                if (uploadFileName.trim().equals("") || uploadFileName == null) {
                    continue;
                }
                //获得上传的文件名 /images/girl/paojie.png
                String fileName = uploadFileName.substring(uploadFileName.lastIndexOf("/") + 1);
                //获取文件的后缀名
                String fileExtName = uploadFileName.substring(uploadFileName.lastIndexOf(".") + 1);

                System.out.println("文件信息 [文件名:" + fileName + "---文件类型:" + fileExtName + "]");

                //可以使用UUID(唯一识别的通行码),保证文件名唯一
                //UUID.randomUUID(),随机生成一个唯一识别的通行码

                //网络传输的东西,都需要序列化
                //POJO,实体类,如果想要在多个电脑上运行, 传输===>需要把对象都序列化了
                //JNI = Java Native Interface
                //implements Serializable : 标记接口, JVM--->Java栈  本地方法栈 native -->C++

                String uuidPath = UUID.randomUUID().toString();

                //-------------------存放地址------------------//
                //文件真实存在的路径 realPath
                String realPath = uploadPath + "/" + uuidPath;
                //给每个文件创建一个对应的文件夹
                File realPathFile = new File(realPath);
                if (!realPathFile.exists()) {
                    realPathFile.mkdir();
                }

                //-------------------文件传输------------------//
                //获得文件上传的流
                InputStream inputStream = fileItem.getInputStream();

                //创建一个文件输出流
                FileOutputStream fos = new FileOutputStream(realPath + "/" + fileName);

                //创建一个缓冲区
                byte[] buffer = new byte[1024 * 1024];

                //判断是否读取完毕
                int len = 0;
                //如果大于0说明还存在数据
                while ((len = inputStream.read(buffer)) > 0) {
                    fos.write(buffer, 0, len);
                }

                //关闭流
                fos.close();
                inputStream.close();

                msg = "文件上传成功!";
                //上传成功,清除临时文件
                fileItem.delete();
            }
        }
        return msg;
    }
}

发送邮件

简单文本

package com.dt;

import com.sun.mail.util.MailSSLSocketFactory;

import javax.mail.*;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import java.security.GeneralSecurityException;
import java.util.Properties;

/**
 * Created with IntelliJ IDEA.
 *
 * @author Dt
 * @Project 功能拓展
 * @Title: MailDemo01
 * @Package com.dt
 * @Description: 发送一封简单的邮件
 * @date 2022/4/2 11:52
 */
public class MailDemo01 {
    public static void main(String[] args) throws GeneralSecurityException, MessagingException {

        Properties prop = new Properties();
        //设置QQ邮箱
        prop.setProperty("mail.host", "smtp.qq.com");
        //邮箱发送协议
        prop.setProperty("mail.transport.protocol", "smtp");
        //需要验证用户名密码
        prop.setProperty("mail.smtp.auth", "true");

        //关于QQ邮箱,还要设置SSL加密,加上以下代码即可
        MailSSLSocketFactory sf = new MailSSLSocketFactory();
        sf.setTrustAllHosts(true);
        //若发送失败,把ssl设置成false
        prop.put("mail.smtp.ssl.enable", "false");
        prop.put("mail.smtp.ssl.socketFactory", sf);

        //使用JavaMail发送邮箱的5个步骤

        //1、创建定义整个应用程序所需的环境信息的session对象

        //QQ才有!其他邮箱不用
        Session session = Session.getDefaultInstance(prop, new Authenticator() {
            @Override
            protected PasswordAuthentication getPasswordAuthentication() {
                return new PasswordAuthentication("746294093@qq.com", "slmlnfrwhcrrbbfj");
            }
        });

        //开启Session的debug模式,这样就可以查看到程序发送Email的运行状态
        session.setDebug(true);

        //2、通过session获得transport对象
        Transport ts = session.getTransport();

        //3、使用邮箱的用户名和授权码连上邮件服务器
        ts.connect("smtp.qq.com", "746294093@qq.com",  "slmlnfrwhcrrbbfj");

        //4、创建邮件:写邮件
        //注意需要传递Session
        //创建邮件对象
        MimeMessage message = new MimeMessage(session);

        //指明邮件的发件人
        message.setFrom(new InternetAddress("746294093@qq.com"));

        //指明邮件的收件人,现在发件人和收件人一样,是自己给自己发
        message.setRecipient(Message.RecipientType.TO, new InternetAddress("746294093@qq.com"));

        //邮件的标题
        message.setSubject("(JavaWeb)只包含文本的简单文件");

        //邮件的文本内容
        message.setContent("<h1 style='color:red'>Hello, World!</h1>", "text/html;charset=UTF-8");

        //5、发送邮件
        ts.sendMessage(message, message.getAllRecipients());

        //6.关闭连接
        ts.close();

    }
}

带图片内嵌的文本

package com.dt;

import com.sun.mail.util.MailSSLSocketFactory;

import javax.activation.DataHandler;
import javax.activation.FileDataSource;
import javax.mail.*;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import java.security.GeneralSecurityException;
import java.util.Properties;

/**
 * Created with IntelliJ IDEA.
 *
 * @author Dt
 * @Project 功能拓展
 * @Title: MailDemo01
 * @Package com.dt
 * @Description: 发送一封简单的邮件
 * @date 2022/4/2 11:52
 */
public class MailDemo02 {
    public static void main(String[] args) throws GeneralSecurityException, MessagingException {

        Properties prop = new Properties();
        //设置QQ邮箱
        prop.setProperty("mail.host", "smtp.qq.com");
        //邮箱发送协议
        prop.setProperty("mail.transport.protocol", "smtp");
        //需要验证用户名密码
        prop.setProperty("mail.smtp.auth", "true");

        //关于QQ邮箱,还要设置SSL加密,加上以下代码即可
        MailSSLSocketFactory sf = new MailSSLSocketFactory();
        sf.setTrustAllHosts(true);
        //若发送失败,把ssl设置成false
        prop.put("mail.smtp.ssl.enable", "false");
        prop.put("mail.smtp.ssl.socketFactory", sf);

        //使用JavaMail发送邮箱的5个步骤

        //1、创建定义整个应用程序所需的环境信息的session对象

        //QQ才有!其他邮箱不用
        Session session = Session.getDefaultInstance(prop, new Authenticator() {
            @Override
            protected PasswordAuthentication getPasswordAuthentication() {
                return new PasswordAuthentication("746294093@qq.com", "slmlnfrwhcrrbbfj");
            }
        });

        //开启Session的debug模式,这样就可以查看到程序发送Email的运行状态
        session.setDebug(true);

        //2、通过session获得transport对象
        Transport ts = session.getTransport();

        //3、使用邮箱的用户名和授权码连上邮件服务器
        ts.connect("smtp.qq.com", "746294093@qq.com",  "slmlnfrwhcrrbbfj");

        //4、创建邮件:写邮件
        //注意需要传递Session
        //创建邮件对象
        MimeMessage message = new MimeMessage(session);

        //指明邮件的发件人
        message.setFrom(new InternetAddress("746294093@qq.com"));

        //指明邮件的收件人,现在发件人和收件人一样,是自己给自己发
        message.setRecipient(Message.RecipientType.TO, new InternetAddress("746294093@qq.com"));

        //邮件的标题
        message.setSubject("(JavaWeb)包含图片的复杂文件");

        //===================================================
        //准备图片数据
        MimeBodyPart image = new MimeBodyPart();
        //图片需要经过数据处理... DataHandler:数据处理
        DataHandler dh = new DataHandler(new FileDataSource("src/img.png"));
        //在我们这个Body中放入这个处理的图片数据
        image.setDataHandler(dh);
        //给图片设置一个ID,我们在后面可以使用
        image.setContentID("img.png");

        //准备正文数据
        MimeBodyPart text = new MimeBodyPart();
        text.setContent("这是一封邮件正文带图片<img src='cid:img.png'>的邮件", "text/html;charset=UTF-8");

        //描述数据关系
        MimeMultipart mm = new MimeMultipart();
        mm.addBodyPart(text);
        mm.addBodyPart(image);
        mm.setSubType("related");

        //把最后编辑好的邮件放到消息当中
        message.setContent(mm);
        //保存修改
        message.saveChanges();


        //===================================================

        //5、发送邮件
        ts.sendMessage(message, message.getAllRecipients());

        //6.关闭连接
        ts.close();

    }
}

带附件的图片内嵌文本

package com.dt;

import com.sun.mail.util.MailSSLSocketFactory;

import javax.activation.DataHandler;
import javax.activation.FileDataSource;
import javax.mail.*;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import java.security.GeneralSecurityException;
import java.util.Properties;

/**
 * Created with IntelliJ IDEA.
 *
 * @author Dt
 * @Project 功能拓展
 * @Title: MailDemo01
 * @Package com.dt
 * @Description: 发送一封简单的邮件
 * @date 2022/4/2 11:52
 */
public class MailDemo03 {
    public static void main(String[] args) throws GeneralSecurityException, MessagingException {

        Properties prop = new Properties();
        //设置QQ邮箱
        prop.setProperty("mail.host", "smtp.qq.com");
        //邮箱发送协议
        prop.setProperty("mail.transport.protocol", "smtp");
        //需要验证用户名密码
        prop.setProperty("mail.smtp.auth", "true");

        //关于QQ邮箱,还要设置SSL加密,加上以下代码即可
        MailSSLSocketFactory sf = new MailSSLSocketFactory();
        sf.setTrustAllHosts(true);
        //若发送失败,把ssl设置成false
        prop.put("mail.smtp.ssl.enable", "false");
        prop.put("mail.smtp.ssl.socketFactory", sf);

        //使用JavaMail发送邮箱的5个步骤

        //1、创建定义整个应用程序所需的环境信息的session对象

        //QQ才有!其他邮箱不用
        Session session = Session.getDefaultInstance(prop, new Authenticator() {
            @Override
            protected PasswordAuthentication getPasswordAuthentication() {
                return new PasswordAuthentication("746294093@qq.com", "slmlnfrwhcrrbbfj");
            }
        });

        //开启Session的debug模式,这样就可以查看到程序发送Email的运行状态
        session.setDebug(true);

        //2、通过session获得transport对象
        Transport ts = session.getTransport();

        //3、使用邮箱的用户名和授权码连上邮件服务器
        ts.connect("smtp.qq.com", "746294093@qq.com",  "slmlnfrwhcrrbbfj");

        //4、创建邮件:写邮件
        MimeMessage mimeMessage = imageMail(session);

        //5、发送邮件
        ts.sendMessage(mimeMessage, mimeMessage.getAllRecipients());

        //6.关闭连接
        ts.close();

    }

    public static MimeMessage imageMail(Session session) throws MessagingException {
        //消息的固定信息
        MimeMessage mimeMessage = new MimeMessage(session);

        //邮件发送人
        mimeMessage.setFrom(new InternetAddress("746294093@qq.com"));
        //邮件接收人,可以同时发送给很多人,我们这里只发给自己
        mimeMessage.setRecipient(Message.RecipientType.TO, new InternetAddress("746294093@qq.com"));
        //邮件主题
        mimeMessage.setSubject("How Dare YOU?");

        /*
        编写邮件内容:
        1.图片
        2.附件
        3.文本
         */

        //图片
        MimeBodyPart body1 = new MimeBodyPart();
        body1.setDataHandler(new DataHandler(new FileDataSource("src/img.png")));
        //设置图片id
        body1.setContentID("img.png");

        //文本
        MimeBodyPart body2 = new MimeBodyPart();
        body2.setContent("请注意,我不是广告<img src='cid:img.png'>", "text/html;charset=UTF-8");

        //附件
        MimeBodyPart body3 = new MimeBodyPart();
        body3.setDataHandler(new DataHandler(new FileDataSource("src/hello.txt")));
        //设置附件名字
        body3.setFileName("hello.txt");

        MimeBodyPart body4 = new MimeBodyPart();
        body4.setDataHandler(new DataHandler(new FileDataSource("src/stu.bin")));
        body4.setFileName("stu.bin");

        //拼装邮件正文内容
        MimeMultipart multipart1 = new MimeMultipart();
        multipart1.addBodyPart(body1);
        multipart1.addBodyPart(body2);
        //文本和图片内嵌
        multipart1.setSubType("related");

        //将拼装好的内容设置为主体
        MimeBodyPart contentText = new MimeBodyPart();
        contentText.setContent(multipart1);

        //拼装附件
        MimeMultipart allFile = new MimeMultipart();
        allFile.addBodyPart(body3);
        allFile.addBodyPart(body4);
        allFile.addBodyPart(contentText);
        //正文和附件都存在邮件中,所有类型设置为mixed
        allFile.setSubType("mixed");

        //放到Message消息中
        mimeMessage.setContent(allFile);
        mimeMessage.saveChanges();

        return mimeMessage;

    }

}

网页实现发送注册邮件

image-20220403003549246

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    
    <servlet>
        <servlet-name>RegisterServlet</servlet-name>
        <servlet-class>com.dt.servlet.RegisterServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>RegisterServlet</servlet-name>
        <url-pattern>/RegisterServlet.do</url-pattern>
    </servlet-mapping>
    
</web-app>

index.jsp

<%--
  Created by IntelliJ IDEA.
  User: Administrator
  Date: 2022/4/2
  Time: 20:37
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>注册</title>
</head>
<body>

<form action="${pageContext.request.contextPath}/RegisterServlet.do" method="post">
    用户名:<input type="text" name="username"><br>
    密码:<input type="password" name="password"><br>
    邮箱:<input type="text" name="email"><br>
    <input type="submit" value="注册">
</form>

</body>
</html>

info.jsp

<%--
  Created by IntelliJ IDEA.
  User: Administrator
  Date: 2022/4/2
  Time: 21:47
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>注册</title>
</head>
<body>

<h1>温馨提示</h1>
${message}

</body>
</html>

User.java

package com.dt.pojo;

import java.io.Serializable;

/**
 * Created with IntelliJ IDEA.
 *
 * @author Dt
 * @Project mail-java
 * @Title: User
 * @Package com.dt.pojo
 * @Description: TODO
 * @date 2022/4/2 20:57
 */
public class User implements Serializable {

    private String username;
    private String password;
    private String email;

    public User() {
    }

    public User(String username, String password, String email) {
        this.username = username;
        this.password = password;
        this.email = email;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    @Override
    public String toString() {
        return "User{" +
                "username='" + username + '\'' +
                ", password='" + password + '\'' +
                ", email='" + email + '\'' +
                '}';
    }
}

Sendmail.java

package com.dt.utils;

import com.dt.pojo.User;
import com.sun.mail.util.MailSSLSocketFactory;

import javax.mail.*;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import java.util.Properties;

/**
 * Created with IntelliJ IDEA.
 *
 * @author Dt
 * @Project mail-java
 * @Title: Sendmail
 * @Package com.dt.utils
 * @Description: 多线程实现用户体验! (异步处理)
 * @date 2022/4/2 21:09
 */
public class Sendmail extends Thread {

    /**
     * 用于给用户发送邮件的邮箱
     */
    private String from = "746294093@qq.com";
    /**
     * 邮箱的用户名
     */
    private String username = "746294093@qq.com";
    /**
     * 邮箱的密码(授权码)
     */
    private String password = "slmlnfrwhcrrbbfj";
    /**
     * 发送邮件的服务器地址
     */
    private String host = "smtp.qq.com";

    private User user;

    public Sendmail(User user) {
        this.user = user;
    }

    /**
     * 重写run方法的实现,在run方法中发送邮件给指定用户
     */
    @Override
    public void run() {
        try {
            Properties prop = new Properties();
            //设置QQ邮箱
            prop.setProperty("mail.host", host);
            //邮箱发送协议
            prop.setProperty("mail.transport.protocol", "smtp");
            //需要验证用户名密码
            prop.setProperty("mail.smtp.auth", "true");

            //关于QQ邮箱,还要设置SSL加密,加上以下代码即可
            MailSSLSocketFactory sf = new MailSSLSocketFactory();
            sf.setTrustAllHosts(true);
            //若发送失败,把ssl设置成false
            prop.put("mail.smtp.ssl.enable", "false");
            prop.put("mail.smtp.ssl.socketFactory", sf);

            //1、创建定义整个应用程序所需的环境信息的session对象
            Session session = Session.getDefaultInstance(prop, new Authenticator() {
                @Override
                protected PasswordAuthentication getPasswordAuthentication() {
                    //发件人邮件用户名,授权码
                    return new PasswordAuthentication("746294093@qq.com", "slmlnfrwhcrrbbfj");
                }
            });

            //开启Session的debug模式,这样就可以查看到程序发送Email的运行状态
            session.setDebug(true);

            //2、通过session获得transport对象
            Transport ts = session.getTransport();

            //3、使用邮箱的用户名和授权码连上邮件服务器
            ts.connect(host, username, password);

            //4、创建邮件
            MimeMessage message = new MimeMessage(session);
            //发件人
            message.setFrom(new InternetAddress(from));
            //收件人
            message.setRecipient(Message.RecipientType.TO, new InternetAddress(user.getEmail()));
            //标题
            message.setSubject("用户注册邮件");

            String info = "恭喜您注册成功,您的用户名:<span style='color:red'>" + user.getUsername() +
                    "</span>,您的密码:<span style='color:red'>" + user.getPassword() +
                    "</span>,请妥善保管,如有问题请联系网站客服!!";

            message.setContent(info, "text/html;charset=UTF-8");
            message.saveChanges();

            //发送邮件
            ts.sendMessage(message, message.getAllRecipients());
            ts.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

RegisterServlet.java

package com.dt.servlet; /**
 * Created with IntelliJ IDEA.
 *
 * @Project mail-java
 * @Title: ${NAME}
 * @Package ${PACKAGE_NAME}
 * @Description: TODO
 * @author Dt
 * @date 2022/4/2 20:50
 */

import com.dt.pojo.User;
import com.dt.utils.Sendmail;

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

@WebServlet(name = "RegisterServlet", value = "/RegisterServlet")
public class RegisterServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //接收用户请求,封装成对象
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        String email = request.getParameter("email");

        User user = new User(username, password, email);

        //用户注册成功后,给用户发送一封邮件
        //我们使用线程来专门发送邮件,防止出现耗时,和网站注册人数过多的情况
        Sendmail send = new Sendmail(user);
        //启动线程,线程启动之后会执行run方法来发送邮件
        send.start();

        //注册用户
        request.setAttribute("message", "注册成功,我们已经发送了一封带了注册信息的电子邮件到您的邮箱,请查收!!");
        request.getRequestDispatcher("info.jsp").forward(request, response);

    }
}
posted @ 2022-10-08 10:03  D..T  阅读(39)  评论(0编辑  收藏  举报