Spring快速入门

文章内容输出来源:拉勾教育Java就业急训营

Spring是什么

  Spring是分层的 Java SE/EE应用 full-stack(全栈式) 轻量级开源框架。
  提供了表现层 SpringMVC和持久层 Spring JDBC Template以及业务层事务管理等众多的企业级应用技术,还能整合开源世界众多著名的第三方框架和类库,逐渐成为使用最多的Java EE 企业应用开源框架。
  两大核心:以 IOC(Inverse Of Control:控制反转)和 AOP(Aspect Oriented Programming:面向切面编程)为内核。

Spring的优势

1)方便解耦,简化开发
   Spring就是一个容器,可以将所有对象创建和关系维护交给Spring管理 什么是耦合度?
   对象之间的关系,通常说当一个模块(对象)更改时也需要更改其他模块(对象),这就是耦合,耦合度过高会使代码的维护成本增加。
   要尽量解耦。
   
2)AOP编程的支持 Spring提供面向切面编程,方便实现程序进行权限拦截,运行监控等功能。 

3)声明式事务的支持 通过配置完成事务的管理,无需手动编程

4)方便测试,降低JavaEE API的使用
Spring对Junit4支持,可以使用注解测试 

5)方便集成各种优秀框架 不排除各种优秀的开源框架,内部提供了对各种优秀框架的直接支持

IOC

控制反转(Inverse Of Control)不是什么技术,而是一种设计思想。它的目的是指导我们设计出更
加松耦合的程序

控制:在java中指的是对象的控制权限(创建、销毁)
反转:指的是对象控制权由原来 由开发者在类中手动控制 反转到 由Spring容器控制

例子

  • 传统方式 之前我们需要一个userDao实例,需要开发者自己手动创建 new UserDao();
  • IOC方式 现在我们需要一个userDao实例,直接从spring的IOC容器获得,对象的创建权交给了spring控制

IOC快速入门

步骤

  1. 创建java项目,导入spring开发基本坐标
  2. 编写Dao接口和实现类
  3. 创建spring核心配置文件
  4. 在spring配置文件中配置 UserDaoImpl
  5. 使用spring相关API获得Bean实例
  • 导入依赖
    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.1.5.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
    </dependencies>
  • 编写接口和实现类
public interface UserDao { 
    public void save(); 
}
public class UserDaoImpl implements UserDao {
    public void save() {
        System.out.println("保存成功了..."); 
    } 
}
  • 创建核心配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    
</beans>
  • 在spring配置文件中配置 UserDaoImpl
    <bean id="userDao" class="com.lagou.dao.impl.UserDaoImpl"></bean>
  • 使用spring相关API获得Bean实例
public class TestSpring {

    @Test
    public void test() {
        ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserDao userDao = (UserDao) classPathXmlApplicationContext.getBean("userDao");
        userDao.save();
    }
}


重点关注BeanFactory 和 ApplicationContext

BeanFactory

BeanFactory是 IOC 容器的核心接口,它定义了IOC的基本功能。

特点:在第一次调用getBean()方法时,创建指定对象的实例

BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));
beanFactory.getBean();

ApplicationContext

代表应用上下文对象,可以获得spring中IOC容器的Bean对象。

特点:在spring容器启动时,加载并创建所有对象的实例

ApplicationContext ac =new ClassPathXmlApplicationContext("applicationContext.xml");
ac.getBean()

Spring配置文件

  • Bean标签基本配置
<bean id="" class=""></bean> 
* 用于配置对象交由Spring来创建。 
* 基本属性: id:Bean实例在Spring容器中的唯一标识 class:Bean的全限定名 
* 默认情况下它调用的是类中的 无参构造函数,如果没有无参构造函数则不能创建成功。
  • Bean标签范围配置
<bean id="" class="" scope=""></bean>

scope属性指对象的作用范围,取值如下:

取值范围 说明
singleton 默认值,单例的
prototype 多例的
request WEB项目中,Spring创建一个Bean的对象,将对象存入到request域中
session WEB项目中,Spring创建一个Bean的对象,将对象存入到session域中
global session WEB项目中,应用在Portlet环境,如果没有Portlet环境那么globalSession 相当于 session
1. 当scope的取值为singleton时 
Bean的实例化个数:1个
Bean的实例化时机:当Spring核心文件被加载时,实例化配置的Bean实例
Bean的生命周期: 对象创建:当应用加载,创建容器时,对象就被创建了
对象运行:只要容器在,对象一直活着
对象销毁:当应用卸载,销毁容器时,对象就被销毁了 
2. 当scope的取值为prototype时 Bean的实例化个数:多个
Bean的实例化时机:当调用getBean()方法时实例化Bean
Bean的生命周期: 对象创建:当使用对象时,创建新的对象实例
对象运行:只要对象在使用中,就一直活着
对象销毁:当对象长时间不用时,被 Java 的垃圾回收器回收了
  • Bean生命周期配置
