实现短信组件 以及 AOP日志

This commit is contained in:
TinyAnts
2022-03-31 19:03:25 +08:00
parent b5edf7381f
commit 962a37ee2a
24 changed files with 1772 additions and 12 deletions

View File

@@ -6,6 +6,7 @@ import com.hxkj.admin.config.SystemConfig;
import com.hxkj.admin.service.ISystemAdminService;
import com.hxkj.admin.service.ISystemRoleMenuService;
import com.hxkj.common.core.AjaxResult;
import com.hxkj.common.entity.log.LogOperate;
import com.hxkj.common.enums.HttpEnum;
import com.hxkj.common.utils.RedisUtil;
import com.hxkj.common.utils.ToolsUtil;

View File

@@ -0,0 +1,16 @@
package com.hxkj.admin.config.aop;
import java.lang.annotation.*;
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface LogAnnotation {
/**
* 模块
* @return String
*/
String title() default "";
}

View File

@@ -0,0 +1,119 @@
package com.hxkj.admin.config.aop;
import com.alibaba.fastjson.JSON;
import com.hxkj.admin.LikeAdminThreadLocal;
import com.hxkj.common.entity.log.LogOperate;
import com.hxkj.common.mapper.log.LogOperateMapper;
import com.hxkj.common.utils.HttpUtil;
import com.hxkj.common.utils.IpUtil;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.*;
@Aspect
@Component
public class LogAspect {
@Resource
LogOperateMapper logOperateMapper;
private static final Logger log = LoggerFactory.getLogger(LogAspect.class);
/**
* 声明切面点拦截那些类
*/
@Pointcut("@annotation(com.hxkj.admin.config.aop.LogAnnotation)")
private void pointCutMethodController() {}
/**
* 环绕通知前后增强
*/
@Around(value = "pointCutMethodController()")
public Object doAroundService(ProceedingJoinPoint joinPoint) throws Throwable {
// 开始时间
long beginTime = System.currentTimeMillis();
// 执行方法
Object result = joinPoint.proceed();
// 执行结束
long endTime = System.currentTimeMillis();
// 执行时长
long takeTime = endTime - beginTime;
// 保存日志
recordLog(joinPoint, beginTime, endTime, takeTime);
// 返回结果
return result;
}
/**
* 记录日志信息
* @param joinPoint joinPoint
* @param startTime 开始时间(毫秒)
* @param endTime 结束时间(毫秒)
* @param takeTime 执行时长(毫秒)
*/
private void recordLog(ProceedingJoinPoint joinPoint, long startTime, long endTime, long takeTime) {
try {
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
if (requestAttributes != null) {
// 取得请求对象
HttpServletRequest request = requestAttributes.getRequest();
// 获取当前的用户
Integer adminId = LikeAdminThreadLocal.getAdminId();
// 获取日志注解
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
LogAnnotation logAnnotation = method.getAnnotation(LogAnnotation.class);
// 方法名称
String className = joinPoint.getTarget().getClass().getName();
String methodName = joinPoint.getSignature().getName();
// 获取请求参数
String queryString = request.getQueryString();
Object[] args = joinPoint.getArgs();
String params = "";
if(args.length>0){
if("POST".equals(request.getMethod())){
params = JSON.toJSONString(args);
} else if("GET".equals(request.getMethod())){
params = queryString;
}
}
// 数据库日志
LogOperate model = new LogOperate();
model.setAdminId(adminId);
model.setTitle(logAnnotation.title());
model.setIp(IpUtil.getIpAddress(request));
model.setType(request.getMethod());
model.setMethod(className + "." + methodName + "()");
model.setUrl(HttpUtil.route());
model.setArgs(params);
model.setStartTime(startTime / 1000);
model.setEndTime(endTime / 1000);
model.setTaskTime(takeTime);
model.setCreateTime(System.currentTimeMillis() / 1000);
logOperateMapper.insert(model);
}
} catch (Exception e) {
log.error("异常信息:{}", e.getMessage());
}
}
}

View File

