├── README.md ├── pom.xml └── src ├── main ├── java │ └── cn │ │ └── blingfeng │ │ └── websocket │ │ ├── WebsocketApplication.java │ │ ├── config │ │ └── WebSocketConfig.java │ │ ├── controller │ │ ├── ChatController.java │ │ └── WebSocketServer.java │ │ ├── pojo │ │ ├── ChatResult.java │ │ ├── Client2ServerMessage.java │ │ ├── Server2ClientMessage.java │ │ └── WxLoginResult.java │ │ └── utils │ │ ├── FastJsonUtils.java │ │ └── HttpRequestUtil.java └── resources │ ├── application.yml │ └── templates │ └── webSocket.html └── test └── java └── cn └── blingfeng └── websocket └── WebsocketApplicationTests.java /README.md: -------------------------------------------------------------------------------- 1 | 微信小程序匿名聊天后端demo 2 | 小程序连接:https://github.com/itblingfeng/wx-chat 3 | 4 | springboot+websocket的简单整合 -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | cn.blingfeng 7 | chat 8 | 0.0.1-SNAPSHOT 9 | jar 10 | 11 | chat 12 | Demo project for Spring Boot 13 | 14 | 15 | org.springframework.boot 16 | spring-boot-starter-parent 17 | 2.0.0.RELEASE 18 | 19 | 20 | 21 | 22 | UTF-8 23 | UTF-8 24 | 1.8 25 | 26 | 27 | 28 | 29 | org.springframework.boot 30 | spring-boot-starter-web 31 | 32 | 33 | 34 | org.springframework.boot 35 | spring-boot-starter-test 36 | test 37 | 38 | 39 | org.java-websocket 40 | Java-WebSocket 41 | 1.3.0 42 | 43 | 44 | 45 | org.springframework.boot 46 | spring-boot-starter-websocket 47 | 48 | 49 | 50 | 51 | com.alibaba 52 | fastjson 53 | 1.2.15 54 | 55 | 56 | 57 | org.apache.httpcomponents 58 | httpclient 59 | 4.5.3 60 | 61 | 62 | 63 | 64 | org.apache.httpcomponents 65 | httpcore 66 | 4.4.8 67 | 68 | 69 | 70 | 71 | 72 | 73 | org.springframework.boot 74 | spring-boot-maven-plugin 75 | 76 | 77 | 78 | 79 | 80 | -------------------------------------------------------------------------------- /src/main/java/cn/blingfeng/websocket/WebsocketApplication.java: -------------------------------------------------------------------------------- 1 | package cn.blingfeng.websocket; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class WebsocketApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(WebsocketApplication.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/cn/blingfeng/websocket/config/WebSocketConfig.java: -------------------------------------------------------------------------------- 1 | package cn.blingfeng.websocket.config; 2 | 3 | import org.springframework.context.annotation.Bean; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.web.socket.server.standard.ServerEndpointExporter; 6 | 7 | @Configuration 8 | public class WebSocketConfig { 9 | @Bean 10 | public ServerEndpointExporter serverEndpointExporter(){ 11 | return new ServerEndpointExporter(); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/cn/blingfeng/websocket/controller/ChatController.java: -------------------------------------------------------------------------------- 1 | package cn.blingfeng.websocket.controller; 2 | 3 | import cn.blingfeng.websocket.pojo.ChatResult; 4 | import cn.blingfeng.websocket.pojo.WxLoginResult; 5 | import cn.blingfeng.websocket.utils.FastJsonUtils; 6 | import cn.blingfeng.websocket.utils.HttpRequestUtil; 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | import org.springframework.util.StringUtils; 10 | import org.springframework.web.bind.annotation.*; 11 | 12 | import java.io.IOException; 13 | import java.util.Queue; 14 | import java.util.Random; 15 | 16 | @RestController 17 | @RequestMapping("chat") 18 | public class ChatController { 19 | 20 | private Integer count; 21 | private String SECRET = ""; 22 | private String APPID = ""; 23 | private String JS_CODE; 24 | @RequestMapping(value = "/random",method = RequestMethod.POST) 25 | public ChatResult randomChat(){ 26 | 27 | //用户随机分配聊天室 28 | Random random = new Random(); 29 | int i = random.nextInt(3); 30 | return new ChatResult(100,"分配成功",i); 31 | 32 | } 33 | @PostMapping("/login/{code}") 34 | public ChatResult auth(@PathVariable("code")String code){ 35 | WxLoginResult wxLoginResult = null; 36 | JS_CODE = code; 37 | String msg; 38 | String loginValidURL = "https://api.weixin.qq.com/sns/jscode2session?appid="+APPID+"&secret="+SECRET+"&js_code="+JS_CODE+"&grant_type=authorization_code"; 39 | try { 40 | wxLoginResult = FastJsonUtils.toBean(HttpRequestUtil.get(loginValidURL), WxLoginResult.class); 41 | } catch (IOException e) { 42 | e.printStackTrace(); 43 | } 44 | System.out.println(wxLoginResult.getOpenid()); 45 | return new ChatResult(200,"success",null); 46 | } 47 | 48 | 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/cn/blingfeng/websocket/controller/WebSocketServer.java: -------------------------------------------------------------------------------- 1 | package cn.blingfeng.websocket.controller; 2 | 3 | import cn.blingfeng.websocket.pojo.Server2ClientMessage; 4 | import cn.blingfeng.websocket.utils.FastJsonUtils; 5 | import org.springframework.stereotype.Component; 6 | 7 | import javax.websocket.*; 8 | import javax.websocket.server.PathParam; 9 | import javax.websocket.server.ServerEndpoint; 10 | import java.io.IOException; 11 | import java.util.Date; 12 | import java.util.Map; 13 | import java.util.concurrent.CopyOnWriteArraySet; 14 | 15 | @ServerEndpoint("/websocket/{id}/{to}") 16 | @Component 17 | public class WebSocketServer { 18 | private static int onlineCount = 0; 19 | private static CopyOnWriteArraySet webSocketSet = 20 | new CopyOnWriteArraySet(); 21 | private Session session; 22 | public String id; 23 | public String to; 24 | @OnOpen 25 | public void onOpen(Session session, 26 | @PathParam("id") String id, 27 | @PathParam("to")String to) throws IOException { 28 | this.session = session; 29 | this.id = id; 30 | this.to = to; 31 | webSocketSet.add(this); 32 | onlineAdd(); 33 | 34 | } 35 | @OnMessage 36 | public void onMessage(String message,Session session) throws IOException { 37 | webSocketSet.stream() 38 | .filter(e->e.to.equals(this.to)&&e!=this) 39 | .forEach(e-> { 40 | try { 41 | e.session.getBasicRemote() 42 | .sendText(FastJsonUtils 43 | .toJSONString(new Server2ClientMessage(message,new Date(),1))); 44 | } catch (IOException e1) { 45 | e1.printStackTrace(); 46 | } 47 | }); 48 | 49 | } 50 | @OnClose 51 | public void close(){ 52 | webSocketSet.remove(this); 53 | onlineSub(); 54 | } 55 | 56 | public synchronized void onlineAdd(){ 57 | onlineCount++; 58 | } 59 | public synchronized void onlineSub(){ 60 | onlineCount--; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/cn/blingfeng/websocket/pojo/ChatResult.java: -------------------------------------------------------------------------------- 1 | package cn.blingfeng.websocket.pojo; 2 | 3 | public class ChatResult { 4 | private Integer code; 5 | 6 | private String message; 7 | 8 | private Object data; 9 | 10 | public ChatResult(Integer code,String message,Object data){ 11 | this.code = code; 12 | this.message = message; 13 | this.data = data; 14 | } 15 | public Integer getCode() { 16 | return code; 17 | } 18 | 19 | public void setCode(Integer code) { 20 | this.code = code; 21 | } 22 | 23 | public String getMessage() { 24 | return message; 25 | } 26 | 27 | public void setMessage(String message) { 28 | this.message = message; 29 | } 30 | 31 | public Object getData() { 32 | return data; 33 | } 34 | 35 | public void setData(Object data) { 36 | this.data = data; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/cn/blingfeng/websocket/pojo/Client2ServerMessage.java: -------------------------------------------------------------------------------- 1 | package cn.blingfeng.websocket.pojo; 2 | 3 | import java.util.Date; 4 | 5 | public class Client2ServerMessage { 6 | private String message; 7 | 8 | private Date sendDate; 9 | 10 | private Integer type; 11 | 12 | public String getMessage() { 13 | return message; 14 | } 15 | 16 | public void setMessage(String message) { 17 | this.message = message; 18 | } 19 | 20 | public Date getSendDate() { 21 | return sendDate; 22 | } 23 | 24 | public void setSendDate(Date sendDate) { 25 | this.sendDate = sendDate; 26 | } 27 | 28 | public Integer getType() { 29 | return type; 30 | } 31 | 32 | public void setType(Integer type) { 33 | this.type = type; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/cn/blingfeng/websocket/pojo/Server2ClientMessage.java: -------------------------------------------------------------------------------- 1 | package cn.blingfeng.websocket.pojo; 2 | 3 | import java.text.SimpleDateFormat; 4 | import java.util.Date; 5 | 6 | public class Server2ClientMessage { 7 | private static SimpleDateFormat time=new SimpleDateFormat("HH:mm:ss"); 8 | public Server2ClientMessage(String message,Date date,Integer type){ 9 | this.message = message; 10 | this.date = date; 11 | this.type = type; 12 | } 13 | private String message; 14 | 15 | private Date date; 16 | 17 | private Integer type; 18 | 19 | public String getMessage() { 20 | return message; 21 | } 22 | 23 | public void setMessage(String message) { 24 | this.message = message; 25 | } 26 | 27 | public String getDate() { 28 | return time.format(date); 29 | } 30 | 31 | public void setDate(Date date) { 32 | this.date = date; 33 | } 34 | 35 | public Integer getType() { 36 | return type; 37 | } 38 | 39 | public void setType(Integer type) { 40 | this.type = type; 41 | } 42 | } -------------------------------------------------------------------------------- /src/main/java/cn/blingfeng/websocket/pojo/WxLoginResult.java: -------------------------------------------------------------------------------- 1 | package cn.blingfeng.websocket.pojo; 2 | 3 | public class WxLoginResult { 4 | 5 | 6 | private String openid; 7 | private String session_key; 8 | private String unionid; 9 | private int errcode; 10 | private String errmsg; 11 | 12 | public String getOpenid() { 13 | return openid; 14 | } 15 | 16 | public void setOpenid(String openid) { 17 | this.openid = openid; 18 | } 19 | 20 | public String getSession_key() { 21 | return session_key; 22 | } 23 | 24 | public void setSession_key(String session_key) { 25 | this.session_key = session_key; 26 | } 27 | 28 | public String getUnionid() { 29 | return unionid; 30 | } 31 | 32 | public void setUnionid(String unionid) { 33 | this.unionid = unionid; 34 | } 35 | 36 | public int getErrcode() { 37 | return errcode; 38 | } 39 | 40 | public void setErrcode(int errcode) { 41 | this.errcode = errcode; 42 | } 43 | 44 | public String getErrmsg() { 45 | return errmsg; 46 | } 47 | 48 | public void setErrmsg(String errmsg) { 49 | this.errmsg = errmsg; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/cn/blingfeng/websocket/utils/FastJsonUtils.java: -------------------------------------------------------------------------------- 1 | package cn.blingfeng.websocket.utils; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import com.alibaba.fastjson.JSONObject; 5 | import com.alibaba.fastjson.serializer.JSONLibDataFormatSerializer; 6 | import com.alibaba.fastjson.serializer.SerializeConfig; 7 | import com.alibaba.fastjson.serializer.SerializerFeature; 8 | 9 | import javax.xml.crypto.dsig.keyinfo.KeyValue; 10 | import java.util.List; 11 | import java.util.Map; 12 | 13 | public class FastJsonUtils { 14 | 15 | private static final SerializeConfig config; 16 | 17 | static { 18 | config = new SerializeConfig(); 19 | config.put(java.util.Date.class, new JSONLibDataFormatSerializer()); // 使用和json-lib兼容的日期输出格式 20 | config.put(java.sql.Date.class, new JSONLibDataFormatSerializer()); // 使用和json-lib兼容的日期输出格式 21 | } 22 | 23 | private static final SerializerFeature[] features = {SerializerFeature.WriteMapNullValue, // 输出空置字段 24 | SerializerFeature.WriteNullListAsEmpty, // list字段如果为null,输出为[],而不是null 25 | SerializerFeature.WriteNullNumberAsZero, // 数值字段如果为null,输出为0,而不是null 26 | SerializerFeature.WriteNullBooleanAsFalse, // Boolean字段如果为null,输出为false,而不是null 27 | SerializerFeature.WriteNullStringAsEmpty // 字符类型字段如果为null,输出为"",而不是null 28 | }; 29 | 30 | 31 | public static String toJSONString(Object object) { 32 | return JSON.toJSONString(object, config, features); 33 | } 34 | 35 | public static String toJSONNoFeatures(Object object) { 36 | return JSON.toJSONString(object, config); 37 | } 38 | 39 | 40 | 41 | public static Object toBean(String text) { 42 | return JSON.parse(text); 43 | } 44 | 45 | public static T toBean(String text, Class clazz) { 46 | return JSON.parseObject(text, clazz); 47 | } 48 | 49 | // 转换为数组 50 | public static Object[] toArray(String text) { 51 | return toArray(text, null); 52 | } 53 | 54 | // 转换为数组 55 | public static Object[] toArray(String text, Class clazz) { 56 | return JSON.parseArray(text, clazz).toArray(); 57 | } 58 | 59 | // 转换为List 60 | public static List toList(String text, Class clazz) { 61 | return JSON.parseArray(text, clazz); 62 | } 63 | 64 | /** 65 | * 将javabean转化为序列化的json字符串 66 | * @param keyvalue 67 | * @return 68 | */ 69 | public static Object beanToJson(KeyValue keyvalue) { 70 | String textJson = JSON.toJSONString(keyvalue); 71 | Object objectJson = JSON.parse(textJson); 72 | return objectJson; 73 | } 74 | 75 | /** 76 | * 将string转化为序列化的json字符串 77 | * @param keyvalue 78 | * @return 79 | */ 80 | public static Object textToJson(String text) { 81 | Object objectJson = JSON.parse(text); 82 | return objectJson; 83 | } 84 | 85 | /** 86 | * json字符串转化为map 87 | * @param s 88 | * @return 89 | */ 90 | public static Map stringToCollect(String s) { 91 | Map m = JSONObject.parseObject(s); 92 | return m; 93 | } 94 | 95 | /** 96 | * 将map转化为string 97 | * @param m 98 | * @return 99 | */ 100 | public static String collectToString(Map m) { 101 | String s = JSONObject.toJSONString(m); 102 | return s; 103 | } 104 | 105 | } -------------------------------------------------------------------------------- /src/main/java/cn/blingfeng/websocket/utils/HttpRequestUtil.java: -------------------------------------------------------------------------------- 1 | package cn.blingfeng.websocket.utils; 2 | 3 | import org.apache.http.client.config.RequestConfig; 4 | import org.apache.http.client.methods.CloseableHttpResponse; 5 | import org.apache.http.client.methods.HttpGet; 6 | import org.apache.http.client.methods.HttpPost; 7 | import org.apache.http.entity.StringEntity; 8 | import org.apache.http.impl.client.CloseableHttpClient; 9 | import org.apache.http.impl.client.HttpClients; 10 | import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; 11 | 12 | import java.io.BufferedReader; 13 | import java.io.IOException; 14 | import java.io.InputStreamReader; 15 | import java.nio.charset.Charset; 16 | 17 | public class HttpRequestUtil { 18 | private static CloseableHttpClient httpClient; 19 | 20 | static { 21 | PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(); 22 | cm.setMaxTotal(100); 23 | cm.setDefaultMaxPerRoute(20); 24 | cm.setDefaultMaxPerRoute(50); 25 | httpClient = HttpClients.custom().setConnectionManager(cm).build(); 26 | } 27 | 28 | public static String get(String url) throws IOException { 29 | CloseableHttpResponse response = null; 30 | BufferedReader in = null; 31 | String result = ""; 32 | try { 33 | HttpGet httpGet = new HttpGet(url); 34 | RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(30000).setConnectionRequestTimeout(30000).setSocketTimeout(30000).build(); 35 | httpGet.setConfig(requestConfig); 36 | httpGet.setConfig(requestConfig); 37 | httpGet.addHeader("Content-type", "application/json; charset=utf-8"); 38 | httpGet.setHeader("Accept", "application/json"); 39 | response = httpClient.execute(httpGet); 40 | in = new BufferedReader(new InputStreamReader(response.getEntity().getContent())); 41 | StringBuffer sb = new StringBuffer(""); 42 | String line = ""; 43 | String NL = System.getProperty("line.separator"); 44 | while ((line = in.readLine()) != null) { 45 | sb.append(line + NL); 46 | } 47 | in.close(); 48 | result = sb.toString(); 49 | } catch (IOException e) { 50 | e.printStackTrace(); 51 | } finally { 52 | try { 53 | if (null != response) { 54 | response.close(); 55 | } 56 | } catch (IOException e) { 57 | e.printStackTrace(); 58 | } 59 | } 60 | return result; 61 | } 62 | 63 | public static String post(String url, String jsonString) { 64 | CloseableHttpResponse response = null; 65 | BufferedReader in = null; 66 | String result = ""; 67 | try { 68 | HttpPost httpPost = new HttpPost(url); 69 | RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(30000).setConnectionRequestTimeout(30000).setSocketTimeout(30000).build(); 70 | httpPost.setConfig(requestConfig); 71 | httpPost.setConfig(requestConfig); 72 | httpPost.addHeader("Content-type", "application/json; charset=utf-8"); 73 | httpPost.setHeader("Accept", "application/json"); 74 | httpPost.setEntity(new StringEntity(jsonString, Charset.forName("UTF-8"))); 75 | response = httpClient.execute(httpPost); 76 | in = new BufferedReader(new InputStreamReader(response.getEntity().getContent())); 77 | StringBuffer sb = new StringBuffer(""); 78 | String line = ""; 79 | String NL = System.getProperty("line.separator"); 80 | while ((line = in.readLine()) != null) { 81 | sb.append(line + NL); 82 | } 83 | in.close(); 84 | result = sb.toString(); 85 | } catch (IOException e) { 86 | e.printStackTrace(); 87 | } finally { 88 | try { 89 | if (null != response) { 90 | response.close(); 91 | } 92 | } catch (IOException e) { 93 | e.printStackTrace(); 94 | } 95 | } 96 | return result; 97 | } 98 | 99 | } -------------------------------------------------------------------------------- /src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 9000 3 | spring: 4 | application: 5 | name: chat 6 | -------------------------------------------------------------------------------- /src/main/resources/templates/webSocket.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SpringBoot实现广播式WebSocket 6 | 7 | 8 | 9 | 10 | 11 |
12 |
13 | 14 | 15 |
16 | 17 |
18 | 19 | 37 | -------------------------------------------------------------------------------- /src/test/java/cn/blingfeng/websocket/WebsocketApplicationTests.java: -------------------------------------------------------------------------------- 1 | package cn.blingfeng.websocket; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class WebsocketApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | --------------------------------------------------------------------------------