SpringBoot:邮件发送

        官网文档:39. Sending Email (spring.io)。

Sending Email

Spring框架提供了JavaMailSender实例,用于发送邮件。

如果SpringBoot项目中包含了相关的启动器,那么就会自动装配一个Bean实例到项目中。

        在SpringBoot项目中引入如下Email启动器,

<!-- spring-boot-starter-mail-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-mail</artifactId>
</dependency>

核心接口和类

核心接口:MailSender

        org.springframework.mail是邮件发送依赖的顶级包,其中提供了邮件发送的核心接口MailSender,该接口提供了两个方法,分别用于指定逐个邮件发送、批量邮件发送。

package org.springframework.mail;

/**
 * This interface defines a strategy for sending simple mails. Can be
 * implemented for a variety of mailing systems due to the simple requirements.
 * For richer functionality like MIME messages, consider JavaMailSender.
 *
 * <p>Allows for easy testing of clients, as it does not depend on JavaMail's
 * infrastructure classes: no mocking of JavaMail Session or Transport necessary.
 */
public interface MailSender {

	/**
	 * Send the given simple mail message.-发送简单邮件
	 * @param simpleMessage the message to send
	 * @throws MailParseException in case of failure when parsing the message
	 * @throws MailAuthenticationException in case of authentication failure
	 * @throws MailSendException in case of failure when sending the message
	 */
	void send(SimpleMailMessage simpleMessage) throws MailException;

	/**
	 * Send the given array of simple mail messages in batch.-批量发送一组简单邮件
	 * @param simpleMessages the messages to send
	 * @throws MailParseException in case of failure when parsing a message
	 * @throws MailAuthenticationException in case of authentication failure
	 * @throws MailSendException in case of failure when sending a message
	 */
	void send(SimpleMailMessage... simpleMessages) throws MailException;

}

        可以看到,其实JavaMailSender接口也作为它的子接口存在,并且内置了一个实现类JavaMailSenderImpl可以供我们直接使用。

邮件消息接口:MailMessage

        邮件消息接口:规定一封电子邮件对应的组成元素,内置了简单邮件消息和媒体邮件消息两个实现子类。

package org.springframework.mail;

import java.util.Date;

/**
 * This is a common interface for mail messages, allowing a user to set key
 * values required in assembling a mail message, without needing to know if
 * the underlying message is a simple text message or a more sophisticated
 * MIME message.
 *
 * <p>Implemented by both SimpleMailMessage and MimeMessageHelper,
 * to let message population code interact with a simple message or a
 * MIME message through a common interface.
 */
public interface MailMessage {

	void setFrom(String from) throws MailParseException;

	void setReplyTo(String replyTo) throws MailParseException;

	void setTo(String to) throws MailParseException;

	void setTo(String... to) throws MailParseException;

	void setCc(String cc) throws MailParseException;

	void setCc(String... cc) throws MailParseException;

	void setBcc(String bcc) throws MailParseException;

	void setBcc(String... bcc) throws MailParseException;

	void setSentDate(Date sentDate) throws MailParseException;

	void setSubject(String subject) throws MailParseException;

	void setText(String text) throws MailParseException;

}

简单邮件对象:SimpleMailMessage 

        可以用来囊括简单邮件信息的类是SimpleMailMessage类,邮件主体内容以简单文本形式为主。

A simple value object that encapsulates the properties of a simple mail such as from and to (plus many others) is the SimpleMailMessage class. 

        该类的源码如下, 

package org.springframework.mail;

import java.io.Serializable;
import java.util.Date;

import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

/**
 * Models a simple mail message, including data such as the from, to, cc, subject,
 * and text fields.
 *
 * <p>Consider {@code JavaMailSender} and JavaMail {@code MimeMessages} for creating
 * more sophisticated messages, for example messages with attachments, special
 * character encodings, or personal names that accompany mail addresses.
 *
 * @author Dmitriy Kopylenko
 * @author Juergen Hoeller
 * @since 10.09.2003
 * @see MailSender
 * @see org.springframework.mail.javamail.JavaMailSender
 * @see org.springframework.mail.javamail.MimeMessagePreparator
 * @see org.springframework.mail.javamail.MimeMessageHelper
 * @see org.springframework.mail.javamail.MimeMailMessage
 */
