Reviewed-on: http://39.105.23.186:3000/develop/digimeta-MultiSaas/pulls/171tags/B.2.6.1_20240104_release
| @@ -62,6 +62,7 @@ public interface RemoteFileService { | |||
| R<Boolean> delete(@RequestParam (value = "url") String url); | |||
| @DeleteMapping(value = "/inner/delete-files") | |||
| R<Boolean> deleteFiles(@RequestParam (value = "urls") List<String> urls); | |||
| @PostMapping(value = "/inner/delete-files") | |||
| @Async | |||
| R<Boolean> deleteFiles(@RequestParam("urls") String[] urls); | |||
| } | |||
| @@ -6,6 +6,7 @@ import com.xueyi.file.api.feign.RemoteFileService; | |||
| import lombok.extern.slf4j.Slf4j; | |||
| import org.springframework.cloud.openfeign.FallbackFactory; | |||
| import org.springframework.stereotype.Component; | |||
| import org.springframework.web.bind.annotation.RequestParam; | |||
| import org.springframework.web.multipart.MultipartFile; | |||
| import java.util.List; | |||
| @@ -54,7 +55,7 @@ public class RemoteFileFallbackFactory implements FallbackFactory<RemoteFileServ | |||
| } | |||
| @Override | |||
| public R<Boolean> deleteFiles(List<String> urls) { | |||
| public R<Boolean> deleteFiles(@RequestParam("urls") String[] urls) { | |||
| return R.fail("删除文件失败:" + throwable.getMessage() ); | |||
| } | |||
| }; | |||
| @@ -0,0 +1,22 @@ | |||
| package com.xueyi.nlt.api.nlt.domain.vo.response; | |||
| import lombok.Data; | |||
| import lombok.NoArgsConstructor; | |||
| import java.io.Serial; | |||
| import java.io.Serializable; | |||
| import java.util.List; | |||
| @Data | |||
| @NoArgsConstructor | |||
| public class DmKnowledgeResponse implements Serializable { | |||
| @Serial | |||
| private static final long serialVersionUID = 1L; | |||
| private Integer accurate; | |||
| private String llm; | |||
| private String question; | |||
| private List<DmKnowledgeResultResponse> result; | |||
| private Integer target; | |||
| } | |||
| @@ -0,0 +1,22 @@ | |||
| package com.xueyi.nlt.api.nlt.domain.vo.response; | |||
| import lombok.Data; | |||
| import lombok.NoArgsConstructor; | |||
| import java.io.Serial; | |||
| import java.io.Serializable; | |||
| @Data | |||
| @NoArgsConstructor | |||
| public class DmKnowledgeResultResponse implements Serializable { | |||
| @Serial | |||
| private static final long serialVersionUID = 1L; | |||
| private String answer; | |||
| private Integer highlight; | |||
| private String id; | |||
| private String knowledgeLib; | |||
| private Integer modelType; | |||
| private String name; | |||
| } | |||
| @@ -2,7 +2,9 @@ package com.xueyi.nlt.api.nlt.feign; | |||
| import com.alibaba.fastjson.JSONObject; | |||
| import com.xueyi.common.core.web.result.AjaxResult; | |||
| import com.xueyi.common.core.web.result.R; | |||
| import com.xueyi.nlt.api.nlt.domain.vo.KnowledgeVo; | |||
| import com.xueyi.nlt.api.nlt.domain.vo.response.DmKnowledgeResponse; | |||
| import com.xueyi.nlt.api.nlt.feign.factory.RemoteQAFallbackFactory; | |||
| import com.xueyi.system.api.sms.domain.vo.SmsReqEntity; | |||
| import com.xueyi.system.api.sms.feign.factory.RemoteSmsFallbackFactory; | |||
| @@ -25,6 +27,6 @@ public interface RemoteQAService { | |||
| @GetMapping("/knowledge") | |||
| AjaxResult query(@RequestParam(value = "man_code") String manCode, @RequestParam(value = "question") String question, @RequestParam(value = "tenant_id") Long tenantId); | |||
| @PostMapping ("/knowledge") | |||
| AjaxResult query(@RequestBody KnowledgeVo vo); | |||
| R<DmKnowledgeResponse> query(@RequestBody KnowledgeVo vo); | |||
| } | |||
| @@ -0,0 +1,24 @@ | |||
| package com.xueyi.nlt.api.nlt.feign; | |||
| import com.alibaba.fastjson2.JSONObject; | |||
| import com.xueyi.nlt.api.nlt.domain.vo.WenxinErnieBotResponse; | |||
| import com.xueyi.nlt.api.nlt.feign.factory.RemoteLandingLlmFallbackFactory; | |||
| import org.springframework.cloud.openfeign.FeignClient; | |||
| import org.springframework.web.bind.annotation.GetMapping; | |||
| import org.springframework.web.bind.annotation.PostMapping; | |||
| import org.springframework.web.bind.annotation.RequestBody; | |||
| import org.springframework.web.bind.annotation.RequestParam; | |||
| @FeignClient(url = "${notification.seniverse.url}",name = "seniverse", fallbackFactory = RemoteLandingLlmFallbackFactory.class) | |||
| public interface RemoteSeniverseService { | |||
| @GetMapping("/v3/weather/now.json") | |||
| JSONObject now(@RequestParam("key") String key, | |||
| @RequestParam("location") String location, | |||
| @RequestParam("language") String language, | |||
| @RequestParam("unit") String unit); | |||
| } | |||
| @@ -1,7 +1,9 @@ | |||
| package com.xueyi.nlt.api.nlt.feign.factory; | |||
| import com.xueyi.common.core.web.result.AjaxResult; | |||
| import com.xueyi.common.core.web.result.R; | |||
| import com.xueyi.nlt.api.nlt.domain.vo.KnowledgeVo; | |||
| import com.xueyi.nlt.api.nlt.domain.vo.response.DmKnowledgeResponse; | |||
| import com.xueyi.nlt.api.nlt.feign.RemoteQAService; | |||
| import lombok.extern.slf4j.Slf4j; | |||
| import org.springframework.cloud.openfeign.FallbackFactory; | |||
| @@ -26,8 +28,8 @@ public class RemoteQAFallbackFactory implements FallbackFactory<RemoteQAService> | |||
| } | |||
| @Override | |||
| public AjaxResult query(KnowledgeVo vo) { | |||
| return AjaxResult.error("查询失败"); | |||
| public R<DmKnowledgeResponse> query(KnowledgeVo vo) { | |||
| return R.fail("知识库查询失败"); | |||
| } | |||
| }; | |||
| } | |||
| @@ -0,0 +1,30 @@ | |||
| package com.xueyi.nlt.api.nlt.feign.factory; | |||
| import com.alibaba.fastjson2.JSONObject; | |||
| import com.xueyi.nlt.api.nlt.domain.vo.DmLandingLlmVo; | |||
| import com.xueyi.nlt.api.nlt.feign.RemoteLandingLlmService; | |||
| import com.xueyi.nlt.api.nlt.feign.RemoteSeniverseService; | |||
| import lombok.extern.slf4j.Slf4j; | |||
| import org.springframework.cloud.openfeign.FallbackFactory; | |||
| import org.springframework.stereotype.Component; | |||
| /** | |||
| * 会议室服务 降级处理 | |||
| * | |||
| * @author xueyi | |||
| */ | |||
| @Slf4j | |||
| @Component | |||
| public class RemoteSeniverseFallbackFactory implements FallbackFactory<RemoteSeniverseService> { | |||
| @Override | |||
| public RemoteSeniverseService create(Throwable throwable) { | |||
| log.error("短信服务调用失败:{}", throwable.getMessage()); | |||
| return new RemoteSeniverseService() { | |||
| @Override | |||
| public JSONObject now(String key, String location, String language, String unit) { | |||
| return null; | |||
| } | |||
| }; | |||
| } | |||
| } | |||
| @@ -1,3 +1,4 @@ | |||
| com.xueyi.nlt.api.nlt.feign.factory.RemoteIntentFallbackFactory | |||
| com.xueyi.nlt.api.nlt.feign.factory.RemoteQAFallbackFactory | |||
| com.xueyi.nlt.api.nlt.feign.factory.RemoteLandingLlmFallbackFactory | |||
| com.xueyi.nlt.api.nlt.feign.factory.RemoteSeniverseFallbackFactory | |||
| @@ -39,6 +39,12 @@ | |||
| <artifactId>xueyi-api-tenant</artifactId> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>io.github.graphql-java</groupId> | |||
| <artifactId>graphql-java-annotations</artifactId> | |||
| <version>21.1</version> | |||
| </dependency> | |||
| </dependencies> | |||
| </project> | |||
| @@ -30,4 +30,7 @@ public interface RemoteLoginService { | |||
| @GetMapping("/login/inner/loginInfo/{enterpriseName}/{userName}/{password}") | |||
| R<LoginUser> getLoginInfoInner(@PathVariable("enterpriseName") String enterpriseName, @PathVariable("userName") String userName, @PathVariable("password") String password, @RequestHeader(SecurityConstants.FROM_SOURCE) String source); | |||
| @GetMapping("/login/inner/loginByPhone/{phone}") | |||
| R<LoginUser> getLoginInfoInnerByPhone(@PathVariable("phone") String phone, @RequestHeader(SecurityConstants.FROM_SOURCE) String source); | |||
| } | |||
| @@ -24,6 +24,11 @@ public class RemoteLoginFallbackFactory implements FallbackFactory<RemoteLoginSe | |||
| public R<LoginUser> getLoginInfoInner(String enterpriseName, String userName, String password, String source) { | |||
| return R.fail("获取登录信息失败:" + throwable.getMessage()); | |||
| } | |||
| @Override | |||
| public R<LoginUser> getLoginInfoInnerByPhone(String phone, String source) { | |||
| return R.fail("获取登录信息失败:" + throwable.getMessage()); | |||
| } | |||
| }; | |||
| } | |||
| } | |||
| @@ -1,13 +0,0 @@ | |||
| package com.xueyi.system.api.device.domain.vo; | |||
| import lombok.Data; | |||
| import lombok.NoArgsConstructor; | |||
| @Data | |||
| @NoArgsConstructor | |||
| public class DeviceTenantSourceMergeVo { | |||
| Long tenantId; | |||
| String sourceSlave; | |||
| } | |||
| @@ -2,8 +2,8 @@ package com.xueyi.system.api.device.feign; | |||
| import com.xueyi.common.core.constant.basic.ServiceConstants; | |||
| import com.xueyi.common.core.web.result.R; | |||
| import com.xueyi.common.core.web.vo.DeviceTenantSourceMergeVo; | |||
| import com.xueyi.system.api.device.domain.po.DmDeviceTenantMergePo; | |||
| import com.xueyi.system.api.device.domain.vo.DeviceTenantSourceMergeVo; | |||
| import com.xueyi.system.api.organize.feign.factory.RemoteUserFallbackFactory; | |||
| import com.xueyi.tenant.api.source.domain.po.TeSourcePo; | |||
| import org.springframework.cloud.openfeign.FeignClient; | |||
| @@ -67,4 +67,6 @@ public class DmManDevicePo extends BaseEntity { | |||
| /* 推流地址 */ | |||
| @Excel(name = "推流地址") | |||
| protected String streamUrl; | |||
| protected String configCreated; | |||
| } | |||
| @@ -77,6 +77,7 @@ public class DmVisitRecordsPo extends TBaseEntity { | |||
| public String toString(){ | |||
| return new StringBuilder("VisitorId: ").append(visitorId).append(", UserId: ").append(userId).append(", VisitDate: ").append(visitDate).append(", VisitTime: ").append(visitTime).append(", Duration: ").append(duration).append(", RecordStatus: ").append(recordStatus).append(", DeptId: ").append(deptId).append(", Num: ").append(num).toString(); | |||
| } | |||
| @@ -3,6 +3,7 @@ package com.xueyi.system.api.digitalmans.domain.po; | |||
| import com.baomidou.mybatisplus.annotation.TableName; | |||
| import com.xueyi.common.core.annotation.Excel; | |||
| import com.xueyi.common.core.web.tenant.base.TBaseEntity; | |||
| import graphql.annotations.annotationTypes.GraphQLField; | |||
| import lombok.Data; | |||
| import lombok.EqualsAndHashCode; | |||
| @@ -30,10 +31,12 @@ public class DmVisitorsPo extends TBaseEntity { | |||
| protected Long roomId; | |||
| /** 访客电话 */ | |||
| @GraphQLField | |||
| @Excel(name = "访客电话") | |||
| protected String phone; | |||
| /** 1:男;2:女 */ | |||
| @GraphQLField | |||
| @Excel(name = "1:男;2:女") | |||
| protected Integer gender; | |||
| @@ -42,10 +45,12 @@ public class DmVisitorsPo extends TBaseEntity { | |||
| protected Integer age; | |||
| /** 访客公司 */ | |||
| @GraphQLField | |||
| @Excel(name = "访客公司") | |||
| protected String visitorCompany; | |||
| /** 访客称呼 */ | |||
| @GraphQLField | |||
| @Excel(name = "访客称呼") | |||
| protected String nickname; | |||
| @@ -54,13 +59,16 @@ public class DmVisitorsPo extends TBaseEntity { | |||
| protected Long deptId; | |||
| /** 访客类型 */ | |||
| @GraphQLField | |||
| @Excel(name = "访客类型") | |||
| protected Long type; | |||
| /** 上传头像 */ | |||
| @GraphQLField | |||
| @Excel(name = "上传头像") | |||
| protected String avatar; | |||
| @GraphQLField | |||
| protected Long resourceId; | |||
| @@ -0,0 +1,19 @@ | |||
| package com.xueyi.system.api.digitalmans.domain.vo; | |||
| import lombok.Data; | |||
| import lombok.NoArgsConstructor; | |||
| import java.io.Serial; | |||
| @Data | |||
| @NoArgsConstructor | |||
| public class DmTipVo { | |||
| @Serial | |||
| private static final long serialVersionUID = 1L; | |||
| private Long id; | |||
| private String name; | |||
| //类型 0-播报知识库 1-大模型 | |||
| private Integer type; | |||
| } | |||
| @@ -3,6 +3,7 @@ package com.xueyi.system.api.digitalmans.feign; | |||
| import com.alibaba.fastjson2.JSONObject; | |||
| import com.xueyi.common.core.constant.basic.SecurityConstants; | |||
| import com.xueyi.common.core.constant.basic.ServiceConstants; | |||
| import com.xueyi.common.core.web.result.AjaxResult; | |||
| import com.xueyi.common.core.web.result.R; | |||
| import com.xueyi.system.api.digitalmans.domain.dto.DmManDeviceDto; | |||
| import com.xueyi.system.api.digitalmans.domain.dto.DmSyncDigitalmanDto; | |||
| @@ -53,7 +54,7 @@ public interface RemoteDigitalmanService { | |||
| @GetMapping("/man/api/mansInfo") | |||
| public R<JSONObject> mansInfo(); | |||
| @GetMapping("/man/delRecognizedRecords") | |||
| public R<JSONObject> delRecognizedRecords(@RequestParam(value = "day") Integer days); | |||
| @GetMapping("/man/api/delRecognizedRecords") | |||
| public AjaxResult delRecognizedRecords(@RequestParam(value = "day") Integer days); | |||
| } | |||
| @@ -6,10 +6,13 @@ import com.xueyi.common.core.constant.basic.ServiceConstants; | |||
| import com.xueyi.common.core.web.result.R; | |||
| import com.xueyi.system.api.digitalmans.domain.vo.DmBatchQuestionsVo; | |||
| import com.xueyi.system.api.digitalmans.domain.vo.DmReceptionVo; | |||
| import com.xueyi.system.api.digitalmans.domain.vo.DmTipVo; | |||
| import com.xueyi.system.api.organize.feign.factory.RemoteUserFallbackFactory; | |||
| import org.springframework.cloud.openfeign.FeignClient; | |||
| import org.springframework.web.bind.annotation.*; | |||
| import java.util.List; | |||
| @FeignClient(contextId = "remoteQuestionanswersService", value = ServiceConstants.SYSTEM_SERVICE, fallbackFactory = RemoteUserFallbackFactory.class) | |||
| public interface RemoteQuestionanswersService { | |||
| @@ -19,4 +22,8 @@ public interface RemoteQuestionanswersService { | |||
| public R<DmReceptionVo> batchInsertInner(@RequestBody DmBatchQuestionsVo dmBatchQuestionsVo, | |||
| @RequestHeader(SecurityConstants.ENTERPRISE_ID) Long enterpriseId, @RequestHeader(SecurityConstants.SOURCE_NAME) String sourceName, @RequestHeader(SecurityConstants.FROM_SOURCE) String source); | |||
| @GetMapping("/questions/inner/tipList") | |||
| @ResponseBody | |||
| R<List<DmTipVo>> tipList(@RequestHeader(SecurityConstants.ENTERPRISE_ID) Long enterpriseId, @RequestHeader(SecurityConstants.SOURCE_NAME) String sourceName, @RequestHeader(SecurityConstants.FROM_SOURCE) String source); | |||
| } | |||
| @@ -0,0 +1,16 @@ | |||
| package com.xueyi.system.api.interfaces.airport.domain.vo; | |||
| import lombok.Data; | |||
| import lombok.NoArgsConstructor; | |||
| import java.io.Serial; | |||
| @Data | |||
| @NoArgsConstructor | |||
| public class PlaneMessageVo { | |||
| @Serial | |||
| private static final long serialVersionUID = 1L; | |||
| private String fNum; | |||
| private String date; | |||
| } | |||
| @@ -0,0 +1,18 @@ | |||
| package com.xueyi.system.api.interfaces.airport.feign; | |||
| import com.alibaba.fastjson2.JSONObject; | |||
| import com.xueyi.common.core.constant.basic.ServiceConstants; | |||
| import com.xueyi.system.api.interfaces.airport.domain.vo.PlaneMessageVo; | |||
| import com.xueyi.system.api.interfaces.airport.feign.factory.RemotePlaneFallbackFactory; | |||
| import org.springframework.cloud.openfeign.FeignClient; | |||
| import org.springframework.web.bind.annotation.PostMapping; | |||
| import org.springframework.web.bind.annotation.RequestBody; | |||
| import org.springframework.web.bind.annotation.RequestHeader; | |||
| @FeignClient(contextId = "remotePlaneController", value = ServiceConstants.SYSTEM_SERVICE, fallbackFactory = RemotePlaneFallbackFactory.class) | |||
| public interface RemotePlaneController { | |||
| @PostMapping("/plane/api/query-flight") | |||
| public JSONObject queryFlight(@RequestBody(required = true)PlaneMessageVo planeMessageVo, | |||
| @RequestHeader("ts") String timestamp, @RequestHeader("sign") String sign); | |||
| } | |||
| @@ -0,0 +1,24 @@ | |||
| package com.xueyi.system.api.interfaces.airport.feign.factory; | |||
| import com.alibaba.fastjson2.JSONObject; | |||
| import com.xueyi.common.core.web.result.R; | |||
| import com.xueyi.system.api.interfaces.airport.domain.vo.PlaneMessageVo; | |||
| import com.xueyi.system.api.interfaces.airport.feign.RemotePlaneController; | |||
| import lombok.extern.slf4j.Slf4j; | |||
| import org.springframework.cloud.openfeign.FallbackFactory; | |||
| import org.springframework.stereotype.Component; | |||
| @Slf4j | |||
| @Component | |||
| public class RemotePlaneFallbackFactory implements FallbackFactory<RemotePlaneController> { | |||
| @Override | |||
| public RemotePlaneController create(Throwable throwable) { | |||
| log.error("航信服务调用失败:{}", throwable.getMessage()); | |||
| return new RemotePlaneController() { | |||
| @Override | |||
| public JSONObject queryFlight(PlaneMessageVo planeMessageVo,String timeStamp, String sign){ | |||
| return R.fail("航班信息服务调用失败:" + throwable.getMessage()).toJson(); | |||
| } | |||
| }; | |||
| } | |||
| } | |||
| @@ -1,5 +1,6 @@ | |||
| package com.xueyi.system.api.staff.domain.dto; | |||
| import com.alibaba.fastjson2.JSONObject; | |||
| import lombok.Data; | |||
| /** | |||
| @@ -35,6 +36,21 @@ public class DmVisitCommonDto { | |||
| private String visitorBase64Img; | |||
| public String toSmsJson(String code, String name, String companyName, String companyAddress, String parkInfo){ | |||
| JSONObject json = new JSONObject(); | |||
| json.put("code", code); | |||
| json.put("nickName", this.getVisitorName()); | |||
| json.put("robotName", name); | |||
| json.put("dateTime", this.getVisitDate()); | |||
| json.put("companyName", companyName); | |||
| json.put("companyAddr", companyAddress); | |||
| json.put("receiverName", this.getEmpName()); | |||
| json.put("receiverPhone", this.getEmpTel()); | |||
| json.put("parkInfo", parkInfo); | |||
| return json.toJSONString(); | |||
| } | |||
| @Override | |||
| public String toString() { | |||
| return "DmVisitCommonDto{" + | |||
| @@ -1,16 +1,13 @@ | |||
| package com.xueyi.system.api.staff.domain.po; | |||
| import java.util.Date; | |||
| import com.fasterxml.jackson.annotation.JsonFormat; | |||
| import com.xueyi.common.core.web.tenant.base.TBaseEntity; | |||
| import com.xueyi.common.core.annotation.Excel; | |||
| import com.baomidou.mybatisplus.annotation.TableName; | |||
| import com.xueyi.common.core.annotation.Excel; | |||
| import com.xueyi.common.core.web.tenant.base.TBaseEntity; | |||
| import lombok.Data; | |||
| import lombok.EqualsAndHashCode; | |||
| import java.io.Serial; | |||
| import static com.xueyi.common.core.constant.basic.EntityConstants.NAME; | |||
| import java.util.Date; | |||
| /** | |||
| * 人员 持久化对象 | |||
| @@ -95,4 +92,6 @@ public class DmStaffPo extends TBaseEntity { | |||
| @Excel(name = "入职日期") | |||
| protected Date hireDate; | |||
| private Long tenantId; | |||
| } | |||
| @@ -53,4 +53,8 @@ public interface RemoteStaffService { | |||
| @GetMapping("/staff/api/inner-recognized-records") | |||
| R<List<DmRecognizedRecordsPo>> _recognizedRecords(@RequestHeader(SecurityConstants.ENTERPRISE_ID) Long enterpriseId, @RequestHeader(SecurityConstants.SOURCE_NAME) String sourceName, @RequestHeader(SecurityConstants.FROM_SOURCE) String source); | |||
| @GetMapping("/staff/api/inner-del-recognized-records-img") | |||
| @ResponseBody | |||
| R delRecognizedRecordsImg(@RequestParam("day") Integer day, @RequestHeader(SecurityConstants.ENTERPRISE_ID) Long enterpriseId, @RequestHeader(SecurityConstants.SOURCE_NAME) String sourceName, @RequestHeader(SecurityConstants.FROM_SOURCE) String source); | |||
| } | |||
| @@ -9,3 +9,5 @@ com.xueyi.system.api.dict.feign.factory.RemoteConfigFallbackFactory | |||
| com.xueyi.system.api.log.feign.factory.RemoteLogFallbackFactory | |||
| com.xueyi.system.api.meeting.feign.factory.RemoteMeetingFallbackFactory | |||
| com.xueyi.system.api.resource.feign.factory.RemoteH5ConfigFallbackFactory | |||
| com.xueyi.system.api.interfaces.airport.feign.factory.RemotePlaneFallbackFactory | |||
| com.xueyi.system.api.sms.feign.factory.RemoteSmsFallbackFactory | |||
| @@ -0,0 +1,19 @@ | |||
| package com.xueyi.tenant.api.tenant.domain.dto; | |||
| import com.xueyi.tenant.api.tenant.domain.po.SysEnterpriseStaff; | |||
| import lombok.Data; | |||
| import lombok.EqualsAndHashCode; | |||
| /** | |||
| * 租户 数据传输对象 | |||
| * | |||
| * @author xueyi | |||
| */ | |||
| @Data | |||
| @EqualsAndHashCode(callSuper = true) | |||
| public class SysEnterpriseStaffDto extends SysEnterpriseStaff { | |||
| private static final long serialVersionUID = 1L; | |||
| private String oldPhone; | |||
| } | |||
| @@ -0,0 +1,30 @@ | |||
| package com.xueyi.tenant.api.tenant.domain.po; | |||
| import com.baomidou.mybatisplus.annotation.TableName; | |||
| import com.xueyi.common.core.web.tenant.base.TBaseEntity; | |||
| import lombok.Data; | |||
| import lombok.EqualsAndHashCode; | |||
| import java.io.Serial; | |||
| /** | |||
| * 人员 持久化对象 | |||
| * | |||
| * @author xueyi | |||
| */ | |||
| @Data | |||
| @EqualsAndHashCode(callSuper = true) | |||
| @TableName(value = "dm_enterprise_staff") | |||
| public class SysEnterpriseStaff extends TBaseEntity { | |||
| @Serial | |||
| private static final long serialVersionUID = 1L; | |||
| protected Long staffId; | |||
| protected String phone; | |||
| private Long tenantId; | |||
| private String openid; | |||
| } | |||
| @@ -63,4 +63,18 @@ public class TeTenantPo extends BaseEntity { | |||
| @TableField(updateStrategy = FieldStrategy.NEVER) | |||
| protected String isDefault; | |||
| @Override | |||
| public String toString(){ | |||
| return "TeTenantPo{" + | |||
| "strategyId=" + strategyId + | |||
| ", name='" + name + '\'' + | |||
| ", systemName='" + systemName + '\'' + | |||
| ", nick='" + nick + '\'' + | |||
| ", logo='" + logo + '\'' + | |||
| ", nameFrequency=" + nameFrequency + | |||
| ", isLessor='" + isLessor + '\'' + | |||
| ", isDefault='" + isDefault + '\'' + | |||
| '}'; | |||
| } | |||
| } | |||
| @@ -0,0 +1,21 @@ | |||
| package com.xueyi.tenant.api.tenant.domain.query; | |||
| import com.xueyi.tenant.api.tenant.domain.po.SysEnterpriseStaff; | |||
| import lombok.Data; | |||
| import lombok.EqualsAndHashCode; | |||
| import java.io.Serial; | |||
| /** | |||
| * 租户 数据查询对象 | |||
| * | |||
| * @author xueyi | |||
| */ | |||
| @Data | |||
| @EqualsAndHashCode(callSuper = true) | |||
| public class SysEnterpriseStaffQuery extends SysEnterpriseStaff { | |||
| @Serial | |||
| private static final long serialVersionUID = 1L; | |||
| } | |||
| @@ -5,6 +5,7 @@ import com.xueyi.common.core.constant.basic.SecurityConstants; | |||
| import com.xueyi.common.core.constant.basic.ServiceConstants; | |||
| import com.xueyi.common.core.web.result.R; | |||
| import com.xueyi.tenant.api.tenant.domain.dto.TeTenantDto; | |||
| import com.xueyi.tenant.api.tenant.domain.po.SysEnterpriseStaff; | |||
| import com.xueyi.tenant.api.tenant.domain.po.TeTenantPo; | |||
| import com.xueyi.tenant.api.tenant.feign.factory.RemoteTenantFallbackFactory; | |||
| import org.springframework.cloud.openfeign.FeignClient; | |||
| @@ -12,6 +13,7 @@ import org.springframework.web.bind.annotation.GetMapping; | |||
| import org.springframework.web.bind.annotation.PostMapping; | |||
| import org.springframework.web.bind.annotation.RequestBody; | |||
| import org.springframework.web.bind.annotation.RequestHeader; | |||
| import org.springframework.web.bind.annotation.RequestParam; | |||
| import java.util.List; | |||
| @@ -36,4 +38,15 @@ public interface RemoteTenantService { | |||
| @GetMapping("/tenant/tenant_list") | |||
| R<List<TeTenantDto>> tenantList(); | |||
| @GetMapping("/tenant/one") | |||
| R<TeTenantPo> tenant(@RequestParam ("phone") String phone, @RequestHeader(SecurityConstants.FROM_SOURCE) String source); | |||
| @GetMapping("/tenant/staff") | |||
| R<SysEnterpriseStaff> existStaff(@RequestParam ("phone") String phone, @RequestHeader(SecurityConstants.FROM_SOURCE) String source); | |||
| @PostMapping("/tenant/staff") | |||
| R<SysEnterpriseStaff> saveEnterpriseStaff(@RequestBody SysEnterpriseStaff staff, @RequestHeader(SecurityConstants.FROM_SOURCE) String source); | |||
| } | |||
| @@ -3,6 +3,8 @@ package com.xueyi.tenant.api.tenant.feign.factory; | |||
| import com.alibaba.fastjson2.JSONObject; | |||
| import com.xueyi.common.core.web.result.R; | |||
| import com.xueyi.tenant.api.tenant.domain.dto.TeTenantDto; | |||
| import com.xueyi.tenant.api.tenant.domain.po.SysEnterpriseStaff; | |||
| import com.xueyi.tenant.api.tenant.domain.po.TeTenantPo; | |||
| import com.xueyi.tenant.api.tenant.feign.RemoteTenantService; | |||
| import lombok.extern.slf4j.Slf4j; | |||
| import org.springframework.cloud.openfeign.FallbackFactory; | |||
| @@ -34,6 +36,22 @@ public class RemoteTenantFallbackFactory implements FallbackFactory<RemoteTenant | |||
| public R<List<TeTenantDto>> tenantList() { | |||
| return null; | |||
| } | |||
| @Override | |||
| public R<TeTenantPo> tenant(String phone, String source) { | |||
| return R.fail("获取租户失败:" + throwable.getMessage()); | |||
| } | |||
| @Override | |||
| public R<SysEnterpriseStaff> existStaff(String phone, String source) { | |||
| return R.fail("验证用户手机号失败:" + throwable.getMessage()); | |||
| } | |||
| @Override | |||
| public R<SysEnterpriseStaff> saveEnterpriseStaff(SysEnterpriseStaff staff, String source) { | |||
| return null; | |||
| } | |||
| }; | |||
| } | |||
| } | |||
| @@ -51,6 +51,11 @@ | |||
| <groupId>com.xueyi</groupId> | |||
| <artifactId>xueyi-common-security</artifactId> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>com.xueyi</groupId> | |||
| <artifactId>xueyi-common-sms</artifactId> | |||
| </dependency> | |||
| </dependencies> | |||
| @@ -1,24 +1,41 @@ | |||
| package com.xueyi.auth.controller; | |||
| import com.alibaba.fastjson2.JSONObject; | |||
| import com.baomidou.mybatisplus.core.toolkit.StringUtils; | |||
| import com.xueyi.auth.form.LoginBody; | |||
| import com.xueyi.auth.form.PhoneLoginBody; | |||
| import com.xueyi.auth.form.RegisterBody; | |||
| import com.xueyi.auth.service.SysLoginService; | |||
| import com.xueyi.common.core.constant.basic.SecurityConstants; | |||
| import com.xueyi.common.core.constant.basic.TenantConstants; | |||
| import com.xueyi.common.core.utils.JwtUtil; | |||
| import com.xueyi.common.core.utils.core.ObjectUtil; | |||
| import com.xueyi.common.core.utils.core.StrUtil; | |||
| import com.xueyi.common.core.web.result.AjaxResult; | |||
| import com.xueyi.common.core.web.result.R; | |||
| import com.xueyi.common.redis.service.RedisService; | |||
| import com.xueyi.common.security.auth.AuthUtil; | |||
| import com.xueyi.common.security.service.TokenService; | |||
| import com.xueyi.common.security.utils.SecurityUtils; | |||
| import com.xueyi.common.sms.configure.SmsProperties; | |||
| import com.xueyi.system.api.model.LoginUser; | |||
| import com.xueyi.system.api.sms.domain.vo.SmsReqEntity; | |||
| import com.xueyi.system.api.sms.feign.RemoteSmsService; | |||
| import com.xueyi.tenant.api.tenant.domain.po.SysEnterpriseStaff; | |||
| import com.xueyi.tenant.api.tenant.feign.RemoteTenantService; | |||
| import org.slf4j.Logger; | |||
| import org.springframework.beans.factory.annotation.Autowired; | |||
| import org.springframework.data.redis.core.RedisTemplate; | |||
| import org.springframework.web.bind.annotation.DeleteMapping; | |||
| import org.springframework.web.bind.annotation.GetMapping; | |||
| import org.springframework.web.bind.annotation.PostMapping; | |||
| import org.springframework.web.bind.annotation.RequestBody; | |||
| import org.springframework.web.bind.annotation.RequestParam; | |||
| import org.springframework.web.bind.annotation.RestController; | |||
| import javax.servlet.http.HttpServletRequest; | |||
| import javax.validation.Valid; | |||
| import java.util.concurrent.TimeUnit; | |||
| /** | |||
| * token 控制 | |||
| @@ -28,12 +45,36 @@ import javax.servlet.http.HttpServletRequest; | |||
| @RestController | |||
| public class TokenController { | |||
| private final Logger log = org.slf4j.LoggerFactory.getLogger(this.getClass()); | |||
| @Autowired | |||
| private TokenService tokenService; | |||
| @Autowired | |||
| private SysLoginService sysLoginService; | |||
| @Autowired | |||
| private RemoteSmsService smsService; | |||
| @Autowired | |||
| private RemoteSmsService remoteSmsService; | |||
| @Autowired | |||
| private SmsProperties smsProperties; | |||
| @Autowired | |||
| private RedisService redisService; | |||
| @Autowired | |||
| private RemoteTenantService tenantService; | |||
| @Autowired | |||
| private RedisTemplate<String, String> redisTemplate; | |||
| private final String REDIS_LOGIN_CODE_PIX = "saas:login:code:"; | |||
| @PostMapping("login") | |||
| public AjaxResult login(@RequestBody LoginBody form) { | |||
| // 用户登录 | |||
| @@ -42,6 +83,25 @@ public class TokenController { | |||
| return AjaxResult.success(tokenService.createToken(userInfo)); | |||
| } | |||
| @PostMapping("phoneLogin") | |||
| public AjaxResult loginByPhone(@Valid @RequestBody PhoneLoginBody form) { | |||
| /*if (!RedisUtil.existed(REDIS_LOGIN_CODE_PIX + form.getPhone())) { | |||
| return AjaxResult.error("手机号输入错误或验证码已过期"); | |||
| } else { | |||
| Integer code = (Integer) RedisUtil.getVal(REDIS_LOGIN_CODE_PIX + form.getPhone()); | |||
| if (null != code && !form.getCode().equals(code.toString())) { | |||
| return AjaxResult.error("验证码输入不正确"); | |||
| } | |||
| }*/ | |||
| // 用户手机号验证登录 | |||
| LoginUser userInfo = sysLoginService.loginByPhone(form.getPhone()); | |||
| if (null == userInfo) { | |||
| return AjaxResult.error("手机号不正确,清查验"); | |||
| } | |||
| // 获取登录token | |||
| return AjaxResult.success(tokenService.createToken(userInfo)); | |||
| } | |||
| @DeleteMapping("logout") | |||
| public AjaxResult logout(HttpServletRequest request) { | |||
| String token = SecurityUtils.getToken(request); | |||
| @@ -76,4 +136,35 @@ public class TokenController { | |||
| sysLoginService.register(registerBody); | |||
| return AjaxResult.success(); | |||
| } | |||
| @GetMapping("validCode") | |||
| public R validCode(@RequestParam String phone) { | |||
| R<SysEnterpriseStaff> staff = tenantService.existStaff(phone, SecurityConstants.INNER); | |||
| if (staff.getData() == null) { | |||
| return R.fail("手机号不存在,请查验"); | |||
| } | |||
| SmsReqEntity smsReqEntity = new SmsReqEntity(); | |||
| smsReqEntity.setPhone(phone); | |||
| String str = StrUtil.generateCode(); | |||
| if (StringUtils.isEmpty(phone)){ | |||
| return R.fail("手机号为空"); | |||
| } else { | |||
| if (redisService.hasKey(REDIS_LOGIN_CODE_PIX + phone)) { | |||
| return R.fail("之前请求的验证码并未失效,请查看短信或稍后重试"); | |||
| } else { | |||
| redisTemplate.opsForValue().setIfAbsent(REDIS_LOGIN_CODE_PIX + phone, str, 5, TimeUnit.MINUTES); | |||
| } | |||
| smsReqEntity.setTemplate(smsProperties.getCodeTemplate()); | |||
| JSONObject map = new JSONObject(); | |||
| map.put("code", str); | |||
| smsReqEntity.setDataMap(map.toJSONString()); | |||
| log.info("发送验证码成功,手机号:{},验证码:{}, sendReq:{}", phone, str, smsReqEntity.toJson().toJSONString()); | |||
| remoteSmsService.sendSms(smsReqEntity); | |||
| } | |||
| return R.ok("验证码发送成功,请查看短信"); | |||
| } | |||
| } | |||
| @@ -0,0 +1,21 @@ | |||
| package com.xueyi.auth.form; | |||
| import lombok.Data; | |||
| import javax.validation.constraints.NotEmpty; | |||
| /** | |||
| * 用户登录对象 | |||
| * | |||
| * @author xueyi | |||
| */ | |||
| @Data | |||
| public class PhoneLoginBody { | |||
| @NotEmpty(message = "手机号不能为空") | |||
| private String phone; | |||
| private String code; | |||
| } | |||
| @@ -18,6 +18,8 @@ import com.xueyi.system.api.log.feign.RemoteLogService; | |||
| import com.xueyi.system.api.model.LoginUser; | |||
| import com.xueyi.system.api.organize.domain.dto.SysUserDto; | |||
| import com.xueyi.tenant.api.tenant.feign.RemoteTenantService; | |||
| import org.slf4j.Logger; | |||
| import org.slf4j.LoggerFactory; | |||
| import org.springframework.beans.factory.annotation.Autowired; | |||
| import org.springframework.stereotype.Component; | |||
| @@ -29,6 +31,8 @@ import org.springframework.stereotype.Component; | |||
| @Component | |||
| public class SysLoginService { | |||
| private final Logger logger = LoggerFactory.getLogger(SysLoginService.class); | |||
| @Autowired | |||
| private RemoteLogService remoteLogService; | |||
| @@ -165,4 +169,17 @@ public class SysLoginService { | |||
| } | |||
| remoteLogService.saveLoginInfo(loginInfo, enterpriseId, sourceName, SecurityConstants.INNER); | |||
| } | |||
| public LoginUser loginByPhone(String phone) { | |||
| logger.info("phone:{}", phone); | |||
| R<LoginUser> loginInfoResult = remoteLoginService.getLoginInfoInnerByPhone(phone, SecurityConstants.INNER); | |||
| if (ObjectUtil.isNull(loginInfoResult.getData())) { | |||
| AjaxResult.warn("手机号可能输错,请查证后重试!"); | |||
| } | |||
| return loginInfoResult.getData(); | |||
| } | |||
| } | |||
| @@ -27,3 +27,4 @@ spring: | |||
| - application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension} | |||
| - application-secret-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension} | |||
| - application-datasource-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension} | |||
| - ali-sms.yml | |||
| @@ -0,0 +1 @@ | |||
| com.xueyi.common.web.entity.domain.mapper.DeviceTenantMergeMapper | |||
| @@ -21,7 +21,8 @@ public class SkillConstants { | |||
| INTRODUCE_STRANGER("24", "熟人介绍生人"), | |||
| BROADCAST_DISPLAY("25", "播报展示"), | |||
| OPEN_DOOR("26", "开门"), | |||
| DELIVERY("33", "寄快递"); | |||
| DELIVERY("33", "寄快递"), | |||
| FLIGHT("34", "航班信息"); | |||
| private final String code; | |||
| private final String info; | |||
| @@ -0,0 +1,88 @@ | |||
| package com.xueyi.common.core.utils; | |||
| import com.alibaba.fastjson.JSONObject; | |||
| import org.springframework.util.DigestUtils; | |||
| import javax.servlet.http.HttpServletRequest; | |||
| import java.io.IOException; | |||
| import java.nio.charset.StandardCharsets; | |||
| import java.util.ArrayList; | |||
| import java.util.List; | |||
| import java.util.Map; | |||
| import java.util.Set; | |||
| import java.util.stream.Collectors; | |||
| public class DecodeRequestUtils { | |||
| /** | |||
| * 获取Request中的JSON字符串 | |||
| * | |||
| * @param request | |||
| * @return | |||
| * @throws IOException | |||
| */ | |||
| public static String getRequestPostStr(HttpServletRequest request) throws IOException { | |||
| byte[] buffer = getRequestPostBytes(request); | |||
| if (buffer == null) { | |||
| return ""; | |||
| } | |||
| String charEncoding = request.getCharacterEncoding(); | |||
| if (charEncoding == null) { | |||
| charEncoding = "UTF-8"; | |||
| } | |||
| return new String(buffer, charEncoding); | |||
| } | |||
| private static byte[] getRequestPostBytes(HttpServletRequest request) throws IOException { | |||
| int contentLength = request.getContentLength(); | |||
| if (contentLength < 0) { | |||
| return null; | |||
| } | |||
| byte[] buffer = new byte[contentLength]; | |||
| for (int i = 0; i < contentLength; ) { | |||
| int readlen = request.getInputStream().read(buffer, i, | |||
| contentLength - i); | |||
| if (readlen == -1) { | |||
| break; | |||
| } | |||
| i += readlen; | |||
| } | |||
| return buffer; | |||
| } | |||
| /** | |||
| * JSON对象转为网址传参格式(按key的首字母从小到大排序) | |||
| * | |||
| * @param jsonObject | |||
| * @return | |||
| */ | |||
| public static String json2pathValue(JSONObject jsonObject) { | |||
| Map map = jsonObject.toJavaObject(Map.class); | |||
| Set<String> set = map.keySet(); | |||
| List<String> keyList = new ArrayList<>(set); | |||
| List<String> collect = keyList.stream().sorted().collect(Collectors.toList()); | |||
| StringBuilder stringBuilder = new StringBuilder(); | |||
| for (String s : collect) { | |||
| String value = map.get(s).toString(); | |||
| stringBuilder.append(s).append("=").append(value).append("&"); | |||
| } | |||
| stringBuilder.deleteCharAt(stringBuilder.lastIndexOf("&")); | |||
| return stringBuilder.toString(); | |||
| } | |||
| /** | |||
| * 计算sign签名 | |||
| * | |||
| * @param jsonObject | |||
| * @param genKey | |||
| * @return | |||
| */ | |||
| public static String calculateSign(JSONObject jsonObject, String genKey) { | |||
| String pathvalue = json2pathValue(jsonObject); | |||
| System.out.println(pathvalue); | |||
| pathvalue = pathvalue + "&gen_key=" + genKey; | |||
| System.out.println(pathvalue); | |||
| String sign = DigestUtils.md5DigestAsHex(pathvalue.getBytes(StandardCharsets.UTF_8)); | |||
| return sign; | |||
| } | |||
| } | |||
| @@ -0,0 +1,42 @@ | |||
| package com.xueyi.common.core.utils.core; | |||
| import javax.crypto.Cipher; | |||
| import javax.crypto.spec.SecretKeySpec; | |||
| import java.security.Key; | |||
| import java.util.Base64; | |||
| /** | |||
| * @author yk | |||
| * @description | |||
| * @date 2024-01-03 18:48 | |||
| */ | |||
| public class CryptoUtil { | |||
| public static final String DEFAULT_KEY = "7uw823wuyeuwiyeehbsuuwgwvsyyeuii"; | |||
| public static String encrypt(String data) throws Exception{ | |||
| Key k = new SecretKeySpec(DEFAULT_KEY.getBytes(), "AES"); | |||
| // 创建 Cipher 对象 | |||
| Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); | |||
| // 初始化 Cipher 对象 | |||
| cipher.init(Cipher.ENCRYPT_MODE, k); | |||
| // 加密数据 | |||
| byte[] ciphertext = cipher.doFinal(data.getBytes()); | |||
| // 输出密文 | |||
| return Base64.getEncoder().encodeToString(ciphertext); | |||
| } | |||
| public static String decrypt(String encryptedData) throws Exception { | |||
| byte[] encryptedDataBytes = Base64.getDecoder().decode(encryptedData); | |||
| Key k = new SecretKeySpec(DEFAULT_KEY.getBytes(), "AES"); | |||
| Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); | |||
| cipher.init(Cipher.DECRYPT_MODE, k); | |||
| byte[] decryptedBytes = cipher.doFinal(encryptedDataBytes); | |||
| //base64加密 | |||
| return new String(decryptedBytes); | |||
| } | |||
| } | |||
| @@ -20,4 +20,32 @@ public class NumberUtil extends cn.hutool.core.util.NumberUtil implements Number | |||
| return number == null ? 0 : number; | |||
| } | |||
| /** | |||
| * @Author yangkai | |||
| * @Description 将int类型的数据转化成X小时Y分钟的形式 | |||
| * @Date 2023/9/21 | |||
| * @Param | |||
| * @return | |||
| **/ | |||
| public static String convertMinutesToHoursMinutes(int minutes) { | |||
| if (minutes < 0) { | |||
| throw new IllegalArgumentException("分钟数不能为负数"); | |||
| } | |||
| int hours = minutes / 60; | |||
| int remainingMinutes = minutes % 60; | |||
| String hourMin = String.format("%d小时%d分钟", hours, remainingMinutes); | |||
| //如果小时数为0,则不显示"小时" | |||
| if (hours == 0) { | |||
| hourMin = String.format("%d分钟", remainingMinutes); | |||
| } | |||
| //如果分钟数为0,则不显示"分钟" | |||
| if (remainingMinutes == 0) { | |||
| hourMin = String.format("%d小时", hours); | |||
| } | |||
| return hourMin; | |||
| } | |||
| } | |||
| @@ -1,9 +1,29 @@ | |||
| package com.xueyi.common.core.utils.core; | |||
| import java.lang.annotation.Annotation; | |||
| import java.lang.reflect.Field; | |||
| import java.util.HashSet; | |||
| import java.util.Set; | |||
| /** | |||
| * 对象工具类 | |||
| * | |||
| * @author xueyi | |||
| */ | |||
| public class ObjectUtil extends cn.hutool.core.util.ObjectUtil { | |||
| public static Set<String> findAnnotatedFields(Class<?> clazz, Class<? extends Annotation> annotationClass) { | |||
| Set<String> annotatedFields = new HashSet<String>(); | |||
| for (Field field : clazz.getDeclaredFields()) { | |||
| if (field.isAnnotationPresent(annotationClass)) { | |||
| annotatedFields.add(field.getName()); | |||
| } | |||
| } | |||
| return annotatedFields; | |||
| } | |||
| } | |||
| @@ -190,4 +190,10 @@ public class StrUtil extends cn.hutool.core.util.StrUtil implements StrPool { | |||
| return result.toString(); | |||
| } | |||
| public static String generateCode() { | |||
| String timeStr = String.valueOf(System.currentTimeMillis()); | |||
| return timeStr.substring(timeStr.length() - 4 ); | |||
| } | |||
| } | |||
| @@ -0,0 +1,16 @@ | |||
| package com.xueyi.common.core.web.vo; | |||
| import lombok.Data; | |||
| import lombok.NoArgsConstructor; | |||
| import java.io.Serializable; | |||
| @Data | |||
| @NoArgsConstructor | |||
| public class DeviceTenantSourceMergeVo implements Serializable { | |||
| Long tenantId; | |||
| String sourceSlave; | |||
| String devId; | |||
| } | |||
| @@ -106,6 +106,7 @@ public class BaseTokenService<User, LoginUser extends BaseLoginUser<User>> { | |||
| Map<String, Object> rspMap = new HashMap<>(); | |||
| rspMap.put("access_token", JwtUtil.createToken(claimsMap)); | |||
| rspMap.put("expires_in", getTacitExpireTime()); | |||
| rspMap.put("tenant_id", enterpriseId); | |||
| return rspMap; | |||
| } | |||
| @@ -141,6 +142,7 @@ public class BaseTokenService<User, LoginUser extends BaseLoginUser<User>> { | |||
| return redisService.getCacheMapValue(getTokenKey(userKey), SecurityConstants.BaseSecurity.ENTERPRISE.getCode()); | |||
| } | |||
| } catch (Exception ignored) { | |||
| System.err.println(ignored.getMessage());; | |||
| } | |||
| return null; | |||
| } | |||
| @@ -177,6 +179,7 @@ public class BaseTokenService<User, LoginUser extends BaseLoginUser<User>> { | |||
| return redisService.getCacheMapValue(getTokenKey(userKey), SecurityConstants.BaseSecurity.USER.getCode()); | |||
| } | |||
| } catch (Exception ignored) { | |||
| System.err.println(ignored.getMessage());; | |||
| } | |||
| return null; | |||
| } | |||
| @@ -213,6 +216,7 @@ public class BaseTokenService<User, LoginUser extends BaseLoginUser<User>> { | |||
| return redisService.getCacheMapValue(getTokenKey(userKey), SecurityConstants.BaseSecurity.LOGIN_USER.getCode()); | |||
| } | |||
| } catch (Exception ignored) { | |||
| System.err.println(ignored.getMessage());; | |||
| } | |||
| return null; | |||
| } | |||
| @@ -260,6 +264,7 @@ public class BaseTokenService<User, LoginUser extends BaseLoginUser<User>> { | |||
| return redisService.getCacheMapValue(getTokenKey(userKey), SecurityConstants.BaseSecurity.SOURCE.getCode()); | |||
| } | |||
| } catch (Exception ignored) { | |||
| System.err.println(ignored.getMessage());; | |||
| } | |||
| return null; | |||
| } | |||
| @@ -297,6 +302,7 @@ public class BaseTokenService<User, LoginUser extends BaseLoginUser<User>> { | |||
| return redisService.getCacheMapValue(getTokenKey(userKey), SecurityConstants.BaseSecurity.EXPIRE_TIME.getCode()); | |||
| } | |||
| } catch (Exception ignored) { | |||
| System.err.println(ignored.getMessage());; | |||
| } | |||
| return null; | |||
| } | |||
| @@ -329,7 +335,7 @@ public class BaseTokenService<User, LoginUser extends BaseLoginUser<User>> { | |||
| */ | |||
| public void refreshToken(HttpServletRequest request) { | |||
| String token = SecurityUtils.getToken(request); | |||
| refreshToken(SecurityUtils.getToken(request)); | |||
| refreshToken(token); | |||
| } | |||
| /** | |||
| @@ -4,9 +4,6 @@ import com.xueyi.common.redis.service.RedisService; | |||
| import org.springframework.beans.factory.annotation.Autowired; | |||
| import org.springframework.stereotype.Component; | |||
| import java.util.HashSet; | |||
| import java.util.Set; | |||
| /** | |||
| * spring sms 工具类 | |||
| * | |||
| @@ -19,6 +16,7 @@ public class SmsService { | |||
| @Autowired | |||
| private RedisService redisService; | |||
| /** | |||
| * @Author yangkai | |||
| * @Description //发送验证码,取时间戳后四位 | |||
| @@ -27,7 +25,6 @@ public class SmsService { | |||
| * @return | |||
| **/ | |||
| public String sendCode(){ | |||
| Set<String> codes = new HashSet<>(); | |||
| String code = ""; | |||
| //确保不重复 | |||
| while(true) { | |||
| @@ -0,0 +1,40 @@ | |||
| package com.xueyi.common.web.config; | |||
| import com.xueyi.common.web.interceptor.ApiRequestInterceptor; | |||
| import org.springframework.context.annotation.Bean; | |||
| import org.springframework.context.annotation.Configuration; | |||
| import org.springframework.web.servlet.config.annotation.InterceptorRegistry; | |||
| import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; | |||
| /** | |||
| * 拦截器配置 | |||
| * | |||
| * @author xueyi | |||
| */ | |||
| @Configuration | |||
| public class WebApiMvcConfig implements WebMvcConfigurer { | |||
| /** | |||
| * 不需要拦截地址 | |||
| */ | |||
| public static final String[] excludeUrls = {"/login", "/logout", "/refresh"}; | |||
| @Override | |||
| public void addInterceptors(InterceptorRegistry registry) { | |||
| System.err.println("WebMvcConfig.addInterceptors======================hshshkbb"); | |||
| registry.addInterceptor(getApiInterceptor()) | |||
| .addPathPatterns("/8888") | |||
| // .addPathPatterns("/**") | |||
| .excludePathPatterns(excludeUrls) | |||
| .order(1); | |||
| } | |||
| /** | |||
| * 自定义请求头拦截器 | |||
| */ | |||
| @Bean | |||
| public ApiRequestInterceptor getApiInterceptor() { | |||
| return new ApiRequestInterceptor(); | |||
| } | |||
| } | |||
| @@ -2,9 +2,10 @@ package com.xueyi.common.web.controller; | |||
| import com.baomidou.mybatisplus.core.toolkit.StringUtils; | |||
| import com.google.common.collect.Lists; | |||
| import com.xueyi.common.core.web.vo.DeviceTenantSourceMergeVo; | |||
| import com.xueyi.common.web.constant.ResponseCode; | |||
| import com.xueyi.common.web.entity.domain.BaseReq; | |||
| import com.xueyi.common.web.response.MyResponse; | |||
| import com.xueyi.system.api.device.domain.vo.DeviceTenantSourceMergeVo; | |||
| import com.xueyi.system.api.device.feign.RemoteDeviceTenantMergeService; | |||
| import org.springframework.beans.factory.annotation.Autowired; | |||
| @@ -21,6 +22,43 @@ public class BaseApiController { | |||
| private MyResponse message = null; | |||
| public MyResponse checkSign(Object t, String sign, String ts){ | |||
| System.err.println("----------header check start----------"); | |||
| if (ts == null || ts.isEmpty()) { | |||
| return output(400, "ts is null"); | |||
| } | |||
| if (sign == null || sign.isEmpty()) { | |||
| return new MyResponse(400, "sign is null"); | |||
| } | |||
| ts.replace(".", ""); | |||
| Long tsVal = Long.parseLong(ts); | |||
| if (ts.length() == 10) { | |||
| // 将10位时间戳转为13位 | |||
| tsVal *= 1000; | |||
| } | |||
| Long currentTs = System.currentTimeMillis(); | |||
| if (currentTs - tsVal > 1000 * 60 || tsVal - currentTs > 1000 * 60){//时间误差正负1分钟内为合法 | |||
| return new MyResponse(400, "请求时间戳ts非法"); | |||
| } | |||
| System.err.println("----------header check complete----------"); | |||
| BaseReq req = null; | |||
| String signStr = ""; | |||
| if (t instanceof BaseReq) { | |||
| req = (BaseReq) t; | |||
| signStr = req.getSign(ts); | |||
| } | |||
| System.err.println(signStr); | |||
| System.err.println(sign); | |||
| System.err.println("----------sign check end----------"); | |||
| if (!sign.equals(signStr)) { | |||
| return output(ResponseCode.AUTH_NOT_PASS); | |||
| } | |||
| return new MyResponse(200); | |||
| } | |||
| public DeviceTenantSourceMergeVo getDeviceTenantSourceMergeVo(String devId){ | |||
| return remoteDeviceTenantMergeService.selectDeviceTenantSourceMerge(devId); | |||
| } | |||
| @@ -0,0 +1,45 @@ | |||
| package com.xueyi.common.web.entity.domain; | |||
| import lombok.Data; | |||
| import org.springframework.util.DigestUtils; | |||
| import java.lang.reflect.Field; | |||
| import java.util.Arrays; | |||
| /** | |||
| * @author yk | |||
| * @description | |||
| * @date 2023-12-06 11:45 | |||
| */ | |||
| @Data | |||
| public class BaseReq { | |||
| public String getSign(String ts){ | |||
| Field[] fields = this.getClass().getDeclaredFields(); | |||
| StringBuilder sb = new StringBuilder(); | |||
| //fields按name字典排序 | |||
| Arrays.sort(fields, (o1, o2) -> o1.getName().compareTo(o2.getName())); | |||
| for (Field field : fields) { | |||
| //设置允许通过反射访问私有变量 | |||
| field.setAccessible(true); | |||
| //获取字段属性名称 | |||
| String name = field.getName(); | |||
| //获取字段的值 | |||
| String value = null; | |||
| try { | |||
| value = field.get(this).toString(); | |||
| sb.append(value); | |||
| } catch (IllegalAccessException e) { | |||
| throw new RuntimeException(e); | |||
| } | |||
| //其他自定义操作 | |||
| System.out.println("字段的属性名称:"+name); | |||
| System.out.println("字段的值:"+value); | |||
| } | |||
| String parmas = sb.toString()+ts; | |||
| System.err.println("加密前的参数:"+parmas); | |||
| //返回md5加密后的值 | |||
| return DigestUtils.md5DigestAsHex(parmas.getBytes()); | |||
| } | |||
| } | |||
| @@ -0,0 +1,21 @@ | |||
| package com.xueyi.common.web.entity.domain.mapper; | |||
| import com.xueyi.common.core.web.vo.DeviceTenantSourceMergeVo; | |||
| import com.xueyi.common.web.annotation.TenantIgnore; | |||
| import com.xueyi.common.web.entity.domain.provider.DeviceTenantSqlProvider; | |||
| import org.apache.ibatis.annotations.Mapper; | |||
| import org.apache.ibatis.annotations.Param; | |||
| import org.apache.ibatis.annotations.SelectProvider; | |||
| /** | |||
| * 设备租户(企业)关联管理 数据封装层 | |||
| * | |||
| * @author xueyi | |||
| */ | |||
| @Mapper | |||
| public interface DeviceTenantMergeMapper { | |||
| @TenantIgnore(tenantLine = true) | |||
| @SelectProvider(type= DeviceTenantSqlProvider.class, method="selectDeviceTenant") | |||
| DeviceTenantSourceMergeVo selectByDeviceId(@Param("deviceId") String deviceId); | |||
| } | |||
| @@ -0,0 +1,14 @@ | |||
| package com.xueyi.common.web.entity.domain.provider; | |||
| import org.apache.ibatis.annotations.Param; | |||
| /** | |||
| * @author yk | |||
| * @description | |||
| * @date 2023-11-25 11:15 | |||
| */ | |||
| public class DeviceTenantSqlProvider { | |||
| public String selectDeviceTenant(@Param("deviceId") String deviceId) { | |||
| return "SELECT ddtm.dev_id, ddtm.tenant_id, s.source_slave FROM dm_device_tenant_merge ddtm JOIN te_tenant t ON t.id=ddtm.tenant_id JOIN te_strategy s ON s.id=t.strategy_id AND dev_id= #{deviceId}"; | |||
| } | |||
| } | |||
| @@ -0,0 +1,82 @@ | |||
| package com.xueyi.common.web.interceptor; | |||
| import com.alibaba.fastjson.JSONObject; | |||
| import com.xueyi.common.core.constant.basic.SecurityConstants; | |||
| import com.xueyi.common.core.context.SecurityContextHolder; | |||
| import com.xueyi.common.core.utils.DecodeRequestUtils; | |||
| import com.xueyi.common.core.web.vo.DeviceTenantSourceMergeVo; | |||
| import com.xueyi.common.web.entity.domain.mapper.DeviceTenantMergeMapper; | |||
| import com.xueyi.system.api.device.feign.RemoteDeviceTenantMergeService; | |||
| import org.apache.commons.lang3.StringUtils; | |||
| import org.slf4j.Logger; | |||
| import org.slf4j.LoggerFactory; | |||
| import org.springframework.beans.factory.annotation.Autowired; | |||
| import org.springframework.web.method.HandlerMethod; | |||
| import org.springframework.web.servlet.HandlerInterceptor; | |||
| import javax.servlet.http.HttpServletRequest; | |||
| import javax.servlet.http.HttpServletResponse; | |||
| /** | |||
| * 自定义API拦截器,验证api请求权限 | |||
| * 会根据传入的deviceId值,验证权限 | |||
| * | |||
| * @author xueyi | |||
| */ | |||
| public class ApiRequestInterceptor implements HandlerInterceptor { | |||
| private static final Logger logger = LoggerFactory.getLogger(ApiRequestInterceptor.class); | |||
| @Autowired | |||
| RemoteDeviceTenantMergeService remoteDeviceTenantMergeService; | |||
| @Autowired | |||
| private DeviceTenantMergeMapper mergeMapper; | |||
| //为以下方法加行级注释 | |||
| @Override | |||
| public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { | |||
| if (!(handler instanceof HandlerMethod)) { | |||
| return true; | |||
| } | |||
| String str = DecodeRequestUtils.getRequestPostStr(request); | |||
| logger.info("请求参数:{}", str); | |||
| JSONObject jsonObject = null; | |||
| if (str.indexOf("{")>-1) { | |||
| jsonObject = JSONObject.parseObject(str);// 解析请求参数 | |||
| } | |||
| if ((request.getParameterMap().containsKey("deviceId")||request.getParameterMap().containsKey("devId")) || (jsonObject!=null && (jsonObject.containsKey("deviceId")||jsonObject.containsKey("devId")))) { | |||
| String devId = request.getParameter("deviceId"); | |||
| devId = StringUtils.isEmpty(devId) ? request.getParameter("devId") : devId; | |||
| if (StringUtils.isEmpty(devId) && jsonObject != null) { | |||
| devId = jsonObject.getString("deviceId"); | |||
| devId = StringUtils.isEmpty(devId) ? jsonObject.getString("devId") : devId; | |||
| } | |||
| /*DeviceTenantSourceMergeVo vo = null; | |||
| if (RedisUtil.existed("saas:source:device:" + devId)) { | |||
| vo = (DeviceTenantSourceMergeVo) RedisUtil.getVal("saas:source:device:" + devId); | |||
| } else { | |||
| vo = remoteDeviceTenantMergeService.selectDeviceTenantSourceMerge(devId); | |||
| RedisUtil.setVal("saas:source:device:" + devId, vo); | |||
| }*/ | |||
| DeviceTenantSourceMergeVo vo = mergeMapper.selectByDeviceId(devId);// 查询设备与租户、来源的关联关系 | |||
| SecurityContextHolder.setEnterpriseId(vo.getTenantId().toString());// 设置企业ID | |||
| SecurityContextHolder.setSourceName(vo.getSourceSlave());// 设置数据源名称 | |||
| SecurityContextHolder.set(SecurityConstants.FROM_SOURCE, SecurityConstants.INNER);// 设置数据来源 | |||
| } | |||
| return true; | |||
| } | |||
| @Override | |||
| public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { | |||
| SecurityContextHolder.remove(); | |||
| } | |||
| } | |||
| @@ -7,6 +7,7 @@ import java.text.DecimalFormat; | |||
| import java.text.ParseException; | |||
| import java.text.ParsePosition; | |||
| import java.text.SimpleDateFormat; | |||
| import java.time.LocalDate; | |||
| import java.time.LocalDateTime; | |||
| import java.time.LocalTime; | |||
| import java.time.ZoneId; | |||
| @@ -16,334 +17,358 @@ import java.util.GregorianCalendar; | |||
| import java.util.List; | |||
| public class DateUtils extends org.apache.commons.lang.time.DateUtils { | |||
| public DateUtils() { | |||
| } | |||
| public static Date getPushForwardDate(Date date, Integer num) { | |||
| if (date == null) { | |||
| return null; | |||
| } else { | |||
| Calendar calendar = Calendar.getInstance(); | |||
| calendar.setTime(date); | |||
| calendar.add(5, -(num - 1)); | |||
| calendar.set(11, 0); | |||
| calendar.set(12, 0); | |||
| calendar.set(13, 0); | |||
| calendar.set(14, 0); | |||
| return calendar.getTime(); | |||
| } | |||
| } | |||
| public static Date getFixedPushForwardDate(Date date, Integer num) { | |||
| if (date == null) { | |||
| return null; | |||
| } else { | |||
| Calendar calendar = Calendar.getInstance(); | |||
| calendar.setTime(date); | |||
| calendar.add(5, -(num)); | |||
| calendar.set(11, 0); | |||
| calendar.set(12, 0); | |||
| calendar.set(13, 0); | |||
| calendar.set(14, 0); | |||
| return calendar.getTime(); | |||
| } | |||
| } | |||
| public static Date getOfDayFirst(Date date) { | |||
| if (date == null) { | |||
| return null; | |||
| } else { | |||
| Calendar calendar = Calendar.getInstance(); | |||
| calendar.setTime(date); | |||
| calendar.set(11, 0); | |||
| calendar.set(12, 0); | |||
| calendar.set(13, 0); | |||
| calendar.set(14, 0); | |||
| return calendar.getTime(); | |||
| } | |||
| } | |||
| public static Date getOfDayLast(Date date) { | |||
| if (date == null) { | |||
| return null; | |||
| } else { | |||
| Calendar calendar = Calendar.getInstance(); | |||
| calendar.setTime(date); | |||
| calendar.set(11, 23); | |||
| calendar.set(12, 59); | |||
| calendar.set(13, 59); | |||
| calendar.set(14, 999); | |||
| return calendar.getTime(); | |||
| } | |||
| } | |||
| public static Date getPageDayLast(Date date) { | |||
| if (date == null) { | |||
| return null; | |||
| } else { | |||
| Calendar calendar = Calendar.getInstance(); | |||
| calendar.setTime(date); | |||
| calendar.add(5, -1); | |||
| calendar.set(11, 23); | |||
| calendar.set(12, 59); | |||
| calendar.set(13, 59); | |||
| calendar.set(14, 999); | |||
| return calendar.getTime(); | |||
| } | |||
| } | |||
| public static Date getFirstDayOfMonth(Date date) { | |||
| new SimpleDateFormat("yyyy-MM-dd "); | |||
| GregorianCalendar gcLast = (GregorianCalendar)Calendar.getInstance(); | |||
| gcLast.setTime(date); | |||
| gcLast.set(Calendar.DAY_OF_MONTH, 1); | |||
| return gcLast.getTime(); | |||
| } | |||
| public static Date getLastDayOfMonth(Date date) { | |||
| Calendar calendar = Calendar.getInstance(); | |||
| calendar.setTime(date); | |||
| calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMaximum(Calendar.DAY_OF_MONTH)); | |||
| return calendar.getTime(); | |||
| } | |||
| public static Date getAttendanceTime(Date date) { | |||
| Calendar calendar = Calendar.getInstance(); | |||
| calendar.setTime(date); | |||
| calendar.add(5, -2); | |||
| calendar.set(11, 23); | |||
| return calendar.getTime(); | |||
| } | |||
| public static String getStartTime() { | |||
| Date dNow = new Date(); | |||
| new Date(); | |||
| Calendar calendar = Calendar.getInstance(); | |||
| calendar.setTime(dNow); | |||
| calendar.add(5, -1); | |||
| Date dBefore = calendar.getTime(); | |||
| SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); | |||
| return sdf.format(dBefore); | |||
| } | |||
| /*/** | |||
| * @Author yangkai | |||
| * @Description 根据字符串日期返回星期几 | |||
| * @Param [datetime] | |||
| * @return java.lang.String | |||
| **/ | |||
| public static String dateToWeek(String datetime) { | |||
| SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd"); | |||
| String[] weekDays = new String[]{"星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"}; | |||
| Calendar cal = Calendar.getInstance(); | |||
| Date datet = null; | |||
| try { | |||
| datet = f.parse(datetime); | |||
| cal.setTime(datet); | |||
| } catch (ParseException var6) { | |||
| var6.printStackTrace(); | |||
| } | |||
| int w = cal.get(7) - 1; | |||
| if (w < 0) { | |||
| w = 0; | |||
| } | |||
| return weekDays[w]; | |||
| } | |||
| public static String getDatePoor(Date endDate, Date nowDate) { | |||
| long nd = 86400000L; | |||
| long nh = 3600000L; | |||
| long nm = 60000L; | |||
| long diff = endDate.getTime() - nowDate.getTime(); | |||
| long day = diff / nd; | |||
| long hour = diff % nd / nh; | |||
| long min = diff % nd % nh / nm; | |||
| return day + ":" + hour; | |||
| } | |||
| /** | |||
| * 1 2 3 4 5 6 7 | |||
| * 日 一 二 三 四 五 六 | |||
| * @param date | |||
| * @return | |||
| */ | |||
| public static Integer getDayOfWeek(Date date) { | |||
| Calendar calendar = Calendar.getInstance(); | |||
| calendar.setTime(date); | |||
| return calendar.get(Calendar.DAY_OF_WEEK); | |||
| } | |||
| public static List<String> generateNearlyDateString(Date currentDate, Integer nearlyDays) { | |||
| Calendar calendar = Calendar.getInstance(); | |||
| calendar.setTime(currentDate); | |||
| List<String> dateStringList = Lists.newLinkedList(); | |||
| for(int i = 0; i < nearlyDays; ++i) { | |||
| calendar.add(5, i == 0 ? 0 : -1); | |||
| dateStringList.add(formatDate(calendar.getTime(), "yyyy-MM-dd")); | |||
| } | |||
| return dateStringList; | |||
| } | |||
| public static String dateDiff(Date startDate, Date endDate) { | |||
| if (null != startDate && null != endDate) { | |||
| Long mills = endDate.getTime() - startDate.getTime(); | |||
| Integer minuteDiff = mills.intValue() / '\uea60'; | |||
| Integer hours = minuteDiff / 60; | |||
| Integer minutes = minuteDiff % 60; | |||
| String hoursStr = hours + "h"; | |||
| String minutesStr = minutes == 0 ? "" : minutes + "m"; | |||
| return hoursStr + minutesStr; | |||
| } else { | |||
| return "0h"; | |||
| } | |||
| } | |||
| public static Integer dateDiffMin(Date startDate, Date endDate) { | |||
| if (null != startDate && null != endDate) { | |||
| Long mills = endDate.getTime() - startDate.getTime(); | |||
| Integer minuteDiff = mills.intValue() / '\uea60'; | |||
| Integer hours = minuteDiff / 60; | |||
| Integer minutes = minuteDiff % 60; | |||
| return hours * 60 + minutes; | |||
| } else { | |||
| return 0; | |||
| } | |||
| } | |||
| public static String intToHourMin(Integer minuteDiff) { | |||
| Integer hours = minuteDiff / 60; | |||
| Integer minutes = minuteDiff % 60; | |||
| return hours+"小时"+ minutes+"分"; | |||
| } | |||
| public static String formatDate(Date date, String pattern) { | |||
| SimpleDateFormat sdf = new SimpleDateFormat(pattern); | |||
| return sdf.format(date); | |||
| } | |||
| public static Date praseStringToDate(String dateStr) throws ParseException { | |||
| SimpleDateFormat sdf = new SimpleDateFormat(); | |||
| return sdf.parse(dateStr); | |||
| } | |||
| public static Date parseLongToDate(Long dateLong) throws ParseException { | |||
| Calendar calendar = Calendar.getInstance(); | |||
| calendar.setTimeInMillis(dateLong); | |||
| return calendar.getTime(); | |||
| } | |||
| public static Date parseLongToDate(String dateLong) throws ParseException { | |||
| BigDecimal number = new BigDecimal(dateLong); | |||
| return parseLongToDate(number.doubleValue()); | |||
| } | |||
| public static Date parseLongToDate(Double dateLong) throws ParseException { | |||
| Calendar calendar = Calendar.getInstance(); | |||
| DecimalFormat df = new DecimalFormat("#"); // 创建DecimalFormat对象 | |||
| String str = df.format(dateLong); | |||
| if (str.indexOf(".")>-1) { | |||
| str = str.replace(".",""); | |||
| } | |||
| str = str.substring(0,13); | |||
| BigDecimal number = new BigDecimal(str); | |||
| calendar.setTimeInMillis(number.longValue()); | |||
| return calendar.getTime(); | |||
| } | |||
| public static String praseLongToDateString(Long dateLong) throws ParseException { | |||
| Calendar calendar = Calendar.getInstance(); | |||
| calendar.setTimeInMillis(dateLong); | |||
| Date date = calendar.getTime(); | |||
| return formatDate(date, "yyyy-MM-dd HH:mm:ss"); | |||
| } | |||
| public static String getMillsSecondsDouble() { | |||
| Long cutime = System.currentTimeMillis(); | |||
| String cutimeStr = String.valueOf(cutime); | |||
| BigDecimal d = new BigDecimal(cutimeStr.substring(0, 10) + "." + cutimeStr.substring(10)); | |||
| return d.stripTrailingZeros().toPlainString(); | |||
| } | |||
| /** | |||
| * | |||
| * @param time 2018-07-06 19:35:23 | |||
| * @param pattern yyyy-MM-dd HH:mm:ss | |||
| * @return | |||
| */ | |||
| public static Date parseStrToDate(String time, String pattern) { | |||
| SimpleDateFormat formatter = new SimpleDateFormat(pattern); | |||
| ParsePosition pos = new ParsePosition(0); | |||
| return formatter.parse(time, pos); | |||
| } | |||
| //形如yyyy-MM-dd格式的时间串,赠加或减少几天 | |||
| //如2022-06-06 增加一天 返回 2022-06-07 | |||
| public static String dateStrAdd(String dateStr, int addDays){ | |||
| Date date1 = DateUtils.parseStrToDate(dateStr, "yyyy-MM-dd"); | |||
| Date date2 = DateUtils.addDays(date1, addDays); | |||
| String dateStr2 = DateUtils.formatDate(date2, "yyyy-MM-dd"); | |||
| return dateStr2; | |||
| } | |||
| public static int dateStrDiff(String startDateStr, String endDateStr) { | |||
| Date date1 = DateUtils.parseStrToDate(startDateStr, "yyyy-MM-dd"); | |||
| Date date2 = DateUtils.parseStrToDate(endDateStr, "yyyy-MM-dd"); | |||
| Calendar cal1 = Calendar.getInstance(); | |||
| cal1.setTime(date1); | |||
| Calendar cal2 = Calendar.getInstance(); | |||
| cal2.setTime(date2); | |||
| int day1= cal1.get(Calendar.DAY_OF_YEAR); | |||
| int day2 = cal2.get(Calendar.DAY_OF_YEAR); | |||
| int year1 = cal1.get(Calendar.YEAR); | |||
| int year2 = cal2.get(Calendar.YEAR); | |||
| if (year1 != year2) {//同一年 | |||
| int timeDistance = 0; | |||
| for (int i = year1; i < year2; i++) { | |||
| if (i % 4 == 0 && i % 100 != 0 || i % 400 == 0) //闰年 | |||
| { | |||
| timeDistance += 366; | |||
| } else { | |||
| timeDistance += 365; | |||
| } | |||
| } | |||
| return timeDistance + (day2 - day1); | |||
| } else {// 不同年 | |||
| return day2 - day1; | |||
| } | |||
| } | |||
| public static LocalDateTime currentDateToLocalDateTime(){ | |||
| Date todayDate = new Date(); | |||
| return dateToLocalDateTime(todayDate); | |||
| } | |||
| public static LocalDateTime dateToLocalDateTime(Date date){ | |||
| LocalDateTime ldt = date.toInstant() | |||
| .atZone( ZoneId.systemDefault() ) | |||
| .toLocalDateTime(); | |||
| return ldt; | |||
| } | |||
| public static String isAmPm(){ | |||
| //判断当前时间是上午还是下午,上午返回am,下午返回pm | |||
| LocalTime currentTime = LocalTime.now(); | |||
| if (currentTime.isBefore(LocalTime.NOON)) { | |||
| return "am"; | |||
| } else { | |||
| return "pm"; | |||
| } | |||
| } | |||
| public DateUtils() { | |||
| } | |||
| public static Date getPushForwardDate(Date date, Integer num) { | |||
| if (date == null) { | |||
| return null; | |||
| } else { | |||
| Calendar calendar = Calendar.getInstance(); | |||
| calendar.setTime(date); | |||
| calendar.add(5, -(num - 1)); | |||
| calendar.set(11, 0); | |||
| calendar.set(12, 0); | |||
| calendar.set(13, 0); | |||
| calendar.set(14, 0); | |||
| return calendar.getTime(); | |||
| } | |||
| } | |||
| public static Date getFixedPushForwardDate(Date date, Integer num) { | |||
| if (date == null) { | |||
| return null; | |||
| } else { | |||
| Calendar calendar = Calendar.getInstance(); | |||
| calendar.setTime(date); | |||
| calendar.add(5, -(num)); | |||
| calendar.set(11, 0); | |||
| calendar.set(12, 0); | |||
| calendar.set(13, 0); | |||
| calendar.set(14, 0); | |||
| return calendar.getTime(); | |||
| } | |||
| } | |||
| public static Date getOfDayFirst(Date date) { | |||
| if (date == null) { | |||
| return null; | |||
| } else { | |||
| Calendar calendar = Calendar.getInstance(); | |||
| calendar.setTime(date); | |||
| calendar.set(11, 0); | |||
| calendar.set(12, 0); | |||
| calendar.set(13, 0); | |||
| calendar.set(14, 0); | |||
| return calendar.getTime(); | |||
| } | |||
| } | |||
| public static Date getOfDayLast(Date date) { | |||
| if (date == null) { | |||
| return null; | |||
| } else { | |||
| Calendar calendar = Calendar.getInstance(); | |||
| calendar.setTime(date); | |||
| calendar.set(11, 23); | |||
| calendar.set(12, 59); | |||
| calendar.set(13, 59); | |||
| calendar.set(14, 999); | |||
| return calendar.getTime(); | |||
| } | |||
| } | |||
| public static Date getPageDayLast(Date date) { | |||
| if (date == null) { | |||
| return null; | |||
| } else { | |||
| Calendar calendar = Calendar.getInstance(); | |||
| calendar.setTime(date); | |||
| calendar.add(5, -1); | |||
| calendar.set(11, 23); | |||
| calendar.set(12, 59); | |||
| calendar.set(13, 59); | |||
| calendar.set(14, 999); | |||
| return calendar.getTime(); | |||
| } | |||
| } | |||
| public static Date getFirstDayOfMonth(Date date) { | |||
| new SimpleDateFormat("yyyy-MM-dd "); | |||
| GregorianCalendar gcLast = (GregorianCalendar) Calendar.getInstance(); | |||
| gcLast.setTime(date); | |||
| gcLast.set(Calendar.DAY_OF_MONTH, 1); | |||
| return gcLast.getTime(); | |||
| } | |||
| public static Date getLastDayOfMonth(Date date) { | |||
| Calendar calendar = Calendar.getInstance(); | |||
| calendar.setTime(date); | |||
| calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMaximum(Calendar.DAY_OF_MONTH)); | |||
| return calendar.getTime(); | |||
| } | |||
| public static Date getAttendanceTime(Date date) { | |||
| Calendar calendar = Calendar.getInstance(); | |||
| calendar.setTime(date); | |||
| calendar.add(5, -2); | |||
| calendar.set(11, 23); | |||
| return calendar.getTime(); | |||
| } | |||
| public static String getStartTime() { | |||
| Date dNow = new Date(); | |||
| new Date(); | |||
| Calendar calendar = Calendar.getInstance(); | |||
| calendar.setTime(dNow); | |||
| calendar.add(5, -1); | |||
| Date dBefore = calendar.getTime(); | |||
| SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); | |||
| return sdf.format(dBefore); | |||
| } | |||
| /*/** | |||
| * @Author yangkai | |||
| * @Description 根据字符串日期返回星期几 | |||
| * @Param [datetime] | |||
| * @return java.lang.String | |||
| **/ | |||
| public static String dateToWeek(String datetime) { | |||
| SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd"); | |||
| String[] weekDays = new String[]{"星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"}; | |||
| Calendar cal = Calendar.getInstance(); | |||
| Date datet = null; | |||
| try { | |||
| datet = f.parse(datetime); | |||
| cal.setTime(datet); | |||
| } catch (ParseException var6) { | |||
| var6.printStackTrace(); | |||
| } | |||
| int w = cal.get(7) - 1; | |||
| if (w < 0) { | |||
| w = 0; | |||
| } | |||
| return weekDays[w]; | |||
| } | |||
| public static String getDatePoor(Date endDate, Date nowDate) { | |||
| long nd = 86400000L; | |||
| long nh = 3600000L; | |||
| long nm = 60000L; | |||
| long diff = endDate.getTime() - nowDate.getTime(); | |||
| long day = diff / nd; | |||
| long hour = diff % nd / nh; | |||
| long min = diff % nd % nh / nm; | |||
| return day + ":" + hour; | |||
| } | |||
| /** | |||
| * 1 2 3 4 5 6 7 | |||
| * 日 一 二 三 四 五 六 | |||
| * | |||
| * @param date | |||
| * @return | |||
| */ | |||
| public static Integer getDayOfWeek(Date date) { | |||
| Calendar calendar = Calendar.getInstance(); | |||
| calendar.setTime(date); | |||
| return calendar.get(Calendar.DAY_OF_WEEK); | |||
| } | |||
| public static List<String> generateNearlyDateString(Date currentDate, Integer nearlyDays) { | |||
| Calendar calendar = Calendar.getInstance(); | |||
| calendar.setTime(currentDate); | |||
| List<String> dateStringList = Lists.newLinkedList(); | |||
| for (int i = 0; i < nearlyDays; ++i) { | |||
| calendar.add(5, i == 0 ? 0 : -1); | |||
| dateStringList.add(formatDate(calendar.getTime(), "yyyy-MM-dd")); | |||
| } | |||
| return dateStringList; | |||
| } | |||
| public static String dateDiff(Date startDate, Date endDate) { | |||
| if (null != startDate && null != endDate) { | |||
| Long mills = endDate.getTime() - startDate.getTime(); | |||
| Integer minuteDiff = mills.intValue() / '\uea60'; | |||
| Integer hours = minuteDiff / 60; | |||
| Integer minutes = minuteDiff % 60; | |||
| String hoursStr = hours + "h"; | |||
| String minutesStr = minutes == 0 ? "" : minutes + "m"; | |||
| return hoursStr + minutesStr; | |||
| } else { | |||
| return "0h"; | |||
| } | |||
| } | |||
| public static Integer dateDiffMin(Date startDate, Date endDate) { | |||
| if (null != startDate && null != endDate) { | |||
| Long mills = endDate.getTime() - startDate.getTime(); | |||
| Integer minuteDiff = mills.intValue() / '\uea60'; | |||
| Integer hours = minuteDiff / 60; | |||
| Integer minutes = minuteDiff % 60; | |||
| return hours * 60 + minutes; | |||
| } else { | |||
| return 0; | |||
| } | |||
| } | |||
| public static String intToHourMin(Integer minuteDiff) { | |||
| Integer hours = minuteDiff / 60; | |||
| Integer minutes = minuteDiff % 60; | |||
| return hours + "小时" + minutes + "分"; | |||
| } | |||
| public static String formatDate(Date date, String pattern) { | |||
| SimpleDateFormat sdf = new SimpleDateFormat(pattern); | |||
| return sdf.format(date); | |||
| } | |||
| public static Date praseStringToDate(String dateStr) throws ParseException { | |||
| SimpleDateFormat sdf = new SimpleDateFormat(); | |||
| return sdf.parse(dateStr); | |||
| } | |||
| public static Date parseLongToDate(Long dateLong) throws ParseException { | |||
| Calendar calendar = Calendar.getInstance(); | |||
| calendar.setTimeInMillis(dateLong); | |||
| return calendar.getTime(); | |||
| } | |||
| public static Date parseLongToDate(String dateLong) throws ParseException { | |||
| BigDecimal number = new BigDecimal(dateLong); | |||
| return parseLongToDate(number.doubleValue()); | |||
| } | |||
| public static Date parseLongToDate(Double dateLong) throws ParseException { | |||
| Calendar calendar = Calendar.getInstance(); | |||
| DecimalFormat df = new DecimalFormat("#"); // 创建DecimalFormat对象 | |||
| String str = df.format(dateLong); | |||
| if (str.indexOf(".") > -1) { | |||
| str = str.replace(".", ""); | |||
| } | |||
| str = str.substring(0, 13); | |||
| BigDecimal number = new BigDecimal(str); | |||
| calendar.setTimeInMillis(number.longValue()); | |||
| return calendar.getTime(); | |||
| } | |||
| public static String praseLongToDateString(Long dateLong) throws ParseException { | |||
| Calendar calendar = Calendar.getInstance(); | |||
| calendar.setTimeInMillis(dateLong); | |||
| Date date = calendar.getTime(); | |||
| return formatDate(date, "yyyy-MM-dd HH:mm:ss"); | |||
| } | |||
| public static String getMillsSecondsDouble() { | |||
| Long cutime = System.currentTimeMillis(); | |||
| String cutimeStr = String.valueOf(cutime); | |||
| BigDecimal d = new BigDecimal(cutimeStr.substring(0, 10) + "." + cutimeStr.substring(10)); | |||
| return d.stripTrailingZeros().toPlainString(); | |||
| } | |||
| /** | |||
| * @param time 2018-07-06 19:35:23 | |||
| * @param pattern yyyy-MM-dd HH:mm:ss | |||
| * @return | |||
| */ | |||
| public static Date parseStrToDate(String time, String pattern) { | |||
| SimpleDateFormat formatter = new SimpleDateFormat(pattern); | |||
| ParsePosition pos = new ParsePosition(0); | |||
| return formatter.parse(time, pos); | |||
| } | |||
| //形如yyyy-MM-dd格式的时间串,赠加或减少几天 | |||
| //如2022-06-06 增加一天 返回 2022-06-07 | |||
| public static String dateStrAdd(String dateStr, int addDays) { | |||
| Date date1 = DateUtils.parseStrToDate(dateStr, "yyyy-MM-dd"); | |||
| Date date2 = DateUtils.addDays(date1, addDays); | |||
| String dateStr2 = DateUtils.formatDate(date2, "yyyy-MM-dd"); | |||
| return dateStr2; | |||
| } | |||
| public static int dateStrDiff(String startDateStr, String endDateStr) { | |||
| Date date1 = DateUtils.parseStrToDate(startDateStr, "yyyy-MM-dd"); | |||
| Date date2 = DateUtils.parseStrToDate(endDateStr, "yyyy-MM-dd"); | |||
| Calendar cal1 = Calendar.getInstance(); | |||
| cal1.setTime(date1); | |||
| Calendar cal2 = Calendar.getInstance(); | |||
| cal2.setTime(date2); | |||
| int day1 = cal1.get(Calendar.DAY_OF_YEAR); | |||
| int day2 = cal2.get(Calendar.DAY_OF_YEAR); | |||
| int year1 = cal1.get(Calendar.YEAR); | |||
| int year2 = cal2.get(Calendar.YEAR); | |||
| if (year1 != year2) {//同一年 | |||
| int timeDistance = 0; | |||
| for (int i = year1; i < year2; i++) { | |||
| if (i % 4 == 0 && i % 100 != 0 || i % 400 == 0) //闰年 | |||
| { | |||
| timeDistance += 366; | |||
| } else { | |||
| timeDistance += 365; | |||
| } | |||
| } | |||
| return timeDistance + (day2 - day1); | |||
| } else {// 不同年 | |||
| return day2 - day1; | |||
| } | |||
| } | |||
| public static LocalDateTime currentDateToLocalDateTime() { | |||
| Date todayDate = new Date(); | |||
| return dateToLocalDateTime(todayDate); | |||
| } | |||
| public static LocalDateTime dateToLocalDateTime(Date date) { | |||
| LocalDateTime ldt = date.toInstant() | |||
| .atZone(ZoneId.systemDefault()) | |||
| .toLocalDateTime(); | |||
| return ldt; | |||
| } | |||
| public static String isAmPm() { | |||
| //判断当前时间是上午还是下午,上午返回am,下午返回pm | |||
| LocalTime currentTime = LocalTime.now(); | |||
| if (currentTime.isBefore(LocalTime.NOON)) { | |||
| return "am"; | |||
| } else { | |||
| return "pm"; | |||
| } | |||
| } | |||
| public static String getChineseWeek(Date date) { | |||
| int week = LocalDate.parse(new SimpleDateFormat("yyyy-MM-dd").format(date)).getDayOfWeek().getValue(); | |||
| switch (week) { | |||
| case 1: | |||
| return "周一"; | |||
| case 2: | |||
| return "周二"; | |||
| case 3: | |||
| return "周三"; | |||
| case 4: | |||
| return "周四"; | |||
| case 5: | |||
| return "周五"; | |||
| case 6: | |||
| return "周六"; | |||
| case 7: | |||
| return "周日"; | |||
| default: | |||
| return ""; | |||
| } | |||
| } | |||
| } | |||
| @@ -3,4 +3,6 @@ com.xueyi.common.web.config.XueYiMyBatisPlusConfig | |||
| com.xueyi.common.web.config.XueYiMyRespConfig | |||
| com.xueyi.common.web.handler.XueYiMetaObjectHandler | |||
| com.xueyi.common.web.handler.TenantLineHandler | |||
| com.xueyi.common.web.aspect.AutoInjectAspect | |||
| com.xueyi.common.web.aspect.AutoInjectAspect | |||
| com.xueyi.common.web.config.WebApiMvcConfig | |||
| com.xueyi.common.web.interceptor.ApiRequestInterceptor | |||
| @@ -37,7 +37,8 @@ public class AuthFilter implements GlobalFilter, Ordered { | |||
| @Autowired | |||
| private RedisService redisService; | |||
| private static final String[] whitePrefix = {"/message/api", "/pass/api", "/meeting/api", "/visit/api", "/file/api","/staff/api","/apkversion/api","/man/api","/holiday/api", "/skill/api", "/intent/api","/system/api","/dept/api"}; | |||
| //TODO. 需要删除,通过nacos配置管理白名单 | |||
| // private static final String[] whitePrefix = {"/message/api", "/pass/api", "/visit/api", "/file/api","/staff/api","/apkversion/api","/man/api","/device/api","/holiday/api", "/skill/api", "/intent/api","/system/api"}; | |||
| @Override | |||
| public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { | |||
| @@ -49,9 +50,9 @@ public class AuthFilter implements GlobalFilter, Ordered { | |||
| if (StrUtil.matches(url, ignoreWhite.getWhites())) { | |||
| return chain.filter(exchange); | |||
| } | |||
| // 跳过不需要验证的路径. | |||
| for (String item : whitePrefix) | |||
| if (url.contains(item)) return chain.filter(exchange); | |||
| // TODO. 需要删除 跳过不需要验证的路径. | |||
| /*for (String item : whitePrefix) | |||
| if (url.contains(item)) return chain.filter(exchange);*/ | |||
| String token = getToken(request); | |||
| if (StrUtil.isEmpty(token)) { | |||
| @@ -78,6 +78,12 @@ | |||
| <version>2.0.29</version> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>com.qiniu</groupId> | |||
| <artifactId>qiniu-java-sdk</artifactId> | |||
| <version>[7.13.0, 7.13.99]</version> | |||
| </dependency> | |||
| </dependencies> | |||
| <build> | |||
| @@ -0,0 +1,54 @@ | |||
| package com.xueyi.file.config; | |||
| import com.qiniu.storage.Region; | |||
| import com.qiniu.storage.UploadManager; | |||
| import com.qiniu.util.Auth; | |||
| import lombok.Data; | |||
| import org.springframework.boot.context.properties.ConfigurationProperties; | |||
| import org.springframework.context.annotation.Bean; | |||
| import org.springframework.context.annotation.Configuration; | |||
| /** | |||
| * Minio 配置信息 | |||
| * | |||
| * @author xueyi | |||
| */ | |||
| @Configuration | |||
| @ConfigurationProperties(prefix = "qiniu") | |||
| @Data | |||
| public class QiNiuConfig { | |||
| /** accessKey */ | |||
| private String accessKey; | |||
| /** secretKey */ | |||
| private String secretKey; | |||
| /** bucket */ | |||
| private String bucket; | |||
| private String tempBucket; | |||
| public String qiNiuUploadToken() { | |||
| Auth auth = Auth.create(accessKey, secretKey); | |||
| String upToken = auth.uploadToken(bucket); | |||
| return upToken; | |||
| } | |||
| public String qiNiuTempUploadToken() { | |||
| Auth auth = Auth.create(accessKey, secretKey); | |||
| String upToken = auth.uploadToken(tempBucket); | |||
| return upToken; | |||
| } | |||
| @Bean | |||
| public UploadManager uploadManager() { | |||
| com.qiniu.storage.Configuration cfg = new com.qiniu.storage.Configuration(Region.region1()); | |||
| cfg.resumableUploadAPIVersion = com.qiniu.storage.Configuration.ResumableUploadAPIVersion.V2;// 指定分片上传版本 | |||
| //...其他参数参考类注释 | |||
| return new UploadManager(cfg); | |||
| } | |||
| } | |||
| @@ -33,6 +33,7 @@ import java.io.File; | |||
| import java.time.LocalDate; | |||
| import java.time.format.DateTimeFormatter; | |||
| import java.util.ArrayList; | |||
| import java.util.Arrays; | |||
| import java.util.List; | |||
| /** | |||
| @@ -249,10 +250,10 @@ public class SysFileController { | |||
| } | |||
| } | |||
| @DeleteMapping(value = "/inner/delete-files") | |||
| public R<Boolean> deleteFilesInner(@RequestParam(value = "urls") List<String> urls) { | |||
| @PostMapping(value = "/inner/delete-files") | |||
| public R<Boolean> deleteFilesInner(@RequestParam("urls") String[] urls) { | |||
| try { | |||
| Boolean result = minioSysFileService.deleteFiles(urls); | |||
| Boolean result = minioSysFileService.deleteFiles(Arrays.stream(urls).toList()); | |||
| return R.ok(result); | |||
| } catch (Exception e) { | |||
| log.error("文件删除失败", e); | |||
| @@ -99,7 +99,23 @@ public class MinioSysFileServiceImpl implements ISysFileService { | |||
| @Override | |||
| public String uploadTempFile(MultipartFile file) throws Exception { | |||
| return null; | |||
| String fileName = FileUploadUtils.extractFilename(file); | |||
| //fileName = URLEncoder.encode(fileName, "UTF-8"); | |||
| log.info("Minio filename: {}" , fileName); | |||
| PutObjectArgs args = PutObjectArgs.builder() | |||
| .bucket(minioConfig.getTempBucketName()) | |||
| .object(fileName) | |||
| .stream(file.getInputStream(), file.getSize(), -1) | |||
| .contentType(file.getContentType()) | |||
| .build(); | |||
| client.putObject(args); | |||
| log.info("Minio 文件上传成功"); | |||
| // 获取fileName的最后一个'/'的位置的字符串,并用URLEncoder进行UTF-8编码后,再拼接到fileName中 | |||
| String splitStr = fileName.substring(fileName.lastIndexOf("/") + 1); | |||
| splitStr = URLEncoder.encode(splitStr, "UTF-8"); | |||
| fileName = fileName.substring(0, fileName.lastIndexOf("/") + 1) + splitStr; | |||
| return minioConfig.getUrl() + "/" + minioConfig.getTempBucketName() + "/" + fileName; | |||
| } | |||
| @Override | |||
| @@ -113,7 +129,7 @@ public class MinioSysFileServiceImpl implements ISysFileService { | |||
| byte[] fileBytes = IOUtils.toByteArray(inputStream); | |||
| // 上传文件到MinIO | |||
| String minioFileName = uploadFileToMinIO(fileName, fileBytes); | |||
| String minioFileName = uploadFileToMinIO(fileName, fileBytes, minioConfig.getBucketName()); | |||
| log.info("MinIO 文件上传成功,Minio 文件名:{}" , minioFileName); | |||
| @@ -136,7 +152,7 @@ public class MinioSysFileServiceImpl implements ISysFileService { | |||
| byte[] fileBytes = IOUtils.toByteArray(inputStream); | |||
| // 上传文件到MinIO | |||
| String minioFileName = uploadFileToMinIO(fileName, fileBytes); | |||
| String minioFileName = uploadFileToMinIO(fileName, fileBytes, minioConfig.getTempBucketName()); | |||
| log.info("MinIO Temp文件上传成功,Minio 文件名:{}", minioFileName); | |||
| @@ -145,13 +161,13 @@ public class MinioSysFileServiceImpl implements ISysFileService { | |||
| splitStr = URLEncoder.encode(splitStr, "UTF-8"); | |||
| fileName = fileName.substring(0, fileName.lastIndexOf("/") + 1) + splitStr; | |||
| return minioConfig.getUrl() + "/" + minioConfig.getBucketName() + "/" + fileName; | |||
| return minioConfig.getUrl() + "/" + minioConfig.getTempBucketName() + "/" + fileName; | |||
| } | |||
| // 上传文件到MinIO | |||
| private String uploadFileToMinIO(String fileName, byte[] fileBytes) throws Exception { | |||
| private String uploadFileToMinIO(String fileName, byte[] fileBytes, String bucketName) throws Exception { | |||
| PutObjectArgs args = PutObjectArgs.builder() | |||
| .bucket(minioConfig.getBucketName()) | |||
| .bucket(bucketName) | |||
| .object(fileName) | |||
| .stream(new ByteArrayInputStream(fileBytes), fileBytes.length, -1) | |||
| .contentType("application/octet-stream") | |||
| @@ -0,0 +1,207 @@ | |||
| package com.xueyi.file.service; | |||
| import com.alibaba.nacos.shaded.com.google.gson.Gson; | |||
| import com.qiniu.common.QiniuException; | |||
| import com.qiniu.http.Response; | |||
| import com.qiniu.storage.UploadManager; | |||
| import com.qiniu.storage.model.DefaultPutRet; | |||
| import com.xueyi.file.config.QiNiuConfig; | |||
| import com.xueyi.file.utils.FileUploadUtils; | |||
| import org.apache.commons.io.IOUtils; | |||
| import org.slf4j.Logger; | |||
| import org.slf4j.LoggerFactory; | |||
| import org.springframework.beans.factory.annotation.Autowired; | |||
| import org.springframework.context.annotation.Primary; | |||
| import org.springframework.stereotype.Service; | |||
| import org.springframework.web.multipart.MultipartFile; | |||
| import java.io.File; | |||
| import java.io.FileOutputStream; | |||
| import java.util.List; | |||
| /** | |||
| * QiNiu 文件存储 | |||
| * | |||
| * @author xueyi | |||
| */ | |||
| @Primary | |||
| @Service | |||
| public class QiNiuSysFileServiceImpl implements ISysFileService { | |||
| private static final Logger log = LoggerFactory.getLogger(QiNiuSysFileServiceImpl.class); | |||
| @Autowired | |||
| private QiNiuConfig qiNiuConfig; | |||
| @Autowired | |||
| private UploadManager uploadManager; | |||
| /** | |||
| * 本地文件上传接口 | |||
| * | |||
| * @param file 上传的文件 | |||
| * @return 访问地址 | |||
| */ | |||
| @Override | |||
| public String uploadFile(MultipartFile file) throws Exception { | |||
| String fileName = FileUploadUtils.extractFilename(file); | |||
| //将MultipartFile类型的文件转换为File类型 | |||
| File localFile = new File(fileName); | |||
| IOUtils.copy(file.getInputStream(), new FileOutputStream(localFile)); | |||
| //fileName = URLEncoder.encode(fileName, "UTF-8"); | |||
| log.info("Minio filename: {}" , fileName); | |||
| try { | |||
| Response response = uploadManager.put(localFile.getAbsolutePath(), fileName, qiNiuConfig.qiNiuUploadToken()); | |||
| //解析上传成功的结果 | |||
| DefaultPutRet putRet = new Gson().fromJson(response.bodyString(), DefaultPutRet.class); | |||
| System.out.println(putRet.key); | |||
| System.out.println(putRet.hash); | |||
| return putRet.key; | |||
| } catch (QiniuException ex) { | |||
| ex.printStackTrace(); | |||
| if (ex.response != null) { | |||
| System.err.println(ex.response); | |||
| try { | |||
| String body = ex.response.toString(); | |||
| System.err.println(body); | |||
| } catch (Exception ignored) { | |||
| } | |||
| } | |||
| } | |||
| return null; | |||
| } | |||
| String uploadFileFun(String fileName, File file, boolean isTemp) throws Exception { | |||
| fileName = FileUploadUtils.extractFilename(fileName); | |||
| log.info("file original filename = {}" , fileName); | |||
| log.info("file size = {} " , file.length()); | |||
| String token = isTemp ? qiNiuConfig.qiNiuTempUploadToken() : qiNiuConfig.qiNiuUploadToken(); | |||
| log.info("Minio filename: {}" , fileName); | |||
| try { | |||
| Response response = uploadManager.put(file.getAbsolutePath(), fileName, token); | |||
| //解析上传成功的结果 | |||
| DefaultPutRet putRet = new Gson().fromJson(response.bodyString(), DefaultPutRet.class); | |||
| System.out.println(putRet.key); | |||
| System.out.println(putRet.hash); | |||
| return putRet.key; | |||
| } catch (QiniuException ex) { | |||
| ex.printStackTrace(); | |||
| if (ex.response != null) { | |||
| System.err.println(ex.response); | |||
| try { | |||
| String body = ex.response.toString(); | |||
| System.err.println(body); | |||
| } catch (Exception ignored) { | |||
| } | |||
| } | |||
| } | |||
| return null; | |||
| } | |||
| @Override | |||
| public String uploadExactFile(MultipartFile file, String extension) throws Exception { | |||
| String fileName = FileUploadUtils.extractFilename(file).replaceAll(extension, ""); | |||
| fileName += extension; | |||
| File localFile = new File(fileName); | |||
| if (!localFile.exists()) { | |||
| if (!localFile.getParentFile().exists()) { | |||
| localFile.getParentFile().mkdirs(); | |||
| } | |||
| } | |||
| IOUtils.copy(file.getInputStream(), new FileOutputStream(localFile)); | |||
| //fileName = URLEncoder.encode(fileName, "UTF-8"); | |||
| log.info("Minio filename: {}" , fileName); | |||
| try { | |||
| Response response = uploadManager.put(localFile.getAbsolutePath(), fileName, qiNiuConfig.qiNiuUploadToken()); | |||
| //解析上传成功的结果 | |||
| DefaultPutRet putRet = new Gson().fromJson(response.bodyString(), DefaultPutRet.class); | |||
| System.out.println(putRet.key); | |||
| System.out.println(putRet.hash); | |||
| return putRet.key; | |||
| } catch (QiniuException ex) { | |||
| ex.printStackTrace(); | |||
| if (ex.response != null) { | |||
| System.err.println(ex.response); | |||
| try { | |||
| String body = ex.response.toString(); | |||
| System.err.println(body); | |||
| } catch (Exception ignored) { | |||
| } | |||
| } | |||
| } | |||
| return null; | |||
| } | |||
| @Override | |||
| public String uploadTempFile(MultipartFile file) throws Exception { | |||
| String fileName = FileUploadUtils.extractFilename(file); | |||
| //fileName = URLEncoder.encode(fileName, "UTF-8"); | |||
| File localFile = new File(fileName); | |||
| IOUtils.copy(file.getInputStream(), new FileOutputStream(localFile)); | |||
| //fileName = URLEncoder.encode(fileName, "UTF-8"); | |||
| log.info("Minio filename: {}" , fileName); | |||
| try { | |||
| Response response = uploadManager.put(localFile.getAbsolutePath(), fileName, qiNiuConfig.qiNiuUploadToken()); | |||
| //解析上传成功的结果 | |||
| DefaultPutRet putRet = new Gson().fromJson(response.bodyString(), DefaultPutRet.class); | |||
| System.out.println(putRet.key); | |||
| System.out.println(putRet.hash); | |||
| return putRet.key; | |||
| } catch (QiniuException ex) { | |||
| ex.printStackTrace(); | |||
| if (ex.response != null) { | |||
| System.err.println(ex.response); | |||
| try { | |||
| String body = ex.response.toString(); | |||
| System.err.println(body); | |||
| } catch (Exception ignored) { | |||
| } | |||
| } | |||
| } | |||
| return null; | |||
| } | |||
| @Override | |||
| public String uploadFile(String fileName, File file) throws Exception { | |||
| return uploadFileFun(fileName, file, false); | |||
| } | |||
| public String uploadTempFile(String fileName, File file) throws Exception { | |||
| return uploadFileFun(fileName, file, true); | |||
| } | |||
| public String uploadFile(File file) throws Exception { | |||
| return uploadFileFun(file.getName(), file, false); | |||
| } | |||
| /** | |||
| * 文件删除接口,通过minio的文件url进行删除 | |||
| * | |||
| * @param url 文件url | |||
| * @return 结果 | |||
| */ | |||
| public Boolean deleteFile(String url) throws Exception { | |||
| return true; | |||
| } | |||
| public Boolean deleteFiles(List<String> urls) throws Exception { | |||
| return true; | |||
| } | |||
| } | |||
| @@ -1,6 +1,8 @@ | |||
| package com.xueyi.job.task; | |||
| import com.xueyi.system.api.digitalmans.feign.RemoteDigitalmanService; | |||
| import org.slf4j.Logger; | |||
| import org.slf4j.LoggerFactory; | |||
| import org.springframework.beans.factory.annotation.Autowired; | |||
| import org.springframework.stereotype.Component; | |||
| @@ -11,6 +13,7 @@ import org.springframework.stereotype.Component; | |||
| */ | |||
| @Component("dmRecognizedRecordsCleanTask") | |||
| public class DmRecognizedRecordsCleanTask { | |||
| private static final Logger log = LoggerFactory.getLogger(DmRecognizedRecordsCleanTask.class); | |||
| @Autowired | |||
| RemoteDigitalmanService remoteDigitalmanService; | |||
| /** | |||
| @@ -20,6 +23,7 @@ public class DmRecognizedRecordsCleanTask { | |||
| public void delOutDays() { | |||
| remoteDigitalmanService.delRecognizedRecords(5); | |||
| log.info("定时任务调度测试:删除过期通行记录照片"); | |||
| remoteDigitalmanService.delRecognizedRecords(60); | |||
| } | |||
| } | |||
| @@ -100,6 +100,11 @@ | |||
| <artifactId>xueyi-api-system</artifactId> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>com.xueyi</groupId> | |||
| <artifactId>xueyi-api-nlt</artifactId> | |||
| </dependency> | |||
| </dependencies> | |||
| <build> | |||
| @@ -3,10 +3,10 @@ package com.xueyi.message.handler; | |||
| import com.alibaba.fastjson2.JSONObject; | |||
| import com.xueyi.common.core.constant.basic.SecurityConstants; | |||
| import com.xueyi.common.core.web.result.R; | |||
| import com.xueyi.common.core.web.vo.DeviceTenantSourceMergeVo; | |||
| import com.xueyi.common.mqtt.annotation.MqttService; | |||
| import com.xueyi.common.mqtt.annotation.MqttTopic; | |||
| import com.xueyi.message.api.transfer.domain.vo.DmDeployScheduleVo; | |||
| import com.xueyi.system.api.device.domain.vo.DeviceTenantSourceMergeVo; | |||
| import com.xueyi.system.api.device.feign.RemoteDeviceTenantMergeService; | |||
| import com.xueyi.system.api.digitalmans.feign.RemoteDigitalmanMqttService; | |||
| import com.xueyi.system.api.version.feign.RemoteReleaseManagerService; | |||
| @@ -9,24 +9,22 @@ import com.xueyi.common.core.constant.digitalman.InitConstants; | |||
| import com.xueyi.common.core.constant.digitalman.MessageConstants; | |||
| import com.xueyi.common.core.web.result.AjaxResult; | |||
| import com.xueyi.common.core.web.result.R; | |||
| import com.xueyi.common.core.web.vo.DeviceTenantSourceMergeVo; | |||
| import com.xueyi.common.redis.utils.RedisUtil; | |||
| import com.xueyi.common.web.utils.DateUtils; | |||
| import com.xueyi.message.api.transfer.domain.vo.DmActiveVo; | |||
| import com.xueyi.message.api.transfer.domain.vo.DmDeviceVo; | |||
| import com.xueyi.message.transfer.service.impl.MessageQueueServiceImpl; | |||
| import com.xueyi.nlt.api.nlt.feign.RemoteSeniverseService; | |||
| import com.xueyi.system.api.authority.feign.RemoteLoginService; | |||
| import com.xueyi.system.api.device.domain.vo.DeviceTenantSourceMergeVo; | |||
| import com.xueyi.system.api.device.feign.RemoteDeviceTenantMergeService; | |||
| import com.xueyi.system.api.digitalmans.domain.dto.DmManDeviceDto; | |||
| import com.xueyi.system.api.digitalmans.domain.dto.DmSkillDto; | |||
| import com.xueyi.system.api.digitalmans.domain.dto.DmSyncDigitalmanDto; | |||
| import com.xueyi.system.api.digitalmans.domain.vo.DmBroadcastVo; | |||
| import com.xueyi.system.api.digitalmans.domain.vo.DmReceptionVo; | |||
| import com.xueyi.system.api.digitalmans.feign.RemoteBroadcastService; | |||
| import com.xueyi.system.api.digitalmans.feign.RemoteDigitalmanService; | |||
| import com.xueyi.system.api.digitalmans.feign.RemoteManDeviceService; | |||
| import com.xueyi.system.api.digitalmans.feign.RemoteReceptionService; | |||
| import com.xueyi.system.api.digitalmans.feign.RemoteSkillService; | |||
| import com.xueyi.system.api.digitalmans.domain.vo.DmTipVo; | |||
| import com.xueyi.system.api.digitalmans.feign.*; | |||
| import com.xueyi.system.api.model.Source; | |||
| import com.xueyi.system.api.organize.domain.dto.SysEnterpriseDto; | |||
| import com.xueyi.system.api.resource.feign.RemoteH5ConfigService; | |||
| @@ -35,14 +33,9 @@ import com.xueyi.system.api.staff.feign.RemoteStaffService; | |||
| import org.slf4j.Logger; | |||
| import org.slf4j.LoggerFactory; | |||
| import org.springframework.beans.factory.annotation.Autowired; | |||
| import org.springframework.beans.factory.annotation.Value; | |||
| import org.springframework.data.redis.core.StringRedisTemplate; | |||
| import org.springframework.web.bind.annotation.PathVariable; | |||
| import org.springframework.web.bind.annotation.RequestBody; | |||
| import org.springframework.web.bind.annotation.RequestMapping; | |||
| import org.springframework.web.bind.annotation.RequestMethod; | |||
| import org.springframework.web.bind.annotation.RequestParam; | |||
| import org.springframework.web.bind.annotation.ResponseBody; | |||
| import org.springframework.web.bind.annotation.RestController; | |||
| import org.springframework.web.bind.annotation.*; | |||
| import javax.servlet.http.HttpServletRequest; | |||
| import javax.servlet.http.HttpServletResponse; | |||
| @@ -91,6 +84,15 @@ public class ApiController { | |||
| @Autowired | |||
| RemoteH5ConfigService remoteH5ConfigService; | |||
| @Autowired | |||
| RemoteQuestionanswersService remoteQuestionanswersService; | |||
| @Autowired | |||
| RemoteSeniverseService remoteSeniverseService; | |||
| @Value("${notification.seniverse.key}") | |||
| private String seniverseKey; | |||
| @RequestMapping(value = "/heartbeat", method = {RequestMethod.POST}) | |||
| @ResponseBody | |||
| @@ -441,4 +443,35 @@ public class ApiController { | |||
| } | |||
| return AjaxResult.success(propertyR.getData()); | |||
| } | |||
| @RequestMapping(value = "/tip_list/{deviceId}", method = {RequestMethod.GET}) | |||
| @ResponseBody | |||
| public AjaxResult tipList(@PathVariable(value = "deviceId") String deviceId, HttpServletResponse response) { | |||
| R<DmManDeviceDto> manDeviceDtoR = manDeviceService.manDeviceInfoInner(deviceId); | |||
| if (manDeviceDtoR.isFail() || manDeviceDtoR.getData() == null) { | |||
| return AjaxResult.warn("设备号获取失败,请检查"); | |||
| } | |||
| Source source = SourceUtil.getSourceCache(manDeviceDtoR.getData().getStrategyId()); | |||
| R<List<DmTipVo>> listR = remoteQuestionanswersService.tipList(manDeviceDtoR.getData().getTId(), source.getMaster(), SecurityConstants.INNER); | |||
| if (listR.isFail()) { | |||
| return AjaxResult.warn("获取tip列表失败,请检查"); | |||
| } | |||
| return AjaxResult.success(listR.getData()); | |||
| } | |||
| /** | |||
| * 意图请求 | |||
| 列表 | |||
| */ | |||
| @RequestMapping(value = "/weather",method = {RequestMethod.GET, RequestMethod.POST}) | |||
| @ResponseBody | |||
| public AjaxResult weather(@RequestParam String city, HttpServletRequest request) { | |||
| log.info("weather:{}", city); | |||
| JSONObject result = remoteSeniverseService.now(seniverseKey,city,"zh-Hans","c"); | |||
| log.info("weather:{}", result); | |||
| return AjaxResult.success(result.getJSONArray("results")); | |||
| } | |||
| } | |||
| @@ -3,10 +3,10 @@ package com.xueyi.modules.auth.controller; | |||
| import com.xueyi.common.core.constant.basic.SecurityConstants; | |||
| import com.xueyi.common.core.web.result.AjaxResult; | |||
| import com.xueyi.common.core.web.vo.DeviceTenantSourceMergeVo; | |||
| import com.xueyi.common.web.controller.BaseApiController; | |||
| import com.xueyi.modules.auth.api.domain.vo.IntentionReqDto; | |||
| import com.xueyi.modules.auth.api.feign.RemoteSkillAuthService; | |||
| import com.xueyi.system.api.device.domain.vo.DeviceTenantSourceMergeVo; | |||
| import org.springframework.beans.factory.annotation.Autowired; | |||
| import org.springframework.web.bind.annotation.RequestBody; | |||
| import org.springframework.web.bind.annotation.RequestMapping; | |||
| @@ -6,6 +6,7 @@ import com.xueyi.common.security.annotation.EnableRyFeignClients; | |||
| import com.xueyi.common.swagger.annotation.EnableCustomSwagger; | |||
| import org.springframework.boot.SpringApplication; | |||
| import org.springframework.boot.autoconfigure.SpringBootApplication; | |||
| import org.springframework.scheduling.annotation.EnableAsync; | |||
| @EnableCustomConfig | |||
| @EnableCustomSwagger | |||
| @@ -1,13 +1,22 @@ | |||
| package com.xueyi.nlt.netty.client; | |||
| import cn.hutool.core.lang.Snowflake; | |||
| import com.alibaba.fastjson2.JSONObject; | |||
| import com.alibaba.nacos.shaded.com.google.gson.Gson; | |||
| import com.alibaba.nacos.shaded.com.google.gson.JsonArray; | |||
| import com.alibaba.nacos.shaded.com.google.gson.JsonObject; | |||
| import com.baomidou.mybatisplus.core.toolkit.StringUtils; | |||
| import com.xueyi.common.core.utils.core.IdUtil; | |||
| import com.xueyi.common.web.interceptor.ApiRequestInterceptor; | |||
| import com.xueyi.nlt.api.netty.domain.vo.DmWebSocketMessageVo; | |||
| import com.xueyi.nlt.netty.server.config.ServerConfig; | |||
| import com.xueyi.nlt.nlt.domain.vo.LlmQueryVo; | |||
| import io.netty.channel.Channel; | |||
| import io.netty.handler.codec.http.websocketx.TextWebSocketFrame; | |||
| import okhttp3.*; | |||
| import org.apache.commons.collections4.CollectionUtils; | |||
| import org.slf4j.Logger; | |||
| import org.slf4j.LoggerFactory; | |||
| import org.springframework.beans.factory.annotation.Autowired; | |||
| import org.springframework.beans.factory.annotation.Value; | |||
| import org.springframework.data.redis.core.RedisTemplate; | |||
| @@ -27,6 +36,7 @@ import java.util.*; | |||
| @Component | |||
| public class WebSocketClient extends WebSocketListener { | |||
| private static final Logger logger = LoggerFactory.getLogger(WebSocketClient.class); | |||
| public static WebSocketClient INSTANCE; | |||
| @Autowired | |||
| private RedisTemplate redisTemplate; | |||
| @@ -50,16 +60,20 @@ public class WebSocketClient extends WebSocketListener { | |||
| // public static String APIKEY = "7c217b3a313f4b66fcc14a8e97f85103";//从开放平台控制台中获取 | |||
| // public static String APISecret = "ZTRiNDQwMTRlOTlmZDQwMDUwYTdjMDM0";//从开放平台控制台中获取 | |||
| public static WebSocket webSocket; | |||
| public static String APPID = "948cf4b6";//从开放平台控制台中获取 | |||
| public static String APIKEY = "54f6e81f40a31d66d976496de895a7a4";//从开放平台控制台中获取 | |||
| public static String APISecret = "ZDYyMjNmMTlkYTE0YWRmOWUwZTYxNjYz";//从开放平台控制台中获取 | |||
| public WebSocket webSocket; | |||
| public static final Gson json = new Gson(); | |||
| // public static String question = "假设你是一位前台,你需要通过与其他人对话来获取会议相关信息,已知今天是2023-7-19,你需要获取会议日期,开始时间,持续时间,会议地点,会议主题。时间用类似00:00的格式输出。对方的话中可能不包含全部信息,对于未知的信息填充为none。如果所有信息都已知那么commit为true。否则为false。将你获得的信息输出为json格式。对方的话是:“明天下午开个会。从两点开到下午三点,在大会议室开,主题是访客接待”,只输出最后的json。输出只有一行,输出格式为{date:,start_time:,duration:,location:,theme:commit:}。";//可以修改question 内容,来向模型提问 | |||
| public static String question = "请帮我安排五一出行计划";//可以修改question 内容,来向模型提问 | |||
| public static String systemRole = ""; | |||
| public static List<String> questions = new ArrayList<>();//可以修改question 内容,来向模型提问 | |||
| // 定义内存共享变量traceId | |||
| public Long traceId; | |||
| public String question = "请帮我安排五一出行计划";//可以修改question 内容,来向模型提问 | |||
| public String systemRole = ""; | |||
| public List<String> questions = new ArrayList<>();//可以修改question 内容,来向模型提问 | |||
| public boolean stream = false; | |||
| public String curUserId = null; | |||
| public String answer = ""; | |||
| public String answerBuf = ""; | |||
| @PostConstruct | |||
| public void init() { | |||
| @@ -73,7 +87,7 @@ public class WebSocketClient extends WebSocketListener { | |||
| synchronized (LOCK) { | |||
| try { | |||
| //构建鉴权httpurl | |||
| String authUrl = getAuthorizationUrl(INSTANCE.hostUrl, INSTANCE.apiKey, INSTANCE.apiSecret); | |||
| String authUrl = getAuthorizationUrl("https://spark-api.xf-yun.com/v3.1/chat", "54f6e81f40a31d66d976496de895a7a4", "ZDYyMjNmMTlkYTE0YWRmOWUwZTYxNjYz"); | |||
| OkHttpClient okHttpClient = new OkHttpClient.Builder().build(); | |||
| String url = authUrl.replace("https://","wss://").replace("http://","ws://"); | |||
| Request request = new Request.Builder().url(url).build(); | |||
| @@ -121,8 +135,12 @@ public class WebSocketClient extends WebSocketListener { | |||
| e.printStackTrace(); | |||
| } | |||
| } | |||
| public void sendMsg(List<String> messages){ | |||
| this.sendMsg(messages,false, null); | |||
| } | |||
| public void sendMsg(List<String> messages,boolean stream,String userId){ | |||
| this.stream = stream; | |||
| this.curUserId = userId; | |||
| if (messages.size() / 2 > 0) { | |||
| systemRole = messages.get(0); | |||
| messages.remove(0); | |||
| @@ -136,7 +154,16 @@ public class WebSocketClient extends WebSocketListener { | |||
| OkHttpClient okHttpClient = new OkHttpClient.Builder().build(); | |||
| String url = authUrl.replace("https://","wss://").replace("http://","ws://"); | |||
| Request request = new Request.Builder().url(url).build(); | |||
| webSocket = okHttpClient.newWebSocket(request,new WebSocketClient()); | |||
| WebSocketClient wsc = new WebSocketClient(); | |||
| wsc.stream = stream; | |||
| wsc.curUserId = userId; | |||
| wsc.questions = questions; | |||
| wsc.question = question; | |||
| wsc.systemRole = systemRole; | |||
| wsc.traceId = IdUtil.getSnowflakeNextId(); | |||
| ServerConfig.currentTraceMap.put(curUserId,wsc.traceId); | |||
| System.out.println("wocket客户端:" + wsc.hashCode()); | |||
| webSocket = okHttpClient.newWebSocket(request,wsc); | |||
| } catch (Exception e) { | |||
| e.printStackTrace(); | |||
| @@ -251,78 +278,152 @@ public class WebSocketClient extends WebSocketListener { | |||
| public void onMessage(WebSocket webSocket, String text) { | |||
| super.onMessage(webSocket, text); | |||
| System.out.println("text:\n" + text); | |||
| if (!StringUtils.isEmpty(curUserId)) { | |||
| if (ServerConfig.currentTraceMap.containsKey(curUserId) && !ServerConfig.currentTraceMap.get(curUserId).equals(traceId)) { | |||
| return; | |||
| } | |||
| } | |||
| ResponseData responseData = json.fromJson(text,ResponseData.class); | |||
| synchronized (LOCK) { | |||
| try { | |||
| // System.out.println("code:\n" + responseData.getHeader().get("code")); | |||
| if (0 == responseData.getHeader().get("code").getAsInt()) { | |||
| System.out.println("###########"); | |||
| System.out.println("getStatus: " + responseData.getHeader().get("status").getAsInt()); | |||
| if (2 != responseData.getHeader().get("status").getAsInt()) { | |||
| System.out.println("****************"); | |||
| Payload pl = json.fromJson(responseData.getPayload(), Payload.class); | |||
| JsonArray temp = (JsonArray) pl.getChoices().get("text"); | |||
| JsonObject jo = (JsonObject) temp.get(0); | |||
| answer += jo.get("content").getAsString(); | |||
| try { | |||
| // System.out.println("code:\n" + responseData.getHeader().get("code")); | |||
| if (0 == responseData.getHeader().get("code").getAsInt()) { | |||
| System.out.println("###########"); | |||
| System.out.println("getStatus: " + responseData.getHeader().get("status").getAsInt()); | |||
| if (2 != responseData.getHeader().get("status").getAsInt()) { | |||
| System.out.println("****************"); | |||
| Payload pl = json.fromJson(responseData.getPayload(), Payload.class); | |||
| JsonArray temp = (JsonArray) pl.getChoices().get("text"); | |||
| JsonObject jo = (JsonObject) temp.get(0); | |||
| answer += jo.get("content").getAsString(); | |||
| answerBuf += jo.get("content").getAsString(); | |||
| // System.out.println(answer); | |||
| } else { | |||
| Payload pl1 = json.fromJson(responseData.getPayload(), Payload.class); | |||
| JsonObject jsonObject = (JsonObject) pl1.getUsage().get("text"); | |||
| int prompt_tokens = jsonObject.get("prompt_tokens").getAsInt(); | |||
| JsonArray temp1 = (JsonArray) pl1.getChoices().get("text"); | |||
| JsonObject jo = (JsonObject) temp1.get(0); | |||
| answer += jo.get("content").getAsString(); | |||
| System.out.println("返回结果为:\n" + answer); | |||
| if (INSTANCE.redisTemplate.hasKey("gpt:websocket:1")) { | |||
| DmWebSocketMessageVo message = (DmWebSocketMessageVo) INSTANCE.redisTemplate.opsForValue().get("gpt:websocket:1"); | |||
| if (message != null && StringUtils.isNotEmpty(message.getTemplate()) && message.getTemplate().equals("birthday")) { | |||
| JSONObject birthdayJo = new JSONObject(); | |||
| birthdayJo.put("content", answer); | |||
| birthdayJo.put("timestamp", message.getFormat().get("timestamp")); | |||
| INSTANCE.stringRedisTemplate.opsForHash().put("group:nlp" + ":" + message.getFormat().getString("orderId"), "birthday", birthdayJo.toString()); | |||
| INSTANCE.redisTemplate.delete("gpt:websocket:1"); | |||
| return; | |||
| } | |||
| if (message!= null && StringUtils.isNotEmpty(message.getTemplate()) && message.getTemplate().equals("hireDate")) { | |||
| JSONObject birthdayJo = new JSONObject(); | |||
| birthdayJo.put("content", answer); | |||
| birthdayJo.put("timestamp", message.getFormat().get("timestamp")); | |||
| INSTANCE.stringRedisTemplate.opsForHash().put("group:nlp" + ":" + message.getFormat().getString("orderId"), "hireDate", birthdayJo.toString()); | |||
| INSTANCE.redisTemplate.delete("gpt:websocket:1"); | |||
| return; | |||
| } | |||
| if (message != null) { | |||
| JSONObject preWebsocketJo = message.getFormat(); | |||
| JSONObject meetingJo = new JSONObject(); | |||
| meetingJo.put("timestamp",preWebsocketJo.get("timestamp")); | |||
| meetingJo.put("content",answer); | |||
| INSTANCE.stringRedisTemplate.opsForHash().put("group:nlp" + ":" + preWebsocketJo.getString("orderId"), "meeting", meetingJo.toString()); | |||
| } | |||
| } else { | |||
| Payload pl1 = json.fromJson(responseData.getPayload(), Payload.class); | |||
| JsonObject jsonObject = (JsonObject) pl1.getUsage().get("text"); | |||
| int prompt_tokens = jsonObject.get("prompt_tokens").getAsInt(); | |||
| JsonArray temp1 = (JsonArray) pl1.getChoices().get("text"); | |||
| JsonObject jo = (JsonObject) temp1.get(0); | |||
| answer += jo.get("content").getAsString(); | |||
| answerBuf += jo.get("content").getAsString(); | |||
| System.out.println("返回结果为:\n" + answer); | |||
| if (INSTANCE.redisTemplate.hasKey("gpt:websocket:1")) { | |||
| DmWebSocketMessageVo message = (DmWebSocketMessageVo) INSTANCE.redisTemplate.opsForValue().get("gpt:websocket:1"); | |||
| if (message != null && StringUtils.isNotEmpty(message.getTemplate()) && message.getTemplate().equals("birthday")) { | |||
| JSONObject birthdayJo = new JSONObject(); | |||
| birthdayJo.put("content", answer); | |||
| birthdayJo.put("timestamp", message.getFormat().get("timestamp")); | |||
| INSTANCE.stringRedisTemplate.opsForHash().put("group:nlp" + ":" + message.getFormat().getString("orderId"), "birthday", birthdayJo.toString()); | |||
| INSTANCE.redisTemplate.delete("gpt:websocket:1"); | |||
| // 清除systemRole | |||
| systemRole = ""; | |||
| }else { | |||
| // 添加缓存 | |||
| INSTANCE.stringRedisTemplate.opsForValue().set("group:websocket:content", answer); | |||
| LOCK.notifyAll(); | |||
| return; | |||
| } | |||
| if (message!= null && StringUtils.isNotEmpty(message.getTemplate()) && message.getTemplate().equals("hireDate")) { | |||
| JSONObject birthdayJo = new JSONObject(); | |||
| birthdayJo.put("content", answer); | |||
| birthdayJo.put("timestamp", message.getFormat().get("timestamp")); | |||
| INSTANCE.stringRedisTemplate.opsForHash().put("group:nlp" + ":" + message.getFormat().getString("orderId"), "hireDate", birthdayJo.toString()); | |||
| INSTANCE.redisTemplate.delete("gpt:websocket:1"); | |||
| return; | |||
| } | |||
| if (message != null) { | |||
| JSONObject preWebsocketJo = message.getFormat(); | |||
| JSONObject meetingJo = new JSONObject(); | |||
| meetingJo.put("timestamp",preWebsocketJo.get("timestamp")); | |||
| meetingJo.put("content",answer); | |||
| INSTANCE.stringRedisTemplate.opsForHash().put("group:nlp" + ":" + preWebsocketJo.getString("orderId"), "meeting", meetingJo.toString()); | |||
| } | |||
| INSTANCE.redisTemplate.delete("gpt:websocket:1"); | |||
| // 清除systemRole | |||
| systemRole = ""; | |||
| }else { | |||
| // 添加上下文 | |||
| INSTANCE.redisTemplate.opsForList().rightPush("group:nlp:null:-1", questions.get(questions.size() - 1)); | |||
| INSTANCE.redisTemplate.opsForList().rightPush("group:nlp:null:-1", answer); | |||
| // 添加缓存 | |||
| INSTANCE.stringRedisTemplate.opsForValue().set("group:websocket:content", answer); | |||
| } | |||
| // webSocket.close(3,"客户端主动断开链接"); | |||
| //webSocket.close(1000,"客户端主动断开链接"); | |||
| //webSocket.close(1000,"客户端主动断开链接"); | |||
| } | |||
| if (this.stream && !StringUtils.isEmpty(curUserId)) { | |||
| Channel ch = ServerConfig.sessionMap.get(curUserId); | |||
| logger.info("当前ch:{}",ch.id().asLongText()); | |||
| if (ch != null) { | |||
| List<String> ttsList = new ArrayList<>(); | |||
| JSONObject jo = new JSONObject(); | |||
| jo.put("action","chat"); | |||
| jo.put("motion","idle"); | |||
| jo.put("traceId",traceId); | |||
| //去除转义符 | |||
| answerBuf = answerBuf.replaceAll("[\\r\\n]", ""); | |||
| //去除引号 | |||
| answerBuf = answerBuf.replaceAll("\"", ""); | |||
| // 处理answer,如果包含"。",则将"。"之前的内容发送给前端 | |||
| while(answerBuf.contains("。") || answerBuf.contains("?") || answerBuf.contains("!") || | |||
| answerBuf.contains("?") || answerBuf.contains("!")) { | |||
| String[] temp = answerBuf.split("。|?|!|\\?|\\!"); | |||
| ttsList.add(temp[0] + answerBuf.charAt(temp[0].length())); | |||
| answerBuf = answerBuf.substring(temp[0].length() + 1); | |||
| } | |||
| if (2 == responseData.getHeader().get("status").getAsInt() && CollectionUtils.isEmpty(ttsList)) { | |||
| jo.put("tts",answerBuf); | |||
| jo.put("status",2); | |||
| logger.info("发送到client:{},id:{},内容:{}",curUserId,ch.id().asLongText(),jo.toJSONString()); | |||
| ch.writeAndFlush(new TextWebSocketFrame(jo.toJSONString())); | |||
| } else { | |||
| for (int i = 0;i <ttsList.size();i++) { | |||
| if (2 == responseData.getHeader().get("status").getAsInt() && i == ttsList.size() - 1) { | |||
| jo.put("status",2); | |||
| } else { | |||
| jo.put("status",1); | |||
| } | |||
| jo.put("tts",ttsList.get(i)); | |||
| String str = jo.toJSONString(); | |||
| logger.info("发送到client:{},id:{},内容:{}",curUserId,ch.id().asLongText(),jo.toJSONString()); | |||
| ch.writeAndFlush(new TextWebSocketFrame(str)); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } else { | |||
| // 添加缓存 | |||
| INSTANCE.stringRedisTemplate.opsForValue().set("group:websocket:content", "-1"); | |||
| System.out.println("返回结果错误:\n" + responseData.getHeader().get("code") + responseData.getHeader().get("message")); | |||
| LOCK.notifyAll(); | |||
| } else { | |||
| // 添加缓存 | |||
| INSTANCE.stringRedisTemplate.opsForValue().set("group:websocket:content", "-1"); | |||
| // 判断流式则返回结束状态 | |||
| if (stream == true) { | |||
| Channel ch = ServerConfig.sessionMap.get(curUserId); | |||
| if (ch != null) { | |||
| JSONObject jo = new JSONObject(); | |||
| jo.put("action","chat"); | |||
| jo.put("motion","idle"); | |||
| jo.put("traceId",traceId); | |||
| jo.put("status",2); | |||
| jo.put("tts","抱歉,您的问题我无法解答。"); | |||
| String str = jo.toJSONString(); | |||
| logger.info("发送到client:{},id:{},内容:{}",curUserId,ch.id().asLongText(),jo.toJSONString()); | |||
| ch.writeAndFlush(new TextWebSocketFrame(str)); | |||
| } | |||
| } | |||
| } catch (Exception e) { | |||
| e.printStackTrace(); | |||
| System.out.println("返回结果错误:\n" + responseData.getHeader().get("code") + responseData.getHeader().get("message")); | |||
| LOCK.notifyAll(); | |||
| } | |||
| } catch (Exception e) { | |||
| if (StringUtils.isNotEmpty(curUserId)) { | |||
| Channel ch = ServerConfig.sessionMap.get(curUserId); | |||
| JSONObject jo = new JSONObject(); | |||
| jo.put("action","chat"); | |||
| jo.put("motion","idle"); | |||
| jo.put("traceId",traceId); | |||
| jo.put("status",2); | |||
| jo.put("tts","大模型出现异常,请稍后重试。"); | |||
| String str = jo.toJSONString(); | |||
| logger.info("发生异常client:{},内容:{}",curUserId,jo.toJSONString()); | |||
| ch.writeAndFlush(new TextWebSocketFrame(str)); | |||
| } | |||
| e.printStackTrace(); | |||
| } | |||
| } | |||
| @@ -0,0 +1,31 @@ | |||
| package com.xueyi.nlt.netty.server; | |||
| import com.xueyi.nlt.netty.server.handler.ChatServerHandler; | |||
| import com.xueyi.nlt.netty.server.handler.HeartbeatHandler; | |||
| import io.netty.channel.ChannelInitializer; | |||
| import io.netty.channel.ChannelPipeline; | |||
| import io.netty.channel.socket.SocketChannel; | |||
| import io.netty.handler.codec.http.HttpObjectAggregator; | |||
| import io.netty.handler.codec.http.HttpServerCodec; | |||
| import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler; | |||
| import io.netty.handler.stream.ChunkedWriteHandler; | |||
| import io.netty.handler.timeout.IdleStateHandler; | |||
| import java.util.concurrent.TimeUnit; | |||
| public class ServerInitializer extends ChannelInitializer<SocketChannel> { | |||
| @Override | |||
| protected void initChannel(SocketChannel ch) throws Exception{ | |||
| ChannelPipeline pipeline = ch.pipeline(); | |||
| pipeline.addLast(new HttpServerCodec()); | |||
| pipeline.addLast(new ChunkedWriteHandler()); | |||
| pipeline.addLast(new HttpObjectAggregator(1024*64)); | |||
| pipeline.addLast(new WebSocketServerProtocolHandler("/chat")); | |||
| pipeline.addLast(new IdleStateHandler(60, 120, 180, TimeUnit.SECONDS)); | |||
| pipeline.addLast(new HeartbeatHandler()); | |||
| // 自定义handler,处理业务逻辑 | |||
| pipeline.addLast(new ChatServerHandler()); | |||
| } | |||
| } | |||
| @@ -0,0 +1,79 @@ | |||
| package com.xueyi.nlt.netty.server; | |||
| import com.xueyi.nlt.netty.client.codec.WsChannelInitializer; | |||
| import com.xueyi.nlt.netty.server.handler.ChatServerHandler; | |||
| import io.netty.bootstrap.ServerBootstrap; | |||
| import io.netty.channel.Channel; | |||
| import io.netty.channel.ChannelFuture; | |||
| import io.netty.channel.EventLoopGroup; | |||
| import io.netty.channel.nio.NioEventLoopGroup; | |||
| import io.netty.channel.socket.nio.NioServerSocketChannel; | |||
| import org.slf4j.Logger; | |||
| import org.slf4j.LoggerFactory; | |||
| import org.springframework.scheduling.annotation.Async; | |||
| import org.springframework.stereotype.Component; | |||
| import javax.annotation.PostConstruct; | |||
| import javax.annotation.PreDestroy; | |||
| import java.net.InetSocketAddress; | |||
| import java.util.Date; | |||
| @Component | |||
| public class WebsocketServer { | |||
| private static final Logger log = LoggerFactory.getLogger(WebsocketServer.class); | |||
| private EventLoopGroup bossGroup; | |||
| private EventLoopGroup workGroup; | |||
| private void run() throws Exception { | |||
| log.info("启动netty服务端"); | |||
| bossGroup = new NioEventLoopGroup(); | |||
| workGroup = new NioEventLoopGroup(); | |||
| try { | |||
| ServerBootstrap serverBootstrap = new ServerBootstrap(); | |||
| serverBootstrap.group(bossGroup, workGroup) | |||
| .channel(NioServerSocketChannel.class) | |||
| .childHandler(new ServerInitializer()); | |||
| // 设置监听端口 | |||
| serverBootstrap.localAddress(new InetSocketAddress(9903)); | |||
| // 启动服务器 | |||
| ChannelFuture channelFuture = serverBootstrap.bind().sync(); | |||
| log.info("Server started and listen on:{}",channelFuture.channel().localAddress()); | |||
| // 对关闭通道进行监听 | |||
| channelFuture.channel().closeFuture().sync(); | |||
| } finally { | |||
| bossGroup.shutdownGracefully(); | |||
| workGroup.shutdownGracefully(); | |||
| } | |||
| } | |||
| /** | |||
| * 初始化服务器 | |||
| */ | |||
| @PostConstruct() | |||
| public void init() { | |||
| new Thread(() -> { | |||
| try { | |||
| run(); | |||
| } catch (Exception e) { | |||
| e.printStackTrace(); | |||
| } | |||
| }).start(); | |||
| } | |||
| @PreDestroy | |||
| public void destroy() throws InterruptedException { | |||
| if (bossGroup != null) { | |||
| bossGroup.shutdownGracefully().sync(); | |||
| } | |||
| if (workGroup != null) { | |||
| workGroup.shutdownGracefully().sync(); | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,15 @@ | |||
| package com.xueyi.nlt.netty.server.config; | |||
| import com.alibaba.fastjson2.JSONObject; | |||
| import com.xueyi.nlt.netty.client.WebSocketClient; | |||
| import io.netty.channel.Channel; | |||
| import java.util.concurrent.ConcurrentHashMap; | |||
| public class ServerConfig { | |||
| public static volatile ConcurrentHashMap<String, Channel> sessionMap = new ConcurrentHashMap<>(); | |||
| public static volatile ConcurrentHashMap<String,Long> currentTraceMap = new ConcurrentHashMap<>(); | |||
| } | |||
| @@ -0,0 +1,204 @@ | |||
| package com.xueyi.nlt.netty.server.handler; | |||
| import com.alibaba.fastjson2.JSONObject; | |||
| import com.baomidou.mybatisplus.core.toolkit.StringUtils; | |||
| import com.xueyi.nlt.netty.server.config.ServerConfig; | |||
| import com.xueyi.nlt.nlt.template.FreeChatTemplate; | |||
| import com.xueyi.nlt.nlt.template.MovieChatTemplate; | |||
| import io.netty.channel.Channel; | |||
| import io.netty.channel.ChannelHandlerContext; | |||
| import io.netty.channel.SimpleChannelInboundHandler; | |||
| import io.netty.handler.codec.http.websocketx.TextWebSocketFrame; | |||
| import io.netty.util.AttributeKey; | |||
| import org.slf4j.Logger; | |||
| import org.slf4j.LoggerFactory; | |||
| import org.springframework.beans.factory.annotation.Autowired; | |||
| import org.springframework.stereotype.Component; | |||
| import javax.annotation.PostConstruct; | |||
| import java.net.InetAddress; | |||
| import java.net.InetSocketAddress; | |||
| import java.time.LocalDateTime; | |||
| @Component | |||
| public class ChatServerHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> { | |||
| // 添加log | |||
| private static final Logger log = LoggerFactory.getLogger(ChatServerHandler.class); | |||
| public static ChatServerHandler INSTANCE; | |||
| @Autowired | |||
| private FreeChatTemplate freeChatTemplate; | |||
| @Autowired | |||
| private MovieChatTemplate movieChatTemplate; | |||
| @PostConstruct | |||
| public void init() { | |||
| INSTANCE = this; | |||
| INSTANCE.freeChatTemplate = this.freeChatTemplate; | |||
| INSTANCE.movieChatTemplate = this.movieChatTemplate; | |||
| } | |||
| @Override | |||
| protected void channelRead0(ChannelHandlerContext channelHandlerContext, TextWebSocketFrame textWebSocketFrame) throws Exception { | |||
| Channel channel = channelHandlerContext.channel(); | |||
| // 判断textWebSocketFrame.text()是否为空,如果为空,则直接返回 | |||
| if (StringUtils.isEmpty(textWebSocketFrame.text()) || StringUtils.isEmpty(textWebSocketFrame.text().trim()) ) { | |||
| channel.writeAndFlush(new TextWebSocketFrame("pong")); | |||
| return; | |||
| } | |||
| // 发送json字符串 | |||
| String text = textWebSocketFrame.text(); | |||
| JSONObject jsonObject = JSONObject.parseObject(text); | |||
| if (jsonObject.size() == 0) { | |||
| //心调检测 | |||
| channel.writeAndFlush(new TextWebSocketFrame("pong")); | |||
| return; | |||
| } | |||
| // 获取到发送人的设备号 | |||
| String devId = jsonObject.getString("devId"); | |||
| // 获取到发送人的用户id | |||
| String msg = jsonObject.getString("msg"); | |||
| synchronized (ServerConfig.class) { | |||
| if (!ServerConfig.sessionMap.containsKey(devId) ) { | |||
| // 说明是第一次登录上来连接,还没有开始聊天,将uid加到map中 | |||
| register(devId, channel); | |||
| } else { | |||
| // 说明已经登录过了,判断当前channel与map中的channel是否一致,不一致则关闭之前的channel | |||
| update(devId, channel); | |||
| } | |||
| try { | |||
| sendMsg(devId, msg); | |||
| } catch (Exception e) { | |||
| JSONObject jo = new JSONObject(); | |||
| jo.put("action","chat"); | |||
| jo.put("motion","idle"); | |||
| jo.put("traceId",""); | |||
| jo.put("status",2); | |||
| jo.put("tts","大模型出现异常,请稍后重试。"); | |||
| String str = jo.toJSONString(); | |||
| log.info("发生异常client:{},内容:{}",devId,jo.toJSONString()); | |||
| channel.writeAndFlush(new TextWebSocketFrame(str)); | |||
| log.error("发送消息失败", e); | |||
| } | |||
| } | |||
| } | |||
| /** | |||
| * 第一次登录进来 | |||
| * | |||
| * @param userId | |||
| * @param channel | |||
| */ | |||
| private void register(String userId, Channel channel) { | |||
| if (!ServerConfig.sessionMap.containsKey(userId)) { //没有指定的userId | |||
| ServerConfig.sessionMap.put(userId, channel); | |||
| // 将用户ID作为自定义属性加入到channel中,方便随时channel中获取用户ID | |||
| AttributeKey<String> key = AttributeKey.valueOf("userId"); | |||
| channel.attr(key).setIfAbsent(userId); | |||
| } | |||
| } | |||
| /** | |||
| * 更新登录信息 | |||
| * | |||
| * @param userId | |||
| * @param channel | |||
| */ | |||
| private void update(String userId, Channel channel) { | |||
| // 获取到之前的channel | |||
| Channel old_channel = ServerConfig.sessionMap.get(userId); | |||
| log.info("设备:{},之前的channel:{},新的channel:{}", userId, old_channel.id().asLongText(), channel.id().asLongText()); | |||
| // 移除之前channel的attr属性 | |||
| if (old_channel !=null && old_channel.hasAttr(AttributeKey.valueOf("userId"))) { | |||
| old_channel.attr(AttributeKey.valueOf("userId")).set(null); | |||
| } | |||
| // 更新sessionMap中的channel | |||
| ServerConfig.sessionMap.put(userId, channel); | |||
| // 将用户ID作为自定义属性加入到channel中,方便随时channel中获取用户ID | |||
| AttributeKey<String> key = AttributeKey.valueOf("userId"); | |||
| channel.attr(key).setIfAbsent(userId); | |||
| } | |||
| /** | |||
| * 开发发送消息,进行聊天 | |||
| * | |||
| * @param msg | |||
| * @param userId | |||
| */ | |||
| private void sendMsg(String userId, Object msg ) { | |||
| log.info("设备:{},收到消息:{}", userId,msg); | |||
| Channel channel1 = ServerConfig.sessionMap.get(userId); | |||
| if (channel1 != null) { | |||
| JSONObject result = INSTANCE.freeChatTemplate.handle(userId, msg.toString(),true); | |||
| // channel1.writeAndFlush(new TextWebSocketFrame("服务器时间" + LocalDateTime.now() + " " + "{\"action\":\"chat\",\"motion\":\"idle\",\"status\":1,\"tts\":\"是的,长津湖是一部2021年上映的中国电影,由陈凯歌、徐克和林超贤执导,吴京、易烊千玺等人主演。\"}")); | |||
| } | |||
| } | |||
| /** | |||
| * 一旦客户端连接上来,该方法被执行 | |||
| * | |||
| * @param ctx | |||
| * @throws Exception | |||
| */ | |||
| @Override | |||
| public void handlerAdded(ChannelHandlerContext ctx) throws Exception { | |||
| String remoteAddress = ""; | |||
| // 获取客户端的IP地址 | |||
| InetSocketAddress socketAddress = (InetSocketAddress) ctx.channel().remoteAddress(); | |||
| if (socketAddress != null) { | |||
| remoteAddress = socketAddress.getAddress().getHostAddress(); | |||
| } else { | |||
| //有时候可能会出现获取客户端IP地址为空的情况,这可能是由于网络架构中存在多级代理(例如Nginx等)而导致的。这时候需要通过HTTP请求头中的X-Forwarded-For字段来获取客户端的IP地址。 | |||
| } | |||
| log.info("handlerAdded 被调用:{},ip:{}" ,ctx.channel().id().asLongText(), remoteAddress); | |||
| } | |||
| /** | |||
| * 断开连接,需要移除用户 | |||
| * | |||
| * @param ctx | |||
| * @throws Exception | |||
| */ | |||
| @Override | |||
| public void handlerRemoved(ChannelHandlerContext ctx) throws Exception { | |||
| removeUserId(ctx); | |||
| } | |||
| /** | |||
| * 移除用户 | |||
| * | |||
| * @param ctx | |||
| */ | |||
| private void removeUserId(ChannelHandlerContext ctx) { | |||
| Channel channel = ctx.channel(); | |||
| AttributeKey<String> key = AttributeKey.valueOf("userId"); | |||
| String userId = channel.attr(key).get(); | |||
| if (userId == null) { | |||
| log.info("断开废弃连接,userId:{},channel:{}:", userId, channel.id().asLongText()); | |||
| return; | |||
| } | |||
| if (ServerConfig.sessionMap.containsKey(userId)) { | |||
| ServerConfig.sessionMap.remove(userId); | |||
| log.info("用户下线,userId:{},channel:{}:", userId, channel.id().asLongText()); | |||
| } | |||
| } | |||
| /** | |||
| * 处理移除,关闭通道 | |||
| * | |||
| * @param ctx | |||
| * @param cause | |||
| * @throws Exception | |||
| */ | |||
| @Override | |||
| public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { | |||
| ctx.close(); | |||
| } | |||
| } | |||
| @@ -0,0 +1,32 @@ | |||
| package com.xueyi.nlt.netty.server.handler; | |||
| import com.xueyi.nlt.netty.server.config.ServerConfig; | |||
| import io.netty.channel.ChannelHandlerContext; | |||
| import io.netty.channel.ChannelInboundHandlerAdapter; | |||
| import io.netty.channel.SimpleChannelInboundHandler; | |||
| import io.netty.handler.codec.http.websocketx.TextWebSocketFrame; | |||
| import io.netty.handler.timeout.IdleState; | |||
| import io.netty.handler.timeout.IdleStateEvent; | |||
| public class HeartbeatHandler extends ChannelInboundHandlerAdapter { | |||
| @Override | |||
| public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { | |||
| //超时事件 | |||
| if (evt instanceof IdleStateEvent) { | |||
| IdleStateEvent event = (IdleStateEvent) evt; | |||
| if (event.state() == IdleState.READER_IDLE){ | |||
| //读空闲 | |||
| System.out.println("读空闲"); | |||
| // 关闭该通道 | |||
| ctx.channel().close(); | |||
| }else if (event.state() == IdleState.WRITER_IDLE){ | |||
| //写空闲 | |||
| System.out.println("写空闲"); | |||
| }else if (event.state() == IdleState.ALL_IDLE){ | |||
| //读写空闲 | |||
| System.out.println("读写空闲"); | |||
| } | |||
| } | |||
| super.userEventTriggered(ctx, evt); | |||
| } | |||
| } | |||
| @@ -1,9 +1,6 @@ | |||
| package com.xueyi.nlt.nlt.controller; | |||
| import co.elastic.clients.elasticsearch.ElasticsearchClient; | |||
| import co.elastic.clients.elasticsearch._types.query_dsl.MatchQuery; | |||
| import co.elastic.clients.elasticsearch.core.SearchResponse; | |||
| import co.elastic.clients.elasticsearch.core.search.Hit; | |||
| import com.alibaba.fastjson2.JSONArray; | |||
| import com.alibaba.fastjson2.JSONObject; | |||
| import com.baomidou.mybatisplus.core.toolkit.StringUtils; | |||
| @@ -12,6 +9,7 @@ import com.xueyi.common.core.constant.basic.SecurityConstants; | |||
| import com.xueyi.common.core.constant.digitalman.MessageConstants; | |||
| import com.xueyi.common.core.constant.digitalman.SkillConstants.SkillType; | |||
| import com.xueyi.common.core.context.SecurityContextHolder; | |||
| import com.xueyi.common.core.utils.DateUtil; | |||
| import com.xueyi.common.core.utils.core.IdUtil; | |||
| import com.xueyi.common.core.web.result.AjaxResult; | |||
| import com.xueyi.common.core.web.result.R; | |||
| @@ -23,7 +21,6 @@ import com.xueyi.common.security.annotation.Logical; | |||
| import com.xueyi.common.security.annotation.RequiresPermissions; | |||
| import com.xueyi.common.web.entity.controller.BaseController; | |||
| import com.xueyi.nlt.api.netty.domain.vo.DmWebSocketMessageVo; | |||
| import com.xueyi.nlt.api.nlt.domain.vo.*; | |||
| import com.xueyi.nlt.api.nlt.domain.vo.response.DmIntentResponse; | |||
| import com.xueyi.nlt.api.nlt.domain.vo.CoversationSessionVo; | |||
| import com.xueyi.nlt.api.nlt.domain.vo.DmIntentVo; | |||
| @@ -31,6 +28,7 @@ import com.xueyi.nlt.api.nlt.domain.vo.DmLandingLlmVo; | |||
| import com.xueyi.nlt.api.nlt.domain.vo.DmRecognitionVo; | |||
| import com.xueyi.nlt.api.nlt.domain.vo.KnowledgeVo; | |||
| import com.xueyi.nlt.api.nlt.domain.vo.TaskKnowledgeVo; | |||
| import com.xueyi.nlt.api.nlt.domain.vo.response.DmKnowledgeResponse; | |||
| import com.xueyi.nlt.api.nlt.feign.RemoteIntentService; | |||
| import com.xueyi.nlt.api.nlt.feign.RemoteLandingLlmService; | |||
| import com.xueyi.nlt.api.nlt.feign.RemoteQAService; | |||
| @@ -51,6 +49,8 @@ import com.xueyi.system.api.digitalmans.feign.RemoteDigitalmanService; | |||
| import com.xueyi.system.api.digitalmans.feign.RemoteManDeviceService; | |||
| import com.xueyi.system.api.digitalmans.feign.RemoteQuestionanswersService; | |||
| import com.xueyi.system.api.digitalmans.feign.RemoteSkillService; | |||
| import com.xueyi.system.api.interfaces.airport.domain.vo.PlaneMessageVo; | |||
| import com.xueyi.system.api.interfaces.airport.feign.RemotePlaneController; | |||
| import com.xueyi.system.api.model.Source; | |||
| import com.xueyi.system.api.organize.domain.dto.SysEnterpriseDto; | |||
| import com.xueyi.system.api.organize.feign.RemoteEnterpriseService; | |||
| @@ -59,6 +59,7 @@ import org.slf4j.LoggerFactory; | |||
| import org.springframework.beans.factory.annotation.Autowired; | |||
| import org.springframework.data.redis.core.RedisTemplate; | |||
| import org.springframework.data.redis.core.StringRedisTemplate; | |||
| import org.springframework.util.DigestUtils; | |||
| import org.springframework.validation.annotation.Validated; | |||
| import org.springframework.web.bind.annotation.DeleteMapping; | |||
| import org.springframework.web.bind.annotation.GetMapping; | |||
| @@ -69,16 +70,11 @@ import org.springframework.web.bind.annotation.RequestBody; | |||
| import org.springframework.web.bind.annotation.RequestMapping; | |||
| import org.springframework.web.bind.annotation.ResponseBody; | |||
| import org.springframework.web.bind.annotation.RestController; | |||
| import java.io.IOException; | |||
| import java.io.Serializable; | |||
| import java.text.DateFormat; | |||
| import java.text.ParseException; | |||
| import java.text.SimpleDateFormat; | |||
| import java.util.*; | |||
| import java.time.Instant; | |||
| import java.time.LocalDateTime; | |||
| import java.time.ZoneId; | |||
| import java.util.concurrent.CountDownLatch; | |||
| import java.time.format.DateTimeFormatter; | |||
| import java.util.Arrays; | |||
| import java.util.Date; | |||
| import java.util.List; | |||
| @@ -120,7 +116,7 @@ public class DmIntentController extends BaseController<DmIntentQuery, DmIntentDt | |||
| @Autowired | |||
| private RemoteIntentService remoteIntentService; | |||
| @Autowired | |||
| private MeetingOrderTemplate meetingOrderTemplate; | |||
| @@ -161,6 +157,9 @@ public class DmIntentController extends BaseController<DmIntentQuery, DmIntentDt | |||
| @Autowired | |||
| private DmRegularMapper regularMapper; | |||
| @Autowired | |||
| private FlightMessageTemplate flightMessageTemplate; | |||
| /** | |||
| * 意图请求 | |||
| 列表 | |||
| @@ -202,7 +201,9 @@ public class DmIntentController extends BaseController<DmIntentQuery, DmIntentDt | |||
| @ResponseBody | |||
| public AjaxResult skillIntentApi(@RequestBody DmIntentVo intent) { | |||
| log.info("交互对象:{}", intent.toString()); | |||
| redisTemplate.opsForValue().increment(("dashboard:server-chart:" + DateUtil.getDate()), 1); | |||
| redisTemplate.opsForValue().increment("dashboard:server", 1); | |||
| redisTemplate.opsForValue().increment(("dashboard:server-chart:" + DateUtil.getDate()), 1); | |||
| R<DmManDeviceDto> manDeviceDtoR = manDeviceService.manDeviceInfoInner(intent.getDevId()); | |||
| if (!manDeviceDtoR.isOk() || manDeviceDtoR.getData() == null) { | |||
| return AjaxResult.error("设备不存在或服务没有启动,请确认。"); | |||
| @@ -230,6 +231,12 @@ public class DmIntentController extends BaseController<DmIntentQuery, DmIntentDt | |||
| response.setSkillCode("33"); | |||
| response.setH5(deliveryOrderTemplate.handle(intent.getDevId(),intent.getContent(), enterpriseId)); | |||
| return AjaxResult.success(response); | |||
| case "flight": | |||
| response.setMsg(""); | |||
| response.setSkillCode("34"); | |||
| response.setH5(flightMessageTemplate.handle(intent.getDevId(),intent.getContent(), enterpriseId)); | |||
| return AjaxResult.success(response); | |||
| } | |||
| } | |||
| @@ -296,7 +303,7 @@ public class DmIntentController extends BaseController<DmIntentQuery, DmIntentDt | |||
| */ | |||
| @PostMapping("/api/searchQA") | |||
| @ResponseBody | |||
| public AjaxResult searchQA(@RequestBody DmIntentVo intent) { | |||
| public DmKnowledgeResponse searchQA(@RequestBody DmIntentVo intent) { | |||
| log.info("交互对象:{}",intent.toString()); | |||
| R<DmManDeviceDto> manDeviceDtoR = manDeviceService.manDeviceInfoInner(intent.getDevId()); | |||
| @@ -306,7 +313,11 @@ public class DmIntentController extends BaseController<DmIntentQuery, DmIntentDt | |||
| knowledgeVo.setTenantId(manDeviceDtoR.getData().getTId()); | |||
| knowledgeVo.setQuestion(intent.getContent()); | |||
| // return remoteQAService.query(manDeviceDtoR.getData().getManCode(),intent.getContent(),manDeviceDtoR.getData().getTId()); | |||
| return remoteQAService.query(knowledgeVo); | |||
| R<DmKnowledgeResponse> dmKnowledgeResponseR = remoteQAService.query(knowledgeVo); | |||
| if (dmKnowledgeResponseR!= null && dmKnowledgeResponseR.getData() != null) { | |||
| return dmKnowledgeResponseR.getData(); | |||
| } | |||
| return null; | |||
| } | |||
| @@ -317,15 +328,63 @@ public class DmIntentController extends BaseController<DmIntentQuery, DmIntentDt | |||
| @ResponseBody | |||
| public AjaxResult searchQuestionAnswer(@RequestBody DmIntentVo intent) { | |||
| log.info("交互对象:{}",intent.toString()); | |||
| redisTemplate.opsForValue().increment("dashboard:recognition", 1); | |||
| redisTemplate.opsForValue().increment("dashboard:server", 1); | |||
| R<DmManDeviceDto> manDeviceDtoR = manDeviceService.manDeviceInfoInner(intent.getDevId()); | |||
| if (manDeviceDtoR.isFail()) { | |||
| return AjaxResult.error("设备号未激活或服务异常"); | |||
| } | |||
| Source source = SourceUtil.getSourceCache(manDeviceDtoR.getData().getStrategyId()); | |||
| String enterpriseName = ""; | |||
| R<SysEnterpriseDto> enterpriseDtoR = remoteEnterpriseService.getInfo(Long.valueOf(manDeviceDtoR.getData().getTId())); | |||
| if (enterpriseDtoR.isOk()) { | |||
| enterpriseName = enterpriseDtoR.getData().getName(); | |||
| } | |||
| DmIntentResponse response = new DmIntentResponse(); | |||
| //先调用意图 | |||
| //根据技能调用知识库或大模型 | |||
| CoversationSessionVo sessionObject = (CoversationSessionVo) redisTemplate2.opsForValue().get("group:device" + ":" + intent.getDevId() + ":" +"session"); | |||
| if(!(sessionObject == null) && sessionObject.getCategory().equals("flight")) { | |||
| response.setMsg(""); | |||
| response.setSkillCode("34"); | |||
| response.setH5(flightMessageTemplate.handle(intent.getDevId(),intent.getContent())); | |||
| return AjaxResult.success(response); | |||
| } | |||
| response = doMatchRegular(intent); | |||
| if (StringUtils.isNotEmpty(response.getSkillCode())) { | |||
| if (SkillType.FLIGHT.getCode().equals(response.getSkillCode()) ) { | |||
| redisTemplate.opsForValue().increment("dashboard:flight", 1); | |||
| pushIntoDashboardRedis(enterpriseName, "查询航班信息", "skill"); | |||
| response.setH5(flightMessageTemplate.handle(intent.getDevId(), intent.getContent())); | |||
| return AjaxResult.success(response); | |||
| } | |||
| } | |||
| // 调用知识库 | |||
| // 调用知识库问答 | |||
| response.setSkillCode("30"); | |||
| DmKnowledgeResponse qaAjax = searchQA(intent); | |||
| String content = ""; | |||
| if (qaAjax != null) { | |||
| log.info("知识库问答返回结果:{}",qaAjax.toString()); | |||
| if (qaAjax.getTarget() == 1 && qaAjax.getAccurate() == 1) { | |||
| content = qaAjax.getResult().get(0).getKnowledgeLib(); | |||
| pushIntoDashboardRedis(enterpriseName,content,"knowledge"); | |||
| response.setH5(JSONObject.from(qaAjax)); | |||
| return AjaxResult.success(response); | |||
| } | |||
| } | |||
| JSONObject joResult = new JSONObject(); | |||
| joResult.put("msg",""); | |||
| joResult.put("target",0); | |||
| DmLandingLlmVo vo = new DmLandingLlmVo(); | |||
| vo.setCategory("bj_unicom"); | |||
| vo.setCategory("airport"); | |||
| vo.addDmLlm("user", intent.getContent()); | |||
| JSONObject testJ = new JSONObject(); | |||
| testJ.put("category","bj_unicom"); | |||
| testJ.put("category","airport"); | |||
| JSONArray ja1 = new JSONArray(); | |||
| JSONObject jo = new JSONObject(); | |||
| jo.put("role","user"); | |||
| @@ -333,13 +392,31 @@ public class DmIntentController extends BaseController<DmIntentQuery, DmIntentDt | |||
| ja1.add(jo); | |||
| testJ.put("messages",ja1); | |||
| JSONObject resultJson = remoteLandingLlmService.query(testJ); | |||
| JSONArray ja = resultJson.getJSONArray("data"); | |||
| if (ja.size() > 0) { | |||
| joResult.put("msg",ja.getJSONObject(0).get("text")); | |||
| joResult.put("target",1); | |||
| log.info("北方大返回:{}",resultJson.toString()); | |||
| if (resultJson.get("status").equals("success")) { | |||
| JSONArray ja = resultJson.getJSONArray("data"); | |||
| if (ja.size() > 0) { | |||
| String text = ja.getJSONObject(0).getString("text"); | |||
| response.setMsg(text); | |||
| // 判断text是否为纯数字 | |||
| if (!text.matches("[0-9]+")) { | |||
| JSONObject joImage = new JSONObject(); | |||
| joImage.put("msg",text); | |||
| // 非纯数字 | |||
| if (ja.getJSONObject(0).containsKey("filename")) { | |||
| // TODO: 2023/9/27 合并知识到知识库 | |||
| String libName = ja.getJSONObject(0).getString("filename").split("\\.")[0]; | |||
| // 添加到知识数据库 | |||
| } | |||
| if (ja.getJSONObject(0).containsKey("imageList") && ja.getJSONObject(0).getJSONArray("imageList").size() > 0) { | |||
| joImage.put("imageUrl",ja.getJSONObject(0).getJSONArray("imageList").getString(0)); | |||
| } | |||
| response.setMsg(""); | |||
| response.setH5(joImage); | |||
| } | |||
| } | |||
| } | |||
| return AjaxResult.success(joResult); | |||
| return AjaxResult.success(response); | |||
| } | |||
| /** | |||
| @@ -388,22 +465,22 @@ public class DmIntentController extends BaseController<DmIntentQuery, DmIntentDt | |||
| // 调用知识库 | |||
| // 调用知识库问答 | |||
| response.setSkillCode("30"); | |||
| AjaxResult qaAjax = searchQA(intent); | |||
| JSONObject qajson = qaAjax.toJson(); | |||
| DmKnowledgeResponse qaAjax = searchQA(intent); | |||
| String content = ""; | |||
| log.info("知识库问答返回结果:{}",qaAjax.toString()); | |||
| if (qajson.containsKey("data") && qajson.getJSONObject("data").containsKey("result") && qajson.getJSONObject("data").size() > 0) { | |||
| content = qajson.getJSONObject("data").getJSONArray("result").getJSONObject(0).getString("knowledge_lib"); | |||
| pushIntoDashboardRedis(enterpriseName,content,"knowledge"); | |||
| response.setH5(JSONObject.from(qaAjax.get("data"))); | |||
| return R.ok(response); | |||
| } | |||
| if (qajson.containsKey("data") && qajson.getJSONObject("data").getString("target").equals("0")) { | |||
| // 知识库没有答案,返回空 | |||
| response.clear(); | |||
| response.setMsg(""); | |||
| if (qaAjax != null) { | |||
| log.info("知识库问答返回结果:{}",qaAjax.toString()); | |||
| if (qaAjax.getTarget() == 1) { | |||
| content = qaAjax.getResult().get(0).getKnowledgeLib(); | |||
| pushIntoDashboardRedis(enterpriseName,content,"knowledge"); | |||
| response.setH5(JSONObject.from(qaAjax)); | |||
| return R.ok(response); | |||
| } | |||
| else { | |||
| // 知识库没有答案,返回空 | |||
| response.clear(); | |||
| response.setMsg(""); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| else { | |||
| @@ -436,6 +513,9 @@ public class DmIntentController extends BaseController<DmIntentQuery, DmIntentDt | |||
| redisTemplate.opsForValue().increment("dashboard:delivery", 1); | |||
| pushIntoDashboardRedis(enterpriseName, "寄快递", "skill"); | |||
| } | |||
| }else if (SkillType.FLIGHT.getCode().equals(intent.getSkillCode()) ) { | |||
| redisTemplate.opsForValue().increment("dashboard:flight", 1); | |||
| pushIntoDashboardRedis(enterpriseName, "查询航班信息", "skill"); | |||
| } | |||
| // 判断是否有权限 | |||
| R<List<DmSkillDto>> skilllistInner = remoteskillService.skilllistInner(intent.getDevId(),"1",Long.parseLong(enterpriseId), source.getMaster(), SecurityConstants.INNER); | |||
| @@ -462,6 +542,9 @@ public class DmIntentController extends BaseController<DmIntentQuery, DmIntentDt | |||
| // 做快递预约处理 | |||
| response.setH5(deliveryOrderTemplate.handle(intent.getDevId(), intent.getContent(), Long.parseLong(SecurityContextHolder.getLocalMap().get("enterprise_id").toString()))); | |||
| break; | |||
| case "34": | |||
| // 做查询航班信息处理 | |||
| response.setH5(flightMessageTemplate.handle(intent.getDevId(), intent.getContent(), Long.parseLong(SecurityContextHolder.getLocalMap().get("enterprise_id").toString()))); | |||
| default: | |||
| break; | |||
| } | |||
| @@ -730,18 +813,20 @@ public class DmIntentController extends BaseController<DmIntentQuery, DmIntentDt | |||
| return matcher.find(); | |||
| } | |||
| private DmIntentResponse doMatchRegular(DmIntentVo intent) { | |||
| private DmIntentResponse doMatchRegular(DmIntentVo intent){ | |||
| DmIntentResponse response = new DmIntentResponse(); | |||
| List <DmRegularPo> regularPos = regularMapper.selectList(null); | |||
| boolean flag = false; | |||
| for (DmRegularPo regularPo : regularPos) { | |||
| if (isMatchRegular(intent.getContent(), regularPo.getExpression())) { | |||
| response.setMsg(regularPo.getText()); | |||
| response.setSkillCode(regularPo.getSkillCode()); | |||
| response.setAction(regularPo.getAction()); | |||
| response.setH5(regularPo.getJson()); | |||
| flag = true; | |||
| break; | |||
| } | |||
| } | |||
| @@ -779,6 +864,7 @@ public class DmIntentController extends BaseController<DmIntentQuery, DmIntentDt | |||
| return response; | |||
| } | |||
| interface Auth { | |||
| /** 系统 - 意图管理 | |||
| 管理 - 列表 */ | |||
| @@ -13,6 +13,7 @@ import java.util.stream.Collectors; | |||
| @NoArgsConstructor | |||
| public class LlmContext implements Serializable { | |||
| private String devId; | |||
| private List<LlmContent> contentList; | |||
| @@ -11,7 +11,7 @@ import java.io.IOException; | |||
| @Component | |||
| public class KafkaMessageConsumer { | |||
| @KafkaListener(groupId = "simpleGroup", topics = "es_info_log") | |||
| // @KafkaListener(groupId = "simpleGroup", topics = "es_info_log") | |||
| public void coumuser(@Payload String record, @Header(KafkaHeaders.RECEIVED_TOPIC) String topic) throws InterruptedException, IOException, IllegalAccessException { | |||
| System.out.println(record); | |||
| System.out.println(topic); | |||
| @@ -8,4 +8,5 @@ import com.xueyi.nlt.nlt.domain.LlmResponse; | |||
| public interface ISysLlmService { | |||
| LlmResponse chat(LlmContext context, LlmParam param); | |||
| LlmResponse stream(LlmContext context, LlmParam param); | |||
| } | |||
| @@ -43,4 +43,12 @@ public class SparkServiceImpl implements ISysLlmService { | |||
| } | |||
| } | |||
| @Override | |||
| public LlmResponse stream(LlmContext context, LlmParam param) { | |||
| List<String> contentArr = context.getContentList().stream().map(LlmContent::getContent).collect(Collectors.toList()); | |||
| webSocketClient.sendMsg(contentArr, true,context.getDevId()); | |||
| LlmResponse response = new LlmResponse(); | |||
| return response; | |||
| } | |||
| } | |||
| @@ -0,0 +1,166 @@ | |||
| package com.xueyi.nlt.nlt.template; | |||
| import com.alibaba.fastjson2.JSONArray; | |||
| import com.alibaba.fastjson2.JSONObject; | |||
| import com.xueyi.common.core.constant.digitalman.SkillConstants; | |||
| import com.xueyi.nlt.api.nlt.domain.vo.CoversationSessionVo; | |||
| import com.xueyi.system.api.interfaces.airport.domain.vo.PlaneMessageVo; | |||
| import com.xueyi.system.api.interfaces.airport.feign.RemotePlaneController; | |||
| import org.slf4j.Logger; | |||
| import org.slf4j.LoggerFactory; | |||
| import org.springframework.beans.factory.annotation.Autowired; | |||
| import org.springframework.data.redis.core.RedisTemplate; | |||
| import org.springframework.stereotype.Service; | |||
| import org.springframework.util.DigestUtils; | |||
| import java.text.ParseException; | |||
| import java.text.SimpleDateFormat; | |||
| import java.util.ArrayList; | |||
| import java.util.Date; | |||
| import java.util.List; | |||
| import java.util.concurrent.TimeUnit; | |||
| import java.util.regex.Matcher; | |||
| import java.util.regex.Pattern; | |||
| @Service("flight-message") | |||
| public class FlightMessageTemplate implements BaseTemplate{ | |||
| private static final Logger log = LoggerFactory.getLogger(FlightMessageTemplate.class); | |||
| @Autowired | |||
| private RedisTemplate<Object,Object> objectRedisTemplate; | |||
| @Autowired | |||
| private RemotePlaneController remotePlaneController; | |||
| private void init(){ | |||
| log.info("航信服务已启动。"); | |||
| } | |||
| @Override | |||
| public JSONObject handle(String dev, String content) { | |||
| return handle(dev, content, 0L); | |||
| } | |||
| @Override | |||
| public JSONObject handle(String devId, String content, Long tenantId) { | |||
| CoversationSessionVo session = (CoversationSessionVo) objectRedisTemplate.opsForValue().get("group:device" + ":" + devId + ":" +"session"); | |||
| boolean flag = true; | |||
| if (session == null) { | |||
| session = new CoversationSessionVo(); | |||
| session.setCategory("flight"); | |||
| JSONObject data = new JSONObject(); | |||
| session.setFormat(new JSONObject()); | |||
| session.getFormat().put("skillCode", SkillConstants.SkillType.FLIGHT.getCode()); | |||
| session.getFormat().put("errorTime", 0); | |||
| flag = false; | |||
| } | |||
| JSONObject result; | |||
| content = content.replace("-", "").replace(" ", "").replace("$", "").toUpperCase(); | |||
| Pattern pattern = Pattern.compile("([A-Z]{2}|\\d[A-Z]|[A-Z]\\d)\\d{4}"); | |||
| Matcher matcher = pattern.matcher(content); | |||
| if(matcher.find()){ | |||
| String fNum = matcher.group(); | |||
| result = checkFlight(fNum, 0); | |||
| if(result.isEmpty()){ | |||
| result = checkFlight(fNum, 1); | |||
| if(result.isEmpty()){ | |||
| result = new JSONObject(); | |||
| result.put("status", -1); | |||
| result.put("skillCode", "34"); | |||
| session.getFormat().put("errorTime", session.getFormat().getInteger("errorTime") + 1); | |||
| }else{ | |||
| session.getFormat().put("errorTime", 0); | |||
| } | |||
| }else{ | |||
| session.getFormat().put("errorTime", 0); | |||
| } | |||
| }else{ | |||
| if(flag){ | |||
| result = new JSONObject(); | |||
| result.put("status", -2); | |||
| result.put("skillCode", "34"); | |||
| session.getFormat().put("errorTime", session.getFormat().getInteger("errorTime") + 1); | |||
| }else{ | |||
| result = new JSONObject(); | |||
| result.put("status", 0); | |||
| result.put("skillCode", "34"); | |||
| } | |||
| } | |||
| if(session.getFormat().getInteger("errorTime") > 5){ | |||
| objectRedisTemplate.delete("group:device" + ":" + devId + ":" +"session"); | |||
| }else{ | |||
| objectRedisTemplate.opsForValue().set("group:device" + ":" + devId + ":" +"session", session, 1, TimeUnit.MINUTES); | |||
| } | |||
| return result; | |||
| } | |||
| private JSONObject checkFlight(String fNum, Integer days) { | |||
| Long timestamp = System.currentTimeMillis(); | |||
| SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); | |||
| String date = dateFormat.format(timestamp + days * 1000 * 60 * 60 * 24); | |||
| String singStr = date + fNum + timestamp; | |||
| String sign = DigestUtils.md5DigestAsHex(singStr.getBytes()); | |||
| PlaneMessageVo planeMessageVo = new PlaneMessageVo(); | |||
| planeMessageVo.setFNum(fNum); | |||
| planeMessageVo.setDate(date); | |||
| JSONObject result = new JSONObject(); | |||
| JSONObject flightMessage = remotePlaneController.queryFlight(planeMessageVo, String.valueOf(timestamp), sign); | |||
| log.info(flightMessage.toString()); | |||
| if (flightMessage.containsKey("reason") && | |||
| flightMessage.getString("reason").equals("success")) { | |||
| JSONObject fullFlight = flightMessage.getJSONArray("result").getJSONObject(0); | |||
| SimpleDateFormat formatter= new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); | |||
| Date dateNow = new Date(System.currentTimeMillis()); | |||
| try{ | |||
| if(dateNow.after(formatter.parse(fullFlight.getString("FlightDeptimePlanDate")))){ | |||
| return new JSONObject(); | |||
| } | |||
| } catch (ParseException e) { | |||
| log.error(e.toString()); | |||
| return new JSONObject(); | |||
| } | |||
| result.put("stopFlag", fullFlight.getInteger("StopFlag")); | |||
| result.put("flightNo", fullFlight.getString("FlightNo")); | |||
| result.put("flightCompany", fullFlight.getString("FlightCompany")); | |||
| JSONArray nowFlights = flightMessage.getJSONArray("result"); | |||
| JSONArray flights = new JSONArray(); | |||
| for (int i = 0; i < nowFlights.size(); i++) { | |||
| JSONObject nowFlight = nowFlights.getJSONObject(i); | |||
| if (nowFlight.getString("StopFlag").equals("0")) { | |||
| JSONObject newFlight = new JSONObject(); | |||
| newFlight.put("Dep", nowFlight.getString("FlightDep")); | |||
| newFlight.put("Arr", nowFlight.getString("FlightArr")); | |||
| newFlight.put("DepTime", nowFlight.getString("FlightDeptimePlanDate")); | |||
| newFlight.put("ArrTime", nowFlight.getString("FlightArrtimePlanDate")); | |||
| flights.add(newFlight); | |||
| } | |||
| } | |||
| result.put("flights", flights); | |||
| List<String> transit = new ArrayList<>(); | |||
| for (int i = 1; i < flights.size(); i++) { | |||
| SimpleDateFormat simpleDateFormat2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); | |||
| try { | |||
| Date begin = simpleDateFormat2.parse(flights.getJSONObject(i - 1).getString("ArrTime")); | |||
| Date end = simpleDateFormat2.parse(flights.getJSONObject(i).getString("DepTime")); | |||
| long minutes = (end.getTime() - begin.getTime()) / (1000 * 60); | |||
| if (minutes < 60) { | |||
| transit.add(String.format("%d分钟", (int) minutes)); | |||
| } else { | |||
| transit.add(String.format("%dh%dm", minutes / 60, minutes % 60)); | |||
| } | |||
| } catch (ParseException e) { | |||
| log.error(e.toString()); | |||
| return new JSONObject(); | |||
| } | |||
| } | |||
| result.put("transit", transit); | |||
| result.put("status", 1); | |||
| result.put("skillCode", "34"); | |||
| } | |||
| return result; | |||
| } | |||
| } | |||
| @@ -17,8 +17,11 @@ import org.springframework.beans.factory.annotation.Autowired; | |||
| import org.springframework.data.redis.core.RedisTemplate; | |||
| import org.springframework.stereotype.Service; | |||
| import javax.annotation.PostConstruct; | |||
| import java.util.ArrayList; | |||
| import java.util.HashMap; | |||
| import java.util.List; | |||
| import java.util.Map; | |||
| @Service("free-chat") | |||
| @@ -31,51 +34,105 @@ public class FreeChatTemplate implements BaseTemplate{ | |||
| @Autowired | |||
| private RedisTemplate<String,String> redisTemplate; | |||
| private Map<String,String> correctWordsMap = new HashMap<>(); | |||
| // 中航信领导来访临时对策 | |||
| // bean初始化加载 | |||
| @PostConstruct | |||
| public void init() { | |||
| //初始化纠错词库 | |||
| correctWordsMap.put("中航讯","中航信"); | |||
| } | |||
| @Override | |||
| public JSONObject handle(String devId, String content) { | |||
| Long operatorId = TerminalSecurityContextHolder.getOperatorId(); | |||
| String redisKey = "group:nlp:" + SecurityContextHolder.getLocalMap().get("enterprise_id") + ":" + operatorId; | |||
| // 根据content内容调用模版并返回结果 | |||
| // 通过redis获取数字人上下文信息 | |||
| Long size = redisTemplate.opsForList().size(redisKey); | |||
| if (size > 8) { | |||
| redisTemplate.opsForList().leftPop(redisKey,2); | |||
| } | |||
| size = redisTemplate.opsForList().size(redisKey); | |||
| List<String> context = new ArrayList<>(); | |||
| context.add("你是一位企业前台。你来自于缔智元公司。你的名字叫小智,你是一位数字员工。"); | |||
| context.addAll(redisTemplate.opsForList().range(redisKey,size-6,size)); | |||
| context.add(content); | |||
| //webSocketClient.sendMsg(context); | |||
| synchronized (WebSocketClient.LOCK) { | |||
| // 通过redis获取数字人上下文信息 | |||
| Long size = redisTemplate.opsForList().size(redisKey); | |||
| if (size > 8) { | |||
| redisTemplate.opsForList().leftPop(redisKey,2); | |||
| } | |||
| size = redisTemplate.opsForList().size(redisKey); | |||
| List<String> context = new ArrayList<>(); | |||
| context.add("你是缔智元公司的前台,你叫小智,你是一位数字人。"); | |||
| context.addAll(redisTemplate.opsForList().range(redisKey,size-6,size)); | |||
| LlmContext llmContext = LlmContext.parse(context,true); | |||
| LlmParam param = new LlmParam(); | |||
| LlmResponse response = sysLlmService.chat(llmContext,param); | |||
| String result = response.getContent(); | |||
| context.add(content); | |||
| // 处理数据 | |||
| if (result.contains("我是科大讯飞")) { | |||
| result = "我是缔智元公司的数字人员工,我采用的是科大讯飞的星火大模型。"; | |||
| } | |||
| //webSocketClient.sendMsg(context); | |||
| LlmContext llmContext = LlmContext.parse(context,true); | |||
| LlmParam param = new LlmParam(); | |||
| LlmResponse response = sysLlmService.chat(llmContext,param); | |||
| String result = response.getContent(); | |||
| if(!StringUtils.isEmpty(result)){ | |||
| // 处理数据 | |||
| if (result.contains("我是科大讯飞")) { | |||
| result = result.replaceAll("科大讯飞", "缔智元"); | |||
| } | |||
| result = result.replaceAll("认知模型", "数字员工"); | |||
| result = result.replaceAll("认知智能模型", "数字员工"); | |||
| if (result.equals("-1")) { | |||
| result = "这个问题超出了我的能力,您可以提出更多关于公司相关问题。"; | |||
| } else { | |||
| result = "这个问题超出了我无法回答,您可以提出更多关于电影相关问题。"; | |||
| } | |||
| if(!StringUtils.isEmpty(result)){ | |||
| redisTemplate.opsForList().rightPush(redisKey,content); | |||
| redisTemplate.opsForList().rightPush(redisKey,result); | |||
| } | |||
| JSONObject resultJson = new JSONObject(); | |||
| resultJson.put("msg",result); | |||
| return resultJson; | |||
| } | |||
| JSONObject resultJson = new JSONObject(); | |||
| resultJson.put("msg",result); | |||
| return resultJson; | |||
| } | |||
| public JSONObject handle(String dev, String content, boolean stream) { | |||
| Long operatorId = TerminalSecurityContextHolder.getOperatorId(); | |||
| String redisKey = "group:nlp:" + SecurityContextHolder.getLocalMap().get("enterprise_id") + ":" + operatorId; | |||
| // 根据content内容调用模版并返回结果 | |||
| synchronized (WebSocketClient.LOCK) { | |||
| // 通过redis获取数字人上下文信息 | |||
| Long size = redisTemplate.opsForList().size(redisKey); | |||
| if (size > 8) { | |||
| redisTemplate.opsForList().leftPop(redisKey,2); | |||
| } | |||
| size = redisTemplate.opsForList().size(redisKey); | |||
| List<String> context = new ArrayList<>(); | |||
| context.add("你是缔智元公司的前台,你叫小智,你是一位数字人,你们公司在北京,你的职能是负责做会议预定和访客预约。"); | |||
| // 中航信领导来访临时对策 | |||
| // 判断如果content包含correctWordsMap中的key,则替换为value | |||
| for (String key : correctWordsMap.keySet()) { | |||
| if (content.contains(key)) { | |||
| content = content.replaceAll(key, correctWordsMap.get(key)); | |||
| } | |||
| } | |||
| //context.addAll(redisTemplate.opsForList().range(redisKey,size-2,size)); | |||
| content = "请用简短的话回答下面的问题:" + content; | |||
| context.add(content); | |||
| //使用stream去除context列表中所有字符串中的引号 | |||
| context = context.stream().map(s -> s.replaceAll("\"", "")).collect(java.util.stream.Collectors.toList()); | |||
| //webSocketClient.sendMsg(context); | |||
| LlmContext llmContext = LlmContext.parse(context,true); | |||
| llmContext.setDevId(dev); | |||
| LlmParam param = new LlmParam(); | |||
| LlmResponse response = sysLlmService.stream(llmContext,param); | |||
| JSONObject resultJson = new JSONObject(); | |||
| resultJson.put("tts","让我想一想。"); | |||
| resultJson.put("motion","idle"); | |||
| resultJson.put("status","0"); | |||
| resultJson.put("action","chat"); | |||
| return resultJson; | |||
| } | |||
| } | |||
| @Override | |||
| public JSONObject handle(String dev, String content, Long tenantId) { | |||
| return null; | |||
| } | |||
| } | |||
| } | |||
| @@ -85,7 +85,6 @@ public class MeetingOrderTemplate implements BaseTemplate { | |||
| private static final List<MeetingParamVo> MEETING_PARAMS = new ArrayList<>(); | |||
| private static JSONObject MEETING_DURATION = new JSONObject(); | |||
| private static List<String> MEETING_TOPIC = new ArrayList<>(); | |||
| @@ -146,7 +145,6 @@ public class MeetingOrderTemplate implements BaseTemplate { | |||
| log.error("解析会议参数失败", e); | |||
| } | |||
| } | |||
| MEETING_DURATION = JSONObject.parseObject(nacosConfigManager.getConfigService().getConfig("meeting_duration_hour", "DEFAULT_GROUP", 5000)); | |||
| String topics = nacosConfigManager.getConfigService().getConfig("meeting_topic", "DEFAULT_GROUP", 5000); | |||
| MEETING_TOPIC.addAll(List.of(topics.split(","))); | |||
| MEETING_CONFIRM = JSONObject.parseObject(nacosConfigManager.getConfigService().getConfig("meeting_confirm_cancel", "DEFAULT_GROUP", 5000)); | |||
| @@ -188,7 +186,7 @@ public class MeetingOrderTemplate implements BaseTemplate { | |||
| // 更新session中的locationId与location | |||
| session.getFormat().put("location",roomsDto.getName()); | |||
| session.getFormat().put("locationId",roomsDto.getId()); | |||
| content = content.replace(roomsDto.getName(), "啊啊啊"); | |||
| content = content.replace(roomsDto.getName(), "@@@"); | |||
| break; | |||
| } | |||
| for(int i = 0;i<10;i++){ | |||
| @@ -200,7 +198,7 @@ public class MeetingOrderTemplate implements BaseTemplate { | |||
| // 更新session中的locationId与location | |||
| session.getFormat().put("location",roomsDto.getName()); | |||
| session.getFormat().put("locationId",roomsDto.getId()); | |||
| content = content.replace(roomsDto.getName(), "啊啊啊"); | |||
| content = content.replace(roomsDto.getName(), "@@@"); | |||
| break; | |||
| } | |||
| } | |||
| @@ -211,14 +209,28 @@ public class MeetingOrderTemplate implements BaseTemplate { | |||
| session = dateSession; | |||
| } | |||
| //判断是否击中持续时间的正则 | |||
| for(String key:MEETING_DURATION.keySet()){ | |||
| if(content.contains(key)){ | |||
| session.getFormat().put("duration", MEETING_DURATION.getIntValue(key)); | |||
| content = content.replace(key, "啊啊啊"); | |||
| break; | |||
| String[] chinesenumber2 = {"一","两","三","四","五","六","七","八","九","十"}; | |||
| for(int i=0;i<10;i++){ | |||
| content = content.replaceAll(chinesenumber2[i],number[i]); | |||
| } | |||
| Pattern pattern = Pattern.compile("(\\d)+(\\.)?(\\d)*(个)?(半)?小时"); | |||
| Matcher matcher = pattern.matcher(content); | |||
| if(matcher.find()){ | |||
| content = content.replace(matcher.group(), "@@@"); | |||
| String matchedNumber =matcher.group().replace("个", "").replace("小时", "").replace("半", ".5"); | |||
| Double tempNumber = Double.parseDouble(matchedNumber) * 60; | |||
| if(String.valueOf(tempNumber).endsWith(".0")){ | |||
| session.getFormat().put("duration", Integer.parseInt(String.valueOf(Double.parseDouble(matchedNumber) * 60).replace(".0", ""))); | |||
| } | |||
| }else{ | |||
| if(content.contains("半小时") || content.contains("半个小时")){ | |||
| session.getFormat().put("duration", 30); | |||
| content = content.replace("半小时", "@@@").replace("半个小时", "@@@"); | |||
| } | |||
| } | |||
| //判断是否集中会议主题正则 | |||
| for(String topic: MEETING_TOPIC){ | |||
| if(content.contains(topic)){ | |||
| session.getFormat().put("meetingIntent", topic); | |||
| @@ -227,14 +239,22 @@ public class MeetingOrderTemplate implements BaseTemplate { | |||
| } | |||
| //判断会议室是否冲突,如果冲突则回传有冲突 | |||
| JSONObject checkObject = session.getFormat(); | |||
| if(checkObject.containsKey("date")){ | |||
| LocalDateTime date = LocalDateTime.parse(session.getFormat().getString("date") + " 00:00:00",DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); | |||
| LocalDateTime now = LocalDateTime.now().withHour(0).withMinute(0).withSecond(0).withNano(0); | |||
| if(now.isAfter(date)){ | |||
| session.getFormat().put("conflict", 1); | |||
| } else{ | |||
| session.getFormat().remove("conflict"); | |||
| } | |||
| } | |||
| if (checkObject.containsKey("date") && checkObject.containsKey("start_time") && checkObject.containsKey("location") && checkObject.containsKey("duration")) { | |||
| JSONObject ret= remoteMeetingService.queryExistOrder(checkObject.getLong("locationId"), checkObject.getString("date"), checkObject.getString("start_time"),checkObject.getInteger("duration"),tenantId,source.getMaster(), SecurityConstants.INNER); | |||
| if (StringUtils.isNotEmpty(ret.getString("err"))) { | |||
| // 会议室冲突,删除时间 | |||
| session.getFormat().put("conflict",1); | |||
| } | |||
| else{ | |||
| session.getFormat().put("conflict",0); | |||
| // 会议室冲突,返回冲突类型 | |||
| session.getFormat().put("conflict", 2); | |||
| }else{ | |||
| session.getFormat().put("conflict", 0); | |||
| } | |||
| } | |||
| @@ -131,12 +131,38 @@ | |||
| <version>8.3.3</version> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>com.googlecode.json-simple</groupId> | |||
| <artifactId>json-simple</artifactId> | |||
| <version>1.1.1</version> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>com.graphql-java</groupId> | |||
| <artifactId>graphql-java</artifactId> | |||
| <version>11.0</version> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>com.alibaba</groupId> | |||
| <artifactId>easyexcel</artifactId> | |||
| <version>3.3.3</version> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>com.github.binarywang</groupId> | |||
| <artifactId>weixin-java-miniapp</artifactId> | |||
| <version>4.6.0</version> | |||
| </dependency> | |||
| </dependencies> | |||
| <build> | |||
| <finalName>${project.artifactId}</finalName> | |||
| <outputDirectory>${project.build.directory}/classes</outputDirectory> | |||
| <plugins> | |||
| <plugin> | |||
| <groupId>org.springframework.boot</groupId> | |||
| @@ -1,6 +1,7 @@ | |||
| package com.xueyi.system.authority.controller; | |||
| import com.xueyi.common.cache.utils.SourceUtil; | |||
| import com.xueyi.common.core.constant.basic.SecurityConstants; | |||
| import com.xueyi.common.core.context.SecurityContextHolder; | |||
| import com.xueyi.common.core.utils.core.CollUtil; | |||
| import com.xueyi.common.core.utils.core.ObjectUtil; | |||
| @@ -14,6 +15,10 @@ import com.xueyi.system.api.model.Source; | |||
| import com.xueyi.system.api.organize.domain.dto.SysEnterpriseDto; | |||
| import com.xueyi.system.api.organize.domain.dto.SysUserDto; | |||
| import com.xueyi.system.authority.service.ISysLoginService; | |||
| import com.xueyi.tenant.api.tenant.domain.po.TeTenantPo; | |||
| import com.xueyi.tenant.api.tenant.feign.RemoteTenantService; | |||
| import org.slf4j.Logger; | |||
| import org.slf4j.LoggerFactory; | |||
| import org.springframework.beans.factory.annotation.Autowired; | |||
| import org.springframework.web.bind.annotation.GetMapping; | |||
| import org.springframework.web.bind.annotation.PathVariable; | |||
| @@ -33,6 +38,7 @@ import java.util.stream.Collectors; | |||
| @RestController | |||
| @RequestMapping("/login") | |||
| public class SysLoginController extends BasisController { | |||
| private final Logger log = LoggerFactory.getLogger(SysLoginController.class); | |||
| @Autowired | |||
| ISysLoginService loginService; | |||
| @@ -92,4 +98,71 @@ public class SysLoginController extends BasisController { | |||
| loginUser.setRouteURL(routeMap); | |||
| return R.ok(loginUser); | |||
| } | |||
| @Autowired | |||
| RemoteTenantService tenantService; | |||
| /** | |||
| * 获取登录信息 | 内部调用, 手机号登录 | |||
| */ | |||
| @InnerAuth | |||
| @GetMapping("/inner/loginByPhone/{phone}") | |||
| public R<LoginUser> getLoginInfoByMobile(@PathVariable("phone") String phone) { | |||
| log.info("获取登录信息 | 内部调用, 手机号登录 | phone: {}", phone); | |||
| R<TeTenantPo> po = tenantService.tenant(phone, SecurityConstants.INNER); | |||
| log.info("获取登录信息 | 内部调用, 手机号登录 | po:{}, {}, {}", po.getMsg(),po.getCode(),po.isFail()); | |||
| if (po.getData() == null) | |||
| return R.fail("指定手机号不存在记录"); | |||
| SysEnterpriseDto enterprise = loginService.loginByEnterpriseName(po.getData().getName()); | |||
| // 不存在直接返回空数据 | 与网络调用错误区分 | |||
| if (ObjectUtil.isNull(enterprise)) | |||
| return R.ok(null, "企业账号不存在"); | |||
| SecurityContextHolder.setEnterpriseId(enterprise.getId().toString()); | |||
| SecurityContextHolder.setIsLessor(enterprise.getIsLessor()); | |||
| Source source = SourceUtil.getSourceCache(enterprise.getStrategyId()); | |||
| // 不存在直接返回空数据 | 与网络调用错误区分 | |||
| if (ObjectUtil.isNull(source)) | |||
| return R.ok(null, "数据源不存在"); | |||
| SecurityContextHolder.setSourceName(source.getMaster()); | |||
| LoginUser loginUser = new LoginUser(); | |||
| loginUser.setEnterprise(enterprise); | |||
| loginUser.setEnterpriseId(enterprise.getId()); | |||
| loginUser.setEnterpriseName(enterprise.getName()); | |||
| loginUser.setIsLessor(enterprise.getIsLessor()); | |||
| loginUser.setSource(source); | |||
| loginUser.setSourceName(source.getMaster()); | |||
| SysUserDto user = loginService.loginByStaff(phone); | |||
| if (ObjectUtil.isNull(user)) | |||
| return R.ok(null, "用户账号不存在"); | |||
| SecurityContextHolder.setUserType(user.getUserType()); | |||
| // 角色权限标识 | |||
| Set<String> roles = loginService.getRolePermission(user.getRoles(), user.getUserType()); | |||
| // 角色Id集合 | |||
| Set<Long> roleIds = CollUtil.isNotEmpty(user.getRoles()) | |||
| ? user.getRoles().stream().map(SysRoleDto::getId).collect(Collectors.toSet()) | |||
| : new HashSet<>(); | |||
| // 菜单权限标识 | |||
| Set<String> permissions = loginService.getMenuPermission(roleIds, user.getUserType()); | |||
| // 权限范围 | |||
| DataScope dataScope = loginService.getDataScope(user.getRoles(), user); | |||
| dataScope.setRoles(roles); | |||
| dataScope.setRoleIds(roleIds); | |||
| dataScope.setPermissions(permissions); | |||
| // 路由路径集合 | |||
| Map<String, String> routeMap = loginService.getMenuRouteMap(roleIds, user.getUserType()); | |||
| loginUser.setUser(user); | |||
| loginUser.setUserId(user.getId()); | |||
| loginUser.setUserName(user.getUserName()); | |||
| loginUser.setUserType(user.getUserType()); | |||
| loginUser.setScope(dataScope); | |||
| loginUser.setRouteURL(routeMap); | |||
| return R.ok(loginUser); | |||
| } | |||
| } | |||
| @@ -68,4 +68,6 @@ public interface ISysLoginService { | |||
| * @return 路由路径集合 | |||
| */ | |||
| Map<String, String> getMenuRouteMap(Set<Long> roleIds, String userType); | |||
| SysUserDto loginByStaff(String phone); | |||
| } | |||
| @@ -1,17 +1,28 @@ | |||
| package com.xueyi.system.authority.service.impl; | |||
| import com.baomidou.mybatisplus.core.toolkit.Wrappers; | |||
| import com.xueyi.common.core.constant.basic.SqlConstants; | |||
| import com.xueyi.common.core.constant.system.AuthorityConstants; | |||
| import com.xueyi.common.core.utils.core.StrUtil; | |||
| import com.xueyi.common.security.utils.SecurityUtils; | |||
| import com.xueyi.common.web.entity.domain.SqlField; | |||
| import com.xueyi.system.api.authority.domain.dto.SysRoleDto; | |||
| import com.xueyi.system.api.model.DataScope; | |||
| import com.xueyi.system.api.organize.domain.dto.SysDeptDto; | |||
| import com.xueyi.system.api.organize.domain.dto.SysEnterpriseDto; | |||
| import com.xueyi.system.api.organize.domain.dto.SysPostDto; | |||
| import com.xueyi.system.api.organize.domain.dto.SysUserDto; | |||
| import com.xueyi.system.api.organize.domain.model.SysUserConverter; | |||
| import com.xueyi.system.api.staff.domain.po.DmStaffPo; | |||
| import com.xueyi.system.authority.service.ISysLoginService; | |||
| import com.xueyi.system.authority.service.ISysMenuService; | |||
| import com.xueyi.system.organize.service.*; | |||
| import com.xueyi.system.organize.mapper.SysUserMapper; | |||
| import com.xueyi.system.organize.service.ISysDeptService; | |||
| import com.xueyi.system.organize.service.ISysEnterpriseService; | |||
| import com.xueyi.system.organize.service.ISysOrganizeService; | |||
| import com.xueyi.system.organize.service.ISysPostService; | |||
| import com.xueyi.system.organize.service.ISysUserService; | |||
| import com.xueyi.system.staff.mapper.DmStaffMapper; | |||
| import org.springframework.beans.factory.annotation.Autowired; | |||
| import org.springframework.stereotype.Service; | |||
| @@ -44,6 +55,9 @@ public class SysLoginServiceImpl implements ISysLoginService { | |||
| @Autowired | |||
| ISysMenuService menuService; | |||
| @Autowired | |||
| DmStaffMapper dmStaffMapper; | |||
| @Autowired | |||
| private ISysOrganizeService organizeService; | |||
| @@ -220,4 +234,21 @@ public class SysLoginServiceImpl implements ISysLoginService { | |||
| ? menuService.getRouteMap() | |||
| : menuService.getRouteMap(roleIds); | |||
| } | |||
| @Autowired | |||
| SysUserMapper userMapper; | |||
| @Autowired | |||
| SysUserConverter sysUserConverter; | |||
| @Override | |||
| public SysUserDto loginByStaff(String phone) { | |||
| DmStaffPo po = dmStaffMapper.selectOne(Wrappers.<DmStaffPo>query().lambda().eq(DmStaffPo::getPhone, phone).last(SqlConstants.LIMIT_ONE)); | |||
| if (po == null) { | |||
| return null; | |||
| } | |||
| SqlField field = new SqlField(SqlConstants.OperateType.EQ, "tenant_id", po.getTenantId()); | |||
| SysUserDto dto = sysUserConverter.mapperDto(userMapper.selectByField(field)) ; | |||
| return dto; | |||
| } | |||
| } | |||
| @@ -4,7 +4,11 @@ import com.xueyi.common.web.entity.service.IBaseService; | |||
| import com.xueyi.system.common.domain.dto.DmHolidayDto; | |||
| import com.xueyi.system.common.domain.query.DmHolidayQuery; | |||
| import java.util.Date; | |||
| public interface IDmHolidayService extends IBaseService<DmHolidayQuery, DmHolidayDto> { | |||
| DmHolidayDto getTodayHoliday(); | |||
| DmHolidayDto isHoliday(Date date); | |||
| } | |||
| @@ -1,5 +1,6 @@ | |||
| package com.xueyi.system.common.service.impl; | |||
| import cn.hutool.core.date.LocalDateTimeUtil; | |||
| import com.xueyi.common.web.entity.service.impl.BaseServiceImpl; | |||
| import com.xueyi.system.common.domain.dto.DmHolidayDto; | |||
| import com.xueyi.system.common.domain.query.DmHolidayQuery; | |||
| @@ -8,14 +9,20 @@ import com.xueyi.system.common.service.IDmHolidayService; | |||
| import org.springframework.stereotype.Service; | |||
| import java.time.LocalDate; | |||
| import java.util.Date; | |||
| @Service | |||
| public class IDmHolidayServiceImpl extends BaseServiceImpl<DmHolidayQuery, DmHolidayDto, IDmHolidayManager> implements IDmHolidayService { | |||
| @Override | |||
| public DmHolidayDto getTodayHoliday() { | |||
| return isHoliday(new Date()); | |||
| } | |||
| @Override | |||
| public DmHolidayDto isHoliday(Date date) { | |||
| DmHolidayQuery query = new DmHolidayQuery(); | |||
| query.setDate(LocalDate.now()); | |||
| query.setDate(LocalDateTimeUtil.of(date).toLocalDate()); | |||
| DmHolidayDto dto = baseManager.selectTodayHoliday(query); | |||
| if (dto != null) { | |||
| return dto; | |||
| @@ -6,6 +6,7 @@ import com.xueyi.common.core.web.result.AjaxResult; | |||
| import com.xueyi.common.core.web.result.R; | |||
| import com.xueyi.common.core.web.validate.V_A; | |||
| import com.xueyi.common.core.web.validate.V_E; | |||
| import com.xueyi.common.core.web.vo.DeviceTenantSourceMergeVo; | |||
| import com.xueyi.common.datasource.annotation.Master; | |||
| import com.xueyi.common.log.annotation.Log; | |||
| import com.xueyi.common.log.enums.BusinessType; | |||
| @@ -14,7 +15,6 @@ import com.xueyi.common.web.annotation.TenantIgnore; | |||
| import com.xueyi.common.web.entity.controller.BaseController; | |||
| import com.xueyi.system.api.device.domain.dto.DmDeviceTenantMergeDto; | |||
| import com.xueyi.system.api.device.domain.po.DmDeviceTenantMergePo; | |||
| import com.xueyi.system.api.device.domain.vo.DeviceTenantSourceMergeVo; | |||
| import com.xueyi.system.api.digitalmans.domain.dto.DmManDeviceDto; | |||
| import com.xueyi.system.api.digitalmans.domain.po.DmManDevicePo; | |||
| import com.xueyi.system.api.model.Source; | |||
| @@ -29,7 +29,15 @@ import com.xueyi.system.organize.service.ISysEnterpriseService; | |||
| import com.xueyi.tenant.api.source.domain.po.TeSourcePo; | |||
| import org.springframework.beans.factory.annotation.Autowired; | |||
| import org.springframework.validation.annotation.Validated; | |||
| import org.springframework.web.bind.annotation.*; | |||
| import org.springframework.web.bind.annotation.DeleteMapping; | |||
| import org.springframework.web.bind.annotation.GetMapping; | |||
| import org.springframework.web.bind.annotation.PathVariable; | |||
| import org.springframework.web.bind.annotation.PostMapping; | |||
| import org.springframework.web.bind.annotation.PutMapping; | |||
| import org.springframework.web.bind.annotation.RequestBody; | |||
| import org.springframework.web.bind.annotation.RequestMapping; | |||
| import org.springframework.web.bind.annotation.RequestParam; | |||
| import org.springframework.web.bind.annotation.RestController; | |||
| import java.io.Serializable; | |||
| import java.util.List; | |||
| @@ -4,6 +4,7 @@ import com.alibaba.fastjson2.JSONObject; | |||
| import com.baomidou.mybatisplus.core.toolkit.StringUtils; | |||
| import com.baomidou.mybatisplus.core.toolkit.Wrappers; | |||
| import com.xueyi.common.cache.utils.DictUtil; | |||
| import com.xueyi.common.cache.utils.SourceUtil; | |||
| import com.xueyi.common.core.constant.basic.BaseConstants; | |||
| import com.xueyi.common.core.constant.basic.SecurityConstants; | |||
| import com.xueyi.common.core.constant.basic.SqlConstants; | |||
| @@ -12,6 +13,7 @@ import com.xueyi.common.core.web.result.AjaxResult; | |||
| import com.xueyi.common.core.web.result.R; | |||
| import com.xueyi.common.core.web.validate.V_A; | |||
| import com.xueyi.common.core.web.validate.V_E; | |||
| import com.xueyi.common.core.web.vo.DeviceTenantSourceMergeVo; | |||
| import com.xueyi.common.log.annotation.Log; | |||
| import com.xueyi.common.log.enums.BusinessType; | |||
| import com.xueyi.common.security.annotation.InnerAuth; | |||
| @@ -20,7 +22,6 @@ import com.xueyi.common.web.entity.controller.BaseController; | |||
| import com.xueyi.common.web.utils.DateUtils; | |||
| import com.xueyi.file.api.feign.RemoteFileService; | |||
| import com.xueyi.message.api.transfer.feign.RemoteTransferService; | |||
| import com.xueyi.system.api.device.domain.vo.DeviceTenantSourceMergeVo; | |||
| import com.xueyi.system.api.device.feign.RemoteDeviceTenantMergeService; | |||
| import com.xueyi.system.api.dict.domain.dto.SysDictDataDto; | |||
| import com.xueyi.system.api.digitalmans.domain.dto.DmDigitalmanWorktimeDto; | |||
| @@ -29,8 +30,10 @@ import com.xueyi.system.api.digitalmans.domain.dto.DmSyncDigitalmanDto; | |||
| import com.xueyi.system.api.digitalmans.domain.po.DmDigitalmanExtPo; | |||
| import com.xueyi.system.api.digitalmans.domain.po.DmManDevicePo; | |||
| import com.xueyi.system.api.digitalmans.feign.RemoteDigitalmanService; | |||
| import com.xueyi.system.api.model.Source; | |||
| import com.xueyi.system.api.sms.domain.vo.DingdingReqEntity; | |||
| import com.xueyi.system.api.sms.feign.RemoteDingdingService; | |||
| import com.xueyi.system.api.staff.feign.RemoteStaffService; | |||
| import com.xueyi.system.device.service.impl.DmDeviceTenantMergeServiceImpl; | |||
| import com.xueyi.system.digitalmans.domain.dto.DmDigitalmanDto; | |||
| import com.xueyi.system.digitalmans.domain.dto.DmDigitalmanExtDto; | |||
| @@ -50,6 +53,8 @@ import com.xueyi.system.emcs.domain.dto.RedisBaseDto; | |||
| import com.xueyi.system.emcs.mapper.DmDeviceLogFileMapper; | |||
| import com.xueyi.system.emcs.mapper.DmExceptionLogMapper; | |||
| import com.xueyi.system.emcs.service.BaseRedisListDataCache; | |||
| import com.xueyi.tenant.api.tenant.domain.dto.TeTenantDto; | |||
| import com.xueyi.tenant.api.tenant.feign.RemoteTenantService; | |||
| import org.slf4j.Logger; | |||
| import org.slf4j.LoggerFactory; | |||
| import org.springframework.beans.factory.annotation.Autowired; | |||
| @@ -461,4 +466,29 @@ public class DmDigitalmanController extends BaseController<DmDigitalmanQuery, Dm | |||
| log.info("删除文件返回结果:{}", r.getData()); | |||
| return R.ok(); | |||
| } | |||
| @Autowired | |||
| private RemoteTenantService tenantService; | |||
| @Autowired | |||
| private RemoteStaffService staffService; | |||
| @GetMapping("/api/delRecognizedRecords") | |||
| public AjaxResult delRecognizedRecords (@RequestParam(value = "day") Integer day){ | |||
| R<List<TeTenantDto>> listR = tenantService.tenantList(); | |||
| if (listR.isFail()) { | |||
| System.out.println("租户列表获取失败"); | |||
| return null; | |||
| } | |||
| List<TeTenantDto> res = listR.getData(); | |||
| TeTenantDto teTenantDto = res.get(0); | |||
| if (teTenantDto != null) { | |||
| Source source = SourceUtil.getSourceCache(teTenantDto.getStrategyId()); | |||
| staffService.delRecognizedRecordsImg(day,teTenantDto.getId(), source.getMaster(), SecurityConstants.INNER); | |||
| } | |||
| return AjaxResult.success(); | |||
| } | |||
| } | |||
| @@ -38,7 +38,6 @@ import com.xueyi.system.emcs.domain.dto.DmExceptionLogDto; | |||
| import com.xueyi.system.emcs.domain.query.DmExceptionLogQuery; | |||
| import com.xueyi.system.emcs.service.IDmExceptionLogService; | |||
| import com.xueyi.system.organize.service.ISysEnterpriseService; | |||
| import com.xueyi.system.pass.mapper.DmRecognizedRecordsMapper; | |||
| import org.slf4j.Logger; | |||
| import org.slf4j.LoggerFactory; | |||
| import org.springframework.beans.factory.annotation.Autowired; | |||
| @@ -376,14 +375,6 @@ public class DmManDeviceController extends BaseController<DmManDeviceQuery, DmMa | |||
| return AjaxResult.success(baseService.restartDevice(type,devId)); | |||
| } | |||
| @Autowired | |||
| private DmRecognizedRecordsMapper mapper; | |||
| @GetMapping("/delRecognizedRecords") | |||
| public AjaxResult delRecognizedRecords (@RequestParam(value = "day") Integer day){ | |||
| mapper.del(day); | |||
| return AjaxResult.success(); | |||
| } | |||
| /** | |||
| * 获取数字人设备管理选择框列表 | |||
| */ | |||
| @@ -1,15 +1,19 @@ | |||
| package com.xueyi.system.digitalmans.controller; | |||
| import com.xueyi.common.core.web.result.AjaxResult; | |||
| import com.xueyi.common.core.web.result.R; | |||
| import com.xueyi.common.core.web.validate.V_A; | |||
| import com.xueyi.common.core.web.validate.V_E; | |||
| import com.xueyi.common.log.annotation.Log; | |||
| import com.xueyi.common.log.enums.BusinessType; | |||
| import com.xueyi.common.security.annotation.InnerAuth; | |||
| import com.xueyi.common.security.annotation.Logical; | |||
| import com.xueyi.common.security.annotation.RequiresPermissions; | |||
| import com.xueyi.common.security.utils.SecurityUtils; | |||
| import com.xueyi.common.web.entity.controller.BaseController; | |||
| import com.xueyi.nlt.api.nlt.domain.vo.TaskKnowledgeVo; | |||
| import com.xueyi.system.api.digitalmans.domain.vo.DmBatchQuestionsVo; | |||
| import com.xueyi.system.api.digitalmans.domain.vo.DmTipVo; | |||
| import com.xueyi.system.digitalmans.domain.dto.DmQuestionsDto; | |||
| import com.xueyi.system.digitalmans.domain.query.DmQuestionsQuery; | |||
| import com.xueyi.system.digitalmans.service.IDmQuestionsService; | |||
| @@ -39,6 +43,13 @@ public class DmQuestionsController extends BaseController<DmQuestionsQuery, DmQu | |||
| return "企业知识库问题" ; | |||
| } | |||
| @InnerAuth | |||
| @GetMapping("/inner/tipList") | |||
| @Log(title = "数字人知识库问题管理", businessType = BusinessType.OTHER) | |||
| @ResponseBody | |||
| public R<List<DmTipVo>> tipList() { | |||
| return R.ok(baseService.tipList()); | |||
| } | |||
| /** | |||
| * 查询企业知识库问题列表 | |||
| */ | |||
| @@ -3,14 +3,18 @@ package com.xueyi.system.digitalmans.controller.api; | |||
| import com.xueyi.common.core.constant.basic.SecurityConstants; | |||
| import com.xueyi.common.core.web.result.AjaxResult; | |||
| import com.xueyi.common.core.web.result.R; | |||
| import com.xueyi.system.api.device.domain.vo.DeviceTenantSourceMergeVo; | |||
| import com.xueyi.common.core.web.vo.DeviceTenantSourceMergeVo; | |||
| import com.xueyi.system.api.digitalmans.domain.dto.DmScreenIconDto; | |||
| import com.xueyi.system.api.digitalmans.feign.RemoteModelService; | |||
| import com.xueyi.system.resource.controller.api.BaseApiController; | |||
| import org.slf4j.Logger; | |||
| import org.slf4j.LoggerFactory; | |||
| import org.springframework.beans.factory.annotation.Autowired; | |||
| import org.springframework.web.bind.annotation.*; | |||
| import org.springframework.web.bind.annotation.GetMapping; | |||
| import org.springframework.web.bind.annotation.PathVariable; | |||
| import org.springframework.web.bind.annotation.RequestMapping; | |||
| import org.springframework.web.bind.annotation.ResponseBody; | |||
| import org.springframework.web.bind.annotation.RestController; | |||
| import java.util.List; | |||
| @@ -1,24 +1,27 @@ | |||
| package com.xueyi.system.digitalmans.manager.impl; | |||
| import com.baomidou.mybatisplus.core.toolkit.Wrappers; | |||
| import com.xueyi.common.core.constant.basic.OperateConstants; | |||
| import com.xueyi.common.web.entity.domain.SlaveRelation; | |||
| import com.xueyi.common.web.entity.manager.impl.BaseManagerImpl; | |||
| import com.xueyi.system.api.digitalmans.domain.dto.DmH5MenuDto; | |||
| import com.xueyi.system.api.digitalmans.domain.dto.DmModelDto; | |||
| import com.xueyi.system.api.digitalmans.domain.dto.DmScreenIconDto; | |||
| import com.xueyi.system.api.digitalmans.domain.po.*; | |||
| import com.xueyi.system.digitalmans.controller.DmQAndAController; | |||
| import com.xueyi.system.api.digitalmans.domain.po.DmDigitalmanPo; | |||
| import com.xueyi.system.api.digitalmans.domain.po.DmH5MenuPo; | |||
| import com.xueyi.system.api.digitalmans.domain.po.DmModelIconPo; | |||
| import com.xueyi.system.api.digitalmans.domain.po.DmModelPo; | |||
| import com.xueyi.system.api.digitalmans.domain.po.DmScreenIconPo; | |||
| import com.xueyi.system.api.resource.domain.po.DmResourcesPo; | |||
| import com.xueyi.system.digitalmans.domain.dto.DmModelUploadDto; | |||
| import com.xueyi.system.api.digitalmans.domain.dto.DmModelDto; | |||
| import com.xueyi.system.api.digitalmans.domain.merge.DmModelIconMerge; | |||
| import com.xueyi.system.digitalmans.domain.model.DmModelConverter; | |||
| import com.xueyi.system.digitalmans.domain.model.DmScreenIconConverter; | |||
| import com.xueyi.system.digitalmans.domain.po.DmManIconPo; | |||
| import com.xueyi.system.digitalmans.domain.query.DmModelQuery; | |||
| import com.xueyi.system.digitalmans.domain.model.DmModelConverter; | |||
| import com.xueyi.system.digitalmans.mapper.*; | |||
| import com.xueyi.common.web.entity.manager.impl.BaseManagerImpl; | |||
| import com.xueyi.system.digitalmans.manager.IDmModelManager; | |||
| import com.xueyi.system.api.resource.domain.po.DmResourcesPo; | |||
| import com.xueyi.system.digitalmans.mapper.merge.DmModelIconMergeMapper; | |||
| import com.xueyi.system.digitalmans.mapper.DmDigitalmanMapper; | |||
| import com.xueyi.system.digitalmans.mapper.DmH5MenuMapper; | |||
| import com.xueyi.system.digitalmans.mapper.DmManIconMapper; | |||
| import com.xueyi.system.digitalmans.mapper.DmModelIconMapper; | |||
| import com.xueyi.system.digitalmans.mapper.DmModelMapper; | |||
| import com.xueyi.system.digitalmans.mapper.DmScreenIconMapper; | |||
| import com.xueyi.system.resource.domain.po.DmBackgroundPo; | |||
| import com.xueyi.system.resource.domain.po.DmScreenOffPo; | |||
| import com.xueyi.system.resource.mapper.DmBackgroundMapper; | |||
| @@ -35,8 +38,6 @@ import java.util.Arrays; | |||
| import java.util.List; | |||
| import java.util.stream.Collectors; | |||
| import static com.xueyi.system.api.digitalmans.domain.merge.MergeGroup.Model_DmModelIcon_GROUP; | |||
| /** | |||
| * 模型管理 数据封装层处理 | |||
| @@ -74,7 +75,6 @@ public class DmModelManager extends BaseManagerImpl<DmModelQuery, DmModelDto, Dm | |||
| @Autowired | |||
| DmH5MenuMapper h5MenuMapper; | |||
| @Autowired | |||
| DmScreenIconConverter screenIconConverter; | |||
| @@ -1,13 +1,17 @@ | |||
| package com.xueyi.system.digitalmans.service; | |||
| import com.xueyi.system.api.digitalmans.domain.vo.DmTipVo; | |||
| import com.xueyi.system.digitalmans.domain.query.DmQuestionsQuery; | |||
| import com.xueyi.system.digitalmans.domain.dto.DmQuestionsDto; | |||
| import com.xueyi.common.web.entity.service.IBaseService; | |||
| import java.util.List; | |||
| /** | |||
| * 企业知识库问题管理 服务层 | |||
| * | |||
| * @author yinruoxi | |||
| */ | |||
| public interface IDmQuestionsService extends IBaseService<DmQuestionsQuery, DmQuestionsDto> { | |||
| List<DmTipVo> tipList(); | |||
| } | |||
| @@ -1,9 +1,13 @@ | |||
| package com.xueyi.system.digitalmans.service.impl; | |||
| import com.xueyi.system.api.digitalmans.domain.vo.DmTipVo; | |||
| import com.xueyi.system.api.organize.domain.dto.SysUserDto; | |||
| import com.xueyi.system.api.organize.domain.query.SysUserQuery; | |||
| import com.xueyi.system.digitalmans.domain.dto.DmQAndADto; | |||
| import com.xueyi.system.digitalmans.domain.dto.DmQuestionsDto; | |||
| import com.xueyi.system.digitalmans.domain.query.DmQAndAQuery; | |||
| import com.xueyi.system.digitalmans.domain.query.DmQuestionsQuery; | |||
| import com.xueyi.system.digitalmans.manager.IDmQAndAManager; | |||
| import com.xueyi.system.digitalmans.service.IDmQuestionsService; | |||
| import com.xueyi.system.digitalmans.manager.IDmQuestionsManager; | |||
| import com.xueyi.common.web.entity.service.impl.BaseServiceImpl; | |||
| @@ -11,6 +15,8 @@ import com.xueyi.system.organize.service.ISysUserService; | |||
| import org.springframework.beans.factory.annotation.Autowired; | |||
| import org.springframework.stereotype.Service; | |||
| import java.util.ArrayList; | |||
| import java.util.Collections; | |||
| import java.util.List; | |||
| /** | |||
| @@ -23,6 +29,9 @@ public class DmQuestionsServiceImpl extends BaseServiceImpl<DmQuestionsQuery, Dm | |||
| @Autowired | |||
| private ISysUserService iSysUserService; | |||
| @Autowired | |||
| private IDmQAndAManager iDmQAndAManager; | |||
| /** | |||
| * 查询企业知识库问题对象列表 | 数据权限 | |||
| * | |||
| @@ -46,4 +55,27 @@ public class DmQuestionsServiceImpl extends BaseServiceImpl<DmQuestionsQuery, Dm | |||
| return questionsDtos; | |||
| } | |||
| @Override | |||
| public List<DmTipVo> tipList() { | |||
| // 获取所有知识库所有列表 | |||
| List<DmQuestionsDto> knowledgeList = baseManager.selectList(new DmQuestionsQuery()); | |||
| // 遍历知识库,获取对应QA结果,存入DmTipVo列表中 | |||
| List<DmTipVo> dmTipVos = new ArrayList<>(); | |||
| knowledgeList.forEach(knowledge -> { | |||
| DmQAndAQuery query = new DmQAndAQuery(); | |||
| query.setKnowledgeId(knowledge.getId()); | |||
| List<DmQAndADto> qAndADtos = iDmQAndAManager.selectList(query); | |||
| qAndADtos.forEach(qAndADto -> { | |||
| DmTipVo dmTipVo = new DmTipVo(); | |||
| dmTipVo.setName(qAndADto.getName()); | |||
| dmTipVo.setId(qAndADto.getId()); | |||
| dmTipVo.setType(0); | |||
| dmTipVos.add(dmTipVo); | |||
| }); | |||
| }); | |||
| // 将dmTipVos列表打乱数组排序 | |||
| Collections.shuffle(dmTipVos); | |||
| return dmTipVos; | |||
| } | |||
| } | |||
| @@ -0,0 +1,42 @@ | |||
| package com.xueyi.system.interfaces.airport.bean; | |||
| import com.xueyi.common.web.entity.domain.BaseReq; | |||
| import lombok.Data; | |||
| import javax.validation.constraints.NotNull; | |||
| /** | |||
| * @author yk | |||
| * @description | |||
| * @date 2023-12-06 11:45 | |||
| */ | |||
| @Data | |||
| public class FlightsQueryReq extends BaseReq { | |||
| @NotNull(message = "Valid校验:出发城市startCity不能为空!") | |||
| private String startCity; | |||
| @NotNull(message = "Valid校验:抵达城市endCity不能为空!") | |||
| private String endCity; | |||
| @NotNull(message = "Valid校验:时间startDate不能为空!") | |||
| private String date; | |||
| @Override | |||
| public String toString() { | |||
| return "PlaneQueryReq{" + | |||
| "START_CITY='" + startCity + '\'' + | |||
| ", END_CITY='" + endCity + '\'' + | |||
| ", START_DATE='" + date + '\'' + | |||
| '}'; | |||
| } | |||
| public String toQueryString() { | |||
| return "START_CITY=" + startCity + | |||
| "&END_CITY=" + endCity + | |||
| "&START_DATE=" + date; | |||
| } | |||
| } | |||
| @@ -0,0 +1,33 @@ | |||
| package com.xueyi.system.interfaces.airport.bean; | |||
| import com.xueyi.common.web.entity.domain.BaseReq; | |||
| import lombok.Data; | |||
| import javax.validation.constraints.NotNull; | |||
| /** | |||
| * @author yk | |||
| * @description | |||
| * @date 2023-12-06 11:45 | |||
| */ | |||
| @Data | |||
| public class PlaneQueryReq extends BaseReq { | |||
| @NotNull(message = "Valid校验:航班号fNum不能为空!") | |||
| private String fNum; | |||
| @NotNull(message = "Valid校验:时间date不能为空!") | |||
| private String date; | |||
| @Override | |||
| public String toString() { | |||
| return "PlaneQueryReq{" + | |||
| "fNum='" + fNum + '\'' + | |||
| ", date='" + date + '\'' + | |||
| '}'; | |||
| } | |||
| public String toQueryString() { | |||
| return "fnum=" + this.fNum + "&date=" + this.date; | |||
| } | |||
| } | |||
| @@ -0,0 +1,127 @@ | |||
| package com.xueyi.system.interfaces.airport.controller; | |||
| import com.alibaba.fastjson2.JSONObject; | |||
| import com.xueyi.common.redis.utils.RedisUtil; | |||
| import com.xueyi.common.web.controller.BaseApiController; | |||
| import com.xueyi.common.web.response.MyResponse; | |||
| import com.xueyi.system.interfaces.airport.bean.FlightsQueryReq; | |||
| import com.xueyi.system.interfaces.airport.bean.PlaneQueryReq; | |||
| import okhttp3.MediaType; | |||
| import okhttp3.OkHttpClient; | |||
| import okhttp3.Request; | |||
| import okhttp3.Response; | |||
| import org.slf4j.Logger; | |||
| import org.slf4j.LoggerFactory; | |||
| import org.springframework.beans.factory.annotation.Value; | |||
| import org.springframework.web.bind.annotation.RequestBody; | |||
| import org.springframework.web.bind.annotation.RequestMapping; | |||
| import org.springframework.web.bind.annotation.RestController; | |||
| import javax.servlet.http.HttpServletRequest; | |||
| import javax.validation.Valid; | |||
| import java.io.IOException; | |||
| /** | |||
| * @author yk | |||
| * @description | |||
| * @date 2023-12-04 14:57 | |||
| */ | |||
| @RestController | |||
| @RequestMapping("/plane/api") | |||
| public class PlaneController extends BaseApiController { | |||
| private final Logger logger = LoggerFactory.getLogger(PlaneController.class); | |||
| @Value("${notification.airport.flight.juhe.key}") | |||
| private String key; | |||
| @Value("${notification.airport.flight.juhe.url}") | |||
| private String juHeUrl; | |||
| @Value("${notification.airport.flight.icredit.app-code}") | |||
| private String icreditCode; | |||
| @Value("${notification.airport.flight.icredit.flights-url}") | |||
| private String icreditUrl; | |||
| @RequestMapping("/query-flight") | |||
| public JSONObject query (@Valid @RequestBody PlaneQueryReq req, HttpServletRequest httpServletRequest) { | |||
| String sign = httpServletRequest.getHeader("sign"); | |||
| String ts = httpServletRequest.getHeader("ts"); | |||
| MyResponse resp = super.checkSign(req, sign, ts); | |||
| if (resp.getStatus() != 200) { | |||
| return resp.toJSON(); | |||
| } | |||
| logger.info("查询航班信息:{}", req); | |||
| String dateStr = req.getDate().replaceAll("-",""); | |||
| String redisKey = "dgman:airport:flight:"+req.getFNum()+":" + dateStr; | |||
| if (RedisUtil.existed(redisKey)){ | |||
| return JSONObject.parseObject(RedisUtil.getVal(redisKey).toString()); | |||
| } | |||
| OkHttpClient client = new OkHttpClient().newBuilder() | |||
| .build(); | |||
| MediaType mediaType = MediaType.parse("application/x-www-form-urlencoded"); | |||
| logger.info("请求参数:{}", "key="+key+"&"+req.toQueryString()); | |||
| okhttp3.RequestBody body = okhttp3.RequestBody.Companion.create("key="+key+"&"+req.toQueryString(), mediaType); | |||
| Request request = new Request.Builder() | |||
| .url(juHeUrl) | |||
| .method("POST", body) | |||
| .addHeader("Content-Type", "application/x-www-form-urlencoded") | |||
| .build(); | |||
| try { | |||
| Response response = client.newCall(request).execute(); | |||
| if (response.isSuccessful()) { | |||
| String result = response.body().string(); | |||
| logger.info("查询航班信息结果:{}", result); | |||
| RedisUtil.setVal(redisKey,result,60*60*24); | |||
| return JSONObject.parseObject(result); | |||
| } | |||
| } catch (IOException e) { | |||
| throw new RuntimeException(e); | |||
| } | |||
| return new JSONObject(); | |||
| } | |||
| @RequestMapping("/flight-list") | |||
| public JSONObject flightList (@Valid @RequestBody FlightsQueryReq req, HttpServletRequest httpServletRequest) { | |||
| String sign = httpServletRequest.getHeader("sign"); | |||
| String ts = httpServletRequest.getHeader("ts"); | |||
| MyResponse resp = super.checkSign(req, sign, ts); | |||
| if (resp.getStatus() != 200) { | |||
| return resp.toJSON(); | |||
| } | |||
| logger.info("查询航班列表信息:{}", req); | |||
| String dateStr = req.getDate().replaceAll("-",""); | |||
| String redisKey = "dgman:airport:flight:"+req.getEndCity()+":" + dateStr; | |||
| if (RedisUtil.existed(redisKey)){ | |||
| return JSONObject.parseObject(RedisUtil.getVal(redisKey).toString()); | |||
| } | |||
| req.setDate(req.getDate().replaceAll("-","")); | |||
| OkHttpClient client = new OkHttpClient().newBuilder() | |||
| .build(); | |||
| Request request = new Request.Builder() | |||
| .url(icreditUrl+"?"+req.toQueryString()) | |||
| .get() | |||
| .addHeader("Authorization", "APPCODE "+icreditCode) | |||
| .addHeader("Content-Type", "application/x-www-form-urlencoded; charset=utf-8") | |||
| .build(); | |||
| try { | |||
| Response response = client.newCall(request).execute(); | |||
| if (response.isSuccessful()) { | |||
| String result = response.body().string(); | |||
| logger.info("查询航班列表结果:{}", result); | |||
| RedisUtil.setVal(redisKey,result,60*60*24); | |||
| return JSONObject.parseObject(result); | |||
| } | |||
| } catch (IOException e) { | |||
| throw new RuntimeException(e); | |||
| } | |||
| return new JSONObject(); | |||
| } | |||
| } | |||
| @@ -0,0 +1,31 @@ | |||
| package com.xueyi.system.interfaces.airport.controller; | |||
| import com.xueyi.system.interfaces.airport.lib.VideoTalkZegoServerAssistant; | |||
| import com.xueyi.system.interfaces.airport.lib.VideoTalkZegoServerAssistant.TokenInfo; | |||
| import org.springframework.web.bind.annotation.PathVariable; | |||
| import org.springframework.web.bind.annotation.RequestMapping; | |||
| import org.springframework.web.bind.annotation.RestController; | |||
| /** | |||
| * @author yk | |||
| * @description | |||
| * @date 2023-12-04 14:57 | |||
| */ | |||
| @RestController | |||
| @RequestMapping("/videoTalk/api") | |||
| public class VideoTalkController { | |||
| @RequestMapping("/genToken/{userId}") | |||
| public TokenInfo genToken (@PathVariable("userId") String userId) { | |||
| long appId = 1648563584L; // 由即构提供 | |||
| String secretKey = "1568a55020c0585e4b6c257fc13c8adc"; // 由即构提供 | |||
| int effectiveTimeInSeconds = 300; // 有效时间,单位:秒 | |||
| String payload = "{\"room_id\":\"demo\"}"; // 填入自定义的payload值,如room_id。 非必输,不传则payload赋值null。 | |||
| VideoTalkZegoServerAssistant.VERBOSE = true; // 正式运行时,最好置为 false | |||
| TokenInfo token = VideoTalkZegoServerAssistant.generateToken04(appId, userId, secretKey, effectiveTimeInSeconds, payload); | |||
| return token; | |||
| } | |||
| } | |||