Bygg et real-time chat-program med modul og vårstart

I denne tutoral vil vi bruke Spring Boot for webutviklingsmiljøet, Websockets for sanntidskommunikasjon, Tomcat for Java-applikasjonsbeholderen, Gradle for å bygge og administrere avhengighetene, Thymeleaf for malgengivelse, MongoDBfor datalagring, og til slutt vil det ikke være noen XML for bønne konfigurasjoner. Bare for å gjøre deg inspirert, på slutten av denne artikkelen, vil du se et fullt fungerende program som vist nedenfor.

1. Scenario

  1. Åpne chat-siden for å kommunisere med vennene sine.
  2. Han blir bedt om å velge et kallenavn.
  3. Han går inn på chat siden og sender en melding. Meldingen sendes til Spring MVC-endepunktet som skal lagres i databasen og kringkastes.
  4. Det angitte sluttpunktet håndterer meldingen og sender den meldingen til alle klientene som er koblet til chatte systemet.

2. Bygg avhengigheter og Gradle Configuration

Før jeg fortsetter med prosjektets interne struktur, la meg forklare hvilke biblioteker vi skal bruke til prosjektfunksjonene som er oppført ovenfor, og administrere dem ved hjelp av Gradle. Når du kloner prosjektet fra GitHub, vil du se en fil som heter build.gradle i prosjektets rotkatalog som nedenfor.

buildscript repositories mavenCentral () avhengigheter classpath ("org.springframework.boot: spring-boot-gradle-plugin: 1.2.4.RELEASE") bruk plugin: 'java' gjelder plugin: 'eclipse' : 'ide' gjelder plugin: 'spring-boot' gjelder plugin: 'war' jar baseName = 'realtime-chat' version = '0.1.0' krig baseName = 'ROOT' sourceCompatibility = 1.7 targetCompatibility = 1,7 repositories mavenCentral () sourceCompatibility = 1.7 targetCompatibility = 1.7 avhengigheter providedRuntime 'org.springframework.boot: spring-boot-starter-tomcat' kompilere ("org.springframework.boot: spring-boot-starter-web") kompilere org.springframework.boot: spring-boot-starter-thymeleaf ") kompilere (" org.springframework.boot: spring-boot-starter-data-mongodb ") kompilere (" org.springframework.boot: spring-boot-starter- websocket ") kompilere (" org.springframework: spring-messaging ") testCompile (" junit: junit ") oppgavepakke (type: Wrapper) gradleVersion = '2.3'

Jeg vil ikke dykke inn i Gradle internals, men la meg forklare de delene vi trenger for vårt prosjekt. Spring Boot er bygget hovedsakelig for å utvikle frittstående applikasjoner i krukke format. I vårt prosjekt vil vi generere en krig prosjekt i stedet for krukke. Det er fordi Modulus trenger en krigsfil for å distribuere prosjektet automatisk til skyen. 

For å generere en krigsfil, har vi brukt bruke plugin: 'war'. Modulus forventer også at krigenavnet skal være ROOT.war som standard, og det er derfor vi har brukt:

krig baseName: 'ROOT.war'

Når du kjører Gradle bygge oppgave, vil det generere en krigsfil å distribuere til Tomcat-containeren. Og til slutt, som du kan gjette, er avhengighetsdelen for tredjepartsbiblioteker for bestemte handlinger. 

Det er alt for prosjektavhengighetsdelen, og du kan se Gradle brukerhåndbok for mer om Gradle.

3. Programvare Design

Hvis du ønsker å utvikle et godt program, er det best å definere prosjektstrukturen i små biter. Du kan se brikkene i hele arkitekturen i vår søknad.

3.1. Modell

