kratos-blog之app

193 阅读13分钟

kratos-blog\app\blog\cmd\blog\main.go

package main

import (
    "flag"
    "github.com/go-kratos/kratos/v2"
    "github.com/go-kratos/kratos/v2/config"
    "github.com/go-kratos/kratos/v2/config/file"
    "github.com/go-kratos/kratos/v2/log"
    "github.com/go-kratos/kratos/v2/middleware/tracing"
    "github.com/go-kratos/kratos/v2/registry"
    "github.com/go-kratos/kratos/v2/transport/grpc"
    "github.com/go-kratos/kratos/v2/transport/http"
    _ "go.uber.org/automaxprocs"
    "kratos-blog/app/blog/internal/conf"
    _ "kratos-blog/app/blog/internal/data"
    "kratos-blog/pkg/server"
    "os"
)

// go build -ldflags "-X main.Version=x.y.z"
var (
    // Name is the name of the compiled software.
    Name = server.BlogService
    // Version is the version of the compiled software.
    Version = "1.0"
    // flagConf is the config flag.
    flagConf string

    id, _ = os.Hostname()
)

func init() {
    flag.StringVar(&flagConf, "conf", "P:\Github\GoLand5\kratos-blog\app\blog\configs", "config path, eg: -conf config.yaml")
}

func newApp(logger log.Logger, gs *grpc.Server, hs *http.Server, r registry.Registrar) *kratos.App {
    return kratos.New(
       kratos.ID(id+"-blog"),
       kratos.Name(Name),
       kratos.Version(Version),
       kratos.Metadata(map[string]string{}),
       kratos.Logger(logger),
       kratos.Server(
          gs,
          //hs, // 开启 HTTP
       ),
       kratos.Registrar(r),
    )
}

func main() {
    flag.Parse()
    logger := log.With(
       log.NewStdLogger(os.Stdout),
       "ts", log.DefaultTimestamp,
       "caller", log.DefaultCaller,
       "service.id", id+"-blog",
       "service.name", Name,
       "service.version", Version,
       "trace.id", tracing.TraceID(),
       "span.id", tracing.SpanID(),
    )
    c := config.New(
       config.WithSource(
          file.NewSource(flagConf),
       ),
    )
    defer c.Close()

    if err := c.Load(); err != nil {
       panic(err)
    }

    var bc conf.Bootstrap
    if err := c.Scan(&bc); err != nil {
       panic(err)
    }
    var rc conf.Registry
    if err := c.Scan(&rc); err != nil {
       panic(err)
    }
    app, cleanup, err := wireApp(&bc, &rc, logger)
    if err != nil {
       panic(err)
    }
    defer cleanup()

    // start and wait for stop signal
    if err := app.Run(); err != nil {
       panic(err)
    }
}

kratos-blog\app\blog\cmd\blog\wire.go

//go:build wireinject
// +build wireinject

// The build tag makes sure the stub is not built in the final build.

package main

import (
    "blog/internal/biz"
    "blog/internal/conf"
    "blog/internal/data"
    "blog/internal/server"
    "blog/internal/service"

    "github.com/go-kratos/kratos/v2"
    "github.com/go-kratos/kratos/v2/log"
    "github.com/google/wire"
)

// wireApp init kratos application.
func wireApp(*conf.Server, *conf.Data, log.Logger) (*kratos.App, func(), error) {
    panic(wire.Build(server.ProviderSet, data.ProviderSet, biz.ProviderSet, service.ProviderSet, newApp))
}

kratos-blog\app\blog\internal\biz\biz.go

package biz

import "github.com/google/wire"

// ProviderSet is biz providers.
var ProviderSet = wire.NewSet(NewBlogUseCase, NewFriendUseCase, NewTagUseCase)

kratos-blog\app\blog\internal\biz\blog.go

package biz

import (
    "context"
    "github.com/go-kratos/kratos/v2/log"
    pb "kratos-blog/api/v1/blog"
    "kratos-blog/pkg/vo"
)

type BlogRepo interface {
    CreateBlog(ctx context.Context, request *pb.CreateBlogRequest) (string, error)
    UpdateBlog(ctx context.Context, request *pb.UpdateBlogRequest) (string, error)
    DeleteBlog(ctx context.Context, request *pb.DeleteBlogRequest) (string, error)
    UpdateIndividualFields(ctx context.Context, request *pb.UpdateIndividualFieldsRequest) (string, error)
    GetByTagName(ctx context.Context, request *pb.GetBlogRequest) (string, []*pb.BlogData, error)
    ListBlog(ctx context.Context, request *pb.ListBlogRequest) (string, []*pb.BlogData, error)
    QueryBlogById(ctx context.Context, request *pb.GetBlogIDRequest) (msg string, da pb.BlogData, e error)
    QueryBlogByTitle(ctx context.Context, request *pb.GetBlogByTitleRequest) (string, []*pb.BlogData, error)
    UpdateOnly(ctx context.Context, request *pb.UpdateOnlyRequest) *pb.UpdateOnlyReply
    CacheBlog(ctx context.Context, request *pb.CreateBlogRequest) *pb.CreateBlogReply
    GetCacheBlog(ctx context.Context) *pb.ListCacheReply
    DeleteCacheBlog(ctx context.Context, request *pb.DeleteCacheBlogRequest) *pb.DeleteCacheBlogReply
    AddSuggestBlog(ctx context.Context, request *pb.SuggestBlogRequest) *pb.SuggestBlogReply
    GetAllSuggestBlog(ctx context.Context, request *pb.SearchAllSuggest) *pb.SearchAllReply
    DeleteSuggestBlog(ctx context.Context, request *pb.SuggestBlogRequest) *pb.SuggestBlogReply
}

// 内嵌接口的结构体不可以直接调用接口的方法
// 结构体方法可以时对内嵌接口定义方法的一层封装
type BlogUseCase struct {
    repo BlogRepo
    log  *log.Helper
}

func NewBlogUseCase(repo BlogRepo, logger log.Logger) *BlogUseCase {
    return &BlogUseCase{repo: repo, log: log.NewHelper(logger)}
}

func SetStatus(code int64, msg string) *pb.CommonReply {
    return &pb.CommonReply{
       Code:   code,
       Result: msg,
    }
}

func (uc *BlogUseCase) AddBlog(ctx context.Context, request *pb.CreateBlogRequest) *pb.CreateBlogReply {
    u, err := uc.repo.CreateBlog(ctx, request)
    status := func(code int64, msg string) *pb.CreateBlogReply {
       return &pb.CreateBlogReply{
          Common: SetStatus(code, msg),
       }
    }
    if err != nil {
       uc.log.Log(log.LevelError, err)
       return status(400, u)
    }
    return status(200, u)
}

func (uc *BlogUseCase) UpdateBlog(ctx context.Context, request *pb.UpdateBlogRequest) *pb.UpdateBlogReply {
    u, err := uc.repo.UpdateBlog(ctx, request)
    status := func(code int64, msg string) *pb.UpdateBlogReply {
       return &pb.UpdateBlogReply{
          Common: SetStatus(code, msg),
       }
    }
    if err != nil {
       uc.log.Log(log.LevelError, err)
       return status(400, u)
    }
    return status(200, u)
}

func (uc *BlogUseCase) DeleteBlog(ctx context.Context, request *pb.DeleteBlogRequest) *pb.DeleteBlogReply {
    u, err := uc.repo.DeleteBlog(ctx, request)
    status := func(code int64, msg string) *pb.DeleteBlogReply {
       return &pb.DeleteBlogReply{
          Common: SetStatus(code, msg),
       }
    }
    if err != nil {
       uc.log.Log(log.LevelError, err)
       return status(400, u)
    }
    return status(200, u)
}

func (uc *BlogUseCase) UpdateIndividualFields(ctx context.Context, request *pb.UpdateIndividualFieldsRequest) *pb.UpdateIndividualFieldsReply {
    u, err := uc.repo.UpdateIndividualFields(ctx, request)
    status := func(code int64, msg string) *pb.UpdateIndividualFieldsReply {
       return &pb.UpdateIndividualFieldsReply{
          Common: SetStatus(code, msg),
       }
    }
    if err != nil {
       uc.log.Log(log.LevelError, err)
       return status(400, u)
    }
    return status(200, u)
}

