首页 > 其他分享 >SpringBoot(六)

SpringBoot(六)

时间:2023-03-26 23:37:04浏览次数:40  
标签:String private public 消息 id 邮件 SpringBoot

5.2任务

这里说的任务系统指的是定时任务。定时任务是企业级开发中必不可少的组成部分,如长周期业务数据的计算,如年度报表,如系统脏数据的处理,再比如系统性能监控报告,还有抢购类活动的商品上架,这些都离不开定时任务。

①Quartz

Quartz技术是一个比较成熟的定时任务框架,但是配置略微复杂,springboot对其进行整合后,简化了一系列的配置,将很多配置采用默认设置,这样开发阶段就简化了很多。

  • 学习springboot整合Quartz前先了解几个Quartz的概念。
    1. 工作(Job):用于定义具体执行的工作
    2. 工作明细(JobDetail):用于描述定时工作相关的信息
    3. 触发器(Trigger):描述了工作明细与调度器的对应关系
    4. 调度器(Scheduler):用于描述触发工作的执行规则,通常使用cron表达式定义规则
  1. 导入springboot整合Quartz的starter

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-quartz</artifactId>
    </dependency>
    
  2. 定义任务Bean,按照Quartz的开发规范制作,继承QuartzJobBean

    public class MyQuartz extends QuartzJobBean {
        @Override
        protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
            System.out.println("quartz task run...");
        }
    }
    
  3. 创建Quartz配置类,定义工作明细(JobDetail)与触发器的(Trigger)bean

    @Configuration
    public class QuartzConfig {
        @Bean
        public JobDetail printJobDetail(){
            //绑定具体的工作
            return JobBuilder.newJob(MyQuartz.class).storeDurably().build();
        }
        @Bean
        public Trigger printJobTrigger(){
            ScheduleBuilder schedBuilder = CronScheduleBuilder.cronSchedule("0/5 * * * * ?");
            //绑定对应的工作明细
            return TriggerBuilder.newTrigger().forJob(printJobDetail()).withSchedule(schedBuilder).build();
        }
    }
    

    工作明细中要设置对应的具体工作,使用newJob()操作传入对应的工作任务类型即可。

    触发器需要绑定任务,使用forJob()操作传入绑定的工作明细对象。此处可以为工作明细设置名称然后使用名称绑定,也可以直接调用对应方法绑定。触发器中最核心的规则是执行时间,此处使用调度器定义执行时间,执行时间描述方式使用的是cron表达式。

    cron表达式的规则,略微复杂,而且格式不能乱设置,不是写个格式就能用的,写不好就会出现冲突问题。

②Task

​ spring根据定时任务的特征,将定时任务的开发简化到了极致。

  1. 开启定时任务功能,在引导类上开启定时任务功能的开关,使用注解@EnableScheduling

    @SpringBootApplication
    //开启定时任务功能
    @EnableScheduling
    public class Springboot22TaskApplication {
        public static void main(String[] args) {
            SpringApplication.run(Springboot22TaskApplication.class, args);
        }
    }
    
  2. 定义Bean,在对应要定时执行的操作上方,使用注解@Scheduled定义执行的时间,执行时间的描述方式还是cron表达式

    @Component
    public class MyBean {
        @Scheduled(cron = "0/1 * * * * ?")
        public void print(){
            System.out.println(Thread.currentThread().getName()+" :spring task run...");
        }
    }
    
    • 如何想对定时任务进行相关配置,可以通过配置文件进行

      spring:
        task:
         	scheduling:
            pool:
             	size: 1							# 任务调度线程池大小 默认 1
            thread-name-prefix: ssm_      	# 调度线程名称前缀 默认 scheduling-      
              shutdown:
                await-termination: false		# 线程池关闭时等待所有任务完成
                await-termination-period: 10s	# 调度线程关闭前最大等待时间,确保最后一定关闭
      

5.3邮件

  • 学习邮件发送之前先了解3个概念,这些概念规范了邮件操作过程中的标准。

    1. SMTP(Simple Mail Transfer Protocol):简单邮件传输协议,用于发送电子邮件的传输协议
    2. POP3(Post Office Protocol - Version 3):用于接收电子邮件的标准协议
    3. IMAP(Internet Mail Access Protocol):互联网消息协议,是POP3的替代协议

