├── .gitignore ├── README.md ├── StudyAdminZuul ├── build.gradle └── src │ └── main │ ├── java │ └── com │ │ └── ityu │ │ └── studyadminzuul │ │ ├── AdminZuulApplication.java │ │ └── filter │ │ └── WebFilter.java │ └── resources │ └── application.yml ├── build.gradle ├── common ├── build.gradle └── src │ └── main │ └── java │ └── com │ └── ityu │ └── common │ └── utils │ ├── JwtTokenUtil.java │ ├── R.java │ └── RUtil.java ├── dependencies.gradle ├── settings.gradle ├── study.md ├── studyadmin ├── build.gradle └── src │ └── main │ ├── java │ └── com │ │ └── ityu │ │ └── studyadmin │ │ ├── StudyAdminApplication.java │ │ ├── client │ │ ├── ApiClient.java │ │ └── ApiClientImpl.java │ │ ├── component │ │ └── JwtPreAuthFilter.java │ │ ├── config │ │ ├── BaseSwaggerConfig.java │ │ ├── CustomDaoAuthenticationProvider.java │ │ ├── CustomHandlerConfiguration.java │ │ ├── PasswordEncoderConfiguration.java │ │ ├── Swagger2.java │ │ └── WebSecurityConfig.java │ │ ├── controller │ │ └── TestAdminController.java │ │ ├── domain │ │ └── AdminUser.java │ │ ├── service │ │ └── AuthDetailsService.java │ │ └── utils │ │ ├── Contans.java │ │ └── SecurityUtils.java │ └── resources │ └── application.yml ├── studyapi ├── build.gradle └── src │ └── main │ ├── java │ └── com │ │ └── ityu │ │ └── studyapi │ │ ├── StudyApiApplication.java │ │ ├── config │ │ ├── BaseSwaggerConfig.java │ │ └── Swagger2.java │ │ └── controller │ │ └── TestController.java │ └── resources │ └── bootstrap.yml ├── studyconfig ├── build.gradle └── src │ └── main │ ├── java │ └── com │ │ └── ityu │ │ └── config │ │ └── ConfigApplication.java │ └── resources │ └── application.yml ├── studyeureka ├── build.gradle └── src │ └── main │ ├── java │ └── com │ │ └── ityu │ │ └── studyeureka │ │ └── EurekaServiceApplication.java │ └── resources │ └── application.yml └── studystreamrmq ├── build.gradle └── src ├── main ├── java │ └── com │ │ └── ityu │ │ └── studystreamrmq │ │ ├── Constants.java │ │ ├── StudyStreamRmqApplication.java │ │ ├── rabbitmq │ │ ├── Customer1.java │ │ ├── QueueEnum.java │ │ ├── RabbitMqConfig.java │ │ └── TestSendMessage.java │ │ └── streamrq │ │ └── MessageBean.java └── resources │ └── application.yml └── test └── java └── com └── ityu └── studystreamrmq └── MyTest.java /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | .gradle/ 3 | .idea/ 4 | gradle/ 5 | gradlew 6 | gradlew.bat 7 | out/ 8 | 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # springcloudstudy 2 | #### springboot gradle 多模块微服务项目 3 | #### spring cloud Eureka Feign Hystrix Zull Config Bus JWT Security 4 | #### 用到了微服务常见技术 5 | #### JWT Security-->studyadmin 6 | #### Eureka Server-->studyeureka 7 | #### Eureka Client-->studyadmin 8 | #### Feign Hystrix-->studyadmin 9 | #### Zull 服务端-->StudyAdminZuul 10 | #### Zull 客户端-->studyadmin 11 | #### Config Bus -->studyconfig 12 | #### Config -->studyapi 13 | #### RabbitMQ -->studystreamrmq 14 | 15 | #### 启动顺序 16 | >studyconfig->studyeureka->后面任意 17 | 18 | #### 微服务 19 | [参考文章](https://blog.csdn.net/yujunlong3919/article/details/103490068) 20 | #### jwt和Security 21 | [参考文章](https://blog.csdn.net/yujunlong3919/article/details/103481152) 22 | #### RabbitMQ 23 | [参考文章](https://blog.csdn.net/yujunlong3919/article/details/103507217) 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /StudyAdminZuul/build.gradle: -------------------------------------------------------------------------------- 1 | 2 | version '1.0-SNAPSHOT' 3 | 4 | 5 | dependencies { 6 | implementation libraries['spring-cloud-starter-netflix-eureka-client'] 7 | implementation libraries['spring-cloud-starter-netflix-zuul'] 8 | // https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-dependencies 9 | 10 | testCompile group: 'junit', name: 'junit', version: '4.12' 11 | } 12 | -------------------------------------------------------------------------------- /StudyAdminZuul/src/main/java/com/ityu/studyadminzuul/AdminZuulApplication.java: -------------------------------------------------------------------------------- 1 | package com.ityu.studyadminzuul; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.cloud.netflix.eureka.EnableEurekaClient; 6 | import org.springframework.cloud.netflix.zuul.EnableZuulProxy; 7 | 8 | 9 | @SpringBootApplication 10 | @EnableEurekaClient 11 | @EnableZuulProxy 12 | public class AdminZuulApplication { 13 | public static void main(String[] args) { 14 | SpringApplication.run(AdminZuulApplication.class, args); 15 | } 16 | 17 | 18 | 19 | } 20 | -------------------------------------------------------------------------------- /StudyAdminZuul/src/main/java/com/ityu/studyadminzuul/filter/WebFilter.java: -------------------------------------------------------------------------------- 1 | package com.ityu.studyadminzuul.filter; 2 | 3 | import com.netflix.zuul.ZuulFilter; 4 | import com.netflix.zuul.context.RequestContext; 5 | import com.netflix.zuul.exception.ZuulException; 6 | import org.apache.commons.lang3.StringUtils; 7 | import org.springframework.stereotype.Component; 8 | 9 | import javax.servlet.http.HttpServletRequest; 10 | import java.io.UnsupportedEncodingException; 11 | import java.net.URLEncoder; 12 | 13 | @Component 14 | public class WebFilter extends ZuulFilter { 15 | @Override 16 | public String filterType() { 17 | return "pre"; 18 | } 19 | 20 | @Override 21 | public int filterOrder() { 22 | return 0; 23 | } 24 | 25 | @Override 26 | public boolean shouldFilter() { 27 | return true; 28 | } 29 | 30 | @Override 31 | public Object run() throws ZuulException { 32 | System.out.println("拦截器启动了"); 33 | RequestContext currentContext = RequestContext.getCurrentContext(); 34 | HttpServletRequest request = currentContext.getRequest(); 35 | if (request.getMethod().equals("OPTIONS")) { 36 | return null; 37 | } 38 | String url = request.getRequestURL().toString(); 39 | if (url.indexOf("/admin/login") > 0) { 40 | return null; 41 | } 42 | 43 | String header = request.getHeader("token"); 44 | if (StringUtils.isNotEmpty(header)) { 45 | currentContext.addZuulRequestHeader("token", header); 46 | } else { 47 | try { 48 | //URLDecoder.decode("xxxxx","UTF-8"); 解码 微服务获取时解码 49 | //在网关添加内容是编码 50 | currentContext.addZuulRequestHeader("token", URLEncoder.encode("没有头的信息", "UTF-8")); 51 | } catch (UnsupportedEncodingException e) { 52 | e.printStackTrace(); 53 | } 54 | } 55 | return null; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /StudyAdminZuul/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 9011 3 | eureka: 4 | client: 5 | service-url: 6 | defaultZone: http://127.0.0.1:6868/eureka/ 7 | instance: 8 | prefer-ip-address: true 9 | spring: 10 | application: 11 | name: study-adminzuul 12 | main: 13 | allow-bean-definition-overriding: true 14 | zuul: 15 | routes: 16 | study-api: 17 | path: /api/** 18 | serviceId: study-api 19 | study-admin: 20 | path: /admin/** 21 | serviceId: study-admin 22 | # strip-prefix: false -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id("org.springframework.boot") version "2.1.9.RELEASE" 3 | id ("java") 4 | } 5 | apply from: 'dependencies.gradle' 6 | allprojects { 7 | 8 | // 定义仓库 9 | repositories { 10 | maven{ url 'https://maven.aliyun.com/repository/public/' } 11 | } 12 | 13 | group 'com.ityu' 14 | version '1.0-SNAPSHOT' 15 | } 16 | 17 | subprojects { 18 | 19 | apply plugin: 'java' 20 | apply plugin: 'idea' 21 | // spring统一依赖管理 22 | apply plugin: 'io.spring.dependency-management' 23 | 24 | dependencyManagement { 25 | imports { 26 | mavenBom org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES 27 | mavenBom 'org.springframework.cloud:spring-cloud-dependencies:Greenwich.SR2' 28 | } 29 | } 30 | 31 | /** 32 | * 避免出现idea中可以运行,编译报错:程序包xxx不存在 33 | * https://blog.csdn.net/li295214001/article/details/88942082 34 | */ 35 | jar { 36 | enabled = true 37 | } 38 | 39 | bootJar { 40 | enabled = true 41 | } 42 | 43 | sourceCompatibility = 1.8 44 | targetCompatibility = 1.8 45 | 46 | // java编译的时候缺省状态下会因为中文字符而失败 47 | [compileJava,compileTestJava,javadoc]*.options*.encoding = 'UTF-8' 48 | 49 | dependencies { 50 | implementation libraries['spring-boot-starter'] 51 | implementation libraries['spring-boot-starter-web'] 52 | implementation libraries['spring-boot-starter-aop'] 53 | compileOnly libraries['lombok'] 54 | annotationProcessor libraries['lombok'] 55 | // implementation libraries['spring-cloud-config-server'] 56 | // implementation libraries['spring-cloud-starter-netflix-eureka-client'] 57 | // implementation libraries['spring-cloud-starter-netflix-eureka-server'] 58 | // implementation libraries['spring-boot-admin-starter-server'] 59 | // implementation libraries['spring-boot-starter-security'] 60 | implementation("cn.hutool:hutool-all:4.6.8") 61 | testImplementation libraries['spring-boot-starter-test'] 62 | } 63 | 64 | } -------------------------------------------------------------------------------- /common/build.gradle: -------------------------------------------------------------------------------- 1 | 2 | version '1.0-SNAPSHOT' 3 | 4 | 5 | dependencies { 6 | implementation libraries['swagger2'] 7 | implementation libraries['swagger-ui'] 8 | implementation libraries['spring-boot-starter-security'] 9 | implementation libraries['fastjson'] 10 | implementation libraries['jwt'] 11 | testCompile group: 'junit', name: 'junit', version: '4.12' 12 | } 13 | -------------------------------------------------------------------------------- /common/src/main/java/com/ityu/common/utils/JwtTokenUtil.java: -------------------------------------------------------------------------------- 1 | package com.ityu.common.utils; 2 | 3 | import io.jsonwebtoken.Claims; 4 | import io.jsonwebtoken.Jwts; 5 | import io.jsonwebtoken.SignatureAlgorithm; 6 | import lombok.extern.slf4j.Slf4j; 7 | import org.springframework.beans.factory.annotation.Value; 8 | import org.springframework.security.core.GrantedAuthority; 9 | import org.springframework.security.core.userdetails.User; 10 | import org.springframework.security.core.userdetails.UserDetails; 11 | import org.springframework.stereotype.Component; 12 | 13 | import java.util.*; 14 | import java.util.stream.Collectors; 15 | import java.util.stream.Stream; 16 | 17 | /** 18 | * JwtToken生成的工具类 19 | * JWT token的格式:header(头)、payload(负载)和signature(签名) 20 | * header的格式(算法、token的类型): 21 | * {"alg": "HS512","typ": "JWT"} 22 | * payload的格式(用户名、创建时间、生成时间): 23 | * {"sub":"wang","created":1489079981393,"exp":1489684781} 24 | * signature的生成算法: 25 | * HMACSHA512(base64UrlEncode(header) + "." +base64UrlEncode(payload),secret) 26 | *

