├── .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 |
--------------------------------------------------------------------------------