本人在学长的推荐下,之后就要用Go开发后端啦!之前已经把go的基础语法过了一遍,现在学习Gin和Gorm框架,特此记录一下,也希望对你们有帮助,当然因为本人是Go新手,所以有写的不对的地方尽情指教,谢谢!

这里顺便再提供一下Go基础语法的中文官方文档

注:本篇文章大部分是基于https://www.topgoer.com/gin%E6%A1%86%E6%9E%B6这个网址写的学习笔记,其他一些则是去网上找的资料和视频,感谢大佬提供的观点和代码!!

Gin框架

用go原生的https包写hello world

package mainimport ("fmt""net/http" //引用http包
)func sayHello(w http.ResponseWriter, r *http.Request)  {_, _ = fmt.Fprintf(w, "<h1>Hello Golang!</h1>")// b, _ := ioutil.ReadFile("./hello.txt") //ioutil这个函数能够读去文本文件// _, _ = fmt.Fprintf(w, string(b))
}func main() {http.HandleFunc("/hello", sayHello) //访问 http://localhost:8080/hello 这个urlerr := http.ListenAndServe(":8080",nil) //监听8080端口,url中可以不用写(因为默认就是8080)if err != nil{fmt.Printf("ERROR:%v\n", err)return}
}

小记: 下载Gin框架 命令行输入:go get -u github.com/gin-gonic/gin

GET请求

package mainimport "github.com/gin-gonic/gin"func main() {r := gin.Default() // 返回默认的路由引擎//指定用户使用GET请求访问/hello时,会执行sayhello这个函数r.GET("/hello", func(c *gin.Context) { //一定要是*gin.Context类型的参数c.JSON(200,gin.H{"message":"Hello golang!",})})//启动服务r.Run(":9090") //改变默认端口号,注意要加 ":" !!!//r.Run()
}

小记:Resful风格的请求:GET:获取、 POST:创建、 DELETE:删除、 PUT:更新

POSTMan安装

这个网上有很多教程,这里就不多提了,提几个重要的点吧:
1.首先这个软件是要用梯子的,包括下载和登陆注册
2.建议下载软件版
3.下载好后新建一个work space之后就可以开始操作了

小记:template框架因为要读取一个html文件,没有做到前后端分离,我个人认为比较落后,这里就先不学它了

获取参数、文件的方式

API获取

