0%

admin监控

admin服务端

依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
<properties>
<java.version>1.8</java.version>
<spring-boot-admin.version>2.3.1</spring-boot-admin.version>
<spring-cloud.version>Hoxton.SR9</spring-cloud.version>
</properties>

<dependencies>
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-server</artifactId>
</dependency>
<!--admin-->
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-server-ui</artifactId>
</dependency>
<!--健康检查-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!-- 邮件-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<!-- 加入密码认证 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>

<dependencyManagement>
<dependencies>
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-dependencies</artifactId>
<version>${spring-boot-admin.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>

yml配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
server:
port: 9304
spring:
application:
name: test-admin
security:
user:
name: admin
password: admin
main:
allow-bean-definition-overriding: true
boot:
admin:
notify:
mail:
#收邮件
to: 619876453@qq.com
# 发件邮箱(要与邮件配置的username相同)
from: 619876453@qq.com
# 邮件设置
mail:
host: smtp.qq.com
username: 619876453
password: abc #授权码
properties:
mail:
smpt:
auth: true
starttls:
enable: true
required: true
eureka:
client:
service‐url:
defaultZone: http://eureka:eureka@localhost:9999/eureka
register-with-eureka: false # 不注册到eureka
fetch-registry: true
instance:
prefer‐ip‐address: true
#服务监控
management:
endpoints:
web:
exposure:
include: '*'
endpoint:
health:
show-details: always
enabled: true
show-components: always

启动类

1
2
@EnableAdminServer
@EnableDiscoveryClient

security安全认证

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
@EnableWebSecurity
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

private final String adminContextPath;

public WebSecurityConfig(AdminServerProperties adminServerProperties) {
this.adminContextPath = adminServerProperties.getContextPath();
}

@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
SavedRequestAwareAuthenticationSuccessHandler successHandler = new SavedRequestAwareAuthenticationSuccessHandler();
successHandler.setTargetUrlParameter( "redirectTo" );

http.authorizeRequests()
.antMatchers( adminContextPath + "/assets/**" ).permitAll()
.antMatchers( adminContextPath + "/login" ).permitAll()
.anyRequest().authenticated()
.and()
.formLogin().loginPage( adminContextPath + "/login" ).successHandler( successHandler ).and()
.logout().logoutUrl( adminContextPath + "/logout" ).and()
.httpBasic().and()
.csrf()
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
.ignoringAntMatchers(
adminContextPath + "/instances",
adminContextPath + "/actuator/**"
);
}
}

admin客户端(eureka服务端)

依赖

1
2
3
4
5
6
7
8
9
10
11
<!-- Admin 服务 -->
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-client</artifactId>
<version>2.2.1</version>
</dependency>
<!--健康检查-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

yml配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
spring:
application:
name: yrl-eureka
security:
user:
name: eureka
password: eureka
boot:
admin:
client:
url: http://admin:admin@localhost:9304
management:
endpoints:
web:
exposure:
include: '*'
endpoint:
health:
show-details: always

安全认证,放行健康检查

1
2
3
4
5
6
7
8
9
10
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable().httpBasic()
.and()
.authorizeRequests().antMatchers("/actuator/**").permitAll()
.anyRequest().authenticated();
}
}

监控

警告

邮件通知,查看上面配置

钉钉通知

启动类

1
2
3
4
@Bean
public DingDingNotifier dingDingNotifier(InstanceRepository repository) {
return new DingDingNotifier(repository);
}

通知类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class DingDingNotifier extends AbstractStatusChangeNotifier {
public DingDingNotifier(InstanceRepository repository) {
super(repository);
}


@Override
protected Mono<Void> doNotify(InstanceEvent event, Instance instance) {
ObjectMapper objectMapper = new ObjectMapper();

String serviceName = instance.getRegistration().getName();
String serviceUrl = instance.getRegistration().getServiceUrl();
String status = instance.getStatusInfo().getStatus();
Map<String, Object> details = instance.getStatusInfo().getDetails();
StringBuilder str = new StringBuilder();
str.append("系统警告 : 【" + serviceName + "】");
str.append("【服务地址】" + serviceUrl);
str.append("【状态】" + status);
try {
str.append("【详情】" + objectMapper.writeValueAsString(details));
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return Mono.fromRunnable(() -> {
DingDingMessageUtil.sendTextMessage(str.toString());
});
}
}

发送工具类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public class DingDingMessageUtil {
public static String access_token = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";

public static void sendTextMessage(String msg) {
try {
Message message = new Message();
message.setMsgtype("text");
message.setText(new MessageInfo(msg));
URL url = new URL("https://oapi.dingtalk.com/robot/send?access_token=" + access_token);
// 建立 http 连接
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setDoOutput(true);
conn.setDoInput(true);
conn.setUseCaches(false);
conn.setRequestMethod("POST");
conn.setRequestProperty("Charset", "UTF-8");
conn.setRequestProperty("Content-Type", "application/Json; charset=UTF-8");
conn.connect();
OutputStream out = conn.getOutputStream();
ObjectMapper objectMapper = new ObjectMapper();
String textMessage = objectMapper.writeValueAsString(message);
byte[] data = textMessage.getBytes();
out.write(data);
out.flush();
out.close();
InputStream in = conn.getInputStream();
byte[] data1 = new byte[in.available()];
in.read(data1);
System.out.println(new String(data1));
} catch (Exception e) {
e.printStackTrace();
}
}
}

消息类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
public class MessageInfo {
private String content;

public MessageInfo(String content) {
this.content = content;
}

public String getContent() {
return content;
}

public void setContent(String content) {
this.content = content;
}
}


public class Message {
private String msgtype;
private MessageInfo text;

public String getMsgtype() {
return msgtype;
}

public void setMsgtype(String msgtype) {
this.msgtype = msgtype;
}

public MessageInfo getText() {
return text;
}

public void setText(MessageInfo text) {
this.text = text;
}
}

钉钉群配置机器人