@@ -1,10 +1,13 @@
package com.hxkj.admin.controller;
import com.hxkj.admin.config.aop.LogAnnotation;
import com.hxkj.common.core.AjaxResult;
import com.hxkj.common.exception.OperateException;
import com.hxkj.common.plugin.sms.SmsDriver;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import java.util.LinkedHashMap;
@@ -14,19 +17,25 @@ import java.util.Map;
@RestController
public class IndexController {
@PostMapping("/aa")
public AjaxResult aa() {
try {
Map<String, String> params = new LinkedHashMap<>();
(new SmsDriver())
.setMobile("15627119239")
.setParam(params)
.sendSms();
return AjaxResult.success();
} catch (OperateException e) {
return AjaxResult.failed(e.getMsg());
}
@PostMapping("/aa")
@LogAnnotation(title = "小河")
public AjaxResult aa(@RequestBody Map<String, String> map) {
System.out.println("急急急");
System.out.println(map);
// try {
// Map<String, String> params = new LinkedHashMap<>();
// (new SmsDriver())
// .setMobile("15627119239")
// .setParam(params)
// .sendSms();
//
// return AjaxResult.success();
// } catch (OperateException e) {
// return AjaxResult.failed(e.getMsg());
// }
return null;
}
}

View File

@@ -0,0 +1,57 @@
package com.hxkj.admin.controller.monitor;
import com.hxkj.common.core.AjaxResult;
import com.hxkj.common.utils.StringUtil;
import org.springframework.data.redis.connection.RedisServerCommands;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.*;
@RestController
@RequestMapping("/api/monitor")
public class CacheController {
@Resource
private RedisTemplate<String, String> redisTemplate;
/**
* 缓存监控
*
* @author fzr
* @return Object
*/
@GetMapping("/cache")
public Object info()
{
Properties info = (Properties) redisTemplate.execute((RedisCallback<Object>) RedisServerCommands::info);
Properties commandStats = (Properties) redisTemplate.execute((RedisCallback<Object>) connection -> connection.info("commandstats"));
Object dbSize = redisTemplate.execute((RedisCallback<Object>) RedisServerCommands::dbSize);
if (commandStats == null) {
return AjaxResult.failed("获取异常");
}
Map<String, Object> result = new HashMap<>(3);
result.put("info", info);
result.put("dbSize", dbSize);
List<Map<String, String>> pieList = new ArrayList<>();
commandStats.stringPropertyNames().forEach(key -> {
Map<String, String> data = new HashMap<>(2);
String property = commandStats.getProperty(key);
data.put("name", StringUtil.removeStart(key, "cmdstat_"));
data.put("value", StringUtil.substringBetween(property, "calls=", ",usec"));
pieList.add(data);
});
result.put("commandStats", pieList);
return AjaxResult.success(result);
}
}

View File

@@ -0,0 +1,26 @@
package com.hxkj.admin.controller.monitor;
import com.hxkj.common.core.AjaxResult;
import com.hxkj.common.core.ServerResult;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/api/monitor")
public class ServerController
{
/**
* 服务器信息
*
* @author fzr
* @return Object
*/
@GetMapping("/server")
public Object info()
{
ServerResult server = new ServerResult();
return AjaxResult.success(server.copyTo());
}
}

View File

@@ -0,0 +1,62 @@
package com.hxkj.admin.controller.setting;
import com.hxkj.admin.service.IBasicsService;
import com.hxkj.common.core.AjaxResult;
import com.hxkj.common.utils.HttpUtil;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.Map;
@RestController
@RequestMapping("/api/setting")
public class BasicsController {
@Resource
IBasicsService iBasicsService;
/**
* 网站信息
*
* @author fzr
* @return Object
*/
@RequestMapping("/website")
public Object website(@RequestBody Map<String, String> params) {
if (HttpUtil.isGet()) {
Map<String, String> map = iBasicsService.getWebsite();
return AjaxResult.success(map);
}
try {
iBasicsService.setWebsite(params);
return AjaxResult.success();
} catch (Exception e) {
return AjaxResult.success(e.getMessage());
}
}
/**
* 备案信息
*
* @author fzr
* @return Object
*/
@RequestMapping("/copyright")
public Object copyright(@RequestBody Map<String, String> params) {
if (HttpUtil.isGet()) {
Map<String, String> map = iBasicsService.getCopyright();
return AjaxResult.success(map);
}
try {
iBasicsService.setCopyright(params);
return AjaxResult.success();
} catch (Exception e) {
return AjaxResult.success(e.getMessage());
}
}
}

View File

@@ -0,0 +1,42 @@
package com.hxkj.admin.service;
import java.util.Map;
/**
* 基础配置服务类
*/
public interface IBasicsService {
/**
* 获取网站信息
*
* @author fzr
* @return Map<String, String>
*/
Map<String, String> getWebsite();
/**
* 获取版权信息
*
* @author fzr
* @return Map<String, String>
*/
Map<String, String> getCopyright();
/**
* 设置网站信息
*
* @author fzr
* @param params 参数
*/
void setWebsite(Map<String, String> params);
/**
* 设置版权信息
*
* @author fzr
* @param params 参数
*/
void setCopyright(Map<String, String> params);
}

View File

@@ -0,0 +1,78 @@
package com.hxkj.admin.service.impl;
import com.hxkj.admin.service.IBasicsService;
import com.hxkj.common.utils.ConfigUtil;
import com.hxkj.common.utils.UrlUtil;
import org.springframework.stereotype.Service;
import java.util.LinkedHashMap;
import java.util.Map;
@Service
public class BasicsServiceImpl implements IBasicsService {
/**
* 获取网站信息
*
* @author fzr
* @return Map<String, String>
*/
@Override
public Map<String, String> getWebsite() {
Map<String, String> config = ConfigUtil.get("website");
Map<String, String> map = new LinkedHashMap<>();
map.put("name", config.getOrDefault("name", ""));
map.put("logo", UrlUtil.toAbsoluteUrl(config.getOrDefault("logo", "")));
map.put("backdrop", UrlUtil.toAbsoluteUrl(config.getOrDefault("backdrop", "")));
return map;
}
/**
* 获取版权信息
*
* @author fzr
* @return Map<String, String>
*/
@Override
public Map<String, String> getCopyright() {
Map<String, String> config = ConfigUtil.get("copyright");
Map<String, String> map = new LinkedHashMap<>();
map.put("privilege", config.getOrDefault("privilege", ""));
map.put("icp_number", UrlUtil.toAbsoluteUrl(config.getOrDefault("icp_number", "")));
map.put("icp_link", UrlUtil.toAbsoluteUrl(config.getOrDefault("icp_link", "")));
map.put("ga_number", UrlUtil.toAbsoluteUrl(config.getOrDefault("ga_number", "")));
map.put("ga_link", UrlUtil.toAbsoluteUrl(config.getOrDefault("ga_link", "")));
return map;
}
/**
* 设置网站信息
*
* @author fzr
* @param params 参数
*/
@Override
public void setWebsite(Map<String, String> params) {
ConfigUtil.set("website", "name", params.getOrDefault("name", ""));
ConfigUtil.set("website", "logo", UrlUtil.toRelativeUrl(params.getOrDefault("logo", "")));
ConfigUtil.set("website", "backdrop", UrlUtil.toRelativeUrl(params.getOrDefault("backdrop", "")));
}
/**
* 设置版权信息
*
* @author fzr
* @param params 参数
*/
@Override
public void setCopyright(Map<String, String> params) {
ConfigUtil.set("copyright", "privilege", params.getOrDefault("privilege", ""));
ConfigUtil.set("copyright", "icp_number", params.getOrDefault("icp_number", ""));
ConfigUtil.set("copyright", "icp_link", params.getOrDefault("icp_link", ""));
ConfigUtil.set("copyright", "ga_number", params.getOrDefault("ga_number", ""));
ConfigUtil.set("copyright", "ga_link", params.getOrDefault("ga_link", ""));
}
}

View File

@@ -77,6 +77,11 @@
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
</dependency>
<!-- Lang3 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<!-- 通用池 -->
<dependency>
<groupId>org.apache.commons</groupId>
@@ -114,6 +119,11 @@
<artifactId>aliyun-java-sdk-core</artifactId>
<version>${aliyun-java.version}</version>
</dependency>
<dependency>
<groupId>com.github.oshi</groupId>
<artifactId>oshi-core</artifactId>
<version>6.1.2</version>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,160 @@
package com.hxkj.common.core;
import com.hxkj.common.entity.server.*;
import com.hxkj.common.utils.ArithUtil;
import com.hxkj.common.utils.IpUtil;
import oshi.SystemInfo;
import oshi.hardware.CentralProcessor;
import oshi.hardware.CentralProcessor.TickType;
import oshi.hardware.GlobalMemory;
import oshi.hardware.HardwareAbstractionLayer;
import oshi.software.os.FileSystem;
import oshi.software.os.OSFileStore;
import oshi.software.os.OperatingSystem;
import oshi.util.Util;
import java.util.*;
/**
* 服务器相关信息
*/
public class ServerResult {
private static final int OSHI_WAIT_SECOND = 1000;
private final Cpu cpu = new Cpu(); // CPU相关信息
private final Mem mem = new Mem(); // 內存相关信息
private final Jvm jvm = new Jvm(); // JVM相关信息
private final Sys sys = new Sys(); // 服务器相关信息
private final List<Disk> disk = new LinkedList<>(); // 磁盘相关信息
/**
* 拷贝数据
*/
public Map<String, Object> copyTo() {
SystemInfo si = new SystemInfo();
HardwareAbstractionLayer hal = si.getHardware();
setCpuInfo(hal.getProcessor());
setMemInfo(hal.getMemory());
setSysInfo();
setJvmInfo();
setSysFiles(si.getOperatingSystem());
Map<String, Object> map = new LinkedHashMap<>();
map.put("cpu", this.cpu);
map.put("mem", this.mem);
map.put("sys", this.sys);
map.put("disk", this.disk);
return map;
}
/**
* 设置CPU信息
*/
private void setCpuInfo(CentralProcessor processor) {
long[] prevTicks = processor.getSystemCpuLoadTicks();
Util.sleep(OSHI_WAIT_SECOND);
long[] ticks = processor.getSystemCpuLoadTicks();
long nice = ticks[TickType.NICE.getIndex()] - prevTicks[TickType.NICE.getIndex()];
long irq = ticks[TickType.IRQ.getIndex()] - prevTicks[TickType.IRQ.getIndex()];
long softer = ticks[TickType.SOFTIRQ.getIndex()] - prevTicks[TickType.SOFTIRQ.getIndex()];
long steal = ticks[TickType.STEAL.getIndex()] - prevTicks[TickType.STEAL.getIndex()];
long cSys = ticks[TickType.SYSTEM.getIndex()] - prevTicks[TickType.SYSTEM.getIndex()];
long user = ticks[TickType.USER.getIndex()] - prevTicks[TickType.USER.getIndex()];
long ioWait = ticks[TickType.IOWAIT.getIndex()] - prevTicks[TickType.IOWAIT.getIndex()];
long idle = ticks[TickType.IDLE.getIndex()] - prevTicks[TickType.IDLE.getIndex()];
long totalCpu = user + nice + cSys + idle + ioWait + irq + softer + steal;
cpu.setCpuNum(processor.getLogicalProcessorCount());
cpu.setTotal(totalCpu);
cpu.setSys(cSys);
cpu.setUsed(user);
cpu.setWait(ioWait);
cpu.setFree(idle);
}
/**
* 设置内存信息
*/
private void setMemInfo(GlobalMemory memory) {
int number = (1024 * 1024 * 1024);
mem.setTotal(ArithUtil.div(memory.getTotal(), number, 2));
mem.setUsed(ArithUtil.div(memory.getTotal() - memory.getAvailable(), number, 2));
mem.setFree(ArithUtil.div(memory.getAvailable(), number, 2));
}
/**
* 设置服务器信息
*/
private void setSysInfo()
{
Properties props = System.getProperties();
sys.setComputerName(IpUtil.getHostName());
sys.setComputerIp(IpUtil.getHostIp());
sys.setOsName(props.getProperty("os.name"));
sys.setOsArch(props.getProperty("os.arch"));
sys.setUserDir(props.getProperty("user.dir"));
}
/**
* 设置Java虚拟机
*/
private void setJvmInfo() {
Properties props = System.getProperties();
jvm.setTotal(Runtime.getRuntime().totalMemory());
jvm.setMax(Runtime.getRuntime().maxMemory());
jvm.setFree(Runtime.getRuntime().freeMemory());
jvm.setVersion(props.getProperty("java.version"));
jvm.setHome(props.getProperty("java.home"));
}
/**
* 设置磁盘信息
*/
private void setSysFiles(OperatingSystem os) {
FileSystem fileSystem = os.getFileSystem();
List<OSFileStore> fsArray = fileSystem.getFileStores();
for (OSFileStore fs : fsArray)
{
long free = fs.getUsableSpace();
long total = fs.getTotalSpace();
long used = total - free;
Disk sysFile = new Disk();
sysFile.setDirName(fs.getMount());
sysFile.setSysTypeName(fs.getType());
sysFile.setTypeName(fs.getName());
sysFile.setTotal(convertFileSize(total));
sysFile.setFree(convertFileSize(free));
sysFile.setUsed(convertFileSize(used));
sysFile.setUsage(ArithUtil.mul(ArithUtil.div(used, total, 4), 100));
disk.add(sysFile);
}
}
/**
* 字节转换
*/
public String convertFileSize(long size) {
long kb = 1024;
long mb = kb * 1024;
long gb = mb * 1024;
if (size >= gb)
{
return String.format("%.1f GB", (float) size / gb);
}
else if (size >= mb)
{
float f = (float) size / mb;
return String.format(f > 100 ? "%.0f MB" : "%.1f MB", f);
}
else if (size >= kb)
{
float f = (float) size / kb;
return String.format(f > 100 ? "%.0f KB" : "%.1f KB", f);
}
else
{
return String.format("%d B", size);
}
}
}

View File

@@ -0,0 +1,31 @@
package com.hxkj.common.entity.log;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
import java.io.Serializable;
/**
* 系统操作日志实体
*/
@Data
public class LogOperate implements Serializable
{
private static final long serialVersionUID = 1L;
@TableId(value="id", type= IdType.AUTO)
private Integer id;
private Integer adminId;
private String type;
private String title;
private String method;
private String ip;
private String url;
private String args;
private Long startTime;
private Long endTime;
private Long taskTime;
private Long createTime;
}

View File

@@ -0,0 +1,45 @@
package com.hxkj.common.entity.server;
import lombok.Data;
import java.io.Serializable;
/**
* CPU相关信息
*/
@Data
public class Cpu implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 核心数
*/
private int cpuNum;
/**
* CPU总的使用率
*/
private double total;
/**
* CPU系统使用率
*/
private double sys;
/**
* CPU用户使用率
*/
private double used;
/**
* CPU当前等待率
*/
private double wait;
/**
* CPU当前空闲率
*/
private double free;
}

