使用RethinkDB与SpringBoot 搭建一个简单的聊天

来源:互联网 发布:2016年淘宝交易额 编辑:程序博客网 时间:2024/06/09 22:09

最近项目有需要用到RethinkDB,故而在网上查询些资料,本文主要借鉴https://geowarin.github.io/spring-boot-and-rethinkdb.html 通过搭建一个聊天应用程序来学习RethinkDB.

RethinkDB 是什么?官网上的介绍是:RethinkDB is the open-source, scalable database that makes building realtime apps dramatically easier.  

一、搭建rethinDB服务端

1、访问RethinkDB官网下载服务端:https://www.rethinkdb.com/docs/install/windows/ 我是在win7环境下搭建的,所以我下载的是windows版本的,如果各位是其他版本的,也可以在https://www.rethinkdb.com/docs/install/ 里面选择对应服务器的版本。


2、启动服务端:将下载好的rethinkdb-2.3.6.zip 解压后,双击rethinkdb.exe 及运行rethinkDB服务端了,默认相关数据是存储在当前目录的,文件名是rethinkdb_data。如果需要保存至指定目录是,需要用命令行执行如:C:\Users\Administrator\Desktop\rethinkdb-2.3.6>rethinkdb.exe -d f:\rethinkDB\data  前提是那个文件夹是存在的。 运行完毕以后,出现Server ready, 即代表服务启动完毕。打开浏览器:localhost:8080 看到如下dashboard 说明启动成功了


二、编写SpringBoot工程  

1、增加maven依赖 主要包含springboot依赖包、org.webjars依赖包、以及RethinkDB的客户端依赖包

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><version>1.3.3.RELEASE</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId><version>1.3.3.RELEASE</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><version>1.3.3.RELEASE</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><version>1.3.3.RELEASE</version></dependency><dependency><groupId>org.webjars</groupId><artifactId>jquery</artifactId><version>3.0.0-alpha1</version></dependency><dependency><groupId>org.webjars</groupId><artifactId>sockjs-client</artifactId><version>1.0.0</version></dependency><dependency><groupId>org.webjars</groupId><artifactId>stomp-websocket</artifactId><version>2.3.3</version></dependency><dependency><groupId>org.webjars</groupId><artifactId>momentjs</artifactId><version>2.11.1</version></dependency><dependency><groupId>com.rethinkdb</groupId><artifactId>rethinkdb-driver</artifactId><version>2.3.3</version></dependency>
2、RethinkDB每个动作都是需要一个connection,所以先见一个工厂

public class RethinkDBConnectionFactory {    private String host;        private int port;    public RethinkDBConnectionFactory(String host,int port) {        this.host = host;        this.port = port;    }    public Connection createConnection() {        return RethinkDB.r.connection().hostname(host).port(port).connect();    }}

配置类:

