在简单分布式系统day02的基础上,我们增加了一个服务,学生成绩查询服务,
grades.go代码如下
package grades
import (
"fmt"
"sync"
)
type Student struct {
ID int
FirstName string
LastName string
Grades []Grade
}
func (s Student)Average()float32 {
var result float32
for _,grade :=range s.Grades{
result+=grade.Score
}
return result/float32(len(s.Grades))
}
type Students []Student
var (
students Students
studentsMutex sync.Mutex
)
func (ss Students)GetByID(id int)(*Student,error) {
for i :=range ss{
if ss[i].ID == id {
return &ss[i], nil
}
}
return nil,fmt.Errorf("Student with ID %d not found",id);
}
type GradeType string
const(
GradeQuiz = GradeType("Quiz")
GradeTest = GradeType("Test")
GradeExam = GradeType("Exam")
)
type Grade struct {
Title string
Type GradeType
Score float32
}
主要功能为定义学生对象的结构体,成绩结构体,通过ID获取某个学生的对象,获取平均值的功能。
mockdata.go代码如下
package grades
func init() {
students = []Student{
{
ID: 1,
FirstName: "Nick",
LastName: "Carter",
Grades: []Grade{
{
Title: "Quiz 1",
Type: GradeQuiz,
Score: 85,
},
},
},
{
ID: 2,
FirstName: "Nick",
LastName: "Carter",
Grades: []Grade{
{
Title: "Quiz 1",
Type: GradeQuiz,
Score: 85,
},
},
},
}
}
手动给students赋值,同时当grades包被调用时,会自动执行init函数
server.go代码内容如下
package grades
import (
"bytes"
"encoding/json"
"fmt"
"log"
"net/http"
"strconv"
"strings"
)
func RegisterHandlers() {
handler:=new(studentsHandler)
http.Handle("/students",handler)
http.Handle("/students/",handler)
}
type studentsHandler struct {}
// /students
// /students/{id}
// /student/{id}/grades
func (sh studentsHandler)ServeHTTP(w http.ResponseWriter,r *http.Request) {
pathSegments :=strings.Split(r.URL.Path,"/")
switch len(pathSegments) {
case 2:
sh.getAll(w,r)
case 3:
id,err :=strconv.Atoi(pathSegments[2])
if err!=nil{
w.WriteHeader(http.StatusNotFound)
return
}
sh.getOne(w,r,id)
case 4:
id,err :=strconv.Atoi(pathSegments[2])
if err!=nil{
w.WriteHeader(http.StatusNotFound)
return
}
sh.addGrade(w,r,id)
default:
w.WriteHeader(http.StatusNotFound)
}
}
func (sh studentsHandler) getAll(w http.ResponseWriter,r *http.Request){
studentsMutex.Lock()
defer studentsMutex.Unlock()
data,err :=sh.toJSON(students)
if err!=nil{
w.WriteHeader(http.StatusInternalServerError)
log.Println(err)
return
}
w.Header().Add("Content-Type","application/json")
w.Write(data)
}
func (sh studentsHandler) getOne(w http.ResponseWriter,r *http.Request,id int){
studentsMutex.Lock()
defer studentsMutex.Unlock()
student,err :=students.GetByID(id)
if err!=nil{
w.WriteHeader(http.StatusNotFound)
log.Println(err)
return
}
data,err :=sh.toJSON(student)
if err!=nil{
w.WriteHeader(http.StatusInternalServerError)
log.Printf("Failed to serialize student:%q",err)
return
}
w.Header().Add("Content-Type","application/json")
w.Write(data)
}
func (sh studentsHandler)addGrade(w http.ResponseWriter,r *http.Request,id int){
studentsMutex.Lock()
defer studentsMutex.Unlock()
student,err :=students.GetByID(id)
if err!=nil{
w.WriteHeader(http.StatusNotFound)
log.Println(err)
return
}
var g Grade
dec:=json.NewDecoder(r.Body)
err =dec.Decode(&g)
if err!=nil {
w.WriteHeader(http.StatusBadRequest)
log.Println(err)
return
}
student.Grades = append(student.Grades,g)
w.WriteHeader(http.StatusCreated)
data,err:=sh.toJSON(g)
if err!=nil{
log.Println(err)
return
}
w.Header().Add("Content-Type","application/json")
w.Write(data)
}
func (sh studentsHandler) toJSON(obj interface{})([]byte,error) {
var b bytes.Buffer
enc:=json.NewEncoder(&b)
err:=enc.Encode(obj)
if err!=nil{
return nil,fmt.Errorf("Failed to serialize students:%s",err)
}
return b.Bytes(),nil
}
实现serveHTTP接口,成为一个handle,有获取所有student的方法,获取单个student的方法,还有添加成绩的方法
registration.go
package registry
type Registration struct {
ServiceName ServiceName
ServiceURL string
}
type ServiceName string
const(
LogService = ServiceName("LogService")
GradingService = ServiceName("GradingService")
)
gradingservice.go内容
package gradingservice
import (
"context"
"distributed/grades"
"distributed/registry"
"distributed/service"
"fmt"
stlog "log"
)
func main() {
host,port:="localhost","6000"
serviceAddress:=fmt.Sprintf("http://%v:%v",host,port)
r :=registry.Registration{
ServiceName: registry.GradingService,
ServiceURL: serviceAddress,
}
ctx,err:= service.Start(
context.Background(),//创建上下文对象
host,
port,
r,
grades.RegisterHandlers,
)
if err!=nil{
stlog.Fatalln(err)
}
<-ctx.Done()
fmt.Println("shutting down grading service.")
}
主要用于分配响应的handle,启动和监听服务,注册服务.