<bean id="" class="" scope="" init-method="" destroy-method=""></bean> 
* init-method:指定类中的初始化方法名称 
* destroy-method:指定类中销毁方法名称
  • Bean实例化三种方式
    • 无参构造方法实例化
    • 工厂静态方法实例化
    • 工厂普通方法实例化

DI

  依赖注入 DI(Dependency Injection):它是 Spring 框架核心 IOC 的具体实现。
  在编写程序时,通过控制反转,把对象的创建交给了 Spring,但是代码中不可能出现没有依赖的情
况。IOC 解耦只是降低他们的依赖关系,但不会消除。例如:业务层仍会调用持久层的方法。
  那这种业务层和持久层的依赖关系,在使用 Spring 之后,就让 Spring 来维护了。简单的说,就是通
过框架把持久层对象传入业务层,而不用我们自己去获取。

Bean依赖注入方式

  • 构造器注入 (要求JavaBean有相应的构造方法)
    <bean id="userDao" class="com.lagou.dao.impl.UserDaoImpl"></bean>
    <bean id="userService" class="com.lagou.service.impl.UserServiceImpl">
        <!--构造器注入 name 构造器中的属性名-->
        <constructor-arg name="userDao1" ref="userDao"></constructor-arg>
    </bean>
  • set方法注入
<bean id="userDao" class="com.lagou.dao.impl.UserDaoImpl"></bean>
    <bean id="userService" class="com.lagou.service.impl.UserServiceImpl">
        <!--set方式注入,要求JavaBean有对应的set方法-->
        <property name="userDao" ref="userDao"></property>
    </bean>
  • p命名空间注入
    本质也是set方法注入
    先引入p命名空间xmlns:p="http://www.springframework.org/schema/p"
<bean id="userDao" class="com.lagou.dao.impl.UserDaoImpl"/> 
<bean id="userService" class="com.lagou.service.impl.UserServiceImpl" p:userDao-ref="userDao"/>

标签知识小节

<bean>标签:创建对象并放到spring的IOC容器
    id属性:在容器中Bean实例的唯一标识,不允许重复
    class属性:要实例化的Bean的全限定名
    scope属性:Bean的作用范围,常用是Singleton(默认)和prototype
<constructor-arg>标签:属性注入 
    name属性:属性名称
    value属性:注入的普通属性值 
    ref属性:注入的对象引用值
<property>标签:属性注入 
    name属性:属性名称
    value属性:注入的普通属性值 
    ref属性:注入的对象引用值 
        <list> 
        <set> 
        <array> 
        <map> 
        <props>
<import>标签:导入其他的Spring的分文件

注解开发

注解 说明
@Component 使用在类上用于实例化Bean
@Controller 使用在web层类上用于实例化Bean
@Service 使用在service层类上用于实例化Bean
@Repository 使用在dao层类上用于实例化Bean
@Autowired 使用在字段上用于根据类型依赖注入
@Qualifier 结合@Autowired一起使用,根据名称进行依赖注入
@Resource 相当于@Autowired+@Qualifier,按照名称进行注入
@Value 注入普通属性
@Scope 标注Bean的作用范围
@PostConstruct 使用在方法上标注该方法是Bean的初始化方法
@PreDestroy 使用在方法上标注该方法是Bean的销毁方法
<!--注解的组件扫描--> 
<context:component-scan base-package="com.lagou"></context:component-scan>

AOP

什么是AOP

  AOP 为 Aspect Oriented Programming 的缩写,意思为面向切面编程。
  AOP 是 OOP(面向对象编程)的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

AOP优点

  1. 在程序运行期间,在不修改源码的情况下对方法进行功能增强
  2. 逻辑清晰,开发核心业务的时候,不必关注增强业务的代码
  3. 减少重复代码,提高开发效率,便于后期维护

AOP底层实现

  实际上,AOP 的底层是通过 Spring提供的的动态代理技术实现的。在运行期间,Spring通过动态代
