(《深入實(shí)踐Spring Boot》筆記2)在Spring Boot中使用數(shù)據(jù)庫(kù)


IDE軟件:IntelliJ IDEA 15.0.2
操作系統(tǒng):Win10
Spring boot版本:1.4.1 Release
Maven版本:apache-maven-3.5.2


一门扇、引言

??使用數(shù)據(jù)庫(kù)是開(kāi)發(fā)基本應(yīng)用的基礎(chǔ)雹有。借助于開(kāi)發(fā)框架偿渡,我們已經(jīng)不用編寫原始的訪問(wèn)數(shù)據(jù)庫(kù)的代碼,也不用調(diào)用JDBC(Java Data Base Connectivity)或者連接池等諸如此類的被稱作底層的代碼霸奕,我們將在高級(jí)的層次上訪問(wèn)數(shù)據(jù)庫(kù)溜宽。而Spring Boot更是突破了以前所有開(kāi)發(fā)框架訪問(wèn)數(shù)據(jù)庫(kù)的方法,在前所未有的更加高級(jí)的層次上訪問(wèn)數(shù)據(jù)庫(kù)质帅。因?yàn)镾pring Boot包含一個(gè)功能強(qiáng)大的資源庫(kù)适揉,為使用Spring Boot的開(kāi)發(fā)者提供了更加簡(jiǎn)便的接口進(jìn)行訪問(wèn)。 本文學(xué)習(xí)怎樣使用傳統(tǒng)的關(guān)系型數(shù)據(jù)庫(kù)临梗,以及近期一段時(shí)間異軍突起的NoSQL(Not Only SQL)數(shù)據(jù)庫(kù)涡扼。 實(shí)例工程使用了分模塊的方式構(gòu)建,各模塊的定義如表:

項(xiàng)目 工程 功能
MySql模塊 mysql 使用MySql
Redis模塊 redis 使用Redis
MongoDB模塊 mongodb 使用MongoDB
Neo4j模塊 neo4j 使用Neo4j

二盟庞、使用Mysql數(shù)據(jù)庫(kù)

??對(duì)于傳統(tǒng)關(guān)系型數(shù)據(jù)庫(kù)來(lái)說(shuō)吃沪,Spring Boot使用JPA(Java Persistence API)資源庫(kù)來(lái)實(shí)現(xiàn)對(duì)數(shù)據(jù)庫(kù)的操作,使用MySQL也是如此什猖。簡(jiǎn)單地說(shuō)票彪,JPA就是為POJO(Plain Ordinary Java Object)提供持久化的標(biāo)準(zhǔn)規(guī)范,即將Java的普通對(duì)象通過(guò)對(duì)象關(guān)系映射(Object-Relational Mapping不狮,ORM)持久化到數(shù)據(jù)庫(kù)中降铸。

  1. MySQL依賴配置
    ??為了使用JPA和MySQL,首先在工程中引入它們的Maven依賴摇零,如代碼清單所示推掸。其中,指定了在運(yùn)行時(shí)調(diào)用MySQL的依賴驻仅。
 <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
 </dependency>

2. 實(shí)體建模
??首先創(chuàng)建一些普通對(duì)象谅畅,用來(lái)與數(shù)據(jù)庫(kù)的表建立映射關(guān)系,接著演示如何使用JPA對(duì)數(shù)據(jù)庫(kù)進(jìn)行增刪查改等存取操作噪服。 假如現(xiàn)在有三個(gè)實(shí)體:部門毡泻、用戶和角色,并且它們具有一定的關(guān)系粘优,即一個(gè)用戶只能隸屬于一個(gè)部門仇味,一個(gè)用戶可以擁有多個(gè)角色。Spring Boot的實(shí)體建模與使用Spring框架時(shí)的定義方法一樣雹顺,同樣比較方便的是使用了注解的方式來(lái)實(shí)現(xiàn)丹墨。
??注解@Table指定關(guān)聯(lián)的數(shù)據(jù)庫(kù)的表名,注解@Id定義一條記錄的唯一標(biāo)識(shí)嬉愧,并結(jié)合注解@GeneratedValue將其設(shè)置為自動(dòng)生成带到。部門實(shí)體只有兩個(gè)字段:id和name。

