Go-kratos 框架微服務(wù)商城實(shí)戰(zhàn)之用戶服務(wù)(一)

????????????????????????????????????kratos 微服務(wù)框架商城實(shí)戰(zhàn)之用戶服務(wù)(一)

推薦看一下Kratos 官方文檔[1]?更加流暢觀看此文章述寡,本機(jī)器這里已經(jīng)安裝好了kratos、proto掀序、wire、make?等所需的命令工具

準(zhǔn)備工作

初始化項(xiàng)目目錄

進(jìn)入自己電腦中存放 Go 項(xiàng)目的目錄,

新建? kratos-shop/service?目錄并進(jìn)入到新建的目錄中,

執(zhí)行?kratos new user?命令并進(jìn)入?user?目錄贯莺,

執(zhí)行命令?kratos proto add api/user/v1/user.proto?还蹲,這時(shí)你在?kratos-shop/service/user/api/user/v1?目錄下會(huì)看到新的?user.proto?文件已經(jīng)創(chuàng)建好了,

接下來(lái)執(zhí)行?kratos proto server api/user/v1/user.proto -t internal/service?命令生成對(duì)應(yīng)的?service?文件。

刪除不需要的 proto 文件?rm -rf api/helloworld/

刪除不需要的 service 文件?rm internal/service/greeter.go

完整的命令代碼如下

mkdir??-p?kratos-shop/service
cd?kratos-shop/service

kratos?new?user
cd?user

kratos?proto?add?api/user/v1/user.proto

kratos?proto?server?api/user/v1/user.proto?-t?internal/service

rm?-rf?api/helloworld/
rm?internal/service/greeter.go

修改?user.proto?文件,內(nèi)容如下:

proto 基本的語(yǔ)法請(qǐng)自行學(xué)習(xí),目前這里只提供了一個(gè)創(chuàng)建用戶的 rpc 接口酷含,后續(xù)會(huì)逐步添加其他 rpc 接口

syntax?=?"proto3";
package?user.v1;
option?go_package?=?"user/api/user/v1;v1";

service?User{
??rpc?CreateUser(CreateUserInfo)?returns?(UserInfoResponse);?//?創(chuàng)建用戶
}

//?創(chuàng)建用戶所需字段
message??CreateUserInfo{
??string?nickName?=?1;
??string?password?=?2;
??string?mobile?=?3;
}

//?返回用戶信息
message?UserInfoResponse{
??int64?id?=?1;
??string?password?=?2;
??string?mobile?=?3;
??string?nickName?=?4;
??int64?birthday?=?5;
??string?gender?=?6;
??int32?role?=?7;
}

生成?user.proto?定義的接口信息

進(jìn)入到?service/user?目錄下,執(zhí)行?make api?命令舱污,

這時(shí)可以看到?user/api/user/v1/?目錄下多出了 proto 創(chuàng)建的文件

cd?user

make?api?

#?目錄結(jié)構(gòu)如下:
├──?api
│???└──?user
│???????└──?v1
│???????????├──?user.pb.go
│???????????├──?user.proto
│???????????└──?user_grpc.pb.go

修改配置文件

修改?user/configs/config.yaml?文件媚赖,代碼如下:

具體鏈接 mysql惧磺、redis 的參數(shù)填寫自己本機(jī)的磨隘,本項(xiàng)目用到的是 gorm 琳拭。trace 是以后要用到的鏈路追蹤的參數(shù),先定義了膘流。

server:
??http:
????addr:?0.0.0.0:8000
????timeout:?1s
??grpc:
????addr:?0.0.0.0:50051
????timeout:?1s
data:
??database:
????driver:?mysql
????source:?root:root@tcp(127.0.0.1:3306)/shop_user?charset=utf8mb4&parseTime=True&loc=Local
??redis:
????addr:?127.0.0.1:6379
????dial_timeout:?1s
????read_timeout:?0.2s
????write_timeout:?0.2s
trace:??endpoint:?http://127.0.0.1:14268/api/traces

新建?user/configs/registry.yaml?文件呼股,引入consul[2]?服務(wù)吸奴,代碼如下:

#?這里引入了?consul?的服務(wù)注冊(cè)與發(fā)現(xiàn)缠局,先把配置加入進(jìn)去
consul:
????address:?127.0.0.1:8500????scheme:?http

修改?user/internal/conf/conf.proto?配置文件

#?文件底部新增?consul?和?trace?的配置信息
message?Trace?{
??string?endpoint?=?1;
}

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

新生成?conf.pb.go?文件读处,執(zhí)行?make config

#?`service/user`?目錄下,執(zhí)行命令make?config

安裝 consul 服務(wù)工具

#?這里使用的是?docker?工具進(jìn)行創(chuàng)建的
docker?run?-d?-p?8500:8500?-p?8300:8300?-p?8301:8301?-p?8302:8302?-p?8600:8600/udp?consul?consul?agent?-dev?-client=0.0.0.0
#?瀏覽器訪問?http://127.0.0.1:8500/ui/dc1/services?測(cè)試是否安裝成功

修改服務(wù)代碼

修改?user/internal/data/?目錄下的文件

修改?greeter.go?為?user.go 添加如下內(nèi)容:

package?data

import?(
????"github.com/go-kratos/kratos/v2/log"
????"github.com/go-redis/redis/extra/redisotel"
????"github.com/go-redis/redis/v8"
????"github.com/google/wire"
????"gorm.io/driver/mysql"
????"gorm.io/gorm"
????"gorm.io/gorm/logger"
????"gorm.io/gorm/schema"
????slog?"log"
????"os"
????"time"
????"user/internal/conf"
)

//?ProviderSet?is?data?providers.
var?ProviderSet?=?wire.NewSet(NewData,?NewDB,?NewRedis,?NewUserRepo)

type?Data?struct?{
????db??*gorm.DB
????rdb?*redis.Client
}

//?NewData?.
func?NewData(c?*conf.Data,?logger?log.Logger,?db?*gorm.DB,?rdb?*redis.Client)?(*Data,?func(),?error)?{
????cleanup?:=?func()?{
????????log.NewHelper(logger).Info("closing?the?data?resources")
????}
????return?&Data{db:?db,?rdb:?rdb},?cleanup,?nil
}

//?NewDB?.
func?NewDB(c?*conf.Data)?*gorm.DB?{
????//?終端打印輸入?sql?執(zhí)行記錄
????newLogger?:=?logger.New(
????????slog.New(os.Stdout,?"\r\n",?slog.LstdFlags),?//?io?writer
????????logger.Config{
????????????SlowThreshold:?time.Second,?//?慢查詢?SQL?閾值
????????????Colorful:??????true,????????//?禁用彩色打印
????????????//IgnoreRecordNotFoundError:?false,
????????????LogLevel:?logger.Info,?//?Log?lever
????????},
????)

????db,?err?:=?gorm.Open(mysql.Open(c.Database.Source),?&gorm.Config{
????????Logger:???????????????????????????????????newLogger,
????????DisableForeignKeyConstraintWhenMigrating:?true,
????????NamingStrategy:???????????????????????????schema.NamingStrategy{
????????????//SingularTable:?true,?//?表名是否加?s
????????},
????})

????if?err?!=?nil?{
????????log.Errorf("failed?opening?connection?to?sqlite:?%v",?err)
????????panic("failed?to?connect?database")
????}

????return?db
}

func?NewRedis(c?*conf.Data)?*redis.Client?{
????rdb?:=?redis.NewClient(&redis.Options{
????????Addr:?????????c.Redis.Addr,
????????Password:?????c.Redis.Password,
????????DB:???????????int(c.Redis.Db),
????????DialTimeout:??c.Redis.DialTimeout.AsDuration(),
????????WriteTimeout:?c.Redis.WriteTimeout.AsDuration(),
????????ReadTimeout:??c.Redis.ReadTimeout.AsDuration(),
????})
????rdb.AddHook(redisotel.TracingHook{})
????if?err?:=?rdb.Close();?err?!=?nil?{
????????log.Error(err)
????}
????return?rdb}

