laravel整理笔记

搭建lamp环境

安装ubuntu14.04 LTS版本

搭建lamp环境:

切换到root:

sudo su

更新源:

apt-get update

安装apache2:

apt-get install apache2

安装php5.5.9:

apt-get install php5

安装mysql:

apt-get install mysql-server mysql-client

安装php对myslq的扩展:

apt-get install php5-mysql

安装laravel需要的加密算法库:

apt-get install mcrypt

安装php加密库:

apt-get install php5-mcrypt

php5的这个加密扩展需要手动修改配置文件才可以使用:

cd /etc/php5/mods-available/   #这个目录是php已经下载的扩展

cd /etc/php5/apache2/conf.d/   #这个目录是php已经加载的扩展(都是软连接)

我们只需要建立个软连接就可以了:

ln -s /etc/php5/mods-available/mcrypt.ini ./

ls  #查看文件,软连接建立成功,扩展就可以用了

重启apache:

apachectl restart

建立phpinfo文件:

cd /var/www/html/  #这是apache的网站根目录

vim info.php

    <?php
        phpinfo();
    ?>

查看服务器IP

ifconfig  (假设为192.168.1.50)

浏览器访问192.168.1.50/info.php

可以看到mcrypt已经加载进去了

安装一些常用的工具:

apt-get install wget      #下载工具 

apt-get install curl  #模拟浏览器

apt-get install openssl 

连接远程服务器

mac电脑用ssh连接:

ssh laravel@192.168.1.50

windowx电脑使用xshell,或者putty连接

composer的安装

下载composer.phar包:
下载地址

上传composer.phar包到服务器:

使用上传工具:

FileZilla

或者mac 终端使用 scp

windows下使用xhsell,  使用rz命令

添加可执行权限:

chmod +x ./composer.phar

每次都要在这个使用很麻烦,添加成全局的就方便了:

 mv composer.phar /bin/composer

验证:

composer -v

安装laravel

全局安装(适用于一个服务器多个laravel项目):

composer global require "laravel/installer"

配置全局环境变量:

cd

vim .profile

最后面写入:

export PATH=$PATH:/root/.config/composer/vendor/bin/

生成laravel项目:

laravel new blog

局部安装(适用于服务器只有一个laravel项目):

composer create-project --prefer-dist laravel/laravel blog

ps:注意虚拟机内存一定要大于1G,不然会报内存不足的错误

修改文件权限:

cd blog

chmod -R 777 storage

本地域名解析和apache虚拟主机配置

修改hosts文件:

mac 在 /etc/hosts

windows 在C:\Windows\System32\drivers\etc\hosts

加入:

192.168.1.50 laravel.demo

配置虚拟主机:

cd /etc/apache2/sites-available

cp 000-default.conf laravel.demo.conf

vim laravel.demo

打开服务器名字配置:

ServerName laravel.demo

建立软连接:

ln -s /etc/apache2/sites-available/laravel.demo.conf ../sites-enabled/

重启服务就可以了:

apachectl restart

git仓库建立与git服务器的搭建

安装git:

apt-get install git

设置你的仓库用户名:

git config --global user.name 'lwt'

git config --global user.email '13521760670@163.com'

初始化git仓库:

cd /var/www/demo

git init

搭建git服务器:

添加用户:
adduser git

克隆裸仓库:
git clone --bare demo demo.git

移动位置:
mv demo.git/ /home/git/

修改权限:
chown -R git:git demo.git/

另一个服务器操作:

生成密钥对(生成位置在当前用户的家目录的.ssh文件里)
ssh-keygen -t rsa

上传公钥到git服务器,这样可以免密码克隆和提交:
cd
cd .ssh
找到 
id_rsa.pub
想办法把这个文件里面的内容弄到git服务器,git用户家目录里面的
.ssh文件夹里面的authorized_keys里面(没有就手动创建,可能会有权限的问题)

这样做完之后,这个服务器就可以免密码克隆git服务器的内容了:
git clone git@git服务器IP:test.git(这个空仓库是在git服务器的git家目录里面的)

apache2重定向(隐藏index文件)

加载重定向模块:

ln -s /etc/apache2/mods-available/rewrite.load /etc/apache2/mods-enabled/

修改配置文件:

vim /etc/apache2/apache2.conf

找到:
Directory /var/www/
把 AllowOverride Node
改为:
AllowOverride all

保存退出,重启apache:

:wq
apachectl restart

