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>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<properties>
|
||||
<netcdf.version>4.5.5</netcdf.version>
|
||||
<grib.version>4.5.5</grib.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<!--jeecg-tools-->
|
||||
|
|
@ -320,5 +325,16 @@
|
|||
<groupId>org.jeecgframework.boot3</groupId>
|
||||
<artifactId>minidao-spring-boot-starter-jsqlparser-4.9</artifactId>
|
||||
</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>
|
||||
</project>
|
||||
|
|
@ -33,23 +33,6 @@ public interface ServiceNameConstants {
|
|||
* 微服务名: 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
|
||||
|
|
|
|||
|
|
@ -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 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.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
|
|
@ -23,12 +27,14 @@ import lombok.experimental.Accessors;
|
|||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
@Accessors(chain = true)
|
||||
public class JeecgEntity implements Serializable {
|
||||
public class BaseEntity implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* ID
|
||||
*/
|
||||
@Null(message = "ID必须为空",groups = { InsertGroup.class})
|
||||
@NotNull(message = "ID不能为空",groups = { UpdateGroup.class})
|
||||
@TableId(type = IdType.ASSIGN_ID)
|
||||
@Schema(description = "ID")
|
||||
private java.lang.String id;
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
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 com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
|
|
@ -14,6 +14,6 @@ import lombok.extern.slf4j.Slf4j;
|
|||
* @Version: 1.0
|
||||
*/
|
||||
@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.system.vo.LoginUser;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
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.system.vo.LoginUser;
|
||||
|
||||
/**
|
||||
* common接口
|
||||
* @author: jeecg-boot
|
||||
*/
|
||||
public interface BaseCommonService {
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -18,10 +18,6 @@ import jakarta.annotation.Resource;
|
|||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @Description: common实现类
|
||||
* @author: jeecg-boot
|
||||
*/
|
||||
@Service
|
||||
@Slf4j
|
||||
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.system.api.factory.SysBaseAPIFallbackFactory;
|
||||
import org.jeecg.common.system.vo.*;
|
||||
import org.jeecg.config.FeignConfig;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
|
@ -29,7 +30,7 @@ import java.util.Set;
|
|||
* @author: jeecg-boot
|
||||
*/
|
||||
@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")
|
||||
public interface ISysBaseAPI extends CommonAPI {
|
||||
|
||||
|
|
|
|||
|
|
@ -1,180 +1,52 @@
|
|||
//package org.jeecg.config;
|
||||
//
|
||||
//import java.io.IOException;
|
||||
//import java.util.ArrayList;
|
||||
//import java.util.Arrays;
|
||||
//import java.util.List;
|
||||
//import java.util.SortedMap;
|
||||
//
|
||||
//import jakarta.servlet.http.HttpServletRequest;
|
||||
//
|
||||
//import org.jeecg.common.config.mqtoken.UserTokenContext;
|
||||
//import org.jeecg.common.constant.CommonConstant;
|
||||
//import org.jeecg.common.util.DateUtils;
|
||||
//import org.jeecg.common.util.PathMatcherUtil;
|
||||
//import org.jeecg.config.sign.interceptor.SignAuthConfiguration;
|
||||
//import org.jeecg.config.sign.util.HttpUtils;
|
||||
//import org.jeecg.config.sign.util.SignUtil;
|
||||
//import org.springframework.beans.factory.ObjectFactory;
|
||||
//import org.springframework.boot.autoconfigure.AutoConfigureBefore;
|
||||
//import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
//import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
|
||||
//import org.springframework.cloud.openfeign.FeignAutoConfiguration;
|
||||
//import org.springframework.cloud.openfeign.support.SpringDecoder;
|
||||
//import org.springframework.cloud.openfeign.support.SpringEncoder;
|
||||
//import org.springframework.context.annotation.Bean;
|
||||
//import org.springframework.context.annotation.Configuration;
|
||||
//import org.springframework.context.annotation.Primary;
|
||||
//import org.springframework.context.annotation.Scope;
|
||||
//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 {
|
||||
//
|
||||
package org.jeecg.config;
|
||||
|
||||
import feign.Feign;
|
||||
import feign.RequestTemplate;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import org.apache.http.HttpHeaders;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||
import feign.Logger;
|
||||
import feign.RequestInterceptor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
@Configuration
|
||||
public class FeignConfig implements RequestInterceptor{
|
||||
|
||||
/**
|
||||
* @param requestTemplate
|
||||
*/
|
||||
@Override
|
||||
public void apply(RequestTemplate requestTemplate) {
|
||||
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
|
||||
HttpServletRequest request = attributes.getRequest();
|
||||
requestTemplate.header("Authorization", request.getHeader("Authorization"));
|
||||
}
|
||||
|
||||
// /**
|
||||
// * 设置feign header参数
|
||||
// * 【X_ACCESS_TOKEN】【X_SIGN】【X_TIMESTAMP】
|
||||
// * @return
|
||||
// */
|
||||
// @Bean
|
||||
// @ConditionalOnMissingBean(RequestInterceptor.class)
|
||||
// public RequestInterceptor requestInterceptor() {
|
||||
// return requestTemplate -> {
|
||||
// return template -> {
|
||||
// ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
|
||||
// if (null != attributes) {
|
||||
// if (attributes != null) {
|
||||
// HttpServletRequest request = attributes.getRequest();
|
||||
// log.debug("Feign request: {}", request.getRequestURI());
|
||||
// // 将token信息放入header中
|
||||
// String token = request.getHeader(CommonConstant.X_ACCESS_TOKEN);
|
||||
// if(token==null || "".equals(token)){
|
||||
// token = request.getParameter("token");
|
||||
// }
|
||||
// String token = request.getHeader(HttpHeaders.AUTHORIZATION);
|
||||
// log.info("Feign Login Request token: {}", token);
|
||||
// requestTemplate.header(CommonConstant.X_ACCESS_TOKEN, token);
|
||||
// }else{
|
||||
// //解决后台任务、MQ中调用feign接口,无会话token的问题
|
||||
// String token = UserTokenContext.getToken();
|
||||
// log.info("Feign No Login token: {}", token);
|
||||
// requestTemplate.header(CommonConstant.X_ACCESS_TOKEN, token);
|
||||
// template.header(HttpHeaders.AUTHORIZATION, 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>
|
||||
<groupId>org.jeecgframework.boot</groupId>
|
||||
<artifactId>jeecg-boot-base-core</artifactId>
|
||||
<version>${jeecgboot.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
<dependency>
|
||||
<groupId>org.jeecgframework.boot</groupId>
|
||||
<artifactId>jeecg-system-local-api</artifactId>
|
||||
<version>3.8.1</version>
|
||||
<version>${jeecgboot.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hibernate</groupId>
|
||||
|
|
|
|||
|
|
@ -1,13 +1,11 @@
|
|||
package org.jeecg.modules.message.entity;
|
||||
|
||||
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.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
|
@ -22,7 +20,7 @@ import lombok.experimental.Accessors;
|
|||
@EqualsAndHashCode(callSuper = false)
|
||||
@Accessors(chain = true)
|
||||
@TableName("sys_sms")
|
||||
public class SysMessage extends JeecgEntity {
|
||||
public class SysMessage extends BaseEntity {
|
||||
/**推送内容*/
|
||||
@Excel(name = "推送内容", width = 15)
|
||||
private java.lang.String esContent;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
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 com.baomidou.mybatisplus.annotation.TableName;
|
||||
|
|
@ -19,7 +19,7 @@ import lombok.experimental.Accessors;
|
|||
@EqualsAndHashCode(callSuper = false)
|
||||
@Accessors(chain = true)
|
||||
@TableName("sys_sms_template")
|
||||
public class SysMessageTemplate extends JeecgEntity{
|
||||
public class SysMessageTemplate extends BaseEntity{
|
||||
/**模板CODE*/
|
||||
@Excel(name = "模板CODE", width = 15)
|
||||
private java.lang.String templateCode;
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import com.baomidou.mybatisplus.annotation.TableName;
|
|||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
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;
|
||||
|
||||
/**
|
||||
|
|
@ -15,7 +15,7 @@ import org.jeecgframework.poi.excel.annotation.Excel;
|
|||
@TableName("oss_file")
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
@Accessors(chain = true)
|
||||
public class OssFile extends JeecgEntity {
|
||||
public class OssFile extends BaseEntity {
|
||||
|
||||
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>
|
||||
<groupId>org.jeecgframework.boot</groupId>
|
||||
<artifactId>jeecg-system-biz</artifactId>
|
||||
<!-- 排除demo模块,demo模块采用微服务独立启动 -->
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.jeecgframework.boot</groupId>
|
||||
<artifactId>jeecg-module-demo</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
<version>${jeecgboot.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- feign 熔断限流、分布式锁、xxljob示例
|
||||
|
|
|
|||
|
|
@ -17,16 +17,10 @@ import org.springframework.context.ConfigurableApplicationContext;
|
|||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
|
||||
/**
|
||||
* 微服务启动类(采用此类启动项目为微服务模式)
|
||||
* 注意: 需要先初始化Nacos的数据库脚本,db/tables_nacos.sql
|
||||
* @author zyf
|
||||
* @date: 2022/4/21 10:55
|
||||
*/
|
||||
|
||||
@Slf4j
|
||||
@SpringBootApplication
|
||||
@EnableFeignClients(basePackages = {"org.jeecg"})
|
||||
|
|
@ -48,7 +42,7 @@ public class JeecgSystemCloudApplication extends SpringBootServletInitializer im
|
|||
String port = env.getProperty("server.port");
|
||||
String path = oConvertUtils.getString(env.getProperty("server.servlet.context-path"));
|
||||
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" +
|
||||
"External: \thttp://" + ip + ":" + port + path + "/doc.html\n" +
|
||||
"Swagger文档: \thttp://" + ip + ":" + port + path + "/doc.html\n" +
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
server:
|
||||
port: 7001
|
||||
port: 8001
|
||||
|
||||
spring:
|
||||
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-weather-start</module>
|
||||
</modules>
|
||||
|
||||
</project>
|
||||
Loading…
Reference in New Issue
Block a user