這里的 wire 概念如果不熟悉的話绎谦,請(qǐng)參看Wire 依賴注入[3]

修改?user/internal/service/?目錄下的文件

修改或者刪除?greeter.go?為?user.go, 添加代碼如下:

package?service

import?(
????"context"
????"github.com/go-kratos/kratos/v2/log"
????v1?"user/api/user/v1"
????"user/internal/biz"
)

type?UserService?struct?{
????v1.UnimplementedUserServer

????uc??*biz.UserUsecase
????log?*log.Helper
}

//?NewUserService?new?a?greeter?service.
func?NewUserService(uc?*biz.UserUsecase,?logger?log.Logger)?*UserService?{
????return?&UserService{uc:?uc,?log:?log.NewHelper(logger)}
}

//?CreateUser?create?a?user
func?(u?*UserService)?CreateUser(ctx?context.Context,?req?*v1.CreateUserInfo)?(*v1.UserInfoResponse,?error)?{
????user,?err?:=?u.uc.Create(ctx,?&biz.User{
????????Mobile:???req.Mobile,
????????Password:?req.Password,
????????NickName:?req.NickName,
????})
????if?err?!=?nil?{
????????return?nil,?err
????}

????userInfoRsp?:=?v1.UserInfoResponse{
????????Id:???????user.ID,
????????Mobile:???user.Mobile,
????????Password:?user.Password,
????????NickName:?user.NickName,
????????Gender:???user.Gender,
????????Role:?????int32(user.Role),
????????Birthday:?user.Birthday,
????}

????return?&userInfoRsp,?nil
}

修改?service.go?文件包个, 代碼如下:

package?service

import?"github.com/google/wire"

//?ProviderSet?is?service?providers.
var?ProviderSet?=?wire.NewSet(NewUserService)

修改或刪除?user/internal/biz/greeter.go?為?user.go 添加如下內(nèi)容:

package?biz

import?(
????"context"
????"github.com/go-kratos/kratos/v2/log"
)

//?定義返回?cái)?shù)據(jù)結(jié)構(gòu)體
type?User?struct?{
????ID???????int64
????Mobile???string
????Password?string
????NickName?string
????Birthday?int64
????Gender???string
????Role?????int
}

type?UserRepo?interface?{
????CreateUser(context.Context,?*User)?(*User,?error)
}

type?UserUsecase?struct?{
????repo?UserRepo
????log??*log.Helper
}

func?NewUserUsecase(repo?UserRepo,?logger?log.Logger)?*UserUsecase?{
????return?&UserUsecase{repo:?repo,?log:?log.NewHelper(logger)}
}

func?(uc?*UserUsecase)?Create(ctx?context.Context,?u?*User)?(*User,?error)?{
????return?uc.repo.CreateUser(ctx,?u)
}

修改?user/internal/biz/biz.go?文件,內(nèi)容如下:

package?biz

import?"github.com/google/wire"

//?ProviderSet?is?biz?providers.
var?ProviderSet?=?wire.NewSet(NewUserUsecase)

修改或刪除?user/internal/data/greeter.go?為?user.go 添加如下內(nèi)容:

package?data

import?(
????"context"
????"crypto/sha512"
????"fmt"
????"github.com/anaskhan96/go-password-encoder"
????"github.com/go-kratos/kratos/v2/log"
????"google.golang.org/grpc/codes"
????"google.golang.org/grpc/status"
????"gorm.io/gorm"
????"time"
????"user/internal/biz"
)
//?定義數(shù)據(jù)表結(jié)構(gòu)體
type?User?struct?{
????ID??????????int64??????`gorm:"primarykey"`
????Mobile??????string?????`gorm:"index:idx_mobile;unique;type:varchar(11)?comment?'手機(jī)號(hào)碼,用戶唯一標(biāo)識(shí)';not?null"`
????Password????string?????`gorm:"type:varchar(100);not?null?"`?//?用戶密碼的保存需要注意是否加密
????NickName????string?????`gorm:"type:varchar(25)?comment?'用戶昵稱'"`
????Birthday????*time.Time?`gorm:"type:datetime?comment?'出生日日期'"`
????Gender??????string?????`gorm:"column:gender;default:male;type:varchar(16)?comment?'female:女,male:男'"`
????Role????????int????????`gorm:"column:role;default:1;type:int?comment?'1:普通用戶歧蒋,2:管理員'"`
????CreatedAt???time.Time??`gorm:"column:add_time"`
????UpdatedAt???time.Time??`gorm:"column:update_time"`
????DeletedAt???gorm.DeletedAt
????IsDeletedAt?bool
}
type?userRepo?struct?{
????data?*Data
????log??*log.Helper
}