func (uc *BlogUseCase) GetByTagName(ctx context.Context, request *pb.GetBlogRequest) *pb.GetBlogReply {
    u, d, err := uc.repo.GetByTagName(ctx, request)
    status := func(code int64, msg string, list []*pb.BlogData) *pb.GetBlogReply {
       return &pb.GetBlogReply{
          Common: SetStatus(code, msg),
          List:   d,
       }
    }
    if err != nil {
       uc.log.Log(log.LevelError, err)
       return status(400, u, nil)
    }
    return status(200, u, d)
}

func (uc *BlogUseCase) ListBlog(ctx context.Context, request *pb.ListBlogRequest) *pb.ListBlogReply {
    u, d, err := uc.repo.ListBlog(ctx, request)
    status := func(code int64, msg string, list []*pb.BlogData) *pb.ListBlogReply {
       return &pb.ListBlogReply{
          Common: SetStatus(code, msg),
          List:   d,
       }
    }
    if err != nil {
       uc.log.Log(log.LevelError, err)
       return status(400, u, nil)
    } else if len(d) == 0 {
       return status(300, vo.QueryEmpty, nil)
    }
    return status(200, u, d)
}

func (uc *BlogUseCase) QueryBlogByID(ctx context.Context, request *pb.GetBlogIDRequest) *pb.GetBlogIDReply {
    u, d, err := uc.repo.QueryBlogById(ctx, request)
    status := func(code int64, msg string, data pb.BlogData) *pb.GetBlogIDReply {
       return &pb.GetBlogIDReply{
          Common: SetStatus(code, msg),
          Data:   &data,
       }
    }
    if err != nil {
       uc.log.Log(log.LevelError, err)
       return status(400, u, d)
    }
    return status(200, u, d)
}

func (uc *BlogUseCase) QueryBlogByTitle(ctx context.Context, request *pb.GetBlogByTitleRequest) *pb.GetBlogByTitleReply {
    u, d, err := uc.repo.QueryBlogByTitle(ctx, request)
    status := func(code int64, msg string, data []*pb.BlogData) *pb.GetBlogByTitleReply {
       return &pb.GetBlogByTitleReply{
          Common: SetStatus(code, msg),
          Data:   data,
       }
    }
    if err != nil {
       uc.log.Log(log.LevelError, err)
       return status(400, u, d)
    }
    return status(200, u, d)
}

func (uc *BlogUseCase) UpdateOnly(ctx context.Context, request *pb.UpdateOnlyRequest) *pb.UpdateOnlyReply {
    return uc.repo.UpdateOnly(ctx, request)
}

func (uc *BlogUseCase) CacheBlog(ctx context.Context, request *pb.CreateBlogRequest) *pb.CreateBlogReply {
    return uc.repo.CacheBlog(ctx, request)
}

func (uc *BlogUseCase) GetAllCacheBlog(ctx context.Context) *pb.ListCacheReply {
    return uc.repo.GetCacheBlog(ctx)
}

func (uc *BlogUseCase) DeleteCacheBlog(ctx context.Context, request *pb.DeleteCacheBlogRequest) *pb.DeleteCacheBlogReply {
    return uc.repo.DeleteCacheBlog(ctx, request)
}

func (uc *BlogUseCase) SetSuggestBlog(ctx context.Context, request *pb.SuggestBlogRequest) *pb.SuggestBlogReply {
    return uc.repo.AddSuggestBlog(ctx, request)
}

func (uc *BlogUseCase) GetSuggestBlog(ctx context.Context, request *pb.SearchAllSuggest) *pb.SearchAllReply {
    return uc.repo.GetAllSuggestBlog(ctx, request)
}
func (uc *BlogUseCase) DeleteSuggestBlog(ctx context.Context, request *pb.SuggestBlogRequest) *pb.SuggestBlogReply {
    return uc.repo.DeleteSuggestBlog(ctx, request)
}

kratos-blog\app\blog\internal\biz\friend.go

package biz

import (
    "context"
    "github.com/go-kratos/kratos/v2/log"
    pb "kratos-blog/api/v1/friend"
)

type FriendRepo interface {
    CreateFriend(ctx context.Context, request *pb.CreateFriendRequest) *pb.CreateFriendReply
    DeleteFriend(ctx context.Context, request *pb.DeleteFriendRequest) *pb.DeleteFriendReply
    SearchAllFriend(ctx context.Context, request *pb.ListFriendRequest) *pb.ListFriendReply
    UpdateFriend(ctx context.Context, request *pb.UpdateFriendRequest) *pb.UpdateFriendReply
    GetFriendByCond(ctx context.Context, request *pb.GetFriendRequest) *pb.GetFriendReply
}

type FriendUseCase struct {
    repo FriendRepo
    log  *log.Helper
}

func NewFriendUseCase(repo FriendRepo, logger log.Logger) *FriendUseCase {
    return &FriendUseCase{repo: repo, log: log.NewHelper(logger)}
}

func (f *FriendUseCase) CreateFriend(ctx context.Context, request *pb.CreateFriendRequest) *pb.CreateFriendReply {
    return f.repo.CreateFriend(ctx, request)
}
func (f *FriendUseCase) DeleteFriend(ctx context.Context, request *pb.DeleteFriendRequest) *pb.DeleteFriendReply {
    return f.repo.DeleteFriend(ctx, request)
}
func (f *FriendUseCase) SearchAllFriend(ctx context.Context, request *pb.ListFriendRequest) *pb.ListFriendReply {
    return f.repo.SearchAllFriend(ctx, request)
}
func (f *FriendUseCase) UpdateFriend(ctx context.Context, request *pb.UpdateFriendRequest) *pb.UpdateFriendReply {
    return f.repo.UpdateFriend(ctx, request)
}
func (f *FriendUseCase) GetFriendByCond(ctx context.Context, request *pb.GetFriendRequest) *pb.GetFriendReply {
    return f.repo.GetFriendByCond(ctx, request)
}

kratos-blog\app\blog\internal\biz\photo.go

package biz

import (
    "context"
    "github.com/go-kratos/kratos/v2/log"
    pb "kratos-blog/api/v1/photo"
)

type PhotoRepo interface {
    CreatePhoto(ctx context.Context, request *pb.CreatePhotoRequest) *pb.CreatePhotoReply
    DeletePhoto(ctx context.Context, request *pb.DeletePhotoRequest) *pb.DeletePhotoReply
    SearchAllPhoto(ctx context.Context, request *pb.ListPhotoRequest) *pb.ListPhotoReply
}

type PhotoUseCase struct {
    repo PhotoRepo
    log  *log.Helper
}

func NewPhotoUseCase(repo PhotoRepo, logger log.Logger) *PhotoUseCase {
    return &PhotoUseCase{repo: repo, log: log.NewHelper(logger)}
}

func (t *PhotoUseCase) CreatePhoto(ctx context.Context, request *pb.CreatePhotoRequest) *pb.CreatePhotoReply {
    return t.repo.CreatePhoto(ctx, request)
}

func (t *PhotoUseCase) DeletePhoto(ctx context.Context, request *pb.DeletePhotoRequest) *pb.DeletePhotoReply {
    return t.repo.DeletePhoto(ctx, request)
}

func (t *PhotoUseCase) SearchAllPhoto(ctx context.Context, request *pb.ListPhotoRequest) *pb.ListPhotoReply {
    return t.repo.SearchAllPhoto(ctx, request)
}

kratos-blog\app\blog\internal\biz\tag.go

package biz

import (
    "context"
    "github.com/go-kratos/kratos/v2/log"
    pb "kratos-blog/api/v1/tag"
)

