ry-01-验证码

1.生成验证码基本思路

思路:提供接口将生成的验证码存入session或redis,将验证码以图片格式或者base64编码串返回给调用端。
存储以一个固定的KEY 例如:captcha_codes+uuid作为key 验证码的计算结果作为value

pom hutool工具类

        <!-- hutool工具类 -->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.7.12</version>
        </dependency>

先生成一个base64编码的案例

        //定义图形验证码的长、宽、验证码字符数、干扰线宽度
        ShearCaptcha shearCaptcha1 = CaptchaUtil.createShearCaptcha(150, 40, 5, 0);
        //生成的字符用作对比
        System.out.println(shearCaptcha1.getCode());
        System.out.println(shearCaptcha1.getImageBase64());
        

base64编码图片

rav01
iVBORw0KGgoAAAANSUhEUgAAAJYAAAAoCAYAAAAcwQPnAAAFd0lEQVR42u2bi09TVxzH/TeWLFu2ZDFZ4h4uy0yWZRlxuhEz4zaHzDEfGzoNG2hhiO6hM5l7CHPEIKBsMBnKBAKC49kCPqACBYQBIlCsQHkMWloE2lL8zd8h96QXSnn0HoTu901OmnPP93Luvf303N/5ncMqIJEEaBU9AhKBRSKwSAQWiURgkQgsEoFFIhFYJAKLNF/1DY9DbF4bfBijhbUHi+G5sEL2uSO2Cs7kt8PQiH1JrqNd3wEb3nmLFQJrhUvT0A8vqYrh2c8LZi0vh5cwn0iNjY9BcMheAstX1N47Ai8cKPIIllTWhBYyvwjZ7XY4/O0RDpY3cBFYy0D74nUcnHWRakjWdIL5voO1DVrt8Ju6UzaiRZ1vUPwaTGYThEaEyaAisHwgvpKgwdhqthGpqm1I5hu1ORW7hhuVFfBB0LYZYC0WLgJrGSirspsDE5Fyy6M3JLGWe//W9SrSvyoqnEO0OWALaKu04sF6suQLXlBnDRpYrVHBi+VRcKw1U+gDn3j4zq+9nA2ZR7+CmM3+8ONGP/hhwxtwctNGyPjmCDSpixXrKzvfH86mPsaKydzi0TtkbuZePM9bRf7RwGG5UmP06M2tNnLv4dRGRe5dAujgIRX0GHtkx4SOWK5waU1tsvqu+gRhYPU0N0Hs1i3wvd9rHsvFSBU8eDDpdX8tbec5MNX1Jzx6tbpj3Nt8J8XrvoPjajgwNe0mj946vZl7MR2hhHbv+xTKrpW7BW4xcC0YrHerf5HVM4w3hUA1MjjIRqm5oJKKNv2C9yPkxBj8fuEpBkta1lqPXmxHX1LaE+CYuO913698WcJhsTk8/0iw3TXYFyXhYE2H62l1GOT21YrP7yTGc3BOb3sfOh6++50TU7OlSacTOnXVkLRnN/ck79+jSL9XtSo+GvX2a916jP0V3FNeEaZIv64ph/lI8uJ5yw2uRYH13Z2sJQlq47YHcGgG9Hq3HstAP/f89PZ6Rfrt/1fHoUHI3OmaNmJO+BYq13zVQvw4Q/QJsMoGm5fVrEoC68T61xX7m5l5fgya5PRnZsRvWE9JX83aL2avU6xPTH7+r8FyTDofGUTjVivU5eawWSGOUNNjLaXU2JLIRyS94bKszdBdxNvq/4lVrE9cG1wMWHjeigXLXephKdVWeQMufR3FUg3TYcI0hAi4bDYTC84RoKKynfL47/p+dvzcn4/D6FifYn2+ekjjE0H8igAr+/hRGTg/+7/JRqzbV8t5MC8CLFeAEDCbfXhq4jDp4MAVlAYp2p/r8k5Lt9Wj99bdYe795HQ1gbUQVWX8JctXmbq7Z3gw5hEFlrHvOn/tYZ6LjZ76S/zY3Xv5ivaHSU8JloJaz5l1zLyLXD/0abASdn7EgcH4yp26GhuEgYXCAB0hulKyldXz1YGsnpqxRpHE7GJhwXbJi8tCKxasRwUXzvYkaEbN5hntuPSTEvKZDC6lv/C6xlM8prJYO9kn1m/WHlf8fnFTnzRDxBlfo2F41leh60wSF7OXC1wrAizXDHxa+AEYNBimYh2nk8VZ54J3zQjoHTZlHzIG6BJMecXv8VfhsKVDyD2HJtXJNvnhVhppFyluqcE6Hpc8e8/UCP0OfBKsglPR817akYqhvk7x6ygs/ZgDhSWnYJOwe27tsc5r45+UeRe1+c+nwRqzWCA+KHBWiPBVqcvOksVjWFdarvkrLLfb04Ted0ZF15w7S3HUKm8aEP4d+CRYKAzcNQlxkLBjO9s6gwVBKvw1Boa67jFPc6mag4Uxl9LCuC0183kGFS5WO5024ffdaxqH6JxWCDhZyROo+BkYrWX/fDFgsS3J8xcOFolEYJEILBKBRSIRWCQCi0RgkUgEFonAIvmK/gOB1MzDx4L9UAAAAABJRU5ErkJggg==