部門實(shí)體的建模如代碼Department.java:

package springboot.example.domain;

import javax.persistence.*;

/**
 * Created by zhang on 2018/2/10.
 */
@Entity
@Table(name="department")
public class Department {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;
    private String name;

    public Department() {
    }

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

??用戶實(shí)體包含三個(gè)字段:id、name和createdate揽惹,其中注解@ManyToOne定義它與部門的多對(duì)一關(guān)系,并且在數(shù)據(jù)庫(kù)表中用字段did來(lái)表示部門的ID四康,注解@ManyToMany定義與角色實(shí)體的多對(duì)多關(guān)系搪搏,并且用中間表user_role來(lái)存儲(chǔ)它們各自的ID,以表示它們的對(duì)應(yīng)關(guān)系闪金。日期類型的數(shù)據(jù)必須使用注解@DateTimeFormat來(lái)進(jìn)行格式化疯溺,以保證它在存取時(shí)能提供正確的格式,避免保存失敗哎垦。注解@JsonBackReference用來(lái)防止關(guān)系對(duì)象的遞歸訪問(wèn)囱嫩。

用戶實(shí)體的建模如代碼User.java:

package springboot.example.domain;

import com.fasterxml.jackson.annotation.JsonBackReference;
import org.springframework.context.annotation.Role;
import org.springframework.format.annotation.DateTimeFormat;

import javax.persistence.*;
import java.util.Date;
import java.util.List;

/**
 * Created by zhang on 2018/2/10.
 */
@Entity
@Table(name="user")
public class User implements java.io.Serializable{
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;
    private String name;
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private Date createDate;

    @ManyToOne
    @JoinColumn(name="did")
    @JsonBackReference
    private Department department;

    @ManyToMany(cascade = {}, fetch = FetchType.EAGER)
    @JoinTable(name="user_role",
        joinColumns = {@JoinColumn(name = "user_id")},
        inverseJoinColumns = {@JoinColumn(name="roles_id")})
    private List<Role> roles;

    public User() {
    }

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Date getCreateDate() {
        return createDate;
    }

    public void setCreateDate(Date createDate) {
        this.createDate = createDate;
    }

    public Department getDepartment() {
        return department;
    }

    public void setDepartment(Department department) {
        this.department = department;
    }

    public List<Role> getRoles() {
        return roles;
    }