安装laravel调试工具

安装:

composer require barryvdh/laravel-debugbar

全格式打印:

dd();

如果没有新的文件,git快捷提交:

git commit -a -m "show"

设置服务提供者:

vi /var/www/demo/config/app.php

找到:
Application Service Providers...

在里面写入:
Barryvdh\Debugbar\ServiceProvider::class,

起个别名,找到:
Class Aliases
写入:
'Debugbar' => Barryvdh\Debugbar\Facade::class,

生成配置文件:
cd /var/www/demo/
php artisan vendor:publish

手动输出错误日志:
php文件中写:
/Debugbar::error('Something is definitely goding wrong');

环境配置和数据库连接

连接:

1. 安装Navicat Premium

2. 然后新建一个mysql连接

3. 然后配置ssh

4. 输入远程服务器的ip和用户名密码

5. 然后配置常规

6. 这里面是以ssh的远程服务器为基础的,所以ip地址就写localhost(代表远程服务器)

7. 输入数据库的用户名和密码

8. 连接成功

配置:

配置文件都在根目录的config文件夹下,找到database.php

可以看到里面的mysql配置,使用了一个env函数

这个函数可以动态加载根目录下得.env里面的全局变量

所以我们只需要修改.env里面的配置就可以了

数据迁移

生成信息记录表:

根目录下:
php artisan migrate

在根目录下 database/migrations 里面存放了动态建表文件

利用laravel命令建立表,有利于数据库迁移:

根目录下:
php artisan make:migration crteate_news_table

会在根目录下的database/migrations文件里夹里生成对应的文件,可以在这个文件里定义表结构

静态资源管理elixir工具

安装nodejs:

wget https://nodejs.org/dist/v4.4.4/node-v4.4.4.tar.gz

tar -zxvf node-v4.4.4.tar.gz

cd node-v4.4.4

./configure

make && make install

安装gulp:

npm install --global gulp

npm install

配置文件在:

根目录下:
gulpfile.js

测试合成文件:

合并多个css文件:
vi gulpfile.js

注释:
min.sass('app.scss');
添加:
mix.styles(['a.css','b.css'],'public/assets/css');
注意:a.css,b.css都在项目根目录下resources下assets的css目录(没有自己建立个)
注意:合成输出的目录在public/assets/css下(没有自己建立)

编译合成:
gulp

查看效果:
cat public/assets/css/all.css

测试编译sass:

vim resources/assets/sass/app.scss
打开文件中的注释,导入bootstrap

测试驱动开发

项目根目录下有一个tests文件夹,在这个里面写测试用例:

cd tests

其中TestCase.php是系统封装的测试,我们自己写的驱动都要集成这个类

ExampleTest.php就是一个列子

我们自己写的测试用例,命名一定要按照规范,即xxxTest.php

测试:

项目根目录下:
./vendor/bin/phpunit 

显示绿色的就是测试通过,红色的的就是没有测试通过

ps:我们在实际的项目开发中,先根据用户需求,写出测试用例,执行测试,肯定都是
红色的呀,然后我们就一个模块一个模块的去完成,让红色慢慢的都变绿,项目也就做完啦

laravel项目生命周期

laravel运行流程

1.public/index.php

项目入口文件

2.bootstrap/cache

    框架的启动文件夹
    cache是项目编译后的所有需要的类和资源

contract容器,帮助我们创建我们需要的对象

3.配置文件

provider:服务提供者
命名空间加类,写在这里面的类,系统会自动帮我们创建对象

aliases:别名
给对象起个别名,方便我们使用

app/console:命令行相关

kenel.php 命令行要使用的东西在这里

app/events:注册事件

app/http:网页请求走这里

app/jobs:消息

  1. 加载app/http/内核 kenel.php

    先走里面的中间件,中间件分全局中间件,和路由中间件
    

app/http/route路由文件,是整个web项目最开始的地方了

模板使用

路由文件位置:

app/Http/routes.php

加载模板

模板位置在:

resources/views/

模板名字:
name.blade.php

加载模板用:
return view('name');

加载views/dir/下的模板:
return view('dir.name');

模板包含

在要页面中这样写:

@include('inc.name')

模板继承

在要继承的页面中这样写:

@extends('layout.app')

我们只继承那些不变的内容,动态的内容我们要留空,在被继承的模板文件中用这个占位:

@yield('content')
在继承它的页面中去实现这个占位的内容

