golang 实现打车
吕致盈 2023-09-12编程经验
前言打车软件是现代生活城市生活必需品之一。为了满足这个需求,我们将使用Golang编程语言来实现一款打车软件。我们会使用技术栈Vue,React和Flutter。我们将会把打车软件原型设计出来
前言
打车软件是现代生活城市生活必需品之一。为了满足这个需求, 我们将使用Golang编程语言来实现一款打车软件。 我们会使用技术栈Vue,React和Flutter。我们将会把打车软件原型设计出来,并实现核心功能。设计原理
首先,让我们来设计打车软件,确定软件主要的需求和功能。在这里,我们必须确保软件具有以下特征:1. 用户可以查看地图或输入地址, 并以此为起点或终点来预订出租车.
2. 用户在订车之前可以查看价格。
3. 用户可以看到预订状态以及预计到达的时间,还可以取消或修改预定。
4. 司机可以查看订单,并以有效的方式/时间到达出租车站点。
以上是我们打车软件的核心功能,下面我们将从这几个方面来实现这个应用程序。首先,让我们开始编写第一个组件。package main import ( "fmt" "time" ) type Passenger struct { Name string Rating int } type Driver struct { Name string Rating int } type Car struct { Model string Plate string } type Order struct { Passenger Passenger Driver Driver Car Car PickUp string DropOff string Status string Price int Time time.Time } func main() { fmt.Println("Creating Passenger") pas := Passenger{Name: "Alice", Rating: 5} fmt.Println("Creating Driver") drv := Driver{Name: "Bob", Rating: 4} fmt.Println("Creating Car") car := Car{Model: "Toyota", Plate: "AAA123"} fmt.Println("Creating Order") ord := Order{ Passenger: pas, Driver: drv, Car: car, PickUp: "123 Park St", DropOff: "456 1st Ave", Status: "Pending", Price: 50, Time: time.Now(), } fmt.Printf("The %s %s is %d years old\n", drv.Name, drv.Rating) fmt.Printf("The %s %s has %d rating\n", pas.Name, pas.Rating) fmt.Printf("The %s %s is on the way\n", ord.Driver.Name, ord.Status) }在上面的代码中,我们定义了`Passenger`, `Driver`, `Car` 和 `Order`几个类型,他们都是我们在打车软件中使用到的关键类型。我们定义了订单, 客户, 司机和汽车,然后我们创建了一个订单,然后输出订单上的一些信息,如:“司机名字 Bob 的评分为 4”, “Alice 的评分为5”以及“状态为待接单”。此时我们已经可以执行我们的第一个 Golang 程序了。
开发核心组件
为了实现我们的核心功能,我们需要定义一些数据结构和函数来完成任务。 在我们的组件中,我们将结合 Golang 中的并发和网络特性。1. 用户可以查看地图或输入地址, 并以此为起点或终点来预订出租车.
首先,我们需要为用户提供一个界面,用户可以在此查看地图和输入地址。为此,我们将使使用 Vue 来创建前端页面,用户将从页面中输入出发点和目的地,并将结果发送到我们的后端系统中。在此之前,首先创建一个简单的 `main.go` 文件用于接收前端页面中传过来的数据,并简单的演示数据的传递和输出。package main import ( "net/http" "fmt" "encoding/json" "github.com/gorilla/mux" ) type Trip struct { Start string End string Distance int Price int } func handleRequest() { router := mux.NewRouter().StrictSlash(true) router.HandleFunc("/", homePage) router.HandleFunc("/trip", createTrip).Methods("POST") fmt.Println("Starting server...") http.ListenAndServe(":8080", router) } func homePage(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "Welcome to the HomePage!") fmt.Println("Endpoint hit: homePage") } func createTrip(w http.ResponseWriter, r *http.Request) { decoder := json.NewDecoder(r.Body) var t Trip err := decoder.Decode(&t) if err != nil { panic(err) } defer r.Body.Close() fmt.Printf("Trip created from %s to %s with distance %d km and price %d", t.Start, t.End, t.Distance, t.Price) } func main() { handleRequest() }在上述代码中,我们创建了一个 `Trip` 类型,以便存储用于创建订单所需的字段,`Start` 和 `End` 表示出发点和目的地,`Distance` 和 `Price` 表示预计的距离和价格。我们的 `createTrip` 函数在接收前端请求时解析 `JSON` 格式的表单数据,创建一个 `Trip` 类型并解码数据,然后在控制台中打印出创建的行程的信息。现在我们可以使用 Python 中的内置功能(如 requests 库和 json 模块)来向我们的后端发送数据,以便创建新旅程。
import requests import json url = "http://localhost:8080/trip" data = { 'Start': '123 Park St', 'End': '456 1st Ave', 'Distance': 10, 'Price': 30 } response = requests.post(url, json.dumps(data)) print(response.content)在我们的 Golang 后端中,我们将从请求中解码这些参数,并使用它们来创建新的行程。 接下来,让我们来完成第二个功能。
2. 用户在订车之前可以查看价格。
为了让用户查看价格,我们需要使用一个第三方 API 来预测行程的距离。如果最后的价格与用户的预期不一致,用户是不喜欢我们的应用程序的。因为我们需要使用现成的 API,我们将以 Go 的方式调用 Google 地图 API。package main import ( "net/http" "fmt" "encoding/json" "io/ioutil" "github.com/gorilla/mux" ) type Location struct { Lat float64 `json:"lat"` Lng float64 `json:"lng"` } type Place struct { PlaceId string `json:"place_id"` Name string `json:"name"` Address string `json:"formatted_address"` Location Location } type Directions struct { Distance float64 `json:"distance"` Duration float64 `json:"duration"` } func handleRequest() { router := mux.NewRouter().StrictSlash(true) router.HandleFunc("/", homePage) router.HandleFunc("/distance", getDistance).Methods("GET") fmt.Println("Starting server...") http.ListenAndServe(":8080", router) } func homePage(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "Welcome to the HomePage!") fmt.Println("Endpoint hit: homePage") } func getDistance(w http.ResponseWriter, r *http.Request) { apiKey := "my_google_api_key" origin := r.FormValue("origin") destination := r.FormValue("destination") url := fmt.Sprintf("https://maps.googleapis.com/maps/api/directions/json?origin=%s&destination=%s&key=%s", origin, destination, apiKey) resp, err := http.Get(url) if err != nil { panic(err) } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { panic(err) } var result map[string]interface{} json.Unmarshal([]byte(body), &result) routes := result["routes"].([]interface{}) route := routes[0].(map[string]interface{}) legs := route["legs"].([]interface{}) leg := legs[0].(map[string]interface{}) distance := leg["distance"].(map[string]interface{})["text"].(string) duration := leg["duration"].(map[string]interface{})["text"].(string) fmt.Printf("Distance: %s\nDuration: %s\n", distance, duration) } func main() { handleRequest() }在上述代码中,我们将 Google Maps 中的 `Direction API` 与我们应用程序相连接。`getDistance` 函数从请求中获取起点和终点的地理位置,然后通过 `Google Maps Directions API` 来获取路线,并计算出两点间的距离和时间。我们还可以使用 Python 或任何其他编程语言作为客户端,向接口提交起点和终点,并获取距离和时间。 现在,我们的用户可以查看价格了。但是,用户还需要知道预计的到站时间和司机的状态。
3. 用户可以看到预订状态以及预计到达的时间,还可以取消或修改预定。
为了实现以上的功能,我们需要一个能够实时查询车辆位置、行驶方向和预计时间的系统。我们将使用第三方 API —— Lyft,来获取司机位置和预计到达时间。package main import ( "net/http" "fmt" "encoding/json" "time" "github.com/gorilla/mux" ) type DriverLocation struct { DriverId int `json:"driver_id"` Lat float64 `json:"lat"` Lng float64 `json:"lng"` } type Eta struct { Minutes int `json:"eta"` } func handleRequest() { router := mux.NewRouter().StrictSlash(true) router.HandleFunc("/", homePage) router.HandleFunc("/driver", getDriverLocation).Methods("GET") router.HandleFunc("/eta", getEta).Methods("GET") fmt.Println("Starting server...") http.ListenAndServe(":8080", router) } func homePage(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "Welcome to the HomePage!") fmt.Println("Endpoint hit: homePage") } func getDriverLocation(w http.ResponseWriter, r *http.Request) { id := r.FormValue("id") apiKey := "my_lyft_api_key" url := fmt.Sprintf("https://api.lyft.com/v1/drivers/%s/location", id) client := &http.Client{} req, err := http.NewRequest("GET", url, nil) if err != nil { panic(err) } req.Header.Add("Authorization", "Bearer "+apiKey) resp, err := client.Do(req) if err != nil { panic(err) } defer resp.Body.Close() decoder := json.NewDecoder(resp.Body) var loc DriverLocation err = decoder.Decode(&loc) if err != nil { panic(err) } fmt.Printf("Driver %d is at location (%f, %f)", loc.DriverId, loc.Lat, loc.Lng) } func getEta(w http.ResponseWriter, r *http.Request) { apiKey := "my_lyft_api_key" start := r.FormValue("start") url := fmt.Sprintf("https://api.lyft.com/v1/eta?start_lat=%s&start_lng=%s", start, apiKey) client := &http.Client{} req, err := http.NewRequest("GET", url, nil) if err != nil { panic(err) } req.Header.Add("Authorization", "Bearer "+apiKey) resp, err := client.Do(req) if err != nil { panic(err) } defer resp.Body.Close() decoder := json.NewDecoder(resp.Body) var eta Eta err = decoder.Decode(&eta) if err != nil { panic(err) } fmt.Printf("Eta is %d minutes", eta.Minutes) } func main() { handleRequest() }在上述文件中,我们使用 Lyft API 来获取司机的实时地理位置和预计到达时间。`getDriverLocation` 函数将获取到的位置信息记录在日志中,而 `getEta` 函数将打印出预计到达的时间。我们还可以编写代码以获取更多信息,并使用这些信息来跟踪司机的位置和状态。理论上,我们的客户端可以通过每秒查询接口的方式来实时更新司机的位置和状态。
4. 司机可以查看订单,并以有效的方式/时间到达出租车站点。
我们已经实现了大部分的功能,现在我们将完成这个最后的功能。我们可以在已经定义的 `Order` 类型上,新增一个 `Location` 字段,来存储感兴趣的地点。我们需要更新该订单状态为“进行中”时,记录司机的位置,并在到达站点后更新状态。为此,我们需要一个相对准确的位置供司机查看,并存储下司机的最后位置,以便向客户端提供具有可操作性的接口。 下面是一个用 Go 编写的简单的订单完成程序。package main import ( "net/http" "fmt" "encoding/json" "time" "github.com/gorilla/mux" ) type Location struct { Lat float64 `json:"lat"` Lng float64 `json:"lng"` } type Passenger struct { Name string Rating int } type Driver struct { Id int `json:"id"` Name string Rating int } type Car struct { Model string `json:"model"` Plate string `json:"plate"` } type Order struct { Passenger Passenger `json:"passenger"` Driver Driver `json:"driver"` Car Car `json:"car"` PickUp Location `json:"pickup"` DropOff Location `json:"dropoff"` Status string `json:"status"` Price int `json:"price"` Time time.Time `json:"time"` } type DriverLocation struct { DriverId int `json:"driver_id"` Lat float64 `json:"lat"` Lng float64 `json:"lng"` } func handleRequest() { router := mux.NewRouter().StrictSlash(true) router.HandleFunc("/", homePage) router.HandleFunc("/order", createOrder).Methods("POST") router.HandleFunc("/order/{id}", getOrder).Methods("GET") router.HandleFunc("/order/{id}", updateOrder).Methods("PUT") router.HandleFunc("/driver", updateDriverLocation).Methods("PUT") fmt.Println("Starting server...") http.ListenAndServe(":8080", router) } func homePage(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "Welcome to the HomePage!") fmt.Println("Endpoint hit: homePage") } func createOrder(w http.ResponseWriter, r *http.Request) { decoder := json.NewDecoder(r.Body) var ord Order err := decoder.Decode(&ord) if err != nil { panic(err) } defer r.Body.Close() fmt.Printf("Order created for passenger %s\n", ord.Passenger.Name) } func getOrder(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) id := vars["id"] apiKey := "my_google_api_key" url := fmt.Sprintf("https://maps.googleapis.com/maps/api/geocode/json?address=%s&key=%s", id, apiKey) resp, err := http.Get(url) if err != nil { panic(err) } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { panic(err) } var result map[string]interface{} json.Unmarshal([]byte(body), &result) geometry := result["results"].([]interface{}) geometry1 := geometry
很赞哦! ()