一、表单的输入
表单是 Web 应用中非常中重要的组成部分,通过表单可以方法的让客户端和服务器进行数据的交互。Go 中对于 form 的处理非常方便,在 Request 中有专门的 form 处理方法。
以登录表单为例,新建一个登录表达 login.gtpl,表单内容如下:
代码语言:javascript复制<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8"/>
<title>Login Form</title>
</head>
<body>
<form action="http://localhost:9000/login" method="post">
USERNAME:<input type="text" name="username"> <br>
PASSWORD:<input type="password" name="password"> <br>
<input type="submit" value="Sing In">
</form>
</body>
</html>
上述表单收集的信息将会递交到服务器的 /login
,当用户输出信息并点击登录的时候,会跳转到服务器的路由 login 里面,所以服务器首先要判断请求时 POST 还是 GET。
http 包中有一个简单的方法可以获取请求方式 r.Method
方法,main.go 文件的代码如下:
import (
"fmt"
"html/template"
"log"
"net/http"
"strings"
)
//noinspection ALL
func main(){
http.HandleFunc("/login", login)
err := http.ListenAndServe(":9000", nil)
if err != nil {
log.Fatal("ListenAndServe: ", err)
}
}
func login(w http.ResponseWriter, r *http.Request){
fmt.Println("method", r.Method) // 获取请求的方式
// GET 请求,跳转至登录界面
if r.Method == "GET" {
t, _ := template.ParseFiles("form/login.gtpl")
t.Execute(w, nil)
} else {
// 请求的是登录数据,执行登录逻辑
r.ParseForm()
fmt.Println("Form Data:", r.Form)
fmt.Println("username: ", r.Form["username"])
fmt.Println("password: ", r.Form["password"])
}
}
上述代码中的 login 方法通过判断语句判断请求方式,如果是 GET 请求则跳转到 login 界面,注意这里填写 login.gtpl 文件的位置一定要准确,否则会报错。
如果不是 GET 请求则会处理提交的数据,其中 r.ParseForm()
会解析 URL,针对 POST 请求则会解析请求体,若没有这一行代码是无法获取的 POST 请求提交的参数的,最后会将提交的数据输出到控制台。
接着就是 main 函数中的路由和端口配置。执行 main 函数启动 Web 服务,在浏览器中输入 localhost:9000/login,浏览器显示如下页面:
当是 GET 请求时显示登录页面,输入用户名和密码,点击提交;此时是 POST 请求,则会执行 esle 代码块,即将提交的信息输出到控制台:
二、表单的验证
在获取到了用户提交的数据之后,存储到数据库之前,需要对用户提交的数据进行校验,校验可以在前端通过 JavaScript 实现,也可以在服务端进行校验。
必填字段
针对表单中的必填字段,可以通过获取提交的数据的长度来判断提交的数据是否为空:
代码语言:javascript复制if len(r.Form["username"][0]) == 0 {
// 字符串为空的处理
}
r.Form
对不同类型的表单元素的留空有不同的处理,对于空文本框、空文本区域以及文件上传,元素的值为空值,而如果是未选中的复选框和单选按钮,则根本不会在 r.Form
中产生相应的条目,在实际获取程序值的时候需要通过 r.Form.Get()
来获取,若字段不存在,则获取的是空值,但是通过这种方式只能获取单个的值,如果是 map 还需要通过 r.Form["username"][0]
这种方式获取。
数字
如果要确保单选框中的输入只能是数字类型,比如获取用户的年龄,可以先转换成 int 类型,然后在处理:
代码语言:javascript复制age, err := strconv.Atoi(r.Form.Get("age"))
if err != nil {
// 转换为 int 类型出错,说明用户的输入不是数字
}
// 用户输入的数字转换成功,进行下一步操作
if age > 100 {
// 年龄超过指定范围
}
还可以通过正则表达式的方式来获取:
代码语言:javascript复制if m, _ := regexp.MatchString("^[0-9] $", r.Form.Get("age")); !m {
return false
}
但是正则表达式的速度相对来说会比较慢。
中文和英文
如果想要获取表单中的中文字符,并确保获取的是正确的中文字符,需要进行验证,而不是随便输入,中文只有通过正则来验证:
代码语言:javascript复制if m, _ := regexp.MatchString("^[\x{4e00}-\x{9fa5}] $", r.Form.Get("chineseName")); !m {
return false
}
如果要获取表单中的英文值,也可以通过正则表达式:
代码语言:javascript复制if m, _ := regexp.MatchString("^[a-zA-Z] $", r.Form.Get("firstName")); !m {
return false
}
Email, 电话号码和电话号码
验证用户输入的 Email 是否正确,可以通过以下方式验证:
代码语言:javascript复制if m, _ := regexp.MatchString(`^([w._]{2,10})@(w{1,}).([a-z]{2,4})$`,
r.Form.Get("email")); !m {
fmt.Println("no")
}else{
fmt.Println("yes")
}
手机号码可以通过如下方式验证:
代码语言:javascript复制if m, _ := regexp.MatchString(`^(1[3|4|5|8][0-9]d{4,8})$`, r.Form.Get("mobile")); !
m {
return false
}
对身份证号码,可以通过如下方式验证:
代码语言:javascript复制//验证 15 位身份证,15 位的是全部数字
if m, _ := regexp.MatchString(`^(d{15})$`, r.Form.Get("usercard")); !m {
return false
}
//验证 18 位身份证,18 位前 17 位为数字,最后一位是校验位,可能为数字或字符 X。
if m, _ := regexp.MatchString(`^(d{17})([0-9]|X)$`, r.Form.Get("usercard")); !m {
return false
}
日期与时间
想要判断用户输入的时间是否正确,可以使用 Go 的 time 包,可以将用户的输入转换成相应的时间,然后进行逻辑判断:
代码语言:javascript复制t := time.Date(2022, time.November, 10, 23, 0, 0, 0, time.UTC)
fmt.Printf(t.Local())
转换成 Go 的时间就可以进行更多的操作了
下拉菜单,单选按钮和复选框
想要判断下拉菜单中是否有条目被选中,比如 select 是这样的:
代码语言:javascript复制<select name="fruit">
<option value="apple">apple</option>
<option value="pear">pear</option>
<option value="banane">banane</option>
</select>
如何判断用户提交的值是 option 其中的一个呢?
代码语言:javascript复制slice := []string{"apple", "pear", "banane"}
for _, v := range slice {
if v == r.Form.Get("fruit") {
return true
}
}
return false
针对单选框判断发送的值为预设的值可以使用如下方式:
代码语言:javascript复制<input type="radio" name="gender" value="1">男
<input type="radio" name="gender" value="2">女
也是通过遍历的方式判断
代码语言:javascript复制slice:=[]int{1,2}
for _, v := range slice {
if v == r.Form.Get("gender") {
return true
}
}
return false
针对复选框的判断有一点不一样,因为复选框接收到的是一个 Slice:
代码语言:javascript复制<input type="checkbox" name="interest" value="football">足球
<input type="checkbox" name="interest" value="basketball">篮球
<input type="checkbox" name="interest" value="tennis">网球
代码语言:javascript复制slice:=[]string{"football","basketball","tennis"}
a:=Slice_diff(r.Form["interest"],slice)
if a == nil{
return true
}
return false