springboot定时任务
@Scheduled(cron ="0 0 9 * * ?")//每天9点
@Scheduled(cron = "0 */10 * * * * ")//10分钟一执行
*/5 * * * * ? //5秒执行一次
@Scheduled(cron ="*/5 * * * * ?")//五秒一次
cron = "0 8 * ? * *" //每小时8分钟
@Scheduled(cron = "0 0 */1 * * ?") //一小时执行一次
使用SpringBoot创建定时任务非常简单,目前主要有以下三种创建方式:
- 一、基于注解(@Scheduled)
- 二、基于接口(SchedulingConfigurer) 前者相信大家都很熟悉,但是实际使用中我们往往想从数据库中读取指定时间来动态执行定时任务,这时候基于接口的定时任务就派上用场了。
- 三、基于注解设定多线程定时任务
一、静态:基于注解
基于注解@Scheduled默认为单线程,开启多个任务时,任务的执行时机会受上一个任务执行时间的影响。
1、创建定时器
使用SpringBoot基于注解来创建定时任务非常简单,只需几行代码便可完成。 代码如下:
@Component
@Configuration //1.主要用于标记配置类,兼备Component的效果。
@EnableScheduling // 2.开启定时任务
public class SaticScheduleTask {
//3.添加定时任务
@Scheduled(cron = "0/5 * * * * ?")
//或直接指定时间间隔,例如:5秒
//@Scheduled(fixedRate=5000)
private void configureTasks() {
System.err.println("执行静态定时任务时间: " + LocalDateTime.now());
}
}
Cron表达式参数分别表示:
- 秒(0~59) 例如0/5表示每5秒
- 分(0~59)
- 时(0~23)
- 日(0~31)的某天,需计算
- 月(0~11)
- 周几( 可填1-7 或 SUN/MON/TUE/WED/THU/FRI/SAT)
@Scheduled:除了支持灵活的参数表达式cron之外,还支持简单的延时操作,例如 fixedDelay ,fixedRate 填写相应的毫秒数即可。
cron ="0 0 8 * * ?" //每天八点
2、启动测试
启动应用,可以看到控制台打印出如下信息:
显然,使用@Scheduled 注解很方便,但缺点是当我们调整了执行周期的时候,需要重启应用才能生效,这多少有些不方便。为了达到实时生效的效果,可以使用接口来完成定时任务。
二、动态:基于接口
基于接口(SchedulingConfigurer)
1、导入依赖包:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>2.0.4.RELEASE</version>
</parent>
<dependencies>
<dependency><!--添加Web依赖 -->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency><!--添加MySql依赖 -->
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency><!--添加Mybatis依赖 配置mybatis的一些初始化的东西-->
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.1</version>
</dependency>
<dependency><!-- 添加mybatis依赖 -->
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.5</version>
<scope>compile</scope>
</dependency>
</dependencies>
2、添加数据库记录:
开启本地数据库mysql,随便打开查询窗口,然后执行脚本内容,如下:
DROP DATABASE IF EXISTS `socks`;
CREATE DATABASE `socks`;
USE `SOCKS`;
DROP TABLE IF EXISTS `cron`;
CREATE TABLE `cron` (
`cron_id` varchar(30) NOT NULL PRIMARY KEY,
`cron` varchar(30) NOT NULL
);
INSERT INTO `cron` VALUES ('1', '0/5 * * * * ?');
然后在项目中的application.yml 添加数据源:
spring:
datasource:
url: jdbc:mysql://localhost:3306/socks
username: root
password: 123456
3、创建定时器
数据库准备好数据之后,我们编写定时任务,注意这里添加的是TriggerTask,目的是循环读取我们在数据库设置好的执行周期,以及执行相关定时任务的内容。
具体代码如下:
@Component
@Configuration //1.主要用于标记配置类,兼备Component的效果。
@EnableScheduling // 2.开启定时任务
public class DynamicScheduleTask implements SchedulingConfigurer {
@Mapper
public interface CronMapper {
@Select("select cron from cron limit 1")
public String getCron();
}
@Autowired //注入mapper
@SuppressWarnings("all")
CronMapper cronMapper;
/**
* 执行定时任务.
*/
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
taskRegistrar.addTriggerTask(
//1.添加任务内容(Runnable)
() -> System.out.println("执行动态定时任务: " + LocalDateTime.now().toLocalTime()),
//2.设置执行周期(Trigger)
triggerContext -> {
//2.1 从数据库获取执行周期
String cron = cronMapper.getCron();
//2.2 合法性校验.
if (StringUtils.isEmpty(cron)) {
// Omitted Code .. }
//2.3 返回执行周期(Date)
return new CronTrigger(cron).nextExecutionTime(triggerContext);
}
);
}
}
4、启动测试
启动应用后,查看控制台,打印时间是我们预期的每10秒一次:
然后打开Navicat ,将执行周期修改为每6秒执行一次,如图:
查看控制台,发现执行周期已经改变,并且不需要我们重启应用,十分方便。如图:
注意: 如果在数据库修改时格式出现错误,则定时任务会停止,即使重新修改正确;此时只能重新启动项目才能恢复。
三、多线程定时任务
基于注解设定多线程定时任务
1、创建多线程定时任务
//@Component注解用于对那些比较中立的类进行注释;
//相对与在持久层、业务层和控制层分别采用 @Repository、@Service 和 @Controller 对分层中的类进行注释
@Component
@EnableScheduling // 1.开启定时任务
@EnableAsync // 2.开启多线程
public class MultithreadScheduleTask {
@Async
@Scheduled(fixedDelay = 1000) //间隔1秒
public void first() throws InterruptedException {
System.out.println("第一个定时任务开始 : " + LocalDateTime.now().toLocalTime() + "\r\n线程 : " + Thread.currentThread().getName());
System.out.println();
Thread.sleep(1000 * 10);
}
@Async
@Scheduled(fixedDelay = 2000)
public void second() {
System.out.println("第二个定时任务开始 : " + LocalDateTime.now().toLocalTime() + "\r\n线程 : " + Thread.currentThread().getName());
System.out.println();
}
}
2、启动测试
启动应用后,查看控制台:
从控制台可以看出,第一个定时任务和第二个定时任务互不影响;
并且,由于开启了多线程,第一个任务的执行时间也不受其本身执行时间的限制,所以需要注意可能会出现重复操作导致数据异常。
代码地址:https://github.com/mmzsblog/springboot-schedule
第一个静态的任务,方法可以定义多个,执行效果如下
SpringBoot对JMS(ActiveMQ)的支持
下载安装
ActiveMQ的官方下载地址:http://activemq.apache.org/download.html,下载安装完成后
进入bin目录,发现有win32和win64两个文件夹,这2个文件夹分别对应windows32位和windows64位操作系统的启动脚本。进入对应的文件夹中双击activemq.bat。即可正常启动
访问http://localhost:8161/admin。输入默认的用户名和密码:admin/admin即可进入ActiveMQ的控制台
2.2 配置
SpringBoot提供了针对ActiveMQ的支持,只需要在pom.xml文件中引入即可:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-activemq</artifactId>
</dependency>
在application.properties配置ActiveMQ的消息代理地址:
spring.activemq.broker-url=tcp://localhost:61616
1
注意,此处配置的消息代理必须让ActiveMQ启动时才有作用,否则无效
在实际情况下,消息的发布者和接受者一般都是分开的,而这里,我们仅作测试,将消息发送者和接收者放在一个程序中
2.3代码文件
2.3.1消息定义
public class Msg implements MessageCreator {
@Override
public Message createMessage(Session session) throws JMSException {
return session.createTextMessage("测试消息");
}
}
2.3.2消息发送及目的地定义
@SpringBootApplication
public class SpringBootMqApplication implements CommandLineRunner{
@Autowired
JmsTemplate jmsTemplate;
public static void main(String[] args) {
SpringApplication.run(SpringBootMqApplication.class, args);
}
@Override
public void run(String... args) throws Exception {
jmsTemplate.send("my-destination",new Msg());
}
}
CommandLineRunner接口中的run方法,是在程序启动后就会执行的代码。JmsTemplate 是用来操作JMS消息的操作类。
2.3.3消息监听
@Component
public class Receiver {
@JmsListener(destination = "my-destination")
public void receivedMessage(String message){
System.out.println("接受到"+message);
}
}
@JmsListener显示的定义了指定要监听的目的地。
2.3.4运行结果
运行结果显示监听收到了消息
ActiveMQ的控制台中显示我们发送的消息
---------------------
作者:程序员赵镇
来源:CSDN
原文:https://blog.csdn.net/u011342403/article/details/77940765
版权声明:本文为博主原创文章,转载请附上博文链接!
springboot中activeMQ消息队列的引入与使用(发送短信)
1.引入pom依赖
<!--activemq-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-activemq</artifactId>
</dependency>
2.application.properties配置文件中
#activemq
spring.activemq.broker-url=tcp://192.168.0.110:61616
spring.activemq.user=admin
spring.activemq.password=admin
spring.activemq.pool.enabled=false
3.创建类
Producer 类(生产者)
@Service
@Slf4j
public class Producer {
@Autowired
private JmsMessagingTemplate JmsMessagingTemplate;//红线运行无错,貌似是idea的问题 ,可忽略
public void sendMsg(String destinationName,String message){
log.info("发送消息:"+message);
Destination Destination = new ActiveMQQueue(destinationName);
JmsMessagingTemplate.convertAndSend(Destination,message);
}
}
Consumer 类(消费者)
@Service
@Slf4j
public class Consumer {
@Autowired
private RedisService redisService;
@JmsListener(destination = "test.queue")
public void receiveMsg(String msg){
log.info("收到消息:"+msg);
}
@JmsListener(destination = "order")
public void order(String msg){
log.info("收到消息:"+msg);
}
@JmsListener(destination = "sendmsg")
public void sendmsg(String msg)throws Exception{
log.info("消息队列收到消息:"+msg);
JSONObject jo = JSONObject.parseObject(msg);
String mobile=jo.getString("mobile");
String msg1 = "{\"code\":\"" + jo.getString("code") + "\"}";
SendSmsResponse response = AliyunSms.sendSms(mobile, "SMS_146801291", msg1);
}
}
4.测试
@ResponseBody
@RequestMapping(value = "/getIdenCode1",method = RequestMethod.POST)
public ReturnVO getIdenCode1(HttpServletRequest request) {
String mobile = request.getParameter("mobile");
String code="123456";
if (StringUtils.isBlank(mobile)) {
return new ReturnVO(0,"缺少必要参数");
}
//消息队列
producer.sendMsg("sendmsg","{\"mobile\":\""+mobile+"\",\"code\":\""+code+"\"}");
return new ReturnVO(true);
}
springboot使用ajax传递对象集合/数组到后台
设有一个bean名叫TestPOJO。
1、使用ajax从前台传递一个对象数组/集合到后台。
前台ajax写法:
1 2 3 4 5 6 7 8 9 10 11 12 13 | var testPOJO=new Array(); //这里组装testPOJO数组 $.ajax({ url:“testController/testPOJOs”, data:JSON.stringify(testPOJO), type:"post", dataType:"json", contentType:"application/json", success:function (res) { }, error:function(msg){ } }); |
后台接收方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | @RestController @RequestMapping("testController") public class testController {
@RequestMapping("/testPOJOs") //如果类的注解是@Controller,那么方法上面还需要加@ResponseBody,因为@ResTController=@Controller+@ResponseBody public String testPOJOs (@RequestBody TestPOJO [] testPOJO) { //操作 }
//或者下面这个 //@RequestMapping("/testPOJOs") //public String testPOJOs (@RequestBody List<TestPOJO> testPOJO) { //操作 //} } |
无论是几维数组,前后台保持一致就行了。
2、传递Map
前台ajax写法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | var testMap={ "a":"aaa", "b":[1,2,3] }; $.ajax({ url:“testController/testMap”, data:JSON.stringify(testMap), type:"post", dataType:"json", contentType:"application/json", success:function (res) { }, error:function(msg){ } }); |
后台接收方法:
1 2 3 4 5 6 7 8 9 10 11 | @RestController @RequestMapping("testController") public class testController {
@RequestMapping("/testMap") public String testMap (@RequestBody Map<String,Object> map) { String a = (String) map.get("a"); List<Integer> b = (List<Integer>) map.get("b"); ... } } |
3、除了传递对象集合,还需要传递其他字段。
前台ajax写法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | var testPOJO=new Array(); //这里组装testPOJO数组 $.ajax({ url:“testController/testPOJOs”, data:{ “strs”: JSON.stringify(testPOJO), “others”,”…” }, type:"post", dataType:"json", success:function (res) { }, error:function(msg){ } }); |
后台接收方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | @RestController @RequestMapping("testController ") public class testController {
@RequestMapping("/testPOJOs") public String testPOJOs (String strs,String others) {
//操作使用fastjson进行字符串对象转换
List<TestPOJO> list=new ArrayList<>();
JSONObject json =new JSONObject();
JSONArray jsonArray= JSONArray.parseArray(strs);
for(int i=0;i<jsonArray.size();i++){
JSONObject jsonResult = jsonArray.getJSONObject(i);
TestPOJO testPOJO=JSONObject.toJavaObject(jsonResult,TestPOJO.class);
list.add(testPOJO); } //其他操作 } } |
或者直接把others和testPOJO数组重新组合一个新数组var arr=[testPOJO,”others的内容”],“strs”: JSON.stringify(arr),只传递一个strs字段就可以,然后后台转换。
4、传递一个数组
前台ajax写法:
1 2 3 4 5 6 7 8 9 | $.ajax({ url: 'testController/listByxxx', data: { "xxxs":xs//xs是一个数组 }, type: "post", dataType: "json", success: function (res) {} }); |
后台接收方法:
1 2 3 4 5 6 7 8 | @RestController @RequestMapping("testController") public class testController { @RequestMapping("/listByxxx") public String listByxxx(@RequestParam(value = "xxxs[]")String[] xxxs){ //操作 } } |
@RequestBody一般用来处理非Content-Type: application/x-www-form-urlencoded编码格式的数据。在GET请求中,不能使用@RequestBody。在POST请求,可以使用@RequestBody和@RequestParam。
Springboot定时任务设置开关
import com.wms.core.utils.datetime.DateTimeUtil;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;
@Component
@Configuration //主要用于标记配置类,兼备Component的效果。
@EnableScheduling //开启定时任务
@RestController
public class QuotaController {
/**
* 任务开关
*/
private boolean taskSwitch = false;
@Resource
QuotaUtil quotaUtil;
@RequestMapping("/quota/open")
public String taskOpen() {
if (taskSwitch == false) {
taskSwitch = true;
return String.format("quota switch is open taskSwitch=%s", true);
}
return String.format("operator is fail taskSwitch=%s", true);
}
@RequestMapping("/quota/close")
public String taskClose() {
if (taskSwitch == true) {
taskSwitch = false;
return String.format("quota switch is close taskSwitch=%s", false);
}
return String.format("operator is fail taskSwitch=%s", false);
}
//各类指标校验任务
@Scheduled(cron ="0 20 08 * * ?")//每天早上08:20进行指标校验
public void quotaTask() throws Exception {
if (taskSwitch == false) {
return;
}
//查询昨天日期
Date before = DateTimeUtil.getBeforeDayTimeOfDay(new Date(), -1);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
String date=sdf.format(before);
List<Map<String, Object>> allquota = quotaUtil.lastStandard(null,null);
quotaUtil.handleQuota(allquota,date,date);
}
}
Thymeleaf结合springboot的使用
网上使用
要想使用Thhymeleaf,首先要在pom.xml文件中单独添加Thymeleaf依赖。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
显示普通文本
创建一个Controller对象,在其中进行参数的传递
@Controller
public class ThymeleafController {
@RequestMapping(value = "show", method = RequestMethod.GET)
public String show(Model model){
model.addAttribute("uid","123456789");
model.addAttribute("name","Jerry");
return "show";
}
}
在SpringBoot默认的页面路径下创建show.html文件,内容如下
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>SpringBoot模版渲染</title>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
</head>
<body>
<p th:text="'用户ID:' + ${uid}"/>
<p th:text="'用户名称:' + ${name}"/>
</body>
</html>
可以看到在p标签中有th:text属性,这个就是thymeleaf的语法,它表示显示一个普通的文本信息。
如果我们要显示的信息是存在资源文件中的,同样可以在页面中显示,例如资源文件中定义了内容welcome.msg=欢迎{0}光临!。可以在页面中将其显示
<h2 th:text="#{welcome.msg('admin')}"/>
另外,在th:utext中还能做一些基础的数学运算
<p th:text="'数学计算:1+2=' + (1 + 2)"/>
作者:Coding小聪
链接:https://www.jianshu.com/p/a842e5b5012e
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
项目中使用
1创建模板
<head th:fragment="header">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title></title>
<meta name="keywords" content="">
<meta name="description" content="">
<link rel="shortcut icon" href="favicon.ico">
<link href="css/bootstrap.min.css?v=3.3.6"
th:href="@{/css/bootstrap.min.css?v=3.3.6}" rel="stylesheet">
<link rel="stylesheet" href="/css/plugins/layui/css/layui.css">
<link href="/css/font-awesome.css?v=4.4.0"
th:href="@{/css/font-awesome.css?v=4.4.0}" rel="stylesheet">
<link href="/css/plugins/bootstrap-table/bootstrap-table.min.css"
th:href="@{/css/plugins/bootstrap-table/bootstrap-table.min.css}"
rel="stylesheet">
<link href="/css/plugins/jsTree/style.min.css" rel="stylesheet">
<link href="/css/plugins/jqTreeGrid/jquery.treegrid.css"
rel="stylesheet">
<!--summernote css -->
<link href="/css/plugins/summernote/summernote-0.8.8.css"
rel="stylesheet">
<link href="css/animate.css" th:href="@{/css/animate.css}"
rel="stylesheet">
<link href="/css/plugins/chosen/chosen.css" rel="stylesheet">
<link href="/css/style.css?v=4.1.0" th:href="@{/css/style.css?v=4.1.0}"
rel="stylesheet">
</head>
<div th:fragment="footer">
<script src="/js/jquery.min.js?v=2.1.4"></script>
<script src="/js/bootstrap.min.js?v=3.3.6"></script>
<script src="/js/plugins/bootstrap-table/bootstrap-table.min.js"></script>
<script src="/js/plugins/bootstrap-table/bootstrap-table-mobile.min.js"></script>
<script
src="/js/plugins/bootstrap-table/locale/bootstrap-table-zh-CN.min.js"></script>
<script src="/js/plugins/validate/jquery.validate.min.js"></script>
<script src="/js/plugins/validate/messages_zh.min.js"></script>
<script src="/js/plugins/jsTree/jstree.min.js"></script>
<script src="/js/plugins/jqTreeGrid/jquery.treegrid.min.js"></script>
<script src="/js/plugins/jqTreeGrid/jquery.treegrid.extension.js"></script>
<script src="/js/plugins/jqTreeGrid/jquery.treegrid.bootstrap3.js"></script>
<script src="/js/plugins/chosen/chosen.jquery.js"></script>
<script src="/js/plugins/layer/layer.js"></script>
<script src="/js/plugins/layui/layui.all.js"></script>
<script src="/js/DateFormatter.js"></script>
<script src="/js/content.js?v=1.0.0"></script>
<!--summernote-->
<script src="/js/plugins/summernote/summernote.js"></script>
<script src="/js/plugins/summernote/summernote-zh-CN.min.js"></script>
<script src="/js/ajax-util.js"></script>
<!-- echarts -->
<!-- <script src="/js/plugins/echarts/echarts-all.js"></script> -->
<script src="/js/plugins/echarts/echarts.min.js"></script>
<script src="/js/plugins/echarts/echarts-liquidfill.js"></script>
</div>
- application.yml配置
spring:
thymeleaf:
mode: LEGACYHTML5
cache: false
- controller里model存值
- @Controller
@RequestMapping("/ossProvince")
public class OssProvinceController {
@Autowired
OssProvinceService ossProvinceService;
/**
* OSS省份上报数据
*/
@GetMapping("/ossProvinceReport")
String main(Model model) {
String province = getUser().getDeptId().toString();
String provinceName = CityUtil.getProvince.get(province);
model.addAttribute("provinceName",provinceName);
return "ossProvinceReport";
}
- html 获得值
引入模板
<div th:include="include :: footer"></div>
获得值法1
<script th:inline="javascript">
var provinceName = [[${provinceName}]];
$("#a1").text(provinceName+"光衰达标率");
$("#span1").text(provinceName+"光衰达标率信息统计");
</script>
获得值法2
<input id="provinceName" th:value='${provinceName}'>
也可以
<span th:text="${date}"></span>
Thymeleaf模板发送邮箱
https://www.cnblogs.com/chancy/p/10456210.html
最简单的 springboot 发送邮件,使用thymeleaf模板
1,导入需要的包
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
2,添加配置
添加配置前先要到邮箱设置里开启SMTP服务
application.yml
spring:
mail:
host: smtp.qq.com
username: xxxxxxx@qq.com #发送邮件人的邮箱
password: xxxxx #这个密码是邮箱设置里SMTP服务生成的授权码
default-encoding: UTF-8
3,编写发送邮箱的类
接收类MailDO.java
package com.bootdo.oa.domain;
import java.util.Map;
/**
* 邮件接收参数
*/
public class MailDO {
//标题
private String title;
//内容
private String content;
//接收人邮件地址
private String email;
//附加,value 文件的绝对地址/动态模板数据
private Map<String, Object> attachment;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Map<String, Object> getAttachment() {
return attachment;
}
public void setAttachment(Map<String, Object> attachment) {
this.attachment = attachment;
}
}
MailService.java
package com.bootdo.oa.service;
import com.bootdo.oa.domain.MailDO;
public interface MailService {
void sendTextMail(MailDO mailDO);
void sendHtmlMail(MailDO mailDO,boolean isShowHtml);
void sendTemplateMail(MailDO mailDO);
}
MailServiceImpl.java
package com.bootdo.oa.service.impl;
import com.bootdo.common.exception.SystemException;
import com.bootdo.oa.domain.MailDO;
import com.bootdo.oa.service.MailService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.FileSystemResource;
import org.springframework.mail.MailException;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context;
import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import java.io.File;
/**
* 发送邮件
*/
@Service
public class MailServiceImpl implements MailService {
private final static Logger log = LoggerFactory.getLogger(MailServiceImpl.class);
//template模板引擎
@Autowired
private TemplateEngine templateEngine;
@Autowired
private JavaMailSender javaMailSender;
@Value("${spring.mail.username}")
private String from;
/**
* 纯文本邮件
* @param mail
*/
@Async //不解释不懂自行百度,友情提示:有坑
@Override
public void sendTextMail(MailDO mail){
//建立邮件消息
SimpleMailMessage message = new SimpleMailMessage();
message.setFrom(from); // 发送人的邮箱
message.setSubject(mail.getTitle()); //标题
message.setTo(mail.getEmail()); //发给谁 对方邮箱
message.setText(mail.getContent()); //内容
try {
javaMailSender.send(message); //发送
} catch (MailException e) {
log.error("纯文本邮件发送失败->message:{}",e.getMessage());
throw new SystemException("邮件发送失败");
}
}
/**
* 发送的邮件是富文本(附件,图片,html等)
* @param mailDO
* @param isShowHtml 是否解析html
*/
@Async
@Override
public void sendHtmlMail(MailDO mailDO, boolean isShowHtml) {
try {
MimeMessage mimeMessage = javaMailSender.createMimeMessage();
//是否发送的邮件是富文本(附件,图片,html等)
MimeMessageHelper messageHelper = new MimeMessageHelper(mimeMessage,true);
messageHelper.setFrom(from);// 发送人的邮箱
messageHelper.setTo(mailDO.getEmail());//发给谁 对方邮箱
messageHelper.setSubject(mailDO.getTitle());//标题
messageHelper.setText(mailDO.getContent(),isShowHtml);//false,显示原始html代码,无效果
//判断是否有附加图片等
if(mailDO.getAttachment() != null && mailDO.getAttachment().size() > 0){
mailDO.getAttachment().entrySet().stream().forEach(entrySet -> {
try {
File file = new File(String.valueOf(entrySet.getValue()));
if(file.exists()){
messageHelper.addAttachment(entrySet.getKey(), new FileSystemResource(file));
}
} catch (MessagingException e) {
log.error("附件发送失败->message:{}",e.getMessage());
throw new SystemException("附件发送失败");
}
});
}
//发送
javaMailSender.send(mimeMessage);
} catch (MessagingException e) {
log.error("富文本邮件发送失败->message:{}",e.getMessage());
throw new SystemException("邮件发送失败");
}
}
/**
* 发送模板邮件 使用thymeleaf模板
* 若果使用freemarker模板
* Configuration configuration = new Configuration(Configuration.VERSION_2_3_28);
* configuration.setClassForTemplateLoading(this.getClass(), "/templates");
* String emailContent = FreeMarkerTemplateUtils.processTemplateIntoString(configuration.getTemplate("mail.ftl"), params);
* @param mailDO
*/
@Async
@Override
public void sendTemplateMail(MailDO mailDO) {
try {
MimeMessage mimeMessage = javaMailSender.createMimeMessage();
MimeMessageHelper messageHelper = new MimeMessageHelper(mimeMessage,true);
messageHelper.setFrom(from);// 发送人的邮箱
messageHelper.setTo(mailDO.getEmail());//发给谁 对方邮箱
messageHelper.setSubject(mailDO.getTitle()); //标题
//使用模板thymeleaf
//Context是导这个包import org.thymeleaf.context.Context;
Context context = new Context();
//定义模板数据
context.setVariables(mailDO.getAttachment());
//获取thymeleaf的html模板
String emailContent = templateEngine.process("/mail/mail",context); //指定模板路径
messageHelper.setText(emailContent,true);
//发送邮件
javaMailSender.send(mimeMessage);
} catch (MessagingException e) {
log.error("模板邮件发送失败->message:{}",e.getMessage());
throw new SystemException("邮件发送失败");
}
}
}
差点忘了还有个模板 mail.html
放在templates/mail目录下
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>title</title>
</head>
<body>
<h3>你看我<span style="font-size: 35px" th:text="${username}"></span>, 哈哈哈!</h3>
</body>
</html>
4,测试
单元测试启动太慢了,直接写controller测试
@GetMapping("/testMail")
public R mail(MailDO mailDO){
try {
mailService.sendTextMail(mailDO);
} catch (Exception e) {
return R.error(e.getMessage());
}
return R.ok();
}
@GetMapping("/htmlMail")
public R mail(MailDO mailDO){
try {
Map<String,Object> map = new HashMap<>();
map.put("附件名","附件的绝对路径");
mailDO.setAttachment(map);
mailService.sendHtmlMail(mailDO,false);
} catch (Exception e) {
return R.error(e.getMessage());
}
return R.ok();
}
@GetMapping("/templateMail")
public R mail(MailDO mailDO){
try {
Map<String,Object> map = new HashMap<>();
map.put("username","我变大了");
mailDO.setAttachment(map);
mailService.sendTemplateMail(mailDO);
} catch (Exception e) {
return R.error(e.getMessage());
}
return R.ok();
}
5,测试结果
我的项目使用
SendMsgController.java
package com.develop.utils;
import com.develop.lightdecay.service.StatisticsService;
import com.develop.utils.MessageUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context;
import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.Map.Entry;
@Component
@Configuration //主要用于标记配置类,兼备Component的效果。
@EnableScheduling //开启定时任务
@RestController
@SuppressWarnings("unchecked")
public class SendMsgController {
@Resource
private TemplateEngine templateEngine;
/**
* 任务开关
*/
private boolean taskSwitch = false;
@Resource
private StatisticsService statisticsService;
@RequestMapping("/sendMsg/open")
public String taskOpen() {
if (taskSwitch == false) {
taskSwitch = true;
return String.format("sendMsg switch is open taskSwitch=%s", true);
}
return String.format("operator is fail taskSwitch=%s", true);
}
@RequestMapping("/sendMsg/close")
public String taskClose() {
if (taskSwitch == true) {
taskSwitch = false;
return String.format("sendMsg switch is close taskSwitch=%s", false);
}
return String.format("operator is fail taskSwitch=%s", false);
}
/**
* 光衰ONU未上报
* @throws Exception
*/
//@Scheduled(cron ="0 0 11 * * ?")//每天11点
@Scheduled(cron ="*/5 * * * * ?")
public void onuTask() throws Exception{
if (taskSwitch == false) {
return;
}
//查询昨天日期
Date before = DateTimeUtil.getBeforeDayTimeOfDay(new Date(), -1);
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
String date=sdf.format(before);
SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy年MM月dd日 HH时mm分ss秒");
String currentTime=sdf1.format(new Date());
//查询未上报ONU的省份
List<Map<String,Object>> provList = statisticsService.noONUProv(date);
//集团异常信息
String jt_mailMessage="";
List<Map<String,Object>> mailDOList = new ArrayList<Map<String,Object>>();
Context contexts = new Context();
//集团邮箱list
List<String> jt_emailList = new ArrayList<String>();
for (Map<String,Object> map: provList) {
Integer provinceCode = (Integer) map.get("provinceCode");
String areaname = (String) map.get("areaname");
Set<Entry<String, Object>> entrySet = map.entrySet();
//各省邮箱list
List<String> emailList = new ArrayList<String>();
for (Entry<String, Object> entry : entrySet) {
if (entry.getKey().contains("email") && entry.getValue() != null && !entry.getValue().equals("")) {
if(provinceCode != 0) {
emailList.add(entry.getValue().toString());
}
if(provinceCode == 0) {
jt_emailList.add(entry.getValue().toString());
}
}
}
if (provinceCode != 0) {
//集团异常信息
// jt_mailMessage += areaname + "省 <br/>";
// jt_mailMessage += "时间:" + date +
// "; 未上报光衰ONU数据" +
// "。<br/>";
Map<String,Object> mailDOs = new HashMap<>();
mailDOs.put("areaname",areaname);
mailDOs.put("date",date);
mailDOs.put("dataType","光衰ONU");
mailDOs.put("currentTime",currentTime);
mailDOList.add(mailDOs);
if(emailList.size()!= 0) {
Map<String,Object> mailDO = new HashMap<>();
mailDO.put("areaname",areaname);
mailDO.put("date",date);
mailDO.put("dataType","光衰ONU");
mailDO.put("currentTime",currentTime);
//使用模板thymeleaf
//Context是导这个包import org.thymeleaf.context.Context;
Context context = new Context();
//定义模板数据
context.setVariables(mailDO);
//获取thymeleaf的html模板
String mailMessage = templateEngine.process("/sendEmail",context); //指定模板路径
//发送邮件
//MessageUtil.sendMessage(emailList.toArray(new String[emailList.size()]), mailMessage, "MAIL", "接入网光衰ONU上报情况");
//各省异常信息
// String mailMessage = "";
// mailMessage += areaname + "省 <br/>";
// mailMessage += "时间:" + date +
// "; 未上报光衰ONU数据,请核查原因后,补传上报" +
// "。<br/>";
// //发送至非集团邮箱
//MessageUtil.sendMessage(emailList.toArray(new String[emailList.size()]), mailMessage, "MAIL", "接入网光衰ONU上报情况");
//
}
}
}
contexts.setVariable("mailDOs",mailDOList);
//获取thymeleaf的html模板
jt_mailMessage = templateEngine.process("/sendEmails",contexts); //指定模板路径
//发送至集团邮箱
if(!jt_mailMessage.equals("") && jt_emailList.size()!= 0 ) {
//MessageUtil.sendMessage(jt_emailList.toArray(new String[jt_emailList.size()]), jt_mailMessage, "MAIL", "接入网光衰ONU上报情况");
String[] smsaddr = new String[1];
smsaddr[0]="18639308158";
MessageUtil.sendMessage(smsaddr, jt_mailMessage, "SMS", null);
}
}
}
sendEmail.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
尊敬的<span th:text="${areaname}"></span>用户,您好:<br/>
系统自动巡检如下日期未上报光衰数据<br/>
<span th:text="${date}"></span>
,未上报<span th:text="${dataType}"></span>数据<br/>
请相关系统,相关干系人核查!<br/>
祝,工作愉快!<br/>
发送时间:<span th:text="${currentTime}"></span>
。【接入网光衰】
</body>
</html>
sendEmails.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
尊敬的集团用户,您好:<br/>
系统自动巡检如下日期未上报光衰数据<br/>
<span th:each="m : ${mailDOs}">
<span th:text="${m.areaname}"></span>省</br>
<span th:text="${m.date}"></span>
,未上报<span th:text="${m.dataType}"></span>数据<br/>
</span>
祝,工作愉快!<br/>
发送时间:<span th:text="${currentTime}"></span>
。【接入网光衰】
</body>
</html>
Freemarker模板发送邮箱
Freemarker是一种模板引擎,可以实现网页即html静态化,把经常访问但不经常更新的页面实现静态化,当后台更新数据的时候,进行静态化
SpringBoot按照模板定时发送邮件,JavaMail发送,支持FreeMark模板渲染 - 简书
Velocity模板发送短信
SendSMSController.java
package com.develop.utils;
import com.develop.common.utils.GenUtils;
import com.develop.lightdecay.service.StatisticsService;
import org.apache.velocity.app.Velocity;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import javax.annotation.Resource;
import java.io.StringWriter;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.Map.Entry;
@Component
@Configuration //主要用于标记配置类,兼备Component的效果。
@EnableScheduling //开启定时任务
@RestController
@SuppressWarnings("unchecked")
public class SendSMSController {
@Resource
private TemplateEngine templateEngine;
/**
* 任务开关
*/
private boolean taskSwitch = false;
@Resource
private StatisticsService statisticsService;
@RequestMapping("/sendSms/open")
public String taskOpen() {
if (taskSwitch == false) {
taskSwitch = true;
return String.format("sendSms switch is open taskSwitch=%s", true);
}
return String.format("operator is fail taskSwitch=%s", true);
}
@RequestMapping("/sendSms/close")
public String taskClose() {
if (taskSwitch == true) {
taskSwitch = false;
return String.format("sendSms switch is close taskSwitch=%s", false);
}
return String.format("operator is fail taskSwitch=%s", false);
}
/**
* 光衰ONU未上报
* @throws Exception
*/
//@Scheduled(cron ="0 0 11 * * ?")//每天11点
@Scheduled(cron ="*/5 * * * * ?")
public void onuTask() throws Exception{
if (taskSwitch == false) {
return;
}
//查询昨天日期
Date before = DateTimeUtil.getBeforeDayTimeOfDay(new Date(), -1);
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
String date=sdf.format(before);
SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy年MM月dd日 HH时mm分ss秒");
String currentTime=sdf1.format(new Date());
//查询未上报ONU的省份
List<Map<String,Object>> provList = statisticsService.noONUProv(date);
//Velocity封装集团异常Context
List<Map<String,Object>> mailDOList = new ArrayList<Map<String,Object>>();
Map<String,Object> mailDOsMap = new HashMap<>();
mailDOsMap.put("currentTime",currentTime);
//集团异常信息
String jt_telMessage="";
//集团手机list
List<String> jt_telList = new ArrayList<String>();
for (Map<String,Object> map: provList) {
Integer provinceCode = (Integer) map.get("provinceCode");
String areaname = (String) map.get("areaname");
Set<Entry<String, Object>> entrySet = map.entrySet();
//各省手机list
List<String> telList = new ArrayList<String>();
for (Entry<String, Object> entry : entrySet) {
if (entry.getKey().contains("tel") && entry.getValue() != null && !entry.getValue().equals("")) {
if(provinceCode != 0) {
telList.add(entry.getValue().toString());
}
if(provinceCode == 0) {
jt_telList.add(entry.getValue().toString());
}
}
}
if (provinceCode != 0) {
//集团异常信息
Map<String,Object> mailDOs = new HashMap<>();
mailDOs.put("areaname",areaname);
mailDOs.put("date",date);
mailDOs.put("dataType","光衰ONU");
mailDOs.put("currentTime",currentTime);
mailDOList.add(mailDOs);
if(telList.size()!= 0) {
//封装模板数据
Map<String,Object> mailDO = new HashMap<>();
mailDO.put("areaname",areaname);
mailDO.put("date",date);
mailDO.put("dataType","光衰ONU");
mailDO.put("currentTime",currentTime);
//获取模板
String template = "templates/sendSMS.vm";
String mailMessage = GenUtils.generatorMessage(template, mailDO);
//发送短信至非集团
//MessageUtil.sendMessage(emailList.toArray(new String[emailList.size()]), mailMessage, "SMS", null);
}
}
}
//获取vm模板
String template = "templates/sendSMES.vm";
mailDOsMap.put("mailDOList",mailDOList);
jt_telMessage = GenUtils.generatorMessage(template, mailDOsMap);
//发送短信至集团
if(!jt_telMessage.equals("") && jt_telList.size()!= 0 ) {
MessageUtil.sendMessage(jt_telList.toArray(new String[jt_telList.size()]), jt_telMessage, "SMS", null);
}
}
}
GenUtils.java
package com.develop.common.utils;
import com.develop.common.config.Constant;
import com.develop.common.domain.ColumnDO;
import com.develop.common.domain.TableDO;
import org.apache.commons.configuration.Configuration;
import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.PropertiesConfiguration;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.WordUtils;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import java.io.File;
import java.io.IOException;
import java.io.StringWriter;
import java.util.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
/**
* 代码生成器 工具类 邮件&短信模板生成
* @author chl
*/
public class GenUtils {
/**
* 根据模板路径和参数生成模板字符串
* @param templatePath 模板路径
* @param params 参数
* @return
*/
public static String generatorMessage(String templatePath, Map<String, Object> params) {
//设置velocity资源加载器
Properties prop = new Properties();
prop.put("file.resource.loader.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
Velocity.init(prop);
//渲染模板
StringWriter sw = new StringWriter();
VelocityContext context = new VelocityContext(params);
Template tpl = Velocity.getTemplate(templatePath, "UTF-8");
tpl.merge(context, sw);
return sw.toString();
}
}
sendSMS.vm
尊敬的$areaname用户,您好:
系统自动巡检如下日期未上报光衰数据
$date,未上报$dataType数据
请相关系统,相关干系人核查!
祝,工作愉快!
发送时间:$currentTime。【接入网光衰】
sendSMES.vm
尊敬的集团用户,您好:
系统自动巡检如下日期未上报光衰数据
#foreach($m in $mailDOList)
$m.areaname省
$m.date,未上报$m.dataType数据
#end
祝,工作愉快!
发送时间:$currentTime。【接入网光衰】
我的消息队列ActiveMQ
ActiveMQUtil.java
package com.develop.rainfall.util;
import java.util.Map;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.MapMessage;
import javax.jms.Message;
import javax.jms.Session;
import org.apache.activemq.command.ActiveMQQueue;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.MessageCreator;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
@Component
public class ActiveMQUtil {
@Autowired
JmsTemplate jmsTemplate;
public void sendMsg(int addhour,Map<String,Object> uorder,Map<String,Object> indexforecast){
jmsTemplate.send("sendmsg",new MessageCreator() {
@Override
public Message createMessage(Session session) throws JMSException {
MapMessage mapMessage = session.createMapMessage();
mapMessage.setObject("addhour", addhour);
mapMessage.setObject("uorder", uorder);
mapMessage.setObject("indexforecast", indexforecast);
System.out.println(("消息队列发送消息:"+mapMessage));
return mapMessage;
}
});
}
}
Consumer.java
package com.develop.rainfall.util;
import java.util.Map;
import org.springframework.jms.annotation.JmsListener;
import org.springframework.stereotype.Component;
import com.alibaba.fastjson.JSONObject;
@Component
public class Consumer {
@JmsListener(destination = "sendmsg")
public void sendmsg(Map msg)throws Exception{
System.out.println(("消息队列收到消息:"+msg));
int addhour = (int)msg.get("addhour");
Map<String,Object> uorder = (Map<String,Object>)msg.get("uorder");
Map<String,Object> indexforecast = (Map<String,Object>)msg.get("indexforecast");
StaticScheduleTask.formMsg(addhour,uorder,indexforecast);
}
}