简单说就是SMPT是发邮件的标准,POP3是收邮件的标准,IMAP是对POP3的升级。

我们制作程序中操作邮件,通常是发邮件,所以SMTP是使用的重点,收邮件大部分都是通过邮件客户端完成,所以开发收邮件的代码极少。

除非你要读取邮件内容,然后解析,做邮件功能的统一处理。例如HR的邮箱收到求职者的简历,可以读取后统一处理。

①发送简单邮件

  1. 导入springboot整合javamail的starter

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-mail</artifactId>
    </dependency>
    
  2. 配置邮箱的登录信息

    #java程序仅用于发送邮件,邮件的功能还是邮件供应商提供的,所以这里是用别人的邮件服务,要配置对应信息。
    spring:
      mail:
      #host配置的是提供邮件服务的主机协议,当前程序仅用于发送邮件,因此配置的是smtp的协议。
        host: smtp.126.com
        username: [email protected]
        #password并不是邮箱账号的登录密码,是邮件供应商提供的一个加密后的密码
        password: test
    
  3. 使用JavaMailSender接口发送邮件

    @Service
    public class SendMailServiceImpl implements SendMailService {
        @Autowired
        private JavaMailSender javaMailSender;
    	//将发送邮件的必要信息(发件人、收件人、标题、正文)封装到SimpleMailMessage对象中,可以根据规则设置发送人昵称等。
        //发送人
        private String from = "[email protected]";
        //接收人
        private String to = "[email protected]";
        //标题
        private String subject = "测试邮件";
        //正文
        private String context = "测试邮件正文内容";
    
        @Override
        public void sendMail() {
            SimpleMailMessage message = new SimpleMailMessage();
            message.setFrom(from+"(小甜甜)");
            message.setTo(to);
            message.setSubject(subject);
            message.setText(context);
            javaMailSender.send(message);
        }
    }
    

