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就行。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM