JavaWeb 二刷笔记

JavaWeb

【完成周期23-5-5-------23-5-22】

Web服务器

1. 技术讲解

1.1ASP

  • 属于微软的,在html中嵌入VB脚本,常用c#,代码过于混乱

1.2PHP

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

1.3JSP/Servlet

  • 使用B/S架构,浏览器服务器,可以承担三高问题(高可靠,高并发,高性能)

2.WEB服务器

概念:处理用户请求并给用户相应的响应
静态web:资源 不变,无法与数据库交互
动态web:显示资源因人而异,可以与数据库交互

2.1Tomcat

  • 安装包下的文件夹含义

    tomcat系统各个文件夹目录是什么意义:
    bin:放置的是Tomcat一些相关的命令,启动的命令(startup)和关闭的命令(shutdown)等等
    conf:(configure)配置文件
    lib:(library)库,依赖的 jar包
    logs:Tomcat 的日志文件
    temp:Tomcat的临时文件夹
    webapps:可执行的项目。默认作为存放开发项目的目录
    work:存放由 jsp翻译成的 .java源文件以及编译的 .class字节码文件(jsp -->java -->class)
    
  • Tomcat 配置环境变量:点击startup.bat启动tomcat服务器【需要配置环境变量】
    在这里插入图片描述

    在这里插入图片描述

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

    • 配置参数测试

      • 可修改端口号以及域名【在conf–server.xml】

      • 端口号image-20231230095452964

      • 域名在这里插入图片描述

·

  • IIS

3. HTTP

3.1 什么是超文本

使用超链接将不同空间位置的文本信息链接到一起

3.2 两个版本

  • 1.0 浏览器请求服务器单个资源,服务器返回资源完 便断开连接
  • 2.0 浏览器可请求服务器多个资源,服务器返回资源后 不会断开连接,需主动断开,或者双方都空余一段时间后自己断开连接

3.3HTTP请求

  • 请求行

  • POST /examples/servlets/servlet/RequestParamExample HTTP/1.1 
    
    • Get :高效,有大小限制,会在地址栏显示,不安全
    • POST:不高效,没有大小限制,不会在地址栏显示,安全
  • 请求头

    Accept:客户端向服务器端表示,我能支持什么类型的数据。
    Referer:真正请求的地址路径,全路径
    Accept-Language:支持语言格式
    User-Agent:用户代理向服务器表明,当前来访的客户端信息。
    Content-Type:提交的数据类型。经过urlencoding编码的form表单的数据
    Accept-Encoding:压缩算法 。
    Connection:保持连接
    Cache-Control:对缓存的操作

  • 请求体

    • name=“abc”&password=“123”

3.4HTTP响应

  • 响应行

    • 响应状态码

      • 2xx 成功
      • 3xx 重定向
      • 4xx网页不存在
      • 5xx 服务器错误 502网关错误
    • HTTP/1.1 200 OK
      
  • 响应头

    Server:服务器是哪一种类型。Tomcat
    Content-Type:服务器返回给客户端的内容类型
    Content-Length:返回的数据长度
    Date:通讯的日期,响 应的时间

  • 响应体

    • 就是接口返回的数据的类型,一般是json串

4.Maven

4.1 Maven是什么?

Maven是一个项目管理的工具,可以对项目进行构建、依赖的管理。我们只需要告诉Maven需要哪些Jar 包,它会帮助我们下载所有的Jar,极大提升开发效率

4.1.1 Maven与IDEA版本对应表

注意:针对一些老项目 还是尽量采用 3.6.3版本,针对idea各个版本的兼容性就很兼容
 0.IDEA 2022 兼容maven 3.8.1及之前的所用版本
 1.IDEA 2021 兼容maven 3.8.1及之前的所用版本
 2.IDEA 2020 兼容Maven 3.6.3及之前所有版本
 3.IDEA 2018 兼容Maven3.6.1及之前所有版本

4.2 Maven安装

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

  • 环境变量配置

    • 添加MAVEN_HOME ,其对应的值为
      在这里插入图片描述在这里插入图片描述

    • 将MAVEN_HOME 添加到PATH中去
      在这里插入图片描述

    • 环境变量配置完测试在这里插入图片描述

4.3 添加阿里云镜像

mirrors:加速下载

<mirror>  
    <id>central</id>  
    <name>central</name>                                          
    <url>http://maven.aliyun.com/nexus/content/groups/public</url> 
    <mirrorOf>central</mirrorOf>  
</mirror>

添加到conf–>settings.xml中去

image-20231231144913572

4.4 本地仓库

<localRepository>E:\JavaWeb\Maven\apache-maven-3.9.1\maven-repo	</localRepository>

建立一个本地仓库 localRepository 【改地址了:D:\Skill\JavaWeb\Maven\apache-maven-3.6.3\maven-repo】在这里插入图片描述

4.5 在IDEA中使用MAVEN

  • 创建maven项目

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

  • 观察maven仓库中多了什么?[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BmvpkI8G-1684856301340)(JavaWeb.assets/image-20230511172447887.png)]

    • 在idea中配置maven【idea项目创建时需要注意这个位置

4.6 问题

  1. 解决Maven 在pom.xml的build中配置resources,来防止我们资源导出失败的问题

    <build>
        <resources>
            <resource>
         		<!-- 设定主资源目录  -->
                <directory>src/main/resources</directory>
                <includes>
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                </includes>
            </resource>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                </includes>
                <filtering>true</filtering>
            </resource>
        </resources>
    </build>
    

5.servlet

5.1 servlet 简介

  • servlet 是sun 公司开发动态web的一项技术。

  • servlet有两个实现类:HttpServlet,GenericServlet

  • sun在API【应用程序接口】上提供了一个接口sevlet,开发servlet程序的步骤。

    1. 编写一个实现了servlet接口的java程序。
    2. 把开发好的java类部署到web 服务器上。
  • servlet:实现了servlet接口的java程序。

5.2 HelloServlet

操作流程:创建一个普通的maven项目-----删除src目录------在父项目中创建一个带有web的maven项目

在子项目中的操作

  1. 创建java类实现servlet接口
package com.lumos.servlet;

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

public class HelloServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        PrintWriter writer = resp.getWriter(); // 相应流
        writer.write("Welcome To Servlet!");
        writer.print("HHHHHHHH----HHHHHH");
    }

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

  1. 编写Servlet映射

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

<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
                    http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0"
         metadata-complete="true">
<!--    注册servlet   -->
    <servlet>
        <servlet-name>hello</servlet-name>
        <servlet-class>com.lumos.servlet.HelloServlet</servlet-class>
    </servlet>
<!--  servlet的请求路径   -->
    <servlet-mapping>
        <servlet-name>hello</servlet-name>
        <url-pattern>/hello</url-pattern>
    </servlet-mapping>
</web-app>

  1. 配置Tomcat

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

  1. 启动与测试

    启动Tomcat即可—自动打开网站【访问】自己写的程序需要在后面加上面映射的/hello,不加则是默认页面

    image-20231231145213866