接着在继承页面中这样写:

    @section('content')
        要实现的代码内容...
    @endsection

控制器与resfulApi的使用

控制器方法约定(resfulApi):

GET index  列表
GET create 创建
POST index 添加一个
GET id 查看
GET edit 修改

创建控制器:

项目目录中使用命令:

php artisan make:controller HomeController --resource
 
会在app/Http/Controller/下面生成对应的控制器

路由设置

在路由文件中配置:

基本路由:

Route::get('/','HomeController@index');

resful路由:

Route::resource('/home/','HomeController');
Route::resource('/home/create','HomeController');
Route::resource('/home/edit','HomeController');

注意:顶级目录好像不支持get方式

对控制器的控制:

生效的方法:

Route::resource('/','HomeController',['only'=>['index','create']]);

不生效的方法设置:

Route::resource('/','HomeController',['except'=>['index','create']]);

服务容器和工厂模式

方便扩展的核心架构就是容器: Service Container

index入口文件中,包含了核心框架应用程序对象:

$app = require_once __DIR__.'/../bootstrap/app.php';

app.php是一个Application对象:

$app = new Illuminate\Foundation\Application(
realpath(__DIR__.'/../')

);

Application继承Container对象:

class Application extends Container implements ApplicationContract, HttpKernelInterface

Container就是一个容器对象,利用各种机制来帮助我们创建对象

Application对象给我们一个这样的方法:

$app->singleton(
Illuminate\Contracts\Debug\ExceptionHandler::class,  //访问这个类名
App\Exceptions\Handler::class                          //放入这个类
);

在服务提供者中,我们可以方便的注册类或接口:

$this->app->bind('A', function ($app) {
return new HelpSpot\API($app['HttpClient']);  //返回一个对象或者类名称 new \App\User();
});
$u->$this->app->make('A');

在app.php文件中绑定:

//相当于给这个类做一个标记,名字是A
$app->bind('A', function ($app) {   
return new HelpSpot\API($app['HttpClient']);  //返回一个对象或者类名称 new \App\User();
});
//这里通过标记,告诉Application工厂给我生产一个对象:
$u->$this->app->make('A');

那么如果是已经new好的对象我们怎么放到容器中进行统一管理呢?

$u = new User();
$this->app-instance('u',$u);

优点:如果我们这个类是需要替换成其他的类的话,我们不用做太多的改动,只需要修改个返回的类的就行了,标记在其他地方都是通用的

根据不同需求生产不同的对象

单例模式:

//这样绑定
$app->singleton('A', function ($app) {   
    return new HelpSpot\API($app['HttpClient']);  //返回一个对象或者类名称 new \App\User();
});
//这样生成
$this->app->make('A');
简介写法:
$this->app['A'];

还可以把我们实例化好的对象放到APP里面统一管理:

$fooBar = new FooBar(new SomethingElse);
$this->app->instance('FooBar', $fooBar);

依赖注入和ioc控制反转

控制反转就是在我们需要一个对象的时候,根据参数的类型,把我们需要的函数注册进来,比如:

class Tb{
    private $ta;
    public function __constauct(\App\Ta $a){
        $this->ta = $a;
    }
}
说明:在我们需要使用Tb这个对象的时候,工厂的方法在创建Tb对象的时候,会同时把我们需要的
参数也创建好,并且填充进来,这样在我们开发程序的时候就会方便很多

要想使用依赖注入和控制反转,就必须先注册类:

$app->bind(\App\Ta::class, \App\Ta::class); $app->bind(\App\Tb::class, \App\Tb::class);

//为什么我们的绑定和官方源码不一样呢,来看看
$app->singleton(
Illuminate\Contracts\Debug\ExceptionHandler::class,  //其实就是一个接口
App\Exceptions\Handler::class                         //具体实现接口的一个类
);

并不是在bootstrap/app.php里面注册,后面会说道

服务提供者和laravel低耦合架构

在入口index.php文件中make 了一个内核:

$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);

内核继承了HttpKernel,在httpKernel中:

//启动配置
protected $bootstrappers = [
    'Illuminate\Foundation\Bootstrap\DetectEnvironment',
    'Illuminate\Foundation\Bootstrap\LoadConfiguration',
    'Illuminate\Foundation\Bootstrap\ConfigureLogging',
    'Illuminate\Foundation\Bootstrap\HandleExceptions',
    'Illuminate\Foundation\Bootstrap\RegisterFacades',
    'Illuminate\Foundation\Bootstrap\RegisterProviders',
    'Illuminate\Foundation\Bootstrap\BootProviders',
];   
//启动了LoadConfiguration配置文件

