代码很乱,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. Windows Server 2016-Hyper-V HNV 新增功能

    本内容主要介绍了Hyper-V 网络虚拟化 (HNV) 功能在 Windows Server 2016 中的新增或更改内容,具体信息如下: HNV更新 功能中的功能 新的或改进 描述 可编程 Hype ...

  2. ASP.NET Aries 高级开发教程:Excel导入之多表高级导入配置(中)

    前言: 在面对Excel的各种复杂导入情况中,多表导入是很常见的情景. 今天就来写一下多表导入是如何配置的. 1.自定义导入模板 怎么自定义: 其实就是自己新建一个Excel了,把列头都写好. 不过有 ...

  3. 发布基于Orchard Core的友浩达科技官网

    2018.9.25 日深圳市友浩达科技有限公司发布基于Orchard Core开发的官网 http://www.weyhd.com/. 本篇文章为你介绍如何基于Orchard Core开发一个公司网站 ...

  4. 【死磕 Spring】—– IOC 之解析Bean:解析 import 标签

    原文出自:http://cmsblogs.com 在博客[死磕Spring]----- IOC 之 注册 BeanDefinition中分析到,Spring 中有两种解析 Bean 的方式.如果根节点 ...

  5. 关于用户与服务端密码的校验问题 !mysql php

    问题:如何拿到服务端的数据与客户端的数据进行对比! 判断是否一致: 问题解决步骤: 建立数据库连接: $conn = mysqli_connect(主机地址,用户名,用户密码,数据库名字): 查询数据 ...

  6. 如何面对被抛弃的System.Data.OracleClient

    Visual Studio2012连接访问ORACLE数据库 近些年因工作内容的转变,很少去编码了.一些简单的需求使用VS+SQL SERVER这对老搭档便可快捷而舒服的搞定.只是近日需要管理一些OR ...

  7. Asp.NetCore轻松学-业务重点-实现一个简单的手机号码验证

    前言     本文纯干货,直接拿走使用,不用付费.在业务开发中,手机号码验证是我们常常需要面对的问题,目前市场上各种各样的手机号码验证方式,比如正则表达式等等,本文结合实际业务场景,在业务级别对手机号 ...

  8. Asp.Net Core 轻松学-利用文件监视进行快速测试开发

    前言     在进行 Asp.Net Core 应用程序开发过程中,通常的做法是先把业务代码开发完成,然后建立单元测试,最后进入本地系统集成测试:在这个过程中,程序员的大部分时间几乎都花费在开发.运行 ...

  9. PHP正则表达式二分法实现mysql盲注脚本

    $sUrl = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'; $sPost = 'inject=Inject&injection='; $sCharset = 'AB ...

  10. Java运行时环境---ClassLoader类加载机制

    背景:听说ClassLoader类加载机制是进入BAT的必经之路. ClassLoader总述: 普通的Java开发其实用到ClassLoader的地方并不多,但是理解透彻ClassLoader类的加 ...