首先准备环境: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.后续补充...
|