@SuppressWarnings("serial")
public class SimpleMailMessage implements MailMessage, Serializable {

	@Nullable
	private String from;

	@Nullable
	private String replyTo;

	@Nullable
	private String[] to;

	@Nullable
	private String[] cc;

	@Nullable
	private String[] bcc;

	@Nullable
	private Date sentDate;

	@Nullable
	private String subject;

	@Nullable
	private String text;


	/**
	 * Create a new {@code SimpleMailMessage}.
	 */
	public SimpleMailMessage() {
	}

	/**
	 * Copy constructor for creating a new {@code SimpleMailMessage} from the state
	 * of an existing {@code SimpleMailMessage} instance.
	 */
	public SimpleMailMessage(SimpleMailMessage original) {
		Assert.notNull(original, "'original' message argument must not be null");
		this.from = original.getFrom();
		this.replyTo = original.getReplyTo();
		this.to = copyOrNull(original.getTo());
		this.cc = copyOrNull(original.getCc());
		this.bcc = copyOrNull(original.getBcc());
		this.sentDate = original.getSentDate();
		this.subject = original.getSubject();
		this.text = original.getText();
	}


	@Override
	public void setFrom(String from) {
		this.from = from;
	}

	@Nullable
	public String getFrom() {
		return this.from;
	}

	@Override
	public void setReplyTo(String replyTo) {
		this.replyTo = replyTo;
	}

	@Nullable
	public String getReplyTo() {
		return this.replyTo;
	}

	@Override
	public void setTo(String to) {
		this.to = new String[] {to};
	}

	@Override
	public void setTo(String... to) {
		this.to = to;
	}

	@Nullable
	public String[] getTo() {
		return this.to;
	}

	@Override
	public void setCc(String cc) {
		this.cc = new String[] {cc};
	}

	@Override
	public void setCc(String... cc) {
		this.cc = cc;
	}

	@Nullable
	public String[] getCc() {
		return this.cc;
	}

	@Override
	public void setBcc(String bcc) {
		this.bcc = new String[] {bcc};
	}

	@Override
	public void setBcc(String... bcc) {
		this.bcc = bcc;
	}

	@Nullable
	public String[] getBcc() {
		return this.bcc;
	}

	@Override
	public void setSentDate(Date sentDate) {
		this.sentDate = sentDate;
	}

	@Nullable
	public Date getSentDate() {
		return this.sentDate;
	}

	@Override
	public void setSubject(String subject) {
		this.subject = subject;
	}

	@Nullable
	public String getSubject() {
		return this.subject;
	}

	@Override
	public void setText(String text) {
		this.text = text;
	}

	@Nullable
	public String getText() {
		return this.text;
	}


	/**
	 * Copy the contents of this message to the given target message.
	 * @param target the {@code MailMessage} to copy to
	 */
	public void copyTo(MailMessage target) {
		Assert.notNull(target, "'target' MailMessage must not be null");
		if (getFrom() != null) {
			target.setFrom(getFrom());
		}
		if (getReplyTo() != null) {
			target.setReplyTo(getReplyTo());
		}
		if (getTo() != null) {
			target.setTo(copy(getTo()));
		}
		if (getCc() != null) {
			target.setCc(copy(getCc()));
		}
		if (getBcc() != null) {
			target.setBcc(copy(getBcc()));
		}
		if (getSentDate() != null) {
			target.setSentDate(getSentDate());
		}
		if (getSubject() != null) {
			target.setSubject(getSubject());
		}
		if (getText() != null) {
			target.setText(getText());
		}
	}


	@Override
	public boolean equals(@Nullable Object other) {
		if (this == other) {
			return true;
		}
		if (!(other instanceof SimpleMailMessage)) {
			return false;
		}
		SimpleMailMessage otherMessage = (SimpleMailMessage) other;
		return (ObjectUtils.nullSafeEquals(this.from, otherMessage.from) &&
				ObjectUtils.nullSafeEquals(this.replyTo, otherMessage.replyTo) &&
				ObjectUtils.nullSafeEquals(this.to, otherMessage.to) &&
				ObjectUtils.nullSafeEquals(this.cc, otherMessage.cc) &&
				ObjectUtils.nullSafeEquals(this.bcc, otherMessage.bcc) &&
				ObjectUtils.nullSafeEquals(this.sentDate, otherMessage.sentDate) &&
				ObjectUtils.nullSafeEquals(this.subject, otherMessage.subject) &&
				ObjectUtils.nullSafeEquals(this.text, otherMessage.text));
	}