type TagRepo interface {
    CreateTag(ctx context.Context, request *pb.CreateTagRequest) *pb.CreateTagReply
    DeleteTag(ctx context.Context, request *pb.DeleteTagRequest) *pb.DeleteTagReply
    SearchAllTag(ctx context.Context, request *pb.ListTagRequest) *pb.ListTagReply
}

type TagUseCase struct {
    repo TagRepo
    log  *log.Helper
}

func NewTagUseCase(repo TagRepo, logger log.Logger) *TagUseCase {
    return &TagUseCase{repo: repo, log: log.NewHelper(logger)}
}

func (t *TagUseCase) CreateTag(ctx context.Context, request *pb.CreateTagRequest) *pb.CreateTagReply {
    return t.repo.CreateTag(ctx, request)
}

func (t *TagUseCase) DeleteTag(ctx context.Context, request *pb.DeleteTagRequest) *pb.DeleteTagReply {
    return t.repo.DeleteTag(ctx, request)
}

func (t *TagUseCase) SearchAllTag(ctx context.Context, request *pb.ListTagRequest) *pb.ListTagReply {
    return t.repo.SearchAllTag(ctx, request)
}

kratos-blog\app\blog\internal\conf\conf.proto

syntax = "proto3";
package kratos.api;

option go_package = "blog/internal/conf;conf";

import "google/protobuf/duration.proto";

message Bootstrap {
  Server server = 1;
  Data data = 2;
  Service service = 3;
}

message Server {
  message HTTP {
    string network = 1;
    string addr = 2;
    google.protobuf.Duration timeout = 3;
  }
  message GRPC {
    string network = 1;
    string addr = 2;
    google.protobuf.Duration timeout = 3;
  }
  HTTP http = 1;
  GRPC grpc = 2;
}

message Data {
  message Database {
    string driver = 1;
    string source = 2;
  }
  message Redis {
    string network = 1;
    string addr = 2;
    google.protobuf.Duration read_timeout = 3;
    google.protobuf.Duration write_timeout = 4;
    int64 db = 5;
    string password = 6;
  }
  Database database = 1;
  Redis redis = 2;
}

message Registry {
  message Consul {
    string address = 1;
    string scheme = 2;
  }
  Consul consul = 1;
}

message Service {
  message User {
    string endpoint = 1;
  }
  User user = 1;
}

kratos-blog\app\blog\internal\data\blog.go

package data

import (
    "context"
    "encoding/json"
    "errors"
    "github.com/go-kratos/kratos/v2/log"
    "kratos-blog/api/v1/blog"
    "kratos-blog/app/blog/internal/biz"
    "kratos-blog/pkg/server"
    "kratos-blog/pkg/vo"
    "strconv"
    "time"
)

const (
    AdminNotes  = server.AdminNotes
    Notes       = server.Notes
    TableName   = server.TableName
    Comment     = server.Comment
    Appear      = server.Appear
    CacheBlog   = server.CacheBlog
    SuggestBlog = server.SuggestBlog
)

type blogRepo struct {
    data *Data
    log  *log.Helper
}

func NewBlogRepo(data *Data, logger log.Logger) biz.BlogRepo {
    return &blogRepo{
       data: data,
       log:  log.NewHelper(logger),
    }
}

// CreateBlog :dev
func (r *blogRepo) CreateBlog(ctx context.Context, request *blog.CreateBlogRequest) (string, error) {
    var blog Blog
    re := r.createBlogFromRequest(request)
    blog = re()
    if err := r.data.db.Create(&blog).Error; err != nil {
       r.log.Info(err)
       return vo.InsertError, err
    }
    return vo.InsertSuccess, nil
}

func (r *blogRepo) UpdateBlog(ctx context.Context, request *blog.UpdateBlogRequest) (string, error) {
    var blog Blog
    f, _ := json.Marshal(&request.Data)
    if err := json.Unmarshal(f, &blog); err != nil {
       panic(err)
    }
    blog.UpdateTime = time.Now().Format("2006-01-02")
    if err := r.data.db.Model(&blog).Where("id = ?", request.Id).Updates(blog).Error; err != nil {
       r.log.Log(log.LevelError, "Error updating blog:", err)
       return vo.UpdateFail, err
    }
    return vo.UpdateSuccess, nil
}

func (r *blogRepo) DeleteBlog(ctx context.Context, request *blog.DeleteBlogRequest) (string, error) {
    cacheKey, _ := r.data.rdb.Get(context.Background(), "privateKey").Result()
    if request.Key == cacheKey {
       if err := r.data.db.Where("id = ?", request.Id).Delete(&Blog{}).Error; err != nil {
          r.log.Log(log.LevelError, err)
          return vo.DeleteError, err
       }
    } else {
       return vo.KeyError, errors.New(vo.KeyError)
    }
    return vo.DeleteSuccess, nil
}

// UpdateIndividualFields :dev Whether comments are allowed on the blog
func (r *blogRepo) UpdateIndividualFields(ctx context.Context, request *blog.UpdateIndividualFieldsRequest) (string,
    error) {
    var condName string
    switch request.Raw {
    case 0:
       condName = Comment
    case 1:
       condName = Appear
    }
    if err := r.data.pf.UpdateFunc(Blog{}, nil, map[string]any{condName: request.Status},
       true); err != nil {
       err := errors.New(vo.UpdateFail)
       r.log.Log(log.LevelError, err)
       return vo.UpdateFail, err
    }
    return vo.UpdateSuccess, nil
}

// createBlogFromRequest :dev create a blog record
func (r *blogRepo) createBlogFromRequest(request *blog.CreateBlogRequest) func() Blog {
    return func() Blog {
       var blog Blog
       f, _ := json.Marshal(&request.Data)
       if err := json.Unmarshal(f, &blog); err != nil {
          panic(err)
       }
       blog.CreateTime = time.Now().Format("2006-01-02")
       blog.UpdateTime = time.Now().Format("2006-01-02")
       blog.Comment = true
       blog.Visits = 0
       blog.Appear = true
       return blog
    }
}

// GetByTagName :dev search blog posts based on tags
func (r *blogRepo) GetByTagName(ctx context.Context, request *blog.GetBlogRequest) (string,
    []*blog.BlogData, error) {
    var (
       blogs []*blog.BlogData
       err   error
    )
    if request.GetPermission().GetAdmin() {
       admin := AdminRoleFactory{r: r, req: request}
       blogs, err = admin.QueryTag()
    } else {
       v := UserOrVisitFactory{r: r, req: request}
       blogs, err = v.QueryTag()
    }
    if err != nil {
       return err.Error(), nil, err
    }
    return vo.QuerySuccess, blogs, nil
}

// ListBlog :dev query all blog posts based on permissions
func (r *blogRepo) ListBlog(ctx context.Context, request *blog.ListBlogRequest) (string,
    []*blog.BlogData, error) {
    var (
       blogs []*blog.BlogData
       err   error
    )
    if request.GetPermission().GetAdmin() {
       admin := AdminRoleFactory{r: r, reb: request}
       blogs, err = admin.QueryListBlog()
    } else {
       v := UserOrVisitFactory{r: r, reb: request}
       blogs, err = v.QueryListBlog()
    }
    if err != nil {
       return vo.QueryFail, blogs, nil
    }
    return vo.QuerySuccess, blogs, nil
}

// QueryBlogById :dev more blog post ID query blog posts
func (r *blogRepo) QueryBlogById(ctx context.Context, request *blog.GetBlogIDRequest) (msg string,
    da blog.BlogData, e error) {
    var b Blog
    if err := r.data.db.Where("id = ?", request.Id).First(&b).Error; err != nil {
       r.log.Errorf("query error %s", err)
       return vo.QueryFail, blog.BlogData{}, err
    }
    if err := r.data.pf.ParseJSONToStruct(b, &da); err != nil {
       return vo.JsonError, blog.BlogData{}, err
    }

    if !b.Appear && !request.GetPermission().GetAdmin() {
       return vo.ForbiddenAccess, blog.BlogData{}, nil
    }
    strID := strconv.Itoa(int(request.Id))
    if r.hasHashField(TableName, strID) {
       currentCount := r.getHashField(TableName, strID)
       r.setHashField(TableName, strID, currentCount+1)
    } else {
       r.setHashField(TableName, strID, 1)
    }
    return vo.QuerySuccess, da, nil
}