@Configurationpublic class RethinkDBConfiguration {    // connect to docker    public static final String DBHOST = "127.0.0.1";    public static final int DBPORT = 28015;    @Bean    public RethinkDBConnectionFactory connectionFactory() {        return new RethinkDBConnectionFactory(DBHOST,DBPORT);    }    @Bean    DbInitializer dbInitializer() {        return new DbInitializer();    }}

3、初始化DB,createDb 主要是rethinkDB的api,如果不熟悉可以,看看https://www.rethinkdb.com/docs/guide/java/ 里面的api入门使用

public class DbInitializer implements InitializingBean {    @Autowired    private RethinkDBConnectionFactory connectionFactory;    @Autowired    private ChatChangesListener chatChangesListener;    private static final RethinkDB r = RethinkDB.r;    public void afterPropertiesSet() throws Exception {        createDb();        chatChangesListener.pushChangesToWebSocket();    }    private void createDb() {        Connection connection = connectionFactory.createConnection();        List<String> dbList = r.dbList().run(connection);        if (!dbList.contains("chat")) {            r.dbCreate("chat").run(connection);        }        List<String> tables = r.db("chat").tableList().run(connection);        if (!tables.contains("messages")) {            r.db("chat").tableCreate("messages").run(connection);            r.db("chat").table("messages").indexCreate("time").run(connection);        }    }}

4、聊天控制器

GET从DB中删除最后20条消息

POST发出新消息

@RestController@RequestMapping("/chat")public class ChatController {    protected final Logger log = LoggerFactory.getLogger(ChatController.class);    private static final RethinkDB r = RethinkDB.r;    @Autowired    private RethinkDBConnectionFactory connectionFactory;    @RequestMapping(method = RequestMethod.POST)    public ChatMessage postMessage(@RequestBody ChatMessage chatMessage) {        chatMessage.setTime(OffsetDateTime.now());        HashMap run = r.db("chat").table("messages").insert(chatMessage)                .run(connectionFactory.createConnection());        log.info("Insert {}", run);        return chatMessage;    }    @RequestMapping(method = RequestMethod.GET)    public List<ChatMessage> getMessages() {        List<ChatMessage> messages = r.db("chat").table("messages")                .orderBy().optArg("index", r.desc("time"))                .limit(20)                .orderBy("time")                .run(connectionFactory.createConnection(), ChatMessage.class);        return messages;    }}
ChatMessage 实体类

public class ChatMessage {    private String message;    private String from;    private OffsetDateTime time;    public ChatMessage() {    }    public ChatMessage(String message, String from, OffsetDateTime time) {        this.message = message;        this.from = from;        this.time = time;    }    public String getMessage() {        return message;    }    public void setMessage(String message) {        this.message = message;    }    public String getFrom() {        return from;    }    public void setFrom(String from) {        this.from = from;    }    public OffsetDateTime getTime() {        return time;    }    public void setTime(OffsetDateTime time) {        this.time = time;    }}
监听数据库表的更新,会将更改的数据通过Websocket推送

@Servicepublic class ChatChangesListener {    protected final Logger log = LoggerFactory.getLogger(ChatChangesListener.class);    private static final RethinkDB r = RethinkDB.r;    @Autowired    private RethinkDBConnectionFactory connectionFactory;    @Autowired    private SimpMessagingTemplate webSocket;    @Async    public void pushChangesToWebSocket() {        Cursor<ChatMessage> cursor = r.db("chat").table("messages").changes()                .getField("new_val")                .run(connectionFactory.createConnection(), ChatMessage.class);        while (cursor.hasNext()) {            ChatMessage chatMessage = cursor.next();            log.info("New message: {}", chatMessage.getMessage());            webSocket.convertAndSend("/topic/messages", chatMessage);        }    }}
配置Websocket
@Configuration@EnableWebSocketMessageBrokerpublic class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {    @Override    public void configureMessageBroker(MessageBrokerRegistry config) {        config.enableSimpleBroker("/topic");    }    public void registerStompEndpoints(StompEndpointRegistry registry) {        registry.addEndpoint("/chatWS").withSockJS();    }}

前端:index

<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <title>Spring boot and Rethinkdb Chat</title>    <link rel="stylesheet" href="css/main.css"></head><body><div id="container">    <div id="chat">        <ul id="messages">        </ul>        <form onsubmit="sendMessage(); return false;">            <div class="chat-message clearfix">                <input name="message-to-send" autocomplete="off" id="messageInput" placeholder="Type your message" />                <button type="submit">Send</button>            </div>        </form>    </div></div><script src="webjars/jquery/3.0.0-alpha1/jquery.js"></script><script src="webjars/sockjs-client/1.0.0/sockjs.js"></script><script src="webjars/stomp-websocket/2.3.3/stomp.js"></script><script src="webjars/momentjs/2.11.1/moment.js"></script><script src="js/main.js"></script></body></html>
CSS样式main.css
*, *:before, *:after {    box-sizing: border-bo}ol, ul {    list-style: none;}body {    background: #C5DDEB;    font: 14px/20px "Lato", Arial, sans-serif;    padding: 40px 0;    color: white;}#container {    margin: 0 auto;    width: 750px;    background: #444753;    border-radius: 5px;}#chat {    width: 750px;    float: left;    background: #F2F5F8;    border-top-right-radius: 5px;    border-bottom-right-radius: 5px;    color: #434651;}#messages {    padding: 30px 30px 20px;    border-bottom: 2px solid white;    overflow-y: scroll;    height: 575px;}.message-data {    margin-bottom: 15px;}.message-data-time {    color: #92959E;    padding-left: 6px;}.message {    color: white;    padding: 10px;    font-size: 16px;    border-radius: 7px;    margin-bottom: 6px;    width: 90%;    position: relative;}.message:after {    bottom: 100%;    left: 7%;    content: " ";    height: 0;    width: 0;    position: absolute;    pointer-events: none;    border: 10px solid transparent;    border-bottom-color: #86BB71;    margin-left: -10px;}.my-message {    background: #86BB71;}.other-message {    background: #6C86D2;}.other-message:after {    border-bottom-color: #6C86D2;    left: 93%;}.chat-message {    padding: 30px;}#messageInput {    width: 100%;    border: none;    padding: 10px 20px;    font: 14px/22px "Lato", Arial, sans-serif;    margin-bottom: 10px;    border-radius: 5px;    resize: none;}button {    float: right;    color: #94C2ED;    font-size: 16px;    text-transform: uppercase;    border: none;    cursor: pointer;    font-weight: bold;    background: #F2F5F8;}button:hover {    color: #7fa9ce;}.align-left {    text-align: left;}.align-right {    text-align: right;}.float-right {    float: right;}.clearfix:after {    visibility: hidden;    display: block;    font-size: 0;    content: " ";    clear: both;    height: 0;}
JS main.js
var userName = window.prompt("Enter your name", "some user");//var userName = "lol";function post(url, data) {    return $.ajax({        type: 'POST',        url: url,        headers: {            'Accept': 'application/json',            'Content-Type': 'application/json'        },        data: JSON.stringify(data)    })}function appendMessage(message) {var time = message.time;    var fromNow = time.year +"-" + time.monthValue + "-" + time.dayOfMonth + " " + time.hour + ":" + time.minute + ":" +time.second;    var $message = $(`<li class="clearfix">        <div class="message-data ${message.from == userName ? 'align-left': 'align-right'}">        <span class="message-data-name">${message.from}</span>        <span class="message-data-time">${fromNow}</span>    </div>    <div class="message ${message.from == userName ? 'my-message': 'other-message float-right'}">        ${message.message}    </div>    </li>`);    var $messages = $('#messages');    $messages.append($message);    $messages.scrollTop($messages.prop("scrollHeight"));}function getPreviousMessages() {    $.get('/chat').done(messages => messages.forEach(appendMessage));}function sendMessage() {    var $messageInput = $('#messageInput');    if($messageInput.val() ==null || $messageInput.val() ==""){    alert("不允许发空消息");    return;    }    var message = {message: $messageInput.val(), from: userName};    $messageInput.val('');    post('/chat', message);}function onNewMessage(result) {    var message = JSON.parse(result.body);    appendMessage(message);}function connectWebSocket() {    var socket = new SockJS('/chatWS');    stompClient = Stomp.over(socket);    //stompClient.debug = null;    stompClient.connect({}, (frame) => {        console.log('Connected: ' + frame);        stompClient.subscribe('/topic/messages', onNewMessage);    });}getPreviousMessages();connectWebSocket();
resources的目录结构为:


三、启动客户端 必须使用jdk1.8

直接执行BootRethinkdbApplication的main方法,然后访问localhost:8093/index.html


具体的github的请见

https://github.com/StephenXiong/rethinkdb-boot







原创粉丝点击