问题

  1. 问题1:子项目中没有出现src目录

    解决方法:添加 -Darchetype=Internal 这条语句,然后重新创建子项目
    在这里插入图片描述

  1. 问题2:解决tomcat控制台是乱码的问题

将UTF-8 设置为GBK就可以了
在这里插入图片描述第51行

5.3 Servlet原理

image-20231230103855089

5.4 映射Mapping 注意事项

优先级问题:有特定的匹配则优先匹配,没有则默认匹配【按照通配符】

  1. 一个servlet对应一个映射路径

    <!--  servlet的请求路径   -->
        <servlet-mapping>
            <servlet-name>hello</servlet-name>
            <url-pattern>/hello</url-pattern>
        </servlet-mapping>
    
  2. 一个servlet对应多个映射路径

    <!--  servlet的请求路径   -->
        <servlet-mapping>
            <servlet-name>hello</servlet-name>
            <url-pattern>/hello</url-pattern>
        </servlet-mapping>
        <!--  servlet的请求路径   -->
        <servlet-mapping>
            <servlet-name>hello</servlet-name>
            <url-pattern>/hello2</url-pattern>
        </servlet-mapping>
        <!--  servlet的请求路径   -->
        <servlet-mapping>
            <servlet-name>hello</servlet-name>
            <url-pattern>/hello3</url-pattern>
        </servlet-mapping>
    
  3. 一个servlet对应通用映射路径

        <!--  servlet的请求路径 【一个servlet对应通配 映射路径】  -->
        <servlet-mapping>
            <servlet-name>hello</servlet-name>
            <url-pattern>/hello/*</url-pattern>
        </servlet-mapping>
        
    
  4. 一个servlet对应默认的映射路径【不管输入什么都会映射到hello】

<!--  servlet的请求路径 【一个servlet对应一个映射路径】  -->
    <servlet-mapping>
        <servlet-name>hello</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>
  1. 一个servlet对应指定前缀或指定后缀 映射路径
    <!--  servlet的请求路径 【一个servlet对应特定结尾映射路径】  -->
    <servlet-mapping>
        <servlet-name>hello</servlet-name>
                <!--    *.linxiaojun 表示必须以.linxiaojun结尾    -->
        <url-pattern>*.linxiaojun</url-pattern>
    </servlet-mapping>
  1. 定义错误网址所导向类

        <!--  servlet的请求路径 【错误路径导向ErrorServlet类中】  -->
       <servlet>
           <servlet-name>Error</servlet-name>
           <servlet-class>com.lumos.servlet.ErrorServlet</servlet-class>
       </servlet>
        <servlet-mapping>
            <servlet-name>Error</servlet-name>
            <url-pattern>/*</url-pattern>
        </servlet-mapping>
    
    package com.lumos.servlet;
    
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    import java.io.PrintWriter;
    
    public class ErrorServlet extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            resp.setContentType("text/html");
            resp.setCharacterEncoding("utf-8");
            PrintWriter writer = resp.getWriter();
            writer.write("<h1>This is 404 Error From ErrorServlet!</h1>");
        }
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            doGet(req, resp);
        }
    }
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4MQSz07R-1684856301344)(JavaWeb.assets/image-20230513150000737.png)][外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KgmFqX08-1684856301345)(JavaWeb.assets/image-20230513150101743.png)]在这里插入图片描述

5.5 ServletContext

  1. 什么是ServletContext

    是基于Web容器和Servlet之间的中间件,可以对下面的Servlet进行管理;Web容器在启动的时候,会为每个应用程序创建一个相对应的ServletContext对象,其代表了当前的应用

  2. 作用

数据共享:不同servlet之间可以通信【getServletContext】

HelloServlet类

public class HelloServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("hello");
        ServletContext context = this.getServletContext();
        String username = (String) context.getAttribute("username");
        resp.setContentType("text/html;charset=utf-8");  //这句话相当于下面两条语句;用于设置编码格式
//        resp.setContentType("text/html");
//        resp.setCharacterEncoding("utf-8");
        resp.getWriter().write("name : "+username);
    }
}

GetContext类

public class GetContext extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        ServletContext context = this.getServletContext(); //获取对象ServletContext
        context.setAttribute("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.lumos.servlet.HelloServlet</servlet-class>  <!-->对应数据类HelloServlet<-->
    </servlet>
    <servlet-mapping>
        <servlet-name>hello</servlet-name>
        <url-pattern>/hello00</url-pattern>
    </servlet-mapping>

    
    <!-->向serverletContext中存储数据<-->
    <servlet>
        <servlet-name>gc</servlet-name>
        <servlet-class>com.lumos.servlet.GetContext</servlet-class>    <!-->对应数据类GetContext<-->
    </servlet>
    <servlet-mapping>
        <servlet-name>gc</servlet-name>
        <url-pattern>/getname</url-pattern>
    </servlet-mapping>
</web-app>

​ 测试结果:在这里插入图片描述

在这里插入图片描述

  • 获取初始化参数【getInitParameter】

GetServletParameters类

public class GetServletParameters extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        ServletContext context = this.getServletContext();
        String url = context.getInitParameter("url");
        resp.getWriter().write(url);
    }

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

Web.xml

<!--  自定义参数  -->
    <context-param>
        <param-name>url</param-name>
        <param-value>jdbc:mysql://localhost:3306/test</param-value>
    </context-param>

<!--  ServletContext获取参数  -->
    <servlet>
        <servlet-name>getPars</servlet-name>
        <servlet-class>com.lumos.servlet.GetServletParameters</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>getPars</servlet-name>
        <url-pattern>/gp</url-pattern>
    </servlet-mapping>

测试结果

在这里插入图片描述

  • 请求转发与重定向【getRequestDispatcher】

在这里插入图片描述

RequestDispatcher类

public class RequestDispatcher extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        ServletContext context = this.getServletContext(); //获取对象ServletContext
        // 将请求转发到/gp下,也就是GetServletParameters;
        javax.servlet.RequestDispatcher requestDispatcher = context.getRequestDispatcher("/gp");
        requestDispatcher.forward(req,resp);
        System.out.println("进入了请求转发类。。。");
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}

web.xml

    <servlet>
        <servlet-name>dispatcher</servlet-name>
        <servlet-class>com.lumos.servlet.RequestDispatcher</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>dispatcher</servlet-name>
        <url-pattern>/dispatcher</url-pattern>
    </servlet-mapping>

测试结果

在这里插入图片描述

  • 获取配置文件

    【resources和java 目录下的配置文件都是在classess目录下 getResouceAsStream()

    db.properties文件

    username=root
    password=123
    driver=jdbc:mysql://localhost:3306/test
    
    public class GetServletProperties extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            Properties prop = new Properties();
            //下面这条语句是重点-----主要是获取流对象  ----从生成的target中进行获取!
            InputStream resourceAsStream = this.getServletContext().getResourceAsStream("/WEB-INF/classes/db.properties");
            prop.load(resourceAsStream);
            String name = prop.getProperty("username");
            String pwd = prop.getProperty("password");
    
            resp.getWriter().write("username: "+name+"\tpwd: "+pwd);
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            doGet(req, resp);
        }
    }
    
    

    web.xml

        <servlet>
            <servlet-name>prop</servlet-name>
            <servlet-class>com.lumos.servlet.GetServletProperties</servlet-class>
        </servlet>
        <servlet-mapping>
            <servlet-name>prop</servlet-name>
            <url-pattern>/prop</url-pattern>
        </servlet-mapping>
    

    测试结果

    image-20231231145556201

5.6 HttpServletResponse

Web服务器接受来自浏览器或客户端的HTTP请求,针对这个请求,服务器分别创建了代表请求的HttpServletRequest,以及代表响应的HttpServletResponse;

  1. response 向浏览器发送响应的方式

    ServletOutputStream out = resp.getOutputStream(); //图片,文件,视频用这个
    PrintWriter writer = resp.getWriter(); //写中文,或文本用这个 ,错误使用可能导致信息传输不完-整
    
  2. HttpServletResponse中方法

        void setDateHeader(java.lang.String s, long l);
    
        void addDateHeader(java.lang.String s, long l);
    
        void setHeader(java.lang.String s, java.lang.String s1);
    
        void addHeader(java.lang.String s, java.lang.String s1);
    
        void setIntHeader(java.lang.String s, int i);
    
        void addIntHeader(java.lang.String s, int i);
    
        void setStatus(int i);
    

​ 3.HttpServletResponse中状态码

    int SC_PAYMENT_REQUIRED = 402;
    int SC_FORBIDDEN = 403;
    int SC_NOT_FOUND = 404;
    int SC_METHOD_NOT_ALLOWED = 405;
  1. 常见应用
    • 下载文件功能
  > * //核心代码
  >   //3.设置浏览器能支持 Content-Disposition 来下载我们所需要的东西
  >   *resp.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(filename, "utf-8"));*

  package com.lumos.servlet;
  
  import javax.servlet.ServletException;
  import javax.servlet.ServletOutputStream;
  import javax.servlet.http.HttpServlet;
  import javax.servlet.http.HttpServletRequest;
  import javax.servlet.http.HttpServletResponse;
  import java.io.FileInputStream;
  import java.io.IOException;
  import java.net.URLEncoder;
  
  /**
   * @Date : 2023-05-15 18:08
   * @Author : linxiaojun
   * @Desc : response-----文件下载【Content-Disposition,attachment;filename=】
   * @En :
   * @Att : 与底层的java输入输出流息息相关
   */
  
  public class FileServlet extends HttpServlet {
      @Override
      protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
          //1.文件下载的路径
          String filepath = "F:\\学科\\程序课程\\java\\Project\\JavaWeb\\javaweb-02-HelloServlet\\response\\src\\main\\resources\\code.txt";
          System.out.println("下载的路径:" + filepath);
          //2.获取文件的文件名
          String filename = filepath.substring(filepath.lastIndexOf("\\") + 1);
          //3.设置浏览器能支持 Content-Disposition 来下载我们所需要的东西,URLEncoder.encode(filename, "utf-8")可将汉字转化为UTF-8格式
          resp.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(filename, "utf-8"));
          // 4.创建输入流
          FileInputStream fis = new FileInputStream(filepath);
          //5.创建输出流
          ServletOutputStream out = resp.getOutputStream();
  
          int len = 0;
          byte[] buffer = new byte[1024];
          //6.将读取的数据信息写入到response中去
          while ((len = fis.read(buffer)) > 0)
              out.write(buffer, 0, len);
          fis.close();
          out.close();
      }
      @Override
      protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
          doGet(req, resp);
      }
  }
  