// UpdateBlogVisitsCount :dev update the number of blog post visits
func (r *blogRepo) UpdateBlogVisitsCount() {
    var blogs []Blog
    if err := r.data.db.Table(Blog{}.TableName()).Find(&blogs).Error; err != nil {
       panic(err)
    }

    // traverse the list
    for _, blog := range blogs {
       visitCount := blog.Visits
       var res error
       cacheCount := r.getHashField(TableName, strconv.Itoa(blog.ID))
       if !r.hasHashField(TableName, strconv.Itoa(blog.ID)) {
          res = r.data.pf.UpdateFunc(Blog{}, map[string]any{"id": blog.ID},
             map[string]any{"visits": 0}, false)
       } else if cacheCount < visitCount {
          r.setHashField(TableName, strconv.Itoa(blog.ID), visitCount)
       } else {
          res = r.data.pf.UpdateFunc(Blog{}, map[string]any{"id": blog.ID},
             map[string]any{"visits": cacheCount}, false)
       }
       if res != nil {
          r.log.Info(blog.ID, "update failed!")
       }
    }
}

// QueryBlogByTitle :dev query for matching blog posts based on the title
func (r *blogRepo) QueryBlogByTitle(ctx context.Context, request *blog.GetBlogByTitleRequest) (string,
    []*blog.BlogData, error) {
    var (
       data  []*blog.BlogData
       blogs []Blog
    )
    keyword := "%" + request.Title + "%"
    if err := r.data.db.Where("title LIKE ?", keyword).Find(&blogs).Error; err != nil {
       r.log.Log(log.LevelError, err)
       return vo.QueryFail, nil, errors.New(vo.QueryFail)
    }
    r.data.pf.ParseJSONToStruct(blogs, &data)
    return vo.QuerySuccess, data, nil
}

func (r *blogRepo) UpdateOnly(ctx context.Context, request *blog.UpdateOnlyRequest) *blog.UpdateOnlyReply {
    var condName string
    switch request.Raw {
    case 0:
       condName = Comment
    case 1:
       condName = Appear
    }
    if err := r.data.pf.UpdateFunc(Blog{}, map[string]any{"id": request.Id},
       map[string]any{condName: request.Res}, false); err != nil {
       return &blog.UpdateOnlyReply{Common: &blog.CommonReply{Code: 400, Result: vo.UpdateFail}}
    }
    return &blog.UpdateOnlyReply{Common: &blog.CommonReply{Code: 200, Result: vo.UpdateSuccess}}
}

func (r *blogRepo) CacheBlog(ctx context.Context, request *blog.CreateBlogRequest) *blog.CreateBlogReply {
    r.setCacheList(CacheBlog, []any{request.Data})
    return &blog.CreateBlogReply{
       Common: &blog.CommonReply{
          Code:   200,
          Result: vo.CreateSuccess,
       },
    }
}

func (r *blogRepo) GetCacheBlog(ctx context.Context) *blog.ListCacheReply {
    return &blog.ListCacheReply{
       Common: &blog.CommonReply{
          Code:   200,
          Result: vo.QuerySuccess,
       },
       List: r.restoreList(CacheBlog),
    }
}

func (r *blogRepo) DeleteCacheBlog(ctx context.Context,
    request *blog.DeleteCacheBlogRequest) *blog.DeleteCacheBlogReply {
    if !r.delListItem(CacheBlog, request.GetKey()) {
       return &blog.DeleteCacheBlogReply{
          Common: &blog.CommonReply{
             Code:   500,
             Result: vo.DeleteError,
          },
       }
    }
    return &blog.DeleteCacheBlogReply{
       Common: &blog.CommonReply{
          Code:   200,
          Result: vo.DeleteSuccess,
       },
    }
}

func (r *blogRepo) AddSuggestBlog(ctx context.Context, request *blog.SuggestBlogRequest) *blog.SuggestBlogReply {
    _, data, err := r.QueryBlogById(ctx, &blog.GetBlogIDRequest{Id: request.GetId()})
    if err != nil {
       r.log.Log(log.LevelError, err)
    }
    r.setCacheList(SuggestBlog, []any{data})
    return &blog.SuggestBlogReply{
       Common: &blog.CommonReply{
          Code:   vo.SuccessRequest,
          Result: vo.InsertSuccess,
       },
    }
}

func (r *blogRepo) DeleteSuggestBlog(ctx context.Context, request *blog.SuggestBlogRequest) *blog.SuggestBlogReply {
    if !r.delListItem(SuggestBlog, request.Id) {
       return &blog.SuggestBlogReply{
          Common: &blog.CommonReply{
             Code:   500,
             Result: vo.DeleteError,
          },
       }
    }
    return &blog.SuggestBlogReply{
       Common: &blog.CommonReply{
          Code:   vo.SuccessRequest,
          Result: vo.DeleteSuccess,
       },
    }
}

func (r *blogRepo) GetAllSuggestBlog(ctx context.Context, request *blog.SearchAllSuggest) *blog.SearchAllReply {
    return &blog.SearchAllReply{Common: &blog.CommonReply{Code: vo.SuccessRequest, Result: vo.QuerySuccess},
       List: r.restoreList(SuggestBlog)}
}

// ***************** Redis Util *********************** //

func (r *blogRepo) setHashField(hashKey, field string, val any) {
    err := r.data.rdb.HSet(CTX, hashKey, field, val).Err()
    if err != nil {
       r.log.Log(log.LevelError, err)
    }
}

func (r *blogRepo) hasHashField(hashKey, field string) bool {
    val, _ := r.data.rdb.HExists(CTX, hashKey, field).Result()
    return val
}

func (r *blogRepo) getHashField(hashKey, field string) uint64 {
    val, err := r.data.rdb.HGet(CTX, hashKey, field).Uint64()
    if err != nil {
       r.log.Log(log.LevelError, err)
    }
    return val
}

func (r *blogRepo) parseList(o []*blog.BlogData) []any {
    m, _ := json.Marshal(&o)
    var newList []any
    if err := json.Unmarshal(m, &newList); err != nil {
       panic(err)
    }
    return newList
}

func (r *blogRepo) restoreList(key string) []*blog.BlogData {
    var newList []*blog.BlogData
    serializedValues, err := r.data.rdb.LRange(CTX, key, 0, -1).Result()
    if err != nil {
       r.log.Log(log.LevelError, "Failed to retrieve values from Redis list:", err)
       panic(err)
    }
    for _, serializedValue := range serializedValues {
       var value blog.BlogData
       if e := json.Unmarshal([]byte(serializedValue), &value); e != nil {
          r.log.Log(log.LevelError, "Failed to deserialize value from JSON:", e)
          continue
       }
       newList = append(newList, &value)
    }
    return newList
}

func (r *blogRepo) setCacheList(key string, o []any) {
    for _, value := range o {
       serializedValue, err := json.Marshal(value)
       if err != nil {
          r.log.Log(log.LevelError, err)
          continue
       }
       i, e := r.data.rdb.RPush(CTX, key, serializedValue).Result()
       if e != nil {
          r.log.Log(log.LevelError, "Failed to push serialized value to Redis list:", e)
       }
       r.log.Log(log.LevelInfo, "Successfully pushed value to Redis list", i)
    }
}

func (r *blogRepo) delListItem(key string, index int64) bool {
    val, err := r.data.rdb.LIndex(CTX, key, index).Result()
    if err != nil {
       r.log.Log(log.LevelError, err)
       return false
    }
    removed, e := r.data.rdb.LRem(CTX, key, index, val).Result()
    if e != nil {
       r.log.Log(log.LevelError, removed, e)
       return false
    }
    return true
}

