代码很乱,bug很多,将就着看吧。参考了很多网上代码,只能说声感谢了。

//cjl.ZongHeInfo.1.0
//目的:对各部门报上来的信息数量进行排名
//思路:预计一年信息量不超过100M,全部存入全局变量GlobalInfoDoc中,以方便排序,统计
//在协程中每5分钟将GlobalInfoDoc用json编码后存入文件中。因此,退出程序前应先手动保存(一定程度上可考虑用signal),避免5分钟内的数据丢失
//重要:生成的json备份文件不能用notepad编辑,要保存为UTF-8 NO BOM package main import (
"io/ioutil"
"math"
"net/url"
"strconv" //"encoding/base64"
"encoding/json"
"fmt"
"log"
"sort"
"strings" "sync" "net/http"
"os"
"os/exec"
"time"
) var (
DEPA = []string{"XX部", "XXX部", "X1部", "X2部", "XX公司", "XX公司", "XX厂", "XXX厂", "XX中心"}
GlobalInfoDoc TInfoDoc //保存了所有报上来的信息,其实就相当于一个文本文件
GlobalConf = make(map[string]string) //配置文件
GlobalManuscripts = "" //约稿要求,直接放投稿页面的placeholder中了 ) type TInfoDoc struct {
Infos []TInfo //属性名一定要大写,血的教训
sync.RWMutex //http是多线程的,加上锁
} type TInfo struct {
Time int64 `json:"name,omitempty"` //`时间`
Title string `json:"title,omitempty"` //`标题`
Content string `json:"Content,omitempty"` //`内容`
Department string `json:"Department,omitempty"` //`单位`
Who string `json:"Who,omitempty"` //`报送人`
Tel string `json:"Tel,omitempty"` //`电话`
Ip string `json:"IP,omitempty"` //IP
} //原计划利用cookie保存,后来认为用不上,把相关代码注释掉了
type TUser struct {
Name string
Tel string
} //用于对所报的信息按单位名称排序
type TInfoRanks []TInfoRank type TInfoRank struct {
Key string
Value int
} func main() {
//打开文件,若文件不存在则生成
year, _, _ := time.Now().Date()
fname := "info" + strconv.Itoa(year)
f, _ := os.OpenFile(fname, os.O_RDWR|os.O_CREATE, )
//将文件内容反序列化到全局变量infoDoc
out, _ := ioutil.ReadAll(f)
//fmt.Println(string(out))
json.Unmarshal(out, &GlobalInfoDoc)
//这里不能用defer f.Close(),因为main函数不会结束
f.Close()
//fmt.Println(infoDoc)
http.HandleFunc("/Add", Add)
http.HandleFunc("/Add2", Add2)
http.HandleFunc("/List", List)
http.HandleFunc("/save", save)
http.HandleFunc("/conf", conf)
http.HandleFunc("/yg", Manuscripts)
http.HandleFunc("/", Index)
exec.Command("cmd", "/c", "C:\\Progra~2\\Google\\Chrome\\Application\\chrome.exe", "http://localhost:8000/Add").Run()
go savefile()
fmt.Println("因5分钟才保存一次文件,所以退出程序前请访问/save以防止最近5分钟提交的信息丢失")
fmt.Println("请访问/conf更新配置文件的allowip")
http.ListenAndServe(":8000", nil) } func checkErr(err error) {
if err != nil {
log.Println(err)
}
} func Index(w http.ResponseWriter, r *http.Request) {
s := `
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<style type="text/css">
a:link,a:visited{
text-decoration:none; /*超链接无下划线*/
color:red;
}
a:hover{
text-decoration:underline; /*鼠标放上去有下划线*/
}
</style>
</head>
<body>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="http://192.168.0.239:8000/Add" target="_blank">信息报送</a>
</body>
</html>
`
fmt.Fprintf(w, s)
} func Add(w http.ResponseWriter, r *http.Request) { //模板
tpl := `<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<style>
input{
width:500px;
}
textarea{
width:500px;
}
.labelspan{
display:inline-block;
width:80px;
}
.input2{
width:410px;
} </style> </head>
<body onload="javascript:init()"> <form action="Add2" method="post" onsubmit="return check()">
<fieldset>
<legend><a href="yg">_</a>信息汇报<a href="List">_</a></legend>
标题: <input id="Title" name="Title" type="text" size="" required="required"><br/>
内容: <textarea id="Content" name="Content" rows="" placeholder="{{Manuscripts}}" required="required"></textarea><br/>
正文限制(-1000字):<span id="txtNum"></span><br/>
部门(单位): <select id="Department" name="Department" required="required">
<option value="">请选择</option>
{{OPTIONS}}
</select><br>
<span class="labelspan">报 送 人:</span> <input id="Who" name="Who" class="input2" value="" type="text" size="" required="required"><br/>
<span class="labelspan">联系电话:</span> <input id="Tel" name="Tel" class="input2" value="" type="text" size="" required="required"><br/>
<input type="submit" value="提交">
</fieldset>
</form>
{{SORTLIST}}
<script>
var txt = document.getElementById("Content");
var txtNum = document.getElementById("txtNum");
txt.addEventListener("keyup", function(){
txtNum.textContent = txt.value.length;
})
</script>
<script>
function check(){
var title = document.getElementById("Title").value;
var Content = document.getElementById("Content").value;
var Department = document.getElementById("Department").selectedIndex;
var Who = document.getElementById("Who").value;
var Tel = document.getElementById("Tel").value;
if(title == null || title == '' ||title.length <){
alert("请完善标题!");
return false;
}else if(Content.length <||Content.length >){
alert("正文限制100至1000字!");
return false;
}else if(Department == ){
alert("请选择部门!");
return false;
}else if(Who.length <){
alert("请填写正确的姓名!");
return false;
}else if(Tel.length <){
alert("请填写联系电话!");
return false;
}
return true;
}
</script>
<script>
function init(){
self.moveTo(, );
self.resizeTo(screen.width, screen.height);}
</script>
</body>
</html>` //读cookie 注意:直接读来自用户的数据不安全
/*
var User TUser
u, err := r.Cookie("u")
if err == nil {
uu, _ := base64.StdEncoding.DecodeString(u.Value)
json.Unmarshal(uu, &User)
}
//fmt.Println(User)
tpl = strings.Replace(tpl, `{{WHO}}`, string(User.Name), -1)
tpl = strings.Replace(tpl, `{{TEL}}`, string(User.Tel), -1)
*/
//选项
var options strings.Builder
for _, v := range DEPA {
fmt.Fprintln(&options, `<option value="`, v, `">`, v, `</option>`)
}
//fmt.Println(options.String()) //统计
year, month, _ := time.Now().Date()
//统计各部门稿件数量的map
//本月
thisMonthFirstDay := time.Date(year, month, , , , , , time.Local) //本月第一天
nextMonthFirstDay := thisMonthFirstDay.AddDate(, , ) //下月第一天
_ThisMonth := periodInfos(thisMonthFirstDay, nextMonthFirstDay) //上月
lastMonthFirstDay := thisMonthFirstDay.AddDate(, -, ) //上月第一天
_LastMonth := periodInfos(lastMonthFirstDay, thisMonthFirstDay) //本年
thisYearFirstDay := time.Date(year, , , , , , , time.Local) //本年第一天
nextYearLastDay := thisYearFirstDay.AddDate(, , ) //明年第一天
_ThisYear := periodInfos(thisYearFirstDay, nextYearLastDay) //将map转切片,用sort.Slice排序后输出
var sortlist strings.Builder
s_ThisMonth := sortByValue(_ThisMonth)
s_LastMonth := sortByValue(_LastMonth)
s_thisYear := sortByValue(_ThisYear)
//本月ol
fmt.Fprintln(&sortlist, `<table><tr><th>本月排序</th><th>上月排序</th><th>本年排序</th><tr><td>`)
fmt.Fprintln(&sortlist, `<ol>`)
for _, v := range s_ThisMonth {
fmt.Fprintln(&sortlist, `<li>`, v.Key, v.Value, `篇`, `</li>`)
}
//上月ol
fmt.Fprintln(&sortlist, `</ol></td><td><ol>`)
for _, v := range s_LastMonth {
fmt.Fprintln(&sortlist, `<li>`, v.Key, v.Value, `篇`, `</li>`)
}
//本年ol
fmt.Fprintln(&sortlist, `</ol></td><td><ol>`)
for _, v := range s_thisYear {
fmt.Fprintln(&sortlist, `<li>`, v.Key, v.Value, `篇`, `</li>`)
}
fmt.Fprintln(&sortlist, `</ol></td></tr></table>`) //替换模板
tpl = strings.Replace(tpl, `{{OPTIONS}}`, options.String(), -)
tpl = strings.Replace(tpl, `{{SORTLIST}}`, sortlist.String(), -)
tpl = strings.Replace(tpl, `{{Manuscripts}}`, GlobalManuscripts, -) //模板输出
fmt.Fprintln(w, tpl) } //对报送的稿件数量排序
func sortByValue(m map[string]int) TInfoRanks { pl := make(TInfoRanks, len(m))
i :=
for k, v := range m {
pl[i] = TInfoRank{k, v}
i++
}
sort.Slice(pl, func(i, j int) bool {
flag := false
if pl[i].Value > pl[j].Value {
flag = true
} else if pl[i].Value == pl[j].Value {
if pl[i].Key < pl[j].Key {
flag = true
}
}
return flag
})
return pl
} func Add2(w http.ResponseWriter, r *http.Request) {
//r.ParseForm()
if r.Method == "POST" {
info := TInfo{}
info.Time = time.Now().Unix()
info.Title = safeFilter(r.PostFormValue("Title"))
info.Content = safeFilter(r.PostFormValue("Content"))
info.Department = safeFilter(r.PostFormValue("Department"))
info.Who = safeFilter(r.PostFormValue("Who"))
info.Tel = safeFilter(r.PostFormValue("Tel"))
ip := r.RemoteAddr
info.Ip = ip[:strings.LastIndex(ip, ":")]
//在全局InfoDoc的Info切片后追加info
GlobalInfoDoc.Lock()
GlobalInfoDoc.Infos = append(GlobalInfoDoc.Infos, info)
GlobalInfoDoc.Unlock() //设置cookie
//base64
/*
u := TUser{}
u.Name = info.Who
u.Tel = info.Tel
us, _ := json.Marshal(u)
uu := base64.StdEncoding.EncodeToString(us)
cookieu := http.Cookie{Name: "u", Value: uu, Path: "/", MaxAge: 86400 * 180}
http.SetCookie(w, &cookieu)
*/
//重定向,避免用户重复提交
http.Redirect(w, r, "Add", http.StatusFound)
return
}
//不允许GET访问
fmt.Fprintln(w, "what are you 弄啥哩!")
} func List(w http.ResponseWriter, r *http.Request) {
ip := r.RemoteAddr
ip = ip[:strings.LastIndex(ip, ":")]
allowip := GlobalConf["allowip"]
if !strings.Contains(allowip, ip) {
fmt.Fprintln(w, "not allow")
return
}
tpl := `
<html><head>
<meta charset="UTF-8">
<title></title>
<style type="text/css">
body{background-color:#f0f0f0;}
table{
width:1000px;
table-layout:fixed;/* 只有定义了表格的布局算法为fixed,下面td的定义才能起作用。 */
}
td{
width:%;
min-width:300px;
word-break:keep-all;/* 不换行 */
white-space:nowrap;/* 不换行 */
overflow:hidden;/* 内容超出宽度时隐藏超出部分的内容 */
text-overflow:ellipsis;/* 当对象内文本溢出时显示省略标记(...) ;需与overflow:hidden;一起使用*/
}
ul{
border:1px solid #;
}
li{
word-break:break-all;
}
.ctx{background-color:#f0f0f9;}
</style>
</head>
<body>
{{TB}}
{{PAGENAV}}
</body></html>` //获取用户输入url参数?p=1中的页码1
uri, _ := url.Parse(r.RequestURI)
urlParam := uri.RawQuery
uri_m, _ := url.ParseQuery(urlParam)
curpage := //设当前页为1
p_uri_int := //用户提供的页码,默认为1
uri_m_p, ok := uri_m["p"]
if ok {
p_uri_int, _ = strconv.Atoi(uri_m_p[])
}
perpage := //每页1000条
numall := len(GlobalInfoDoc.Infos)
if numall <= {
fmt.Fprintln(w, "无数据")
return
} //总信息数
maxpage := int(math.Ceil(float64(numall) / float64(perpage))) //末页 if p_uri_int <= {
curpage =
} else if p_uri_int > maxpage {
curpage = maxpage
} else {
curpage = p_uri_int
}
pagenav := `<a href=List>首页</a> <a href=List?p=` + strconv.Itoa(curpage-) + `>上一页</a> <a href=List?p=` + strconv.Itoa(curpage+) + `>下一页</a> <a href=List?p=` + strconv.Itoa(maxpage) + `>尾页</a>` //以ul>li方式输出表格
var sb strings.Builder
//逆序输出1000条,最新的稿件显示在最上面
start1000 := numall - (curpage-)*
end1000 := numall - curpage* + //如:从1001到2000,而不是1000到2000,所以加1
if end1000 < {
end1000 = //逆序输出,最后一条也就是第一条
}
for i := start1000; i >= end1000; i-- {
info := GlobalInfoDoc.Infos[i-] //第一条对应的索引为0,所以减1
time1 := time.Unix(int64(), ).Format("2006-01-02 15:04:05")
fmt.Fprintln(&sb, `<ul>`)
fmt.Fprintln(&sb, `<li>`, `ID:`, i, `</li>`)
fmt.Fprintln(&sb, `<li>`, time1, `</li>`)
fmt.Fprintln(&sb, `<li>`, info.Title, `</li>`)
fmt.Fprintln(&sb, `<li class="ctx">`, info.Content, `</li>`)
fmt.Fprintln(&sb, `<li>`, info.Department, `</li>`)
fmt.Fprintln(&sb, `<li>`, info.Who, `</li>`)
fmt.Fprintln(&sb, `<li>`, info.Tel, `</li>`)
fmt.Fprintln(&sb, `<li>`, info.Ip, `</li>`)
fmt.Fprintln(&sb, `</ul>`)
} //替换模板
tpl = strings.Replace(tpl, `{{TB}}`, sb.String(), -)
tpl = strings.Replace(tpl, `{{PAGENAV}}`, pagenav, -)
fmt.Fprintln(w, tpl)
} func save(w http.ResponseWriter, r *http.Request) {
savefile()
} //保存GlobalInfoDoc,每5分钟保存一次
func savefile() {
t1 := time.Tick( * time.Second)
for {
select {
case <-t1:
//fmt.Println("t1定时器")
year, _, _ := time.Now().Date()
fname := "info" + strconv.Itoa(year)
//文件不存在则创建
_, _ = os.OpenFile(fname, os.O_RDWR|os.O_CREATE, )
out, _ := json.Marshal(GlobalInfoDoc)
ioutil.WriteFile(fname, out, os.ModeExclusive)
}
} } //安全过滤字符串
func safeFilter(s string) string {
s = strings.Replace(s, `=`, `=`, -)
s = strings.Replace(s, `'`, `’`, -1)
s = strings.Replace(s, `"`, `”`, -1)
s = strings.Replace(s, `<`, `〈`, -)
s = strings.Replace(s, `>`, `〉`, -)
s = strings.Replace(s, string(byte()), `<br>`, -)
return s
} //统计一段时间内的稿件数量排名
func periodInfos(t1, t2 time.Time) map[string]int {
m := make(map[string]int, len(DEPA))
for _, v := range DEPA {
m[v] =
}
//更新投稿数量
for _, info := range GlobalInfoDoc.Infos {
dp := strings.TrimSpace(info.Department) //这里将字符串转[]byte后发现前后有空格,asii为32
if _, ok := m[dp]; ok {
if info.Time >= t1.Unix() && info.Time < t2.Unix() {
m[dp]++
}
} }
return m
} //读配置文件
func conf(w http.ResponseWriter, r *http.Request) {
//配置文件中每行的格式类似:a=1
//将a=1解析到map中,k为等号左边的a,v为等号右边的1
var m = make(map[string]string, )
fname := "conf.txt"
//文件不存在则创建
f, _ := os.OpenFile(fname, os.O_RDWR|os.O_CREATE, )
defer f.Close()
if si, _ := f.Stat(); si.Size() == {
f.WriteString("allowip=[::1],192.168.3.4,192.168.2.4")
}
b, _ := ioutil.ReadFile(fname)
c := strings.Split(string(b), "\n")
for _, v := range c { if v != "" {
d := strings.Split(v, "=")
m[d[]] = d[]
}
}
var l *sync.Mutex
l = new(sync.Mutex)
l.Lock()
defer l.Unlock()
GlobalConf = m
} //设置约稿内容
func Manuscripts(w http.ResponseWriter, r *http.Request) {
ip := r.RemoteAddr
ip = ip[:strings.LastIndex(ip, ":")]
allowip := GlobalConf["allowip"]
if !strings.Contains(allowip, ip) {
fmt.Fprintln(w, "not allow")
return
}
//输入录入页面
if r.Method == "GET" {
tpl := `
<html>
<head>
<meta charset="utf-8">
<title></title></head>
<body>
<form action="" method="POST">
<textarea id="yg" name="yg" rows= cols= value="" >{{Manuscripts}}</textarea>
<input type="submit" value="提交">
</form>
</body>
</html>
`
//替换模板
tpl = strings.Replace(tpl, `{{Manuscripts}}`, GlobalManuscripts, -)
fmt.Fprintln(w, tpl)
return
} else if r.Method == "POST" {
s := r.PostFormValue("yg")
var l *sync.Mutex
l = new(sync.Mutex)
l.Lock()
defer l.Unlock()
GlobalManuscripts = s
//同时将约稿内容保存为yg.txt 如果用ioutil.WriteFile,则os.ModeAppend是无效的
//outil.WriteFile("yg.txt", []byte(s), os.ModeAppend)
fl, err := os.OpenFile("yg.txt", os.O_APPEND|os.O_CREATE, )
if err != nil {
return
}
defer fl.Close()
fl.Write([]byte(s))
//重定向,避免用户重复提交
http.Redirect(w, r, "Add", http.StatusFound)
return
} else {
fmt.Fprintln(w, "what are you 弄啥哩!")
} }