​ 结果验证:

image-20231231145747137

  • **验证码功能 ** [

  • //将BufferedImage图像保存在本地计算机
    BufferedImage image=new BufferedImage(wid,hei,BufferedImage.TYPE_INT_RGB);
    File file = new File("output.png"); //保存的目录地址
    boolean png = ImageIO.write(image, "png", file); //图像对象,后缀名,文件路径-->决定写在哪里
    
  • ]

//清除浏览器的缓存
resp.setDateHeader("expires",-1);
resp.setHeader("Cache-Control","no-cache");
resp.setHeader("Pragma","no-cache");

package com.lumos.servlet;

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

/**
 * @Date : 2023-05-15 20:11
 * @Author : linxiaojun
 * @Desc : response实现验证码功能
 * @En :
 * @Att :
 */

public class ImageServlet extends HttpServlet {

    static String[] strs={"a","b","c","d","e","f","g","h","i","j","k","m","n",
            "o","p","q","r","s","t","u","v","w","x","y","z","2","3","4","5","6","7","8","9"};
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //让浏览器3s自动刷新一次
        resp.setHeader("refresh","3");
        //设置浏览器打开页面的格式
        resp.setContentType("image/png");
        //不让浏览器存在缓存
        resp.setDateHeader("expires",-1);
        resp.setHeader("Cache-Control","no-cache");
        resp.setHeader("Pragma","no-cache");

        int wid=150;//定义图片宽度
        int hei=50;//定义图片高度
        int x=25,y=35;
        Random random=new Random();
        //1.画板
        BufferedImage image=new BufferedImage(wid,hei,BufferedImage.TYPE_INT_RGB);
        //2.获取画笔的对象
        Graphics g=image.getGraphics();
        //3.设置画笔参数
        g.setColor(Color.white);//设置填充颜色
        g.fillRect(0,0,wid,hei);//填充矩形,覆盖原矩形
        g.setColor(Color.red);//重新填充
        g.setFont(new Font("楷体",Font.BOLD,25));
        //4.画数字
        for (int i = 0; i <4; i++) {
            int num=random.nextInt(strs.length);
            g.drawString(strs[num],x,y);
            x+=30;
        }
        //5.画干扰线
        for (int i = 0; i <3 ; i++) {
            int x1=random.nextInt(30);
            int y1=random.nextInt(50);
            int x2=random.nextInt(30)+100;
            int y2=random.nextInt(50);
            g.drawLine(x1,y1,x2,y2);
        }
        //直接将验证码输出到浏览器
        ImageIO.write(image,"png", resp.getOutputStream());
    }

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

结果验证:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zLnNt5KH-1684856301346)(JavaWeb.assets/image-20230517095017247.png)]

  • 重定向功能

    URL路径会发生改变
    在这里插入图片描述

    关键代码

    resp.sendRedirect("./IdentifyingCode");
    

    实现代码

    package com.lumos.servlet;
    
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    
    /**
     * @Date : 2023-05-17 10:05
     * @Author : linxiaojun
     * @Desc : 实现重定向
     * @En :
     * @Att : 区别重定向与请求转发的区别
     */
    
    public class RedirectServlet extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            resp.sendRedirect("./IdentifyingCode");  //需要用.表示当前项目下
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            doGet(req, resp);
        }
    }
    