在config/app.php中,return了一个数组,其中:

这个提供了服务提供者的路径:
'providers' => [
    Illuminate\Auth\AuthServiceProvider::class,
    Illuminate\Broadcasting\BroadcastServiceProvider::class,
    Illuminate\Bus\BusServiceProvider::class,
    Illuminate\Cache\CacheServiceProvider::class,
    Illuminate\Foundation\Providers\ConsoleSupportServiceProvider::class,
    Illuminate\Cookie\CookieServiceProvider::class,
    Illuminate\Database\DatabaseServiceProvider::class,
    Illuminate\Encryption\EncryptionServiceProvider::class,
    Illuminate\Filesystem\FilesystemServiceProvider::class,
    Illuminate\Foundation\Providers\FoundationServiceProvider::class,
    Illuminate\Hashing\HashServiceProvider::class,
    Illuminate\Mail\MailServiceProvider::class,
   ]
httpKernel中会根据这个路径注册服务提供者,生成对应的对象

在Providers文件夹下,有各种注册的服务提供者:

AppServiceProvider.php中继承了Serviceprovider,Serviceprovider中传了一个$app对象:
    public function __construct($app)
{
    $this->app = $app;
}
在AppServiceProvider.php中,有两个函数:
    public function boot()   //启动函数,先执行这个,可以进行一些前提配置
{
    //
    $a = 111;
}
 public function register()  //注册绑定类
{
    //
    $this->app->bind('\App\Ta::class',\App\Ta:class);
        $this->app->bind('\App\Tb::class',\App\Tb:class);
}

总结一下

laravel是怎么运行的

最大就是容器对象:Application

管理laravel框架里面的所有内容
要想使用这些功能,我们要先注册

什么是服务:

 把解决某一个相关功能一系列相关的类打包封装,就是一个服务

服务提供者做什么的:

服务提供者就是扩展我们功能的地方
Application根据配置文件帮我们把服务注册,而所有我们需要的服务功能都是在
服务提供者文件中进行注册的(/app/Providers/AppServiceProvider.php)

这样在多人开发的时候,每个人把要注册的类写在自己的服务提供者中
Providers/的文件中(自己建立)的register的方法里面

Facades的使用

为了在每次使用类的使用不在生成重复的对象,或者夸文件使用一个对象,我们需要这样使用对象:

User::getName();

这样来配置我们自己的类:

namespace App\Http;
class Z extends \Illuminate\Support\Facades\Facade
{
    protected static function getFacadeAccessor()
    {
        return '\App\TA';
    }
}

Z继承Facade,返回一个类名,这样我们在使用Z类的时候,会自动调用TA类的方法
使用: \App\Http\Z::getTitle() 调用的就是TA类脸的getTitle()方法
注意:必须用单列模式注册TA类

我们来做个简化,在用的时候不带命名空间:

在配置文件中,我们给\App\Http\Z起个别名就好了:

'Z' => \App\Http\Z::class,

中间件

为了不把大量的代码都写在controler里面,我们把某一些特定的服务提取出来,当做中间件

各种验证什么的就由中间件来做

创建中间件

项目更目录下:

php artisan make:middleware testMiddleware

然后注册中间件:

配置文件/app/Http/Kernel.php

protected $middlewareGroups = [ ]
全局中间件,无论如何都是会执行的

protected $routeMiddleware = [ ]
自定义别名中间件,我们一般把中间件注册在这里

调用中间件:

单个:
Route::get('/mid', ['middleware'=>'test',function () {
return redirect('/facades');
}]);

多个:
Route::get('/mid', ['middleware'=>['test','test2'],function () {
return redirect('/facades');
}]);

路由组使用中间件:
Route::group(['middleware' => 'auth'], function () {
    Route::get('/', function ()    {
        // 使用 Auth 中间件
    });

    Route::get('user/profile', function () {
        // 使用 Auth 中间件
    });
});
路由组共用中间件 auth
在路由里配置中间件很适合很多个方法都使用同一个中间件
一般用于生产验证和权限验证

只对一个控制器生效的中间件:
在控制器的构造函数中这样写:
public function __construct()
{
    $this->middleware('test');
}
这样在使用控制器的时候,优先加载中间件

Request

