瀏覽代碼

提交操控无人机接口代码

develop
wanjing 7 月之前
父節點
當前提交
36b5b77dfb
共有 13 個檔案被更改,包括 252 行新增103 行删除
  1. +7
    -0
      tuoheng-service/tuoheng-admin/src/main/java/com/tuoheng/admin/controller/AccidentController.java
  2. +56
    -0
      tuoheng-service/tuoheng-admin/src/main/java/com/tuoheng/admin/request/accident/DroneControlRequest.java
  3. +14
    -0
      tuoheng-service/tuoheng-admin/src/main/java/com/tuoheng/admin/service/accident/AccidentServiceImpl.java
  4. +9
    -0
      tuoheng-service/tuoheng-admin/src/main/java/com/tuoheng/admin/service/accident/IAccidentService.java
  5. +0
    -1
      tuoheng-service/tuoheng-admin/src/main/java/com/tuoheng/admin/service/third/airport/AirportService.java
  6. +0
    -6
      tuoheng-service/tuoheng-admin/src/main/java/com/tuoheng/admin/service/third/airport/AirportServiceImpl.java
  7. +76
    -3
      tuoheng-service/tuoheng-admin/src/main/java/com/tuoheng/admin/service/third/airport/control/AirportDroneControlService.java
  8. +8
    -20
      tuoheng-service/tuoheng-admin/src/main/java/com/tuoheng/admin/service/third/airport/control/DroneContinueService.java
  9. +12
    -20
      tuoheng-service/tuoheng-admin/src/main/java/com/tuoheng/admin/service/third/airport/control/DroneExecuteService.java
  10. +32
    -0
      tuoheng-service/tuoheng-admin/src/main/java/com/tuoheng/admin/service/third/airport/control/DroneGuideFlightService.java
  11. +6
    -17
      tuoheng-service/tuoheng-admin/src/main/java/com/tuoheng/admin/service/third/airport/control/DronePauseService.java
  12. +8
    -17
      tuoheng-service/tuoheng-admin/src/main/java/com/tuoheng/admin/service/third/airport/control/DroneReturnHomeService.java
  13. +24
    -19
      tuoheng-service/tuoheng-admin/src/main/java/com/tuoheng/admin/service/third/airport/control/DroneUndoService.java

+ 7
- 0
tuoheng-service/tuoheng-admin/src/main/java/com/tuoheng/admin/controller/AccidentController.java 查看文件

public JsonResult statisticsByMonth() { public JsonResult statisticsByMonth() {
return accidentService.statisticsByMonth(); return accidentService.statisticsByMonth();
} }

@PostMapping(value = "/droneControl")
public JsonResult droneControl(@RequestBody DroneControlRequest request) {
// log.info("进入操作无人机接口, request={}", request);
return accidentService.droneControl(request);
}

} }

+ 56
- 0
tuoheng-service/tuoheng-admin/src/main/java/com/tuoheng/admin/request/accident/DroneControlRequest.java 查看文件

package com.tuoheng.admin.request.accident;

import lombok.Data;

/**
* 事故上报请求实体
*
* @author wanjing
* @team tuoheng
* @date 2023-03-15
*/
@Data
public class DroneControlRequest {

/**
* 任务id
*/
private String inspectionId;

/**
* 操作类型:1:悬停;2:指点飞行;3:继续任务;4:立即返航;5:取消任务
*/
private Integer type;

/**
* 机场任务ID
*/
private Integer airportTaskId;

/**
* 巡检机场id
*/
private Integer airportId;

/**
* 高度
*/
private Integer zalt;

/**
* 纬度
*/
private String latitude;

/**
* 经度
*/
private String longitude;

/**
* 租户code
*/
private String tenantCode;


}

+ 14
- 0
tuoheng-service/tuoheng-admin/src/main/java/com/tuoheng/admin/service/accident/AccidentServiceImpl.java 查看文件

