In article 1 and 2, we matched externally submitted data (such as form data) to the Request layer model by frame binding, and externally displayed data was converted to the Response layer model by copier function.
- Request layer: The model accepts external submitted data and filters and verifies the correctness of external data;
- Response layer: display data externally, hide sensitive fields or unnecessary fields;
We use three real cases to demonstrate the flexibility of these two layers
Case 1: Amount unit conversion
In the development of the project, most of the units of amount are accurate to minutes. In the database, the data type of amount is int, which can effectively avoid most floating point calculation problems, but there will be inconsistent amount units: 1. User withdrawal is in units of yuan. For example, when a user enters withdrawal amount 10.5, it corresponds to the Request layer
Let’s look at the request layer conversion. The code is as follows:
Technical selection: Precision computing library Decimal
package request
type MoneyS struct {
Val int
}
func (req *MoneyS) UnmarshalJSON(b []byte) error {
float, err := strconv.ParseFloat(string(b),64)
iferr ! =nil {
return err
}
if float <= 0 {
return errors.New("The amount cannot be negative.")
}
req.Val = int(decimal.NewFromFloat(float).Mul(decimal.NewFromFloat(100)).IntPart())
return nil
}
func (req *MoneyS) Value(a) int {
return req.Val
}
Copy the code
Code analysis: custom Money structure, the implementation of UnmarshalJSON function, floating point conversion to integer type.
How to convert response layer, the code is as follows:
package response
type User struct {
ID int `json:"id"`
Nickname string `json:"nickname"`
Money Money `json:"money"`
}
type Money int
func (resp Money) MarshalJSON(a) ([]byte, error) {
d, _ := decimal.NewFromFloat(float64(resp)).Mul(decimal.NewFromFloat(0.01)).Float64()
str := fmt.Sprintf("%.2f", d)
return []byte(str), nil
}
Copy the code
Code analysis: custom Money structure, MarshalJSON function to achieve the conversion of integer type into two floating point number.
Case 2: Automatic image URL interception and completion
In the scenario where the user updates the profile picture, the server returns the profile picture address generated by the user uploading the profile picture and displays the page, for example, img.test.com/header.jpg. If there is no problem with the user viewing the profile picture, the server submits the profile picture address to the database. In order to save database space, Header. JPG image name will only be saved, the domain name will be omitted, but when the user views the user information, the server will return the image address and require the complete image address: 1. When the user submits the complete profile picture address, the image name needs to be captured, which corresponds to the Request layer. 2
How to intercept request layer, the code is as follows:
package request
type UserUpdate struct {
HeaderImage ImageURL `form:"headerImage"`
}
type ImageURL string
func (req *ImageURL) Name(a) string {
return strings.Replace(string(*req), "http://img.test.com/"."".- 1)}Copy the code
Code analysis: Create a string alias, ImageURL, and implement the Name function to capture the Name of the image. You can also implement the UnmarshalJSON function to capture the Name of the image, as described in the Money structure. The main idea here is to show a variety of ways to solve the problem.
How to complete the response layer, the code is as follows:
package response
type ImageURL string
func (resp ImageURL) MarshalJSON(a) ([]byte, error) {
url := fmt.Sprintf(`"%s"`."http://img.test.com/" + resp)
return []byte(url), nil
}
Copy the code
Code analysis: new string alias ImageURL structure, implement MarshalJSON function, automatically complete the image address. Source link
Case 3: Time format conversion
package response
import (
"fmt"
"time"
)
type DateTime struct {
time.Time
}
func (dt DateTime) MarshalJSON(a) ([]byte, error) {
if dt.Time.IsZero() {
return []byte(""""), nil // Returns an empty string if time is empty
//return []byte("null"), nil // Returns null if time is null
}
formatted := fmt.Sprintf(`"%s"`, dt.Time.Format("The 2006-01-02 15:04:05"))
return []byte(formatted), nil
}
func (dt *DateTime) Scan(v interface{}) error {
value, ok := v.(time.Time)
if ok {
*dt = DateTime{Time: value}
return nil
}
return fmt.Errorf("can not convert %v to timestamp", v)
}
Copy the code
Case 4: Webpage image multiple domain name to improve loading speed
For example, Chrome supports a maximum of 6 concurrent requests for the same domain name. Many websites use multiple image domain names to improve the speed of image loading. For example, the picture loading waterfall stream on the homepage of JINGdong is shown in the following figure. Img13, img30, img10, imG20, img13, img10How to implement this function can be in the above ImageURL MarshalJSON function, randomly to complete the image name of the different image domain
During project development, parameters submitted externally and data displayed externally are often changeable requirements, so I hope readers can have a good experience of it. Recall that they did not encounter such problems in development, and proficiently apply request layer and response layer.