type Blog struct {
    ID         int    `json:"id" gorm:"primary_key;auto_increment"`
    Title      string `json:"title"`
    Preface    string `json:"preface"`
    Photo      string `json:"photo"`
    Tag        string `json:"tag"`
    CreateTime string `gorm:"column:createTime" json:"createTime"`
    UpdateTime string `gorm:"column:updateTime" json:"updateTime"`
    Visits     uint64 `json:"visits"`
    Content    string `json:"content"`
    Appear     bool   `json:"appear"`
    Comment    bool   `json:"gateway"`
}

func (b Blog) TableName() string {
    return "person_table"
}

kratos-blog\app\blog\internal\data\cron.go

package data

import (
    "fmt"
    "github.com/robfig/cron/v3"
)

func init() {
    CronDay()
}

// ********** Scheduled tasks ******************//

func CronDay() {
    c := cron.New()
    b := blogRepo{}
    e, err := c.AddFunc("0 0 * * *", func() {
       go b.UpdateBlogVisitsCount()
    })
    fmt.Println(e, err)
    c.Start()
}

kratos-blog\app\blog\internal\data\data.go

package data

import (
    "context"
    "github.com/go-kratos/kratos/contrib/registry/consul/v2"
    "github.com/go-kratos/kratos/v2/log"
    "github.com/go-kratos/kratos/v2/middleware/recovery"
    "github.com/go-kratos/kratos/v2/middleware/tracing"
    "github.com/go-kratos/kratos/v2/registry"
    "github.com/go-kratos/kratos/v2/selector"
    "github.com/go-kratos/kratos/v2/selector/wrr"
    "github.com/go-kratos/kratos/v2/transport/grpc"
    "github.com/google/wire"
    consulAPI "github.com/hashicorp/consul/api"
    "github.com/redis/go-redis/v9"
    grpcx "google.golang.org/grpc"
    "gorm.io/driver/mysql"
    "gorm.io/gorm"
    "kratos-blog/api/v1/user"
    "kratos-blog/app/blog/internal/conf"
    "kratos-blog/pkg/model"
    "sync"
    "time"
)

var (
    CTX = context.Background()
    // ProviderSet is data providers.
    ProviderSet = wire.NewSet(NewData, NewRegistrar, NewDiscovery)
    mu          sync.Mutex
)

// Data .
type Data struct {
    log *log.Helper
    uc  user.UserClient
    db  *gorm.DB
    rdb *redis.Client
    pf  model.PublicFunc
    c   *conf.Bootstrap
}

// NewData .
func NewData(c *conf.Bootstrap, logger log.Logger, db *gorm.DB, rdb *redis.Client, uc user.UserClient) (*Data, error) {
    l := log.NewHelper(log.With(logger, "module", "data"))
    pf := model.NewOFunc(l, db)
    return &Data{log: l, uc: uc, db: db, rdb: rdb, pf: pf, c: c}, nil
}

// NewRegistrar add consul
func NewRegistrar(conf *conf.Registry) registry.Registrar {
    c := consulAPI.DefaultConfig()
    c.Address = conf.Consul.Address
    c.Scheme = conf.Consul.Scheme
    c.Namespace = ""
    cli, err := consulAPI.NewClient(c)
    if err != nil {
       panic(err)
    }
    r := consul.New(cli, consul.WithHealthCheck(false))
    return r
}

func NewDiscovery(conf *conf.Registry) registry.Discovery {
    c := consulAPI.DefaultConfig()
    c.Address = conf.Consul.Address
    c.Scheme = conf.Consul.Scheme
    cli, err := consulAPI.NewClient(c)
    if err != nil {
       panic(err)
    }
    r := consul.New(cli, consul.WithHealthCheck(false))
    return r
}

func NewDB(conf *conf.Data) *gorm.DB {
    db, err := gorm.Open(mysql.Open(conf.Database.Source), &gorm.Config{
       DisableForeignKeyConstraintWhenMigrating: true,
    })
    if err != nil {
       panic("failed to connect database")
    }
    InitDB(db)
    return db
}

func InitDB(db *gorm.DB) {
    if err := db.AutoMigrate(
       &Blog{},
       &Tag{},
       &Friend{},
       &Photo{},
    ); err != nil {
       panic(err)
    }
}

func NewRDB(conf *conf.Data) *redis.Client {
    return redis.NewClient(
       &redis.Options{
          Addr:     conf.Redis.Addr,
          DB:       int(conf.Redis.Db),
          Password: conf.Redis.Password,
       },
    )
}
func NewGrpcServiceClient(sr *conf.Service, rr registry.Discovery) user.UserClient {
    selector.SetGlobalSelector(wrr.NewBuilder())
    conn, err := grpc.DialInsecure(
       context.Background(),
       grpc.WithEndpoint(sr.User.Endpoint),
       grpc.WithDiscovery(rr),
       grpc.WithMiddleware(
          tracing.Client(),
          recovery.Recovery(),
       ),
       grpc.WithOptions(grpcx.WithStatsHandler(&tracing.ClientHandler{})),
       grpc.WithHealthCheck(true),
       grpc.WithTimeout(5*time.Second),
    )
    if err != nil {
       panic(err)
    }
    c := user.NewUserClient(conn)
    return c
}

kratos-blog\app\blog\internal\data\friend.go

package data

import (
    "context"
    "github.com/go-kratos/kratos/v2/log"
    pb "kratos-blog/api/v1/friend"
    "kratos-blog/app/blog/internal/biz"
    "kratos-blog/pkg/vo"
    "time"
)

type Friend struct {
    ID      int    `json:"id" gorm:"primary_key;auto_increment"`
    Title   string `json:"title"`
    Preface string `json:"preface"`
    Url     string `json:"url"`
    Photo   string `json:"photo"`
    Date    string `json:"date"`
}

func (f *Friend) TableName() string {
    return "friend_table"
}

type friendRepo struct {
    data *Data
    log  *log.Helper
}

func NewFriendRepo(data *Data, logger log.Logger) biz.FriendRepo {
    return &friendRepo{
       data: data,
       log:  log.NewHelper(logger),
    }
}

func (t *friendRepo) CreateFriend(ctx context.Context, request *pb.CreateFriendRequest) *pb.CreateFriendReply {
    var friend Friend
    t.data.pf.ParseJSONToStruct(request.Data, &friend)
    friend.Date = time.Now().Format("2006-01-02")
    if err := t.data.db.Create(&friend).Error; err != nil {
       return &pb.CreateFriendReply{Common: &pb.CommonReply{Code: 500, Result: vo.InsertError}}
    }
    return &pb.CreateFriendReply{
       Common: &pb.CommonReply{Code: 200, Result: vo.InsertSuccess},
    }
}

func (t *friendRepo) DeleteFriend(ctx context.Context, request *pb.DeleteFriendRequest) *pb.DeleteFriendReply {
    if err := t.data.pf.DeleteFunc(Friend{}, map[string]any{"id": request.Id}); err != nil {
       return &pb.DeleteFriendReply{
          Common: &pb.CommonReply{
             Code:   500,
             Result: vo.DeleteError,
          },
       }
    }
    return &pb.DeleteFriendReply{
       Common: &pb.CommonReply{
          Code:   200,
          Result: vo.DeleteSuccess,
       },
    }
}

func (t *friendRepo) SearchAllFriend(ctx context.Context, request *pb.ListFriendRequest) *pb.ListFriendReply {
    data, err := t.data.pf.QueryFunc(Friend{}, nil, true)
    if err != nil {
       t.log.Log(log.LevelError, err)
       return &pb.ListFriendReply{
          Common: &pb.CommonReply{
             Code:   400,
             Result: vo.QueryFail,
          },
       }
    }
    var friendData []*pb.FriendData
    e := t.data.pf.ParseJSONToStruct(data, &friendData)
    if e != nil {
       t.log.Log(log.LevelError, e)
    }
    if len(friendData) == 0 {
       return &pb.ListFriendReply{
          Common: &pb.CommonReply{
             Code:   400,
             Result: vo.QueryEmpty,
          },
       }
    }
    return &pb.ListFriendReply{
       Common: &pb.CommonReply{
          Code:   200,
          Result: vo.QuerySuccess,
       },
       Data: friendData,
    }
}

func (t *friendRepo) UpdateFriend(ctx context.Context, request *pb.UpdateFriendRequest) *pb.UpdateFriendReply {
    var val map[string]any
    t.data.pf.ParseJSONToStruct(request.Data, &val)
    err := t.data.pf.UpdateFunc(Friend{}, map[string]any{"id": request.Data.Id}, val, false)
    if err != nil {
       t.log.Log(log.LevelError, err)
       return &pb.UpdateFriendReply{
          Common: &pb.CommonReply{
             Code:   vo.BadRequest,
             Result: vo.UpdateFail,
          },
       }
    }
    return &pb.UpdateFriendReply{Common: &pb.CommonReply{Code: vo.SuccessRequest, Result: vo.UpdateSuccess}}
}

func (t *friendRepo) GetFriendByCond(ctx context.Context, request *pb.GetFriendRequest) *pb.GetFriendReply {
    body, err := t.data.pf.QueryFunc(Friend{}, map[string]any{"id": request.Id}, false)
    if err != nil {
       t.log.Log(log.LevelError, err)
    }
    var friend pb.FriendData
    t.data.pf.ParseJSONToStruct(body, &friend)
    return &pb.GetFriendReply{
       Common: &pb.CommonReply{
          Code:   vo.SuccessRequest,
          Result: vo.QuerySuccess,
       },
       Data: &friend,
    }
}

kratos-blog\app\blog\internal\data\move_data_test.go

package data

import (
    "fmt"
    "gorm.io/driver/mysql"
    "gorm.io/gorm"
    "sync"
    "testing"
)

const (
    remoteSource = "root:123456@tcp(127.0.0.1:3306)/beifen"
    localSource  = "root:123456@tcp(127.0.0.1:3306)/test"
)

var (
    wg sync.Mutex
    mx sync.WaitGroup
)

func newDB(source string) *gorm.DB {
    db, err := gorm.Open(mysql.Open(source), &gorm.Config{
       DisableForeignKeyConstraintWhenMigrating: true,
    })
    if err != nil {
       panic("failed to connect database")
    }
    return db
}

type RemoteBlog struct {
    ID         int    `json:"id" gorm:"primary_key;auto_increment"`
    Title      string `json:"title"`
    Preface    string `json:"preface"`
    Photo      string `json:"photo"`
    Tag        string `json:"tag"`
    CreateTime string `json:"create_time"`
    UpdateTime string `json:"update_time"`
    Comment    string `json:"comment"`
    Visits     string `json:"visits"`
    Content    string `json:"content"`
    Appear     string `json:"appear"`
}

func GetAllBlog() []RemoteBlog {
    db := newDB(remoteSource)
    var blogs []RemoteBlog
    if err := db.Table("person_table").Find(&blogs).Error; err != nil {
       panic(err)
    }
    return blogs
}

func UpdateLocalBlogData() {
    db := newDB(localSource)
    remoteBlog := GetAllBlog()
    mx.Add(1)
    go func() {
       defer mx.Done()
       for _, blog := range remoteBlog {
          wg.Lock()
          var newBlog Blog
          newBlog.ID = blog.ID
          newBlog.Title = blog.Title
          newBlog.Preface = blog.Preface
          newBlog.Photo = blog.Photo
          newBlog.Tag = blog.Tag
          newBlog.CreateTime = blog.CreateTime
          newBlog.UpdateTime = blog.UpdateTime
          newBlog.Visits = 0
          newBlog.Content = blog.Content
          newBlog.Comment = true
          newBlog.Appear = true
          if err := db.Table("person_table").Create(&newBlog).Error; err != nil {
             fmt.Println(err)
             continue
          }
          wg.Unlock()
       }
    }()
    mx.Wait()
}

type BlogPhoto struct {
    ID       int    `json:"id" gorm:"primary_key;auto_increment"`
    Photo    string `json:"photo"`
    Date     string `json:"date"`
    Title    string `json:"title"`
    Position string `json:"position"`
}

func TestCreateBlog(t *testing.T) {
    UpdateLocalBlogData()
}

kratos-blog\app\blog\internal\data\photo.go

package data

import (
    "context"
    "github.com/go-kratos/kratos/v2/log"
    pb "kratos-blog/api/v1/photo"
    "kratos-blog/app/blog/internal/biz"
    "kratos-blog/pkg/vo"
)

type Photo struct {
    ID       int    `json:"id" gorm:"primary_key;auto_increment"`
    Photo    string `json:"photo"`
    Date     string `json:"date"`
    Title    string `json:"title"`
    Position string `json:"position"`
}

func (t *Photo) TableName() string {
    return "blogphoto"
}

type photoRepo struct {
    data *Data
    log  *log.Helper
}

func NewPhotoRepo(data *Data, logger log.Logger) biz.PhotoRepo {
    return &photoRepo{
       data: data,
       log:  log.NewHelper(logger),
    }
}

func (t *photoRepo) CreatePhoto(ctx context.Context, request *pb.CreatePhotoRequest) *pb.CreatePhotoReply {
    var photo Photo
    t.data.pf.ParseJSONToStruct(request.Data, &photo)
    if err := t.data.db.Create(&photo).Error; err != nil {
       return &pb.CreatePhotoReply{Common: &pb.CommonReply{Code: 500, Result: vo.InsertError}}
    }
    return &pb.CreatePhotoReply{
       Common: &pb.CommonReply{Code: 200, Result: vo.InsertSuccess},
    }
}

func (t *photoRepo) DeletePhoto(ctx context.Context, request *pb.DeletePhotoRequest) *pb.DeletePhotoReply {
    if err := t.data.pf.DeleteFunc(Photo{}, map[string]any{"id": request.Id}); err != nil {
       return &pb.DeletePhotoReply{
          Common: &pb.CommonReply{
             Code:   500,
             Result: vo.DeleteError,
          },
       }
    }
    return &pb.DeletePhotoReply{
       Common: &pb.CommonReply{
          Code:   200,
          Result: vo.DeleteSuccess,
       },
    }
}

func (t *photoRepo) SearchAllPhoto(ctx context.Context, request *pb.ListPhotoRequest) *pb.ListPhotoReply {
    data, err := t.data.pf.QueryFunc(Photo{}, nil, true)
    if err != nil {
       t.log.Log(log.LevelError, err)
       return &pb.ListPhotoReply{
          Common: &pb.CommonReply{
             Code:   400,
             Result: vo.QueryFail,
          },
       }
    }
    var photoData []*pb.PhotoData
    e := t.data.pf.ParseJSONToStruct(data, &photoData)
    if e != nil {
       t.log.Log(log.LevelError, e)
    }
    if len(photoData) == 0 {
       return &pb.ListPhotoReply{
          Common: &pb.CommonReply{
             Code:   400,
             Result: vo.QueryEmpty,
          },
       }
    }
    return &pb.ListPhotoReply{
       Common: &pb.CommonReply{
          Code:   200,
          Result: vo.QuerySuccess,
       },
       Data: photoData,
    }
}

kratos-blog\app\blog\internal\data\role.go

package data

import (
    "errors"
    "kratos-blog/api/v1/blog"
    "kratos-blog/pkg/vo"
)

type BlogFactory interface {
    QueryTag() ([]*blog.BlogData, error)
    QueryListBlog() ([]*blog.BlogData, error)
}

type AdminRoleFactory struct {
    r   *blogRepo
    req *blog.GetBlogRequest
    reb *blog.ListBlogRequest
}
type UserOrVisitFactory struct {
    r   *blogRepo
    req *blog.GetBlogRequest
    reb *blog.ListBlogRequest
}

func (a *AdminRoleFactory) QueryTag() ([]*blog.BlogData, error) {
    var blogs []*blog.BlogData
    res, err := a.r.data.pf.QueryFunc(Blog{}, map[string]any{
       "tag": a.req.Tag,
    }, true)
    if err != nil || res == nil {
       a.r.log.Info(vo.QueryEmpty)
       return nil, errors.New(vo.QueryEmpty)
    }
    a.r.data.pf.ParseJSONToStruct(res, &blogs)
    if len(blogs) == 0 {
       return nil, errors.New(vo.ListEmpty)
    }
    return blogs, nil
}