理技术动态的生成代理对象,代理对象方法执行时进行增强功能的介入,在去调用目标对象的方法,从而完成功能的增强。
  在 Spring中,框架会根据目标类是否实现了接口来决定采用哪种动态代理的方式。
    当bean实现接口时,会用JDK代理模式
    当bean没有实现接口,用cglib实现(可以强制使用cglib(在spring配置中加入<aop:aspectj-autoproxy proxyt-target-class=”true”/>)

AOP相关术语

* Target(目标对象):代理的目标对象 

* Proxy(代理):一个类被 AOP 织入增强后,就产生一个结果代理类 

* Joinpoint(连接点):所谓连接点是指那些可以被拦截到的点。在spring中,这些点指的是方法,因为 spring只支持方法类型的连接点 

* Pointcut(切入点):所谓切入点是指我们要对哪些 Joinpoint 进行拦截的定义 

* Advice(通知/ 增强):所谓通知是指拦截到 Joinpoint 之后所要做的事情就是通知
        分类:前置通知、后置通知、异常通知、最终通知、环绕通知 

* Aspect(切面):是切入点和通知(引介)的结合 

* Weaving(织入):是指把增强应用到目标对象来创建新的代理对象的过程。spring采用动态代理织入,而AspectJ采用编译期织入和类装载期织入。

AOP快速入门

步骤

  1. 创建java项目,导入AOP相关坐标
  2. 创建目标接口和目标实现类(定义切入点)
  3. 创建通知类及方法(定义通知)
  4. 将目标类和通知类对象创建权交给spring
  5. 在核心配置文件中配置织入关系,及切面
  6. 编写测试代码
  • 导入AOP依赖
        <!--导入spring的context坐标,context依赖aop-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.1.5.RELEASE</version>
        </dependency>
        <!-- aspectj的织入(切点表达式需要用到该jar包) -->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.8.13</version>
        </dependency>
        <!--spring整合junit-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>5.1.5.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
  • 创建切入点
public class Targer { 
    public void transfer() { 
        System.out.println("转账业务..."); 
    } 
}
  • 创建通知类和通知方法
public class MyAdvice {
    public void before() {
        System.out.println("before...");
    }
}
  • 将目标类和通知类对象创建权交给spring
<!--目标类交给IOC容器--> 
<bean id="accountService" class="com.lagou.service.impl.Target"> </bean> 
<!--通知类交给IOC容器-->
<bean id="myAdvice" class="com.lagou.advice.MyAdvice"></bean>
  • 在核心配置文件中配置织入关系,及切面
    导入aop命名空间
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
    <!--目标类交给IOC容器-->
    <bean id="accountService" class="com.lagou.service.impl.Target"></bean> 
    <!--通知类交给IOC容器-->
    <bean id="myAdvice" class="com.lagou.advice.MyAdvice"></bean>
    <aop:config> 
        <!--引入通知类-->
        <aop:aspect ref="myAdvice"> 
            <!--配置目标类的transfer方法执行时,使用通知类的before方法进行前置增强-->
            <aop:before method="before" pointcut="execution(public void com.lagou.service.impl.Target.transfer())"></aop:before>
        </aop:aspect>
    </aop:config>
</beans>
  • 编写测试代码
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml") 
class AOPTest { 

    @Autowired private Target target; 
    
    @Test public void testTransfer() throws Exception {
        target.transfer(); 
    } 
}

XML配置AOP详解

切点表达式

execution([修饰符] 返回值类型 包名.类名.方法名(参数))

  • 访问修饰符可以省略
  • 返回值类型、包名、类名、方法名可以使用星号 * 代替,代表任意
  • 包名与类名之间一个点 . 代表当前包下的类,两个点 ..
  • 表示当前包及其子包下的类
  • 参数列表可以使用两个点 .. 表示任意个数,任意类型的参数列表
<aop:config> 
    <!--抽取的切点表达式--> 
    <aop:pointcut id="myPointcut" expression="execution(* com.lagou.service..*.* (..))"> </aop:pointcut> 
    <aop:aspect ref="myAdvice"> 
        <aop:before method="before" pointcut-ref="myPointcut"></aop:before>
    </aop:aspect> 
</aop:config>

通知类型

header 1 header 2
row 1 col 1 row 1 col 2
row 2 col 1 row 2 col 2
名称 标签 说明
前置通知 <aop:before> 用于配置前置通知。指定增强的方法在切入点方法之前执行
后置通知 <aop:afterReturning> 用于配置后置通知。指定增强的方法在切入点方法之后执行
异常通知 <aop:afterThrowing> 用于配置异常通知。指定增强的方法出现异常后执行
最终通知 <aop:after> 用于配置最终通知。无论切入点方法执行时是否有异常,都会执行
环绕通知 <aop:around> 用于配置环绕通知。开发者可以手动控制增强代码在什么时候执行

注意:通常情况下,环绕通知都是独立使用的

基于注解配置AOP

  • 通知类
@Aspect
@Component
public class MyAspect {
    @Before("execution(* com.lagou..*.*(..))")
    public void before() {
        System.out.println("before...");
    }
}

  • 在配置文件中开启组件扫描和 AOP 的自动代理
<!--组件扫描--> 
<context:component-scan base-package="com.lagou"/>
<!--aop的自动代理-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>

JdbcTemplate

  JdbcTemplate是spring框架中提供的一个模板对象,是对原始繁琐的Jdbc API对象的简单封装。
核心对象

JdbcTemplate jdbcTemplate = new JdbcTemplate(DataSource dataSource);

核心方法

int update(); 执行增、删、改语句 
List<T> query(); 查询多个 
T queryForObject(); 查询一个 
new BeanPropertyRowMapper<>(); 实现ORM映射封装
  • 编写spring配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
    <context:component-scan base-package="com.lagou"/>
    <context:property-placeholder location="classpath:jdbc.properties"/>
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${jdbc.driver}"></property>
        <property name="url" value="${jdbc.url}"></property>
        <property name="username" value="${jdbc.username}"></property>
        <property name="password" value="${jdbc.password}"></property>
    </bean>
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <constructor-arg name="dataSource" ref="dataSource"></constructor-arg>
    </bean>
</beans>

事务控制

Spring的事务控制可以分为编程式事务控制和声明式事务控制。

编程式
开发者直接把事务的代码和业务代码耦合到一起,在实际开发中不用。
声明式
开发者采用配置的方式来实现的事务控制,业务代码与事务代码实现解耦合,使用的AOP思想。

事务隔离级别

设置隔离级别,可以解决事务并发产生的问题,如脏读、不可重复读和虚读(幻读)。

* ISOLATION_DEFAULT 使用数据库默认级别 
* ISOLATION_READ_UNCOMMITTED 读未提交 
* ISOLATION_READ_COMMITTED 读已提交 
* ISOLATION_REPEATABLE_READ 可重复读 
* ISOLATION_SERIALIZABLE 串行化

事务传播行为

事务传播行为指的就是当一个业务方法【被】另一个业务方法调用时,应该如何进行事务控制。


基于XML的声明式事务控制

在 Spring 配置文件中声明式的处理事务来代替代码式的处理事务。底层采用AOP思想来实现的。

声明式事务控制明确事项:

  • 核心业务代码(目标对象) (切入点是谁?)
  • 事务增强代码(Spring已提供事务管理器))(通知是谁?)
  • 切面配置(切面如何配置?)