laravel默认帮我们开启了csrf验证,这样我们在本地提交表单是提交不过去的,我们为了测试,先关闭:

在app/Http/Kernel.php文件中,注释掉这个:
//            \App\Http\Middleware\VerifyCsrfToken::class,

这个csrf认证可以验证非法请求或者表单的重复提交,后面会说道

测试request

在方法里这样用:

public function store(Request $request)
{
   //提交到数据库
   dd($request);
 }
 打印可以看出,里面包含了关于一次请求的所有信息
 
 取值:
 $requset['name'];

validate验证

在stroe方法中这样写:

$this->validate($request, [
  'name' => 'required',
  'email' => 'required|email',
]);

开启错误提示:

在模板引擎中这样写:

@if (count($errors) > 0)
<div class="alert alert-danger">
    <ul>
        @foreach ($errors->all() as $error)
            <li>{{ $error }}</li>
        @endforeach
    </ul>
</div>
@endif

但是呢,验证都放在方法中,代码就不会那么纯洁了,我们需要一个单独表单请求验证文件:

php artisan make:request StoreBlogPostRequest

新生成的类文件会被放在 app/Http/Requests 目录下。让我们将一些验证规则加入到 rules 方法中:
public function rules()
{
    return [
        'title' => 'required|unique:posts|max:255',
        'body' => 'required',
    ];
}

在控制器的方法中这样使用:
public function store(StoreBlogPostRequest $request)
{
    // 传入的请求是有效的...
}

开启csrf认证

打开我们之前关闭的中间件:

\App\Http\Middleware\VerifyCsrfToken::class,

然后呢,我们需要在表单中加入一个隐藏域,用来传递服务器传来的token:

<input type="hidden" name="_token" value="{{ csrf_token() }}">

表单助手插件:

安装:

composer require laravelcollective/html

配置,在config/app.php中:

Collective\Html\HtmlServiceProvider::class

别名:
'Form' => Collective\Html\FormFacade::class,
'Html' => Collective\Html\HtmlFacade::class, 

模板中这样用:

{!! Form::open(array('route'=>'test.store','class'=>'form','novalidate'=>'novalidate')) !!}
{!! Form::label('your name') !!}
{!! Form::text('name',null,
    array('required',
        'class'=>'form-control',
        'placeholder'=>'your name')) !!}
{!! Form::label('your email') !!}
{!! Form::text('email',null,
    array('required',
        'class'=>'form-control',
        'placeholder'=>'your email address')) !!}
{!! Form::submit('添加') !!}

在用户填写错误的时候,会保留用户的填写信息

orm模型

就是把数据表的结构跟我们的一个类对应上了

创建模型

数据模型建立(生成文件在app文件夹下):

普通建立:
php artisan make:model Test

建立的同时生成数据库迁移:
php artisan make:model Test --migration

之后我们就可以在控制其中很方便的使用模型对象了:

    $test = new Test();  //要现在开始引入命名空间
    $test->name = $request['name'];
    $test->email = $request['email'];
    $test->save();
    // $test->where('id',1)->delete();
    dd($test->all());

利用邮件服务将表单推送到手机

为了方便将提示信息推送给用户,我们使用邮箱服务:

首先安装email扩展:

composer require guzzlehttp/guzzle

然后修改配置文件,根目录下得.env文件,这样改:

MAIL_DRIVER=smtp
MAIL_HOST=smtp.163.com
MAIL_PORT=25
MAIL_USERNAME=n13521760670@163.com
MAIL_PASSWORD=******
MAIL_ENCRYPTION=null

config/mail.php也要修改:

  'from' => ['address' => 'n13521760670@163.com', 'name' => 'n13521760670@163.com'],

在控制器中这样使用:

    $data = [
        'name' => $request->get('name'),
        'email' => $request->get('email')
    ];
    \Mail::send('email', $data, function ($m) use ($data) {
        $m->from('n13521760670@163.com', '测试发送邮件');
        $m->to('975974740@qq.com',$data['name'])->subject('laravel练习使用邮件');
    });

模板中这样设置信息:

<p>
用户:{{$name}} email:{{$email}}
正在练习使用laravel
</p>

利用laravel认证模板完成用户注册登录

主要是利用框架自带的Auth模块

未完待续...

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,839评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,543评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,116评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,371评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,384评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,111评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,416评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,053评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,558评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,007评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,117评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,756评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,324评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,315评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,539评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,578评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,877评论 2 345

推荐阅读更多精彩内容