怎么样整合Struts2框架和Java EE7 WebSocket API实现消息推送

J2EE 码拜 8年前 (2016-03-19) 1299次浏览
本人自定义一个Action,并且该Action也是WS连接的服务器端点,这个Action需要怎么写呢?ServletActionContext.getContext()和ServletActionContext.getRequest()都是null,怎么回事呢?不在框架里使用,一切正常啊!
源码如下:

<constant name="struts.action.excludePattern" value="/_wsHandler"></constant>
package cn.edu.cqupt.sims.web.action;
import java.io.IOException;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.atomic.AtomicInteger;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
import org.apache.struts2.ServletActionContext;
import org.springframework.web.socket.server.standard.SpringConfigurator;
import cn.edu.cqupt.sims.domain.Admin;
import cn.edu.cqupt.sims.domain.Application4Leave;
import cn.edu.cqupt.sims.domain.Student;
@ServerEndpoint( value="/_wsHandler", configurator = SpringConfigurator.class)
public class WebSocketHandler {
	private static final AtomicInteger conNum = new AtomicInteger(0);
    private static final Set<Student> connections = new CopyOnWriteArraySet<Student>();
    private static final ConcurrentMap<String,String> map = new ConcurrentHashMap<String,String>();
    private Session session;
    
    public WebSocketHandler() {
    }
    @OnOpen
    public void start(Session session) {
        this.session = session;
        System.out.println(ServletActionContext.getContext());      //null
        System.out.println(ServletActionContext.getRequest());     //null
        /*
         * 麻痹的,是什么原因导致ServletActionContext.getContext()为null的?
         * 
         */
    	Map<String,Object> appSession = ServletActionContext.getContext().getSession();
    	  
    	Student student= (Student) appSession.get("stuloginer");
    	Admin admin= (Admin) appSession.get("admloginer");
    	if(student != null){
        	String username=student.getUsername();
            String session_id=session.getId();
            connections.add(student);
            map.put(username, session_id);
            String message = String.format("%s %s", username, "has joined !");
            System.out.println(message+" session_id = "+session_id+" current online clients : "+conNum.get());
            broadcast(message);
    	}
    
    	if(admin != null){
            String username=admin.getUsername();
            String message = String.format("%s %s", username, "has joined !");
            System.out.println(message+" current online clients : "+conNum.get());
    	}
    
    }
    //此时不能用注解修饰该方法啊:@onClose,原因是参数是人为传进去的,
    //假如注解了该方法将会自动调用,参数就为null喽。
    public void end(Student student) {
    	/*
    	 * 其实当某一学生客户端离开系统时,就要将其从connnections中删除,但是这一点并不轻松;
    	 * 本人是这样做的?当学生离开系统时就会触发onclose()方法,于是在该方法内发送该学生的名字啊,
    	 * 服务器端incoming()接收消息并调用end()
    	 */
    	if(student == null){
    		return;
    	}
        connections.remove(student);
        
        String message = String.format("%s %s", student.getUsername(), "has disconnected !");
        System.out.println(message+" current online clients : "+conNum.get());
        broadcast(message);
    }
    @OnMessage
    public void incoming(String message) {	//message:您有新消息
        
    	if(message.equals("您有新消息")){
            // 对谁审批就将消息发送给谁
            Application4Leave r4l = (Application4Leave)ServletActionContext.getRequest().getSession().getAttribute("ws_send_to");
            String nickName = r4l.getUsername();   
            System.out.println(message);
            broadcast2SB(nickName,message);
    	}
        
        if(! message.equals("您有新消息"))
        	Iterator<Student> it=connections.iterator();
        	while(it.hasNext()){
        		Student student=it.next();
        		if(student.getUsername().equals(message)){
        			System.out.println(message);
        			end(student);
        		}
        	}
        }
    }
    @OnError
    public void onError(Throwable t) throws Throwable {
        System.out.println("Chat Error: \n" + t.getCause());
    }
    
    // 向全部客户端推动消息
    private  void broadcast(String msg) {
        for (Student client : connections) {
            try {
                synchronized (client) {
                	System.out.println(this.session.isOpen());		//true or false
                	this.session.getBasicRemote().sendText(msg);
                }
            } catch (IOException e) {
                System.out.println("Chat Error: Failed to send message to client: \n"+e.getMessage());
                connections.remove(client);
                try {
                    this.session.close();
                } catch (IOException e1) {
                    e.printStackTrace();
                }
                String message = String.format("%s %s", client.getUsername(), "has been disconnected.");
                broadcast(message);
            }
        }
    }
    
    // 精确地向某一客户端发送消息
    // 首先要知道该客户端的登录名,我们根据登录名来精确定位发送······
    public  void broadcast2SB(String nickName,String msg){
    	for(Student client : connections){
    		synchronized(client){
    			if(client.getUsername().equals(nickName)){
    				try{
    					this.session.getBasicRemote().sendText(msg);
    				}catch(IOException e2){
    					e2.printStackTrace();
    				}
    			}
    		}
    	}
    }
    
    public String execute(){
    	return "none";
    }
}
解决方案

40


CodeBye 版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权 , 转载请注明怎么样整合Struts2框架和Java EE7 WebSocket API实现消息推送
喜欢 (0)
[1034331897@qq.com]
分享 (0)