├── README.md ├── SpringBootDemo ├── .gitignore ├── pom.xml └── src │ └── main │ ├── java │ └── com │ │ └── xiaour │ │ └── spring │ │ └── boot │ │ ├── Application.java │ │ ├── config │ │ └── MyBatisConfig.java │ │ ├── controller │ │ └── TestCtrl.java │ │ ├── entity │ │ └── UserInfo.java │ │ ├── exception │ │ ├── OApiException.java │ │ └── OApiResultException.java │ │ ├── filter │ │ ├── DruidStatFilter.java │ │ └── MyFilter.java │ │ ├── mapper │ │ └── UserInfoMapper.java │ │ ├── service │ │ ├── RedisService.java │ │ └── impl │ │ │ └── RedisServiceImpl.java │ │ ├── task │ │ └── Task.java │ │ └── utils │ │ └── JsonUtil.java │ └── resources │ ├── application.yml │ ├── mapper │ └── UserInfoMapper.xml │ └── mybatis-config.xml ├── SpringBootDemoV2 ├── .gitignore ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── github │ │ │ └── xiaour │ │ │ ├── Application.java │ │ │ ├── config │ │ │ └── DuckPorperties.java │ │ │ ├── constants │ │ │ └── Api.java │ │ │ ├── controller │ │ │ └── DemoController.java │ │ │ ├── exception │ │ │ ├── AesException.java │ │ │ └── OApiException.java │ │ │ ├── service │ │ │ ├── DubboService.java │ │ │ └── impl │ │ │ │ └── DubboServiceImpl.java │ │ │ └── utils │ │ │ ├── ByteGroup.java │ │ │ ├── HttpHelper.java │ │ │ ├── IDGenerate.java │ │ │ ├── JsonUtil.java │ │ │ ├── PKCS7Encoder.java │ │ │ ├── SHA1.java │ │ │ ├── Test.java │ │ │ ├── WXBizMsgCrypt.java │ │ │ ├── WXBizMsgCryptTest.java │ │ │ ├── XMLParse.java │ │ │ └── Xml2JsonUtil.java │ └── resources │ │ ├── application.yml │ │ └── static │ │ └── banner.png │ └── test │ └── java │ └── com │ └── github │ └── xiaour │ └── SpringBootDemoV2ApplicationTests.java ├── SpringBootDemoV3 ├── .gitignore ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── xiaour │ │ │ └── spring │ │ │ └── boot │ │ │ ├── SpringBootDemoV3Application.java │ │ │ ├── controller │ │ │ └── CatController.java │ │ │ ├── entity │ │ │ ├── Cat.java │ │ │ ├── PageIndex.java │ │ │ └── PageInfo.java │ │ │ └── service │ │ │ └── CatService.java │ └── resources │ │ └── application.properties │ └── test │ └── java │ └── com │ └── xiaour │ └── spring │ └── boot │ └── SpringBootDemoV3ApplicationTests.java ├── SpringBootKafkaDemo ├── SpringBootKafkaDemo.iml ├── pom.xml ├── src │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── xiaour │ │ │ │ └── spring │ │ │ │ └── boot │ │ │ │ └── kafka │ │ │ │ ├── KafkaApplication.java │ │ │ │ ├── consumer │ │ │ │ └── Consumer.java │ │ │ │ └── producer │ │ │ │ ├── Message.java │ │ │ │ ├── Producer.java │ │ │ │ └── SendController.java │ │ └── resources │ │ │ └── application.yml │ └── test │ │ └── java │ │ └── com │ │ └── xiaour │ │ └── spring │ │ └── boot │ │ └── kafka │ │ └── KafkaApplicationTests.java └── target │ └── classes │ └── com │ └── xiaour │ └── spring │ └── boot │ └── kafka │ └── producer │ └── Message.class ├── SpringBootRocketMqDemo ├── .gitignore ├── .mvn │ └── wrapper │ │ ├── maven-wrapper.jar │ │ └── maven-wrapper.properties ├── SpringbootRocketMQ.md ├── mvnw ├── mvnw.cmd ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── xiaour │ │ │ └── spring │ │ │ └── boot │ │ │ └── rocketmq │ │ │ ├── SpringBootRocketmqDemoApplication.java │ │ │ ├── consumer │ │ │ └── Consumer.java │ │ │ ├── controller │ │ │ └── TestController.java │ │ │ └── producer │ │ │ └── Producer.java │ └── resources │ │ └── application.yml │ └── test │ └── java │ └── com │ └── xiaour │ └── spring │ └── boot │ └── rocketmq │ └── SpringBootRocketmqDemoApplicationTests.java ├── SpringWebFluxDemo ├── .gitignore ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── github │ │ │ └── xiaour │ │ │ └── flux │ │ │ ├── SpringWebFluxDemoApplication.java │ │ │ ├── controller │ │ │ ├── HelloWorlController.java │ │ │ ├── SSEController.java │ │ │ └── UserController.java │ │ │ ├── entity │ │ │ └── User.java │ │ │ └── service │ │ │ └── UserService.java │ └── resources │ │ └── application.properties │ └── test │ └── java │ └── com │ └── github │ └── xiaour │ └── flux │ └── SpringWebFluxDemoApplicationTests.java └── pom.xml /README.md: -------------------------------------------------------------------------------- 1 | ## 相关文章 2 | 3 | 1.[SpringMVC配置太多?试试SpringBoot](https://xiaour.github.io/2018/05/02/The_SpringMVC_configuration_is_too_much_Try_SpringBoot/) 4 | 5 | 2.[Springboot集成Kafka](https://xiaour.github.io/2018/05/23/Springboot_integrated_Kafka/) 6 | 7 | 3.[Springboot集成RocketMQ](https://xiaour.github.io/2018/08/16/SpringbootRocketMQ/) 8 | 9 | 4.Webflux Spring异步编程,你将发现新大陆(代码已经部分上传,blog完善中...) 10 | 11 | 5.[利用EasyExcel,两行代码开发一个和API结果一致的生成Excel功能](https://github.com/xiaour/EasyExport#readme) 12 | 13 | ## 代码部分 14 | 15 | ⭐️ SpringBootDemo 16 | 本代码集成了SpringBoot+MyBatis+Redis+MySql。 17 | 最新的部分经网友指正已经把冗余的代码去掉了,代码部分和配置文件部分都有相关的注释; 18 | git clone 到本地后就可以运行了,项目中使用到的数据库表如下 19 | 20 | ```sql 21 | -- ---------------------------- 22 | -- Table structure for `user_info` 23 | -- ---------------------------- 24 | DROP TABLE IF EXISTS `user_info`; 25 | CREATE TABLE `user_info` ( 26 | `id` int(8) NOT NULL AUTO_INCREMENT, 27 | `name` varchar(20) NOT NULL, 28 | `age` int(2) DEFAULT NULL, 29 | PRIMARY KEY (`id`) 30 | ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8; 31 | 32 | -- ---------------------------- 33 | -- Records of user_info 34 | -- ---------------------------- 35 | INSERT INTO `user_info` VALUES ('1', 'xiaour', '18'); 36 | ``` 37 | 38 | ⭐️ SpringBootDemoV2 39 | 代码主要和SpringBootDemo的区别是使用了Springboot2.0 40 | 41 | 2018.08.22 添加了Twitter ID生成算法的工具,每秒支持12万ID生成。 42 | 43 | ⭐️ SpringBootKafkaDemo 44 | Springboot2.0继承了Kafka消息中间件 45 | 46 | ⭐️ SpringBootRocketMqDemo 47 | Springboot2.0继承了RocketMQ4.3消息中间件 48 | 49 | ⭐️ SpringWebfluxDemo 50 | Webflux Spring异步编程。 51 | 52 | 53 | --------------------------------- 54 | 有兴趣的朋友可以关注一下最新开源的 55 | [spring.boot.sapi.starter](https://github.com/xiaour/spring.boot.sapi.starter) 56 | 57 | -------------------------------------------------------------------------------- /SpringBootDemo/.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | -------------------------------------------------------------------------------- /SpringBootDemo/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.github.xiaour 8 | springbootv1 9 | 0.0.1-SNAPSHOT 10 | SpringBootDemo 11 | Demo project for Spring Boot 12 | jar 13 | 14 | 15 | 16 | 17 | org.springframework.boot 18 | spring-boot-starter-parent 19 | 1.5.2.RELEASE 20 | 21 | 22 | 23 | 24 | 25 | 26 | org.springframework.boot 27 | spring-boot-starter-thymeleaf 28 | 29 | 30 | 31 | org.springframework.boot 32 | spring-boot-devtools 33 | true 34 | 35 | 36 | 37 | org.springframework.boot 38 | spring-boot-configuration-processor 39 | true 40 | 41 | 42 | 43 | org.springframework.boot 44 | spring-boot-starter-redis 45 | 1.3.8.RELEASE 46 | 47 | 48 | 49 | org.mybatis.spring.boot 50 | mybatis-spring-boot-starter 51 | 1.3.0 52 | 53 | 54 | 55 | com.alibaba 56 | druid 57 | 1.0.19 58 | 59 | 60 | 61 | mysql 62 | mysql-connector-java 63 | 64 | 65 | 66 | com.github.pagehelper 67 | pagehelper 68 | 3.7.5 69 | 70 | 71 | 72 | 73 | javax.inject 74 | javax.inject 75 | 1 76 | 77 | 78 | javax 79 | javaee-api 80 | 7.0 81 | provided 82 | 83 | 84 | 85 | javax.servlet 86 | javax.servlet-api 87 | 88 | 89 | 90 | com.google.code.gson 91 | gson 92 | 93 | 94 | 95 | commons-codec 96 | commons-codec 97 | 98 | 99 | 100 | com.alibaba 101 | fastjson 102 | 1.2.83 103 | 104 | 105 | 106 | commons-io 107 | commons-io 108 | 2.7 109 | 110 | 111 | 112 | org.apache.httpcomponents 113 | httpclient 114 | 115 | 116 | 117 | org.apache.httpcomponents 118 | httpmime 119 | 120 | 121 | 122 | 123 | org.apache.poi 124 | poi 125 | 4.1.1 126 | 127 | 128 | org.apache.poi 129 | poi-ooxml 130 | 3.13 131 | 132 | 133 | org.apache.poi 134 | ooxml-schemas 135 | 1.1 136 | 137 | 138 | 139 | 140 | 141 | 142 | 1.8 143 | 144 | 145 | 146 | 147 | 148 | org.springframework.boot 149 | spring-boot-maven-plugin 150 | 151 | 152 | 153 | 154 | -------------------------------------------------------------------------------- /SpringBootDemo/src/main/java/com/xiaour/spring/boot/Application.java: -------------------------------------------------------------------------------- 1 | package com.xiaour.spring.boot; 2 | 3 | import org.mybatis.spring.annotation.MapperScan; 4 | import org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration; 5 | import org.springframework.beans.factory.annotation.Value; 6 | import org.springframework.boot.SpringApplication; 7 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 8 | import org.springframework.boot.autoconfigure.SpringBootApplication; 9 | import org.springframework.boot.context.embedded.ConfigurableEmbeddedServletContainer; 10 | import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizer; 11 | import org.springframework.boot.web.servlet.ServletComponentScan; 12 | import org.springframework.boot.web.support.SpringBootServletInitializer; 13 | 14 | /** 15 | * 16 | * @ClassName Application 17 | * @author Zhang.Tao 18 | * @Date 2017年4月27日 下午5:30:34 19 | * @version V2.0.0 20 | */ 21 | 22 | @SpringBootApplication(exclude = MybatisAutoConfiguration.class) 23 | @ServletComponentScan 24 | @MapperScan("com.xiaour.spring.boot.mapper") 25 | public class Application extends SpringBootServletInitializer implements EmbeddedServletContainerCustomizer { 26 | 27 | @Value("${server.port}") 28 | private int port;//应用的端口 29 | /** 30 | * 启动入口 31 | * @param args 32 | */ 33 | public static void main(String ... args){ 34 | SpringApplication.run(Application.class, args); 35 | } 36 | 37 | /** 38 | * 自定义端口 39 | */ 40 | @Override 41 | public void customize(ConfigurableEmbeddedServletContainer container) { 42 | container.setPort(port); 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /SpringBootDemo/src/main/java/com/xiaour/spring/boot/config/MyBatisConfig.java: -------------------------------------------------------------------------------- 1 | package com.xiaour.spring.boot.config; 2 | 3 | import com.alibaba.druid.pool.DruidDataSource; 4 | import org.apache.ibatis.session.SqlSessionFactory; 5 | import org.mybatis.spring.SqlSessionFactoryBean; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties; 8 | import org.springframework.context.annotation.Bean; 9 | import org.springframework.context.annotation.Configuration; 10 | import org.springframework.core.io.support.PathMatchingResourcePatternResolver; 11 | 12 | 13 | /** 14 | * @Date: 2018-12-26 12:05 15 | * @version: v1.0 16 | * @Description: mybatis stater从某个版本后去掉了自动配置,需要用config配置 17 | */ 18 | @Configuration 19 | public class MyBatisConfig { 20 | 21 | @Autowired 22 | private DataSourceProperties dataSourceProperties; 23 | 24 | 25 | @Bean(name = "dataSource") 26 | public DruidDataSource dataSource() { 27 | DruidDataSource dataSource = new DruidDataSource(); 28 | dataSource.setUrl(dataSourceProperties.getUrl()); 29 | 30 | dataSource.setDriverClassName(dataSourceProperties.getDriverClassName()); 31 | dataSource.setUsername(dataSourceProperties.getUsername()); 32 | dataSource.setPassword(dataSourceProperties.getPassword()); 33 | 34 | return dataSource; 35 | 36 | } 37 | 38 | @Bean 39 | public SqlSessionFactory sqlSessionFactory() throws Exception { 40 | SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean(); 41 | sqlSessionFactoryBean.setDataSource(dataSource()); 42 | sqlSessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver() 43 | .getResources(("classpath*:mapper/*.xml"))); 44 | return sqlSessionFactoryBean.getObject(); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /SpringBootDemo/src/main/java/com/xiaour/spring/boot/controller/TestCtrl.java: -------------------------------------------------------------------------------- 1 | package com.xiaour.spring.boot.controller; 2 | 3 | 4 | import com.xiaour.spring.boot.service.RedisService; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.core.LocalVariableTableParameterNameDiscoverer; 7 | import org.springframework.core.ParameterNameDiscoverer; 8 | import org.springframework.web.bind.annotation.PathVariable; 9 | import org.springframework.web.bind.annotation.RequestMapping; 10 | import org.springframework.web.bind.annotation.RestController; 11 | 12 | import com.xiaour.spring.boot.entity.UserInfo; 13 | import com.xiaour.spring.boot.mapper.UserInfoMapper; 14 | import com.xiaour.spring.boot.utils.JsonUtil; 15 | 16 | import java.util.Arrays; 17 | import java.util.HashMap; 18 | import java.util.List; 19 | import java.util.Map; 20 | 21 | 22 | /** 23 | * Created by xiaour on 2017/4/19. 24 | */ 25 | @RestController 26 | @RequestMapping(value="/test") 27 | public class TestCtrl { 28 | 29 | @Autowired 30 | private RedisService redisService; 31 | 32 | @Autowired 33 | private UserInfoMapper userInfoMapper; 34 | 35 | @RequestMapping(value="/index") 36 | public String index(){ 37 | return "hello world"; 38 | } 39 | 40 | /** 41 | * 向redis存储值 42 | * @param key 43 | * @param value 44 | * @return 45 | * @throws Exception 46 | */ 47 | @RequestMapping("/set") 48 | public String set(String key, String value) throws Exception{ 49 | 50 | redisService.set(key, value); 51 | return "success"; 52 | } 53 | 54 | /** 55 | * 获取redis中的值 56 | * @param key 57 | * @return 58 | */ 59 | @RequestMapping("/get") 60 | public String get(String key){ 61 | try { 62 | return redisService.get(key); 63 | } catch (Exception e) { 64 | e.printStackTrace(); 65 | } 66 | return ""; 67 | } 68 | 69 | /** 70 | * 获取数据库中的用户 71 | * @param id 72 | * @return 73 | */ 74 | @RequestMapping("/getUser/{id}") 75 | public String get(@PathVariable("id")int id){ 76 | try { 77 | UserInfo user= userInfoMapper.selectByPrimaryKey(id); 78 | return JsonUtil.getJsonString(user); 79 | } catch (Exception e) { 80 | e.printStackTrace(); 81 | } 82 | return ""; 83 | } 84 | 85 | 86 | public static void main(String[] args) { 87 | Map keyMap= new HashMap<>(); 88 | keyMap.put("id","编号"); 89 | keyMap.put("name","名称"); 90 | 91 | String [] cnCloumn={"编号","名称"}; 92 | 93 | System.out.println(Arrays.asList(convertMap(keyMap, cnCloumn))); 94 | 95 | } 96 | 97 | public static String[] convertMap(Map keyMap,String [] dataList){ 98 | 99 | for(int i=0;i m:keyMap.entrySet()){ 102 | if(m.getValue().equals(dataList[i])){ 103 | dataList[i]=m.getKey(); 104 | } 105 | } 106 | } 107 | 108 | return dataList; 109 | } 110 | 111 | 112 | public static String getName(String name,String add){ 113 | return null; 114 | } 115 | 116 | public static void testGetClassName() { 117 | // 方法1:通过SecurityManager的保护方法getClassContext() 118 | String clazzName = new SecurityManager() { 119 | public String getClassName() { 120 | return getClassContext()[1].getName(); 121 | } 122 | }.getClassName(); 123 | System.out.println(clazzName); 124 | // 方法2:通过Throwable的方法getStackTrace() 125 | String clazzName2 = new Throwable().getStackTrace()[1].getClassName(); 126 | System.out.println(clazzName2); 127 | // 方法3:通过分析匿名类名称() 128 | String clazzName3 = new Object() { 129 | public String getClassName() { 130 | String clazzName = this.getClass().getName(); 131 | return clazzName.substring(0, clazzName.lastIndexOf('$')); 132 | } 133 | }.getClassName(); 134 | System.out.println(clazzName3); 135 | //方法4:通过Thread的方法getStackTrace() 136 | String clazzName4 = Thread.currentThread().getStackTrace()[2].getClassName(); 137 | System.out.println(clazzName4); 138 | } 139 | 140 | 141 | 142 | } 143 | -------------------------------------------------------------------------------- /SpringBootDemo/src/main/java/com/xiaour/spring/boot/entity/UserInfo.java: -------------------------------------------------------------------------------- 1 | package com.xiaour.spring.boot.entity; 2 | 3 | import java.util.Date; 4 | 5 | public class UserInfo { 6 | private Integer id; 7 | 8 | private String name; 9 | 10 | private String age; 11 | 12 | public Integer getId() { 13 | return id; 14 | } 15 | 16 | public void setId(Integer id) { 17 | this.id = id; 18 | } 19 | 20 | public String getName() { 21 | return name; 22 | } 23 | 24 | public void setName(String name) { 25 | this.name = name; 26 | } 27 | 28 | public String getAge() { 29 | return age; 30 | } 31 | 32 | public void setAge(String age) { 33 | this.age = age; 34 | } 35 | 36 | } -------------------------------------------------------------------------------- /SpringBootDemo/src/main/java/com/xiaour/spring/boot/exception/OApiException.java: -------------------------------------------------------------------------------- 1 | package com.xiaour.spring.boot.exception; 2 | 3 | public class OApiException extends Exception { 4 | 5 | public OApiException(int errCode, String errMsg) { 6 | super("error code: " + errCode + ", error message: " + errMsg); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /SpringBootDemo/src/main/java/com/xiaour/spring/boot/exception/OApiResultException.java: -------------------------------------------------------------------------------- 1 | package com.xiaour.spring.boot.exception; 2 | 3 | public class OApiResultException extends OApiException { 4 | 5 | public static final int ERR_RESULT_RESOLUTION = -2; 6 | 7 | public OApiResultException(String field) { 8 | super(ERR_RESULT_RESOLUTION, "Cannot resolve field " + field + " from oapi resonpse"); 9 | } 10 | 11 | } 12 | -------------------------------------------------------------------------------- /SpringBootDemo/src/main/java/com/xiaour/spring/boot/filter/DruidStatFilter.java: -------------------------------------------------------------------------------- 1 | package com.xiaour.spring.boot.filter; 2 | 3 | import javax.servlet.annotation.WebFilter; 4 | import javax.servlet.annotation.WebInitParam; 5 | 6 | import com.alibaba.druid.support.http.WebStatFilter; 7 | 8 | @WebFilter(filterName="druidWebStatFilter",urlPatterns="/*", 9 | initParams={ 10 | @WebInitParam(name="exclusions",value="*.js,*.gif,*.jpg,*.bmp,*.png,*.css,*.ico,/druid/*")// 忽略资源 11 | }) 12 | public class DruidStatFilter extends WebStatFilter{ 13 | 14 | } 15 | -------------------------------------------------------------------------------- /SpringBootDemo/src/main/java/com/xiaour/spring/boot/filter/MyFilter.java: -------------------------------------------------------------------------------- 1 | package com.xiaour.spring.boot.filter; 2 | 3 | import java.io.IOException; 4 | 5 | import javax.servlet.Filter; 6 | import javax.servlet.FilterChain; 7 | import javax.servlet.FilterConfig; 8 | import javax.servlet.ServletException; 9 | import javax.servlet.ServletRequest; 10 | import javax.servlet.ServletResponse; 11 | import javax.servlet.annotation.WebFilter; 12 | import javax.servlet.annotation.WebInitParam; 13 | import javax.servlet.annotation.WebServlet; 14 | import javax.servlet.http.HttpServletRequest; 15 | import javax.servlet.http.HttpServletResponse; 16 | 17 | import org.springframework.boot.context.properties.ConfigurationProperties; 18 | 19 | import com.alibaba.druid.support.http.StatViewServlet; 20 | 21 | /** 22 | * Created by xiaour on 2017/4/19. 23 | */ 24 | @WebServlet(urlPatterns = "/druid/*", 25 | initParams={ 26 | @WebInitParam(name="allow",value=""),// IP白名单 (没有配置或者为空,则允许所有访问) 27 | @WebInitParam(name="deny",value="192.168.0.1"),// IP黑名单 (存在共同时,deny优先于allow) 28 | @WebInitParam(name="loginUsername",value="root"),// 用户名 29 | @WebInitParam(name="loginPassword",value="123456"),// 密码 30 | @WebInitParam(name="resetEnable",value="false")// 禁用HTML页面上的“Reset All”功能 31 | }) 32 | @ConfigurationProperties("cacheServer") 33 | @WebFilter(filterName="myFilter",urlPatterns="/*") 34 | public class MyFilter extends StatViewServlet implements Filter{ 35 | 36 | 37 | /** 38 | */ 39 | private static final long serialVersionUID = 1L; 40 | 41 | @Override 42 | public void init(FilterConfig filterConfig) throws ServletException { 43 | 44 | } 45 | 46 | @Override 47 | public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { 48 | HttpServletRequest request = (HttpServletRequest) servletRequest; 49 | System.out.println(request.getRequestURI()); 50 | HttpServletResponse response = (HttpServletResponse) servletResponse; 51 | filterChain.doFilter(request, response); 52 | } 53 | 54 | @Override 55 | public void destroy() { 56 | 57 | } 58 | 59 | 60 | 61 | } 62 | -------------------------------------------------------------------------------- /SpringBootDemo/src/main/java/com/xiaour/spring/boot/mapper/UserInfoMapper.java: -------------------------------------------------------------------------------- 1 | package com.xiaour.spring.boot.mapper; 2 | 3 | import com.xiaour.spring.boot.entity.UserInfo; 4 | import org.apache.ibatis.annotations.Mapper; 5 | import org.springframework.stereotype.Component; 6 | 7 | @Component 8 | @Mapper 9 | public interface UserInfoMapper { 10 | 11 | UserInfo selectByPrimaryKey(Integer id); 12 | 13 | } -------------------------------------------------------------------------------- /SpringBootDemo/src/main/java/com/xiaour/spring/boot/service/RedisService.java: -------------------------------------------------------------------------------- 1 | package com.xiaour.spring.boot.service; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * Created by zhangtao on 2017/11/8. 7 | */ 8 | 9 | public interface RedisService { 10 | 11 | boolean set(String key, String value) throws Exception; 12 | 13 | String get(String key) throws Exception; 14 | 15 | boolean expire(String key, long expire) throws Exception; 16 | 17 | boolean setList(String key, List list) throws Exception; 18 | 19 | List getList(String key, Class clz) throws Exception; 20 | 21 | long lpush(String key, Object obj) throws Exception; 22 | 23 | long rpush(String key, Object obj) throws Exception; 24 | 25 | void hmset(String key, Object obj) throws Exception; 26 | 27 | T hget(String key, Class clz) throws Exception; 28 | 29 | 30 | void del(String key) throws Exception; 31 | 32 | List hmGetAll(String key, Class clz) throws Exception; 33 | 34 | String lpop(String key) throws Exception; 35 | } 36 | -------------------------------------------------------------------------------- /SpringBootDemo/src/main/java/com/xiaour/spring/boot/service/impl/RedisServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.xiaour.spring.boot.service.impl; 2 | 3 | 4 | import com.xiaour.spring.boot.service.RedisService; 5 | import com.xiaour.spring.boot.utils.JsonUtil; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.dao.DataAccessException; 8 | import org.springframework.data.redis.connection.RedisConnection; 9 | import org.springframework.data.redis.core.RedisCallback; 10 | import org.springframework.data.redis.core.RedisTemplate; 11 | import org.springframework.data.redis.serializer.RedisSerializer; 12 | import org.springframework.stereotype.Service; 13 | import org.springframework.transaction.annotation.Transactional; 14 | import org.springframework.util.Assert; 15 | 16 | import java.util.*; 17 | import java.util.concurrent.TimeUnit; 18 | 19 | /** 20 | * Created by xiaour.github.com on 2017/11/8. 21 | */ 22 | @Service("redisService") 23 | @Transactional(rollbackFor = Exception.class) 24 | public class RedisServiceImpl implements RedisService { 25 | 26 | private static int seconds=3600*24; 27 | 28 | @Autowired 29 | private RedisTemplate redisTemplate; 30 | 31 | @Override 32 | public boolean set(final String key, final String value) throws Exception { 33 | Assert.hasText(key,"Key is not empty."); 34 | boolean result = redisTemplate.execute(new RedisCallback() { 35 | @Override 36 | public Boolean doInRedis(RedisConnection connection) throws DataAccessException { 37 | RedisSerializer serializer = redisTemplate.getStringSerializer(); 38 | connection.set(serializer.serialize(key), serializer.serialize(value)); 39 | return true; 40 | } 41 | }); 42 | return result; 43 | } 44 | 45 | public String get(final String key) throws Exception { 46 | Assert.hasText(key,"Key is not empty."); 47 | String result = redisTemplate.execute(new RedisCallback() { 48 | @Override 49 | public String doInRedis(RedisConnection connection) throws DataAccessException { 50 | RedisSerializer serializer = redisTemplate.getStringSerializer(); 51 | byte[] value = connection.get(serializer.serialize(key)); 52 | return serializer.deserialize(value); 53 | } 54 | }); 55 | return result; 56 | } 57 | 58 | public void del(final String key) throws Exception { 59 | Assert.hasText(key,"Key is not empty."); 60 | 61 | redisTemplate.execute(new RedisCallback() { 62 | @Override 63 | public Long doInRedis(RedisConnection conn) throws DataAccessException { 64 | RedisSerializer serializer = redisTemplate.getStringSerializer(); 65 | return conn.del(serializer.serialize(key)); 66 | } 67 | }); 68 | } 69 | 70 | 71 | 72 | @Override 73 | public boolean expire(final String key, long expire) { 74 | return redisTemplate.expire(key, expire, TimeUnit.SECONDS); 75 | } 76 | 77 | @Override 78 | public boolean setList(String key, List list) throws Exception { 79 | Assert.hasText(key,"Key is not empty."); 80 | 81 | String value = JsonUtil.getJsonString(list); 82 | return set(key,value); 83 | } 84 | 85 | @Override 86 | public List getList(String key,Class clz) throws Exception{ 87 | 88 | Assert.hasText(key,"Key is not empty."); 89 | 90 | String json = get(key); 91 | if(json!=null){ 92 | List list = JsonUtil.readJson2Array(json,clz); 93 | return list; 94 | } 95 | return null; 96 | } 97 | 98 | @Override 99 | public long lpush(final String key, Object obj)throws Exception { 100 | Assert.hasText(key,"Key is not empty."); 101 | 102 | final String value = JsonUtil.getJsonString(obj); 103 | long result = redisTemplate.execute(new RedisCallback() { 104 | @Override 105 | public Long doInRedis(RedisConnection connection) throws DataAccessException { 106 | RedisSerializer serializer = redisTemplate.getStringSerializer(); 107 | long count = connection.lPush(serializer.serialize(key), serializer.serialize(value)); 108 | return count; 109 | } 110 | }); 111 | return result; 112 | } 113 | 114 | @Override 115 | public long rpush(final String key, Object obj) throws Exception{ 116 | Assert.hasText(key,"Key is not empty."); 117 | 118 | final String value = JsonUtil.getJsonString(obj); 119 | long result = redisTemplate.execute(new RedisCallback() { 120 | @Override 121 | public Long doInRedis(RedisConnection connection) throws DataAccessException { 122 | RedisSerializer serializer = redisTemplate.getStringSerializer(); 123 | long count = connection.rPush(serializer.serialize(key), serializer.serialize(value)); 124 | return count; 125 | } 126 | }); 127 | return result; 128 | } 129 | 130 | @Override 131 | public void hmset(String key, Object obj) throws Exception{ 132 | Assert.hasText(key,"Key is not empty."); 133 | 134 | Map data=JsonUtil.readJsonByteMap(JsonUtil.getJsonString(obj)); 135 | redisTemplate.execute(new RedisCallback() { 136 | @Override 137 | public String doInRedis(RedisConnection connection) throws DataAccessException { 138 | RedisSerializer serializer = redisTemplate.getStringSerializer(); 139 | connection.hMSet(serializer.serialize(key),data); 140 | return ""; 141 | } 142 | }); 143 | } 144 | 145 | @Override 146 | public T hget(String key, Class clz) throws Exception{ 147 | Assert.hasText(key,"Key is not empty."); 148 | 149 | return redisTemplate.execute(new RedisCallback() { 150 | 151 | @Override 152 | public T doInRedis(RedisConnection connection) throws DataAccessException { 153 | RedisSerializer serializer = redisTemplate.getStringSerializer(); 154 | 155 | Map result; 156 | 157 | Map data=connection.hGetAll(serializer.serialize(key)); 158 | result= new HashMap<>(); 159 | for (Map.Entry entry: data.entrySet()) { 160 | result.put(serializer.deserialize(entry.getKey()),serializer.deserialize(entry.getValue())); 161 | } 162 | 163 | return JsonUtil.json2Obj(JsonUtil.getJsonString(result),clz); 164 | } 165 | }); 166 | } 167 | 168 | @Override 169 | public List hmGetAll(String key,Class clz) throws Exception{ 170 | Assert.hasText(key,"Key is not empty."); 171 | 172 | List> dataList= new ArrayList<>(); 173 | return redisTemplate.execute(new RedisCallback>() { 174 | @Override 175 | public List doInRedis(RedisConnection connection) throws DataAccessException { 176 | RedisSerializer serializer = redisTemplate.getStringSerializer(); 177 | 178 | Set keysSet=redisTemplate.keys(key); 179 | Map data; 180 | Map result; 181 | for(String newKey:keysSet) { 182 | data=connection.hGetAll(serializer.serialize(newKey)); 183 | result= new HashMap<>(); 184 | for (Map.Entry entry: data.entrySet()) { 185 | result.put(serializer.deserialize(entry.getKey()),serializer.deserialize(entry.getValue())); 186 | } 187 | dataList.add(result); 188 | } 189 | return JsonUtil.readJson2Array(JsonUtil.getJsonString(dataList),clz); 190 | } 191 | }); 192 | } 193 | 194 | @Override 195 | public String lpop(final String key) throws Exception{ 196 | Assert.hasText(key,"Key is not empty."); 197 | 198 | String result = redisTemplate.execute(new RedisCallback() { 199 | @Override 200 | public String doInRedis(RedisConnection connection) throws DataAccessException { 201 | RedisSerializer serializer = redisTemplate.getStringSerializer(); 202 | byte[] res = connection.lPop(serializer.serialize(key)); 203 | return serializer.deserialize(res); 204 | } 205 | }); 206 | return result; 207 | } 208 | } 209 | -------------------------------------------------------------------------------- /SpringBootDemo/src/main/java/com/xiaour/spring/boot/task/Task.java: -------------------------------------------------------------------------------- 1 | package com.xiaour.spring.boot.task; 2 | 3 | import org.springframework.context.annotation.Configuration; 4 | import org.springframework.scheduling.annotation.EnableScheduling; 5 | import org.springframework.scheduling.annotation.Scheduled; 6 | 7 | @Configuration 8 | @EnableScheduling // 启用定时任务 9 | public class Task { 10 | 11 | @Scheduled(cron="0 0/1 * * * ?") 12 | public void run(){ 13 | System.out.println("Scheduled Running..."); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /SpringBootDemo/src/main/java/com/xiaour/spring/boot/utils/JsonUtil.java: -------------------------------------------------------------------------------- 1 | package com.xiaour.spring.boot.utils; 2 | 3 | import com.google.gson.*; 4 | import com.google.gson.reflect.TypeToken; 5 | 6 | import java.lang.reflect.Type; 7 | import java.util.ArrayList; 8 | import java.util.HashMap; 9 | import java.util.List; 10 | import java.util.Map; 11 | 12 | public class JsonUtil { 13 | 14 | private static Gson gson = null; 15 | 16 | static{ 17 | gson = new Gson(); 18 | } 19 | 20 | public static synchronized Gson newInstance(){ 21 | if(gson == null){ 22 | gson = new Gson(); 23 | } 24 | return gson; 25 | } 26 | 27 | public static String getJsonString(Object obj){ 28 | return gson.toJson(obj); 29 | } 30 | 31 | public static T toBean(String json,Class clz){ 32 | 33 | return gson.fromJson(json, clz); 34 | } 35 | 36 | public static Map readJson2MapObj(String json,Class clz){ 37 | Map map = gson.fromJson(json, new TypeToken>(){}.getType()); 38 | Map result = new HashMap<>(); 39 | for(String key:map.keySet()){ 40 | result.put(key,gson.fromJson(map.get(key),clz) ); 41 | } 42 | return result; 43 | } 44 | 45 | public static T json2Obj(String json,Class clz){ 46 | return gson.fromJson(json,clz); 47 | } 48 | 49 | public static Map toMap(String json){ 50 | Map map = gson.fromJson(json, new TypeToken>(){}.getType()); 51 | return map; 52 | } 53 | 54 | public static Map readJsonStrMap(String json) { 55 | Map map = gson.fromJson(json, new TypeToken>(){}.getType()); 56 | Map result = new HashMap<>(); 57 | for(String key:map.keySet()){ 58 | result.put(key,gson.fromJson(map.get(key),String.class) ); 59 | } 60 | return result; 61 | } 62 | 63 | public static Map readJsonByteMap(String json) { 64 | Map map = gson.fromJson(json, new TypeToken>(){}.getType()); 65 | Map vmap = new HashMap<>(); 66 | for(String key:map.keySet()){ 67 | vmap.put(key.getBytes(),gson.fromJson(map.get(key),String.class).getBytes() ); 68 | } 69 | return vmap; 70 | 71 | } 72 | 73 | 74 | public static List readJson2Array(String json, Class clz){ 75 | JsonArray array = new JsonParser().parse(json).getAsJsonArray(); 76 | List list = new ArrayList<>(); 77 | for(final JsonElement elem : array){ 78 | list.add(gson.fromJson(elem, (Type)clz)); 79 | } 80 | return list; 81 | } 82 | 83 | } -------------------------------------------------------------------------------- /SpringBootDemo/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | #服务启动端口 2 | server : 3 | port : 8080 4 | 5 | #数据库配置 6 | spring: 7 | datasource: 8 | url: jdbc:mysql://127.0.0.1:9966/study?useUnicode=true&characterEncoding=utf8&allowMultiQueries=true&autoReconnect=true&useSSL=false&verifyServerCertificate=false 9 | username: your.account 10 | password: your.pass 11 | # 使用druid数据源 12 | type: com.alibaba.druid.pool.DruidDataSource 13 | driver-class-name: com.mysql.jdbc.Driver 14 | redis: 15 | host: 127.0.0.1 16 | #redis密码,没有密码的可以用~表示 17 | password: ~ 18 | port: 6379 19 | pool: 20 | max-active: 100 21 | max-idle: 10 22 | max-wait: 100000 23 | # Mybatis mapper 映射路径配置 24 | mybatis: 25 | type-aliases-package: com.xiaour.spring.boot.mapper 26 | mapper-locations: classpath*:mapper/*.xml 27 | configLocation: classpath:mybatis-config.xml 28 | 29 | # 日志输出 30 | logging: 31 | file: D:/boot.log 32 | level: 33 | com.ibatis:DEBUG 34 | root:DEBUG 35 | 36 | task: 37 | cron:0 0/5 * * * ? 38 | 39 | 40 | -------------------------------------------------------------------------------- /SpringBootDemo/src/main/resources/mapper/UserInfoMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /SpringBootDemo/src/main/resources/mybatis-config.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /SpringBootDemoV2/.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | !.mvn/wrapper/maven-wrapper.jar 3 | 4 | ### STS ### 5 | .apt_generated 6 | .classpath 7 | .factorypath 8 | .project 9 | .settings 10 | .springBeans 11 | 12 | ### IntelliJ IDEA ### 13 | .idea 14 | *.iws 15 | *.iml 16 | *.ipr 17 | 18 | ### NetBeans ### 19 | nbproject/private/ 20 | build/ 21 | nbbuild/ 22 | dist/ 23 | nbdist/ 24 | .nb-gradle/ -------------------------------------------------------------------------------- /SpringBootDemoV2/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | com.github.xiaour 7 | springbootv2 8 | 0.0.1-SNAPSHOT 9 | SpringBootDemoV2 10 | Demo project for Spring Boot V2 11 | jar 12 | 13 | 14 | 15 | org.springframework.boot 16 | spring-boot-starter-parent 17 | 2.4.2 18 | 19 | 20 | 21 | 22 | UTF-8 23 | UTF-8 24 | 1.8 25 | 26 | 27 | 28 | 29 | org.springframework.boot 30 | spring-boot-starter-data-redis 31 | 32 | 33 | 34 | org.springframework.boot 35 | spring-boot-starter-web 36 | 37 | 38 | 39 | com.alibaba.boot 40 | dubbo-spring-boot-starter 41 | 0.1.0 42 | 43 | 44 | 45 | org.apache.zookeeper 46 | zookeeper 47 | 3.7.2 48 | 49 | 50 | 51 | 52 | org.springframework.boot 53 | spring-boot-starter-test 54 | test 55 | 56 | 57 | 58 | com.google.code.gson 59 | gson 60 | 2.8.9 61 | 62 | 63 | 64 | commons-codec 65 | commons-codec 66 | 1.10 67 | 68 | 69 | 70 | junit 71 | junit 72 | 4.13.1 73 | 74 | 75 | 76 | org.jodd 77 | jodd-http 78 | 3.7.1 79 | 80 | 81 | 82 | org.apache.httpcomponents 83 | httpclient 84 | 85 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | org.springframework.boot 99 | spring-boot-maven-plugin 100 | 101 | 102 | 103 | 104 | 105 | 106 | -------------------------------------------------------------------------------- /SpringBootDemoV2/src/main/java/com/github/xiaour/Application.java: -------------------------------------------------------------------------------- 1 | package com.github.xiaour; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | 7 | @SpringBootApplication 8 | public class Application { 9 | 10 | 11 | 12 | public static void main(String[] args) { 13 | //SpringApplication.run(Application.class, args); 14 | 15 | 16 | } 17 | 18 | 19 | 20 | } 21 | -------------------------------------------------------------------------------- /SpringBootDemoV2/src/main/java/com/github/xiaour/config/DuckPorperties.java: -------------------------------------------------------------------------------- 1 | package com.github.xiaour.config; 2 | 3 | import org.springframework.boot.context.properties.ConfigurationProperties; 4 | import org.springframework.context.annotation.Configuration; 5 | 6 | /** 7 | * @Author: Xiaour 8 | * @Description: 9 | * @Date: 2018/3/1 下午5:04 10 | */ 11 | @Configuration 12 | @ConfigurationProperties(prefix="duck") 13 | public class DuckPorperties{ 14 | 15 | private String duckName; 16 | 17 | private int totalCount; 18 | 19 | public String getDuckName() { 20 | return duckName; 21 | } 22 | 23 | public void setDuckName(String duckName) { 24 | this.duckName = duckName; 25 | } 26 | 27 | public int getTotalCount() { 28 | return totalCount; 29 | } 30 | 31 | public void setTotalCount(int totalCount) { 32 | this.totalCount = totalCount; 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /SpringBootDemoV2/src/main/java/com/github/xiaour/constants/Api.java: -------------------------------------------------------------------------------- 1 | package com.github.xiaour.constants; 2 | 3 | /** 4 | * @Author: Xiaour 5 | * @Description: 6 | * @Date: 2018/3/13 上午10:09 7 | */ 8 | public class Api { 9 | 10 | /** 11 | * 获取第三方平台component_access_token 12 | */ 13 | public static final String component_token="https://api.weixin.qq.com/cgi-bin/component/api_component_token"; 14 | 15 | /** 16 | * 获取预授权码pre_auth_code 17 | */ 18 | public static final String create_preauthcode="https://api.weixin.qq.com/cgi-bin/component/api_create_preauthcode?component_access_token="; 19 | 20 | /** 21 | * 使用授权码换取公众号或小程序的接口调用凭据和授权信息 22 | */ 23 | public static final String query_auth="https://api.weixin.qq.com/cgi-bin/component/api_query_auth?component_access_token="; 24 | 25 | /** 26 | * 获取(刷新)授权公众号或小程序的接口调用凭据(令牌) 27 | */ 28 | public static final String authorizer_token="https:// api.weixin.qq.com /cgi-bin/component/api_authorizer_token?component_access_token="; 29 | 30 | /** 31 | * 获取授权方的帐号基本信息 32 | */ 33 | public static final String get_authorizer_info="https://api.weixin.qq.com/cgi-bin/component/api_get_authorizer_info?component_access_token="; 34 | 35 | /** 36 | * 获取授权方的选项设置信息 37 | */ 38 | public static final String get_authorizer_option="https://api.weixin.qq.com/cgi-bin/component/api_get_authorizer_option?component_access_token="; 39 | 40 | /** 41 | * 设置授权方的选项信息 42 | */ 43 | public static final String set_authorizer_option="https://api.weixin.qq.com/cgi-bin/component/api_set_authorizer_option?component_access_token="; 44 | 45 | 46 | enum Type{ 47 | A; 48 | } 49 | 50 | 51 | } 52 | -------------------------------------------------------------------------------- /SpringBootDemoV2/src/main/java/com/github/xiaour/controller/DemoController.java: -------------------------------------------------------------------------------- 1 | package com.github.xiaour.controller; 2 | 3 | import com.github.xiaour.config.DuckPorperties; 4 | import org.springframework.beans.factory.annotation.Autowired; 5 | import org.springframework.boot.context.properties.bind.Binder; 6 | import org.springframework.web.bind.annotation.RequestMapping; 7 | import org.springframework.web.bind.annotation.RestController; 8 | 9 | import java.util.HashMap; 10 | import java.util.Map; 11 | 12 | /** 13 | * @Author: Xiaour 14 | * @Description: 15 | * @Date: 2018/3/1 下午4:54 16 | */ 17 | @RestController 18 | public class DemoController { 19 | @Autowired 20 | private DuckPorperties duckPorperties; 21 | 22 | @RequestMapping("/amazing") 23 | public Map amazing() { 24 | /** 25 | * 如果不需要其他的结构,可以直接返回对象类型,不必要强制JSON格式。Springboot默认支持转为json 26 | */ 27 | Map obj= new HashMap<>(); 28 | obj.put("name","xiaour"); 29 | obj.put("age","18"); 30 | obj.put("age","18"); 31 | return obj; 32 | } 33 | 34 | @RequestMapping("/duck") 35 | public String duck() { 36 | /** 37 | * 自动装配模式的配置文件属性。 38 | */ 39 | return duckPorperties.getDuckName(); 40 | } 41 | 42 | 43 | 44 | 45 | } 46 | -------------------------------------------------------------------------------- /SpringBootDemoV2/src/main/java/com/github/xiaour/exception/AesException.java: -------------------------------------------------------------------------------- 1 | package com.github.xiaour.exception; 2 | 3 | @SuppressWarnings("serial") 4 | public class AesException extends Exception { 5 | 6 | public final static int OK = 0; 7 | public final static int ValidateSignatureError = -40001; 8 | public final static int ParseXmlError = -40002; 9 | public final static int ComputeSignatureError = -40003; 10 | public final static int IllegalAesKey = -40004; 11 | public final static int ValidateAppidError = -40005; 12 | public final static int EncryptAESError = -40006; 13 | public final static int DecryptAESError = -40007; 14 | public final static int IllegalBuffer = -40008; 15 | //public final static int EncodeBase64Error = -40009; 16 | //public final static int DecodeBase64Error = -40010; 17 | //public final static int GenReturnXmlError = -40011; 18 | 19 | private int code; 20 | 21 | private static String getMessage(int code) { 22 | switch (code) { 23 | case ValidateSignatureError: 24 | return "签名验证错误"; 25 | case ParseXmlError: 26 | return "xml解析失败"; 27 | case ComputeSignatureError: 28 | return "sha加密生成签名失败"; 29 | case IllegalAesKey: 30 | return "SymmetricKey非法"; 31 | case ValidateAppidError: 32 | return "appid校验失败"; 33 | case EncryptAESError: 34 | return "aes加密失败"; 35 | case DecryptAESError: 36 | return "aes解密失败"; 37 | case IllegalBuffer: 38 | return "解密后得到的buffer非法"; 39 | // case EncodeBase64Error: 40 | // return "base64加密错误"; 41 | // case DecodeBase64Error: 42 | // return "base64解密错误"; 43 | // case GenReturnXmlError: 44 | // return "xml生成失败"; 45 | default: 46 | return null; // cannot be 47 | } 48 | } 49 | 50 | public int getCode() { 51 | return code; 52 | } 53 | 54 | public AesException(int code) { 55 | super(getMessage(code)); 56 | this.code = code; 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /SpringBootDemoV2/src/main/java/com/github/xiaour/exception/OApiException.java: -------------------------------------------------------------------------------- 1 | package com.github.xiaour.exception; 2 | 3 | import java.io.IOException; 4 | 5 | public class OApiException extends Exception { 6 | 7 | /** 8 | */ 9 | private static final long serialVersionUID = 1L; 10 | 11 | public OApiException(int errCode, String errMsg) { 12 | super("error code: " + errCode + ", error message: " + errMsg); 13 | } 14 | 15 | public OApiException(IOException e) { 16 | super(e); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /SpringBootDemoV2/src/main/java/com/github/xiaour/service/DubboService.java: -------------------------------------------------------------------------------- 1 | package com.github.xiaour.service; 2 | 3 | /** 4 | * @Author: Xiaour 5 | * @Description: 6 | * @Date: 2018/4/25 16:57 7 | */ 8 | 9 | public interface DubboService { 10 | 11 | String hello(String name); 12 | 13 | 14 | } 15 | -------------------------------------------------------------------------------- /SpringBootDemoV2/src/main/java/com/github/xiaour/service/impl/DubboServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.github.xiaour.service.impl; 2 | 3 | import com.alibaba.dubbo.config.annotation.Service; 4 | import com.github.xiaour.service.DubboService; 5 | 6 | /** 7 | * @Author: Xiaour 8 | * @Description: 9 | * @Date: 2018/4/25 16:59 10 | */ 11 | 12 | 13 | @Service( 14 | version = "1.0.0", 15 | application = "${dubbo.application.id}", 16 | protocol = "${dubbo.protocol.id}", 17 | registry = "${dubbo.registry.id}" 18 | ) 19 | public class DubboServiceImpl implements DubboService { 20 | @Override 21 | public String hello(String name) { 22 | return "Hello,"+name; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /SpringBootDemoV2/src/main/java/com/github/xiaour/utils/ByteGroup.java: -------------------------------------------------------------------------------- 1 | package com.github.xiaour.utils; 2 | 3 | import java.util.ArrayList; 4 | 5 | class ByteGroup { 6 | ArrayList byteContainer = new ArrayList(); 7 | 8 | public byte[] toBytes() { 9 | byte[] bytes = new byte[byteContainer.size()]; 10 | for (int i = 0; i < byteContainer.size(); i++) { 11 | bytes[i] = byteContainer.get(i); 12 | } 13 | return bytes; 14 | } 15 | 16 | public ByteGroup addBytes(byte[] bytes) { 17 | for (byte b : bytes) { 18 | byteContainer.add(b); 19 | } 20 | return this; 21 | } 22 | 23 | public int size() { 24 | return byteContainer.size(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /SpringBootDemoV2/src/main/java/com/github/xiaour/utils/HttpHelper.java: -------------------------------------------------------------------------------- 1 | package com.github.xiaour.utils; 2 | 3 | 4 | 5 | import com.github.xiaour.constants.Api; 6 | import com.github.xiaour.exception.OApiException; 7 | import com.google.gson.JsonObject; 8 | import org.apache.http.HttpEntity; 9 | import org.apache.http.client.config.RequestConfig; 10 | import org.apache.http.client.methods.CloseableHttpResponse; 11 | import org.apache.http.client.methods.HttpGet; 12 | import org.apache.http.client.methods.HttpPost; 13 | import org.apache.http.entity.StringEntity; 14 | import org.apache.http.impl.client.CloseableHttpClient; 15 | import org.apache.http.impl.client.HttpClients; 16 | import org.apache.http.protocol.BasicHttpContext; 17 | import org.apache.http.util.EntityUtils; 18 | import org.springframework.web.client.RestTemplate; 19 | 20 | import java.io.IOException; 21 | import java.util.Map; 22 | 23 | 24 | public class HttpHelper { 25 | 26 | 27 | private static RestTemplate restTemplate = new RestTemplate(); 28 | 29 | private static JsonObject jsonObject = null; 30 | 31 | static{ 32 | jsonObject = new JsonObject(); 33 | } 34 | 35 | public static synchronized JsonObject instance(){ 36 | if(jsonObject == null){ 37 | jsonObject = new JsonObject(); 38 | } 39 | return jsonObject; 40 | } 41 | 42 | 43 | public static JsonObject httpGet(String url) throws OApiException { 44 | HttpGet httpGet = new HttpGet(url); 45 | CloseableHttpResponse response = null; 46 | CloseableHttpClient httpClient = HttpClients.createDefault(); 47 | RequestConfig requestConfig = RequestConfig.custom(). 48 | setSocketTimeout(10000).setConnectTimeout(10000).build(); 49 | httpGet.setConfig(requestConfig); 50 | 51 | try { 52 | response = httpClient.execute(httpGet, new BasicHttpContext()); 53 | 54 | if (response.getStatusLine().getStatusCode() != 200) { 55 | return null; 56 | } 57 | HttpEntity entity = response.getEntity(); 58 | if (entity != null) { 59 | String resultStr = EntityUtils.toString(entity, "utf-8"); 60 | return jsonObject.getAsJsonObject(resultStr); 61 | 62 | } 63 | } catch (IOException e) { 64 | throw new OApiException(e); 65 | } finally { 66 | if (response != null) try { 67 | response.close(); 68 | } catch (IOException e) { 69 | throw new OApiException(e); 70 | } 71 | } 72 | 73 | return null; 74 | } 75 | 76 | 77 | public static String postXmlStr(String url,String xmlStr) throws OApiException { 78 | HttpPost httpPost = new HttpPost(url); 79 | CloseableHttpResponse response = null; 80 | CloseableHttpClient httpClient = HttpClients.createDefault(); 81 | RequestConfig requestConfig = RequestConfig.custom(). 82 | setSocketTimeout(10000).setConnectTimeout(10000).build(); 83 | httpPost.setConfig(requestConfig); 84 | httpPost.addHeader("Content-Type", "application/xml"); 85 | try { 86 | StringEntity requestEntity = new StringEntity(xmlStr, "utf-8"); 87 | httpPost.setEntity(requestEntity); 88 | 89 | response = httpClient.execute(httpPost, new BasicHttpContext()); 90 | 91 | if (response.getStatusLine().getStatusCode() != 200) { 92 | 93 | return null; 94 | } 95 | HttpEntity entity = response.getEntity(); 96 | if (entity != null) { 97 | String resultStr = EntityUtils.toString(entity, "utf-8"); 98 | return resultStr; 99 | } 100 | } catch (IOException e) { 101 | throw new OApiException(e); 102 | } finally { 103 | if (response != null) try { 104 | response.close(); 105 | } catch (IOException e) { 106 | throw new OApiException(e); 107 | } 108 | } 109 | 110 | return null; 111 | } 112 | 113 | 114 | public static JsonObject httpPost(String url, Object data) throws OApiException { 115 | HttpPost httpPost = new HttpPost(url); 116 | CloseableHttpResponse response = null; 117 | CloseableHttpClient httpClient = HttpClients.createDefault(); 118 | RequestConfig requestConfig = RequestConfig.custom(). 119 | setSocketTimeout(10000).setConnectTimeout(10000).build(); 120 | httpPost.setConfig(requestConfig); 121 | httpPost.addHeader("Content-Type", "application/json"); 122 | try { 123 | String dataStr=JsonUtil.getJsonString(data); 124 | StringEntity requestEntity = new StringEntity(dataStr, "utf-8"); 125 | httpPost.setEntity(requestEntity); 126 | response = httpClient.execute(httpPost, new BasicHttpContext()); 127 | 128 | if (response.getStatusLine().getStatusCode() != 200) { 129 | 130 | return null; 131 | } 132 | 133 | HttpEntity entity = response.getEntity(); 134 | 135 | if (entity != null) { 136 | String resultStr = EntityUtils.toString(entity, "utf-8"); 137 | return jsonObject.getAsJsonObject(resultStr); 138 | } 139 | } catch (IOException e) { 140 | throw new OApiException(e); 141 | } finally { 142 | if (response != null) try { 143 | response.close(); 144 | } catch (IOException e) { 145 | throw new OApiException(e); 146 | } 147 | } 148 | 149 | return null; 150 | } 151 | 152 | 153 | 154 | /** 155 | * Get方法 156 | * 157 | * @param url:地址 158 | * @param returnClassName:返回对象类型,如:String.class 159 | * @param parameters:parameter参数 160 | * @return 161 | */ 162 | public static T getByRest(String url, Class returnClassName, Map parameters){ 163 | if (parameters == null) { 164 | return restTemplate.getForObject(url, returnClassName); 165 | } 166 | return restTemplate.getForObject(url, returnClassName, parameters); 167 | } 168 | 169 | /** 170 | * post请求,包含了路径,返回类型,Header,Parameter 171 | * 172 | * @param url:地址 173 | * @param returnClassName:返回对象类型,如:String.class 174 | * @param inputParameter 175 | * @param jsonBody 176 | * @return 177 | */ 178 | public static T postByRest(String url,Class returnClassName,Map inputParameter,String jsonBody){ 179 | 180 | org.springframework.http.HttpEntity formEntity = new org.springframework.http.HttpEntity<>(jsonBody); 181 | if (inputParameter==null) { 182 | return restTemplate.postForObject(url, formEntity, returnClassName); 183 | } 184 | return restTemplate.postForObject(url, formEntity, returnClassName, inputParameter); 185 | } 186 | 187 | 188 | /* 189 | public static String postWithKey(String appid,String keyPath, String url, WxRefundDto dto) throws OApiException { 190 | SSLContext sslContext = Pksc12KeyStore.initSSLContext(appid,dto.getMch_id(),keyPath); 191 | HttpRequest request = HttpRequest.post(url).withConnectionProvider(new SSLSocketHttpConnectionProvider(sslContext)); 192 | request.bodyText(dto.toXml()); 193 | HttpResponse response = request.send(); 194 | return response.bodyText(); 195 | }*/ 196 | 197 | 198 | public static void main(String[] args) { 199 | 200 | /* String jsonStr="{\"component_appid\":\"wxa797588149020de4\",\"component_verify_ticket\":\"ticket@@@6PEMgS7QZ2xzxJn9bdrOd6DB2xzm5I3liChyE8l4MdkruB10OzJl0FNsirqBXWoiB631xmw2fCHf84wCOSt9ZA\",\"component_appsecret\":\"a38dd974a9e6490dfbf5b21cd38f9996\"}\n"; 201 | String json= HttpHelper.postByRest(Api.component_token,String.class,null,jsonStr); 202 | Map jsonMap= JsonUtil.json2Obj(json,Map.class); 203 | 204 | 205 | 206 | 207 | System.out.println(jsonMap);*/ 208 | 209 | 210 | try { 211 | JsonObject jo= HttpHelper.httpPost("https://api.weixin.qq.com/cgi-bin/menu/get?access_token=7_LptTbnbGrlk8OrF3fSreUPozwvDXm_lE1LB-lqVXxD5VYW2XLcRCQ3G4FTwhe1LR670PkaItKHZm7TY4Ms-ECf8oDslqhyE3rUMo3GrqKLOFs8owbj9SSkF3Y6kYqd0GiYtzbgNLopPeP8AiDNYdABAXHS",null); 212 | System.out.println(jo.toString()); 213 | } catch (Exception e) { 214 | e.printStackTrace(); 215 | } 216 | } 217 | 218 | 219 | } 220 | -------------------------------------------------------------------------------- /SpringBootDemoV2/src/main/java/com/github/xiaour/utils/IDGenerate.java: -------------------------------------------------------------------------------- 1 | package com.github.xiaour.utils; 2 | 3 | import java.util.Date; 4 | import java.util.Random; 5 | import java.util.concurrent.CountDownLatch; 6 | import java.util.concurrent.ExecutorService; 7 | import java.util.concurrent.Executors; 8 | 9 | /** 10 | * @Author: Xiaour 11 | * @Description: 一个基于Twitter的 12 | * @Date: 2018/8/22 14:24 13 | */ 14 | public class IDGenerate { 15 | 16 | private static final long startTimeStamp = 1534919378079L; //定义一个起始时间 new Date().getTime() 17 | 18 | private static final long workerIdBits = 6L; 19 | private static final long dataCenterIdBits = 6L; 20 | private static final long maxWorkerId = -1L ^ (-1L << workerIdBits); 21 | private static final long maxDataCenterId = -1L ^ (-1L << dataCenterIdBits); 22 | 23 | private static final long sequenceBits = 14L; 24 | private static final long workerIdShift = sequenceBits; 25 | private static final long dataCenterIdShift = sequenceBits + workerIdBits; 26 | private static final long timestampLeftShift = sequenceBits + workerIdBits + dataCenterIdBits; 27 | private static final long sequenceMask = -1L ^ (-1L << sequenceBits); 28 | private static final Random r = new Random(); 29 | 30 | private final long workerId; 31 | private final long dataCenterId; 32 | private final long idEpoch; 33 | private long lastTimestamp = -1L; 34 | private long sequence = 0; 35 | 36 | public IDGenerate() { 37 | this(startTimeStamp); 38 | } 39 | 40 | public IDGenerate(long idEpoch) { 41 | this(r.nextInt((int) maxWorkerId), r.nextInt((int) maxDataCenterId), 0, idEpoch); 42 | } 43 | 44 | public IDGenerate(long workerId, long dataCenterId, long sequence) { 45 | this(workerId, dataCenterId, sequence, startTimeStamp); 46 | } 47 | 48 | public IDGenerate(long workerId, long dataCenterId, long sequence, long idEpoch) { 49 | this.workerId = workerId; 50 | this.dataCenterId = dataCenterId; 51 | this.sequence = sequence; 52 | this.idEpoch = idEpoch; 53 | 54 | if (workerId < 0 || workerId > maxWorkerId) { 55 | throw new IllegalArgumentException("workerId is illegal: " + workerId); 56 | } 57 | if (dataCenterId < 0 || dataCenterId > maxDataCenterId) { 58 | throw new IllegalArgumentException("dataCenterId is illegal: " + dataCenterId); 59 | } 60 | 61 | if (idEpoch >= timeGen()) { 62 | throw new IllegalArgumentException("idEpoch is illegal: " + idEpoch); 63 | } 64 | } 65 | 66 | public long getDataCenterId() { 67 | return dataCenterId; 68 | } 69 | 70 | public long getWorkerId() { 71 | return workerId; 72 | } 73 | 74 | public long getTime() { 75 | return timeGen(); 76 | } 77 | 78 | public synchronized long nextId() { 79 | long timestamp = timeGen(); 80 | if (timestamp < lastTimestamp) { 81 | throw new IllegalArgumentException("Clock moved backwards."); 82 | } 83 | 84 | if (lastTimestamp == timestamp) { 85 | sequence = (sequence + 1) & sequenceMask; 86 | if (sequence == 0) { 87 | timestamp = tilNextMillis(lastTimestamp); 88 | } 89 | } else { 90 | sequence = 0; 91 | } 92 | 93 | lastTimestamp = timestamp; 94 | long id = ((timestamp - idEpoch) << timestampLeftShift) | (dataCenterId << 95 | dataCenterIdShift) | (workerId << workerIdShift) | sequence; 96 | return id; 97 | } 98 | 99 | public long getIdTimestamp(long id) { 100 | return idEpoch + (id >> timestampLeftShift); 101 | } 102 | 103 | private long tilNextMillis(long lastTimestamp) { 104 | long timestamp = timeGen(); 105 | while (timestamp <= lastTimestamp) { 106 | timestamp = timeGen(); 107 | } 108 | 109 | return timestamp; 110 | } 111 | 112 | private long timeGen() { 113 | return System.currentTimeMillis(); 114 | } 115 | 116 | @Override 117 | public String toString() { 118 | final StringBuilder sb = new StringBuilder("IdBitWorker{"); 119 | sb.append("workerId=").append(workerId); 120 | sb.append(", dataCenterId=").append(dataCenterId); 121 | sb.append(", idEpoch=").append(idEpoch); 122 | sb.append(", lastTimestamp=").append(lastTimestamp); 123 | sb.append(", sequence=").append(sequence); 124 | sb.append('}'); 125 | return sb.toString(); 126 | } 127 | 128 | public static void main(String[] args) throws Exception { 129 | IDGenerate worker = new IDGenerate(); 130 | ExecutorService executor = Executors.newFixedThreadPool(8); 131 | 132 | CountDownLatch countDownLatch = new CountDownLatch(1000000); 133 | Runnable run = () -> { 134 | //这里是最主要ID部分 135 | System.out.println(worker.nextId()); 136 | countDownLatch.countDown(); 137 | }; 138 | 139 | long startTime = System.currentTimeMillis(); 140 | for (int i = 0; i < 1000000; i++) { 141 | executor.execute(run); 142 | } 143 | countDownLatch.await(); 144 | System.out.println(System.currentTimeMillis() - startTime); 145 | executor.shutdown(); 146 | 147 | System.out.println(new Date().getTime()); 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /SpringBootDemoV2/src/main/java/com/github/xiaour/utils/JsonUtil.java: -------------------------------------------------------------------------------- 1 | package com.github.xiaour.utils; 2 | 3 | import com.google.gson.*; 4 | import com.google.gson.reflect.TypeToken; 5 | 6 | import java.lang.reflect.Type; 7 | import java.util.ArrayList; 8 | import java.util.HashMap; 9 | import java.util.List; 10 | import java.util.Map; 11 | 12 | public class JsonUtil{ 13 | 14 | 15 | private static Gson gson = null; 16 | 17 | static{ 18 | gson = new Gson(); 19 | } 20 | 21 | public static synchronized Gson newInstance(){ 22 | if(gson == null){ 23 | gson = new Gson(); 24 | } 25 | return gson; 26 | } 27 | 28 | public static String getJsonString(Object obj){ 29 | return gson.toJson(obj); 30 | } 31 | 32 | public static T toBean(String json,Class clz){ 33 | 34 | return gson.fromJson(json, clz); 35 | } 36 | 37 | public static Map readJson2MapObj(String json,Class clz){ 38 | Map map = gson.fromJson(json, new TypeToken>(){}.getType()); 39 | Map result = new HashMap<>(); 40 | for(String key:map.keySet()){ 41 | result.put(key,gson.fromJson(map.get(key),clz) ); 42 | } 43 | return result; 44 | } 45 | 46 | public static T json2Obj(String json,Class clz){ 47 | return gson.fromJson(json,clz); 48 | } 49 | 50 | public static Map toMap(String json){ 51 | Map map = gson.fromJson(json, new TypeToken>(){}.getType()); 52 | return map; 53 | } 54 | 55 | public static Map readJsonStrMap(String json) { 56 | Map map = gson.fromJson(json, new TypeToken>(){}.getType()); 57 | Map result = new HashMap<>(); 58 | for(String key:map.keySet()){ 59 | result.put(key,gson.fromJson(map.get(key),String.class) ); 60 | } 61 | return result; 62 | } 63 | 64 | public static Map readJsonByteMap(String json) { 65 | Map map = gson.fromJson(json, new TypeToken>(){}.getType()); 66 | Map vmap = new HashMap<>(); 67 | for(String key:map.keySet()){ 68 | vmap.put(key.getBytes(),gson.fromJson(map.get(key),String.class).getBytes() ); 69 | } 70 | return vmap; 71 | 72 | } 73 | 74 | 75 | public static List readJson2Array(String json, Class clz){ 76 | JsonArray array = new JsonParser().parse(json).getAsJsonArray(); 77 | List list = new ArrayList<>(); 78 | for(final JsonElement elem : array){ 79 | list.add(gson.fromJson(elem, (Type)clz)); 80 | } 81 | return list; 82 | } 83 | 84 | } -------------------------------------------------------------------------------- /SpringBootDemoV2/src/main/java/com/github/xiaour/utils/PKCS7Encoder.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 对公众平台发送给公众账号的消息加解密示例代码. 3 | * 4 | * @copyright Copyright (c) 1998-2014 Tencent Inc. 5 | */ 6 | 7 | // ------------------------------------------------------------------------ 8 | 9 | package com.github.xiaour.utils; 10 | 11 | import java.nio.charset.Charset; 12 | import java.util.Arrays; 13 | 14 | /** 15 | * 提供基于PKCS7算法的加解密接口. 16 | */ 17 | class PKCS7Encoder { 18 | static Charset CHARSET = Charset.forName("utf-8"); 19 | static int BLOCK_SIZE = 32; 20 | 21 | /** 22 | * 获得对明文进行补位填充的字节. 23 | * 24 | * @param count 需要进行填充补位操作的明文字节个数 25 | * @return 补齐用的字节数组 26 | */ 27 | static byte[] encode(int count) { 28 | // 计算需要填充的位数 29 | int amountToPad = BLOCK_SIZE - (count % BLOCK_SIZE); 30 | if (amountToPad == 0) { 31 | amountToPad = BLOCK_SIZE; 32 | } 33 | // 获得补位所用的字符 34 | char padChr = chr(amountToPad); 35 | String tmp = new String(); 36 | for (int index = 0; index < amountToPad; index++) { 37 | tmp += padChr; 38 | } 39 | return tmp.getBytes(CHARSET); 40 | } 41 | 42 | /** 43 | * 删除解密后明文的补位字符 44 | * 45 | * @param decrypted 解密后的明文 46 | * @return 删除补位字符后的明文 47 | */ 48 | static byte[] decode(byte[] decrypted) { 49 | int pad = (int) decrypted[decrypted.length - 1]; 50 | if (pad < 1 || pad > 32) { 51 | pad = 0; 52 | } 53 | return Arrays.copyOfRange(decrypted, 0, decrypted.length - pad); 54 | } 55 | 56 | /** 57 | * 将数字转化成ASCII码对应的字符,用于对明文进行补码 58 | * 59 | * @param a 需要转化的数字 60 | * @return 转化得到的字符 61 | */ 62 | static char chr(int a) { 63 | byte target = (byte) (a & 0xFF); 64 | return (char) target; 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /SpringBootDemoV2/src/main/java/com/github/xiaour/utils/SHA1.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 对公众平台发送给公众账号的消息加解密示例代码. 3 | * 4 | * @copyright Copyright (c) 1998-2014 Tencent Inc. 5 | */ 6 | 7 | // ------------------------------------------------------------------------ 8 | 9 | package com.github.xiaour.utils; 10 | 11 | import com.github.xiaour.exception.AesException; 12 | 13 | import java.security.MessageDigest; 14 | import java.util.Arrays; 15 | 16 | /** 17 | * SHA1 class 18 | * 19 | * 计算公众平台的消息签名接口. 20 | */ 21 | class SHA1 { 22 | 23 | /** 24 | * 用SHA1算法生成安全签名 25 | * @param token 票据 26 | * @param timestamp 时间戳 27 | * @param nonce 随机字符串 28 | * @param encrypt 密文 29 | * @return 安全签名 30 | * @throws AesException 31 | */ 32 | public static String getSHA1(String token, String timestamp, String nonce, String encrypt) throws AesException 33 | { 34 | try { 35 | String[] array = new String[] { token, timestamp, nonce, encrypt }; 36 | StringBuffer sb = new StringBuffer(); 37 | // 字符串排序 38 | Arrays.sort(array); 39 | for (int i = 0; i < 4; i++) { 40 | sb.append(array[i]); 41 | } 42 | String str = sb.toString(); 43 | // SHA1签名生成 44 | MessageDigest md = MessageDigest.getInstance("SHA-1"); 45 | md.update(str.getBytes()); 46 | byte[] digest = md.digest(); 47 | 48 | StringBuffer hexstr = new StringBuffer(); 49 | String shaHex = ""; 50 | for (int i = 0; i < digest.length; i++) { 51 | shaHex = Integer.toHexString(digest[i] & 0xFF); 52 | if (shaHex.length() < 2) { 53 | hexstr.append(0); 54 | } 55 | hexstr.append(shaHex); 56 | } 57 | return hexstr.toString(); 58 | } catch (Exception e) { 59 | e.printStackTrace(); 60 | throw new AesException(AesException.ComputeSignatureError); 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /SpringBootDemoV2/src/main/java/com/github/xiaour/utils/Test.java: -------------------------------------------------------------------------------- 1 | package com.github.xiaour.utils; 2 | 3 | /** 4 | * @Author: Xiaour 5 | * @Description: 6 | * @Date: 2018/3/2 上午10:35 7 | */ 8 | public class Test { 9 | 10 | 11 | } 12 | -------------------------------------------------------------------------------- /SpringBootDemoV2/src/main/java/com/github/xiaour/utils/WXBizMsgCrypt.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 对公众平台发送给公众账号的消息加解密示例代码. 3 | * 4 | * @copyright Copyright (c) 1998-2014 Tencent Inc. 5 | */ 6 | 7 | // ------------------------------------------------------------------------ 8 | 9 | /** 10 | * 针对org.apache.commons.codec.binary.Base64, 11 | * 需要导入架包commons-codec-1.9(或commons-codec-1.8等其他版本) 12 | * 官方下载地址:http://commons.apache.org/proper/commons-codec/download_codec.cgi 13 | */ 14 | package com.github.xiaour.utils; 15 | 16 | import java.nio.charset.Charset; 17 | import java.util.Arrays; 18 | import java.util.Random; 19 | 20 | import javax.crypto.Cipher; 21 | import javax.crypto.spec.IvParameterSpec; 22 | import javax.crypto.spec.SecretKeySpec; 23 | 24 | import com.github.xiaour.exception.AesException; 25 | import org.apache.commons.codec.binary.Base64; 26 | 27 | /** 28 | * 提供接收和推送给公众平台消息的加解密接口(UTF8编码的字符串). 29 | *
    30 | *
  1. 第三方回复加密消息给公众平台
  2. 31 | *
  3. 第三方收到公众平台发送的消息,验证消息的安全性,并对消息进行解密。
  4. 32 | *