27 | * 如何让token失效 28 | *

29 | * 就是把token存到redis中,如果用户的token修改了,就修改token 30 | * 多一次判断,如果token有效,再判断redis中是否匹配,匹配则有效,否则则无效 31 | */ 32 | 33 | @Slf4j 34 | @Component 35 | public class JwtTokenUtil { 36 | public static final String TOKEN_HEADER = "Authorization"; 37 | public static final String TOKEN_PREFIX = "Bearer "; 38 | 39 | //签发者 40 | private static final String ISS = "Gent.Ni"; 41 | private static final String CLAIM_KEY_USERNAME = "sub"; 42 | private static final String CLAIM_KEY_CREATED = "created"; 43 | 44 | private static final String ROLE_CLAIMS = "role"; 45 | 46 | private String secret = "111111"; 47 | 48 | private Long expiration = 604800L; 49 | 50 | /** 51 | * 根据负责生成JWT的token 52 | */ 53 | private String generateToken(Map claims) { 54 | return Jwts.builder() 55 | .setClaims(claims) 56 | .setExpiration(generateExpirationDate()) 57 | .signWith(SignatureAlgorithm.HS512, secret) 58 | .compact(); 59 | } 60 | 61 | /** 62 | * 从token中获取JWT中的负载 63 | */ 64 | private Claims getClaimsFromToken(String token) { 65 | Claims claims = null; 66 | try { 67 | claims = Jwts.parser() 68 | .setSigningKey(secret) 69 | .parseClaimsJws(token) 70 | .getBody(); 71 | } catch (Exception e) { 72 | log.info("JWT格式验证失败:{}", token); 73 | } 74 | return claims; 75 | } 76 | 77 | /** 78 | * 生成token的过期时间 79 | */ 80 | private Date generateExpirationDate() { 81 | return new Date(System.currentTimeMillis() + expiration * 1000); 82 | } 83 | 84 | /** 85 | * 从token中获取登录用户名 86 | */ 87 | public String getUserNameFromToken(String token) { 88 | String username; 89 | try { 90 | Claims claims = getClaimsFromToken(token); 91 | username = claims.getSubject(); 92 | } catch (Exception e) { 93 | username = null; 94 | } 95 | return username; 96 | } 97 | 98 | /** 99 | * 验证token是否还有效 100 | * 101 | * @param token 客户端传入的token 102 | * @param userDetails 从数据库中查询出来的用户信息 103 | */ 104 | public boolean validateToken(String token, UserDetails userDetails) { 105 | String username = getUserNameFromToken(token); 106 | return username.equals(userDetails.getUsername()) && !isTokenExpired(token); 107 | } 108 | 109 | /** 110 | * 判断token是否已经失效 111 | */ 112 | private boolean isTokenExpired(String token) { 113 | Date expiredDate = getExpiredDateFromToken(token); 114 | return expiredDate.before(new Date()); 115 | } 116 | 117 | /** 118 | * 从token中获取过期时间 119 | */ 120 | private Date getExpiredDateFromToken(String token) { 121 | Claims claims = getClaimsFromToken(token); 122 | return claims.getExpiration(); 123 | } 124 | 125 | /** 126 | * 根据用户信息生成token 127 | */ 128 | public String generateToken(UserDetails userDetails) { 129 | Map claims = new HashMap<>(); 130 | claims.put(CLAIM_KEY_USERNAME, userDetails.getUsername()); 131 | List stringStream = userDetails.getAuthorities().stream().map(t -> t.getAuthority()).collect(Collectors.toList()); 132 | claims.put(ROLE_CLAIMS, stringStream); 133 | claims.put(CLAIM_KEY_CREATED, new Date()); 134 | return generateToken(claims); 135 | } 136 | public String generateToken(String username) { 137 | Map claims = new HashMap<>(); 138 | claims.put(CLAIM_KEY_USERNAME, username); 139 | claims.put(CLAIM_KEY_CREATED, new Date()); 140 | return generateToken(claims); 141 | } 142 | /** 143 | * 判断token是否可以被刷新 144 | */ 145 | public boolean canRefresh(String token) { 146 | return !isTokenExpired(token); 147 | } 148 | 149 | /** 150 | * 刷新token 151 | */ 152 | public String refreshToken(String token) { 153 | Claims claims = getClaimsFromToken(token); 154 | claims.put(CLAIM_KEY_CREATED, new Date()); 155 | return generateToken(claims); 156 | } 157 | 158 | // 获取用户角色 159 | public List getUserRole(String token) { 160 | return (List) getClaimsFromToken(token).get(ROLE_CLAIMS); 161 | } 162 | 163 | 164 | public static void main(String[] args) { 165 | JwtTokenUtil jwtTokenUtil = new JwtTokenUtil(); 166 | //String s = jwtTokenUtil.generateToken("admin"); 167 | String userNameFromToken = jwtTokenUtil.getUserNameFromToken("eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJhZG1pbiIsImNyZWF0ZWQiOjE1NzU5NjgzODUwMjksImV4cCI6MTU3NjU3MzE4NX0.aAsObZruK3fhAB7GOzO-AgQGcR7CvCXdrUoo8LJVcJ2BLWRYQ4HuO6tP7cW4FXGJ8PZEvI82RxFrL5Ano8ALig"); 168 | System.out.println(userNameFromToken); 169 | 170 | } 171 | } 172 | -------------------------------------------------------------------------------- /common/src/main/java/com/ityu/common/utils/R.java: -------------------------------------------------------------------------------- 1 | package com.ityu.common.utils; 2 | 3 | 4 | import io.swagger.annotations.ApiModel; 5 | import io.swagger.annotations.ApiModelProperty; 6 | import lombok.Data; 7 | 8 | import java.io.Serializable; 9 | 10 | @Data 11 | @ApiModel(value="R",description="统一数据信息") 12 | public class R implements Serializable { 13 | @ApiModelProperty(value="状态吗 0成功 1失败",name="code",example="0") 14 | public int code; 15 | @ApiModelProperty(value="状态吗 true成功 false失败",name="status",example="0") 16 | public boolean status; 17 | @ApiModelProperty(value="错误信息",name="msg",example="密码不对") 18 | public String msg; 19 | @ApiModelProperty(value="对象信息",name="data") 20 | public T data; 21 | } 22 | -------------------------------------------------------------------------------- /common/src/main/java/com/ityu/common/utils/RUtil.java: -------------------------------------------------------------------------------- 1 | package com.ityu.common.utils; 2 | 3 | 4 | 5 | 6 | public class RUtil { 7 | public final static int SUCCESS = 0; 8 | public final static int FAILED = 1; 9 | public static R success(Object obj){ 10 | R resultVO = new R(); 11 | resultVO.setData(obj); 12 | resultVO.setCode(SUCCESS); 13 | resultVO.setMsg("成功"); 14 | resultVO.setStatus(true); 15 | return resultVO; 16 | } 17 | public static R error(Integer code,String msg){ 18 | R resultVO = new R(); 19 | resultVO.setCode(code); 20 | resultVO.setMsg(msg); 21 | resultVO.setStatus(false); 22 | return resultVO; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /dependencies.gradle: -------------------------------------------------------------------------------- 1 | ext.versions = [ 2 | springBoot : '2.1.9.RELEASE', 3 | springCloud : '2.0.1.RELEASE', 4 | eurekaServer : '1.0.0.RELEASE', 5 | adminServer : '2.2.0', 6 | commonsLang3 : '3.8.1' 7 | ] 8 | 9 | // 各种可能会用到的jar包 10 | ext.libraries = [ 11 | // Spring Boot 12 | "spring-boot-starter" : "org.springframework.boot:spring-boot-starter:${versions.springBoot}", 13 | "spring-boot-starter-security" : "org.springframework.boot:spring-boot-starter-security:${versions.springBoot}", 14 | "spring-boot-starter-web" : "org.springframework.boot:spring-boot-starter-web:${versions.springBoot}", 15 | "spring-boot-starter-actuator" : "org.springframework.boot:spring-boot-starter-actuator:${versions.springBoot}", 16 | "spring-boot-starter-aop" : "org.springframework.boot:spring-boot-starter-aop:${versions.springBoot}", 17 | "spring-boot-starter-log4j2" : "org.springframework.boot:spring-boot-starter-log4j2:${versions.springBoot}", 18 | "spring-boot-starter-test" : "org.springframework.boot:spring-boot-starter-test:${versions.springBoot}", 19 | "spring-boot-starter-amqp" : "org.springframework.boot:spring-boot-starter-amqp:${versions.springBoot}", 20 | "spring-boot-starter-tomcat" : "org.springframework.boot:spring-boot-starter-tomcat:${versions.springBoot}", 21 | "spring-boot-starter-jdbc" : "org.springframework.boot:spring-boot-starter-jdbc:${versions.springBoot}", 22 | "spring-boot-starter-data-rest" : "org.springframework.boot:spring-boot-starter-data-rest:${versions.springBoot}", 23 | "spring-cloud-config-server" : "org.springframework.cloud:spring-cloud-config-server:${versions.springCloud}", 24 | "spring-cloud-starter-config" : "org.springframework.cloud:spring-cloud-starter-config:${versions.springCloud}", 25 | "spring-cloud-starter-netflix-zuul" : "org.springframework.cloud:spring-cloud-starter-netflix-zuul:${versions.springCloud}", 26 | "spring-boot-admin-starter-server" : "de.codecentric:spring-boot-admin-starter-server:${versions.adminServer}", 27 | "spring-cloud-starter-netflix-eureka-client" : "org.springframework.cloud:spring-cloud-starter-netflix-eureka-client:${versions.springCloud}", 28 | "spring-cloud-starter-netflix-eureka-server" : "org.springframework.cloud:spring-cloud-starter-netflix-eureka-server:${versions.springCloud}", 29 | "spring-cloud-stream-binder-rabbit" : "org.springframework.cloud:spring-cloud-stream-binder-rabbit:${versions.springCloud}", 30 | "spring-cloud-bus" : "org.springframework.cloud:spring-cloud-bus:${versions.springCloud}", 31 | "spring-cloud-starter-openfeign" : "org.springframework.cloud:spring-cloud-starter-openfeign:${versions.springCloud}", 32 | // apache tools 33 | "commons-lang3" : "org.apache.commons:commons-lang3:${versions.commonsLang3}", 34 | "swagger2" : "io.springfox:springfox-swagger2:2.9.2", 35 | "swagger-ui" : "io.springfox:springfox-swagger-ui:2.9.2", 36 | "lombok" : "org.projectlombok:lombok", 37 | "fastjson" : "com.alibaba:fastjson:1.2.51", 38 | "jwt" : "io.jsonwebtoken:jjwt:0.9.1", 39 | 40 | 41 | 42 | ] -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * This file was generated by the Gradle 'init' task. 3 | * 4 | * The settings file is used to specify which projects to include in your build. 5 | * 6 | * Detailed information about configuring a multi-project build in Gradle can be found 7 | * in the user guide at https://docs.gradle.org/4.5.1/userguide/multi_project_builds.html 8 | */ 9 | 10 | rootProject.name = 'cloudstudy' 11 | include 'studyconfig' 12 | include 'studyeureka' 13 | include 'StudyAdminZuul' 14 | include 'studyadmin' 15 | include 'studyapi' 16 | include 'common' 17 | include 'studystreamrmq' 18 | include 'studystreamrmqcustomer' 19 | 20 | -------------------------------------------------------------------------------- /study.md: -------------------------------------------------------------------------------- 1 | #### gradle 配置 多模块 2 | 3 | ##### 1.创建gradle(parent)项目 4 | ##### 2.选上parent右键创建model(gradle) 5 | ##### 3. 把parent的build.gradle的内容放到allprojects {},plugins {id("xxxx")}要改成apply plugin:'xxx',然后添加公共依赖, 6 | ##### 4. 删除model的build.gradle和parent的重复内容 如果依赖其他 model,可以添加compile project(":model_name") 7 | ##### 5.在需要打bootjar包的model中添加plugins{id("org.springframework.boot") version "2.3.2.RELEASE"} 8 | ##### 6.修改打包名字和版本号 9 | 10 | ##### 7. parent build.gradle 11 | 12 | ```groovy 13 | apply from: 'dependencies.gradle' 14 | allprojects{ 15 | apply plugin: 'java' 16 | 17 | group 'com.ityu' 18 | version '1.0-SNAPSHOT' 19 | 20 | sourceCompatibility = 1.8 21 | 22 | repositories { 23 | mavenCentral() 24 | maven{ url 'https://maven.aliyun.com/repository/public/' } 25 | } 26 | 27 | dependencies { 28 | testCompile group: 'junit', name: 'junit', version: '4.12' 29 | implementation libraries['spring-boot-starter'] 30 | implementation libraries['spring-boot-starter-web'] 31 | implementation libraries['swagger2'] 32 | implementation libraries['swagger-ui'] 33 | } 34 | } 35 | 36 | ``` 37 | ##### 7. module-1 build.gradle 38 | 39 | ```groovy 40 | plugins { 41 | id "io.freefair.lombok" version "5.3.0" 42 | } 43 | dependencies { 44 | implementation libraries['web3j'] 45 | implementation libraries['okhttp'] 46 | } 47 | 48 | ``` 49 | 50 | ##### 8. module-2 build.gradle 51 | 52 | ```groovy 53 | plugins { 54 | id 'org.springframework.boot' version '2.4.5' 55 | id "io.freefair.lombok" version "5.3.0" 56 | } 57 | 58 | dependencies { 59 | compile project(":common") 60 | testImplementation libraries['spring-boot-starter-test'] 61 | 62 | } 63 | 64 | 65 | ``` 66 | 67 | 68 | ###### 9. other 69 | ```groovy 70 | rootProject.name = 'blockstudy' 71 | include 'common' 72 | include 'blockApi' 73 | 74 | ``` 75 | -------------------------------------------------------------------------------- /studyadmin/build.gradle: -------------------------------------------------------------------------------- 1 | 2 | version '1.0-SNAPSHOT' 3 | 4 | dependencies { 5 | implementation libraries['spring-cloud-starter-netflix-eureka-client'] 6 | implementation libraries['swagger2'] 7 | implementation libraries['swagger-ui'] 8 | implementation libraries['spring-cloud-starter-openfeign'] 9 | implementation libraries['spring-boot-starter-security'] 10 | implementation libraries['fastjson'] 11 | compile project(':common') 12 | testCompile group: 'junit', name: 'junit', version: '4.12' 13 | } 14 | -------------------------------------------------------------------------------- /studyadmin/src/main/java/com/ityu/studyadmin/StudyAdminApplication.java: -------------------------------------------------------------------------------- 1 | package com.ityu.studyadmin; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.cloud.client.discovery.EnableDiscoveryClient; 6 | import org.springframework.cloud.netflix.eureka.EnableEurekaClient; 7 | import org.springframework.cloud.openfeign.EnableFeignClients; 8 | 9 | @SpringBootApplication 10 | @EnableEurekaClient 11 | @EnableFeignClients 12 | @EnableDiscoveryClient 13 | public class StudyAdminApplication { 14 | public static void main(String[] args) { 15 | SpringApplication.run(StudyAdminApplication.class, args); 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /studyadmin/src/main/java/com/ityu/studyadmin/client/ApiClient.java: -------------------------------------------------------------------------------- 1 | package com.ityu.studyadmin.client; 2 | 3 | import com.ityu.common.utils.R; 4 | import org.springframework.cloud.openfeign.FeignClient; 5 | import org.springframework.stereotype.Component; 6 | import org.springframework.web.bind.annotation.PostMapping; 7 | import org.springframework.web.bind.annotation.RequestParam; 8 | 9 | @FeignClient(value = "study-api", fallback = ApiClientImpl.class) 10 | @Component 11 | public interface ApiClient { 12 | //, @RequestHeader(value = "token", required = false) String token 13 | @PostMapping(value = "/api/test") 14 | R test(@RequestParam(value = "data") String data); 15 | } 16 | -------------------------------------------------------------------------------- /studyadmin/src/main/java/com/ityu/studyadmin/client/ApiClientImpl.java: -------------------------------------------------------------------------------- 1 | package com.ityu.studyadmin.client; 2 | 3 | import com.ityu.common.utils.R; 4 | import com.ityu.common.utils.RUtil; 5 | import org.springframework.stereotype.Component; 6 | 7 | @Component 8 | public class ApiClientImpl implements ApiClient { 9 | 10 | @Override 11 | public R test(String data) { 12 | return RUtil.success("熔断器起作用了" + data); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /studyadmin/src/main/java/com/ityu/studyadmin/component/JwtPreAuthFilter.java: -------------------------------------------------------------------------------- 1 | package com.ityu.studyadmin.component; 2 | 3 | 4 | import com.ityu.common.utils.JwtTokenUtil; 5 | import org.springframework.security.authentication.AuthenticationManager; 6 | import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; 7 | import org.springframework.security.core.GrantedAuthority; 8 | import org.springframework.security.core.authority.SimpleGrantedAuthority; 9 | import org.springframework.security.core.context.SecurityContextHolder; 10 | import org.springframework.security.web.authentication.www.BasicAuthenticationFilter; 11 | 12 | import javax.servlet.FilterChain; 13 | import javax.servlet.ServletException; 14 | import javax.servlet.http.HttpServletRequest; 15 | import javax.servlet.http.HttpServletResponse; 16 | import java.io.IOException; 17 | import java.util.Collection; 18 | import java.util.HashSet; 19 | import java.util.List; 20 | 21 | 22 | 23 | /** 24 | * @author: 倪明辉 25 | * @date: 2019/3/6 16:20 26 | * @description: 对所有请求进行过滤 27 | * BasicAuthenticationFilter继承于OncePerRequestFilter==》确保在一次请求只通过一次filter,而不需要重复执行。 28 | */ 29 | public class JwtPreAuthFilter extends BasicAuthenticationFilter { 30 | 31 | private final JwtTokenUtil jwtTokenUtil; 32 | 33 | public JwtPreAuthFilter(AuthenticationManager authenticationManager, JwtTokenUtil jwtTokenUtil) { 34 | super(authenticationManager); 35 | this.jwtTokenUtil = jwtTokenUtil; 36 | } 37 | 38 | /** 39 | * description: 从request的header部分读取Token 40 | * 41 | * @param request 42 | * @param response 43 | * @param chain 44 | * @return void 45 | */ 46 | @Override 47 | protected void doFilterInternal(HttpServletRequest request, 48 | HttpServletResponse response, 49 | FilterChain chain) throws IOException, ServletException { 50 | String tokenHeader = request.getHeader(JwtTokenUtil.TOKEN_HEADER); 51 | System.out.println("tokenHeader:" + tokenHeader); 52 | // 如果请求头中没有Authorization信息则直接放行了 53 | if (tokenHeader == null || !tokenHeader.startsWith(JwtTokenUtil.TOKEN_PREFIX)) { 54 | chain.doFilter(request, response); 55 | return; 56 | } 57 | // 如果请求头中有token,则进行解析,并且设置认证信息 58 | SecurityContextHolder.getContext().setAuthentication(getAuthentication(tokenHeader)); 59 | super.doFilterInternal(request, response, chain); 60 | } 61 | 62 | /** 63 | * description: 读取Token信息,创建UsernamePasswordAuthenticationToken对象 64 | * 65 | * @param tokenHeader 66 | * @return org.springframework.security.authentication.UsernamePasswordAuthenticationToken 67 | */ 68 | private UsernamePasswordAuthenticationToken getAuthentication(String tokenHeader) { 69 | //解析Token时将“Bearer ”前缀去掉 70 | String token = tokenHeader.replace(JwtTokenUtil.TOKEN_PREFIX, ""); 71 | String username = jwtTokenUtil.getUserNameFromToken(token); 72 | List roles = jwtTokenUtil.getUserRole(token); 73 | Collection authorities = new HashSet<>(); 74 | if (roles != null) { 75 | for (String role : roles) { 76 | // authorities.add(new SimpleGrantedAuthority(ROLE_PRE+role)); 77 | //hasRole('admin') 78 | 79 | //hasAuthority('admin') 80 | //@PreAuthorize("hasAuthority('ROLE_XYZ')")与@PreAuthorize("hasRole('XYZ')")相同 81 | authorities.add(new SimpleGrantedAuthority(role)); 82 | } 83 | } 84 | if (username != null) { 85 | return new UsernamePasswordAuthenticationToken(username, null, authorities); 86 | } 87 | return null; 88 | } 89 | } -------------------------------------------------------------------------------- /studyadmin/src/main/java/com/ityu/studyadmin/config/BaseSwaggerConfig.java: -------------------------------------------------------------------------------- 1 | package com.ityu.studyadmin.config; 2 | 3 | import io.swagger.annotations.ApiOperation; 4 | import org.springframework.context.annotation.Bean; 5 | import springfox.documentation.builders.ParameterBuilder; 6 | import springfox.documentation.builders.PathSelectors; 7 | import springfox.documentation.builders.RequestHandlerSelectors; 8 | import springfox.documentation.service.*; 9 | import springfox.documentation.spi.DocumentationType; 10 | import springfox.documentation.spi.service.contexts.SecurityContext; 11 | import springfox.documentation.spring.web.plugins.Docket; 12 | 13 | import java.util.ArrayList; 14 | import java.util.List; 15 | import java.util.stream.Collectors; 16 | import java.util.stream.Stream; 17 | 18 | /** 19 | * 文档配置 20 | * 21 | * @author lihe 22 | */ 23 | public abstract class BaseSwaggerConfig { 24 | 25 | 26 | private final static String TOKEN = "token"; 27 | private final static String DEVICE_NO = "deviceNo"; 28 | private final static String USER_ID = "userId"; 29 | 30 | private final static String PASS_AS = "header"; 31 | 32 | 33 | 34 | /** 35 | * 子类用于自定义接口参数 36 | * 37 | * @return api 配置 38 | */ 39 | protected abstract ApiInfo apiInfo(); 40 | 41 | 42 | @Bean 43 | public Docket createRestApi() { 44 | ParameterBuilder ticketPar = new ParameterBuilder(); 45 | List pars = new ArrayList<>(); 46 | // Parameter parameter = ticketPar.name("Authorization").description("用户信息") 47 | // .modelRef(new ModelRef("string")).parameterType("header") 48 | // .required(false).build();//header中的ticket参数非必填,传空也可以 49 | // pars.add(parameter); //根据每个方法名也知道当前方法在设置什么参数 50 | 51 | List data = new ArrayList(); 52 | data.add(securityContext()); 53 | return new Docket(DocumentationType.SWAGGER_2) 54 | .securitySchemes(security()) 55 | .securityContexts(data) 56 | .apiInfo(apiInfo()) 57 | .globalOperationParameters(pars) 58 | .select() 59 | .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class)) 60 | .paths(PathSelectors.any()) 61 | .build(); 62 | } 63 | 64 | 65 | private Stream getKeyStream(){ 66 | return Stream.of(TOKEN, DEVICE_NO, USER_ID); 67 | } 68 | 69 | 70 | private List security() { 71 | return this.getKeyStream() 72 | .map(x -> new ApiKey(x, x, PASS_AS)) 73 | .collect(Collectors.toList()); 74 | } 75 | 76 | private SecurityContext securityContext() { 77 | return SecurityContext.builder() 78 | .securityReferences(defaultAuth()) 79 | .forPaths(PathSelectors.any()) 80 | .build(); 81 | } 82 | 83 | private List defaultAuth() { 84 | AuthorizationScope authorizationScope 85 | = new AuthorizationScope("global", "accessEverything"); 86 | AuthorizationScope[] authorizationScopes = new AuthorizationScope[1]; 87 | authorizationScopes[0] = authorizationScope; 88 | return this.getKeyStream() 89 | .map(x -> new SecurityReference(x, authorizationScopes)) 90 | .collect(Collectors.toList()); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /studyadmin/src/main/java/com/ityu/studyadmin/config/CustomDaoAuthenticationProvider.java: -------------------------------------------------------------------------------- 1 | package com.ityu.studyadmin.config; 2 | 3 | import com.ityu.studyadmin.service.AuthDetailsService; 4 | import org.springframework.beans.factory.annotation.Autowired; 5 | import org.springframework.context.annotation.Bean; 6 | import org.springframework.context.annotation.Configuration; 7 | import org.springframework.security.authentication.dao.DaoAuthenticationProvider; 8 | import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; 9 | 10 | @Configuration 11 | public class CustomDaoAuthenticationProvider { 12 | @Autowired 13 | private AuthDetailsService authDetailsService; 14 | 15 | @Autowired 16 | private BCryptPasswordEncoder passwordEncoder; 17 | 18 | @Bean 19 | public DaoAuthenticationProvider daoAuthenticationProvider() { 20 | DaoAuthenticationProvider provider = new DaoAuthenticationProvider(); 21 | provider.setUserDetailsService(authDetailsService); 22 | provider.setPasswordEncoder(passwordEncoder); 23 | provider.setHideUserNotFoundExceptions(false); 24 | return provider; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /studyadmin/src/main/java/com/ityu/studyadmin/config/CustomHandlerConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.ityu.studyadmin.config; 2 | 3 | import com.alibaba.fastjson.JSONObject; 4 | import com.ityu.common.utils.JwtTokenUtil; 5 | import com.ityu.common.utils.RUtil; 6 | import com.ityu.studyadmin.domain.AdminUser; 7 | import com.ityu.studyadmin.utils.SecurityUtils; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.context.annotation.Bean; 10 | import org.springframework.context.annotation.Configuration; 11 | import org.springframework.http.MediaType; 12 | import org.springframework.security.core.userdetails.User; 13 | import org.springframework.security.web.AuthenticationEntryPoint; 14 | import org.springframework.security.web.access.AccessDeniedHandler; 15 | import org.springframework.security.web.authentication.AuthenticationFailureHandler; 16 | import org.springframework.security.web.authentication.AuthenticationSuccessHandler; 17 | import org.springframework.security.web.authentication.logout.LogoutSuccessHandler; 18 | 19 | @Configuration 20 | public class CustomHandlerConfiguration { 21 | 22 | @Autowired 23 | JwtTokenUtil jwtTokenUtil; 24 | 25 | /** 26 | * 访问接入点处理 27 | * 28 | * @return 29 | */ 30 | @Bean 31 | public AuthenticationEntryPoint authenticationEntryPoint() { 32 | AuthenticationEntryPoint entryPoint = (request, response, e) -> { 33 | //NO_LOGIN 34 | response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE); 35 | response.getWriter().write(JSONObject.toJSONString(RUtil.error(-1, e.getMessage()))); 36 | }; 37 | return entryPoint; 38 | } 39 | 40 | /** 41 | * 接入过后问题处理 42 | * 43 | * @return 44 | */ 45 | @Bean 46 | public AccessDeniedHandler accessDeniedHandler() { 47 | AccessDeniedHandler accessDeniedHandler = (request, response, e) -> { 48 | //NO_PERMISSION 49 | response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE); 50 | response.getWriter().write(JSONObject.toJSONString(RUtil.error(-1, e.getMessage()))); 51 | }; 52 | return accessDeniedHandler; 53 | } 54 | 55 | /** 56 | * 登录成功后的处理 57 | * 58 | * @return 59 | */ 60 | @Bean 61 | public AuthenticationSuccessHandler authenticationSuccessHandler() { 62 | AuthenticationSuccessHandler authenticationSuccessHandler = (request, response, authentication) -> { 63 | //返回数据 64 | response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE); 65 | String s = JwtTokenUtil.TOKEN_PREFIX+jwtTokenUtil.generateToken(SecurityUtils.getCurrentUser()); 66 | response.getWriter().write(JSONObject.toJSONString(RUtil.success(AdminUser.getInstance().setToken(s)))); 67 | }; 68 | return authenticationSuccessHandler; 69 | } 70 | 71 | /** 72 | * 登录失败后的处理 73 | * 74 | * @return 75 | */ 76 | @Bean 77 | public AuthenticationFailureHandler authenticationFailureHandler() { 78 | AuthenticationFailureHandler authenticationFailureHandler = (request, response, e) -> { 79 | //ACCOUNT_ERROR 80 | response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE); 81 | response.getWriter().write(JSONObject.toJSONString(RUtil.error(-1, e.getMessage()))); 82 | }; 83 | return authenticationFailureHandler; 84 | } 85 | 86 | /** 87 | * 登出成功后的处理 88 | * 89 | * @return 90 | */ 91 | @Bean 92 | public LogoutSuccessHandler logoutSuccessHandler() { 93 | LogoutSuccessHandler logoutSuccessHandler = (request, response, authentication) -> { 94 | response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE); 95 | response.getWriter().write(JSONObject.toJSONString(RUtil.success("退出成功"))); 96 | }; 97 | return logoutSuccessHandler; 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /studyadmin/src/main/java/com/ityu/studyadmin/config/PasswordEncoderConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.ityu.studyadmin.config; 2 | 3 | import org.springframework.context.annotation.Bean; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; 6 | @Configuration 7 | public class PasswordEncoderConfiguration { 8 | /** 9 | * 密码加密 10 | */ 11 | @Bean 12 | public BCryptPasswordEncoder passwordEncoder(){ 13 | return new BCryptPasswordEncoder(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /studyadmin/src/main/java/com/ityu/studyadmin/config/Swagger2.java: -------------------------------------------------------------------------------- 1 | package com.ityu.studyadmin.config; 2 | 3 | import org.springframework.context.annotation.Configuration; 4 | import springfox.documentation.builders.ApiInfoBuilder; 5 | import springfox.documentation.service.ApiInfo; 6 | import springfox.documentation.swagger2.annotations.EnableSwagger2; 7 | 8 | 9 | @Configuration 10 | @EnableSwagger2 11 | public class Swagger2 extends BaseSwaggerConfig { 12 | 13 | /** 14 | * 创建该API的基本信息(这些基本信息会展现在文档页面中) 15 | * 访问地址:http://项目实际地址/swagger-ui.html 16 | * 17 | * @return 18 | */ 19 | @Override 20 | protected ApiInfo apiInfo() { 21 | return new ApiInfoBuilder() 22 | .title("Ma-vendor-api") 23 | .description("Ma-vendor-api") 24 | .termsOfServiceUrl("http://www.build.com") 25 | .version("1.0.0") 26 | .build(); 27 | } 28 | } 29 | 30 | -------------------------------------------------------------------------------- /studyadmin/src/main/java/com/ityu/studyadmin/config/WebSecurityConfig.java: -------------------------------------------------------------------------------- 1 | package com.ityu.studyadmin.config; 2 | 3 | import com.ityu.common.utils.JwtTokenUtil; 4 | import com.ityu.studyadmin.component.JwtPreAuthFilter; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.context.annotation.Bean; 7 | import org.springframework.context.annotation.Configuration; 8 | import org.springframework.http.HttpMethod; 9 | import org.springframework.security.authentication.dao.DaoAuthenticationProvider; 10 | import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; 11 | import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; 12 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 13 | import org.springframework.security.config.annotation.web.builders.WebSecurity; 14 | import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; 15 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; 16 | import org.springframework.security.config.http.SessionCreationPolicy; 17 | import org.springframework.security.web.AuthenticationEntryPoint; 18 | import org.springframework.security.web.access.AccessDeniedHandler; 19 | import org.springframework.security.web.authentication.AuthenticationFailureHandler; 20 | import org.springframework.security.web.authentication.AuthenticationSuccessHandler; 21 | import org.springframework.security.web.authentication.logout.LogoutSuccessHandler; 22 | 23 | import static com.ityu.studyadmin.utils.Contans.ROLE_ADMIN; 24 | 25 | @Configuration 26 | @EnableWebSecurity 27 | @EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true) 28 | public class WebSecurityConfig extends WebSecurityConfigurerAdapter { 29 | 30 | //认证处理类 31 | @Autowired 32 | private DaoAuthenticationProvider daoAuthenticationProvider; 33 | 34 | //认证成功 35 | @Autowired 36 | private AuthenticationSuccessHandler successHandler; 37 | 38 | //认证失败 39 | @Autowired 40 | private AuthenticationFailureHandler failureHandler; 41 | 42 | //登出成功 43 | @Autowired 44 | private LogoutSuccessHandler logoutSuccessHandler; 45 | 46 | @Autowired 47 | private AccessDeniedHandler deniedHandler; 48 | 49 | //认证EntryPoint 50 | @Autowired 51 | private AuthenticationEntryPoint entryPoint; 52 | 53 | @Override 54 | protected void configure(AuthenticationManagerBuilder builder) throws Exception { 55 | builder.authenticationProvider(daoAuthenticationProvider); 56 | } 57 | 58 | @Override 59 | public void configure(WebSecurity web) throws Exception { 60 | web.ignoring() 61 | .antMatchers(HttpMethod.OPTIONS, "/api/**") 62 | .antMatchers("/swagger-ui.html") 63 | .antMatchers("/webjars/**") 64 | .antMatchers("/swagger-resources/**") 65 | .antMatchers("/v2/**"); 66 | } 67 | 68 | @Override 69 | protected void configure(HttpSecurity http) throws Exception { 70 | //用户端 71 | // http.authorizeRequests().antMatchers("/**").permitAll() 72 | // .anyRequest().authenticated().and().csrf().disable(); 73 | //后台管理 74 | // http.csrf().disable() 75 | // .exceptionHandling() 76 | // .authenticationEntryPoint(entryPoint) 77 | // .accessDeniedHandler(deniedHandler) 78 | // .and().authorizeRequests() 79 | // .anyRequest().authenticated() 80 | // .and() 81 | // //不用再写登录接口了 82 | // .formLogin().loginPage("/api/user/login") 83 | // .usernameParameter("user") 84 | // .passwordParameter("pwd") 85 | // .successHandler(successHandler) 86 | // .failureHandler(failureHandler) 87 | // .and() 88 | // //不用再写退出登录接口了 89 | // .logout().logoutUrl("/api/user/logout") 90 | // .logoutSuccessHandler(logoutSuccessHandler) 91 | // .and() 92 | // .headers() 93 | // .frameOptions() 94 | // .disable() 95 | // .and().sessionManagement().maximumSessions(1800); 96 | 97 | 98 | http.cors() 99 | .and() 100 | // 关闭csrf 101 | .csrf().disable() 102 | // 关闭session 103 | .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) 104 | .and() 105 | .exceptionHandling() 106 | .accessDeniedHandler(deniedHandler) 107 | .authenticationEntryPoint(entryPoint) 108 | .and() 109 | .authorizeRequests() 110 | // 需要角色为ADMIN才能删除该资源 111 | .antMatchers(HttpMethod.DELETE, "/tasks/**").hasAnyRole(ROLE_ADMIN) 112 | // 测试用资源,需要验证了的用户才能访问 113 | .antMatchers("/tasks/**").authenticated() 114 | // 其他都放行了 115 | .anyRequest().permitAll() 116 | .and() 117 | .formLogin() 118 | .loginPage("/api/user/login") 119 | .usernameParameter("user") 120 | .passwordParameter("pwd") 121 | .successHandler(successHandler) 122 | .failureHandler(failureHandler) 123 | .permitAll() 124 | .and() 125 | .logout()//默认注销行为为logout 126 | .logoutUrl("/api/user/logout") 127 | .logoutSuccessHandler(logoutSuccessHandler) 128 | .and() 129 | // 添加到过滤链中 130 | // 先是UsernamePasswordAuthenticationFilter用于login校验 131 | // 再通过OncePerRequestFilter,对其他请求过滤 132 | .addFilter(new JwtPreAuthFilter(authenticationManager(), getJwtTokenUtil())); 133 | 134 | 135 | } 136 | 137 | @Bean 138 | public JwtTokenUtil getJwtTokenUtil(){ 139 | return new JwtTokenUtil(); 140 | } 141 | 142 | } 143 | -------------------------------------------------------------------------------- /studyadmin/src/main/java/com/ityu/studyadmin/controller/TestAdminController.java: -------------------------------------------------------------------------------- 1 | package com.ityu.studyadmin.controller; 2 | 3 | import com.ityu.common.utils.R; 4 | import com.ityu.common.utils.RUtil; 5 | import com.ityu.studyadmin.client.ApiClient; 6 | import com.ityu.studyadmin.utils.SecurityUtils; 7 | import feign.HeaderMap; 8 | import io.swagger.annotations.ApiImplicitParam; 9 | import io.swagger.annotations.ApiImplicitParams; 10 | import io.swagger.annotations.ApiOperation; 11 | import lombok.extern.slf4j.Slf4j; 12 | import org.springframework.beans.factory.annotation.Autowired; 13 | import org.springframework.security.access.prepost.PreAuthorize; 14 | import org.springframework.security.core.context.SecurityContextHolder; 15 | import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; 16 | import org.springframework.web.bind.annotation.PostMapping; 17 | import org.springframework.web.bind.annotation.RequestMapping; 18 | import org.springframework.web.bind.annotation.RequestParam; 19 | import org.springframework.web.bind.annotation.RestController; 20 | 21 | import javax.servlet.http.HttpServletRequest; 22 | 23 | @RestController 24 | @RequestMapping("/admin") 25 | @Slf4j 26 | public class TestAdminController { 27 | 28 | @Autowired 29 | ApiClient apiClient; 30 | 31 | @Autowired 32 | BCryptPasswordEncoder bCryptPasswordEncoder; 33 | 34 | @Autowired 35 | HttpServletRequest servletRequest; 36 | 37 | @ApiOperation(value = "测试調用接口") 38 | @ApiImplicitParams({ // 参数说明 39 | @ApiImplicitParam(name = "data", paramType = "query", value = "加密后的数据", dataType = "string"), 40 | }) 41 | @PostMapping(value = "/test") 42 | public R test(@RequestParam(value = "data") String data) { 43 | return RUtil.success("admin" + data); 44 | } 45 | 46 | 47 | @ApiOperation(value = "调用其他模块接口测试") 48 | @ApiImplicitParams({ // 参数说明 49 | @ApiImplicitParam(name = "data", paramType = "query", value = "加密后的数据", dataType = "string"), 50 | }) 51 | @PostMapping(value = "/feign") 52 | public R testApi(@RequestParam(value = "data") String data) { 53 | String header = servletRequest.getHeader("token"); 54 | System.out.println(header); 55 | return apiClient.test(data); 56 | } 57 | 58 | @ApiOperation(value = "测试BCryptPasswordEncoder加密") 59 | @ApiImplicitParams({ // 参数说明 60 | @ApiImplicitParam(name = "data", paramType = "query", value = "需要加密的数据", dataType = "string"), 61 | }) 62 | @PostMapping(value = "/encoder") 63 | public R encoder(@RequestParam(value = "data") String data) { 64 | String encode = bCryptPasswordEncoder.encode(data); 65 | return RUtil.success(encode); 66 | } 67 | 68 | @ApiOperation(value = "测试BCryptPasswordEncoder 密码是否正确") 69 | @ApiImplicitParams({ // 参数说明 70 | @ApiImplicitParam(name = "data", paramType = "query", value = "需要解密的数据", dataType = "string"), 71 | @ApiImplicitParam(name = "encodeData", paramType = "query", value = "需要解密的数据", dataType = "string"), 72 | }) 73 | @PostMapping(value = "/matches") 74 | public R matches(@RequestParam(value = "data") String data, @RequestParam("encodeData") String encodeData) { 75 | boolean matches = bCryptPasswordEncoder.matches(data, encodeData); 76 | return RUtil.success(matches); 77 | } 78 | 79 | @ApiOperation(value = "测试权限接口hasAuthority") 80 | @PostMapping(value = "/testPreAuthorize") 81 | @PreAuthorize("hasAuthority('admin')") 82 | public R testPreAuthorize() { 83 | return RUtil.success("admin" + SecurityContextHolder.getContext().getAuthentication().getPrincipal()); 84 | } 85 | 86 | 87 | @ApiOperation(value = "测试权限接口") 88 | @PostMapping(value = "/testPreAuthorizeRole") 89 | @PreAuthorize("hasRole('admin')") 90 | public R testPreAuthorizeRole() { 91 | return RUtil.success("admin" + SecurityContextHolder.getContext().getAuthentication().getPrincipal()); 92 | } 93 | 94 | } 95 | -------------------------------------------------------------------------------- /studyadmin/src/main/java/com/ityu/studyadmin/domain/AdminUser.java: -------------------------------------------------------------------------------- 1 | package com.ityu.studyadmin.domain; 2 | 3 | import lombok.Data; 4 | import lombok.experimental.Accessors; 5 | 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | 9 | import static com.ityu.studyadmin.utils.Contans.ROLE_ADMIN; 10 | 11 | @Data 12 | @Accessors(chain = true) 13 | public class AdminUser { 14 | private String username; 15 | private String password; 16 | private String token; 17 | private List roles; 18 | 19 | 20 | public static AdminUser getInstance(){ 21 | List roles = new ArrayList<>(); 22 | roles.add(ROLE_ADMIN); 23 | return new AdminUser().setUsername(ROLE_ADMIN).setPassword("$2a$10$vsN8gbDG/EzYUxrm40nZqu1ldtBwnV6bfs9cPomH7n85dqsdWUHEy").setRoles(roles); 24 | } 25 | 26 | 27 | } 28 | -------------------------------------------------------------------------------- /studyadmin/src/main/java/com/ityu/studyadmin/service/AuthDetailsService.java: -------------------------------------------------------------------------------- 1 | package com.ityu.studyadmin.service; 2 | 3 | import com.ityu.studyadmin.domain.AdminUser; 4 | import org.springframework.security.core.authority.SimpleGrantedAuthority; 5 | import org.springframework.security.core.userdetails.User; 6 | import org.springframework.security.core.userdetails.UserDetails; 7 | import org.springframework.security.core.userdetails.UserDetailsService; 8 | import org.springframework.security.core.userdetails.UsernameNotFoundException; 9 | import org.springframework.stereotype.Service; 10 | 11 | import java.util.ArrayList; 12 | import java.util.List; 13 | 14 | import static com.ityu.studyadmin.utils.Contans.ROLE_ADMIN; 15 | 16 | @Service 17 | //@Transactional 18 | public class AuthDetailsService implements UserDetailsService { 19 | @Override 20 | public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { 21 | List simpleGrantedAuthorities = new ArrayList<>(); 22 | simpleGrantedAuthorities.add(new SimpleGrantedAuthority(ROLE_ADMIN)); 23 | AdminUser user = AdminUser.getInstance(); 24 | return new User(user.getUsername(), user.getPassword(), simpleGrantedAuthorities); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /studyadmin/src/main/java/com/ityu/studyadmin/utils/Contans.java: -------------------------------------------------------------------------------- 1 | package com.ityu.studyadmin.utils; 2 | 3 | public class Contans { 4 | public static final String ROLE_ADMIN = "admin"; 5 | public static final String ROLE_PRE = "ROLE_"; 6 | } 7 | -------------------------------------------------------------------------------- /studyadmin/src/main/java/com/ityu/studyadmin/utils/SecurityUtils.java: -------------------------------------------------------------------------------- 1 | package com.ityu.studyadmin.utils; 2 | 3 | import org.springframework.security.core.Authentication; 4 | import org.springframework.security.core.context.SecurityContext; 5 | import org.springframework.security.core.context.SecurityContextHolder; 6 | import org.springframework.security.core.userdetails.UserDetails; 7 | 8 | public class SecurityUtils { 9 | public static UserDetails getCurrentUser() { 10 | SecurityContext securityContext = SecurityContextHolder.getContext(); 11 | Authentication authentication = securityContext.getAuthentication(); 12 | if (authentication != null && authentication.getPrincipal() instanceof UserDetails) { 13 | return ((UserDetails) authentication.getPrincipal()); 14 | } else { 15 | return null; 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /studyadmin/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 8087 3 | eureka: 4 | client: 5 | service-url: 6 | defaultZone: http://127.0.0.1:6868/eureka/ 7 | instance: 8 | prefer-ip-address: true 9 | spring: 10 | application: 11 | name: study-admin 12 | 13 | feign: 14 | hystrix: 15 | enabled: true 16 | -------------------------------------------------------------------------------- /studyapi/build.gradle: -------------------------------------------------------------------------------- 1 | 2 | version '1.0-SNAPSHOT' 3 | 4 | dependencies { 5 | implementation libraries['swagger2'] 6 | implementation libraries['swagger-ui'] 7 | implementation libraries['spring-cloud-starter-netflix-eureka-client'] 8 | implementation libraries['spring-cloud-starter-config'] 9 | implementation libraries['spring-cloud-stream-binder-rabbit'] 10 | implementation libraries['spring-boot-starter-actuator'] 11 | implementation libraries['spring-cloud-bus'] 12 | testCompile group: 'junit', name: 'junit', version: '4.12' 13 | compile project(':common') 14 | } 15 | -------------------------------------------------------------------------------- /studyapi/src/main/java/com/ityu/studyapi/StudyApiApplication.java: -------------------------------------------------------------------------------- 1 | package com.ityu.studyapi; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.cloud.netflix.eureka.EnableEurekaClient; 6 | import org.springframework.web.bind.annotation.CrossOrigin; 7 | 8 | @SpringBootApplication 9 | @EnableEurekaClient 10 | public class StudyApiApplication { 11 | public static void main(String[] args) { 12 | SpringApplication.run(StudyApiApplication.class, args); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /studyapi/src/main/java/com/ityu/studyapi/config/BaseSwaggerConfig.java: -------------------------------------------------------------------------------- 1 | package com.ityu.studyapi.config; 2 | 3 | import io.swagger.annotations.ApiOperation; 4 | 5 | import org.springframework.context.annotation.Bean; 6 | import springfox.documentation.builders.ParameterBuilder; 7 | import springfox.documentation.builders.PathSelectors; 8 | import springfox.documentation.builders.RequestHandlerSelectors; 9 | import springfox.documentation.service.*; 10 | import springfox.documentation.spi.DocumentationType; 11 | import springfox.documentation.spi.service.contexts.SecurityContext; 12 | import springfox.documentation.spring.web.plugins.Docket; 13 | 14 | import java.util.ArrayList; 15 | import java.util.List; 16 | import java.util.stream.Collectors; 17 | import java.util.stream.Stream; 18 | 19 | /** 20 | * 文档配置 21 | * 22 | * @author lihe 23 | */ 24 | public abstract class BaseSwaggerConfig { 25 | 26 | 27 | private final static String TOKEN = "token"; 28 | private final static String DEVICE_NO = "deviceNo"; 29 | private final static String USER_ID = "userId"; 30 | 31 | private final static String PASS_AS = "header"; 32 | 33 | 34 | 35 | /** 36 | * 子类用于自定义接口参数 37 | * 38 | * @return api 配置 39 | */ 40 | protected abstract ApiInfo apiInfo(); 41 | 42 | 43 | @Bean 44 | public Docket createRestApi() { 45 | ParameterBuilder ticketPar = new ParameterBuilder(); 46 | List pars = new ArrayList<>(); 47 | // Parameter parameter = ticketPar.name("Authorization").description("用户信息") 48 | // .modelRef(new ModelRef("string")).parameterType("header") 49 | // .required(false).build();//header中的ticket参数非必填,传空也可以 50 | // pars.add(parameter); //根据每个方法名也知道当前方法在设置什么参数 51 | 52 | List data = new ArrayList(); 53 | data.add(securityContext()); 54 | return new Docket(DocumentationType.SWAGGER_2) 55 | .securitySchemes(security()) 56 | .securityContexts(data) 57 | .apiInfo(apiInfo()) 58 | .globalOperationParameters(pars) 59 | .select() 60 | .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class)) 61 | .paths(PathSelectors.any()) 62 | .build(); 63 | } 64 | 65 | 66 | private Stream getKeyStream(){ 67 | return Stream.of(TOKEN, DEVICE_NO, USER_ID); 68 | } 69 | 70 | 71 | private List security() { 72 | return this.getKeyStream() 73 | .map(x -> new ApiKey(x, x, PASS_AS)) 74 | .collect(Collectors.toList()); 75 | } 76 | 77 | private SecurityContext securityContext() { 78 | return SecurityContext.builder() 79 | .securityReferences(defaultAuth()) 80 | .forPaths(PathSelectors.any()) 81 | .build(); 82 | } 83 | 84 | private List defaultAuth() { 85 | AuthorizationScope authorizationScope 86 | = new AuthorizationScope("global", "accessEverything"); 87 | AuthorizationScope[] authorizationScopes = new AuthorizationScope[1]; 88 | authorizationScopes[0] = authorizationScope; 89 | return this.getKeyStream() 90 | .map(x -> new SecurityReference(x, authorizationScopes)) 91 | .collect(Collectors.toList()); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /studyapi/src/main/java/com/ityu/studyapi/config/Swagger2.java: -------------------------------------------------------------------------------- 1 | package com.ityu.studyapi.config; 2 | 3 | import org.springframework.context.annotation.Configuration; 4 | import springfox.documentation.builders.ApiInfoBuilder; 5 | import springfox.documentation.service.ApiInfo; 6 | import springfox.documentation.swagger2.annotations.EnableSwagger2; 7 | 8 | 9 | @Configuration 10 | @EnableSwagger2 11 | public class Swagger2 extends BaseSwaggerConfig { 12 | 13 | /** 14 | * 创建该API的基本信息(这些基本信息会展现在文档页面中) 15 | * 访问地址:http://项目实际地址/swagger-ui.html 16 | * 17 | * @return 18 | */ 19 | @Override 20 | protected ApiInfo apiInfo() { 21 | return new ApiInfoBuilder() 22 | .title("Ma-vendor-api") 23 | .description("Ma-vendor-api") 24 | .termsOfServiceUrl("http://www.build.com") 25 | .version("1.0.0") 26 | .build(); 27 | } 28 | } 29 | 30 | -------------------------------------------------------------------------------- /studyapi/src/main/java/com/ityu/studyapi/controller/TestController.java: -------------------------------------------------------------------------------- 1 | package com.ityu.studyapi.controller; 2 | 3 | import com.ityu.common.utils.R; 4 | import com.ityu.common.utils.RUtil; 5 | import io.swagger.annotations.ApiImplicitParam; 6 | import io.swagger.annotations.ApiImplicitParams; 7 | import io.swagger.annotations.ApiOperation; 8 | import lombok.extern.slf4j.Slf4j; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.beans.factory.annotation.Value; 11 | import org.springframework.cloud.context.config.annotation.RefreshScope; 12 | import org.springframework.web.bind.annotation.PostMapping; 13 | import org.springframework.web.bind.annotation.RequestMapping; 14 | import org.springframework.web.bind.annotation.RequestParam; 15 | import org.springframework.web.bind.annotation.RestController; 16 | 17 | import javax.servlet.http.HttpServletRequest; 18 | 19 | @RestController 20 | @RequestMapping("/api") 21 | @Slf4j 22 | @RefreshScope 23 | public class TestController { 24 | 25 | 26 | @Value("${ityu}") 27 | private String ityu = ""; 28 | 29 | @Autowired 30 | HttpServletRequest servletRequest; 31 | 32 | @ApiOperation(value = "测试調用接口") 33 | @ApiImplicitParams({ // 参数说明 34 | @ApiImplicitParam(name = "data", paramType = "query", value = "加密后的数据", dataType = "string"), 35 | }) 36 | @PostMapping(value = "/test") 37 | public R test(@RequestParam(value = "data") String data) { 38 | String header = servletRequest.getHeader("token"); 39 | return RUtil.success(ityu + "api" + data + "=header=" + header); 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /studyapi/src/main/resources/bootstrap.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | cloud: 3 | config: 4 | name: api 5 | profile: dev 6 | lable: master 7 | uri: http://127.0.0.1:12000 -------------------------------------------------------------------------------- /studyconfig/build.gradle: -------------------------------------------------------------------------------- 1 | version '1.0-SNAPSHOT' 2 | 3 | 4 | dependencies { 5 | implementation libraries['spring-cloud-config-server'] 6 | implementation libraries['spring-cloud-stream-binder-rabbit'] 7 | implementation libraries['spring-cloud-bus'] 8 | testCompile group: 'junit', name: 'junit', version: '4.12' 9 | } 10 | -------------------------------------------------------------------------------- /studyconfig/src/main/java/com/ityu/config/ConfigApplication.java: -------------------------------------------------------------------------------- 1 | package com.ityu.config; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.cloud.config.server.EnableConfigServer; 6 | 7 | @SpringBootApplication 8 | @EnableConfigServer 9 | public class ConfigApplication { 10 | public static void main(String[] args) { 11 | SpringApplication.run(ConfigApplication.class, args); 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /studyconfig/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | rabbitmq: 3 | host: 47.94.169.13 4 | port: 5675 5 | virtual-host: / 6 | username: user 7 | password: 111111 8 | publisher-confirms: true #如果对异步消息需要回调必须设置为true 9 | application: 10 | name: study-config 11 | cloud: 12 | config: 13 | server: 14 | git: 15 | uri: https://gitee.com/lanlingkeji_yu.jl/srpingcloudstudyconfig.git 16 | server: 17 | port: 12000 18 | 19 | management: 20 | endpoints: 21 | web: 22 | exposure: 23 | include: bus-refresh 24 | -------------------------------------------------------------------------------- /studyeureka/build.gradle: -------------------------------------------------------------------------------- 1 | 2 | version '1.0-SNAPSHOT' 3 | 4 | dependencies { 5 | implementation libraries['spring-cloud-starter-netflix-eureka-server'] 6 | testCompile group: 'junit', name: 'junit', version: '4.12' 7 | } 8 | -------------------------------------------------------------------------------- /studyeureka/src/main/java/com/ityu/studyeureka/EurekaServiceApplication.java: -------------------------------------------------------------------------------- 1 | package com.ityu.studyeureka; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; 6 | 7 | @SpringBootApplication 8 | @EnableEurekaServer 9 | public class EurekaServiceApplication { 10 | public static void main(String[] args) { 11 | SpringApplication.run(EurekaServiceApplication.class, args); 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /studyeureka/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 6868 3 | eureka: 4 | client: 5 | service-url: 6 | defaultZone: http://127.0.0.1:${server.port}/eureka/ 7 | register-with-eureka: false 8 | fetch-registry: false 9 | spring: 10 | application: 11 | name: study-eureka 12 | -------------------------------------------------------------------------------- /studystreamrmq/build.gradle: -------------------------------------------------------------------------------- 1 | 2 | version '1.0-SNAPSHOT' 3 | 4 | 5 | dependencies { 6 | implementation libraries['spring-boot-starter-amqp'] 7 | implementation libraries['fastjson'] 8 | testCompile group: 'junit', name: 'junit', version: '4.12' 9 | } 10 | -------------------------------------------------------------------------------- /studystreamrmq/src/main/java/com/ityu/studystreamrmq/Constants.java: -------------------------------------------------------------------------------- 1 | package com.ityu.studystreamrmq; 2 | 3 | public class Constants { 4 | 5 | public static final String INPUT_CHANNEL = "inputChannel"; 6 | public static final String OUTPUT_CHANNEL = "outputChannel"; 7 | } 8 | -------------------------------------------------------------------------------- /studystreamrmq/src/main/java/com/ityu/studystreamrmq/StudyStreamRmqApplication.java: -------------------------------------------------------------------------------- 1 | package com.ityu.studystreamrmq; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | 7 | @SpringBootApplication 8 | public class StudyStreamRmqApplication { 9 | public static void main(String[] args) { 10 | SpringApplication.run(StudyStreamRmqApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /studystreamrmq/src/main/java/com/ityu/studystreamrmq/rabbitmq/Customer1.java: -------------------------------------------------------------------------------- 1 | package com.ityu.studystreamrmq.rabbitmq; 2 | 3 | import com.rabbitmq.client.Channel; 4 | import lombok.extern.slf4j.Slf4j; 5 | import org.springframework.amqp.rabbit.annotation.RabbitHandler; 6 | import org.springframework.amqp.rabbit.annotation.RabbitListener; 7 | import org.springframework.amqp.support.AmqpHeaders; 8 | import org.springframework.messaging.handler.annotation.Header; 9 | import org.springframework.stereotype.Component; 10 | 11 | import java.io.IOException; 12 | 13 | @Component 14 | @RabbitListener(queues = "ityu.order.cancel") 15 | @Slf4j 16 | public class Customer1 { 17 | 18 | @RabbitHandler 19 | public void handle(String message, Channel channel, @Header(AmqpHeaders.DELIVERY_TAG) long tag) throws IOException { 20 | System.out.println(System.currentTimeMillis()); 21 | System.out.println(message); 22 | // try { 23 | // /** 24 | // * 防止重复消费,可以根据传过来的唯一ID先判断缓存数据库中是否有数据 25 | // * 1、有数据则不消费,直接应答处理 26 | // * 2、缓存没有数据,则进行消费处理数据,处理完后手动应答 27 | // * 3、如果消息 处理异常则,可以存入数据库中,手动处理(可以增加短信和邮件提醒功能) 28 | // */ 29 | // channel.basicAck(message.getMessageProperties().getDeliveryTag(), false); 30 | // } catch (IOException e) { 31 | // e.printStackTrace(); 32 | // channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, true); 33 | // } 34 | 35 | 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /studystreamrmq/src/main/java/com/ityu/studystreamrmq/rabbitmq/QueueEnum.java: -------------------------------------------------------------------------------- 1 | package com.ityu.studystreamrmq.rabbitmq; 2 | 3 | import lombok.Getter; 4 | 5 | /** 6 | * 消息队列枚举配置 7 | * Created by macro on 2018/9/14. 8 | */ 9 | @Getter 10 | public enum QueueEnum { 11 | /** 12 | * 消息通知队列 13 | */ 14 | QUEUE_ORDER_CANCEL("ityu.order.direct", "ityu.order.cancel", "ityu.order.cancel"), 15 | /** 16 | * 消息通知ttl队列 17 | */ 18 | QUEUE_TTL_ORDER_CANCEL("ityu.order.direct.ttl", "ityu.order.cancel.ttl", "ityu.order.cancel.ttl"); 19 | 20 | /** 21 | * 交换名称 22 | */ 23 | private String exchange; 24 | /** 25 | * 队列名称 26 | */ 27 | private String name; 28 | /** 29 | * 路由键 30 | */ 31 | private String routeKey; 32 | 33 | QueueEnum(String exchange, String name, String routeKey) { 34 | this.exchange = exchange; 35 | this.name = name; 36 | this.routeKey = routeKey; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /studystreamrmq/src/main/java/com/ityu/studystreamrmq/rabbitmq/RabbitMqConfig.java: -------------------------------------------------------------------------------- 1 | package com.ityu.studystreamrmq.rabbitmq; 2 | 3 | 4 | import org.springframework.amqp.ImmediateAcknowledgeAmqpException; 5 | import org.springframework.amqp.core.*; 6 | import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory; 7 | import org.springframework.amqp.rabbit.connection.ConnectionFactory; 8 | import org.springframework.amqp.rabbit.listener.RabbitListenerContainerFactory; 9 | import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer; 10 | import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter; 11 | import org.springframework.context.annotation.Bean; 12 | import org.springframework.context.annotation.Configuration; 13 | 14 | /** 15 | * 消息队列配置 16 | * Created by macro on 2018/9/14. 17 | *

18 | * http://47.94.169.13:15675/#/ 19 | *

20 | * FanoutExchange: 将消息分发到所有的绑定队列,无routingkey的概念 21 | * HeadersExchange :通过添加属性key-value匹配 22 | * DirectExchange:按照routingkey分发到指定队列 23 | * TopicExchange:多关键字匹配 24 | */ 25 | @Configuration 26 | public class RabbitMqConfig { 27 | 28 | /** 29 | * 订单消息实际消费队列所绑定的交换机 30 | */ 31 | @Bean 32 | DirectExchange orderDirect() { 33 | return (DirectExchange) ExchangeBuilder 34 | .directExchange(QueueEnum.QUEUE_ORDER_CANCEL.getExchange()) 35 | .durable(true) 36 | .build(); 37 | } 38 | 39 | /** 40 | * 所绑定的交换机 41 | * 订单延迟队列队列 42 | */ 43 | @Bean 44 | DirectExchange orderTtlDirect() { 45 | return (DirectExchange) ExchangeBuilder 46 | .directExchange(QueueEnum.QUEUE_TTL_ORDER_CANCEL.getExchange()) 47 | .durable(true) 48 | .build(); 49 | } 50 | 51 | 52 | /** 53 | * 订单实际消费队列 54 | */ 55 | @Bean 56 | public Queue orderQueue() { 57 | return new Queue(QueueEnum.QUEUE_ORDER_CANCEL.getName()); 58 | } 59 | 60 | /** 61 | * 订单延迟队列(死信队列) 62 | */ 63 | @Bean 64 | public Queue orderTtlQueue() { 65 | return QueueBuilder 66 | .durable(QueueEnum.QUEUE_TTL_ORDER_CANCEL.getName()) 67 | .withArgument("x-dead-letter-exchange", QueueEnum.QUEUE_ORDER_CANCEL.getExchange())//到期后转发的交换机 68 | .withArgument("x-dead-letter-routing-key", QueueEnum.QUEUE_ORDER_CANCEL.getRouteKey())//到期后转发的路由键 69 | .build(); 70 | } 71 | 72 | /** 73 | * 将订单队列绑定到交换机 74 | */ 75 | @Bean 76 | Binding orderBinding(DirectExchange orderDirect, Queue orderQueue) { 77 | return BindingBuilder 78 | .bind(orderQueue) 79 | .to(orderDirect) 80 | .with(QueueEnum.QUEUE_ORDER_CANCEL.getRouteKey()); 81 | } 82 | 83 | /** 84 | * 将订单延迟队列绑定到交换机 85 | */ 86 | @Bean 87 | Binding orderTtlBinding(DirectExchange orderTtlDirect, Queue orderTtlQueue) { 88 | return BindingBuilder 89 | .bind(orderTtlQueue) 90 | .to(orderTtlDirect) 91 | .with(QueueEnum.QUEUE_TTL_ORDER_CANCEL.getRouteKey()); 92 | } 93 | 94 | 95 | //https://www.jianshu.com/p/2c5eebfd0e95 96 | // @Bean 97 | // public RabbitListenerContainerFactory rabbitListenerContainerFactory(ConnectionFactory connectionFactory) { 98 | // SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory(); 99 | // factory.setConnectionFactory(connectionFactory); 100 | // factory.setMessageConverter(new Jackson2JsonMessageConverter()); 101 | // factory.setAcknowledgeMode(AcknowledgeMode.MANUAL); //开启手动 ack 102 | // return factory; 103 | // } 104 | 105 | // @Bean 106 | // public SimpleMessageListenerContainer messageListenerContainer(ConnectionFactory connectionFactory) { 107 | // SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(); 108 | // container.setConnectionFactory(connectionFactory); 109 | // container.setQueueNames("consumer_queue"); // 监听的队列 110 | // container.setAcknowledgeMode(AcknowledgeMode.AUTO); // 根据情况确认消息 111 | // container.setMessageListener((MessageListener) (message) -> { 112 | // System.out.println("====接收到消息====="); 113 | // System.out.println(new String(message.getBody())); 114 | // //抛出NullPointerException异常则重新入队列 115 | // //throw new NullPointerException("消息消费失败"); 116 | // //当抛出的异常是AmqpRejectAndDontRequeueException异常的时候,则消息会被拒绝,且requeue=false 117 | // //throw new AmqpRejectAndDontRequeueException("消息消费失败"); 118 | // //当抛出ImmediateAcknowledgeAmqpException异常,则消费者会被确认 119 | // throw new ImmediateAcknowledgeAmqpException("消息消费失败"); 120 | // }); 121 | // return container; 122 | // } 123 | 124 | } 125 | -------------------------------------------------------------------------------- /studystreamrmq/src/main/java/com/ityu/studystreamrmq/rabbitmq/TestSendMessage.java: -------------------------------------------------------------------------------- 1 | package com.ityu.studystreamrmq.rabbitmq; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import org.springframework.amqp.core.Message; 5 | import org.springframework.amqp.rabbit.connection.CorrelationData; 6 | import org.springframework.amqp.rabbit.core.RabbitTemplate; 7 | import org.springframework.stereotype.Component; 8 | 9 | import java.util.UUID; 10 | 11 | @Component 12 | @Slf4j 13 | public class TestSendMessage implements RabbitTemplate.ConfirmCallback, RabbitTemplate.ReturnCallback { 14 | 15 | 16 | private final RabbitTemplate rabbitTemplate; 17 | 18 | public TestSendMessage(RabbitTemplate rabbitTemplate) { 19 | this.rabbitTemplate = rabbitTemplate; 20 | rabbitTemplate.setConfirmCallback(this::confirm); //rabbitTemplate如果为单例的话,那回调就是最后设置的内容 21 | rabbitTemplate.setReturnCallback(this::returnedMessage); 22 | rabbitTemplate.setMandatory(true); 23 | } 24 | 25 | public void sendMsg(String exchange, String routkey, Object content) { 26 | CorrelationData correlationId = new CorrelationData(UUID.randomUUID().toString()); 27 | rabbitTemplate.convertAndSend(exchange, routkey, content, correlationId); 28 | 29 | } 30 | 31 | @Override 32 | public void confirm(CorrelationData correlationData, boolean ack, String cause) { 33 | log.info(" 消息确认的id: " + correlationData); 34 | if (ack) { 35 | log.info("消息发送成功"); 36 | //发送成功 删除本地数据库存的消息 37 | } else { 38 | log.info("消息发送失败:id " + correlationData + "消息发送失败的原因" + cause); 39 | // 根据本地消息的状态为失败,可以用定时任务去处理数据 40 | 41 | } 42 | } 43 | 44 | @Override 45 | public void returnedMessage(Message message, int replyCode, String replyText, String exchange, String routingKey) { 46 | log.info("returnedMessage [消息从交换机到队列失败] message:" + message); 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /studystreamrmq/src/main/java/com/ityu/studystreamrmq/streamrq/MessageBean.java: -------------------------------------------------------------------------------- 1 | package com.ityu.studystreamrmq.streamrq; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | 6 | @Data 7 | @AllArgsConstructor 8 | public class MessageBean { 9 | private String title; 10 | } 11 | -------------------------------------------------------------------------------- /studystreamrmq/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | rabbitmq: 3 | host: 47.94.169.13 4 | port: 5675 5 | virtual-host: / 6 | username: user 7 | password: 111111 8 | publisher-confirms: true #如果对异步消息需要回调必须设置为true 9 | cache: 10 | channel: 11 | size: 100 12 | 13 | server: 14 | port: 8089 15 | 16 | -------------------------------------------------------------------------------- /studystreamrmq/src/test/java/com/ityu/studystreamrmq/MyTest.java: -------------------------------------------------------------------------------- 1 | package com.ityu.studystreamrmq; 2 | 3 | 4 | import com.ityu.studystreamrmq.rabbitmq.QueueEnum; 5 | import com.ityu.studystreamrmq.rabbitmq.TestSendMessage; 6 | import org.junit.Test; 7 | import org.junit.runner.RunWith; 8 | 9 | import org.springframework.amqp.AmqpException; 10 | import org.springframework.amqp.core.Message; 11 | import org.springframework.amqp.core.MessagePostProcessor; 12 | import org.springframework.amqp.rabbit.core.RabbitTemplate; 13 | import org.springframework.beans.factory.annotation.Autowired; 14 | import org.springframework.boot.test.context.SpringBootTest; 15 | import org.springframework.test.context.junit4.SpringRunner; 16 | 17 | @RunWith(SpringRunner.class) 18 | @SpringBootTest 19 | public class MyTest { 20 | 21 | @Autowired 22 | private TestSendMessage amqpTemplate; 23 | @Autowired 24 | private RabbitTemplate amqpTemplate2; 25 | 26 | @Test 27 | public void sendMsg() { 28 | amqpTemplate.sendMsg(QueueEnum.QUEUE_ORDER_CANCEL.getExchange(), QueueEnum.QUEUE_ORDER_CANCEL.getName(), "你好啊不错哦"); 29 | } 30 | 31 | @Test 32 | public void sendMsg2() { 33 | System.out.println(System.currentTimeMillis()); 34 | amqpTemplate2.convertAndSend(QueueEnum.QUEUE_TTL_ORDER_CANCEL.getExchange(), QueueEnum.QUEUE_TTL_ORDER_CANCEL.getRouteKey(), "我是延迟消息你能发现不50000", message -> { 35 | message.getMessageProperties().setExpiration("500000"); 36 | return message; 37 | }); 38 | } 39 | 40 | 41 | } 42 | --------------------------------------------------------------------------------