preface
I have already had a general understanding of the basic syntax of Go, but there is still a long way to Go before I can really learn a language. Today I learned a lot about the web banking project in the tutorial. Previous articles :Golang(1) — Rookie handbook # Nuggets article # juejin.cn/post/695215…
Project planning
This project is to realize a web-based banking service based on Go, and its basic functions are as follows:
- Display account information: user name, mobile phone type, phone number, balance, etc.
- Deposit;
- A withdrawal;
- Transfer (i.e. transfer from account A to account B);
- Automatic test function;
What can be learned through this project?
- Basic architecture of Go project;
- Net/HTTP usage;
- Go automatic test code writing;
The project architecture
The code tree of this project is as follows:
Bankapi is the main function of the program, which is responsible for calling the function interface provided by Bankcore to realize the CORRESPONDING HTTP. Bankcore is the function that implements bank operations;
Project details
See the project code below, and refer to the notes for a detailed explanation of the code:
//main.go package main import ( "encoding/json" "fmt" "github.com/msft/bank" "log" "net/http" "strconv" ) // CustomAccount ... type CustomAccount struct { *bank.Account } // Statement ... func (c *CustomAccount) Statement() string { json, err := json.Marshal(c) if err ! = nil {return err.error ()} return string(json)} // Float and Account mapping Var accounts = map[float64]*CustomAccount{} func main() { accounts[1001] = &CustomAccount{ Account: &bank.Account{ Customer: bank.Customer{ Name: "John", Address: "Los Angeles, California", Phone: "(213) 555 0147", }, Number: 1001, }, } accounts[1002] = &CustomAccount{ Account: &bank.Account{ Customer: bank.Customer{ Name: "Mark", Address: "Irvine, California", Phone: "(949) 555 0198", }, Number: } //handler is equivalent to the callback function: After user access, Http.handlefunc ("/statement", statement) http.handlefunc ("/deposit", deposit) http.handlefunc ("/withdraw", Withdraw) http.handlefunc ("/transfer", transfer) // Start an HTTP server with the specified listener address and handler. // The handler parameter is usually nil, which means using the package variable DefaultServeMux as the handler. // The Handle and HandleFunc functions can add handlers to DefaultServeMux.Fatal(http.listenandServe ("localhost:8000", Func deposit(w http.ResponseWriter, req *http.Request) { numberqs := req.URL.Query().Get("number") amountqs := req.URL.Query().Get("amount") if numberqs == "" { fmt.Fprintf(w, "Account number is missing!" ) return } if number, err := strconv.ParseFloat(numberqs, 64); err ! = nil { fmt.Fprintf(w, "Invalid account number!" ) } else if amount, err := strconv.ParseFloat(amountqs, 64); err ! = nil { fmt.Fprintf(w, "Invalid amount number!" ) } else { account, ok := accounts[number] if ! ok { fmt.Fprintf(w, "Account with number %v can't be found!" , number) } else { err := account.Deposit(amount) if err ! = nil { fmt.Fprintf(w, "%v", err) } else { fmt.Fprintf(w, Func withdraw(w http.responsewriter)}}}} // req *http.Request) { numberqs := req.URL.Query().Get("number") amountqs := req.URL.Query().Get("amount") if numberqs == "" { fmt.Fprintf(w, "Account number is missing!" ) return } if number, err := strconv.ParseFloat(numberqs, 64); err ! = nil { fmt.Fprintf(w, "Invalid account number!" ) } else if amount, err := strconv.ParseFloat(amountqs, 64); err ! = nil { fmt.Fprintf(w, "Invalid amount number!" ) } else { account, ok := accounts[number] if ! ok { fmt.Fprintf(w, "Account with number %v can't be found!" , number) } else { err := account.Withdraw(amount) if err ! = nil { fmt.Fprintf(w, "%v", err) } else { fmt.Fprintf(w, Account.statement ())}}}} // Func transfer(w http.responsewriter, req *http.Request) { numberqs := req.URL.Query().Get("number") amountqs := req.URL.Query().Get("amount") destqs := req.URL.Query().Get("dest") if numberqs == "" { fmt.Fprintf(w, "Account number is missing!" ) return } if number, err := strconv.ParseFloat(numberqs, 64); err ! = nil { fmt.Fprintf(w, "Invalid account number!" ) } else if amount, err := strconv.ParseFloat(amountqs, 64); err ! = nil { fmt.Fprintf(w, "Invalid amount number!" ) } else if dest, err := strconv.ParseFloat(destqs, 64); err ! = nil { fmt.Fprintf(w, "Invalid account destination number!" ) } else { if accountA, ok := accounts[number]; ! ok { fmt.Fprintf(w, "Account with number %v can't be found!" , number) } else if accountB, ok := accounts[dest]; ! ok { fmt.Fprintf(w, "Account with number %v can't be found!" , dest) } else { err := accountA.Transfer(amount, accountB.Account) if err ! = nil { fmt.Fprintf(w, "%v", err) } else { fmt.Fprintf(w, Accounta.statement ())}}}} // Print the message to the callback function func Statement(w http.responsewriter, req *http.Request) { numberqs := req.URL.Query().Get("number") if numberqs == "" { fmt.Fprintf(w, "Account number is missing!" ) return } number, err := strconv.ParseFloat(numberqs, 64) if err ! = nil { fmt.Fprintf(w, "Invalid account number!" ) } else { account, ok := accounts[number] if ! ok { fmt.Fprintf(w, "Account with number %v can't be found!" , number) } else { json.NewEncoder(w).Encode(bank.Statement(account)) } } }Copy the code
//bank.go package bank import ( "errors" "fmt" ) // Customer ... type Customer struct { Name string Address string Phone string } // Account ... Func (a *Account) Deposit(amount float64) type Account struct {Customer Number int32 Balance float64} error { if amount <= 0 { return errors.New("the amount to deposit should be greater than zero") } a.Balance += amount Func (a *Account) Withdraw(amount float64) error {if amount <= 0 {return errors.New("the amount to withdraw should be greater than zero") } if a.Balance < amount { return errors.New("the amount to withdraw should be greater than the account's balance") } a.Balance -= amount return nil } // Statement ... func (a *Account) Statement() string { return fmt.Sprintf("%v - %v - %v", a.Number, a.Name, a.Balance) } // Transfer function func (a *Account) Transfer(amount float64, dest *Account) error { if amount <= 0 { return errors.New("the amount to transfer should be greater than zero") } if a.Balance < amount { return errors.New("the amount to transfer should be greater than the account's balance") } a.Withdraw(amount) dest.Deposit(amount) return nil } // Bank ... type Bank interface { Statement() string } // Statement ... func Statement(b Bank) string { return b.Statement() }Copy the code
The module configuration is as follows:
//bankapi/go.mod
module bankapi
go 1.16
require (
github.com/msft/bank v0.0.1
)
replace github.com/msft/bank => ../bankcore
Copy the code
//bankcore/go.mod
module github.com/msft/bank
go 1.16
Copy the code
In fact, the overall operation process of the above project can be represented by the following block diagram:
The results show
At this stage, HTML and GO have not been combined, so the webpage display is rather rough, and the corresponding HTTP request can only be realized by modifying the URL, the specific functions are as follows:
Display account information:
http://localhost:8000/statement?number=1001
Copy the code
Enter the url in the browser to display the corresponding account information (there are only two accounts in the code 1002 1001). Number =1001 indicates that the account is 1001. The result is:
Deposit:
http://localhost:8000/deposit?number=1001&amount=1000
Copy the code
The above URL means to deposit 1000 in account 1001 with the following result:
Withdrawals?
http://localhost:8000/withdraw?number=1001&amount=1000
Copy the code
The 1000 just saved was taken out again:
Can I make a transfer?
http://localhost:8000/transfer?number=1001&amount=1000&dest=1002
Copy the code
Transfer account 1001 from account 1000 to account 1002 (the original account 1002 had no money), the result is as follows:
I’ll write an HTML page later to visualize these actions (via buttons). Hopefully this project will help you familiarize yourself with the basic syntax of Go.
(To be continued)
The articles
Golang(1) — Rookie Handbook # Nuggets article # juejin.cn/post/695215…
The resources
Docs.microsoft.com/zh-cn/learn…