Servlet (Java Web 学习笔记)

1.Servlet 技术

a)什么是 Servlet

1、Servlet 是 JavaEE 规范之一。规范就是接口
2、Servlet 就 JavaWeb 三大组件之一。三大组件分别是:Servlet 程序、Filter 过滤器、Listener 监听器。
3、Servlet 是运行在服务器上的一个 java 小程序,它可以接收客户端发送过来的请求,并响应数据给客户端。

b)手动实现 Servlet 程序

1、编写一个类去实现 Servlet 接口
2、实现 service 方法,处理请求,并响应数据
3、到 web.xml 中去配置 servlet 程序的访问地址

Servlet 程序的示例代码:
在这里插入图片描述

web.xml 中的配置:

在这里插入图片描述

常见的错误 1:url-pattern 中配置的路径没有以斜杠打头。
在这里插入图片描述

常见错误 2:servlet-name 配置的值不存在:

在这里插入图片描述

常见错误 3:servlet-class 标签的全类名配置错误:

在这里插入图片描述

c)url 地址到 Servlet 程序的访问

在这里插入图片描述

d)Servlet 的生命周期

1、执行 Servlet 构造器方法
2、执行 init 初始化方法

第一、二步,是在第一次访问,的时候创建 Servlet 程序会调用。

3、执行 service 方法

第三步,每次访问都会调用。

4、执行 destroy 销毁方法

第四步,在 web 工程停止的时候调用。

e)GET 和 POST 请求的分发处理

public class HelloServlet implements Servlet {

/**
*service 方法是专门用来处理请求和响应的
*@param servletRequest
*@param servletResponse
*@throws ServletException
*@throws IOException
*/
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws
ServletException, IOException {
System.out.println("3 service === Hello Servlet 被访问了");
// 类型转换(因为它有getMethod()方法)
HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
// 获取请求的方式
String method = httpServletRequest.getMethod();

if ("GET".equals(method)) { doGet();
} else if ("POST".equals(method)) { 
doPost();
}

}

/**
*做get 请求的操作
*/
public void doGet(){ System.out.println("get 请求"); 
System.out.println("get 请求");
}
/**
*做post 请求的操作
*/
public void doPost(){ System.out.println("post 请求"); 
System.out.println("post 请求");
}

}

f)通过继承 HttpServlet 实现 Servlet 程序

一般在实际项目开发中,都是使用继承 HttpServlet 类的方式去实现 Servlet 程序。

1、编写一个类去继承 HttpServlet 类
2、根据业务需要重写 doGet 或 doPost 方法
3、到 web.xml 中的配置 Servlet 程序的访问地址

Servlet 类的代码:
在这里插入图片描述

web.xml 中的配置:

在这里插入图片描述

g)使用 IDEA 创建 Servlet 程序

菜单:new ->Servlet 程序
在这里插入图片描述

配置 Servlet 的信息:

在这里插入图片描述

h)Servlet 类的继承体系

在这里插入图片描述

2.ServletConfig 类

ServletConfig 类从类名上来看,就知道是 Servlet 程序的配置信息类。
Servlet 程序和 ServletConfig 对象都是由 Tomcat 负责创建,我们负责使用。
Servlet 程序默认是第一次访问的时候创建,ServletConfig 是每个 Servlet 程序创建时,就创建一个对应的 ServletConfig 对象。

a)ServletConfig 类的三大作用

1、可以获取 Servlet 程序的别名 servlet-name 的值
2、获取初始化参数 init-param
3、获取 ServletContext 对象

web.xml 中的配置:

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

Servlet 中的代码:
在这里插入图片描述

注意点:
在这里插入图片描述

3.ServletContext 类

a)什么是 ServletContext?

1、ServletContext 是一个接口,它表示 Servlet 上下文对象
2、一个 web 工程,只有一个 ServletContext 对象实例。
3、ServletContext 对象是一个域对象。
4、ServletContext 是在 web 工程部署启动的时候创建。在 web 工程停止的时候销毁。

什么是域对象?

域对象,是可以像 Map 一样存取数据的对象,叫域对象。这里的域指的是存取数据的操作范围,整个 web 工程。

  	     		存数据			取数据			删除数据
Map				put()			get()			remove()
域对象		setAttribute()	getAttribute()	removeAttribute();

b)ServletContext 类的四个作用