​ 结果验证:

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

5.7 HttpServletRequest

  1. 一个是请求转发
  2. 一个是获取参数
  • 重定向和转发的区别?

    • 相同点:都能跳转页面

    • 不同点:请求转发的时候,URL不会发生变化 307

      ​ 重定向的时候,URL会发生变化 302

package com.lumos.servlet;

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

/**
 * @Date : 2023-05-18 10:31
 * @Author : linxiaojun
 * @Desc :request 实现用户登录,登录成功后跳转到成功的页面
 * @En :
 * @Att :
 */

public class LoginServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        String[] hobbies = req.getParameterValues("hobby");
        System.out.println(username+":"+password+"\n"+ Arrays.toString(hobbies));
        //请求转发到另一个界面
        req.getRequestDispatcher("./success.jsp").forward(req,resp);
    }

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

6. Cookie && Session

6.1 什么是会话?

会话:用户打开一个浏览器,在浏览器中点开n多超链接,然后关闭浏览器,这个过程可以称之为会话

有状态会话:来过一次后续就知道该同学来过

6.2 实现会话的两种技术

  • Cookie:应用于客户端
  • Session:应用于服务端

6.3 Cookie

  • Tip

    • 服务器响应客户端cookie
    • 一般保存在本地用户appdata目录下
    • 一个cookie最多保存一个信息,最多发送20个cookie
    • 每一个cookie大小限制为4kb
    • 300个cookie浏览器上限
  • 删除cookie

    • 不设置cookie有效期 【关闭浏览器时cookie自动删掉】
    • 设置cookie有效期为0【cookie.setMaxAge(0)】
  • 编码和解码的问题

  •  URLEncoder.encode("abc","utf-8")
      URLDecoder.decode("abc","utf-8")
    
package com.lumos.servlet;

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

/**
 * @Date : 2023-05-18 11:54
 * @Author : linxiaojun
 * @Desc : cookie的使用
 * @En :
 * @Att : 1.编码和解码的问题
 *            URLEncoder.encode("abc","utf-8")
 *            URLDecoder.decode("abc","utf-8")
 *            2. cookie是键值对
 *			3.解决中文乱码:req.setCharacterEncoding("utf-8")
 						resp.setCharacterEncoding("UTf-8");
 						 resp.setHeader("Content-Type","text/html;charset=utf-8");
 */

public class cookieDemo1 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
      	//获取cookie对象
        Cookie[] cookies = req.getCookies();
        for (int i = 0; i < cookies.length; i++) {
            System.out.println(cookies[i]);
            if (cookies != null) {
                if (cookies[i].getName().equals("lastLoginTime")) {
                    //输出时间
                    Long time = Long.parseLong(cookies[i].getValue());
                    Date date = new Date(time);
                    resp.getWriter().write("\nLast Login Time:" + date.toLocaleString());
                }
            } else {
                resp.getWriter().write("This is your first time come here!\n");
            }
            Cookie ck = new Cookie("lastLoginTime", "" + System.currentTimeMillis());
            ck.setMaxAge(1000); // 设置有效时间【保存在浏览器的时间】
            resp.addCookie(ck);//添加cookie
        }
    }

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

6.4 Session

  • 什么是session?
  • 服务器会为每个浏览器创建一个session对象,存在周期为只要浏览器未关闭即存在,且一个session独占一个浏览器
  • 配置session失效时间
<!--   使用配置文件来配置session失效时间 -->
<session-config>
    <!--    配置默认失效时间,以分钟为单位    -->
    <session-timeout>1</session-timeout>
</session-config>
  • 手动注销session
package com.lumos.servlet;

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

/**
 * @Date : 2023-05-18 20:56
 * @Author : linxiaojun
 * @Desc : 手动注销session
 * @En :
 * @Att :
 */

public class SessionDemo4 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //防止编码错误
        req.setCharacterEncoding("utf-8");
        resp.setContentType("utf-8");
        resp.setContentType("text/html;charset=utf-8");
        //获取session
        HttpSession session = req.getSession();
        //手动配置session失效
        session.removeAttribute("name");
        session.invalidate(); 
    }

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

6.5 session 与 cookie的区别?

  • cookie是把数据存储到用户的浏览器中,浏览器可以同时保存多个
  • session 是把数据存储到用户独占的session中,服务器端保存

servletContext【ApplicationContext】可以使不同session用户进行访问

7.JSP

7.1 什么是JSP

JSP:JAVA Server Pages java服务器端页面,与servlet一样,用于动态web技术

特点:可以在jsp中嵌套java语言,与写HTML类似

7.2 JSP原理

jsp原理

7.3 环境搭建【添加依赖】

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>javaweb-04-jsp</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
            <dependency>
    <!--   servlet依赖-->
                <groupId>javax.servlet</groupId>
                <artifactId>servlet-api</artifactId>
                <version>2.5</version>
            </dependency>
    <!-- servlet.jsp依赖 -->
            <dependency>
                <groupId>javax.servlet.jsp</groupId>
                <artifactId>jsp-api</artifactId>
                <version>2.2</version>
            </dependency>

    <!--      jstl表达式的依赖  -->
            <dependency>
                <groupId>javax.servlet.jsp.jstl</groupId>
                <artifactId>jstl-api</artifactId>
                <version>1.2</version>
            </dependency>

    <!--    standard标签库依赖    -->
            <dependency>
                <groupId>taglibs</groupId>
                <artifactId>standard</artifactId>
                <version>1.1.2</version>
            </dependency>
    </dependencies>

</project>

7.4 JSP语法

  • JSP表达式1

    <%-- 1.jsp表达式,作用: 取值输出到客户端 --%>
      <%=new Date()%>
    
  • JSP代码片段2

    <%-- 2.jsp脚本片段 --%>
      <%
        int sum=0;
        for (int i = 0; i < 10; i++) {
          sum+=i;
        }
        out.print("和为:"+sum);
      %>
    
  • JAVA代码中嵌入HTML

    <%-- 2.1.在java代码中嵌入html --%>
    <%
        for (int i = 0; i < 10; i++) {
    %>
    <h1 align="center">hello , world <%=i%>
    </h1>
    <%}%>
    
  • JSP 的全局声明3:需要加!,jsp声明会被编译到java类中,而其他的都被编译到service方法中

    <%--3.jsp全局声明--%>
    <%!
        static {
            System.out.println("进入了静态块中");
        }
        private int count=0;
        public void test(){}
    %>
    
  • 注释【jsp注释不会显示,html注释会显示】

  • image-20240106153336522

7.5 JSP指令

  1. 定制错误页面<%@page args %>image-20240106160650600

image-20240106160518444

2.include :包含文件
image-20240106162018925

结果

