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 {@Nullableprivate String from;@Nullableprivate String replyTo;@Nullableprivate String[] to;@Nullableprivate String[] cc;@Nullableprivate String[] bcc;@Nullableprivate Date sentDate;@Nullableprivate String subject;@Nullableprivate 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();}@Overridepublic void setFrom(String from) {this.from = from;}@Nullablepublic String getFrom() {return this.from;}@Overridepublic void setReplyTo(String replyTo) {this.replyTo = replyTo;}@Nullablepublic String getReplyTo() {return this.replyTo;}@Overridepublic void setTo(String to) {this.to = new String[] {to};}@Overridepublic void setTo(String... to) {this.to = to;}@Nullablepublic String[] getTo() {return this.to;}@Overridepublic void setCc(String cc) {this.cc = new String[] {cc};}@Overridepublic void setCc(String... cc) {this.cc = cc;}@Nullablepublic String[] getCc() {return this.cc;}@Overridepublic void setBcc(String bcc) {this.bcc = new String[] {bcc};}@Overridepublic void setBcc(String... bcc) {this.bcc = bcc;}@Nullablepublic String[] getBcc() {return this.bcc;}@Overridepublic void setSentDate(Date sentDate) {this.sentDate = sentDate;}@Nullablepublic Date getSentDate() {return this.sentDate;}@Overridepublic void setSubject(String subject) {this.subject = subject;}@Nullablepublic String getSubject() {return this.subject;}@Overridepublic void setText(String text) {this.text = text;}@Nullablepublic 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());}}@Overridepublic 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));}@Overridepublic 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;}@Overridepublic 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();}@Nullableprivate 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();}@Overridepublic void setFrom(String from) throws MailParseException {try {this.helper.setFrom(from);}catch (MessagingException ex) {throw new MailParseException(ex);}}@Overridepublic void setReplyTo(String replyTo) throws MailParseException {try {this.helper.setReplyTo(replyTo);}catch (MessagingException ex) {throw new MailParseException(ex);}}@Overridepublic void setTo(String to) throws MailParseException {try {this.helper.setTo(to);}catch (MessagingException ex) {throw new MailParseException(ex);}}@Overridepublic void setTo(String... to) throws MailParseException {try {this.helper.setTo(to);}catch (MessagingException ex) {throw new MailParseException(ex);}}@Overridepublic void setCc(String cc) throws MailParseException {try {this.helper.setCc(cc);}catch (MessagingException ex) {throw new MailParseException(ex);}}@Overridepublic void setCc(String... cc) throws MailParseException {try {this.helper.setCc(cc);}catch (MessagingException ex) {throw new MailParseException(ex);}}@Overridepublic void setBcc(String bcc) throws MailParseException {try {this.helper.setBcc(bcc);}catch (MessagingException ex) {throw new MailParseException(ex);}}@Overridepublic void setBcc(String... bcc) throws MailParseException {try {this.helper.setBcc(bcc);}catch (MessagingException ex) {throw new MailParseException(ex);}}@Overridepublic void setSentDate(Date sentDate) throws MailParseException {try {this.helper.setSentDate(sentDate);}catch (MessagingException ex) {throw new MailParseException(ex);}}@Overridepublic void setSubject(String subject) throws MailParseException {try {this.helper.setSubject(subject);}catch (MessagingException ex) {throw new MailParseException(ex);}}@Overridepublic 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: smtphost: smtp.qq.comdefault-encoding: UTF-8username: email-accountpassword: key/passwordproperties:mail:debug: true #开启日志打印smtp:auth: truestarttls:enable: truerequired: true

邮件发送

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

SimpleMailMessage发送

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


@Component
public class EmailSendServiceImpl implements EmailSenderService {@Autowiredprivate JavaMailSender mailSender;@Overridepublic 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: .htmlmode: HTML

邮件模板定制

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

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

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

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

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

       

