SpringCloud微服务实战——搭建企业级开发框架(四十三):多租户可设置的

源代码 2024-9-10 03:53:57 26 0 来自 中国
  在一样寻常生存中,邮件已经被聊天软件、短信等更便捷的信息传送方式取代。但在一样寻常工作中,我们的紧张的信息关照等非常有须要去归档追溯,那么邮件就是不可或缺的信息传送渠道。对于我们工作中经常用到的体系,内里也根本都集成了邮件发送功能。
  SpringBoot提供了基于JavaMail的starter,我们只要按照官方的阐明设置邮件服务器信息,即可使我们的体系拥有发送电子邮件的功能。但是,在我们GitEgg开发框架的实际业务开发过程中,有两个标题须要办理:一个是SpringBoot邮箱服务器的设置是设置在设置文件中的,不支持机动的界面设置。别的一个是我们的开发框架须要支持多租户,那么此时须要对SpringBoot提供的邮件发送功能举行扩展,以满意我们的需求。
那么,基于以上需求和标题,我们对GitEgg框架举行扩展,增长以下功能:
1、扩展体系设置:将邮箱服务器的设置信息长期化到数据库、Redis缓存,和设置文件一起使用,订定读取优先级。

2、扩展多租户设置:假如体系开启了多租户功能,那么在邮件发送时,起首读取租户的当前设置,假如没有设置,那么在读取体系设置。

3、自有选择服务器:用户可在体系界面上选择指定的邮箱服务器举行邮件发送。

4、提供邮件发送模板:用户可选择预先订定的邮件模板举行发送特定邮件。

5、增长发送数目、频率限定:增长设置,限定模板邮件的发送数目和频率。

6、生存邮件发送记载:不愿定把全部附件都生存,只需生存邮件发送关键信息,假如须要生存全部附件等须要自己扩展。

  同一个租户可以设置多个电子邮件服务器,但只可以设置一个服务器为启用状态。默认环境下,体系关照类的功能只使用启用状态的服务器举行邮件发送。在有定制化需求的环境下,好比从页面直接指定某个服务器举行邮件发送,那么提供可以选择的接口,指定某个服务器举行邮件发送。
一、集成spring-boot-starter-mail扩展根本邮件发送功能

1、在根本框架gitegg-platform中新建gitegg-platform-mail子项目,引入邮件必须的相干依赖包。

    <dependencies>        <!-- gitegg Spring Boot自界说及扩展 -->        <dependency>            <groupId>com.gitegg.platform</groupId>            <artifactId>gitegg-platform-boot</artifactId>        </dependency>        <dependency>            <groupId>org.springframework.boot</groupId>            <artifactId>spring-boot-configuration-processor</artifactId>            <optional>true</optional>        </dependency>        <dependency>            <groupId>org.springframework.boot</groupId>            <artifactId>spring-boot-starter-mail</artifactId>            <!-- 去除springboot默认的logback设置-->            <exclusions>                <exclusion>                    <groupId>org.springframework.boot</groupId>                    <artifactId>spring-boot-starter-logging</artifactId>                </exclusion>            </exclusions>        </dependency>    </dependencies>2、扩展邮件服务器设置类,增长租户等信息,方便从缓存读取到信息之后举行设置转换。

@Data@JsonIgnoreProperties(ignoreUnknown = true)public class GitEggMailProperties extends MailProperties {    /**     * 设置id     */    private Long id;    /**     * 租户id     */    private Long tenantId;    /**     * 渠道id     */    private String channelCode;    /**     * 状态     */    private Integer channelStatus;    /**     * 设置的md5值     */    private String md5;}3、扩展邮件发送实现类JavaMailSenderImpl,添加多租户和邮箱服务器编码,便于多租户和渠道选择。

@Datapublic class GitEggJavaMailSenderImpl extends JavaMailSenderImpl {    /**     * 设置id     */    private Long id;    /**     * 租户id     */    private Long tenantId;    /**     * 渠道编码     */    private String channelCode;    /**     * 设置的md5值     */    private String md5;}4、新建邮件发送实例工厂类JavaMailSenderFactory,在邮件发送时,根据需求生产须要的邮件发送实例。