Vi utvikler et chatprogram, så vi kan si at vi har en ChatMessageModel modell (dvs. domeneobjekt). Mens vi lagrer eller ser på chatmeldingsdetaljene, kan vi kaste chatobjektet fra eller til dette ChatMessageModel modell. Også, vi kan bruke Bruker modell for chat-brukere, men for å gjøre applikasjonen enklere, vil vi bare bruke kallenavn som tekst. De ChatMessageModel modellen har følgende felt: tekst, forfatter, og lag dato. Klassepresentasjonen av denne modellen er som følger:

pakke realtime.domain; importer org.springframework.data.annotation.Id; importer java.util.Date; / ** * @author huseyinbabal * / offentlig klasse ChatMessageModel @Id private String id; privat streng tekst; Private String forfatter; privat Dato createDate; offentlig ChatMessageModel ()  offentlig ChatMessageModel (String text, String author, Date createDate) this.text = text; this.author = author; this.createDate = createDate;  offentlig String getText () returtekst;  Offentlig tomt settText (String tekst) this.text = text;  offentlig String getAuthor () returforfatter;  public void setAuthor (String author) this.author = author;  offentlig dato getCreateDate () return createDate;  offentlig tomt settCreateDate (Date createDate) this.createDate = createDate;  @ Override public String toString () return "+" \ "id \": \ "" + id + '\ "' +", \ "text \": \ "" + tekst + '\ " + ", \" forfatter \ ": \" "+ forfatter + '\"' + ", \" createDate \ ": \" "+ createDate +" \ "" + '';  

Dette domenenavnet hjelper oss til å representere chatmeldingen som JSON når det trengs. Vår modell er OK, så la oss fortsette med kontrollerne.

3.2. Controller

Kontrolleren er oppførselen til søknaden din. Dette betyr at du må holde kontrolleren enkel og i stand til lett samhandling med domenemodeller og andre tjenester. Vi forventer at våre kontrollere skal håndtere:

  1. Chat melding lagre forespørsler
  2. Viser de nyeste chatmeldingene
  3. Ser på chatprogramsiden
  4. Ser på innloggingssiden
  5. Broadcast chat meldinger til klienter

Her kan du se de samlede endpoengene:

pakke realtime.controller; importer org.springframework.beans.factory.annotation.Autowired; importer org.springframework.data.domain.PageRequest; importer org.springframework.data.domain.Sort; importer org.springframework.http.HttpEntity; importer org.springframework.http.HttpStatus; importere org.springframework.http.ResponseEntity; importere org.springframework.messaging.handler.annotation.MessageMapping; importere org.springframework.messaging.handler.annotation.SendTo; importer org.springframework.stereotype.Controller; importer org.springframework.web.bind.annotation.RequestMapping; importer org.springframework.web.bind.annotation.RequestMethod; importere realtime.domain.ChatMessageModel; importere realtime.message.ChatMessage; importere realtime.repository.ChatMessageRepository; importer java.util.Date; importer java.util.List; / ** * @author huseyinbabal * / @Controller offentlig klasse ChatMessageController @ Utnevnt privat ChatMessageRepository chatMessageRepository; @RequestMapping ("/ login") offentlig String logg inn () return "login";  @RequestMapping ("/ chat") offentlig String chat () return "chat";  @RequestMapping (value = "/ messages", metode = RequestMethod.POST) @MessageMapping ("/ newMessage") @SendTo ("/ topic / newMessage") offentlig ChatMessage lagre (ChatMessageModel chatMessageModel) ChatMessageModel chatMessage = ny ChatMessageModel (chatMessageModel .getText (), chatMessageModel.getAuthor (), ny dato ()); ChatMessageModel message = chatMessageRepository.save (chatMessage); Liste chatMessageModelList = chatMessageRepository.findAll (ny PageRequest (0, 5, Sort.Direction.DESC, "createDate")). getContent (); returner ny ChatMessage (chatMessageModelList.toString ());  @RequestMapping (value = "/ messages", metode = RequestMethod.GET) offentlig HttpEntity list () Liste chatMessageModelList = chatMessageRepository.findAll (ny PageRequest (0, 5, Sort.Direction.DESC, "createDate")). getContent (); returnere ny ResponseEntity (chatMessageModelList, HttpStatus.OK);  

