Commit 0879ca0d by 涂亚平

Merge remote-tracking branch 'origin/master' into 2.7.1人脸识别版本

2 parents 6747d4f4 b3033f79
......@@ -221,6 +221,22 @@
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<dependency>
<groupId>com.tencentcloudapi</groupId>
<artifactId>tencentcloud-sdk-java</artifactId>
<version>3.1.322</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
</dependency>
<!-- <dependency>-->
<!-- <groupId>org.springframework.boot</groupId>-->
<!-- <artifactId>spring-boot-starter-data-mongodb</artifactId>-->
......
......@@ -3,6 +3,7 @@ package com.subsidy;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.web.bind.annotation.RestController;
......@@ -11,6 +12,7 @@ import org.springframework.web.bind.annotation.RestController;
@SpringBootApplication
@MapperScan(basePackages = {"com.subsidy.mapper"})
@EnableScheduling
@EnableCaching
@EnableAsync
public class MeishuApplication {
......
package com.subsidy.common.constant;
import lombok.Getter;
@Getter
public class VodConstant {
/* 流量 */
public final static String FLUX = "Flux";
/* 带宽 */
public final static String BANDWIDTH = "Bandwidth";
/* 请求数 */
public final static String REQUESTS = "Requests";
/* 请求命中率 */
public final static String HITRATE = "Hitrate";
/* IP访问次数 */
public final static String IP_VISITS = "Ip_visits";
/* 带宽缓存key */
public final static String BANDWIDTH_CACHE_KEY = "CDNStatBandwidthCache";
/* 流量缓存key */
public final static String FLUX_CACHE_KEY = "CDNStatFluxCache";
/* 自定义缓存名称(ehcache.xml中的自定义规则名称) */
public final static String CDN_STAT_DETAILS_CACHE_NAME = "CDNStatDetails";
}
package com.subsidy.dto.company;
import lombok.Data;
@Data
public class DataOverviewDTO {
private Long companyId;
}
......@@ -53,4 +53,6 @@ public interface ClassDictMapper extends BaseMapper<ClassDictDO> {
* 班级信息 -- 获取课程信息 + 公司信息
* */
ClassAndCompanyInfoVO getClassAndCompanyInfoVO(Long classId);
Integer getClassCount();
}
......@@ -97,4 +97,9 @@ public interface VodPlayHistoryMapper extends BaseMapper<VodPlayHistoryDO> {
List<VodPlayHistoryDO> getVodPlayDay(Long classId, Long memberId, Date endDate);
double getStudyTotal();
double getSubsidyStudyTotal();
int getStudyHistoryNum();
}
......@@ -6,8 +6,9 @@ import com.subsidy.dto.administer.OperatorsDTO;
import com.subsidy.dto.company.AddCompanyDTO;
import com.subsidy.dto.company.GetCompanyMembersDTO;
import com.subsidy.model.CompanyDictDO;
import com.subsidy.model.MemberDO;
import com.subsidy.vo.administer.OperatorsVO;
import com.subsidy.vo.company.CDNStatDetailsVO;
import com.subsidy.vo.company.DataOverviewVO;
import com.subsidy.vo.company.GetAllCompanyVO;
import com.subsidy.vo.company.GetCompanyMembersVO;
import com.subsidy.vo.company.MemberSummaryVO;
......@@ -38,4 +39,9 @@ public interface CompanyDictService extends IService<CompanyDictDO> {
MemberSummaryVO memberSummary(GetCompanyMembersDTO getCompanyMembersDTO);
DataOverviewVO getCompanyDataOverview();
List<CDNStatDetailsVO> getCDNBandwidthStatDetails();
List<CDNStatDetailsVO> getCDNFluxStatDetails();
}
......@@ -44,7 +44,6 @@ import com.subsidy.model.MemberDepartmentMappingDO;
import com.subsidy.model.OprAdmDictDO;
import com.subsidy.model.PaperDictDO;
import com.subsidy.model.RoleAdministerMappingDO;
import com.subsidy.model.RoleDictDO;
import com.subsidy.model.SignInRecordDO;
import com.subsidy.model.VodDictDO;
import com.subsidy.service.AdministerService;
......@@ -86,12 +85,12 @@ import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedInputStream;
......@@ -115,7 +114,6 @@ import java.util.concurrent.atomic.AtomicInteger;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
/**
* <p>
* 管理平台用户 服务实现类
......@@ -175,9 +173,6 @@ public class AdministerServiceImpl extends ServiceImpl<AdministerMapper, Adminis
@Autowired
private SignInRecordMapper signInRecordMapper;
//@Autowired
//private MongoTemplate mongoTemplate;
@Autowired
private PaperDictMapper paperDictMapper;
......@@ -380,8 +375,9 @@ public class AdministerServiceImpl extends ServiceImpl<AdministerMapper, Adminis
return ConstantUtils.SET_SUCCESS;
}
@Override
@Cacheable(value = "ResultData", key = "'classId_'+#classDetailDTO.getId()")
public ClassSummaryVO classSummary(ClassDetailDTO classDetailDTO) {
ClassSummaryVO classSummaryVO = new ClassSummaryVO();
//班级人数
......
......@@ -4,26 +4,50 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.subsidy.common.RedisPrefixConstant;
import com.subsidy.common.configure.VODConfig;
import com.subsidy.common.constant.VodConstant;
import com.subsidy.common.exception.HttpException;
import com.subsidy.dto.administer.OperatorsDTO;
import com.subsidy.dto.company.AddCompanyDTO;
import com.subsidy.dto.company.GetCompanyMembersDTO;
import com.subsidy.mapper.AdministerMapper;
import com.subsidy.mapper.ClassDictMapper;
import com.subsidy.mapper.ClassHourDictMapper;
import com.subsidy.mapper.ClassTypeDictMapper;
import com.subsidy.mapper.CompanyDictMapper;
import com.subsidy.mapper.CompanyFieldMappingMapper;
import com.subsidy.mapper.CourseDictMapper;
import com.subsidy.mapper.DepartmentDictMapper;
import com.subsidy.mapper.FieldDictMapper;
import com.subsidy.mapper.JobDictMapper;
import com.subsidy.mapper.MemberMapper;
import com.subsidy.mapper.RankDictMapper;
import com.subsidy.mapper.RoleAdministerMappingMapper;
import com.subsidy.mapper.RotationImgDictMapper;
import com.subsidy.mapper.VodPlayHistoryMapper;
import com.subsidy.mapper.*;
import com.subsidy.model.*;
import com.subsidy.service.CompanyDictService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.subsidy.util.ConstantUtils;
import com.subsidy.util.DateFormatUtil;
import com.subsidy.util.EhCacheUtil;
import com.subsidy.util.VodUtil;
import com.subsidy.vo.administer.OperatorsVO;
import com.subsidy.vo.company.CDNStatDetailsVO;
import com.subsidy.vo.company.DataOverviewVO;
import com.subsidy.vo.company.GetAllCompanyVO;
import com.subsidy.vo.company.GetCompanyMembersVO;
import com.tencentcloudapi.vod.v20180717.models.StatDataItem;
import org.apache.commons.collections.CollectionUtils;
import com.subsidy.vo.company.MemberSummaryVO;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
......@@ -71,6 +95,18 @@ public class CompanyDictServiceImpl extends ServiceImpl<CompanyDictMapper, Compa
@Autowired
private MemberMapper memberMapper;
@Autowired
private ClassDictMapper classDictMapper;
@Autowired
private CourseDictMapper courseDictMapper;
@Autowired
private VodPlayHistoryMapper vodPlayHistoryMapper;
@Autowired
private VODConfig vodConfig;
public IPage<OperatorsVO> operators(OperatorsDTO operatorsDTO) {
Page pager = new Page(operatorsDTO.getPageNum(), operatorsDTO.getPageSize());
......@@ -252,6 +288,55 @@ public class CompanyDictServiceImpl extends ServiceImpl<CompanyDictMapper, Compa
return this.baseMapper.getCompanyMembers(pager,getCompanyMembersDTO.getCompanyId(),getCompanyMembersDTO.getUserName());
}
@Override
public DataOverviewVO getCompanyDataOverview() {
DataOverviewVO dataOverviewVO = new DataOverviewVO();
int companyNum = this.baseMapper.selectCount(new QueryWrapper<>());
/* 机构数量 */
dataOverviewVO.setCompanyNum(companyNum);
List<MemberDO> memberList = memberMapper.selectList(new QueryWrapper<>());
if(CollectionUtils.isNotEmpty(memberList)) {
int realNameNum = (int) memberList.stream().filter(m -> StringUtils.isNotBlank(m.getIdCard())).count();
/* 注册人数 */
dataOverviewVO.setRegistrantsNum(memberList.size());
/* 实名注册人数 */
dataOverviewVO.setRealNameNum(realNameNum);
}
/* 培训项目数量 */
int classNum = classDictMapper.getClassCount();
dataOverviewVO.setClassNum(classNum);
List<CourseDictDO> courseList = courseDictMapper.selectList(new QueryWrapper<>());
if(CollectionUtils.isNotEmpty(courseList)) {
/* 资源数量 */
dataOverviewVO.setCourseNum(courseList.size());
/* 专项资源数量 */
int subsidyCourseNum = (int) courseList.stream().filter(courseDictDO -> StringUtils.isNotBlank(courseDictDO.getCourseType()) &&
courseDictDO.getCourseType().equals("补贴培训")).count();
dataOverviewVO.setSubsidyCourseNum(subsidyCourseNum);
}
/* 累计学习时长(小时) */
double studyTotal = vodPlayHistoryMapper.getStudyTotal();
if(studyTotal > 0) {
dataOverviewVO.setStudyTotal(new BigDecimal(studyTotal).divide(new BigDecimal(Math.pow(60, 2)), 2, BigDecimal.ROUND_UP).doubleValue());
}
/* 专项资源时(小时) */
double subsidyStudyTotal = vodPlayHistoryMapper.getSubsidyStudyTotal();
if(subsidyStudyTotal > 0) {
dataOverviewVO.setSubsidyStudyTotal(new BigDecimal(subsidyStudyTotal).divide(new BigDecimal(Math.pow(60,2)), 2, BigDecimal.ROUND_UP).doubleValue());
}
/* 学习过程记录人次 */
int studyHistoryNum = vodPlayHistoryMapper.getStudyHistoryNum();
dataOverviewVO.setStudyHistoryNum(studyHistoryNum);
return dataOverviewVO;
}
public MemberSummaryVO memberSummary(GetCompanyMembersDTO getCompanyMembersDTO){
MemberSummaryVO memberSummaryVO = new MemberSummaryVO();
......@@ -273,4 +358,59 @@ public class CompanyDictServiceImpl extends ServiceImpl<CompanyDictMapper, Compa
return memberSummaryVO;
}
@Override
public List<CDNStatDetailsVO> getCDNBandwidthStatDetails() {
/*
* 根据今天时间查询七天前的数据
* 先从缓存中获取数据,如果缓存中没有数据,从远程请求中获取, 避免频繁请求
* 缓存28800秒(8小时)失效,重新远程请求更新数据
*/
List<CDNStatDetailsVO> data = new ArrayList<>();
if(EhCacheUtil.getEhCache(VodConstant.CDN_STAT_DETAILS_CACHE_NAME, VodConstant.BANDWIDTH_CACHE_KEY) != null) {
return (List<CDNStatDetailsVO>) EhCacheUtil.getEhCache(VodConstant.CDN_STAT_DETAILS_CACHE_NAME, VodConstant.BANDWIDTH_CACHE_KEY);
} else {
String startDate =LocalDateTime.now().minusDays(6).withNano(0)+"+08:00";
String endDate = LocalDateTime.now().withNano(0)+"+08:00";
StatDataItem[] statDataItems = VodUtil.DescribeCDNStatDetails(vodConfig, VodConstant.BANDWIDTH ,startDate, endDate);
for (StatDataItem statDataItem : statDataItems) {
CDNStatDetailsVO sd = new CDNStatDetailsVO();
LocalDateTime localDateTime = LocalDateTime.parse(statDataItem.getTime().replace("+08:00",""));
Date date = DateFormatUtil.localDateTimeToDate(localDateTime);
sd.setTime(DateFormatUtil.format(date, DateFormatUtil.FMT_sdf_yMd));
BigDecimal bigDecimal = new BigDecimal(statDataItem.getValue()).divide(new BigDecimal(1000000));
sd.setValue(bigDecimal.setScale(2, BigDecimal.ROUND_UP));
data.add(sd);
}
EhCacheUtil.putEhCache(VodConstant.CDN_STAT_DETAILS_CACHE_NAME, VodConstant.BANDWIDTH_CACHE_KEY, data);
return data;
}
}
@Override
public List<CDNStatDetailsVO> getCDNFluxStatDetails() {
/*
* 根据今天时间查询七天前的数据
* 先从缓存中获取数据,如果缓存中没有数据,从远程请求中获取,避免频繁请求
* 缓存28800秒(8小时)失效,重新远程请求更新数据
*/
List<CDNStatDetailsVO> data = new ArrayList<>();
if(EhCacheUtil.getEhCache(VodConstant.CDN_STAT_DETAILS_CACHE_NAME, VodConstant.FLUX_CACHE_KEY) != null) {
return (List<CDNStatDetailsVO>) EhCacheUtil.getEhCache(VodConstant.CDN_STAT_DETAILS_CACHE_NAME, VodConstant.FLUX_CACHE_KEY);
} else {
String startDate =LocalDateTime.now().minusDays(6).withNano(0)+"+08:00";
String endDate = LocalDateTime.now().withNano(0)+"+08:00";
StatDataItem[] statDataItems = VodUtil.DescribeCDNStatDetails(vodConfig, VodConstant.FLUX ,startDate, endDate);
for (StatDataItem statDataItem : statDataItems) {
CDNStatDetailsVO sd = new CDNStatDetailsVO();
LocalDateTime localDateTime = LocalDateTime.parse(statDataItem.getTime().replace("+08:00",""));
Date date = DateFormatUtil.localDateTimeToDate(localDateTime);
sd.setTime(DateFormatUtil.format(date, DateFormatUtil.FMT_sdf_yMd));
BigDecimal bigDecimal = new BigDecimal(statDataItem.getValue()).divide(new BigDecimal(Math.pow(1000, 3)));
sd.setValue(bigDecimal.setScale(2, BigDecimal.ROUND_UP));
data.add(sd);
}
EhCacheUtil.putEhCache(VodConstant.CDN_STAT_DETAILS_CACHE_NAME, VodConstant.FLUX_CACHE_KEY, data);
return data;
}
}
}
......@@ -66,9 +66,9 @@ public class VodDictServiceImpl extends ServiceImpl<VodDictMapper, VodDictDO> im
if(null == vod) {
throw new HttpException(18000);
}
this.baseMapper.deleteById(vodDictDO.getId());
VodUtil.deleteMedia(vodDictDO.getVodCode());
this.baseMapper.deleteById(vodDictDO.getId());
VodUtil.deleteMedia(vodConfig, vodDictDO.getVodCode());
}
@Override
......@@ -85,12 +85,13 @@ public class VodDictServiceImpl extends ServiceImpl<VodDictMapper, VodDictDO> im
orderNo = vod.getOrderNo() + 1;
}
}
vodDictDO.setOrderNo(orderNo);
this.baseMapper.insert(vodDictDO);
//测试环境就不转码了
if (env.equals("prod")){
VodUtil.processMedia(vodDictDO.getVodCode());
VodUtil.processMedia(vodConfig, vodDictDO.getVodCode());
}
}
......
package com.subsidy.util;
import net.sf.ehcache.Cache;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.Element;
import org.springframework.util.ClassUtils;
/**
* <p>
* Ehcache
* </p>
*
* @author DengMin
* @since 2022/8/1
*/
public class EhCacheUtil {
static CacheManager cacheManager = CacheManager.newInstance(ClassUtils.getDefaultClassLoader().getResource("").getPath()+"ehcache.xml");
/**
* 添加缓存
* @param cacheName
* @param key
* @param value
*/
public static void putEhCache(String cacheName, String key, Object value) {
Cache cache = cacheManager.getCache(cacheName);
Element element = new Element(key, value);
cache.put(element);
}
/**
* 获取缓存数据
* @param cacheName
* @param key
* @return
*/
public static Object getEhCache(String cacheName, String key) {
Cache cache = cacheManager.getCache(cacheName);
Element element = cache.get(key);
return element == null ? null : element.getObjectValue();
}
/**
* 删除缓存
* @param cacheName
* @param key
*/
public static void deleteEhCache(String cacheName, String key) {
Cache cache = cacheManager.getCache(cacheName);
cache.remove(key);
}
}
......@@ -6,21 +6,28 @@ import com.tencentcloudapi.common.Credential;
import com.tencentcloudapi.common.exception.TencentCloudSDKException;
import com.tencentcloudapi.common.profile.ClientProfile;
import com.tencentcloudapi.common.profile.HttpProfile;
import com.tencentcloudapi.cvm.v20170312.models.DescribeZonesResponse;
import com.tencentcloudapi.vod.v20180717.VodClient;
import com.tencentcloudapi.vod.v20180717.models.DeleteMediaRequest;
import com.tencentcloudapi.vod.v20180717.models.DescribeCDNUsageDataRequest;
import com.tencentcloudapi.vod.v20180717.models.DescribeCDNUsageDataResponse;
import com.tencentcloudapi.vod.v20180717.models.MediaProcessTaskInput;
import com.tencentcloudapi.vod.v20180717.models.ProcessMediaRequest;
import com.tencentcloudapi.vod.v20180717.models.ProcessMediaResponse;
import com.tencentcloudapi.vod.v20180717.models.StatDataItem;
import com.tencentcloudapi.vod.v20180717.models.TranscodeTaskInput;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
/**
* <p>
* 腾讯云 - 云点播API
* </p>
*
* @author DengMin
* @since 2022/8/1
*/
@Component
public class VodUtil {
@Autowired
private static VODConfig vodConfig;
private static String endpoint = "vod.tencentcloudapi.com";
/**
......@@ -28,7 +35,7 @@ public class VodUtil {
* @param vodCode
* @return
*/
public static ProcessMediaResponse processMedia(String vodCode) {
public static ProcessMediaResponse processMedia(VODConfig vodConfig, String vodCode) {
try {
//上传后直接转码
Credential cred = new Credential(vodConfig.getSecretId(), vodConfig.getSecretKey());
......@@ -59,7 +66,7 @@ public class VodUtil {
* 删除腾讯云上原视频
* @param vodCode
*/
public static void deleteMedia(String vodCode) {
public static void deleteMedia(VODConfig vodConfig, String vodCode) {
try {
//删除原视频
Credential cred = new Credential(vodConfig.getSecretId(), vodConfig.getSecretKey());
......@@ -76,6 +83,41 @@ public class VodUtil {
// 返回的resp是一个DeleteMediaResponse的实例,与请求对象对应
client.DeleteMedia(req);
} catch (TencentCloudSDKException e) {
throw new HttpException(99999, e.getMessage());
}
}
/**
* 云点播域名的CDN统计数据
* @param vodConfig
* @param DataType
* @param startTime
* @param endTime
* @return
*/
public static StatDataItem[] DescribeCDNStatDetails(VODConfig vodConfig, String DataType, String startTime, String endTime) {
try {
Credential cred = new Credential(vodConfig.getSecretId(), vodConfig.getSecretKey());
// 实例化一个http选项,可选的,没有特殊需求可以跳过
HttpProfile httpProfile = new HttpProfile();
httpProfile.setEndpoint(endpoint);
// 实例化一个client选项,可选的,没有特殊需求可以跳过
ClientProfile clientProfile = new ClientProfile();
clientProfile.setHttpProfile(httpProfile);
// 实例化要请求产品的client对象,clientProfile是可选的
VodClient client = new VodClient(cred, "", clientProfile);
// 实例化一个请求对象,每个接口都会对应一个request对象
DescribeCDNUsageDataRequest req = new DescribeCDNUsageDataRequest();
req.setStartTime(startTime);
req.setEndTime(endTime);
req.setDataType(DataType);
// 返回的resp是一个DescribeCDNUsageDataResponse的实例,与请求对象对应
DescribeCDNUsageDataResponse resp = client.DescribeCDNUsageData(req);
// 返回的resp是一个DescribeCDNStatDetailsResponse的实例,与请求对象对应
return resp.getData();
} catch (TencentCloudSDKException e) {
e.printStackTrace();
throw new HttpException(99999, e.getMessage());
}
}
}
......@@ -40,6 +40,10 @@ public class WebSocketUtil implements WebSocketHandler {
@Autowired
private OprMemDictMapper oprMemDictMapper;
private int heartbeatMin = 1; // 断连最小心跳次数
private int heartbeatMax = 3; // 断连最大心跳次数
private int reconnectionSeconds = 60; //每次断连间隔重新连接秒
/**
* 存放建立连接webSocket对象
*/
......@@ -58,14 +62,13 @@ public class WebSocketUtil implements WebSocketHandler {
Long id = Long.valueOf(params.split("=")[1]);
if(null != webSocketMap && webSocketMap.get(id) != null) {
if(webSocketMap.get(id).isOpen()) {
/*
相同账户进行挤号,发送消息给前者WebSocket通知账户已在其他地方登录
*/
/* 相同账户进行挤号,发送消息给WebSocket通知账户已在其他地方登录 */
webSocketMap.get(id).sendMessage(new TextMessage(JSONObject.toJSONString(ResponseData.generateCreatedResponse(1011))));
webSocketMap.get(id).close();
} else {
/*
* 如果上次连接的WebSocket状态是关闭,并且上一次记录时间大于60秒的,则判断为这次登陆是免密码登陆的重新记录上线时间
* 如果上次连接的WebSocket状态是关闭,
* 并且上一次记录时间大于 { heartbeatMax * reconnectionSeconds } 秒(心跳检测机制),则判断为这次登陆是免密码登陆的重新记录上线时间
*/
List<OprMemDictDO> list = oprMemDictMapper.selectList(new QueryWrapper<OprMemDictDO>()
.lambda()
......@@ -74,7 +77,7 @@ public class WebSocketUtil implements WebSocketHandler {
Calendar calendar = Calendar.getInstance();
calendar.setTime(DateFormatUtil.localDateTimeToDate(list.get(0).getCreateDate()));
calendar.add(Calendar.SECOND,60);
calendar.add(Calendar.SECOND,heartbeatMax * reconnectionSeconds);
if(calendar.getTime().after(DateFormatUtil.localDateTimeToDate(list.get(0).getCreateDate()))) {
if(list.get(0).getOprType().equals("登出")) {
OprMemDictDO oprMemDictDO = new OprMemDictDO();
......@@ -127,9 +130,6 @@ public class WebSocketUtil implements WebSocketHandler {
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception{
if(null != session) {
/*
断开连接后不会马上判断为下线状态,而是进入60秒的心跳检测机制,如果60秒内没有进行重连,则判断为下线,记录下线时间和状态
*/
if(null != webSocketMap) {
String params = session.getUri().getQuery();
Long id = Long.valueOf(params.split("=")[1]);
......@@ -141,29 +141,36 @@ public class WebSocketUtil implements WebSocketHandler {
}
/**
* 断开连接后60秒后进行判断是否重新连接了,如果没有连接成功则判断为下线
* 断开连接后进行三次心跳验证判断是否重新连接了,如果没有连接成功则判断为下线
*
* @param session
*/
public void heartbeat(WebSocketSession session) {
ScheduledExecutorService service = Executors.newScheduledThreadPool(1);
ScheduledFuture scheduledFuture = service.scheduleAtFixedRate(new Runnable() {
int beatsNum = heartbeatMin;
@SneakyThrows
@Override
public void run() {
if(null != session && !session.isOpen()) {
String params = session.getUri().getQuery();
Long id = Long.valueOf(params.split("=")[1]);
OprMemDictDO oprMemDictDO = new OprMemDictDO();
oprMemDictDO.setUserId(id);
oprMemDictDO.setResult(1);
oprMemDictDO.setOprType("登出");
oprMemDictDO.setIpAddress(session.getRemoteAddress().getHostName());
oprMemDictMapper.insert(oprMemDictDO);
while (beatsNum > heartbeatMax) {
String params = session.getUri().getQuery();
Long id = Long.valueOf(params.split("=")[1]);
OprMemDictDO oprMemDictDO = new OprMemDictDO();
oprMemDictDO.setUserId(id);
oprMemDictDO.setResult(1);
oprMemDictDO.setOprType("登出");
oprMemDictDO.setIpAddress(session.getRemoteAddress().getHostName());
oprMemDictMapper.insert(oprMemDictDO);
taskMap.get(session.getId()).cancel(true);
}
beatsNum++;
} else if (null != session && session.isOpen()) {
/* 时间段内重新连接了结束验证 */
taskMap.get(session.getId()).cancel(true);
}
}
}, 1, 1, TimeUnit.MINUTES);
}, 0, reconnectionSeconds, TimeUnit.SECONDS);
taskMap.put(session.getId(), scheduledFuture);
}
......
package com.subsidy.vo.company;
import lombok.Data;
import java.io.Serializable;
import java.math.BigDecimal;
@Data
public class CDNStatDetailsVO implements Serializable {
private String time;
private BigDecimal value;
}
package com.subsidy.vo.company;
import lombok.Data;
@Data
public class DataOverviewVO {
/**
* 机构数
*/
private Integer companyNum;
/**
* 注册人数
*/
private Integer registrantsNum;
/**
* 实名制注册人数
*/
private Integer realNameNum;
/**
* 培训项目数量
*/
private Integer classNum;
/**
* 资源数量
*/
private Integer courseNum;
/**
* 学习过程记录人次
*/
private Integer studyHistoryNum;
/**
* 累计学习时长
*/
private Double studyTotal;
/**
* 专项资源数量
*/
private Integer subsidyCourseNum;
/**
* 专项资源时长
*/
private Double subsidyStudyTotal;
}
......@@ -2,7 +2,7 @@
spring.server.port=23457
# 数据源配置
spring.datasource.url=jdbc:mysql://47.97.19.66:3306/subsidy_test?autoReconnect=true&useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8
spring.datasource.url=jdbc:mysql://116.62.57.92:3306/subsidy_test?autoReconnect=true&useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8
#spring.datasource.url=jdbc:mysql://rm-uf6rab73w0qg843opxo.mysql.rds.aliyuncs.com:3306/subsidy_test?autoReconnect=true&useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
......
......@@ -34,6 +34,9 @@ mybatis-plus.global-config.db-config.logic-delete-value=NOW()
mybatis-plus.global-config.db-config.logic-not-delete-value=NULL
#日志配置
logging.config=classpath:logback-spring.xml
#ehcache缓存配置
spring.cache.type=ehcache
spring.cache.ehcache.config=classpath:ehcache.xml
# 阿里云短信
sms.product=Dysmsapi
sms.domain=dysmsapi.aliyuncs.com
......
<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd">
<diskStore path="java.io.tmpdir" />
<defaultCache eternal="false"
maxElementsInMemory="1000"
overflowToDisk="false"
diskPersistent="true"
timeToIdleSeconds="0"
timeToLiveSeconds="600"
memoryStoreEvictionPolicy="LRU" />
<!--
maxElementsInMemory 缓存最大个数,若放入Cache中的元素超过这个数值,则有以下两种情况
1)若overflowToDisk=true,则会将Cache中多出的元素放入磁盘文件中
2)若overflowToDisk=false,则根据memoryStoreEvictionPolicy策略替换Cache中原有的元素
eternal 缓存中对象是否永久有效
timeToIdleSeconds 缓存数据在失效前的允许闲置时间(单位:秒),仅当eternal=false时使用,默认值是0表示可闲置时间无穷大,若超过这个时间没有访问此Cache中的某个元素,那么此元素将被从Cache中清除
timeToLiveSeconds 缓存数据的总的存活时间(单位:秒),仅当eternal=false时使用,从创建开始计时,失效结束
overflowToDisk 内存不足时,是否启用磁盘缓存
diskPersistent 是否缓存虚拟机重启期数据
maxBytesLocalHeap 限制堆内存字节大小
-->
<!-- 云点播数据统计缓存 -->
<cache name="CDNStatDetails"
maxElementsInMemory="10000"
eternal="false"
overflowToDisk="false"
diskPersistent="false"
timeToIdleSeconds="0"
timeToLiveSeconds="28800"
memoryStoreEvictionPolicy="LRU"/>
<!-- 普通数据缓存 -->
<cache name="ResultData"
maxElementsInMemory="10000"
eternal="false"
overflowToDisk="false"
diskPersistent="false"
timeToIdleSeconds="0"
timeToLiveSeconds="7200"
memoryStoreEvictionPolicy="LRU"/>
</ehcache>
\ No newline at end of file
......@@ -169,4 +169,16 @@
AND cd.delete_date IS NULL
AND d.delete_date IS NULL
</select>
<select id="getClassCount" resultType="java.lang.Integer">
SELECT
count(t1.id)
FROM
class_dict t1
LEFT JOIN course_dict t2 ON t2.id = t1.course_id
WHERE
t2.course_type = "补贴培训"
AND t1.delete_date IS NULL
AND t2.delete_date IS NULL
</select>
</mapper>
......@@ -398,4 +398,36 @@
t.create_date
</select>
<select id="getStudyTotal" resultType="java.lang.Double">
SELECT
sum( play_length )
FROM
vod_play_history
WHERE
delete_date IS NULL
</select>
<select id="getSubsidyStudyTotal" resultType="java.lang.Double">
SELECT
sum( t1.play_length )
FROM
vod_play_history t1
LEFT JOIN class_dict t2 ON t2.id = t1.class_id
LEFT JOIN course_dict t3 ON t3.id = t2.course_id
WHERE
t3.course_type = "补贴培训"
AND t1.delete_date IS NULL
AND t2.delete_date IS NULL
AND t3.delete_date IS NULL
</select>
<select id="getStudyHistoryNum" resultType="java.lang.Integer">
SELECT
count(DISTINCT member_id)
FROM
vod_play_history
WHERE
delete_date IS NULL
</select>
</mapper>
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!