There is only one domain class for the application:
package asia.grails.simplechat class Message { String nickname Date date = new Date() String message }This model/table will accumulate the chat message logs. Then the application will just select the last few messages to display in the screen of the user.
For registration, here is the controller and view
package asia.grails.simplechat class ChatController { def index() { } def join(String nickname) { if ( nickname.trim() == '' ) { redirect(action:'index') } else { session.nickname = nickname render (view: 'chat') } } }
index.gsp
<!DOCTYPE html> <html> <head> <meta name="layout" content="main"/> <title>Simple Chat</title> </head> <body> <g:form action="join"> <label for="nickname">Please enter your name</label> <g:textField name="nickname"/> <g:submitButton name="Join Chat"/> </g:form> </body> </html>The entry point to the application is the action index, which renders the page that contains the registration form index.gsp. The view shows a simple usage of a form. Notice that parameters submitted sent to the server side can be automatically mapped by name. Since the action join has a parameter String nickname, the control <g:textField name="nickname"/> will be mapped to it.
For the chat page, here are the contents of the controller and views:
package asia.grails.simplechat class ChatController { def retrieveLatestMessages() { def messages = Message.listOrderByDate(order: 'desc', max:10) [messages:messages.reverse()] } def submitMessage(String message) { new Message(nickname: session.nickname, message:message).save() render "<script>retrieveLatestMessages()</script>" } }
chat.gsp
<!DOCTYPE html> <html> <head> <meta name="layout" content="main"/> <title>Simple Chat</title> <g:javascript library="jquery"/> </head> <body> <div id="chatMessages"></div> <input type="text" id="messageBox" name="message" onkeypress="messageKeyPress(this,event);"/> <div id="temp"></div> <script> function messageKeyPress(field,event) { var theCode = event.keyCode ? event.keyCode : event.which ? event.which : event.charCode; var message = $('#messageBox').val(); if (theCode == 13){ <g:remoteFunction action="submitMessage" params="\'message=\'+message" update="temp"/> $('#messageBox').val(''); return false; } else { return true; } } function retrieveLatestMessages() { <g:remoteFunction action="retrieveLatestMessages" update="chatMessages"/> } function pollMessages() { retrieveLatestMessages(); setTimeout('pollMessages()', 5000); } pollMessages(); </script> </body> </html>
retrieveLatestMessages.gsp
<g:each in="${messages}" var="message"> <div> <span class="nickname">${message.nickname}</span> - <span class="msg">${message.message}</span> </div> </g:each>Look at chat.gsp first. What it does is to continuously request from the server for the latest messages. That is what the functions retrieveLatestMessages and pollMessages does.
If you want to have the chat page as the default landingpage of the application, just configure it in UrlMappings. For example:
class UrlMappings { static mappings = { "/$controller/$action?/$id?"{ constraints { // apply constraints here } } "/" (controller:"chat", action:"index") "500"(view:'/error') } }This just says that when the root of the application is access /, then the index action of chat controller is invoked.