1、获取 web.xml 中配置的上下文参数 context-param 2、获取当前的工程路径,格式: /工程路径
3、获取工程部署后在服务器硬盘上的绝对路径
4、像 Map 一样存取数据

ServletContext 演示代码:
在这里插入图片描述
在这里插入图片描述

web.xml 中的配置:
在这里插入图片描述

ServletContext 像 Map 一样存取数据:

ContextServlet1 代码:

在这里插入图片描述

ContextServlet2 代码:

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

4.HTTP 协议

a)什么是 HTTP 协议

什么是协议?

协议是指双方,或多方,相互约定好,大家都需要遵守的规则,叫协议。

所谓 HTTP 协议,就是指,客户端和服务器之间通信时,发送的数据,需要遵守的规则,叫 HTTP 协议。

HTTP 协议中的数据又叫报文。

b)请求的 HTTP 协议格式

客户端给服务器发送数据叫请求。服务器给客户端回传数据叫响应。

请求又分为 GET 请求,和 POST 请求两种

i.GET 请求

1、请求行

(1)请求的方式 GET
(2)请求的资源路径[+?+请求参数]
(3)请求的协议的版本号 HTTP/1.1 2、请求头
key : value 组成 不同的键值对,表示不同的含义。

在这里插入图片描述

ii.POST 请求

1、请求行

(1)请求的方式 POST
(2)请求的资源路径[+?+请求参数]
(3)请求的协议的版本号 HTTP/1.1

2、请求头

  1. key : value 不同的请求头,有不同的含义

空行

3、请求体 ===>>> 就是发送给服务器的数据
在这里插入图片描述

iii.常用请求头的说明

Accept: 表示客户端可以接收的数据类型
Accpet-Languege: 表示客户端可以接收的语言类型
User-Agent: 表示客户端浏览器的信息
Host: 表示请求时的服务器 ip 和端口号

iv.哪些是GET 请求,哪些是 POST 请求

GET 请求有哪些:

1、form 标签 method=get 2、a 标签
3、link 标签引入 css
4、Script 标签引入 js 文件
5、img 标签引入图片
6、iframe 引入 html 页面
7、在浏览器地址栏中输入地址后敲回车

POST 请求有哪些:

8、form 标签 method=post

c)响应的 HTTP 协议格式

1、响应行

(1)响应的协议和版本号
(2)响应状态码
(3)响应状态描述符

2、响应头

(1) key : value 不同的响应头,有其不同含义空行

3、响应体 ---->>> 就是回传给客户端的数据
在这里插入图片描述

d)常用的响应码说明

200 表示请求成功
302 表示请求重定向(明天讲)
404 表示请求服务器已经收到了,但是你要的数据不存在(请求地址错误)
500 表示服务器已经收到请求,但是服务器内部错误(代码错误)

e)MIME 类型说明

MIME 是 HTTP 协议中数据类型。
MIME 的英文全称是"Multipurpose Internet Mail Extensions" 多功能 Internet 邮件扩充服务。MIME 类型的格式是“大类型/小类型”,并与某一种文件的扩展名相对应。

常见的 MIME 类型:

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

谷歌浏览器如何查看 HTTP 协议:
在这里插入图片描述

火狐浏览器如何查看 HTTP 协议:
在这里插入图片描述

5.HttpServletRequest 类

a)HttpServletRequest 类有什么作用。

每次只要有请求进入 Tomcat 服务器,Tomcat 服务器就会把请求过来的 HTTP 协议信息解析好封装到 Request 对象中。然后传递到 service 方法(doGet 和 doPost)中给我们使用。我们可以通过 HttpServletRequest 对象,获取到所有请求的信息。

b)HttpServletRequest 类的常用方法

i.getRequestURI() 获取请求的资源路径
ii.getRequestURL() 获取请求的统一资源定位符(绝对路径)
iii.getRemoteHost() 获取客户端的 ip 地址
iv.getHeader() 获取请求头
v.getParameter() 获取请求的参数
vi.getParameterValues() 获取请求的参数(多个值的时候使用)
vii.getMethod() 获取请求的方式GET 或POST
viii.setAttribute(key, value); 设置域数据
ix.getAttribute(key); 获取域数据
x.getRequestDispatcher() 获取请求转发对象

常用API 示例代码:

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

c)如何获取请求参数

表单:

在这里插入图片描述

Java 代码:
在这里插入图片描述在这里插入图片描述

doGet 请求的中文乱码解决:
在这里插入图片描述

d)POST 请求的中文乱码解决