Første og andre endepunkter er bare for visning av innloggings- og hoved chat siden. Den tredje handlingen er å håndtere ny chat-lagring og kringkasting. Etter at meldingen er lagret, vil den bli varslet til klienter gjennom / Tema / meldingkanal. For å lagre meldingsdata til MongoDB, vil vi bruke et MongoDB-depot.  

Som du kan se, er det to typer endepunkt / meldinger: GET og POST. Når du gjør en POST-forespørsel til sluttpunkt / meldinger Med riktig meldings nyttelast vil den automatisk bli kastet til ChatMessageModel-klassen, og meldingen vil bli lagret i MongoDB. Etter vellykket lagring vil den automatisk bli presset til klientene. Men hvordan? I den handlingen er det en merknad @SendTo ( "/ emne / newMessage"). Dette vil sende innholdet returnert fra funksjonen til klientene. Og det returnerte innholdet er som nedenfor:

... returnere ny ChatMessage (chatMessageModelList.toString ()); ... 

Dette er den siste meldingen fra databasen:

Ovennevnte melding vil bli konvertert til et format for WebSocket-kommunikasjon. Denne kanalmeldingen blir håndtert på klientsiden med et tredjeparts JavaScript-bibliotek, og det blir behandlet i følgende seksjoner. 

For melding db operasjoner, fjær-boot-starter-data-mongodb benyttes. Dette biblioteket hjelper oss til lagringsoperasjoner, og å lage et lagerobjekt for MongoDB er veldig enkelt. Du kan se eksemplet ChatMessageRepository under:

pakke realtime.repository; importere org.springframework.data.mongodb.repository.MongoRepository; importere realtime.domain.ChatMessageModel; importer java.util.List; / ** * @author huseyinbabal * / offentlig grensesnitt ChatMessageRepository utvider MongoRepository Liste findAllByOrderByCreateDateAsc ();  

Hvis du oppretter et grensesnitt og utvider MongoRepository, Du vil automatisk kunne bruke CRUD-operasjoner som finne(), findAll (), lagre(), etc. 

Som du kan se, MongoRepository Forventer et domeneobjekt. Vi har allerede definert denne modellen i modell-delen av opplæringen. I dette depotet har vi definert en tilpasset funksjon som heter findAllByOrderByCreateDateAsc ()

Hvis du noen gang har brukt JPA før du kan forstå dette enkelt, men la meg forklare dette kort. Hvis du definerer et funksjonsnavn i et grensesnitt som strekker seg MongoRepository, Dette funksjonsnavnet blir analysert på en forespørsel på bakenden ved våren automatisk. Det vil være noe som helst:

VELG * FRA ChatMessageModel WHERE 1 ORDER BY createDate ASC

I ChatMessageController, Vi brukte denne funksjonen, og vi har også brukt standardfunksjonene til MongoRepository:

chatMessageRepository.findAll (ny PageRequest (0, 5, Sort.Direction.DESC, "createDate")). getContent ()

findAll brukes en parameter for sortering og paginering. Du kan se på veiledningen på vårens hjemmeside for mer informasjon om Spring JPA.

3.3. Utsikt

I visningsdelen har vi bare to sider. En av dem er påloggingssiden, for å få brukernavnet til brukeren, og den andre er den viktigste chat siden for å sende meldinger til chat-brukere. 

Som du kan se i kontrolleren delen ovenfor, blir de gjengitt ved å bruke to endepunkter, /Logg Innog / chatFor å lage interaktive sider bruker vi noen tredjeparts JavaScript-biblioteker. Vi vil bruke dem fra CDN-sider. Du kan se påloggingssiden nedenfor:

             

Velg et kallenavn for å skrive inn chat

