(六)java面试题 Struts、Spring、Hibernate、Mybatis框技术2018-06-06

1.Struts2.0有几种标签库

【参考答案】

UI标签、控制标签、数据标签、杂项标签

2.struts2必备包有哪些?

【参考答案】

commons-fileupload-1.2.1.jar

freemarker-2.3.13.jar

ognl-2.6.11.jar

struts2-core-2.1.6.jar

xwork-2.1.2.jar

3.Hiberbate优化方法有那些?

【参考答案】

1)尽量使用many-to-one,避免使用one-to-many

2)灵活使用单向one-to-many

3)不用一对一,使用多对一代替一对一

4)配置对象缓存,不使用集合缓存

5)一对多使用Bag多对一使用Set

6)继承使用显示多态HQL:from object polymorphism="exlicit"避免查处所有对象

7)消除大表,使用二级缓存

4.应用服务器与Web Server的区别

【参考答案】

Web服务器(Web Server)

Web服务器可以解析(handles)HTTP协议。当Web服务器接收到一个HTTP请求,会返回一个HTTP响应,例如送回一个HTML页面。为了处理一个请求,Web服务器可以响应一个静态页面或图片,进行页面跳转,或者把动态响应的产生委托给一些其它的程序例如CGI脚本,JSP脚本,servlets,ASP脚本,服务器端JavaScript,或者一些其它的服务器端技术。无论它们(译者注:脚本)的目的如何,这些服务器端的程序通常产生一个HTML的响应来让浏览器可以浏览。

应用程序服务器

通过各种协议,可以包括HTTP,把商业逻辑暴露给客户端应用程序。Web服务器主要是处理向浏览器发送HTML以供浏览,而应用程序服务器提供访问商业逻辑的途径以供客户端应用程序使用。应用程序使用此商业逻辑就象你调用对象的一个方法(或过程语言中的一个函数)一样。

应用程序服务器的客户端(包含有图形用户界面(GUI)的)可能会运行在一台PC、一个Web服务器或者甚至是其它的应用程序服务器上。在应用程序服务器与其客户端之间来回穿梭的信息不仅仅局限于简单的显示标记。相反,这种信息就是程序逻辑。正是由于这种逻辑取得了数据和方法调用的形式而不是静态HTML,所以客户端才可以随心所欲的使用这种被暴露的商业逻辑。

在大多数情形下,应用程序服务器是通过组件的应用程序接口把商业逻辑暴露(给客户端应用程序)的,例如基于J2EE应用程序服务器的EJB组件模型。此外,应用程序服务器可以管理自己的资源,例如,安全,事务处理,资源池,和消息。就象Web服务器一样,应用程序服务器配置了多种可扩展和容错技术。

5.如何设置Hibernate二级缓存

【参考答案】

1、首先要打开二级缓存,在hibernate.cfg.xml中添加如下配置:

true

2、Hibernate的二级缓存使用第三方的缓存工具来实现,所以我们需要指定Hibernate使用哪个缓存工具。如下配置指定Hibernate使用EhCache缓存工具。

org.hibernate.cache.EhCacheProvider

3、Hibernate在默认情况下并不会对所有实体对象进行缓存,所以,我们需要指定缓存哪些对象,在实体对象的映射文件中(相应的标签内部),添加如下配置:

usage="read-only"是“只读”缓存策略。

6.ApplicationContextBeanFactory有什么区别?

【参考答案】

BeanFactory实际上是实例化,配置和管理众多bean的容器。这些bean通常会彼此合作,因而它们之间会产生依赖,而这种依赖只是体现在Bean与Bean之间的依赖这些依赖关系可以通过配置来反映,而ApplicationContextbeans包是BeanFactory的子类,提供了以编程的方式管理和操控bean的基本功能,而context包增加了ApplicationContext,它以一种更加面向框架的方式增强了BeanFactory的功能,简单说他增强了面向Web容器的功能。ApplictionContext完全采用声明式方式来使用容器,甚至不用去手工创建它,Web应用的启动进程中用它启动ApplicationContext。当然用编程的方式创建一个ApplicationContext对象可以有以下几种方式或实现:

1、ClassPathXmlApplicationContext:从类路径中的XML文件载入上下文定义信息,把上下文定义文件当作类路径资源。

2、FileSystemXmlApplicationContext:从文件系统中的XML文件载入上下文定义信息。

3、XmlWebApplicationContext:从Web系统中的XMl文件载入上下文信息。

7.Spring MVCStruts2 MVC的不同之处?【杭州网阙科技】

【参考答案】

1、请求处理机制:spring mvc是基于方法的设计,而sturts是基于类,每次发一次请求都会实例一个action,每个action都会被注入属性,而spring基于方法,粒度更细。

2、参数传递:struts是在接受参数的时候,可以用属性来接受参数,这就说明参数是让多个方法共享的。

3、设计思想上:struts更加符合oop的编程思想,spring就比较谨慎,在servlet上扩展。

4、intercepter的实现机制:struts有以自己的interceptor机制,spring mvc用的是独立的AOP方式。这样导致struts的配置文件量还是比spring mvc大,虽然struts的配置能继承,所以我觉得论使用上来讲,spring mvc使用更加简洁,开发效率Spring MVC确实比struts2高。

8.Spring使用了哪些设计模式,这样用有什么好处?

【参考答案】

最典型的像:工厂模式,Spring的IOC容器就是一个大的Bean实例的工厂,负责Bean的周期管理。单例模式,这个和Spring的IOC一起的,既然是IOC是一个大工厂,那个Bean对象为减少内存开销就需要提供单例特征。适配器模式,在Spring的AOP编程中随处可见Adapter模式的应用。代理模式,为其它对象提供一种代理访问的机制。观察者模式,当对象发生变化时,其它对象需要得到相应更新,Spring中应用也较为普遍。

【分析】

