本片文章永远免费是为了让码友们少走弯路
首先先声明版本
SpringCloud版本
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Greenwich.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
SpringBoot版本
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.2.RELEASE</version>
</parent>
SpringAdmin版本
<properties>
<boot.admin.version>2.1.2</boot.admin.version>
</properties>
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-server</artifactId>
<version>${boot.admin.version}</version>
</dependency>
引导类上开启SpringAdmin服务注解
@EnableConfigurationProperties(DingTalkNotifierConfig.class)
@ComponentScans({@ComponentScan("com.fuyubl.areca.security.notifier"), @ComponentScan("com.fuyubl.areca.security.security")})
@SpringBootApplication
@EnableAdminServer
@EnableDiscoveryClient
public class MonitorApplication {
public static void main(String[] args) {
SpringApplication.run(MonitorApplication.class, args);
}
}
yml配置文件
server:
port: 8868
spring:
application:
name: areca-monitor
mail:
host: smtp.126.com
username: 你的邮箱
password: smtp秘钥
properties:
mail:
smtp:
auth: true
starttls: true
required: true
ssl:
enable: true
socketFactory:
port: 465
class: javax.net.ssl.SSLSocketFactory
port: 465
security:
user:
name: admin
password: 123456
boot:
#服务状态发生改变发送邮件
admin:
notify:
mail:
to: xxx@126.com
from: xxx@126.com
dingtalk:
enable: true
type: text
# 是否@所有人
atAll: false
#人员名单列表
staff: 1333333000,
cloud:
nacos:
discovery:
server-addr: localhost:8848
profiles:
active: ${PROFILES_ACTIVE:dev}
management:
endpoints:
web:
exposure:
include: '*'
endpoint:
health:
show-details: ALWAYS
logfile:
enabled: true
SpringAdmin安全认证
package com.fuyubl.areca.security.security;
import com.alibaba.nacos.common.util.HttpMethod;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
//httpSecurity.authorizeRequests().anyRequest().permitAll();
httpSecurity.csrf().disable();
httpSecurity.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.authorizeRequests()
.antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
.antMatchers(HttpMethod.POST).permitAll()
.antMatchers(HttpMethod.PUT).permitAll()
.antMatchers(HttpMethod.DELETE).permitAll()
.antMatchers(HttpMethod.GET).permitAll();
httpSecurity.headers().cacheControl();
}
}
自定义监听服务状态 继承 AbstractEventNotifier 或者AbstractStatusChangeNotifier都可以
直接贴代码
package com.fuyubl.areca.security.notifier;
import com.alibaba.fastjson.JSONObject;
import com.fuyubl.areca.security.bean.DingTalkFactroy;
import com.fuyubl.areca.security.enums.ServerStatusInfo;
import com.fuyubl.areca.security.utils.DateUtils;
import de.codecentric.boot.admin.server.domain.entities.Instance;
import de.codecentric.boot.admin.server.domain.entities.InstanceRepository;
import de.codecentric.boot.admin.server.domain.events.InstanceEvent;
import de.codecentric.boot.admin.server.notify.AbstractEventNotifier;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;
import java.util.Date;
import java.util.Map;
@Slf4j
@Component
public class DingDingNotifier extends AbstractEventNotifier {
@Autowired
private DingTalkFactroy factroy;
public DingDingNotifier(InstanceRepository repository) {
super(repository);
}
@Override
protected Mono<Void> doNotify(InstanceEvent event, Instance instance) {
String status = instance.getStatusInfo().getStatus();
if (status.equals(ServerStatusInfo.STATUS_UNKNOWN.getStatus())) {
log.info("服务状态未知~", instance.getStatusInfo().getStatus(), ServerStatusInfo.statusInfo(status));
}
String serviceName = instance.getRegistration().getName();
String serviceUrl = instance.getRegistration().getServiceUrl();
Map<String, Object> details = instance.getStatusInfo().getDetails();
StringBuilder str = new StringBuilder();
str.append("服务监控中心:>>>>>areca-monitor<<<<<" + "\n");
str.append("【服务名称】 : " + serviceName + "" + "\n");
str.append("【服务地址】" + serviceUrl + "\n");
str.append("【状态】" + status + ":" + ServerStatusInfo.statusInfo(status) + "\n");
str.append("【预警详情】:" + JSONObject.toJSONString(details) + "\n");
str.append("【预警时间】" + DateUtils.pattern(new Date()) + "\n\n\n");
return Mono.fromRunnable(() -> {
factroy.builder().sendMag(str.toString());
});
}
}
钉钉发送信息的类型有很多种 普通文本,图文,超链接形式 于是我做成了抽象类结合抽象工厂模式去发送消息
package com.fuyubl.areca.security.notifier;
import com.fuyubl.areca.security.constant.DingTalkConstants;
import com.sun.org.apache.xml.internal.security.utils.Base64;
import lombok.extern.slf4j.Slf4j;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.net.URLEncoder;
/**
* @author dlh
* @date 2022/8/17 15:10
*/
@Slf4j
public abstract class DingTalkNotfier {
///我这边测试就先写死token和secret
public static String access_token = "你的机器人token纯token";
public static String secret = "SE开头的秘钥";
/**
* Msg消息发送
*/
abstract void sendMag(String msg);
/**
* link
*
* @param msg
* @param url
*/
abstract void sendMag(String msg, String url,String title);
/**
* 获取URL
*
* @return
* @throws Exception
*/
public static String getUrl() {
Long timestamp = System.currentTimeMillis();
String sign = null;
try {
sign = getSign(timestamp, secret);
} catch (Exception e) {
log.error("发送钉钉消息时出现异常~", e, e.getMessage());
e.printStackTrace();
}
return String.format(DingTalkConstants.API_SEND_MESSAGE_SIGN, access_token, timestamp, sign);
}
/**
* 获取签名
*
* @param timestamp 时间戳
* @param secret 钉钉群机器人的签名秘钥
* @return
* @throws Exception
*/
private static String getSign(Long timestamp, String secret) throws Exception {
String stringToSign = timestamp + "\n" + secret;
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(new SecretKeySpec(secret.getBytes("UTF-8"), "HmacSHA256"));
byte[] signData = mac.doFinal(stringToSign.getBytes("UTF-8"));
return URLEncoder.encode(new String(Base64.encode(signData)), "UTF-8");
}
}
普通文本类型
package com.fuyubl.areca.security.notifier;
import com.dingtalk.api.DefaultDingTalkClient;
import com.dingtalk.api.DingTalkClient;
import com.dingtalk.api.request.OapiRobotSendRequest;
import com.dingtalk.api.response.OapiRobotSendResponse;
import com.fuyubl.areca.security.bean.DingTalkNotifierConfig;
import com.fuyubl.areca.security.constant.DingTalkMagType;
import com.taobao.api.ApiException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* @author dlh
* @date 2022/8/17 15:12
*/
@Slf4j
@Component
public class TextDingTalkNotifier extends DingTalkNotfier {
@Autowired
private DingTalkNotifierConfig config;
/**
* 钉钉发送文本消息
*/
@Override
void sendMag(String mag) {
if (!config.getEnable()) {
return;
}
//构建钉钉连接
OapiRobotSendResponse execute = null;
DingTalkClient client = new DefaultDingTalkClient(getUrl());
OapiRobotSendRequest request = new OapiRobotSendRequest();
request.setMsgtype(DingTalkMagType.textType);
//消息类型
OapiRobotSendRequest.Text text = new OapiRobotSendRequest.Text();
text.setContent(mag);
request.setText(text);
//发送人员名单
OapiRobotSendRequest.At at = new OapiRobotSendRequest.At();
at.setAtMobiles(config.getStaff());
at.setIsAtAll(config.getAtAll());
request.setAt(at);
try {
execute = client.execute(request);
} catch (ApiException e) {
log.error("钉钉发送消息异常", e, e.getMessage());
e.printStackTrace();
}
if (execute.isSuccess()) {
log.info("钉钉发送消息成功~ ,请注意查收!");
} else {
log.error("消息发送失败:原因" + execute.getErrmsg(), execute.getErrcode());
}
}
@Override
void sendMag(String msg, String url, String total) {
return;
}
}
Markdown消息类型
package com.fuyubl.areca.security.notifier;
import com.dingtalk.api.DefaultDingTalkClient;
import com.dingtalk.api.DingTalkClient;
import com.dingtalk.api.request.OapiRobotSendRequest;
import com.dingtalk.api.response.OapiRobotSendResponse;
import com.fuyubl.areca.security.bean.DingTalkNotifierConfig;
import com.fuyubl.areca.security.constant.DingTalkMagType;
import com.taobao.api.ApiException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* @author dlh
* @date 2022/8/17 15:51
*/
@Component
@Slf4j
public class MarkdownDingTalkNotfier extends DingTalkNotfier {
@Autowired
private DingTalkNotifierConfig config;
@Override
void sendMag(String msg) {
return;
}
@Override
void sendMag(String msg, String url, String title) {
if (!config.getEnable()) {
return;
}
OapiRobotSendResponse execute = null;
DingTalkClient client = new DefaultDingTalkClient(getUrl());
OapiRobotSendRequest request = new OapiRobotSendRequest();
request.setMsgtype(DingTalkMagType.markdownType);
OapiRobotSendRequest.Markdown markdown = new OapiRobotSendRequest.Markdown();
markdown.setTitle(title);
markdown.setText(msg);
request.setMarkdown(markdown);
try {
execute = client.execute(request);
} catch (ApiException e) {
log.error("钉钉发送消息异常", e, e.getMessage());
e.printStackTrace();
}
if (execute.isSuccess()) {
log.info("钉钉发送消息成功~ ,请注意查收!");
}else {
log.error("消息发送失败:原因" + execute.getErrmsg(), execute.getErrcode());
}
}
}
还有最后一个link类型
package com.fuyubl.areca.security.notifier;
import com.dingtalk.api.DefaultDingTalkClient;
import com.dingtalk.api.DingTalkClient;
import com.dingtalk.api.request.OapiRobotSendRequest;
import com.dingtalk.api.response.OapiRobotSendResponse;
import com.fuyubl.areca.security.bean.DingTalkNotifierConfig;
import com.fuyubl.areca.security.constant.DingTalkMagType;
import com.taobao.api.ApiException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* @author dlh
* @date 2022/8/17 15:44
*/
@Component
@Slf4j
public class LinkDingTalkNotifier extends DingTalkNotfier {
@Autowired
private DingTalkNotifierConfig config;
@Override
void sendMag(String msg) {
return;
}
@Override
void sendMag(String msg, String url, String title) {
if (!config.getEnable()) {
return;
}
OapiRobotSendResponse execute = null;
DingTalkClient client = new DefaultDingTalkClient(getUrl());
OapiRobotSendRequest request = new OapiRobotSendRequest();
request.setMsgtype(DingTalkMagType.linkType);
OapiRobotSendRequest.Link link = new OapiRobotSendRequest.Link();
link.setMessageUrl(url);
link.setPicUrl("");
link.setTitle(title);
link.setText(msg);
request.setLink(link);
try {
execute = client.execute(request);
} catch (ApiException e) {
log.error("钉钉发送消息异常", e, e.getMessage());
e.printStackTrace();
}
if (execute.isSuccess()) {
log.info("钉钉发送消息成功~ ,请注意查收!");
}else {
log.error("消息发送失败:原因" + execute.getErrmsg(), execute.getErrcode());
}
}
}
简单吧 其实没啥区别 需要的自己改改啥的
时间工具类简单的
public class DateUtils {
private static final String forMart = "yyyy-MM-dd HH:mm:ss";
public static String pattern(Date targt) {
SimpleDateFormat sim = new SimpleDateFormat(forMart);
return sim.format(targt);
}
}
一些常量
package com.fuyubl.areca.security.constant;
/**
* @author dlh
* @date 2022/8/17 15:15
*/
public interface DingTalkMagType {
/**
* 文本类型
*/
String textType = "text";
/**
* 图文类型
*/
String linkType = "link";
/**
* 超链接类型
*/
String markdownType = "markdown";
}
钉钉发送url
package com.fuyubl.areca.security.constant;
public class DingTalkConstants {
public static final String SERVER_URL = "https://oapi.dingtalk.com";
public static final String API_SEND_MESSAGE = SERVER_URL + "/robot/send?access_token=%s";
public static final String API_SEND_MESSAGE_SIGN = SERVER_URL + "/robot/send?access_token=%s×tamp=%s&sign=%s";
}
读取配置文件
package com.fuyubl.areca.security.bean;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Primary;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* @author dlh
* @date 2022/8/17 15:32
*/
@PropertySource("classpath:application.yml")
@Primary
@Component
@ConfigurationProperties(prefix = "spring.boot.admin.dingtalk", ignoreUnknownFields = true)
public class DingTalkNotifierConfig {
/**
* 是否启用钉钉
*/
private Boolean enable;
/**
* 消息类型
*/
private String type;
/**
* 是否推送给所有成员
*/
private Boolean atAll;
/**
* 指定人员
*/
private List staff;
public Boolean getEnable() {
return enable;
}
public void setEnable(Boolean enable) {
this.enable = enable;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public Boolean getAtAll() {
return atAll;
}
public void setAtAll(Boolean atAll) {
this.atAll = atAll;
}
public List getStaff() {
return staff;
}
public void setStaff(List staff) {
this.staff = staff;
}
}
然后结合工厂模式
package com.fuyubl.areca.security.bean;
import com.fuyubl.areca.security.constant.DingTalkMagType;
import com.fuyubl.areca.security.notifier.DingTalkNotfier;
import com.fuyubl.areca.security.notifier.LinkDingTalkNotifier;
import com.fuyubl.areca.security.notifier.MarkdownDingTalkNotfier;
import com.fuyubl.areca.security.notifier.TextDingTalkNotifier;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author dlh
* @date 2022/8/17 15:55
*/
@Configuration
public class DingTalkFactroy {
@Autowired
private DingTalkNotifierConfig conf;
@Bean
public DingTalkNotfier builder() {
switch (conf.getType()) {
case DingTalkMagType.linkType:
return new LinkDingTalkNotifier();
case DingTalkMagType.textType:
return new TextDingTalkNotifier();
case DingTalkMagType.markdownType:
return new MarkdownDingTalkNotfier();
}
return null;
}
}
到这里就完篇 最主要注意的是 版本关系