    public void setRoles(List<Role> roles) {
        this.roles = roles;
    }
}

??角色實(shí)體建模比較簡(jiǎn)單,只要按設(shè)計(jì)的要求漏设,定義id和name字段即可墨闲,當(dāng)然同樣必須保證id的唯一性并將其設(shè)定為自動(dòng)生成。

角色實(shí)體的建模如代碼Role.java:

package springboot.example.domain;

import javax.persistence.*;

/**
 * Created by zhang on 2018/2/10.
 */



@Entity
@Table(name="role")
public class Role implements java.io.Serializable{
    @Id
    @GeneratedValue(strategy= GenerationType.IDENTITY)
    private Long id;
    private String name;
    public Role(){
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
  1. 實(shí)體持久化
    ??通過(guò)上面三個(gè)實(shí)體的定義郑口,實(shí)現(xiàn)了使用Java的普通對(duì)象(POJO)與數(shù)據(jù)庫(kù)表建立映射關(guān)系(ORM)鸳碧,接下來(lái)使用JPA來(lái)實(shí)現(xiàn)持久化。 它是一個(gè)接口犬性,并繼承于JPA資源庫(kù)JpaRepository接口瞻离,使用注解@Repository將這個(gè)接口也定義為一個(gè)資源庫(kù),使它能被其他程序引用乒裆,并為其他程序提供存取數(shù)據(jù)庫(kù)的功能套利。 使用相同的方法,可以定義部門實(shí)體和角色實(shí)體的資源庫(kù)接口鹤耍。接口同樣繼承于JpaRepository接口肉迫,只要注意使用的參數(shù)是各自的實(shí)體對(duì)象即可。

用戶實(shí)體使用JPA進(jìn)行持久化的例子如代碼UserRepository.java:

package springboot.example.Repository;

import org.springframework.data.jpa.repository.JpaRepository;
import springboot.example.domain.User;

/**
 * Created by zhang on 2018/2/10.
 */
public interface UserRepository extends JpaRepository<User,Long>{

}

??這樣就實(shí)現(xiàn)存取數(shù)據(jù)庫(kù)的功能了《杳郏現(xiàn)在可以對(duì)數(shù)據(jù)庫(kù)進(jìn)行增刪查改昂拂、進(jìn)行分頁(yè)查詢和指定排序的字段等操作。 或許你還有疑問(wèn)抛猖,我們定義的實(shí)體資源庫(kù)接口并沒(méi)有聲明一個(gè)方法格侯,也沒(méi)有對(duì)接口有任何實(shí)現(xiàn)的代碼,甚至連一條SQL查詢語(yǔ)句都沒(méi)有寫财著,使用JPA就是可以這么簡(jiǎn)單联四。我們來(lái)看看JpaRe-pository的繼承關(guān)系,JpaRepository繼承于PagingAndSortingRepository撑教,它提供了分頁(yè)和排序功能朝墩,是的,使用JPA就是可以這么簡(jiǎn)單伟姐。我們來(lái)看看JpaRe-pository的繼承關(guān)系收苏,你也許會(huì)明白一些亿卤。JpaRepository繼承于PagingAndSortingRepository,它提供了分頁(yè)和排序功能鹿霸,PagingAndSortingRepository繼承于Crud-Repository排吴,它提供了簡(jiǎn)單的增刪查改功能。因?yàn)槎x的接口繼承于JpaRepository懦鼠,所以它傳遞性地繼承上面所有這些接口钻哩,并擁有這些接口的所有方法,這樣就不難理解為何它包含那么多功能了肛冶。這些接口提供的一些方法如下:

<S extends T> S save(S var1); 
T findOne(ID var1); 
long count(); 
void delete(ID var1); 
void delete(T var1); 
void deleteAll(); 
Page<T> findAll(Pageable var1); 
List<T> findAll(); 
List<T> findAll(Sort var1); 
List<T> findAll(Iterable<ID> var1); 
void deleteAllInBatch(); 
T getOne(ID var1); 
......

??JPA還提供了一些自定義聲明方法的規(guī)則街氢,例如,在接口中使用關(guān)鍵字findBy睦袖、readBy珊肃、getBy作為方法名的前綴,拼接實(shí)體類中的屬性字段(首個(gè)字母大寫)扣泊,并可選擇拼接一些SQL查詢關(guān)鍵字來(lái)組合成一個(gè)查詢方法近范。例如,對(duì)于用戶實(shí)體延蟹,下列查詢關(guān)鍵字可以這樣使用:

·And评矩,例如findByIdAndName(Long id,String name)阱飘;
·Or斥杜,例如findByIdOrName(Long id,String name)沥匈;
·Between蔗喂,例如findByCreatedateBetween(Date start,Date end)高帖;
·LessThan缰儿,例如findByCreatedateLessThan(Date start);
·GreaterThan散址,例如findByCreatedateGreaterThan(Date start)乖阵;
·IsNull,例如findByNameIsNull()预麸;
·IsNotNull瞪浸,例如findByNameIsNotNull(); 
·NotNull吏祸,與IsNotNull等價(jià)对蒲;
·Like,例如findByNameLike(String name); 
·NotLike蹈矮,例如findByNameNotLike(String name)砰逻; 
·OrderBy,例如findByNameOrderByIdAsc(String name)含滴; 
·Not诱渤,例如findByNameNot(String name); 
·In谈况,例如findByNameIn(Collection<String>nameList); 
·NotIn递胧,例如findByNameNotIn(Collection<String>nameList)碑韵。

??又如下列對(duì)用戶實(shí)體類自定義的方法聲明,它們都是符合JPA規(guī)則的缎脾,這些方法也不用實(shí)現(xiàn)祝闻,JPA將會(huì)代理實(shí)現(xiàn)這些方法。

User findByNameLike(String name); 
User readByName(String name);
List<User> getByCreatedateLessThan(Date star);
  1. Mysql測(cè)試
    ??現(xiàn)在遗菠,為了驗(yàn)證上面設(shè)計(jì)的正確性,我們用一個(gè)實(shí)例來(lái)測(cè)試一下。 首先宾茂,增加一個(gè)使用JPA的配置類廊佩,其中@EnableTransac-tionManagement啟用了JPA的事務(wù)管理;@EnableJpaRepositories啟用了JPA資源庫(kù)并指定了上面定義的接口資源庫(kù)的位置贺拣;@EntityScan指定了定義實(shí)體的位置蓖谢,它將導(dǎo)入我們定義的實(shí)體。注意譬涡,在測(cè)試時(shí)使用的JPA配置類可能與這個(gè)配置略有不同闪幽,這個(gè)配置的一些配置參數(shù)是從配置文件中讀取的,而測(cè)試時(shí)使用的配置類把一些配置參數(shù)都包含在類定義中了涡匀。

配置類JpaConfiguration.java

package springboot.example.config;

import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.transaction.annotation.EnableTransactionManagement;

/**
* Created by zhang on 2018/2/10.
*/
@Order(Ordered.HIGHEST_PRECEDENCE)
@Configuration
@EnableTransactionManagement(proxyTargetClass=true)
@EnableJpaRepositories(basePackages="dbdemo.**.repository")
@EntityScan(basePackages="dbdemo.**.entity")
public class JpaConfiguration {
   @Bean
   PersistenceExceptionTranslationPostProcessor persistenceExceptionTranslationPostProcessor(){
       return new PersistenceExceptionTranslationPostProcessor();
   } 
}

??其次盯腌,在MySQL數(shù)據(jù)庫(kù)服務(wù)器中創(chuàng)建一個(gè)數(shù)據(jù)庫(kù)test,然后配置一個(gè)可以訪問(wèn)這個(gè)數(shù)據(jù)庫(kù)的用戶及其密碼陨瘩。數(shù)據(jù)庫(kù)的表結(jié)構(gòu)可以不用創(chuàng)建腕够,在程序運(yùn)行時(shí)將會(huì)按照實(shí)體的定義自動(dòng)創(chuàng)建。如果還沒(méi)有創(chuàng)建一個(gè)具有完全權(quán)限訪問(wèn)數(shù)據(jù)庫(kù)test的用戶拾酝,可以在連接MySQL服務(wù)器的查詢窗口中執(zhí)行下面指令燕少,這個(gè)指令假設(shè)你將在本地中訪問(wèn)數(shù)據(jù)庫(kù)。

數(shù)據(jù)源和JPA配置application.yml:

spring:
    datasource:
         url: jdbc:mysql://localhost:3306/test?characterEncoding=utf8
         username: root
         password: root
    jpa:
         database: MYSQL
         show-sql: true
         #Hibernate ddl auto (validate|create|create-drop|update)         
         hibernate:
                ddl-auto: update             
         properties:
                hibernate:                 
                dialect: org.hibernate.dialect.MySQL5Dialect

??配置中將ddl-atuo設(shè)置為update蒿囤,就是使用Hibernate來(lái)自動(dòng)更新表結(jié)構(gòu)的客们,即如果數(shù)據(jù)表不存在則創(chuàng)建,或者如果修改了表結(jié)構(gòu),在程序啟動(dòng)時(shí)則執(zhí)行表結(jié)構(gòu)的同步更新底挫。

??最后恒傻,編寫一個(gè)測(cè)試程序,測(cè)試程序首先初始化數(shù)據(jù)庫(kù)建邓,創(chuàng)建一個(gè)部門盈厘,命名為“開(kāi)發(fā)部”,創(chuàng)建一個(gè)角色官边,命名為admin沸手,創(chuàng)建一個(gè)用戶,命名為user注簿,同時(shí)將它的所屬部門設(shè)定為上面創(chuàng)建的部門契吉,并將現(xiàn)有的所有角色都分配給這個(gè)用戶。然后使用分頁(yè)的方式查詢所有用戶的列表诡渴,并從查到的用戶列表中捐晶,打印出用戶的名稱、部門的名稱和第一個(gè)角色的名稱等信息妄辩。

測(cè)試程序代碼清單:MysqlTest.java

import org.apache.log4j.Logger;
import org.junit.Test;
import org.junit.Before;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.util.Assert;
import springboot.example.Repository.DepartmentRepository;
import springboot.example.Repository.RoleRepository;
import springboot.example.Repository.UserRepository;
import springboot.example.config.JpaConfiguration;
import springboot.example.domain.Department;
import springboot.example.domain.Role;
import springboot.example.domain.User;
import java.util.Date;
import java.util.List;

/**
 * Created by zhang on 2018/2/10.
 */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes={JpaConfiguration.class})
public class MysqlTest{
    private static Logger logger = Logger.getLogger(MysqlTest.class);
    @Autowired
    private UserRepository userRepository;
    @Autowired
    DepartmentRepository departmentRepository;
    @Autowired
    RoleRepository roleRepository;
    @Before public void initData(){
        userRepository.deleteAll();
        roleRepository.deleteAll();
        departmentRepository.deleteAll();
        Department department = new Department();
        department.setName(" 開(kāi)發(fā)部 ");
        departmentRepository.save(department);
        Assert.notNull(department.getId());
        Role role = new Role();
        role.setName("admin");
        roleRepository.save(role);
        Assert.notNull(role.getId());
        User user = new User();
        user.setName("user");
        user.setCreateDate(new Date());
        user.setDepartment(department);
        List<Role> roles = roleRepository.findAll();
        Assert.notNull(roles);
        user.setRoles(roles);
        userRepository.save(user);
        Assert.notNull(user.getId());
    }