@Slf4jpublic class JavaMailSenderFactory {    private RedisTemplate redisTemplate;    private JavaMailSenderImpl javaMailSenderImpl;    /**     * 是否开启租户模式     */    private Boolean enable;    /**     * JavaMailSender 缓存     * 只管存在多个微服务,但是只须要在每个微服务初始化一次即可     */    private final static Map<String, GitEggJavaMailSenderImpl> javaMailSenderMap = new ConcurrentHashMap<>();    public JavaMailSenderFactory(RedisTemplate redisTemplate, JavaMailSenderImpl javaMailSenderImpl, Boolean enable) {        this.redisTemplate = redisTemplate;        this.javaMailSenderImpl = javaMailSenderImpl;        this.enable = enable;    }    /**     * 指定邮件发送渠道     * @return     */    public JavaMailSenderImpl getMailSender(String... channelCode){        if (null == channelCode || channelCode.length == GitEggConstant.COUNT_ZERO                || null == channelCode[GitEggConstant.Number.ZERO])        {            return this.getDefaultMailSender();        }        // 起首判定是否开启多租户        String mailConfigKey = JavaMailConstant.MAIL_TENANT_CONFIG_KEY;        if (enable) {            mailConfigKey += GitEggAuthUtils.getTenantId();        } else {            mailConfigKey = JavaMailConstant.MAIL_CONFIG_KEY;        }        // 从缓存获取邮件设置信息        // 根据channel code获取设置,用channel code时,不区分是否是默认设置        String propertiesStr = (String) redisTemplate.opsForHash().get(mailConfigKey, channelCode[GitEggConstant.Number.ZERO]);        if (StringUtils.isEmpty(propertiesStr))        {            throw new BusinessException("未获取到[" + channelCode[GitEggConstant.Number.ZERO] + "]的邮件设置信息");        }        GitEggMailProperties properties = null;        try {            properties = JsonUtils.jsonToPojo(propertiesStr, GitEggMailProperties.class);        } catch (Exception e) {            log.error("转换邮件设置信息非常:{}", e);            throw new BusinessException("转换邮件设置信息非常:" + e);        }        return this.getMailSender(mailConfigKey, properties);    }    /**     * 不指定邮件发送渠道,取默认设置     * @return     */    public JavaMailSenderImpl getDefaultMailSender(){        // 起首判定是否开启多租户        String mailConfigKey = JavaMailConstant.MAIL_TENANT_CONFIG_KEY;        if (enable) {            mailConfigKey += GitEggAuthUtils.getTenantId();        } else {            mailConfigKey = JavaMailConstant.MAIL_CONFIG_KEY;        }        // 获取全部邮件设置列表        Map<Object, Object> propertiesMap = redisTemplate.opsForHash().entries(mailConfigKey);        Iterator<Map.Entry<Object, Object>> entries = propertiesMap.entrySet().iterator();        // 假如没有设置取哪个设置,那么获取默认的设置        GitEggMailProperties properties = null;        try {            while (entries.hasNext()) {                Map.Entry<Object, Object> entry = entries.next();                // 转为体系设置对象                GitEggMailProperties propertiesEnable = JsonUtils.jsonToPojo((String) entry.getValue(), GitEggMailProperties.class);                if (propertiesEnable.getChannelStatus().intValue() == GitEggConstant.ENABLE) {                    properties = propertiesEnable;                    break;                }            }        } catch (Exception e) {            e.printStackTrace();        }        return this.getMailSender(mailConfigKey, properties);    }    private JavaMailSenderImpl getMailSender(String mailConfigKey, GitEggMailProperties properties) {        // 根据最新设置信息判定是否从当地获取mailSender,在设置生存时,盘算实体设置的md5值,然后举行比力,不要在每次对比的时间举行md5盘算        if (null != properties && !StringUtils.isEmpty(properties.getMd5()))        {            GitEggJavaMailSenderImpl javaMailSender = javaMailSenderMap.get(mailConfigKey);            if (null == javaMailSender || !properties.getMd5().equals(javaMailSender.getMd5()))            {                // 假如没有设置信息,那么直接返回体系默认设置的mailSender                javaMailSender = new GitEggJavaMailSenderImpl();                this.applyProperties(properties, javaMailSender);                javaMailSender.setMd5(properties.getMd5());                javaMailSender.setId(properties.getId());                // 将MailSender放入缓存                javaMailSenderMap.put(mailConfigKey, javaMailSender);            }            return javaMailSender;        }        else        {            return this.javaMailSenderImpl;        }    }    private void applyProperties(MailProperties properties, JavaMailSenderImpl sender) {        sender.setHost(properties.getHost());        if (properties.getPort() != null) {            sender.setPort(properties.getPort());        }        sender.setUsername(properties.getUsername());        sender.setPassword(properties.getPassword());        sender.setProtocol(properties.getProtocol());        if (properties.getDefaultEncoding() != null) {            sender.setDefaultEncoding(properties.getDefaultEncoding().name());        }        if (!properties.getProperties().isEmpty()) {            sender.setJavaMailProperties(this.asProperties(properties.getProperties()));        }    }    private Properties asProperties(Map<String, String> source) {        Properties properties = new Properties();        properties.putAll(source);        return properties;    }}5、设置异步邮件发送的线程池,这里需留意异步线程池上下文变量共享标题,有两种方式办理,一个是使用装饰器TaskDecorator将父子线程变量举行复制,另有一种方式是transmittable-thread-local来共享线程上下文,这里不睁开描述,后续会专门针对如安在微服务异步线程池中共享上线文举行阐明。

@Configurationpublic class MailThreadPoolConfig {    @Value("${spring.mail-task.execution.pool.core-size}")    private int corePoolSize;    @Value("${spring.mail-task.execution.pool.max-size}")    private int maxPoolSize;    @Value("${spring.mail-task.execution.pool.queue-capacity}")    private int queueCapacity;    @Value("${spring.mail-task.execution.thread-name-prefix}")    private String namePrefix;    @Value("${spring.mail-task.execution.pool.keep-alive}")    private int keepAliveSeconds;    /**     * 邮件发送的线程池     * @return     */    @Bean("mailTaskExecutor")    public Executor mailTaskExecutor(){        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();        //最大线程数        executor.setMaxPoolSize(maxPoolSize);        //焦点线程数        executor.setCorePoolSize(corePoolSize);        //任务队列的巨细        executor.setQueueCapacity(queueCapacity);        //线程前缀名        executor.setThreadNamePrefix(namePrefix);        //线程存活时间        executor.setKeepAliveSeconds(keepAliveSeconds);        // 设置装饰器,父子线程共享request header变量        executor.setTaskDecorator(new RequestHeaderTaskDecorator());        /**         * 拒绝处置惩罚战略         * CallerRunsPolicy():交由调用方线程运行,好比 main 线程。         * AbortPolicy():直接抛出非常。         * DiscardPolicy():直接扬弃。         * DiscardOldestPolicy():扬弃队列中最老的任务。         */        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());        // 线程初始化        executor.initialize();        return executor;    }}6、增长邮件发送结果的摆列类MailResultCodeEnum

public enum MailResultCodeEnum {    /**     * 默认     */    SUCCESS("success", "邮件发送乐成"),    /**     * 自界说     */    ERROR("error", "邮件发送失败");    public String code;    public String message;    MailResultCodeEnum(String code, String message) {        this.code = code;        this.message = message;    }    public String getCode() {        return code;    }    public void setCode(String code) {        this.code = code;    }    public String getMessage() {        return message;    }    public void setMessage(String message) {        this.message = message;    }}7、增长邮箱服务器相干默认设置的常量类JavaMailConstant.java

public class JavaMailConstant {    /**     * Redis JavaMail设置config key     */    public static final String MAIL_CONFIG_KEY = "mail:config";    /**     * 当开启多租户模式时,Redis JavaMail设置config key     */    public static final String MAIL_TENANT_CONFIG_KEY = "mail:tenant:config:";}8、增长GitEggJavaMail主动装配类,根据Nacos大概体系设置举行装配。

@Slf4j@Configuration@RequiredArgsConstructor(onConstructor_ = @Autowired)public class GitEggJavaMailConfiguration {    private final JavaMailSenderImpl javaMailSenderImpl;        private final RedisTemplate redisTemplate;    /**     * 是否开启租户模式     */    @Value("${tenant.enable}")    private Boolean enable;        @Bean    public JavaMailSenderFactory gitEggAuthRequestFactory() {        return new JavaMailSenderFactory(redisTemplate, javaMailSenderImpl, enable);    }}二、增长邮箱服务器设置界面