func (a *UserOrVisitFactory) QueryTag() ([]*blog.BlogData, error) {
    var blogs []*blog.BlogData
    res, err := a.r.data.pf.QueryFunc(Blog{}, map[string]any{
       "tag":    a.req.Tag,
       "appear": true,
    }, true)
    if err != nil || res == nil {
       a.r.log.Info(vo.QueryEmpty)
       return nil, errors.New(vo.QueryEmpty)
    }
    a.r.data.pf.ParseJSONToStruct(res, &blogs)
    if len(blogs) == 0 {
       return nil, errors.New(vo.ListEmpty)
    }
    return blogs, nil
}

func (r *blogRepo) parse(m any, blogs *[]*blog.BlogData) {
    var data []*blog.BlogData
    e := r.data.pf.ParseJSONToStruct(m, &data)
    if e != nil {
       panic(e)
    }
    *blogs = data
}

func (a *AdminRoleFactory) QueryListBlog() ([]*blog.BlogData, error) {
    var blogs []*blog.BlogData
    var b []Blog

    if exists, _ := a.r.data.rdb.Exists(CTX, AdminNotes).Result(); exists == 1 {
       return a.r.restoreList(AdminNotes), nil
    }
    a.r.data.db.Model(Blog{}).Order("createTime desc").Find(&b)
    a.r.parse(b, &blogs)
    a.r.setCacheList(AdminNotes, a.r.parseList(blogs))
    if len(blogs) == 0 {
       a.r.log.Info(vo.QueryEmpty)
       return nil, errors.New(vo.QueryEmpty)
    }
    return blogs, nil
}

func (a *UserOrVisitFactory) QueryListBlog() ([]*blog.BlogData, error) {
    var blogs []*blog.BlogData
    var b []Blog
    if exists, _ := a.r.data.rdb.Exists(CTX, Notes).Result(); exists == 1 {
       return a.r.restoreList(Notes), nil
    }
    a.r.data.db.Model(Blog{}).Order("createTime desc").Where("appear = ?", true).Find(&b)
    a.r.parse(b, &blogs)
    a.r.setCacheList(Notes, a.r.parseList(blogs))
    if len(blogs) == 0 {
       a.r.log.Info(vo.QueryEmpty)
       return nil, errors.New(vo.QueryEmpty)
    }
    return blogs, nil
}

kratos-blog\app\blog\internal\data\tag.go

package data

import (
    "context"
    "github.com/go-kratos/kratos/v2/log"
    pb "kratos-blog/api/v1/tag"
    "kratos-blog/app/blog/internal/biz"
    "kratos-blog/pkg/vo"
)

type Tag struct {
    ID      int    `json:"id" gorm:"primary_key;auto_increment"`
    TagName string `gorm:"column:tagName" json:"tagName"`
}

func (t *Tag) TableName() string {
    return "tag"
}

type tagRepo struct {
    data *Data
    log  *log.Helper
}

func NewTagRepo(data *Data, logger log.Logger) biz.TagRepo {
    return &tagRepo{
       data: data,
       log:  log.NewHelper(logger),
    }
}

func (t *tagRepo) CreateTag(ctx context.Context, request *pb.CreateTagRequest) *pb.CreateTagReply {
    var tag Tag
    t.data.pf.ParseJSONToStruct(request.Data, &tag)
    if err := t.data.db.Create(&tag).Error; err != nil {
       return &pb.CreateTagReply{Common: &pb.CommonReply{Code: 500, Result: vo.InsertError}}
    }
    return &pb.CreateTagReply{
       Common: &pb.CommonReply{Code: 200, Result: vo.InsertSuccess},
    }
}

func (t *tagRepo) DeleteTag(ctx context.Context, request *pb.DeleteTagRequest) *pb.DeleteTagReply {
    if err := t.data.pf.DeleteFunc(Tag{}, map[string]any{"id": request.Id}); err != nil {
       return &pb.DeleteTagReply{
          Common: &pb.CommonReply{
             Code:   500,
             Result: vo.DeleteError,
          },
       }
    }
    return &pb.DeleteTagReply{
       Common: &pb.CommonReply{
          Code:   200,
          Result: vo.DeleteSuccess,
       },
    }
}

func (t *tagRepo) SearchAllTag(ctx context.Context, request *pb.ListTagRequest) *pb.ListTagReply {
    data, err := t.data.pf.QueryFunc(Tag{}, nil, true)
    if err != nil {
       t.log.Log(log.LevelError, err)
       return &pb.ListTagReply{
          Common: &pb.CommonReply{
             Code:   400,
             Result: vo.QueryFail,
          },
       }
    }
    var tagData []*pb.TagData
    e := t.data.pf.ParseJSONToStruct(data, &tagData)
    if e != nil {
       t.log.Log(log.LevelError, e)
    }
    if len(tagData) == 0 {
       return &pb.ListTagReply{
          Common: &pb.CommonReply{
             Code:   400,
             Result: vo.QueryEmpty,
          },
       }
    }
    return &pb.ListTagReply{
       Common: &pb.CommonReply{
          Code:   200,
          Result: vo.QuerySuccess,
       },
       Data: tagData,
    }
}

kratos-blog\app\blog\internal\server\grpc.go

package server

import (
    "github.com/go-kratos/kratos/v2/log"
    "github.com/go-kratos/kratos/v2/middleware/recovery"
    "github.com/go-kratos/kratos/v2/transport/grpc"
    v1 "kratos-blog/api/v1/blog"
    v3 "kratos-blog/api/v1/friend"
    v4 "kratos-blog/api/v1/photo"
    v2 "kratos-blog/api/v1/tag"
    "kratos-blog/app/blog/internal/conf"
    "kratos-blog/app/blog/internal/service"
)

// NewGRPCServer new a gRPC server.
func NewGRPCServer(c *conf.Server, blog *service.BlogService,
    friend *service.FriendService,
    tag *service.TagService,
    photo *service.PhotoService,
    logger log.Logger) *grpc.Server {
    var opts = []grpc.ServerOption{
       grpc.Middleware(
          recovery.Recovery(),
       ),
    }
    if c.Grpc.Network != "" {
       opts = append(opts, grpc.Network(c.Grpc.Network))
    }
    if c.Grpc.Addr != "" {
       opts = append(opts, grpc.Address(c.Grpc.Addr))
    }
    if c.Grpc.Timeout != nil {
       opts = append(opts, grpc.Timeout(c.Grpc.Timeout.AsDuration()))
    }
    srv := grpc.NewServer(opts...)
    v1.RegisterBlogServer(srv, blog)
    v2.RegisterTagServer(srv, tag)
    v3.RegisterFriendServer(srv, friend)
    v4.RegisterPhotoServer(srv, photo)
    return srv
}

kratos-blog\app\blog\internal\server\http.go

package server

import (
    "github.com/go-kratos/kratos/v2/log"
    "github.com/go-kratos/kratos/v2/middleware/recovery"
    "github.com/go-kratos/kratos/v2/transport/http"
    v1 "kratos-blog/api/v1/blog"
    v3 "kratos-blog/api/v1/friend"
    v2 "kratos-blog/api/v1/tag"
    "kratos-blog/app/blog/internal/conf"
    "kratos-blog/app/blog/internal/service"
)

// NewHTTPServer new an HTTP server.
func NewHTTPServer(cf *conf.Bootstrap, blog *service.BlogService,
    friend *service.FriendService,
    tag *service.TagService,
    logger log.Logger) *http.Server {
    c := cf.Server
    var opts = []http.ServerOption{
       http.Middleware(
          recovery.Recovery(),
       ),
    }

    if c.Http.Network != "" {
       opts = append(opts, http.Network(c.Http.Network))
    }
    if c.Http.Addr != "" {
       opts = append(opts, http.Address(c.Http.Addr))
    }
    if c.Http.Timeout != nil {
       opts = append(opts, http.Timeout(c.Http.Timeout.AsDuration()))
    }
    srv := http.NewServer(opts...)

    // 注册服务接口
    v1.RegisterBlogHTTPServer(srv, blog)
    v2.RegisterTagHTTPServer(srv, tag)
    v3.RegisterFriendHTTPServer(srv, friend)
    return srv
}