	@Override
	public int hashCode() {
		int hashCode = ObjectUtils.nullSafeHashCode(this.from);
		hashCode = 29 * hashCode + ObjectUtils.nullSafeHashCode(this.replyTo);
		hashCode = 29 * hashCode + ObjectUtils.nullSafeHashCode(this.to);
		hashCode = 29 * hashCode + ObjectUtils.nullSafeHashCode(this.cc);
		hashCode = 29 * hashCode + ObjectUtils.nullSafeHashCode(this.bcc);
		hashCode = 29 * hashCode + ObjectUtils.nullSafeHashCode(this.sentDate);
		hashCode = 29 * hashCode + ObjectUtils.nullSafeHashCode(this.subject);
		return hashCode;
	}

	@Override
	public String toString() {
		StringBuilder sb = new StringBuilder("SimpleMailMessage: ");
		sb.append("from=").append(this.from).append("; ");
		sb.append("replyTo=").append(this.replyTo).append("; ");
		sb.append("to=").append(StringUtils.arrayToCommaDelimitedString(this.to)).append("; ");
		sb.append("cc=").append(StringUtils.arrayToCommaDelimitedString(this.cc)).append("; ");
		sb.append("bcc=").append(StringUtils.arrayToCommaDelimitedString(this.bcc)).append("; ");
		sb.append("sentDate=").append(this.sentDate).append("; ");
		sb.append("subject=").append(this.subject).append("; ");
		sb.append("text=").append(this.text);
		return sb.toString();
	}


	@Nullable
	private static String[] copyOrNull(@Nullable String[] state) {
		if (state == null) {
			return null;
		}
		return copy(state);
	}

	private static String[] copy(String[] state) {
		return state.clone();
	}

}

媒体邮件对象:MimeMailMessage

        MemeMailMessage表示媒体邮件对象,可以实现自定义邮件模板的动态填充和邮件发送。

/*
 * Copyright 2002-2017 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.mail.javamail;

import java.util.Date;

import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;

import org.springframework.mail.MailMessage;
import org.springframework.mail.MailParseException;

/**
 * Implementation of the MailMessage interface for a JavaMail MIME message,
 * to let message population code interact with a simple message or a MIME
 * message through a common interface.
 *
 * <p>Uses a MimeMessageHelper underneath. Can either be created with a
 * MimeMessageHelper instance or with a JavaMail MimeMessage instance.
 *
 * @author Juergen Hoeller
 * @since 1.1.5
 * @see MimeMessageHelper
 * @see javax.mail.internet.MimeMessage
 */
public class MimeMailMessage implements MailMessage {

	private final MimeMessageHelper helper;


	/**
	 * Create a new MimeMailMessage based on the given MimeMessageHelper.
	 * @param mimeMessageHelper the MimeMessageHelper
	 */
	public MimeMailMessage(MimeMessageHelper mimeMessageHelper) {
		this.helper = mimeMessageHelper;
	}

	/**
	 * Create a new MimeMailMessage based on the given JavaMail MimeMessage.
	 * @param mimeMessage the JavaMail MimeMessage
	 */
	public MimeMailMessage(MimeMessage mimeMessage) {
		this.helper = new MimeMessageHelper(mimeMessage);
	}

	/**
	 * Return the MimeMessageHelper that this MimeMailMessage is based on.
	 */
	public final MimeMessageHelper getMimeMessageHelper() {
		return this.helper;
	}

	/**
	 * Return the JavaMail MimeMessage that this MimeMailMessage is based on.
	 */
	public final MimeMessage getMimeMessage() {
		return this.helper.getMimeMessage();
	}


	@Override
	public void setFrom(String from) throws MailParseException {
		try {
			this.helper.setFrom(from);
		}
		catch (MessagingException ex) {
			throw new MailParseException(ex);
		}
	}

