diff --git a/32-platform/platform/http/handing/routes.go b/32-platform/platform/http/handing/routes.go new file mode 100644 index 0000000..8c720bb --- /dev/null +++ b/32-platform/platform/http/handing/routes.go @@ -0,0 +1,123 @@ +package handing + +import ( + "net/http" + "reflect" + "regexp" + "strings" +) + +// HandlerEntry 路由条目 +type HandlerEntry struct { + // 路由前缀 + Prefix string + // 路由处理对象 + Handler interface{} +} + +type Route struct { + // HTTP 方法 + httpMethod string + // 路由前缀 + prefix string + // 路由处理对象名称 + handlerName string + actionName string + // 路由的正则表达式 + expression regexp.Regexp + // 路由方法 + handlerMethod reflect.Method +} + +var httpMethods = []string{ + http.MethodGet, + http.MethodPost, + http.MethodDelete, + http.MethodPut, +} + +func generateRoutes(entries ...HandlerEntry) []Route { + routes := make([]Route, 0, 10) + for _, entry := range entries { + // 获取处理对象的类型 + handlerType := reflect.TypeOf(entry.Handler) + // 获取处理对象中字段的所有方法 + promotedMethods := getAnonymousFieldMethods(handlerType) + // 遍历处理对象的所有方法 + for i := 0; i < handlerType.NumMethod(); i++ { + method := handlerType.Method(i) + methodName := strings.ToUpper(method.Name) + // 遍历 http 方法类型 + for _, httpMethod := range httpMethods { + if strings.Index(methodName, httpMethod) == 0 { + // 假如方法为字段的方法,则忽略 + if matchesPromotedMethodName(method, promotedMethods) { + continue + } + // 建立路由 + route := Route{ + // HTTP 方法 + httpMethod: httpMethod, + // 路由前缀 + prefix: entry.Prefix, + // 路由处理对象名称 + handlerName: strings.Split(handlerType.Name(), "Handler")[0], + // 动作名称 + actionName: strings.Split(methodName, httpMethod)[1], + // 调用方法 + handlerMethod: method, + } + // 生成正则表达式地址匹配 + generateRegularExpression(entry.Prefix, &route) + routes = append(routes, route) + } + } + } + } + return routes +} + +func matchesPromotedMethodName(method reflect.Method, methods []reflect.Method) bool { + for _, m := range methods { + if m.Name == method.Name { + return true + } + } + return false +} + +func getAnonymousFieldMethods(target reflect.Type) []reflect.Method { + var methods []reflect.Method + // 获取处理对象的所有字段 + for i := 0; i < target.NumField(); i++ { + field := target.Field(i) + if field.Anonymous && field.IsExported() { + // 获取字段的所有方法 + for j := 0; j < field.Type.NumField(); j++ { + method := field.Type.Method(j) + if method.IsExported() { + methods = append(methods, method) + } + } + } + } + return methods +} + +func generateRegularExpression(prefix string, route *Route) { + if prefix != "" && !strings.HasPrefix(prefix, "/") { + prefix += "/" + } + pattern := "(?i)" + "/" + prefix + route.actionName + if route.httpMethod == http.MethodGet { + for i := 1; i < route.handlerMethod.Type.NumIn(); i++ { + if route.handlerMethod.Type.In(i).Kind() == reflect.Int { + pattern += "/([0-9]*)" + } else { + pattern += "/([a-zA-Z0-9_]*)" + } + } + } + pattern = "^" + pattern + "[/]?$" + route.expression = *regexp.MustCompile(pattern) +} diff --git a/32-platform/platform/placeholder/name_handler.go b/32-platform/platform/placeholder/name_handler.go new file mode 100644 index 0000000..68ba3ae --- /dev/null +++ b/32-platform/platform/placeholder/name_handler.go @@ -0,0 +1,41 @@ +package placeholder + +import ( + "fmt" + "platform/logging" +) + +var names = []string{"Alice", "Bob", "charlie", "Dora"} + +type NameHandler struct { + logging.Logger +} + +type NewName struct { + Name string + InsertAtStart bool +} + +func (n NameHandler) GetName(i int) string { + n.Logger.Debugf("GetName method invoked with argument: %v", i) + if i < len(names) { + return fmt.Sprintf("Name #%v : %v", i, names[i]) + } else { + return fmt.Sprintf("Index out of bounds") + } +} + +func (n NameHandler) GetNames() string { + n.Logger.Debug("GetNames method invoked") + return fmt.Sprintf("Names: %v", names) +} + +func (n NameHandler) PostName(new NewName) string { + n.Logger.Debugf("PostName method invoked with argument: %v", new) + if new.InsertAtStart { + names = append([]string{new.Name}, names...) + } else { + names = append(names, new.Name) + } + return fmt.Sprintf("Names: %v", names) +}