webSocket以及https
需求:就是当后台操作完大量的数据之后,需要通知前端修改状态,于是第一时间想到了使用WebSocket。
概念的话这里就不解释了。
直接贴上我的代码,在springBoot中的使用。
首先在pom.xml中加入依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency>
将配置类加入容器管理
@Configuration public class WebSocketConfiguration { @Bean public ServerEndpointExporter serverEndpointExporter(){ return new ServerEndpointExporter(); } }
websocket服务端
@ServerEndpoint("/websocket/submitOnline") @Component public class WebSocketServer { private Logger log = Logger.getLogger("webSocketServer"); private static Map<String, Session> clients = new ConcurrentHashMap<>(); @Autowired private AdsMsgPlanService adsMsgPlanService; public static WebSocketServer webSocketServer; @PostConstruct public void init(){ webSocketServer = this; webSocketServer.adsMsgPlanService = this.adsMsgPlanService; } @OnOpen public void onOpen(Session session) throws InterruptedException { log.info("有新客户端连接了"+session.getId()); clients.put(session.getId(),session); } @OnClose public void onClose(Session session){ log.info("有用户断开了"+session.getId()); clients.remove(session.getId()); } @OnError public void onError(Throwable throwable){ throwable.printStackTrace(); } @OnMessage public void onMessage(String message){ log.info("服务端收到客户端发来的消息"+message);
//这里是我自己的业务逻辑 Result result = null; try { SubmitOnlineVo submitOnlineVo = new SubmitOnlineVo(); submitOnlineVo.setId(Integer.parseInt(message)); submitOnlineVo.setStatus(PlanStatusConstant.ATONLINE); Integer i = webSocketServer.adsMsgPlanService.updatePlan(submitOnlineVo); if(i==-1){ result = new Result(BusinessConstant.SYSTEM_ERROR_CODE, "上线人数超过30万!!!", i); }else if(i==0){ result = new Result(BusinessConstant.SYSTEM_ERROR_CODE, "修改失败", i); }else{ Map<String,String> map = new HashMap<>(); map.put("id",message); map.put("status","上线待投放"); result = new Result(BusinessConstant.SYSTEM_SUCESS_CODE, "修改成功", map); } this.sendAll(JSON.toJSONString(result)); }catch (Exception e){ e.printStackTrace(); result = new Result(BusinessConstant.SYSTEM_ERROR_CODE, e.getMessage(), null); this.sendAll(JSON.toJSONString(result)); } } private void sendAll(String message){ for (Map.Entry<String, Session> sessionEntry : clients.entrySet()) { sessionEntry.getValue().getAsyncRemote().sendText(message); } } }
客户端代码(前端并不是我写的,只是自己测试的时候写的一个简单页面)
<html> <head></head> <body> <div id="messageId"></div> <script> var socket; if(typeof(WebSocket) == "undefined") { console.log("您的浏览器不支持WebSocket"); }else{ console.log("您的浏览器支持WebSocket"); //实现化WebSocket对象,指定要连接的服务器地址与端口 建立连接 socket = new WebSocket("ws://localhost:8080/websocket/submitOnline"); //打开事件 socket.onopen = function() { console.log("Socket 已打开"); socket.send("dfgh"); }; //获得消息事件 socket.onmessage = function(msg) { console.log(msg.data); //发现消息进入 开始处理前端触发逻辑 let msgDiv = document.getElementById("messageId"); msgDiv.innerHTML += msg.data; }; //关闭事件 socket.onclose = function() { console.log("Socket已关闭"); }; //发生了错误事件 socket.onerror = function() { alert("Socket发生了错误"); //此时可以尝试刷新页面 } } </script> </body> </html>
这个时候一个websocket已经搭建好了,但是这个时候的安全性存在问题.
因为是ws,就类似于http嘛,所以就想弄成wss的,也就是https
然后我这边通过jdk生成一个密钥来在本地实现一个https.
在cmd中输入(要配置了jdk的环境变量)
keytool -genkey -alias tomcat -storetype PKCS12 -keyalg RSA -keysize 2048 -keystore keystore.p12 -validity 3650
参数就不一一解释了.
然后会在c盘/用户/当前用户文件夹下生成一个keystore.p12的文件.
将它放到项目的resources目录下,然后在application.properties文件中加入如下配置
server.port=8443 server.ssl.enabled=true server.ssl.key-store=classpath:keystore.p12 server.ssl.key-store-password=ouyang(你在cmd中输入的密码) server.ssl.key-store-type=PKCS12 server.ssl.key-alias=tomcat
然后一个配置类(允许http和https请求同时存在,将http转发到https)
@Configuration public class ConnectorConfig { @Bean public ServletWebServerFactory servletContainer() { TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory() { @Override protected void postProcessContext(Context context) { SecurityConstraint securityConstraint = new SecurityConstraint(); securityConstraint.setUserConstraint("CONFIDENTIAL"); SecurityCollection collection = new SecurityCollection(); collection.addPattern("/*");//设置所有路径都配置https securityConstraint.addCollection(collection); context.addConstraint(securityConstraint); } }; tomcat.addAdditionalTomcatConnectors(getHttpConnector()); return tomcat; } private Connector getHttpConnector() { Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol"); connector.setScheme("http"); connector.setPort(8080); connector.setSecure(false); connector.setRedirectPort(8443); return connector; } }
如果要在postman中测试还需要关闭ssl certificate verification
这时候我们就可以将客户端的websocket代码改成wss来保证安全性了,当然这只是本地测试,在实际的生产环境应该都是https协议,所以直接使用wss就行。