import com.tuoheng.admin.service.accident.statistics.StatisticsByMonthService; import com.tuoheng.admin.service.accident.statistics.StatisticsByMonthService;
import com.tuoheng.admin.service.accident.verify.AccidentVerifyCompletedService; import com.tuoheng.admin.service.accident.verify.AccidentVerifyCompletedService;
import com.tuoheng.admin.service.accident.verify.AccidentVerifyService; import com.tuoheng.admin.service.accident.verify.AccidentVerifyService;
import com.tuoheng.admin.service.third.airport.control.AirportDroneControlService;
import com.tuoheng.common.core.common.BaseServiceImpl; import com.tuoheng.common.core.common.BaseServiceImpl;
import com.tuoheng.common.core.utils.JsonResult; import com.tuoheng.common.core.utils.JsonResult;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@Autowired @Autowired
private StatisticsByMonthService statisticsByMonthService; private StatisticsByMonthService statisticsByMonthService;


@Autowired
private AirportDroneControlService airportDroneControlService;

@Override @Override
public JsonResult getRealtimeInfoList(QueryAccidentRealtimeInfoListRequest request) { public JsonResult getRealtimeInfoList(QueryAccidentRealtimeInfoListRequest request) {
return queryAccidentRealtimeInfoListService.getList(request); return queryAccidentRealtimeInfoListService.getList(request);
public JsonResult statisticsByMonth() { public JsonResult statisticsByMonth() {
return statisticsByMonthService.statistics(); return statisticsByMonthService.statistics();
} }

/**
* 操作无人机
*
* @return 结果
*/
@Override
public JsonResult droneControl(DroneControlRequest request) {
return airportDroneControlService.exec(request);
}
} }

+ 9
- 0
tuoheng-service/tuoheng-admin/src/main/java/com/tuoheng/admin/service/accident/IAccidentService.java 查看文件

*/ */
JsonResult statisticsByMonth(); JsonResult statisticsByMonth();



/**
* 操作无人机
*
* @return 结果
*/
JsonResult droneControl(DroneControlRequest request);


} }

+ 0
- 1
tuoheng-service/tuoheng-admin/src/main/java/com/tuoheng/admin/service/third/airport/AirportService.java 查看文件



JsonResult reversalFlight(ReversalFlightRequest request); JsonResult reversalFlight(ReversalFlightRequest request);


JsonResult controlDrone(Integer inspectionId);
} }

+ 0
- 6
tuoheng-service/tuoheng-admin/src/main/java/com/tuoheng/admin/service/third/airport/AirportServiceImpl.java 查看文件

return reversalFlightService.reversalFlight(request); return reversalFlightService.reversalFlight(request);
} }


@Override
public JsonResult controlDrone(Integer inspectionId) {
return null;
}


} }

+ 76
- 3
tuoheng-service/tuoheng-admin/src/main/java/com/tuoheng/admin/service/third/airport/control/AirportDroneControlService.java 查看文件

package com.tuoheng.admin.service.third.airport.control; package com.tuoheng.admin.service.third.airport.control;