33 | * 说明:异常java.security.InvalidKeyException:illegal Key Size的解决方案 34 | *
    35 | *
  1. 在官方网站下载JCE无限制权限策略文件(JDK7的下载地址: 36 | * http://www.oracle.com/technetwork/java/javase/downloads/jce-7-download-432124.html
  2. 37 | *
  3. 下载后解压,可以看到local_policy.jar和US_export_policy.jar以及readme.txt
  4. 38 | *
  5. 如果安装了JRE,将两个jar文件放到%JRE_HOME%\lib\security目录下覆盖原来的文件
  6. 39 | *
  7. 如果安装了JDK,将两个jar文件放到%JDK_HOME%\jre\lib\security目录下覆盖原来文件
  8. 40 | *
41 | */ 42 | public class WXBizMsgCrypt { 43 | static Charset CHARSET = Charset.forName("utf-8"); 44 | Base64 base64 = new Base64(); 45 | byte[] aesKey; 46 | String token; 47 | String appId; 48 | 49 | /** 50 | * 构造函数 51 | * @param token 公众平台上,开发者设置的token 52 | * @param encodingAesKey 公众平台上,开发者设置的EncodingAESKey 53 | * @param appId 公众平台appid 54 | * 55 | * @throws AesException 执行失败,请查看该异常的错误码和具体的错误信息 56 | */ 57 | public WXBizMsgCrypt(String token, String encodingAesKey, String appId) throws AesException { 58 | if (encodingAesKey.length() != 43) { 59 | throw new AesException(AesException.IllegalAesKey); 60 | } 61 | 62 | this.token = token; 63 | this.appId = appId; 64 | aesKey = Base64.decodeBase64(encodingAesKey + "="); 65 | } 66 | 67 | // 生成4个字节的网络字节序 68 | byte[] getNetworkBytesOrder(int sourceNumber) { 69 | byte[] orderBytes = new byte[4]; 70 | orderBytes[3] = (byte) (sourceNumber & 0xFF); 71 | orderBytes[2] = (byte) (sourceNumber >> 8 & 0xFF); 72 | orderBytes[1] = (byte) (sourceNumber >> 16 & 0xFF); 73 | orderBytes[0] = (byte) (sourceNumber >> 24 & 0xFF); 74 | return orderBytes; 75 | } 76 | 77 | // 还原4个字节的网络字节序 78 | int recoverNetworkBytesOrder(byte[] orderBytes) { 79 | int sourceNumber = 0; 80 | for (int i = 0; i < 4; i++) { 81 | sourceNumber <<= 8; 82 | sourceNumber |= orderBytes[i] & 0xff; 83 | } 84 | return sourceNumber; 85 | } 86 | 87 | // 随机生成16位字符串 88 | public String getRandomStr() { 89 | String base = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; 90 | Random random = new Random(); 91 | StringBuffer sb = new StringBuffer(); 92 | for (int i = 0; i < 16; i++) { 93 | int number = random.nextInt(base.length()); 94 | sb.append(base.charAt(number)); 95 | } 96 | return sb.toString(); 97 | } 98 | 99 | /** 100 | * 对明文进行加密. 101 | * 102 | * @param text 需要加密的明文 103 | * @return 加密后base64编码的字符串 104 | * @throws AesException aes加密失败 105 | */ 106 | public String encrypt(String randomStr, String text) throws AesException { 107 | ByteGroup byteCollector = new ByteGroup(); 108 | byte[] randomStrBytes = randomStr.getBytes(CHARSET); 109 | byte[] textBytes = text.getBytes(CHARSET); 110 | byte[] networkBytesOrder = getNetworkBytesOrder(textBytes.length); 111 | byte[] appidBytes = appId.getBytes(CHARSET); 112 | 113 | // randomStr + networkBytesOrder + text + appid 114 | byteCollector.addBytes(randomStrBytes); 115 | byteCollector.addBytes(networkBytesOrder); 116 | byteCollector.addBytes(textBytes); 117 | byteCollector.addBytes(appidBytes); 118 | 119 | // ... + pad: 使用自定义的填充方式对明文进行补位填充 120 | byte[] padBytes = PKCS7Encoder.encode(byteCollector.size()); 121 | byteCollector.addBytes(padBytes); 122 | 123 | // 获得最终的字节流, 未加密 124 | byte[] unencrypted = byteCollector.toBytes(); 125 | 126 | try { 127 | // 设置加密模式为AES的CBC模式 128 | Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding"); 129 | SecretKeySpec keySpec = new SecretKeySpec(aesKey, "AES"); 130 | IvParameterSpec iv = new IvParameterSpec(aesKey, 0, 16); 131 | cipher.init(Cipher.ENCRYPT_MODE, keySpec, iv); 132 | 133 | // 加密 134 | byte[] encrypted = cipher.doFinal(unencrypted); 135 | 136 | // 使用BASE64对加密后的字符串进行编码 137 | String base64Encrypted = base64.encodeToString(encrypted); 138 | 139 | return base64Encrypted; 140 | } catch (Exception e) { 141 | e.printStackTrace(); 142 | throw new AesException(AesException.EncryptAESError); 143 | } 144 | } 145 | 146 | /** 147 | * 对密文进行解密. 148 | * 149 | * @param text 需要解密的密文 150 | * @return 解密得到的明文 151 | * @throws AesException aes解密失败 152 | */ 153 | public String decrypt(String text) throws AesException { 154 | byte[] original; 155 | try { 156 | // 设置解密模式为AES的CBC模式 157 | Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding"); 158 | SecretKeySpec key_spec = new SecretKeySpec(aesKey, "AES"); 159 | IvParameterSpec iv = new IvParameterSpec(Arrays.copyOfRange(aesKey, 0, 16)); 160 | cipher.init(Cipher.DECRYPT_MODE, key_spec, iv); 161 | 162 | // 使用BASE64对密文进行解码 163 | byte[] encrypted = Base64.decodeBase64(text); 164 | 165 | // 解密 166 | original = cipher.doFinal(encrypted); 167 | } catch (Exception e) { 168 | e.printStackTrace(); 169 | throw new AesException(AesException.DecryptAESError); 170 | } 171 | 172 | String xmlContent, from_appid; 173 | try { 174 | // 去除补位字符 175 | byte[] bytes = PKCS7Encoder.decode(original); 176 | 177 | // 分离16位随机字符串,网络字节序和AppId 178 | byte[] networkOrder = Arrays.copyOfRange(bytes, 16, 20); 179 | 180 | int xmlLength = recoverNetworkBytesOrder(networkOrder); 181 | 182 | xmlContent = new String(Arrays.copyOfRange(bytes, 20, 20 + xmlLength), CHARSET); 183 | from_appid = new String(Arrays.copyOfRange(bytes, 20 + xmlLength, bytes.length), 184 | CHARSET); 185 | } catch (Exception e) { 186 | e.printStackTrace(); 187 | throw new AesException(AesException.IllegalBuffer); 188 | } 189 | 190 | // appid不相同的情况 191 | if (!from_appid.equals(appId)) { 192 | throw new AesException(AesException.ValidateAppidError); 193 | } 194 | return xmlContent; 195 | 196 | } 197 | 198 | /** 199 | * 将公众平台回复用户的消息加密打包. 200 | *
    201 | *
  1. 对要发送的消息进行AES-CBC加密
  2. 202 | *
  3. 生成安全签名
  4. 203 | *
  5. 将消息密文和安全签名打包成xml格式
  6. 204 | *
205 | * 206 | * @param replyMsg 公众平台待回复用户的消息,xml格式的字符串 207 | * @param timeStamp 时间戳,可以自己生成,也可以用URL参数的timestamp 208 | * @param nonce 随机串,可以自己生成,也可以用URL参数的nonce 209 | * 210 | * @return 加密后的可以直接回复用户的密文,包括msg_signature, timestamp, nonce, encrypt的xml格式的字符串 211 | * @throws AesException 执行失败,请查看该异常的错误码和具体的错误信息 212 | */ 213 | public String encryptMsg(String replyMsg, String timeStamp, String nonce) throws AesException { 214 | // 加密 215 | String encrypt = encrypt(getRandomStr(), replyMsg); 216 | 217 | // 生成安全签名 218 | if (timeStamp == "") { 219 | timeStamp = Long.toString(System.currentTimeMillis()); 220 | } 221 | 222 | String signature = SHA1.getSHA1(token, timeStamp, nonce, encrypt); 223 | 224 | // System.out.println("发送给平台的签名是: " + signature[1].toString()); 225 | // 生成发送的xml 226 | String result = XMLParse.generate(encrypt, signature, timeStamp, nonce); 227 | return result; 228 | } 229 | 230 | /** 231 | * 检验消息的真实性,并且获取解密后的明文. 232 | *
    233 | *
  1. 利用收到的密文生成安全签名,进行签名验证
  2. 234 | *
  3. 若验证通过,则提取xml中的加密消息
  4. 235 | *
  5. 对消息进行解密
  6. 236 | *
237 | * 238 | * @param msgSignature 签名串,对应URL参数的msg_signature 239 | * @param timeStamp 时间戳,对应URL参数的timestamp 240 | * @param nonce 随机串,对应URL参数的nonce 241 | * @param encrypt 密文,对应POST请求的数据 242 | * 243 | * @return 解密后的原文 244 | * @throws AesException 执行失败,请查看该异常的错误码和具体的错误信息 245 | */ 246 | public String decryptMsg(String msgSignature, String timeStamp, String nonce, String encrypt) 247 | throws AesException { 248 | 249 | // 密钥,公众账号的app secret 250 | // 提取密文 251 | 252 | // 验证安全签名 253 | String signature = SHA1.getSHA1(token, timeStamp, nonce, encrypt); 254 | 255 | // 和URL中的签名比较是否相等 256 | // System.out.println("第三方收到URL中的签名:" + msg_sign); 257 | // System.out.println("第三方校验签名:" + signature); 258 | if (!signature.equals(msgSignature)) { 259 | throw new AesException(AesException.ValidateSignatureError); 260 | } 261 | 262 | // 解密 263 | String result = decrypt(encrypt); 264 | return result; 265 | } 266 | 267 | /** 268 | * 验证URL 269 | * @param msgSignature 签名串,对应URL参数的msg_signature 270 | * @param timeStamp 时间戳,对应URL参数的timestamp 271 | * @param nonce 随机串,对应URL参数的nonce 272 | * @param echoStr 随机串,对应URL参数的echostr 273 | * 274 | * @return 解密之后的echostr 275 | * @throws AesException 执行失败,请查看该异常的错误码和具体的错误信息 276 | */ 277 | public String verifyUrl(String msgSignature, String timeStamp, String nonce, String echoStr) 278 | throws AesException { 279 | String signature = SHA1.getSHA1(token, timeStamp, nonce, echoStr); 280 | 281 | if (!signature.equals(msgSignature)) { 282 | throw new AesException(AesException.ValidateSignatureError); 283 | } 284 | 285 | String result = decrypt(echoStr); 286 | return result; 287 | } 288 | 289 | } -------------------------------------------------------------------------------- /SpringBootDemoV2/src/main/java/com/github/xiaour/utils/WXBizMsgCryptTest.java: -------------------------------------------------------------------------------- 1 | package com.github.xiaour.utils; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import java.io.IOException; 6 | import java.io.StringReader; 7 | 8 | import javax.xml.parsers.DocumentBuilder; 9 | import javax.xml.parsers.DocumentBuilderFactory; 10 | import javax.xml.parsers.ParserConfigurationException; 11 | 12 | import com.github.xiaour.exception.AesException; 13 | import org.junit.After; 14 | import org.junit.AfterClass; 15 | import org.junit.Before; 16 | import org.junit.BeforeClass; 17 | import org.junit.Test; 18 | import org.w3c.dom.Document; 19 | import org.w3c.dom.Element; 20 | import org.w3c.dom.NodeList; 21 | import org.xml.sax.InputSource; 22 | import org.xml.sax.SAXException; 23 | 24 | public class WXBizMsgCryptTest { 25 | String encodingAesKey = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFG"; 26 | String token = "pamtest"; 27 | String timestamp = "1409304348"; 28 | String nonce = "xxxxxx"; 29 | String appId = "wxb11529c136998cb6"; 30 | String replyMsg = "我是中文abcd123"; 31 | String xmlFormat = ""; 32 | String afterAesEncrypt = "jn1L23DB+6ELqJ+6bruv21Y6MD7KeIfP82D6gU39rmkgczbWwt5+3bnyg5K55bgVtVzd832WzZGMhkP72vVOfg=="; 33 | String randomStr = "aaaabbbbccccdddd"; 34 | 35 | String replyMsg2 = "1407743423"; 36 | String afterAesEncrypt2 = "jn1L23DB+6ELqJ+6bruv23M2GmYfkv0xBh2h+XTBOKVKcgDFHle6gqcZ1cZrk3e1qjPQ1F4RsLWzQRG9udbKWesxlkupqcEcW7ZQweImX9+wLMa0GaUzpkycA8+IamDBxn5loLgZpnS7fVAbExOkK5DYHBmv5tptA9tklE/fTIILHR8HLXa5nQvFb3tYPKAlHF3rtTeayNf0QuM+UW/wM9enGIDIJHF7CLHiDNAYxr+r+OrJCmPQyTy8cVWlu9iSvOHPT/77bZqJucQHQ04sq7KZI27OcqpQNSto2OdHCoTccjggX5Z9Mma0nMJBU+jLKJ38YB1fBIz+vBzsYjrTmFQ44YfeEuZ+xRTQwr92vhA9OxchWVINGC50qE/6lmkwWTwGX9wtQpsJKhP+oS7rvTY8+VdzETdfakjkwQ5/Xka042OlUb1/slTwo4RscuQ+RdxSGvDahxAJ6+EAjLt9d8igHngxIbf6YyqqROxuxqIeIch3CssH/LqRs+iAcILvApYZckqmA7FNERspKA5f8GoJ9sv8xmGvZ9Yrf57cExWtnX8aCMMaBropU/1k+hKP5LVdzbWCG0hGwx/dQudYR/eXp3P0XxjlFiy+9DMlaFExWUZQDajPkdPrEeOwofJb"; 37 | 38 | @BeforeClass 39 | public static void setUpBeforeClass() throws Exception { 40 | } 41 | 42 | @AfterClass 43 | public static void tearDownAfterClass() throws Exception { 44 | } 45 | 46 | @Before 47 | public void setUp() throws Exception { 48 | 49 | } 50 | 51 | @After 52 | public void tearDown() throws Exception { 53 | } 54 | 55 | @Test 56 | public void testNormal() throws ParserConfigurationException, SAXException, IOException { 57 | try { 58 | WXBizMsgCrypt pc = new WXBizMsgCrypt(token, encodingAesKey, appId); 59 | String afterEncrpt = pc.encryptMsg(replyMsg, timestamp, nonce); 60 | 61 | DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); 62 | DocumentBuilder db = dbf.newDocumentBuilder(); 63 | StringReader sr = new StringReader(afterEncrpt); 64 | InputSource is = new InputSource(sr); 65 | Document document = db.parse(is); 66 | 67 | Element root = document.getDocumentElement(); 68 | NodeList nodelist1 = root.getElementsByTagName("Encrypt"); 69 | NodeList nodelist2 = root.getElementsByTagName("MsgSignature"); 70 | 71 | String encrypt = nodelist1.item(0).getTextContent(); 72 | String msgSignature = nodelist2.item(0).getTextContent(); 73 | String fromXML = String.format(xmlFormat, encrypt); 74 | 75 | // 第三方收到公众号平台发送的消息 76 | String afterDecrpt = pc.decryptMsg(msgSignature, timestamp, nonce, fromXML); 77 | assertEquals(replyMsg, afterDecrpt); 78 | } catch (AesException e) { 79 | fail("正常流程,怎么就抛出异常了??????"); 80 | } 81 | } 82 | 83 | @Test 84 | public void testAesEncrypt() { 85 | try { 86 | WXBizMsgCrypt pc = new WXBizMsgCrypt(token, encodingAesKey, appId); 87 | assertEquals(afterAesEncrypt, pc.encrypt(randomStr, replyMsg)); 88 | } catch (AesException e) { 89 | e.printStackTrace(); 90 | fail("no异常"); 91 | } 92 | } 93 | 94 | @Test 95 | public void testAesEncrypt2() { 96 | try { 97 | WXBizMsgCrypt pc = new WXBizMsgCrypt(token, encodingAesKey, appId); 98 | assertEquals(afterAesEncrypt2, pc.encrypt(randomStr, replyMsg2)); 99 | 100 | } catch (AesException e) { 101 | e.printStackTrace(); 102 | fail("no异常"); 103 | } 104 | } 105 | 106 | @Test 107 | public void testIllegalAesKey() { 108 | try { 109 | new WXBizMsgCrypt(token, "abcde", appId); 110 | } catch (AesException e) { 111 | assertEquals(AesException.IllegalAesKey, e.getCode()); 112 | return; 113 | } 114 | fail("错误流程不抛出异常???"); 115 | } 116 | 117 | @Test 118 | public void testValidateSignatureError() throws ParserConfigurationException, SAXException, 119 | IOException { 120 | try { 121 | WXBizMsgCrypt pc = new WXBizMsgCrypt(token, encodingAesKey, appId); 122 | String afterEncrpt = pc.encryptMsg(replyMsg, timestamp, nonce); 123 | DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); 124 | DocumentBuilder db = dbf.newDocumentBuilder(); 125 | StringReader sr = new StringReader(afterEncrpt); 126 | InputSource is = new InputSource(sr); 127 | Document document = db.parse(is); 128 | 129 | Element root = document.getDocumentElement(); 130 | NodeList nodelist1 = root.getElementsByTagName("Encrypt"); 131 | 132 | String encrypt = nodelist1.item(0).getTextContent(); 133 | String fromXML = String.format(xmlFormat, encrypt); 134 | pc.decryptMsg("12345", timestamp, nonce, fromXML); // 这里签名错误 135 | } catch (AesException e) { 136 | assertEquals(AesException.ValidateSignatureError, e.getCode()); 137 | return; 138 | } 139 | fail("错误流程不抛出异常???"); 140 | } 141 | 142 | @Test 143 | public void testVerifyUrl() throws AesException { 144 | WXBizMsgCrypt wxcpt = new WXBizMsgCrypt("QDG6eK", 145 | "jWmYm7qr5nMoAUwZRjGtBxmz3KA1tkAj3ykkR6q2B2C", "wx5823bf96d3bd56c7"); 146 | String verifyMsgSig = "5c45ff5e21c57e6ad56bac8758b79b1d9ac89fd3"; 147 | String timeStamp = "1409659589"; 148 | String nonce = "263014780"; 149 | String echoStr = "P9nAzCzyDtyTWESHep1vC5X9xho/qYX3Zpb4yKa9SKld1DsH3Iyt3tP3zNdtp+4RPcs8TgAE7OaBO+FZXvnaqQ=="; 150 | wxcpt.verifyUrl(verifyMsgSig, timeStamp, nonce, echoStr); 151 | // 只要不抛出异常就好 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /SpringBootDemoV2/src/main/java/com/github/xiaour/utils/XMLParse.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 对公众平台发送给公众账号的消息加解密示例代码. 3 | * 4 | * @copyright Copyright (c) 1998-2014 Tencent Inc. 5 | */ 6 | 7 | // ------------------------------------------------------------------------ 8 | 9 | package com.github.xiaour.utils; 10 | 11 | import java.io.StringReader; 12 | 13 | import javax.xml.parsers.DocumentBuilder; 14 | import javax.xml.parsers.DocumentBuilderFactory; 15 | 16 | import com.github.xiaour.exception.AesException; 17 | import org.w3c.dom.Document; 18 | import org.w3c.dom.Element; 19 | import org.w3c.dom.NodeList; 20 | import org.xml.sax.InputSource; 21 | 22 | /** 23 | * XMLParse class 24 | * 25 | * 提供提取消息格式中的密文及生成回复消息格式的接口. 26 | */ 27 | class XMLParse { 28 | 29 | /** 30 | * 提取出xml数据包中的加密消息 31 | * @param xmltext 待提取的xml字符串 32 | * @return 提取出的加密消息字符串 33 | * @throws AesException 34 | */ 35 | public static Object[] extract(String xmltext) throws AesException { 36 | Object[] result = new Object[3]; 37 | try { 38 | DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); 39 | DocumentBuilder db = dbf.newDocumentBuilder(); 40 | StringReader sr = new StringReader(xmltext); 41 | InputSource is = new InputSource(sr); 42 | Document document = db.parse(is); 43 | 44 | Element root = document.getDocumentElement(); 45 | NodeList nodelist1 = root.getElementsByTagName("Encrypt"); 46 | 47 | result[0] = 0; 48 | result[1] = nodelist1.item(0).getTextContent(); 49 | 50 | if(root.getElementsByTagName("ToUserName")!=null) { 51 | NodeList nodelist2 = root.getElementsByTagName("ToUserName"); 52 | result[2] = nodelist2.item(0).getTextContent(); 53 | } 54 | return result; 55 | } catch (Exception e) { 56 | e.printStackTrace(); 57 | throw new AesException(AesException.ParseXmlError); 58 | } 59 | } 60 | 61 | /** 62 | * 生成xml消息 63 | * @param encrypt 加密后的消息密文 64 | * @param signature 安全签名 65 | * @param timestamp 时间戳 66 | * @param nonce 随机字符串 67 | * @return 生成的xml字符串 68 | */ 69 | public static String generate(String encrypt, String signature, String timestamp, String nonce) { 70 | 71 | String format = "\n" + "\n" 72 | + "\n" 73 | + "%3$s\n" + "\n" + ""; 74 | return String.format(format, encrypt, signature, timestamp, nonce); 75 | 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /SpringBootDemoV2/src/main/java/com/github/xiaour/utils/Xml2JsonUtil.java: -------------------------------------------------------------------------------- 1 | package com.github.xiaour.utils; 2 | 3 | import com.google.gson.JsonArray; 4 | import com.google.gson.JsonObject; 5 | import org.dom4j.*; 6 | 7 | import java.util.List; 8 | 9 | /** 10 | * XML转成JSON 11 | * 12 | * @ClassName Xml2JsonUtil 13 | * @author xiaour@github.com 14 | * @Date 2017年6月13日 下午6:30:00 15 | * @version V2.0.0 16 | */ 17 | public class Xml2JsonUtil { 18 | 19 | /** 20 | * xml转json 21 | * @param xmlStr 22 | * @return 23 | * @throws DocumentException 24 | */ 25 | public static JsonObject xml2Json(String xmlStr) throws DocumentException{ 26 | Document doc= DocumentHelper.parseText(xmlStr); 27 | JsonObject json=new JsonObject(); 28 | dom4j2Json(doc.getRootElement(), json); 29 | return json; 30 | } 31 | 32 | /** 33 | * xml转json 34 | * @param element 35 | * @param json 36 | */ 37 | private static void dom4j2Json(Element element,JsonObject json){ 38 | //如果是属性 39 | for(Object o:element.attributes()){ 40 | Attribute attr=(Attribute)o; 41 | if(!isEmpty(attr.getValue())){ 42 | json.addProperty("@"+attr.getName(), attr.getValue()); 43 | } 44 | } 45 | List chdEl=element.elements(); 46 | if(chdEl.isEmpty()&&!isEmpty(element.getText())){//如果没有子元素,只有一个值 47 | json.addProperty(element.getName(), element.getText()); 48 | } 49 | 50 | for(Element e:chdEl){//有子元素 51 | if(!e.elements().isEmpty()){//子元素也有子元素 52 | JsonObject chdjson=new JsonObject(); 53 | dom4j2Json(e,chdjson); 54 | Object o=json.get(e.getName()); 55 | if(o!=null){ 56 | JsonArray jsona=null; 57 | if(o instanceof JsonObject){//如果此元素已存在,则转为jsonArray 58 | JsonObject jsono=(JsonObject)o; 59 | json.remove(e.getName()); 60 | jsona=new JsonArray(); 61 | jsona.add(jsono); 62 | jsona.add(chdjson); 63 | } 64 | if(o instanceof JsonArray){ 65 | jsona=(JsonArray)o; 66 | jsona.add(chdjson); 67 | } 68 | json.add(e.getName(), jsona); 69 | }else{ 70 | if(!chdjson.isJsonNull()){ 71 | json.add(e.getName(), chdjson); 72 | } 73 | } 74 | 75 | 76 | }else{//子元素没有子元素 77 | for(Object o:element.attributes()){ 78 | Attribute attr=(Attribute)o; 79 | if(!isEmpty(attr.getValue())){ 80 | json.addProperty("@"+attr.getName(), attr.getValue()); 81 | } 82 | } 83 | if(!e.getText().isEmpty()){ 84 | json.addProperty(e.getName(), e.getText()); 85 | } 86 | } 87 | } 88 | } 89 | 90 | private static boolean isEmpty(String str) { 91 | 92 | if (str == null || str.trim().isEmpty() || "null".equals(str)) { 93 | return true; 94 | } 95 | return false; 96 | } 97 | 98 | } 99 | -------------------------------------------------------------------------------- /SpringBootDemoV2/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | banner: 3 | image: 4 | location: static/banner.png 5 | duck: 6 | duckName: DonDonald Fauntleroy Duck 7 | totalCount: 1 8 | 9 | server: 10 | servlet: 11 | context-path: /xiaour-dubbo 12 | port: 8081 13 | dubbo: 14 | scan: 15 | base-packages: com.github.xiaour.service 16 | application: 17 | id: xiaour-provider 18 | name: xiaour-provider 19 | registry: 20 | address: zookeeper://127.0.0.1:2181 21 | id: my-registry 22 | protocol: 23 | id: dubbo 24 | name: dubbo 25 | port: 20880 -------------------------------------------------------------------------------- /SpringBootDemoV2/src/main/resources/static/banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaour/SpringBootDemo/155c426b33fc9553d5a8d50201247a1ceddc1712/SpringBootDemoV2/src/main/resources/static/banner.png -------------------------------------------------------------------------------- /SpringBootDemoV2/src/test/java/com/github/xiaour/SpringBootDemoV2ApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.github.xiaour; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class SpringBootDemoV2ApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /SpringBootDemoV3/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | !**/src/main/**/target/ 5 | !**/src/test/**/target/ 6 | 7 | ### STS ### 8 | .apt_generated 9 | .classpath 10 | .factorypath 11 | .project 12 | .settings 13 | .springBeans 14 | .sts4-cache 15 | 16 | ### IntelliJ IDEA ### 17 | .idea 18 | *.iws 19 | *.iml 20 | *.ipr 21 | 22 | ### NetBeans ### 23 | /nbproject/private/ 24 | /nbbuild/ 25 | /dist/ 26 | /nbdist/ 27 | /.nb-gradle/ 28 | build/ 29 | !**/src/main/**/build/ 30 | !**/src/test/**/build/ 31 | 32 | ### VS Code ### 33 | .vscode/ 34 | -------------------------------------------------------------------------------- /SpringBootDemoV3/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 3.2.3 9 | 10 | 11 | 12 | com.github.xiaour 13 | springbootv3 14 | 0.0.1-SNAPSHOT 15 | SpringBootDemoV3 16 | Demo project for Spring Boot 17 | jar 18 | 19 | 20 | 17 21 | 22 | 23 | 24 | 25 | 26 | org.springframework.boot 27 | spring-boot-starter 28 | 29 | 30 | 31 | org.springframework.boot 32 | spring-boot-starter-test 33 | test 34 | 35 | 36 | 37 | org.springframework.boot 38 | spring-boot-starter-web 39 | 40 | 41 | 42 | io.github.xiaour 43 | easy-export 44 | 1.0.1-RELEASE 45 | 46 | 47 | 48 | com.alibaba 49 | easyexcel 50 | 2.2.3 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | org.springframework.boot 59 | spring-boot-maven-plugin 60 | 61 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /SpringBootDemoV3/src/main/java/com/xiaour/spring/boot/SpringBootDemoV3Application.java: -------------------------------------------------------------------------------- 1 | package com.xiaour.spring.boot; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class SpringBootDemoV3Application { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(SpringBootDemoV3Application.class, args); 11 | //System.out.println(Math.max(10,11)); 12 | } 13 | 14 | 15 | } 16 | -------------------------------------------------------------------------------- /SpringBootDemoV3/src/main/java/com/xiaour/spring/boot/controller/CatController.java: -------------------------------------------------------------------------------- 1 | package com.xiaour.spring.boot.controller; 2 | 3 | import com.xiaour.spring.boot.entity.PageIndex; 4 | import com.xiaour.spring.boot.entity.PageInfo; 5 | import com.xiaour.spring.boot.service.CatService; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.web.bind.annotation.GetMapping; 8 | import org.springframework.web.bind.annotation.RequestMapping; 9 | import org.springframework.web.bind.annotation.RestController; 10 | 11 | @RestController 12 | @RequestMapping("/cat") 13 | public class CatController { 14 | 15 | private CatService catService; 16 | 17 | @Autowired 18 | public CatController(CatService catService) { 19 | this.catService = catService; 20 | } 21 | 22 | @GetMapping("list") 23 | public PageInfo getCatList() { 24 | PageIndex index = new PageIndex(); 25 | index.setPageIndex(1); 26 | index.setPageSize(30); 27 | return catService.getCatList(index); 28 | } 29 | 30 | 31 | 32 | 33 | 34 | } 35 | -------------------------------------------------------------------------------- /SpringBootDemoV3/src/main/java/com/xiaour/spring/boot/entity/Cat.java: -------------------------------------------------------------------------------- 1 | package com.xiaour.spring.boot.entity; 2 | 3 | import com.alibaba.excel.annotation.ExcelProperty; 4 | 5 | public class Cat { 6 | 7 | /** 8 | * 宠物昵称 9 | */ 10 | @ExcelProperty(value = "昵称") 11 | private String nickName; 12 | 13 | /** 14 | * 年龄 15 | */ 16 | @ExcelProperty(value = "年龄") 17 | private Integer age; 18 | 19 | /** 20 | * 品种 21 | */ 22 | @ExcelProperty(value = "品种") 23 | private String category; 24 | 25 | public Cat() { 26 | } 27 | 28 | public Cat(String nickName, Integer age, String category) { 29 | this.nickName = nickName; 30 | this.age = age; 31 | this.category = category; 32 | } 33 | 34 | public String getNickName() { 35 | return nickName; 36 | } 37 | 38 | public Cat setNickName(String nickName) { 39 | this.nickName = nickName; 40 | return this; 41 | } 42 | 43 | public Integer getAge() { 44 | return age; 45 | } 46 | 47 | public Cat setAge(Integer age) { 48 | this.age = age; 49 | return this; 50 | } 51 | 52 | public String getCategory() { 53 | return category; 54 | } 55 | 56 | public Cat setCategory(String category) { 57 | this.category = category; 58 | return this; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /SpringBootDemoV3/src/main/java/com/xiaour/spring/boot/entity/PageIndex.java: -------------------------------------------------------------------------------- 1 | package com.xiaour.spring.boot.entity; 2 | 3 | public class PageIndex { 4 | 5 | private Integer pageIndex; 6 | 7 | private Integer pageSize; 8 | 9 | public Integer getPageIndex() { 10 | return pageIndex; 11 | } 12 | 13 | public void setPageIndex(Integer pageIndex) { 14 | this.pageIndex = pageIndex; 15 | } 16 | 17 | public Integer getPageSize() { 18 | return pageSize; 19 | } 20 | 21 | public void setPageSize(Integer pageSize) { 22 | this.pageSize = pageSize; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /SpringBootDemoV3/src/main/java/com/xiaour/spring/boot/entity/PageInfo.java: -------------------------------------------------------------------------------- 1 | package com.xiaour.spring.boot.entity; 2 | 3 | import java.util.List; 4 | 5 | public class PageInfo { 6 | 7 | private List list; 8 | 9 | private Integer total; 10 | 11 | public List getList() { 12 | return list; 13 | } 14 | 15 | public void setList(List list) { 16 | this.list = list; 17 | } 18 | 19 | public Integer getTotal() { 20 | return total; 21 | } 22 | 23 | public void setTotal(Integer total) { 24 | this.total = total; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /SpringBootDemoV3/src/main/java/com/xiaour/spring/boot/service/CatService.java: -------------------------------------------------------------------------------- 1 | package com.xiaour.spring.boot.service; 2 | 3 | import com.github.xiaour.easyexport.annotation.EasyExport; 4 | import com.github.xiaour.easyexport.annotation.EasyExportSingle; 5 | import com.xiaour.spring.boot.entity.Cat; 6 | import com.xiaour.spring.boot.entity.PageIndex; 7 | import com.xiaour.spring.boot.entity.PageInfo; 8 | import org.springframework.stereotype.Service; 9 | 10 | import java.util.ArrayList; 11 | import java.util.List; 12 | 13 | @EasyExport 14 | @Service 15 | public class CatService { 16 | 17 | /** 18 | * 这里主要是模拟数据和分页参数的一些主要逻辑 19 | * @param pageIndex 模拟的分页参数,这里面是伪代码,无需实现 20 | * @return 21 | */ 22 | @EasyExportSingle(value = "小猫明细",modelClass = Cat.class) 23 | public PageInfo getCatList(PageIndex pageIndex){ 24 | 25 | PageInfo page = new PageInfo(); 26 | 27 | List list = new ArrayList<>(); 28 | 29 | //下面提供了两种实体赋值方式,大家可以试试那种更方便 30 | Cat cat1 = new Cat("咪咪",1,"波斯猫"); 31 | 32 | Cat cat2 = new Cat().setNickName("汤姆").setAge(6).setCategory("金渐层"); 33 | 34 | list.add(cat1); 35 | 36 | list.add(cat2); 37 | 38 | page.setList(list); 39 | 40 | page.setTotal(list.size()); 41 | 42 | return page; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /SpringBootDemoV3/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | server.servlet.context-path= /demo3 2 | 3 | #??easyexport 4 | easyexport.enabled=true 5 | #?????? 6 | #?????????? 7 | easyexport.fetch.page.size=5000 8 | #???????????????????true??????? 9 | easyexport.file.delete=true 10 | #???????????????????Sheet????sheet???150000 11 | easyexport.file.sheet.size=15000 12 | #???? 13 | easyexport.field.page.number=pageIndex 14 | #??????? 15 | easyexport.field.page.size=pageSize -------------------------------------------------------------------------------- /SpringBootDemoV3/src/test/java/com/xiaour/spring/boot/SpringBootDemoV3ApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.xiaour.spring.boot; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class SpringBootDemoV3ApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /SpringBootKafkaDemo/SpringBootKafkaDemo.iml: -------------------------------------------------------------------------------- 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 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /SpringBootKafkaDemo/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | com.github.xiaour 7 | KafkaDemo 8 | 0.0.1-SNAPSHOT 9 | jar 10 | 11 | kafka 12 | Kafka Demo project for Spring Boot 13 | 14 | 15 | org.springframework.boot 16 | spring-boot-starter-parent 17 | 2.0.2.RELEASE 18 | 19 | 20 | 21 | 22 | UTF-8 23 | UTF-8 24 | 1.8 25 | 26 | 27 | 28 | 29 | org.springframework.boot 30 | spring-boot-starter 31 | 32 | 33 | org.springframework.kafka 34 | spring-kafka 35 | 36 | 37 | 38 | org.springframework.boot 39 | spring-boot-starter-test 40 | test 41 | 42 | 43 | 44 | com.google.code.gson 45 | gson 46 | 2.8.9 47 | 48 | 49 | org.springframework.boot 50 | spring-boot-starter-web 51 | 2.5.12 52 | 53 | 54 | org.springframework 55 | spring-context 56 | 5.2.22.RELEASE 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | org.springframework.boot 65 | spring-boot-maven-plugin 66 | 67 | 68 | 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /SpringBootKafkaDemo/src/main/java/com/xiaour/spring/boot/kafka/KafkaApplication.java: -------------------------------------------------------------------------------- 1 | package com.xiaour.spring.boot.kafka; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class KafkaApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(KafkaApplication.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /SpringBootKafkaDemo/src/main/java/com/xiaour/spring/boot/kafka/consumer/Consumer.java: -------------------------------------------------------------------------------- 1 | package com.xiaour.spring.boot.kafka.consumer; 2 | 3 | import org.apache.kafka.clients.consumer.ConsumerRecord; 4 | import org.springframework.kafka.annotation.KafkaListener; 5 | import org.springframework.stereotype.Component; 6 | 7 | import java.util.Optional; 8 | 9 | /** 10 | * @Author: Xiaour 11 | * @Description: 12 | * @Date: 2018/5/22 15:03 13 | */ 14 | @Component 15 | public class Consumer { 16 | 17 | @KafkaListener(topics = {"test"}) 18 | public void listen(ConsumerRecord record){ 19 | 20 | Optional kafkaMessage = Optional.ofNullable(record.value()); 21 | 22 | if (kafkaMessage.isPresent()) { 23 | 24 | Object message = kafkaMessage.get(); 25 | System.out.println("---->"+record); 26 | System.out.println("---->"+message); 27 | 28 | } 29 | 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /SpringBootKafkaDemo/src/main/java/com/xiaour/spring/boot/kafka/producer/Message.java: -------------------------------------------------------------------------------- 1 | package com.xiaour.spring.boot.kafka.producer; 2 | 3 | import java.util.Date; 4 | 5 | /** 6 | * @Author: Xiaour 7 | * @Description: 8 | * @Date: 2018/5/22 15:09 9 | */ 10 | public class Message { 11 | 12 | private String id; 13 | 14 | private String msg; 15 | 16 | private Date sendTime; 17 | 18 | public String getId() { 19 | return id; 20 | } 21 | 22 | public void setId(String id) { 23 | this.id = id; 24 | } 25 | 26 | public String getMsg() { 27 | return msg; 28 | } 29 | 30 | public void setMsg(String msg) { 31 | this.msg = msg; 32 | } 33 | 34 | public Date getSendTime() { 35 | return sendTime; 36 | } 37 | 38 | public void setSendTime(Date sendTime) { 39 | this.sendTime = sendTime; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /SpringBootKafkaDemo/src/main/java/com/xiaour/spring/boot/kafka/producer/Producer.java: -------------------------------------------------------------------------------- 1 | package com.xiaour.spring.boot.kafka.producer; 2 | 3 | import com.google.gson.Gson; 4 | import com.google.gson.GsonBuilder; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.kafka.core.KafkaTemplate; 7 | import org.springframework.stereotype.Component; 8 | 9 | import java.util.Date; 10 | import java.util.UUID; 11 | 12 | /** 13 | * @Author: Xiaour 14 | * @Description: 15 | * @Date: 2018/5/22 15:07 16 | */ 17 | @Component 18 | public class Producer { 19 | 20 | @Autowired 21 | private KafkaTemplate kafkaTemplate; 22 | 23 | private static Gson gson = new GsonBuilder().create(); 24 | 25 | //发送消息方法 26 | public void send() { 27 | Message message = new Message(); 28 | message.setId("KFK_"+System.currentTimeMillis()); 29 | message.setMsg(UUID.randomUUID().toString()); 30 | message.setSendTime(new Date()); 31 | kafkaTemplate.send("test", gson.toJson(message)); 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /SpringBootKafkaDemo/src/main/java/com/xiaour/spring/boot/kafka/producer/SendController.java: -------------------------------------------------------------------------------- 1 | package com.xiaour.spring.boot.kafka.producer; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.web.bind.annotation.RequestMapping; 5 | import org.springframework.web.bind.annotation.RestController; 6 | 7 | /** 8 | * @Author: Xiaour 9 | * @Description: 10 | * @Date: 2018/5/22 15:13 11 | */ 12 | @RestController 13 | @RequestMapping("/kafka") 14 | public class SendController { 15 | 16 | @Autowired 17 | private Producer producer; 18 | 19 | @RequestMapping(value = "/send") 20 | public String send() { 21 | producer.send(); 22 | return "{\"code\":0}"; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /SpringBootKafkaDemo/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | servlet: 3 | context-path: / 4 | port: 8080 5 | spring: 6 | kafka: 7 | bootstrap-servers: 127.0.0.1:9092 8 | #生产者的配置,大部分我们可以使用默认的,这里列出几个比较重要的属性 9 | producer: 10 | #每批次发送消息的数量 11 | batch-size: 16 12 | #设置大于0的值将使客户端重新发送任何数据,一旦这些数据发送失败。注意,这些重试与客户端接收到发送错误时的重试没有什么不同。允许重试将潜在的改变数据的顺序,如果这两个消息记录都是发送到同一个partition,则第一个消息失败第二个发送成功,则第二条消息会比第一条消息出现要早。 13 | retries: 0 14 | #producer可以用来缓存数据的内存大小。如果数据产生速度大于向broker发送的速度,producer会阻塞或者抛出异常,以“block.on.buffer.full”来表明。这项设置将和producer能够使用的总内存相关,但并不是一个硬性的限制,因为不是producer使用的所有内存都是用于缓存。一些额外的内存会用于压缩(如果引入压缩机制),同样还有一些用于维护请求。 15 | buffer-memory: 33554432 16 | #key序列化方式 17 | key-serializer: org.apache.kafka.common.serialization.StringSerializer 18 | value-serializer: org.apache.kafka.common.serialization.StringSerializer 19 | #消费者的配置 20 | consumer: 21 | #Kafka中没有初始偏移或如果当前偏移在服务器上不再存在时,默认区最新 ,有三个选项 【latest, earliest, none】 22 | auto-offset-reset: latest 23 | #是否开启自动提交 24 | enable-auto-commit: true 25 | #自动提交的时间间隔 26 | auto-commit-interval: 100 27 | #key的解码方式 28 | key-deserializer: org.apache.kafka.common.serialization.StringDeserializer 29 | #value的解码方式 30 | value-deserializer: org.apache.kafka.common.serialization.StringDeserializer 31 | #在/usr/local/etc/kafka/consumer.properties中有配置 32 | group-id: test-consumer-group 33 | 34 | -------------------------------------------------------------------------------- /SpringBootKafkaDemo/src/test/java/com/xiaour/spring/boot/kafka/KafkaApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.xiaour.spring.boot.kafka; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class KafkaApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /SpringBootKafkaDemo/target/classes/com/xiaour/spring/boot/kafka/producer/Message.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaour/SpringBootDemo/155c426b33fc9553d5a8d50201247a1ceddc1712/SpringBootKafkaDemo/target/classes/com/xiaour/spring/boot/kafka/producer/Message.class -------------------------------------------------------------------------------- /SpringBootRocketMqDemo/.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | !.mvn/wrapper/maven-wrapper.jar 3 | 4 | ### STS ### 5 | .apt_generated 6 | .classpath 7 | .factorypath 8 | .project 9 | .settings 10 | .springBeans 11 | .sts4-cache 12 | 13 | ### IntelliJ IDEA ### 14 | .idea 15 | *.iws 16 | *.iml 17 | *.ipr 18 | 19 | ### NetBeans ### 20 | /nbproject/private/ 21 | /build/ 22 | /nbbuild/ 23 | /dist/ 24 | /nbdist/ 25 | /.nb-gradle/ -------------------------------------------------------------------------------- /SpringBootRocketMqDemo/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaour/SpringBootDemo/155c426b33fc9553d5a8d50201247a1ceddc1712/SpringBootRocketMqDemo/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /SpringBootRocketMqDemo/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.5.3/apache-maven-3.5.3-bin.zip 2 | -------------------------------------------------------------------------------- /SpringBootRocketMqDemo/SpringbootRocketMQ.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Springboot集成ROcketMQ 3 | categories: [Springboot],[MQ] 4 | date: 2018-05-23 10:43:12 5 | tags: 6 | --- 7 | 8 | post-cover"" 9 | 10 | 有一段时间没有写东西了,最近工作和生活上发生了一些变化,总算是有点时间来歇一歇自己想要分享的,2018年转眼过去一多半了,想来自己今年好像也没有太多的积累。尽可能的让自己能够多做一些技术上的事情。 11 | 12 | 从开篇写Springboot系列的教程已经一年多了,Springboot也从1.x升级到了2.x,目前教程中的代码部分大多都是使用Springboot2.x了。 13 | 14 | Springboot从开始到流行起来的到现在的风靡是很多开发越来越简单,经我调查发现大部分开发人员都已经开始在生产环境使用,除了一些老的项目或者难以改变技术架构的项目外,Springboot可以说是作为JAVA开发人员必不可少的伙伴了。 15 | 16 | 如今大多数的JAVA系组件都开发除了自己的boot版本,有一些做的比较优秀,也有一些做的不是那么好,本篇要介绍的RocketMQ在boot上做的就不算很好,有很多开发者自己封装了boot版本,官方可能会在未来出现更好版本的boot;但是没有boot版没关系,咱们自己几行配置也是完全可以做到快速使用RocketMQ了。 17 | 18 | 在这里我要提一下官方版本的RocketMQ4.3,因为本文就是基于RocketMQ4.3的,"RocketMQ4.3正式发布支持了分布式事务"。这一消息让很多开发者跃跃欲试,以前rocketMQ没有将分布式事务作为一个发行版的部分,基本都是开发者自己实现的事务部分。下面我们从最基础的安装RocketMQ开始,再介绍代码中如何实现基本的配置。 19 | 20 | ###下载安装RocketMQ 21 | 22 | ``` 23 | # wget http://mirrors.hust.edu.cn/apache/rocketmq/4.3.0/rocketmq-all-4.3.0-source-release.zip 24 | # unzip rocketmq-all-4.3.0-source-release.zip 25 | # mvn -Prelease-all -DskipTests clean install -U 26 | # cd distribution/target/apache-rocketmq 27 | ``` 28 | 29 | ###启动NameServer,启动后NameServer的端口是9876,请确保自己的9876端口未被占用 30 | ``` 31 | # nohup sh bin/mqnamesrv & 32 | # tail -f ~/logs/rocketmqlogs/namesrv.log 33 | The Name Server boot success... 34 | ``` 35 | 36 | ### 启动Broker 37 | ``` 38 | # nohup sh bin/mqbroker -n localhost:9876 & 39 | # tail -f ~/logs/rocketmqlogs/broker.log 40 | The broker[%s, 172.30.30.233:10911] boot success... 41 | ``` 42 | 启动成功了之后我们就可以创建新的Springboot项目了,如何创建项目这里我就不在介绍了,Eclipse和Idea的方式大同小异,目录结构基本都是一样的。 43 | 44 | 首先每次说到Springboot的项目都是要先讲讲这个boot的配置,按照惯例呢我先给配置,配置上都有每一行配置的注释,大家可以参考。 45 | ### 代码示例pom.xml 46 | ``` 47 | 48 | org.springframework.boot 49 | spring-boot-starter-parent 50 | 2.0.4.RELEASE 51 | 52 | 53 | 54 | 55 | UTF-8 56 | UTF-8 57 | 1.8 58 | 59 | 60 | 61 | 62 | org.springframework.boot 63 | spring-boot-starter-data-redis 64 | 65 | 66 | 67 | org.springframework.boot 68 | spring-boot-starter-test 69 | test 70 | 71 | 72 | 73 | 74 | org.apache.rocketmq 75 | rocketmq-client 76 | 4.3.0 77 | 78 | 79 | 80 | org.springframework.boot 81 | spring-boot-starter-web 82 | RELEASE 83 | 84 | 85 | ``` 86 | ###application.yml 87 | ``` 88 | apache: 89 | rocketmq: 90 | #消费者的配置 91 | consumer: 92 | pushConsumer: XiaourPushConsumer 93 | #生产者的配置 94 | producer: 95 | producerGroup: Xiaour 96 | #Nameserver的地址,这里配置你MQ安装的机器上的IP就好,我这里在本机安装的 97 | namesrvAddr: 127.0.0.1:9876 98 | ``` 99 | 100 | ###Producer 消息生产者 101 | ```java 102 | import org.apache.commons.lang3.time.StopWatch; 103 | import org.apache.rocketmq.client.exception.MQBrokerException; 104 | import org.apache.rocketmq.client.exception.MQClientException; 105 | import org.apache.rocketmq.client.producer.DefaultMQProducer; 106 | import org.apache.rocketmq.client.producer.SendResult; 107 | import org.apache.rocketmq.common.message.Message; 108 | import org.apache.rocketmq.remoting.common.RemotingHelper; 109 | import org.apache.rocketmq.remoting.exception.RemotingException; 110 | import org.springframework.beans.factory.annotation.Value; 111 | import org.springframework.stereotype.Component; 112 | 113 | import javax.annotation.PostConstruct; 114 | import java.io.UnsupportedEncodingException; 115 | 116 | /** 117 | * @Author: Xiaour 118 | * @Description:生产者 119 | * @Date: 2018/8/9 14:52 120 | */ 121 | 122 | @Component 123 | public class Producer { 124 | 125 | /** 126 | * 生产者的组名 127 | */ 128 | @Value("${apache.rocketmq.producer.producerGroup}") 129 | private String producerGroup; 130 | 131 | private DefaultMQProducer producer; 132 | /** 133 | * NameServer 地址 134 | */ 135 | @Value("${apache.rocketmq.namesrvAddr}") 136 | private String namesrvAddr; 137 | 138 | @PostConstruct 139 | public void defaultMQProducer() { 140 | 141 | //生产者的组名 142 | producer= new DefaultMQProducer(producerGroup); 143 | //指定NameServer地址,多个地址以 ; 隔开 144 | producer.setNamesrvAddr(namesrvAddr); 145 | producer.setVipChannelEnabled(false); 146 | try { 147 | producer.start(); 148 | System.out.println("-------->:producer启动了"); 149 | } catch (MQClientException e) { 150 | e.printStackTrace(); 151 | } 152 | } 153 | 154 | public String send(String topic,String tags,String body) throws InterruptedException, RemotingException, MQClientException, MQBrokerException, UnsupportedEncodingException { 155 | Message message = new Message(topic, tags, body.getBytes(RemotingHelper.DEFAULT_CHARSET)); 156 | StopWatch stop = new StopWatch(); 157 | stop.start(); 158 | SendResult result = producer.send(message); 159 | System.out.println("发送响应:MsgId:" + result.getMsgId() + ",发送状态:" + result.getSendStatus()); 160 | stop.stop(); 161 | return "{\"MsgId\":\""+result.getMsgId()+"\"}"; 162 | } 163 | } 164 | ``` 165 | ###Consumer 消息消费者 166 | 167 | ```java 168 | import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer; 169 | import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus; 170 | import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently; 171 | import org.apache.rocketmq.common.consumer.ConsumeFromWhere; 172 | import org.apache.rocketmq.common.message.Message; 173 | import org.springframework.beans.factory.annotation.Value; 174 | import org.springframework.boot.CommandLineRunner; 175 | 176 | import org.springframework.stereotype.Component; 177 | 178 | /** 179 | * @Author: Xiaour 180 | * @Description:消费者 181 | * @Date: 2018/8/9 14:51 182 | */ 183 | 184 | @Component 185 | public class Consumer implements CommandLineRunner { 186 | 187 | /** 188 | * 消费者 189 | */ 190 | @Value("${apache.rocketmq.consumer.pushConsumer}") 191 | private String pushConsumer; 192 | 193 | /** 194 | * NameServer 地址 195 | */ 196 | @Value("${apache.rocketmq.namesrvAddr}") 197 | private String namesrvAddr; 198 | 199 | 200 | /** 201 | * 初始化RocketMq的监听信息,渠道信息 202 | */ 203 | public void messageListener(){ 204 | 205 | DefaultMQPushConsumer consumer=new DefaultMQPushConsumer("SpringBootRocketMqGroup"); 206 | 207 | consumer.setNamesrvAddr(namesrvAddr); 208 | try { 209 | 210 | // 订阅PushTopic下Tag为push的消息,都订阅消息 211 | consumer.subscribe("PushTopic", "push"); 212 | 213 | // 程序第一次启动从消息队列头获取数据 214 | consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_FIRST_OFFSET); 215 | //可以修改每次消费消息的数量,默认设置是每次消费一条 216 | consumer.setConsumeMessageBatchMaxSize(1); 217 | 218 | //在此监听中消费信息,并返回消费的状态信息 219 | consumer.registerMessageListener((MessageListenerConcurrently) (msgs, context) -> { 220 | 221 | // 会把不同的消息分别放置到不同的队列中 222 | for(Message msg:msgs){ 223 | 224 | System.out.println("接收到了消息:"+new String(msg.getBody())); 225 | } 226 | return ConsumeConcurrentlyStatus.CONSUME_SUCCESS; 227 | }); 228 | 229 | consumer.start(); 230 | 231 | } catch (Exception e) { 232 | e.printStackTrace(); 233 | } 234 | } 235 | 236 | @Override 237 | public void run(String... args) throws Exception { 238 | this.messageListener(); 239 | } 240 | } 241 | ``` 242 | ###测试接口用例 243 | 这里我们用一个接口来测试我们的消息发送会不会被消费者接收。 244 | 245 | ```java 246 | @RestController 247 | public class TestController { 248 | @Autowired 249 | private Producer producer; 250 | 251 | @RequestMapping("/push") 252 | public String pushMsg(String msg){ 253 | try { 254 | return producer.send("PushTopic","push",msg); 255 | } catch (InterruptedException e) { 256 | e.printStackTrace(); 257 | } catch (RemotingException e) { 258 | e.printStackTrace(); 259 | } catch (MQClientException e) { 260 | e.printStackTrace(); 261 | } catch (MQBrokerException e) { 262 | e.printStackTrace(); 263 | } catch (UnsupportedEncodingException e) { 264 | e.printStackTrace(); 265 | } 266 | return "ERROR"; 267 | } 268 | } 269 | ``` 270 | 在Springboot启动类启动后,在浏览器访问http://127.0.0.1:8080/push?hello,页面提示{"MsgId":"AC100AB660C618B4AAC2XXXXXXXX"}就表示消息发送成功啦。 271 | 我们可以再IDE控制台中看到输出的结果, 272 | ```text 273 | 发送响应:MsgId:AC100AB660C618B4AAC2XXXXXXXX,发送状态:SEND_OK 274 | 接收到了消息:hello 275 | ``` 276 | 这时候我们的整合基本上就完成啦。 277 | 278 | 具体代码可以在github获取哦。SpringBootRocketMqDemo@github](https://github.com/xiaour/SpringBootDemo/tree/master/SpringBootRocketMqDemo)获取哦。 -------------------------------------------------------------------------------- /SpringBootRocketMqDemo/mvnw: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # ---------------------------------------------------------------------------- 3 | # Licensed to the Apache Software Foundation (ASF) under one 4 | # or more contributor license agreements. See the NOTICE file 5 | # distributed with this work for additional information 6 | # regarding copyright ownership. The ASF licenses this file 7 | # to you under the Apache License, Version 2.0 (the 8 | # "License"); you may not use this file except in compliance 9 | # with the License. You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, 14 | # software distributed under the License is distributed on an 15 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | # KIND, either express or implied. See the License for the 17 | # specific language governing permissions and limitations 18 | # under the License. 19 | # ---------------------------------------------------------------------------- 20 | 21 | # ---------------------------------------------------------------------------- 22 | # Maven2 Start Up Batch script 23 | # 24 | # Required ENV vars: 25 | # ------------------ 26 | # JAVA_HOME - location of a JDK home dir 27 | # 28 | # Optional ENV vars 29 | # ----------------- 30 | # M2_HOME - location of maven2's installed home dir 31 | # MAVEN_OPTS - parameters passed to the Java VM when running Maven 32 | # e.g. to debug Maven itself, use 33 | # set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 34 | # MAVEN_SKIP_RC - flag to disable loading of mavenrc files 35 | # ---------------------------------------------------------------------------- 36 | 37 | if [ -z "$MAVEN_SKIP_RC" ] ; then 38 | 39 | if [ -f /etc/mavenrc ] ; then 40 | . /etc/mavenrc 41 | fi 42 | 43 | if [ -f "$HOME/.mavenrc" ] ; then 44 | . "$HOME/.mavenrc" 45 | fi 46 | 47 | fi 48 | 49 | # OS specific support. $var _must_ be set to either true or false. 50 | cygwin=false; 51 | darwin=false; 52 | mingw=false 53 | case "`uname`" in 54 | CYGWIN*) cygwin=true ;; 55 | MINGW*) mingw=true;; 56 | Darwin*) darwin=true 57 | # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home 58 | # See https://developer.apple.com/library/mac/qa/qa1170/_index.html 59 | if [ -z "$JAVA_HOME" ]; then 60 | if [ -x "/usr/libexec/java_home" ]; then 61 | export JAVA_HOME="`/usr/libexec/java_home`" 62 | else 63 | export JAVA_HOME="/Library/Java/Home" 64 | fi 65 | fi 66 | ;; 67 | esac 68 | 69 | if [ -z "$JAVA_HOME" ] ; then 70 | if [ -r /etc/gentoo-release ] ; then 71 | JAVA_HOME=`java-config --jre-home` 72 | fi 73 | fi 74 | 75 | if [ -z "$M2_HOME" ] ; then 76 | ## resolve links - $0 may be a link to maven's home 77 | PRG="$0" 78 | 79 | # need this for relative symlinks 80 | while [ -h "$PRG" ] ; do 81 | ls=`ls -ld "$PRG"` 82 | link=`expr "$ls" : '.*-> \(.*\)$'` 83 | if expr "$link" : '/.*' > /dev/null; then 84 | PRG="$link" 85 | else 86 | PRG="`dirname "$PRG"`/$link" 87 | fi 88 | done 89 | 90 | saveddir=`pwd` 91 | 92 | M2_HOME=`dirname "$PRG"`/.. 93 | 94 | # make it fully qualified 95 | M2_HOME=`cd "$M2_HOME" && pwd` 96 | 97 | cd "$saveddir" 98 | # echo Using m2 at $M2_HOME 99 | fi 100 | 101 | # For Cygwin, ensure paths are in UNIX format before anything is touched 102 | if $cygwin ; then 103 | [ -n "$M2_HOME" ] && 104 | M2_HOME=`cygpath --unix "$M2_HOME"` 105 | [ -n "$JAVA_HOME" ] && 106 | JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 107 | [ -n "$CLASSPATH" ] && 108 | CLASSPATH=`cygpath --path --unix "$CLASSPATH"` 109 | fi 110 | 111 | # For Migwn, ensure paths are in UNIX format before anything is touched 112 | if $mingw ; then 113 | [ -n "$M2_HOME" ] && 114 | M2_HOME="`(cd "$M2_HOME"; pwd)`" 115 | [ -n "$JAVA_HOME" ] && 116 | JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" 117 | # TODO classpath? 118 | fi 119 | 120 | if [ -z "$JAVA_HOME" ]; then 121 | javaExecutable="`which javac`" 122 | if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then 123 | # readlink(1) is not available as standard on Solaris 10. 124 | readLink=`which readlink` 125 | if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then 126 | if $darwin ; then 127 | javaHome="`dirname \"$javaExecutable\"`" 128 | javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" 129 | else 130 | javaExecutable="`readlink -f \"$javaExecutable\"`" 131 | fi 132 | javaHome="`dirname \"$javaExecutable\"`" 133 | javaHome=`expr "$javaHome" : '\(.*\)/bin'` 134 | JAVA_HOME="$javaHome" 135 | export JAVA_HOME 136 | fi 137 | fi 138 | fi 139 | 140 | if [ -z "$JAVACMD" ] ; then 141 | if [ -n "$JAVA_HOME" ] ; then 142 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 143 | # IBM's JDK on AIX uses strange locations for the executables 144 | JAVACMD="$JAVA_HOME/jre/sh/java" 145 | else 146 | JAVACMD="$JAVA_HOME/bin/java" 147 | fi 148 | else 149 | JAVACMD="`which java`" 150 | fi 151 | fi 152 | 153 | if [ ! -x "$JAVACMD" ] ; then 154 | echo "Error: JAVA_HOME is not defined correctly." >&2 155 | echo " We cannot execute $JAVACMD" >&2 156 | exit 1 157 | fi 158 | 159 | if [ -z "$JAVA_HOME" ] ; then 160 | echo "Warning: JAVA_HOME environment variable is not set." 161 | fi 162 | 163 | CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher 164 | 165 | # traverses directory structure from process work directory to filesystem root 166 | # first directory with .mvn subdirectory is considered project base directory 167 | find_maven_basedir() { 168 | 169 | if [ -z "$1" ] 170 | then 171 | echo "Path not specified to find_maven_basedir" 172 | return 1 173 | fi 174 | 175 | basedir="$1" 176 | wdir="$1" 177 | while [ "$wdir" != '/' ] ; do 178 | if [ -d "$wdir"/.mvn ] ; then 179 | basedir=$wdir 180 | break 181 | fi 182 | # workaround for JBEAP-8937 (on Solaris 10/Sparc) 183 | if [ -d "${wdir}" ]; then 184 | wdir=`cd "$wdir/.."; pwd` 185 | fi 186 | # end of workaround 187 | done 188 | echo "${basedir}" 189 | } 190 | 191 | # concatenates all lines of a file 192 | concat_lines() { 193 | if [ -f "$1" ]; then 194 | echo "$(tr -s '\n' ' ' < "$1")" 195 | fi 196 | } 197 | 198 | BASE_DIR=`find_maven_basedir "$(pwd)"` 199 | if [ -z "$BASE_DIR" ]; then 200 | exit 1; 201 | fi 202 | 203 | export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} 204 | echo $MAVEN_PROJECTBASEDIR 205 | MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" 206 | 207 | # For Cygwin, switch paths to Windows format before running java 208 | if $cygwin; then 209 | [ -n "$M2_HOME" ] && 210 | M2_HOME=`cygpath --path --windows "$M2_HOME"` 211 | [ -n "$JAVA_HOME" ] && 212 | JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` 213 | [ -n "$CLASSPATH" ] && 214 | CLASSPATH=`cygpath --path --windows "$CLASSPATH"` 215 | [ -n "$MAVEN_PROJECTBASEDIR" ] && 216 | MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` 217 | fi 218 | 219 | WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 220 | 221 | exec "$JAVACMD" \ 222 | $MAVEN_OPTS \ 223 | -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ 224 | "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ 225 | ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" 226 | -------------------------------------------------------------------------------- /SpringBootRocketMqDemo/mvnw.cmd: -------------------------------------------------------------------------------- 1 | @REM ---------------------------------------------------------------------------- 2 | @REM Licensed to the Apache Software Foundation (ASF) under one 3 | @REM or more contributor license agreements. See the NOTICE file 4 | @REM distributed with this work for additional information 5 | @REM regarding copyright ownership. The ASF licenses this file 6 | @REM to you under the Apache License, Version 2.0 (the 7 | @REM "License"); you may not use this file except in compliance 8 | @REM with the License. You may obtain a copy of the License at 9 | @REM 10 | @REM http://www.apache.org/licenses/LICENSE-2.0 11 | @REM 12 | @REM Unless required by applicable law or agreed to in writing, 13 | @REM software distributed under the License is distributed on an 14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | @REM KIND, either express or implied. See the License for the 16 | @REM specific language governing permissions and limitations 17 | @REM under the License. 18 | @REM ---------------------------------------------------------------------------- 19 | 20 | @REM ---------------------------------------------------------------------------- 21 | @REM Maven2 Start Up Batch script 22 | @REM 23 | @REM Required ENV vars: 24 | @REM JAVA_HOME - location of a JDK home dir 25 | @REM 26 | @REM Optional ENV vars 27 | @REM M2_HOME - location of maven2's installed home dir 28 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands 29 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending 30 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven 31 | @REM e.g. to debug Maven itself, use 32 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 33 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files 34 | @REM ---------------------------------------------------------------------------- 35 | 36 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' 37 | @echo off 38 | @REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' 39 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% 40 | 41 | @REM set %HOME% to equivalent of $HOME 42 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") 43 | 44 | @REM Execute a user defined script before this one 45 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre 46 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending 47 | if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" 48 | if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" 49 | :skipRcPre 50 | 51 | @setlocal 52 | 53 | set ERROR_CODE=0 54 | 55 | @REM To isolate internal variables from possible post scripts, we use another setlocal 56 | @setlocal 57 | 58 | @REM ==== START VALIDATION ==== 59 | if not "%JAVA_HOME%" == "" goto OkJHome 60 | 61 | echo. 62 | echo Error: JAVA_HOME not found in your environment. >&2 63 | echo Please set the JAVA_HOME variable in your environment to match the >&2 64 | echo location of your Java installation. >&2 65 | echo. 66 | goto error 67 | 68 | :OkJHome 69 | if exist "%JAVA_HOME%\bin\java.exe" goto init 70 | 71 | echo. 72 | echo Error: JAVA_HOME is set to an invalid directory. >&2 73 | echo JAVA_HOME = "%JAVA_HOME%" >&2 74 | echo Please set the JAVA_HOME variable in your environment to match the >&2 75 | echo location of your Java installation. >&2 76 | echo. 77 | goto error 78 | 79 | @REM ==== END VALIDATION ==== 80 | 81 | :init 82 | 83 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn". 84 | @REM Fallback to current working directory if not found. 85 | 86 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% 87 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir 88 | 89 | set EXEC_DIR=%CD% 90 | set WDIR=%EXEC_DIR% 91 | :findBaseDir 92 | IF EXIST "%WDIR%"\.mvn goto baseDirFound 93 | cd .. 94 | IF "%WDIR%"=="%CD%" goto baseDirNotFound 95 | set WDIR=%CD% 96 | goto findBaseDir 97 | 98 | :baseDirFound 99 | set MAVEN_PROJECTBASEDIR=%WDIR% 100 | cd "%EXEC_DIR%" 101 | goto endDetectBaseDir 102 | 103 | :baseDirNotFound 104 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR% 105 | cd "%EXEC_DIR%" 106 | 107 | :endDetectBaseDir 108 | 109 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig 110 | 111 | @setlocal EnableExtensions EnableDelayedExpansion 112 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a 113 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% 114 | 115 | :endReadAdditionalConfig 116 | 117 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" 118 | 119 | set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" 120 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 121 | 122 | %MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* 123 | if ERRORLEVEL 1 goto error 124 | goto end 125 | 126 | :error 127 | set ERROR_CODE=1 128 | 129 | :end 130 | @endlocal & set ERROR_CODE=%ERROR_CODE% 131 | 132 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost 133 | @REM check for post script, once with legacy .bat ending and once with .cmd ending 134 | if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" 135 | if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" 136 | :skipRcPost 137 | 138 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' 139 | if "%MAVEN_BATCH_PAUSE%" == "on" pause 140 | 141 | if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% 142 | 143 | exit /B %ERROR_CODE% 144 | -------------------------------------------------------------------------------- /SpringBootRocketMqDemo/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | com.github.xiaour 7 | rocketmqDemo 8 | 0.0.1-SNAPSHOT 9 | SpringBootRocketmqDemo 10 | Demo project for RocketMQ 11 | jar 12 | 13 | 14 | org.springframework.boot 15 | spring-boot-starter-parent 16 | 2.0.4.RELEASE 17 | 18 | 19 | 20 | 21 | UTF-8 22 | UTF-8 23 | 1.8 24 | 25 | 26 | 27 | 28 | org.springframework.boot 29 | spring-boot-starter-data-redis 30 | 31 | 32 | 33 | org.springframework.boot 34 | spring-boot-starter-test 35 | test 36 | 37 | 38 | 39 | 40 | org.apache.rocketmq 41 | rocketmq-client 42 | 4.3.0 43 | 44 | 45 | org.springframework.boot 46 | spring-boot-starter-web 47 | 2.5.12 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | org.springframework.boot 57 | spring-boot-maven-plugin 58 | 59 | 60 | 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /SpringBootRocketMqDemo/src/main/java/com/xiaour/spring/boot/rocketmq/SpringBootRocketmqDemoApplication.java: -------------------------------------------------------------------------------- 1 | package com.xiaour.spring.boot.rocketmq; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class SpringBootRocketmqDemoApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(SpringBootRocketmqDemoApplication.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /SpringBootRocketMqDemo/src/main/java/com/xiaour/spring/boot/rocketmq/consumer/Consumer.java: -------------------------------------------------------------------------------- 1 | package com.xiaour.spring.boot.rocketmq.consumer; 2 | 3 | import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer; 4 | import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus; 5 | import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently; 6 | import org.apache.rocketmq.common.consumer.ConsumeFromWhere; 7 | import org.apache.rocketmq.common.message.Message; 8 | import org.springframework.beans.factory.annotation.Value; 9 | import org.springframework.boot.CommandLineRunner; 10 | 11 | import org.springframework.stereotype.Component; 12 | 13 | /** 14 | * @Author: Xiaour 15 | * @Description:消费者 16 | * @Date: 2018/8/9 14:51 17 | */ 18 | 19 | @Component 20 | public class Consumer implements CommandLineRunner { 21 | 22 | /** 23 | * 消费者 24 | */ 25 | @Value("${apache.rocketmq.consumer.pushConsumer}") 26 | private String pushConsumer; 27 | 28 | /** 29 | * NameServer 地址 30 | */ 31 | @Value("${apache.rocketmq.namesrvAddr}") 32 | private String namesrvAddr; 33 | 34 | 35 | /** 36 | * 初始化RocketMq的监听信息,渠道信息 37 | */ 38 | public void messageListener(){ 39 | 40 | DefaultMQPushConsumer consumer=new DefaultMQPushConsumer("SpringBootRocketMqGroup"); 41 | 42 | consumer.setNamesrvAddr(namesrvAddr); 43 | try { 44 | 45 | // 订阅PushTopic下Tag为push的消息,都订阅消息 46 | consumer.subscribe("PushTopic", "push"); 47 | 48 | // 程序第一次启动从消息队列头获取数据 49 | consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_FIRST_OFFSET); 50 | //可以修改每次消费消息的数量,默认设置是每次消费一条 51 | consumer.setConsumeMessageBatchMaxSize(1); 52 | 53 | //在此监听中消费信息,并返回消费的状态信息 54 | consumer.registerMessageListener((MessageListenerConcurrently) (msgs, context) -> { 55 | 56 | // 会把不同的消息分别放置到不同的队列中 57 | for(Message msg:msgs){ 58 | 59 | System.out.println("接收到了消息:"+new String(msg.getBody())); 60 | } 61 | return ConsumeConcurrentlyStatus.CONSUME_SUCCESS; 62 | }); 63 | 64 | consumer.start(); 65 | 66 | } catch (Exception e) { 67 | e.printStackTrace(); 68 | } 69 | } 70 | 71 | @Override 72 | public void run(String... args) throws Exception { 73 | this.messageListener(); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /SpringBootRocketMqDemo/src/main/java/com/xiaour/spring/boot/rocketmq/controller/TestController.java: -------------------------------------------------------------------------------- 1 | package com.xiaour.spring.boot.rocketmq.controller; 2 | 3 | import com.xiaour.spring.boot.rocketmq.producer.Producer; 4 | import org.apache.rocketmq.client.exception.MQBrokerException; 5 | import org.apache.rocketmq.client.exception.MQClientException; 6 | import org.apache.rocketmq.remoting.exception.RemotingException; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.web.bind.annotation.RequestMapping; 9 | import org.springframework.web.bind.annotation.RestController; 10 | 11 | import java.io.UnsupportedEncodingException; 12 | 13 | /** 14 | * @Author: Xiaour 15 | * @Description: 这里是为了测试 16 | * @Date: 2018/8/9 15:16 17 | */ 18 | @RestController 19 | public class TestController { 20 | @Autowired 21 | private Producer producer; 22 | 23 | @RequestMapping("/push") 24 | public String pushMsg(String msg){ 25 | try { 26 | return producer.send("PushTopic","push",msg); 27 | } catch (InterruptedException e) { 28 | e.printStackTrace(); 29 | } catch (RemotingException e) { 30 | e.printStackTrace(); 31 | } catch (MQClientException e) { 32 | e.printStackTrace(); 33 | } catch (MQBrokerException e) { 34 | e.printStackTrace(); 35 | } catch (UnsupportedEncodingException e) { 36 | e.printStackTrace(); 37 | } 38 | return "ERROR"; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /SpringBootRocketMqDemo/src/main/java/com/xiaour/spring/boot/rocketmq/producer/Producer.java: -------------------------------------------------------------------------------- 1 | package com.xiaour.spring.boot.rocketmq.producer; 2 | 3 | import org.apache.commons.lang3.time.StopWatch; 4 | import org.apache.rocketmq.client.exception.MQBrokerException; 5 | import org.apache.rocketmq.client.exception.MQClientException; 6 | import org.apache.rocketmq.client.producer.DefaultMQProducer; 7 | import org.apache.rocketmq.client.producer.SendResult; 8 | import org.apache.rocketmq.common.message.Message; 9 | import org.apache.rocketmq.remoting.common.RemotingHelper; 10 | import org.apache.rocketmq.remoting.exception.RemotingException; 11 | import org.springframework.beans.factory.annotation.Value; 12 | import org.springframework.stereotype.Component; 13 | 14 | import javax.annotation.PostConstruct; 15 | import java.io.UnsupportedEncodingException; 16 | 17 | /** 18 | * @Author: Xiaour 19 | * @Description:生产者 20 | * @Date: 2018/8/9 14:52 21 | */ 22 | 23 | @Component 24 | public class Producer { 25 | 26 | /** 27 | * 生产者的组名 28 | */ 29 | @Value("${apache.rocketmq.producer.producerGroup}") 30 | private String producerGroup; 31 | 32 | private DefaultMQProducer producer; 33 | /** 34 | * NameServer 地址 35 | */ 36 | @Value("${apache.rocketmq.namesrvAddr}") 37 | private String namesrvAddr; 38 | 39 | @PostConstruct 40 | public void defaultMQProducer() { 41 | 42 | //生产者的组名 43 | producer= new DefaultMQProducer(producerGroup); 44 | //指定NameServer地址,多个地址以 ; 隔开 45 | producer.setNamesrvAddr(namesrvAddr); 46 | producer.setVipChannelEnabled(false); 47 | try { 48 | producer.start(); 49 | System.out.println("-------->:producer启动了"); 50 | } catch (MQClientException e) { 51 | e.printStackTrace(); 52 | } 53 | } 54 | 55 | public String send(String topic,String tags,String body) throws InterruptedException, RemotingException, MQClientException, MQBrokerException, UnsupportedEncodingException { 56 | Message message = new Message(topic, tags, body.getBytes(RemotingHelper.DEFAULT_CHARSET)); 57 | StopWatch stop = new StopWatch(); 58 | stop.start(); 59 | SendResult result = producer.send(message); 60 | System.out.println("发送响应:MsgId:" + result.getMsgId() + ",发送状态:" + result.getSendStatus()); 61 | stop.stop(); 62 | return "{\"MsgId\":\""+result.getMsgId()+"\"}"; 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /SpringBootRocketMqDemo/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | apache: 2 | rocketmq: 3 | consumer: 4 | pushConsumer: XiaourPushConsumer 5 | producer: 6 | producerGroup: Xiaour 7 | namesrvAddr: 192.168.2.5:9876 -------------------------------------------------------------------------------- /SpringBootRocketMqDemo/src/test/java/com/xiaour/spring/boot/rocketmq/SpringBootRocketmqDemoApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.xiaour.spring.boot.rocketmq; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class SpringBootRocketmqDemoApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /SpringWebFluxDemo/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | /target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | 5 | ### STS ### 6 | .apt_generated 7 | .classpath 8 | .factorypath 9 | .project 10 | .settings 11 | .springBeans 12 | .sts4-cache 13 | 14 | ### IntelliJ IDEA ### 15 | .idea 16 | *.iws 17 | *.iml 18 | *.ipr 19 | 20 | ### NetBeans ### 21 | /nbproject/private/ 22 | /nbbuild/ 23 | /dist/ 24 | /nbdist/ 25 | /.nb-gradle/ 26 | /build/ 27 | -------------------------------------------------------------------------------- /SpringWebFluxDemo/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.1.3.RELEASE 9 | 10 | 11 | com.github.xiaour 12 | fluxDemo 13 | 0.0.1-SNAPSHOT 14 | SpringWebFluxDemo 15 | Demo project for Web Flux 16 | 17 | 18 | 1.8 19 | 20 | 21 | 22 | 23 | org.springframework.boot 24 | spring-boot-starter-web 25 | 26 | 27 | 28 | org.springframework.boot 29 | spring-boot-starter-webflux 30 | 31 | 32 | 33 | org.springframework.boot 34 | spring-boot-starter-test 35 | test 36 | 37 | 38 | 39 | 40 | 41 | 42 | org.springframework.boot 43 | spring-boot-maven-plugin 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /SpringWebFluxDemo/src/main/java/com/github/xiaour/flux/SpringWebFluxDemoApplication.java: -------------------------------------------------------------------------------- 1 | package com.github.xiaour.flux; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class SpringWebFluxDemoApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(SpringWebFluxDemoApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /SpringWebFluxDemo/src/main/java/com/github/xiaour/flux/controller/HelloWorlController.java: -------------------------------------------------------------------------------- 1 | package com.github.xiaour.flux.controller; 2 | 3 | import org.springframework.web.bind.annotation.GetMapping; 4 | import org.springframework.web.bind.annotation.RequestMapping; 5 | import org.springframework.web.bind.annotation.RestController; 6 | import reactor.core.publisher.Mono; 7 | 8 | /** 9 | * @Author: cityuu@163.com 10 | * @Date: 2019-02-27 16:26 11 | * @version: v1.0 12 | * @Description: 入门案例 13 | */ 14 | 15 | @RestController 16 | @RequestMapping("/") 17 | public class HelloWorlController { 18 | 19 | @GetMapping("hello") 20 | public Mono hello(){ 21 | return Mono.just("hello World!"); 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /SpringWebFluxDemo/src/main/java/com/github/xiaour/flux/controller/SSEController.java: -------------------------------------------------------------------------------- 1 | package com.github.xiaour.flux.controller; 2 | 3 | import io.netty.util.internal.ThreadLocalRandom; 4 | import org.springframework.http.codec.ServerSentEvent; 5 | import org.springframework.web.bind.annotation.GetMapping; 6 | import org.springframework.web.bind.annotation.RequestMapping; 7 | import org.springframework.web.bind.annotation.RestController; 8 | import reactor.core.publisher.Flux; 9 | import reactor.util.function.Tuples; 10 | 11 | import java.time.Duration; 12 | 13 | /** 14 | * @Author: cityuu@163.com 15 | * @Date: 2019-02-27 16:37 16 | * @version: v1.0 17 | * @Description: 服务器推送接口 18 | */ 19 | @RestController 20 | @RequestMapping("/sse") 21 | public class SSEController { 22 | 23 | @GetMapping("/randomNumbers") 24 | public Flux> randomNumbers() { 25 | return Flux.interval(Duration.ofSeconds(2)) 26 | .map(seq -> Tuples.of(seq, ThreadLocalRandom.current().nextInt())) 27 | .map(data -> ServerSentEvent.builder() 28 | .event("random") 29 | .id(Long.toString(data.getT1())) 30 | .data(data.getT2()) 31 | .build()); 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /SpringWebFluxDemo/src/main/java/com/github/xiaour/flux/controller/UserController.java: -------------------------------------------------------------------------------- 1 | package com.github.xiaour.flux.controller; 2 | 3 | import com.github.xiaour.flux.entity.User; 4 | import com.github.xiaour.flux.service.UserService; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.web.bind.annotation.*; 7 | import reactor.core.publisher.Flux; 8 | import reactor.core.publisher.Mono; 9 | 10 | import java.util.Objects; 11 | 12 | /** 13 | * @Author: cityuu@163.com 14 | * @Date: 2019-02-27 16:33 15 | * @version: v1.0 16 | * @Description: 用户管理接口 17 | */ 18 | @RestController 19 | @RequestMapping("/user") 20 | public class UserController { 21 | 22 | @Autowired 23 | private UserService userService; 24 | 25 | 26 | @GetMapping("") 27 | public Flux list() { 28 | return userService.list(); 29 | } 30 | 31 | @GetMapping("/{id}") 32 | public Mono getById(@PathVariable("id") final String id) { 33 | return this.userService.getById(id); 34 | } 35 | 36 | @PostMapping("") 37 | public Mono create(@RequestBody final User user) { 38 | return this.userService.createOrUpdate(user); 39 | } 40 | 41 | @PutMapping("/{id}") 42 | public Mono update(@PathVariable("id") final String id, @RequestBody final User user) { 43 | Objects.requireNonNull(user); 44 | user.setId(id); 45 | return this.userService.createOrUpdate(user); 46 | } 47 | 48 | @DeleteMapping("/{id}") 49 | public Mono delete(@PathVariable("id") final String id) { 50 | return this.userService.delete(id); 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /SpringWebFluxDemo/src/main/java/com/github/xiaour/flux/entity/User.java: -------------------------------------------------------------------------------- 1 | package com.github.xiaour.flux.entity; 2 | 3 | /** 4 | * @Author: cityuu@suiyueyule.com 5 | * @Date: 2019-02-27 16:31 6 | * @version: v1.0 7 | * @Description: 8 | */ 9 | public class User { 10 | 11 | private String id; 12 | 13 | private String name; 14 | 15 | private Integer age; 16 | 17 | public String getId() { 18 | return id; 19 | } 20 | 21 | public void setId(String id) { 22 | this.id = id; 23 | } 24 | 25 | public String getName() { 26 | return name; 27 | } 28 | 29 | public void setName(String name) { 30 | this.name = name; 31 | } 32 | 33 | public Integer getAge() { 34 | return age; 35 | } 36 | 37 | public void setAge(Integer age) { 38 | this.age = age; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /SpringWebFluxDemo/src/main/java/com/github/xiaour/flux/service/UserService.java: -------------------------------------------------------------------------------- 1 | package com.github.xiaour.flux.service; 2 | 3 | import com.github.xiaour.flux.entity.User; 4 | import org.springframework.stereotype.Service; 5 | import reactor.core.publisher.Flux; 6 | import reactor.core.publisher.Mono; 7 | 8 | import java.util.Map; 9 | import java.util.concurrent.ConcurrentHashMap; 10 | 11 | /** 12 | * @Author: cityuu@suiyueyule.com 13 | * @Date: 2019-02-27 16:30 14 | * @version: v1.0 15 | * @Description: 16 | */ 17 | @Service 18 | public class UserService { 19 | 20 | private final Map data = new ConcurrentHashMap<>(); 21 | 22 | public Flux list() { 23 | return Flux.fromIterable(this.data.values()); 24 | } 25 | 26 | public Flux getById(final Flux ids) { 27 | return ids.flatMap(id -> Mono.justOrEmpty(this.data.get(id))); 28 | } 29 | 30 | public Mono getById(final String id) { 31 | return Mono.justOrEmpty(this.data.get(id)); 32 | } 33 | 34 | public Mono createOrUpdate(final User user) { 35 | this.data.put(user.getId(), user); 36 | return Mono.just(user); 37 | } 38 | 39 | public Mono delete(final String id) { 40 | return Mono.justOrEmpty(this.data.remove(id)); 41 | } 42 | 43 | 44 | } 45 | -------------------------------------------------------------------------------- /SpringWebFluxDemo/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /SpringWebFluxDemo/src/test/java/com/github/xiaour/flux/SpringWebFluxDemoApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.github.xiaour.flux; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class SpringWebFluxDemoApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | com.github.xiaour 7 | com.xiaour.spring.boot 8 | 0.0.1-SNAPSHOT 9 | SpringBootDemo 10 | SpringBoot set demo 11 | pom 12 | 13 | 14 | SpringBootDemo 15 | SpringBootDemoV2 16 | SpringBootDemoV3 17 | SpringBootKafkaDemo 18 | SpringBootRocketMqDemo 19 | SpringWebFluxDemo 20 | 21 | 22 | 23 | 24 | 17 25 | 26 | 27 | 28 | --------------------------------------------------------------------------------