一、效果:一个图片应用

1、可上传图片到uploads目录。

2、可浏览和评论图片(用富文本编辑器输入)

二、梳理一下相关知识:

1、iris框架(模板输出,session)

2、富文本编辑器、sqlite3(保存评论文字内容)

 二、参考MVC设计模式,手工建以下目录结构和文件,- 表示目录层级  \表示目录,

-irisMVC

--main.go                    //go主程序

--config.json               //配置文件

--m\               //model层,处理数据库

---m.go

--v\                            //view ,视图

---index.html          //首页模板;

---upload.html     //上传图片

---comment.html  //评论图片

--db\                         //保存sqlite3格式数据库

---pic.db                //这个文件是在代码中自动生成的

--uploads\                 //保存上传图片

--static\                      //静态文件,css,js,logo

注:说是MVC,为简化代码,我将controller控制器层、路由都写在main.go中了

另外,可使用项目热重启,参考https://www.cnblogs.com/pu369/p/10691747.html  

三、从main.go开始写代码

1、main.go


/*
//config.json
{
"appname": "IrisDemo",
"port": 8000
}
*/
package main import (
"encoding/json"
"fmt"
"html/template"
"io"
"io/ioutil"
"os"
"strconv"
"time" "github.com/kataras/iris/sessions" "github.com/kataras/iris" _ "github.com/mattn/go-sqlite3" "irisMVC/m"
) //配置文件结构
type Coniguration struct {
Appname string `json:appname`
Port string `json:port`
CreatedAt time.Time `json:"created"`
} //全局变量conf,包含了配置文件内容
var conf Coniguration //初始化
func init() {
//读配置文件
file, _ := os.Open("config.json")
defer file.Close()
decoder := json.NewDecoder(file)
err := decoder.Decode(&conf)
if err != nil {
fmt.Println("Error:", err)
}
fmt.Println(conf.Port)
} func main() {
app := iris.New()
//session
sess := sessions.New(sessions.Config{Cookie: "sessionscookieid", Expires: * time.Minute}) //静态文件目录,如http://localhost:8000/staticwwwurl/1.txt
app.StaticWeb("/staticwwwurl", "./mystatic")
//获得model层数据库对象,用于操作数据库,同时,初始化数据库
db := m.NewDb()
// onInterrupt contains a list of the functions that should be called when CTRL+C/CMD+C or a unix kill //command received.
iris.RegisterOnInterrupt(func() {
db.ORM.Close()
}) tmpl := iris.HTML("./v", ".html")
//增加模板函数
tmpl.AddFunc("Itoa", func(i int64) string {
return strconv.FormatInt(i, )
})
//解决富文本输出转义问题
tmpl.AddFunc("unescaped", func(x string) interface{} { return template.HTML(x) }) //注册视图目录
app.RegisterView(tmpl)
//路由
//主页
app.Get("/", func(ctx iris.Context) {
//绑定数据
ctx.ViewData("Title", conf.Appname)
pics := db.ListPic()
ctx.ViewData("Pic", pics)
// 渲染视图文件: ./v/index.html
ctx.View("index.html") })
//评论图片
app.Post("/comment", func(ctx iris.Context) {
id := ctx.PostValue("Pid")
comment := ctx.PostValue("Comment")
db.Comment(id, comment)
ctx.HTML("评论成功")
}).Name = "comment" //Name用于生成urlpath app.Get("/comment/{Id:int}", func(ctx iris.Context) {
id, _ := ctx.Params().GetInt("Id")
ctx.ViewData("Pid", id)
ctx.View("comment.html")
}).Name = "comment1"
//上传图片
app.Get("/upload", func(ctx iris.Context) {
ctx.View("upload.html")
})
//限制上传文件大小10M,硬编码
app.Post("/upload", iris.LimitRequestBodySize(<<), func(ctx iris.Context) {
// Get the file from the request.
file, info, err := ctx.FormFile("uploadfile")
if err != nil {
ctx.StatusCode(iris.StatusInternalServerError)
ctx.HTML("Error while uploading: <b>" + err.Error() + "</b>")
return
}
defer file.Close()
fname := info.Filename
//创建一个具有相同名称的文件
//假设你有一个名为'upload'的文件夹
//出于安全需要,可以在这里过滤文件类型,处理文件名后缀
out, err := os.OpenFile("./upload/"+fname, os.O_WRONLY|os.O_CREATE, )
if err != nil {
ctx.StatusCode(iris.StatusInternalServerError)
ctx.HTML("Error while uploading: <b>" + err.Error() + "</b>")
return
}
defer out.Close()
io.Copy(out, file) //可以将,看成=,可以理解为:将file的值赋给out
//然后将fname存入数据库pic.db的PIC表
db.SavePic(fname)
ctx.HTML("上传成功")
})
//下载图片
app.Get("/pic/{url}", func(ctx iris.Context) {
//我将一张图片改名为3.html,并复制到upload文件夹中。
//下面两行是直接下载图片
//file := "./upload/3.html"
//ctx.SendFile(file, "c.jpg")
//下面是在网页上显示图片
ctx.Header("Content-Type", "image/png")
ctx.Header("Content-Disposition", fmt.Sprint("inline; filename=\"aaa\""))
file, err := ioutil.ReadFile("./upload/3.html")
if err != nil {
ctx.HTML("查无此图片")
return
}
ctx.Write(file)
})
//session的简单使用
app.Get("/admin", func(ctx iris.Context) {
//可在这里用sess.UseDatabase,可参考:https://blog.csdn.net/wangshubo1989/article/details/78344183
s := sess.Start(ctx)
//set session values
s.Set("login name", "iris session")
i, err := s.GetInt("num")
if err != nil {
i =
}
i +=
s.Set("num", i)
ctx.HTML(fmt.Sprintf("%s %d", s.GetString("name"), i))
}) app.Run(iris.Addr(":" + conf.Port))
}