使用<%@include file=args %> 是把引入的文件合成一个【三个文件合成一个】

<%@include file="header.jsp"%>
<h1>这是网站主题</h1>
<%@include file="footer.jsp"%>

采用jsp的方式是将引入的文件作为一个独立的文件处理的【三个文件为三个】

<jsp:include page="header.jsp"></jsp:include>
<h1>This is the body of webside</h1>
<jsp:include page="footer.jsp"></jsp:include>

7.6 九大内置对象 【作用域】

  • PageContext 【可存东西】

  • Request 【可存东西】

  • Response

  • Session 【可存东西】

  • Application 【可存东西】

  • Config

  • out

  • Page

  • Exception

    实现代码

<%--
  Created by IntelliJ IDEA.
  User: lin
  Date: 2024/1/6
  Time: 16:28
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<%
pageContext.setAttribute("name1","李学年1"); //请求的数据在当前页面有效
request.setAttribute("name2","李学年2");//请求的数据在一次请求中有效,请求转发时会携带这个数据
session.setAttribute("name3","李学年3");//请求的数据在一次会话中有效,也就是打开浏览器到关闭
application.setAttribute("name4","李学年4");//请求的数据在整个服务器中 有效,服务器的打开到关闭
    //可以按照下面的方法【利用最后一个参数的不同】来代替上面的方法
//    pageContext.setAttribute("name4","abc",PageContext.APPLICATION_SCOPE);
%>
<%
    //取值方式1;
    String n1 = (String) pageContext.findAttribute("name1");
    String n2 = (String) pageContext.findAttribute("name2");
    String n3 = (String) pageContext.findAttribute("name3");
    String n4 = (String) pageContext.findAttribute("name4");
%>
<%--取值方式二:正则表达式--%>
<h1>${name1}</h1>
<h1>${name2}</h1>
<h1>${name3}</h1>
<h1>${name4}</h1>
<h1>${name5}</h1>
</body>
</html>

转发方式

<%
    //前端转发
    pageContext.forward("index.jsp");
    //后端转发request.getRequestDispatcher("index.jsp").forward(request,response);
%>

7.7 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开发对象
  • JSP 标签

    <h1>This is jspTag pages</h1>
    <%
    应用1:Include包含文件
     应用2:forword转发
        应用3:携带参数
        %>
    <jsp:forward page="context.jsp">
        <jsp:param name="name" value="female"/>
        <jsp:param name="age" value="12"/>
    </jsp:forward>
    
    <jsp:include page="common/head.jsp"/>
    
    <%//取参数%>
    <%=request.getParameter("name")%>
    <%=request.getParameter("age")%>
    

    image-20240106171659452

  • JSTL标签

    JSTL标签库的组成部分

    >核心标签库: core, 简称c

    >格式化标签库: format, 简称fmt

    >函数标签库: function, 简称fn

    核心标签【掌握部分这个就ok】

    核心标签库导入的语句为:
    <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
    
    • TIP:在tomacat的lib目录下也需要导入standard和jstl的jar包

    • 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> list = new ArrayList<>();
          list.add("李四");
          list.add("张三");
          list.add("王五");
          list.add("赵六");
          list.add("六七");
          request.setAttribute("lis",list);
      %>
      <%--*********  --%>
      
      <c:forEach var="abc" items="${lis}" begin="1" step="2"> 
          <c:out value="${abc}"/><br>
      </c:forEach>
      </body>
      </html>
      
      
      
      • c_if

        <%@ page contentType="text/html;charset=UTF-8" language="java" %>
        <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
        <html>
        <head>
            <title>Title</title>
        </head>
        <body>
        <h3>This is jstlCore test pages</h3>
        <form action="jstlCore.jsp" method="get">
            <%--${param.username}el表达式获取对象--%>
            <input name="username" value="${param.username}">
            <input type="submit" value="submit">
        </form>
        <c:if test="${param.username=='admin'}" var="isAdmin">
            <c:out value="YES,admin 欢迎你 "/>
        </c:if>
        <%--自闭合标签--%>
        <c:out value="${isAdmin}"/>	
        </body>
        </html>
        
        

7.8 servlet 与JSP的异同点

序号servletJSP
1是在java中嵌套html代码,支持html标签在html中嵌套java代码,支持java语言
2用于业务层处理逻辑用于展示层显示数据
3修改后需重新编译部署修改后不需重新编译以及运行

8.MVC三层架构

8.1 什么是MVC

model【包含entity,dao,service,操作】 view【展示】 controller【中间件】

在这里插入图片描述

9.Filter过滤器

9.1 什么是过滤器?

用来过滤网站中的数据

  • 处理字符的乱码
  • 登录验证
  • 处理垃圾请求

在这里插入图片描述
开发步骤

  • 导包
    在这里插入图片描述

  • 实现接口

    package com.lumos.filter;
    
    import javax.servlet.*;
    import java.io.IOException;
    
    /**
     * @Date : 2023-05-21 18:38
     * @Author : linxiaojun
     * @Desc : filter实现请求自动编码
     */
    
    public class CharEncodingFilter implements Filter {
        public void init(FilterConfig filterConfig) throws ServletException {
            System.out.println("filter 初始化");
        }
    
        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("filter执行前");
            filterChain.doFilter(servletRequest,servletResponse);  //*****这句话是关键
            System.out.println("filter执行后");
        }
    
        public void destroy() {
            System.out.println("filter销毁");
        }
    }
    
    
    web.xml注册filter
    <filter>
        <filter-name>charEncodingFilter</filter-name>
        <filter-class>com.lumos.filter.CharEncodingFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>charEncodingFilter</filter-name>
        <url-pattern>/servlet/*</url-pattern>
    </filter-mapping>
    
  • 过滤器实现用户输入正确密码后进入success页面,注销后,不可访问success页面,未注销可访问【注意路径问题】

效果图

image-20240106220925403

jsp代码

login.jsp

<html>
<%@page contentType="text/html; charset=utf-8" language="java" %>
<body>
<form method="post" action="./login1">
    用户名:<input type="text" name="username">
    <input type="submit" value="submit">
</form>
</body>
</html>

success.jsp【注意success.jsp是在sys目录下的】

<html>
<%@page contentType="text/html; charset=utf-8" language="java" %>
<body>
<p> 登录成功啦</p>
<%--<a href="login.jsp">点击注销</a>--%>
<form method="post" action="../logout">
    <input type="submit" value="logout">
</form>
</body>
</html>

false.jsp

pjsp<html>
<%@page contentType="text/html; charset=utf-8" language="java" %>
<body>
<p>登录失败</p>
<a href="login.jsp">点击重新登录</a>
</body>
</html>

web.xml

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

<web-app>
    <display-name>Archetype Created Web Application</display-name>
    <servlet>
        <servlet-name>showServlet</servlet-name>
        <servlet-class>com.lumos.servlet.ServletDemo</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>showServlet</servlet-name>
        <url-pattern>/servlet/showServlet</url-pattern>
    </servlet-mapping>

    <servlet-mapping>
        <servlet-name>showServlet</servlet-name>
        <url-pattern>/show</url-pattern>
    </servlet-mapping>


    <servlet>
        <servlet-name>login</servlet-name>
        <servlet-class>com.lumos.servlet.Login</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>login</servlet-name>
        <url-pattern>/login1</url-pattern>
    </servlet-mapping>


    <servlet>
        <servlet-name>logout</servlet-name>
        <servlet-class>com.lumos.servlet.Logout</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>logout</servlet-name>
        <url-pattern>/logout</url-pattern>
    </servlet-mapping>

    <filter>
        <filter-name>CharacterEncoding</filter-name>
        <filter-class>com.lumos.filter.Filter1</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>CharacterEncoding</filter-name>
        <url-pattern>/servlet/*</url-pattern>
    </filter-mapping>


    <filter>
        <filter-name>loginFilter</filter-name>
        <filter-class>com.lumos.filter.Filter2</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>loginFilter</filter-name>
        <url-pattern>/sys/*</url-pattern>
    </filter-mapping>

    <listener>
        <listener-class>com.lumos.listener.Listener_</listener-class>
    </listener>
</web-app>

logout.java

package com.lumos.servlet;

import com.lumos.constant.Con_;

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

/**
 * @CreateDate: 2024/1/6 20:28
 * @Description:
 * @English:
 * @Author: lin
 */