就说上面几个了,这种问题无法一追溯,把所有Spring用到的设计模式一一回答出来,重要的是你只需要让面试官觉得你对Spring有较深的理解和应用即可。

9.Hibernate有哪几种查询数据的方法?

【参考答案】

hibernate查询有三种方式:HQL查询、结构化SQL查询、QBC查询

10.3个框架在项目在项目当中的用,BaseDao是用来做什么的。

【参考答案】

DAO组件主要提供数据库访问操作,针对不同数据源表持久化操作进行了封装,这样可以提供其它层的访问接口,使得组件之间解耦。而BaseDAO是这些所有这些不同的持久化的DAO的公共API进行了封装,进一步抽象提取,使其它各组件DAO从BaseDAO中派生,增强系统的重用性、维护性、扩展性。

11.ThreadLocal在项目中的实际意义?

【参考答案】

ThreadLocal和其它同步机制相比从另一个角度来解决多线程的并发访问,它为每一个线程维护一个和该线程绑定的变量的副本,从而隔离了多个线程的数据,每一个线程都拥有自己的变量副本,从而也就没有必要对该变量进行同步了。还提供了线程安全的共享对象,在编写多线程代码时,可以把不安全的整个变量封装进ThreadLocal

ThreadLocal可以大量减少参数的传递,可以使代码简洁,但一个线程会绑定多个自己定义的局部对象,ThreadLocal是抽象在线程上的对象创建工厂,目前的Tomcat5使用了线程池,一个线程处理一个request,这样ThreadLocal对象可以抽象的绑定在request生命周期,不会存在线程危机,而且线程池也平衡了这些ThreadLocal

12.Spring对多种ORM框架提供了很好的支持,结合事务管理描述spring从哪些方面提供了对Hibernate的支持。

【参考答案】

1、SessionFactory管理。使用Spring整合Hibernate时我们不需要hibernate.cfg.xml文件。首先,在applicationContext.xml中配置数据源(dataSource)bean和session工厂(sessionFactory)bean。

2、持入层管理。Spring提供了HibernateTemplate,用于持久层访问,无需打开Session及关闭Session。它只要获得SessionFactory的引用,将可以只读地打开Session,并在持久化访问结束后关闭Session,对持久层逻辑,通用的操作(如对数据库中数据的增,删,改,查)有HibernateTemplate完成。

3、对DAO的支持:通过继承HibernateDaoSupport实现DAO基本操作。

4、对事务支持:Spring的声明式事务和编程式事务,很好的将持久化的操作纳入事务管理。

13.Hibernatesession.save()session.saveOrUpdate()的区别?

【参考答案】

1.save()方法,调用save方法时,首先会在session缓存中查找保存对象如果实体对象已经处于Persient状态,直接返回;否则并将保存至数据库,对象变为持久状态。

2.saveOrUpdate()方法:和save方法一样首先在session缓存中查找,判断对象是否为为保存状态,如果对象处于Persient,不执行操作,处于Transient执行save操作,处于Detached调用saveOrUpdate将对象与session重新关联(简单的说就是该方法会先看该对象是否已经存在,如果已经存在就更新,否则新增保存),如果此时saveOrUpdate的对象与另一个与Session关联的对象持有相同的持久化标识则抛出相同的标识符异常。

14.Hibernatesedssion.get()session.load()的区别?

【参考答案】

Session.load/get方法均可以根据指定的实体类和id从数据库读取记录,并返回与之对应的实体对象。其区别在于:

1)如果未能发现符合条件的记录,get方法返回null,而load方法会抛出一个ObjectNotFoundException。

2)load支持延迟加载,get不支持

3)load方法可返回实体的代理类实例,而get方法永远直接返回实体类。

4)load方法可以充分利用内部缓存和二级缓存中的现有数据,get方法则仅仅在内部缓存中进行数据查找,如没有发现对应数据,将越过二级缓存,直接调用SQL完成数据读取。

15.annotation的使用方法和用途主要分为几类?

【参考答案】

1、内建Annotation——Java5.0版在java语法中经常用到的内建Annotation:

2、开发者自定义Annotation:由开发者自定义Annotation类型;

3、使用第三方开发的Annotation类型

16.Struts2是怎么实现MVC的?

【参考答案】

MVC就是model view controller,三种组件,Struts2实现Controller主要由一系列的前端过滤器(Filter)实现Controller。Model层主要由Struts2的Action组件实现。View层主要是由Struts2的标签库、Freemarker等组件实现视图层

17.介绍下hibernate【上海数字政通】

【参考答案】

Hibernate是一个开放源代码Java语言下的对象关系映射解决方案。它为面向对象的领域模型到传统的关系型数据库的映射,提供了一个使用方便的框架。Hibernate也是目前Java开发中最为流行的数据库持久层框架。将软件开发人员从大量相同的数据持久层相关编程工作中解放出来,Hibernate不仅负责从Java类到数据库表的映射(还包括从Java数据类型到SQL数据类型的映射),还提供了面向对象的数据查询检索机制,从而极大地缩短的手动处理SQL和JDBC上的开发时间。

18.Struts2中,配置文件中通配符是怎么表示和使用的?使用通配符后有什么好处。【上海咯勤】

示例1调用相同Action中的不同方法

/login.jsp

/error.jsp

/welcome.jsp

其中表达式{1}的值name属性值中第一个*的值。

如果用户请求的URL为loginAction.action,则调用Jcuckoo.LoginRegistAction中的login方法;

如果用户请求的URL为registerAction.action,则调用Jcuckoo.LoginRegistAction中的register方法

示例2:带转视图

/input.jsp

/{1}.jsp

当处理结果是input时,会转到/input.jsp页面

当处理结果是success时,

如果crud_create.action,则会执行Jcuckoo.CrudAction中的create方法,并且跳转到/create.jsp;

