国标通道编辑支持仅保存修改的字段

This commit is contained in:
lin
2025-11-06 15:50:42 +08:00
parent f89dee6393
commit 01e72407ac
10 changed files with 198 additions and 66 deletions

View File

@@ -22,6 +22,7 @@ import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpHeaders;
@@ -33,6 +34,7 @@ import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.async.DeferredResult;
import java.beans.PropertyDescriptor;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.List;
@@ -86,13 +88,26 @@ public class ChannelController {
@Operation(summary = "更新通道", security = @SecurityRequirement(name = JwtUtils.HEADER))
@PostMapping("/update")
public void update(@RequestBody CommonGBChannel channel){
BeanWrapperImpl wrapper = new BeanWrapperImpl(channel);
int count = 0;
for (PropertyDescriptor pd : wrapper.getPropertyDescriptors()) {
String name = pd.getName();
if ("class".equals(name)) continue;
if (pd.getReadMethod() == null) continue;
Object val = wrapper.getPropertyValue(name);
if (val != null) count++;
}
Assert.isTrue(count > 1, "未进行任何修改");
channelService.update(channel);
}
@Operation(summary = "重置国标通道", security = @SecurityRequirement(name = JwtUtils.HEADER))
@PostMapping("/reset")
public void reset(Integer id){
channelService.reset(id);
public void reset(ResetParam param){
Assert.notNull(param.getId(), "通道ID不能为空");
Assert.notEmpty(param.getChanelFields(), "待重置字段不可以空");
channelService.reset(param.getId(), param.getChanelFields());
}
@Operation(summary = "增加通道", security = @SecurityRequirement(name = JwtUtils.HEADER))

View File

@@ -0,0 +1,15 @@
package com.genersoft.iot.vmp.gb28181.controller.bean;
import lombok.Getter;
import lombok.Setter;
import java.util.List;
@Getter
@Setter
public class ResetParam {
private Integer id;
private List<String> chanelFields;
}

View File

@@ -117,40 +117,40 @@ public interface CommonGBChannelMapper {
@Update(value = {" <script>" +
"UPDATE wvp_device_channel " +
"SET update_time=#{updateTime}" +
", gb_device_id = #{gbDeviceId}" +
", gb_name = #{gbName}" +
", gb_manufacturer = #{gbManufacturer}" +
", gb_model = #{gbModel}" +
", gb_owner = #{gbOwner}" +
", gb_civil_code = #{gbCivilCode}" +
", gb_block = #{gbBlock}" +
", gb_address = #{gbAddress}" +
", gb_parental = #{gbParental}" +
", gb_parent_id = #{gbParentId}" +
", gb_safety_way = #{gbSafetyWay}" +
", gb_register_way = #{gbRegisterWay}" +
", gb_cert_num = #{gbCertNum}" +
", gb_certifiable = #{gbCertifiable}" +
", gb_err_code = #{gbErrCode}" +
", gb_end_time = #{gbEndTime}" +
", gb_ip_address = #{gbIpAddress}" +
", gb_port = #{gbPort}" +
", gb_password = #{gbPassword}" +
", gb_status = #{gbStatus}" +
", gb_longitude = #{gbLongitude}" +
", gb_latitude = #{gbLatitude}" +
", gb_ptz_type = #{gbPtzType}" +
", gb_position_type = #{gbPositionType}" +
", gb_room_type = #{gbRoomType}" +
", gb_use_type = #{gbUseType}" +
", gb_supply_light_type = #{gbSupplyLightType}" +
", gb_direction_type = #{gbDirectionType}" +
", gb_resolution = #{gbResolution}" +
", gb_business_group_id = #{gbBusinessGroupId}" +
", gb_download_speed = #{gbDownloadSpeed}" +
", gb_svc_space_support_mod = #{gbSvcSpaceSupportMod}" +
", gb_svc_time_support_mode = #{gbSvcTimeSupportMode}" +
", enable_broadcast = #{enableBroadcast}" +
"<if test='gbDeviceId != null' > , gb_device_id = #{gbDeviceId}</if> " +
"<if test='gbName != null' > , gb_name = #{gbName}</if> " +
"<if test='gbManufacturer != null' > , gb_manufacturer = #{gbManufacturer}</if> " +
"<if test='gbModel != null' > , gb_model = #{gbModel}</if> " +
"<if test='gbOwner != null' > , gb_owner = #{gbOwner}</if> " +
"<if test='gbCivilCode != null' > , gb_civil_code = #{gbCivilCode}</if> " +
"<if test='gbBlock != null' > , gb_block = #{gbBlock}</if> " +
"<if test='gbAddress != null' > , gb_address = #{gbAddress}</if> " +
"<if test='gbParental != null' > , gb_parental = #{gbParental}</if> " +
"<if test='gbParentId != null' > , gb_parent_id = #{gbParentId}</if> " +
"<if test='gbSafetyWay != null' > , gb_safety_way = #{gbSafetyWay}</if> " +
"<if test='gbRegisterWay != null' > , gb_register_way = #{gbRegisterWay}</if> " +
"<if test='gbCertNum != null' > , gb_cert_num = #{gbCertNum}</if> " +
"<if test='gbCertifiable != null' > , gb_certifiable = #{gbCertifiable}</if> " +
"<if test='gbErrCode != null' > , gb_err_code = #{gbErrCode}</if> " +
"<if test='gbEndTime != null' > , gb_end_time = #{gbEndTime}</if> " +
"<if test='gbIpAddress != null' > , gb_ip_address = #{gbIpAddress}</if> " +
"<if test='gbPort != null' > , gb_port = #{gbPort}</if> " +
"<if test='gbPassword != null' > , gb_password = #{gbPassword}</if> " +
"<if test='gbStatus != null' > , gb_status = #{gbStatus}</if> " +
"<if test='gbLongitude != null' > , gb_longitude = #{gbLongitude}</if> " +
"<if test='gbLatitude != null' > , gb_latitude = #{gbLatitude}</if> " +
"<if test='gbPtzType != null' > , gb_ptz_type = #{gbPtzType}</if> " +
"<if test='gbPositionType != null' > , gb_position_type = #{gbPositionType}</if> " +
"<if test='gbRoomType != null' > , gb_room_type = #{gbRoomType}</if> " +
"<if test='gbUseType != null' > , gb_use_type = #{gbUseType}</if> " +
"<if test='gbSupplyLightType != null' > , gb_supply_light_type = #{gbSupplyLightType}</if> " +
"<if test='gbDirectionType != null' > , gb_direction_type = #{gbDirectionType}</if> " +
"<if test='gbResolution != null' > , gb_resolution = #{gbResolution}</if> " +
"<if test='gbBusinessGroupId != null' > , gb_business_group_id = #{gbBusinessGroupId}</if> " +
"<if test='gbDownloadSpeed != null' > , gb_download_speed = #{gbDownloadSpeed}</if> " +
"<if test='gbSvcSpaceSupportMod != null' > , gb_svc_space_support_mod = #{gbSvcSpaceSupportMod}</if> " +
"<if test='gbSvcTimeSupportMode != null' > , gb_svc_time_support_mode = #{gbSvcTimeSupportMode}</if> " +
"<if test='enableBroadcast != null' > , enable_broadcast = #{enableBroadcast}</if> " +
" WHERE id = #{gbId}"+
" </script>"})
int update(CommonGBChannel commonGBChannel);
@@ -236,17 +236,13 @@ public interface CommonGBChannelMapper {
@Update(value = {" <script>" +
" UPDATE wvp_device_channel " +
" SET update_time=#{updateTime}, gb_device_id = null, gb_name = null, gb_manufacturer = null," +
" gb_model = null, gb_owner = null, gb_block = null, gb_address = null," +
" gb_parental = null, gb_parent_id = null, gb_safety_way = null, gb_register_way = null, gb_cert_num = null," +
" gb_certifiable = null, gb_err_code = null, gb_end_time = null, gb_secrecy = null, gb_ip_address = null, " +
" gb_port = null, gb_password = null, gb_status = null, gb_longitude = null, gb_latitude = null, " +
" gb_ptz_type = null, gb_position_type = null, gb_room_type = null, gb_use_type = null, gb_supply_light_type = null, " +
" gb_direction_type = null, gb_resolution = null, gb_business_group_id = null, gb_download_speed = null, gb_svc_space_support_mod = null, " +
" gb_svc_time_support_mode = null" +
" WHERE id = #{id} and data_type = #{dataType} and data_device_id = #{dataDeviceId}"+
" SET update_time=#{updateTime}" +
"<foreach collection='fields' index='index' item='item' separator=';'> " +
", #{item} = null" +
"</foreach> " +
" WHERE id = #{id}"+
" </script>"})
void reset(@Param("id") int id, @Param("dataType") Integer dataType, @Param("dataDeviceId") int dataDeviceId, @Param("updateTime") String updateTime);
void reset(@Param("id") int id, List<String> fields, @Param("updateTime") String updateTime);
@SelectProvider(type = ChannelProvider.class, method = "queryByIds")
@@ -421,7 +417,7 @@ public interface CommonGBChannelMapper {
", gb_ip_address=#{item.gbIpAddress}" +
", gb_port=#{item.gbPort}" +
", gb_password=#{item.gbPassword}" +
", gb_status=#{item.gbStatus}" +
"<if test='item.gbStatus != null' > , gb_status=#{item.gbStatus}</if> " +
", gb_longitude=#{item.gbLongitude}" +
", gb_latitude=#{item.gbLatitude}" +
", gb_ptz_type=#{item.gbPtzType}" +

View File

@@ -309,12 +309,12 @@ public interface GroupMapper {
@Select("<script>" +
" SELECT " +
" ANY_VALUE(coalesce( wdc.gb_parent_id, wdc.parent_id)) as deviceId," +
" MIN(coalesce( wdc.gb_parent_id, wdc.parent_id)) as deviceId," +
" COUNT(*) AS allCount," +
" SUM(CASE WHEN coalesce( wdc.gb_status, wdc.status) = 'ON' THEN 1 ELSE 0 END) AS onlineCount" +
" FROM " +
" wvp_device_channel wdc " +
" where wdc.channel_type = 0 AND wdc.data_type != 2 AND (wdc.gb_ptz_type is null || ( wdc.gb_ptz_type != 98 AND wdc.gb_ptz_type != 99)) " +
" where wdc.channel_type = 0 AND wdc.data_type != 2 AND (wdc.gb_ptz_type is null or ( wdc.gb_ptz_type != 98 AND wdc.gb_ptz_type != 99)) " +
" AND coalesce( wdc.gb_parent_id, wdc.parent_id) in " +
" <foreach collection='groupList' item='item' open='(' separator=',' close=')' > #{item.deviceId}</foreach>" +
" GROUP BY coalesce(wdc.gb_parent_id, wdc.parent_id)" +

View File

@@ -42,7 +42,7 @@ public interface IGbChannelService {
List<NetworkIdentificationType> getNetworkIdentificationTypeList();
void reset(int id);
void reset(int id, List<String> chanelFields);
PageInfo<CommonGBChannel> queryListByCivilCode(int page, int count, String query, Boolean online, Integer channelType, String civilCode);

View File

@@ -2,6 +2,7 @@ package com.genersoft.iot.vmp.gb28181.service.impl;
import com.alibaba.excel.support.cglib.beans.BeanMap;
import com.alibaba.excel.util.BeanMapUtils;
import com.alibaba.fastjson2.JSONObject;
import com.genersoft.iot.vmp.common.VideoManagerConstants;
import com.genersoft.iot.vmp.common.enums.ChannelDataType;
import com.genersoft.iot.vmp.conf.DynamicTask;
@@ -25,11 +26,13 @@ import com.genersoft.iot.vmp.utils.TileUtils;
import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.google.common.base.CaseFormat;
import lombok.extern.slf4j.Slf4j;
import no.ecc.vectortile.VectorTileEncoder;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.GeometryFactory;
import org.locationtech.jts.geom.Point;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
@@ -165,26 +168,28 @@ public class GbChannelServiceImpl implements IGbChannelService {
CommonGBChannel oldChannel = commonGBChannelMapper.queryById(commonGBChannel.getGbId());
commonGBChannel.setUpdateTime(DateUtil.getNow());
int result = commonGBChannelMapper.update(commonGBChannel);
if (result > 0) {
try {
CommonGBChannel newChannel = commonGBChannelMapper.queryById(commonGBChannel.getGbId());
// 发送通知
eventPublisher.channelEventPublishForUpdate(commonGBChannel, oldChannel);
eventPublisher.channelEventPublishForUpdate(newChannel, oldChannel);
if (commonGBChannel.getGbLongitude() != null && !Objects.equals(oldChannel.getGbLongitude(), commonGBChannel.getGbLongitude())
&& commonGBChannel.getGbLatitude() != null && !Objects.equals(oldChannel.getGbLatitude(), commonGBChannel.getGbLatitude())) {
if (newChannel.getGbLongitude() != null && !Objects.equals(oldChannel.getGbLongitude(), newChannel.getGbLongitude())
&& newChannel.getGbLatitude() != null && !Objects.equals(oldChannel.getGbLatitude(), newChannel.getGbLatitude())) {
MobilePosition mobilePosition = new MobilePosition();
mobilePosition.setDeviceId(commonGBChannel.getGbDeviceId());
mobilePosition.setChannelId(commonGBChannel.getGbId());
mobilePosition.setDeviceName(commonGBChannel.getGbName());
mobilePosition.setDeviceId(newChannel.getGbDeviceId());
mobilePosition.setChannelId(newChannel.getGbId());
mobilePosition.setDeviceName(newChannel.getGbName());
mobilePosition.setCreateTime(DateUtil.getNow());
mobilePosition.setTime(DateUtil.getNow());
mobilePosition.setLongitude(commonGBChannel.getGbLongitude());
mobilePosition.setLatitude(commonGBChannel.getGbLatitude());
mobilePosition.setLongitude(newChannel.getGbLongitude());
mobilePosition.setLatitude(newChannel.getGbLatitude());
eventPublisher.mobilePositionEventPublish(mobilePosition);
}
} catch (Exception e) {
log.warn("[更新通道通知] 发送失败,{}", commonGBChannel.getGbDeviceId(), e);
log.warn("[更新通道通知] 发送失败,{}", JSONObject.toJSONString(commonGBChannel), e);
}
}
return result;
@@ -422,8 +427,9 @@ public class GbChannelServiceImpl implements IGbChannelService {
}
@Override
public void reset(int id) {
public void reset(int id, List<String> chanelFields) {
log.info("[重置国标通道] id: {}", id);
Assert.notEmpty(chanelFields, "待重置字段为空");
CommonGBChannel channel = getOne(id);
if (channel == null) {
log.warn("[重置国标通道] 未找到对应Id的通道: id: {}", id);
@@ -433,8 +439,18 @@ public class GbChannelServiceImpl implements IGbChannelService {
log.warn("[重置国标通道] 非国标下级通道无法重置: id: {}", id);
throw new ControllerException(ErrorCode.ERROR100.getCode(), "非国标下级通道无法重置");
}
List<String> dbFields = new ArrayList<>();
for (String chanelField : chanelFields) {
BeanWrapperImpl wrapper = new BeanWrapperImpl(channel);
if (wrapper.isReadableProperty(chanelField)) {
dbFields.add(CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, chanelField));
}
}
Assert.notEmpty(dbFields, "待重置字段为空");
// 这个多加一个参数,为了防止将非国标的通道通过此方法清空内容,导致意外发生
commonGBChannelMapper.reset(id, ChannelDataType.GB28181, channel.getDataDeviceId(), DateUtil.getNow());
commonGBChannelMapper.reset(id, dbFields, DateUtil.getNow());
CommonGBChannel channelNew = getOne(id);
// 发送通过更新通知
try {

View File

@@ -102,7 +102,9 @@ public class RedisPushStreamListMsgListener implements MessageListener {
streamPush.setUpdateTime(DateUtil.getNow());
streamPush.setGbDeviceId(pushStreamMessage.getGbId());
streamPush.setGbName(pushStreamMessage.getName());
streamPush.setGbStatus(pushStreamMessage.isStatus() ? "ON" : "OFF");
if (pushStreamMessage.getStatus() != null) {
streamPush.setGbStatus(pushStreamMessage.getStatus() ? "ON" : "OFF");
}
//存在就只修改 name和gbId
streamPushItemForUpdate.add(streamPush);
}

View File

@@ -9,7 +9,7 @@ public class RedisPushStreamMessage {
private String app;
private String stream;
private String name;
private boolean status;
private Boolean status;
// 终端所属的虚拟组织
private String groupGbId;
// 终端所属的虚拟组织别名 可选可作为地方同步组织结构到wvp时的关联关系
@@ -31,7 +31,9 @@ public class RedisPushStreamMessage {
push.setGbManufacturer(manufacturer);
push.setGbModel(model);
push.setGbPtzType(ptzType);
push.setGbStatus(status?"ON":"OFF");
if (status != null) {
push.setGbStatus(status?"ON":"OFF");
}
push.setEnableBroadcast(0);
return push;
}