 如何使用邮件模板

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

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

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

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

示例代码

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

@Component
public class EmailSendServiceImpl implements EmailSenderService {@Autowiredprivate JavaMailSender mailSender;@Autowiredprivate TemplateEngine templateEngine;@Overridepublic R sendMimeEmail(String from, String to, String subject) {//create a new JavaMail MimeMessageMimeMessage 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 paramsmimeMessageHelper.setFrom(from);mimeMessageHelper.setTo(to);mimeMessageHelper.setSubject(subject);//create html-text based on thymeleaf templateContext 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.mzph.cn/news/171575.shtml

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

相关文章

Add, Divide and Floor(cf round 158 div2)

题目&#xff1a;给你一个整数数组 a1,a2,…,an 。在一次操作中&#xff0c;你可以选择一个整数 x &#xff0c;并用 (a[i]x)/2 替换 ai ( (a[i]x)/2表示将 y(a[i]x)/2舍入为最接近的整数(下取整)。 ⌊y⌋ 表示将 y 舍入为最接近的整数&#xff09;来替换从 1 到 n 的所有 i。…

【数据分享】2019-2023年我国区县逐月新房房价数据(Excel/Shp格式)

房价是一个城市发展程度的重要体现&#xff0c;一个城市的房价越高通常代表这个城市越发达&#xff0c;对于人口的吸引力越大&#xff01;因此&#xff0c;房价数据是我们在各项城市研究中都非常常用的数据&#xff01;之前我们分享过2019-2023年我国地级市逐月房价数据&#x…

Spring Boot 项目中读取 YAML 文件中的数组、集合和 HashMap

在 Spring Boot 项目中&#xff0c;我们经常使用 YAML 文件来配置应用程序的属性。在这篇博客中&#xff0c;我将模拟如何在 Java 的 Spring Boot 项目中读取 YAML 文件中的数组、集合和 HashMap。 1. 介绍 YAML&#xff08;YAML Aint Markup Language&#xff09;是一种人类…

OpenMp并行编程

目录 介绍编译用法>OpenMp parallel>OpenMp for>OpenMp private、firstprivate、lastprivate>OpenMp section>OpenMp reduction>OpenMp single>OpenMp master>OpenMp barrier OpenMp的API函数 介绍 OpenMp是一种并行编程模型&#xff0c;旨在简化多线…

【Spring集成MyBatis】MyBatis注解开发

文章目录 1. MyBatis的常用注解2. 基于注解的MyBatis增删改查增删改查完整代码加载映射关系测试代码 3. MyBatis的注解实现复杂映射开发一对一操作的实现一对一操作实现的第二种方式一对多操作的实现多对多操作实现 1. MyBatis的常用注解 2. 基于注解的MyBatis增删改查 使用注…

Linux加强篇004-Vim编辑器与Shell命令脚本

目录 前言 1. Vim文本编辑器 1.1 编写简单文档 1.2 配置主机名称 1.3 配置网卡信息 1.4 配置软件仓库 2. 编写Shell脚本 2.1 编写简单的脚本 2.2 接收用户的参数 2.3 判断用户的参数 3. 流程控制语句 3.1 if条件测试语句 3.2 for条件循环语句 3.3 while条件循环语…

【开源】基于JAVA的高校学院网站

项目编号&#xff1a; S 020 &#xff0c;文末获取源码。 \color{red}{项目编号&#xff1a;S020&#xff0c;文末获取源码。} 项目编号&#xff1a;S020&#xff0c;文末获取源码。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 学院院系模块2.2 竞赛报名模块2.3 教…

Postman如何使用(三):使用数据文件

数据文件是非常强大的方式使用不同的测试数据来测试我们的API&#xff0c;以检查它们是否在各种情况下都能正常运行。我们可以认为数据文件是“Collection Runner”中每个请求的参数。下面&#xff0c;我们通过一个例子来说明如何使用数据文件。 这篇文章需要结合下面两个文件进…

史上最全前端知识点+高频面试题合集,十二大专题,命中率高达95%

前言&#xff1a; 下面分享一些关于阿里&#xff0c;美团&#xff0c;深信服等公司的面经&#xff0c;供大家参考一下。大家也可以去收集一些其他的面试题&#xff0c;可以通过面试题来看看自己有哪里不足。也可以了解自己想去的公司会问什么问题&#xff0c;进行有针对的复习。…

PowerShell基础

1. Tab键补全 有时候不记得指令全称&#xff0c;只记得开头几个字母&#xff0c;使用Tab键可显式建议选项&#xff0c;再次按Tab可以往后翻&#xff0c;ShiftTab可以往前翻。 2. 查看指令类型 Get-Command -Name Get-Alias 指令是遵循一定的格式规范的&#xff0c;如动词加名…

css之选择第一个或最后一个元素、第n个标签、选择偶数或奇数标签、选择最后n个标签、等差数列标签的选择、first、last、nth、child

MENU first-child选择列表中的第一个标签last-child选择列表中的最后一个标签nth-child(n)选择列表中的第n个标签nth-child(2n)选择列表中的偶数位标签nth-child(2n-1)选择列表中的奇数位标签nth-child(nm)选择从第m个到最后一个标签nth-child(-nm)选择从第1个到第m个nth-last-…

Python与设计模式--桥梁模式

11-Python与设计模式–桥梁模式 一、画笔与形状 在介绍原型模式的一节中&#xff0c;我们举了个图层的例子&#xff0c;这一小节内容&#xff0c;我们同样以类似画图的例子&#xff0c; 说明一种结构类设计模式&#xff1a;桥梁模式。 在一个画图程序中&#xff0c;常会见到这…

《数据结构与算法之美》读书笔记2

链表操作的技巧 1.理解指针 将摸个变量赋值给指针&#xff0c;实际上就是将这个变量的地址赋给指针&#xff0c;或者&#xff0c;指针中存储了这个变量的地址&#xff0c;指向了这个变量&#xff0c;所以可以通过指针找到这个变量。 2.内存泄漏或指针丢失 删除链表节点时&a…

人工智能|机器学习——循环神经网络的简洁实现

循环神经网络的简洁实现 如何使用深度学习框架的高级API提供的函数更有效地实现相同的语言模型。 我们仍然从读取时光机器数据集开始。 import torch from torch import nn from torch.nn import functional as F from d2l import torch as d2lbatch_size, num_steps 32, 35 t…

itop4412移植lrzsz工具踩坑笔记

4412开发板在传输文件一直用的都是tftp文件传输&#xff0c;但这样效率有点慢&#xff0c;平常在linux上习惯用lrzsz工具来传输文件&#xff0c;特此记录下&#xff0c;因为不熟悉linux编译 踩坑了很多地方 在操作前 我们的虚拟机要线安装好编译环境 下载lrzsz源码&#xff0…

一起学docker系列之十docker安装tomcat实践

目录 前言1 安装tomcat的步骤步骤 1: 查找并拉取 Tomcat 镜像步骤 2: 运行 Tomcat 容器步骤 3: 管理 Tomcat 容器步骤 4: 访问 Tomcat 首页 2 解决访问首页的404访问不到的问题2.1 Tomcat 10 的默认设置问题2.2 端口映射或防火墙问题 3 推荐使用 Tomcat 8.5 版本总结 前言 当安…

最轻量级最完整的屏幕适配完全适配各个手机方案

当你看到这篇博客的时候,说明你已经迈出了惊人的一步,已经慢慢进入高级资深开发工程师行列了,这是开发之路必备技能。 当你接到一个任务时,每天按照需求原型、设计师UI图立刻积极的开发完成后,满满的兴高采烈去打包提测,板凳还没做安稳,测试人员就提了一个又一个的BUG,…

【华为OD题库-037】跳房子2-java

题目 跳房子&#xff0c;也叫跳飞机&#xff0c;是一种世界性的儿童游戏游戏。参与者需要分多个回合按顺序跳到第1格直到房子的最后一格&#xff0c;然后获得一次选房子的机会&#xff0c;直到所有房子被选完&#xff0c;房子最多的人获胜。 跳房子的过程中&#xff0c;如果有踩…

【Docker】从零开始:11.Harbor搭建企业镜像仓库

【Docker】从零开始&#xff1a;11.Harbor搭建企业镜像仓库 1. Harbor介绍2. 软硬件要求(1). 硬件要求(2). 软件要求 3.Harbor优势4.Harbor的误区5.Harbor的几种安装方式6.在线安装(1).安装composer(2).配置内核参数,开启路由转发(3).下载安装包并解压(4).创建并修改配置文件(5…

element-ui DatePicker 日期选择器-控制选择精确到时分秒-禁止选择今天之前-或者今天之后日期### 前言

前言 最近在使用芋道框架时候&#xff0c;后端使用生成代码&#xff0c;时间因为类型问题&#xff0c;只能是时间戳&#xff0c;否则为空&#xff08;1970-&#xff09; 前端其实很简单只要在日期选择器把类型改成时间错即可&#xff0c;但根据业务需求需要精确到时分秒 把时…