	@Override
	public void setReplyTo(String replyTo) throws MailParseException {
		try {
			this.helper.setReplyTo(replyTo);
		}
		catch (MessagingException ex) {
			throw new MailParseException(ex);
		}
	}

	@Override
	public void setTo(String to) throws MailParseException {
		try {
			this.helper.setTo(to);
		}
		catch (MessagingException ex) {
			throw new MailParseException(ex);
		}
	}

	@Override
	public void setTo(String... to) throws MailParseException {
		try {
			this.helper.setTo(to);
		}
		catch (MessagingException ex) {
			throw new MailParseException(ex);
		}
	}

	@Override
	public void setCc(String cc) throws MailParseException {
		try {
			this.helper.setCc(cc);
		}
		catch (MessagingException ex) {
			throw new MailParseException(ex);
		}
	}

	@Override
	public void setCc(String... cc) throws MailParseException {
		try {
			this.helper.setCc(cc);
		}
		catch (MessagingException ex) {
			throw new MailParseException(ex);
		}
	}

	@Override
	public void setBcc(String bcc) throws MailParseException {
		try {
			this.helper.setBcc(bcc);
		}
		catch (MessagingException ex) {
			throw new MailParseException(ex);
		}
	}

	@Override
	public void setBcc(String... bcc) throws MailParseException {
		try {
			this.helper.setBcc(bcc);
		}
		catch (MessagingException ex) {
			throw new MailParseException(ex);
		}
	}

	@Override
	public void setSentDate(Date sentDate) throws MailParseException {
		try {
			this.helper.setSentDate(sentDate);
		}
		catch (MessagingException ex) {
			throw new MailParseException(ex);
		}
	}

	@Override
	public void setSubject(String subject) throws MailParseException {
		try {
			this.helper.setSubject(subject);
		}
		catch (MessagingException ex) {
			throw new MailParseException(ex);
		}
	}

	@Override
	public void setText(String text) throws MailParseException {
		try {
			this.helper.setText(text);
		}
		catch (MessagingException ex) {
			throw new MailParseException(ex);
		}
	}

}

异常接口:MailException

 This package also contains a hierarchy of checked exceptions that provide a higher level of abstraction over the lower level mail system exceptions, with the root exception being MailException.

        Mail是邮件发送的异常处理根接口,源码如下,

@SuppressWarnings("serial")
public abstract class MailException extends NestedRuntimeException {

	/**
	 * Constructor for MailException.
	 * @param msg the detail message
	 */
	public MailException(String msg) {
		super(msg);
	}

	/**
	 * Constructor for MailException.
	 * @param msg the detail message
	 * @param cause the root cause from the mail API in use
	 */
	public MailException(@Nullable String msg, @Nullable Throwable cause) {
		super(msg, cause);
	}

}

        当然,它也内置了一系列子接口,

        基本含义如下, 

MailSendException:邮件发送失败异常

MailParseException:非法的邮件配置属性

MailPreparationException:邮件模板渲染出错时,会抛出此类异常。

MailAuthenticationException:认证失败异常。

application.yml配置

        要使用JavaMailSender实现邮件发送,那么就需要先对其进行配置。通过上述内容的初步了解,基本上可以确定我们要配置的参数就和JavaMailSenderImpl实现子类相关了,其成员属性如下,和SpringBoot官网配置文档给出的配置参数也是一一对应的。

JavaMailSenderImpl实现子类
springBoot官网配置文档

        我所做的配置如下,

spring:
  mail:
    protocol: smtp
    host: smtp.qq.com
    default-encoding: UTF-8
    username: email-account
    password: key/password
    properties:
      mail:
        debug: true #开启日志打印
        smtp:
          auth: true
          starttls:
            enable: true
            required: true

邮件发送

        上面了解到两种邮件形式,所以,接下来我们尝试一下,如何发送简单文本邮件,以及自定义模板的邮件。

SimpleMailMessage发送

        简单邮件的发送示例代码如下,其中:JavaMailSender 实例即为文章开头部分提到的,由Spring框架自动注入的Bean实例。


@Component
public class EmailSendServiceImpl implements EmailSenderService {

    @Autowired
    private JavaMailSender mailSender;

    @Override
    public R sendSimpleEmail(String from, String to, String subject, String text) {
        try {
            //创建邮件对象
            SimpleMailMessage mailMessage = new SimpleMailMessage();
            //设置邮件属性
            mailMessage.setFrom(from);//发件人
            mailMessage.setTo(to);//收件人
            mailMessage.setSubject(subject);//主题
            mailMessage.setText(text);//文本内容
            mailMessage.setSentDate(new Date());//发送日期
            //发送邮件
            this.mailSender.send(mailMessage);
            //返回消息
            return R.ok("邮件发送成功!");
        } catch (MailException e) {
            e.printStackTrace();
            return R.fail("邮件发送失败!");
        }
    }
}

MimeMailMessage发送

        为了方便向邮件中写入自定义内容,所以自定义邮件模板需要借助后端的模板引擎来实现,此处我们选择thymeleaf模板引擎。以下为此时的依赖,

       <!-- spring-boot-starter-mail-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-mail</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>

thymeleaf配置

         如上图所示,thymeleaf模板引擎内置了一套配置规则,最简单的方式就是将其原模原样的写到application.yml配置文件中即可。

        以下为我的配置项,

spring:
  thymeleaf:
    prefix: classpath:/templates/
    suffix: .html
    mode: HTML

邮件模板定制

邮件模板定制,其实就是写一个前端页面,然后借助thymeleaf模板引擎的表达式语法,实现自定义内容的动态填充即可。

关于Thymeleaf的表达式语法,详情可参阅官网文档:Tutorial: Using Thymeleaf

        但是说实话,对于简单的文本替换,以下的简单表达式语法基本就能满足了。

 关于邮件模板的定制,如果要求特别高的话,可以自己从零开始写;但是,如果要快速实现的话,也可以借助在线生成工具,这里比较推荐:拉易网提供的精美邮件定制服务,里面内置了一些可以直接使用的邮件模板,也可以在此基础上进行个性化定制,零代码自动生成。

最终将定制好的模板下载下来即可。

       

 如何使用邮件模板

        那么我们下载下来的邮件模板如何使用呢?

其实和我们的Thymeleaf模板引擎配置相关,毕竟是要将这个模板交给Thymeleaf模板引擎进行值的动态替换和渲染的。

这里对应于thymeleaf的prefix配置项,我的email.html邮件模板就放在templates路径下。

        另外,为了实现动态替换文本,例如:我这里想要实现邮件验证码,那么,我就要通过表达式语法,提供一个文本字符串的变量verifyCode,以便于在后面发送邮件时,将这个变量替换为任何我们随机生成的验证码字符串。

示例代码

终于来到代码环节了,但是前面的环节也确实缺一不可。

@Component
public class EmailSendServiceImpl implements EmailSenderService {

    @Autowired
    private JavaMailSender mailSender;
    @Autowired
    private TemplateEngine templateEngine;


    @Override
    public R sendMimeEmail(String from, String to, String subject) {
        //create a new JavaMail MimeMessage
        MimeMessage mimeMailMessage = this.mailSender.createMimeMessage();
        MimeMessageHelper mimeMessageHelper = null;
        try {
            /**
             * mimeMessage – the mime message to work on
             * multipart – whether to create a multipart message that supports alternative texts, inline elements and attachments (corresponds to MULTIPART_MODE_MIXED_RELATED)
             */
            mimeMessageHelper = new MimeMessageHelper(mimeMailMessage, true);
            //setting basic params
            mimeMessageHelper.setFrom(from);
            mimeMessageHelper.setTo(to);
            mimeMessageHelper.setSubject(subject);
            //create html-text based on thymeleaf template
            Context context = new Context();
            context.setVariable("verifyCode","456935");
            String process = templateEngine.process("email", context);
            //设置邮件内容
            /**
             * process:the text for the message
             * html:whether to apply content type "text/html" for an HTML mail, using default content type ("text/plain") else
             */
            mimeMessageHelper.setText(process,true);
            //发送邮件
            this.mailSender.send(mimeMailMessage);
            return R.ok("邮件发送成功!");
        } catch (MessagingException e) {
            e.printStackTrace();
            return R.fail("邮件发送失败!");
        }
    }
}

* 模板变量替换:Context探究

        先看一下源码注释,