在这里插入图片描述

e)请求的转发

什么是请求的转发?

请求转发是指,服务器收到请求后,从一次资源跳转到另一个资源的操作叫请求转发。

在这里插入图片描述

Servlet1 代码:

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

Servlet2 代码:
在这里插入图片描述

f)base 标签的作用

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

g)Web 中的相对路径和绝对路径

在 javaWeb 中,路径分为相对路径和绝对路径两种: 相对路径是:

. 表示当前目录
… 表示上一级目录
资源名 表示当前目录/资源名

绝对路径:

http://ip:port/工程路径/资源路径

在实际开发中,路径都使用绝对路径,而不简单的使用相对路径。

1、绝对路径
2、base+相对

h)web 中 / 斜杠的不同意义

在 web 中 / 斜杠 是一种绝对路径。

/ 斜杠 如果被浏览器解析,得到的地址是:http://ip:port/

<a href="/">斜杠</a>

/ 斜杠 如果被服务器解析,得到的地址是:http://ip:port/工程路径

1、<url-pattern>/servlet1</url-pattern>
2、servletContext.getRealPath(“/”); 
3、request.getRequestDispatcher(“/”)

特殊情况:

response.sendRediect(“/”); 把斜杠发送给浏览器解析。得到 http://ip:port/

6.HttpServletResponse 类

a)HttpServletResponse 类的作用

HttpServletResponse 类和 HttpServletRequest 类一样。每次请求进来,Tomcat 服务器都会创建一个 Response 对象传递给 Servlet 程序去使用。HttpServletRequest 表示请求过来的信息,HttpServletResponse 表示所有响应的信息,
我们如果需要设置返回给客户端的信息,都可以通过 HttpServletResponse 对象来进行设置

b)两个输出流的说明。

字节流 getOutputStream(); 常用于下载(传递二进制数据)
字符流 getWriter(); 常用于回传字符串(常用)
两个流同时只能使用一个。
使用了字节流,就不能再使用字符流,反之亦然,否则就会报错。

在这里插入图片描述

c)如何往客户端回传数据

要求 : 往客户端回传 字符串 数据。

在这里插入图片描述

d)响应的乱码解决

解决响应中文乱码方案一(不推荐使用):
在这里插入图片描述

解决响应中文乱码方案二(推荐):
在这里插入图片描述

e)请求重定向

请求重定向,是指客户端给服务器发请求,然后服务器告诉客户端说。我给你一些地址。你去新地址访问。叫请求 重定向(因为之前的地址可能已经被废弃)。

在这里插入图片描述

请求重定向的第一种方案:

// 设置响应状态码302 ,表示重定向,(已搬迁)
resp.setStatus(302);
// 设置响应头,说明 新的地址在哪里
resp.setHeader(“Location”, “http://localhost:8080”);

请求重定向的第二种方案(推荐使用):

resp.sendRedirect(“http://localhost:8080”);

7. 文件的下载

1 要获取下载文件的路径

2 下载的文件名是啥?

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

4 获取下载文件的输入流

5 创建缓冲区

6 获取OutputStream对象

7 将FileOutputStream流写入到bufer缓冲区

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

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

    in.close();
    out.close();
}

8. 验证码功能

验证怎么来的?

前端实现

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

package com.kuang.servlet;

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

public class ImageServlet extends HttpServlet {

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

        //如何让浏览器3秒自动刷新一次;
        resp.setHeader("refresh","3");
        
        //在内存中创建一个图片
        BufferedImage image = new BufferedImage(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);
    }
}
<servlet>
	<servlet-name>ImageServlet</servlet-name>
	<servlet-class>com.kuang.servlet.ImageServlet</servlet-class>
</servlet>
<servlet-mapping>
	<servlet-name>Imageservlet</servlet-name>
	<url-pattern>/img</url-pattern>
</servlet-mapping>

9. 文件的上传

① 文件上传的注意事项

1.为保证服务器安全,上传文件应该放在外界无法直接访问的目录下, 比如放于WEB-INF目录下。

2.为防止文件覆盖的现象发生,要为上传文件产生一个唯一 的文件名,为避免同名图片的出现可以使用MD5加密还有uid,时间戳等等。

3.要限制上传文件的最大值。

4.可以限制上传文件的类型,在收到上传文件名时,判断后缀名是否合法。

② 文件上传原理
在这里插入图片描述

