1.完成气象预测任务新增、修改、删除、分页查询、查询任务日志功能
2.完成气象数据管理功能文件校验、文件上传、文件删除功能 3.解决cloud服务数据传递功能
This commit is contained in:
parent
dd27760a00
commit
e5ad6fd156
4671
db/stas.sql
4671
db/stas.sql
File diff suppressed because one or more lines are too long
|
|
@ -38,6 +38,11 @@
|
||||||
</snapshots>
|
</snapshots>
|
||||||
</repository>
|
</repository>
|
||||||
</repositories>
|
</repositories>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<netcdf.version>4.5.5</netcdf.version>
|
||||||
|
<grib.version>4.5.5</grib.version>
|
||||||
|
</properties>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<!--jeecg-tools-->
|
<!--jeecg-tools-->
|
||||||
|
|
@ -320,5 +325,16 @@
|
||||||
<groupId>org.jeecgframework.boot3</groupId>
|
<groupId>org.jeecgframework.boot3</groupId>
|
||||||
<artifactId>minidao-spring-boot-starter-jsqlparser-4.9</artifactId>
|
<artifactId>minidao-spring-boot-starter-jsqlparser-4.9</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<!-- 读取 .nc 文件 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>edu.ucar</groupId>
|
||||||
|
<artifactId>netcdf4</artifactId>
|
||||||
|
<version>${netcdf.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>edu.ucar</groupId>
|
||||||
|
<artifactId>grib</artifactId>
|
||||||
|
<version>${grib.version}</version>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</project>
|
</project>
|
||||||
|
|
@ -33,23 +33,6 @@ public interface ServiceNameConstants {
|
||||||
* 微服务名: demo模块
|
* 微服务名: demo模块
|
||||||
*/
|
*/
|
||||||
String SERVICE_DEMO = "jeecg-demo";
|
String SERVICE_DEMO = "jeecg-demo";
|
||||||
/**
|
|
||||||
* 微服务名:joa模块
|
|
||||||
*/
|
|
||||||
String SERVICE_JOA = "jeecg-joa";
|
|
||||||
|
|
||||||
// /**
|
|
||||||
// * 微服务名:online在线模块
|
|
||||||
// */
|
|
||||||
// String SERVICE_ONLINE = "jeecg-online";
|
|
||||||
// /**
|
|
||||||
// * 微服务名:OA模块
|
|
||||||
// */
|
|
||||||
// String SERVICE_EOA = "jeecg-eoa";
|
|
||||||
// /**
|
|
||||||
// * 微服务名:表单设计模块
|
|
||||||
// */
|
|
||||||
// String SERVICE_FORM = "jeecg-desform";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gateway通过header传递根路径 basePath
|
* gateway通过header传递根路径 basePath
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
package org.jeecg.common.constant.enums;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 气象数据来源说明枚举
|
||||||
|
*/
|
||||||
|
public enum WeatherDataSourceEnum {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 盘古模型
|
||||||
|
*/
|
||||||
|
PANGU(1),
|
||||||
|
/**
|
||||||
|
* Graphcast
|
||||||
|
*/
|
||||||
|
GRAPHCAST(2),
|
||||||
|
/**
|
||||||
|
* 再分析数据
|
||||||
|
*/
|
||||||
|
RE_ANALYSIS(3);
|
||||||
|
|
||||||
|
private Integer key;
|
||||||
|
|
||||||
|
WeatherDataSourceEnum(Integer key) {
|
||||||
|
this.key = key;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getKey(){
|
||||||
|
return this.key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
package org.jeecg.common.constant.enums;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文件类型说明枚举
|
||||||
|
*/
|
||||||
|
public enum WeatherFilePrefixEnum {
|
||||||
|
|
||||||
|
|
||||||
|
FORECAST(0, "panguweather_");
|
||||||
|
|
||||||
|
private Integer key;
|
||||||
|
|
||||||
|
private String value;
|
||||||
|
|
||||||
|
WeatherFilePrefixEnum(Integer key, String value) {
|
||||||
|
this.key = key;
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getKey(){
|
||||||
|
return this.key;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getValue(){
|
||||||
|
return this.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getValueByKey(int key) {
|
||||||
|
for (WeatherFilePrefixEnum prefix : WeatherFilePrefixEnum.values()) {
|
||||||
|
if (prefix.getKey() == key) {
|
||||||
|
return prefix.getValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
package org.jeecg.common.constant.enums;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文件类型说明枚举
|
||||||
|
*/
|
||||||
|
public enum WeatherFileSuffixEnum {
|
||||||
|
|
||||||
|
|
||||||
|
GRIB("grib"),GRIB2("grib2");;
|
||||||
|
|
||||||
|
private String value;
|
||||||
|
|
||||||
|
WeatherFileSuffixEnum(String value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getValue(){
|
||||||
|
return this.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
package org.jeecg.common.constant.enums;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 预测模型说明枚举
|
||||||
|
*/
|
||||||
|
public enum WeatherModelEnum {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 盘古模型
|
||||||
|
*/
|
||||||
|
PANGU(1),
|
||||||
|
/**
|
||||||
|
* Graphcast
|
||||||
|
*/
|
||||||
|
GRAPHCAST(2);
|
||||||
|
|
||||||
|
private Integer key;
|
||||||
|
|
||||||
|
WeatherModelEnum(Integer key) {
|
||||||
|
this.key = key;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getKey(){
|
||||||
|
return this.key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
package org.jeecg.common.constant.enums;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 预测任务状态说明枚举
|
||||||
|
*/
|
||||||
|
public enum WeatherTaskStatusEnum {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 未开始
|
||||||
|
*/
|
||||||
|
NOT_STARTED(0),
|
||||||
|
/**
|
||||||
|
* 未开始
|
||||||
|
*/
|
||||||
|
IN_OPERATION(1),
|
||||||
|
/**
|
||||||
|
* 已完成
|
||||||
|
*/
|
||||||
|
COMPLETED(2);
|
||||||
|
|
||||||
|
private Integer key;
|
||||||
|
|
||||||
|
WeatherTaskStatusEnum(Integer key) {
|
||||||
|
this.key = key;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getKey(){
|
||||||
|
return this.key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
package org.jeecg.common.constant.enums;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文件类型说明枚举
|
||||||
|
*/
|
||||||
|
public enum WeatherTypeEnum {
|
||||||
|
|
||||||
|
|
||||||
|
TEMPERATURE(0, "panguweather_"),
|
||||||
|
PRESSURE(1, "PRESSURE"),
|
||||||
|
HUMIDITY(2, "HUMIDITY"),
|
||||||
|
WIND(3, "WIND"),
|
||||||
|
PRECIPITATION(4, "PRECIPITATION");
|
||||||
|
|
||||||
|
private Integer key;
|
||||||
|
|
||||||
|
private String value;
|
||||||
|
|
||||||
|
WeatherTypeEnum(Integer key, String value) {
|
||||||
|
this.key = key;
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getKey(){
|
||||||
|
return this.key;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getValue(){
|
||||||
|
return this.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
package org.jeecg.common.properties;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Component
|
||||||
|
@ConfigurationProperties(prefix = "filesystem")
|
||||||
|
public class SystemStorageProperties {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 系统存储根路径
|
||||||
|
*/
|
||||||
|
private String rootPath;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 盘古模型预测数据存储路径
|
||||||
|
*/
|
||||||
|
private String pangu;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* graphcast模型预测数据存储路径
|
||||||
|
*/
|
||||||
|
private String graphcast;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 再分析数据存储路径
|
||||||
|
*/
|
||||||
|
private String reAnalysis;
|
||||||
|
}
|
||||||
|
|
@ -3,6 +3,10 @@ package org.jeecg.common.system.base.entity;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
import jakarta.validation.constraints.Null;
|
||||||
|
import org.jeecg.common.validgroup.InsertGroup;
|
||||||
|
import org.jeecg.common.validgroup.UpdateGroup;
|
||||||
import org.jeecgframework.poi.excel.annotation.Excel;
|
import org.jeecgframework.poi.excel.annotation.Excel;
|
||||||
import org.springframework.format.annotation.DateTimeFormat;
|
import org.springframework.format.annotation.DateTimeFormat;
|
||||||
|
|
||||||
|
|
@ -23,12 +27,14 @@ import lombok.experimental.Accessors;
|
||||||
@Data
|
@Data
|
||||||
@EqualsAndHashCode(callSuper = false)
|
@EqualsAndHashCode(callSuper = false)
|
||||||
@Accessors(chain = true)
|
@Accessors(chain = true)
|
||||||
public class JeecgEntity implements Serializable {
|
public class BaseEntity implements Serializable {
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ID
|
* ID
|
||||||
*/
|
*/
|
||||||
|
@Null(message = "ID必须为空",groups = { InsertGroup.class})
|
||||||
|
@NotNull(message = "ID不能为空",groups = { UpdateGroup.class})
|
||||||
@TableId(type = IdType.ASSIGN_ID)
|
@TableId(type = IdType.ASSIGN_ID)
|
||||||
@Schema(description = "ID")
|
@Schema(description = "ID")
|
||||||
private java.lang.String id;
|
private java.lang.String id;
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
package org.jeecg.common.system.base.service.impl;
|
package org.jeecg.common.system.base.service.impl;
|
||||||
|
|
||||||
import org.jeecg.common.system.base.entity.JeecgEntity;
|
import org.jeecg.common.system.base.entity.BaseEntity;
|
||||||
import org.jeecg.common.system.base.service.JeecgService;
|
import org.jeecg.common.system.base.service.JeecgService;
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
|
@ -14,6 +14,6 @@ import lombok.extern.slf4j.Slf4j;
|
||||||
* @Version: 1.0
|
* @Version: 1.0
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class JeecgServiceImpl<M extends BaseMapper<T>, T extends JeecgEntity> extends ServiceImpl<M, T> implements JeecgService<T> {
|
public class JeecgServiceImpl<M extends BaseMapper<T>, T extends BaseEntity> extends ServiceImpl<M, T> implements JeecgService<T> {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,67 @@
|
||||||
|
package org.jeecg.common.system.query;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
|
||||||
|
public class PageRequest {
|
||||||
|
|
||||||
|
/** 当前记录起始索引 */
|
||||||
|
private Integer pageNum;
|
||||||
|
|
||||||
|
/** 每页显示记录数 */
|
||||||
|
private Integer pageSize;
|
||||||
|
|
||||||
|
/** 排序列 */
|
||||||
|
private String orderByColumn;
|
||||||
|
|
||||||
|
/** 排序的方向desc或者asc */
|
||||||
|
private String isAsc = "asc";
|
||||||
|
|
||||||
|
public PageRequest() {
|
||||||
|
this.pageNum = 1;
|
||||||
|
this.pageSize = 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getPageNum() {
|
||||||
|
return pageNum;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPageNum(Integer pageNum) {
|
||||||
|
this.pageNum = pageNum;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getPageSize() {
|
||||||
|
return pageSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPageSize(Integer pageSize) {
|
||||||
|
this.pageSize = pageSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getOrderByColumn() {
|
||||||
|
return orderByColumn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOrderByColumn(String orderByColumn) {
|
||||||
|
this.orderByColumn = orderByColumn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getIsAsc() {
|
||||||
|
return isAsc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIsAsc(String isAsc) {
|
||||||
|
if (StrUtil.isNotEmpty(isAsc))
|
||||||
|
{
|
||||||
|
// 兼容前端排序类型
|
||||||
|
if ("ascending".equals(isAsc))
|
||||||
|
{
|
||||||
|
isAsc = "asc";
|
||||||
|
}
|
||||||
|
else if ("descending".equals(isAsc))
|
||||||
|
{
|
||||||
|
isAsc = "desc";
|
||||||
|
}
|
||||||
|
this.isAsc = isAsc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,254 @@
|
||||||
|
package org.jeecg.common.util;
|
||||||
|
|
||||||
|
import ucar.ma2.Array;
|
||||||
|
import ucar.ma2.ArrayDouble;
|
||||||
|
import ucar.ma2.DataType;
|
||||||
|
import ucar.ma2.Index;
|
||||||
|
import ucar.nc2.Attribute;
|
||||||
|
import ucar.nc2.NetcdfFile;
|
||||||
|
import ucar.nc2.NetcdfFileWriter;
|
||||||
|
import ucar.nc2.Variable;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
public final class NcUtil {
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(NcUtil.class);
|
||||||
|
private static final List<String> SPECIAL_VARS = List.of("CO", "ASIJ");
|
||||||
|
private static final double ROUNDING_FACTOR = 1000d;
|
||||||
|
|
||||||
|
private NcUtil() {
|
||||||
|
throw new IllegalStateException("Utility class");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 读取三维数据,如果为四维数据,层级固定读取第一层数据,降为三维数据
|
||||||
|
*/
|
||||||
|
public static List<List<List<Double>>> getNCByName(NetcdfFile ncfile, String name, int layer) {
|
||||||
|
Objects.requireNonNull(ncfile, "NetcdfFile cannot be null");
|
||||||
|
Objects.requireNonNull(name, "Variable name cannot be null");
|
||||||
|
|
||||||
|
try {
|
||||||
|
Variable variable = ncfile.findVariable(name);
|
||||||
|
Array data = variable.read();
|
||||||
|
int[] shape = data.getShape();
|
||||||
|
Index index = data.getIndex();
|
||||||
|
|
||||||
|
List<List<List<Double>>> resultAll = new ArrayList<>(shape[0]);
|
||||||
|
|
||||||
|
if (shape.length == 3) {
|
||||||
|
process3DData(data, index, shape, name, resultAll);
|
||||||
|
} else {
|
||||||
|
process4DData(data, index, shape, name, layer, resultAll);
|
||||||
|
}
|
||||||
|
|
||||||
|
return resultAll;
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.error("Error reading variable {} from NetCDF file", name, e);
|
||||||
|
throw new RuntimeException("Failed to read NetCDF data", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取一维NC数据
|
||||||
|
*/
|
||||||
|
public static List<Double> getNCList(NetcdfFile ncFile, String name) {
|
||||||
|
Objects.requireNonNull(ncFile, "NetcdfFile cannot be null");
|
||||||
|
Objects.requireNonNull(name, "Variable name cannot be null");
|
||||||
|
|
||||||
|
try {
|
||||||
|
Variable variable = ncFile.findVariable(name);
|
||||||
|
Array data = variable.read();
|
||||||
|
int[] shape = data.getShape();
|
||||||
|
Index index = data.getIndex();
|
||||||
|
|
||||||
|
List<Double> resultAll = new ArrayList<>(shape[0]);
|
||||||
|
for (int k = 0; k < shape[0]; k++) {
|
||||||
|
resultAll.add(processValue(data.getDouble(index.set(k)), name));
|
||||||
|
}
|
||||||
|
return resultAll;
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.error("Error reading variable {} from NetCDF file", name, e);
|
||||||
|
throw new RuntimeException("Failed to read NetCDF data", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void process3DData(Array data, Index index, int[] shape, String name,
|
||||||
|
List<List<List<Double>>> resultAll) {
|
||||||
|
for (int i = 0; i < shape[0]; i++) {
|
||||||
|
List<List<Double>> resultPiece = new ArrayList<>(shape[1]);
|
||||||
|
for (int j = 0; j < shape[1]; j++) {
|
||||||
|
List<Double> strings = new ArrayList<>(shape[2]);
|
||||||
|
for (int k = 0; k < shape[2]; k++) {
|
||||||
|
strings.add(processValue(data.getDouble(index.set(i, j, k)), name));
|
||||||
|
}
|
||||||
|
resultPiece.add(strings);
|
||||||
|
}
|
||||||
|
resultAll.add(resultPiece);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void process4DData(Array data, Index index, int[] shape, String name,
|
||||||
|
int layer, List<List<List<Double>>> resultAll) {
|
||||||
|
for (int i = 0; i < shape[0]; i++) {
|
||||||
|
List<List<Double>> resultPiece = new ArrayList<>(shape[2]);
|
||||||
|
for (int j = 0; j < shape[2]; j++) {
|
||||||
|
List<Double> strings = new ArrayList<>(shape[3]);
|
||||||
|
for (int k = 0; k < shape[3]; k++) {
|
||||||
|
strings.add(processValue(data.getDouble(index.set(i, layer, j, k)), name));
|
||||||
|
}
|
||||||
|
resultPiece.add(strings);
|
||||||
|
}
|
||||||
|
resultAll.add(resultPiece);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 特殊处理,最多读取24小时,14层数据四维数据
|
||||||
|
*/
|
||||||
|
public static List<List<List<List<Double>>>> getNCByName(NetcdfFile ncFile, String name) {
|
||||||
|
return getNCDataWithFullLayers(ncFile, name, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 完整读取所有四维数据
|
||||||
|
*/
|
||||||
|
public static List<List<List<List<Double>>>> getNCAllTimeByName(NetcdfFile ncFile, String name) {
|
||||||
|
return getNCDataWithFullLayers(ncFile, name, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<List<List<List<Double>>>> getNCDataWithFullLayers(NetcdfFile ncFile,
|
||||||
|
String name,
|
||||||
|
boolean allTime) {
|
||||||
|
Objects.requireNonNull(ncFile, "NetcdfFile cannot be null");
|
||||||
|
Objects.requireNonNull(name, "Variable name cannot be null");
|
||||||
|
|
||||||
|
try {
|
||||||
|
Variable variable = ncFile.findVariable(name);
|
||||||
|
Array data = variable.read();
|
||||||
|
int[] shape = data.getShape();
|
||||||
|
Index index = data.getIndex();
|
||||||
|
|
||||||
|
List<List<List<List<Double>>>> resultAll = new ArrayList<>(shape[0]);
|
||||||
|
|
||||||
|
for (int i = 0; i < shape[0]; i++) {
|
||||||
|
List<List<List<Double>>> resultLayer = new ArrayList<>(shape[1]);
|
||||||
|
for (int l = 0; l < shape[1]; l++) {
|
||||||
|
List<List<Double>> resultPiece = new ArrayList<>(shape[2]);
|
||||||
|
for (int j = 0; j < shape[2]; j++) {
|
||||||
|
List<Double> strings = new ArrayList<>(shape[3]);
|
||||||
|
for (int k = 0; k < shape[3]; k++) {
|
||||||
|
strings.add(processValue(data.getDouble(index.set(i, l, j, k)), name));
|
||||||
|
}
|
||||||
|
resultPiece.add(strings);
|
||||||
|
}
|
||||||
|
resultLayer.add(resultPiece);
|
||||||
|
}
|
||||||
|
resultAll.add(resultLayer);
|
||||||
|
}
|
||||||
|
|
||||||
|
return resultAll;
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.error("Error reading variable {} from NetCDF file", name, e);
|
||||||
|
throw new RuntimeException("Failed to read NetCDF data", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取NC文件维度信息
|
||||||
|
*/
|
||||||
|
public static int[] getShapeByName(NetcdfFile ncfile, String name) {
|
||||||
|
Objects.requireNonNull(ncfile, "NetcdfFile cannot be null");
|
||||||
|
Objects.requireNonNull(name, "Variable name cannot be null");
|
||||||
|
|
||||||
|
try {
|
||||||
|
Variable variable = ncfile.findVariable(name);
|
||||||
|
Array data = variable.read();
|
||||||
|
return data.getShape();
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.error("Error getting shape for variable {} from NetCDF file", name, e);
|
||||||
|
throw new RuntimeException("Failed to get NetCDF shape", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成NC文件,并支持持续写入文件
|
||||||
|
*/
|
||||||
|
public static void genNcFile(List<List<List<List<Double>>>> dataList,
|
||||||
|
String newNcFilePath,
|
||||||
|
String variableName) {
|
||||||
|
Objects.requireNonNull(dataList, "Data list cannot be null");
|
||||||
|
Objects.requireNonNull(newNcFilePath, "File path cannot be null");
|
||||||
|
Objects.requireNonNull(variableName, "Variable name cannot be null");
|
||||||
|
|
||||||
|
try {
|
||||||
|
File file = new File(newNcFilePath);
|
||||||
|
boolean fileExists = file.exists();
|
||||||
|
|
||||||
|
// 数据维度
|
||||||
|
int tstepNum = dataList.size();
|
||||||
|
int layNum = dataList.get(0).size();
|
||||||
|
int rowNum = dataList.get(0).get(0).size();
|
||||||
|
int colNum = dataList.get(0).get(0).get(0).size();
|
||||||
|
|
||||||
|
NetcdfFileWriter ncWriter = fileExists ?
|
||||||
|
NetcdfFileWriter.openExisting(newNcFilePath) :
|
||||||
|
NetcdfFileWriter.createNew(NetcdfFileWriter.Version.netcdf3, newNcFilePath);
|
||||||
|
|
||||||
|
if (fileExists) {
|
||||||
|
ncWriter.setRedefineMode(true);
|
||||||
|
} else {
|
||||||
|
// 定义维度
|
||||||
|
ncWriter.addDimension(null, "TSTEP", tstepNum);
|
||||||
|
ncWriter.addDimension(null, "LAY", layNum);
|
||||||
|
ncWriter.addDimension(null, "ROW", rowNum);
|
||||||
|
ncWriter.addDimension(null, "COL", colNum);
|
||||||
|
ncWriter.addDimension(null, "LAYER", 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
Variable dataVar = ncWriter.addVariable(null, variableName, DataType.DOUBLE,
|
||||||
|
variableName.contains("AERDEP") ? "TSTEP LAYER ROW COL" : "TSTEP LAY ROW COL");
|
||||||
|
|
||||||
|
// 关联维度到变量
|
||||||
|
ncWriter.addVariableAttribute(dataVar, new Attribute("units", "none"));
|
||||||
|
ncWriter.addVariableAttribute(dataVar, new Attribute("long_name", variableName));
|
||||||
|
|
||||||
|
if (fileExists) {
|
||||||
|
ncWriter.setRedefineMode(false);
|
||||||
|
} else {
|
||||||
|
ncWriter.create();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将数据转换为NetCDF数组
|
||||||
|
ArrayDouble.D4 dataArray = new ArrayDouble.D4(tstepNum, layNum, rowNum, colNum);
|
||||||
|
for (int i = 0; i < tstepNum; i++) {
|
||||||
|
List<List<List<Double>>> layData = dataList.get(i);
|
||||||
|
for (int j = 0; j < layNum; j++) {
|
||||||
|
List<List<Double>> rowData = layData.get(j);
|
||||||
|
for (int r = 0; r < rowNum; r++) {
|
||||||
|
List<Double> colData = rowData.get(r);
|
||||||
|
for (int c = 0; c < colNum; c++) {
|
||||||
|
dataArray.set(dataArray.getIndex().set(i, j, r, c), colData.get(c));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ncWriter.write(dataVar, dataArray);
|
||||||
|
ncWriter.close();
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("Error generating NetCDF file {}", newNcFilePath, e);
|
||||||
|
throw new RuntimeException("Failed to generate NetCDF file", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static double processValue(double value, String name) {
|
||||||
|
return SPECIAL_VARS.contains(name) ? value :
|
||||||
|
Math.ceil(value * ROUNDING_FACTOR) / ROUNDING_FACTOR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
package org.jeecg.common.validgroup;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增验证组
|
||||||
|
*/
|
||||||
|
public interface InsertGroup {
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
package org.jeecg.common.validgroup;
|
||||||
|
|
||||||
|
public interface UpdateGroup {
|
||||||
|
}
|
||||||
|
|
@ -3,6 +3,7 @@ package org.jeecg.config.security;
|
||||||
import org.jeecg.common.api.CommonAPI;
|
import org.jeecg.common.api.CommonAPI;
|
||||||
import org.jeecg.common.system.vo.LoginUser;
|
import org.jeecg.common.system.vo.LoginUser;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
import org.springframework.context.annotation.Lazy;
|
import org.springframework.context.annotation.Lazy;
|
||||||
import org.springframework.core.convert.converter.Converter;
|
import org.springframework.core.convert.converter.Converter;
|
||||||
import org.springframework.security.authentication.AbstractAuthenticationToken;
|
import org.springframework.security.authentication.AbstractAuthenticationToken;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,99 @@
|
||||||
|
package org.jeecg.modules.base.entity;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 气象数据文件表
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@TableName("stas_weather_data")
|
||||||
|
public class WeatherData {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ID
|
||||||
|
*/
|
||||||
|
@TableId(type = IdType.ASSIGN_ID)
|
||||||
|
@Schema(description = "ID")
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文件名称
|
||||||
|
*/
|
||||||
|
@TableField(value = "file_name")
|
||||||
|
private String fileName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文件大小
|
||||||
|
*/
|
||||||
|
@TableField(value = "file_size")
|
||||||
|
private Double fileSize;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文件类型
|
||||||
|
*/
|
||||||
|
@TableField(value = "file_ext")
|
||||||
|
private String fileExt;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 气象数据开始时间
|
||||||
|
*/
|
||||||
|
@TableField(value = "data_start_time")
|
||||||
|
private LocalDateTime dataStartTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 气象数据结束时间
|
||||||
|
*/
|
||||||
|
@TableField(value = "data_end_time")
|
||||||
|
private LocalDateTime dataEndTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 数据来源(1-盘古模型,2-graphcast,3-再分析数据)
|
||||||
|
*/
|
||||||
|
@TableField(value = "data_source")
|
||||||
|
private Integer dataSource;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文件存储路径
|
||||||
|
*/
|
||||||
|
@TableField(value = "file_path")
|
||||||
|
private String filePath;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建人
|
||||||
|
*/
|
||||||
|
@TableField(value = "create_by")
|
||||||
|
private String createBy;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建时间
|
||||||
|
*/
|
||||||
|
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
@TableField(value = "create_time")
|
||||||
|
private Date createTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文件MD5值
|
||||||
|
*/
|
||||||
|
@TableField(value = "md5_value")
|
||||||
|
private String md5Value;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 总分片数
|
||||||
|
*/
|
||||||
|
@TableField(value = "share_total")
|
||||||
|
private Integer shareTotal;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分片索引
|
||||||
|
*/
|
||||||
|
@TableField(value = "share_index")
|
||||||
|
private Integer shareIndex;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,85 @@
|
||||||
|
package org.jeecg.modules.base.entity;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
import jakarta.validation.constraints.NotBlank;
|
||||||
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
import jakarta.validation.constraints.Null;
|
||||||
|
import lombok.Data;
|
||||||
|
import org.jeecg.common.system.base.entity.BaseEntity;
|
||||||
|
import org.jeecg.common.validgroup.InsertGroup;
|
||||||
|
import org.jeecg.common.validgroup.UpdateGroup;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 天气预测任务表
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@TableName("stas_weather_task")
|
||||||
|
public class WeatherTask extends BaseEntity {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 任务名称
|
||||||
|
*/
|
||||||
|
@NotBlank(message = "任务名称不能为空",groups = {InsertGroup.class, UpdateGroup.class})
|
||||||
|
@TableField(value = "task_name")
|
||||||
|
private String taskName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 任务状态(0-未开始,1-运行中,2-已完成)
|
||||||
|
*/
|
||||||
|
@Null(message = "任务状态必须为空",groups = {InsertGroup.class, UpdateGroup.class})
|
||||||
|
@TableField(value = "task_status")
|
||||||
|
private Integer taskStatus;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 耗时(小时),默认0
|
||||||
|
*/
|
||||||
|
@Null(message = "耗时参数必须为空",groups = {InsertGroup.class, UpdateGroup.class})
|
||||||
|
@TableField(value = "time_consuming")
|
||||||
|
private Integer timeConsuming;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 预测模型(1-盘古、2-Graphcast)
|
||||||
|
*/
|
||||||
|
@NotNull(message = "预测模型不能为空",groups = {InsertGroup.class, UpdateGroup.class})
|
||||||
|
@TableField(value = "prediction_model")
|
||||||
|
private Integer predictionModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 开始预测日期
|
||||||
|
*/
|
||||||
|
@NotNull(message = "预测开始日期不能为空",groups = {InsertGroup.class, UpdateGroup.class})
|
||||||
|
@TableField(value = "start_date")
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd")
|
||||||
|
private LocalDate startDate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 开始预测时间
|
||||||
|
*/
|
||||||
|
@NotNull(message = "预测开始时间不能为空",groups = {InsertGroup.class, UpdateGroup.class})
|
||||||
|
@TableField(value = "start_time")
|
||||||
|
private Integer startTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 预测时长
|
||||||
|
*/
|
||||||
|
@NotNull(message = "预测时长不能为空",groups = {InsertGroup.class, UpdateGroup.class})
|
||||||
|
@TableField(value = "lead_time")
|
||||||
|
private Integer leadTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 数据来源(1-cds,2-本地文件)
|
||||||
|
*/
|
||||||
|
@NotNull(message = "数据来源不能为空",groups = {InsertGroup.class, UpdateGroup.class})
|
||||||
|
@TableField(value = "data_sources")
|
||||||
|
private Integer dataSources;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 如果data_sources为2,则存储本地文件路径
|
||||||
|
*/
|
||||||
|
@TableField(value = "input_file")
|
||||||
|
private String inputFile;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,44 @@
|
||||||
|
package org.jeecg.modules.base.entity;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 天气预测任务日志表
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@TableName("stas_weather_task_log")
|
||||||
|
public class WeatherTaskLog{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ID
|
||||||
|
*/
|
||||||
|
@TableId(type = IdType.ASSIGN_ID)
|
||||||
|
@Schema(description = "ID")
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 任务表主键
|
||||||
|
*/
|
||||||
|
@TableField(value = "task_id")
|
||||||
|
private String taskId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 任务运行过程日志
|
||||||
|
*/
|
||||||
|
@TableField(value = "log_content")
|
||||||
|
private String logContent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建时间
|
||||||
|
*/
|
||||||
|
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
private LocalDateTime createTime;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
package org.jeecg.modules.base.mapper;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import org.jeecg.modules.base.entity.WeatherData;
|
||||||
|
|
||||||
|
public interface WeatherDataMapper extends BaseMapper<WeatherData> {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
package org.jeecg.modules.base.mapper;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import org.jeecg.modules.base.entity.WeatherTaskLog;
|
||||||
|
|
||||||
|
public interface WeatherTaskLogMapper extends BaseMapper<WeatherTaskLog> {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
package org.jeecg.modules.base.mapper;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import org.jeecg.modules.base.entity.WeatherTask;
|
||||||
|
|
||||||
|
public interface WeatherTaskMapper extends BaseMapper<WeatherTask> {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||||
|
<mapper namespace="org.jeecg.modules.base.mapper.WeatherDataMapper">
|
||||||
|
|
||||||
|
</mapper>
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||||
|
<mapper namespace="org.jeecg.modules.base.mapper.WeatherTaskLogMapper">
|
||||||
|
|
||||||
|
</mapper>
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||||
|
<mapper namespace="org.jeecg.modules.base.mapper.WeatherTaskMapper">
|
||||||
|
|
||||||
|
</mapper>
|
||||||
|
|
@ -3,10 +3,6 @@ package org.jeecg.modules.base.service;
|
||||||
import org.jeecg.common.api.dto.LogDTO;
|
import org.jeecg.common.api.dto.LogDTO;
|
||||||
import org.jeecg.common.system.vo.LoginUser;
|
import org.jeecg.common.system.vo.LoginUser;
|
||||||
|
|
||||||
/**
|
|
||||||
* common接口
|
|
||||||
* @author: jeecg-boot
|
|
||||||
*/
|
|
||||||
public interface BaseCommonService {
|
public interface BaseCommonService {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -18,10 +18,6 @@ import jakarta.annotation.Resource;
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
/**
|
|
||||||
* @Description: common实现类
|
|
||||||
* @author: jeecg-boot
|
|
||||||
*/
|
|
||||||
@Service
|
@Service
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class BaseCommonServiceImpl implements BaseCommonService {
|
public class BaseCommonServiceImpl implements BaseCommonService {
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ import org.jeecg.common.constant.enums.EmailTemplateEnum;
|
||||||
import org.jeecg.common.desensitization.annotation.SensitiveDecode;
|
import org.jeecg.common.desensitization.annotation.SensitiveDecode;
|
||||||
import org.jeecg.common.system.api.factory.SysBaseAPIFallbackFactory;
|
import org.jeecg.common.system.api.factory.SysBaseAPIFallbackFactory;
|
||||||
import org.jeecg.common.system.vo.*;
|
import org.jeecg.common.system.vo.*;
|
||||||
|
import org.jeecg.config.FeignConfig;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
|
||||||
import org.springframework.cloud.openfeign.FeignClient;
|
import org.springframework.cloud.openfeign.FeignClient;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
@ -29,7 +30,7 @@ import java.util.Set;
|
||||||
* @author: jeecg-boot
|
* @author: jeecg-boot
|
||||||
*/
|
*/
|
||||||
@Component
|
@Component
|
||||||
@FeignClient(contextId = "sysBaseRemoteApi", value = ServiceNameConstants.SERVICE_SYSTEM, fallbackFactory = SysBaseAPIFallbackFactory.class)
|
@FeignClient(contextId = "sysBaseRemoteApi", value = ServiceNameConstants.SERVICE_SYSTEM, fallbackFactory = SysBaseAPIFallbackFactory.class,configuration = FeignConfig.class)
|
||||||
@ConditionalOnMissingClass("org.jeecg.modules.system.service.impl.SysBaseApiImpl")
|
@ConditionalOnMissingClass("org.jeecg.modules.system.service.impl.SysBaseApiImpl")
|
||||||
public interface ISysBaseAPI extends CommonAPI {
|
public interface ISysBaseAPI extends CommonAPI {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,180 +1,52 @@
|
||||||
//package org.jeecg.config;
|
package org.jeecg.config;
|
||||||
//
|
|
||||||
//import java.io.IOException;
|
import feign.Feign;
|
||||||
//import java.util.ArrayList;
|
import feign.RequestTemplate;
|
||||||
//import java.util.Arrays;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
//import java.util.List;
|
import org.apache.http.HttpHeaders;
|
||||||
//import java.util.SortedMap;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||||
//
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||||
//import jakarta.servlet.http.HttpServletRequest;
|
import org.springframework.context.annotation.Bean;
|
||||||
//
|
import org.springframework.context.annotation.Configuration;
|
||||||
//import org.jeecg.common.config.mqtoken.UserTokenContext;
|
import org.springframework.web.context.request.RequestContextHolder;
|
||||||
//import org.jeecg.common.constant.CommonConstant;
|
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||||
//import org.jeecg.common.util.DateUtils;
|
import feign.Logger;
|
||||||
//import org.jeecg.common.util.PathMatcherUtil;
|
import feign.RequestInterceptor;
|
||||||
//import org.jeecg.config.sign.interceptor.SignAuthConfiguration;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
//import org.jeecg.config.sign.util.HttpUtils;
|
|
||||||
//import org.jeecg.config.sign.util.SignUtil;
|
@Slf4j
|
||||||
//import org.springframework.beans.factory.ObjectFactory;
|
@Configuration
|
||||||
//import org.springframework.boot.autoconfigure.AutoConfigureBefore;
|
public class FeignConfig implements RequestInterceptor{
|
||||||
//import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
|
||||||
//import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
|
/**
|
||||||
//import org.springframework.cloud.openfeign.FeignAutoConfiguration;
|
* @param requestTemplate
|
||||||
//import org.springframework.cloud.openfeign.support.SpringDecoder;
|
*/
|
||||||
//import org.springframework.cloud.openfeign.support.SpringEncoder;
|
@Override
|
||||||
//import org.springframework.context.annotation.Bean;
|
public void apply(RequestTemplate requestTemplate) {
|
||||||
//import org.springframework.context.annotation.Configuration;
|
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
|
||||||
//import org.springframework.context.annotation.Primary;
|
HttpServletRequest request = attributes.getRequest();
|
||||||
//import org.springframework.context.annotation.Scope;
|
requestTemplate.header("Authorization", request.getHeader("Authorization"));
|
||||||
//import org.springframework.http.MediaType;
|
}
|
||||||
//import org.springframework.web.context.request.RequestContextHolder;
|
|
||||||
//import org.springframework.web.context.request.ServletRequestAttributes;
|
|
||||||
//
|
|
||||||
//import com.alibaba.fastjson.JSON;
|
|
||||||
//import com.alibaba.fastjson.serializer.SerializerFeature;
|
|
||||||
//import com.alibaba.fastjson.support.config.FastJsonConfig;
|
|
||||||
//import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
|
|
||||||
//import com.alibaba.fastjson.support.springfox.SwaggerJsonSerializer;
|
|
||||||
//
|
|
||||||
//import feign.Feign;
|
|
||||||
//import feign.Logger;
|
|
||||||
//import feign.RequestInterceptor;
|
|
||||||
//import feign.codec.Decoder;
|
|
||||||
//import feign.codec.Encoder;
|
|
||||||
//import feign.form.spring.SpringFormEncoder;
|
|
||||||
//import lombok.extern.slf4j.Slf4j;
|
|
||||||
//
|
|
||||||
///**
|
|
||||||
// * @Description: FeignConfig
|
|
||||||
// * @author: JeecgBoot
|
|
||||||
// */
|
|
||||||
//@ConditionalOnClass(Feign.class)
|
|
||||||
//@AutoConfigureBefore(FeignAutoConfiguration.class)
|
|
||||||
//@Slf4j
|
|
||||||
//@Configuration
|
|
||||||
//public class FeignConfig {
|
|
||||||
//
|
|
||||||
// /**
|
// /**
|
||||||
// * 设置feign header参数
|
// * 设置feign header参数
|
||||||
// * 【X_ACCESS_TOKEN】【X_SIGN】【X_TIMESTAMP】
|
// * 【X_ACCESS_TOKEN】【X_SIGN】【X_TIMESTAMP】
|
||||||
// * @return
|
// * @return
|
||||||
// */
|
// */
|
||||||
// @Bean
|
// @Bean
|
||||||
|
// @ConditionalOnMissingBean(RequestInterceptor.class)
|
||||||
// public RequestInterceptor requestInterceptor() {
|
// public RequestInterceptor requestInterceptor() {
|
||||||
// return requestTemplate -> {
|
// return template -> {
|
||||||
// ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
|
// ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
|
||||||
// if (null != attributes) {
|
// if (attributes != null) {
|
||||||
// HttpServletRequest request = attributes.getRequest();
|
// HttpServletRequest request = attributes.getRequest();
|
||||||
// log.debug("Feign request: {}", request.getRequestURI());
|
// log.debug("Feign request: {}", request.getRequestURI());
|
||||||
// // 将token信息放入header中
|
// // 将token信息放入header中
|
||||||
// String token = request.getHeader(CommonConstant.X_ACCESS_TOKEN);
|
// String token = request.getHeader(HttpHeaders.AUTHORIZATION);
|
||||||
// if(token==null || "".equals(token)){
|
|
||||||
// token = request.getParameter("token");
|
|
||||||
// }
|
|
||||||
// log.info("Feign Login Request token: {}", token);
|
// log.info("Feign Login Request token: {}", token);
|
||||||
// requestTemplate.header(CommonConstant.X_ACCESS_TOKEN, token);
|
// template.header(HttpHeaders.AUTHORIZATION, token);
|
||||||
// }else{
|
|
||||||
// //解决后台任务、MQ中调用feign接口,无会话token的问题
|
|
||||||
// String token = UserTokenContext.getToken();
|
|
||||||
// log.info("Feign No Login token: {}", token);
|
|
||||||
// requestTemplate.header(CommonConstant.X_ACCESS_TOKEN, token);
|
|
||||||
// }
|
// }
|
||||||
//
|
|
||||||
// //================================================================================================================
|
|
||||||
// //针对特殊接口,进行加签验证 ——根据URL地址过滤请求 【字典表参数签名验证】
|
|
||||||
// if (PathMatcherUtil.matches(Arrays.asList(SignAuthConfiguration.SIGN_URL_LIST),requestTemplate.path())) {
|
|
||||||
// try {
|
|
||||||
// log.info("============================ [begin] fegin api url ============================");
|
|
||||||
// log.info(requestTemplate.path());
|
|
||||||
// log.info(requestTemplate.method());
|
|
||||||
// String queryLine = requestTemplate.queryLine();
|
|
||||||
// String questionMark="?";
|
|
||||||
// if(queryLine!=null && queryLine.startsWith(questionMark)){
|
|
||||||
// queryLine = queryLine.substring(1);
|
|
||||||
// }
|
|
||||||
// log.info(queryLine);
|
|
||||||
// if(requestTemplate.body()!=null){
|
|
||||||
// log.info(new String(requestTemplate.body()));
|
|
||||||
// }
|
|
||||||
// SortedMap<String, String> allParams = HttpUtils.getAllParams(requestTemplate.path(),queryLine,requestTemplate.body(),requestTemplate.method());
|
|
||||||
// String sign = SignUtil.getParamsSign(allParams);
|
|
||||||
// log.info(" Feign request params sign: {}",sign);
|
|
||||||
// log.info("============================ [end] fegin api url ============================");
|
|
||||||
// requestTemplate.header(CommonConstant.X_SIGN, sign);
|
|
||||||
// requestTemplate.header(CommonConstant.X_TIMESTAMP, String.valueOf(System.currentTimeMillis()));
|
|
||||||
// } catch (IOException e) {
|
|
||||||
// e.printStackTrace();
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// //================================================================================================================
|
|
||||||
// };
|
// };
|
||||||
// }
|
// }
|
||||||
//
|
|
||||||
//
|
}
|
||||||
//
|
|
||||||
// /**
|
|
||||||
// * Feign 客户端的日志记录,默认级别为NONE
|
|
||||||
// * Logger.Level 的具体级别如下:
|
|
||||||
// * NONE:不记录任何信息
|
|
||||||
// * BASIC:仅记录请求方法、URL以及响应状态码和执行时间
|
|
||||||
// * HEADERS:除了记录 BASIC级别的信息外,还会记录请求和响应的头信息
|
|
||||||
// * FULL:记录所有请求与响应的明细,包括头信息、请求体、元数据
|
|
||||||
// */
|
|
||||||
// @Bean
|
|
||||||
// Logger.Level feignLoggerLevel() {
|
|
||||||
// return Logger.Level.FULL;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// /**
|
|
||||||
// * Feign支持文件上传
|
|
||||||
// * @param messageConverters
|
|
||||||
// * @return
|
|
||||||
// */
|
|
||||||
// @Bean
|
|
||||||
// @Primary
|
|
||||||
// @Scope("prototype")
|
|
||||||
// public Encoder multipartFormEncoder(ObjectFactory<HttpMessageConverters> messageConverters) {
|
|
||||||
// return new SpringFormEncoder(new SpringEncoder(messageConverters));
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// // update-begin--Author:sunjianlei Date:20210604 for: 给 Feign 添加 FastJson 的解析支持 ----------
|
|
||||||
// /**
|
|
||||||
// * 给 Feign 添加 FastJson 的解析支持
|
|
||||||
// */
|
|
||||||
// @Bean
|
|
||||||
// public Encoder feignEncoder() {
|
|
||||||
// return new SpringEncoder(feignHttpMessageConverter());
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// @Bean("apiFeignDecoder")
|
|
||||||
// public Decoder feignDecoder() {
|
|
||||||
// return new SpringDecoder(feignHttpMessageConverter());
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// /**
|
|
||||||
// * 设置解码器为fastjson
|
|
||||||
// *
|
|
||||||
// * @return
|
|
||||||
// */
|
|
||||||
// private ObjectFactory<HttpMessageConverters> feignHttpMessageConverter() {
|
|
||||||
// final HttpMessageConverters httpMessageConverters = new HttpMessageConverters(this.getFastJsonConverter());
|
|
||||||
// return () -> httpMessageConverters;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// private FastJsonHttpMessageConverter getFastJsonConverter() {
|
|
||||||
// FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();
|
|
||||||
//
|
|
||||||
// List<MediaType> supportedMediaTypes = new ArrayList<>();
|
|
||||||
// MediaType mediaTypeJson = MediaType.valueOf(MediaType.APPLICATION_JSON_VALUE);
|
|
||||||
// supportedMediaTypes.add(mediaTypeJson);
|
|
||||||
// converter.setSupportedMediaTypes(supportedMediaTypes);
|
|
||||||
// FastJsonConfig config = new FastJsonConfig();
|
|
||||||
// config.getSerializeConfig().put(JSON.class, new SwaggerJsonSerializer());
|
|
||||||
// config.setSerializerFeatures(SerializerFeature.DisableCircularReferenceDetect);
|
|
||||||
// converter.setFastJsonConfig(config);
|
|
||||||
//
|
|
||||||
// return converter;
|
|
||||||
// }
|
|
||||||
// // update-end--Author:sunjianlei Date:20210604 for: 给 Feign 添加 FastJson 的解析支持 ----------
|
|
||||||
//
|
|
||||||
//}
|
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jeecgframework.boot</groupId>
|
<groupId>org.jeecgframework.boot</groupId>
|
||||||
<artifactId>jeecg-boot-base-core</artifactId>
|
<artifactId>jeecg-boot-base-core</artifactId>
|
||||||
|
<version>${jeecgboot.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</project>
|
</project>
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jeecgframework.boot</groupId>
|
<groupId>org.jeecgframework.boot</groupId>
|
||||||
<artifactId>jeecg-system-local-api</artifactId>
|
<artifactId>jeecg-system-local-api</artifactId>
|
||||||
<version>3.8.1</version>
|
<version>${jeecgboot.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.hibernate</groupId>
|
<groupId>org.hibernate</groupId>
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,11 @@
|
||||||
package org.jeecg.modules.message.entity;
|
package org.jeecg.modules.message.entity;
|
||||||
|
|
||||||
import org.jeecg.common.aspect.annotation.Dict;
|
import org.jeecg.common.aspect.annotation.Dict;
|
||||||
import org.jeecg.common.system.base.entity.JeecgEntity;
|
import org.jeecg.common.system.base.entity.BaseEntity;
|
||||||
import org.jeecgframework.poi.excel.annotation.Excel;
|
import org.jeecgframework.poi.excel.annotation.Excel;
|
||||||
import org.springframework.format.annotation.DateTimeFormat;
|
import org.springframework.format.annotation.DateTimeFormat;
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.annotation.TableName;
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.experimental.Accessors;
|
import lombok.experimental.Accessors;
|
||||||
|
|
@ -22,7 +20,7 @@ import lombok.experimental.Accessors;
|
||||||
@EqualsAndHashCode(callSuper = false)
|
@EqualsAndHashCode(callSuper = false)
|
||||||
@Accessors(chain = true)
|
@Accessors(chain = true)
|
||||||
@TableName("sys_sms")
|
@TableName("sys_sms")
|
||||||
public class SysMessage extends JeecgEntity {
|
public class SysMessage extends BaseEntity {
|
||||||
/**推送内容*/
|
/**推送内容*/
|
||||||
@Excel(name = "推送内容", width = 15)
|
@Excel(name = "推送内容", width = 15)
|
||||||
private java.lang.String esContent;
|
private java.lang.String esContent;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
package org.jeecg.modules.message.entity;
|
package org.jeecg.modules.message.entity;
|
||||||
|
|
||||||
import org.jeecg.common.system.base.entity.JeecgEntity;
|
import org.jeecg.common.system.base.entity.BaseEntity;
|
||||||
import org.jeecgframework.poi.excel.annotation.Excel;
|
import org.jeecgframework.poi.excel.annotation.Excel;
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.annotation.TableName;
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
|
@ -19,7 +19,7 @@ import lombok.experimental.Accessors;
|
||||||
@EqualsAndHashCode(callSuper = false)
|
@EqualsAndHashCode(callSuper = false)
|
||||||
@Accessors(chain = true)
|
@Accessors(chain = true)
|
||||||
@TableName("sys_sms_template")
|
@TableName("sys_sms_template")
|
||||||
public class SysMessageTemplate extends JeecgEntity{
|
public class SysMessageTemplate extends BaseEntity{
|
||||||
/**模板CODE*/
|
/**模板CODE*/
|
||||||
@Excel(name = "模板CODE", width = 15)
|
@Excel(name = "模板CODE", width = 15)
|
||||||
private java.lang.String templateCode;
|
private java.lang.String templateCode;
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.experimental.Accessors;
|
import lombok.experimental.Accessors;
|
||||||
import org.jeecg.common.system.base.entity.JeecgEntity;
|
import org.jeecg.common.system.base.entity.BaseEntity;
|
||||||
import org.jeecgframework.poi.excel.annotation.Excel;
|
import org.jeecgframework.poi.excel.annotation.Excel;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -15,7 +15,7 @@ import org.jeecgframework.poi.excel.annotation.Excel;
|
||||||
@TableName("oss_file")
|
@TableName("oss_file")
|
||||||
@EqualsAndHashCode(callSuper = false)
|
@EqualsAndHashCode(callSuper = false)
|
||||||
@Accessors(chain = true)
|
@Accessors(chain = true)
|
||||||
public class OssFile extends JeecgEntity {
|
public class OssFile extends BaseEntity {
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
|
|
||||||
27
jeecg-module-weather/pom.xml
Normal file
27
jeecg-module-weather/pom.xml
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<parent>
|
||||||
|
<groupId>org.jeecgframework.boot</groupId>
|
||||||
|
<artifactId>jeecg-boot-parent</artifactId>
|
||||||
|
<version>3.8.1</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<artifactId>jeecg-module-weather</artifactId>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<maven.compiler.source>17</maven.compiler.source>
|
||||||
|
<maven.compiler.target>17</maven.compiler.target>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jeecgframework.boot</groupId>
|
||||||
|
<artifactId>jeecg-boot-base-core</artifactId>
|
||||||
|
<version>${jeecgboot.version}</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</project>
|
||||||
|
|
@ -0,0 +1,87 @@
|
||||||
|
package org.jeecg.controller;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import jakarta.validation.constraints.NotBlank;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.apache.commons.codec.digest.DigestUtils;
|
||||||
|
import org.jeecg.common.api.vo.Result;
|
||||||
|
import org.jeecg.common.aspect.annotation.AutoLog;
|
||||||
|
import org.jeecg.common.constant.enums.WeatherFileSuffixEnum;
|
||||||
|
import org.jeecg.service.WeatherDataService;
|
||||||
|
import org.jeecg.vo.FileExistVo;
|
||||||
|
import org.jeecg.vo.FileUploadResultVo;
|
||||||
|
import org.jeecg.vo.FileVo;
|
||||||
|
import org.jeecg.vo.WeatherResultVO;
|
||||||
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Validated
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("weatherData")
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class WeatherDataController {
|
||||||
|
|
||||||
|
private final WeatherDataService weatherDataService;
|
||||||
|
|
||||||
|
|
||||||
|
@AutoLog(value = "验证文件是否存在")
|
||||||
|
@Operation(summary = "验证文件是否存在")
|
||||||
|
@GetMapping("verifyFileExist")
|
||||||
|
public FileExistVo verifyFileExist(@NotBlank(message = "文件MD5值不能为空") String fileMD5Value) {
|
||||||
|
FileExistVo fileExist = weatherDataService.verifyFileExist(fileMD5Value);
|
||||||
|
return fileExist;
|
||||||
|
}
|
||||||
|
|
||||||
|
@AutoLog(value = "上传文件")
|
||||||
|
@Operation(summary = "上传文件")
|
||||||
|
@PostMapping("uploadFile")
|
||||||
|
public FileUploadResultVo uploadFile(FileVo fileVo){
|
||||||
|
if (!fileVo.getFileExt().equals(WeatherFileSuffixEnum.GRIB.getValue()) && !fileVo.getFileExt().equals(WeatherFileSuffixEnum.GRIB2.getValue())){
|
||||||
|
throw new RuntimeException("不支持当前上传的文件类型!");
|
||||||
|
}
|
||||||
|
FileUploadResultVo resultVo = weatherDataService.uploadFile(fileVo);
|
||||||
|
return resultVo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 气象预测
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@AutoLog(value = "气象预测-气象数据查询")
|
||||||
|
@Operation(summary = "气象预测-气象数据查询")
|
||||||
|
@GetMapping(value = "getWeatherData")
|
||||||
|
public Result<WeatherResultVO> getWeatherData(Integer type,
|
||||||
|
LocalDateTime startTime,
|
||||||
|
int hour) {
|
||||||
|
return Result.OK(weatherDataService.getWeatherData(type,startTime,hour));
|
||||||
|
}
|
||||||
|
|
||||||
|
@AutoLog(value = "删除气象数据")
|
||||||
|
@Operation(summary = "删除气象数据")
|
||||||
|
@DeleteMapping("delete")
|
||||||
|
public Result<?> delete(@RequestBody List<String> ids){
|
||||||
|
weatherDataService.delete(ids);
|
||||||
|
return Result.OK();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String calculateMD5(String filePath) throws IOException {
|
||||||
|
try (InputStream is = new FileInputStream(filePath)) {
|
||||||
|
return DigestUtils.md5Hex(is);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
try {
|
||||||
|
String md5 = calculateMD5("F:\\工作\\五木\\放射性核素监测数据综合分析及氙本底源解析系统\\其他资料\\气象数据\\中国CRA40再分析数据\\CRA40\\20250523\\CRA40_AVO_2025052300_GLB_0P25_HOUR_V1_0_0.grib2");
|
||||||
|
System.out.println("MD5: " + md5);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,73 @@
|
||||||
|
package org.jeecg.controller;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import jakarta.validation.constraints.NotBlank;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.jeecg.common.api.vo.Result;
|
||||||
|
import org.jeecg.common.aspect.annotation.AutoLog;
|
||||||
|
import org.jeecg.common.system.query.PageRequest;
|
||||||
|
import org.jeecg.common.validgroup.InsertGroup;
|
||||||
|
import org.jeecg.common.validgroup.UpdateGroup;
|
||||||
|
import org.jeecg.modules.base.entity.WeatherTask;
|
||||||
|
import org.jeecg.service.WeatherTaskService;
|
||||||
|
import org.springframework.format.annotation.DateTimeFormat;
|
||||||
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@Validated
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("weatherTask")
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class WeatherTaskController {
|
||||||
|
|
||||||
|
private final WeatherTaskService weatherTaskService;
|
||||||
|
|
||||||
|
@AutoLog(value = "查询天气预测任务列表")
|
||||||
|
@Operation(summary = "查询天气预测任务列表")
|
||||||
|
@GetMapping(value = "page")
|
||||||
|
public Result<?> page(PageRequest pageRequest, String taskName, Integer taskStatus,
|
||||||
|
@DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate startDate,
|
||||||
|
@DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate endDate) {
|
||||||
|
IPage<WeatherTask> page = weatherTaskService.page(pageRequest, taskName, taskStatus, startDate,endDate);
|
||||||
|
Map<String, Object> rspData = new HashMap<>();
|
||||||
|
rspData.put("rows", page.getRecords());
|
||||||
|
rspData.put("total", page.getTotal());
|
||||||
|
return Result.OK(rspData);
|
||||||
|
}
|
||||||
|
|
||||||
|
@AutoLog(value = "新增天气预测任务")
|
||||||
|
@Operation(summary = "新增天气预测任务")
|
||||||
|
@PostMapping("create")
|
||||||
|
public Result<?> create(@RequestBody @Validated(value = InsertGroup.class) WeatherTask weatherTask){
|
||||||
|
weatherTaskService.cteate(weatherTask);
|
||||||
|
return Result.OK();
|
||||||
|
}
|
||||||
|
|
||||||
|
@AutoLog(value = "修改天气预测任务")
|
||||||
|
@Operation(summary = "修改天气预测任务")
|
||||||
|
@PutMapping("update")
|
||||||
|
public Result<?> update(@RequestBody @Validated(value = UpdateGroup.class) WeatherTask weatherTask){
|
||||||
|
weatherTaskService.update(weatherTask);
|
||||||
|
return Result.OK();
|
||||||
|
}
|
||||||
|
|
||||||
|
@AutoLog(value = "删除天气预测任务")
|
||||||
|
@Operation(summary = "删除天气预测任务")
|
||||||
|
@DeleteMapping("delete")
|
||||||
|
public Result<?> delete(@RequestBody List<String> ids){
|
||||||
|
weatherTaskService.delete(ids);
|
||||||
|
return Result.OK();
|
||||||
|
}
|
||||||
|
|
||||||
|
@AutoLog(value = "获取天气预测任务过程日志")
|
||||||
|
@Operation(summary = "获取天气预测任务过程日志")
|
||||||
|
@GetMapping("getTaskLog")
|
||||||
|
public Result<?> getTaskLog(@NotBlank(message = "预测任务ID不能为空") String taskId){
|
||||||
|
return Result.OK(weatherTaskService.getTaskLog(taskId));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,48 @@
|
||||||
|
package org.jeecg.service;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||||
|
import org.jeecg.common.system.query.PageRequest;
|
||||||
|
import org.jeecg.modules.base.entity.WeatherData;
|
||||||
|
import org.jeecg.vo.FileExistVo;
|
||||||
|
import org.jeecg.vo.FileUploadResultVo;
|
||||||
|
import org.jeecg.vo.FileVo;
|
||||||
|
import org.jeecg.vo.WeatherResultVO;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public interface WeatherDataService {
|
||||||
|
|
||||||
|
WeatherResultVO getWeatherData(Integer type, LocalDateTime startTime, int hour);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页查询气象数据
|
||||||
|
* @param pageRequest
|
||||||
|
* @param fileExt
|
||||||
|
* @param dataSource
|
||||||
|
* @param startTime
|
||||||
|
* @param endTime
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
IPage<WeatherData> page(PageRequest pageRequest,String fileExt,Integer dataSource,LocalDateTime startTime,LocalDateTime endTime);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验证文件是否存在
|
||||||
|
* @param fileMD5Value 文件唯一MD5值
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
FileExistVo verifyFileExist(String fileMD5Value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 上传文件
|
||||||
|
* @param fileVo
|
||||||
|
*/
|
||||||
|
FileUploadResultVo uploadFile(FileVo fileVo);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除气象数据
|
||||||
|
* @param ids
|
||||||
|
*/
|
||||||
|
void delete(List<String> ids);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,58 @@
|
||||||
|
package org.jeecg.service;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
import org.jeecg.common.system.query.PageRequest;
|
||||||
|
import org.jeecg.modules.base.entity.WeatherTask;
|
||||||
|
import org.jeecg.modules.base.entity.WeatherTaskLog;
|
||||||
|
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 天气预报预测任务管理
|
||||||
|
*/
|
||||||
|
public interface WeatherTaskService extends IService<WeatherTask> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页查询任务列表
|
||||||
|
* @param pageRequest
|
||||||
|
* @param taskName
|
||||||
|
* @param taskStatus
|
||||||
|
* @param startDate
|
||||||
|
* @param endDate
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
IPage<WeatherTask> page(PageRequest pageRequest,String taskName,Integer taskStatus,LocalDate startDate,LocalDate endDate);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建天气预报预测任务
|
||||||
|
* @param weatherTask
|
||||||
|
*/
|
||||||
|
void cteate(WeatherTask weatherTask);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改天气预报预测任务
|
||||||
|
* @param weatherTask
|
||||||
|
*/
|
||||||
|
void update(WeatherTask weatherTask);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除预测任务
|
||||||
|
* @param ids
|
||||||
|
*/
|
||||||
|
void delete(List<String> ids);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 运行任务
|
||||||
|
* @param id
|
||||||
|
*/
|
||||||
|
void runTask(Integer id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取任务运行日志
|
||||||
|
* @param taskId
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
List<WeatherTaskLog> getTaskLog(String taskId);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,459 @@
|
||||||
|
package org.jeecg.service.impl;
|
||||||
|
|
||||||
|
import cn.hutool.core.io.FileUtil;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||||
|
import com.baomidou.mybatisplus.core.toolkit.StringPool;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import lombok.val;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.jeecg.common.constant.enums.WeatherDataSourceEnum;
|
||||||
|
import org.jeecg.common.constant.enums.WeatherTypeEnum;
|
||||||
|
import org.jeecg.common.exception.JeecgBootException;
|
||||||
|
import org.jeecg.common.properties.SystemStorageProperties;
|
||||||
|
import org.jeecg.common.system.query.PageRequest;
|
||||||
|
import org.jeecg.common.util.NcUtil;
|
||||||
|
import org.jeecg.modules.base.entity.WeatherData;
|
||||||
|
import org.jeecg.modules.base.mapper.WeatherDataMapper;
|
||||||
|
import org.jeecg.service.WeatherDataService;
|
||||||
|
import org.jeecg.vo.FileExistVo;
|
||||||
|
import org.jeecg.vo.FileUploadResultVo;
|
||||||
|
import org.jeecg.vo.FileVo;
|
||||||
|
import org.jeecg.vo.WeatherResultVO;
|
||||||
|
import org.springframework.beans.BeanUtils;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
import ucar.nc2.NetcdfFile;
|
||||||
|
import java.io.*;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.math.RoundingMode;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class WeatherDataServiceImpl extends ServiceImpl<WeatherDataMapper, WeatherData> implements WeatherDataService {
|
||||||
|
|
||||||
|
private final SystemStorageProperties systemStorageProperties;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据类型和小时数获取天气数据
|
||||||
|
* @param type 天气类型
|
||||||
|
* @param startTime 开始时间
|
||||||
|
* @param hour 小时数
|
||||||
|
* @return 天气数据列表
|
||||||
|
*/
|
||||||
|
public WeatherResultVO getWeatherData(Integer type, LocalDateTime startTime, int hour) {
|
||||||
|
|
||||||
|
// 参数校验
|
||||||
|
try {
|
||||||
|
Objects.requireNonNull(type, "天气类型不能为空");
|
||||||
|
Objects.requireNonNull(startTime, "开始时间不能为空");
|
||||||
|
if (hour <= 0) {
|
||||||
|
throw new IllegalArgumentException("小时数必须大于0");
|
||||||
|
}
|
||||||
|
} catch (NullPointerException | IllegalArgumentException e) {
|
||||||
|
log.error("参数校验失败: type={}, startTime={}, hour={}", type, startTime, hour, e);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 文件处理
|
||||||
|
String filePath;
|
||||||
|
try {
|
||||||
|
filePath = buildFilePath(startTime, hour, type);
|
||||||
|
if (!isFileValid(filePath)) {
|
||||||
|
log.warn("文件无效或不存在: {}", filePath);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("文件路径构建失败: type={}, hour={}", type, hour, e);
|
||||||
|
throw new JeecgBootException("文件路径处理失败", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
WeatherResultVO weatherResultVO = new WeatherResultVO();
|
||||||
|
try (NetcdfFile ncFile = NetcdfFile.open(filePath)) {
|
||||||
|
// 基础数据获取
|
||||||
|
List<Double> lonData = NcUtil.getNCList(ncFile, "lon");
|
||||||
|
List<Double> latData = NcUtil.getNCList(ncFile, "lat");
|
||||||
|
|
||||||
|
if (lonData == null || lonData.isEmpty() || latData == null || latData.isEmpty()) {
|
||||||
|
log.error("经纬度数据为空: file={}", filePath);
|
||||||
|
throw new JeecgBootException("基础经纬度数据缺失");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 按类型处理数据
|
||||||
|
List<List<Double>> dataList = new ArrayList<>();
|
||||||
|
try {
|
||||||
|
if (WeatherTypeEnum.WIND.getKey().equals(type)) {
|
||||||
|
getWindData(ncFile, weatherResultVO);
|
||||||
|
return weatherResultVO;
|
||||||
|
} else if (WeatherTypeEnum.TEMPERATURE.getKey().equals(type)) {
|
||||||
|
dataList = processTemperatureData(ncFile, lonData, latData);
|
||||||
|
} else if (WeatherTypeEnum.PRESSURE.getKey().equals(type)) {
|
||||||
|
dataList = processPressureData(ncFile, lonData, latData);
|
||||||
|
} else if (WeatherTypeEnum.HUMIDITY.getKey().equals(type)) {
|
||||||
|
dataList = processHumidityData(ncFile, lonData, latData);
|
||||||
|
} else {
|
||||||
|
throw new JeecgBootException("未知天气类型!");
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("天气数据处理失败: type={}", type, e);
|
||||||
|
throw new JeecgBootException("天气数据处理异常", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 结果处理
|
||||||
|
try {
|
||||||
|
List<Double> flattenedList = new ArrayList<>();
|
||||||
|
flattenList(dataList, flattenedList);
|
||||||
|
List<Double> maxMin = getMaxMin(flattenedList);
|
||||||
|
|
||||||
|
weatherResultVO.setMax(maxMin.get(0));
|
||||||
|
weatherResultVO.setMin(maxMin.get(1));
|
||||||
|
weatherResultVO.setSn(latData.size());
|
||||||
|
weatherResultVO.setWe(lonData.size());
|
||||||
|
weatherResultVO.setDataList(dataList);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("结果数据处理失败", e);
|
||||||
|
throw new JeecgBootException("结果数据处理异常", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("NetCDF文件处理失败: {}", filePath, e);
|
||||||
|
throw new JeecgBootException("文件读取失败", e);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("未知处理错误", e);
|
||||||
|
throw new JeecgBootException("未知处理错误", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return weatherResultVO;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页查询气象数据
|
||||||
|
*
|
||||||
|
* @param pageRequest
|
||||||
|
* @param fileExt
|
||||||
|
* @param dataSource
|
||||||
|
* @param startTime
|
||||||
|
* @param endTime
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public IPage<WeatherData> page(PageRequest pageRequest, String fileExt, Integer dataSource, LocalDateTime startTime, LocalDateTime endTime) {
|
||||||
|
LambdaQueryWrapper<WeatherData> queryWrapper = new LambdaQueryWrapper<>();
|
||||||
|
queryWrapper.eq(Objects.nonNull(dataSource),WeatherData::getDataSource, dataSource);
|
||||||
|
queryWrapper.between((Objects.nonNull(startTime) && Objects.nonNull(endTime)),WeatherData::getDataStartTime,startTime,endTime);
|
||||||
|
queryWrapper.eq(StringUtils.isNotBlank(fileExt),WeatherData::getFileExt, fileExt);
|
||||||
|
|
||||||
|
IPage<WeatherData> iPage = new Page<>(pageRequest.getPageNum(),pageRequest.getPageSize());
|
||||||
|
return this.baseMapper.selectPage(iPage, queryWrapper);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验证文件是否存在
|
||||||
|
*
|
||||||
|
* @param fileMD5Value 文件唯一MD5值
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public FileExistVo verifyFileExist(String fileMD5Value) {
|
||||||
|
LambdaQueryWrapper<WeatherData> wrapper = new LambdaQueryWrapper<>();
|
||||||
|
wrapper.eq(WeatherData::getMd5Value, fileMD5Value);
|
||||||
|
|
||||||
|
FileExistVo fileExist = new FileExistVo();
|
||||||
|
WeatherData weatherData = this.baseMapper.selectOne(wrapper);
|
||||||
|
if(Objects.nonNull(weatherData)) {
|
||||||
|
fileExist.setExist(true);
|
||||||
|
fileExist.setFileId(weatherData.getId());
|
||||||
|
fileExist.setShareTotal(weatherData.getShareTotal());
|
||||||
|
fileExist.setShareIndex(weatherData.getShareIndex());
|
||||||
|
}
|
||||||
|
return fileExist;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 上传文件
|
||||||
|
*
|
||||||
|
* @param fileVo
|
||||||
|
*/
|
||||||
|
@Transactional(rollbackFor = RuntimeException.class)
|
||||||
|
@Override
|
||||||
|
public FileUploadResultVo uploadFile(FileVo fileVo) {
|
||||||
|
try{
|
||||||
|
MultipartFile file = fileVo.getFile();
|
||||||
|
//文件保存路径
|
||||||
|
String storagePath = this.getFileStoragePath(fileVo.getDataSource(), fileVo.getFileName());
|
||||||
|
fileVo.setFilePath(storagePath);
|
||||||
|
|
||||||
|
//如果上传策略是分片则加分片后缀
|
||||||
|
if(fileVo.isFileShare()) {
|
||||||
|
storagePath += StringPool.DOT;
|
||||||
|
storagePath += fileVo.getShareIndex();
|
||||||
|
}
|
||||||
|
//保存文件
|
||||||
|
File shareFile = new File(storagePath.toString());
|
||||||
|
if(!shareFile.getParentFile().exists()) {
|
||||||
|
shareFile.getParentFile().setWritable(true);
|
||||||
|
shareFile.getParentFile().mkdirs();
|
||||||
|
}
|
||||||
|
file.transferTo(shareFile);
|
||||||
|
|
||||||
|
//保存文件信息入库
|
||||||
|
String id= null;
|
||||||
|
FileExistVo fileExist = this.verifyFileExist(fileVo.getMd5Value());
|
||||||
|
if(fileExist.isExist()) {
|
||||||
|
WeatherData queryResult = this.baseMapper.selectById(fileExist.getFileId());
|
||||||
|
queryResult.setShareIndex(fileVo.getShareIndex());
|
||||||
|
this.baseMapper.updateById(queryResult);
|
||||||
|
id = queryResult.getId();
|
||||||
|
}else {
|
||||||
|
WeatherData weatherData = new WeatherData();
|
||||||
|
BeanUtils.copyProperties(fileVo, weatherData);
|
||||||
|
this.baseMapper.insert(weatherData);
|
||||||
|
id = weatherData.getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean flag = false;
|
||||||
|
if(fileVo.isFileShare()) {
|
||||||
|
if(fileVo.getShareIndex() == (fileVo.getShareTotal()-1)) {
|
||||||
|
this.merge(fileVo);
|
||||||
|
flag = true;
|
||||||
|
}
|
||||||
|
}else {
|
||||||
|
flag = true;
|
||||||
|
}
|
||||||
|
//获取文件数据开始日期
|
||||||
|
//计算文件大小M
|
||||||
|
WeatherData queryResult = this.baseMapper.selectById(id);
|
||||||
|
File dataFile = new File(storagePath);
|
||||||
|
if(dataFile.exists() && dataFile.length()>0){
|
||||||
|
BigDecimal divideVal = new BigDecimal("1024");
|
||||||
|
BigDecimal bg = new BigDecimal(dataFile.length());
|
||||||
|
BigDecimal fileSize = bg.divide(divideVal).divide(divideVal).setScale(2, RoundingMode.HALF_UP);
|
||||||
|
queryResult.setFileSize(fileSize.doubleValue());
|
||||||
|
|
||||||
|
this.baseMapper.updateById(queryResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
FileUploadResultVo result = new FileUploadResultVo();
|
||||||
|
result.setCompleted(flag);
|
||||||
|
result.setId(id);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}catch (Exception e){
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除气象数据
|
||||||
|
*
|
||||||
|
* @param ids
|
||||||
|
*/
|
||||||
|
@Transactional(rollbackFor = RuntimeException.class)
|
||||||
|
@Override
|
||||||
|
public void delete(List<String> ids) {
|
||||||
|
this.baseMapper.deleteBatchIds(ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文件合并
|
||||||
|
* @param fileVo
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
private void merge(FileVo fileVo)throws Exception {
|
||||||
|
String storagePath = this.getFileStoragePath(fileVo.getDataSource(), fileVo.getFileName());
|
||||||
|
|
||||||
|
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(storagePath,true));
|
||||||
|
BufferedInputStream bis = null;
|
||||||
|
try {
|
||||||
|
byte[] byt = new byte[10*1024];
|
||||||
|
int len;
|
||||||
|
for(int i=0;i<fileVo.getShareTotal();i++) {
|
||||||
|
bis = new BufferedInputStream(new FileInputStream(storagePath+"."+i));
|
||||||
|
while((len = bis.read(byt))!=-1) {
|
||||||
|
bos.write(byt, 0, len);
|
||||||
|
}
|
||||||
|
if(null != bis) {
|
||||||
|
bis.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error(fileVo.getFileName()+"文件分片上传异常");
|
||||||
|
throw new RuntimeException("文件上传失败,请重新上传");
|
||||||
|
}finally {
|
||||||
|
if(null != bos) {
|
||||||
|
bos.flush();
|
||||||
|
bos.close();
|
||||||
|
}
|
||||||
|
if(null != bis) {
|
||||||
|
bis.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int i=0;i<fileVo.getShareTotal();i++) {
|
||||||
|
File file = new File(storagePath+"."+i);
|
||||||
|
if(file.exists()) {
|
||||||
|
file.delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 拼接文件存储路径
|
||||||
|
* @param dataSource
|
||||||
|
* @param fileName
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private String getFileStoragePath(Integer dataSource,String fileName) {
|
||||||
|
StringBuilder storagePath = new StringBuilder();
|
||||||
|
storagePath.append(this.systemStorageProperties.getRootPath());
|
||||||
|
storagePath.append(File.separator);
|
||||||
|
if (WeatherDataSourceEnum.PANGU.getKey().equals(dataSource)) {
|
||||||
|
storagePath.append(this.systemStorageProperties.getPangu());
|
||||||
|
} else if (WeatherDataSourceEnum.GRAPHCAST.getKey().equals(dataSource)) {
|
||||||
|
storagePath.append(this.systemStorageProperties.getGraphcast());
|
||||||
|
}else if (WeatherDataSourceEnum.RE_ANALYSIS.getKey().equals(dataSource)) {
|
||||||
|
storagePath.append(this.systemStorageProperties.getReAnalysis());
|
||||||
|
}
|
||||||
|
storagePath.append(File.separator);
|
||||||
|
storagePath.append(fileName);
|
||||||
|
return storagePath.toString();
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 构建文件路径
|
||||||
|
*/
|
||||||
|
private String buildFilePath(LocalDateTime startTime, int hour, Integer type) {
|
||||||
|
// LocalDateTime targetTime = startTime.plusHours(hour);
|
||||||
|
// String fileName = WeatherFilePrefixEnum.getValueByKey(type) + targetTime.format(DateTimeFormatter.ofPattern("yyyyMMddHH"))
|
||||||
|
// + WeatherFileSuffixEnum.getValueByKey(type);
|
||||||
|
// return systemStorageProperties.getWeather_file() + fileName;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查文件是否有效
|
||||||
|
*/
|
||||||
|
private boolean isFileValid(String filePath) {
|
||||||
|
Path path = Paths.get(filePath);
|
||||||
|
return Files.exists(path) && !Files.isDirectory(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取风场数据
|
||||||
|
*/
|
||||||
|
private void getWindData(NetcdfFile ncFile,WeatherResultVO weatherResultVO) {
|
||||||
|
List<List<Double>> results = new ArrayList<>();
|
||||||
|
try {
|
||||||
|
List<List<Double>> u = NcUtil.getNCByName(ncFile, "u-component_of_wind_height_above_ground", 0).get(0);
|
||||||
|
List<List<Double>> v = NcUtil.getNCByName(ncFile, "v-component_of_wind_height_above_ground", 0).get(0);
|
||||||
|
|
||||||
|
for (int i = 0; i < u.size(); i++) {
|
||||||
|
for (int j = 0; j < u.get(0).size(); j++) {
|
||||||
|
results.add(List.of(u.get(i).get(j), v.get(i).get(j)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
weatherResultVO.setSn(u.size());
|
||||||
|
weatherResultVO.setWe(u.get(0).size());
|
||||||
|
weatherResultVO.setDataList(results);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理温度数据
|
||||||
|
*/
|
||||||
|
private List<List<Double>> processTemperatureData(NetcdfFile ncFile, List<Double> lonData, List<Double> latData) {
|
||||||
|
try {
|
||||||
|
List<List<List<Double>>> tDataList = NcUtil.getNCByName(ncFile, "Temperature_height_above_ground", 0);
|
||||||
|
return processWeatherData(tDataList, lonData, latData, value -> value - 273.15);
|
||||||
|
} catch (Exception e) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理气压数据
|
||||||
|
*/
|
||||||
|
private List<List<Double>> processPressureData(NetcdfFile ncFile, List<Double> lonData, List<Double> latData) {
|
||||||
|
try {
|
||||||
|
List<List<List<Double>>> pDataList = NcUtil.getNCByName(ncFile, "Pressure_msl", 0);
|
||||||
|
return processWeatherData(pDataList, lonData, latData, value -> value / 1000);
|
||||||
|
} catch (Exception e) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理湿度数据
|
||||||
|
*/
|
||||||
|
private List<List<Double>> processHumidityData(NetcdfFile ncFile, List<Double> lonData, List<Double> latData) {
|
||||||
|
try {
|
||||||
|
List<List<List<Double>>> hDataList = NcUtil.getNCByName(ncFile, "Specific_humidity_isobaric", 0);
|
||||||
|
return processWeatherData(hDataList, lonData, latData, value -> value);
|
||||||
|
} catch (Exception e) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通用天气数据处理方法
|
||||||
|
*/
|
||||||
|
private List<List<Double>> processWeatherData(List<List<List<Double>>> dataList,
|
||||||
|
List<Double> lonData,
|
||||||
|
List<Double> latData,
|
||||||
|
ValueConverter converter) {
|
||||||
|
List<List<Double>> results = new ArrayList<>();
|
||||||
|
for (int i = 0; i < latData.size(); i++) {
|
||||||
|
for (int j = 0; j < lonData.size(); j++) {
|
||||||
|
double value = j < dataList.get(0).get(i).size()
|
||||||
|
? dataList.get(0).get(i).get(j)
|
||||||
|
: dataList.get(0).get(i).get(0);
|
||||||
|
results.add(List.of(lonData.get(j), latData.get(i), converter.convert(value)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 递归地将嵌套列表中的所有 Double 值提取出来
|
||||||
|
public void flattenList(List<?> nestedList, List<Double> flattenedList) {
|
||||||
|
for (Object element : nestedList) {
|
||||||
|
if (element instanceof List) {
|
||||||
|
flattenList((List<?>) element, flattenedList);
|
||||||
|
} else {
|
||||||
|
flattenedList.add((Double) element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取最大最小值
|
||||||
|
*/
|
||||||
|
public static List<Double> getMaxMin(List<Double> flattenedList) {
|
||||||
|
if (flattenedList == null || flattenedList.isEmpty()) {
|
||||||
|
return List.of(0.0, 0.0);
|
||||||
|
}
|
||||||
|
return List.of(Collections.max(flattenedList), Collections.min(flattenedList));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 函数式接口,用于值转换
|
||||||
|
*/
|
||||||
|
@FunctionalInterface
|
||||||
|
private interface ValueConverter {
|
||||||
|
double convert(double value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,151 @@
|
||||||
|
package org.jeecg.service.impl;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.val;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.jeecg.common.constant.enums.WeatherTaskStatusEnum;
|
||||||
|
import org.jeecg.common.system.query.PageRequest;
|
||||||
|
import org.jeecg.modules.base.entity.WeatherTask;
|
||||||
|
import org.jeecg.modules.base.entity.WeatherTaskLog;
|
||||||
|
import org.jeecg.modules.base.mapper.WeatherTaskLogMapper;
|
||||||
|
import org.jeecg.modules.base.mapper.WeatherTaskMapper;
|
||||||
|
import org.jeecg.service.WeatherTaskService;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 天气预报预测任务管理
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class WeatherTaskServiceImpl extends ServiceImpl<WeatherTaskMapper, WeatherTask> implements WeatherTaskService {
|
||||||
|
|
||||||
|
private final WeatherTaskLogMapper weatherTaskLogMapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页查询任务列表
|
||||||
|
* @param pageRequest
|
||||||
|
* @param taskName
|
||||||
|
* @param taskStatus
|
||||||
|
* @param startDate
|
||||||
|
* @param endDate
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public IPage<WeatherTask> page(PageRequest pageRequest, String taskName, Integer taskStatus, LocalDate startDate,LocalDate endDate) {
|
||||||
|
LambdaQueryWrapper<WeatherTask> queryWrapper = new LambdaQueryWrapper<>();
|
||||||
|
queryWrapper.eq(Objects.nonNull(taskStatus),WeatherTask::getTaskStatus, taskStatus);
|
||||||
|
queryWrapper.between((Objects.nonNull(startDate) && Objects.nonNull(endDate)),WeatherTask::getStartDate,startDate,endDate);
|
||||||
|
queryWrapper.like(StringUtils.isNotBlank(taskName),WeatherTask::getTaskName,taskName);
|
||||||
|
queryWrapper.orderByDesc(WeatherTask::getStartDate);
|
||||||
|
|
||||||
|
IPage<WeatherTask> iPage = new Page<>(pageRequest.getPageNum(), pageRequest.getPageSize());
|
||||||
|
return this.page(iPage, queryWrapper);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建天气预报预测任务
|
||||||
|
* @param weatherTask
|
||||||
|
*/
|
||||||
|
@Transactional(rollbackFor = RuntimeException.class)
|
||||||
|
@Override
|
||||||
|
public void cteate(WeatherTask weatherTask) {
|
||||||
|
//校验任务名称是否已存在
|
||||||
|
LambdaQueryWrapper<WeatherTask> checkNameWrapper = new LambdaQueryWrapper<>();
|
||||||
|
checkNameWrapper.eq(WeatherTask::getTaskName,weatherTask.getTaskName());
|
||||||
|
WeatherTask checkNameResult = this.getOne(checkNameWrapper);
|
||||||
|
if(Objects.nonNull(checkNameResult)){
|
||||||
|
throw new RuntimeException("此任务名称已存在");
|
||||||
|
}
|
||||||
|
//校验任务预测时间是否已重复
|
||||||
|
LambdaQueryWrapper<WeatherTask> checkDateWrapper = new LambdaQueryWrapper<>();
|
||||||
|
checkDateWrapper.eq(WeatherTask::getStartDate,weatherTask.getStartDate());
|
||||||
|
checkDateWrapper.eq(WeatherTask::getStartTime,weatherTask.getStartTime());
|
||||||
|
WeatherTask checkDateResult = this.getOne(checkDateWrapper);
|
||||||
|
if(Objects.nonNull(checkDateResult)){
|
||||||
|
throw new RuntimeException("此当前预测时间为参数的任务已存在");
|
||||||
|
}
|
||||||
|
weatherTask.setTaskStatus(WeatherTaskStatusEnum.NOT_STARTED.getKey());
|
||||||
|
this.save(weatherTask);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改天气预报预测任务
|
||||||
|
* @param weatherTask
|
||||||
|
*/
|
||||||
|
@Transactional(rollbackFor = RuntimeException.class)
|
||||||
|
@Override
|
||||||
|
public void update(WeatherTask weatherTask) {
|
||||||
|
//校验数据是否存在
|
||||||
|
WeatherTask queryResult = this.getById(weatherTask.getId());
|
||||||
|
if(Objects.isNull(queryResult)){
|
||||||
|
throw new RuntimeException("此任务不存在");
|
||||||
|
}
|
||||||
|
//校验任务名称是否已存在
|
||||||
|
LambdaQueryWrapper<WeatherTask> checkNameWrapper = new LambdaQueryWrapper<>();
|
||||||
|
checkNameWrapper.eq(WeatherTask::getTaskName,weatherTask.getTaskName());
|
||||||
|
WeatherTask checkNameResult = this.getOne(checkNameWrapper);
|
||||||
|
if(Objects.nonNull(checkNameResult) && !weatherTask.getId().equals(checkNameResult.getId())){
|
||||||
|
throw new RuntimeException("此任务名称已存在");
|
||||||
|
}
|
||||||
|
//校验任务预测时间是否已重复
|
||||||
|
LambdaQueryWrapper<WeatherTask> checkDateWrapper = new LambdaQueryWrapper<>();
|
||||||
|
checkDateWrapper.eq(WeatherTask::getStartDate,weatherTask.getStartDate());
|
||||||
|
checkDateWrapper.eq(WeatherTask::getStartTime,weatherTask.getStartTime());
|
||||||
|
WeatherTask checkDateResult = this.getOne(checkDateWrapper);
|
||||||
|
if(Objects.nonNull(checkDateResult) && !weatherTask.getId().equals(checkNameResult.getId())){
|
||||||
|
throw new RuntimeException("此当前预测时间为参数的任务已存在");
|
||||||
|
}
|
||||||
|
queryResult.setTaskName(weatherTask.getTaskName());
|
||||||
|
queryResult.setPredictionModel(weatherTask.getPredictionModel());
|
||||||
|
queryResult.setStartDate(weatherTask.getStartDate());
|
||||||
|
queryResult.setStartTime(weatherTask.getStartTime());
|
||||||
|
queryResult.setLeadTime(weatherTask.getLeadTime());
|
||||||
|
queryResult.setDataSources(weatherTask.getDataSources());
|
||||||
|
queryResult.setInputFile(weatherTask.getInputFile());
|
||||||
|
this.updateById(queryResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除预测任务
|
||||||
|
* @param ids
|
||||||
|
*/
|
||||||
|
@Transactional(rollbackFor = RuntimeException.class)
|
||||||
|
@Override
|
||||||
|
public void delete(List<String> ids) {
|
||||||
|
this.baseMapper.deleteBatchIds(ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 运行任务
|
||||||
|
*
|
||||||
|
* @param id
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void runTask(Integer id) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取任务运行日志
|
||||||
|
*
|
||||||
|
* @param taskId
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public List<WeatherTaskLog> getTaskLog(String taskId) {
|
||||||
|
LambdaQueryWrapper<WeatherTaskLog> queryWrapper = new LambdaQueryWrapper<>();
|
||||||
|
queryWrapper.eq(WeatherTaskLog::getTaskId,taskId);
|
||||||
|
queryWrapper.select(WeatherTaskLog::getCreateTime,WeatherTaskLog::getLogContent);
|
||||||
|
queryWrapper.orderByAsc(WeatherTaskLog::getCreateTime);
|
||||||
|
return this.weatherTaskLogMapper.selectList(queryWrapper);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
package org.jeecg.vo;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 校验文件是否存在VO
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class FileExistVo implements Serializable{
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
private boolean exist;
|
||||||
|
|
||||||
|
private String fileId;
|
||||||
|
|
||||||
|
private Integer shareTotal;
|
||||||
|
|
||||||
|
private Integer shareIndex;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
package org.jeecg.vo;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 上传文件结果VO
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class FileUploadResultVo implements Serializable{
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否上传完毕
|
||||||
|
*/
|
||||||
|
private boolean completed;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 记录id
|
||||||
|
*/
|
||||||
|
private String id;
|
||||||
|
}
|
||||||
28
jeecg-module-weather/src/main/java/org/jeecg/vo/FileVo.java
Normal file
28
jeecg-module-weather/src/main/java/org/jeecg/vo/FileVo.java
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
package org.jeecg.vo;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.annotation.JSONField;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import org.jeecg.modules.base.entity.WeatherData;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 上传文件VO
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
public class FileVo extends WeatherData {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否进行分片
|
||||||
|
*/
|
||||||
|
private boolean fileShare;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 上传文件
|
||||||
|
*/
|
||||||
|
@JSONField(serialize = false)
|
||||||
|
private MultipartFile file;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
package org.jeecg.vo;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class WeatherResultVO {
|
||||||
|
private List<List<Double>> dataList;
|
||||||
|
private double max;
|
||||||
|
private double min;
|
||||||
|
private int sn;
|
||||||
|
private int we;
|
||||||
|
}
|
||||||
|
|
@ -28,13 +28,7 @@
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jeecgframework.boot</groupId>
|
<groupId>org.jeecgframework.boot</groupId>
|
||||||
<artifactId>jeecg-system-biz</artifactId>
|
<artifactId>jeecg-system-biz</artifactId>
|
||||||
<!-- 排除demo模块,demo模块采用微服务独立启动 -->
|
<version>${jeecgboot.version}</version>
|
||||||
<exclusions>
|
|
||||||
<exclusion>
|
|
||||||
<groupId>org.jeecgframework.boot</groupId>
|
|
||||||
<artifactId>jeecg-module-demo</artifactId>
|
|
||||||
</exclusion>
|
|
||||||
</exclusions>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!-- feign 熔断限流、分布式锁、xxljob示例
|
<!-- feign 熔断限流、分布式锁、xxljob示例
|
||||||
|
|
|
||||||
|
|
@ -17,16 +17,10 @@ import org.springframework.context.ConfigurableApplicationContext;
|
||||||
import org.springframework.core.env.Environment;
|
import org.springframework.core.env.Environment;
|
||||||
import org.springframework.data.redis.core.RedisTemplate;
|
import org.springframework.data.redis.core.RedisTemplate;
|
||||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||||
|
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
|
|
||||||
/**
|
|
||||||
* 微服务启动类(采用此类启动项目为微服务模式)
|
|
||||||
* 注意: 需要先初始化Nacos的数据库脚本,db/tables_nacos.sql
|
|
||||||
* @author zyf
|
|
||||||
* @date: 2022/4/21 10:55
|
|
||||||
*/
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@SpringBootApplication
|
@SpringBootApplication
|
||||||
@EnableFeignClients(basePackages = {"org.jeecg"})
|
@EnableFeignClients(basePackages = {"org.jeecg"})
|
||||||
|
|
@ -48,7 +42,7 @@ public class JeecgSystemCloudApplication extends SpringBootServletInitializer im
|
||||||
String port = env.getProperty("server.port");
|
String port = env.getProperty("server.port");
|
||||||
String path = oConvertUtils.getString(env.getProperty("server.servlet.context-path"));
|
String path = oConvertUtils.getString(env.getProperty("server.servlet.context-path"));
|
||||||
log.info("\n----------------------------------------------------------\n\t" +
|
log.info("\n----------------------------------------------------------\n\t" +
|
||||||
"Application Jeecg-Boot is running! Access URLs:\n\t" +
|
"Application STAS-System is running! Access URLs:\n\t" +
|
||||||
"Local: \t\thttp://localhost:" + port + path + "/doc.html\n" +
|
"Local: \t\thttp://localhost:" + port + path + "/doc.html\n" +
|
||||||
"External: \thttp://" + ip + ":" + port + path + "/doc.html\n" +
|
"External: \thttp://" + ip + ":" + port + path + "/doc.html\n" +
|
||||||
"Swagger文档: \thttp://" + ip + ":" + port + path + "/doc.html\n" +
|
"Swagger文档: \thttp://" + ip + ":" + port + path + "/doc.html\n" +
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
server:
|
server:
|
||||||
port: 7001
|
port: 8001
|
||||||
|
|
||||||
spring:
|
spring:
|
||||||
application:
|
application:
|
||||||
|
|
|
||||||
36
jeecg-server-cloud/jeecg-weather-start/pom.xml
Normal file
36
jeecg-server-cloud/jeecg-weather-start/pom.xml
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<parent>
|
||||||
|
<groupId>org.jeecgframework.boot</groupId>
|
||||||
|
<artifactId>jeecg-server-cloud</artifactId>
|
||||||
|
<version>3.8.1</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<artifactId>jeecg-weather-start</artifactId>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<maven.compiler.source>17</maven.compiler.source>
|
||||||
|
<maven.compiler.target>17</maven.compiler.target>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jeecgframework.boot</groupId>
|
||||||
|
<artifactId>jeecg-boot-starter3-cloud</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jeecgframework.boot</groupId>
|
||||||
|
<artifactId>jeecg-system-cloud-api</artifactId>
|
||||||
|
<version>${jeecgboot.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jeecgframework.boot</groupId>
|
||||||
|
<artifactId>jeecg-module-weather</artifactId>
|
||||||
|
<version>${jeecgboot.version}</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</project>
|
||||||
|
|
@ -0,0 +1,55 @@
|
||||||
|
package org.jeecg;
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.jeecg.common.base.BaseMap;
|
||||||
|
import org.jeecg.common.constant.GlobalConstants;
|
||||||
|
import org.jeecg.common.util.oConvertUtils;
|
||||||
|
import org.springframework.boot.CommandLineRunner;
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||||
|
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
|
||||||
|
import org.springframework.cloud.openfeign.EnableFeignClients;
|
||||||
|
import org.springframework.context.ConfigurableApplicationContext;
|
||||||
|
import org.springframework.core.env.Environment;
|
||||||
|
import org.springframework.data.redis.core.RedisTemplate;
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.net.UnknownHostException;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@SpringBootApplication
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@EnableFeignClients
|
||||||
|
public class JeecgWeatherCloudApplication extends SpringBootServletInitializer implements CommandLineRunner {
|
||||||
|
|
||||||
|
private final RedisTemplate<String, Object> redisTemplate;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
|
||||||
|
return application.sources(JeecgWeatherCloudApplication.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) throws UnknownHostException {
|
||||||
|
ConfigurableApplicationContext application = SpringApplication.run(JeecgWeatherCloudApplication.class, args);
|
||||||
|
Environment env = application.getEnvironment();
|
||||||
|
String ip = InetAddress.getLocalHost().getHostAddress();
|
||||||
|
String port = env.getProperty("server.port");
|
||||||
|
String path = oConvertUtils.getString(env.getProperty("server.servlet.context-path"));
|
||||||
|
log.info("\n----------------------------------------------------------\n\t" +
|
||||||
|
"Application STAS-Weather is running! Access URLs:\n\t" +
|
||||||
|
"Local: \t\thttp://localhost:" + port + path + "/doc.html\n" +
|
||||||
|
"External: \thttp://" + ip + ":" + port + path + "/doc.html\n" +
|
||||||
|
"Swagger文档: \thttp://" + ip + ":" + port + path + "/doc.html\n" +
|
||||||
|
"----------------------------------------------------------");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run(String... args) {
|
||||||
|
BaseMap params = new BaseMap();
|
||||||
|
params.put(GlobalConstants.HANDLER_NAME, GlobalConstants.LODER_ROUDER_HANDLER);
|
||||||
|
//刷新网关
|
||||||
|
redisTemplate.convertAndSend(GlobalConstants.REDIS_TOPIC_NAME, params);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
server:
|
||||||
|
port: 8002
|
||||||
|
|
||||||
|
spring:
|
||||||
|
application:
|
||||||
|
name: jeecg-weather
|
||||||
|
cloud:
|
||||||
|
nacos:
|
||||||
|
config:
|
||||||
|
server-addr: @config.server-addr@
|
||||||
|
group: @config.group@
|
||||||
|
namespace: @config.namespace@
|
||||||
|
username: @config.username@
|
||||||
|
password: @config.password@
|
||||||
|
discovery:
|
||||||
|
server-addr: ${spring.cloud.nacos.config.server-addr}
|
||||||
|
group: @config.group@
|
||||||
|
namespace: @config.namespace@
|
||||||
|
username: @config.username@
|
||||||
|
password: @config.password@
|
||||||
|
config:
|
||||||
|
import:
|
||||||
|
- optional:nacos:jeecg.yaml
|
||||||
|
- optional:nacos:jeecg-@profile.name@.yaml
|
||||||
|
|
@ -0,0 +1,77 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<configuration debug="false">
|
||||||
|
<!--定义日志文件的存储地址 -->
|
||||||
|
<property name="LOG_HOME" value="../logs" />
|
||||||
|
|
||||||
|
<!--<property name="COLOR_PATTERN" value="%black(%contextName-) %red(%d{yyyy-MM-dd HH:mm:ss}) %green([%thread]) %highlight(%-5level) %boldMagenta( %replace(%caller{1}){'\t|Caller.{1}0|\r\n', ''})- %gray(%msg%xEx%n)" />-->
|
||||||
|
<!-- 控制台输出 -->
|
||||||
|
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||||
|
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
|
||||||
|
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符
|
||||||
|
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50}:%L - %msg%n</pattern>-->
|
||||||
|
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %highlight(%-5level) %cyan(%logger{50}:%L) - %msg%n</pattern>
|
||||||
|
</encoder>
|
||||||
|
</appender>
|
||||||
|
|
||||||
|
<!-- 按照每天生成日志文件 -->
|
||||||
|
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||||
|
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
|
||||||
|
<!--日志文件输出的文件名 -->
|
||||||
|
<FileNamePattern>${LOG_HOME}/jeecg-system-%d{yyyy-MM-dd}.%i.log</FileNamePattern>
|
||||||
|
<!--日志文件保留天数 -->
|
||||||
|
<MaxHistory>30</MaxHistory>
|
||||||
|
<maxFileSize>10MB</maxFileSize>
|
||||||
|
</rollingPolicy>
|
||||||
|
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
|
||||||
|
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符 -->
|
||||||
|
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50}:%L - %msg%n</pattern>
|
||||||
|
</encoder>
|
||||||
|
</appender>
|
||||||
|
|
||||||
|
<!-- 生成 error html格式日志开始 -->
|
||||||
|
<appender name="HTML" class="ch.qos.logback.core.FileAppender">
|
||||||
|
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
|
||||||
|
<!--设置日志级别,过滤掉info日志,只输入error日志-->
|
||||||
|
<level>ERROR</level>
|
||||||
|
</filter>
|
||||||
|
<encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
|
||||||
|
<layout class="ch.qos.logback.classic.html.HTMLLayout">
|
||||||
|
<pattern>%p%d%msg%M%F{32}%L</pattern>
|
||||||
|
</layout>
|
||||||
|
</encoder>
|
||||||
|
<file>${LOG_HOME}/error-log.html</file>
|
||||||
|
</appender>
|
||||||
|
<!-- 生成 error html格式日志结束 -->
|
||||||
|
|
||||||
|
<!-- 每天生成一个html格式的日志开始 -->
|
||||||
|
<appender name="FILE_HTML" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||||
|
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
|
||||||
|
<!--日志文件输出的文件名 -->
|
||||||
|
<FileNamePattern>${LOG_HOME}/jeecg-system-%d{yyyy-MM-dd}.%i.html</FileNamePattern>
|
||||||
|
<!--日志文件保留天数 -->
|
||||||
|
<MaxHistory>30</MaxHistory>
|
||||||
|
<MaxFileSize>10MB</MaxFileSize>
|
||||||
|
</rollingPolicy>
|
||||||
|
<encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
|
||||||
|
<layout class="ch.qos.logback.classic.html.HTMLLayout">
|
||||||
|
<pattern>%p%d%msg%M%F{32}%L</pattern>
|
||||||
|
</layout>
|
||||||
|
</encoder>
|
||||||
|
</appender>
|
||||||
|
<!-- 每天生成一个html格式的日志结束 -->
|
||||||
|
|
||||||
|
<!--myibatis log configure -->
|
||||||
|
<logger name="com.apache.ibatis" level="TRACE" />
|
||||||
|
<logger name="java.sql.Connection" level="DEBUG" />
|
||||||
|
<logger name="java.sql.Statement" level="DEBUG" />
|
||||||
|
<logger name="java.sql.PreparedStatement" level="DEBUG" />
|
||||||
|
|
||||||
|
<!-- 日志输出级别 -->
|
||||||
|
<root level="INFO">
|
||||||
|
<appender-ref ref="STDOUT" />
|
||||||
|
<appender-ref ref="FILE" />
|
||||||
|
<appender-ref ref="HTML" />
|
||||||
|
<appender-ref ref="FILE_HTML" />
|
||||||
|
</root>
|
||||||
|
|
||||||
|
</configuration>
|
||||||
|
|
@ -20,6 +20,7 @@
|
||||||
|
|
||||||
<!-- 监控和测试例子 -->
|
<!-- 监控和测试例子 -->
|
||||||
<module>jeecg-visual</module>
|
<module>jeecg-visual</module>
|
||||||
|
<module>jeecg-weather-start</module>
|
||||||
</modules>
|
</modules>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
Loading…
Reference in New Issue
Block a user