②发送网页正文邮件

  • 此处只修改上面的发送内容

    @Service
    public class SendMailServiceImpl2 implements SendMailService {
        @Autowired
        private JavaMailSender javaMailSender;
    
        //发送人
        private String from = "[email protected]";
        //接收人
        private String to = "[email protected]";
        //标题
        private String subject = "测试邮件";
        //正文
        private String context = "<img src='test.JPG'/><a href='https://www.baidu.com'>点开有惊喜</a>";
    
        public void sendMail() {
            try {
                MimeMessage message = javaMailSender.createMimeMessage();
                MimeMessageHelper helper = new MimeMessageHelper(message);
                helper.setFrom(to+"(小甜甜)");
                helper.setTo(from);
                helper.setSubject(subject);
                helper.setText(context,true);		//此处设置正文支持html解析
    
                javaMailSender.send(message);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    

③发送带有附件的邮件

  • 同上

    @Service
    public class SendMailServiceImpl2 implements SendMailService {
        @Autowired
        private JavaMailSender javaMailSender;
    
        //发送人
        private String from = "[email protected]";
        //接收人
        private String to = "[email protected]";
        //标题
        private String subject = "测试邮件";
        //正文
        private String context = "测试邮件正文";
    
        public void sendMail() {
            try {
                MimeMessage message = javaMailSender.createMimeMessage();
                MimeMessageHelper helper = new MimeMessageHelper(message,true);		//此处设置支持附件
                helper.setFrom(to+"(小甜甜)");
                helper.setTo(from);
                helper.setSubject(subject);
                helper.setText(context);
    
                //添加附件
                File f1 = new File("mail.jar");
                File f2 = new File("resources\\test.png");
    
                helper.addAttachment(f1.getName(),f1);
                helper.addAttachment("测试.png",f2);
    
                javaMailSender.send(message);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    

5.4消息

从广义角度来说,消息其实就是信息,但是和信息又有所不同。信息通常被定义为一组数据,而消息除了具有数据的特征之外,还有消息的来源与接收的概念。通常发送消息的一方称为消息的生产者,接收消息的一方称为消息的消费者。这样比较后,发现其实消息和信息差别还是很大的。

信息通常就是一组数据,但是消息由于有了生产者和消费者,就出现了消息中所包含的信息可以被二次解读,生产者发送消息,可以理解为生产者发送了一个信息,也可以理解为生产者发送了一个命令; 消费者接收消息,可以理解为消费者得到了一个信息,也可以理解为消费者得到了一个命令。对比一下我们会发现信息是一个基本数据,而命令则可以关联下一个行为动作,这样就可以理解为基于接收的消息相当于得到了一个行为动作,使用这些行为动作就可以组织成一个业务逻辑,进行进一步的操作。 总的来说,消息其实也是一组信息,只是为其赋予了全新的含义,因为有了消息的流动,并且是有方向性的流动,带来了基于流动的行为产生的全新解读。开发者就可以基于消息的这种特殊解,将其换成代码中的指令。

  • 对于消息的生产者与消费者的工作模式,还可以将消息划分成两种模式,同步消费与异步消息。
  • 同步消息就是生产者发送完消息,等待消费者处理,消费者处理完将结果告知生产者,然后生产者继续向下执行业务。
  • 异步消息就是生产者发送完消息,无需等待消费者处理完毕,生产者继续向下执行其他动作。

①Java处理消息的标准规范

  • ​ 目前企业级开发中广泛使用的消息处理技术共三大类
    1. JMS
    2. AMQP
    3. MQTT

​ 为什么是三大类,而不是三个技术呢?因为这些都是规范,就想JDBC技术,是个规范,开发针对规范开发,运行还要靠实现类,例如MySQL提供了JDBC的实现,最终运行靠的还是实现。并且这三类规范都是针对异步消息进行处理的,也符合消息的设计本质,处理异步的业务。

JMS

JMS(Java Message Service),这是一个规范,作用等同于JDBC规范,提供了与消息服务相关的API接口。

  1. JMS消息模型

    1. 点对点模型:peer-2-peer,生产者会将消息发送到一个保存消息的容器中,通常使用队列模型,使用队列保存消息。一个队列的消息只能被一个消费者消费,或未被及时消费导致超时。这种模型下,生产者和消费者是一对一绑定的。
    2. 发布订阅模型:publish-subscribe,生产者将消息发送到一个保存消息的容器中,也是使用队列模型来保存。但是消息可以被多个消费者消费,生产者和消费者完全独立,相互不需要感知对方的存在。
    • 以上这种分类是从消息的生产和消费过程来进行区分,针对消息所包含的信息不同,还可以进行不同类别的划分。
  2. JMS消息种类

    1. TextMessage
    2. MapMessage
    3. BytesMessage
    4. StreamMessage
    5. ObjectMessage
    6. Message (只有消息头和属性
    • JMS主张不同种类的消息,消费方式不同,可以根据使用需要选择不同种类的消息。
AMQP

JMS的问世为消息中间件提供了很强大的规范性支撑,但是使用的过程中就开始被人诟病,比如JMS设置的极其复杂的多种类消息处理机制。本来分门别类处理挺好的 为什么会被诟病呢?原因就在于JMS的设计是J2EE规范,站在Java开发的角度思考问题。但是现实往往是复杂度很高的。 比如我有一个.NET开发的系统A,有一个Java开发的系统B,现在要从A系统给B系统发业务消息,结果两边数据格式不统一,没法操作。 JMS不是可以统一数据格式吗?提供了6种数据种类,总有一款适合你啊。NO,一个都不能用。因为A系统的底层语言不是Java语言开发的,根本不支持那些对象。 这就意味着如果想使用现有的业务系统A继续开发已经不可能了,必须推翻重新做使用Java语言开发的A系统。

AMQP的出现解决的是消息传递时使用的消息种类的问题,化繁为简,但是其并没有完全推翻JMS的操作API,所以说AMQP仅仅是一种协议,规范了数据传输的格式而已。

AMQP(advanced message queuing protocol):一种协议(高级消息队列协议,也是消息代理规范),规范了网络交换的数据格式,兼容JMS操作。

  1. 优点
    • 具有跨平台性,服务器供应商,生产者,消费者可以使用不同的语言来实现
  2. AMQP消息种类
    • byte[]
  3. AMQP消息模型
    • AMQP在JMS的消息模型基础上又进行了进一步的扩展,除了点对点发布订阅的模型,开发了几种全新的消息模型,适应各种各样的消息发送。
      1. direct exchange
      2. fanout exchange
      3. topic exchange
      4. headers exchange
      5. system exchange
    • 目前实现了AMQP协议的消息中间件技术也很多,而且都是较为流行的技术,例如:RabbitMQ、StormMQ、RocketMQ
MQTT

MQTT(Message Queueing Telemetry Transport)消息队列遥测传输,专为小设备设计,是物联网(IOT)生态系统中主要成分之一。由于与JavaEE企业级开发没有交集,不学。

KafKa

Kafka,一种高吞吐量的分布式发布订阅消息系统,提供实时消息功能。Kafka技术并不是作为消息中间件为主要功能的产品,但是其拥有发布订阅的工作模式,也可以充当消息中间件来使用,而且目前企业级开发中其身影也不少见。

②购物订单发送手机短信案例

为了便于下面演示各种各样的消息中间件技术,我们创建一个购物过程生成订单时为用户发送短信的案例环境,模拟使用消息中间件实现发送手机短信的过程。

  • 手机验证码案例需求

    • 执行下单业务时(模拟此过程),调用消息服务,将要发送短信的订单id传递给消息中间件

    • 消息处理服务接收到要发送的订单id后输出订单id(模拟发短信)

      由于不涉及数据读写,仅开发业务层与表现层,其中短信处理的业务代码独立开发

订单业务
  1. 业务层接口

    //模拟传入订单id,执行下订单业务,参数为虚拟设定,实际应为订单对应的实体类
    public interface OrderService {
        void order(String id);
    }
    
  2. 业务层实现

    //业务层转调短信处理的服务MessageService
    @Service
    public class OrderServiceImpl implements OrderService {
        @Autowired
        private MessageService messageService;
        
        @Override
        public void order(String id) {
            //一系列操作,包含各种服务调用,处理各种业务
            System.out.println("订单处理开始");
            //短信消息处理
            messageService.sendMessage(id);
            System.out.println("订单处理结束");
            System.out.println();
        }
    }
    
  3. 表现层服务

    //表现层对外开发接口,传入订单id即可(模拟)
    @RestController
    @RequestMapping("/orders")
    public class OrderController {
    
        @Autowired
        private OrderService orderService;
    
        @PostMapping("{id}")
        public void order(@PathVariable String id){
            orderService.order(id);
        }
    }
    
短信处理业务
  1. 业务层接口

    //短信处理业务层接口提供两个操作,发送要处理的订单id到消息中间件,另一个操作目前暂且设计成处理消息,实际消息的处理过程不应该是手动执行,应该是自动执行,到具体实现时再进行设计
    public interface MessageService {
        void sendMessage(String id);
        String doMessage();
    }
    
  2. 业务层实现

    //短信处理业务层实现中使用集合先模拟消息队列,观察效果
    @Service
    public class MessageServiceImpl implements MessageService {
        private ArrayList<String> msgList = new ArrayList<String>();
    
        @Override
        public void sendMessage(String id) {
            System.out.println("待发送短信的订单已纳入处理队列,id:"+id);
            msgList.add(id);
        }
    
        @Override
        public String doMessage() {
            String id = msgList.remove(0);
            System.out.println("已完成短信发送业务,id:"+id);
            return id;
        }
    }
    
  3. 表现层服务

    //	短信处理表现层接口暂且开发出一个处理消息的入口,但是此业务是对应业务层中设计的模拟接口,实际业务不需要设计此接口。
    @RestController
    @RequestMapping("/msgs")
    public class MessageController {
    
        @Autowired
        private MessageService messageService;
    
        @GetMapping
        public String doMessage(){
            String id = messageService.doMessage();
            return id;
        }
    }
    

下面开启springboot整合各种各样的消息中间件,从严格满足JMS规范的ActiveMQ开始

标签:String,private,public,消息,id,邮件,SpringBoot
From: https://www.cnblogs.com/Myvlog/p/17259953.html

相关文章