2.config.json
{
"appname": "IrisDemo 1.0",
"port": ""
}

3.m.go

package m

import (
"strconv"
"time" "github.com/go-xorm/xorm"
_ "github.com/mattn/go-sqlite3"
) //数据库对象DB,对xorm进行了包装 //注意骆峰法
type Db struct {
ORM *xorm.Engine
} //数据库表
//Admin 管理员表
type Admin struct {
ID int64 // xorm默认自动递增
A管理员名 string
Password string `xorm:"varchar(200)"`
CreatedAt time.Time `xorm:"created"`
} //Pic 用户对图片评论的表
type Pic struct {
Id int64 // xorm默认自动递增
Url string //图片保存路径
Comment string `xorm:"text"` //评论
CreatedAt time.Time `xorm:"created"`
} //User 用户表
type User struct {
Id int64 // xorm默认自动递增
A用户名 string
Password string `xorm:"varchar(200)"`
CreatedAt time.Time `xorm:"created"`
} //生成数据库
func NewDb() *Db {
//初始化数据库
orm, _ := xorm.NewEngine("sqlite3", "./db/db.db")
//此时生成数据库文件db/picdb.db,以及表USER、PIC
_ = orm.Sync2(new(User), new(Pic))
db := new(Db)
db.ORM = orm
return db
}
func (d *Db) SavePic(url string) {
pic := new(Pic)
pic.Url = url
d.ORM.Insert(pic)
}
func (d *Db) ListPic() []Pic {
var p []Pic
_ = d.ORM.Sql("select * from pic LIMIT 3 OFFSET 0").Find(&p)
//以下三句没解决富文本被当成string输出的问题。最后采取的办法是:注册模板函数unescaped
//for i := range p {
// p[i].Comment = template.HTMLEscaper(p[i].Comment)
// fmt.Println(p[i].Comment)
//}
return p
}
func (d *Db) Comment(id, comment string) {
var p Pic
idi, _ := strconv.ParseInt(id, , )
_, _ = d.ORM.ID(idi).Get(&p)
p.Comment += comment
//id为int64或string都可以
d.ORM.ID(id).Update(p)
}

