diff --git a/framework/pom.xml b/framework/pom.xml index da681cb3..5e0b4b74 100644 --- a/framework/pom.xml +++ b/framework/pom.xml @@ -51,7 +51,10 @@ - + + org.springframework.boot + spring-boot-starter-websocket + org.springframework.boot spring-boot-starter-web diff --git a/framework/src/main/java/cn/lili/common/security/AuthUser.java b/framework/src/main/java/cn/lili/common/security/AuthUser.java index f49f2051..18bdcec3 100644 --- a/framework/src/main/java/cn/lili/common/security/AuthUser.java +++ b/framework/src/main/java/cn/lili/common/security/AuthUser.java @@ -68,6 +68,12 @@ public class AuthUser implements Serializable { */ private Boolean isSuper = false; + /** + * 租户id + */ + private String tenantId; + + public AuthUser(String username, String id, String nickName, String face, UserEnums role) { this.username = username; this.face = face; diff --git a/framework/src/main/java/cn/lili/common/security/enums/UserEnums.java b/framework/src/main/java/cn/lili/common/security/enums/UserEnums.java index 07d86b64..919b6693 100644 --- a/framework/src/main/java/cn/lili/common/security/enums/UserEnums.java +++ b/framework/src/main/java/cn/lili/common/security/enums/UserEnums.java @@ -14,7 +14,8 @@ public enum UserEnums { MEMBER("会员"), STORE("商家"), MANAGER("管理员"), - SYSTEM("系统"); + SYSTEM("系统"), + SEAT("坐席"); private final String role; UserEnums(String role) { diff --git a/framework/src/main/java/cn/lili/common/swagger/Swagger2Config.java b/framework/src/main/java/cn/lili/common/swagger/Swagger2Config.java index 3d92f8d5..3b795d22 100644 --- a/framework/src/main/java/cn/lili/common/swagger/Swagger2Config.java +++ b/framework/src/main/java/cn/lili/common/swagger/Swagger2Config.java @@ -95,6 +95,19 @@ public class Swagger2Config { .securityContexts(securityContexts()); } + @Bean + public Docket imRestApi() { + return new Docket(DocumentationType.SWAGGER_2) + .groupName("im") + .apiInfo(apiInfo()).select() + //扫描所有有注解的api,用这种方式更灵活 + .apis(RequestHandlerSelectors.basePackage("cn.lili.controller.im")) + .paths(PathSelectors.any()) + .build() + .securitySchemes(securitySchemes()) + .securityContexts(securityContexts()); + } + @Bean public Docket memberRestApi() { return new Docket(DocumentationType.SWAGGER_2) diff --git a/framework/src/main/java/cn/lili/im/entity/ImUser.java b/framework/src/main/java/cn/lili/im/entity/ImUser.java deleted file mode 100644 index 0be58571..00000000 --- a/framework/src/main/java/cn/lili/im/entity/ImUser.java +++ /dev/null @@ -1,26 +0,0 @@ -package cn.lili.im.entity; - - -import cn.lili.mybatis.BaseTenantEntity; -import com.baomidou.mybatisplus.annotation.TableName; -import io.swagger.annotations.ApiModel; -import lombok.Data; - -/** - * @author Chopper - */ -@Data -@TableName("li_im_users") -@ApiModel(value = "Im消息") -public class ImUser extends BaseTenantEntity { - - private static final long serialVersionUID = 1L; - /** - * 头像 - */ - private String face; - /** - * 昵称 - */ - private String name; -} \ No newline at end of file diff --git a/framework/src/main/java/cn/lili/im/mapper/ImUserMapper.java b/framework/src/main/java/cn/lili/im/mapper/ImUserMapper.java deleted file mode 100644 index 8cb2340b..00000000 --- a/framework/src/main/java/cn/lili/im/mapper/ImUserMapper.java +++ /dev/null @@ -1,13 +0,0 @@ -package cn.lili.im.mapper; - -import cn.lili.im.entity.ImUser; -import com.baomidou.mybatisplus.core.mapper.BaseMapper; - -/** - * Im消息 Dao层 - * - * @author Chopper - */ -public interface ImUserMapper extends BaseMapper { - -} \ No newline at end of file diff --git a/framework/src/main/java/cn/lili/im/service/ImUserService.java b/framework/src/main/java/cn/lili/im/service/ImUserService.java deleted file mode 100644 index e825f87b..00000000 --- a/framework/src/main/java/cn/lili/im/service/ImUserService.java +++ /dev/null @@ -1,21 +0,0 @@ -package cn.lili.im.service; - -import cn.lili.im.entity.ImUser; -import com.baomidou.mybatisplus.extension.service.IService; - -/** - * Im消息 业务层 - * - * @author Chopper - */ -public interface ImUserService extends IService { - - /** - * 注册用户 - * - * @param accessToken - * @return - */ - ImUser register(String accessToken); - -} \ No newline at end of file diff --git a/framework/src/main/java/cn/lili/im/serviceimpl/ImUserServiceImpl.java b/framework/src/main/java/cn/lili/im/serviceimpl/ImUserServiceImpl.java deleted file mode 100644 index fe92173e..00000000 --- a/framework/src/main/java/cn/lili/im/serviceimpl/ImUserServiceImpl.java +++ /dev/null @@ -1,39 +0,0 @@ -package cn.lili.im.serviceimpl; - -import cn.lili.common.security.AuthUser; -import cn.lili.common.security.context.UserContext; -import cn.lili.im.entity.ImUser; -import cn.lili.im.mapper.ImUserMapper; -import cn.lili.im.service.ImUserService; -import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; -import lombok.RequiredArgsConstructor; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -/** - * Im消息 业务实现 - * - * @author Chopper - */ -@Service -@Transactional(rollbackFor = Exception.class) -@RequiredArgsConstructor(onConstructor = @__(@Autowired)) -public class ImUserServiceImpl extends ServiceImpl implements ImUserService { - - @Override - public ImUser register(String accessToken) { - AuthUser authUser = UserContext.getAuthUser(accessToken); - ImUser imUser; - //如果用户存在 - imUser = this.getById(authUser.getId()); - if (imUser == null) { - imUser = new ImUser(); - imUser.setId(authUser.getId()); - imUser.setName(authUser.getNickName()); - this.save(imUser); - } - return imUser; - } - -} \ No newline at end of file diff --git a/framework/src/main/java/cn/lili/im/config/CustomSpringConfigurator.java b/framework/src/main/java/cn/lili/modules/im/config/CustomSpringConfigurator.java similarity index 96% rename from framework/src/main/java/cn/lili/im/config/CustomSpringConfigurator.java rename to framework/src/main/java/cn/lili/modules/im/config/CustomSpringConfigurator.java index a09cc961..d9f825c0 100644 --- a/framework/src/main/java/cn/lili/im/config/CustomSpringConfigurator.java +++ b/framework/src/main/java/cn/lili/modules/im/config/CustomSpringConfigurator.java @@ -1,4 +1,4 @@ -package cn.lili.im.config; +package cn.lili.modules.im.config; import org.springframework.beans.BeansException; diff --git a/framework/src/main/java/cn/lili/im/config/WebSocketConfigurator.java b/framework/src/main/java/cn/lili/modules/im/config/WebSocketConfigurator.java similarity index 93% rename from framework/src/main/java/cn/lili/im/config/WebSocketConfigurator.java rename to framework/src/main/java/cn/lili/modules/im/config/WebSocketConfigurator.java index af42081e..c6de471b 100644 --- a/framework/src/main/java/cn/lili/im/config/WebSocketConfigurator.java +++ b/framework/src/main/java/cn/lili/modules/im/config/WebSocketConfigurator.java @@ -1,4 +1,4 @@ -package cn.lili.im.config; +package cn.lili.modules.im.config; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; diff --git a/framework/src/main/java/cn/lili/im/entity/ImMessage.java b/framework/src/main/java/cn/lili/modules/im/entity/dos/ImMessage.java similarity index 83% rename from framework/src/main/java/cn/lili/im/entity/ImMessage.java rename to framework/src/main/java/cn/lili/modules/im/entity/dos/ImMessage.java index ccc58d49..31d2da5a 100644 --- a/framework/src/main/java/cn/lili/im/entity/ImMessage.java +++ b/framework/src/main/java/cn/lili/modules/im/entity/dos/ImMessage.java @@ -1,6 +1,6 @@ -package cn.lili.im.entity; +package cn.lili.modules.im.entity.dos; -import cn.lili.im.entity.enums.MessageType; +import cn.lili.modules.im.entity.enums.MessageTypeEnum; import cn.lili.mybatis.BaseEntity; import com.baomidou.mybatisplus.annotation.TableName; import io.swagger.annotations.ApiModel; @@ -34,7 +34,7 @@ public class ImMessage extends BaseEntity { /** * 消息类型 */ - private MessageType messageType; + private MessageTypeEnum messageType; /** * 聊天id diff --git a/framework/src/main/java/cn/lili/im/entity/ImTalk.java b/framework/src/main/java/cn/lili/modules/im/entity/dos/ImTalk.java similarity index 98% rename from framework/src/main/java/cn/lili/im/entity/ImTalk.java rename to framework/src/main/java/cn/lili/modules/im/entity/dos/ImTalk.java index 9eb8502c..99d1b4a9 100644 --- a/framework/src/main/java/cn/lili/im/entity/ImTalk.java +++ b/framework/src/main/java/cn/lili/modules/im/entity/dos/ImTalk.java @@ -1,4 +1,4 @@ -package cn.lili.im.entity; +package cn.lili.modules.im.entity.dos; import cn.lili.common.utils.SnowFlake; diff --git a/framework/src/main/java/cn/lili/modules/im/entity/dos/QA.java b/framework/src/main/java/cn/lili/modules/im/entity/dos/QA.java new file mode 100644 index 00000000..0d6bd3f2 --- /dev/null +++ b/framework/src/main/java/cn/lili/modules/im/entity/dos/QA.java @@ -0,0 +1,31 @@ +package cn.lili.modules.im.entity.dos; + +import cn.lili.mybatis.BaseEntity; +import com.baomidou.mybatisplus.annotation.TableName; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 问题答案 + * + * @author Chopper + * @version v1.0 + * 2022-02-09 17:59 + */ +@Data +@TableName("li_qa") +@ApiModel(value = "租户问答") +@NoArgsConstructor +public class QA extends BaseEntity { + + @ApiModelProperty(value = "租户id") + private Integer tenantId; + + @ApiModelProperty(value = "问题") + private String question; + + @ApiModelProperty(value = "答案") + private String answer; +} diff --git a/framework/src/main/java/cn/lili/modules/im/entity/dos/Seat.java b/framework/src/main/java/cn/lili/modules/im/entity/dos/Seat.java new file mode 100644 index 00000000..40bdfd84 --- /dev/null +++ b/framework/src/main/java/cn/lili/modules/im/entity/dos/Seat.java @@ -0,0 +1,47 @@ +package cn.lili.modules.im.entity.dos; + +import cn.lili.mybatis.BaseTenantEntity; +import com.baomidou.mybatisplus.annotation.TableName; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotEmpty; + +/** + * 坐席 + * + * @author Chopper + * @version v1.0 + * 2022-02-09 17:08 + */ +@Data +@TableName("li_seat") +@ApiModel(value = "坐席") +@NoArgsConstructor +public class Seat extends BaseTenantEntity { + + @ApiModelProperty(value = "租户id") + private String tenantId; + + @ApiModelProperty(value = "坐席用户名") + private String username; + + @ApiModelProperty(value = "会员头像") + private String face; + + @ApiModelProperty(value = "坐席密码") + private String password; + + @ApiModelProperty(value = "昵称") + private String nickName; + + @ApiModelProperty(value = "坐席状态") + private Boolean disabled; + + @NotEmpty(message = "手机号码不能为空") + @ApiModelProperty(value = "手机号码", required = true) + private String mobile; + +} diff --git a/framework/src/main/java/cn/lili/modules/im/entity/dos/SeatSetting.java b/framework/src/main/java/cn/lili/modules/im/entity/dos/SeatSetting.java new file mode 100644 index 00000000..a462ce7e --- /dev/null +++ b/framework/src/main/java/cn/lili/modules/im/entity/dos/SeatSetting.java @@ -0,0 +1,36 @@ +package cn.lili.modules.im.entity.dos; + +import cn.lili.mybatis.BaseTenantEntity; +import com.baomidou.mybatisplus.annotation.TableName; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 坐席设置 + * + * @author Chopper + * @version v1.0 + * 2022-02-09 17:55 + */ +@Data +@TableName("li_seat_setting") +@ApiModel(value = "坐席设置") +@NoArgsConstructor +public class SeatSetting extends BaseTenantEntity { + + @ApiModelProperty(value = "租户idid") + private String tenantId; + + @ApiModelProperty(value = "欢迎语") + private String welcome; + + @ApiModelProperty(value = "离线自动回复") + private String outLineAutoReply; + + @ApiModelProperty(value = "长时间自动回复") + private String longTermAutoReply; + + +} diff --git a/framework/src/main/java/cn/lili/im/entity/dto/MessageQueryParams.java b/framework/src/main/java/cn/lili/modules/im/entity/dto/MessageQueryParams.java similarity index 93% rename from framework/src/main/java/cn/lili/im/entity/dto/MessageQueryParams.java rename to framework/src/main/java/cn/lili/modules/im/entity/dto/MessageQueryParams.java index f10da119..865bd27e 100644 --- a/framework/src/main/java/cn/lili/im/entity/dto/MessageQueryParams.java +++ b/framework/src/main/java/cn/lili/modules/im/entity/dto/MessageQueryParams.java @@ -1,9 +1,9 @@ -package cn.lili.im.entity.dto; +package cn.lili.modules.im.entity.dto; import cn.lili.common.enums.ResultCode; import cn.lili.common.exception.ServiceException; import cn.lili.common.utils.StringUtils; -import cn.lili.im.entity.ImMessage; +import cn.lili.modules.im.entity.dos.ImMessage; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import lombok.Data; diff --git a/framework/src/main/java/cn/lili/im/entity/enums/MessageResultType.java b/framework/src/main/java/cn/lili/modules/im/entity/enums/MessageResultType.java similarity index 90% rename from framework/src/main/java/cn/lili/im/entity/enums/MessageResultType.java rename to framework/src/main/java/cn/lili/modules/im/entity/enums/MessageResultType.java index ed268da8..ba54b5d5 100644 --- a/framework/src/main/java/cn/lili/im/entity/enums/MessageResultType.java +++ b/framework/src/main/java/cn/lili/modules/im/entity/enums/MessageResultType.java @@ -1,4 +1,4 @@ -package cn.lili.im.entity.enums; +package cn.lili.modules.im.entity.enums; /** * 返回消息类型枚举 diff --git a/framework/src/main/java/cn/lili/modules/im/entity/enums/MessageStatusEnum.java b/framework/src/main/java/cn/lili/modules/im/entity/enums/MessageStatusEnum.java new file mode 100644 index 00000000..687c814c --- /dev/null +++ b/framework/src/main/java/cn/lili/modules/im/entity/enums/MessageStatusEnum.java @@ -0,0 +1,31 @@ +package cn.lili.modules.im.entity.enums; + +/** + * 消息的类型 + * + * @author liushuai(liushuai711 @ gmail.com) + * @version v4.0 + * @Description: + * @since 2022/2/10 16:36 + */ +public enum MessageStatusEnum { + //socket刚打开时发送的消息,这个一般是是刚打开socket链接,进行登录,传入token用 + CONNECT, + //心跳类型的消息,此种类型的消息只有 type 、 text 两种属性 + HEARTBEAT, + //用户打开一个对话框,准备跟某人聊天时 + OPEN, + //客服进行自动回复。客户端发起这种类型请求,则是在拉取对方是否有自动回复,如果有,服务端就会给客户端发送过自动回复的信息 + AUTO_REPLY, + //正常收发消息沟通,文字、表情等沟通 + MSG, + //扩展。比如发送商品、发送订单 + EXTEND, + //系统提示,如提示 对方已离线 + SYSTEM, + //服务端发送到客户端,用于设置客户端的用户信息。会吧 com.xnx3.yunkefu.core.vo.bean.User 传过去 + SET_USER, + //结束服务 + CLOSE_SERVICE; + +} diff --git a/framework/src/main/java/cn/lili/im/entity/enums/MessageType.java b/framework/src/main/java/cn/lili/modules/im/entity/enums/MessageTypeEnum.java similarity index 74% rename from framework/src/main/java/cn/lili/im/entity/enums/MessageType.java rename to framework/src/main/java/cn/lili/modules/im/entity/enums/MessageTypeEnum.java index 593afd78..b09bc981 100644 --- a/framework/src/main/java/cn/lili/im/entity/enums/MessageType.java +++ b/framework/src/main/java/cn/lili/modules/im/entity/enums/MessageTypeEnum.java @@ -1,11 +1,11 @@ -package cn.lili.im.entity.enums; +package cn.lili.modules.im.entity.enums; /** * 消息类型 * * @author liushuai */ -public enum MessageType { +public enum MessageTypeEnum { /** * 消息类型枚举 *

diff --git a/framework/src/main/java/cn/lili/modules/im/entity/enums/OnlineStatusEnum.java b/framework/src/main/java/cn/lili/modules/im/entity/enums/OnlineStatusEnum.java new file mode 100644 index 00000000..837a4493 --- /dev/null +++ b/framework/src/main/java/cn/lili/modules/im/entity/enums/OnlineStatusEnum.java @@ -0,0 +1,14 @@ +package cn.lili.modules.im.entity.enums; + +/** + * 坐席在线状态 + * + * @author Chopper + * @version v1.0 + * 2022-02-10 16:37 + */ +public enum OnlineStatusEnum { + // 在线/下线 + ONLINE, + OUTLINE; +} diff --git a/framework/src/main/java/cn/lili/im/entity/enums/OperationType.java b/framework/src/main/java/cn/lili/modules/im/entity/enums/OperationType.java similarity index 89% rename from framework/src/main/java/cn/lili/im/entity/enums/OperationType.java rename to framework/src/main/java/cn/lili/modules/im/entity/enums/OperationType.java index 4c68971a..5909222e 100644 --- a/framework/src/main/java/cn/lili/im/entity/enums/OperationType.java +++ b/framework/src/main/java/cn/lili/modules/im/entity/enums/OperationType.java @@ -1,4 +1,4 @@ -package cn.lili.im.entity.enums; +package cn.lili.modules.im.entity.enums; /** * 操作类型枚举 diff --git a/framework/src/main/java/cn/lili/im/entity/vo/ImTalkVO.java b/framework/src/main/java/cn/lili/modules/im/entity/vo/ImTalkVO.java similarity index 95% rename from framework/src/main/java/cn/lili/im/entity/vo/ImTalkVO.java rename to framework/src/main/java/cn/lili/modules/im/entity/vo/ImTalkVO.java index b3707452..1fa1b561 100644 --- a/framework/src/main/java/cn/lili/im/entity/vo/ImTalkVO.java +++ b/framework/src/main/java/cn/lili/modules/im/entity/vo/ImTalkVO.java @@ -1,6 +1,6 @@ -package cn.lili.im.entity.vo; +package cn.lili.modules.im.entity.vo; -import cn.lili.im.entity.ImTalk; +import cn.lili.modules.im.entity.dos.ImTalk; import cn.lili.mybatis.BaseTenantEntity; import com.fasterxml.jackson.annotation.JsonFormat; import io.swagger.annotations.ApiModel; diff --git a/framework/src/main/java/cn/lili/im/entity/vo/MessageOperation.java b/framework/src/main/java/cn/lili/modules/im/entity/vo/MessageOperation.java similarity index 70% rename from framework/src/main/java/cn/lili/im/entity/vo/MessageOperation.java rename to framework/src/main/java/cn/lili/modules/im/entity/vo/MessageOperation.java index 602e3b9b..b4360bc6 100644 --- a/framework/src/main/java/cn/lili/im/entity/vo/MessageOperation.java +++ b/framework/src/main/java/cn/lili/modules/im/entity/vo/MessageOperation.java @@ -1,8 +1,8 @@ -package cn.lili.im.entity.vo; +package cn.lili.modules.im.entity.vo; import cn.lili.common.utils.StringUtils; -import cn.lili.im.entity.enums.MessageType; -import cn.lili.im.entity.enums.OperationType; +import cn.lili.modules.im.entity.enums.MessageTypeEnum; +import cn.lili.modules.im.entity.enums.OperationType; import lombok.Data; /** @@ -20,6 +20,11 @@ public class MessageOperation { */ private String to; + /** + * 发送者 + */ + private String from; + /** * 聊天id */ @@ -28,7 +33,7 @@ public class MessageOperation { /** * 消息类型 */ - private MessageType messageType; + private MessageTypeEnum messageType; /** * 消息内容 */ @@ -42,7 +47,7 @@ public class MessageOperation { public void setMessageType(String messageType) { if (!StringUtils.isEmpty(messageType)) { - this.messageType = MessageType.valueOf(messageType); + this.messageType = MessageTypeEnum.valueOf(messageType); } } } diff --git a/framework/src/main/java/cn/lili/im/entity/vo/MessageVO.java b/framework/src/main/java/cn/lili/modules/im/entity/vo/MessageVO.java similarity index 77% rename from framework/src/main/java/cn/lili/im/entity/vo/MessageVO.java rename to framework/src/main/java/cn/lili/modules/im/entity/vo/MessageVO.java index 5c4b0222..420091e1 100644 --- a/framework/src/main/java/cn/lili/im/entity/vo/MessageVO.java +++ b/framework/src/main/java/cn/lili/modules/im/entity/vo/MessageVO.java @@ -1,6 +1,6 @@ -package cn.lili.im.entity.vo; +package cn.lili.modules.im.entity.vo; -import cn.lili.im.entity.enums.MessageResultType; +import cn.lili.modules.im.entity.enums.MessageResultType; import lombok.AllArgsConstructor; import lombok.Data; diff --git a/framework/src/main/java/cn/lili/im/entity/vo/ReadMessage.java b/framework/src/main/java/cn/lili/modules/im/entity/vo/ReadMessage.java similarity index 84% rename from framework/src/main/java/cn/lili/im/entity/vo/ReadMessage.java rename to framework/src/main/java/cn/lili/modules/im/entity/vo/ReadMessage.java index 64b20f86..bbeb7d11 100644 --- a/framework/src/main/java/cn/lili/im/entity/vo/ReadMessage.java +++ b/framework/src/main/java/cn/lili/modules/im/entity/vo/ReadMessage.java @@ -1,4 +1,4 @@ -package cn.lili.im.entity.vo; +package cn.lili.modules.im.entity.vo; import lombok.Data; diff --git a/framework/src/main/java/cn/lili/modules/im/entity/vo/SeatVO.java b/framework/src/main/java/cn/lili/modules/im/entity/vo/SeatVO.java new file mode 100644 index 00000000..d1df9d1c --- /dev/null +++ b/framework/src/main/java/cn/lili/modules/im/entity/vo/SeatVO.java @@ -0,0 +1,22 @@ +package cn.lili.modules.im.entity.vo; + +import cn.lili.modules.im.entity.dos.Seat; +import lombok.Data; + +/** + * 客服VO + * + * @author Chopper + * @version v1.0 + * 2022-02-10 15:02 + */ +@Data +public class SeatVO extends Seat { + + /** + * 在线状态 + */ + private String onlineStatus; + + +} diff --git a/framework/src/main/java/cn/lili/im/mapper/ImMessageMapper.java b/framework/src/main/java/cn/lili/modules/im/mapper/ImMessageMapper.java similarity index 66% rename from framework/src/main/java/cn/lili/im/mapper/ImMessageMapper.java rename to framework/src/main/java/cn/lili/modules/im/mapper/ImMessageMapper.java index 4b3ac1a1..e82b0cac 100644 --- a/framework/src/main/java/cn/lili/im/mapper/ImMessageMapper.java +++ b/framework/src/main/java/cn/lili/modules/im/mapper/ImMessageMapper.java @@ -1,6 +1,6 @@ -package cn.lili.im.mapper; +package cn.lili.modules.im.mapper; -import cn.lili.im.entity.ImMessage; +import cn.lili.modules.im.entity.dos.ImMessage; import com.baomidou.mybatisplus.core.mapper.BaseMapper; /** diff --git a/framework/src/main/java/cn/lili/im/mapper/ImTalkMapper.java b/framework/src/main/java/cn/lili/modules/im/mapper/ImTalkMapper.java similarity index 66% rename from framework/src/main/java/cn/lili/im/mapper/ImTalkMapper.java rename to framework/src/main/java/cn/lili/modules/im/mapper/ImTalkMapper.java index 4377dc59..d5f0d2b1 100644 --- a/framework/src/main/java/cn/lili/im/mapper/ImTalkMapper.java +++ b/framework/src/main/java/cn/lili/modules/im/mapper/ImTalkMapper.java @@ -1,6 +1,6 @@ -package cn.lili.im.mapper; +package cn.lili.modules.im.mapper; -import cn.lili.im.entity.ImTalk; +import cn.lili.modules.im.entity.dos.ImTalk; import com.baomidou.mybatisplus.core.mapper.BaseMapper; /** diff --git a/framework/src/main/java/cn/lili/modules/im/mapper/QAMapper.java b/framework/src/main/java/cn/lili/modules/im/mapper/QAMapper.java new file mode 100644 index 00000000..f5592316 --- /dev/null +++ b/framework/src/main/java/cn/lili/modules/im/mapper/QAMapper.java @@ -0,0 +1,16 @@ +package cn.lili.modules.im.mapper; + + +import cn.lili.modules.im.entity.dos.QA; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +/** + * 问答处理层 + * + * @author pikachu + * @since 2020-02-18 15:18:56 + */ +public interface QAMapper extends BaseMapper { + + +} \ No newline at end of file diff --git a/framework/src/main/java/cn/lili/modules/im/mapper/SeatMapper.java b/framework/src/main/java/cn/lili/modules/im/mapper/SeatMapper.java new file mode 100644 index 00000000..98d7b6ae --- /dev/null +++ b/framework/src/main/java/cn/lili/modules/im/mapper/SeatMapper.java @@ -0,0 +1,16 @@ +package cn.lili.modules.im.mapper; + + +import cn.lili.modules.im.entity.dos.Seat; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +/** + * 坐席处理层 + * + * @author pikachu + * @since 2020-02-18 15:18:56 + */ +public interface SeatMapper extends BaseMapper { + + +} \ No newline at end of file diff --git a/framework/src/main/java/cn/lili/modules/im/mapper/SeatSettingMapper.java b/framework/src/main/java/cn/lili/modules/im/mapper/SeatSettingMapper.java new file mode 100644 index 00000000..9e130ef3 --- /dev/null +++ b/framework/src/main/java/cn/lili/modules/im/mapper/SeatSettingMapper.java @@ -0,0 +1,16 @@ +package cn.lili.modules.im.mapper; + + +import cn.lili.modules.im.entity.dos.SeatSetting; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +/** + * 坐席设置处理层 + * + * @author pikachu + * @since 2020-02-18 15:18:56 + */ +public interface SeatSettingMapper extends BaseMapper { + + +} \ No newline at end of file diff --git a/framework/src/main/java/cn/lili/im/service/ImMessageService.java b/framework/src/main/java/cn/lili/modules/im/service/ImMessageService.java similarity index 89% rename from framework/src/main/java/cn/lili/im/service/ImMessageService.java rename to framework/src/main/java/cn/lili/modules/im/service/ImMessageService.java index 7b58c900..def4c1f3 100644 --- a/framework/src/main/java/cn/lili/im/service/ImMessageService.java +++ b/framework/src/main/java/cn/lili/modules/im/service/ImMessageService.java @@ -1,6 +1,6 @@ -package cn.lili.im.service; +package cn.lili.modules.im.service; -import cn.lili.im.entity.ImMessage; +import cn.lili.modules.im.entity.dos.ImMessage; import com.baomidou.mybatisplus.extension.service.IService; import java.util.List; diff --git a/framework/src/main/java/cn/lili/im/service/ImTalkService.java b/framework/src/main/java/cn/lili/modules/im/service/ImTalkService.java similarity index 87% rename from framework/src/main/java/cn/lili/im/service/ImTalkService.java rename to framework/src/main/java/cn/lili/modules/im/service/ImTalkService.java index f9919cd6..50277d31 100644 --- a/framework/src/main/java/cn/lili/im/service/ImTalkService.java +++ b/framework/src/main/java/cn/lili/modules/im/service/ImTalkService.java @@ -1,6 +1,6 @@ -package cn.lili.im.service; +package cn.lili.modules.im.service; -import cn.lili.im.entity.ImTalk; +import cn.lili.modules.im.entity.dos.ImTalk; import com.baomidou.mybatisplus.extension.service.IService; /** diff --git a/framework/src/main/java/cn/lili/modules/im/service/QAService.java b/framework/src/main/java/cn/lili/modules/im/service/QAService.java new file mode 100644 index 00000000..49f8572b --- /dev/null +++ b/framework/src/main/java/cn/lili/modules/im/service/QAService.java @@ -0,0 +1,25 @@ +package cn.lili.modules.im.service; + + +import cn.lili.common.vo.PageVO; +import cn.lili.modules.im.entity.dos.QA; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.IService; + +/** + * 问答 + * + * @author pikachu + * @since 2020-02-18 16:18:56 + */ +public interface QAService extends IService { + + /** + * 查询店铺问题 + * @param word + * @param pageVO + * @return + */ + IPage getStoreQA(String word, PageVO pageVO); + +} \ No newline at end of file diff --git a/framework/src/main/java/cn/lili/modules/im/service/SeatService.java b/framework/src/main/java/cn/lili/modules/im/service/SeatService.java new file mode 100644 index 00000000..b0cf8eac --- /dev/null +++ b/framework/src/main/java/cn/lili/modules/im/service/SeatService.java @@ -0,0 +1,60 @@ +package cn.lili.modules.im.service; + + +import cn.lili.common.security.token.Token; +import cn.lili.modules.im.entity.dos.Seat; +import cn.lili.modules.im.entity.vo.SeatVO; +import com.baomidou.mybatisplus.extension.service.IService; + +import java.util.List; + +/** + * 坐席业务 + * + * @author pikachu + * @since 2020-02-18 16:18:56 + */ +public interface SeatService extends IService { + + + /** + * 获取坐席列表 + * + * @param storeId 店铺id + * @return + */ + List seatVoList(String storeId); + + /** + * 坐席登录 + * + * @param username + * @param password + * @return + */ + Token usernameLogin(String username, String password); + + /** + * 快捷登录code 生成 + * + * @param username 用户名 + * @return + */ + String createQuickLoginCode(String username); + + /** + * 快捷登录 + * + * @param code + * @return + */ + Token quickLogin(String code); + + /** + * 查询坐席 + * + * @param username + * @return + */ + Seat findByUsername(String username); +} \ No newline at end of file diff --git a/framework/src/main/java/cn/lili/modules/im/service/SeatSettingService.java b/framework/src/main/java/cn/lili/modules/im/service/SeatSettingService.java new file mode 100644 index 00000000..364ba10f --- /dev/null +++ b/framework/src/main/java/cn/lili/modules/im/service/SeatSettingService.java @@ -0,0 +1,30 @@ +package cn.lili.modules.im.service; + +import cn.lili.modules.im.entity.dos.SeatSetting; +import com.baomidou.mybatisplus.extension.service.IService; + +/** + * 坐席设置业务 + * + * @author pikachu + * @since 2020-02-18 16:18:56 + */ +public interface SeatSettingService extends IService { + + + /** + * 根据店铺id获取坐席配置 + * + * @param storeId + * @return + */ + SeatSetting getSetting(String storeId); + + /** + * 根据店铺修改坐席设置 + * + * @param seatSetting 坐席设置 + * @return + */ + SeatSetting updateByStore(SeatSetting seatSetting); +} \ No newline at end of file diff --git a/framework/src/main/java/cn/lili/im/serviceimpl/ImMessageServiceImpl.java b/framework/src/main/java/cn/lili/modules/im/serviceimpl/ImMessageServiceImpl.java similarity index 91% rename from framework/src/main/java/cn/lili/im/serviceimpl/ImMessageServiceImpl.java rename to framework/src/main/java/cn/lili/modules/im/serviceimpl/ImMessageServiceImpl.java index 6f2fa9a3..4452895a 100644 --- a/framework/src/main/java/cn/lili/im/serviceimpl/ImMessageServiceImpl.java +++ b/framework/src/main/java/cn/lili/modules/im/serviceimpl/ImMessageServiceImpl.java @@ -1,10 +1,10 @@ -package cn.lili.im.serviceimpl; +package cn.lili.modules.im.serviceimpl; import cn.lili.common.security.context.UserContext; -import cn.lili.im.entity.ImMessage; -import cn.lili.im.mapper.ImMessageMapper; -import cn.lili.im.service.ImMessageService; -import cn.lili.im.service.ImTalkService; +import cn.lili.modules.im.entity.dos.ImMessage; +import cn.lili.modules.im.mapper.ImMessageMapper; +import cn.lili.modules.im.service.ImMessageService; +import cn.lili.modules.im.service.ImTalkService; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; diff --git a/framework/src/main/java/cn/lili/im/serviceimpl/ImTalkServiceImpl.java b/framework/src/main/java/cn/lili/modules/im/serviceimpl/ImTalkServiceImpl.java similarity index 61% rename from framework/src/main/java/cn/lili/im/serviceimpl/ImTalkServiceImpl.java rename to framework/src/main/java/cn/lili/modules/im/serviceimpl/ImTalkServiceImpl.java index a2f4c28a..6dee1ab5 100644 --- a/framework/src/main/java/cn/lili/im/serviceimpl/ImTalkServiceImpl.java +++ b/framework/src/main/java/cn/lili/modules/im/serviceimpl/ImTalkServiceImpl.java @@ -1,19 +1,22 @@ -package cn.lili.im.serviceimpl; +package cn.lili.modules.im.serviceimpl; import cn.lili.common.enums.ResultCode; import cn.lili.common.exception.ServiceException; import cn.lili.common.security.context.UserContext; -import cn.lili.im.entity.ImTalk; -import cn.lili.im.entity.ImUser; -import cn.lili.im.mapper.ImTalkMapper; -import cn.lili.im.service.ImTalkService; -import cn.lili.im.service.ImUserService; +import cn.lili.modules.im.entity.dos.ImTalk; +import cn.lili.modules.im.mapper.ImTalkMapper; +import cn.lili.modules.im.service.ImTalkService; +import cn.lili.modules.member.entity.dos.Member; +import cn.lili.modules.member.service.MemberService; +import cn.lili.modules.store.entity.dos.Store; +import cn.lili.modules.store.service.StoreService; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import org.stringtemplate.v4.ST; /** * 聊天 业务实现 @@ -26,7 +29,10 @@ import org.springframework.transaction.annotation.Transactional; public class ImTalkServiceImpl extends ServiceImpl implements ImTalkService { @Autowired - private ImUserService imUserService; + private MemberService memberService; + + @Autowired + private StoreService storeService; @Override public ImTalk getTalkByUser(String userId1, String userId2) { @@ -34,15 +40,34 @@ public class ImTalkServiceImpl extends ServiceImpl impleme queryWrapper.eq(ImTalk::getUserId2, userId2); queryWrapper.eq(ImTalk::getUserId1, userId1); ImTalk imTalk = this.getOne(queryWrapper); - ImUser imUser1 = imUserService.getById(userId1); - ImUser imUser2 = imUserService.getById(userId2); + Member self = memberService.getById(userId1); + Store selfStore = storeService.getById(userId1); + //如果没有聊天,则创建聊天 if (imTalk == null) { - if (imUser1 == null || imUser2 == null) { + // 没有登录的这个账户信息 + if (self == null && selfStore ==null) { return null; } - imTalk = new ImTalk(userId1, userId2, imUser1.getFace(), imUser2.getFace(), imUser1.getName(), imUser2.getName()); + //当自己为店铺时 + if(selfStore != null){ + //没有这个用户信息 + Member other = memberService.getById(userId2); + if(other == null){ + return null; + } + //自己为店铺其他人必定为用户 + imTalk = new ImTalk(userId1, userId2, selfStore.getStoreLogo(), other.getFace(), selfStore.getStoreName(), other.getNickName()); + }else if(self != null){ + //没有这个店铺信息 + Store otherStore = storeService.getById(userId2); + if(otherStore == null){ + return null; + } + //当自己为用户时 其他人必定为店铺 + imTalk = new ImTalk(userId1, userId2, self.getFace(), otherStore.getStoreLogo(), self.getNickName(), otherStore.getStoreName()); + } this.save(imTalk); } else { imTalk = check(imTalk); diff --git a/framework/src/main/java/cn/lili/modules/im/serviceimpl/QAServiceImpl.java b/framework/src/main/java/cn/lili/modules/im/serviceimpl/QAServiceImpl.java new file mode 100644 index 00000000..2ee78fbc --- /dev/null +++ b/framework/src/main/java/cn/lili/modules/im/serviceimpl/QAServiceImpl.java @@ -0,0 +1,32 @@ +package cn.lili.modules.im.serviceimpl; + +import cn.lili.common.security.context.UserContext; +import cn.lili.common.vo.PageVO; +import cn.lili.modules.im.entity.dos.QA; +import cn.lili.modules.im.mapper.QAMapper; +import cn.lili.modules.im.service.QAService; +import cn.lili.mybatis.util.PageUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +/** + * 坐席业务层实现 + * + * @author pikachu + * @since 2020-02-18 16:18:56 + */ +@Service +@Transactional(rollbackFor = Exception.class) +public class QAServiceImpl extends ServiceImpl implements QAService { + + @Override + public IPage getStoreQA(String word, PageVO pageVo) { + LambdaQueryWrapper qaLambdaQueryWrapper = new LambdaQueryWrapper<>(); + qaLambdaQueryWrapper.eq(QA::getTenantId, UserContext.getCurrentUser().getTenantId()); + qaLambdaQueryWrapper.like(QA::getQuestion, word); + return this.page(PageUtil.initPage(pageVo), qaLambdaQueryWrapper); + } +} \ No newline at end of file diff --git a/framework/src/main/java/cn/lili/modules/im/serviceimpl/SeatServiceImpl.java b/framework/src/main/java/cn/lili/modules/im/serviceimpl/SeatServiceImpl.java new file mode 100644 index 00000000..cac28af1 --- /dev/null +++ b/framework/src/main/java/cn/lili/modules/im/serviceimpl/SeatServiceImpl.java @@ -0,0 +1,111 @@ +package cn.lili.modules.im.serviceimpl; + +import cn.lili.cache.Cache; +import cn.lili.common.enums.ResultCode; +import cn.lili.common.exception.ServiceException; +import cn.lili.common.security.token.Token; +import cn.lili.common.utils.StringUtils; +import cn.lili.modules.im.entity.dos.Seat; +import cn.lili.modules.im.entity.enums.OnlineStatusEnum; +import cn.lili.modules.im.entity.vo.SeatVO; +import cn.lili.modules.im.mapper.SeatMapper; +import cn.lili.modules.im.service.SeatService; +import cn.lili.modules.im.token.SeatTokenGenerate; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; +import java.util.UUID; +import java.util.stream.Collectors; + +/** + * 坐席业务层实现 + * + * @author pikachu + * @since 2020-02-18 16:18:56 + */ +@Service +@Transactional(rollbackFor = Exception.class) +public class SeatServiceImpl extends ServiceImpl implements SeatService { + + + @Autowired + private SeatTokenGenerate seatTokenGenerate; + + @Autowired + private Cache cache; + + /** + * 快捷登录缓存前缀 + */ + private static String prefix = "{quick_login}_"; + + + @Override + public List seatVoList(String storeId) { + + LambdaQueryWrapper seatLambdaQueryWrapper = new LambdaQueryWrapper<>(); + seatLambdaQueryWrapper.eq(Seat::getTenantId, storeId); + List list = this.list(seatLambdaQueryWrapper); + + //转换模型为VO + List results = list.stream().map(item -> (SeatVO) item).collect(Collectors.toList()); + //填充坐席当前状态 + //todo + results.forEach(item -> { + item.setOnlineStatus(OnlineStatusEnum.ONLINE.name()); + }); + return results; + } + + @Override + public Token usernameLogin(String username, String password) { + + Seat seat = this.findByUsername(username); + //判断用户是否存在 + if (seat == null || !seat.getDisabled()) { + throw new ServiceException(ResultCode.ERROR); + } + //判断密码是否输入正确 + if (!new BCryptPasswordEncoder().matches(password, seat.getPassword())) { + throw new ServiceException(ResultCode.ERROR); + } + return seatTokenGenerate.createToken(seat, true); + } + + @Override + public String createQuickLoginCode(String username) { + String code = UUID.randomUUID().toString(); + cache.put(prefix + code, username, 20L); + return code; + } + + @Override + public Token quickLogin(String code) { + String username = cache.get(prefix + code); + cache.remove(prefix + code); + if (StringUtils.isEmpty(username)) { + throw new ServiceException(ResultCode.ERROR); + } + return seatTokenGenerate.createToken(findByUsername(username), true); + } + + /** + * 查询坐席 + * + * @param username + * @return + */ + @Override + public Seat findByUsername(String username) { + LambdaQueryWrapper seatLambdaQueryWrapper = new LambdaQueryWrapper<>(); + seatLambdaQueryWrapper.eq(Seat::getUsername, username); + return this.getOne(seatLambdaQueryWrapper); + } + + +} \ No newline at end of file diff --git a/framework/src/main/java/cn/lili/modules/im/serviceimpl/SeatSettingServiceImpl.java b/framework/src/main/java/cn/lili/modules/im/serviceimpl/SeatSettingServiceImpl.java new file mode 100644 index 00000000..e5ec4a8e --- /dev/null +++ b/framework/src/main/java/cn/lili/modules/im/serviceimpl/SeatSettingServiceImpl.java @@ -0,0 +1,48 @@ +package cn.lili.modules.im.serviceimpl; + +import cn.lili.common.enums.ResultCode; +import cn.lili.common.exception.ServiceException; +import cn.lili.modules.im.entity.dos.SeatSetting; +import cn.lili.modules.im.mapper.SeatSettingMapper; +import cn.lili.modules.im.service.SeatSettingService; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +/** + * 坐席设置业务层实现 + * + * @author pikachu + * @since 2020-02-18 16:18:56 + */ +@Service +@Transactional(rollbackFor = Exception.class) +public class SeatSettingServiceImpl extends ServiceImpl implements SeatSettingService { + @Override + public SeatSetting getSetting(String storeId) { + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(SeatSetting::getTenantId, storeId); + SeatSetting seatSetting = this.baseMapper.selectOne(queryWrapper); + if (seatSetting == null) { + seatSetting = new SeatSetting(); + seatSetting.setOutLineAutoReply("您好,我现在不在线,请您留下关键内容和联系方式,我看到后会立马回电。"); + seatSetting.setLongTermAutoReply("您好,我正在查阅相关资料,请您稍等。"); + seatSetting.setWelcome("您好,请问有什么可以帮您?"); + seatSetting.setTenantId(storeId); + this.save(seatSetting); + } + return seatSetting; + } + + @Override + public SeatSetting updateByStore(SeatSetting seatSetting) { + SeatSetting oldSetting = this.baseMapper.selectById(seatSetting.getId()); + if (oldSetting.getTenantId().equals(seatSetting.getTenantId())) { + this.updateById(seatSetting); + } else { + throw new ServiceException(ResultCode.ERROR); + } + return seatSetting; + } +} \ No newline at end of file diff --git a/framework/src/main/java/cn/lili/modules/im/token/SeatTokenGenerate.java b/framework/src/main/java/cn/lili/modules/im/token/SeatTokenGenerate.java new file mode 100644 index 00000000..482bcded --- /dev/null +++ b/framework/src/main/java/cn/lili/modules/im/token/SeatTokenGenerate.java @@ -0,0 +1,42 @@ +package cn.lili.modules.im.token; + +import cn.lili.common.security.AuthUser; +import cn.lili.common.security.enums.UserEnums; +import cn.lili.common.security.token.Token; +import cn.lili.common.security.token.TokenUtil; +import cn.lili.common.security.token.base.AbstractTokenGenerate; +import cn.lili.modules.im.entity.dos.Seat; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * 会员token生成 + * + * @author Chopper + * @version v4.0 + * @since 2020/11/16 10:50 + */ +@Component +public class SeatTokenGenerate extends AbstractTokenGenerate { + @Autowired + private TokenUtil tokenUtil; + + @Override + public Token createToken(Seat seat, Boolean longTerm) { + AuthUser authUser = new AuthUser( + seat.getUsername(), + seat.getId(), + seat.getNickName(), + seat.getFace(), + UserEnums.SEAT); + authUser.setTenantId(seat.getTenantId()); + //登陆成功生成token + return tokenUtil.createToken(seat.getUsername(), authUser, longTerm, UserEnums.SEAT); + } + + @Override + public Token refreshToken(String refreshToken) { + return tokenUtil.refreshToken(refreshToken, UserEnums.SEAT); + } + +} diff --git a/im-api/pom.xml b/im-api/pom.xml new file mode 100644 index 00000000..7f823cf4 --- /dev/null +++ b/im-api/pom.xml @@ -0,0 +1,34 @@ + + + 4.0.0 + + im-api + + + cn.lili + lili-shop-parent + ${revision} + ../pom.xml + + + + + cn.lili + framework + ${revision} + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + \ No newline at end of file diff --git a/im-api/src/main/java/cn/lili/ImApiApplication.java b/im-api/src/main/java/cn/lili/ImApiApplication.java new file mode 100644 index 00000000..67078506 --- /dev/null +++ b/im-api/src/main/java/cn/lili/ImApiApplication.java @@ -0,0 +1,31 @@ +package cn.lili; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; +import org.springframework.web.socket.server.standard.ServerEndpointExporter; + + +/** + * @author liushuai + */ +@SpringBootApplication +public class ImApiApplication { + + public static void main(String[] args) { + SpringApplication.run(ImApiApplication.class, args); + } + + /** + * 如果使用独立的servlet容器, + * 而不是直接使用springboot的内置容器, + * 就不要注入ServerEndpointExporter, + * 因为它将由容器自己提供和管理 + * + * @return + */ + @Bean + public ServerEndpointExporter serverEndpointExporter() { + return new ServerEndpointExporter(); + } +} diff --git a/manager-api/src/main/java/cn/lili/controller/im/ImManagerController.java b/im-api/src/main/java/cn/lili/controller/im/ImManagerController.java similarity index 99% rename from manager-api/src/main/java/cn/lili/controller/im/ImManagerController.java rename to im-api/src/main/java/cn/lili/controller/im/ImManagerController.java index bb40225f..787b4c57 100644 --- a/manager-api/src/main/java/cn/lili/controller/im/ImManagerController.java +++ b/im-api/src/main/java/cn/lili/controller/im/ImManagerController.java @@ -33,7 +33,7 @@ import java.util.List; @Slf4j @RestController @Api(tags = "管理员") -@RequestMapping("/manager/passport/user") +@RequestMapping("/manager/im/passport/user") @Validated public class ImManagerController { @Autowired diff --git a/im-api/src/main/java/cn/lili/controller/im/ImMessageController.java b/im-api/src/main/java/cn/lili/controller/im/ImMessageController.java new file mode 100644 index 00000000..2e4b9079 --- /dev/null +++ b/im-api/src/main/java/cn/lili/controller/im/ImMessageController.java @@ -0,0 +1,82 @@ +package cn.lili.controller.im; + +import cn.lili.common.enums.ResultCode; +import cn.lili.common.enums.ResultUtil; +import cn.lili.common.vo.ResultMessage; +import cn.lili.modules.im.entity.dos.ImMessage; +import cn.lili.modules.im.entity.dto.MessageQueryParams; +import cn.lili.modules.im.service.ImMessageService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + + +/** + * @author Chopper + */ +@RestController +@Api(tags = "Im消息接口") +@RequestMapping("/lili/imMessage") +@Transactional(rollbackFor = Exception.class) +@RequiredArgsConstructor(onConstructor = @__(@Autowired)) +public class ImMessageController { + + private final ImMessageService imMessageService; + + @GetMapping(value = "/{id}") + @ApiOperation(value = "查看Im消息详情") + public ResultMessage get(@PathVariable String id) { + + ImMessage imMessage = imMessageService.getById(id); + return new ResultUtil().setData(imMessage); + } + + @GetMapping + @ApiOperation(value = "分页获取Im消息") + public ResultMessage> historyMessage(MessageQueryParams messageQueryParams) { + List data = imMessageService.list(messageQueryParams.initQueryWrapper()); + return new ResultUtil>().setData(data); + } + + @PostMapping + @ApiOperation(value = "新增Im消息") + public ResultMessage save(ImMessage imMessage) { + + if (imMessageService.save(imMessage)) { + return new ResultUtil().setData(imMessage); + } + return new ResultUtil().setErrorMsg(ResultCode.ERROR); + } + + @PutMapping("/{id}") + @ApiOperation(value = "更新Im消息") + public ResultMessage update(@PathVariable String id, ImMessage imMessage) { + if (imMessageService.updateById(imMessage)) { + return new ResultUtil().setData(imMessage); + } + return new ResultUtil().setErrorMsg(ResultCode.ERROR); + } + + @DeleteMapping(value = "/{ids}") + @ApiOperation(value = "删除Im消息") + public ResultMessage delAllByIds(@PathVariable List ids) { + + imMessageService.removeByIds(ids); + return ResultUtil.success(ResultCode.SUCCESS); + } + + + @GetMapping(value = "/newMessage") + @ApiOperation(value = "删除Im消息") + public ResultMessage hasNewMessage(String accessToken) { + + return ResultUtil.data(imMessageService.hasNewMessage(accessToken)); + } + + +} diff --git a/im-api/src/main/java/cn/lili/controller/im/ImTalkController.java b/im-api/src/main/java/cn/lili/controller/im/ImTalkController.java new file mode 100644 index 00000000..6b9cfb20 --- /dev/null +++ b/im-api/src/main/java/cn/lili/controller/im/ImTalkController.java @@ -0,0 +1,93 @@ +package cn.lili.controller.im; + +import cn.lili.common.enums.ResultCode; +import cn.lili.common.enums.ResultUtil; +import cn.lili.common.security.AuthUser; +import cn.lili.common.security.context.UserContext; +import cn.lili.common.vo.ResultMessage; +import cn.lili.modules.im.entity.dos.ImTalk; +import cn.lili.modules.im.entity.vo.ImTalkVO; +import cn.lili.modules.im.service.ImTalkService; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.bind.annotation.*; + +import java.util.List; +import java.util.stream.Collectors; + + +/** + * @author Chopper + */ +@RestController +@Api(tags = "聊天接口") +@RequestMapping("/lili/imTalk") +@Transactional(rollbackFor = Exception.class) +@RequiredArgsConstructor(onConstructor = @__(@Autowired)) +public class ImTalkController { + + private final ImTalkService imTalkService; + + @GetMapping(value = "/{id}") + @ApiOperation(value = "查看聊天详情") + public ResultMessage get(@PathVariable String id) { + + ImTalk imTalk = imTalkService.getById(id); + return new ResultUtil().setData(imTalk); + } + + @GetMapping(value = "/user/{uid}") + @ApiOperation(value = "查看与某人聊天详情") + public ResultMessage getUser(@PathVariable String uid) { + AuthUser authUser = UserContext.getCurrentUser(); + return ResultUtil.data(imTalkService.getTalkByUser(authUser.getId(), uid)); + } + + @GetMapping(value = "/top") + @ApiOperation(value = "查看与某人聊天详情") + public ResultMessage top(String id, Boolean top) { + imTalkService.top(id, top); + return ResultUtil.success(); + } + + @GetMapping("/list") + @ApiOperation(value = "分页获取聊天") + public ResultMessage> getByPage() { + AuthUser authUser = UserContext.getCurrentUser(); + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(ImTalk::getUserId1, authUser.getId()).or().eq(ImTalk::getUserId2, authUser.getId()); + List imTalks = imTalkService.list(queryWrapper); + + List results = imTalks.stream().map(imTalk -> { + return new ImTalkVO(imTalk, authUser.getId()); + }).collect(Collectors.toList()); + + return ResultUtil.data(results); + } + + @GetMapping("/store/list") + @ApiOperation(value = "分页获取商家聊天") + public ResultMessage> getStoreTalkList() { + AuthUser authUser = UserContext.getCurrentUser(); + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(ImTalk::getUserId1, authUser.getStoreId()).or().eq(ImTalk::getUserId2, authUser.getStoreId()); + List imTalks = imTalkService.list(queryWrapper); + + List results = imTalks.stream().map(imTalk -> { + return new ImTalkVO(imTalk, authUser.getStoreId()); + }).collect(Collectors.toList()); + + return ResultUtil.data(results); + } + + @DeleteMapping(value = "/{id}") + @ApiOperation(value = "删除聊天") + public ResultMessage disable(@PathVariable String id) { + imTalkService.disable(id); + return ResultUtil.success(ResultCode.SUCCESS); + } +} diff --git a/im-api/src/main/java/cn/lili/controller/im/ImUserController.java b/im-api/src/main/java/cn/lili/controller/im/ImUserController.java new file mode 100644 index 00000000..f1de0768 --- /dev/null +++ b/im-api/src/main/java/cn/lili/controller/im/ImUserController.java @@ -0,0 +1,51 @@ +package cn.lili.controller.im; + + +import cn.lili.common.enums.ResultUtil; +import cn.lili.common.security.AuthUser; +import cn.lili.common.security.context.UserContext; +import cn.lili.common.vo.ResultMessage; +import cn.lili.modules.member.entity.dos.Member; +import cn.lili.modules.member.service.MemberService; +import cn.lili.modules.store.entity.dos.Store; +import cn.lili.modules.store.service.StoreService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + + +/** + * @author Chopper + */ +@RestController +@Api(tags = "Im消息接口") +@RequestMapping("/lili/imUser") +@Transactional(rollbackFor = Exception.class) +@RequiredArgsConstructor(onConstructor = @__(@Autowired)) +public class ImUserController { + + private final MemberService memberService; + + @Autowired + private StoreService storeService; + + @GetMapping + @ApiOperation(value = "获取用户信息") + public ResultMessage getImUser() { + AuthUser authUser = UserContext.getCurrentUser(); + return ResultUtil.data(memberService.getById(authUser.getId())); + } + + @GetMapping("/store") + @ApiOperation(value = "获取用户信息") + public ResultMessage getStoreUser() { + AuthUser authUser = UserContext.getCurrentUser(); + return ResultUtil.data(storeService.getById(authUser.getStoreId())); + } + +} diff --git a/im-api/src/main/java/cn/lili/controller/im/QAStoreController.java b/im-api/src/main/java/cn/lili/controller/im/QAStoreController.java new file mode 100644 index 00000000..e024d0c7 --- /dev/null +++ b/im-api/src/main/java/cn/lili/controller/im/QAStoreController.java @@ -0,0 +1,62 @@ +package cn.lili.controller.im; + +import cn.lili.common.enums.ResultUtil; +import cn.lili.common.vo.PageVO; +import cn.lili.common.vo.ResultMessage; +import cn.lili.modules.im.entity.dos.QA; +import cn.lili.modules.im.service.QAService; +import com.baomidou.mybatisplus.core.metadata.IPage; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiImplicitParam; +import io.swagger.annotations.ApiOperation; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; + +/** + * 管理端,自定义分词接口 + * + * @author paulG + * @since 2020/10/16 + **/ +@Slf4j +@RestController +@Api(tags = "管理端,自定义分词接口") +@RequestMapping("/store/qa") +public class QAStoreController { + + @Autowired + private QAService qaService; + + @ApiOperation(value = "添加问答") + @PostMapping + public ResultMessage addCustomWords(@Valid QA qa) { + qaService.save(qa); + return ResultUtil.data(qa); + } + + @ApiOperation(value = "修改自定义问答") + @PutMapping + public ResultMessage updateCustomWords(@Valid QA qa) { + qaService.updateById(qa); + return ResultUtil.data(qa); + } + + @ApiOperation(value = "删除自定义分词") + @DeleteMapping("/{id}") + public ResultMessage deleteCustomWords(@NotNull @PathVariable String id) { + qaService.removeById(id); + return ResultUtil.success(); + } + + @ApiOperation(value = "分页获取自定义分词") + @ApiImplicitParam(name = "word", value = "问题", required = true, dataType = "String", paramType = "query") + @GetMapping("/page") + public ResultMessage> getCustomWords(@RequestParam String word, PageVO pageVo) { + return ResultUtil.data(qaService.getStoreQA(word, pageVo)); + } + +} diff --git a/im-api/src/main/java/cn/lili/controller/im/SeatLogin.java b/im-api/src/main/java/cn/lili/controller/im/SeatLogin.java new file mode 100644 index 00000000..685c546d --- /dev/null +++ b/im-api/src/main/java/cn/lili/controller/im/SeatLogin.java @@ -0,0 +1,59 @@ +package cn.lili.controller.im; + +import cn.lili.common.enums.ResultUtil; +import cn.lili.common.vo.ResultMessage; +import cn.lili.modules.im.service.SeatService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiImplicitParam; +import io.swagger.annotations.ApiImplicitParams; +import io.swagger.annotations.ApiOperation; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * 坐席登录接口 + * + * @author Chopper + * @version v1.0 + * 2022-02-10 16:40 + */ +@Slf4j +@RestController +@Api(tags = "坐席端") +@RequestMapping("/seat/login") +public class SeatLogin { + + @Autowired + private SeatService seatService; + + @ApiOperation(value = "登录接口") + @ApiImplicitParams({ + @ApiImplicitParam(name = "username", value = "用户名", required = true, paramType = "query"), + @ApiImplicitParam(name = "password", value = "密码", required = true, paramType = "query") + }) + @PostMapping("/userLogin") + public ResultMessage userLogin(String username, String password) { + return ResultUtil.data(this.seatService.usernameLogin(username, password)); + } + + @ApiOperation(value = "商家快捷登录客服") + @PostMapping("/quicklogin") + public ResultMessage quickLogin(String code) { + return ResultUtil.data(this.seatService.quickLogin(code)); + } + + + @ApiOperation(value = "登出") + @PostMapping("/logout") + public ResultMessage logout() { + //todo +// UserContext.getCurrentUser().getId() +// verificationServiceClient.check(uuid); + return ResultUtil.success(); + } + + +} diff --git a/im-api/src/main/java/cn/lili/controller/im/SeatSettingStoreController.java b/im-api/src/main/java/cn/lili/controller/im/SeatSettingStoreController.java new file mode 100644 index 00000000..48c99ed8 --- /dev/null +++ b/im-api/src/main/java/cn/lili/controller/im/SeatSettingStoreController.java @@ -0,0 +1,44 @@ +package cn.lili.controller.im; + +import cn.lili.common.enums.ResultUtil; +import cn.lili.common.security.context.UserContext; +import cn.lili.common.vo.ResultMessage; +import cn.lili.modules.im.entity.dos.SeatSetting; +import cn.lili.modules.im.service.SeatSettingService;; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * 店铺端,分类绑定参数组管理接口 + * + * @author pikachu + * @since 2020-02-18 15:18:56 + */ +@RestController +@Api(tags = "店铺端,坐席设置") +@RequestMapping("/store/seat/setting") +@Transactional(rollbackFor = Exception.class) +public class SeatSettingStoreController { + + @Autowired + private SeatSettingService seatSettingService; + + @ApiOperation(value = "查询坐席设置") + @GetMapping + public ResultMessage getSetting() { + return ResultUtil.data(seatSettingService.getSetting(UserContext.getCurrentUser().getTenantId())); + } + + @ApiOperation(value = "更新坐席设置") + @PutMapping + public void update(SeatSetting seatSetting) { + seatSetting.setTenantId(UserContext.getCurrentUser().getTenantId()); + seatSettingService.updateByStore(seatSetting); + } +} diff --git a/im-api/src/main/java/cn/lili/controller/im/SeatStoreController.java b/im-api/src/main/java/cn/lili/controller/im/SeatStoreController.java new file mode 100644 index 00000000..9edd6857 --- /dev/null +++ b/im-api/src/main/java/cn/lili/controller/im/SeatStoreController.java @@ -0,0 +1,42 @@ +package cn.lili.controller.im; + +import cn.lili.common.enums.ResultUtil; +import cn.lili.common.security.context.UserContext; +import cn.lili.common.vo.ResultMessage; +import cn.lili.modules.im.entity.vo.SeatVO; +import cn.lili.modules.im.service.SeatService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +/** + * SeatController + * + * @author Chopper + * @version v1.0 + * 2022-02-10 11:50 + */ +@RestController +@Api(tags = "店铺端,坐席管理") +@RequestMapping("/store/seat/setting") +@Transactional(rollbackFor = Exception.class) +public class SeatStoreController { + + + @Autowired + private SeatService seatService; + + @ApiOperation(value = "分页获取坐席") + @GetMapping("/list") + public ResultMessage> getSeats() { + return ResultUtil.data(seatService.seatVoList(UserContext.getCurrentUser().getTenantId())); + } + + +} diff --git a/im-api/src/main/java/cn/lili/controller/im/SeatStoreManagerController.java b/im-api/src/main/java/cn/lili/controller/im/SeatStoreManagerController.java new file mode 100644 index 00000000..c729903b --- /dev/null +++ b/im-api/src/main/java/cn/lili/controller/im/SeatStoreManagerController.java @@ -0,0 +1,39 @@ +package cn.lili.controller.im; + +import cn.lili.common.enums.ResultUtil; +import cn.lili.common.vo.ResultMessage; +import cn.lili.modules.im.entity.vo.SeatVO; +import cn.lili.modules.im.service.SeatService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +/** + * SeatController + * + * @author Chopper + * @version v1.0 + * 2022-02-10 11:50 + */ +@RestController +@Api(tags = "店铺端,坐席管理") +@RequestMapping("/manager/seat/setting") +@Transactional(rollbackFor = Exception.class) +public class SeatStoreManagerController { + + @Autowired + private SeatService seatService; + + @ApiOperation(value = "查看店铺坐席列表") + @GetMapping("/list") + public ResultMessage> getSeats(String storeId) { + return ResultUtil.data(seatService.seatVoList(storeId)); + } + +} diff --git a/im-api/src/main/java/cn/lili/controller/im/WebSocketServer.java b/im-api/src/main/java/cn/lili/controller/im/WebSocketServer.java new file mode 100644 index 00000000..48638619 --- /dev/null +++ b/im-api/src/main/java/cn/lili/controller/im/WebSocketServer.java @@ -0,0 +1,172 @@ +package cn.lili.controller.im; + +import cn.lili.cache.Cache; +import cn.lili.common.security.AuthUser; +import cn.lili.common.security.context.UserContext; +import cn.lili.common.utils.SnowFlake; +import cn.lili.modules.im.config.CustomSpringConfigurator; +import cn.lili.modules.im.entity.dos.ImMessage; +import cn.lili.modules.im.entity.enums.MessageResultType; +import cn.lili.modules.im.entity.vo.MessageOperation; +import cn.lili.modules.im.entity.vo.MessageVO; +import cn.lili.modules.im.service.ImMessageService; +import cn.lili.modules.member.entity.dos.Member; +import cn.lili.modules.member.service.MemberService; +import com.alibaba.druid.util.StringUtils; +import com.alibaba.fastjson.JSON; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import javax.websocket.*; +import javax.websocket.server.PathParam; +import javax.websocket.server.ServerEndpoint; +import java.io.IOException; +import java.util.Date; +import java.util.concurrent.ConcurrentHashMap; + +/** + * @author liushuai + */ +@Component +@ServerEndpoint(value = "/lili/webSocket/{accessToken}", configurator = CustomSpringConfigurator.class) +@Slf4j +public class WebSocketServer { + /** + * 消息服务 + */ + @Autowired + private ImMessageService imMessageService; + + /** + * im用户服务 + */ + @Autowired + private MemberService memberService; + + + @Autowired + private Cache cache; + /** + * 在线人数 + * PS 注意,只能单节点,如果多节点部署需要自行寻找方案 + */ + private static ConcurrentHashMap sessionPools = new ConcurrentHashMap<>(); + + /** + * 建立连接 + * + * @param session + */ + @OnOpen + public void onOpen(@PathParam("accessToken") String accessToken, Session session) throws IOException { + AuthUser authUser = UserContext.getAuthUser(accessToken); + Member member = memberService.getById(authUser.getId()); + sessionPools.put(authUser.getId(), session); + MessageVO messageVO = new MessageVO(MessageResultType.FRIENDS, member); + sendMessage(authUser.getId(), messageVO); + } + + /** + * 关闭连接 + */ + @OnClose + public void onClose(@PathParam("accessToken") String accessToken) { + log.info("断开连接:{}", accessToken); + sessionPools.remove(UserContext.getAuthUser(accessToken).getId()); + } + + /** + * 发送消息 + * + * @param msg + * @throws IOException + */ + @OnMessage + public void onMessage(@PathParam("accessToken") String accessToken, String msg) { + log.error(msg); + MessageOperation messageOperation = JSON.parseObject(msg, MessageOperation.class); + operation(accessToken, messageOperation); + } + + /** + * IM操作 + * + * @param accessToken + * @param messageOperation + */ + private void operation(String accessToken, MessageOperation messageOperation) { + + AuthUser authUser = UserContext.getAuthUser(accessToken); + switch (messageOperation.getOperationType()) { + case PING: + break; + case MESSAGE: + //保存消息 + ImMessage imMessage = new ImMessage(); + imMessage.setFromUser(messageOperation.getFrom()); + imMessage.setMessageType(messageOperation.getMessageType()); + imMessage.setIsRead(false); + imMessage.setText(messageOperation.getContext()); + imMessage.setTalkId(messageOperation.getTalkId()); + imMessage.setCreateTime(new Date()); + imMessage.setToUser(messageOperation.getTo()); + imMessage.setId(SnowFlake.getIdStr()); + imMessageService.save(imMessage); + //发送消息 + sendMessage(messageOperation.getTo(), new MessageVO(MessageResultType.MESSAGE, imMessage)); + break; + case READ: + if (!StringUtils.isEmpty(messageOperation.getContext())) { + imMessageService.read(messageOperation.getTalkId(), accessToken); + } + break; + case UNREAD: + sendMessage(authUser.getId(), new MessageVO(MessageResultType.UN_READ, imMessageService.unReadMessages(accessToken))); + break; + case HISTORY: + sendMessage(authUser.getId(), new MessageVO(MessageResultType.HISTORY, imMessageService.historyMessage(accessToken, messageOperation.getTo()))); + break; + default: + break; + } + } + + /** + * 发送消息 + * + * @param key 密钥 + * @param message 消息对象 + */ + private void sendMessage(String key, MessageVO message) { + Session session = sessionPools.get(key); + if (session != null) { + try { + session.getBasicRemote().sendText(JSON.toJSONString(message, true)); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + /** + * socket exception + * + * @param session + * @param throwable + */ + @OnError + public void onError(Session session, Throwable throwable) { + throwable.printStackTrace(); + } + + /** + * 获取店铺id + * + * @return + */ + private String storeKey(String storeId) { + return "STORE_" + storeId; + } + +} diff --git a/im-api/src/main/java/cn/lili/controller/security/ImSecurityConfig.java b/im-api/src/main/java/cn/lili/controller/security/ImSecurityConfig.java new file mode 100644 index 00000000..185b3ad9 --- /dev/null +++ b/im-api/src/main/java/cn/lili/controller/security/ImSecurityConfig.java @@ -0,0 +1,53 @@ +package cn.lili.controller.security; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer; +import org.springframework.web.cors.CorsConfigurationSource; + +/** + * spring Security 核心配置类 通用安全 + * + * @author Chopper + * @version v4.0 + * @since 2020/11/14 16:20 + */ +@Slf4j +@Configuration +@EnableGlobalMethodSecurity(prePostEnabled = true) +public class ImSecurityConfig extends WebSecurityConfigurerAdapter { + + + /** + * spring security -》 权限不足处理 + */ + @Autowired + private CorsConfigurationSource corsConfigurationSource; + + @Override + protected void configure(HttpSecurity http) throws Exception { + + ExpressionUrlAuthorizationConfigurer.ExpressionInterceptUrlRegistry registry = http + .authorizeRequests(); + registry + .and() + //禁止网页iframe + .headers().frameOptions().disable() + .and() + .authorizeRequests() + //任何请求 + .anyRequest() + //需要身份认证 + .permitAll() + .and() + //允许跨域 + .cors().configurationSource(corsConfigurationSource).and() + //关闭跨站请求防护 + .csrf().disable(); + } + +} diff --git a/im-api/src/main/resources/application.yml b/im-api/src/main/resources/application.yml new file mode 100644 index 00000000..09e55476 --- /dev/null +++ b/im-api/src/main/resources/application.yml @@ -0,0 +1,275 @@ +server: + port: 8885 + + servlet: + context-path: / + + tomcat: + uri-encoding: UTF-8 + threads: + min-spare: 50 + max: 1000 + +# 与Spring Boot 2一样,默认情况下,大多数端点都不通过http公开,我们公开了所有端点。对于生产,您应该仔细选择要公开的端点。 +management: + # health: + # elasticsearch: + # enabled: false + # datasource: + # enabled: false + endpoints: + web: + exposure: + include: '*' +spring: + application: + name: im-api + # 要在其中注册的Spring Boot Admin Server的URL。 + boot: + admin: + client: + url: http://127.0.0.1:8000 + cache: + type: redis + # Redis + redis: + host: 127.0.0.1 + port: 6379 + password: lilishop + lettuce: + pool: + # 连接池最大连接数(使用负值表示没有限制) 默认 8 + max-active: 200 + # 连接池最大阻塞等待时间(使用负值表示没有限制) 默认 -1 + max-wait: 20 + # 连接池中的最大空闲连接 默认 8 + max-idle: 10 + # 连接池中的最小空闲连接 默认 8 + min-idle: 8 + # 文件大小上传配置 + servlet: + multipart: + max-file-size: 20MB + max-request-size: 20MB + jackson: + time-zone: GMT+8 + serialization: + #关闭jackson 对json做解析 + fail-on-empty-beans: false + + shardingsphere: + datasource: + # 数据库名称,可自定义,可以为多个,以逗号隔开,每个在这里定义的库,都要在下面定义连接属性 + names: default-datasource + default-datasource: + type: com.alibaba.druid.pool.DruidDataSource + driverClassName: com.mysql.cj.jdbc.Driver + url: jdbc:mysql://127.0.0.1:3306/lilishop?useUnicode=true&characterEncoding=utf-8&useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai + username: root + password: lilishop + maxActive: 20 + initialSize: 5 + maxWait: 60000 + minIdle: 5 + timeBetweenEvictionRunsMillis: 60000 + minEvictableIdleTimeMillis: 300000 + validationQuery: SELECT 1 FROM DUAL + testWhileIdle: true + testOnBorrow: false + testOnReturn: false + #是否缓存preparedStatement,也就是PSCache。在mysql下建议关闭。 PSCache对支持游标的数据库性能提升巨大,比如说oracle。 + poolPreparedStatements: false + #要启用PSCache,-1为关闭 必须配置大于0,当大于0时,poolPreparedStatements自动触发修改为true 可以把这个数值配置大一些,比如说100 + maxOpenPreparedStatements: -1 + #配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙 + filters: stat,wall,log4j2 + #通过connectProperties属性来打开mergeSql功能;慢SQL记录 + connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000 + #合并多个DruidDataSource的监控数据 + useGlobalDataSourceStat: true + loginUsername: druid + loginPassword: druid + # sharding: + # default-data-source-name: default-datasource + # #需要拆分的表,可以设置多个 在 li_order 级别即可 + # tables: + # #需要进行分表的逻辑表名 + # li_order: + # #实际的表结点,下面代表的是li_order_为开头的所有表,如果能确定表的范围例如按月份分表,这里的写法是data2020.li_order_$->{2020..2021}_$->{01..12} 表示例如 li_order_2020_01 li_order_2020_03 li_order_2021_01 + # actual-data-nodes: data2020.li_order_$->{2019..2021}_$->{01..12} + # table-strategy: + # # 分表策略,根据创建日期 + # standard: + # sharding-column: create_time + # #分表策略 + # precise-algorithm-class-name: cn.lili.mybatis.sharding.CreateTimeShardingTableAlgorithm + # #范围查询实现 + # range-algorithm-class-name: cn.lili.mybatis.sharding.CreateTimeShardingTableAlgorithm + props: + #是否打印逻辑SQL语句和实际SQL语句,建议调试时打印,在生产环境关闭 + sql: + show: false + +# 忽略鉴权url +ignored: + urls: + - /editor-app/** + - /actuator** + - /actuator/** + - /MP_verify_qSyvBPhDsPdxvOhC.txt + - /weixin/** + - /source/** + - /manager/passport/user/login + - /manager/passport/user/refresh/** + - /manager/other/elasticsearch + - /manager/other/customWords + - /druid/** + - /swagger-ui.html + - /doc.html + - /swagger-resources/** + - /swagger/** + - /webjars/** + - /v2/api-docs + - /configuration/ui + - /boot-admin + - /**/*.js + - /**/*.css + - /**/*.png + - /**/*.ico + +# Swagger界面内容配置 +swagger: + title: lili API接口文档 + description: lili Api Documentation + version: 1.0.0 + termsOfServiceUrl: https://pickmall.cn + contact: + name: lili + url: https://pickmall.cn + email: admin@pickmall.com + +# Mybatis-plus +mybatis-plus: + mapper-locations: classpath*:mapper/*.xml + configuration: + #缓存开启 + cache-enabled: true + #日志 +# log-impl: org.apache.ibatis.logging.stdout.StdOutImpl + +# 日志 +logging: + config: classpath:logback-spring.xml + # 输出级别 + level: + cn.lili: info + # org.hibernate: debug + # org.springframework: debug + file: + # 指定路径 + path: lili-logs + logback: + rollingpolicy: + # 最大保存天数 + max-history: 7 + # 每个文件最大大小 + max-file-size: 5MB +#加密参数 +jasypt: + encryptor: + password: lili + +lili: + system: + isDemoSite: true + # 脱敏级别: + # 0:不做脱敏处理 + # 1:管理端用户手机号等信息脱敏 + # 2:商家端信息脱敏(为2时,表示管理端,商家端同时脱敏) + sensitiveLevel: 1 + statistics: + # 在线人数统计 X 小时。这里设置48,即统计过去48小时每小时在线人数 + onlineMember: 48 + # 当前在线人数刷新时间间隔,单位秒,设置为600,则每10分钟刷新一次 + currentOnlineUpdate: 600 + #qq lbs 申请 + lbs: + key: 4BYBZ-7MT6S-PUAOA-6BNWL-FJUD7-UUFXT + sk: zhNKVrJK6UPOhqIjn8AQvG37b9sz6 + #域名 + domain: + pc: https://pc.b2b2c.pickmall.cn + wap: https://m.b2b2c.pickmall.cn + store: https://store.b2b2c.pickmall.cn + admin: https://admin.b2b2c.pickmall.cn + #api地址 + api: + buyer: https://buyer-api.pickmall.cn + common: https://common-api.pickmall.cn + manager: https://admin-api.pickmall.cn + store: https://store-api.pickmall.cn + + # jwt 细节设定 + jwt-setting: + # token过期时间(分钟) + tokenExpireTime: 60 + + # 使用Spring @Cacheable注解失效时间 + cache: + # 过期时间 单位秒 永久不过期设为-1 + timeout: 1500 + #多线程配置 + thread: + corePoolSize: 5 + maxPoolSize: 50 + queueCapacity: 50 + data: + elasticsearch: + cluster-name: elasticsearch + cluster-nodes: 127.0.0.1:9200 + index: + number-of-replicas: 0 + number-of-shards: 3 + index-prefix: lili + schema: http + # account: + # username: elastic + # password: LiLiShopES + logstash: + server: 127.0.0.1:4560 + rocketmq: + promotion-topic: lili_promotion_topic + promotion-group: lili_promotion_group + msg-ext-topic: lili_msg_topic + msg-ext-group: lili_msg_group + goods-topic: lili_goods_topic + goods-group: lili_goods_group + order-topic: lili_order_topic + order-group: lili_order_group + member-topic: lili_member_topic + member-group: lili_member_group + other-topic: lili_other_topic + other-group: lili_other_group + notice-topic: lili_notice_topic + notice-group: lili_notice_group + notice-send-topic: lili_send_notice_topic + notice-send-group: lili_send_notice_group + after-sale-topic: lili_after_sale_topic + after-sale-group: lili_after_sale_group +rocketmq: + name-server: 127.0.0.1:9876 + producer: + group: lili_group + send-message-timeout: 30000 + +xxl: + job: + admin: + addresses: http://127.0.0.1:9001/xxl-job-admin + executor: + appname: xxl-job-executor-lilishop + address: + ip: + port: 8891 + logpath: ./xxl-job/executor + logretentiondays: 7 \ No newline at end of file diff --git a/im-api/src/main/resources/logback-spring.xml b/im-api/src/main/resources/logback-spring.xml new file mode 100644 index 00000000..b7c9425a --- /dev/null +++ b/im-api/src/main/resources/logback-spring.xml @@ -0,0 +1,58 @@ + + + + + + + + + + + ${APP_NAME} + + + + ${LOG_FILE_PATH}/${APP_NAME}-%d{yyyy-MM-dd}.log + 30 + + + ${FILE_LOG_PATTERN} + + + + + ${LOG_FILE_PATH}/rocketmq.log + + ${LOG_FILE_PATH}/rocketmq/rocketmq-%d{yyyy-MM-dd}.log + 30 + 30MB + + + %d{yy-MM-dd.HH:mm:ss.SSS} [%-16t] %-5p %-22c{0} %X{ServiceId} - %m%n + + + + + + + + + + + ${LOGSTASH_SERVER} + + + + UTC + + + + {"appName":"${APP_NAME}"} + + + + + + + + \ No newline at end of file diff --git a/pom.xml b/pom.xml index 839cd79b..fb8c22ca 100644 --- a/pom.xml +++ b/pom.xml @@ -71,6 +71,7 @@ common-api consumer admin + im-api