På innloggingssiden har vi et eksempel på kallenavn. Når du klikker Skriv inn Chat, Ditt kallenavn vil bli lagret i en informasjonskapsel. Dette kallenavnet blir brukt til å angi forfatterfeltet for chatmelding. Når du klikker Skriv inn Chat, Chat-siden vil bli åpnet. Hvis du allerede er innlogget og går til påloggingssiden, blir du omdirigert til chat siden. 

Her er chat siden:

                 

Realtime Chat Application med Spring Boot, Websockets og MongoDB



Chat historie

Denne siden er bare for å vise og sende meldinger. Meldinger blir levert til denne siden via WebSockets. På denne siden kan du se sockjs og stompjs. Disse er for håndtering av varsler. Når en ny melding kommer, blir det siste meldingsområdet repopulert. 

Forresten, når du først åpner chat siden, blir de siste meldingene hentet i meldingsområdet. Som du kan se på JavaScript-siden, er vår meldingskanal ny melding. Så, vi lytter til denne kanalen, og når du klikker på Sende knappen, vil meldingen i tekstboksen bli sendt til sluttpunktet og denne meldingen vil bli sendt til de tilkoblede klientene etter vellykket lagring.

Som du kan se, er programvarearkitekturen her veldig enkel og lett å utvikle. Vi har produksjonsklar kode, og la oss distribuere den til Modulus.

Modulus er en av de beste PaaS for å distribuere, skalere og overvåke søknaden din på språket du ønsker.

4. Distribusjon 

4.1. Forutsetninger

Før du distribuerer programmet, la oss lage en database ved hjelp av modulpanelet. Du trenger en Modulus-konto for dba-opprettelse og applikasjonsutplassering, så vær så snill å opprette en konto hvis du ikke har en. 

Gå til modulskjermbildet og opprett en database:

På databasenes opprettelsesskjerm, vennligst oppgi et databasenavn, velg MongoDB-versjonen (jeg har brukt 2.6.3, så det vil være bedre hvis du velger 2.6.3 også), og endelig definere en bruker å bruke database lese / skrive operasjoner. 

Du kan få en MongoDB-URL etter å ha opprettet databasen. Vi vil bruke MongoDB URL i miljøvariablene som skal brukes av Spring Boot-applikasjonen.

For å angi miljøvariabler for MongoDB, må du ha et program. Gå til dashbord og klikk prosjekter. Klikk på denne siden Opprett nytt prosjekt.

For å fortsette å konfigurere miljøvariablene, gå til dashbord og klikk prosjekter. Velg prosjektet ditt, og klikk Administrasjon. Bla nedover siden, og sett miljøvariabler med nøkkelen SPRING_DATA_MONGODB_URI og verdien av databasen URI:

Når du distribuerer programmet, vil våren bruke denne miljøvariabelen. Vi har gjort med kravene, og la oss fortsette med distribusjonsdelen.

4.2. Distribusjon med CLI

For å distribuere prosjektet, kjør en gradvis byggeoppgave:

gradvis bygge

Denne oppgaven vil generere en krigsfil som heter ROOT.war. Kopier denne filen til en ny mappe og installer modul CLI hvis du ikke har det.

npm installer -g modulus

Logg inn på systemet;

modul innlogging

Nå utfør følgende kommando for å distribuere ROOT.war til modulen.

moduler distribuere

Dette vil distribuere krigsfilen, og du kan hale prosjektloggene for å se statusen for distribusjonen din ved å utføre følgende kommando:

modulus prosjekt logger hale

Det er alt med distribusjonen!

5. Konklusjon

Hovedformålet med denne opplæringen er å vise deg hvordan du lager et sanntids chatprogram med Spring Boot, WebSockets og MongoDB. 

For å kjøre prosjektet i produksjon, brukes Modulus som en PaaS-leverandør. Modulus har svært enkle trinn for distribusjon, og det har også en intern database (MongoDB) for våre prosjekter. Ved siden av dette kan du bruke svært nyttige verktøy i modulskjermbildet, for eksempel Logger, Varsler, Automatisk skalering, Dbadministrasjon og mer.