package mainimport ("github.com/gin-gonic/gin""net/http""strings"
)func main() {r := gin.Default()r.GET("/user/:name/*action", func(c *gin.Context) { //通过匿名函数的方式实现的对url的抓取name := c.Param("name") //获得url中的nameaction := c.Param("action")//截取/action = strings.Trim(action, "/") //获得url中的最后一个参数c.String(http.StatusOK, name+" is "+action)})//默认为监听8080端口r.Run(":8000")
}


URL中获取参数(Get方式)
用Query()来获得参数
用DefaultQuery()来设置默认参数

package mainimport ("fmt""net/http""github.com/gin-gonic/gin"
)func main() {r := gin.Default()r.GET("/user", func(c *gin.Context) {//指定默认值//http://localhost:8080/user 才会打印出来默认的值name := c.DefaultQuery("name", "小恐龙")c.String(http.StatusOK, fmt.Sprintf("hello %s", name))})r.Run()
}

当name没有传进get参数时,返回为默认的小恐龙:


当然也可以传进参数:

表单获取参数(一般是Post方式)

表单参数可以通过PostForm()方法获取,该方法默认解析的是x-www-form-urlencoded或from-data格式的参数
(这里也同样没有前后端分离,不推荐)
html文件:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta http-equiv="X-UA-Compatible" content="ie=edge"><title>Document</title>
</head>
<body><form action="http://localhost:8080/form" method="post" action="application/x-www-form-urlencoded">用户名:<input type="text" name="username" placeholder="请输入你的用户名">  <br>密&nbsp;&nbsp;&nbsp;码:<input type="password" name="userpassword" placeholder="请输入你的密码">  <br><input type="submit" value="提交"></form>
</body>
</html>

go后台文件

package main//
import ("fmt""net/http""github.com/gin-gonic/gin"
)func main() {r := gin.Default()r.POST("/form", func(c *gin.Context) {types := c.DefaultPostForm("type", "post")username := c.PostForm("username")password := c.PostForm("userpassword")c.String(http.StatusOK, fmt.Sprintf("username:%s,password:%s,type:%s", username, password, types))})r.Run()
}

上传文件(单个或多个)
html文件:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta http-equiv="X-UA-Compatible" content="ie=edge"><title>Document</title>
</head>
<body>
<form action="http://localhost:8080/upload" method="post" enctype="multipart/form-data">上传文件:<input type="file" name="file" ><input type="submit" value="提交">
</form>
</body>
</html>

用FormFile()函数来获得上传的文件
SaveUploadedFile用于保存

go文件:

package mainimport ("github.com/gin-gonic/gin""net/http"
)func main() {r := gin.Default()// 限制表单上传大小 8MB,默认为32MBr.MaxMultipartMemory = 8 << 20r.POST("/upload", func(c *gin.Context) {file, err := c.FormFile("file")if err != nil {c.String(500, "上传图片出错")}//c.JSON(200, gin.H{"message": file.Header.Context})c.SaveUploadedFile(file, file.Filename)c.String(http.StatusOK, file.Filename)})r.Run()
}

gin好像暂时没有限制文件大小的函数,那么我们就自己写一个,也不是很难。
就是一个要注意的点是要把原来的c.FormFile变成c.Request.FormFile。

package mainimport ("log""net/http""github.com/gin-gonic/gin"
)func main() {r := gin.Default()//上传单个文件r.POST("/upload", func(c *gin.Context) {_, headers, err := c.Request.FormFile("file")if err != nil {log.Printf("Error when try to get file: %v", err)}//headers.Size 获取文件大小if headers.Size > 1024*1024*2 { //限制2MB的大小c.String(200,"文件太大了")return//获取文件类型}else if headers.Header.Get("Content-Type") != "image/png" {c.String(200,"只允许上传png图片")return}else{//Go返回json数据的方法之一;利用map(还有一种方法是用结构体)my_json := map[string]interface{}{ "1":"成功","2":true,}c.JSON(200,my_json)}//headers.Header.Get("Content-Type")获取上传文件的类型c.SaveUploadedFile(headers, "./video/"+headers.Filename)c.String(http.StatusOK, headers.Filename)})//上传多个文件//r.POST("/upload", func(c *gin.Context) {//    form, err := c.MultipartForm()//   if err != nil {//      c.String(http.StatusBadRequest, fmt.Sprintf("get err %s", err.Error()))// }// // 获取所有图片// files := form.File["files"]//    // 遍历所有图片// for _, file := range files {//     // 逐个存//        if err := c.SaveUploadedFile(file, file.Filename); err != nil {//         c.String(http.StatusBadRequest, fmt.Sprintf("upload err %s", err.Error()))//          return//        }// }// c.String(200, fmt.Sprintf("upload ok %d files", len(files)))//})r.Run()
}

路由和路由组

路由:就是一个通过一个路径去用一种方法去请求数据
路由中不同的请求方法以及后台处理

r.any()可以对任何请求做出处理
r.NoRoute()可以自定义404页面
示例:

package mainimport ("github.com/gin-gonic/gin"
)
func main() {// 默认使用了2个中间件Logger(), Recovery()r := gin.Default()r.NoRoute(func(c *gin.Context) {c.JSON(404, gin.H{"msg": "12138"})})r.Run()
}

路由组

package mainimport ("github.com/gin-gonic/gin""fmt"
)// gin的helloWorldfunc main() {// 1.创建路由// 默认使用了2个中间件Logger(), Recovery()r := gin.Default()// 路由组1 ,处理GET请求v1 := r.Group("/v1")// {} 是书写规范{v1.GET("/login", login)v1.GET("submit", submit)//路由组的可以嵌套的//xx := v1.shopGroup("xx")//xx.GET("/oo",my_func)}v2 := r.Group("/v2"){v2.POST("/login", login)v2.POST("/submit", submit)}r.Run(":8000")
}func login(c *gin.Context) {name := c.DefaultQuery("name", "jack")c.String(200, fmt.Sprintf("hello %s\n", name))
}func submit(c *gin.Context) {name := c.DefaultQuery("name", "lily")c.String(200, fmt.Sprintf("hello %s\n", name))
}

效果图:


小记: 不同文件夹下要导入函数的话,导出的函数首字母需要大写

JSON数据的解析和绑定:

小记:gin.h{...}和map[string]interface{}{...}的效果是一样的

package mainimport ("github.com/gin-gonic/gin""net/http"
)// 定义接收数据的结构体
type Login struct {// binding:"required"修饰的字段,若接收为空值,则报错,是必须字段User    string `form:"username" json:"user" uri:"user" xml:"user" binding:"required"`Pssword string `form:"password" json:"password" uri:"password" xml:"password" binding:"required"`
}func main() {// 1.创建路由// 默认使用了2个中间件Logger(), Recovery()r := gin.Default()// JSON绑定r.POST("loginJSON", func(c *gin.Context) {// 声明接收的变量var json Login //声明json为Login类型的结构体// 将request的body中的数据,自动按照json格式解析到结构体if err := c.ShouldBindJSON(&json); err != nil {//c.ShouldBindUri(...)是用于解析url中的参数的//c.Bind(...)是用于解析form中的参数的// 返回错误信息// gin.H封装了生成json数据的工具c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})return}// 判断用户名密码是否正确if json.User != "root" || json.Pssword != "admin" {c.JSON(http.StatusBadRequest, gin.H{"status": "304"})return}c.JSON(http.StatusOK, gin.H{"status": "200"})})r.Run(":8000")
}

注意: 上面结构体定义时使用了结构体tag,因为go的限制,所以结构体内名字只能返回大写开头,于是我们就可以用tag去定制结构体在不同方法请求时所传入参数名称的不同
User string `form:"username" json:"user" uri:"user" xml:"user" binding:"required"
比如这句话,用form请求时就应该是username
binding:"required"就说明是必要参数,若接收为空值,则报错,是必须字段。

重定向

package mainimport ("net/http""github.com/gin-gonic/gin"
)func main() {r := gin.Default()r.GET("/index", func(c *gin.Context) {c.Redirect(http.StatusMovedPermanently, "http://www.5lmh.com")})r.Run()
}

异步执行和同步执行

这里用到了go程的概念,没有了解的小伙伴可以去康康文档

package mainimport ("log""time""github.com/gin-gonic/gin"
)func main() {// 1.创建路由// 默认使用了2个中间件Logger(), Recovery()r := gin.Default()// 1.异步r.GET("/long_async", func(c *gin.Context) {// 需要搞一个副本copyContext := c.Copy()// 异步处理go func() {time.Sleep(3 * time.Second)log.Println("异步执行:" + copyContext.Request.URL.Path)}()})// 2.同步r.GET("/long_sync", func(c *gin.Context) {time.Sleep(3 * time.Second)log.Println("同步执行:" + c.Request.URL.Path)})r.Run(":8000")
}

效果:

中间件

局部中间件
用于在浏览器和服务器中间处理的函数,一般是所有网站都需要使用的函数,比如登录认证、权限校验、数据分页、记录日志、耗时统计等。
原理图类似下图:

package mainimport ("fmt""github.com/gin-gonic/gin""time"
)func hello(c *gin.Context){c.JSON(200,gin.H{"msg":"index",})
}func m1(c *gin.Context){fmt.Println("进入验证...")start := time.Now()c.Next() // 调用后续处理函数(hello) !!!important//c.Abort() //阻止调用后续的处理函数cost := time.Since(start)fmt.Printf("cost:%v\n", cost)
}func main() {r := gin.Default()r.GET("/index", m1, hello)r.Run()
}

像上面的m1就是一个简单的中间件函数,
它在hello函数之前执行,可以决定hello函数执行的逻辑。
效果图:

全局中间件

用r.use(…)

package mainimport ("fmt""github.com/gin-gonic/gin""time"
)func hello(c *gin.Context){c.JSON(200,gin.H{"msg":"index",})
}func m1(c *gin.Context){fmt.Println("进入验证...")start := time.Now()c.Next() // 调用后续处理函数(hello) !!!important//c.Abort() //阻止调用后续的处理函数cost := time.Since(start)fmt.Printf("cost:%v\n", cost)
}func main() {r := gin.Default()//只要请求就要通过m1这个中间件(其实就是一个函数)r.Use(m1)r.GET("/index", hello)r.Run()
}

好用的中间件推荐
网址

会话控制:(cookie和session)

搜索、设置、删除cookie:

package mainimport ("fmt""github.com/gin-gonic/gin"
)func main() {// 1.创建路由// 默认使用了2个中间件Logger(), Recovery()r := gin.Default()// 服务端要给客户端cookier.GET("cookie", func(c *gin.Context) {// 获取客户端是否携带cookiecookie, err := c.Cookie("key_cookie")if err != nil {cookie = "NotSet"// 给客户端设置cookie//  maxAge int, 单位为秒// path,cookie所在目录// domain string,域名//   secure 是否智能通过https访问// httpOnly bool  是否允许别人通过js获取自己的cookiec.SetCookie("key_cookie", "value_cookie", 60, "/","localhost", false, true)//删除cookie的话就可以直接设置时长为0或者为空//c.SetCookie("key_cookie", "", 60, "/","localhost", false, true)//c.SetCookie("key_cookie", "value_cookie", 0, "/","localhost", false, true)}fmt.Printf("cookie的值是: %s\n", cookie)})r.Run(":8000")
}

请求:http://localhost:8000/cookie 后查看cookie

小记:Cookie的缺点:1.不安全,明文、2.增加带宽消耗、3.可以被禁用、4.cookie有上限

session的设置、查找和删除(值设为nil)

package mainimport ("github.com/gin-contrib/sessions""github.com/gin-contrib/sessions/cookie""github.com/gin-gonic/gin"
)func main() {// 初始化一个cookie存储对象// something-very-secret应该是一个你自己的密匙,只要不被别人知道就行var store = cookie.NewStore([]byte("something-very-secret"))r := gin.Default()//使用中间件,store是之前创建的存储引擎,可以替换成其他引擎//mysession是之后会存储到浏览器上cookie中的名字,服务器通过这个名字去找到对应的sessionr.Use(sessions.Sessions("mysession", store))r.GET("/save", func(c *gin.Context) {session := sessions.Default(c)v := session.Get("count")var count intif v == nil {count = 0}else {count = v.(int)count++}session.Set("count",count)session.Save()c.JSON(200, gin.H{"now the count":count})})r.GET("/get", func(c *gin.Context) {session := sessions.Default(c)v := session.Get("count")c.JSON(200, gin.H{"the count":v})})err := r.Run()if err != nil {return}
}

效果图:


gin中是没有session包的,所以需要我们自己去导入其他的session包

参数验证

结构体验证:
在定义结构体的对象的后面写上要求

package mainimport ("fmt""time""github.com/gin-gonic/gin"
)//Person ..
type Person struct {//不能为空并且大于10Age      int       `form:"age" binding:"required,gt=10"`Name     string    `form:"name" binding:"required"`Birthday time.Time `form:"birthday" time_format:"2006-01-02" time_utc:"1"`
}func main() {r := gin.Default()r.GET("/5lmh", func(c *gin.Context) {var person Personif err := c.ShouldBind(&person); err != nil {c.String(500, fmt.Sprint(err))return}c.String(200, fmt.Sprintf("%#v", person))})r.Run()
}

自定义函数验证

package mainimport ("fmt""github.com/go-playground/validator/v10"
)type Users struct {Name   string `form:"name" json:"name" validate:"required,CustomValidationErrors"`//包含自定义函数Age   uint8 `form:"age" json:"age" validate:"required,gt=18"`Passwd   string `form:"passwd" json:"passwd" validate:"required,max=20,min=6"`Code   string `form:"code" json:"code" validate:"required,len=6"`
}func main() {// 测试传入的数据users := &Users{Name:      "admin",Age:        121,Passwd:       "126783",Code:            "123456",}validate := validator.New()//注册自定义函数_=validate.RegisterValidation("CustomValidationErrors", CustomValidationErrors)err := validate.Struct(users)if err != nil {for _, err := range err.(validator.ValidationErrors) {fmt.Println(err)//Key: 'Users.Name' Error:Field validation for 'Name' failed on the 'CustomValidationErrors' tagreturn}}return
}func CustomValidationErrors(fl validator.FieldLevel) bool {return fl.Field().String() != "admin"
}

CustomValidationErrors是自己定义的函数,可以自定义过滤参数

注:一定要看清楚结构体后面的tag加的是validate而不是binding,这个是因为validator版本的问题导致的,这个问题搞了我半天,,一定要看清楚validator的版本是v10的,v9、v8都可能出问题

这里再分享一个大佬对这个包使用方法发总结:网址

其他常用功能

记录日志

package mainimport ("io""os""github.com/gin-gonic/gin"
)func main() {gin.DisableConsoleColor()// Logging to a file.f, _ := os.Create("gin.log")gin.DefaultWriter = io.MultiWriter(f)// 如果需要同时将日志写入文件和控制台,请使用以下代码。// gin.DefaultWriter = io.MultiWriter(f, os.Stdout)r := gin.Default()r.GET("/ping", func(c *gin.Context) {c.String(200, "pong")})r.Run()
}

效果图:

验证码

///正在更新ing

Gorm框架

小记:英文Go Object(对象) Relational(关系) Mapping(映射)

Gorm的安装

命令行输入:

go get -u gorm.io/gorm
go get -u gorm.io/driver/sqlite

基本操作

这里以mysql为例

package mainimport ("fmt""github.com/jinzhu/gorm"_ "github.com/jinzhu/gorm/dialects/mysql"
)type Gorm_test struct {ID     int    //注意:如果定义了ID,则会被默认为主键Name   stringGender stringHobby  string
}func main() {mysql_conn := fmt.Sprintf("%s:%s@(%s:%d)/%s?charset=utf8mb4&parseTime=True&loc=Local", "root", "1234", "127.0.0.1", 3306, "mydatabase")//赋值给全局变量 Db 没有 := 就是赋值db, err := gorm.Open("mysql", mysql_conn)if err != nil {panic(err)}fmt.Println("初始化数据库成功......")//创建表,把结构体和数据表关联起来db.AutoMigrate(&Gorm_test{})//创建数据行u1 := Gorm_test{1, "小恐龙", "男", "钢琴"}db.Create(&u1) //这边建议加上&fmt.Println("添加数据成功")//查询var u Gorm_test//用First函数查询第一个db.First(&u) //查询第一个,把它赋值给u 注意,要修改结构体一定要传指针!fmt.Printf("u:%#v\n", u)//更新数据db.Model(&u).Update("hobby", "打击乐")fmt.Println("更改数据成功")//删除db.Delete(&u)fmt.Println("删除数据成功")}

效果图:

小记:gorm在我们关联结构体时会创建一个数据库,名字就算把我们结构体的名字小写并且后面加上s

查询plus

package mainimport ("fmt""github.com/jinzhu/gorm"_ "github.com/jinzhu/gorm/dialects/mysql"
)type Gorm_test struct {ID     int    //注意:如果定义了ID,则会被默认为主键Name   stringGender stringHobby  string
}func main() {mysql_conn := fmt.Sprintf("%s:%s@(%s:%d)/%s?charset=utf8mb4&parseTime=True&loc=Local", "root", "1234", "127.0.0.1", 3306, "mydatabase")//赋值给全局变量 Db 没有 := 就是赋值db, err := gorm.Open("mysql", mysql_conn)if err != nil {panic(err)}fmt.Println("初始化数据库成功......")//创建表,把结构体和数据表关联起来db.AutoMigrate(&Gorm_test{})var test Gorm_testdb.First(&test, 4) //根据主键(当前为ID),如果为空则返回:{0  }   只能查出符号条件的第一条fmt.Println(test)var test1 []Gorm_testdb.Where("name = ?", "zlz").Find(&test1) //查询所有符合的记录并保存在test1数组中  海曙注意一定要加&!!!fmt.Println(test1)
}

小记:当查询不出来数据时,可以在结构体后面指定字段名,类似: ID int `gorm:"column:ID"

其他Go的知识

实时加载工具Air

这里我直接引用大佬的文章吧:网址

Go包管理工具Go Mod

具体操作可以看看这个:网址

注意的点:
需要主文件夹下面有main.go
每次创建新项目后,可以命令行输入:
go mod init 你的文件夹名
go mod tidy
之后就能自动帮你下载包啦

云服务器liunx宝塔面板配置Go环境

分享大佬的网址:网址

Go的项目结构与导包

一般我们是利用Go mod来管理包

一个项目一般只有一个go.mod

比如说我的项目叫sisipai,那么首先建一个大文件夹,下面建立两个小文件夹叫article和quku,还有一个main.go作为项目的主要文件

在article和quku中也分别有一个main.go的文件
里面第一行分别是

//注意要首字母大写
package Article //表明是Article的这个包
//和
package Quku //表明是Quku的这个包

注意:在article和quku中不能由.idea或者go.mod、go.sum这种东西出现(一个项目一般只有一个go.mod)

再切回sisipai这个主文件夹,写

package main
//这时候就可以import了
import ("sisipai/Article""sisipai/Qupu"
)

如果出现报错,不要慌,在sisipai文件夹命令行下输入:

go mod init sispai
go mod tidy

就可以自己帮你找包啦!
成功运行

Go项目放在服务端运行

如果服务端是Linux,想直接放文件上去运行的话可以在本地先编译好Linux所可以运行的文件,再直接放到服务器上去跑。
方法:依次在命令行输入:

set GOARCH=amd64
set GOOS=linux
go build .

接着就会生成一个和你项目名称相同的没有后缀名的文件,这个就算linux可以执行的文件。
把它拖到你的服务器上,然后给个运行权限:

chmod +x [你的项目名称]

就可以加上"./"运行啦!

端口问题
很多新手小白(比如说我)在一开始并不知道如何让自己的go文件在服务端跑起来之后访问它,那么今天我们来解决一下这个问题。

首先你端口要是这样的:(如果你要在8080端口下运行的话)

_ = r.Run("0.0.0.0:8080“)

然后别忘了把防火墙给开启了,放行8080端口
接下去就好啦!你可以试试用curl 127.0.0.1:8080端口测试,也可以通过你服务器的公网IP访问试试。

Go语言设置跨域访问

网址
通过使用cors的中间件改变header来实现跨域,一般要给域名加上https

等待完善ing…

Go Web学习笔记(Gin和Gorm)相关推荐

  1. 2019年Java Web学习笔记目录

    Java Web学习笔记目录 1.Java Web学习笔记01:动态网站初体验 2.Java Web学习笔记02:在Intellij里创建Web项目 3.Java Web学习笔记03:JSP元素 4. ...

  2. web学习笔记-html-html新增

    CCS学习系列笔记 web学习笔记–css(1) web学习笔记–css(2) web学习笔记–css(3) web学习笔记-html-html新增 1.html基本发展 2.h5新增的功能 3.新增 ...

  3. 【慕课网】Web学习笔记———CSS3 (一)

    [Web学习笔记]CSS3 (一) CSS3代码语法 CSS注释代码 CSS样式 内联式css样式 嵌入式css样式 外部式css样式 权值 CSS3选择器 标签选择器 类选择器 ID选择器 类与ID ...

  4. java web学习笔记(持续更新)

    java web学习笔记 一.Java Web简介 二.认识Servlet 1.什么是Servlet? 2.请求路径 3.tomcat 4.Servlet的使用 三.Servlet简单应用 1.创建S ...

  5. [原创]java WEB学习笔记02:javaWeb开发的目录结构

    本博客为原创:综合 尚硅谷(http://www.atguigu.com)的系统教程(深表感谢)和 网络上的现有资源(博客,文档,图书等),资源的出处我会标明 本博客的目的:①总结自己的学习过程,相当 ...

  6. [原创]java WEB学习笔记48:其他的Servlet 监听器:域对象中属性的变更的事件监听器 (3 个),感知 Session 绑定的事件监听器(2个)...

    本博客为原创:综合 尚硅谷(http://www.atguigu.com)的系统教程(深表感谢)和 网络上的现有资源(博客,文档,图书等),资源的出处我会标明 本博客的目的:①总结自己的学习过程,相当 ...

  7. [原创]java WEB学习笔记58:Struts2学习之路---Result 详解 type属性,通配符映射

    本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱 ...

  8. [原创]java WEB学习笔记35:java WEB 中关于绝对路径 和相对路径问题

    本博客为原创:综合 尚硅谷(http://www.atguigu.com)的系统教程(深表感谢)和 网络上的现有资源(博客,文档,图书等),资源的出处我会标明 本博客的目的:①总结自己的学习过程,相当 ...

  9. 移动web——学习笔记整理

    目录 Day1 00.流式布局 00.1目标 00.2目录 01.移动端浏览器 02.视口(layout viewport) 03.meta视口标签(单标签) 04.物理像素&物理像素比 05 ...

最新文章

  1. (原)调用jpeglib对图像进行压缩
  2. java图片上传下载_java web 文件上传与下载
  3. 代码管理 ,git 命令整理
  4. 64位的Mac OS X也有Windows.Forms了
  5. 山寨威武 仿冒Xoom先于行货获得Android 4.0升级
  6. 事业单位计算机知识c语言,事业单位考试计算机基础知识C语言程序设计
  7. unity3d android hdr,Unity3d 中的 HDR_BLOOM
  8. 想要定位其中的iframe并切进去的定位方法
  9. Hexo博文加密思路总结
  10. 数组中大于等于左侧所有数,小于等于右侧所有数的数
  11. a 机械硬盘损坏,如何恢复数据
  12. 简单的 Nodejs jade 实现Hello world
  13. 使用Robotframework-ride,导入Selenium2Library库后缺少“Open Browser”关键字
  14. 刘卫国python语言程序设计实验题答案_Python语言程序设计-中国大学mooc-试题题目及答案...
  15. php学好要多久,零基础php自学要多久
  16. 全网最全之接口测试【加密解密攻防完整版】实战教程详解
  17. 飞腾CPU 麒麟系统 安装docker
  18. 魔兽争霸3在win10中调节亮度的办法
  19. R语言 数据正态化+标准化
  20. 从excel中读取信号,首先计算信号的vmd分解,得到imf分量

热门文章

  1. 计量经济学 (1.2)
  2. VM虚拟机下载与安装
  3. axure 8 修改axhub-column-data的数据和配置
  4. Axhub Charts的图表 点击后 无法进行中继器的数据编辑(axure 9)问题解决
  5. 廖雪峰的博客——一个Python学习网站
  6. 微信登录实现-Android
  7. Paxos算法与Fischer-Lynch-Paterson结论
  8. 华为防火墙配置目的nat
  9. 万能的zookeeper,分布式环境的动物管理员
  10. 【ArcGIS微课1000例】0035:地图面状符号设计教程