如果crud_delete.action,则会执行Jcuckoo.CrudAction中的delete方法,并且跳转到/delete.jsp;

优点:

使用通配符能规范命名格式,简洁配置文件,加速开发效率,也是Struts倡导的一种开发模式。

19.Hibernate中的HQLcriteria的区别?

【参考答案】

1.QBC(Query by Criteria)查询对查询条件进行了面向对象封装,符合编程人员的思维方式;

2.HQL(Hibernate Query Language)查询提供了更加丰富的和灵活的查询特性,在涵盖Criteria查询的所有功能的前提下,提供了类似标准SQL语句的查询方式,同时也提供了更加面向对象的封装。

20.介绍hibernate延持加载属性

【参考答案】

Hibernate通过lazy来指定加载策略,一般值为true或false,。设为flase表示立即加载,true表过延迟加载。

21.列举你接触过的框架,说明特点和原理

【参考答案】

Struts2的特点:自己总结一下。

Hibernate特点:

1.基于JDBC的主流持久化框架,是一个优秀的ORM实现,对JDBC访问数据库的代码做了封装,大大简化了数据访问层繁琐的重复性代码。

2. hibernate使用Java反射机制,而不是字节码增强程序来实现透明性。

3. hibernate的性能非常好,因为它是个轻量级框架。映射的灵活性很出色。它支持各种关系数据库,从一对一到多对多的各种复杂关系。

Spring特点:

Spring框架的主要优势之一低侵入式的架构思想,实现了IOC容器。另外一个AOP的编程也在很多应用场合下地位较重。提供了对各种不同类型框架的支持,如:Web容器、持入层、事务层、其它J2EE组件等。

22.解释一下IOC,以及spring的举例

【参考答案】

IOC称为控制反转,也叫依赖注入,ioc是Spring的核心组件,它通过配置文件,将需要创建的对象以池的方式管理,将实例注入到需要的对象中区,是对象依赖于注入而不依赖于实现,解决了各个组件的耦合度,使得项目在后期的维护和扩展上非常方便。如在ssh框架整合中,我们将datasource对象注入给sessionFactory,再将sessionFactory注入给dao组件,再将dao组件注入给struts的Action组件,在将action对象注入给struts的拦截器。

23.解释一下mvc以及熟悉的mvc框架

【参考答案】

MVC是Model-View-Controller的简写。Model代表的是应用的业务逻辑(通过JavaBean,EJB组件实现),View是应用的表示层(由JSP、HTML、各种Taglib等组成),Controller是提供应用程序的中心控制处理。通过这种设计模型把应用逻辑,处理过程和显示逻辑分成不同的组件实现,这些组件可以进行交互和重用,另外有利于维护。

Struts1、Struts2、Spring MVC、WebWork等这些都是属于基于MVC模式实现的框架

24.Spring工作原理

【参考答案】

内部最核心的就是IOC了,动态注入,让一个对象的创建不用new了,可以自动的生产,这其实就是利用java里的反射,反射其实就是在运行时动态的去创建、调用对象,Spring就是在运行时,跟xml  Spring的配置文件来动态的创建对象,和调用对象里的方法的还有一个核心就是AOP这个就是面向切面编程,可以为某一类对象进行监督和控制(也就是在调用这类对象的具体方法的前后去调用你指定的模块)从而达到对一个模块扩充的功能。这些都是通过配置类达到的

Spring目的:

就是让对象与对象(模块与模块)之间的关系没有通过代码来关联,都是通过配置类说明管理的(Spring根据这些配置内部通过反射去动态的组装对象)要记住:Spring是一个容器,凡是在容器里的对象才会有Spring所提供的这些服务和功能

25.Hibernate中离线查询与在线查询的区别

【参考答案】

Criteria和DetachedCriteria的主要区别在于创建的形式不一样,Criteria是在线的,所以它是由Hibernate Session进行创建的;而DetachedCriteria是离线的,创建时无需Session,DetachedCriteria提供了2个静态方法forClass(Class)或forEntityName(Name)进行DetachedCriteria实例的创建。

26.Struts2实现拦截器的原理?

【参考答案】

拦截器是AOP中的概念,它本身是一段代码,可以通过定义“织入点”,来指定拦截器的代码在“织入点”的前后执行,从而起到拦截的作用。而Struts2的Interceptor,其拦截的对象是Action代码,可以定义在Action代码之前或者之后执行拦截器的代码。

1.整个结构就如同一个堆栈,除了Action以外,堆栈中的其他元素是Interceptor

2. Action位于堆栈的底部。由于堆栈"先进后出"的特性,而这些都是围绕着Action的,当我们请求Action时,必须首先把位于Action上端的Interceptor拿出来执行。

27.Struts2的实现原理。【高达软件】

【参考答案】

1、客户端初始化一个指向Servlet容器(例如Tomcat)的请求

2、这个请求经过一系列的过滤器(Filter)(这些过滤器中有一个叫做ActionContextCleanUp的可选过滤器,这个过滤器对于Struts2和其他框架的集成很有帮助,例如:SiteMesh Plugin);

3、接着FilterDispatcher被调用,FilterDispatcher询问ActionMapper来决定这个请求是否需要调用某个Action;

4、如果ActionMapper决定需要调用某个Action,FilterDispatcher把请求的处理交给ActionProxy;

5、ActionProxy通过Configuration Manager询问框架的配置文件,找到需要调用的Action类;

6、ActionProxy创建一个ActionInvocation的实例。

7、ActionInvocation实例使用命名模式来调用,在调用Action的过程前后,涉及到相关拦截器(Intercepter)的调用。

8、一旦Action执行完毕,ActionInvocation负责根据struts.xml中的配置找到对应的返回结果。返回结果通常是(但不总是,也可能是另外的一个Action链)一个需要被表示的JSP或者FreeMarker的模版。在表示的过程中可以使用Struts2框架中继承的标签。在这个过程中需要涉及到ActionMapper