用golang写了个统计各单位报送的信息数量的微服务的更多相关文章

  1. 如何加速golang写业务的开发速度

    如何加速golang写业务的开发速度 不要忌讳panic golang写业务代码经常会被吐槽,写业务太慢了,其中最大的吐槽点就是,处理各种error太麻烦了.一个项目中,会有30%或者更多的是在处理e ...

  2. 使用golang写一个redis-cli

    使用golang写一个redis-cli 0. redis通信协议 redis的客户端(redis-cli)和服务端(redis-server)的通信是建立在tcp连接之上, 两者之间数据传输的编码解 ...

  3. Golang写文件的坑

    Golang写文件一般使用os.OpenFile返回文件指针的Write方法或者WriteString或者WriteAt方法,但是在使用这三个方法时候经常会遇到写入的内容和实际内容有出入,因为这几个函 ...

  4. github上用golang写的项目

    1.moby/moby docker的新马甲 2.kubernetes/kubernetes 分布式容器管理 3.grafana/grafana 一个可视化面板,有漂亮的仪表盘,多种数据来源,适合做系 ...

  5. [goa]golang微服务框架学习--安装使用

      当项目逐渐变大之后,服务增多,开发人员增加,单纯的使用go来写服务会遇到风格不统一,开发效率上的问题. 之前研究go的微服务架构go-kit最让人头疼的就是定义服务之后,还要写很多重复的框架代码, ...

  6. Golang微服务实践

    背景 在之前的文章<漫谈微服务>我已经简单的介绍过微服务,微服务特性是轻量级跨平台和跨语言的服务,也列举了比较了集中微服务通信的手段的利弊,本文将通过RPC通信的方式实现一个增删查Redi ...

  7. 【GoLang】go 微服务框架 && Web框架学习资料

    参考资料: 通过beego快速创建一个Restful风格API项目及API文档自动化:  http://www.cnblogs.com/huligong1234/p/4707282.html Go 语 ...

  8. 【GoLang】GoLang 微服务、开源库等参考资料

    参考资料: GoLang书籍: https://github.com/dariubs/GoBooksGo名库: https://github.com/Unknwon/go-rock-libraries ...

  9. 【GoLang】golang 微服务框架 go-kit

    golang-Microservice Go kit - A toolkit for microservices kubernetes go-kit_百度搜索 Peter Bourgon谈使用Go和& ...

随机推荐

  1. python3 字符编码与转码的理解

    额...上通识课讲到了NLP12条,感觉讲的挺好的,照着抄一条先... 1,没有两个人是一样的 没有两个人的人生经验会完全一样,所以没有两个人的信念,价值和规条系统会是一样. 因此没有两个人对同一件事 ...

  2. ASP.NET Core 中断请求了解一下(翻译)

    ASP.NET Core知多少系列:总体介绍及目录 本文所讲方式仅适用于托管在Kestrel Server中的应用.如果托管在IIS和IIS Express上时,ASP.NET Core Module ...

  3. Fork/Jion框架详解

    ◆Fork/Jion框架可以干什么◆ 如果你要处理1万条数据,但是你的能力暂时还不够,一个简单快捷的办法就是你可以把每次只处理100条,等到处理100次之后再把所有的结果聚合起来你就处理完了这1万条数 ...

  4. PERL学习笔记---正则表达式的应用

    使用m//匹配 //这是m//(模式匹配)的一种简写.同qw//操作一样,可以使用任何成对的分隔符.因此,可以使用m(fred), m<fred>, m{fred}, m[fred],或者 ...

  5. Java Spring MVC框架搭建(一)

    环境准备 >>>>>>java JDK和tomcat,eclipse 1.创建项目 2.项目名称自定义,这边为demo 3.我们已经创建完一个动态网站的项目,还得下 ...

  6. 老毛桃pe安装系统

    1.准备一个空白U盘,插入电脑. 2.下载老毛桃pe 3.下载完成后,打开老毛桃,默认制作成系统盘,傻瓜操作,无需修改参数 4.打开浏览器,下载要安装的系统 www.msdn.itellyou.cn ...

  7. 《HelloGitHub》第 27 期

    公告 网站新增了简单的搜索功能,可以通过项目名称或地址搜索.查看项目.欢迎star和推荐项目,我们一只在路上,希望志同道合者加入进来. 现招募专栏负责人: C# Java <HelloGitHu ...

  8. 基于Socket通讯(C#)和WebSocket协议(net)编写的两种聊天功能(文末附源码下载地址)

    今天我们来盘一盘Socket通讯和WebSocket协议在即时通讯的小应用——聊天. 理论大家估计都知道得差不多了,小编也通过查阅各种资料对理论知识进行了充电,发现好多demo似懂非懂,拷贝回来又运行 ...

  9. js 控制随机数生成概率

    基本思路:把Math.random()生成的数看着百分比,然后定义每个整数值取值范围. 'use strict'; export default class GL { /** * 构造函数 * @pa ...

  10. 用Gogs在Windows上搭建Git服务

    1.下载并安装Git,如有需求,请重启服务器让Path中的环境变量生效. 2.下载并安装Gogs,请注意,在Windows中部署时,请下载MiniWinService(mws)版本. 3.在Maria ...