该文章是我在学习及实践过程中总结的SpringBoot整合其他常用的功能,其中包含了该功能的说明和详细的代码演示,该文章会持续更新。
如果文章有误,欢迎大家的指正,同时也期待与大家的交流。本人的联系方式 jenson_97@163.com
一、SpringBoot整合异步任务
该功能通常用于处理那些非核心任务,比如购物的流水信息、邮件功能、短信功能等,该技术最大程度的实现了与应用程序的解耦。
代码演示
新建一个专门用于处理异步任务的service:
@Slf4j
@Component
public class AsyncTask {
//注入Component
@Autowired
private OtherServiceImpl otherService;
@Async
public void makeLog(String content){
log.info("[{}]打印日志,信息为:[{}]",DateUtil.now(),content);
}
@Async
public void doSomething(){
otherService.doSomething();
}
}
该类用于去处理其他所有需要异步处理的任务,核心注解是 @Async
之后在SpringBoot的主启动类中添加 @EnableAsync,用于开启异步任务的自动配置功能。
@EnableAsync
@SpringBootApplication
public class AsyncApplication {
public static void main(String[] args) {
SpringApplication.run(AsyncApplication.class, args);
}
}
在编写一个controller用于测试该异步功能
@Slf4j
@RestController
@RequestMapping("/test")
public class TestController {
@Autowired
private AsyncTask task;
@GetMapping("/log")
public String testMakeLog(String content){
task.makeLog(content);
return content;
}
@GetMapping("/dosomething")
public String testDoSomething(){
//...其他逻辑
task.doSomething();
return "OK";
}
}
使用浏览器测试异步任务的执行情况:
测试通过
二、SpringBoot整合定时任务
定时任务主要用于处理在指定时间后执行的某项任务。他的作用就相当于一个闹钟,在闹钟响铃后,我就执行起床任务。
代码示例
@Slf4j
@Configuration
//开启定时任务的自动配置功能
@EnableScheduling
public class TimerTaskService {
//注入Component
@Autowired
private OtherServiceImpl otherService;
//从0秒开始,每隔5秒执行一次
@Scheduled(cron = "0/5 * * * * ? ")
public void doSomething(){
otherService.doSomething();
}
}
核心注解:@EnableScheduling,@Scheduled,
@EnableScheduling注解用于开启定时任务的自动配置功能。
@Scheduled标记一个方法,作用是多久执行一次由该注解指定的函数,@Scheduled注解所包括的常用的属性有:①cron,cron表达式可以指定一个时间点,该任务将会满足该时间点去执行。②fixedRate,他使用一个毫秒值来指定多久执行一次定时任务,比如:@Scheduled(fixedRate=2000)表示每过两秒执行一次该任务。 ③fixedDelay,他控制该方法执行的间隔时间,从上一次方法执行完开始计时(毫秒计时),比如@Scheduled(fixedDelay=5000)表示在上一次方法执行完毕后,5秒之后执行下一次该方法。
cron表达式可以使用在线生成器生成:在线Cron表达式生成器
测试
测试通过
三、SpringBoot整合RocketMQ
逻辑:生产者向MQ集群的Broker发送一条Group为MQ-STUDENT-GROUP,Topic为MQ-STUDENT-TOPIC包含Student对象的消息,消费者去消费该Group,Topic下的消息。
1).测试的Student对象
package com.lsnu.entitis;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
/**
* @author Jenson
* @since 2020/10/2 11:03
**/
@Data
@Accessors(chain = true)
public class Student implements Serializable {
private Integer id;
private String name;
private Integer age;
}
2).消息生产者
主要依赖信息:
<!--RocketMQ-->
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-spring-boot-starter</artifactId>
<version>2.0.3</version>
</dependency>
主配置文件:
#server
server.port=8080
#RocketMQ
rocketmq.name-server=192.168.43.228:9876;192.168.43.44:9876
rocketmq.producer.group=MQ-STUDENT-GROUP
rocketmq.producer.topic=MQ-STUDENT-TOPIC
生产者向MQ发送消息:
package com.lsnu.producer.controllers;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import com.lsnu.entitis.Student;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.client.exception.MQBrokerException;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.common.message.Message;
import org.apache.rocketmq.remoting.exception.RemotingException;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author Jenson
* @since 2020/10/2 11:16
**/
@Slf4j
@RestController
public class SendMessageController {
@Autowired
private RocketMQTemplate rocketMQTemplate;
@Value("${rocketmq.producer.topic}")
private String topic;
@GetMapping("/send-message")
public String sendMessage(Student student) throws InterruptedException, RemotingException, MQClientException, MQBrokerException {
//将封装的student对象发送到MQ
String body = JSON.toJSONString(student);
//消息体
Message message = new Message(topic,body.getBytes());
//开始发送
SendResult sendResult = rocketMQTemplate.getProducer().send(message);
log.info("消息生产者发送消息成功,当前时间[{}]", DateUtil.now());
//在页面显示发送结果
return sendResult.toString();
}
}
3).消息消费者
主要依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--RocketMQ-->
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-spring-boot-starter</artifactId>
<version>2.0.3</version>
</dependency>
主配置文件:
#server
server.port=8081
#RocketMQ
rocketmq.name-server=192.168.43.228:9876;192.168.43.44:9876
rocketmq.consumer.group=MQ-STUDENT-GROUP
rocketmq.consumer.topic=MQ-STUDENT-TOPIC
消息监听器:
package com.lsnu.consumer;
import cn.hutool.core.date.DateUtil;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.common.message.MessageExt;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.springframework.stereotype.Component;
/**
* @author Jenson
* @since 2020/10/2 11:33
**/
@Slf4j
@Component
@RocketMQMessageListener(topic = "${rocketmq.consumer.topic}",consumerGroup = "${rocketmq.consumer.group}")
public class ConsumerResult implements RocketMQListener<MessageExt> {
@SneakyThrows
public void onMessage(MessageExt messageExt) {
log.info("消费者开始消费,当前时间[{}]", DateUtil.now());
String result = new String(messageExt.getBody(),"UTF-8");
log.info("消息消费者获得的结果为:[{}]",result);
}
}
4).测试
启动RocketMQ集群:
启动消费者与生产者时候之后浏览器测试localhost:8080/send-message链接:
生产者:
生产者控制台:
消费者:
该Demo的源码我贴在Github上:传送门
测试通过
四、SpringBoot整合JApiDocs
如果你和我一样觉得Swagger注解使得代码看起来眼花缭乱,很繁杂,非常不简洁的话,那么就试试JApiDocs吧,他会根据代码中的注释去生成文档信息,之后汇总到指定路径下的html页面中,我们可以将其添加到云端,这样更加便于协同开发。
添加依赖
<!-- JApiDocs -->
<dependency>
<groupId>io.github.yedaxia</groupId>
<artifactId>japidocs</artifactId>
<version>1.4.3</version>
</dependency>
使用JApiDocs
在任何一个main方法中执行以下代码:
package com.lsnu.test;
import io.github.yedaxia.apidocs.Docs;
import io.github.yedaxia.apidocs.DocsConfig;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* 主启动类
*
* @author Jenson
*/
@SpringBootApplication
public class TestApplication {
public static void main(String[] args) {
docsConfig();
SpringApplication.run(TestApplication.class, args);
}
private static void docsConfig(){
DocsConfig config = new DocsConfig();
config.setProjectPath("D:\\HelloWorld\\test"); // root project path
config.setProjectName("test"); // project name
config.setApiVersion("V1.0"); // api version
config.setDocsPath("D:\\"); // api docs target path
config.setAutoGenerate(Boolean.TRUE); // auto generate
Docs.buildHtmlDocs(config); // execute to generate
}
}
而程序员只需要在自己的代码中简单的使用注释说明某一个接口的作用即可,比如:
/**
* 处理管理员的登录逻辑
*
* @param request request请求
* @param session HttpSession会话对象
* @return 返回登录结果
*/
@PostMapping("/login")
public String login(HttpServletRequest request, HttpSession session) {
String result = "登录结果";
return JSONObject.toJSON(result).toString();
}
运行该项目的main方法:
会在你所指定的路径下生成基于版本号的文件夹,其中包含了所有的文档信息:
这样就使得代码看起来非常简洁,除了基本的注释之外没有其他的冗余信息。
五、SpringBoot整合支付宝付款
如有需要,请看我的另一篇博客,附上—>传送门
六、SpringBoot整合Thymeleaf
1、配置使用Thymeleaf
· 引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
· 使用Thymeleaf语法整合前端代码
需要在HTML文件中引入约束头文件,如下:
<html lang="en" xmlns:th="http://www.thymeleaf.org">
具体的Thyemleaf语法可以在官网查找:https://www.thymeleaf.org/
2、解决Thymeleaf加载样式表css失败的问题
我们平时在使用Thymeleaf时,极有可能遇到以下两个坑:
启动后,在访问页面时,仅仅有数据,而没有样式,浏览器的控制台报css文件404,出现以上问题的原因我总结为这两种:
①.所有对静态文件的请求都被拦截了
import com.lsnu.travel.config.interceptors.SessionInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* @author Jenson
* @since 2020/9/2 12:03
**/
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Autowired
private SessionInterceptor sessionInterceptor;
@Override
public void addViewControllers(ViewControllerRegistry registry) {
//请求映射
registry.addViewController("/").setViewName("index");
registry.addViewController("/index").setViewName("index");
registry.addViewController("/index.html").setViewName("index");
}
/**
* 拦截未登录请求 除了登录和注册请求
*
* @param registry 拦截器注册器
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
//需要排除的请求
String[] excludes = new String[]{"/css/**", "/js/**", "/img/**", "/login/**", "/register/**", "/index", "/"};
//用于拦截未登录请求
registry.addInterceptor(sessionInterceptor)
.addPathPatterns("/**")
.excludePathPatterns(excludes);
}
}
在拦截时需要排除css、js、img等等静态请求,否则所有的静态请求都将被拦截,从而导致加载所有的静态文件出现404。
②.前端路径配置错误
这种问题也是大家最容易碰到的,也是最容易忽视的。在html页面的配置如下:
<link rel="stylesheet" th:href="@{../static/css/index.css}">
<link rel="stylesheet" th:href="@{../static/css/logIn.css}">
目录结构如下:
在前端访问,失败 ,我仔仔细细检查了无数遍(在失败我真要砸电脑了),发现配置路径没错啊,但是在前端css文件就是找不到…
出现这种问题的原因是因为,SpringBoot项目已经规定将html页面存放于templates下,静态文件存放于static文件下, 所以在请求静态问文件时,会默认在src、href等属性前面加上static结构,如果此时我们在href下加上static,那么整个路径就是/static/static…,自然会出现404错误。
知道了原因,解决问题的办法就显而易见了,直接去掉static即可:
<link rel="stylesheet" th:href="@{/css/index.css}">
<link rel="stylesheet" th:href="@{/css/logIn.css}">
再次访问前端页面,成功…
关键词:SpringBoot Thymeleaf css 样式表 404
如果有帮到你,可以给咱个三连在离开么(◕‿◕✿)