《物联网反向呼叫项目》下(JaveWeb部分)

《物联网反向呼叫项目》下(JaveWeb部分)

文章目录

    • 项目概要
    • 相关代码
      • SpringBoot代码
        • controller
        • mapper
        • pojo
        • service
          • pagerService
          • pagerServiceImpl
        • application.yml
        • pages
          • MQTT
          • HTTP
          • 完整代码
      • Mysql表结构
      • 项目部署
      • 接口测试
    • 小结

项目概要

        自制一款可以联网操作的呼叫器正向手机发送ID可以控制响起,反向温度过高进行报警,手机网页端可以通过MQTT协议和ESP8266模块通信,ESP8266再通过串口和51单片机进行通信。添加温度报警功能,C51单片机通过获取到温度利用串口和ESP8266通信,将温度数据传递到ESP8266模块上。ESP8266模块再通过HTTP请求向后台Java接口进行数据的上传,保存到数据库中,并且实现数据的实时显示。该项目,不是特别的完美可以有很多创新和改进的地方,但主要实现了ESP8266的MQTT、HTTP网络通信协议应用,还有串口通信的使用,大家可以当做例子进行学习。

相关代码

SpringBoot代码

        首先先看一下项目的目录结构,将从以下6个红色标记的目录依次展开讲解,都是比较简单的内容。

controller

        controller中有俩个方法一个是UpdateTemperatureById(通过id上传更新数据库中所存储的代码),SelectTemperatureById(通过id获取当前数据库中所存储的温度),分别都是调用pagerService中的getRoomTemperature和updateTemperature后续会介绍。

package ***.example.pager.controller;

import ***.example.pager.pojo.R;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/pager")
public class pagerController {

    @Autowired
    private ***.example.pager.service.pagerService pagerService;
    /**
     * 上传温度到数据库
     * @param id
     * @param Temperature
     * @return
     */
    @GetMapping("/{id}/{Temperature}")
    public R UpdateTemperatureById(@PathVariable Integer id,@PathVariable Integer Temperature){
        try {
            pagerService.updateTemperature(id,Temperature);
            return new R(true,"200","null");
        }catch (Exception e){
            e.printStackTrace();
            return new R(false,"500","null");
        }
    }
    /**
     * 获取温度通过id
     * @param id
     * @return
     */
    @GetMapping("/{id}")
    public R SelectTemperatureById(@PathVariable Integer id){
        try {
            int roomTemperature = pagerService.getRoomTemperature(id);
            return new R(true,"200",roomTemperature);
        }catch (Exception e){
            e.printStackTrace();
            return new R(false,"500","null");
        }
    }
}
mapper

        这里使用了mybatis,使用@Mapper实现了自动代理,通过使用注解的方式进行SQL语句的书写,@Select是查询语句,@Update是更新数据语句,分别实现了温度的获取和温度的上传。

package ***.example.pager.mapper;

import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;

@Mapper
public interface Temperature {

    @Select("select Temperature from pagerRt where id=#{id}")
    int getTemperature(int id);
    @Update("UPDATE pagerRt set Temperature = #{Temperature} where id = #{id}")
    void updateTemperature(int id,int Temperature);
}
pojo

        为了统一响应数据结构,因此自定义了一个名为R的类,规定了response所响应的数据结构,有三个字段:flag(业务执行结果是否成功),message(返回结果的信息),data(返回的数据)。这样的好处是,方便前端对返回返回数据的获取,固定了获取格式,使得代码整洁统一,便于维护。

package ***.example.pager.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class R {
    private boolean flag;//执行结果,true为执行成功 false为执行失败
    private String message;//返回结果信息
    private Object data;//返回数据
}
service
pagerService

        pagerService接口中有俩个方法前面也有所提到一个是getRoomTemperature,一个是updateTemperature。

package ***.example.pager.service;

import org.springframework.stereotype.Service;

@Service
public interface pagerService {
    int getRoomTemperature(Integer id);
    void updateTemperature(int id,int Temperature);
}
pagerServiceImpl

        pargerServiceImpl为pagerService接口的实现类,实现了接口中的两个方法,并进行了相关业务的操作,具体操作也是通过之前提到的Mapper中的两个数据库操作的语句进行实现。 

package ***.example.pager.service.impl;

import ***.example.pager.mapper.Temperature;
import ***.example.pager.service.pagerService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.***ponent;

@***ponent
public class pagerServiceImpl implements pagerService {
    @Autowired
    private Temperature temperature;
    @Override
    public int getRoomTemperature(Integer id) {
        return temperature.getTemperature(id);
    }

    @Override
    public void updateTemperature(int id, int Temperature) {
        temperature.updateTemperature(id,Temperature);
    }
}
application.yml

        该文件是配置文件,由于项目的简单,配置内容也相对较少,就是关于端口号的配置,Mysql数据库的配置,还有mybatis-plus的配置。

server:
  port: 81

spring:
  datasource:
    druid:
      driver-class-name: ***.mysql.cj.jdbc.Driver
      url: jdbc:mysql://xxx.xxx.xxx.xxx:3306/pager?serverTimezone=UTC
      username: root
      password: 6d35ddeaddf92a38