1 所需jar包

 <!--文件上传,导入文件上传的jar包,commons-fileupload , Maven会自动帮我们导入他的依赖包 commons-io包;-->
    <dependency>
      <groupId>commons-fileupload</groupId>
      <artifactId>commons-fileupload</artifactId>
      <version>1.3.3</version>
    </dependency>

2 index.jsp
加载服务器地址固定写法:"${pageContext.request.contextPath}/upload.do"

<html>
<body>
<form action="${pageContext.request.contextPath}/upload.do" enctype="multipart/form-data" method="post">
    <input type="file" name="file"/>
    <input type="submit" value="upload">
    </form>
</body>
</html>

3 FileServlet

public class FileServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

    @Override
    protected void doGet(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(); //创建这个目录
        }
        //级存,临时文件
        //临时路径,假如文件超过J预期的大小,我们就把他放到一一个临时文件中,过几天自动删除,或者提醒用户转存为承久
        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负责处理上传的文件数据并将表单中每个输入项封装成- - 个FileItem对象。
        在使用ServletFileUpload对象解析请求时需要DiskFileItemFactory对象。
        所以,我们需要在进行解析工作前构造好DiskFileItemFactory对象。
        通过ServletFileUpload对象的构造方法或setFileItemFactory()方法设置ServletFileUpload对象的fileItemFactory属性。
        */
        try {
            //1.创建DiskFileItemFactory对象,处理文件上传路径或者大小限制的;
            DiskFileItemFactory factory = getDiskFileItemFactory(file);
            //2.获取ServletFileUpload
            ServletFileUpload upload = getServletFileUpload(factory);
            //3.处理上传的文件

            String msg = uploadParseRequest(upload, request, uploadPath);
            //servlet请求转发消息
            request.setAttribute("msg", msg);
            request.getRequestDispatcher("info.jsp").forward(request, response);

        } 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 FileUploadException, IOException {
        String msg = "";
        //3.把前端请求解析,封装成一个FileItem对象
        List<FileItem> fileItems = upload.parseRequest(request);
        for (FileItem fileItem : fileItems) {
            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);
                //获得文件的后缀名
                String fileExtName = uploadFileName.substring(uploadFileName.lastIndexOf(".") + 1);
                /*
                如果文件后缀名fileExtName 不是我们所需要的
                就直接return,不处理,告诉用户文件类型不对。
                */
                System.out.println("文件信息[件名: " + fileName + "---文件类型" + fileExtName + "]");
                //可以使用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();
                //创建一个文件输出流
                //realPath =真实的文件夹;
                //差了一个文件;加上输出文件的名字+"/"+uuidFileName
                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;
    }
}

4 web.xml

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


</web-app>

5 info.xml

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

6 将文件从本地传至服务器
在这里插入图片描述
注意:上面的目录只是我们编写代码的文件目录,而我们点击项目发布之后,IDEA会产生一个target文件夹
在这里插入图片描述
在这里插入图片描述

10. 邮件发送

1. 传输协议

SMTP协议

发送邮件:我们通常把处理用户smtp请求(邮件发送请求)的服务器称之为SMTP服务器(邮件发送服务器)。

POP3协议

接收邮件:我们通常把处理用户pop3请求(邮件接收请求)的服务器称之为POP3服务器(邮件接收服务器)。

2. 邮件收发原理

在这里插入图片描述

1首先通过smtp协议连接到Smtp服务器,然后发送一封邮件给网易的邮件服务器

2网易分析发现需要去QQ的邮件服务器,通过smtp协议将邮件转投给QQ的Smtp服务器

3QQ将接收到的邮件存储在xxx@qq.com这个邮件账号的空间中

4再通过Pop3协议连接到Pop3服务器收取邮件

5从xxx@qq.com这个邮件账号的空间中取出邮件

6Pop3服务器将取出来的邮件送出去

【注意】有可能填写的收件人地址,发件人地址等信息都正确了,控制台也打印了正确的信息,但是在收件箱就是收不到信息。这是因为可能收件箱服务器拒收了你发的邮件(比如认为你的邮件是广告),这时候可能在垃圾箱里能找到,可能找不到。解决办法是重复的邮件内容不要多次发送,或者更换收件箱试试

3. Java发送邮件

概述

我们将用代码完成邮件的发送。这在实际项目中应用的非常广泛,比如注册需要发送邮件进行账号激活,再比如OA项目中利用邮件进行任务提醒等等。