//?NewUserRepo?.?這里需要注意谜洽,上面?data?文件?wire?注入的是此方法阐虚,方法名不要寫錯(cuò)了
func?NewUserRepo(data?*Data,?logger?log.Logger)?biz.UserRepo?{
????return?&userRepo{
????????data:?data,
????????log:??log.NewHelper(logger),
????}
}

//?CreateUser?.
func?(r?*userRepo)?CreateUser(ctx?context.Context,?u?*biz.User)?(*biz.User,?error)?{
????var?user?User
????//?驗(yàn)證是否已經(jīng)創(chuàng)建
????result?:=?r.data.db.Where(&biz.User{Mobile:?u.Mobile}).First(&user)
????if?result.RowsAffected?==?1?{
????????return?nil,?status.Errorf(codes.AlreadyExists,?"用戶已存在")
????}

????user.Mobile?=?u.Mobile
????user.NickName?=?u.NickName
????user.Password?=?encrypt(u.Password)?//?密碼加密
????res?:=?r.data.db.Create(&user)
????if?res.Error?!=?nil?{
????????return?nil,?status.Errorf(codes.Internal,?res.Error.Error())
????}
????return?&biz.User{
????????ID:???????user.ID,
????????Mobile:???user.Mobile,
????????Password:?user.Password,
????????NickName:?user.NickName,
????????Gender:???user.Gender,
????????Role:?????user.Role,
????},?nil
}

//?Password?encryption
func?encrypt(psd?string)?string?{
????options?:=?&password.Options{SaltLen:?16,?Iterations:?10000,?KeyLen:?32,?HashFunction:?sha512.New}
????salt,?encodedPwd?:=?password.Encode(psd,?options)
????return?fmt.Sprintf("$pbkdf2-sha512$%s$%s",?salt,?encodedPwd)
}

修改?user/internal/server/?目錄下的文件

這里用不到 http 服務(wù)刪除?http.go?文件奥秆,修改?grpc.go?文件內(nèi)容如下:

?package?server

import?(
????"github.com/go-kratos/kratos/v2/log"
????"github.com/go-kratos/kratos/v2/middleware/logging"
????"github.com/go-kratos/kratos/v2/middleware/recovery"
????"github.com/go-kratos/kratos/v2/transport/grpc"
????v1?"user/api/user/v1"
????"user/internal/conf"
????"user/internal/service"
)

//?NewGRPCServer?new?a?gRPC?server.
func?NewGRPCServer(c?*conf.Server,?greeter?*service.UserService,?logger?log.Logger)?*grpc.Server?{
????var?opts?=?[]grpc.ServerOption{
????????grpc.Middleware(
????????????recovery.Recovery(),
????????????logging.Server(logger),
????????),
????}
????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.RegisterUserServer(srv,?greeter)
????return?srv
}

修改?server.go?文件,這里加入了 consul 的服務(wù),內(nèi)容如下:

package?server

import?(
????"github.com/go-kratos/kratos/v2/registry"
????"github.com/google/wire"
????"user/internal/conf"

????consul?"github.com/go-kratos/kratos/contrib/registry/consul/v2"
????consulAPI?"github.com/hashicorp/consul/api"
)

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

//?NewRegistrar?引入?consul
func?NewRegistrar(conf?*conf.Registry)?registry.Registrar?{
????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
}

修改啟動(dòng)程序

修改?user/cmd/wire.go文件

這里注入了consul需要的配置,需要添加進(jìn)來(lái)