import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.tuoheng.admin.constant.SystemConstant; import com.tuoheng.admin.constant.SystemConstant;
import com.tuoheng.admin.entity.Inspection;
import com.tuoheng.admin.entity.Tenant;
import com.tuoheng.admin.enums.MarkEnum;
import com.tuoheng.admin.mapper.InspectionMapper;
import com.tuoheng.admin.mapper.TenantMapper;
import com.tuoheng.admin.request.accident.DroneControlRequest;
import com.tuoheng.admin.utils.CurrentUserUtil;
import com.tuoheng.common.core.config.common.CommonConfig; import com.tuoheng.common.core.config.common.CommonConfig;
import com.tuoheng.common.core.exception.ServiceException; import com.tuoheng.common.core.exception.ServiceException;
import com.tuoheng.common.core.utils.JsonResult; import com.tuoheng.common.core.utils.JsonResult;
@Service @Service
public class AirportDroneControlService { public class AirportDroneControlService {


@Autowired
private TenantMapper tenantMapper;

@Autowired
private InspectionMapper inspectionMapper;

@Autowired
private DroneContinueService droneContinueService;

@Autowired
private DroneGuideFlightService droneGuideFlightService;

@Autowired
private DronePauseService dronePauseService;

@Autowired
private DroneReturnHomeService droneReturnHomeService;

@Autowired
private DroneUndoService droneUndoService;

@Autowired @Autowired
@Qualifier("restTemplate") @Qualifier("restTemplate")
private RestTemplate restTemplate; private RestTemplate restTemplate;


/**
* @return
*/
public JsonResult exec(DroneControlRequest request) {
//查询当前对应的任务
Inspection inspection = inspectionMapper.selectOne(Wrappers.<Inspection>lambdaQuery()
.eq(Inspection::getId, request.getInspectionId())
.eq(Inspection::getMark, MarkEnum.VALID.getCode()));
if (ObjectUtil.isEmpty(inspection)) {
throw new ServiceException("操控无人机,该任务不存在");
}

Tenant tenant = tenantMapper.selectById(CurrentUserUtil.getTenantId());
if (ObjectUtil.isEmpty(tenant)) {
throw new ServiceException("操控无人机,该租户不存在");
}
request.setAirportId(inspection.getAirportId());
request.setAirportTaskId(request.getAirportTaskId());
request.setTenantCode(tenant.getCode());

// 1:悬停;2:指点飞行;3:继续任务;4:立即返航;5:取消任务
JSONObject jsonObject = null;
if (1 == request.getType()) {
// 悬停
jsonObject = dronePauseService.getJSONObject(request);
} else if (2 == request.getType()) {
// 指点飞行
jsonObject = droneGuideFlightService.getJSONObject(request);
} else if (3 == request.getType()) {
// 继续任务
jsonObject = droneContinueService.getJSONObject(request);
} else if (4 == request.getType()) {
// 立即返航
jsonObject = droneReturnHomeService.getJSONObject(request);
} else if (5 == request.getType()) {
// 取消任务
jsonObject = droneUndoService.getJSONObject(request);
} else {
throw new ServiceException("操控无人机,错误的操作指令");
}
JsonResult jsonResult = this.call(jsonObject);
return jsonResult;
}


/** /**
* @return * @return
*/ */
public JsonResult exec(JSONObject jsonObject) {
private JsonResult call(JSONObject jsonObject) {
String url = CommonConfig.airportURL + SystemConstant.API_AIRPORT_DRONE_CONTROL; String url = CommonConfig.airportURL + SystemConstant.API_AIRPORT_DRONE_CONTROL;
log.info("调用机场平台,操作无人机,url:{}", url); log.info("调用机场平台,操作无人机,url:{}", url);
log.info("调用机场平台,操作无人机,jsonObject:{}", jsonObject); log.info("调用机场平台,操作无人机,jsonObject:{}", jsonObject);
try { try {
response = restTemplate.exchange(url, HttpMethod.POST, httpEntity, JsonResult.class); response = restTemplate.exchange(url, HttpMethod.POST, httpEntity, JsonResult.class);
} catch (Exception e) { } catch (Exception e) {
log.error("调用机场平台,接口异常, url:{}", url);
log.error("调用机场平台,接口异常, httpEntity:{}", httpEntity);
log.error("调用机场平台,操作无人机,接口异常, url:{}", url);
log.error("调用机场平台,操作无人机,接口异常, httpEntity:{}", httpEntity);
throw new ServiceException("调用机场平台,接口异常"); throw new ServiceException("调用机场平台,接口异常");
} }
JsonResult jsonResult = response.getBody(); JsonResult jsonResult = response.getBody();

+ 8
- 20
tuoheng-service/tuoheng-admin/src/main/java/com/tuoheng/admin/service/third/airport/control/DroneContinueService.java 查看文件



import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import com.tuoheng.admin.constant.SystemConstant; import com.tuoheng.admin.constant.SystemConstant;
import com.tuoheng.admin.entity.Inspection;
import com.tuoheng.admin.request.accident.DroneControlRequest;
import com.tuoheng.common.core.config.common.CommonConfig; import com.tuoheng.common.core.config.common.CommonConfig;
import com.tuoheng.common.core.exception.ServiceException; import com.tuoheng.common.core.exception.ServiceException;
import com.tuoheng.common.core.utils.JsonResult; import com.tuoheng.common.core.utils.JsonResult;
@Service @Service
public class DroneContinueService { public class DroneContinueService {


@Autowired
private AirportDroneControlService airportDroneControlService;

/** /**
* 用机场平台,原无人机继续巡检
* 用机场平台,原无人机继续巡检
* *
* @param airportId 机场Id
* @param taskId 巡检任务Id
*/
public JsonResult continuee(Integer airportId, Integer taskId) {
log.info("继续任务, taskId={}", taskId);
JSONObject jsonObject = this.getJSONObject(airportId, taskId);
JsonResult result = airportDroneControlService.exec(jsonObject);
return result;
}

/**
* @param airportId
* @param taskId
* @param request
* @return * @return
*/ */
private JSONObject getJSONObject(Integer airportId, Integer taskId) {
public JSONObject getJSONObject(DroneControlRequest request) {
log.info("继续巡检, inspectionId={}", request.getInspectionId());
JSONObject jsonObject = new JSONObject(); JSONObject jsonObject = new JSONObject();
jsonObject.put("zhilin", "04"); jsonObject.put("zhilin", "04");
jsonObject.put("airportId", airportId);
jsonObject.put("taskId", taskId);
jsonObject.put("airportId", request.getAirportId());
jsonObject.put("taskId", request.getAirportTaskId());
jsonObject.put("msg", "继续巡检"); jsonObject.put("msg", "继续巡检");
return jsonObject; return jsonObject;
} }

+ 12
- 20
tuoheng-service/tuoheng-admin/src/main/java/com/tuoheng/admin/service/third/airport/control/DroneExecuteService.java 查看文件

package com.tuoheng.admin.service.third.airport.control; package com.tuoheng.admin.service.third.airport.control;


import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.tuoheng.admin.constant.SystemConstant; import com.tuoheng.admin.constant.SystemConstant;
import com.tuoheng.admin.entity.Inspection;
import com.tuoheng.admin.entity.Tenant;
import com.tuoheng.admin.enums.MarkEnum;
import com.tuoheng.admin.mapper.TenantMapper;
import com.tuoheng.admin.request.accident.DroneControlRequest;
import com.tuoheng.common.core.utils.JsonResult; import com.tuoheng.common.core.utils.JsonResult;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@Service @Service
public class DroneExecuteService { public class DroneExecuteService {


@Autowired
private AirportDroneControlService airportDroneControlService;

/** /**
* 执行任务 * 执行任务
* *
* @param taskId
* @return
*/
public JsonResult callBack(Integer taskId, String url, Integer airportId, String tenantCode) {
log.info("执行任务, taskId={}", taskId);
JSONObject jsonObject = this.getJSONObject(taskId, url, airportId, tenantCode);
JsonResult result = airportDroneControlService.exec(jsonObject);
return result;
}

/**
* @param taskId
* @param url
* @param request
* @return * @return
*/ */
private JSONObject getJSONObject(Integer taskId, String url, Integer airportId, String tenantCode) {
public JSONObject getJSONObject(DroneControlRequest request) {
String url = "";
JSONObject jsonObject = new JSONObject(); JSONObject jsonObject = new JSONObject();
jsonObject.put("requestId", taskId);
jsonObject.put("airportId", airportId);
jsonObject.put("requestId", request.getAirportTaskId());
jsonObject.put("airportId", request.getAirportId());
jsonObject.put("code", SystemConstant.PLATFORM_CODE); jsonObject.put("code", SystemConstant.PLATFORM_CODE);
jsonObject.put("tenantCode", tenantCode);
jsonObject.put("tenantCode", request.getTenantCode());
jsonObject.put("wayUrl", url); jsonObject.put("wayUrl", url);
return jsonObject; return jsonObject;
} }

+ 32
- 0
tuoheng-service/tuoheng-admin/src/main/java/com/tuoheng/admin/service/third/airport/control/DroneGuideFlightService.java 查看文件

package com.tuoheng.admin.service.third.airport.control;

import com.alibaba.fastjson.JSONObject;
import com.tuoheng.admin.constant.DroneControlConstant;
import com.tuoheng.admin.entity.Inspection;
import com.tuoheng.admin.request.accident.DroneControlRequest;
import com.tuoheng.common.core.utils.JsonResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Slf4j
@Service
public class DroneGuideFlightService {

/**
* 指点飞行
*
* @param request
* @return
*/
public JSONObject getJSONObject(DroneControlRequest request) {
log.info("指点飞行, inspectionId={}", request.getInspectionId());
JSONObject jsonObject = new JSONObject();
jsonObject.put("taskId", request.getAirportTaskId());
jsonObject.put("airportId", request.getAirportId());
jsonObject.put("zalt", request.getZalt());
jsonObject.put("zlon", request.getLongitude());
jsonObject.put("zlat", request.getLatitude());
return jsonObject;
}
}

+ 6
- 17
tuoheng-service/tuoheng-admin/src/main/java/com/tuoheng/admin/service/third/airport/control/DronePauseService.java 查看文件



import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import com.tuoheng.admin.constant.DroneControlConstant; import com.tuoheng.admin.constant.DroneControlConstant;
import com.tuoheng.admin.entity.Inspection;
import com.tuoheng.admin.request.accident.DroneControlRequest;
import com.tuoheng.common.core.utils.JsonResult; import com.tuoheng.common.core.utils.JsonResult;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@Service @Service
public class DronePauseService { public class DronePauseService {


@Autowired
private AirportDroneControlService airportDroneControlService;

/** /**
* 航线暂停 * 航线暂停
* *
* @param airportId
* @return
*/
public JsonResult pause(Integer airportId) {
log.info("航线暂停, airportId={}", airportId);
JSONObject jsonObject = this.getJSONObject(airportId);
JsonResult result = airportDroneControlService.exec(jsonObject);
return result;
}

/**
* @param airportId
* @param request
* @return * @return
*/ */
private JSONObject getJSONObject(Integer airportId) {
public JSONObject getJSONObject(DroneControlRequest request) {
log.info("航线暂停, inspectionId={}", request.getInspectionId());
JSONObject jsonObject = new JSONObject(); JSONObject jsonObject = new JSONObject();
jsonObject.put("zhilin", DroneControlConstant.PAUSE); jsonObject.put("zhilin", DroneControlConstant.PAUSE);
jsonObject.put("airportId", Integer.valueOf(airportId));
jsonObject.put("airportId", request.getAirportTaskId());
jsonObject.put("msg", "航线暂停"); jsonObject.put("msg", "航线暂停");
return jsonObject; return jsonObject;
} }

+ 8
- 17
tuoheng-service/tuoheng-admin/src/main/java/com/tuoheng/admin/service/third/airport/control/DroneReturnHomeService.java 查看文件



import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import com.tuoheng.admin.constant.DroneControlConstant; import com.tuoheng.admin.constant.DroneControlConstant;
import com.tuoheng.admin.entity.Inspection;
import com.tuoheng.admin.request.accident.DroneControlRequest;
import com.tuoheng.common.core.utils.JsonResult; import com.tuoheng.common.core.utils.JsonResult;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;


@Slf4j @Slf4j
@Service
public class DroneReturnHomeService { public class DroneReturnHomeService {


@Autowired
private AirportDroneControlService airportDroneControlService;

/** /**
* 一键返航 * 一键返航
* *
* @param airportId
* @return
*/
public JsonResult returnHome(Integer airportId) {
log.info("一键返航, airportId={}", airportId);
JSONObject jsonObject = this.getJSONObject(airportId);
JsonResult result = airportDroneControlService.exec(jsonObject);
return result;
}

/**
* @param airportId
* @param request
* @return * @return
*/ */
private JSONObject getJSONObject(Integer airportId) {
public JSONObject getJSONObject(DroneControlRequest request) {
log.info("一键返航, inspectionId={}", request.getInspectionId());
JSONObject jsonObject = new JSONObject(); JSONObject jsonObject = new JSONObject();
jsonObject.put("zhilin", DroneControlConstant.RETURN_HOME); jsonObject.put("zhilin", DroneControlConstant.RETURN_HOME);
jsonObject.put("airportId", airportId);
jsonObject.put("airportId", request.getAirportId());
jsonObject.put("msg", "一键返航"); jsonObject.put("msg", "一键返航");
return jsonObject; return jsonObject;
} }

+ 24
- 19
tuoheng-service/tuoheng-admin/src/main/java/com/tuoheng/admin/service/third/airport/control/DroneUndoService.java 查看文件

package com.tuoheng.admin.service.third.airport.control; package com.tuoheng.admin.service.third.airport.control;


import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import com.tuoheng.admin.constant.SystemConstant; import com.tuoheng.admin.constant.SystemConstant;
import com.tuoheng.admin.entity.Inspection;
import com.tuoheng.admin.request.accident.DroneControlRequest;
import com.tuoheng.admin.service.third.airport.AirportService;
import com.tuoheng.admin.service.third.airport.GetAirLineListService;
import com.tuoheng.admin.service.third.airport.GetAirportListByAirportIds;
import com.tuoheng.admin.vo.AirportInfoVo;
import com.tuoheng.admin.vo.AirportLineVo;
import com.tuoheng.common.core.exception.ServiceException;
import com.tuoheng.common.core.utils.JsonResult; import com.tuoheng.common.core.utils.JsonResult;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;


import java.util.List;

@Slf4j @Slf4j
@Service @Service
public class DroneUndoService { public class DroneUndoService {


@Autowired @Autowired
private AirportDroneControlService airportDroneControlService;
private GetAirportListByAirportIds getAirportListByAirportIds;


/** /**
* 取消任务 * 取消任务
* *
* @param taskId
* @param airportCode
* @return
*/
public JsonResult callBack(Integer taskId, String airportCode) {
log.info("取消任务, taskId={}", taskId);
JSONObject jsonObject = this.getJSONObject(taskId, airportCode);
JsonResult result = airportDroneControlService.exec(jsonObject);
return result;
}

/**
* @param taskId
* @param airportCode
* @param request
* @return * @return
*/ */
private JSONObject getJSONObject(Integer taskId, String airportCode) {
public JSONObject getJSONObject(DroneControlRequest request) {
log.info("取消任务, inspectionId={}", request.getInspectionId());
List<AirportInfoVo> airportInfoVoList = getAirportListByAirportIds.getAirportInfo(String.valueOf(request.getAirportId()));
if (CollectionUtil.isEmpty(airportInfoVoList)) {
log.error("操控无人机,该机场不存在, ");
throw new ServiceException("操控无人机,该机场不存在");
}
AirportInfoVo airportInfoVo = airportInfoVoList.get(9);
JSONObject jsonObject = new JSONObject(); JSONObject jsonObject = new JSONObject();
jsonObject.put("code", SystemConstant.PLATFORM_CODE); jsonObject.put("code", SystemConstant.PLATFORM_CODE);
// jsonObject.put("tenantCode", NJHSJConstant.TENANT_CODE);
jsonObject.put("airportCode", airportCode);
jsonObject.put("taskId", taskId);
jsonObject.put("tenantCode", request.getTenantCode());
jsonObject.put("airportCode", airportInfoVo.getCode());
jsonObject.put("taskId", request.getAirportTaskId());
return jsonObject; return jsonObject;
} }



Loading…
取消
儲存