websocket

参考案例

概念

websocket是全双工通道,建立连接后可以双向发送消息。

Tomcat 7.0.5之后开始支持websocket,并实现了websocket规范。Java websocket应用由一系列WebSocketEndpoint组成。一个Endpoint是一个Java对象,代表WebSocket链接的一段端,对于服务端,可以视为处理WebSocket消息的接口,就像servlet处理http一样。(注:建立一个websocket链接就会新建一个Endpoint对象)

有两种方式定义Endpointt:
1、继承javax.websocket.Endpoint类并实现其方法。
2、定义POJO 并添加@ServerEndpoint注解

数据传输

服务端接受数据

通过Session(和http中的session不同)添加MessageHandler消息处理器来接受消息,当采用注解方式定义Endpoint时,通过@OnMessage注解指定接受消息的方法。

服务端推送数据

发送消息是由RemoteEndpoint完成,其实例由Session维护,根据使用情况,我们可以通过Session.getBasicRemote获取同步消息发送实例,然后调用sendXxx()方法可以发送消息,可以通过Session.getAsyncRemote获取异步消息发送实例。

后端实现

继承Endpoint 实现方式

onOpen方法:建立链接之后自动调用
onClose方法:链接关闭自动调用
onError方法:链接中出现问题自动调用

注解@ServerEndpoint 实现方式(主要)

@OnClose
@OnOpen
@OnError

示例代码

@ServerEndpoint("/robin")//后面是资源路径
public class ChatEndPoint{
	private static Set<ChatEndPoint> webSocketSet = new HashSet<>();

	private Session session;
	
	@OnMessage
	public void onMessage(String message,Session session)throws IOException{
		//message 是接受到的客户端发送来的消息;session
		System.out.println("get message"+message);
		System.out.println(session);
		//将消息发给其他用户
		for(ChatEndPoint chat:webSocketSet){
			if(chat!=this){
				chat.session.getBasicRemote().setText(message);
			}
		}
	}
	
	@OnOpen
	public void onOpen(Session session){
		this.session = session;
		webSocketSet.add(this);
	}
	
	@OnClose
	public void onClose(Session session){
		
	}

	@OnError
	public void onError(Session session,Throwable error){
		
	}
}

基于websocket实现聊天室(后端代码)

依赖

webSocket依赖

<dependency>
	<groupId>org.springframework.bootgroupId>
    <artifactId>spring-boot-starter-websocketartifactId>
dependency>

公共资源

Message类,客户端to服务端

@Data
public class Message{
	private String toName;
	private String message;
}

ResultMessage,服务端to客户端

@Data
public class ResultMessage{
	private boolean isSystem;
	private String fromName;
	private Object message;//如果是系统消息则是数组
}

MessageUtils,消息工具类

public class MessageUtils {
    public static String getMessage(boolean isSystemMessage,String fromName,Object message){
        try {
            ResultMessage result = new ResultMessage();
            result.setSystem(isSystemMessage);
            result.setMessage(message);
            if (fromName!=null){
                result.setFromName(fromName);
            }
            //把字符串转成json格式的字符串
            ObjectMapper mapper = new ObjectMapper();
            return mapper.writeValueAsString(result);
        }catch (JsonProcessingException e){
            e.printStackTrace();
        }
        return null;
    }
}

用户登录

@RestController
public class LoginController {
    @RequestMapping("/toLogin")
    public Result tologin(@RequestParam("user") String user,@RequestParam("pwd") String pwd, HttpSession session){
        Result result = new Result();
        if (user.equals("张三")&&pwd.equals("123")){
            result.setFlag(true);
            session.setAttribute("user",user);
        }else if (user.equals("李四")&&pwd.equals("123")){
            result.setFlag(true);
            session.setAttribute("user",user);
        }else if (user.equals("123")&&pwd.equals("123")){
            result.setFlag(true);
            session.setAttribute("user",user);
        }
        else if (user.equals("王五")&&pwd.equals("123")){
            result.setFlag(true);
            session.setAttribute("user",user);
        }else {
            result.setFlag(false);
            result.setMessage("登录失败");
        }
        return result;
    }

    @RequestMapping("/getUsername")
    public String getUsername(HttpSession session){
        String username = (String) session.getAttribute("user");
        return username;
    }
}

Endpoint

@ServerEndpoint(value = "/chat",configurator = GetHttpSessionConfigurator.class)//注意这里
@Component
public class ChatEndpoint {

    //用来存储每个用户客户端对象的ChatEndpoint对象
    private static Map<String,ChatEndpoint> onlineUsers = new ConcurrentHashMap<>();

    //声明session对象,通过对象可以发送消息给指定的用户
    private Session session;

    //声明HttpSession对象,我们之前在HttpSession对象中存储了用户名
    private HttpSession httpSession;

    //连接建立
    @OnOpen
    public void onOpen(Session session, EndpointConfig config){
        this.session = session;
        HttpSession httpSession = (HttpSession) config.getUserProperties().get(HttpSession.class.getName());
        this.httpSession = httpSession;
        //存储登陆的对象
        String username = (String)httpSession.getAttribute("user");
        onlineUsers.put(username,this);

        //将当前在线用户的用户名推送给所有的客户端
        //1 获取消息
        String message = MessageUtils.getMessage(true, null, getNames());
        //2 调用方法进行系统消息的推送
        broadcastAllUsers(message);
    }

    private void broadcastAllUsers(String message){
        try {
            //将消息推送给所有的客户端
            Set<String> names = onlineUsers.keySet();
            for (String name : names) {
                ChatEndpoint chatEndpoint = onlineUsers.get(name);
                chatEndpoint.session.getBasicRemote().sendText(message);
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    //返回在线用户名
    private Set<String> getNames(){
        return onlineUsers.keySet();
    }

    //收到消息
    @OnMessage
    public void onMessage(String message,Session session){
        //将数据转换成对象
        try {
            ObjectMapper mapper =new ObjectMapper();
            Message mess = mapper.readValue(message, Message.class);
            String toName = mess.getToName();
            String data = mess.getMessage();
            String username = (String) httpSession.getAttribute("user");
            String resultMessage = MessageUtils.getMessage(false, username, data);
            //发送数据
            onlineUsers.get(toName).session.getBasicRemote().sendText(resultMessage);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
    //关闭
    @OnClose
    public void onClose(Session session) {
        String username = (String) httpSession.getAttribute("user");
        //从容器中删除指定的用户
        onlineUsers.remove(username);
        MessageUtils.getMessage(true,null,getNames());
    }
}

配置类

需要加了配置类 Spring才会管理。

@Configuration
public class WebSocketConfig {
    @Bean
    //注入ServerEndpointExporter bean对象,自动注册使用注解@ServerEndpoint的bean
    public ServerEndpointExporter serverEndpointExporter(){
        return new ServerEndpointExporter();
    }
}

其他

获取HttpSession的类

public class GetHttpSessionConfigurator extends ServerEndpointConfig.Configurator {
    @Override
    public void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response) {
        //获取HttpSession对象
        HttpSession httpSession = (HttpSession) request.getHttpSession();
        sec.getUserProperties().put(HttpSession.class.getName(),httpSession);
    }
}

你可能感兴趣的:(Java,前端,websocket)