mybatis-plus:
  global-config:
    db-config:
      id-type: auto
pages

        该目录下存放的是前端页面的HTML文件,这里面我们使用了element-ui框架进行设计,主要的重点在于MQTT协议的使用,还用对后端接口请求的发送。

MQTT

        下面的代码是关于MQTT的一些配置和发送消息代码,以及MQTT的初始化,options中的URL是MQTT服务器地址,Topic以及clientid要和ESP8266中设置的一致,不要按照我的来,根据自己的情况进行设置即可。

       options: {
                    url: 'ws://test.ranye-iot.***:8080',
                    // 需要修改
                    topic: 'connect_all_esp8266_mqtt_shanguqinliu_yinshuiji_topic',
                    connectTimeout: 5000,
                    clientId: 'connect_all_esp8266_mqtt_shanguqinliu_yinshuiji_' + new Date().getTime(),
                    clean: false,
                    keepAliveInterval: 30
                }
            /**
             * 发送消息
             */
            mqttPublish(status) {
                // 向指定topic发送消息,topic要保持一致
                this.client.publish(this.options.topic, status.toString(), {
                    qos: 1
                });
            },
            /**
             * mqtt初始化
             */
            mqttConf() {
                // 链接mqtt
                this.client = mqtt.connect(this.options.url, this.options);
                // 链接成功回调方法
                this.client.on('connect', function() {
                    myVue.client.subscribe(myVue.options.topic, function(err) {
                        if (!err) {
                            console.log('订阅成功:', myVue.options.topic)
                        } else {
                            console.log('订阅失败:', myVue.options.topic, err)
                        }
                    })
                }).on('reconnect', function(error) {
                }).on('error', function(error) {
                }).on('end', function() {
                }).on('message', function(topic, message) {
                    // 接收到消息
                    myVue.status = Number(message);
                    myVue.descTextStyle = {
                        color: myVue.color[Number(message)]
                    };
                });
            }
        }
HTTP

        下面的代码是HTTP请求的代码,以获取温度的代码为例,使用的是axios构造请求体和设置请求方式,发送异步请求。并且多响应的数据进行获取,加载到前端页面上。

            /**
             * 获取温度
             * @constructor
             */
            getRoomTemperature(){
                var that=this;
                axios.get("/pager/1",{
                    id: 1
                }).then((resp)=>{
                    if (resp.data.flag){
                        console.log(resp)
                        that.RoomTemperature = resp.data.data;
                    }
                })
                const element = document.querySelector('.dishext');
                if (this.RoomTemperature>70){
                    this.openAudio(1);
                    element.style.color = 'red';
                }else if (this.RoomTemperature>40&&this.RoomTemperature<70){
                    this.openAudio(0);
                    element.style.color = 'yellow';
                }else {
                    this.openAudio(0);
                    element.style.color = 'blue';
                }
            },
            openAudio(Start){
                const audio = document.getElementById('myAudio');
                if (Start ===1){
                    audio.play();
                }else {
                    audio.pause();
                }
            }
 完整代码

        下面是前端页面的完整代码,里面的难度不是特别大,有问题可以信息我或者留言我们讨论。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-***patible" content="IE=edge">
    <!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! -->
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0,user-scalable=no,minimal-ui">
    <meta name="description" content="">
    <meta name="author" content="">
    <title>寻呼手机端</title>
    <script type="text/javascript" src="../plugins/js/vue.min.js"></script>
    <script type="text/javascript" src="../plugins/js/iview.min.js"></script>
    <script src="../plugins/js/mqtt.js"></script>
    <link rel="stylesheet" type="text/css" href="../plugins/elementui/index.css">
    <script type="text/javascript" src="../plugins/vue/vue.js"></script>
    <script type="text/javascript" src="../plugins/elementui/index.js"></script>
    <script type="text/javascript" src="../plugins/elementui/axios.min.js"></script>
    <script type="text/javascript" src="https://cdn.bootcdn.***/ajax/libs/qs/6.11.0/qs.js"></script>
</head>
<div class="app" id="dishbody" style="background-image: url('https://shanguqinliu.oss-***-beijing.aliyuncs.***/49e24e79a9432c8e0632ad8477***735.jpg')">
    <audio muted="muted" id="myAudio" src="../Ring/Warn.mp3"></audio>
    <el-container>
        <el-main>
            <h2 class="dishext" style="font-size:30px;font-family:'华文宋体'">{{'当前温度:'+RoomTemperature+'摄氏度'}}</h2>
        </el-main>
        <el-footer>
            <el-input class="input" type="text" placeholder="请输入ID"  v-model="form.id"  clearable>
                <template slot="prepend" style="height: 60px;" >ID</template>
            </el-input>
            <div @click="SendId()" style="text-align: center; width: 330px;height:200px; line-height:600px;">
                <img :src="showImg[0]" class="img" tyle="display: inline-block; vertical-align: middle;"/>
            </div>
        </el-footer>
    </el-container>
