diff --git a/README.md b/README.md
index e1ea1fa..5424e7a 100644
--- a/README.md
+++ b/README.md
@@ -7,6 +7,10 @@
- github | Spring Boot 系列 :[https://github.com/gf-huanchupk/SpringBootLearning](https://github.com/gf-huanchupk/SpringBootLearning),记得star哦!
- github | Spring Cloud 系列 :[https://github.com/gf-huanchupk/SpringCloudLearning](https://github.com/gf-huanchupk/SpringCloudLearning),记得star哦!
+### RocketMQ 系列
+- [RocketMQ 教程 | RocketMQ 简介](http://blog.itwolfed.com/blog/98)
+- [RocketMQ 教程 | RocketMQ 安装](http://blog.itwolfed.com/blog/99)
+- [RocketMQ 教程 | RocketMQ 常用消息类型](http://blog.itwolfed.com/blog/101)
### Spring Boot 系列
@@ -25,6 +29,7 @@
- [Spring Boot 教程 | Spring Boot Security OAuth2 实现支持JWT令牌的授权服务器](http://blog.itwolfed.com/blog/17)
- [Spring Boot 教程 | Spring Boot Actuator 整合 Prometheus](http://blog.itwolfed.com/blog/18)
- [Spring Boot 教程 | Spring Boot 集成 Seata 解决分布式事务问题](http://blog.itwolfed.com/blog/19)
+- [Spring Boot 教程 | Spring Boot 使用 JSR303 实现参数验证](http://blog.itwolfed.com/blog/97)
### Spring Cloud 系列
@@ -83,7 +88,7 @@
-
+
欢迎扫码或微信搜索公众号《程序员果果》关注我,更多精彩内容不能错过 ~~
diff --git a/springboot-jsr303/.gitignore b/springboot-jsr303/.gitignore
new file mode 100644
index 0000000..a2a3040
--- /dev/null
+++ b/springboot-jsr303/.gitignore
@@ -0,0 +1,31 @@
+HELP.md
+target/
+!.mvn/wrapper/maven-wrapper.jar
+!**/src/main/**
+!**/src/test/**
+
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.iml
+*.ipr
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+build/
+
+### VS Code ###
+.vscode/
diff --git a/springboot-jsr303/.mvn/wrapper/MavenWrapperDownloader.java b/springboot-jsr303/.mvn/wrapper/MavenWrapperDownloader.java
new file mode 100644
index 0000000..24c6680
--- /dev/null
+++ b/springboot-jsr303/.mvn/wrapper/MavenWrapperDownloader.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2007-present the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.net.*;
+import java.io.*;
+import java.nio.channels.*;
+import java.util.Properties;
+
+public class MavenWrapperDownloader {
+
+ private static final String WRAPPER_VERSION = "0.5.6";
+ /**
+ * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided.
+ */
+ private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/"
+ + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar";
+
+ /**
+ * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to
+ * use instead of the default one.
+ */
+ private static final String MAVEN_WRAPPER_PROPERTIES_PATH =
+ ".mvn/wrapper/maven-wrapper.properties";
+
+ /**
+ * Path where the maven-wrapper.jar will be saved to.
+ */
+ private static final String MAVEN_WRAPPER_JAR_PATH =
+ ".mvn/wrapper/maven-wrapper.jar";
+
+ /**
+ * Name of the property which should be used to override the default download url for the wrapper.
+ */
+ private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl";
+
+ public static void main(String args[]) {
+ System.out.println( "- Downloader started" );
+ File baseDirectory = new File( args[0] );
+ System.out.println( "- Using base directory: " + baseDirectory.getAbsolutePath() );
+
+ // If the maven-wrapper.properties exists, read it and check if it contains a custom
+ // wrapperUrl parameter.
+ File mavenWrapperPropertyFile = new File( baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH );
+ String url = DEFAULT_DOWNLOAD_URL;
+ if (mavenWrapperPropertyFile.exists()) {
+ FileInputStream mavenWrapperPropertyFileInputStream = null;
+ try {
+ mavenWrapperPropertyFileInputStream = new FileInputStream( mavenWrapperPropertyFile );
+ Properties mavenWrapperProperties = new Properties();
+ mavenWrapperProperties.load( mavenWrapperPropertyFileInputStream );
+ url = mavenWrapperProperties.getProperty( PROPERTY_NAME_WRAPPER_URL, url );
+ } catch (IOException e) {
+ System.out.println( "- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'" );
+ } finally {
+ try {
+ if (mavenWrapperPropertyFileInputStream != null) {
+ mavenWrapperPropertyFileInputStream.close();
+ }
+ } catch (IOException e) {
+ // Ignore ...
+ }
+ }
+ }
+ System.out.println( "- Downloading from: " + url );
+
+ File outputFile = new File( baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH );
+ if (!outputFile.getParentFile().exists()) {
+ if (!outputFile.getParentFile().mkdirs()) {
+ System.out.println(
+ "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'" );
+ }
+ }
+ System.out.println( "- Downloading to: " + outputFile.getAbsolutePath() );
+ try {
+ downloadFileFromURL( url, outputFile );
+ System.out.println( "Done" );
+ System.exit( 0 );
+ } catch (Throwable e) {
+ System.out.println( "- Error downloading" );
+ e.printStackTrace();
+ System.exit( 1 );
+ }
+ }
+
+ private static void downloadFileFromURL(String urlString, File destination) throws Exception {
+ if (System.getenv( "MVNW_USERNAME" ) != null && System.getenv( "MVNW_PASSWORD" ) != null) {
+ String username = System.getenv( "MVNW_USERNAME" );
+ char[] password = System.getenv( "MVNW_PASSWORD" ).toCharArray();
+ Authenticator.setDefault( new Authenticator() {
+ @Override
+ protected PasswordAuthentication getPasswordAuthentication() {
+ return new PasswordAuthentication( username, password );
+ }
+ } );
+ }
+ URL website = new URL( urlString );
+ ReadableByteChannel rbc;
+ rbc = Channels.newChannel( website.openStream() );
+ FileOutputStream fos = new FileOutputStream( destination );
+ fos.getChannel().transferFrom( rbc, 0, Long.MAX_VALUE );
+ fos.close();
+ rbc.close();
+ }
+
+}
diff --git a/springboot-jsr303/.mvn/wrapper/maven-wrapper.jar b/springboot-jsr303/.mvn/wrapper/maven-wrapper.jar
new file mode 100644
index 0000000..2cc7d4a
Binary files /dev/null and b/springboot-jsr303/.mvn/wrapper/maven-wrapper.jar differ
diff --git a/springboot-jsr303/.mvn/wrapper/maven-wrapper.properties b/springboot-jsr303/.mvn/wrapper/maven-wrapper.properties
new file mode 100644
index 0000000..642d572
--- /dev/null
+++ b/springboot-jsr303/.mvn/wrapper/maven-wrapper.properties
@@ -0,0 +1,2 @@
+distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip
+wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar
diff --git a/springboot-jsr303/pom.xml b/springboot-jsr303/pom.xml
new file mode 100644
index 0000000..e42f567
--- /dev/null
+++ b/springboot-jsr303/pom.xml
@@ -0,0 +1,57 @@
+
+
+ 4.0.0
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 2.3.0.RELEASE
+
+
+ com.itwolfed
+ springboot-jsr303
+ 0.0.1-SNAPSHOT
+ springboot-jsr303
+ Demo project for Spring Boot
+
+
+ 1.8
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-validation
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ org.projectlombok
+ lombok
+ true
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+ org.junit.vintage
+ junit-vintage-engine
+
+
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+
+
diff --git a/springboot-jsr303/src/main/java/com/itwolfed/SpringbootJsr303Application.java b/springboot-jsr303/src/main/java/com/itwolfed/SpringbootJsr303Application.java
new file mode 100644
index 0000000..c45a832
--- /dev/null
+++ b/springboot-jsr303/src/main/java/com/itwolfed/SpringbootJsr303Application.java
@@ -0,0 +1,13 @@
+package com.itwolfed;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class SpringbootJsr303Application {
+
+ public static void main(String[] args) {
+ SpringApplication.run( SpringbootJsr303Application.class, args );
+ }
+
+}
diff --git a/springboot-jsr303/src/main/java/com/itwolfed/controller/UserController.java b/springboot-jsr303/src/main/java/com/itwolfed/controller/UserController.java
new file mode 100644
index 0000000..a3832ab
--- /dev/null
+++ b/springboot-jsr303/src/main/java/com/itwolfed/controller/UserController.java
@@ -0,0 +1,21 @@
+package com.itwolfed.controller;
+
+import com.itwolfed.entity.User;
+import com.itwolfed.utils.Result;
+import com.itwolfed.valid.Groups;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+
+@RestController
+@RequestMapping("/user")
+public class UserController {
+
+ @PostMapping("")
+ public Result save (@Validated(Groups.Add.class) User user) {
+ return Result.ok();
+ }
+
+}
diff --git a/springboot-jsr303/src/main/java/com/itwolfed/entity/User.java b/springboot-jsr303/src/main/java/com/itwolfed/entity/User.java
new file mode 100644
index 0000000..3de6ffe
--- /dev/null
+++ b/springboot-jsr303/src/main/java/com/itwolfed/entity/User.java
@@ -0,0 +1,30 @@
+package com.itwolfed.entity;
+
+import com.itwolfed.valid.Groups;
+import com.itwolfed.valid.ListValue;
+import lombok.Data;
+
+import javax.validation.constraints.Email;
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Null;
+import javax.validation.constraints.Pattern;
+
+
+@Data
+public class User {
+
+ @Null(message = "新增不需要指定id" , groups = Groups.Add.class)
+ @NotNull(message = "修改需要指定id" , groups = Groups.Update.class)
+ private Integer id;
+ @NotBlank(message = "用户名不能为空")
+ @NotNull
+ private String username;
+ @Pattern(regexp = "^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]{8,16}$", message = "密码必须为8~16个字母和数字组合")
+ private String password;
+ @Email
+ private String email;
+ @ListValue( message = "性别应指定相应的值" , vals = {1,2} , groups = {Groups.Add.class , Groups.Update.class})
+ private Integer gender;
+
+}
diff --git a/springboot-jsr303/src/main/java/com/itwolfed/exception/GlobalExceptionControllerAdvice.java b/springboot-jsr303/src/main/java/com/itwolfed/exception/GlobalExceptionControllerAdvice.java
new file mode 100644
index 0000000..03abdd3
--- /dev/null
+++ b/springboot-jsr303/src/main/java/com/itwolfed/exception/GlobalExceptionControllerAdvice.java
@@ -0,0 +1,36 @@
+package com.itwolfed.exception;
+
+import com.itwolfed.utils.Result;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.validation.BindException;
+import org.springframework.validation.BindingResult;
+import org.springframework.web.bind.MethodArgumentNotValidException;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 统一异常处理
+ */
+@Slf4j
+@RestControllerAdvice(basePackages = "com.itwolfed.controller")
+public class GlobalExceptionControllerAdvice {
+
+ @ExceptionHandler(value= {MethodArgumentNotValidException.class , BindException.class})
+ public Result handleVaildException(Exception e){
+ BindingResult bindingResult = null;
+ if (e instanceof MethodArgumentNotValidException) {
+ bindingResult = ((MethodArgumentNotValidException)e).getBindingResult();
+ } else if (e instanceof BindException) {
+ bindingResult = ((BindException)e).getBindingResult();
+ }
+ Map
errorMap = new HashMap<>(16);
+ bindingResult.getFieldErrors().forEach((fieldError)->
+ errorMap.put(fieldError.getField(),fieldError.getDefaultMessage())
+ );
+ return Result.build(400 , "非法参数 !" , errorMap);
+ }
+
+}
diff --git a/springboot-jsr303/src/main/java/com/itwolfed/utils/Result.java b/springboot-jsr303/src/main/java/com/itwolfed/utils/Result.java
new file mode 100644
index 0000000..fb0600f
--- /dev/null
+++ b/springboot-jsr303/src/main/java/com/itwolfed/utils/Result.java
@@ -0,0 +1,63 @@
+package com.itwolfed.utils;
+
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * 自定义响应结构
+ */
+@Getter
+@Setter
+public class Result {
+
+ // 响应业务状态
+ private Integer status;
+
+ // 响应消息
+ private String msg;
+
+ // 响应中的数据
+ private Object data;
+
+
+ public Result() {
+
+ }
+
+ public static Result ok(Object data) {
+
+ return new Result(200 , data);
+ }
+
+ public static Result ok() {
+ return new Result(200 , null);
+ }
+
+ public static Result build(Integer status, String msg) {
+ return new Result(status, msg, null);
+ }
+
+
+ public static Result build(Integer status, String msg , Object data) {
+ return new Result(status,msg,data);
+ }
+
+ public Result(Integer status,String msg) {
+ this.status = status;
+ this.msg = msg;
+ }
+
+
+ public Result(Integer status,Object data) {
+ this.status = status;
+ this.data = data;
+ }
+
+ public Result(Integer status, String msg, Object data) {
+ this.status = status;
+ this.msg = msg;
+ this.data = data;
+ }
+
+}
\ No newline at end of file
diff --git a/springboot-jsr303/src/main/java/com/itwolfed/valid/Groups.java b/springboot-jsr303/src/main/java/com/itwolfed/valid/Groups.java
new file mode 100644
index 0000000..621049d
--- /dev/null
+++ b/springboot-jsr303/src/main/java/com/itwolfed/valid/Groups.java
@@ -0,0 +1,7 @@
+package com.itwolfed.valid;
+
+
+public class Groups {
+ public interface Add{}
+ public interface Update{}
+}
diff --git a/springboot-jsr303/src/main/java/com/itwolfed/valid/ListValue.java b/springboot-jsr303/src/main/java/com/itwolfed/valid/ListValue.java
new file mode 100644
index 0000000..f3effce
--- /dev/null
+++ b/springboot-jsr303/src/main/java/com/itwolfed/valid/ListValue.java
@@ -0,0 +1,25 @@
+package com.itwolfed.valid;
+
+import javax.validation.Constraint;
+import javax.validation.Payload;
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.*;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+
+@Documented
+@Constraint(validatedBy = { ListValueConstraintValidator.class })
+@Target({ METHOD, FIELD, ANNOTATION_TYPE })
+@Retention(RUNTIME)
+public @interface ListValue {
+ String message() default "";
+
+ Class>[] groups() default { };
+
+ Class extends Payload>[] payload() default { };
+
+ int[] vals() ;
+}
\ No newline at end of file
diff --git a/springboot-jsr303/src/main/java/com/itwolfed/valid/ListValueConstraintValidator.java b/springboot-jsr303/src/main/java/com/itwolfed/valid/ListValueConstraintValidator.java
new file mode 100644
index 0000000..1b99a94
--- /dev/null
+++ b/springboot-jsr303/src/main/java/com/itwolfed/valid/ListValueConstraintValidator.java
@@ -0,0 +1,37 @@
+package com.itwolfed.valid;
+
+
+import javax.validation.ConstraintValidator;
+import javax.validation.ConstraintValidatorContext;
+import java.util.HashSet;
+import java.util.Set;
+
+public class ListValueConstraintValidator implements ConstraintValidator {
+
+ private Set set = new HashSet<>();
+ /**
+ * 初始化方法
+ */
+ @Override
+ public void initialize(ListValue constraintAnnotation) {
+
+ int[] vals = constraintAnnotation.vals();
+ for (int val : vals) {
+ set.add(val);
+ }
+
+ }
+
+ /**
+ * 判断是否校验成功
+ *
+ * @param value 需要校验的值
+ * @param context
+ * @return
+ */
+ @Override
+ public boolean isValid(Integer value, ConstraintValidatorContext context) {
+
+ return set.contains(value);
+ }
+}
diff --git a/springboot-jsr303/src/main/resources/application.yml b/springboot-jsr303/src/main/resources/application.yml
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/springboot-jsr303/src/main/resources/application.yml
@@ -0,0 +1 @@
+
diff --git a/springboot-jsr303/src/test/java/com/itwolfed/SpringbootJsr303ApplicationTests.java b/springboot-jsr303/src/test/java/com/itwolfed/SpringbootJsr303ApplicationTests.java
new file mode 100644
index 0000000..c6cfbc9
--- /dev/null
+++ b/springboot-jsr303/src/test/java/com/itwolfed/SpringbootJsr303ApplicationTests.java
@@ -0,0 +1,13 @@
+package com.itwolfed;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+
+@SpringBootTest
+class SpringbootJsr303ApplicationTests {
+
+ @Test
+ void contextLoads() {
+ }
+
+}
diff --git a/springboot-rocketmq-message/.gitignore b/springboot-rocketmq-message/.gitignore
new file mode 100644
index 0000000..1e4385b
--- /dev/null
+++ b/springboot-rocketmq-message/.gitignore
@@ -0,0 +1,36 @@
+HELP.md
+target/
+!.mvn/wrapper/maven-wrapper.jar
+!**/src/main/**/target/
+!**/src/test/**/target/
+
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.iml
+*.ipr
+mvnw.cmd
+mvnw
+.mvn
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+build/
+!**/src/main/**/build/
+!**/src/test/**/build/
+
+### VS Code ###
+.vscode/
diff --git a/springboot-rocketmq-message/pom.xml b/springboot-rocketmq-message/pom.xml
new file mode 100644
index 0000000..310f5b8
--- /dev/null
+++ b/springboot-rocketmq-message/pom.xml
@@ -0,0 +1,57 @@
+
+
+ 4.0.0
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 2.1.10.RELEASE
+
+
+ com.itwolfed
+ springboot-rocketmq-message
+ 0.0.1-SNAPSHOT
+ springboot-rocketmq-message
+ Demo project for Spring Boot
+
+ 1.8
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ org.apache.rocketmq
+ rocketmq-spring-boot-starter
+ 2.1.1
+
+
+ org.projectlombok
+ lombok
+ 1.18.16
+ provided
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+ org.junit.vintage
+ junit-vintage-engine
+
+
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+
+
diff --git a/springboot-rocketmq-message/src/main/java/com/itwolfed/RocketmqMessageNormalApplication.java b/springboot-rocketmq-message/src/main/java/com/itwolfed/RocketmqMessageNormalApplication.java
new file mode 100644
index 0000000..43e68eb
--- /dev/null
+++ b/springboot-rocketmq-message/src/main/java/com/itwolfed/RocketmqMessageNormalApplication.java
@@ -0,0 +1,13 @@
+package com.itwolfed;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class RocketmqMessageNormalApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run( RocketmqMessageNormalApplication.class, args );
+ }
+
+}
diff --git a/springboot-rocketmq-message/src/main/java/com/itwolfed/msg/Consumer.java b/springboot-rocketmq-message/src/main/java/com/itwolfed/msg/Consumer.java
new file mode 100644
index 0000000..090ac08
--- /dev/null
+++ b/springboot-rocketmq-message/src/main/java/com/itwolfed/msg/Consumer.java
@@ -0,0 +1,18 @@
+package com.itwolfed.msg;
+
+import lombok.extern.slf4j.Slf4j;
+import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
+import org.apache.rocketmq.spring.core.RocketMQListener;
+import org.springframework.stereotype.Component;
+
+@Component
+@Slf4j
+@RocketMQMessageListener(topic = "Topic-Normal",consumerGroup = "consumer-msg-group")
+public class Consumer implements RocketMQListener {
+
+ @Override
+ public void onMessage(String message) {
+ log.info("Receive message:{}" , message);
+ }
+
+}
diff --git a/springboot-rocketmq-message/src/main/java/com/itwolfed/msg/DelayConsumer.java b/springboot-rocketmq-message/src/main/java/com/itwolfed/msg/DelayConsumer.java
new file mode 100644
index 0000000..f85a4c7
--- /dev/null
+++ b/springboot-rocketmq-message/src/main/java/com/itwolfed/msg/DelayConsumer.java
@@ -0,0 +1,18 @@
+package com.itwolfed.msg;
+
+import lombok.extern.slf4j.Slf4j;
+import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
+import org.apache.rocketmq.spring.core.RocketMQListener;
+import org.springframework.stereotype.Component;
+
+@Component
+@Slf4j
+@RocketMQMessageListener(topic = "Topic-Delay",consumerGroup = "consumer-delay-group")
+public class DelayConsumer implements RocketMQListener {
+
+ @Override
+ public void onMessage(String message) {
+ log.info("Receive message:{}" , message);
+ }
+
+}
diff --git a/springboot-rocketmq-message/src/main/java/com/itwolfed/msg/OrderConsumer.java b/springboot-rocketmq-message/src/main/java/com/itwolfed/msg/OrderConsumer.java
new file mode 100644
index 0000000..994aa25
--- /dev/null
+++ b/springboot-rocketmq-message/src/main/java/com/itwolfed/msg/OrderConsumer.java
@@ -0,0 +1,18 @@
+package com.itwolfed.msg;
+
+import lombok.extern.slf4j.Slf4j;
+import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
+import org.apache.rocketmq.spring.core.RocketMQListener;
+import org.springframework.stereotype.Component;
+
+@Component
+@Slf4j
+@RocketMQMessageListener(topic = "Topic-Order",consumerGroup = "consumer-order-group")
+public class OrderConsumer implements RocketMQListener {
+
+ @Override
+ public void onMessage(String message) {
+ log.info("Receive message:{}" , message);
+ }
+
+}
diff --git a/springboot-rocketmq-message/src/main/java/com/itwolfed/msg/Producer.java b/springboot-rocketmq-message/src/main/java/com/itwolfed/msg/Producer.java
new file mode 100644
index 0000000..71b9709
--- /dev/null
+++ b/springboot-rocketmq-message/src/main/java/com/itwolfed/msg/Producer.java
@@ -0,0 +1,128 @@
+package com.itwolfed.msg;
+
+import lombok.extern.slf4j.Slf4j;
+import org.apache.rocketmq.client.producer.LocalTransactionState;
+import org.apache.rocketmq.client.producer.SendCallback;
+import org.apache.rocketmq.client.producer.SendResult;
+import org.apache.rocketmq.client.producer.SendStatus;
+import org.apache.rocketmq.client.producer.TransactionSendResult;
+import org.apache.rocketmq.common.message.Message;
+import org.apache.rocketmq.spring.core.RocketMQTemplate;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.messaging.support.MessageBuilder;
+import org.springframework.stereotype.Component;
+
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+@Slf4j
+@Component
+public class Producer {
+
+
+ @Autowired
+ private RocketMQTemplate rocketMQTemplate;
+
+ /**
+ * 普通消息
+ */
+ public void sendMsg() throws Exception {
+
+ Message message = new Message(
+ // 普通消息所属的Topic
+ "Topic-Normal",
+ // Message Tag可理解为Gmail中的标签,对消息进行再归类,方便Consumer指定过滤条件在消息队列 RocketMQ 版的服务器过滤。
+ "TagA",
+ // Message Body可以是任何二进制形式的数据。
+ "Hello MQ".getBytes()
+ );
+ rocketMQTemplate.getProducer().send( message );
+ // 等同于上面的方式(常用)
+ //rocketMQTemplate.convertAndSend("Topic-Normal:TagA","Hello MQ".getBytes());
+ }
+
+ /**
+ * 异步发送普通消息
+ */
+ public void sendAsyncMsg() {
+ Map map = new HashMap<>();
+ map.put( "name", "zs" );
+ map.put( "age", 20 );
+
+ rocketMQTemplate.asyncSend( "Topic-Normal", map, new SendCallback() {
+ @Override
+ public void onSuccess(SendResult sendResult) {
+ // 消息发送成功。
+ log.info( "async send success" );
+ }
+
+ @Override
+ public void onException(Throwable throwable) {
+ // 消息发送失败,需要进行重试处理,可重新发送这条消息或持久化这条数据进行补偿处理。
+ log.info( "async send fail" );
+ }
+ } );
+ }
+
+ /**
+ * 顺序消息
+ */
+ public void sendOrderlyMsg() {
+ //根据指定的hashKey按顺序发送
+ for (int i = 0; i < 1000; i++) {
+ String orderId = "biz_" + i % 10;
+ // 分区顺序消息中区分不同分区的关键字段,Sharding Key与普通消息的key是完全不同的概念。
+ // 全局顺序消息,该字段可以设置为任意非空字符串。
+ String shardingKey = String.valueOf( orderId );
+ try {
+ SendResult sendResult = rocketMQTemplate.syncSendOrderly( "Topic-Order", "send order msg".getBytes(), shardingKey );
+ // 发送消息,只要不抛异常就是成功。
+ if (sendResult != null) {
+ System.out.println( new Date() + " Send mq message success . msgId is:" + sendResult.getMsgId() );
+ }
+ } catch (Exception e) {
+ // 消息发送失败,需要进行重试处理,可重新发送这条消息或持久化这条数据进行补偿处理。
+ System.out.println( new Date() + " Send mq message failed" );
+ e.printStackTrace();
+ }
+ }
+ }
+
+ /**
+ * 延时消息
+ */
+ public void sendDelayMsg() {
+ rocketMQTemplate.syncSend( "Topic-Delay",
+ MessageBuilder.withPayload( "Hello MQ".getBytes() ).build(),
+ 3000,
+ //设置延时等级3,这个消息将在10s之后发送(现在只支持固定的几个时间,详看delayTimeLevel)
+ //messageDelayLevel = "1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h";
+ 3 );
+ }
+
+ /**
+ * 批量消息
+ */
+ public void sendBatchMsg(List messages) {
+ rocketMQTemplate.syncSend( "springboot-rocketmq", messages );
+
+ }
+
+ /**
+ * 事务消息
+ */
+ public void sendTransactionMsg(){
+ TransactionSendResult transactionSendResult = rocketMQTemplate.sendMessageInTransaction(
+ "Topic-Tx:TagA",
+ MessageBuilder.withPayload( "Hello MQ transaction===".getBytes() ).build(),
+ null );
+ SendStatus sendStatus = transactionSendResult.getSendStatus();
+ LocalTransactionState localTransactionState = transactionSendResult.getLocalTransactionState();
+
+ System.out.println( new Date() + " Send mq message status "+ sendStatus +" , localTransactionState "+ localTransactionState );
+ }
+
+
+}
diff --git a/springboot-rocketmq-message/src/main/java/com/itwolfed/msg/TxConsumerListener.java b/springboot-rocketmq-message/src/main/java/com/itwolfed/msg/TxConsumerListener.java
new file mode 100644
index 0000000..84975de
--- /dev/null
+++ b/springboot-rocketmq-message/src/main/java/com/itwolfed/msg/TxConsumerListener.java
@@ -0,0 +1,22 @@
+package com.itwolfed.msg;
+
+import lombok.extern.slf4j.Slf4j;
+import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
+import org.apache.rocketmq.spring.core.RocketMQListener;
+import org.springframework.stereotype.Component;
+
+
+@Component
+@Slf4j
+@RocketMQMessageListener(topic = "Topic-Tx",consumerGroup = "consumer-tx-group")
+public class TxConsumerListener implements RocketMQListener {
+
+
+
+ @Override
+ public void onMessage(String message) {
+
+ log.info("Receive message:{}" , message);
+ }
+
+}
diff --git a/springboot-rocketmq-message/src/main/java/com/itwolfed/msg/TxProducerListener.java b/springboot-rocketmq-message/src/main/java/com/itwolfed/msg/TxProducerListener.java
new file mode 100644
index 0000000..3eb5c8a
--- /dev/null
+++ b/springboot-rocketmq-message/src/main/java/com/itwolfed/msg/TxProducerListener.java
@@ -0,0 +1,45 @@
+package com.itwolfed.msg;
+
+import org.apache.rocketmq.spring.annotation.RocketMQTransactionListener;
+import org.apache.rocketmq.spring.core.RocketMQLocalTransactionListener;
+import org.apache.rocketmq.spring.core.RocketMQLocalTransactionState;
+import org.springframework.messaging.Message;
+import org.springframework.stereotype.Component;
+
+
+@Component
+@RocketMQTransactionListener
+public class TxProducerListener implements RocketMQLocalTransactionListener {
+
+ @Override
+ public RocketMQLocalTransactionState executeLocalTransaction(Message msg, Object arg) {
+ // 执行本地事务
+ System.out.println("TX message listener execute local transaction");
+ RocketMQLocalTransactionState result;
+ try {
+ // 业务代码( 例如下订单 )
+ result = RocketMQLocalTransactionState.COMMIT;
+ } catch (Exception e) {
+ System.out.println("execute local transaction error");
+ result = RocketMQLocalTransactionState.UNKNOWN;
+ }
+ return result;
+ }
+
+ @Override
+ public RocketMQLocalTransactionState checkLocalTransaction(Message msg) {
+ // 检查本地事务( 例如检查下订单是否成功 )
+ System.out.println("TX message listener check local transaction");
+ RocketMQLocalTransactionState result;
+ try {
+ //业务代码( 根据检查结果,决定是COMMIT或ROLLBACK )
+ result = RocketMQLocalTransactionState.COMMIT;
+ } catch (Exception e) {
+ // 异常就回滚
+ System.out.println("check local transaction error");
+ result = RocketMQLocalTransactionState.ROLLBACK;
+ }
+ return result;
+ }
+
+}
diff --git a/springboot-rocketmq-message/src/main/resources/application.yml b/springboot-rocketmq-message/src/main/resources/application.yml
new file mode 100644
index 0000000..fa3511d
--- /dev/null
+++ b/springboot-rocketmq-message/src/main/resources/application.yml
@@ -0,0 +1,7 @@
+server:
+ port: 8080
+
+rocketmq:
+ name-server: 172.16.250.129:9876
+ producer:
+ group: myGroup
\ No newline at end of file
diff --git a/springboot-rocketmq-message/src/test/java/com/itwolfed/RocketmqMessageNormalApplicationTests.java b/springboot-rocketmq-message/src/test/java/com/itwolfed/RocketmqMessageNormalApplicationTests.java
new file mode 100644
index 0000000..29f75c4
--- /dev/null
+++ b/springboot-rocketmq-message/src/test/java/com/itwolfed/RocketmqMessageNormalApplicationTests.java
@@ -0,0 +1,62 @@
+package com.itwolfed;
+
+
+import com.itwolfed.msg.Producer;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringRunner;
+
+
+@RunWith(SpringRunner.class)
+@SpringBootTest
+public class RocketmqMessageNormalApplicationTests {
+
+ @Autowired
+ private Producer producer;
+
+
+
+ /**
+ * 测试普通消息
+ */
+ @Test
+ public void sendMsg() throws Exception {
+ producer.sendMsg();
+ }
+
+ /**
+ * 异步发送普通消息
+ */
+ @Test
+ public void sendAsyncMsg() {
+ producer.sendAsyncMsg();
+ }
+
+ /**
+ * 顺序消息
+ */
+ @Test
+ public void sendOrderlyMsg() {
+ producer.sendOrderlyMsg();
+ }
+
+ /**
+ * 延时消息
+ */
+ @Test
+ public void sendDelayMsg() {
+ producer.sendDelayMsg();
+ }
+
+ /**
+ * 事务消息
+ */
+ @Test
+ public void sendTransactionMsg(){
+ producer.sendTransactionMsg();
+ }
+
+
+}