---
# System prepended metadata

title: Angular+Mqtt+PHP+MariaDB+Leaflet

---

# Angular+Mqtt+PHP+MariaDB+Leaflet
## [先參照前篇完成基本leafmap](https://hackmd.io/@109213067/BJBlg0Mio/https%3A%2F%2Fhackmd.io%2FuIjQMqtqQM64Z1LnXKzOgw%3Fview)
## 流程
Angular前端新增標記 -> PHP(傳給Mqtt) -> Angular接收Mqtt訊息 -> PHP(存進MariaDB) + 在Leaflet上新增標記 -> 顯示在Angular前端
## 程式碼
### MariaDB
* 新增table存放地圖標記(id，座標1，座標2，座標名稱)
```sql=1
CREATE TABLE `mqttMap` (`id` int(10) NOT NULL PRIMARY KEY auto_increment,`p1` varchar(50) NOT NULL,`p2` varchar(50) NOT NULL,`text` varchar(50) NOT NULL) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
```
### PHP
* 新增sendMqttMap.php(傳送地圖標記給Mqtt):
```php=1
<?php
header('Access-Control-Allow-Origin: *');
header('Content-Type: application/json; charset=UTF-8');
header('Access-Control-Allow-Methods: GET,POST,PUT,DELETE,OPTIONS');
header('Access-Control-Max-Age: 3600');
header('Access-Control-Allow-Headers: Content-Type,Access-Control-Allow-Headers, Authorization, X-Requested-With');
header('Cache-Control: no-cache, must-revalidate');
header('Expires: Sat, 26 Jul 1997 05:00:00 GMT');
header('Access-Control-Allow-Credentials: true');
$data = json_decode(file_get_contents("php://input"));
if (!isset($data->message)) {
  echo json_encode(['success' => 0, 'message' => 'field is empty!']);
  exit;
};
$message = $data->message;
//$message = "321";
require('vendor/autoload.php');

use \PhpMqtt\Client\MqttClient;
use \PhpMqtt\Client\ConnectionSettings;

$server   = '192.168.1.244'; // ip
$port     = 1883;
$clientId = rand(5, 15);
$username = 'emqx_user';
$password = null;
$clean_session = false;
$connectionSettings = new ConnectionSettings();
$connectionSettings
  ->setUsername($username)
  ->setPassword(null)
  ->setKeepAliveInterval(60)  // Last Will 設定
  ->setLastWillTopic('emqx/test/last-will')
  ->setLastWillMessage('client disconnect')
  ->setLastWillQualityOfService(1);
    
$mqtt = new MqttClient($server, $port, $clientId);

$mqtt->connect($connectionSettings);

// 發布 (topic_name, context)
$mqtt->publish('Map', $message, 0);
// 放開連線
$mqtt->disconnect();
?>
```
* 新增storeMqttMap.php(地圖標記存進資料庫):
```php=1
<?php
header('Access-Control-Allow-Origin: *');
header('Content-Type: application/json; charset=UTF-8');
header('Access-Control-Allow-Methods: GET,POST,PUT,DELETE,OPTIONS');
header('Access-Control-Max-Age: 3600');
header('Access-Control-Allow-Headers: Content-Type,Access-Control-Allow-Headers, Authorization, X-Requested-With');
header('Cache-Control: no-cache, must-revalidate');
header('Expires: Sat, 26 Jul 1997 05:00:00 GMT');
header('Access-Control-Allow-Credentials: true');
$servername = "localhost";
$username = "kenny";
$password = "Kenny061256";
$dbname = "test";

// Create connection
$conn = new mysqli($servername, $username, $password, $dbname);
//
$data = json_decode(file_get_contents("php://input"));
//echo json_encode($data->message);
if (!isset($data->p1)||!isset($data->p2)||!isset($data->text)) {
    echo json_encode(['success' => 0, 'message' => 'some fields are empty!']);
    exit;
};
// Check connection
if ($conn->connect_error) {
   die("Connection failed: " . $conn->connect_error);
   }
   $p1 = $data->p1;
   $p2 = $data->p2;
   $text = $data->text;
   $sql = "insert into `mqttMap`(p1,p2,text)values(";
   $sql .= "'".$p1."',";
   $sql .= "'".$p2."',";
   $sql .= "'".$text."')";
   //$conn->execute($sql);
   $conn->query($sql);
   $conn->close();

?>
```
### Angular
* data.service.ts新增呼叫sendMqttMap.php:
```c#=1
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Injectable } from '@angular/core';

@Injectable()
export class DataService {
    constructor(private http: HttpClient) {}
    getData() {
        const httpOptions = {
	        headers: new HttpHeaders({
                'Content-Type': 'application/json',
                'Authorization': 'Bearer ' + localStorage.getItem('token'),
	            'Access-Control-Alllow-Origin': '*',
		        'Access-Control-Allow-Methods': 'GET,POST,PUT,DELETE"'
	        })
	    };
	    return this.http.post('http://localhost/data.php', httpOptions);						
    }
    addData(job: Object){
	    return this.http.post('http://localhost/insert.php', job);
    }
    searchData(job: Object){
	    return this.http.post('http://localhost/search.php', job);
    }
    editData(job: Object){
	    return this.http.post('http://localhost/edit.php', job);
    }
    deleteData(job: Object){
        return this.http.post('http://localhost/delete.php', job);
    }
    sendMqtt(text: Object){
        return this.http.post('http://localhost/connectMqtt.php',text);
    }
    storeMqtt(text:Object){
        return this.http.post('http://localhost/storeMqtt.php',text);
    }
    sendMqttMap(text: Object){
        return this.http.post('http://localhost/sendMqttMap.php',text);
    }
    storeMqttMap(mark:Object){
        return this.http.post('http://localhost/storeMqttMap.php',mark);
    }
}
```
* leafmap.component.html新增輸入欄位:
```html=1
<h1>Map</h1>
<input #p1 placeholder="p1"/>
<input #p2 placeholder="p2"/>
<input #p3 placeholder="text"/>
<button (click)="sendMqtt(p1.value,p2.value,p3.value); p1.value='';p2.value='';p3.value=''">send</button>
<div class="map-container">
    <div class="map-frame">
      <div id="map"></div>
    </div>
</div>
```
* leafmap.component.ts新增接收、傳遞Mqtt、新增標記:
```c#=1
import { Component,OnInit} from '@angular/core';
import * as L from 'leaflet';
import { icon, Marker } from 'leaflet';
import { MqttService } from 'ngx-mqtt';
import { DataService } from '../data.service';

@Component({
  selector: 'app-leafmap',
  templateUrl: './leafmap.component.html',
  styleUrls: ['./leafmap.component.css']
})

export class LeafmapComponent{
  map:any;
  newMark:string="";
  MarkList:string[]=[];
  constructor(private dataService: DataService,private mqttService: MqttService) {}
  ngOnInit() {
    this.mqttService.connect();
    this.mqttService.observe('Map').subscribe((message)=>{
      this.newMark = message.payload.toString();
      this.MarkList = this.newMark.split(",");
      const mark = {p1:this.MarkList[0],p2:this.MarkList[1],text:this.MarkList[2]}
      this.dataService.storeMqttMap(mark).subscribe(response=>{
      });
      this.addMarker(this.MarkList[0],this.MarkList[1],this.MarkList[2]);
    });
    const iconRetinaUrl = 'assets/marker-icon-2x.png';
    const iconUrl = 'assets/marker-icon.png';
    const shadowUrl = 'assets/marker-shadow.png';
    const iconDefault = icon ({
      iconRetinaUrl,
      iconUrl,
      shadowUrl,
      iconSize: [25,41],
      iconAnchor: [12,41],
      popupAnchor: [1,-34],
      tooltipAnchor: [16,-28],
      shadowSize: [41,41]
    });
    Marker.prototype.options.icon = iconDefault;
    this.map = L.map('map', {
      center: [23.952672279106505, 120.92716871995295],
      zoom: 16
    });
    const tiles = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
      maxZoom: 19,
      minZoom: 3,
      attribution: '&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'
    });
    const marker1 = L
      .marker([23.952672279106505, 120.92716871995295],{title:'管院'})
      .addTo(this.map)
      .bindPopup("<h1>管院在這裡</h1>");
    const marker2 = L
      .marker([23.941804203963905, 120.9308004137981],{title:''})
      .addTo(this.map)
      .bindPopup("<h1>住的地方</h1>")
    const marker3 = L
      .marker([22.69037999999579, 120.32945971836486],{title:'管院'})
      .addTo(this.map)
      .bindPopup("<h1>我家啦</h1>")
    const marker4 = L
      .marker([23.128122197367723, 113.34752774482281],{title:'管院'})
      .addTo(this.map)
      .bindPopup("<h1>暨南大学</h1>")
    marker1.openPopup();
    tiles.addTo(this.map);
  }
  addMarker(p1:string,p2:string,text:string) {
    const marker4 = L
      .marker([this.convertNum(p1), this.convertNum(p2)],{title:text})
      .addTo(this.map)
      .bindPopup("<h1>"+text+"</h1>")
  }
  sendMqtt(p1:string,p2:string,text:string) {
    const addmark = {message:p1+","+p2+","+text};
    this.dataService.sendMqttMap(addmark).subscribe(response => {
      alert('send mark to Mqtt!');
      //window.location.reload();
    });
  }
  convertNum(text:string) {
    return parseFloat(text);
  }
}
```