28.简述spring的事务传播行为和隔离级别

【参考答案】

spring的事务传播行为:

Spring在TransactionDefinition接口中规定了7种类型的事务传播行为,它们规定了事务方法和事务方法发生嵌套调用时事务如何进行传播:

PROPAGATION_REQUIRED:如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。这是最常见的选择。

PROPAGATION_SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行。

PROPAGATION_MANDATORY:使用当前的事务,如果当前没有事务,就抛出异常。

PROPAGATION_REQUIRES_NEW:新建事务,如果当前存在事务,把当前事务挂起。

PROPAGATION_NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。

PROPAGATION_NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。

PROPAGATION_NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作。

Spring的隔离级别

1、Serializable:最严格的级别,事务串行执行,资源消耗最大;

2、REPEATABLE READ:保证了一个事务不会修改已经由另一个事务读取但未提交(回滚)的数据。避免了“脏读取”和“不可重复读取”的情况,但是带来了更多的性能损失。

3、READ COMMITTED:大多数主流数据库的默认事务等级,保证了一个事务不会读到另一个并行事务已修改但未提交的数据,避免了“脏读取”。该级别适用于大多数系统。

4、Read Uncommitted:保证了读取过程中不会读取到非法数据。

29.Ibatis框架和Hibernate框架各有什么特点?

【参考答案】

比较方面

Ibatis框架

Hibernate框架

从设计思路来看

从关系型开始到对象型的思路来解决数据库的操作问题

从对象的角度的思路来解决数据库的操作问题

从方便性上来看

半自动

全自动

从sql语句书写来看

要写sql语句

一般不用写,但是有时候我们还是要用书写hql语句的

从映射角度来看

映射sql语句的输入输出参数

对数据库表结构来进行映射

30.为什么要用ORM?JDBC有何不一样?

【参考答案】

orm是一种思想,就是把object对象转变成数据库中的记录,或者把数据库中的记录转变成object对象,我们可以用jdbc来实现这种思想,orm的思想本质就是建立是JDBC上,对JDBC的一种封装,这种封装可以省去了直接使用jdbc的繁琐细节,提高了开发效率,现在用的较多的ORM工具很多,一般我们公司采用的ORM框架主要有hibernate和MyBatis。当然也听说一些其他orm工具,如toplink,ojb等。

31.谈谈你对SpringAOP思想的理解。

【参考答案】

AOP(Aspect-OrientedProgramming,面向方面编程),可以说是OOP(Object-Oriented Programing,面向对象编程)的补充和完善。OOP引入封装、继承和多态性等概念来建立一种对象层次结构,用以模拟公共行为的一个集合。当我们需要为分散的对象引入公共行为的时候,OOP则显得无能为力。也就是说,OOP允许你定义从上到下的关系,但并不适合定义从左到右的关系。例如日志功能,日志代码往往水平地散布在所有对象层次中,而与它所散布到的对象的核心功能毫无关系。对于其他类型的代码,如安全性、异常处理和透明的持续性也是如此。这种散布在各处的无关的代码被称为横切(cross-cutting)代码,在OOP设计中,它导致了大量代码的重复,而不利于各个模块的重用。而AOP技术则恰恰相反,它利用一种称为“横切”的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其名为“Aspect”,即方面。所谓“方面”,简单地说,就是将那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可操作性和可维护性。AOP代表的是一个横向的关系,如果说“对象”是一个空心的圆柱体,其中封装的是对象的属性和行为;那么面向方面编程的方法,就仿佛一把利刃,将这些空心圆柱体剖开,以获得其内部的消息。而剖开的切面,也就是所谓的“方面”了。然后它又以巧夺天功的妙手将这些剖开的切面复原,不留痕迹。

使用“横切”技术,AOP把软件系统分为两个部分:核心关注点和横切关注点。业务处理的主要流程是核心关注点,与之关系不大的部分是横切关注点。横切关注点的一个特点是,他们经常发生在核心关注点的多处,而各处都基本相似。比如权限认证、日志、事务处理。Aop的作用在于分离系统中的各种关注点,将核心关注点和横切关注点分离开来。

实现AOP的技术,主要分为两大类:一是采用动态代理技术,利用截取消息的方式,对该消息进行装饰,以取代原有对象行为的执行;二是采用静态织入的方式,引入特定的语法创建“方面”,从而使得编译器可以在编译期间织入有关“方面”的代码。

32.谈谈你对Spring的理解。

【参考答案】

1.Spring实现了工厂模式的工厂类(在这里有必要解释清楚什么是工厂模式),这个类名为BeanFactory(实际上是一个接口),在程序中通常BeanFactory的子类ApplicationContext。Spring相当于一个大的工厂类,在其配置文件中通过元素配置用于创建实例对象的类名和实例对象的属性。

2. Spring提供了对IOC良好支持,IOC是一种编程思想,是一种架构艺术,利用这种思想可以很好地实现模块之间的解耦。IOC也称为DI(Depency Injection)。

3. Spring提供了对AOP技术的良好封装,AOP称为面向切面编程,就是系统中有很多各不相干的类的方法,在这些众多方法中要加入某种系统功能的代码,例如,加入日志,加入权限判断,加入异常处理,这种应用称为AOP。实现AOP功能采用的是代理技术,客户端程序不再调用目标,而调用代理类,代理类与目标类对外具有相同的方法声明,有两种方式可以实现相同的方法声明,一是实现相同的接口,二是作为目标的子类在,JDK中采用Proxy类产生动态代理的方式为某个接口生成实现类,如果要为某个类生成子类,则可以用CGLI B。在生成的代理类的方法中加入系统功能和调用目标类的相应方法,系统功能的代理以Advice对象进行提供,显然要创建出代理对象,至少需要目标类和Advice类。

33.说说struts1struts2的区别。【首都信息面试题】