public class Logout extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        Object attribute = req.getSession().getAttribute(Con_.USER_SESSION);
        if(attribute!=null){
            req.getSession().removeAttribute(Con_.USER_SESSION);
            resp.sendRedirect("login.jsp");

        }else resp.sendRedirect("login.jsp");
    }

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

login.java

package com.lumos.servlet;

import com.lumos.constant.Con_;

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

/**
 * @CreateDate: 2024/1/6 20:24
 * @Description:
 * @English:
 * @Author: lin
 */
public class Login extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String username = req.getParameter("username");
        if(username.equals("admin1")){
            req.getSession().setAttribute(Con_.USER_SESSION,req.getSession().getId());
            resp.sendRedirect("./sys/success.jsp");
        }else resp.sendRedirect("./false.jsp");
    }

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

filter.java

package com.lumos.filter;

import com.lumos.constant.Con_;

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

/**
 * @CreateDate: 2024/1/6 20:58
 * @Description:
 * @English:
 * @Author: lin
 */
public class Filter2 implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest req= (HttpServletRequest) request;
        HttpServletResponse resp = (HttpServletResponse) response;
        if(req.getSession().getAttribute(Con_.USER_SESSION)==null){
            resp.sendRedirect("../false.jsp");
        }
        chain.doFilter(req,resp);
    }

    @Override
    public void destroy() {

    }
}

10.监听器

实现步骤

  • 实现接口

    package com.lumos.listener;
    
    import javax.servlet.ServletContext;
    import javax.servlet.http.HttpSessionEvent;
    import javax.servlet.http.HttpSessionListener;
    
    /**
     * @Date : 2023-05-21 19:35
     * @Author : linxiaojun
     * @Desc :使用HTTPSessionListener监听器在网站中统计在线人数
     * @En :
     * @Att :
     */
    
    public class OnlinePeopleCount implements HttpSessionListener {
        public void sessionCreated(HttpSessionEvent hse) {
            ServletContext sc = hse.getSession().getServletContext();
            System.out.println(hse.getSession().getId());
            Integer count = (Integer) sc.getAttribute("OnlinePeopleCount");
            if(count==null){
                count=new Integer(1);
            }else{
                int i = count.intValue();
                count=new Integer(i+1);
            }
            sc.setAttribute("OnlinePeopleCount",count);
        }
    
        public void sessionDestroyed(HttpSessionEvent hse) {
            ServletContext sc = hse.getSession().getServletContext();
            System.out.println("销毁:"+hse.getSession().getId());
            Integer count = (Integer) sc.getAttribute("OnlinePeopleCount");
            if(count==null){
                count=new Integer(0);
            }else{
                int i = count.intValue();
                count=new Integer(i-1);
            }
            hse.getSession().invalidate();
            sc.setAttribute("OnlinePeopleCount",count);
        }
    }
    
    
    • web.xml中配置

          <listener>
              <listener-class>com.lumos.listener.OnlinePeopleCount</listener-class>
          </listener>
      

image-20240106195333146

11.smbms

JSONArray.toJSONString(map)//将map转化为json数据【利用FastJson】
按钮点击跳转的方式
<a href="./download">
    <button>下载</button>
</a>

<button onclick="window.location.href='./download'" type="button" id="add">download</button>
</body>

12.文件上传

参考链接https://www.cnblogs.com/yayuya/p/16082761.html

12.1 导入网络传输的包

   <!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->
    <dependency>
      <groupId>commons-fileupload</groupId>
      <artifactId>commons-fileupload</artifactId>
      <version>1.3.3</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
    <dependency>
      <groupId>commons-io</groupId>
      <artifactId>commons-io</artifactId>
      <version>2.15.0</version>
    </dependency>

js包
  <dependency>
      <!--   servlet依赖-->
      <groupId>javax.servlet</groupId>
      <artifactId>servlet-api</artifactId>
      <version>2.5</version>
    </dependency>
    <!-- servlet.jsp依赖 -->
      <dependency>
        <groupId>javax.servlet.jsp</groupId>
        <artifactId>jsp-api</artifactId>
        <version>2.2</version>
      </dependency>

    <!--      jstl表达式的依赖  -->
    <dependency>
      <groupId>javax.servlet.jsp.jstl</groupId>
      <artifactId>jstl-api</artifactId>
      <version>1.2</version>
    </dependency>

    <!--    standard标签库依赖    -->
    <dependency>
      <groupId>taglibs</groupId>
      <artifactId>standard</artifactId>
      <version>1.1.2</version>
    </dependency>

12.2 文件上传的注意事项

  • 保证服务器安全,上传的文件应该放在外界无法访问的目录下,如WEB-INF目录下
  • 为防止上传文件覆盖的情况,需要为每个上传的文件设置一个独立的文件名或者id
  • 限制上传文件的数量
  • 限制上传文件的类型,即判断文件是否合法

12.3代码

package com.lumos.servlet;

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.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.UUID;

/**
 * @CreateDate: 2024/1/13 0:20
 * @Description:
 * @English:
 * @Author: lin
 */
