前段时间接到一个需求,给在线的APP写一个在线客服系统,还不让使用第三方。研究了java的websocket。将客服和客户都放在一个聊天室,用标识给相关聊天推送聊天内容。先贴代码
package com.pengbao.web.chat;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import javax.servlet.http.HttpServletRequest;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import com.pengbao.common.Constants;
import com.pengbao.common.ResponseData;
import com.pengbao.config.SpringApplicationContext;
import com.pengbao.enums.ConnetType;
import com.pengbao.enums.WebStatus;
import com.pengbao.model.AccountsAdmins;
import com.pengbao.model.AccountsUsers;
import com.pengbao.model.WebSocketMessage;
import com.pengbao.service.inteface.AccountsAdminsService;
import com.pengbao.service.inteface.AccountsUsersService;
import com.pengbao.service.inteface.WebSocketMessageService;
import com.pengbao.util.DateUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import com.alibaba.fastjson.JSON;
/**
* Created by lzg on 2017/10/18.
*
* @ServerEndpoint 注解是一个类层次的注解,它的功能主要是将目前的类定义成一个websocket服务器端
* 注解的值将被用于监听用户连接的终端访问URL地址,客户端可以通过这个URL来连接到WebSocket服务器端
*/
@Controller//这里是给非websocket接口注解的Controller
@ServerEndpoint(value = "/websocket/{type}/{userName}")//这里是websocket接口
@Component
public class WebSocketController {
private static Logger logger = LoggerFactory.getLogger(WebSocketController.class);
// 静态变量,用来记录当前链接数
private static long maxSize = 10000000;//传输图片的最大值
private static int onlineCount = 0;//当前客户在线人数
private int type = 0;// 0表示客服,1表示用户
private String userName = "";
private String userId = "";
ApplicationContext act = SpringApplicationContext.applicationContext();//由于加了ServerEndpoint注解,service层不能直接注入,需要通过这个注入service
AccountsAdminsService accountsAdminsService = act.getBean(AccountsAdminsService.class);
AccountsUsersService accountsUsersService = act.getBean(AccountsUsersService.class);
WebSocketMessageService webSocketMessageService = act.getBean(WebSocketMessageService.class);
//chatMap用于记录客服对应的客户,以便于相关操作
private static Map<String, List<String>> chatMap = new HashMap<>();
//客户保存列表
private static Map<String, WebSocketController> userSocketMap = new HashMap<>();
//客服保存列表
private static Map<String, WebSocketController> serviceSocketMap = new HashMap<>();
// 与某个客户端的链接会话,需要通过他来给客户端发送消息
private Session session;
// 加载内部类 解决Sping线程无法注入业务逻辑层
/**
* 连接建立成功调用的方法
*
* @param session 可选的参数。session为与某个客户端的连接会话,需要通过它来给客户端发送数据
*/
@OnOpen
public void onOpen(@PathParam("type") String type, @PathParam("userName") String userName, Session session) {
this.session = session;
if (type.equals("0")) {//客服连接,此时的userName是客服唯一标识,我用的是客服Id,所以赋值给userId
this.userId = userName;
AccountsAdmins admin = accountsAdminsService.selectByAdminId(this.userId);
if (admin != null) {
serviceSocketMap.put(userName, this);
Map<String, Object> map = new HashMap<>();