func?initApp(*conf.Server,?*conf.Data,?*conf.Registry,?log.Logger)?(*kratos.App,?func(),?error)?{
????panic(wire.Build(server.ProviderSet,?data.ProviderSet,?biz.ProviderSet,?service.ProviderSet,?newApp))}

修改?user/cmd/user/main.go?文件

package?main

import?(
????"flag"
????"os"

????"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"
????"user/internal/conf"
)

//?go?build?-ldflags?"-X?main.Version=x.y.z"
var?(
????//?Name?is?the?name?of?the?compiled?software.
????Name?=?"shop.users.service"
????//?Version?is?the?version?of?the?compiled?software.
????Version?=?"v1"
????//?flagconf?is?the?config?flag.
????flagconf?string

????id,?_?=?os.Hostname()
)

func?init()?{
????flag.StringVar(&flagconf,?"conf",?"../../configs",?"config?path,?eg:?-conf?config.yaml")
}

func?newApp(logger?log.Logger,?gs?*grpc.Server,?rr?registry.Registrar)?*kratos.App?{
????return?kratos.New(
????????kratos.ID(id+"shop.user.service"),
????????kratos.Name(Name),
????????kratos.Version(Version),
????????kratos.Metadata(map[string]string{}),
????????kratos.Logger(logger),
????????kratos.Server(
????????????gs,
????????),
????????kratos.Registrar(rr),?//?consul?的引入
????)
}