【参考答案】

从以下几个方面来一一总结Struts1与Struts2的区别:

Servlet依赖性

由于Action在被调用时,HttpServletRequestHttpServletResponse被传递到execute()方法中,Struts1中的Action对Servlet的API是有依赖性的.但如果在Struts2中,Action就不会对容器有依赖了,因为Action是由简单的POJO组成的.在Struts2中,servlet上下文以简单的Map的形式表现出来,这使得Action可以得到独立的测试.如果需要,Struts2也可以访问原始的请求与响应。不过,其他的框架元素减少或排除直接访问HttpServetRequest或HttpServletResponse的必要。

Action

使用抽象类而不是接口设计是Struts1设计上的问题,这已经在Struts2中得到了解决.Struts1中的Action类需要继承框架中依赖的抽象基础类.但在Struts2中,Action类可能会也可能不会实现接口来启用可选的或者自定义的服务.在Struts2中,Action是不会依赖于容器的,因为它是由简单的POJO组成的.Struts2提供了一个基础的ActionSupport类来实现一些常用的接口。尽管这样,Action接口仍然不是必须要继承的,任何含有execute方法的POJO对象都可以当作Action对象来用。

验证

Struts1与Struts2都支持通过validate方法的手动验证.Struts1使用ActionForm中的validate方法或者通过扩展Commons Validator来进行校验.然而,Struts2支持通过Validate方法与Xwork校验框架的手动验证.Xwork框架支持验证链到子属性----使用为属性类文件和校验上下文定义的验证.

线程模型

在Struts1中,Action资源一定是线程安全或者同步的.所以Action是singletons并且线程安全的,一定只有一个Action类的实例处理该Action的所有请求,singleton策略限制了Struts1的Action所能完成的,并且需要更加谨慎的开发.但是在Struts2中,Action对象对每一个请求都生成实例,所以在Struts2中不存在线程安全的问题。

易测性

测试Struts1的程序会有些复杂.测试Struts1 Action的主要它依赖容器。但是在Struts2中,Action可以经由创建Action的实例,设置属性和调用方法来得到测试。Struts2中的测试是很简单的,不依赖于容器。

获取输入

Struts1使用ActionForm来捕获输入,而且所有的ActionForm需要继承一个框架依赖的基类.由于JavaBean不能当作ActionForm来用,开发人员不得不创建冗繁的类来获取输入.不过Struts2使用Action属性(例如输入属性不依赖于底层框架)这避免了需要创建第二个输入对象,从此冗繁减少了.此外在Struts2中,Action的属性可以通过标签在web页面中得到访问,POJO表单对象和POJO Action.甚至富对象类型,包括业务或域对象,都可以被当作输入/输出对象来使用。

表达式语言

Struts1与JSTL整合,所以它使用JSTL表达式语言.Struts1的表达式语言含有遍历图表的基础对象,但是在集合和索引属性的支持上表现不好.Struts2同样支持JSTL,但是它也支持一种更强大且灵活的表达式语言----“对象图标记语言”(OGNL)

将绑定值到视图中

在视图层,Struts1使用标准的JSP来绑定对象(在模型层被处理的)到页面上下文来进行访问.然而Struts2使用一种叫做值栈的技术,这使得标签可以访问值而不需将视图与正在呈递的对象类型连接起来.值栈允许重用一些属性名相同但类型不同的视图类型.

类型转换

通常Struts1的ActionForm属性都是String型的。Struts1使用Commons-Beanutils进行类型转换,这些针对每一个类的类型转换无法为每一个实例配置。然而Struts2使用OGNL来进行类型转换.框架包含了针对基础类型,常见对象类型与原始类型的转换器。

Action的生存周期

Struts1支持对每一个模块的请求处理器的分离(生命周期),但是同一模块下的所有Action必须共享相同的生命周期。Struts2支持通过拦截器栈为每一个Action创建不同的生命周期.自定义栈可以视需要对不同的Action使用.

34.简述HibernateJDBC的优缺点?如何书写一个one to many配置文件

【参考答案】

1、封装了jdbc,简化了很多重复性代码。

2、简化了DAO层编码工作,使开发更对象化了。

3、移植性好,支持各种数据库,如果换个数据库只要在配置文件中变换配置就可以了,不用改变hibernate代码。

4、支持透明持久化,因为hibernate操作的是纯粹的(pojo)java类,没有实现任何接口,没有侵入性。

说明:

One to many配置见下题

35.Hibernate的一对多和多对一双向关联的orm配置?

【参考答案】

配置一对多

多对一

36.hibernateinverse属性的作用?

【参考答案】

在Hibernate中,术语inverse是反转的意思,在关联关系中,inverse="false"为主控方,由主控方负责维护对象的关联关系,如果设为主控方对象,主控对象更新,则负责更新另一方对象更新。

37.Spring的依赖注入是什么意思?给一个Beanmessage属性,字符串类型,注入值为"Hello"XML配置文件该怎么写?

【参考答案】

依赖注入(Dependency Injection)和控制反转(Inversion of Control)是同一个概念。具体含义是:当某一个Java类,需要另一个Java类的协助时,在传统的程序设计过程中,通常由当前类(调用者)来创建被调用者的实例,然后使用被调用者的方法。但在Spring里,创建被调用者的工作不再由调用者来完成,而是由其它类(往往是工厂类)或容器(Spring IOC容器)完成,当前调用者从其它类或容器中来获取被调用者的实例,这种方式称为控制反转;创建被调用者实例的工作通常由Spring容器来完成,然后注入调用者,因此也称为依赖注入,这是Spring的一种编程思想的体现。

依赖注入在设计模式也体现得非常多,比如说工厂模式和构建模式,这种就是一个依赖注入的实现

38.JDO是什么?

【参考答案】

JDO是Java对象持久化的新的规范,为java data object的简称,也是一个用于存取某种数据仓库中的对象的标准化API。JDO提供了透明的对象存储,因此对开发人员来说,存储数据对象完全不需要额外的代码(如JDBC API的使用)。这些繁琐的例行工作已经转移到JDO产品提供商身上,使开发人员解脱出来,从而集中时间和精力在业务逻辑上。另外,JDO很灵活,因为它可以在任何数据底层上运行。JDBC只是面向关系数据库(RDBMS)JDO更通用,提供到任何数据底层的存储功能,比如关系数据库、文件、XML以及对象数据库(ODBMS)等等,使得应用可移植性更强。

39.SpringEJB的区别?

【参考答案】

提供商无关性

EJB 3.0是一个被设计为对提供商没有依赖性的开放的标准。EJB 3.0规范由企业JAVA社区的主流开源组织和厂商共同编写和支持的。EJB 3.0框架使开发者的应用程序实现可以独立于应用服务器。而Spring一直是一个非标准的技术,尽管你在任何应用服务器都上可以使用Spring框架,但基于Spring的应用仍然被限制于Spring本身和在你的应用中使用到的Spring提供的各种特别服务。

服务整合

Spring框架是建立在应用服务器和服务库之上,它的服务整合代码(如数据访问模板和Helper类)是基于框架的,并暴露给应用开发者。相反,EJB 3.0框架是紧密整合到应用服务器中的,它的服务整合代码是封装在一个标准的接口下的。

服务聚合的灵活性

由于Spring中的服务整合代码是作为编程接口暴露给应用开发者的,因此开发人员可以根据需要来聚合多个服务。这个特性使你可以集成一个你自己的“轻量”级应用服务器。通常,EJB 3.0应用服务器不提供给开发者这种按照你的需要来选择服务的灵活性。大多数情况,你会得到一系列已经预先打包好的特性,其中有些你可能是不需要的。

声明式服务

EJB 3.0和Spring都将运行时服务(如事务管理、安全、日志、消息、和信息服务)连接给应用程序。由于这些服务同应用程序的业务逻辑并不是直接相关的,因此,它们不被应用程序本身来管理。相反,这些服务被服务容器(如EJB 3.0和Spring)以不可见的方式在运行时提供给应用程序。开发人员(或系统管理员)通过配置来告诉容器什么时候,以怎样的方式来应用这些服务。

注射依赖

Spring和EJB 3.0都提供了大量的DI模式支持。但是,它们之间也有着根本的不同。Spring支持了通常意义上的但是复杂的基于XML配置文件的注射依赖API;EJB 3.0支持的注射大多数通用服务对象(如,EJB和容器对象)和JNDI对象,它通过简单的JAVA注解来完成。

40.SSH框架的优缺点。【北京科瑞明面试题】

【参考答案】

先说说Struts:

1.struts第一个优点应该是实现了MVC。

对Servlet依赖减少,低侵入式的设计

2.Action线程安全的设计

3.功能强大的OGNL表达式使用。

4.支持多种复合视图,表现层的使用也多样化,像JSP\freeMarker\Velocity。

5.拦截器的应用,实现了AOP的思想,方便重用与扩展

6.自动类型转换功能。

7.相对低粗度的数据验证功能

Struts缺点:

Struts2中Action中取得从jsp中传过来的参数时,如果页面过于复杂,会造成对象臃肿。

Spring优点:

1、非常优秀的轻量级,低侵入式的框架。

2、IOC的容器周期式的管理,降低组件的偶合。

3、对其它容器有非常好的支持,像对持久层的Hibernate、Ibaits、TOP Link

等。

Spring缺点:

1.Web层的MVC框架单过于单薄,对页面框架的支持,跟其它框架还有很大的差距。

2.不是一站式解决方案。

3.使用了反射来管理其容器中的bean,在程序中增大了内存和运行计算的时间。

4.部分组件功能还有待完善

Hibernate的优点:

1、非常好的ORM的框架,在MVC的切分和JDBC的封装上做的很好。

缺点:

1、对复杂查询,多变的查询,完成起来有难度。

2、自动化程序高,改写灵活性不够。

2、缓存不是太高效,所以有些企业单独会选择缓存框架或者弃用Hibernate的原因之一。

41.Spring有哪几种注入方式?

【参考答案】

3种方法。构造属入、属性注入、接口注入

42.Hibernate原理

【参考答案】

1.读取并解析配置文件

2.读取并解析映射信息,创建SessionFactory

3.打开Sesssion

4.创建事务Transation

5.持久化操作

6.提交事务

7.关闭Session

8.关闭SesstionFactory

43.Spring MVC工作机制及为什么要用?【杭州网阙科技】

【参考答案】

1、客户端所有的请求都提交给DispatcherServlet,它会委托应用系统的其他模块负责负责对请求进行真正的处理工作。

2.DispatcherServlet查询一个或多个HandlerMapping,找到处理请求的Controller.

3.DispatcherServlet请请求提交到目标Controller

4.Controller进行业务逻辑处理后,会返回一个ModelAndView

5.Dispathcher查询一个或多个ViewResolver视图解析器,找到ModelAndView对象指定的视图对象

6.视图对象负责渲染返回给客户端。

44.spring中常用的几种advice

【参考答案】

BeforeAdvice(前织入)、AfterAdvice(后织入)、ArroundAdvice(前后织入)ThrowAdvice(异常织入)

45.Springbean的配置scope表示什么含义?可以有哪几种取值。

【参考答案】

scope表示Bean的生命周期或者叫Bean的作用域。scope的值有两个:

1、singleton,为单例属性,即Spring IoC容器只会创建该bean的唯一一个实例,这也是默认的。

2、prototype为原型属性,即每一次请求都会产生一个新的bean实例。

46.Hibernate对象有几种状态?如何转换

【参考答案】

共3种状态,分别是:Transient状态(瞬时)、Persient状态(持久)、Detached(脱管状态)状态。

47.springOpenSessionInViewFilter作用什么的,解决了什么问题

【参考答案】

解决Hibernate的Session的关闭与开启问题。

SSH整合问题:Hibernate允许对关联对象、属性进行延迟加载,但是必须保证延迟加载的操作限于同一个Hibernate Session范围之内进行。如果Service层返回一个启用了延迟加载功能的领域对象给Web层,当Web层访问到那些需要延迟加载的数据时,由于加载领域对象的Hibernate Session已经关闭,这些导致延迟加载数据的访问异常。而Spring为我们提供的OpenSessionInViewFilter过滤器为我们很好的解决了这个问题。OpenSessionInViewFilter的主要功能是用来把一个Hibernate Session和一次完整的请求过程对应的线程相绑定,允许在事务提交之后延迟加载显示所需要的对象。实现"Open Session in View"的模式。

【补充说明】

配置如下:

Spring OpenSessionInViewFilter

org.springframework.orm.hibernate3.support.OpenSessionInViewFilter

sessionFactoryBean

sessionFactory

Spring OpenSessionInViewFilter

/*

一般在项目中SSH整合时,我们会加入上面的配置,解决延迟加载时的异常。

48.hibernate有哪五个核心接口。

【参考答案】

Configuration接口,SessionFactory接口,Session接口,Transaction接口,Query和Criteria接口

49.Hibernate中有几种关系映射【嘉瑞互动】

【参考答案】

主要有单向一对一、单向一对多、单向多对一、单向多对多、双向一对一、双向一对多、双向多对多。

50.介绍一下Hibernate的一级缓存与二级缓存。

缓存就是把以前从数据库中查询出来和使用过的对象保存在内存中(一个数据结构中),这个数据结构通常是或类似Hashmap,当以后要使用某个对象时,先查询缓存中是否有这个对象,如果有则使用缓存中的对象,如果没有则去查询数据库,并将查询出来的对象保存在缓存中,以便下次使用。Hibernate的Session就是一种缓存,我们通常将之称为Hibernate的一级缓存,当想使用session从数据库中查询出一个对象时,Session也是先从自己内部查看是否存在这个对象,存在则直接返回,不存在才去访问数据库,并将查询的结果保存在自己内部。由于Session代表一次会话过程,一个Session与一个数据库连接相关连,所以Session最好不要长时间保持打开,通常仅用于一个事务当中,在事务结束时就应关闭。并且Session是线程不安全的,被多个线程共享时容易出现问题。通常只有那种全局意义上的缓存才是真正的缓存应用,才有较大的缓存价值,因此,Hibernate的Session这一级缓存的缓存作用并不明显,应用价值不大。

Hibernate的二级缓存就是要为Hibernate配置一种全局缓存,让多个线程和多个事务都可以共享这个缓存。一般我们叫它sessionFactory缓存,也叫进程级的缓存,使用第3方插件实现的,也值缓存实体,生命周期和sessionFactory一致,可以进行管理。

二级缓存具体实现:

首先配置第3放插件,我们用的是EHCache,在hibernate.cfg.xml文件中加入

true

在映射中也要显示的调用,

二级缓存之查询缓存:对普通属性进行缓存。如果关联的表发生了修改,那么查询缓存的生命周期也结束了。

程序中必须手动启用查询缓存:query.setCacheable(true);

51.如何在WEB里面配置SPRING【首都信息面试题】

【参考答案】

主要配置Spring  Web监听器

52.Hibernate中的Cascade属性有什么作用?

cascade属性的作用是描述关联对象进行操作时的级联特性。可以有以下几种取值:

all :所有情况下均进行关联操作。

save-update:(级联保存)表明保存或更新当前对象时会级联保存或更新他所关联的对象。

none:所有情况下均不进行关联操作。这是默认值。

delete:(级联删除)级联删除所关联的对象。

all-delete-orphan:自动删除不再和父对象关联的子对象。并且,在出现上面两种情况时执行上面两种的功能,可以说是一个全自动的属性值。

53.Struts1优缺点

【参考答案】

优点:

1)实现MVC模式,结构清晰,使开发者只关注业务逻辑的实现.

2)有丰富的tag可以用,Struts的标记库(Taglib),如能灵活动用,则能大大提高开发效率

3)页面导航

4)使系统的脉络更加清晰。通过一个配置文件,即可把握整个系统各部分之间的联系,这对于后期的维护有着莫大的好处。尤其是当另一批开发者接手这个项目时,这种优势体现得更加明显。

5)提供Exception处理机制。

6)数据库链接池管理。

7)支持I18N (国际化)

缺点

1)转到展示层时,需要配置forward,如果有十个展示层的jsp,需要配置十次struts,而且还不包括有时候目录、文件变更,需要重新修改forward,注意,每

2)Struts的Action必需是thread-safe方式,它仅仅允许一个实例去处理所有的请求。所以action用到的所有的资源都必需统一同步,这个就引起了线程安全的问题。

3)测试不方便. Struts的每个Action都同Web层耦合在一起,这样它的测试依赖于Web容器,单元测试也很难实现

4)类型的转换. Struts的FormBean把所有的数据都作为String类型,它可以使用工具Commons-Beanutils进行类型转化。但它的转化都是在Class级别,而且转化的类型是不可配置的。

5)对Servlet的依赖性过强. Struts处理Action时必需要依赖ServletRequest和ServletResponse,所有它摆脱不了Servlet容器。

6)前端表达式语言方面集成了JSTL,所以它主要使用JSTL的表达式语言来获取数据。可是JSTL的表达式语言在Collection和索引属性方面处理显得很弱。

7)对Action执行的控制困难. Struts创建一个Action,如果想控制它的执行顺序将会非常困难。

8)对Action执行前和后的处理. Struts处理Action的时候是基于class的hierarchies,很难在action处理前和后进行操作。

9)对事件支持不够.在struts中,实际是一个表单Form对应一个Action类(或DispatchAction),换一句话说:在Struts中实际是一个表单只能对应一个事件。

54.整合springstruts1的方法,那种最好,为什么?

【参考答案】

答:1.第一种方法:

Struts的Action继承Spring的ActionSupport类,并在Action中获取Spring的ApplicationContext。这是最简单的一种整合方式,但有三个缺点:第一,Struts与Spring紧密耦合,不能改换到其他IoC容器;第二,难以使用Spring AOP特性;第三,对于需要使用DispatchAction的Struts应用无能为力。

2.第二种方法:

在Struts的配置文件中,以Spring的DelegatingRequestProcessor类代替Struts的RequestProcessor类,并在Spring的配置文件中定义与Struts配置文件中对应的bean,从而将Struts的Action与Spring分开,并把Struts的动作置于Spring的控制之下。这种整合方式的优点是将不再依赖Spring这个特定的IoC容器,但必须依赖Struts的RequestProcessor类。

3.第三种方法:

通过Spring的DelegatingActionProxy类代理Struts的动作,即在Struts配置文件中,定义的type属性全部改为DelegatingActionProxy,而不是具体的类名,并在Spring配置文件中定义与Struts动作映射对应的bean,从而将Struts的Action与Spring分开,并把Struts的动作置于Spring的控制之下。无疑,这是最灵活的一种整合方式。

【分析】

注意一般说几种整合方式所指的就是Struts1

55.Struts1.2的工作原理

【参考答案】

1.ActionServlet核心控制器会拦截所有*.do的请求

2.从struts-config.xml中找到用户请求的Action

3.通过struts-config.xml中的配置再去找这个Action对应的ActionForm,并实例化

4.把用户填写的数据自动填充到ActionForm中(调用ActionForm中的setXX()方法填充)

5.同时把ActionForm放入到指定的范围中(request,session)

6.然后把请求转发给Action

7.Action获取ActionForm中的值然后调用业务逻辑层实现功能

8.在通过ActionMapping查找Actionforward实现转发;

56.谈谈Struts1中的ActionServlet

【参考答案】

中心控制器,负责所以请求处理,并根据配置文件,将请求转到指定Action执行,并根据Action的ActionForward返回,转到指定视图。

57.Struts1.XActionServletActionFormActionActionMapping各起什么作用?

【参考答案】

a.Actionservlet为控制器,接受用户请求并派发给相应的Action组件处理;

b.ActionForm主要用于封装请求中的数据和简单验证

c.Action组件具体对用户的请求进行处理

d.ActionMapping封装当前用户请求Action相关的配置信息

58.Struts 1Action类与Struts 2Action类区别?

【参考答案】

Struts 1要求Action类要扩展自一个抽象基类。Struts 1的一个共有的问题是面向抽象类编程而不是面向接口编程。

Struts 2的Action类实现了一个Action接口,连同其他接口一起实现可选择和自定义的服务。

Struts 1 Action类是单例类,因只有一个示例控制所有的请求。

Struts 2 Action对象每一个请求都实例化对象,所以没有程安全的问题。

59.谈谈你对Struts1的理解。

【参考答案】

1.struts是一个按MVC模式设计的Web层框架,其实它就是一个大大的servlet,这个Servlet名为ActionServlet,或是ActionServlet的子类。我们可以在web.xml文件中将符合某种特征的所有请求交给这个Servlet处理,这个Servlet再参照一个配置文件(通常为/WEB-INF/struts-config.xml)将各个请求分别分配给不同的action去处理。

2.ActionServlet把请求交给action去处理之前,会将请求参数封装成一个formbean对象(就是一个java类,这个类中的每个属性对应一个请求参数)

3.要说明的是,ActionServlet把formbean对象传递给action的execute方法之前,可能会调用formbean的validate方法进行校验,只有校验通过后才将这个formbean对象传递给action的execute方法,否则,它将返回一个错误页面,这个错误页面由input属性指定,(看配置文件)作者为什么将这里命名为input属性,而不是error属性,我们后面结合实际的运行效果进行分析。

4.action执行完后要返回显示的结果视图,这个结果视图是用一个ActionForward对象来表示的,actionforward对象通过struts-config.xml配置文件中的配置关联到某个jsp页面,因为程序中使用的是在struts-config.xml配置文件为jsp页面设置的逻辑名,这样可以实现action程序代码与返回的jsp页面名称的解耦。

60.Struts1中的action是安全线程么?为什么

【参考答案】

Servlet是在多线程环境下的。即可能有多个请求发给一个servelt实例,每个请求是一个线程。

struts下的action也类似,同样在多线程环境下。

为多线程环境编写代码。我们的controller servlet指挥创建你的Action类的一个实例,用此实例来服务所有的请求。因此,你必须编写线程安全的Action类。遵循与写线程安全的servlet同样的方针。

61.Struts1actionform属于哪一层

【参考答案】

属于视图层组件,负责封装页面表单数据。

62.struts控制器组件的主要包括?

【参考答案】

ActionServlet组件:充当struts框架的中央控制器。

RequestProcessor组件,充当每个子应用模块的请求处理器

Action组件,负责处理一项具体的业务。

63.常见的缓存技术举例【大唐动力面试题】

【参考答案】

操作系统磁盘缓存->减少磁盘机械操作

数据库缓存->减少文件系统I/O

应用程序缓存->减少对数据库的查询

Web服务器缓存->减少应用服务器请求

客户端浏览器缓存->减少对网站的访问

64.Spring为基础的J2EE项目中,一般如何分层?每个层的作用是什么?事务控制放在哪一层?

一般分为持久层(DAO层)、业务层(Service层)、控制层、视图层;

事务一般放在业务层,以一个业务作为一个事务分割的最小单位。

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

推荐阅读更多精彩内容