话不多说直接上代码
<!--spring默认使用yml中的配置,但有时候要用传统的xml或properties配置,就需要使用spring-boot-configuration-processor了-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- commons工具 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
package com.system.monitor.controller;
import com.system.common.utils.Ret;
import com.system.monitor.entity.JvmInfo;
import com.system.monitor.entity.ServerInfo;
import com.system.monitor.entity.TomcatInfo;
import com.system.monitor.helper.ActuatorHelper;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import static com.system.monitor.endpoint.LaterMetricsEndpoint.MetricResponse;
import java.util.List;
/**
* @author DELL
*/
@Controller("monitorView")
@RequiredArgsConstructor
public class ViewController {
private final ActuatorHelper actuatorHelper;
@GetMapping("jvm")
@ResponseBody
public Ret jvmInfo(Model model) {
List<MetricResponse> jvm = actuatorHelper.getMetricResponseByType("jvm");
JvmInfo jvmInfo = actuatorHelper.getJvmInfoFromMetricData(jvm);
model.addAttribute("jvm", jvmInfo);
return Ret.ok("msg", jvmInfo);
}
@GetMapping("tomcat")
@ResponseBody
public Ret tomcatInfo(Model model) {
List<MetricResponse> tomcat = actuatorHelper.getMetricResponseByType("tomcat");
TomcatInfo tomcatInfo = actuatorHelper.getTomcatInfoFromMetricData(tomcat);
model.addAttribute("tomcat", tomcatInfo);
return Ret.ok("msg", tomcatInfo);
}
@GetMapping("server")
@ResponseBody
public Ret serverInfo(Model model) {
List<MetricResponse> jdbcInfo = actuatorHelper.getMetricResponseByType("jdbc");
List<MetricResponse> systemInfo = actuatorHelper.getMetricResponseByType("system");
List<MetricResponse> processInfo = actuatorHelper.getMetricResponseByType("process");
ServerInfo serverInfo = actuatorHelper.getServerInfoFromMetricData(jdbcInfo, systemInfo, processInfo);
model.addAttribute("server", serverInfo);
return Ret.ok("msg", serverInfo);
}
}
相关类
ActuatorHelper.java
package com.system.monitor.helper;
import com.google.common.base.Predicates;
import com.system.common.annotation.Helper;
import com.system.common.utils.DateUtil;
import com.system.monitor.endpoint.LaterMetricsEndpoint;
import com.system.monitor.entity.JvmInfo;
import com.system.monitor.entity.ServerInfo;
import com.system.monitor.entity.TomcatInfo;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
/**
* @author DELL
*/
@Helper
@RequiredArgsConstructor
public class ActuatorHelper {
private static final BigDecimal DECIMAL = new BigDecimal("1048576");
private final LaterMetricsEndpoint metricsEndpoint;
public List<LaterMetricsEndpoint.MetricResponse> getMetricResponseByType(String type) {
LaterMetricsEndpoint.ListNamesResponse listNames = metricsEndpoint.listNames();
Set<String> names = listNames.getNames();
Iterable<String> jvm = names.stream()
.filter(Predicates.containsPattern(type)::apply)
.collect(Collectors.toList());
List<LaterMetricsEndpoint.MetricResponse> metricResponseList = new ArrayList<>();
jvm.forEach(s -> {
LaterMetricsEndpoint.MetricResponse metric = metricsEndpoint.metric(s, null);
metricResponseList.add(metric);
});
return metricResponseList;
}
public JvmInfo getJvmInfoFromMetricData(List<LaterMetricsEndpoint.MetricResponse> metrics) {
JvmInfo jvmInfo = new JvmInfo();
metrics.forEach(d -> {
String name = d.getName();
LaterMetricsEndpoint.Sample sample = d.getMeasurements().get(0);
Double value = sample.getValue();
switch (name) {
case "jvm.memory.max":
jvmInfo.setJvmMemoryMax(convertToMb(value));
break;
case "jvm.memory.committed":
jvmInfo.setJvmMemoryCommitted(convertToMb(value));
break;
case "jvm.memory.used":
jvmInfo.setJvmMemoryUsed(convertToMb(value));
break;
case "jvm.buffer.memory.used":
jvmInfo.setJvmBufferMemoryUsed(convertToMb(value));
break;
case "jvm.buffer.count":
jvmInfo.setJvmBufferCount(value);
break;
case "jvm.threads.daemon":
jvmInfo.setJvmThreadsdaemon(value);
break;
case "jvm.threads.live":
jvmInfo.setJvmThreadsLive(value);
break;
case "jvm.threads.peak":
jvmInfo.setJvmThreadsPeak(value);
break;
case "jvm.classes.loaded":
jvmInfo.setJvmClassesLoaded(value);
break;
case "jvm.classes.unloaded":
jvmInfo.setJvmClassesUnloaded(value);
break;
case "jvm.gc.memory.allocated":
jvmInfo.setJvmGcMemoryAllocated(convertToMb(value));
break;
case "jvm.gc.memory.promoted":
jvmInfo.setJvmGcMemoryPromoted(convertToMb(value));
break;
case "jvm.gc.max.data.size":
jvmInfo.setJvmGcMaxDataSize(convertToMb(value));
break;
case "jvm.gc.live.data.size":
jvmInfo.setJvmGcLiveDataSize(convertToMb(value));
break;
default:
}
});
return jvmInfo;
}
public TomcatInfo getTomcatInfoFromMetricData(List<LaterMetricsEndpoint.MetricResponse> metrics) {
TomcatInfo tomcatInfo = new TomcatInfo();
metrics.forEach(d -> {
String name = d.getName();
LaterMetricsEndpoint.Sample sample = d.getMeasurements().get(0);
Double value = sample.getValue();
switch (name) {
case "tomcat.sessions.created":
tomcatInfo.setTomcatSessionsCreated(value);
break;
case "tomcat.sessions.expired":
tomcatInfo.setTomcatSessionsExpired(value);
break;
case "tomcat.sessions.active.current":
tomcatInfo.setTomcatSessionsActiveCurrent(value);
break;
case "tomcat.sessions.active.max":
tomcatInfo.setTomcatSessionsActiveMax(value);
break;
case "tomcat.sessions.rejected":
tomcatInfo.setTomcatSessionsRejected(value);
break;
case "tomcat.global.error":
tomcatInfo.setTomcatGlobalError(value);
break;
case "tomcat.global.sent":
tomcatInfo.setTomcatGlobalSent(value);
break;
case "tomcat.global.request.max":
tomcatInfo.setTomcatGlobalRequestMax(value);
break;
case "tomcat.threads.current":
tomcatInfo.setTomcatThreadsCurrent(value);
break;
case "tomcat.threads.config.max":
tomcatInfo.setTomcatThreadsConfigMax(value);
break;
case "tomcat.threads.busy":
tomcatInfo.setTomcatThreadsBusy(value);
break;
default:
}
});
return tomcatInfo;
}
public ServerInfo getServerInfoFromMetricData(List<LaterMetricsEndpoint.MetricResponse> jdbcInfo,
List<LaterMetricsEndpoint.MetricResponse> systemInfo,
List<LaterMetricsEndpoint.MetricResponse> processInfo) {
ServerInfo serverInfo = new ServerInfo();
jdbcInfo.forEach(j -> {
String name = j.getName();
LaterMetricsEndpoint.Sample sample = j.getMeasurements().get(0);
Double value = sample.getValue();
switch (name) {
case "jdbc.connections.active":
serverInfo.setJdbcConnectionsActive(value);
break;
case "jdbc.connections.max":
serverInfo.setJdbcConnectionsMax(value);
break;
case "jdbc.connections.min":
serverInfo.setJdbcConnectionsMin(value);
break;
default:
}
});
systemInfo.forEach(s -> {
String name = s.getName();
LaterMetricsEndpoint.Sample sample = s.getMeasurements().get(0);
Double value = sample.getValue();
switch (name) {
case "system.cpu.count":
serverInfo.setSystemCpuCount(value);
break;
case "system.cpu.usage":
serverInfo.setSystemCpuUsage(value);
break;
default:
}
});
processInfo.forEach(p -> {
String name = p.getName();
LaterMetricsEndpoint.Sample sample = p.getMeasurements().get(0);
Double value = sample.getValue();
switch (name) {
case "process.cpu.usage":
serverInfo.setProcessCpuUsage(value);
break;
case "process.uptime":
serverInfo.setProcessUptime(value);
break;
case "process.start.time":
NumberFormat numberFormat = NumberFormat.getInstance();
numberFormat.setMaximumFractionDigits(20);
numberFormat.setGroupingUsed(false);
long timeMillis = Long.parseLong(StringUtils.replace(numberFormat.format(value), ".", ""));
String startTime = DateUtil.getDateFormat(new Date(timeMillis), DateUtil.FULL_TIME_SPLIT_PATTERN);
serverInfo.setProcessStartTime(startTime);
default:
}
});
return serverInfo;
}
private static Double convertToMb(Object value) {
return new BigDecimal(String.valueOf(value))
.divide(DECIMAL, 3, RoundingMode.HALF_UP).doubleValue();
}
}
LaterMetricsEndpoint.java
含有内部类
package com.system.monitor.endpoint;
import com.system.common.annotation.FebsEndPoint;
import io.micrometer.core.instrument.Meter;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Statistic;
import io.micrometer.core.instrument.Tag;
import io.micrometer.core.instrument.composite.CompositeMeterRegistry;
import org.springframework.boot.actuate.endpoint.InvalidEndpointRequestException;
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
import org.springframework.boot.actuate.endpoint.annotation.Selector;
import org.springframework.lang.Nullable;
import java.util.*;
import java.util.function.BiFunction;
import java.util.stream.Collectors;
/**
* @author DELL
*/
@FebsEndPoint
public class LaterMetricsEndpoint {
private final MeterRegistry registry;
public LaterMetricsEndpoint(MeterRegistry registry) {
this.registry = registry;
}
@ReadOperation
public ListNamesResponse listNames() {
Set<String> names = new LinkedHashSet<>();
this.collectNames(names, this.registry);
return new ListNamesResponse(names);
}
private void collectNames(Set<String> names, MeterRegistry registry) {
if (registry instanceof CompositeMeterRegistry) {
((CompositeMeterRegistry)registry).getRegistries().forEach((member) -> this.collectNames(names, member));
} else {
registry.getMeters().stream().map(this::getName).forEach(names::add);
}
}
private String getName(Meter meter) {
return meter.getId().getName();
}
@ReadOperation
public MetricResponse metric(@Selector String requiredMetricName, @Nullable List<String> tag) {
List<Tag> tags = this.parseTags(tag);
Collection<Meter> meters = this.findFirstMatchingMeters(this.registry, requiredMetricName, tags);
if (meters.isEmpty()) {
return null;
} else {
Map<Statistic, Double> samples = this.getSamples(meters);
Map<String, Set<String>> availableTags = this.getAvailableTags(meters);
tags.forEach((t) -> {
Set<String> var10000 = availableTags.remove(t.getKey());
});
Meter.Id meterId = meters.iterator().next().getId();
return new MetricResponse(requiredMetricName, meterId.getDescription(), meterId.getBaseUnit(), this.asList(samples, Sample::new), this.asList(availableTags, AvailableTag::new));
}
}
private List<Tag> parseTags(List<String> tags) {
return tags == null ? Collections.emptyList() : tags.stream().map(this::parseTag).collect(Collectors.toList());
}
private Tag parseTag(String tag) {
String[] parts = tag.split(":", 2);
if (parts.length != 2) {
throw new InvalidEndpointRequestException("Each tag parameter must be in the form 'key:value' but was: " + tag, "Each tag parameter must be in the form 'key:value'");
} else {
return Tag.of(parts[0], parts[1]);
}
}
private Collection<Meter> findFirstMatchingMeters(MeterRegistry registry, String name, Iterable<Tag> tags) {
return registry instanceof CompositeMeterRegistry ? this.findFirstMatchingMeters((CompositeMeterRegistry)registry, name, tags) : registry.find(name).tags(tags).meters();
}
private Collection<Meter> findFirstMatchingMeters(CompositeMeterRegistry composite, String name, Iterable<Tag> tags) {
return composite.getRegistries().stream().map((registry) -> this.findFirstMatchingMeters(registry, name, tags)).filter((matching) -> !matching.isEmpty()).findFirst().orElse(Collections.emptyList());
}
private Map<Statistic, Double> getSamples(Collection<Meter> meters) {
Map<Statistic, Double> samples = new LinkedHashMap<>();
meters.forEach((meter) -> this.mergeMeasurements(samples, meter));
return samples;
}
private void mergeMeasurements(Map<Statistic, Double> samples, Meter meter) {
meter.measure().forEach((measurement) -> {
Double var10000 = samples.merge(measurement.getStatistic(), measurement.getValue(), this.mergeFunction(measurement.getStatistic()));
});
}
private BiFunction<Double, Double, Double> mergeFunction(Statistic statistic) {
return Statistic.MAX.equals(statistic) ? Double::max : Double::sum;
}
private Map<String, Set<String>> getAvailableTags(Collection<Meter> meters) {
Map<String, Set<String>> availableTags = new HashMap<>(10);
meters.forEach((meter) -> this.mergeAvailableTags(availableTags, meter));
return availableTags;
}
private void mergeAvailableTags(Map<String, Set<String>> availableTags, Meter meter) {
meter.getId().getTags().forEach((tag) -> {
Set<String> value = Collections.singleton(tag.getValue());
availableTags.merge(tag.getKey(), value, this::merge);
});
}
private <T> Set<T> merge(Set<T> set1, Set<T> set2) {
Set<T> result = new HashSet<>(set1.size() + set2.size());
result.addAll(set1);
result.addAll(set2);
return result;
}
private <K, V, T> List<T> asList(Map<K, V> map, BiFunction<K, V, T> mapper) {
return map.entrySet().stream().map((entry) -> mapper.apply(entry.getKey(), entry.getValue())).collect(Collectors.toList());
}
public static final class Sample {
private final Statistic statistic;
private final Double value;
Sample(Statistic statistic, Double value) {
this.statistic = statistic;
this.value = value;
}
public Statistic getStatistic() {
return this.statistic;
}
public Double getValue() {
return this.value;
}
@Override
public String toString() {
return "MeasurementSample { statistic=" + this.statistic + ", value=" + this.value + '}';
}
}
public static final class AvailableTag {
private final String tag;
private final Set<String> values;
AvailableTag(String tag, Set<String> values) {
this.tag = tag;
this.values = values;
}
public String getTag() {
return this.tag;
}
public Set<String> getValues() {
return this.values;
}
}
public static final class MetricResponse {
private final String name;
private final String description;
private final String baseUnit;
private final List<Sample> measurements;
private final List<AvailableTag> availableTags;
MetricResponse(String name, String description, String baseUnit, List<Sample> measurements, List<AvailableTag> availableTags) {
this.name = name;
this.description = description;
this.baseUnit = baseUnit;
this.measurements = measurements;
this.availableTags = availableTags;
}
public String getName() {
return this.name;
}
public String getDescription() {
return this.description;
}
public String getBaseUnit() {
return this.baseUnit;
}
public List<Sample> getMeasurements() {
return this.measurements;
}
public List<AvailableTag> getAvailableTags() {
return this.availableTags;
}
}
public static final class ListNamesResponse {
private final Set<String> names;
ListNamesResponse(Set<String> names) {
this.names = names;
}
public Set<String> getNames() {
return this.names;
}
}
}
实体类
package com.system.monitor.entity;
import lombok.Data;
import java.io.Serializable;
/**
* @author DELL
*/
@Data
public class JvmInfo implements Serializable {
private static final long serialVersionUID = -5178501845351050670L;
/**
* JVM 最大内存
*/
private Double jvmMemoryMax;
/**
* JVM 可用内存
*/
private Double jvmMemoryCommitted;
/**
* JVM 已用内存
*/
private Double jvmMemoryUsed;
/**
* JVM 缓冲区已用内存
*/
private Double jvmBufferMemoryUsed;
/**
* 当前缓冲区数量
*/
private Double jvmBufferCount;
/**
* JVM 守护线程数量
*/
private Double jvmThreadsdaemon;
/**
* JVM 当前活跃线程数量
*/
private Double jvmThreadsLive;
/**
* JVM 峰值线程数量
*/
private Double jvmThreadsPeak;
/**
* JVM 已加载 Class 数量
*/
private Double jvmClassesLoaded;
/**
* JVM 未加载 Class 数量
*/
private Double jvmClassesUnloaded;
/**
* GC 时, 年轻代分配的内存空间
*/
private Double jvmGcMemoryAllocated;
/**
* GC 时, 老年代分配的内存空间
*/
private Double jvmGcMemoryPromoted;
/**
* GC 时, 老年代的最大内存空间
*/
private Double jvmGcMaxDataSize;
/**
* FullGC 时, 老年代的内存空间
*/
private Double jvmGcLiveDataSize;
}
package com.system.monitor.entity;
import lombok.Data;
import java.io.Serializable;
/**
* @author DELL
*/
@Data
public class ServerInfo implements Serializable {
private static final long serialVersionUID = 5915203206170057447L;
/**
* 应用已运行时长
*/
private Double processUptime;
/**
* 应用 CPU占用率
*/
private Double processCpuUsage;
/**
* 应用启动时间点
*/
private String processStartTime;
/**
* 系统 CPU核心数
*/
private Double systemCpuCount;
/**
* 系统 CPU 使用率
*/
private Double systemCpuUsage;
/**
* 当前活跃 JDBC连接数
*/
private Double jdbcConnectionsActive;
/**
* JDBC最小连接数
*/
private Double jdbcConnectionsMin;
/**
* JDBC最大连接数
*/
private Double jdbcConnectionsMax;
}
package com.system.monitor.entity;
import lombok.Data;
import java.io.Serializable;
/**
* @author DELL
*/
@Data
public class TomcatInfo implements Serializable {
private static final long serialVersionUID = 5817092425802069572L;
/**
* tomcat 已创建 session 数
*/
private Double tomcatSessionsCreated;
/**
* tomcat 已过期 session 数
*/
private Double tomcatSessionsExpired;
/**
* tomcat 当前活跃 session 数
*/
private Double tomcatSessionsActiveCurrent;
/**
* tomcat 活跃 session 数峰值
*/
private Double tomcatSessionsActiveMax;
/**
* 超过session 最大配置后,拒绝的 session 个数
*/
private Double tomcatSessionsRejected;
/**
* 发送的字节数
*/
private Double tomcatGlobalSent;
/**
* request 请求最长耗时
*/
private Double tomcatGlobalRequestMax;
/**
* tomcat 全局异常数量
*/
private Double tomcatGlobalError;
/**
* tomcat 当前线程数(包括守护线程)
*/
private Double tomcatThreadsCurrent;
/**
* tomcat 配置的线程最大数
*/
private Double tomcatThreadsConfigMax;
/**
* tomcat 当前繁忙线程数
*/
private Double tomcatThreadsBusy;
}
启动类,随意
package com.system.common.runner;
import com.system.common.entity.FebsConstant;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.stereotype.Component;
import java.net.InetAddress;
@Slf4j
@Component
@RequiredArgsConstructor
public class StartedUpRunner implements ApplicationRunner {
private final ConfigurableApplicationContext context;
@Value("${server.port:8080}")
private String port;
@Value("${server.servlet.context-path:}")
private String contextPath;
@Value("${spring.profiles.active}")
private String active;
@Override
public void run(ApplicationArguments args) throws Exception {
if (context.isActive()) {
InetAddress address = InetAddress.getLocalHost();
String url = String.format("http://%s:%s", address.getHostAddress(), port);
if (StringUtils.isNotBlank(contextPath)) {
url += contextPath;
}
log.info(" __ ___ _ ___ _ ____ _____ ____ ");
log.info("----------------------------| | |_ | | | |_ ");
log.info("--------------------------------------_ |_| |_|__ ");
log.info("------------------------------------------------------- ");
log.info("系统启动完毕,地址:{}", url);
if (StringUtils.equalsIgnoreCase(active, FebsConstant.DEVELOP)) {
String os = System.getProperty("os.name");
// 默认为 windows时才自动打开页面
if (StringUtils.containsIgnoreCase(os, "windows")) {
//使用默认浏览器打开系统登录页
Runtime.getRuntime().exec("cmd /c start " + url+"/jvm");
}
}
}
}
}
注解
package com.system.common.annotation;
import org.springframework.core.annotation.AliasFor;
import org.springframework.stereotype.Component;
import java.lang.annotation.*;
/**
*
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Helper {
@AliasFor(annotation = Component.class)
String value() default "";
}
package com.system.common.annotation;
import org.springframework.core.annotation.AliasFor;
import org.springframework.stereotype.Component;
import java.lang.annotation.*;
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface FebsEndPoint {
@AliasFor(annotation = Component.class)
String value() default "";
}
工具类
package com.system.common.utils;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.Locale;
/**
* 时间工具类
*
* @author
*/
public class DateUtil {
public static final String FULL_TIME_PATTERN = "yyyyMMddHHmmss";
public static final String FULL_TIME_SPLIT_PATTERN = "yyyy-MM-dd HH:mm:ss";
public static final String CST_TIME_PATTERN = "EEE MMM dd HH:mm:ss zzz yyyy";
public static String formatFullTime(LocalDateTime localDateTime) {
return formatFullTime(localDateTime, FULL_TIME_PATTERN);
}
public static String formatFullTime(LocalDateTime localDateTime, String pattern) {
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(pattern);
return localDateTime.format(dateTimeFormatter);
}
public static String getDateFormat(Date date, String dateFormatType) {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(dateFormatType, Locale.CHINA);
return simpleDateFormat.format(date);
}
public static String formatCstTime(String date, String format) throws ParseException {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(CST_TIME_PATTERN, Locale.US);
Date usDate = simpleDateFormat.parse(date);
return DateUtil.getDateFormat(usDate, format);
}
public static String formatInstant(Instant instant, String format) {
LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
return localDateTime.format(DateTimeFormatter.ofPattern(format));
}
}
package com.system.common.utils;
import java.security.MessageDigest;
/**
* Created with IntelliJ IDEA.
*
* @Auther: cqwuliu
* @Date: 2021/09/09/15:20 will_isme@163.com
* @Description:
*/
public class HashKit {
public static final long FNV_OFFSET_BASIS_64 = 0xcbf29ce484222325L;
public static final long FNV_PRIME_64 = 0x100000001b3L;
private static final java.security.SecureRandom random = new java.security.SecureRandom();
private static final char[] HEX_DIGITS = "0123456789abcdef".toCharArray();
private static final char[] CHAR_ARRAY = "_-0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray();
public static long fnv1a64(String key) {
long hash = FNV_OFFSET_BASIS_64;
for(int i=0, size=key.length(); i<size; i++) {
hash ^= key.charAt(i);
hash *= FNV_PRIME_64;
}
return hash;
}
public static String md5(String srcStr){
return hash("MD5", srcStr);
}
public static String sha1(String srcStr){
return hash("SHA-1", srcStr);
}
public static String sha256(String srcStr){
return hash("SHA-256", srcStr);
}
public static String sha384(String srcStr){
return hash("SHA-384", srcStr);
}
public static String sha512(String srcStr){
return hash("SHA-512", srcStr);
}
public static String hash(String algorithm, String srcStr) {
try {
MessageDigest md = MessageDigest.getInstance(algorithm);
byte[] bytes = md.digest(srcStr.getBytes("utf-8"));
return toHex(bytes);
}
catch (Exception e) {
throw new RuntimeException(e);
}
}
public static String toHex(byte[] bytes) {
StringBuilder ret = new StringBuilder(bytes.length * 2);
for (int i=0; i<bytes.length; i++) {
ret.append(HEX_DIGITS[(bytes[i] >> 4) & 0x0f]);
ret.append(HEX_DIGITS[bytes[i] & 0x0f]);
}
return ret.toString();
}
/**
* md5 128bit 16bytes
* sha1 160bit 20bytes
* sha256 256bit 32bytes
* sha384 384bit 48bytes
* sha512 512bit 64bytes
*/
public static String generateSalt(int saltLength) {
StringBuilder salt = new StringBuilder(saltLength);
for (int i=0; i<saltLength; i++) {
salt.append(CHAR_ARRAY[random.nextInt(CHAR_ARRAY.length)]);
}
return salt.toString();
}
public static String generateSaltForSha256() {
return generateSalt(32);
}
public static String generateSaltForSha512() {
return generateSalt(64);
}
public static boolean slowEquals(byte[] a, byte[] b) {
if (a == null || b == null) {
return false;
}
int diff = a.length ^ b.length;
for(int i=0; i<a.length && i<b.length; i++) {
diff |= a[i] ^ b[i];
}
return diff == 0;
}
}
package com.system.common.utils;
import java.util.HashMap;
import java.util.Map;
/**
* Created with IntelliJ IDEA.
*
* @Auther: cqwuliu
* @Date: 2021/09/09/15:17 will_isme@163.com
* @Description:
*/
public class Ret extends HashMap {
private static final String STATE = "state";
private static final String STATE_OK = "ok";
private static final String STATE_FAIL = "fail";
public Ret() {
}
public static Ret by(Object key, Object value) {
return new Ret().set(key, value);
}
public static Ret create(Object key, Object value) {
return new Ret().set(key, value);
}
public static Ret create() {
return new Ret();
}
public static Ret ok() {
return new Ret().setOk();
}
public static Ret ok(Object key, Object value) {
return ok().set(key, value);
}
public static Ret fail() {
return new Ret().setFail();
}
public static Ret fail(Object key, Object value) {
return fail().set(key, value);
}
public Ret setOk() {
super.put(STATE, STATE_OK);
return this;
}
public Ret setFail() {
super.put(STATE, STATE_FAIL);
return this;
}
public boolean isOk() {
Object state = get(STATE);
if (STATE_OK.equals(state)) {
return true;
}
if (STATE_FAIL.equals(state)) {
return false;
}
throw new IllegalStateException("调用 isOk() 之前,必须先调用 ok()、fail() 或者 setOk()、setFail() 方法");
}
public boolean isFail() {
Object state = get(STATE);
if (STATE_FAIL.equals(state)) {
return true;
}
if (STATE_OK.equals(state)) {
return false;
}
throw new IllegalStateException("调用 isFail() 之前,必须先调用 ok()、fail() 或者 setOk()、setFail() 方法");
}
public Ret set(Object key, Object value) {
super.put(key, value);
return this;
}
public Ret setIfNotBlank(Object key, String value) {
if (StrKit.notBlank(value)) {
set(key, value);
}
return this;
}
public Ret setIfNotNull(Object key, Object value) {
if (value != null) {
set(key, value);
}
return this;
}
public Ret set(Map map) {
super.putAll(map);
return this;
}
public Ret set(Ret ret) {
super.putAll(ret);
return this;
}
public Ret delete(Object key) {
super.remove(key);
return this;
}
public <T> T getAs(Object key) {
return (T)get(key);
}
public String getStr(Object key) {
Object s = get(key);
return s != null ? s.toString() : null;
}
public Integer getInt(Object key) {
Number n = (Number)get(key);
return n != null ? n.intValue() : null;
}
public Long getLong(Object key) {
Number n = (Number)get(key);
return n != null ? n.longValue() : null;
}
public Number getNumber(Object key) {
return (Number)get(key);
}
public Boolean getBoolean(Object key) {
return (Boolean)get(key);
}
/**
* key 存在,并且 value 不为 null
*/
public boolean notNull(Object key) {
return get(key) != null;
}
/**
* key 不存在,或者 key 存在但 value 为null
*/
public boolean isNull(Object key) {
return get(key) == null;
}
/**
* key 存在,并且 value 为 true,则返回 true
*/
public boolean isTrue(Object key) {
Object value = get(key);
return (value instanceof Boolean && ((Boolean)value == true));
}
/**
* key 存在,并且 value 为 false,则返回 true
*/
public boolean isFalse(Object key) {
Object value = get(key);
return (value instanceof Boolean && ((Boolean)value == false));
}
public boolean equals(Object ret) {
return ret instanceof Ret && super.equals(ret);
}
}
package com.system.common.utils;
/**
* Created with IntelliJ IDEA.
*
* @Auther: cqwuliu
* @Date: 2021/09/09/15:19 will_isme@163.com
* @Description:
*/
public class StrKit {
/**
* 首字母变小写
*/
public static String firstCharToLowerCase(String str) {
char firstChar = str.charAt(0);
if (firstChar >= 'A' && firstChar <= 'Z') {
char[] arr = str.toCharArray();
arr[0] += ('a' - 'A');
return new String(arr);
}
return str;
}
/**
* 首字母变大写
*/
public static String firstCharToUpperCase(String str) {
char firstChar = str.charAt(0);
if (firstChar >= 'a' && firstChar <= 'z') {
char[] arr = str.toCharArray();
arr[0] -= ('a' - 'A');
return new String(arr);
}
return str;
}
/**
* 字符串为 null 或者内部字符全部为 ' ' '\t' '\n' '\r' 这四类字符时返回 true
*/
public static boolean isBlank(String str) {
if (str == null) {
return true;
}
int len = str.length();
if (len == 0) {
return true;
}
for (int i = 0; i < len; i++) {
switch (str.charAt(i)) {
case ' ':
case '\t':
case '\n':
case '\r':
// case '\b':
// case '\f':
break;
default:
return false;
}
}
return true;
}
public static boolean notBlank(String str) {
return !isBlank(str);
}
public static boolean notBlank(String... strings) {
if (strings == null || strings.length == 0) {
return false;
}
for (String str : strings) {
if (isBlank(str)) {
return false;
}
}
return true;
}
public static boolean notNull(Object... paras) {
if (paras == null) {
return false;
}
for (Object obj : paras) {
if (obj == null) {
return false;
}
}
return true;
}
public static String toCamelCase(String stringWithUnderline) {
if (stringWithUnderline.indexOf('_') == -1) {
return stringWithUnderline;
}
stringWithUnderline = stringWithUnderline.toLowerCase();
char[] fromArray = stringWithUnderline.toCharArray();
char[] toArray = new char[fromArray.length];
int j = 0;
for (int i=0; i<fromArray.length; i++) {
if (fromArray[i] == '_') {
// 当前字符为下划线时,将指针后移一位,将紧随下划线后面一个字符转成大写并存放
i++;
if (i < fromArray.length) {
toArray[j++] = Character.toUpperCase(fromArray[i]);
}
}
else {
toArray[j++] = fromArray[i];
}
}
return new String(toArray, 0, j);
}
public static String join(String[] stringArray) {
StringBuilder sb = new StringBuilder();
for (String s : stringArray) {
sb.append(s);
}
return sb.toString();
}
public static String join(String[] stringArray, String separator) {
StringBuilder sb = new StringBuilder();
for (int i=0; i<stringArray.length; i++) {
if (i > 0) {
sb.append(separator);
}
sb.append(stringArray[i]);
}
return sb.toString();
}
public static boolean slowEquals(String a, String b) {
byte[] aBytes = (a != null ? a.getBytes() : null);
byte[] bBytes = (b != null ? b.getBytes() : null);
return HashKit.slowEquals(aBytes, bBytes);
}
public static boolean equals(String a, String b) {
return a == null ? b == null : a.equals(b);
}
public static String getRandomUUID() {
return java.util.UUID.randomUUID().toString().replace("-", "");
}
}