Commit 5aa65891 by Milovan Samardzic

WebSocketConfig

parent fd4f4f00
...@@ -60,6 +60,10 @@ ...@@ -60,6 +60,10 @@
<artifactId>spring-security-test</artifactId> <artifactId>spring-security-test</artifactId>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
</dependencies> </dependencies>
<build> <build>
......
package com.example.SkuciSe.configuration.WebSocket;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class Message {
private String messageContent;
}
package com.example.SkuciSe.configuration.WebSocket;
import com.example.SkuciSe.model.korisnik.Korisnik;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.simp.annotation.SendToUser;
import org.springframework.stereotype.Controller;
import org.springframework.web.util.HtmlUtils;
import java.security.Principal;
@Controller
public class MessageController {
@MessageMapping("/private-message")
@SendToUser("topic/private-messages")
public ResponseMessage getPrivateMessage(final Message message,
final Principal principal)throws InterruptedException{
Thread.sleep(1000);
return new ResponseMessage(HtmlUtils.htmlEscape(
"Sending private message to user " + principal.getName() + ": "
+ message.getMessageContent())
);
}
}
package com.example.SkuciSe.configuration.WebSocket;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@AllArgsConstructor
@Getter
@Setter
@NoArgsConstructor
public class ResponseMessage {
private String content;
}
package com.example.SkuciSe.configuration.WebSocket;
import com.sun.security.auth.UserPrincipal;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.server.support.DefaultHandshakeHandler;
import java.security.Principal;
import java.util.Map;
public class UserHandshakeHandler extends DefaultHandshakeHandler {
private final Logger LOG = LoggerFactory.getLogger(UserHandshakeHandler.class);
@Override
protected Principal determineUser(ServerHttpRequest request, WebSocketHandler wsHandler, Map<String, Object> attributes) {
return new UserPrincipal(SecurityContextHolder.getContext().getAuthentication().getName());
}
}
package com.example.SkuciSe.configuration.WebSocket;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class WSController {
@Autowired
private WSService service;
@PostMapping("/send-private-message/{mail}")
public void sendPrivateMessage(@PathVariable("mail") final String mail,
@RequestBody final Message message) {
service.notifyUser(mail, message.getMessageContent());
}
}
package com.example.SkuciSe.configuration.WebSocket;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.stereotype.Service;
@Service
public class WSService {
private final SimpMessagingTemplate messagingTemplate;
@Autowired
public WSService(SimpMessagingTemplate messagingTemplate) {
this.messagingTemplate = messagingTemplate;
}
public void notifyUser(final String mail, final String message) {
ResponseMessage response = new ResponseMessage(message);
messagingTemplate.convertAndSendToUser(mail, "/topic/private-messages", response);
}
}
\ No newline at end of file
package com.example.SkuciSe.configuration.WebSocket;
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/topic");
config.setApplicationDestinationPrefixes("/ws");
}
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("out-websocket")
.withSockJS();
}
}
package com.example.SkuciSe.controller; package com.example.SkuciSe.controller;
import com.example.SkuciSe.configuration.EmailPostoji; import com.example.SkuciSe.configuration.EmailPostoji;
import com.example.SkuciSe.configuration.WebSocket.Message;
import com.example.SkuciSe.model.korisnik.Korisnik; import com.example.SkuciSe.model.korisnik.Korisnik;
import com.example.SkuciSe.model.korisnik.KorisnikDetails; import com.example.SkuciSe.model.korisnik.KorisnikDetails;
import com.example.SkuciSe.model.oglas.Oglas; import com.example.SkuciSe.model.oglas.Oglas;
...@@ -8,12 +9,14 @@ import com.example.SkuciSe.repository.KorisnikRepository; ...@@ -8,12 +9,14 @@ import com.example.SkuciSe.repository.KorisnikRepository;
import com.example.SkuciSe.repository.LokacijaRepository; import com.example.SkuciSe.repository.LokacijaRepository;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.ui.Model; import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import java.io.IOException; import java.io.IOException;
import java.security.Principal;
import java.util.Base64; import java.util.Base64;
@Controller @Controller
...@@ -78,4 +81,9 @@ public class AppController ...@@ -78,4 +81,9 @@ public class AppController
model.addAttribute("loggedUser",loggedUser); model.addAttribute("loggedUser",loggedUser);
return "portfolio"; return "portfolio";
} }
@GetMapping("/chat")
public String getChat(Model model,@AuthenticationPrincipal KorisnikDetails loggedUser){
model.addAttribute("loggedUser",loggedUser);
return "chat";
}
} }
var stompClient = null;
$(document).ready(function() {
console.log("Index page is ready");
connect();
$("#send-private").click(function() {
sendPrivateMessage();
});
});
function connect() {
var socket = new SockJS('out-websocket');
stompClient = Stomp.over(socket);
stompClient.connect({}, function (frame) {
console.log('Connected: ' + frame);
stompClient.subscribe('/user/topic/private-messages', function (message) {
showMessage(JSON.parse(message.body).content);
});
});
}
function showMessage(message) {
$("#messages").append("<tr><td>" + message + "</td></tr>");
}
function sendPrivateMessage() {
console.log("sending private message");
stompClient.send("/ws/private-message", {}, JSON.stringify({'messageContent': $("#private-message").val()}));
}
\ No newline at end of file
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"/>
<meta name="description" content=""/>
<meta name="author" content=""/>
<title>SkuciSe</title>
<link rel="shortcut icon" type="image/x-icon" href="/images/logo.ico"/>
<link href='https://fonts.googleapis.com/css?family=Jost' rel='stylesheet'>
<link href="//maxcdn.bootstrapcdn.com/bootstrap/4.1.1/css/bootstrap.min.css" rel="stylesheet" id="bootstrap-css">
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css"
/>
<!-- Favicon-->
<link rel="icon" type="image/x-icon" href="assets/favicon.ico"/>
<!-- CSS only -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-gH2yIJqKdNHPEq0n4Mqa/HGKIhSkIHeL5AyhkYV8i59U5AR6csBvApHHNl/vI1Bx" crossorigin="anonymous">
<!-- Core theme CSS (includes Bootstrap)-->
<link href="/css/style.css" rel="stylesheet"/>
</head>
<body th:object="${loggedUser}">
<nav class="navbar navbar-icon-top navbar-expand-lg p-3">
<a class="navbar-brand" href="#"> </a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent"
aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav mr-auto">
<li class="nav-item active">
<a class="nav-link" th:href="@{/index}">
<i class="fa fa-home"></i>
Pocetna
<span class="sr-only">(current)</span>
</a>
</li>
<li class="nav-item active">
<a class="nav-link" href="/lista-oglasa">
<i class="fa fa-poll-h"></i>
Lista oglasa
<span class="sr-only">(current)</span>
</a>
</li>
<li class="nav-item active">
<a class="nav-link" th:href="@{/onama}">
<i class="fa-sharp fa-solid fa-address-card"></i>
<p>O nama</p>
<span class="sr-only">(current)</span>
</a>
</li>
<li class="nav-item active">
<a class="nav-link" th:href="@{/portfolio}">
<i class="fa-solid fa-briefcase"></i>
<p>Portfolio</p>
<span class="sr-only">(current)</span>
</a>
</li>
</ul>
<form class="form-inline my-2 my-lg-0" th:if="${loggedUser != null}">
<a th:href="@{/novi-oglas}">
<button type="button" class="btn btn-primary btn-md mr-2"><i class="fa-solid fa-plus"></i> Postavite
novi oglas
</button>
</a>
</form>
<ul class="navbar-nav">
<li class="nav-item" th:if="${loggedUser == null}">
<a th:href="@{/login}"><i class="fas fa-sign-in-alt" style="color:#495056"></i><span
style="padding:10px;color:#495056">Prijavi se</span></a>
</li>
<li class="nav-item" th:if="${loggedUser == null}">
<a th:href="@{/register}"><i class="fa-solid fa-circle-user" style="color:#495056"></i><span
style="padding:10px;color:#495056">Registruj se</span></a>
</li>
<li th:if="${loggedUser != null}">
<div class="dropdown mr-4">
<button class="btn btn-secondary dropdown-toggle round" type="button" id="dropdownMenuButton"
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<i class="fa-solid fa-circle-user"></i><span style="padding:10px;"
th:text="${loggedUser.getKorisnik().getIme()}"></span>
</button>
<div class="dropdown-menu" aria-labelledby="dropdownMenuButton">
<a class="dropdown-item" th:href="@{/profile}">Moj Profil</a>
<a class="dropdown-item" th:href="@{/profile/moji-oglasi}">Moji Oglasi</a>
<a class="dropdown-item" th:href="@{/profile/moji-zahtevi}">Moji Zahtevi</a>
<a th:if="${loggedUser.getKorisnik().getTipId() == 2}" class="dropdown-item"
th:href="@{/lista-korisnika}">Lista Profila</a>
<form th:action="@{/logout}" method="post" id="my_form" class="dropdown-item">
<a href="#" onclick="document.getElementById('my_form').submit(); return false;"><i
class="fas fa-sign-in-alt"></i><span style="padding:5px;">Odjavi se</span></a>
</form>
</div>
</div>
</li>
</ul>
</div>
</nav>
<section class="features-icons bg-light text-center">
<div class="row" style="margin-top: 10px">
<div class="col-md-12">
<form class="form-inline">
<div class="form-group">
<label for="private-message">Private Message</label>
<input type="text" id="private-message" class="form-control" placeholder="Enter your message here...">
</div>
<button id="send-private" class="btn btn-default" type="button">Send Private Message</button>
</form>
</div>
</div>
<div class="row">
<div class="col-md-12">
<table id="message-history" class="table table-striped">
<thead>
<tr>
<th>Messages
</th>
</tr>
</thead>
<tbody id="messages">
</tbody>
</table>
</div>
</div>
</section>
<div class="container-fluid pb-0 mb-0 justify-content-center text-light ">
<footer>
<div class="row my-5 justify-content-center py-5">
<div class="col-11">
<div class="row ">
<div class="col-xl-8 col-md-4 col-sm-4 col-12 my-auto mx-auto a"><h3
class="text-muted mb-md-0 mb-5 bold-text">SkuciSe</h3></div>
<div class="col-xl-2 col-md-4 col-sm-4 col-12"><h6 class="mb-3 mb-lg-4 bold-text "><b>MENI </b><i class="fa-solid fa-bars"></i></h6>
<ul class="list-unstyled">
<li><a href="/index" style="text-decoration: none;color:#627482;" onmouseover="this.style.color='#989c9e'" onMouseOut="this.style.color='#627482'">Pocetna</a></li>
<li><a href="/onama" style="text-decoration: none;color:#627482;" onmouseover="this.style.color='#989c9e'" onMouseOut="this.style.color='#627482'">O nama</a></li>
<li><a href="/portfolio" style="text-decoration: none;color:#627482;" onmouseover="this.style.color='#989c9e'" onMouseOut="this.style.color='#627482'">Portfolio</a></li>
</ul>
</div>
<div class="col-xl-2 col-md-4 col-sm-4 col-12"><h6
class="mb-3 mb-lg-4 text-muted bold-text mt-sm-0 mt-5"><b>ADRESA </b><i class="fa-solid fa-map-pin"></i></h6>
<p><a href="http://maps.google.com/maps?daddr=Radoja Domanovića 12 Kragujevac&amp;" style="text-decoration: none;color:#627482;" onmouseover="this.style.color='#989c9e'" onMouseOut="this.style.color='#627482'">Radoja Domanovića 12 Kragujevac 34000</a></p>
</div>
<div class="row ">
<div class="col-xl-8 col-md-4 col-sm-4 col-auto my-md-0 mt-5 order-sm-1 order-3 align-self-end"><p
class="social text-muted mb-0 pb-0 bold-text"><span class="mx-2"><i class="fa fa-facebook"
aria-hidden="true"></i></span>
<span class="mx-2"><i class="fa fa-linkedin-square" aria-hidden="true"></i></span> <span
class="mx-2"><i class="fa fa-twitter" aria-hidden="true"></i></span> <span class="mx-2"><i
class="fa fa-instagram" aria-hidden="true"></i></span></p><small class="rights"><span>&#174;</span>
SkuciSe. Sva prava zadrzana.</small></div>
<div class="col-xl-2 col-md-4 col-sm-4 col-auto order-1 align-self-end "><h6
class="mt-55 mt-2 text-muted bold-text"><b>Korisnicki centar </b><i class="fa-solid fa-phone"></i></h6><small> <span><i
class="fa fa-envelope" aria-hidden="true"></i></span><a href="mailto:someone@yoursite.com" style="text-decoration: none;color:#627482;" onmouseover="this.style.color='#989c9e'" onMouseOut="this.style.color='#627482'"> skucise@gmail.com</a> </small></div>
</div>
</div>
</div></div>
</footer>
</div>
<!-- JavaScript Bundle with Popper -->
<script src="//maxcdn.bootstrapcdn.com/bootstrap/4.1.1/js/bootstrap.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/sockjs-client/1.6.1/sockjs.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/stomp.js/2.3.3/stomp.min.js"></script>
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js"
integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN"
crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.12.9/dist/umd/popper.min.js"
integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q"
crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.0.0/dist/js/bootstrap.min.js"
integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl"
crossorigin="anonymous"></script>
<script src="https://kit.fontawesome.com/51d1fadef3.js" crossorigin="anonymous"></script>
<script src="/js/socket.js"></script>
</body>
</html>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment