首先准备环境:SpringMVC4.0、WebSocket、Tomcat7.0,具体配置就不说了,网上有。
目的:在控制层(Controller)实现springmvc和websocket的统一接口映射,即websocket访问后台也可以像springmvc访问Controller方法一样
实现原理:定义一个主要的websocket处理类,在这个websocket的基础下进行接口分发和参数映射。
具体方法:
1.通过字符串或JSON(方便映射前端的js对象)来传递访问的路径,也就是调用Controller的某个方法。RequestMappingHandlerMapping对象持有Controller的所有配置接口和方法信息,遍历接口信息,匹配到前端的访问路径就可以进行调用了。
2.参数映射有很多方案,最简单的统一用Map传参,Controller的接口也支持,这样就实现了接口的通用。
下面是主要的websocket消息处理类
@SuppressWarnings("unchecked")
public class MainHandler extends TextWebSocketHandler{
@Autowired
private RequestMappingHandlerMapping requestMappingHandlerMapping;
@Override
public void handleTextMessage(WebSocketSession session,
TextMessage message) throws Exception {
// TODO Auto-generated method stub
String msg = message.getPayload();
Map<RequestMappingInfo, HandlerMethod> map = requestMappingHandlerMapping.getHandlerMethods();
Object result = null;
String url = msg;
Map<String, Object> parameter = new HashMap<String, Object>();
Pattern pattern = Pattern.compile("^\\{(\"\\w+\":\\S+,{0,1})+\\}$");
if(pattern.matcher(msg).matches()){
JSONObject json = JSONObject.fromObject(message.getPayload());
if(json.get("url") != null){
url = String.valueOf(json.get("url"));
if(json.get("params") != null){
parameter = (Map<String, Object>) json.get("params");
}
}
}
for (Map.Entry<RequestMappingInfo, HandlerMethod> m : map.entrySet()) {
RequestMappingInfo info = m.getKey();
HandlerMethod method = m.getValue();
PatternsRequestCondition p = info.getPatternsCondition();
if(p.getPatterns().size() > 0 && p.getPatterns().toArray()[0].equals(url)){
String url_pt = String.valueOf(p.getPatterns().toArray()[0]);
String methodName = url_pt.substring(url_pt.lastIndexOf('/')+1);
Class<?> cls = method.getMethod().getDeclaringClass();
Object controller = cls.newInstance();
boolean success = true;
try{
result = cls.getDeclaredMethod(methodName, Map.class).invoke(controller, parameter);
}catch(Exception e){
success = false;
}
if(!success){
try{
result = cls.getDeclaredMethod(methodName).invoke(controller);
}catch(Exception e){
success = false;
}
}
if(!success) result = "未找到指定方法或方法参数不匹配";
break;
}
}
if(result != null){
session.sendMessage(new TextMessage(String.valueOf(result).getBytes()));
}
}
}
前端发送:
WSClient.fn.pushMsgEvent = function(msgEvent){
if(typeof msgEvent == "function") this.msgPool.push(_opts.msgEvent);
return this.msgPool;
}
1.一般来说,SpringMVC和WebSocket的接口整合是在service层,SpringMVC的Controller层通常不做任何业务处理或少量处理,只负责提供接口。个人实现这套方案只是想通过注解的形式来定义WebSocket的接口,顺便通用一下
2.如果Controller的接口参数不想用Map,则可以重载一个参数为Map的函数,如下:
@RequestMapping("/test")
public @ResponseBody List test(HttpServletRequest request){
return test(request.getParameterMap());
}
public @ResponseBody List test(Map map){
System.out.println(map);
List<String> tmp = new ArrayList<String>();
tmp.add("1222");
tmp.add("2333");
return tmp;
}
3.后续补充...