步骤

  1. 引入tx命名空间
  2. 事务管理器通知配置
  3. 事务管理器AOP配置
  4. 测试事务控制转账业务代码
  • 引入tx命名空间
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w2.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation=" http://www.springframework.org/schema/beans 
       http://www.springframework.org/s 
       chema/beans/spring-beans.xsd 
       http://www.springframework.org/schema/context 
       http://www.springframework.org/schema/context/spring-context.xsd 
       http://www.springframework.org/schema/aop 
       http://www.springframework.org/schema/aop/spring-aop.xsd 
       http://www.springframework.org/schema/tx 
       http://www.springframework.org/schema/tx/spring-tx.xsd">
    
    
</beans>
  • 事务管理器通知配置
    <!--事务管理器-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean> 
    <!--通知增强-->
    <tx:advice id="txAdvice" transaction-manager="transactionManager"> 
        <!--定义事务的属性-->
        <tx:attributes>
            <tx:method name="*"/>
        </tx:attributes>
    </tx:advice>
  • 事务管理器AOP配置
    <!--aop配置-->
    <aop:config> 
        <!--切面配置-->
        <aop:advisor advice-ref="txAdvice" pointcut="execution(* com.lagou.serivce..*.*(..))"></aop:advisor>
    </aop:config>
  • 测试事务控制转账业务代码
@Override
    public void transfer(String outUser, String inUser, Double money) {
        accountDao.out(outUser, money); 
        // 制造异常 
        int i = 1 / 0;
        accountDao.in(inUser, money);
    }

事务参数的配置详解

<tx:method name="transfer" isolation="REPEATABLE_READ" propagation="REQUIRED" timeout="-1" read-only="false"/> 
* name:切点方法名称 
* isolation:事务的隔离级别 
* propogation:事务的传播行为 
* timeout:超时时间 
* read-only:是否只读

基于注解的声明式事务控制

常用注解

@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.REPEATABLE_READ, timeout = -1, readOnly = false)可以加在方法上或者类上
编写配置文件

     <!--省略之前datsSource、jdbcTemplate、组件扫描配置-->
     <!--事务管理器-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean> 
    <!--事务的注解支持-->
    <tx:annotation-driven/>
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,558评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,002评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,036评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,024评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,144评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,255评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,295评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,068评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,478评论 1 305
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,789评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,965评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,649评论 4 336
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,267评论 3 318
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,982评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,223评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,800评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,847评论 2 351