</div>
<script>
    const myVue =new Vue({
        el: "#dishbody",
        props: {
            msg: String
        },
        data() {
            return {
                form: {
                    id: '',
                    other: ''
                },
                color: ['#E9E9E9', '#19BF6C'],
                showImg: ['../img/Call.png'],
                descTextStyle: {
                    color: '#E9E9E9'
                },
                RoomTemperature:23,
                audioStart:0,
                client: null,
                options: {
                    url: 'ws://test.ranye-iot.***:8080',
                    // 需要修改
                    topic: 'connect_all_esp8266_mqtt_shanguqinliu_yinshuiji_topic',
                    connectTimeout: 5000,
                    clientId: 'connect_all_esp8266_mqtt_shanguqinliu_yinshuiji_' + new Date().getTime(),
                    clean: false,
                    keepAliveInterval: 30
                }
            }
        },
        methods: {
            /**
             * 获取温度
             * @constructor
             */
            getRoomTemperature(){
                var that=this;
                axios.get("/pager/1",{
                    id: 1
                }).then((resp)=>{
                    if (resp.data.flag){
                        console.log(resp)
                        that.RoomTemperature = resp.data.data;
                    }
                })
                const element = document.querySelector('.dishext');
                if (this.RoomTemperature>70){
                    this.openAudio(1);
                    element.style.color = 'red';
                }else if (this.RoomTemperature>40&&this.RoomTemperature<70){
                    this.openAudio(0);
                    element.style.color = 'yellow';
                }else {
                    this.openAudio(0);
                    element.style.color = 'blue';
                }
            },
            openAudio(Start){
                const audio = document.getElementById('myAudio');
                if (Start ===1){
                    audio.play();
                }else {
                    audio.pause();
                }
            }
            ,
            /**
             * 呼叫ID
             */
            SendId(){
                this.$message({
                    type:"su***ess",
                    message:"呼叫请求已发送"
                })
                let Id = '$'+this.form.id;
                console.log(Id);
                this.mqttPublish(Id);
            },
            /**
             * 发送消息
             */
            mqttPublish(status) {
                // 向指定topic发送消息,topic要保持一致
                this.client.publish(this.options.topic, status.toString(), {
                    qos: 1
                });
            },
            /**
             * mqtt初始化
             */
            mqttConf() {
                // 链接mqtt
                this.client = mqtt.connect(this.options.url, this.options);
                // 链接成功回调方法
                this.client.on('connect', function() {
                    myVue.client.subscribe(myVue.options.topic, function(err) {
                        if (!err) {
                            console.log('订阅成功:', myVue.options.topic)
                        } else {
                            console.log('订阅失败:', myVue.options.topic, err)
                        }
                    })
                }).on('reconnect', function(error) {
                }).on('error', function(error) {
                }).on('end', function() {
                }).on('message', function(topic, message) {
                    // 接收到消息
                    myVue.status = Number(message);
                    myVue.descTextStyle = {
                        color: myVue.color[Number(message)]
                    };
                });
            }
        },
        mounted() {
            that = this;
            var t2 = window.setInterval("that.getRoomTemperature()",3000);
            this.mqttConf();
        }
    })
</script>
<style scoped>
    #dishbody {
        width: 100%;
        height: 100%;
        min-width: 50px;
        background-size: 100% 100%;
        background-position: center center;
        overflow: auto;
        background-repeat: no-repeat;
        position: fixed;
        line-height: 100%;
        padding-top: 0px;
    }
    .input {
        margin-top: 60px;
        width: 343px;
    }
    .dishext {
        margin-bottom: 20px;
        line-height: 50px;
        text-align: center;
        font-size: 30px;
        font-weight: bolder;
        color: rgb(150, 164, 232);
        text-shadow: 2px 2px 4px #000000;
    }
    .dishdata {
        width: 320px;
        height: 300px;
        transform: translate(-50%);
        margin-left: 50%;
    }
    .tool {
        display: flex;
        justify-content: space-between;
        color: #606266;
    }
    .rem{
        margin-left: 40px;
    }
    .remleft{
        margin-left: -30px;
    }
    .shou {
        cursor: pointer;
        color: #606266;
    }
    .butt {
        margin-top: 10px;
        text-align: center;
    }
    .app {
        max-width: 750px;
        margin: 0 auto;
    }
</style>
</body>
</html>

        下面是前段页面的效果图展示,当获取到不同的温度时候字体的颜色有所不同,0~40度为蓝色;41~69为黄色;大于70度为红色,并且伴随有警报声。

小结

        代码和文件比较多,如果想参考可以到评论区留言,我私发给你。文中有不清楚的地方也可以私信我,或者评论区留言。本文关注度高的话会更新最终部分的内容,分享给大家,制作不易,请大家多多评论,多多点赞转发!!!

转载请说明出处内容投诉
CSS教程_站长资源网 » 《物联网反向呼叫项目》下(JaveWeb部分)

发表评论

欢迎 访客 发表评论

一个令你着迷的主题!

查看演示 官网购买