├── pom.xml
└── src
└── main
├── java
└── com
│ └── ffy
│ └── mqtt
│ ├── Application.java
│ ├── constant
│ └── Constant.java
│ ├── model
│ └── Message.java
│ ├── mqtt
│ ├── IMqttSender.java
│ ├── MqttReceiverConfig.java
│ ├── MqttResHandler.java
│ ├── MqttSenderConfig.java
│ └── SynMqttSender.java
│ ├── util
│ └── DefaultFuture.java
│ └── web
│ └── TestController.java
└── resources
├── application-dev.yml
├── application-prod.yml
├── application.yml
└── logback-spring.xml
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | com.ffy
8 | mqtt
9 | 1.0-SNAPSHOT
10 |
11 |
12 | org.springframework.boot
13 | spring-boot-starter-parent
14 | 2.3.6.RELEASE
15 |
16 |
17 |
18 | org.springframework.boot
19 | spring-boot-starter
20 |
21 |
22 | org.springframework
23 | spring-context
24 |
25 |
26 | org.springframework.boot
27 | spring-boot-starter-test
28 | test
29 |
30 |
31 | cn.hutool
32 | hutool-all
33 | 5.3.7
34 |
35 |
36 | org.springframework.boot
37 | spring-boot-starter-web
38 |
39 |
40 | org.projectlombok
41 | lombok
42 | 1.16.4
43 |
44 |
45 |
46 | org.apache.commons
47 | commons-lang3
48 | 3.2.1
49 |
50 |
51 | org.springframework.boot
52 | spring-boot-starter-integration
53 |
54 |
55 | org.springframework.integration
56 | spring-integration-stream
57 |
58 |
59 | org.springframework.integration
60 | spring-integration-mqtt
61 |
62 |
63 |
64 | org.springframework.boot
65 | spring-boot-starter-amqp
66 |
67 |
68 |
69 |
--------------------------------------------------------------------------------
/src/main/java/com/ffy/mqtt/Application.java:
--------------------------------------------------------------------------------
1 | package com.ffy.mqtt;
2 |
3 |
4 | import org.springframework.boot.SpringApplication;
5 | import org.springframework.boot.autoconfigure.SpringBootApplication;
6 |
7 | @SpringBootApplication
8 | public class Application {
9 | public static void main(String[] args) {
10 | SpringApplication.run(Application.class);
11 | }
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/src/main/java/com/ffy/mqtt/constant/Constant.java:
--------------------------------------------------------------------------------
1 | package com.ffy.mqtt.constant;
2 |
3 | public interface Constant {
4 | String MQTT_QUEUE="mqtt.queue";
5 | String MQTT_TOPIC_REQ ="/mqtt/order/request";
6 | String MQTT_TOPIC_RES ="/mqtt/order/response";
7 | }
8 |
--------------------------------------------------------------------------------
/src/main/java/com/ffy/mqtt/model/Message.java:
--------------------------------------------------------------------------------
1 | package com.ffy.mqtt.model;
2 |
3 | import lombok.Data;
4 |
5 | //https://juejin.cn/post/6844904079274180621
6 | @Data
7 | public class Message {
8 | Long messageId;
9 | String playLoad;
10 | }
11 |
--------------------------------------------------------------------------------
/src/main/java/com/ffy/mqtt/mqtt/IMqttSender.java:
--------------------------------------------------------------------------------
1 | package com.ffy.mqtt.mqtt;
2 |
3 | import org.springframework.integration.annotation.MessagingGateway;
4 | import org.springframework.integration.mqtt.support.MqttHeaders;
5 | import org.springframework.messaging.handler.annotation.Header;
6 | import org.springframework.stereotype.Component;
7 | //https://www.hangge.com/blog/cache/detail_2610.html
8 |
9 | /**
10 | * MQTT生产者消息发送接口
11 | */
12 | @Component()
13 | @MessagingGateway(defaultRequestChannel = MqttSenderConfig.CHANNEL_NAME_OUT)
14 | public interface IMqttSender {
15 | /**
16 | * 发送信息到MQTT服务器
17 | *
18 | * @param data 发送的文本
19 | */
20 | void sendToMqtt(String data);
21 |
22 | /**
23 | * 发送信息到MQTT服务器
24 | *
25 | * @param topic 主题
26 | * @param payload 消息主体
27 | */
28 | void sendToMqtt(@Header(MqttHeaders.TOPIC) String topic,
29 | String payload);
30 |
31 | /**
32 | * 发送信息到MQTT服务器
33 | *
34 | * @param topic 主题
35 | * @param qos 对消息处理的几种机制。
36 | * 0 表示的是订阅者没收到消息不会再次发送,消息会丢失。
37 | * 1 表示的是会尝试重试,一直到接收到消息,但这种情况可能导致订阅者收到多次重复消息。
38 | * 2 多了一次去重的动作,确保订阅者收到的消息有一次。
39 | * @param payload 消息主体
40 | */
41 | void sendToMqtt(@Header(MqttHeaders.TOPIC) String topic,
42 | @Header(MqttHeaders.QOS) int qos,
43 | String payload);
44 |
45 |
46 | }
47 |
--------------------------------------------------------------------------------
/src/main/java/com/ffy/mqtt/mqtt/MqttReceiverConfig.java:
--------------------------------------------------------------------------------
1 | package com.ffy.mqtt.mqtt;
2 |
3 | import cn.hutool.json.JSONUtil;
4 | import com.ffy.mqtt.constant.Constant;
5 | import lombok.extern.slf4j.Slf4j;
6 | import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
7 | import org.springframework.beans.factory.annotation.Autowired;
8 | import org.springframework.beans.factory.annotation.Value;
9 | import org.springframework.context.annotation.Bean;
10 | import org.springframework.context.annotation.Configuration;
11 | import org.springframework.integration.annotation.ServiceActivator;
12 | import org.springframework.integration.channel.DirectChannel;
13 | import org.springframework.integration.core.MessageProducer;
14 | import org.springframework.integration.mqtt.core.DefaultMqttPahoClientFactory;
15 | import org.springframework.integration.mqtt.core.MqttPahoClientFactory;
16 | import org.springframework.integration.mqtt.inbound.MqttPahoMessageDrivenChannelAdapter;
17 | import org.springframework.integration.mqtt.support.DefaultPahoMessageConverter;
18 | import org.springframework.messaging.Message;
19 | import org.springframework.messaging.MessageChannel;
20 | import org.springframework.messaging.MessageHandler;
21 | import org.springframework.messaging.MessagingException;
22 | import org.apache.commons.lang3.StringUtils;
23 |
24 | /**
25 | * MQTT配置,消费者
26 | */
27 | @Configuration
28 | @Slf4j
29 | public class MqttReceiverConfig {
30 | /**
31 | * 订阅的bean名称
32 | */
33 | public static final String CHANNEL_NAME_IN = "mqttInboundChannel";
34 |
35 | // 客户端与服务器之间的连接意外中断,服务器将发布客户端的“遗嘱”消息
36 | private static final byte[] WILL_DATA;
37 | static {
38 | WILL_DATA = "offline".getBytes();
39 | }
40 |
41 | @Value("${mqtt.username}")
42 | private String username;
43 |
44 | @Value("${mqtt.password}")
45 | private String password;
46 |
47 | @Value("${mqtt.url}")
48 | private String url;
49 |
50 | @Value("${mqtt.receiver.clientId}")
51 | private String clientId;
52 |
53 | @Value("${mqtt.receiver.defaultTopic}")
54 | private String defaultTopic;
55 |
56 |
57 |
58 |
59 | /**
60 | * MQTT连接器选项
61 | */
62 | @Bean
63 | public MqttConnectOptions getReceiverMqttConnectOptions(){
64 | MqttConnectOptions options = new MqttConnectOptions();
65 | // 设置连接的用户名
66 | if(!username.trim().equals("")){
67 | options.setUserName(username);
68 | }
69 | // 设置连接的密码
70 | options.setPassword(password.toCharArray());
71 | // 设置连接的地址
72 | options.setServerURIs(StringUtils.split(url, ","));
73 | // 设置超时时间 单位为秒
74 | options.setConnectionTimeout(10);
75 | // 设置会话心跳时间 单位为秒 服务器会每隔1.5*20秒的时间向客户端发送心跳判断客户端是否在线
76 | // 但这个方法并没有重连的机制
77 | options.setKeepAliveInterval(20);
78 | return options;
79 | }
80 |
81 | /**
82 | * MQTT客户端
83 | */
84 | @Bean
85 | public MqttPahoClientFactory receiverMqttClientFactory() {
86 | DefaultMqttPahoClientFactory factory = new DefaultMqttPahoClientFactory();
87 | factory.setConnectionOptions(getReceiverMqttConnectOptions());
88 | return factory;
89 | }
90 |
91 | /**
92 | * MQTT信息通道(消费者)
93 | */
94 | @Bean(name = CHANNEL_NAME_IN)
95 | public MessageChannel mqttInboundChannel() {
96 | return new DirectChannel();
97 | }
98 |
99 | /**
100 | * MQTT消息订阅绑定(消费者)
101 | */
102 | @Bean
103 | public MessageProducer inbound() {
104 | // 可以同时消费(订阅)多个Topic
105 | MqttPahoMessageDrivenChannelAdapter adapter =
106 | new MqttPahoMessageDrivenChannelAdapter(
107 | clientId, receiverMqttClientFactory(),
108 | StringUtils.split(defaultTopic, ","));
109 | adapter.setCompletionTimeout(5000);
110 | adapter.setConverter(new DefaultPahoMessageConverter());
111 | adapter.setQos(1);
112 | // 设置订阅通道
113 | adapter.setOutputChannel(mqttInboundChannel());
114 | return adapter;
115 | }
116 |
117 | @Autowired
118 | MqttResHandler mqttResHandler;
119 | /**
120 | * MQTT消息处理器(消费者)
121 | */
122 | @Bean
123 | @ServiceActivator(inputChannel = CHANNEL_NAME_IN)
124 | public MessageHandler handler() {
125 | return new MessageHandler() {
126 | @Override
127 | public void handleMessage(Message> message) throws MessagingException {
128 | String topic = message.getHeaders().get("mqtt_receivedTopic").toString();
129 |
130 | if(topic.equals(Constant.MQTT_TOPIC_RES)){
131 | String msg = message.getPayload().toString();
132 | mqttResHandler.deal(JSONUtil.toBean(msg,com.ffy.mqtt.model.Message.class));
133 | }
134 | String msg = message.getPayload().toString();
135 | log.info("\n--------------------START-------------------\n" +
136 | "接收到订阅消息:\ntopic:" + topic + "\nmessage:" + msg +
137 | "\n---------------------END--------------------");
138 | }
139 | };
140 | }
141 |
142 | }
143 |
144 |
--------------------------------------------------------------------------------
/src/main/java/com/ffy/mqtt/mqtt/MqttResHandler.java:
--------------------------------------------------------------------------------
1 | package com.ffy.mqtt.mqtt;
2 |
3 | import cn.hutool.json.JSONUtil;
4 | import com.ffy.mqtt.model.Message;
5 | import com.ffy.mqtt.rabbitmq.SimpleSender;
6 | import com.ffy.mqtt.util.DefaultFuture;
7 |
8 | import org.springframework.beans.factory.annotation.Autowired;
9 | import org.springframework.stereotype.Component;
10 |
11 | @Component
12 | public class MqttResHandler {
13 |
14 |
15 | public void deal(Message msg){
16 | //根据messageId判断是否是本机发送的消息
17 | Long msgId = msg.getMessageId();
18 | if(DefaultFuture.contains(msgId)){
19 | DefaultFuture.received(msg);
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/main/java/com/ffy/mqtt/mqtt/MqttSenderConfig.java:
--------------------------------------------------------------------------------
1 | package com.ffy.mqtt.mqtt;
2 |
3 | import org.apache.commons.lang3.StringUtils;
4 | import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
5 | import org.springframework.beans.factory.annotation.Value;
6 | import org.springframework.context.annotation.Bean;
7 | import org.springframework.context.annotation.Configuration;
8 | import org.springframework.integration.annotation.IntegrationComponentScan;
9 | import org.springframework.integration.annotation.ServiceActivator;
10 | import org.springframework.integration.channel.DirectChannel;
11 | import org.springframework.integration.mqtt.core.DefaultMqttPahoClientFactory;
12 | import org.springframework.integration.mqtt.core.MqttPahoClientFactory;
13 | import org.springframework.integration.mqtt.outbound.MqttPahoMessageHandler;
14 | import org.springframework.messaging.MessageChannel;
15 | import org.springframework.messaging.MessageHandler;
16 |
17 | @Configuration
18 | @IntegrationComponentScan
19 | public class MqttSenderConfig {
20 | @Value("${mqtt.username}")
21 | private String username;
22 |
23 | @Value("${mqtt.password}")
24 | private String password;
25 |
26 | @Value("${mqtt.url}")
27 | private String url;
28 |
29 | @Value("${mqtt.clientId}")
30 | private String clientId;
31 |
32 | @Value("${mqtt.defaultTopic}")
33 | private String defaultTopic;
34 |
35 | @Value("${mqtt.completionTimeout}")
36 | private int completionTimeout ; //连接超时
37 |
38 | @Value("${mqtt.willData}")
39 | private String WILL_DATA ; //连接超时
40 |
41 | /**
42 | * 发布的bean名称
43 | */
44 | public static final String CHANNEL_NAME_OUT = "mqttOutboundChannel";
45 |
46 | /**
47 | * 发布的bean名称
48 | */
49 | public static final String CHANNEL_NAME_OUT_2 = "mqttOutboundChannel_2";
50 |
51 | /**
52 | * MQTT连接器选项
53 | */
54 | @Bean
55 | public MqttConnectOptions getSenderMqttConnectOptions(){
56 | MqttConnectOptions options=new MqttConnectOptions();
57 | // 设置连接的用户名
58 | if(!username.trim().equals("")){
59 | options.setUserName(username);
60 | }
61 | // 设置连接的密码
62 | options.setPassword(password.toCharArray());
63 | // 设置连接的地址
64 | options.setServerURIs(StringUtils.split(url, ","));
65 | // 设置超时时间 单位为秒
66 | options.setConnectionTimeout(10);
67 | // 设置会话心跳时间 单位为秒 服务器会每隔1.5*20秒的时间向客户端发送心跳判断客户端是否在线
68 | // 但这个方法并没有重连的机制
69 | options.setKeepAliveInterval(20);
70 | // 设置“遗嘱”消息的话题,若客户端与服务器之间的连接意外中断,服务器将发布客户端的“遗嘱”消息。
71 |
72 | options.setWill("willTopic", WILL_DATA.getBytes(), 2, false);
73 |
74 | options.setMaxInflight(1000);
75 | return options;
76 | }
77 | /**
78 | * MQTT客户端
79 | */
80 | @Bean
81 | public MqttPahoClientFactory senderMqttClientFactory() {
82 | DefaultMqttPahoClientFactory factory = new DefaultMqttPahoClientFactory();
83 | factory.setConnectionOptions(getSenderMqttConnectOptions());
84 | return factory;
85 | }
86 |
87 | //接收通道
88 | @Bean
89 | public MessageChannel mqttInputChannel() {
90 | return new DirectChannel();
91 | }
92 |
93 |
94 |
95 | /**
96 | * MQTT信息通道(生产者)
97 | */
98 | @Bean(name = CHANNEL_NAME_OUT)
99 | public MessageChannel mqttOutboundChannel() {
100 | return new DirectChannel();
101 | }
102 |
103 |
104 |
105 |
106 | /**
107 | * MQTT消息处理器(生产者)
108 | */
109 | @Bean
110 | @ServiceActivator(inputChannel = CHANNEL_NAME_OUT)
111 | public MessageHandler mqttOutbound() {
112 | MqttPahoMessageHandler messageHandler = new MqttPahoMessageHandler(
113 | clientId,
114 | senderMqttClientFactory());
115 | messageHandler.setAsync(true);
116 | messageHandler.setDefaultTopic(defaultTopic);
117 | return messageHandler;
118 | }
119 |
120 |
121 |
122 | }
123 |
--------------------------------------------------------------------------------
/src/main/java/com/ffy/mqtt/mqtt/SynMqttSender.java:
--------------------------------------------------------------------------------
1 | package com.ffy.mqtt.mqtt;
2 |
3 | import cn.hutool.json.JSONUtil;
4 | import com.ffy.mqtt.constant.Constant;
5 | import com.ffy.mqtt.model.Message;
6 | import com.ffy.mqtt.util.DefaultFuture;
7 | import org.springframework.beans.factory.annotation.Autowired;
8 | import org.springframework.stereotype.Component;
9 |
10 |
11 | @Component
12 | public class SynMqttSender {
13 | @Autowired
14 | IMqttSender iMqttSender;
15 | public DefaultFuture sendMessage(Message msg) {
16 | Long msgId = DefaultFuture.generateId();
17 | msg.setMessageId(msgId);
18 | iMqttSender.sendToMqtt(Constant.MQTT_TOPIC_REQ,1, JSONUtil.toJsonStr(msg));
19 | DefaultFuture future = new DefaultFuture(msg.getMessageId(),30);
20 | return future;
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/main/java/com/ffy/mqtt/util/DefaultFuture.java:
--------------------------------------------------------------------------------
1 | package com.ffy.mqtt.util;
2 |
3 | import cn.hutool.core.lang.Snowflake;
4 | import cn.hutool.core.util.IdUtil;
5 | import com.ffy.mqtt.model.Message;
6 | import lombok.Data;
7 | import lombok.SneakyThrows;
8 | import lombok.extern.slf4j.Slf4j;
9 |
10 | import java.util.Map;
11 | import java.util.concurrent.*;
12 | import java.util.concurrent.atomic.AtomicLong;
13 | import java.util.concurrent.locks.Condition;
14 | import java.util.concurrent.locks.Lock;
15 | import java.util.concurrent.locks.ReentrantLock;
16 |
17 | @Data
18 | @Slf4j
19 | public class DefaultFuture implements Future {
20 | private static final Map FUTURES = new ConcurrentHashMap();
21 | private final Lock lock = new ReentrantLock();
22 | private final Condition done = lock.newCondition();
23 | private int timeout;
24 | private long id;
25 | private final long start = System.currentTimeMillis();
26 | private boolean cancel = false;
27 | public final static AtomicLong REQUEST_ID_GEN = new AtomicLong(0);
28 | private Message msg;
29 | public DefaultFuture(Long id, int timeout){
30 | this.id=id;
31 | this.timeout=timeout;
32 | FUTURES.put(id, this);
33 | }
34 |
35 | public DefaultFuture( int timeout){
36 | this.id=generateId();
37 | this.timeout=timeout;
38 | FUTURES.put(id, this);
39 | }
40 |
41 | public static Long generateId(){
42 | Snowflake snowflake = IdUtil.createSnowflake(1, 1);
43 | long id = snowflake.nextId();
44 | return id;
45 | }
46 | @Override
47 | public boolean cancel(boolean mayInterruptIfRunning) {
48 | FUTURES.remove(id);
49 | this. cancel=true;
50 | return true;
51 | }
52 |
53 | @Override
54 | public boolean isCancelled() {
55 | return cancel;
56 | }
57 |
58 | @Override
59 | public boolean isDone() {
60 | return msg != null;
61 | }
62 |
63 | @SneakyThrows
64 | @Override
65 | public Message get() {
66 | return get(timeout,TimeUnit.SECONDS);
67 | }
68 |
69 | @Override
70 | public Message get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
71 | if (timeout <= 0) {
72 | throw new RuntimeException("参数错误");
73 | }
74 | if (! isDone()) {
75 | long start = System.currentTimeMillis();
76 | lock.lock();
77 | try {
78 | while (! isDone()) {
79 | done.await(timeout, TimeUnit.SECONDS);
80 | if (isDone() || System.currentTimeMillis() - start > timeout) {
81 | break;
82 | }
83 | }
84 | } catch (InterruptedException e) {
85 | throw new RuntimeException(e);
86 | } finally {
87 | lock.unlock();
88 | }
89 | if (! isDone()) {
90 | throw new RuntimeException("请求超时");
91 | }
92 | }
93 | return msg;
94 | }
95 |
96 | private long getStartTimestamp() {
97 | return start;
98 | }
99 | public static boolean contains(Long msgId){
100 | return FUTURES.containsKey(msgId);
101 | }
102 |
103 | public static void received( Message msg) {
104 | DefaultFuture future = FUTURES.remove(msg.getMessageId());
105 | if (future != null) {
106 | future.doReceived(msg);
107 | }
108 |
109 | }
110 | private void doReceived(Message res) {
111 | lock.lock();
112 | try {
113 | this.msg = res;
114 | if (done != null) {
115 | done.signal();
116 | }
117 | } finally {
118 | lock.unlock();
119 | }
120 | }
121 |
122 | private static class RemotingInvocationTimeoutScan implements Runnable {
123 |
124 | @Override
125 | public void run() {
126 | while (true) {
127 | try {
128 | for (DefaultFuture future : FUTURES.values()) {
129 | if (future == null || future.isDone()) {
130 | continue;
131 | }
132 | if (System.currentTimeMillis() - future.getStartTimestamp() > future.getTimeout()*1000) {
133 | Message timeoutResponse = new Message();
134 | timeoutResponse.setMessageId(future.getId());
135 | timeoutResponse.setPlayLoad("超时");
136 | DefaultFuture.received(timeoutResponse);
137 | }
138 | }
139 | Thread.sleep(30);
140 | } catch (Throwable e) {
141 | log.error("Exception when scan the timeout invocation of remoting.", e);
142 | }
143 | }
144 | }
145 | }
146 |
147 | static {
148 | Thread th = new Thread(new RemotingInvocationTimeoutScan(), "MqttResponseTimeoutScanTimer");
149 | th.setDaemon(true);
150 | th.start();
151 | }
152 | }
153 |
--------------------------------------------------------------------------------
/src/main/java/com/ffy/mqtt/web/TestController.java:
--------------------------------------------------------------------------------
1 | package com.ffy.mqtt.web;
2 |
3 | import com.ffy.mqtt.model.Message;
4 | import com.ffy.mqtt.mqtt.SynMqttSender;
5 | import com.ffy.mqtt.util.DefaultFuture;
6 | import org.springframework.beans.factory.annotation.Autowired;
7 | import org.springframework.web.bind.annotation.PostMapping;
8 | import org.springframework.web.bind.annotation.RequestBody;
9 | import org.springframework.web.bind.annotation.RequestMapping;
10 | import org.springframework.web.bind.annotation.RestController;
11 |
12 | @RestController
13 | @RequestMapping("mqtt")
14 | public class TestController {
15 | @Autowired
16 | SynMqttSender synMqttSender;
17 | @PostMapping("send")
18 | public Message sendMsg(@RequestBody Message message){
19 | DefaultFuture future = synMqttSender.sendMessage(message);
20 | return future.get();
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/main/resources/application-dev.yml:
--------------------------------------------------------------------------------
1 | server:
2 | port: 8081
3 | mqtt:
4 | username: guest # 账号
5 | password: guest # 密码
6 | url: tcp://127.0.0.1:1883 # mqtt连接tcp地址
7 | clientId: test # 客户端Id,每个启动的id要不同
8 | defaultTopic: test # 默认主题
9 | timeout: 100 # 超时时间
10 | keepalive: 100 # 保持连接数
11 | willData: 100 #遗嘱”消息
12 | completionTimeout: 20
13 | receiver:
14 | clientId: receiver
15 | defaultTopic: /mqtt/#
--------------------------------------------------------------------------------
/src/main/resources/application-prod.yml:
--------------------------------------------------------------------------------
1 | server:
2 | port: 8081
3 | netty:
4 | port: 16879
5 | spring:
6 | #redis
7 | redis:
8 | database: 0
9 | host: 127.0.0.1
10 | port: 6379
11 | password:
12 | pool:
13 | maxActive: 24
14 | maxWait: -1
15 | maxIdle: 10
16 | minIdle: 0
17 |
--------------------------------------------------------------------------------
/src/main/resources/application.yml:
--------------------------------------------------------------------------------
1 | spring:
2 | # 默认的profile为dev,其他环境通过指定启动参数使用不同的profile,比如:
3 | # 测试环境:java -jar my-spring-boot.jar --spring.profiles.active=test
4 | # 生产环境:java -jar my-spring-boot.jar --spring.profiles.active=prod
5 | profiles:
6 | active: dev
7 | logging:
8 | level:
9 | root: info
10 |
--------------------------------------------------------------------------------
/src/main/resources/logback-spring.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | %white(%d{yyyy-MM-dd HH:mm:ss}) %green([%thread]) %highlight(%-5level) %magenta(%logger) - %cyan(%msg%n)
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | ${LOG_HOME}/%d{yyyy-MM-dd}.log
23 |
24 | 3
25 |
26 |
27 |
28 | %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------