1,注解跨域
@Slf4j
@RestController
@RequestMapping("${xxxx.tjbh.api-prefix}/access")
@Api(tags = "接入终端合规统计")
@CrossOrigin //跨域
public class AccessTerminalStatisticsController {
@Resource
AccessTerminalStatisticsService accessTerminalStatisticsService;
/**
* 终端设备统计
*
* @return
*/
@GetMapping("/getTeminalList")
@ApiOperation(value = "终端设备统计",notes = "websocket主题:/topic/clientDeviceStatistic")
public Result<List<ClientDeviceStatisticDTO>> getTeminalList() {
return new Result<>("0000000000", "返回成功", accessTerminalStatisticsService.getTeminalList());
}
}
2,缓存
package com.xxxx.uss.bcs.cache;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.util.Map;
/**
* <h1>区域设备在线统计缓存</h1>
*/
@Component
@Slf4j
public class RegionDeviceCache {
/**
* 默认存取12个小时内的数据
*/
private static final Long DEFAULT_HOUR = 12L;
@Value("${task.schedule.region-device}")
private Long regionDevice;
@PostConstruct//被@PostConstruct修饰的方法会在服务器加载Servlet的时候运行,并且只会被服务器执行一次。PostConstruct //在构造函数之后执行,init()方法之前执行。可以使用@PostConstruct注解一个方法来完成初始化
public void init() {
long maximumSize = DEFAULT_HOUR * 60 * 60 * 1000 / regionDevice;
log.info("静态属性初始化:【{}秒钟】,最大缓存长度:【{}】", regionDevice/1000,maximumSize);
AREA_DEVICE_CACHE = CacheBuilder.newBuilder().maximumSize(maximumSize).build();//本地缓存(数据量小的情况)
}
/**
* K:时间 V:AreaEntity
*/
private static Cache<String, Map<String, Object>> AREA_DEVICE_CACHE;
public static Cache<String, Map<String, Object>> getAreaDeviceCache() {
return AREA_DEVICE_CACHE;
}
public static void setAreaDeviceCache(String k, Map<String, Object> value) {
AREA_DEVICE_CACHE.put(k, value);
}
}
使用:
存:
RegionDeviceCache.setAreaDeviceCache(CommonConstants.SIMPLE_TIME_MINUTE_FORMATTER.format(LocalDateTime.now()), result);
取:
List<Map.Entry<String, Map<String, Object>>> entryList = RegionDeviceCache.getAreaDeviceCache().asMap().entrySet()
.stream()
.sorted(Comparator.comparing(Map.Entry::getKey)) //按照时间排序
.collect(Collectors.toList());
3,全局异常
package com.xxx.uss.bcs.common.exception;
import com.xxx.framework.common.base.Result;
import com.xxx.framework.common.exception.BaseErrorCode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.client.RestClientException;
/**
* 添加全局异常处理
*
* @Author xiangchao
* @create 2020/8/20 14:51
*/
@ControllerAdvice
@Slf4j
public class CustomerExceptionHandler{
@ResponseBody
@ExceptionHandler(RestClientException.class)
public Result handlerRestClientException(RestClientException e) {
log.error("底层接口调用失败:[{}]", e.getMessage());
return Result.error(BaseErrorCode.SYS_INTERNAL_ERROR.getErrorCode(), "底层接口调用失败");
}
@ResponseBody
@ExceptionHandler({Exception.class})
public ResponseEntity<Object> globalHandle(Exception e) {
Result result = Result.of(BaseErrorCode.SYS_INTERNAL_ERROR);
log.error("exception={}", e.getMessage());
return new ResponseEntity(result, HttpStatus.INTERNAL_SERVER_ERROR);
}
}
4,单独用feignClient 启动类添加 @EnableFeignClients就可以用了
package com.xxx.uss.bcs.client;
import com.xxx.uss.bcs.common.constant.CommonConstants;
import com.xxx.uss.bcs.dto.response.IpcDTO;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
/**
* @Author xiangchao
* @create 2020/8/4 17:35
*/
@Component
@FeignClient(url = "${feignClient.hostName.bbs-device}", name = "bss-device-manager")//url:192.168.xx.xx ,name不重复就行
public interface BSSDeviceManagerFeignClient {
/**
* 报警TOP区域 获取所有设备信息
*
* @param pageSize 设置0为查全部
* @return
*/
@GetMapping(value = "/api/infra-udm/v0.1/channel/listChannelAndDevice", headers="User=usercode:admin&username:admin")//添加header信息
IpcDTO getIpcInfo(@RequestParam("page_size") Integer pageSize);
}
5,websocket
后端:
package com.xxx.uss.bcs.common.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;
/**
* WebSocket配置
*
* @Author xiangchao
* @create 2020/8/6 17:16
*/
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
@Value("${unisinsight.tjbh.api-prefix}")
String apiPrefix;
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
// 开启/ws-cgs端点
registry.addEndpoint(apiPrefix + "tibh")
.// 允许跨域访问
setAllowedOrigins("*")
// 使用sockJS
.withSockJS();
}
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
// 订阅topic的前缀,订阅topic必须是这种格式 /element/topic1/xxx ,客户端订阅地址的前缀
registry.enableSimpleBroker("/topic");
// 客户端给服务端发消息的地址的前缀
registry.setApplicationDestinationPrefixes("/topic");
}
}
package com.xxxx.uss.bcs.task;
import com.xxx.framework.common.base.Result;
import com.xxx.uss.bcs.service.VideoRatioService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
/**
* 摄像机状态统计定时任务
*
* @Author xiangchao
* @create 2020/8/7 14:15
*/
@Slf4j
@Component
public class VideoRatioTask {
@Resource
VideoRatioService videoRatioService;
/**
* 消息发送模板
*/
@Resource
SimpMessagingTemplate simpMessagingTemplate;
/**
* 录像完整率(定时任务)
*
* @return
*/
@Scheduled(initialDelay = 0, fixedRateString = "${task.schedule.videoRatio-complete}")
@Async
public void getVideoRatioComplete() {
log.info("录像完整率:{}", new Result<>("0000000000", "返回成功", videoRatioService.getVideoRatioComplete()));
// 推送数据
simpMessagingTemplate.convertAndSend("/topic/videoStatusComplete", new Result<>("0000000000", "返回成功", videoRatioService.getVideoRatioComplete()));
}
}
前端:
6 Controller接口设置请求头
例如:
1,固定传headers
@GetMapping(value = "/api/infra-udm/v0.1/channel/listChannelAndDevice", headers = "User=usercode:admin&username:admin")
IpcDTO getIpcInfo(@RequestParam("page_size") Integer pageSize);
2,动态传headers //调用此方法的时候在将“usercode:admin&username:admin”传进去给userHeaders
@GetMapping(value = "/api/infra-udm/v0.1/channel/listChannelAndDevice")
IpcDTO getIpcInfo(@RequestParam("page_size") Integer pageSize, @RequestHeaders("User") String userHeaders);