public class uploadServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //判断上传的文件是普通表单还是带文件的表单,两者有区别,文件的要传输,普通的表单收取字符串
        if (!ServletFileUpload.isMultipartContent(req)) {//是否包含文件
            return;//不是,终止方法运行,说明这个一个普通的表单,直接返回
        }//如果通过了这个if,说明我们的表单是带文件上传的

        //创建上传文件的保存路径,建议在WEB-INF路径下,安全,用户无法直接访问上传的文件;
        String uploadPath = this.getServletContext().getRealPath("WEB-INF/upload");//获得:全局上下文.真实地址
        //判断这个文件有没有
        File uploadFile = new File(uploadPath);
        if (!uploadFile.exists()) {//如果文件不存在
            uploadFile.mkdir();//创建这个目录
        }

    /*
        缓存:临时文件 tmp
        文件上传速度太慢了,给他个中间商,慢慢上传,保证是匀速进来的
         */
        //临时路径,假设文件超过了预期的大小,我们就把他放到一个临时文件中,过几天自动删除,或者提醒用户转存为永久
        String tmpPath = this.getServletContext().getRealPath("WEB-INF/tmp");//获得:全局上下文.真实地址
        //判断这个文件有没有
        File file = new File(tmpPath);
        if (!file.exists()) {//如果文件不存在
            file.mkdir();//创建这个临时目录
        }

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

   	 		/*
            流程:
            ServletFileUpload负责处理上传的文件数据,并将表单中每个输入项封装成一个Fileltem对象,
            在使用ServletFilelpload对象(上传)解析请求时,需要DiskFileltemFactory对象。
            所以,我们需要在进行解析工作前构造好DiskFileltemFactory对象,
            通过SevletFileUpload对象的构造方法或setFileltemFactory()方法
            设置ServletFileUpload对象的fileltemFactory属性。
    		*/

        try {
            /*核心代码:处理这几个类*/
            //1.创建 DiskFileItemFactory(磁盘工厂)对象,处理文件上传路径或者大小限制
            DiskFileItemFactory factory = getDiskFileItemFactory(file);

            //2.获取 ServletFileUpload
            ServletFileUpload upload = getServletFileUpload(factory);//把 factory 类作为参数传递进来

            //3.处理上传的文件
            String msg = uploadParseRequest(upload, req, uploadPath);
            //servlet请求转发消息
            req.getSession().setAttribute("msg", msg);
            req.getRequestDispatcher("info.jsp").forward(req, resp);
        } catch (FileUploadException e) {
            e.printStackTrace();
        }


    }

    public static DiskFileItemFactory getDiskFileItemFactory(File file) {
        DiskFileItemFactory factory = new DiskFileItemFactory();
        //通过这个工厂设置一个缓存区,当上传的文件大于这个缓冲区的时候,将他放入到临时文件中
        factory.setSizeThreshold(1024 * 1024);//缓冲区为1M
        factory.setRepository(file);//临时目录的保存目录,需要一个File
        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 IOException, FileUploadException, FileUploadException {

        String msg = "";
        //3.把前端请求解析,封装成一个FileItem对象,需要从ServletFileUpload对象中获取
        List<FileItem> fileItems = upload.parseRequest(request);
        //fileItem 每一个表单对象
        for (FileItem fileItem : fileItems) {
            //判断上传的文件(控件)是普通的表单还是带文件的表单,判断是不是 input file
            if (fileItem.isFormField()) {//普通表单
                //getFieldName:前端表单控件的name
                String name = fileItem.getFieldName();
                String value = fileItem.getString("UTF-8");//处理乱码
                System.out.println(name + ":" + value);
            } else { //文件表单 ,(用到工具类)
                //===============处理文件===================
                //拿到文件名字
                String uploadFileName = fileItem.getName();
                System.out.println("上传的文件名:" + uploadFileName);
                //判断文件名
                if (uploadFileName.trim().equals("") || uploadFileName == null) {
                    continue;
                }
                //获得上传的文件名  /images/girl/paojie/png
                //字符串游戏
                String fileName = uploadFileName.substring(uploadFileName.lastIndexOf("/") + 1);//最后一个 / +1
                //获得文件的后缀名
                String fileExtName = uploadFileName.substring(uploadFileName.lastIndexOf(".") + 1);
        /*
                        如果文件后缀名 fileExtName 不是我们需要的,
                        就直接return,不处理,告诉用户文件类型不对。
                     */
                System.out.println("文件信息[件名:" + fileName + "---文件类型" + fileExtName + "]");

        /*面试题
          网络传输中的东西,都需要序列化
          POJO,实体类,如果想要在多个电脑上运行,  需要:传输==>把对象都序列化了
          写POJO实体类时,把这个接口 implements Serializable 加上 ,标记接口(没有方法的接口)
          标记接口:java虚拟机(JVM)在运行到的时候,它去识别,假设实现了 Serializable 这个接口,会帮你做一些事情。
          JVM中有一个本地方法栈:native,它是调用C++的,java虚拟机底层是C++写的。
          JNI = Java Native Interface  java本地化接口,
          java是无法操作计算机的,java是操作JVM的,JVM操作计算机(操作系统)
          JVM中还有一个java栈,平时写东西在java栈中写,本地方法栈是C++做的、操作系统来做
          公司里常用UUID,这个安全
        */

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

                //===============处理文件完毕=========== ========

                //文件存到哪? uploadPath
                //文件真实存在的路径 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;
    }

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

13.邮件发送

参考连接:https://blog.csdn.net/weixin_52093131/article/details/121958148

13.1对象关系

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

13.2 导入对用的包

image-20240115123754975

13.3

邮件分为

  • 简单邮件:纯文本,没有附件和图片

    package com.lumos;
    
    
    import com.sun.mail.util.MailSSLSocketFactory;
    
    import javax.mail.*;
    import javax.mail.internet.InternetAddress;
    import javax.mail.internet.MimeMessage;
    import java.util.Properties;
    
    /**
     * @CreateDate: 2024/1/15 13:11
     * @Description: 简单邮件发送【只涉及文本】
     * @English:
     * @Author: lin
     */
    // 授权码:oyvawtjctoetgdhg
        /*
        * 实现步骤
     1.创建session对象
    
    2.创建Transport对象
    
    3.使用邮箱的用户名和授权码连上邮件服务器
    
    4.创建一个Message对象(需要传递session)message需要指明发件人、收件人以及文件内容
    
    5.发送邮件
    
    6.关闭连接
        * */
    public class Mail {
        public static void main(String[] args) throws Exception {
            Properties prop = new Properties();
            prop.setProperty("mail.host", "smtp.qq.com");///设置QQ邮件服务器
            prop.setProperty("mail.transport.protocol", "smtp");///邮件发送协议
            prop.setProperty("mail.smtp.auth", "true");//需要验证用户密码
            prop.put("mail.smtp.ssl.protocols", "TLSv1.2");
            //端口
            prop.setProperty("mail.smtp.port", "465");
            //QQ邮箱需要设置SSL加密【qq独有】
            MailSSLSocketFactory sf = new MailSSLSocketFactory();
            sf.setTrustAllHosts(true);
            prop.put("mail.smtp.ssl.enable", "true");
            prop.put("mail.smtp.ssl.socketFactory", sf);
    
            //使用javaMail发送邮件的5个步骤
            //1.创建定义整个应用程序所需要的环境信息的session对象
            Session session = Session.getDefaultInstance(prop, new Authenticator() {
                @Override
                protected PasswordAuthentication getPasswordAuthentication() {
                    return new PasswordAuthentication("1350048132@qq.com", "oyvawtjctoetgdhg");
                }
            });
            //开启session的debug模式,这样可以查看到程序发送Email的运行状态
            session.setDebug(true);
            //2.通过session得到transport对象
            Transport ts = session.getTransport();
            //3.使用邮箱的用户名和授权码连上邮件服务器
            ts.connect("smtp.qq.com", "1350048132@qq.com", "oyvawtjctoetgdhg");
            //4.创建邮件:写文件
            //注意需要传递session
            MimeMessage message = new MimeMessage(session);
            //指明邮件的发件人
            message.setFrom(new InternetAddress("1350048132@qq.com"));
            //指明邮件的收件人
            message.setRecipient(Message.RecipientType.TO, new InternetAddress("1547438538@qq.com"));
            //邮件标题
            message.setSubject("邮件测试" + "--来自Java");
            //邮件的文本内容
            message.setContent("你好哇", "text/html;charset=UTF-8");
            //5.发送邮件
            ts.sendMessage(message, message.getAllRecipients());
    
            //6.关闭连接
            ts.close();
    
        }
    }
    
    
  • 复杂邮件:有附件和图片

//在上述基础上增加了附件与图片代码段 
message.setSubject("邮件测试带图片" + "--来自Java");
        //=================================准备图片数据=======================================
        MimeBodyPart image=new MimeBodyPart();
        //图片需要经过数据化的处理
        DataHandler dh=new DataHandler(new FileDataSource("D:\\Skill\\Project\\mavenLearn\\功能扩展\\mail-java\\src\\富士山.jpg"));
        //在part中放入这个处理过图片的数据
        image.setDataHandler(dh);
        //给这个part设置一个ID名字
        image.setContentID("bz.jpg");

        //准备正文的数据
        MimeBodyPart text=new MimeBodyPart();
        text.setContent("这是一张正文<img src='cid:bz.jpg'>","text/html;charset=UTF-8");

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

        //设置到消息中,保存修改
        message.setContent(mm);
        message.saveChanges();

14.使用邮件实现注册功能

用户注册后发送给用户邮件一封信息【可以扩展为用户注册,用户忘记密码后找回密码】

RegServlet

package com.lumos.servlet;

import com.lumos.entity.User;
import com.lumos.utils.SendMail;

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

/**
 * @CreateDate: 2024/1/15 14:58
 * @Description: SERVLET接受前端参数,异步发送邮件
 * @English:
 * @Author: lin
 */
public class RegMailServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        String mail = req.getParameter("mail");
        //把用户的请求封装成一个对象
        User user = new User(username,password,mail);

        //启动线程,重定向页面
        /*
        用户注册成功后,给用户发送一封邮件
        我们使用线程来专门发送邮件,防止出现耗时、白屏和网站注册人数过多的情况
         */
        SendMail send = new SendMail(user);
        send.start();
        //注册用户
        req.setAttribute("message","注册成功,我们已经发了一封要了注册信息的电子邮件,请查收!如网络不稳定,请稍等");
        req.getRequestDispatcher("info.jsp").forward(req,resp);

    }

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

SendMail异步发送邮件工具类

package com.lumos.utils;

/**
 * @CreateDate: 2024/1/15 15:08
 * @Description: 异步处理发送邮件,提高用户体验
 * @English:
 * @Author: lin
 */

import com.lumos.entity.User;
import com.sun.mail.util.MailSSLSocketFactory;
import javax.mail.*;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import java.util.Properties;


/*
网站3秒原则:用户体验

让用户不等待,事情也还做?
用户执行完这个方法,它还走它的东西,我走我的页面
通过多线程,实现用户体验!(异步处理)

 */
public class SendMail extends Thread{

    //用于给用户发送邮件的邮箱
    private String from = "1350048132@qq.com" ;
    //邮箱的用户名
    private String username = " 1350048132@qq.com" ;
    //邮箱的密码
    private String password = "oyvawtjctoetgdhg";
    //发送邮件的服务器地址
    private String host ="smtp.qq.com" ;

    //导入一个类
    private User user;
    public SendMail(User user){
        this.user = user;
    }


    @Override
    public void run() {

        try {
            Properties prop = new Properties();

            prop.setProperty("mail.host",host);///设置QQ邮件服务器
            prop.setProperty("mail.transport.protocol","smtp");///邮件发送协议
            prop.setProperty("mail.smtp.auth","true");//需要验证用户密码
            prop.put("mail.smtp.ssl.protocols", "TLSv1.2");
            //QQ邮箱需要设置SSL加密
            MailSSLSocketFactory sf = new MailSSLSocketFactory();
            sf.setTrustAllHosts(true);
            prop.put("mail.smtp.ssl.enable","true");
            prop.put("mail.smtp.ssl.socketFactory",sf);

            //使用javaMail发送邮件的5个步骤

            //1.创建定义整个应用程序所需要的环境信息的session对象
            Session session= Session.getDefaultInstance(prop, new Authenticator() {
                @Override
                protected PasswordAuthentication getPasswordAuthentication() {
                    return new PasswordAuthentication(from,password);
                }
            });
            //开启session的debug模式,这样可以查看到程序发送Email的运行状态
            session.setDebug(true);

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

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

            //4.创建邮件:写文件

            //注意需要传递session
            MimeMessage message = new MimeMessage(session);
            //指明邮件的发件人
            message.setFrom(new InternetAddress(from));
            //指明邮件的收件人
            message.setRecipient(Message.RecipientType.TO,new InternetAddress(user.getMail()));//从前端接收的
            //邮件标题
            message.setSubject("注册通知");
            //邮件的文本内容

            String info  = "恭喜你("+user.getUsername()+")成功注册!"+"密码:"+user.getPassword();
            message.setContent(info,"text/html;charset=UTF-8");
            message.saveChanges();//保存更改

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

            //6.关闭连接
            ts.close();
        }catch (Exception e){
            System.out.println(e);
        }
    }
}


前端页面index.jsp

<%@page contentType="text/html;charset=utf-8"%>
<html>
<head><title>Mail Register</title></head>
<body>
<span style="text-align: center"><h2>Mail Reg</h2></span>
<div style="text-align: center">
<form action="./reg" method="post">
    用户名:<input type="text" name="username"><br>
    密码: <input type="password" name="password"><br>
    邮箱:<input type="text" name="mail" >
    <input type="submit" value="注册">
</form>
</div>
</body>
</html>

web.xml

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

<web-app>
  <display-name>Archetype Created Web Application</display-name>
  <servlet>
    <servlet-name>regMail</servlet-name>
    <servlet-class>com.lumos.servlet.RegMailServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>regMail</servlet-name>
    <url-pattern>/reg</url-pattern>
  </servlet-mapping>
</web-app>

  • 23
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值