4.几个html模板

4.1 index.html

<!DOCTYPE html>
<head>
<meta charset="utf-8">
<title>{{.Title}}</title>
</head>
<body> {{range $i, $v := .Pic}}
{{$v.Id}}&nbsp;&nbsp;{{$v.Url}}&nbsp;&nbsp;{{$v.CreatedAt}}&nbsp;&nbsp;{{$v.Comment | unescaped}}&nbsp;&nbsp;<a href={{urlpath "comment" }}/{{Itoa $v.Id}}>点评</a> <a href={{urlpath "comment1" $v.Url}}>未实现</a> <img src=/pic/{{$v.Url}}><br/>
{{end}} </body>
</html>

4.2 upload.html

<!DOCTYPE html>
<head>
<meta charset="utf-8">
<title>{{.Title}}</title>
</head>
<body>
<form enctype="multipart/form-data" action="upload" method="POST">
<input type="file" name="uploadfile" /> <input type="hidden" name="token" value="{{.}}" /> <input type="submit" value="upload" />
</form>
</body>
</html>

4.3 comment.html

<!DOCTYPE html>
<head>
<meta charset="utf-8">
<title>{{.Title}}</title>
</head>
<body>
<form action="/comment" method="post">
Id: <input type="text" name="Pid" value={{.Pid}} />
评论: <input type="text" id="Comment" name="Comment" /> <br />
<input type="submit" value="提交"/>
</form>
<!-- 注意, 只需要引用 JS,无需引用任何 CSS !!!--> <script src="https://cdn.bootcss.com/wangEditor/10.0.13/wangEditor.min.js"></script>
<script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script>
<div id="div1">
<p>这句必须在段落标签内</p>
</div> <script type="text/javascript">
var E = window.wangEditor
var editor = new E('#div1')
var $text1 = $('#Comment')
editor.customConfig.onchange = function (html) {
// 监控变化,同步更新到 input
$text1.val(html)
}
editor.create()
// 初始化 input 的值
$text1.val(editor.txt.html())
</script>
</body>
</html>

参考:

理解Golang包导入https://studygolang.com/articles/3189

图片输出 https://www.jianshu.com/p/583f473fe2c2、 https://blog.csdn.net/ssssny/article/details/77717287

session https://blog.csdn.net/wangshubo1989/article/details/78344183

富文本的显示问题 https://yq.aliyun.com/articles/348899      https://studygolang.com/articles/1741

还可通过 https://sourcegraph.com搜索相应的源码、https://gocn.vip/question/822

修改数组元素的问题 https://blog.csdn.net/xiaoquantouer/article/details/80392656

数据类型转换 https://blog.csdn.net/u013485530/article/details/80906569

golang web实战之三(基于iris框架的 web小应用,数据库采用 sqlite3 )的更多相关文章

  1. 如何快速搭建一个基于ServiceStack框架的web服务

    ServiceStack是一个高性能的.NET Web Service 平台,能够简化开发高性能的REST (支持JSON,XML,JSV,HTML,MsgPack,ProtoBuf,CSV等消息格式 ...

  2. SZhe_Scan碎遮:一款基于Flask框架的web漏洞扫描神器

    SZhe_Scan碎遮:一款基于Flask框架的web漏洞扫描神器 天幕如遮,唯我一刀可碎千里华盖,纵横四海而无阻,是谓碎遮 --取自<有匪> 写在前面 这段时间很多时间都在忙着编写该项目 ...

  3. 使用NetBeans搭建基于Spring框架的Web应用

    NetBeans下载链接:https://netbeans.org/. 第一步:选择“文件”菜单下的“新建项目”: 第二步:类别选择“Java Web”,项目选择“Web应用程序”,单击“下一步”: ...

  4. 基于Spring框架的Web应用开发笔记 - Outline

    Motivation 最近的工作涉及Web框架搭建,在了解公司原有采用框架基础上对Web开发技术栈做了一次升级,在次做记录. Audience J2EE Web Application Develop ...

  5. 基于testng框架的web自动化测试

    package baidutest; import org.openqa.selenium.By; import org.openqa.selenium.WebDriver; import org.o ...

  6. 基于SqlSugar的数据库访问处理的封装,在.net6框架的Web API上开发应用

    我前面几篇随笔介绍了关于几篇关于SqlSugar的基础封装,已经可以直接应用在Winform项目开发上,并且基础接口也通过了单元测试,同时测试通过了一些Winform功能页面:本篇随笔继续深化应用开发 ...

  7. 基于Spring框架应用的权限控制系统的研究和实现

    摘 要: Spring框架是一个优秀的多层J2EE系统框架,Spring本身没有提供对系统的安全性支持.Acegi是基于Spring IOC 和 AOP机制实现的一个安全框架.本文探讨了Acegi安全 ...

  8. golang web实战之二(iris)

    之前写了一篇为:golang web实战之一(beego,mvc postgresql) 听说iris更好: 1.  iris hello world package main import &quo ...

  9. ASP.NET Web Api构建基于REST风格的服务实战系列教程

    使用ASP.NET Web Api构建基于REST风格的服务实战系列教程[十]——使用CacheCow和ETag缓存资源 系列导航地址http://www.cnblogs.com/fzrain/p/3 ...

随机推荐

  1. 20-Perl 正则表达式

    1.Perl 正则表达式正则表达式(regular expression)描述了一种字符串匹配的模式,可以用来检查一个串是否含有某种子串.将匹配的子串做替换或者从某个串中取出符合某个条件的子串等.Pe ...

  2. Python(十) —— 多进程多线程

    进程线程概念 进程理解为一个程序,具体完成工作的是线程.比如说启动一个 QQ ,QQ 程序里面可以聊天,设置,查找好友等,那么这些功能就理解成各个线程,也就是单进程多线程的一个模式.进程理解成人脑子, ...

  3. windows下 qt5&vs2010 在qtCreator下中文乱码

    环境:windows2012下 qt5.3.1 & vs2010 在qtCreator3.1.2下中文乱码 解决方法:在相关文件中加入代码 #ifdef Q_OS_WIN32 #if _MSC ...

  4. O035、Nova Suspend / Rescue 操作详解

    参考https://www.cnblogs.com/CloudMan6/p/5503501.html   Suspend / Resume   有时候需要长时间暂停 instance , 可以通过 S ...

  5. vue入门:(组件)

    模板:(template)模板声明了数据和最终展现给用户的DOM之间的映射关系. 初始数据:(data)一个组件的初始数据状态.对于可复用的组件来说,通常是私有的状态. 接收外部参数:(props)组 ...

  6. SpringBoot设置首页(默认页)跳转

    SpringBoot设置首页(默认页)跳转 方案1:controller里添加一个"/"的映射路径 @RequestMapping("/")public Str ...

  7. 关于同一台服务器上两个PHP项目相互访问超时的问题

    当一台服务器部署多个PHP项目,各自运行时并无干扰, 即使都使用 9000端口来跑php 但是有一种情况,当其中一个项目需要调用另一个php项目的接口时,便会超时,这是因为php是单线程的同步的 也许 ...

  8. 用Buildout来构建Python项目

    用Buildout来构建Python项目   什么是Buildout (Remixed by Matt Hamilton, original from http://xkcd.com/303) Bui ...

  9. ORACLE 常用函数学习笔记

    1.字符串截取方法 --5SELECT INSTR('8.30~9.00', '~') FROM dual; --8.30SELECT SUBSTR ('8.30~9.00', 0, INSTR (' ...

  10. 2.Nginx基本配置

    1. Nginx相关概念 代理服务器一般分为正向代理(通常直接称为代理服务器)和反向代理. 通常的代理服务器,只用于代理内部网络对Internet的连接请求,客户机必须指定代理服务器,并将本来要直接发 ...