This is websocketHandler
#Service
#Slf4j
public class ChatWebSocketHandler implements WebSocketHandler {
private final Sinks.Many<Event> chatMessageSink = Sinks.many().multicast().directBestEffort();
private final Flux<Event> chatMessageFlux = chatMessageSink.asFlux();
private final ObjectMapper objectMapper = new ObjectMapper();
public Mono<Void> handle(WebSocketSession session) {
Flux<WebSocketMessage> sendMessage = chatMessageFlux
.map(this::toString)
.map(session::textMessage);
Mono<Void> output = session.send(sendMessage);
Mono<Void> input = session
.receive()
.map(WebSocketMessage::getPayloadAsText)
.doOnNext(event -> {
chatMessageSink.tryEmitNext(toEvent(event));
})
.map(this::toEvent)
.then();
return Mono.zip(input, output).then();
}
#SneakyThrows
private Event toEvent(String message) {
return objectMapper.readValue(message, Event.class);
}
#SneakyThrows
private String toString(Event event) {
return objectMapper.writeValueAsString(event);
}
}
This is DTO.(mapping data from client)
#Setter
#Getter
#Builder
#NoArgsConstructor
#AllArgsConstructor
#ToString
public class Event {
private int id;
private String content;
private String sender;
}
This code is working normally.
But all clients are getting messages.
I would like to send message only to specific client like members of chat room.
help me.
Related
I have a java service.
Service receives a message, enriches it, stores it in a database, and sends it to kafka.
The service is made of reactive streams, DAO layer made of jdbc.
Controller:
#Api #Slf4j #Validated
#RestController
#ParametersAreNonnullByDefault
#RequiredArgsConstructor
public class IncomingMessageController {
private final IncomingMessageProcessingService processingService;
#PostMapping(value = "/incoming")
public Mono<ResponseEntity<String>> handleIncomingMessages(
#RequestBody VkIncomingMessage message
) {
return processingService.processMessage(message)
.then(Mono.just(ResponseEntity
.status(HttpStatus.OK)
.body("ok")));
}
}
Processing Service:
#Slf4j
#Service
#ParametersAreNonnullByDefault
public class IncomingMessageProcessingService {
private final List<IncomingMessageProcessor> incomingMessageProcessors;
public IncomingMessageProcessingService(
Optional<LoggingIncomingMessageProcessor> loggingIncomingMessageProcessor,
Optional<SendToKafkaIncomingMessageProcessor> kafkaIncomingMessageProcessor
) {
incomingMessageProcessors = new ArrayList<>();
loggingIncomingMessageProcessor.ifPresent(this.incomingMessageProcessors::add);
kafkaIncomingMessageProcessor.ifPresent(this.incomingMessageProcessors::add);
}
public Mono<VkIncomingDto> processMessage(VkIncomingMessage vkIncomingMessage) {
var vkIncomingDto = MessageMappingUtils.toVkIncomingDto(vkIncomingMessage);
var vkIncomingDtoMono = Mono.just(vkIncomingDto);
for (var processor : incomingMessageProcessors) {
vkIncomingDtoMono = processor.processIncomingMessage(vkIncomingDtoMono);
}
return vkIncomingDtoMono;
}
}
LoggingIncomingMessageProcessor:
#Slf4j
#Service
#RequiredArgsConstructor
#ParametersAreNonnullByDefault
#ConditionalOnProperty(
name = {"toggle.logging-incoming-processor"},
havingValue = "true",
matchIfMissing = true)
public class LoggingIncomingMessageProcessor
implements IncomingMessageProcessor {
private final IncomingMessagesDao incomingMessagesDao;
private final MessagesDao messagesDao;
private final IdGenerator idGenerator;
#Override
public Mono<VkIncomingDto> processIncomingMessage(Mono<VkIncomingDto> vkIncomingDtoMono) {
return vkIncomingDtoMono
.flatMap(vkIncomingDto -> {
var originalMsgOutLogin = getOriginalMsgOutLogin(Long.parseLong(vkIncomingDto.vkIncoming.getObject()
.getMessage()
.getMessageTag()));
var enrichedIncomingMessage = enrichVkIncomingMessages(vkIncomingDto, originalMsgOutLogin);
incomingMessagesDao.insert(enrichedIncomingMessage);
return Mono.just(enrichedIncomingMessage);
});
}
private VkIncomingDto enrichVkIncomingMessages(VkIncomingDto vkIncomingDto, String login) {
return vkIncomingDto.toBuilder()
.id(idGenerator.getNext())
.vkMessageId(Long.parseLong(Objects.requireNonNull(
vkIncomingDto.vkIncoming.getObject().getMessage().getMessageTag())))
.login(login)
.build();
}
private String getOriginalMsgOutLogin(Long originalMsgOutId) {
return messagesDao.getLoginToIdMap(Set.of(originalMsgOutId)).get(originalMsgOutId);
}
}
SendToKafkaIncomingMessageProcessor:
#Slf4j
#RequiredArgsConstructor
#Repository
#ParametersAreNonnullByDefault
#ConditionalOnProperty(
name = {"toggle.kafka-incoming-processor", "server.providermode"},
havingValue = "true",
matchIfMissing = true)
public class SendToKafkaIncomingMessageProcessor implements IncomingMessageProcessor {
private final VkIncomingMessageProducer messageProducer;
#Override
public Mono<VkIncomingDto> processIncomingMessage(Mono<VkIncomingDto> vkIncomingDtoMono) {
return vkIncomingDtoMono
.flatMap(vkIncomingDto -> messageProducer.sendMessage(MessageMappingUtils.toIncomingMessage(vkIncomingDto)))
.then(vkIncomingDtoMono);
}
}
I need to return an enriched message from LoggingIncomingMessageProcessor in order to send this information to Kafka.
The problem is that the code inside flatMap is run twice, resulting in 2 records being saved to the database and 1 message being sent to kafka.
I try to create a facebook messenger bot
I tried Victor de la Cruz method,the code is below
, and here is the origin code:
https://www.codementor.io/#vcg_cruz/a-facebook-messenger-bot-m2g6wgcxb#comments-m2g6wgcxb
it works but when I send a message it generates an infinite loop of conversation
this the result screen shot
#RestController()
#RequestMapping("webhook")
public class WebHook {
private final String PAGE_TOKEN ="THIS_IS_THE_TOKEN_YOU_COPIED_BEFORE";
private final String VERIFY_TOKEN="A_SECRET_VERIFY_TOKEN";
//this is for reply messages
private final String FB_MSG_URL="https://graph.facebook.com/v2.6/me/messages?access_token="
+ PAGE_TOKEN;
//logger to watch whats happening in our bot
private final Logger logger = LoggerFactory.getLogger(WebHook.class);
private final RestTemplate template = new RestTemplate();
//This is necessary for register a webhook in facebook
#GetMapping()
#ResponseStatus(HttpStatus.OK)
public String get(#RequestParam(name = "hub.verify_token")String token,
#RequestParam(name = "hub.challenge")String challenge){
if(token!=null && !token.isEmpty() && token.equals(VERIFY_TOKEN)){
return challenge;
}else{
return "Wrong Token";
}
}
//This method reply all messages with: 'This is a test message'
#PostMapping
#ResponseStatus(HttpStatus.OK)
public void post(#RequestBody FacebookHookRequest request){
logger.info("Message from chat: {}",request);
request.getEntry().forEach(e->{
e.getMessaging().forEach(m->{
String id = m.getSender().get("id");
sendReply(id,"This is a test message");
});
});
}
private void sendReply(String id,String text){
FacebookMessageResponse response = new FacebookMessageResponse();
response.setMessage_type("text");
response.getRecipient().put("id",id);
response.getMessage().put("text",text);
HttpEntity<FacebookMessageResponse> entity = new HttpEntity<>(response);
String result = template.postForEntity(FB_MSG_URL,entity,String.class).getBody();
logger.info("Message result: {}",result);
}
}
/************************************/
#Data
#NoArgsConstructor
#AllArgsConstructor
#ToString
public class FacebookEntry implements Serializable {
private String id;
private Long time;
private List<FacebookMessaging> messaging = new ArrayList<>();
}
#Data
#NoArgsConstructor
#AllArgsConstructor
#ToString
public class FacebookHookRequest implements Serializable {
private String object;
private List<FacebookEntry> entry = new ArrayList<>();
}
#Data
#NoArgsConstructor
#AllArgsConstructor
#ToString
public class FacebookMessage implements Serializable {
private String mid;
private Long seq;
private String text;
}
#Data
#NoArgsConstructor
#AllArgsConstructor
#ToString
public class FacebookMessageResponse implements Serializable {
private String message_type;
private Map<String,String> recipient = new HashMap<>();
private Map<String,String> message = new HashMap<>();
}
#Data
#NoArgsConstructor
#AllArgsConstructor
#ToString
public class FacebookMessaging implements Serializable {
private Map<String,String> sender;
private Map<String,String> recipient;
private Long timestamp;
private FacebookMessage message;
}
You're responding to yourself I assume. Similar to how the Discord API works, your post method is being called when you receive your own message. You most likely want to check if the message author is from yourself.
I'm using Spring Boot framework and my response returns duplicated with reversed backward.
I'm asking for advices, how can i solve this situation?
Controller End Point
#GetMapping("/getPDetailsW/{W}")
public PPreviewW getPDetailsPreviewW(#PathVariable String W) {
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss");
LocalDateTime now = LocalDateTime.now();
String nullCheckBill = "bos";
PPreviewW response = new PromoPreviewWGsm();
PPreviewInfo pPreviewInfo = listRepository.findPByW(W);
log.info(dtf.format(now) + "|getPDetailsPreviewW|" + W+ "|için istek atıldı.");
response.setDisplayId(pPreviewInfo.getDISPLAY_ID());
response.setAccountCode(pPreviewInfo.getACCOUNT_CODE());
if (pPreviewInfo.W!= "bos") {
nullCheckBill = promoPreviewInfo.W;
}
if (nullCheckBill == "bos") {
response.setNEXTFLAG(Boolean.FALSE);
} else {
response.setNEXTFLAG(Boolean.TRUE);
}
return response;
}
I have #RestController annotation at top of my Controller class.
PPreviewW response class
#Getter
#Setter
public class PPreviewW implements Serializable {
public String DisplayId;
public String AccountCode;
}
I'm using lombok getters and setters
Repository Class
public PPreviewInfo findPByW(String W) {
PPreviewInfo list = jdbcTemplate
.queryForObject(QueryConstants.GET_P_PREVIEW_INFOW, new Object[]{W}, new PPreviewInfoMapper());
return list;
}
#Repository and #Autowired annotations at top of Repository class.
and QueryContants includes my sql which returns correct size for example like XXXX and YYYY
PPreviewInfo Class
#Getter
#Setter
public class PPreviewInfo {
public String CUSTOMER_ID;
public String BILLING_ACCOUNT_CODE;
}
PPreviewInfoMapper Class
public class PPreviewInfoMapper implements RowMapper<PPreviewInfo> {
#Override
public PPreviewInfo mapRow(ResultSet rs, int i) throws SQLException {
PPreviewInfo pbn = new PPreviewInfo();
pbn.setDISPLAY_ID(rs.getString("DISPLAY_ID"));
pbn.setACCOUNT_CODE(rs.getString("ACCOUNT_CODE"));
return pbn;
}
}
response
{"DisplayId":"XXXX","AccountCode":"YYYYYY","NEXTFLAG":true,"nextflag":true,"displayId":"XXXX","accountCode":"YYYYYY"}
The visibility of the attributes might be causing the issue, you can see if changing them to private might help in resolution:
#Getter
#Setter
public class PPreviewW implements Serializable {
private String DisplayId;
I am currently setting up a Rest API server using Spring Boot (v2.5.5), Spring Data Couchbase (v4.2.5) and Couchbase (v6.6.1).
I get a really strange behavior when requesting
count() -> 0
findAll() -> []
Whereas
findById() is returning a result.
My entity:
{"mkey": { "keyContent": "AA", "mkeyStatus": "L" }, "sequences": [ { "direction": "B", "loc1Value": "NCE", "loc2Value": "NYC" } ] }
#Document #Data #AllArgsConstructor #NoArgsConstructor #EqualsAndHashCode public class AirlineProfile {
#Id private String id;
#Field private MKey mkey;
#Field private List<Sequence> sequences;
#EqualsAndHashCode #AllArgsConstructor #NoArgsConstructor #Data static class MKey {
#Field private String keyContent;
#Field private String mkeyStatus;
}
#EqualsAndHashCode #AllArgsConstructor #NoArgsConstructor #Data static class Sequence {
#Field private String loc1Value;
#Field private String loc2Value;
#Field private String direction;
}
}
My repository is extending the CrudRepository.
public interface AirlineProfileRepository extends CrudRepository<AirlineProfile, String> {}
While my Service is the following:
#Service #Qualifier("AirlineProfileServiceImpl") public class AirlineProfileServiceImpl
implements AirlineProfileService {
#Autowired private AirlineProfileRepository airlineProfileRepository;
#Override
public long count() {
return airlineProfileRepository.count();
}
#Override
public List<AirlineProfile> findAll() {
List<AirlineProfile> airlineProfiles = new ArrayList<>();
for (AirlineProfile airlineProfile : airlineProfileRepository.findAll()) {
airlineProfiles.add(airlineProfile);
}
return airlineProfiles;
}
#Override public AirlineProfile findById(String id) {
return airlineProfileRepository.findById(id).orElse(null);
}
}
And my controller the following:
#RestController #RequestMapping("/api") public class AirlineProfileController {
#Autowired AirlineProfileService airlineProfileService;
#GetMapping("/airlineprofile/count") public long count() {
System.out.println("Count");
return airlineProfileService.count();
}
#GetMapping("/airlineprofile/all") public List<AirlineProfile> getAllAirlineProfiles() {
System.out.println("Get all AirlineProfile");
return airlineProfileService.findAll();
}
#GetMapping("/airlineprofile/id={id}") public AirlineProfile getAirlineProfileById(#PathVariable String id) {
System.out.println("Get AirlineProfile for id = " + id);
return airlineProfileService.findById(id);
}
}
I do not know if I missed something at Server or Couchbase side ... :(
Thank you for your help!
Ok, found that:
public interface AirlineProfileRepository extends CrudRepository<AirlineProfile, String> {
#Query("#{#n1ql.selectEntity}")
List<AirlineProfile> findAll();
}
Is working ...
So, I am questioning myself about the usability of findAll() ...
I'm making a small learning project. In it i'm reading some JSON from a restservice and persisting it in a postgres DB. The restservice has several JSON models that are available from different URL's. I have created a simple reader class that reads the JSON from a url and sends it to the DB. This works with the Model and Service classes hardcoded in the Reader class. I am trying to make it more generic however so i can use the reader class and pass in the model class and service class (that has an add method that calls the save method form the repository for that Model). I tried this with the models implementing an interface and having the interface as parameter in the constructor of the reader class or passing the model classname as a string to the Reader constructor and it being a parameter for a Classloader.
I haven't gotten it to work and probably it is a silly syntax problem but maybe somebody here can help out. Below are the classes:
#Slf4j
#Service
#AllArgsConstructor
public class Reader {
private MapService mapService;
public void readStream(String url) {
try (InputStream is = new URL(url).openStream()) {
JsonReader reader = new JsonReader(new InputStreamReader(is, "UTF-8"));
Gson gson = new GsonBuilder().create();
reader.beginArray();
while (reader.hasNext()) {
MapInputModel map = gson.fromJson(reader, MapInputModel.class);
mapService.add(map);
}
reader.close();
} catch (MalformedURLException e) {
log.error("MalformedURLException" + e.getMessage());
} catch (IOException e) {
log.error("IOException" + e.getMessage());
}
}
}
.
#Service
#RequiredArgsConstructor
#Transactional(propagation = Propagation.REQUIRED)
public class MapService {
private final MapModelMapper mapModelMapper;
private final MapEntityRepository mapEntityRepository;
public void add(final MapInputModel mapInputModel) {
mapEntityRepository.save(mapModelMapper.toEntity(mapInputModel));
}
.
#Getter
#AllArgsConstructor
public class MapInputModel {
private String name;
private List<String> translations;
}
The Mapservice and MapInputModel need to be replaceable with similar classes, like:
#Getter
#AllArgsConstructor
public class IconModel {
Map<String, String> icon;
}
I'm using SpringBoot and Lombok in this project.
-------- edit: updated classmodels ---------
#Getter
#AllArgsConstructor
public class MapInputModel implements InputModel {
private String name;
private List<String> translations;
}
public interface IService<T>{
void add(final T model);
}
#Service
#RequiredArgsConstructor
#Transactional(propagation = Propagation.REQUIRED)
public class MapService implements IService<MapInputModel> {
private final MapModelMapper mapModelMapper;
private final MapEntityRepository mapEntityRepository;
#Override
public void add(final MapInputModel mapInputModel) {
mapEntityRepository.save(mapModelMapper.toEntity(mapInputModel));
}
}
#Slf4j
public class Reader {
private IService<InputModel> service;
private InputModel model;
public Reader(IService<InputModel> service, InputModel model) {
this.service = service;
this.model = model;
}
// code
}