SpringBoot:邮件发送

news2024/9/21 4:29:56

        官网文档: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键值对的形式出现。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

小红书干货类笔记怎么写?建议收藏

小红书干货类笔记是指在小红书这个社交平台上&#xff0c;用户分享的各种实用、有价值的生活技巧、经验、心得等内容的笔记。这类笔记通常具有以下特点&#xff1a;内容详实、实用性强、独特见解、图文并茂。 比如&#xff1a;某个妆要怎么化、某种技能该怎么学、某个城市该怎…

前端环境变量释义import.meta.env.xxx

视频教程 彻底搞懂前端环境变量使用和原理&#xff0c;超清楚_哔哩哔哩_bilibili 添加命令行参数 --modexxxxx 新建.env.xxxx文件,其中.env文件会在所有环境下生效 以VITE_开头&#xff0c;字符串无需加双引号 使用import.meta.env.VITE_xxxxx进行调用

跨境电商客服系统:提升客户满意度与优化电商体验的关键

随着全球电子商务的快速发展&#xff0c;跨境电商已经成为新的商业发展趋势。在这个高度竞争的市场环境中&#xff0c;优质的客户服务成为区分优秀与平庸的关键因素。一个高效的跨境电商客服系统不仅可以提高客户满意度&#xff0c;还能帮助企业优化电商体验&#xff0c;进而提…

图解系列--密钥,随机数,应用技术

密钥 1.生成密钥 1.1.用随机数生成密钥 密码学用途的伪随机数生成器必须是专门针对密码学用途而设计的。 1.2.用口令生成密钥 一般都是将口令输入单向散列函数&#xff0c;然后将得到的散列值作为密钥使用。 在使用口令生成密钥时&#xff0c;为了防止字典攻击&#xff0c;需要…

flutter 极光集成华为厂商推送:Could not resolve com.huawei.agconnect:agcp:1.9.1.301

前提&#xff1a;已经按照极光官网配置好准备工作 问题截图&#xff1a; 主要一直通过vscode启动项目&#xff0c;下载华为包失败。通过和极光的开发沟通&#xff0c;在Android Studio中配置代理Ps&#xff1a;代理信息 检查链接成功&#xff0c;即可去下载插件包 然后正常执…

【技巧】PDF文件如何编辑?

日常办公中我们经常会用到PDF文件&#xff0c;PDF具备很好的兼容性、稳定性及安全性&#xff0c;但却不容易编辑&#xff0c;那PDF要如何编辑呢&#xff1f; 如果打开PDF文件就只是只读的性质&#xff0c;说明文件是在线打开&#xff0c;或者通过PDF阅读器打开的&#xff0c;这…

nodejs+vue线上生活超市购物商城系统w2c42

超市管理系统的开发流程包括对超市管理系统的需求分析&#xff0c;软件的设计建模以及编写程序实现系统所需功能这三个阶段。对超市管理系统的需求分析。在这个阶段&#xff0c;通过查阅书籍&#xff0c;走访商场搜集相关资料&#xff0c;了解经营者对软件功能的具体所需和建议…

人工智能和AR/VR:AI在AR和VR中扮演什么角色?行业应用有哪些?

增强现实技术和虚拟现实技术&#xff08;AR/VR&#xff09;发展前景广阔&#xff0c;备受各大企业关注。事实上&#xff0c;近四分之三的行业领导者表示&#xff0c;他们预计这些沉浸式技术将于未来五年内成为主流。高盛公司报告称&#xff0c;到2025年&#xff0c;AR/VR行业值…

Golang版本处理Skywalking Trace上报数据

Tips: 中间记录了解决问题的过程&#xff0c;如不感兴趣可直接跳至结尾 首先去es里查询skywalking trace的元数据 可以拿到一串base64加密后的data_binary(直接解密不能用&#xff0c;会有乱码&#xff0c;可参考https://github.com/apache/skywalking/issues/7423) 对data_b…

SkyWalking配置报警推送到企业微信

1、先在企业微信群里创建一个机器人&#xff0c;复制webhook的地址&#xff1a; 2、找到SkyWalking部署位置的alarm-settings.yml文件 编辑&#xff0c;在最后面加上此段配置 &#xff01;&#xff01;&#xff01;一定格式要对&#xff0c;不然一直报警报不出来按照网上指导…

Leaflet结合Echarts实现迁徙图

效果图如下&#xff1a; <!DOCTYPE html> <html><head><title>Leaflet结合Echarts4实现迁徙图</title><meta charset"utf-8" /><meta name"viewport" content"widthdevice-width, initial-scale1.0">…

计算机系统的存储原理

文章目录 高速缓存存储设备的层次结构操作系统的两个基本功能参考 高速缓存 高速缓存至关重要。 helloworld 程序揭示了一个重要的问题&#xff1a;系统花费了大量的时间把信息从一个地方挪到另一个地方。 程序的机器指令最初是存放在磁盘上&#xff0c;当程序加载时&#xf…

c语言打印金字塔

输入行数n,打印n行的金字塔。如图&#xff1a; 先分析其规律。 打印n行&#xff0c;即外层循环n次。再分析每一层的规律&#xff0c;先具体化举例&#xff0c;举一个行数为5的金字塔。可以发现每一行前面的空格呈递减趋势&#xff0c;且与行数有关系&#xff1a;空格数行数-层…

STM32_3(GPIO)

GPIO简介 GPIO&#xff08;General Purpose Input Output&#xff09;通用输入输出口8种输入输出模式输出模式可控制端口输出高电平&#xff0c;驱动LED、蜂鸣器、模拟通信协议输出时许等输入模式可读取端口的高低电平或电压&#xff0c;用于读取按键输入、外接模块电平信号输…

AD7021C 触摸感应加灯光调节芯片IC 可用于触摸台灯、触摸玩具灯等

AD7021C触摸感应 IC 是为实现人体触摸界面而设计的集成电路。可替代机械式轻触按键&#xff0c;实现防水防尘、密封隔离、坚固美观的操作界面。使用该芯片可以实现 LED 灯光亮度调节&#xff0c;方案所需的外围电路简单&#xff0c;操作方便。确定好灵敏度选择电容&#xff…

【MybatisPlus】简介与使用

MyBatisPlus 1.简介 MyBatisPlus&#xff08;简称MP&#xff09;是一个MyBatis的增强工具&#xff0c;在MyBatis的基础上只做增强不做改变&#xff0c;为简化开发、提高效率而生 官网&#xff1a;https://baomidou.com/ MyBatis-Plus特性&#xff1a; 无侵入&#xff1a;只…

主机dbeaver访问gitlab容器中的pg

映射5432端口- 5431:5432或者从docker客户端查看 version: 3.6 services:web:image: gitlab/gitlab-ce:latestrestart: alwayshostname: localhostenvironment:GITLAB_OMNIBUS_CONFIG: |external_url http://localhost:8929gitlab_rails[gitlab_shell_ssh_port] 2224ports:- …

【漏洞复现】DPTech VPN存在任意文件读取漏洞

漏洞描述 DPtech是在网络、安全及应用交付领域集研发、生产、销售于一体的高科技企业。DPtech VPN智能安全网关是迪普科技面向广域互联应用场景推出的专业安全网关产品&#xff0c;集成了IPSec、SSL、L2TP、GRE等多种VPN技术&#xff0c;支持国密算法&#xff0c;实现分支机构…

详解Java的static关键字

文章目录 &#x1f384;静态方法&#x1f33a;静态方法和非静态方法对比&#x1f6f8;静态方法实例&#x1f6f8;非静态方法实例 &#x1f339;static关键字⭐static变量⭐static代码块 &#x1f384;静态方法 不依赖于对象实例&#xff1a;静态方法不需要依赖于任何对象实例&…

【JavaEE】操作系统与进程

作者主页&#xff1a;paper jie_博客 本文作者&#xff1a;大家好&#xff0c;我是paper jie&#xff0c;感谢你阅读本文&#xff0c;欢迎一建三连哦。 本文录入于《JavaEE》专栏&#xff0c;本专栏是针对于大学生&#xff0c;编程小白精心打造的。笔者用重金(时间和精力)打造&…