View File

@@ -0,0 +1,50 @@
package com.hxkj.common.entity.server;
import lombok.Data;
import java.io.Serializable;
/**
* 系统文件相关信息
*/
@Data
public class Disk implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 盘符路径
*/
private String dirName;
/**
* 盘符类型
*/
private String sysTypeName;
/**
* 文件类型
*/
private String typeName;
/**
* 总大小
*/
private String total;
/**
* 剩余大小
*/
private String free;
/**
* 已经使用量
*/
private String used;
/**
* 资源的使用率
*/
private double usage;
}

View File

@@ -0,0 +1,40 @@
package com.hxkj.common.entity.server;
import lombok.Data;
import java.io.Serializable;
/**
* JVM相关信息
*/
@Data
public class Jvm implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 当前JVM占用的内存总数(M)
*/
private double total;
/**
* JVM最大可用内存总数(M)
*/
private double max;
/**
* JVM空闲内存(M)
*/
private double free;
/**
* JDK版本
*/
private String version;
/**
* JDK路径
*/
private String home;
}

View File

@@ -0,0 +1,30 @@
package com.hxkj.common.entity.server;
import lombok.Data;
import java.io.Serializable;
/**
* 內存相关信息
*/
@Data
public class Mem implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 内存总量
*/
private double total;
/**
* 已用内存
*/
private double used;
/**
* 剩余内存
*/
private double free;
}