2.ry案例生成验证码思路

代码解读

验证码操作处理类

/**
 * 验证码操作处理
 *
 * @author Lion Li
 */
@SaIgnore
@Slf4j
@Validated
@RequiredArgsConstructor
@RestController
public class CaptchaController {

    private final CaptchaProperties captchaProperties;
    private final ISysConfigService configService;
    private final MailProperties mailProperties;

    /**
     * 短信验证码
     *
     * @param phonenumber 用户手机号
     */
    @GetMapping("/captchaSms")
    public R<Void> smsCaptcha(@NotBlank(message = "{user.phonenumber.not.blank}") String phonenumber) {
        String key = CacheConstants.CAPTCHA_CODE_KEY + phonenumber;
        String code = RandomUtil.randomNumbers(4);
        RedisUtils.setCacheObject(key, code, Duration.ofMinutes(Constants.CAPTCHA_EXPIRATION));
        // 验证码模板id 自行处理 (查数据库或写死均可)
        String templateId = "";
        LinkedHashMap<String, String> map = new LinkedHashMap<>(1);
        map.put("code", code);
        SmsBlend smsBlend = SmsFactory.createSmsBlend(SupplierType.ALIBABA);
        SmsResponse smsResponse = smsBlend.sendMessage(phonenumber, templateId, map);
        if (!"OK".equals(smsResponse.getCode())) {
            log.error("验证码短信发送异常 => {}", smsResponse);
            return R.fail(smsResponse.getMessage());
        }
        return R.ok();
    }

    /**
     * 邮箱验证码
     *
     * @param email 邮箱
     */
    @GetMapping("/captchaEmail")
    public R<Void> emailCode(@NotBlank(message = "{user.email.not.blank}") String email) {
        if (!mailProperties.getEnabled()) {
            return R.fail("当前系统没有开启邮箱功能!");
        }
        String key = CacheConstants.CAPTCHA_CODE_KEY + email;
        String code = RandomUtil.randomNumbers(4);
        RedisUtils.setCacheObject(key, code, Duration.ofMinutes(Constants.CAPTCHA_EXPIRATION));
        try {
            MailUtils.sendText(email, "登录验证码", "您本次验证码为:" + code + ",有效性为" + Constants.CAPTCHA_EXPIRATION + "分钟,请尽快填写。");
        } catch (Exception e) {
            log.error("验证码短信发送异常 => {}", e.getMessage());
            return R.fail(e.getMessage());
        }
        return R.ok();
    }

    /**
     * 生成验证码
     */
    @GetMapping("/captchaImage")
    public R<Map<String, Object>> getCode() {
        Map<String, Object> ajax = new HashMap<>();

        //applicalyion 中配置例如captcha: spring初始化时候 将类CaptchaProperties 生成Bean
        boolean captchaEnabled = configService.selectCaptchaEnabled();
        ajax.put("captchaEnabled", captchaEnabled);
        if (!captchaEnabled) {
            return R.ok(ajax);
        }
        // 保存验证码信息
        String uuid = IdUtil.simpleUUID();
        String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + uuid;

        CaptchaType captchaType = captchaProperties.getType();
        //获取验证码类型
        boolean isMath = CaptchaType.MATH == captchaType;
        //获取验证码长度
        Integer length = isMath ? captchaProperties.getNumberLength() : captchaProperties.getCharLength();
        // CodeGenerator 反射生成验证码生成器
        CodeGenerator codeGenerator = ReflectUtils.newInstance(captchaType.getClazz(), length);

        AbstractCaptcha captcha = SpringUtils.getBean(captchaProperties.getCategory().getClazz());

        captcha.setGenerator(codeGenerator);
        captcha.createCode();
        String code = captcha.getCode();
        if (isMath) {
            ExpressionParser parser = new SpelExpressionParser();
            Expression exp = parser.parseExpression(StringUtils.remove(code, "="));
            code = exp.getValue(String.class);
        }
        RedisUtils.setCacheObject(verifyKey, code, Duration.ofMinutes(Constants.CAPTCHA_EXPIRATION));
        ajax.put("uuid", uuid);
        ajax.put("img", captcha.getImageBase64());
        return R.ok(ajax);
    }

}
2.1 从缓存中读取是否开启的验证码认证

