im
This commit is contained in:
parent
fc71d2d1ca
commit
49b517f1ab
@ -51,7 +51,10 @@
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-websocket</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
|
@ -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;
|
||||
|
@ -14,7 +14,8 @@ public enum UserEnums {
|
||||
MEMBER("会员"),
|
||||
STORE("商家"),
|
||||
MANAGER("管理员"),
|
||||
SYSTEM("系统");
|
||||
SYSTEM("系统"),
|
||||
SEAT("坐席");
|
||||
private final String role;
|
||||
|
||||
UserEnums(String role) {
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
@ -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<ImUser> {
|
||||
|
||||
}
|
@ -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<ImUser> {
|
||||
|
||||
/**
|
||||
* 注册用户
|
||||
*
|
||||
* @param accessToken
|
||||
* @return
|
||||
*/
|
||||
ImUser register(String accessToken);
|
||||
|
||||
}
|
@ -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<ImUserMapper, ImUser> 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;
|
||||
}
|
||||
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package cn.lili.im.config;
|
||||
package cn.lili.modules.im.config;
|
||||
|
||||
|
||||
import org.springframework.beans.BeansException;
|
@ -1,4 +1,4 @@
|
||||
package cn.lili.im.config;
|
||||
package cn.lili.modules.im.config;
|
||||
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
|
@ -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
|
@ -1,4 +1,4 @@
|
||||
package cn.lili.im.entity;
|
||||
package cn.lili.modules.im.entity.dos;
|
||||
|
||||
|
||||
import cn.lili.common.utils.SnowFlake;
|
@ -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;
|
||||
}
|
@ -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;
|
||||
|
||||
}
|
@ -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;
|
||||
|
||||
|
||||
}
|
@ -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;
|
||||
|
@ -1,4 +1,4 @@
|
||||
package cn.lili.im.entity.enums;
|
||||
package cn.lili.modules.im.entity.enums;
|
||||
|
||||
/**
|
||||
* 返回消息类型枚举
|
@ -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;
|
||||
|
||||
}
|
@ -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 {
|
||||
/**
|
||||
* 消息类型枚举
|
||||
* <p>
|
@ -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;
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package cn.lili.im.entity.enums;
|
||||
package cn.lili.modules.im.entity.enums;
|
||||
|
||||
/**
|
||||
* 操作类型枚举
|
@ -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;
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
@ -1,4 +1,4 @@
|
||||
package cn.lili.im.entity.vo;
|
||||
package cn.lili.modules.im.entity.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
@ -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;
|
||||
|
||||
|
||||
}
|
@ -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;
|
||||
|
||||
/**
|
@ -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;
|
||||
|
||||
/**
|
@ -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<QA> {
|
||||
|
||||
|
||||
}
|
@ -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<Seat> {
|
||||
|
||||
|
||||
}
|
@ -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<SeatSetting> {
|
||||
|
||||
|
||||
}
|
@ -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;
|
@ -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;
|
||||
|
||||
/**
|
@ -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<QA> {
|
||||
|
||||
/**
|
||||
* 查询店铺问题
|
||||
* @param word
|
||||
* @param pageVO
|
||||
* @return
|
||||
*/
|
||||
IPage<QA> getStoreQA(String word, PageVO pageVO);
|
||||
|
||||
}
|
@ -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<Seat> {
|
||||
|
||||
|
||||
/**
|
||||
* 获取坐席列表
|
||||
*
|
||||
* @param storeId 店铺id
|
||||
* @return
|
||||
*/
|
||||
List<SeatVO> 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);
|
||||
}
|
@ -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<SeatSetting> {
|
||||
|
||||
|
||||
/**
|
||||
* 根据店铺id获取坐席配置
|
||||
*
|
||||
* @param storeId
|
||||
* @return
|
||||
*/
|
||||
SeatSetting getSetting(String storeId);
|
||||
|
||||
/**
|
||||
* 根据店铺修改坐席设置
|
||||
*
|
||||
* @param seatSetting 坐席设置
|
||||
* @return
|
||||
*/
|
||||
SeatSetting updateByStore(SeatSetting seatSetting);
|
||||
}
|
@ -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;
|
@ -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<ImTalkMapper, ImTalk> 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<ImTalkMapper, ImTalk> 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);
|
@ -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<QAMapper, QA> implements QAService {
|
||||
|
||||
@Override
|
||||
public IPage<QA> getStoreQA(String word, PageVO pageVo) {
|
||||
LambdaQueryWrapper<QA> qaLambdaQueryWrapper = new LambdaQueryWrapper<>();
|
||||
qaLambdaQueryWrapper.eq(QA::getTenantId, UserContext.getCurrentUser().getTenantId());
|
||||
qaLambdaQueryWrapper.like(QA::getQuestion, word);
|
||||
return this.page(PageUtil.initPage(pageVo), qaLambdaQueryWrapper);
|
||||
}
|
||||
}
|
@ -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<SeatMapper, Seat> implements SeatService {
|
||||
|
||||
|
||||
@Autowired
|
||||
private SeatTokenGenerate seatTokenGenerate;
|
||||
|
||||
@Autowired
|
||||
private Cache<String> cache;
|
||||
|
||||
/**
|
||||
* 快捷登录缓存前缀
|
||||
*/
|
||||
private static String prefix = "{quick_login}_";
|
||||
|
||||
|
||||
@Override
|
||||
public List<SeatVO> seatVoList(String storeId) {
|
||||
|
||||
LambdaQueryWrapper<Seat> seatLambdaQueryWrapper = new LambdaQueryWrapper<>();
|
||||
seatLambdaQueryWrapper.eq(Seat::getTenantId, storeId);
|
||||
List<Seat> list = this.list(seatLambdaQueryWrapper);
|
||||
|
||||
//转换模型为VO
|
||||
List<SeatVO> 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<Seat> seatLambdaQueryWrapper = new LambdaQueryWrapper<>();
|
||||
seatLambdaQueryWrapper.eq(Seat::getUsername, username);
|
||||
return this.getOne(seatLambdaQueryWrapper);
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -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<SeatSettingMapper, SeatSetting> implements SeatSettingService {
|
||||
@Override
|
||||
public SeatSetting getSetting(String storeId) {
|
||||
LambdaQueryWrapper<SeatSetting> 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;
|
||||
}
|
||||
}
|
@ -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<Seat> {
|
||||
@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);
|
||||
}
|
||||
|
||||
}
|
34
im-api/pom.xml
Normal file
34
im-api/pom.xml
Normal file
@ -0,0 +1,34 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>im-api</artifactId>
|
||||
|
||||
<parent>
|
||||
<groupId>cn.lili</groupId>
|
||||
<artifactId>lili-shop-parent</artifactId>
|
||||
<version>${revision}</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>cn.lili</groupId>
|
||||
<artifactId>framework</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
|
||||
</project>
|
31
im-api/src/main/java/cn/lili/ImApiApplication.java
Normal file
31
im-api/src/main/java/cn/lili/ImApiApplication.java
Normal file
@ -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();
|
||||
}
|
||||
}
|
@ -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
|
@ -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<ImMessage> get(@PathVariable String id) {
|
||||
|
||||
ImMessage imMessage = imMessageService.getById(id);
|
||||
return new ResultUtil<ImMessage>().setData(imMessage);
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
@ApiOperation(value = "分页获取Im消息")
|
||||
public ResultMessage<List<ImMessage>> historyMessage(MessageQueryParams messageQueryParams) {
|
||||
List<ImMessage> data = imMessageService.list(messageQueryParams.initQueryWrapper());
|
||||
return new ResultUtil<List<ImMessage>>().setData(data);
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
@ApiOperation(value = "新增Im消息")
|
||||
public ResultMessage<ImMessage> save(ImMessage imMessage) {
|
||||
|
||||
if (imMessageService.save(imMessage)) {
|
||||
return new ResultUtil<ImMessage>().setData(imMessage);
|
||||
}
|
||||
return new ResultUtil<ImMessage>().setErrorMsg(ResultCode.ERROR);
|
||||
}
|
||||
|
||||
@PutMapping("/{id}")
|
||||
@ApiOperation(value = "更新Im消息")
|
||||
public ResultMessage<ImMessage> update(@PathVariable String id, ImMessage imMessage) {
|
||||
if (imMessageService.updateById(imMessage)) {
|
||||
return new ResultUtil<ImMessage>().setData(imMessage);
|
||||
}
|
||||
return new ResultUtil<ImMessage>().setErrorMsg(ResultCode.ERROR);
|
||||
}
|
||||
|
||||
@DeleteMapping(value = "/{ids}")
|
||||
@ApiOperation(value = "删除Im消息")
|
||||
public ResultMessage<Object> delAllByIds(@PathVariable List ids) {
|
||||
|
||||
imMessageService.removeByIds(ids);
|
||||
return ResultUtil.success(ResultCode.SUCCESS);
|
||||
}
|
||||
|
||||
|
||||
@GetMapping(value = "/newMessage")
|
||||
@ApiOperation(value = "删除Im消息")
|
||||
public ResultMessage<Boolean> hasNewMessage(String accessToken) {
|
||||
|
||||
return ResultUtil.data(imMessageService.hasNewMessage(accessToken));
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -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<ImTalk> get(@PathVariable String id) {
|
||||
|
||||
ImTalk imTalk = imTalkService.getById(id);
|
||||
return new ResultUtil<ImTalk>().setData(imTalk);
|
||||
}
|
||||
|
||||
@GetMapping(value = "/user/{uid}")
|
||||
@ApiOperation(value = "查看与某人聊天详情")
|
||||
public ResultMessage<ImTalk> 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<List<ImTalkVO>> getByPage() {
|
||||
AuthUser authUser = UserContext.getCurrentUser();
|
||||
LambdaQueryWrapper<ImTalk> queryWrapper = new LambdaQueryWrapper<>();
|
||||
queryWrapper.eq(ImTalk::getUserId1, authUser.getId()).or().eq(ImTalk::getUserId2, authUser.getId());
|
||||
List<ImTalk> imTalks = imTalkService.list(queryWrapper);
|
||||
|
||||
List<ImTalkVO> 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<List<ImTalkVO>> getStoreTalkList() {
|
||||
AuthUser authUser = UserContext.getCurrentUser();
|
||||
LambdaQueryWrapper<ImTalk> queryWrapper = new LambdaQueryWrapper<>();
|
||||
queryWrapper.eq(ImTalk::getUserId1, authUser.getStoreId()).or().eq(ImTalk::getUserId2, authUser.getStoreId());
|
||||
List<ImTalk> imTalks = imTalkService.list(queryWrapper);
|
||||
|
||||
List<ImTalkVO> 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<Object> disable(@PathVariable String id) {
|
||||
imTalkService.disable(id);
|
||||
return ResultUtil.success(ResultCode.SUCCESS);
|
||||
}
|
||||
}
|
@ -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<Member> getImUser() {
|
||||
AuthUser authUser = UserContext.getCurrentUser();
|
||||
return ResultUtil.data(memberService.getById(authUser.getId()));
|
||||
}
|
||||
|
||||
@GetMapping("/store")
|
||||
@ApiOperation(value = "获取用户信息")
|
||||
public ResultMessage<Store> getStoreUser() {
|
||||
AuthUser authUser = UserContext.getCurrentUser();
|
||||
return ResultUtil.data(storeService.getById(authUser.getStoreId()));
|
||||
}
|
||||
|
||||
}
|
@ -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<QA> addCustomWords(@Valid QA qa) {
|
||||
qaService.save(qa);
|
||||
return ResultUtil.data(qa);
|
||||
}
|
||||
|
||||
@ApiOperation(value = "修改自定义问答")
|
||||
@PutMapping
|
||||
public ResultMessage<QA> updateCustomWords(@Valid QA qa) {
|
||||
qaService.updateById(qa);
|
||||
return ResultUtil.data(qa);
|
||||
}
|
||||
|
||||
@ApiOperation(value = "删除自定义分词")
|
||||
@DeleteMapping("/{id}")
|
||||
public ResultMessage<String> 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<IPage<QA>> getCustomWords(@RequestParam String word, PageVO pageVo) {
|
||||
return ResultUtil.data(qaService.getStoreQA(word, pageVo));
|
||||
}
|
||||
|
||||
}
|
59
im-api/src/main/java/cn/lili/controller/im/SeatLogin.java
Normal file
59
im-api/src/main/java/cn/lili/controller/im/SeatLogin.java
Normal file
@ -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<Object> userLogin(String username, String password) {
|
||||
return ResultUtil.data(this.seatService.usernameLogin(username, password));
|
||||
}
|
||||
|
||||
@ApiOperation(value = "商家快捷登录客服")
|
||||
@PostMapping("/quicklogin")
|
||||
public ResultMessage<Object> quickLogin(String code) {
|
||||
return ResultUtil.data(this.seatService.quickLogin(code));
|
||||
}
|
||||
|
||||
|
||||
@ApiOperation(value = "登出")
|
||||
@PostMapping("/logout")
|
||||
public ResultMessage<Object> logout() {
|
||||
//todo
|
||||
// UserContext.getCurrentUser().getId()
|
||||
// verificationServiceClient.check(uuid);
|
||||
return ResultUtil.success();
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -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<SeatSetting> 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);
|
||||
}
|
||||
}
|
@ -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<List<SeatVO>> getSeats() {
|
||||
return ResultUtil.data(seatService.seatVoList(UserContext.getCurrentUser().getTenantId()));
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -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<List<SeatVO>> getSeats(String storeId) {
|
||||
return ResultUtil.data(seatService.seatVoList(storeId));
|
||||
}
|
||||
|
||||
}
|
172
im-api/src/main/java/cn/lili/controller/im/WebSocketServer.java
Normal file
172
im-api/src/main/java/cn/lili/controller/im/WebSocketServer.java
Normal file
@ -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<String, Session> 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;
|
||||
}
|
||||
|
||||
}
|
@ -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<HttpSecurity>.ExpressionInterceptUrlRegistry registry = http
|
||||
.authorizeRequests();
|
||||
registry
|
||||
.and()
|
||||
//禁止网页iframe
|
||||
.headers().frameOptions().disable()
|
||||
.and()
|
||||
.authorizeRequests()
|
||||
//任何请求
|
||||
.anyRequest()
|
||||
//需要身份认证
|
||||
.permitAll()
|
||||
.and()
|
||||
//允许跨域
|
||||
.cors().configurationSource(corsConfigurationSource).and()
|
||||
//关闭跨站请求防护
|
||||
.csrf().disable();
|
||||
}
|
||||
|
||||
}
|
275
im-api/src/main/resources/application.yml
Normal file
275
im-api/src/main/resources/application.yml
Normal file
@ -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
|
58
im-api/src/main/resources/logback-spring.xml
Normal file
58
im-api/src/main/resources/logback-spring.xml
Normal file
@ -0,0 +1,58 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE configuration>
|
||||
<configuration>
|
||||
<include resource="org/springframework/boot/logging/logback/defaults.xml"/>
|
||||
<include resource="org/springframework/boot/logging/logback/console-appender.xml"/>
|
||||
<!--应用名称-->
|
||||
<springProperty scope="context" name="APP_NAME" source="spring.application.name"/>
|
||||
<!--日志文件保存路径-->
|
||||
<springProperty scope="context" name="LOG_FILE_PATH" source="logging.file.path"/>
|
||||
<springProperty scope="context" name="LOGSTASH_SERVER" source="lili.data.logstash.server"/>
|
||||
<contextName>${APP_NAME}</contextName>
|
||||
|
||||
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||
<fileNamePattern>${LOG_FILE_PATH}/${APP_NAME}-%d{yyyy-MM-dd}.log</fileNamePattern>
|
||||
<maxHistory>30</maxHistory>
|
||||
</rollingPolicy>
|
||||
<encoder>
|
||||
<pattern>${FILE_LOG_PATTERN}</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<appender name="RocketmqClientAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>${LOG_FILE_PATH}/rocketmq.log</file>
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||
<fileNamePattern>${LOG_FILE_PATH}/rocketmq/rocketmq-%d{yyyy-MM-dd}.log</fileNamePattern>
|
||||
<maxHistory>30</maxHistory>
|
||||
<totalSizeCap>30MB</totalSizeCap>
|
||||
</rollingPolicy>
|
||||
<encoder>
|
||||
<pattern>%d{yy-MM-dd.HH:mm:ss.SSS} [%-16t] %-5p %-22c{0} %X{ServiceId} - %m%n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
<logger name="RocketmqClient" additivity="false">
|
||||
<level value="info" />
|
||||
<appender-ref ref="RocketmqClientAppender"/>
|
||||
</logger>
|
||||
|
||||
<!--输出到elk的LOGSTASH-->
|
||||
<appender name="LOGSTASH" class="net.logstash.logback.appender.LogstashTcpSocketAppender">
|
||||
<!-- 配置elk日志收集 配饰的是 LOGSTASH 的地址-->
|
||||
<destination>${LOGSTASH_SERVER}</destination>
|
||||
<encoder charset="UTF-8" class="net.logstash.logback.encoder.LogstashEncoder">
|
||||
<providers>
|
||||
<timestamp>
|
||||
<timeZone>UTC</timeZone>
|
||||
</timestamp>
|
||||
</providers>
|
||||
<!--自定义字段 区分项目-->
|
||||
<customFields>{"appName":"${APP_NAME}"}</customFields>
|
||||
</encoder>
|
||||
</appender>
|
||||
<root level="INFO">
|
||||
<appender-ref ref="CONSOLE"/>
|
||||
<appender-ref ref="FILE"/>
|
||||
<appender-ref ref="LOGSTASH"/>
|
||||
</root>
|
||||
</configuration>
|
Loading…
x
Reference in New Issue
Block a user