IContext接口的非web(场景)实现,适用于非web场景。

        我们继续查看Context父类AbstractContext实现的IContext接口,可以看到,有一个我们刚才用于动态替换thymeleaf模板变量的方法,

        注意到它还提供了一个重载方法,可以实现多个模板变量值的设置,都是以key-value键值对的形式出现。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/187618.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

十大排序之计数排序、桶排序、基数排序(详解)

文章目录 &#x1f412;个人主页&#x1f3c5;算法思维框架&#x1f4d6;前言&#xff1a; &#x1f380;计数排序 时间复杂度O(nk)&#x1f387;1. 算法步骤思想&#x1f387;2.动画实现&#x1f387; 3.代码实现 &#x1f380;桶排序&#x1f387;1. 算法步骤思想&#x1f38…

activiti流程变量操作api

文章目录 runtimeServicetaskServicedelegateTask测试绘制流程图启动流程runtimeService&taskService查询变量runtimeService&taskService设置变量 runtimeService // ## runtimeService操作的都是executionId runtimeService.startProcessInstanceByKey(processDefin…

ACL权限

ACL权限 目录&#xff1a; 1. 什么是ACL 2. 操作步骤 1. 什么是ACL ACL是Access Control List的缩写&#xff0c;即访问控制列表 每个项目成员在有一个自己的项目目录&#xff0c;对自己的目录有完全权限 项目组中的成员对项目目录也有完全权限 其他人对项目目录没有…

互联网时代的身份标识有哪些?

在互联网时代&#xff0c;我们的在线活动几乎都与IP地址相关。无论是浏览网页、观看视频&#xff0c;还是进行在线交易和沟通交流&#xff0c;我们的设备都会分配到一个独特的IP地址。然而&#xff0c;你可能并未意识到的是&#xff0c;IP地址不仅标识了我们在网络中的身份&…

MySQL 索引相关问题,建议搭建好环境,真实操作一下索引应用到的各种场景

文章目录 什么是 B-tree 和 Btree &#xff1f;B-Tree 和 BTree的区别&#xff1f;MySQL 联合唯一索引是BTree&#xff0c;会带来什么原则&#xff1f;主键索引和单字段唯一索引有什么区别吗什么是 聚簇索引和非聚簇索引 &#xff1f;创建一个三百万数据量的表格&#xff0c;方…

HCIP-七、IS-IS 综合实验

七、IS-IS 综合实验 实验拓扑实验需求及解法1.如图所示&#xff0c;配置所有路由器的接口IP地址。2.运行IS-IS&#xff0c;进程号13.IS-IS优化4.路径优化 实验拓扑 实验需求及解法 本实验模拟IS-IS综合网络&#xff0c;完成以下需求&#xff1a; 1.如图所示&#xff0c;配置所…

Acrel-2000电力监控系统在上海大世界保护修缮工程项目中的应用

摘要&#xff1a;安科瑞生产厂家1876150/-6237黄安南 介绍上海大世界电力监控系统&#xff0c;采用智能电力仪表采集配电现场的各种电参量和开关信号。系统采用现场就地组网的方式&#xff0c;组网后通过现场总线通讯并远传至后台&#xff0c;通过Acrel-2000型电力监控系统实现…

Matplotlib图形配置与样式表_Python数据分析与可视化

Matplotlib图形配置与样式表 配置图形修改默认配置rcParams样式表 Matplotlib的默认图形设置经常被用户诟病。虽然2.0版本已经有了很大改善&#xff0c;但是掌握自定义配置的方法可以让我们打造自己的艺术风格。 配置图形 我们可以通过修个单个图形配置&#xff0c;使得最终图…

搜索引擎语法

演示自定的Google hacking语法&#xff0c;解释含意以及在渗透过程中的作用 Google hacking site&#xff1a;限制搜索范围为某一网站&#xff0c;例如&#xff1a;site:baidu.com &#xff0c;可以搜索baidu.com 的一些子域名。 inurl&#xff1a;限制关键字出现在网址的某…

【数据分享】我国12.5米分辨率的坡度数据(免费获取)