View File

@@ -0,0 +1,40 @@
package com.hxkj.common.entity.server;
import lombok.Data;
import java.io.Serializable;
/**
* 系统相关信息
*/
@Data
public class Sys implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 服务器名称
*/
private String computerName;
/**
* 服务器Ip
*/
private String computerIp;
/**
* 项目路径
*/
private String userDir;
/**
* 操作系统
*/
private String osName;
/**
* 系统架构
*/
private String osArch;
}

View File

@@ -0,0 +1,12 @@
package com.hxkj.common.mapper.log;
import com.hxkj.common.basics.BaseMapper;
import com.hxkj.common.entity.log.LogOperate;
import org.apache.ibatis.annotations.Mapper;
/**
* 系统操作日志
*/
@Mapper
public interface LogOperateMapper extends BaseMapper<LogOperate> {
}

View File

@@ -0,0 +1,109 @@
package com.hxkj.common.utils;
import java.math.BigDecimal;
import java.math.RoundingMode;
/**
* 算术运算工具
*/
public class ArithUtil {
/** 默认除法运算精度 */
private static final int DEF_DIV_SCALE = 10;
/** 这个类不能实例化 */
private ArithUtil() {}
/**
* 提供精确的加法运算
*
* @param v1 被加数
* @param v2 加数
* @return 两个参数的和
*/
public static double add(double v1, double v2) {
BigDecimal b1 = new BigDecimal(Double.toString(v1));
BigDecimal b2 = new BigDecimal(Double.toString(v2));
return b1.add(b2).doubleValue();
}
/**
* 提供精确的减法运算
*
* @param v1 被减数
* @param v2 减数
* @return 两个参数的差
*/
public static double sub(double v1, double v2) {
BigDecimal b1 = new BigDecimal(Double.toString(v1));
BigDecimal b2 = new BigDecimal(Double.toString(v2));
return b1.subtract(b2).doubleValue();
}
/**
* 提供精确的乘法运算
*
* @param v1 被乘数
* @param v2 乘数
* @return 两个参数的积
*/
public static double mul(double v1, double v2) {
BigDecimal b1 = new BigDecimal(Double.toString(v1));
BigDecimal b2 = new BigDecimal(Double.toString(v2));
return b1.multiply(b2).doubleValue();
}
/**
* 提供(相对)精确的除法运算,当发生除不尽的情况时,精确到
* 小数点以后10位以后的数字四舍五入。
* @param v1 被除数
* @param v2 除数
* @return 两个参数的商
*/
public static double div(double v1, double v2) {
return div(v1, v2, DEF_DIV_SCALE);
}
/**
* 提供(相对)精确的除法运算。当发生除不尽的情况时,由scale参数指
* 定精度,以后的数字四舍五入。
*
* @param v1 被除数
* @param v2 除数
* @param scale 表示表示需要精确到小数点以后几位。
* @return 两个参数的商
*/
public static double div(double v1, double v2, int scale) {
if (scale < 0)
{
throw new IllegalArgumentException(
"The scale must be a positive integer or zero");
}
BigDecimal b1 = new BigDecimal(Double.toString(v1));
BigDecimal b2 = new BigDecimal(Double.toString(v2));
if (b1.compareTo(BigDecimal.ZERO) == 0)
{
return BigDecimal.ZERO.doubleValue();
}
return b1.divide(b2, scale, RoundingMode.HALF_UP).doubleValue();
}
/**
* 提供精确的小数位四舍五入处理
*
* @param v 需要四舍五入的数字
* @param scale 小数点后保留几位
* @return 四舍五入后的结果
*/
public static double round(double v, int scale) {
if (scale < 0)
{
throw new IllegalArgumentException(
"The scale must be a positive integer or zero");
}
BigDecimal b = new BigDecimal(Double.toString(v));
BigDecimal one = BigDecimal.ONE;
return b.divide(one, scale, RoundingMode.HALF_UP).doubleValue();
}
}