func?main()?{
????flag.Parse()
????logger?:=?log.With(log.NewStdLogger(os.Stdout),
????????"ts",?log.DefaultTimestamp,
????????"caller",?log.DefaultCaller,
????????"service.id",?id,
????????"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)
????}
????//?consul?的引入
????var?rc?conf.Registry?
????if?err?:=?c.Scan(&rc);?err?!=?nil?{
????????panic(err)
????}
????app,?cleanup,?err?:=?initApp(bc.Server,?bc.Data,?&rc,?logger)
????if?err?!=?nil?{
????????panic(err)
????}
????defer?cleanup()

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

修改根目錄?user/makefile?文件

????在?go?generate?./...?下面添加代碼

????wire:????????cd?cmd/user/?&&?wire

根目錄執(zhí)行?make wire?命令

#?service/usermake?wire

啟動(dòng)程序

別忘記根據(jù) data 里面的 user struct 創(chuàng)建對(duì)應(yīng)的數(shù)據(jù)庫(kù)表,這里也可以寫一個(gè) gorm 創(chuàng)建表的文件進(jìn)行創(chuàng)建歹嘹。

啟動(dòng)程序 kratos run

根目錄?service/user?執(zhí)行命令????kratos?run

簡(jiǎn)單測(cè)試

由于沒寫對(duì)外訪問的 http 服務(wù)尺上,這里還沒有加入單元測(cè)試怎抛,所以先創(chuàng)建個(gè)文件鏈接啟動(dòng)過的 grpc 服務(wù)簡(jiǎn)單測(cè)試一下马绝。

根目錄新建?user/test/user.go?文件富稻,添加如下內(nèi)容:

package?main

import?(
????"context"
????"fmt"
????"google.golang.org/grpc"
????v1?"user/api/user/v1"
)

var?userClient?v1.UserClient
var?conn?*grpc.ClientConn

func?main()?{
????Init()

????TestCreateUser()?//?創(chuàng)建用戶

????conn.Close()
}

//?Init?初始化?grpc?鏈接?注意這里鏈接的?端口
func?Init()?{
????var?err?error
????conn,?err?=?grpc.Dial("127.0.0.1:50051",?grpc.WithInsecure())
????if?err?!=?nil?{
????????panic("grpc?link?err"?+?err.Error())
????}
????userClient?=?v1.NewUserClient(conn)
}

func?TestCreateUser()?{

????rsp,?err?:=?userClient.CreateUser(context.Background(),?&v1.CreateUserInfo{
????????Mobile:???fmt.Sprintf("1388888888%d",?1),
????????Password:?"admin123",
????????NickName:?fmt.Sprintf("YWWW%d",?1),
????})
????if?err?!=?nil?{
????????panic("grpc?創(chuàng)建用戶失敗"?+?err.Error())
????}
????fmt.Println(rsp.Id)}

這里別忘記啟動(dòng) kratos user 服務(wù)之后椭赋,再執(zhí)行 test/user.go 文件哪怔,查詢執(zhí)行結(jié)果认境,是否有個(gè)ID輸出 查詢自己的數(shù)據(jù)庫(kù)叉信,看看是否有插入的數(shù)據(jù)了硼身。

源碼已經(jīng)上傳到?GitHub[4]?上了,下一篇開始逐步完善用戶服務(wù)的接口。

上帝喜歡笨人
我的想法很簡(jiǎn)單讶迁,既然自己能力有限连茧,就按照有限的能力盡力而為就好,不要以為有了什么高科技的時(shí)間管理工具就能做更多事情巍糯。人有多大本事啸驯,做多大事情。
36篇原創(chuàng)內(nèi)容
公眾號(hào)

Reference

Go工程化-依賴注入 https://go-kratos.dev/blog/go-project-wire

Project Layout 最佳實(shí)踐 https://go-kratos.dev/blog/go-layout-operation-process

引用鏈接

[1]?Kratos 官方文檔:?https://go-kratos.dev/docs/getting-started/start
[2]?consul:?https://www.consul.io/
[3]?Wire 依賴注入:?https://go-kratos.dev/docs/guide/wire

[4]?GitHub:?https://github.com/aliliin/kratos-shop

本文使用 文章同步助手 同步

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末祟峦,一起剝皮案震驚了整個(gè)濱河市罚斗,隨后出現(xiàn)的幾起案子宅楞,更是在濱河造成了極大的恐慌针姿,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,198評(píng)論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件厌衙,死亡現(xiàn)場(chǎng)離奇詭異距淫,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)婶希,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,334評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門榕暇,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人喻杈,你說我怎么就攤上這事彤枢。” “怎么了筒饰?”我有些...
    開封第一講書人閱讀 167,643評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵缴啡,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我龄砰,道長(zhǎng)盟猖,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,495評(píng)論 1 296
  • 正文 為了忘掉前任换棚,我火速辦了婚禮式镐,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘固蚤。我一直安慰自己娘汞,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,502評(píng)論 6 397
  • 文/花漫 我一把揭開白布夕玩。 她就那樣靜靜地躺著你弦,像睡著了一般惊豺。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上禽作,一...
    開封第一講書人閱讀 52,156評(píng)論 1 308
  • 那天尸昧,我揣著相機(jī)與錄音,去河邊找鬼旷偿。 笑死烹俗,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的萍程。 我是一名探鬼主播幢妄,決...
    沈念sama閱讀 40,743評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼茫负!你這毒婦竟也來(lái)了蕉鸳?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,659評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤忍法,失蹤者是張志新(化名)和其女友劉穎潮尝,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體缔赠,經(jīng)...
    沈念sama閱讀 46,200評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡衍锚,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,282評(píng)論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了嗤堰。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片戴质。...
    茶點(diǎn)故事閱讀 40,424評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖踢匣,靈堂內(nèi)的尸體忽然破棺而出告匠,到底是詐尸還是另有隱情,我是刑警寧澤离唬,帶...
    沈念sama閱讀 36,107評(píng)論 5 349
  • 正文 年R本政府宣布后专,位于F島的核電站,受9級(jí)特大地震影響输莺,放射性物質(zhì)發(fā)生泄漏戚哎。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,789評(píng)論 3 333
  • 文/蒙蒙 一嫂用、第九天 我趴在偏房一處隱蔽的房頂上張望型凳。 院中可真熱鬧,春花似錦嘱函、人聲如沸甘畅。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,264評(píng)論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)疏唾。三九已至蓄氧,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間槐脏,已是汗流浹背喉童。 一陣腳步聲響...
    開封第一講書人閱讀 33,390評(píng)論 1 271
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留顿天,地道東北人泄朴。 一個(gè)月前我還...
    沈念sama閱讀 48,798評(píng)論 3 376
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像露氮,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子钟沛,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,435評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容