完成客户端在启动时进行一次主机基本信息上报

This commit is contained in:
柏码の讲师 2023-11-30 18:37:02 +08:00
parent c23e06acbc
commit c00d2ecee6
13 changed files with 211 additions and 6 deletions

View File

@ -36,6 +36,11 @@
<artifactId>spring-boot-starter-test</artifactId> <artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>com.github.oshi</groupId>
<artifactId>oshi-core</artifactId>
<version>6.4.0</version>
</dependency>
</dependencies> </dependencies>
<build> <build>

View File

@ -2,9 +2,13 @@ package com.example.config;
import com.alibaba.fastjson2.JSONObject; import com.alibaba.fastjson2.JSONObject;
import com.example.entity.ConnectionConfig; import com.example.entity.ConnectionConfig;
import com.example.entity.data.BaseDetail;
import com.example.utils.MonitorUtils;
import com.example.utils.NetUtils; import com.example.utils.NetUtils;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
@ -17,11 +21,14 @@ import java.util.Scanner;
@Slf4j @Slf4j
@Configuration @Configuration
public class ServerConfiguration { public class ServerConfiguration implements ApplicationRunner {
@Resource @Resource
NetUtils net; NetUtils net;
@Resource
MonitorUtils monitor;
@Bean @Bean
ConnectionConfig connectionConfig() { ConnectionConfig connectionConfig() {
log.info("正在加载服务端连接配置..."); log.info("正在加载服务端连接配置...");
@ -31,6 +38,13 @@ public class ServerConfiguration {
return config; return config;
} }
@Override
public void run(ApplicationArguments args) throws Exception {
log.info("正在向服务端更新基本系统信息...");
BaseDetail detail = monitor.monitorBaseData();
net.updateBaseDetails(detail);
}
private ConnectionConfig registerToServer() { private ConnectionConfig registerToServer() {
Scanner scanner = new Scanner(System.in); Scanner scanner = new Scanner(System.in);
String token, address; String token, address;

View File

@ -0,0 +1,17 @@
package com.example.entity.data;
import lombok.Data;
import lombok.experimental.Accessors;
@Data
@Accessors(chain = true)
public class BaseDetail {
String osArch;
String osName;
String osVersion;
int osBit;
int cpuCore;
double memory;
double disk;
String ip;
}

View File

@ -0,0 +1,54 @@
package com.example.utils;
import com.example.entity.data.BaseDetail;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import oshi.SystemInfo;
import oshi.hardware.HardwareAbstractionLayer;
import oshi.hardware.NetworkIF;
import oshi.hardware.HWDiskStore;
import oshi.software.os.OperatingSystem;
import java.io.IOException;
import java.net.NetworkInterface;
import java.util.Properties;
@Slf4j
@Component
public class MonitorUtils {
private final SystemInfo info = new SystemInfo();
private final Properties properties = System.getProperties();
public BaseDetail monitorBaseData() {
OperatingSystem os = info.getOperatingSystem();
HardwareAbstractionLayer hardware = info.getHardware();
double memory = hardware.getMemory().getTotal() / 1024.0 / 1024 / 1024;
double diskSize = hardware.getDiskStores().stream().mapToLong(HWDiskStore::getSize).sum() / 1024.0 / 1024 / 1024;
try {
String ip = null;
for (NetworkIF network : hardware.getNetworkIFs()) {
String[] iPv4addr = network.getIPv4addr();
NetworkInterface ni = network.queryNetworkInterface();
if(!ni.isLoopback() && !ni.isPointToPoint() && ni.isUp() && !ni.isVirtual()
&& (ni.getName().startsWith("eth") || ni.getName().startsWith("en"))
&& iPv4addr.length > 0) {
ip = network.getIPv4addr()[0];
break;
}
}
return new BaseDetail()
.setOsBit(os.getBitness())
.setOsArch(properties.getProperty("os.arch"))
.setOsVersion(os.getVersionInfo().getVersion())
.setOsName(os.getFamily())
.setCpuCore(hardware.getProcessor().getLogicalProcessorCount())
.setMemory(memory)
.setDisk(diskSize)
.setIp(ip);
} catch (IOException e) {
log.error("读取系统基本信息时出错", e);
return null;
}
}
}

View File

@ -3,6 +3,7 @@ package com.example.utils;
import com.alibaba.fastjson2.JSONObject; import com.alibaba.fastjson2.JSONObject;
import com.example.entity.ConnectionConfig; import com.example.entity.ConnectionConfig;
import com.example.entity.Response; import com.example.entity.Response;
import com.example.entity.data.BaseDetail;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Lazy;
@ -34,6 +35,31 @@ public class NetUtils {
return response.success(); return response.success();
} }
public void updateBaseDetails(BaseDetail detail){
Response response = this.doPost("/detail", detail);
if(response.success()) {
log.info("系统基本信息更新已完成");
} else {
log.error("系统基本信息更新失败: {}", response.getMessage());
}
}
private Response doPost(String url, Object data) {
try {
String rawData = JSONObject.from(data).toJSONString();
HttpRequest request = HttpRequest.newBuilder().POST(HttpRequest.BodyPublishers.ofString(rawData))
.uri(new URI(config.getAddress() + "/monitor" + url))
.header("Content-Type", "application/json")
.header("Authorization", config.getToken())
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
return JSONObject.parseObject(response.body()).to(Response.class);
} catch (Exception e) {
log.error("在发起服务端请求时出现错误", e);
return Response.errorResponse(e);
}
}
private Response doGet(String url) { private Response doGet(String url) {
return this.doGet(url, config.getAddress(), config.getToken()); return this.doGet(url, config.getAddress(), config.getToken());
} }

View File

@ -1,12 +1,13 @@
package com.example.controller; package com.example.controller;
import com.example.entity.RestBean; import com.example.entity.RestBean;
import com.example.entity.dto.Client;
import com.example.entity.vo.request.ClientDetailVO;
import com.example.service.ClientService; import com.example.service.ClientService;
import com.example.utils.Const;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import org.springframework.web.bind.annotation.GetMapping; import jakarta.validation.Valid;
import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController @RestController
@RequestMapping("/monitor") @RequestMapping("/monitor")
@ -20,4 +21,11 @@ public class ClientController {
return service.verifyAndRegister(token) ? return service.verifyAndRegister(token) ?
RestBean.success() : RestBean.failure(401, "客户端注册失败请检查Token是否正确"); RestBean.success() : RestBean.failure(401, "客户端注册失败请检查Token是否正确");
} }
@PostMapping("/detail")
public RestBean<Void> updateClientDetails(@RequestAttribute(Const.ATTR_CLIENT) Client client,
@RequestBody @Valid ClientDetailVO vo) {
service.updateClientDetail(vo, client);
return RestBean.success();
}
} }

View File

@ -1,5 +1,6 @@
package com.example.entity.dto; package com.example.entity.dto;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableName;
import com.example.entity.BaseData; import com.example.entity.BaseData;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
@ -11,6 +12,7 @@ import java.util.Date;
@TableName("db_client") @TableName("db_client")
@AllArgsConstructor @AllArgsConstructor
public class Client implements BaseData { public class Client implements BaseData {
@TableId
Integer id; Integer id;
String name; String name;
String token; String token;

View File

@ -0,0 +1,20 @@
package com.example.entity.dto;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
@Data
@TableName("db_client_detail")
public class ClientDetail {
@TableId
Integer id;
String osArch;
String osName;
String osVersion;
int osBit;
int cpuCore;
double memory;
double disk;
String ip;
}

View File

@ -0,0 +1,24 @@
package com.example.entity.vo.request;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
@Data
public class ClientDetailVO {
@NotNull
String osArch;
@NotNull
String osName;
@NotNull
String osVersion;
@NotNull
int osBit;
@NotNull
int cpuCore;
@NotNull
double memory;
@NotNull
double disk;
@NotNull
String ip;
}

View File

@ -1,6 +1,7 @@
package com.example.filter; package com.example.filter;
import com.auth0.jwt.interfaces.DecodedJWT; import com.auth0.jwt.interfaces.DecodedJWT;
import com.example.entity.RestBean;
import com.example.entity.dto.Client; import com.example.entity.dto.Client;
import com.example.service.ClientService; import com.example.service.ClientService;
import com.example.utils.Const; import com.example.utils.Const;
@ -43,6 +44,8 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter {
Client client = service.findClient(authorization); Client client = service.findClient(authorization);
if(client == null) { if(client == null) {
response.setStatus(401); response.setStatus(401);
response.setCharacterEncoding("utf-8");
response.getWriter().write(RestBean.failure(401, "未授权").asJsonString());
return; return;
} else { } else {
request.setAttribute(Const.ATTR_CLIENT, client); request.setAttribute(Const.ATTR_CLIENT, client);

View File

@ -0,0 +1,9 @@
package com.example.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.entity.dto.ClientDetail;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface ClientDetailMapper extends BaseMapper<ClientDetail> {
}

View File

@ -2,10 +2,12 @@ package com.example.service;
import com.baomidou.mybatisplus.extension.service.IService; import com.baomidou.mybatisplus.extension.service.IService;
import com.example.entity.dto.Client; import com.example.entity.dto.Client;
import com.example.entity.vo.request.ClientDetailVO;
public interface ClientService extends IService<Client> { public interface ClientService extends IService<Client> {
String registerToken(); String registerToken();
Client findClient(String token); Client findClient(String token);
Client findClient(Integer id); Client findClient(Integer id);
boolean verifyAndRegister(String token); boolean verifyAndRegister(String token);
void updateClientDetail(ClientDetailVO vo, Client client);
} }

View File

@ -2,15 +2,21 @@ package com.example.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.entity.dto.Client; import com.example.entity.dto.Client;
import com.example.entity.dto.ClientDetail;
import com.example.entity.vo.request.ClientDetailVO;
import com.example.mapper.ClientDetailMapper;
import com.example.mapper.ClientMapper; import com.example.mapper.ClientMapper;
import com.example.service.ClientService; import com.example.service.ClientService;
import jakarta.annotation.PostConstruct; import jakarta.annotation.PostConstruct;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.security.SecureRandom; import java.security.SecureRandom;
import java.util.Date; import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
import java.util.Objects;
import java.util.Random; import java.util.Random;
@Slf4j @Slf4j
@ -22,6 +28,9 @@ public class ClientServiceImpl extends ServiceImpl<ClientMapper, Client> impleme
private final HashMap<Integer, Client> clientIdCache = new HashMap<>(); private final HashMap<Integer, Client> clientIdCache = new HashMap<>();
private final HashMap<String, Client> clientTokenCache = new HashMap<>(); private final HashMap<String, Client> clientTokenCache = new HashMap<>();
@Resource
private ClientDetailMapper detailMapper;
@PostConstruct @PostConstruct
public void initClientCache() { public void initClientCache() {
this.list().forEach(this::addClientCache); this.list().forEach(this::addClientCache);
@ -57,6 +66,18 @@ public class ClientServiceImpl extends ServiceImpl<ClientMapper, Client> impleme
return false; return false;
} }
@Override
public void updateClientDetail(ClientDetailVO vo, Client client) {
ClientDetail detail = new ClientDetail();
BeanUtils.copyProperties(vo, detail);
detail.setId(client.getId());
if(Objects.nonNull(detailMapper.selectById(client.getId()))) {
detailMapper.updateById(detail);
} else {
detailMapper.insert(detail);
}
}
private void addClientCache(Client client) { private void addClientCache(Client client) {
clientIdCache.put(client.getId(), client); clientIdCache.put(client.getId(), client);
clientTokenCache.put(client.getToken(), client); clientTokenCache.put(client.getToken(), client);