View File

@@ -125,5 +125,19 @@ public class HttpUtil {
return "";
}
/**
* 判断是否是GET请求
*
* @author fzr
* @return Boolean
*/
public static Boolean isGet() {
ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
if (servletRequestAttributes != null) {
HttpServletRequest request = servletRequestAttributes.getRequest();
return request.getMethod().equals("GET");
}
return false;
}
}

View File

@@ -0,0 +1,252 @@
package com.hxkj.common.utils;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import javax.servlet.http.HttpServletRequest;
import java.net.InetAddress;
import java.net.UnknownHostException;
/**
* IP工具类
*/
public class IpUtil {
/**
* 获取客户端IP
*
* @param request 请求对象
* @return IP地址
*/
public static String getIpAddress(HttpServletRequest request)
{
if (request == null)
{
return "unknown";
}
String ip = request.getHeader("x-forwarded-for");
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
{
ip = request.getHeader("Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
{
ip = request.getHeader("X-Forwarded-For");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
{
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
{
ip = request.getHeader("X-Real-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
{
ip = request.getRemoteAddr();
}
return "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : getMultistageReverseProxyIp(ip);
}
/**
* 检查是否为内部IP地址
*
* @param ip IP地址
* @return 结果
*/
public static boolean internalIp(String ip)
{
byte[] addr = textToNumericFormatV4(ip);
return internalIp(addr) || "127.0.0.1".equals(ip);
}
/**
* 检查是否为内部IP地址
*
* @param address byte地址
* @return 结果
*/
private static boolean internalIp(byte[] address)
{
if (address == null || address.length < 2)
{
return true;
}
final byte b0 = address[0];
final byte b1 = address[1];
// 10.x.x.x/8
final byte SECTION_1 = 0x0A;
// 172.16.x.x/12
final byte SECTION_2 = (byte) 0xAC;
final byte SECTION_3 = (byte) 0x10;
final byte SECTION_4 = (byte) 0x1F;
// 192.168.x.x/16
final byte SECTION_5 = (byte) 0xC0;
final byte SECTION_6 = (byte) 0xA8;
switch (b0)
{
case SECTION_1:
return true;
case SECTION_2:
if (b1 >= SECTION_3 && b1 <= SECTION_4)
{
return true;
}
case SECTION_5:
if (b1 == SECTION_6) {
return true;
}
default:
return false;
}
}
/**
* 将IPv4地址转换成字节
*
* @param text IPv4地址
* @return byte 字节
*/
public static byte[] textToNumericFormatV4(String text)
{
if (text.length() == 0)
{
return null;
}
byte[] bytes = new byte[4];
String[] elements = text.split("\\.", -1);
try
{
long l;
int i;
switch (elements.length)
{
case 1:
l = Long.parseLong(elements[0]);
if ((l < 0L) || (l > 4294967295L))
{
return null;
}
bytes[0] = (byte) (int) (l >> 24 & 0xFF);
bytes[1] = (byte) (int) ((l & 0xFFFFFF) >> 16 & 0xFF);
bytes[2] = (byte) (int) ((l & 0xFFFF) >> 8 & 0xFF);
bytes[3] = (byte) (int) (l & 0xFF);
break;
case 2:
l = Integer.parseInt(elements[0]);
if ((l < 0L) || (l > 255L))
{
return null;
}
bytes[0] = (byte) (int) (l & 0xFF);
l = Integer.parseInt(elements[1]);
if ((l < 0L) || (l > 16777215L))
{
return null;
}
bytes[1] = (byte) (int) (l >> 16 & 0xFF);
bytes[2] = (byte) (int) ((l & 0xFFFF) >> 8 & 0xFF);
bytes[3] = (byte) (int) (l & 0xFF);
break;
case 3:
for (i = 0; i < 2; ++i)
{
l = Integer.parseInt(elements[i]);
if ((l < 0L) || (l > 255L))
{
return null;
}
bytes[i] = (byte) (int) (l & 0xFF);
}
l = Integer.parseInt(elements[2]);
if ((l < 0L) || (l > 65535L))
{
return null;
}
bytes[2] = (byte) (int) (l >> 8 & 0xFF);
bytes[3] = (byte) (int) (l & 0xFF);
break;
case 4:
for (i = 0; i < 4; ++i)
{
l = Integer.parseInt(elements[i]);
if ((l < 0L) || (l > 255L))
{
return null;
}
bytes[i] = (byte) (int) (l & 0xFF);
}
break;
default:
return null;
}
}
catch (NumberFormatException e)
{
return null;
}
return bytes;
}
/**
* 获取IP地址
*
* @return 本地IP地址
*/
public static String getHostIp()
{
try {
return InetAddress.getLocalHost().getHostAddress();
}
catch (UnknownHostException ignored) { }
return "127.0.0.1";
}
/**
* 获取主机名
*
* @return 本地主机名
*/
public static String getHostName()
{
try {
return InetAddress.getLocalHost().getHostName();
}
catch (UnknownHostException ignored) {}
return "未知";
}
/**
* 从多级反向代理中获得第一个非unknown IP地址
*
* @param ip 获得的IP地址
* @return 第一个非unknown IP地址
*/
public static String getMultistageReverseProxyIp(String ip) {
if (ip != null && ip.indexOf(",") > 0) {
final String[] ips = ip.trim().split(",");
for (String subIp : ips) {
if (!isUnknown(subIp)) {
ip = subIp;
break;
}
}
}
return ip;
}
/**
* 检测给定字符串是否为未知多用于检测HTTP请求相关
*
* @param checkString 被检测的字符串
* @return 是否未知
*/
public static boolean isUnknown(String checkString)
{
return StringUtils.isBlank(checkString) || "unknown".equalsIgnoreCase(checkString);
}
}

View File

@@ -0,0 +1,546 @@
package com.hxkj.common.utils;
import org.springframework.util.AntPathMatcher;
import java.util.*;
/**
* 字符串工具类
*/
public class StringUtil extends org.apache.commons.lang3.StringUtils
{
/** 空字符串 */
private static final String NULL_STR = "";
/** 下划线 */
private static final char SEPARATOR = '_';
/**
* 获取参数不为空值
*
* @param value defaultValue 要判断的value
* @return value 返回值
*/
public static <T> T nvl(T value, T defaultValue)
{
return value != null ? value : defaultValue;
}
/**
* 判断一个Collection是否为空, 包含List, Set, Queue
*
* @param coll 要判断的Collection
* @return true为空 false非空
*/
public static boolean isEmpty(Collection<?> coll)
{
return isNull(coll) || coll.isEmpty();
}
/**
* 判断一个Collection是否非空,包含List, Set, Queue
*
* @param coll 要判断的Collection
* @return true非空 false
*/
public static boolean isNotEmpty(Collection<?> coll)
{
return !isEmpty(coll);
}
/**
* 判断一个对象数组是否为空
*
* @param objects 要判断的对象数组
** @return true为空 false非空
*/
public static boolean isEmpty(Object[] objects)
{
return isNull(objects) || (objects.length == 0);
}
/**
* 判断一个对象数组是否非空
*
* @param objects 要判断的对象数组
* @return true非空 false
*/
public static boolean isNotEmpty(Object[] objects)
{
return !isEmpty(objects);
}
/**
* 判断一个Map是否为空
*
* @param map 要判断的Map
* @return true为空 false非空
*/
public static boolean isEmpty(Map<?, ?> map)
{
return isNull(map) || map.isEmpty();
}
/**
* 判断一个Map是否为空
*
* @param map 要判断的Map
* @return true非空 false
*/
public static boolean isNotEmpty(Map<?, ?> map)
{
return !isEmpty(map);
}
/**
* 判断一个字符串是否为空串
*
* @param str String
* @return true为空 false非空
*/
public static boolean isEmpty(String str)
{
return isNull(str) || NULL_STR.equals(str.trim());
}
/**
* 判断一个字符串是否为非空串
*
* @param str String
* @return true非空串 false空串
*/
public static boolean isNotEmpty(String str)
{
return !isEmpty(str);
}
/**
* * 判断一个对象是否为空
*
* @param object Object
* @return true为空 false非空
*/
public static boolean isNull(Object object)
{
return object == null;
}
/**
* * 判断一个对象是否非空
*
* @param object Object
* @return true非空 false
*/
public static boolean isNotNull(Object object)
{
return !isNull(object);
}
/**
* 判断一个对象是否是数组类型Java基本型别的数组
*
* @param object 对象
* @return true是数组 false不是数组
*/
public static boolean isArray(Object object)
{
return isNotNull(object) && object.getClass().isArray();
}
/**
* 去空格
*/
public static String trim(String str)
{
return (str == null ? "" : str.trim());
}
/**
* 截取字符串
*
* @param str 字符串
* @param start 开始
* @return 结果
*/
public static String substring(final String str, int start)
{
if (str == null)
{
return NULL_STR;
}
if (start < 0)
{
start = str.length() + start;
}
if (start < 0)
{
start = 0;
}
if (start > str.length())
{
return NULL_STR;
}
return str.substring(start);
}
/**
* 截取字符串
*
* @param str 字符串
* @param start 开始
* @param end 结束
* @return 结果
*/
public static String substring(final String str, int start, int end)
{
if (str == null)
{
return NULL_STR;
}
if (end < 0)
{
end = str.length() + end;
}
if (start < 0)
{
start = str.length() + start;
}
if (end > str.length())
{
end = str.length();
}
if (start > end)
{
return NULL_STR;
}
if (start < 0)
{
start = 0;
}
if (end < 0)
{
end = 0;
}
return str.substring(start, end);
}
/**
* 字符串转set
*
* @param str 字符串
* @param sep 分隔符
* @return set集合
*/
public static Set<String> str2Set(String str, String sep)
{
return new HashSet<String>(str2List(str, sep, true, false));
}
/**
* 字符串转list
*
* @param str 字符串
* @param sep 分隔符
* @param filterBlank 过滤纯空白
* @param trim 去掉首尾空白
* @return list集合
*/
public static List<String> str2List(String str, String sep, boolean filterBlank, boolean trim)
{
List<String> list = new ArrayList<String>();
if (StringUtil.isEmpty(str))
{
return list;
}
// 过滤空白字符串
if (filterBlank && StringUtil.isBlank(str))
{
return list;
}
String[] split = str.split(sep);
for (String string : split)
{
if (filterBlank && StringUtil.isBlank(string))
{
continue;
}
if (trim)
{
string = string.trim();
}
list.add(string);
}
return list;
}
/**
* 查找指定字符串是否包含指定字符串列表中的任意一个字符串同时串忽略大小写
*
* @param cs 指定字符串
* @param searchCharSequences 需要检查的字符串数组
* @return 是否包含任意一个字符串
*/
public static boolean containsAnyIgnoreCase(CharSequence cs, CharSequence... searchCharSequences)
{
if (isEmpty(cs) || isEmpty(searchCharSequences))
{
return false;
}
for (CharSequence testStr : searchCharSequences)
{
if (containsIgnoreCase(cs, testStr))
{
return true;
}
}
return false;
}
/**
* 驼峰转下划线命名
*/
public static String toUnderScoreCase(String str)
{
if (str == null)
{
return null;
}
StringBuilder sb = new StringBuilder();
// 前置字符是否大写
boolean preCharIsUpperCase = true;
// 当前字符是否大写
boolean curreCharIsUpperCase = true;
// 下一字符是否大写
boolean nexteCharIsUpperCase = true;
for (int i = 0; i < str.length(); i++)
{
char c = str.charAt(i);
if (i > 0)
{
preCharIsUpperCase = Character.isUpperCase(str.charAt(i - 1));
}
else
{
preCharIsUpperCase = false;
}
curreCharIsUpperCase = Character.isUpperCase(c);
if (i < (str.length() - 1))
{
nexteCharIsUpperCase = Character.isUpperCase(str.charAt(i + 1));
}
if (preCharIsUpperCase && curreCharIsUpperCase && !nexteCharIsUpperCase)
{
sb.append(SEPARATOR);
}
else if ((i != 0 && !preCharIsUpperCase) && curreCharIsUpperCase)
{
sb.append(SEPARATOR);
}
sb.append(Character.toLowerCase(c));
}
return sb.toString();
}
/**
* 是否包含字符串
*
* @param str 验证字符串
* @param strArr 字符串组
* @return 包含返回true
*/
public static boolean inStringIgnoreCase(String str, String... strArr)
{
if (str != null && strArr != null)
{
for (String s : strArr)
{
if (str.equalsIgnoreCase(trim(s)))
{
return true;
}
}
}
return false;
}
/**
* 将下划线大写方式命名的字符串转换为驼峰式。
* 如果转换前的下划线大写方式命名的字符串为空,
* 则返回空字符串。 例如HELLO_WORLD->HelloWorld
*
* @param name 转换前的下划线大写方式命名的字符串
* @return 转换后的驼峰式命名的字符串
*/
public static String convertToCamelCase(String name)
{
StringBuilder result = new StringBuilder();
// 快速检查
if (name == null || name.isEmpty())
{
// 没必要转换
return "";
}
else if (!name.contains("_"))
{
// 不含下划线,仅将首字母大写
return name.substring(0, 1).toUpperCase() + name.substring(1);
}
// 用下划线将原始字符串分割
String[] camels = name.split("_");
for (String camel : camels)
{
// 跳过原始字符串中开头、结尾的下换线或双重下划线
if (camel.isEmpty())
{
continue;
}
// 首字母大写
result.append(camel.substring(0, 1).toUpperCase());
result.append(camel.substring(1).toLowerCase());
}
return result.toString();
}
/**
* 驼峰式命名法 例如user_name->userName
*
* @param s 字符串
* @return 驼峰字符串
*/
public static String toCamelCase(String s)
{
if (s == null)
{
return null;
}
s = s.toLowerCase();
StringBuilder sb = new StringBuilder(s.length());
boolean upperCase = false;
for (int i = 0; i < s.length(); i++)
{
char c = s.charAt(i);
if (c == SEPARATOR)
{
upperCase = true;
}
else if (upperCase)
{
sb.append(Character.toUpperCase(c));
upperCase = false;
}
else
{
sb.append(c);
}
}
return sb.toString();
}
/**
* 查找指定字符串是否匹配指定字符串列表中的任意一个字符串
*
* @param str 指定字符串
* @param strArr 需要检查的字符串数组
* @return 是否匹配
*/
public static boolean matches(String str, List<String> strArr)
{
if (isEmpty(str) || isEmpty(strArr))
{
return false;
}
for (String pattern : strArr)
{
if (isMatch(pattern, str))
{
return true;
}
}
return false;
}
/**
* 判断url是否与规则配置:
* ? 表示单个字符;
* * 表示一层路径内的任意字符串,不可跨层级;
* ** 表示任意层路径;
*
* @param pattern 匹配规则
* @param url 需要匹配的url
* @return boolean
*/
public static boolean isMatch(String pattern, String url)
{
AntPathMatcher matcher = new AntPathMatcher();
return matcher.match(pattern, url);
}
/**
* 数字左边补齐0,使之达到指定长度。
* 注意,如果数字转换为字符串后,长度大于size,则只保留 最后size个字符。
*
* @param num 数字对象
* @param size 字符串指定长度
* @return 返回数字的字符串格式,该字符串为指定长度。
*/
public static String padL(final Number num, final int size)
{
return padL(num.toString(), size, '0');
}
/**
* 字符串左补齐
* 如果原始字符串s长度大于size,则只保留最后size个字符。
*
* @param s 原始字符串
* @param size 字符串指定长度
* @param c 用于补齐的字符
* @return 返回指定长度的字符串,由原字符串左补齐或截取得到。
*/
public static String padL(final String s, final int size, final char c)
{
final StringBuilder sb = new StringBuilder(size);
if (s != null)
{
final int len = s.length();
if (s.length() <= size)
{
for (int i = size - len; i > 0; i--)
{
sb.append(c);
}
sb.append(s);
}
else
{
return s.substring(len - size, len);
}
}
else
{
for (int i = size; i > 0; i--)
{
sb.append(c);
}
}
return sb.toString();
}
}

View File

@@ -22,6 +22,10 @@ public class UrlUtil {
* @return String
*/
public static String toAbsoluteUrl(String url) {
if (url == null || url.equals("")) {
return "";
}
if(url.indexOf("/") != 0) {
url = "/" + url;
}

View File

@@ -29,6 +29,7 @@
<lombok.version>1.18.22</lombok.version>
<fastJson.version>1.2.78</fastJson.version>
<apache-commons.version>2.10.0</apache-commons.version>
<commons-lang3.version>3.12.0</commons-lang3.version>
<gson.version>2.9.0</gson.version>
<qiniu.version>7.9.5</qiniu.version>
<qcloud-version>5.6.54</qcloud-version>
@@ -84,6 +85,12 @@
<artifactId>fastjson</artifactId>
<version>${fastJson.version}</version>
</dependency>
<!-- Lang3 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>${commons-lang3.version}</version>
</dependency>
<!-- 通用池 -->
<dependency>
<groupId>org.apache.commons</groupId>