kratos-blog\app\blog\internal\server\server.go

package server

import (
    "github.com/google/wire"
)

// ProviderSet is server providers.
var ProviderSet = wire.NewSet(NewGRPCServer, NewHTTPServer)

kratos-blog\app\blog\internal\service\blog.go

package service

import (
    "context"
    pb "kratos-blog/api/v1/blog"
    "kratos-blog/app/blog/internal/biz"
)

type BlogService struct {
    pb.UnimplementedBlogServer
    uc *biz.BlogUseCase
}

func NewBlogService(uc *biz.BlogUseCase) *BlogService {
    return &BlogService{uc: uc}
}

func (s *BlogService) CreateBlog(ctx context.Context, req *pb.CreateBlogRequest) (*pb.CreateBlogReply, error) {
    return s.uc.AddBlog(ctx, req), nil
}
func (s *BlogService) UpdateBlog(ctx context.Context, req *pb.UpdateBlogRequest) (*pb.UpdateBlogReply, error) {
    return s.uc.UpdateBlog(ctx, req), nil
}
func (s *BlogService) UpdateIndividualFields(ctx context.Context, req *pb.UpdateIndividualFieldsRequest) (*pb.UpdateIndividualFieldsReply, error) {
    return s.uc.UpdateIndividualFields(ctx, req), nil
}
func (s *BlogService) DeleteBlog(ctx context.Context, req *pb.DeleteBlogRequest) (*pb.DeleteBlogReply, error) {
    return s.uc.DeleteBlog(ctx, req), nil
}
func (s *BlogService) GetBlogByTag(ctx context.Context, req *pb.GetBlogRequest) (*pb.GetBlogReply, error) {
    return s.uc.GetByTagName(ctx, req), nil
}
func (s *BlogService) ListBlog(ctx context.Context, req *pb.ListBlogRequest) (*pb.ListBlogReply, error) {
    return s.uc.ListBlog(ctx, req), nil
}
func (s *BlogService) GetBlogByID(ctx context.Context, req *pb.GetBlogIDRequest) (*pb.GetBlogIDReply, error) {
    return s.uc.QueryBlogByID(ctx, req), nil
}
func (s *BlogService) GetBlogByTitle(ctx context.Context, req *pb.GetBlogByTitleRequest) (*pb.GetBlogByTitleReply, error) {
    return s.uc.QueryBlogByTitle(ctx, req), nil
}
func (s *BlogService) UpdateOnly(ctx context.Context, req *pb.UpdateOnlyRequest) (*pb.UpdateOnlyReply, error) {
    return s.uc.UpdateOnly(ctx, req), nil
}
func (s *BlogService) CacheBlog(ctx context.Context, req *pb.CreateBlogRequest) (*pb.CreateBlogReply, error) {
    return s.uc.CacheBlog(ctx, req), nil
}
func (s *BlogService) GetCacheBlog(ctx context.Context, req *pb.ListBlogRequest) (*pb.ListCacheReply, error) {
    return s.uc.GetAllCacheBlog(ctx), nil
}
func (s *BlogService) DeleteCacheBlog(ctx context.Context, req *pb.DeleteCacheBlogRequest) (*pb.DeleteCacheBlogReply, error) {
    return s.uc.DeleteCacheBlog(ctx, req), nil
}
func (s *BlogService) AddSuggestBlog(ctx context.Context, req *pb.SuggestBlogRequest) (*pb.SuggestBlogReply, error) {
    return s.uc.SetSuggestBlog(ctx, req), nil
}
func (s *BlogService) GetAllSuggest(ctx context.Context, req *pb.SearchAllSuggest) (*pb.SearchAllReply, error) {
    return s.uc.GetSuggestBlog(ctx, req), nil
}
func (s *BlogService) DeleteSuggestBlog(ctx context.Context, req *pb.SuggestBlogRequest) (*pb.SuggestBlogReply, error) {
    return s.uc.DeleteSuggestBlog(ctx, req), nil
}

kratos-blog\app\blog\internal\service\friend.go

package service

import (
    "context"
    pb "kratos-blog/api/v1/friend"
    "kratos-blog/app/blog/internal/biz"
)

type FriendService struct {
    pb.UnimplementedFriendServer
    uc *biz.FriendUseCase
}

func NewFriendService(uc *biz.FriendUseCase) *FriendService {
    return &FriendService{uc: uc}
}

func (s *FriendService) CreateFriend(ctx context.Context, req *pb.CreateFriendRequest) (*pb.CreateFriendReply, error) {
    return s.uc.CreateFriend(ctx, req), nil
}
func (s *FriendService) UpdateFriend(ctx context.Context, req *pb.UpdateFriendRequest) (*pb.UpdateFriendReply, error) {
    return s.uc.UpdateFriend(ctx, req), nil
}
func (s *FriendService) DeleteFriend(ctx context.Context, req *pb.DeleteFriendRequest) (*pb.DeleteFriendReply, error) {
    return s.uc.DeleteFriend(ctx, req), nil
}
func (s *FriendService) GetFriend(ctx context.Context, req *pb.GetFriendRequest) (*pb.GetFriendReply, error) {
    return s.uc.GetFriendByCond(ctx, req), nil
}
func (s *FriendService) ListFriend(ctx context.Context, req *pb.ListFriendRequest) (*pb.ListFriendReply, error) {
    return s.uc.SearchAllFriend(ctx, req), nil
}

kratos-blog\app\blog\internal\service\photo.go

package service

import (
    "context"
    pb "kratos-blog/api/v1/photo"
    "kratos-blog/app/blog/internal/biz"
)

type PhotoService struct {
    pb.UnimplementedPhotoServer
    uc *biz.PhotoUseCase
}

func NewPhotoService(uc *biz.PhotoUseCase) *PhotoService {
    return &PhotoService{uc: uc}
}

func (s *PhotoService) CreatePhoto(ctx context.Context, req *pb.CreatePhotoRequest) (*pb.CreatePhotoReply, error) {
    return s.uc.CreatePhoto(ctx, req), nil
}
func (s *PhotoService) DeletePhoto(ctx context.Context, req *pb.DeletePhotoRequest) (*pb.DeletePhotoReply, error) {
    return s.uc.DeletePhoto(ctx, req), nil
}
func (s *PhotoService) ListPhoto(ctx context.Context, req *pb.ListPhotoRequest) (*pb.ListPhotoReply, error) {
    return s.uc.SearchAllPhoto(ctx, req), nil
}

kratos-blog\app\blog\internal\service\service.go

package service

import "github.com/google/wire"

// ProviderSet is service providers.
var ProviderSet = wire.NewSet(NewBlogService, NewTagService)

kratos-blog\app\blog\internal\service\tag.go

package service

import (
    "context"
    "kratos-blog/app/blog/internal/biz"

    pb "kratos-blog/api/v1/tag"
)

type TagService struct {
    pb.UnimplementedTagServer
    uc *biz.TagUseCase
}

func NewTagService(uc *biz.TagUseCase) *TagService {
    return &TagService{uc: uc}
}

func (s *TagService) CreateTag(ctx context.Context, req *pb.CreateTagRequest) (*pb.CreateTagReply, error) {
    return s.uc.CreateTag(ctx, req), nil
}
func (s *TagService) DeleteTag(ctx context.Context, req *pb.DeleteTagRequest) (*pb.DeleteTagReply, error) {
    return s.uc.DeleteTag(ctx, req), nil
}
func (s *TagService) ListTag(ctx context.Context, req *pb.ListTagRequest) (*pb.ListTagReply, error) {
    return s.uc.SearchAllTag(ctx, req), nil
}

终于写完一个服务😭了,还有3个😭😭😭