  邮箱服务器的设置,实际就是差别邮箱渠道的设置,这里我们将表和字段设计好,然后使用GitEgg自带代码天生器,天生业务的CRUD代码即可。
1、邮箱渠道设置表设计

CREATE TABLE `t_sys_mail_channel`  (  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',  `tenant_id` bigint(20) NOT NULL DEFAULT 0 COMMENT '租户id',  `channel_code` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '渠道编码',  `channel_name` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '渠道名称',  `host` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT 'SMTP服务器地点',  `port` int(11) NULL DEFAULT NULL COMMENT 'SMTP服务器端口',  `username` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '账户名',  `password` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '暗码',  `protocol` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'smtp' COMMENT '协议',  `default_encoding` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '默认编码',  `jndi_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '会话JNDI名称',  `properties` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT 'JavaMail 设置',  `channel_status` tinyint(2) NOT NULL DEFAULT 0 COMMENT '渠道状态 1有效 0禁用',  `md5` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT 'MD5',  `comments` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '描述',  `create_time` datetime(0) NULL DEFAULT NULL COMMENT '创建时间',  `creator` bigint(20) NULL DEFAULT NULL COMMENT '创建者',  `update_time` datetime(0) NULL DEFAULT NULL COMMENT '更新时间',  `operator` bigint(20) NULL DEFAULT NULL COMMENT '更新者',  `del_flag` tinyint(2) NULL DEFAULT 0 COMMENT '是否删除',  PRIMARY KEY (`id`) USING BTREE) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '邮件渠道' ROW_FORMAT = DYNAMIC;SET FOREIGN_KEY_CHECKS = 1;2、根据表设计,然后设置代码天生界面,天生前后端代码。

1.png 3、天生代码后,举行相干权限设置,前端界面展示:

三、以同样的方式增长邮箱模板设置界面和邮件发送日志记载

1、邮箱模板和邮件发送日志数据库表设计

邮件模板数据库表设计:
CREATE TABLE `t_sys_mail_template`  (  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',  `tenant_id` bigint(20) NOT NULL DEFAULT 0 COMMENT '租户id',  `template_code` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '模板编码',  `template_name` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '模板名称',  `sign_name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '模板署名',  `template_status` tinyint(2) NOT NULL DEFAULT 1 COMMENT '模板状态',  `template_type` tinyint(2) NULL DEFAULT NULL COMMENT '模板范例',  `template_content` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '模板内容',  `cache_code_key` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '缓存key',  `cache_time_out` bigint(20) NULL DEFAULT 0 COMMENT '缓存有效期 值',  `cache_time_out_unit` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '缓存有效期 单位',  `send_times_limit` bigint(20) NULL DEFAULT 0 COMMENT '发送次数限定',  `send_times_limit_period` bigint(20) NULL DEFAULT 0 COMMENT '限定时间间隔',  `send_times_limit_period_unit` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '限定时间间隔 单位',  `comments` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '描述',  `create_time` datetime(0) NULL DEFAULT NULL COMMENT '创建时间',  `creator` bigint(20) NULL DEFAULT NULL COMMENT '创建者',  `update_time` datetime(0) NULL DEFAULT NULL COMMENT '更新时间',  `operator` bigint(20) NULL DEFAULT NULL COMMENT '更新者',  `del_flag` tinyint(2) NULL DEFAULT 0 COMMENT '是否删除',  PRIMARY KEY (`id`) USING BTREE) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '邮件模板' ROW_FORMAT = DYNAMIC;SET FOREIGN_KEY_CHECKS = 1;邮件日志数据库表设计:
CREATE TABLE `t_sys_mail_log`  (  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',  `tenant_id` bigint(20) NOT NULL DEFAULT 0 COMMENT '租户id',  `channel_id` bigint(20) NULL DEFAULT NULL COMMENT 'mail渠道id',  `template_id` bigint(20) NULL DEFAULT NULL COMMENT 'mail模板id',  `mail_subject` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '邮件主题',  `mail_from` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '发送人',  `mail_to` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '收件人',  `mail_cc` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '抄送',  `mail_bcc` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '密抄送',  `mail_content` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '邮件内容',  `attachment_name` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '0' COMMENT '附件名称',  `attachment_size` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '0' COMMENT '附件巨细',  `send_time` datetime(0) NULL DEFAULT NULL COMMENT '发送时间',  `send_result_code` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '1' COMMENT '发送结果码',  `send_result_msg` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '发送结果消息',  `create_time` datetime(0) NULL DEFAULT NULL COMMENT '创建日期',  `creator` bigint(20) NULL DEFAULT NULL COMMENT '创建者',  `update_time` datetime(0) NULL DEFAULT NULL COMMENT '更新日期',  `operator` bigint(20) NULL DEFAULT NULL COMMENT '更新者',  `del_flag` tinyint(2) NOT NULL DEFAULT 0 COMMENT '是否删除 1:删除 0:不删除',  PRIMARY KEY (`id`) USING BTREE) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '邮件记载' ROW_FORMAT = DYNAMIC;SET FOREIGN_KEY_CHECKS = 1;2、邮件模板和邮件发送日志界面

四、QQ邮箱设置和阿里云企业邮箱设置测试

  上面的根本功能开发完成之后,那么我们就须要举行测试,这里选择两种范例的邮箱举行测试,一种是QQ邮箱,另有一种是阿里云企业邮箱。
1、QQ邮箱设置

QQ邮箱在设置的时间不能使用QQ的登录暗码,须要单独设置QQ邮箱的授权码,下面是利用步调:

  • 开通qq邮箱的smtp功能
5.png

7.png

  • 颠末一系列的验证之后,会获取到一个授权码:

    8.png
  • 体系中设置QQ邮箱相干信息

    9.png
2、 阿里云企业邮箱设置

阿里云企业邮箱的设置相比力而言就简朴一些,设置的暗码就是企业邮箱登录的暗码。

  • 账户设置,开启POP3/SMTP和IMAP/SMTP服务


  • 体系中设置阿里云企业邮箱相干信息


3、Nacos中设置默认邮件服务器,同时增长邮件异步线程池设置

  mail:    username: XXXXXXXXXXX    password: XXXXXXXXXX    default-encoding: UTF-8    host: smtp.mxhichina.com    port: 25    protocol: smtp    properties:      mail:        smtp:          auth: true          ssl:            enable: false  # 异步发送邮件,焦点线程池数设置  mail-task:    execution:      pool:        core-size: 5        max-size: 10        queue-capacity: 5        keep-alive: 60      thread-name-prefix: mail-send-task-4、在邮件渠道设置界面举行邮件发送测试,有两种测试方式,一种是选择指定渠道举行发送,别的一种是选择体系默认渠道举行邮件发送。发送完成后查察邮件日志模块,查抄是否有邮件发送乐成的记载。


  • 选择须要测试的邮箱服务器
12.png

  • 填写测试邮箱发送内容
13.png

  • 查察邮箱发送日志
GitEgg-Cloud是一款基于SpringCloud整合搭建的企业级微服务应用开发框架,开源项目地点:

Gitee: https://gitee.com/wmz1930/GitEgg
GitHub: https://github.com/wmz1930/GitEgg
接待感爱好的小同伴Star支持一下。
您需要登录后才可以回帖 登录 | 立即注册

Powered by CangBaoKu v1.0 小黑屋藏宝库It社区( 冀ICP备14008649号 )

GMT+8, 2024-10-19 04:25, Processed in 0.220451 second(s), 35 queries.© 2003-2025 cbk Team.

快速回复 返回顶部 返回列表