@Cacheable(cacheNames = CacheNames.SYS_CONFIG, key = “#configKey”)
在缓存(可以是Redis也可以是Spring的缓存)中查找NAME为 CacheNames.SYS_CONFIG 的MAP再用EL表达式找 MAP的key为 #configKey 的VALUE

  Controller
  boolean captchaEnabled = configService.selectCaptchaEnabled();
  
  ServiceImpl
    /**
     * 获取验证码开关
     *
     * @return true开启,false关闭
     */
    @Override
    public boolean selectCaptchaEnabled() {
        String captchaEnabled = SpringUtils.getAopProxy(this).selectConfigByKey("sys.account.captchaEnabled");
        if (StringUtils.isEmpty(captchaEnabled)) {
            return true;
        }
        return Convert.toBool(captchaEnabled);
    }

    /**
     * 根据键名查询参数配置信息
     *
     * @param configKey 参数key
     * @return 参数键值
     */
    @Cacheable(cacheNames = CacheNames.SYS_CONFIG, key = "#configKey")
    @Override
    public String selectConfigByKey(String configKey) {
        SysConfig retConfig = baseMapper.selectOne(new LambdaQueryWrapper<SysConfig>().eq(SysConfig::getConfigKey, configKey));
        if (ObjectUtil.isNotNull(retConfig)) {
            return retConfig.getConfigValue();
        }
        return StringUtils.EMPTY;
    }
2.2 生成redis验证码KEY
        // 保存验证码信息
        String uuid = IdUtil.simpleUUID();
        String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + uuid;
2.3配置类中获取验证码配置

yaml 为了可随意切换验证码类型和干扰类型

captcha:
  # 页面 <参数设置> 可开启关闭 验证码校验
  # 验证码类型 math 数组计算 char 字符验证
  type: MATH
  # line 线段干扰 circle 圆圈干扰 shear 扭曲干扰
  category: CIRCLE
  # 数字验证码位数
  numberLength: 1
  # 字符验证码长度
  charLength: 4

配置类 CaptchaProperties.java 获取yaml中的配置

/**
* 验证码 配置属性
*
* @author Lion Li
*/
@Data
@Component
@ConfigurationProperties(prefix = "captcha")
public class CaptchaProperties {

  /**
   * 验证码类型
   */
  private CaptchaType type;

  /**
   * 验证码类别
   */
  private CaptchaCategory category;

  /**
   * 数字验证码位数
   */
  private Integer numberLength;

  /**
   * 字符验证码长度
   */
  private Integer charLength;
}

枚举类 CaptchaType (验证码类型)CaptchaCategory (验证码类别)

/**
 * 验证码类型
 *
 * @author Lion Li
 */
@Getter
@AllArgsConstructor
public enum CaptchaType {

    /**
     * 数字验证码
     */
    MATH(UnsignedMathGenerator.class),

    /**
     * 字符验证码
     */
    CHAR(RandomGenerator.class);

    private final Class<? extends CodeGenerator> clazz;
}
2.4拿到验证码配置信息
        CaptchaType captchaType = captchaProperties.getType();
        //获取验证码类型
        boolean isMath = CaptchaType.MATH == captchaType;
        //获取验证码长度
        Integer length = isMath ? captchaProperties.getNumberLength() : captchaProperties.getCharLength();
2.5 通过反射生成,字符或者数字的验证码文字生成器 (CodeGenerator)
       /**
        * 验证码类别
       */
        private CaptchaCategory category;


        CodeGenerator codeGenerator = ReflectUtils.newInstance(captchaType.getClazz(), length);
        //通过条码干扰的bena类型 动态获取抽象验证码的基本属性
        AbstractCaptcha captcha = SpringUtils.getBean(captchaProperties.getCategory().getClazz());
SpringUtils.getBean(captchaProperties.getCategory().getClazz()) 通过类型拿到干扰验证码配置类
/**
 * 验证码配置
 *
 * @author Lion Li
 */
@Configuration
public class CaptchaConfig {

    private static final int WIDTH = 160;
    private static final int HEIGHT = 60;
    private static final Color BACKGROUND = Color.PINK;
    private static final Font FONT = new Font("Arial", Font.BOLD, 48);

    /**
     * 圆圈干扰验证码
     */
    @Lazy
    @Bean
    public CircleCaptcha circleCaptcha() {
        CircleCaptcha captcha = CaptchaUtil.createCircleCaptcha(WIDTH, HEIGHT);
        captcha.setBackground(BACKGROUND);
        captcha.setFont(FONT);
        return captcha;
    }

    /**
     * 线段干扰的验证码
     */
    @Lazy
    @Bean
    public LineCaptcha lineCaptcha() {
        LineCaptcha captcha = CaptchaUtil.createLineCaptcha(WIDTH, HEIGHT);
        captcha.setBackground(BACKGROUND);
        captcha.setFont(FONT);
        return captcha;
    }

    /**
     * 扭曲干扰验证码
     */
    @Lazy
    @Bean
    public ShearCaptcha shearCaptcha() {
        ShearCaptcha captcha = CaptchaUtil.createShearCaptcha(WIDTH, HEIGHT);
        captcha.setBackground(BACKGROUND);
        captcha.setFont(FONT);
        return captcha;
    }
}
2.6 生成验证码保存到redis 返回UUID
        //通过条码干扰的bena类型 动态获取抽象验证码的基本属性
        AbstractCaptcha captcha = SpringUtils.getBean(captchaProperties.getCategory().getClazz());

        captcha.setGenerator(codeGenerator);
        captcha.createCode();
        String code = captcha.getCode();
        if (isMath) {
            ExpressionParser parser = new SpelExpressionParser();
            Expression exp = parser.parseExpression(StringUtils.remove(code, "="));
            code = exp.getValue(String.class);
        }
    
        RedisUtils.setCacheObject(verifyKey, code, Duration.ofMinutes(Constants.CAPTCHA_EXPIRATION));
        ajax.put("uuid", uuid);
        ajax.put("img", captcha.getImageBase64());
        return R.ok(ajax);

3.验证码登录 Redis获取保存的code比较值是否相同

    /**
  * 校验验证码
  *
  * @param username 用户名
  * @param code     验证码
  * @param uuid     唯一标识
  */
 public void validateCaptcha(String username, String code, String uuid) {
     String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + StringUtils.defaultString(uuid, "");
     String captcha = RedisUtils.getCacheObject(verifyKey);
     RedisUtils.deleteObject(verifyKey);
     if (captcha == null) {
         recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire"));
         throw new CaptchaExpireException();
     }
     if (!code.equalsIgnoreCase(captcha)) {
         recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error"));
         throw new CaptchaException();
     }
 }

4.邮箱验证码登录(注册)

4.1邮箱配置,验证码发送,验证码保存Redis

yaml配置邮箱

--- # mail 邮件发送
mail:
enabled: true
host: smtp.qq.com
port: 465
# 是否需要用户名密码验证
auth: true
# 发送方,遵循RFC-822标准
from: work.****@qq.com
# 用户名(注意:如果使用foxmail邮箱,此处user为qq号)
user: work.****@qq.com
# 密码(注意,某些邮箱需要为SMTP服务单独设置密码,详情查看相关帮助)
pass: abcedfg
# 使用 STARTTLS安全连接,STARTTLS是对纯文本通信协议的扩展。
starttlsEnable: true
# 使用SSL安全连接
sslEnable: true
# SMTP超时时长,单位毫秒,缺省值不超时
timeout: 0
# Socket连接超时值,单位毫秒,缺省值不超时
connectionTimeout: 0

初始化将参数加载到配置类中

/**
* JavaMail 配置属性
*
* @author Michelle.Chung
*/
@Data
@Component
@ConfigurationProperties(prefix = "mail")
public class MailProperties {

   /**
    * 过滤开关
    */
   private Boolean enabled;

   /**
    * SMTP服务器域名
    */
   private String host;

   /**
    * SMTP服务端口
    */
   private Integer port;

   /**
    * 是否需要用户名密码验证
    */
   private Boolean auth;

   /**
    * 用户名
    */
   private String user;

   /**
    * 密码
    */
   private String pass;

   /**
    * 发送方,遵循RFC-822标准
    */
   private String from;

   /**
    * 使用 STARTTLS安全连接,STARTTLS是对纯文本通信协议的扩展。它将纯文本连接升级为加密连接(TLS或SSL), 而不是使用一个单独的加密通信端口。
    */
   private Boolean starttlsEnable;

   /**
    * 使用 SSL安全连接
    */
   private Boolean sslEnable;

   /**
    * SMTP超时时长,单位毫秒,缺省值不超时
    */
   private Long timeout;

   /**
    * Socket连接超时值,单位毫秒,缺省值不超时
    */
   private Long connectionTimeout;
}

发送验证码

    /**
   * 邮箱验证码
   *
   * @param email 邮箱
   */
  @GetMapping("/captchaEmail")
  public R<Void> emailCode(@NotBlank(message = "{user.email.not.blank}") String email) {
      if (!mailProperties.getEnabled()) {
          return R.fail("当前系统没有开启邮箱功能!");
      }
      String key = CacheConstants.CAPTCHA_CODE_KEY + email;
      String code = RandomUtil.randomNumbers(4);
      RedisUtils.setCacheObject(key, code, Duration.ofMinutes(Constants.CAPTCHA_EXPIRATION));
      try {
          MailUtils.sendText(email, "登录验证码", "您本次验证码为:" + code + ",有效性为" + Constants.CAPTCHA_EXPIRATION + "分钟,请尽快填写。");
      } catch (Exception e) {
          log.error("验证码短信发送异常 => {}", e.getMessage());
          return R.fail(e.getMessage());
      }
      return R.ok();
  }

邮箱工具类

/**
* 邮件工具类
*/
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class MailUtils {

  private static final MailAccount ACCOUNT = SpringUtils.getBean(MailAccount.class);

  /**
   * 获取邮件发送实例
   */
  public static MailAccount getMailAccount() {
      return ACCOUNT;
  }

  /**
   * 获取邮件发送实例 (自定义发送人以及授权码)
   *
   * @param user 发送人
   * @param pass 授权码
   */
  public static MailAccount getMailAccount(String from, String user, String pass) {
      ACCOUNT.setFrom(StringUtils.blankToDefault(from, ACCOUNT.getFrom()));
      ACCOUNT.setUser(StringUtils.blankToDefault(user, ACCOUNT.getUser()));
      ACCOUNT.setPass(StringUtils.blankToDefault(pass, ACCOUNT.getPass()));
      return ACCOUNT;
  }

  /**
   * 使用配置文件中设置的账户发送文本邮件,发送给单个或多个收件人<br>
   * 多个收件人可以使用逗号“,”分隔,也可以通过分号“;”分隔
   *
   * @param to      收件人
   * @param subject 标题
   * @param content 正文
   * @param files   附件列表
   * @return message-id
   * @since 3.2.0
   */
  public static String sendText(String to, String subject, String content, File... files) {
      return send(to, subject, content, false, files);
  }

  /**
   * 使用配置文件中设置的账户发送HTML邮件,发送给单个或多个收件人<br>
   * 多个收件人可以使用逗号“,”分隔,也可以通过分号“;”分隔
   *
   * @param to      收件人
   * @param subject 标题
   * @param content 正文
   * @param files   附件列表
   * @return message-id
   * @since 3.2.0
   */
  public static String sendHtml(String to, String subject, String content, File... files) {
      return send(to, subject, content, true, files);
  }

  /**
   * 使用配置文件中设置的账户发送邮件,发送单个或多个收件人<br>
   * 多个收件人可以使用逗号“,”分隔,也可以通过分号“;”分隔
   *
   * @param to      收件人
   * @param subject 标题
   * @param content 正文
   * @param isHtml  是否为HTML
   * @param files   附件列表
   * @return message-id
   */
  public static String send(String to, String subject, String content, boolean isHtml, File... files) {
      return send(splitAddress(to), subject, content, isHtml, files);
  }

  /**
   * 使用配置文件中设置的账户发送邮件,发送单个或多个收件人<br>
   * 多个收件人、抄送人、密送人可以使用逗号“,”分隔,也可以通过分号“;”分隔
   *
   * @param to      收件人,可以使用逗号“,”分隔,也可以通过分号“;”分隔
   * @param cc      抄送人,可以使用逗号“,”分隔,也可以通过分号“;”分隔
   * @param bcc     密送人,可以使用逗号“,”分隔,也可以通过分号“;”分隔
   * @param subject 标题
   * @param content 正文
   * @param isHtml  是否为HTML
   * @param files   附件列表
   * @return message-id
   * @since 4.0.3
   */
  public static String send(String to, String cc, String bcc, String subject, String content, boolean isHtml, File... files) {
      return send(splitAddress(to), splitAddress(cc), splitAddress(bcc), subject, content, isHtml, files);
  }

  /**
   * 使用配置文件中设置的账户发送文本邮件,发送给多人
   *
   * @param tos     收件人列表
   * @param subject 标题
   * @param content 正文
   * @param files   附件列表
   * @return message-id
   */
  public static String sendText(Collection<String> tos, String subject, String content, File... files) {
      return send(tos, subject, content, false, files);
  }

  /**
   * 使用配置文件中设置的账户发送HTML邮件,发送给多人
   *
   * @param tos     收件人列表
   * @param subject 标题
   * @param content 正文
   * @param files   附件列表
   * @return message-id
   * @since 3.2.0
   */
  public static String sendHtml(Collection<String> tos, String subject, String content, File... files) {
      return send(tos, subject, content, true, files);
  }

  /**
   * 使用配置文件中设置的账户发送邮件,发送给多人
   *
   * @param tos     收件人列表
   * @param subject 标题
   * @param content 正文
   * @param isHtml  是否为HTML
   * @param files   附件列表
   * @return message-id
   */
  public static String send(Collection<String> tos, String subject, String content, boolean isHtml, File... files) {
      return send(tos, null, null, subject, content, isHtml, files);
  }

  /**
   * 使用配置文件中设置的账户发送邮件,发送给多人
   *
   * @param tos     收件人列表
   * @param ccs     抄送人列表,可以为null或空
   * @param bccs    密送人列表,可以为null或空
   * @param subject 标题
   * @param content 正文
   * @param isHtml  是否为HTML
   * @param files   附件列表
   * @return message-id
   * @since 4.0.3
   */
  public static String send(Collection<String> tos, Collection<String> ccs, Collection<String> bccs, String subject, String content, boolean isHtml, File... files) {
      return send(getMailAccount(), true, tos, ccs, bccs, subject, content, null, isHtml, files);
  }

  // ------------------------------------------------------------------------------------------------------------------------------- Custom MailAccount

  /**
   * 发送邮件给多人
   *
   * @param mailAccount 邮件认证对象
   * @param to          收件人,多个收件人逗号或者分号隔开
   * @param subject     标题
   * @param content     正文
   * @param isHtml      是否为HTML格式
   * @param files       附件列表
   * @return message-id
   * @since 3.2.0
   */
  public static String send(MailAccount mailAccount, String to, String subject, String content, boolean isHtml, File... files) {
      return send(mailAccount, splitAddress(to), subject, content, isHtml, files);
  }

  /**
   * 发送邮件给多人
   *
   * @param mailAccount 邮件帐户信息
   * @param tos         收件人列表
   * @param subject     标题
   * @param content     正文
   * @param isHtml      是否为HTML格式
   * @param files       附件列表
   * @return message-id
   */
  public static String send(MailAccount mailAccount, Collection<String> tos, String subject, String content, boolean isHtml, File... files) {
      return send(mailAccount, tos, null, null, subject, content, isHtml, files);
  }

  /**
   * 发送邮件给多人
   *
   * @param mailAccount 邮件帐户信息
   * @param tos         收件人列表
   * @param ccs         抄送人列表,可以为null或空
   * @param bccs        密送人列表,可以为null或空
   * @param subject     标题
   * @param content     正文
   * @param isHtml      是否为HTML格式
   * @param files       附件列表
   * @return message-id
   * @since 4.0.3
   */
  public static String send(MailAccount mailAccount, Collection<String> tos, Collection<String> ccs, Collection<String> bccs, String subject, String content, boolean isHtml, File... files) {
      return send(mailAccount, false, tos, ccs, bccs, subject, content, null, isHtml, files);
  }

  /**
   * 使用配置文件中设置的账户发送HTML邮件,发送给单个或多个收件人<br>
   * 多个收件人可以使用逗号“,”分隔,也可以通过分号“;”分隔
   *
   * @param to       收件人
   * @param subject  标题
   * @param content  正文
   * @param imageMap 图片与占位符,占位符格式为cid:$IMAGE_PLACEHOLDER
   * @param files    附件列表
   * @return message-id
   * @since 3.2.0
   */
  public static String sendHtml(String to, String subject, String content, Map<String, InputStream> imageMap, File... files) {
      return send(to, subject, content, imageMap, true, files);
  }

  /**
   * 使用配置文件中设置的账户发送邮件,发送单个或多个收件人<br>
   * 多个收件人可以使用逗号“,”分隔,也可以通过分号“;”分隔
   *
   * @param to       收件人
   * @param subject  标题
   * @param content  正文
   * @param imageMap 图片与占位符,占位符格式为cid:$IMAGE_PLACEHOLDER
   * @param isHtml   是否为HTML
   * @param files    附件列表
   * @return message-id
   */
  public static String send(String to, String subject, String content, Map<String, InputStream> imageMap, boolean isHtml, File... files) {
      return send(splitAddress(to), subject, content, imageMap, isHtml, files);
  }

  /**
   * 使用配置文件中设置的账户发送邮件,发送单个或多个收件人<br>
   * 多个收件人、抄送人、密送人可以使用逗号“,”分隔,也可以通过分号“;”分隔
   *
   * @param to       收件人,可以使用逗号“,”分隔,也可以通过分号“;”分隔
   * @param cc       抄送人,可以使用逗号“,”分隔,也可以通过分号“;”分隔
   * @param bcc      密送人,可以使用逗号“,”分隔,也可以通过分号“;”分隔
   * @param subject  标题
   * @param content  正文
   * @param imageMap 图片与占位符,占位符格式为cid:$IMAGE_PLACEHOLDER
   * @param isHtml   是否为HTML
   * @param files    附件列表
   * @return message-id
   * @since 4.0.3
   */
  public static String send(String to, String cc, String bcc, String subject, String content, Map<String, InputStream> imageMap, boolean isHtml, File... files) {
      return send(splitAddress(to), splitAddress(cc), splitAddress(bcc), subject, content, imageMap, isHtml, files);
  }

  /**
   * 使用配置文件中设置的账户发送HTML邮件,发送给多人
   *
   * @param tos      收件人列表
   * @param subject  标题
   * @param content  正文
   * @param imageMap 图片与占位符,占位符格式为cid:$IMAGE_PLACEHOLDER
   * @param files    附件列表
   * @return message-id
   * @since 3.2.0
   */
  public static String sendHtml(Collection<String> tos, String subject, String content, Map<String, InputStream> imageMap, File... files) {
      return send(tos, subject, content, imageMap, true, files);
  }

  /**
   * 使用配置文件中设置的账户发送邮件,发送给多人
   *
   * @param tos      收件人列表
   * @param subject  标题
   * @param content  正文
   * @param imageMap 图片与占位符,占位符格式为cid:$IMAGE_PLACEHOLDER
   * @param isHtml   是否为HTML
   * @param files    附件列表
   * @return message-id
   */
  public static String send(Collection<String> tos, String subject, String content, Map<String, InputStream> imageMap, boolean isHtml, File... files) {
      return send(tos, null, null, subject, content, imageMap, isHtml, files);
  }

  /**
   * 使用配置文件中设置的账户发送邮件,发送给多人
   *
   * @param tos      收件人列表
   * @param ccs      抄送人列表,可以为null或空
   * @param bccs     密送人列表,可以为null或空
   * @param subject  标题
   * @param content  正文
   * @param imageMap 图片与占位符,占位符格式为cid:$IMAGE_PLACEHOLDER
   * @param isHtml   是否为HTML
   * @param files    附件列表
   * @return message-id
   * @since 4.0.3
   */
  public static String send(Collection<String> tos, Collection<String> ccs, Collection<String> bccs, String subject, String content, Map<String, InputStream> imageMap, boolean isHtml, File... files) {
      return send(getMailAccount(), true, tos, ccs, bccs, subject, content, imageMap, isHtml, files);
  }

  // ------------------------------------------------------------------------------------------------------------------------------- Custom MailAccount

  /**
   * 发送邮件给多人
   *
   * @param mailAccount 邮件认证对象
   * @param to          收件人,多个收件人逗号或者分号隔开
   * @param subject     标题
   * @param content     正文
   * @param imageMap    图片与占位符,占位符格式为cid:$IMAGE_PLACEHOLDER
   * @param isHtml      是否为HTML格式
   * @param files       附件列表
   * @return message-id
   * @since 3.2.0
   */
  public static String send(MailAccount mailAccount, String to, String subject, String content, Map<String, InputStream> imageMap, boolean isHtml, File... files) {
      return send(mailAccount, splitAddress(to), subject, content, imageMap, isHtml, files);
  }

  /**
   * 发送邮件给多人
   *
   * @param mailAccount 邮件帐户信息
   * @param tos         收件人列表
   * @param subject     标题
   * @param content     正文
   * @param imageMap    图片与占位符,占位符格式为cid:$IMAGE_PLACEHOLDER
   * @param isHtml      是否为HTML格式
   * @param files       附件列表
   * @return message-id
   * @since 4.6.3
   */
  public static String send(MailAccount mailAccount, Collection<String> tos, String subject, String content, Map<String, InputStream> imageMap, boolean isHtml, File... files) {
      return send(mailAccount, tos, null, null, subject, content, imageMap, isHtml, files);
  }

  /**
   * 发送邮件给多人
   *
   * @param mailAccount 邮件帐户信息
   * @param tos         收件人列表
   * @param ccs         抄送人列表,可以为null或空
   * @param bccs        密送人列表,可以为null或空
   * @param subject     标题
   * @param content     正文
   * @param imageMap    图片与占位符,占位符格式为cid:$IMAGE_PLACEHOLDER
   * @param isHtml      是否为HTML格式
   * @param files       附件列表
   * @return message-id
   * @since 4.6.3
   */
  public static String send(MailAccount mailAccount, Collection<String> tos, Collection<String> ccs, Collection<String> bccs, String subject, String content, Map<String, InputStream> imageMap,
                            boolean isHtml, File... files) {
      return send(mailAccount, false, tos, ccs, bccs, subject, content, imageMap, isHtml, files);
  }

  /**
   * 根据配置文件,获取邮件客户端会话
   *
   * @param mailAccount 邮件账户配置
   * @param isSingleton 是否单例(全局共享会话)
   * @return {@link Session}
   * @since 5.5.7
   */
  public static Session getSession(MailAccount mailAccount, boolean isSingleton) {
      Authenticator authenticator = null;
      if (mailAccount.isAuth()) {
          authenticator = new UserPassAuthenticator(mailAccount.getUser(), mailAccount.getPass());
      }

      return isSingleton ? Session.getDefaultInstance(mailAccount.getSmtpProps(), authenticator) //
          : Session.getInstance(mailAccount.getSmtpProps(), authenticator);
  }

  // ------------------------------------------------------------------------------------------------------------------------ Private method start

  /**
   * 发送邮件给多人
   *
   * @param mailAccount      邮件帐户信息
   * @param useGlobalSession 是否全局共享Session
   * @param tos              收件人列表
   * @param ccs              抄送人列表,可以为null或空
   * @param bccs             密送人列表,可以为null或空
   * @param subject          标题
   * @param content          正文
   * @param imageMap         图片与占位符,占位符格式为cid:${cid}
   * @param isHtml           是否为HTML格式
   * @param files            附件列表
   * @return message-id
   * @since 4.6.3
   */
  private static String send(MailAccount mailAccount, boolean useGlobalSession, Collection<String> tos, Collection<String> ccs, Collection<String> bccs, String subject, String content,
                             Map<String, InputStream> imageMap, boolean isHtml, File... files) {
      final Mail mail = Mail.create(mailAccount).setUseGlobalSession(useGlobalSession);

      // 可选抄送人
      if (CollUtil.isNotEmpty(ccs)) {
          mail.setCcs(ccs.toArray(new String[0]));
      }
      // 可选密送人
      if (CollUtil.isNotEmpty(bccs)) {
          mail.setBccs(bccs.toArray(new String[0]));
      }

      mail.setTos(tos.toArray(new String[0]));
      mail.setTitle(subject);
      mail.setContent(content);
      mail.setHtml(isHtml);
      mail.setFiles(files);

      // 图片
      if (MapUtil.isNotEmpty(imageMap)) {
          for (Map.Entry<String, InputStream> entry : imageMap.entrySet()) {
              mail.addImage(entry.getKey(), entry.getValue());
              // 关闭流
              IoUtil.close(entry.getValue());
          }
      }

      return mail.send();
  }

  /**
   * 将多个联系人转为列表,分隔符为逗号或者分号
   *
   * @param addresses 多个联系人,如果为空返回null
   * @return 联系人列表
   */
  private static List<String> splitAddress(String addresses) {
      if (StrUtil.isBlank(addresses)) {
          return null;
      }

      List<String> result;
      if (StrUtil.contains(addresses, CharUtil.COMMA)) {
          result = StrUtil.splitTrim(addresses, CharUtil.COMMA);
      } else if (StrUtil.contains(addresses, ';')) {
          result = StrUtil.splitTrim(addresses, ';');
      } else {
          result = CollUtil.newArrayList(addresses);
      }
      return result;
  }
  // ------------------------------------------------------------------------------------------------------------------------ Private method end

}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值