地形数据&#xff0c;也叫DEM数据&#xff0c;是我们在各项研究中最常使用的数据之一。之前我们分享过源于NASA地球科学数据网站发布的12.5米分辨率DEM地形数据&#xff08;可查看之前的文章获悉详情&#xff09;&#xff0c;这个DEM数据的优点是精度高。 基于DEM地形数据&…

【OpenGauss源码学习 —— 执行算子(Merge Join 算子)】

执行算子&#xff08;Merge Join 算子&#xff09; 连接算子Merge Join 算子ExecInitMergeJoin 函数MergeJoin 结构体 ExecMergeJoin 函数MergeJoinState 结构体 ExecEndMergeJoin 函数 总结 声明&#xff1a;本文的部分内容参考了他人的文章。在编写过程中&#xff0c;我们尊重…

阿里云windwos 安装oracle数据库,外部用工具连接不上,只能在服务器本机通过127.0.0.1 连接

1. 首先检查阿里云服务器安全组端口是否开放 oracle 数据库端口 2. 其次找到oracle 安装的目录&#xff0c;打开这俩个文件&#xff0c;将localhost 修改为 服务器本机名称 3.重启oracle 监听服务&#xff0c;就可以连接了

新手如何买卖基金,基金投资基础入门

一、教程描述 本套基金教程&#xff0c;大小2.50G&#xff0c;共有13个文件。 二、教程目录 第01课&#xff1a;基金入门&#xff0c;学会投资其实不难.mp4 第02课&#xff1a;基金分类&#xff0c;琳琅满目清清楚楚.mp4 第03课&#xff1a;以稳取胜&#xff0c;稳健基金稳…

程序的编译与链接(详解)

程序的编译与链接 本章内容如下&#xff1a; 1:程序的翻译环境与执行环境的介绍 2:详解程序的翻译环境(编译链接) 2.1预处理阶段干了啥2.2编译阶段干了啥2.3汇编阶段干了啥2.4链接阶段干了啥 3:预处理详解 预定义符号的介绍#define 的介绍(宏与标识符号)#与##的介绍宏与函数…

【MinIO】几个有用的方法

在windows总安装Minio 这是一篇不错的安装指南 进入网址 在Windows安装时&#xff0c;选择相应的exe文件下载&#xff0c;下载到本地后&#xff0c;使用如下的命令即可在前台启动&#xff1a; minio.exe server D:\your_path 或者将该路径写进环境变量的path中&#xff0c;…

怎么当代课老师教学生

老师朋友们&#xff0c;有没有帮忙当过代课老师呢&#xff1f;或者&#xff0c;没当过的老师是不是对这种职业充满了好奇&#xff1f;让我来分享一下&#xff0c;当代课老师的日常是什么样的吧&#xff01; 备课 说起备课&#xff0c;那可是个大工程&#xff01;不过&#xff…

微信消息推送说明

1 打开任务清单 2 编辑任务清单设置 名字解释 姓名&#xff1a;微信名字 内容&#xff1a;要发送消息 定时&#xff1a;从几点开始发送 每隔几分钟&#xff1a;每隔几分钟重复发送一次 重复次数&#xff1a;每隔几分钟重复发送几次 响玲&#xff1a;定时语音电话&#x…

掌握高效性能测试技能:JMeter基础入门!

一、JMeter基础 A、JMeter介绍 Apache JMeter是Apache组织开发的基于Java的压力测试工具。 Apache JMeter may be used to test performance both on static and dynamic resources (files, Servlets, Perl scripts, Java Objects, Data Bases and Queries, FTP Servers and …

Unity UGUI的自动布局-LayoutGroup(水平布局)组件

Horizontal Layout Group | Unity UI | 1.0.0 1. 什么是HorizontalLayoutGroup组件&#xff1f; HorizontalLayoutGroup是Unity UGUI中的一种布局组件&#xff0c;用于在水平方向上对子物体进行排列和布局。它可以根据一定的规则自动调整子物体的位置和大小&#xff0c;使它们…

机器人规划算法——movebase导航框架源码分析

这里对MoveBase类的类成员进行了声明&#xff0c;以下为比较重要的几个类成员函数。 构造函数 MoveBase::MoveBase | 初始化Action 控制主体 MoveBase::executeCb收到目标&#xff0c;触发全局规划线程&#xff0c;循环执行局部规划 全局规划线程 void MoveBase::planThread |…