    @Test
    public void findPage(){
        Pageable pageable = new PageRequest(0, 10, new Sort(Sort.Direction.ASC, "id"));
        Page<User> page = userRepository.findAll(pageable);
        Assert.notNull(page);
        for(User user : page.getContent()) {
            logger.info(user);
        }
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末惑灵,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子眼耀,更是在濱河造成了極大的恐慌英支,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,651評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件畔塔,死亡現(xiàn)場(chǎng)離奇詭異潭辈,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)澈吨,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,468評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門把敢,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人谅辣,你說(shuō)我怎么就攤上這事修赞。” “怎么了桑阶?”我有些...
    開(kāi)封第一講書人閱讀 162,931評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵柏副,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我蚣录,道長(zhǎng)割择,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 58,218評(píng)論 1 292
  • 正文 為了忘掉前任萎河,我火速辦了婚禮荔泳,結(jié)果婚禮上蕉饼,老公的妹妹穿的比我還像新娘。我一直安慰自己玛歌,他們只是感情好昧港,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,234評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著支子,像睡著了一般创肥。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上值朋,一...
    開(kāi)封第一講書人閱讀 51,198評(píng)論 1 299
  • 那天叹侄,我揣著相機(jī)與錄音,去河邊找鬼昨登。 笑死圈膏,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的篙骡。 我是一名探鬼主播,決...
    沈念sama閱讀 40,084評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼丈甸,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼糯俗!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起睦擂,我...
    開(kāi)封第一講書人閱讀 38,926評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤得湘,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后顿仇,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體淘正,經(jīng)...
    沈念sama閱讀 45,341評(píng)論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,563評(píng)論 2 333
  • 正文 我和宋清朗相戀三年臼闻,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了鸿吆。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,731評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡述呐,死狀恐怖惩淳,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情乓搬,我是刑警寧澤思犁,帶...
    沈念sama閱讀 35,430評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站进肯,受9級(jí)特大地震影響激蹲,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜江掩,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,036評(píng)論 3 326
  • 文/蒙蒙 一学辱、第九天 我趴在偏房一處隱蔽的房頂上張望乘瓤。 院中可真熱鬧,春花似錦项郊、人聲如沸馅扣。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 31,676評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)差油。三九已至,卻和暖如春任洞,著一層夾襖步出監(jiān)牢的瞬間蓄喇,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 32,829評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工交掏, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留妆偏,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,743評(píng)論 2 368
  • 正文 我出身青樓盅弛,卻偏偏與公主長(zhǎng)得像钱骂,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子挪鹏,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,629評(píng)論 2 354

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