使用Java发送 E-mail 十分简单,但是首先你应该准备 JavaMail API 和Java Activation Framework 。

得到两个jar包:

  • mail.jar
  • activation.jar

JavaMail 是sun公司(现以被甲骨文收购)为方便Java开发人员在应用程序中实现邮件发送和接收功能而提供的一套标准开发包,它支持一些常用的邮件协议,如前面所讲的SMTP,POP3,IMAP,还有MIME等。我们在使用JavaMail API 编写邮件时,无须考虑邮件的底层实现细节,只要调用JavaMail 开发包中相应的API类就可以了。

我们可以先尝试发送一封简单的邮件,首先请确保电脑可以连接网络。

  • 创建包含邮件服务器的网络连接信息的Session对象。
  • 创建代表邮件内容的Message对象
  • 创建Transport对象,连接服务器,发送Message,关闭连接

主要有四个核心类,我们在编写程序时,记住这四个核心类,就很容易编写出Java邮件处理程序,如图所示:

在这里插入图片描述

1. 纯文本邮件

先在项目中导入jar包

导入的就是在概述中提到的activation,jar和mail.jar包,如图所示:

在这里插入图片描述

QQ邮箱中获取对应的权限

QQ邮箱需要安全验证,我们需要获取他对应的权限;

进入QQ邮箱–>邮箱设置–>账户,下滑找到POP3/IMAP/SMTP/Exchange/CardDav/CalDav服务,开启POP3/SMTP服务,如图所示:

在这里插入图片描述
在这里插入图片描述
记住这16位授权码,然后开始编写测试程序:

public class SendEmail {

    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"); // 需要验证用户名密码

        // 关于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个步骤

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

        Session session = Session.getDefaultInstance(prop, new Authenticator() {
            public PasswordAuthentication getPasswordAuthentication() {
                //发件人邮件用户名、授权码
                return new PasswordAuthentication("545646733@qq.com", "授权码");
            }
        });


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

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

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

        //4、创建邮件

        //创建邮件对象
        MimeMessage message = new MimeMessage(session);

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

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

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

        //邮件的文本内容
        message.setContent("你好啊!", "text/html;charset=UTF-8");

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

        ts.close();
    }

}

2. 带图片和附件的邮件

先认识两个类一个名词:

MIME(多用途互联网邮件扩展类型)

MimeBodyPart类

javax.mail.internet.MimeBodyPart类 表示的是一个MIME消息,它和MimeMessage类一样都是从Part接口继承过来。

MimeMultipart类

javax.mail.internet.MimeMultipart是抽象类 Multipart的实现子类,它用来组合多个MIME消息。一个MimeMultipart对象可以包含多个代表MIME消息的MimeBodyPart对象。
在这里插入图片描述

1 创建包含内嵌图片的邮件

前面的例子中是单独的使用HTML或者是纯文本内容,但是有时候我们需要在纯文本中使用内嵌的方式显示一些图片,因此就要将纯文本和内嵌图片单独存放在MimeBodyPart中然后再将其存放在一个Mimemultipart对象中即可。

代码如下:

public class SendImageEmail {
    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"); // 需要验证用户名密码

        // 关于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() {
            public PasswordAuthentication getPasswordAuthentication() {
                //发件人邮件用户名、授权码
                return new PasswordAuthentication("545646733@qq.com", "授权码");
            }
        });


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

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

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

        //4、创建邮件

        //创建邮件
        MimeMessage message = new MimeMessage(session);

        // 设置邮件的基本信息
        //发件人
        message.setFrom(new InternetAddress("545646733@qq.com"));
        //收件人
        message.setRecipient(Message.RecipientType.TO, new InternetAddress("545646733@qq.com"));
        //邮件标题
        message.setSubject("带图片的邮件");

        // 准备邮件数据

        // 准备图片数据
        MimeBodyPart image = new MimeBodyPart();
        DataHandler dh = new DataHandler(new FileDataSource("src/resources/bz.jpg"));
        image.setDataHandler(dh);
        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();

        //5.发送邮件
        ts.sendMessage(message, message.getAllRecipients());
        ts.close();
    }
}
2 带图片和附件的复杂邮件发送

代码如下:

public class SendFileMail {
    public static void main(String[] args) throws MessagingException, GeneralSecurityException {

        //创建一个配置文件保存并读取信息
        Properties properties = new Properties();

        //设置qq邮件服务器
        properties.setProperty("mail.host","smtp.qq.com");
        //设置发送的协议
        properties.setProperty("mail.transport.protocol","smtp");
        //设置用户是否需要验证
        properties.setProperty("mail.smtp.auth", "true");


        //=================================只有QQ存在的一个特性,需要建立一个安全的链接
        // 关于QQ邮箱,还要设置SSL加密,加上以下代码即可
        MailSSLSocketFactory sf = new MailSSLSocketFactory();
        sf.setTrustAllHosts(true);
        properties.put("mail.smtp.ssl.enable", "true");
        properties.put("mail.smtp.ssl.socketFactory", sf);

        //=================================准备工作完毕

        //1.创建一个session会话对象;
        Session session = Session.getDefaultInstance(properties, new Authenticator() {
            @Override
            protected PasswordAuthentication getPasswordAuthentication() {
                return new PasswordAuthentication("545646733@qq.com", "授权码");
            }
        });

        //可以通过session开启Dubug模式,查看所有的过程
        session.setDebug(true);


        //2.获取连接对象,通过session对象获得Transport,需要捕获或者抛出异常;
        Transport tp = session.getTransport();

        //3.连接服务器,需要抛出异常;
        tp.connect("smtp.qq.com","545646733@qq.com","授权码");

        //4.连接上之后我们需要发送邮件;
        MimeMessage mimeMessage = imageMail(session);

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

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

    }


    public static MimeMessage imageMail(Session session) throws MessagingException {

        //消息的固定信息
        MimeMessage mimeMessage = new MimeMessage(session);

        //邮件发送人
        mimeMessage.setFrom(new InternetAddress("545646733@qq.com"));
        //邮件接收人,可以同时发送给很多人,我们这里只发给自己;
        mimeMessage.setRecipient(Message.RecipientType.TO, new InternetAddress("545646733@qq.com"));
        mimeMessage.setSubject("我也不知道是个什么东西就发给你了"); //邮件主题


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

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

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

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

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

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

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

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


        //放到Message消息中
        mimeMessage.setContent(allFile);
        mimeMessage.saveChanges();//保存修改


        return mimeMessage;

    }

}

4. JavaWeb发送邮件

现在很多的网站都提供有用户注册功能, 通常我们注册成功之后就会收到一封来自注册网站的邮件。邮件里面的内容可能包含了我们的注册的用户名和密码以及一个激活账户的超链接等信息。今天我们也来实现一个这样的功能,用户注册成功之后,就将用户的注册信息以Email的形式发送到用户的注册邮箱当中,实现发送邮件功能就得借助于JavaMail了。

项目实现:

  1. 新建一个JavaWeb项目,配置tomcat的参数,然后添加jar包(记得在tomcat目录下的common目录下也导包,不然会报500错误),并且添加实体类User,Servlet类RegisterServlet,工具类Sendmail,如图所示:
    在这里插入图片描述
    2.User类代码如下:
public class User {

    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 + '\'' +
                '}';
    }
}

3.前端注册页面register.jsp代码如下:

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

4.工具类Sendmail类代码如下:

public class Sendmail extends Thread {

    //用于给用户发送邮件的邮箱
    private String from = "24736743@qq.com";
    //邮箱的用户名
    private String username = "24736743@qq.com";
    //邮箱的密码
    private String password = "授权码";
    //发送邮件的服务器地址
    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();
            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);
            prop.put("mail.smtp.ssl.enable", "true");
            prop.put("mail.smtp.ssl.socketFactory", sf);

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

            //开启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 = "恭喜您注册成功,您的用户名:" + user.getUsername() + ",您的密码:" + user.getPassword() + ",请妥善保管,如有问题请联系网站客服!!";

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

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

5.Servlet类RegisterServlet类代码如下:

public class RegisterServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        try {
            //接收用户请求,封装成对象
            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);
        } catch (Exception e) {
            e.printStackTrace();
            request.setAttribute("message", "注册失败!!");
            request.getRequestDispatcher("info.jsp").forward(request, response);
        }
    }


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

6.配置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>register</servlet-name>
        <servlet-class>com.kuang.servlet.RegisterServlet</servlet-class>
    </servlet>
    
    <servlet-mapping>
        <servlet-name>register</servlet-name>
        <url-pattern>/RegisterServlet.do</url-pattern>
    </servlet-mapping>
</web-app>

7.编写反馈页面info.jsp,代码如下:
```html
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>提示信息</title>
</head>
<body>
    ${message}
</body>
</html>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值