关闭

关闭

关闭

封号提示

内容

首页 Spring基础教程.pdf

Spring基础教程.pdf

Spring基础教程.pdf

上传者: trkqytr 2011-10-10 评分 0 0 0 0 0 0 暂无简介 简介 举报

简介:本文档为《Spring基础教程pdf》,可适用于IT/计算机领域,主题内容包含Spring快速入门教程开发你的第一个Spring程序翻译整理:HantsyBai<hantsytomcom>本章学习用strutsMVC框架作前端符等。

Spring快速入门教程开发你的第一个Spring程序翻译整理:HantsyBai<hantsytomcom>本章学习用strutsMVC框架作前端Spring做中间层Hibernate作后端来开发一个简单的Spring应用程序。在第章将使用SpringMVC框架对它进行重构。本章包含以下内容:编写功能性测试。配置Hibernate和Transaction。载入Spring的applicationContextxml文件。设置业务代理(businessdelegates)和DAO的依赖性。把spring写入Struts程序。概述你将会创建一个简单的程序完成最基本的CRUD(Create,Retrieve,Update和Delete)操作。这个程序叫MyUsers作为本书的样例。这是一个层架构的web程序通过一个Action来调用业务代理再通过它来回调DAO类。下面的流程图表示了MyUsers是如何工作的。数字表明了流程的先后顺序从web层(UserAction)到中间层(UserManager)再到数据层(UserDAO)然后返回。鉴于大多数读者都比较熟悉struts本程序采用它作为MVC框架。Spring的魅力在于它宣称式的事务处理依懒性的绑定和持久性的支持。第章中将用Spring框架对它进行重构。接下来你会进行以下几个步骤:下载Struts和Spring。创建项目目录和antBuild文件。为持久层创建一个单元测试(unittests)。配置Hibernate和Spring。编写HIbernateDAO的实现。进行单元测试通过DAO验证CRUD。创建一个Manager来声明事务处理。为strutsAction编写测试程序。为web层创建一个Action和model(DynaActionForm)。进行单元测试通过Action验证CRUD。创建JSP页面以通过浏览器来进行CRUD操作。通过浏览器来验证JSP页面的功能。用velocity模板替换JSP页面。使用CommonsValidator添加验证。下载Struts和Spring下载安装以下组件:•JDK(或以上)•Tomcat•Ant设置以下环境变量:•JAVAHOME•ANTHOME•CATALINAHOME把以下路径添加到PATH中:•JAVAHOMEbin•ANTHOMEbin•CATALINAHOMEbin为了开发基于java的web项目开发人员必须事先下载必需的jars,建好开发目录结构和antbuild文件。对于单一的struts项目可以利用struts中现成的strutsblankwar。对于基于SpringMVC框架的项目可以用Spring中的webappminimalwar。这只为开发作准备两者都没有进行strutsspring集成也没有考虑单元测试。为此我们为读者准备了Equinox。Equinox为开发Strutsspring式的程序提供一个基本框架。它已经定义好了目录结构和antbuild文件(针对compiling,deploying,testing)并且提供了struts,spring,Hibernate开发要用到的jars文件。Equinox中大部分目录结构和antbuild文件来自我的开源项目AppFuse。可以说Equinox是一个简化的AppFuse它在最小配置情况下为快速web开发提供了便利。由于Equinox源于AppFuse,所以在包名数据库名及其它地方都找到它的影子。这是为让你从基于Equinox的程序过渡到更为复杂的AppFuse。从http:sourcebeatcomdownloads上下载Equinox解压到一个合适的位置开始准备MyUsers的开发。创建项目目录和antbuild文件为了设置初始的目录结构把下载的Equinox解压到硬盘。建议windows用户把项目放在C:SourceUnixLinux用户放在~dev(译注:在当前用户目录建一个dev目录)中。windows用户可以设置一个HOME环境变量值为C:Source。最简单的方法是把Equinox解压到你的喜欢的地方进入equinox目录运行antnewDappanme=myusers。tips:在windows使用cygwin(wwwcygwinorg)就可以像UnixLinux系统一样使用正斜杠本书所有路径均采用正斜杠。其它使用反斜杠系统(如windows中命令行窗口)的用户请作相应的调整。现在MyUsers程序已经有如下的目录结构:Equinox包含一个简单而功能强大的buildxml,它可以用ant来进行编译布署和测试。ant中已经定义好targets,在equinox运行ant,将看到如下内容:echoAvailabletargetsare:echocompile>CompileallJavafilesechowar>PackageasWARfileechodeploy>Deployapplicationasdirectoryechodeploywar>DeployapplicationasaWARfileechoinstall>InstallapplicationinTomcatechoremove>RemoveapplicationfromTomcatechoreload>ReloadapplicationinTomcatechostart>StartTomcatapplicationechostop>StopTomcatapplicationecholist>ListTomcatapplicationsechoclean>DeletescompiledclassesandWARechonew>CreatesanewprojectEquinox支持tomcat的anttasks(任务)。这些已经集成在Equinox中解讲一下如何进行集成的有助于理解它们的工作原理。Tomcat和anttomcat中定义了一组任务可以通过Manager来安装(install),删除(remove)重载(reload)webapps。要使用这些任务可以把所有的定义写在一个属性文件中。在Eqinox的根目录下有一个名为tomcatTasksproperties包含如下内容。deploy=orgapachecatalinaantDeployTaskundeploy=orgapachecatalinaantUndeployTaskremove=orgapachecatalinaantRemoveTaskreload=orgapachecatalinaantReloadTaskstart=orgapachecatalinaantStartTaskstop=orgapachecatalinaantStopTasklist=orgapachecatalinaantListTask在buildxml定义一些任务来安装删除重新载入应用程序。<!TomcatAntTasks><taskdeffile="tomcatTasksproperties"><classpath><pathelementpath="${tomcathome}serverlibcatalinaantjar"><classpath><taskdef><targetname="install"description="InstallapplicationinTomcat"depends="war"><deployurl="${tomcatmanagerurl}"username="${tomcatmanagerusername}"password="${tomcatmanagerpassword}"path="${webappname}"war="file:${distdir}${webappname}war"><target><targetname="remove"description="RemoveapplicationfromTomcat"><undeployurl="${tomcatmanagerurl}"username="${tomcatmanagerusername}"password="${tomcatmanagerpassword}"path="${webappname}"><target><targetname="reload"description="ReloadapplicationinTomcat"><reloadurl="${tomcatmanagerurl}"username="${tomcatmanagerusername}"password="${tomcatmanagerpassword}"path="${webappname}"><target><targetname="start"description="StartTomcatapplication"><starturl="${tomcatmanagerurl}"username="${tomcatmanagerusername}"password="${tomcatmanagerpassword}"path="${webappname}"><target><targetname="stop"description="StopTomcatapplication"><stopurl="${tomcatmanagerurl}"username="${tomcatmanagerusername}"password="${tomcatmanagerpassword}"path="${webappname}"><target><targetname="list"description="ListTomcatapplications"><listurl="${tomcatmanagerurl}"username="${tomcatmanagerusername}"password="${tomcatmanagerpassword}"><target>在上面列出的target中必须定义一些${tomcat*}变量。在根目录下有一个buildproperties默认定义如下:#PropertiesforTomcatServertomcatmanagerurl=http:localhost:managertomcatmanagerusername=admintomcatmanagerpassword=admin确保admin用户可以访问Manager应用打开$CATALINAHOMEconftomcatusersxml中是否存在下面一行。如果不存在请自己添加。注意roles属性可能是一个以逗号(“,”)隔开的系列。<userusername="admin"password="admin"roles="manager">为了测试所有修改保存所有文件启动tomcat。从命令行中进行myusers目录运行antlist可以看到tomcatserver上运行的应用程序。好了现在运行antdeploy来安装MyUsers。打开浏览器在地址栏中输入http:localhost:myusers出现如图的“EquinoxWelcome”画面。下一节将写一个User对象和一个维护其持久性的HibernateDAO对象。用Sping来管理DAO类及其依赖性。最会写一个业务代理用到AOP和声明式事务处理。为持久层编写单元测试在myUsers程序使用Hibernat作为持久层。Hinbernate是一个OR映像框架用来关联java对象和数据库中的表(tables)。它使得对象的CRUD操作变得非常简单Spring结合了Hibernate变得更加容易。从Hibernate转向SpringHibernate会减少的代码。这主要是因为ServiceLocater和一些DAOFactory类的废弃spring的实时异常代替了Hibernate的检测式的异常。写一个单元测试有助于规范UserDAO接口。为UserDAO写一个JUint测试程序要完成以下几步:在testorgappfusedao下新建一个UserDAOTestjava类。它继承了同一个包中的BaseDAOTestCase其父类初始化了Spring的ApplictionContext(来自webWEBINFapplictionContextxml)以下是JUnit测试的代码。packageorgappfusedaouseyourIDEtohandleimportspublicclassUserDAOTestextendsBaseDAOTestCase{privateUseruser=privateUserDAOdao=protectedvoidsetUp()throwsException{log=LogFactorygetLog(UserDAOTestclass)dao=(UserDAO)ctxgetBean("userDAO")}protectedvoidtearDown()throwsException{dao=}publicstaticvoidmain(Stringargs){junittextuiTestRunnerrun(UserDAOTestclass)}}这个类还不能编译因为还没有UserDAO接口。在这之前来写一些来验证User的CRUD操作。为UserDAOTest类添加testSave和testAddAndRemove方法如下:publicvoidtestSaveUser()throwsException{user=newUser()usersetFirstName("Rod")usersetLastName("Johnson")daosaveUser(user)assertTrue("primarykeyassigned",usergetId()!=)loginfo(user)assertTrue(usergetFirstName()!=)}publicvoidtestAddAndRemoveUser()throwsException{user=newUser()usersetFirstName("Bill")usersetLastName("Joy")daosaveUser(user)assertTrue(usergetId()!=)assertTrue(usergetFirstName()equals("Bill"))if(logisDebugEnabled()){logdebug("removinguser")}daoremoveUser(usergetId())assert(daogetUser(usergetId()))}从这些方法中可以看到你需要在UserDAO创建以下方法:saveUser(User)removeUser(Long)getUser(Long)getUsers()(返回数据库的所有用户)在srcorgappfusedao目录下建一个名为UserDAOjava类的输入以下代码:tips:如果你使用eclipse,idea之类的IDE左边会出现在一个灯泡提示类不存在可以即时创建。packageorgappfusedaouseyourIDEtohandleimportspublicinterfaceUserDAOextendsDAO{publicListgetUsers()publicUsergetUser(LonguserId)publicvoidsaveUser(Useruser)publicvoidremoveUser(LonguserId)}为了UserDAOjava,UserDAOTestjava编译通过还要建一个Userjava类。在srcorgappfusemodel下建一个Userjava文件添加几个成员变量:id,firstName,lastName如下。packageorgappfusemodelpublicclassUserextendsBaseObject{privateLongidprivateStringfirstNameprivateStringlastName*用你熟悉的IDE来生成getters和settersEclipse中右击>Source>GenerateGettersandSetters*}注意你继承了BaseObject类它包含几个有用的方法:toString(),equlas(),hasCode(),后两个是Hibernate必须的。建好User后用IDE打开UserDAO和UserDAOTest两个类优化导入。配置Hibernate和Spring现在已经有了POJO(PlainOldJavaObject),写一个映像文件Hibernate就可能维护它。在orgappfusemodel中新建一个名为Userhbmxml文件内容如下:<xmlversion=""encoding=""><!DOCTYPEhibernatemappingPUBLIC"HibernateHibernateMappingDTDEN""http:hibernatesourceforgenethibernatemappingdtd"><hibernatemapping><classname="orgappfusemodelUser"table="appuser"><idname="id"column="id"unsavedvalue=""><generatorclass="increment"><id><propertyname="firstName"column="firstname"not="true"><propertyname="lastName"column="lastname"not="true"><class><hibernatemapping>在webWEBINF下的applictionContextxml中添加映像。打开文件找到<propertyname=mappingResources>改成如下:<propertyname="mappingResources"><list><value>orgappfusemodelUserhbmxml<value><list><property>在applictionContextxml中你可以看到数据库是怎幺工作的Hibernate和Spring是如何协作的。Eqinox会使用名为dbappfuse的HSQL数据库。它将在你的ant“db”目录下创建详细配置在“HowSpringIsConfiguredinEquinox”一节中描述。运行antdeployreload(Tomcat正在运行)在Tomcat控制台的日志中可以看到数据表正在创建。INFOSchemaExportexecute()|RunninghbmddlschemaexportINFOSchemaExportexecute()|exportinggeneratedschematodatabaseINFOConnectionProviderFactorynewConnectionProvider()|Initializingconnectionprovider:orgspringframeworkormhibernateLocalDataSourceConnectionProviderINFODriverManagerDataSourcegetConnectionFromDriverManager()|CreatingnewJDBCconnectiontojdbc:hsqldb:dbappfuseINFOSchemaExportexecute()|schemaexportcompleteTip:如果你想看到更多或更少的日志修改webWEBINFclasseslogjxml的设置。为了验证数据库已经建好运行antbrowser启动hsqlconsole。你会看到如的HSQLDatabaseManager。Equinox中spring是怎幺配置的使用Spring配置任何基于jee的web程序都很简单。至少你简单的添加Spring的ContextLoaderListener到你的webxml中。<listener><listenerclass>orgspringframeworkwebcontextContextLoaderListener<listenerclass><listener>这是一个ServletContextListener它会在启动web应用进行初始化。默认情况下它会查找webWEBINFapplictionContextxml文件你可以指定名为contextConfigLocation的<contextparam>元素来进行修改例如:<contextparam><paramname>contextConfigLocation<paramname><paramvalue>WEBINFsampleContextxml<paramvalue><contextparam><paramvalue>元素可以是以空格或是逗号隔开的一系列路径。在Equnox中Spring的配置使用了这个Listener和默认的contextConfigLocation。那幺Spring怎幺知道Hibernate的存在?这就Spring的魅力所在它让依赖性的绑定变得非常简单。请参阅applicationContextxml的全部内容:<xmlversion=""encoding=""><!DOCTYPEbeansPUBLIC"SPRINGDTDBEANEN""http:wwwspringframeworkorgdtdspringbeansdtd"><beans><beanid="dataSource"class="orgspringframeworkjdbcdatasourceDriverManagerDataSource"><propertyname="driverClassName"><value>orghsqldbjdbcDriver<value><property><propertyname="url"><value>jdbc:hsqldb:dbappfuse<value><property><propertyname="username"><value>sa<value><property><propertyname="password"><value><value><property><bean><!HibernateSessionFactory><beanid="sessionFactory"class="orgspringframeworkormhibernateLocalSessionFactoryBean"><propertyname="dataSource"><reflocal="dataSource"><property><propertyname="mappingResources"><list><value>orgappfusemodelUserhbmxml<value><list><property><propertyname="hibernateProperties"><props><propkey="hibernatedialect">netsfhibernatedialectHSQLDialect<prop><propkey="hibernatehbmddlauto">create<prop><props><property><bean><!TransactionmanagerforasingleHibernateSessionFactory(alternativetoJTA)><beanid="transactionManager"class="orgspringframeworkormhibernateHibernateTransactionManager"><propertyname="sessionFactory"><reflocal="sessionFactory"><property><bean><beans>第一bean代表HSQL数据库Spring仅仅是调用LocalSessionFactoryBeanr的setDataSource(DataSource)使之工作。如果你想用JNDIDataSource替换可以bean的定义改成类似下面的几行:<beanid="dataSource"class="orgspringframeworkjndiJndiObjectFactoryBean"><propertyname="jndiName"><value>java:compenvjdbcappfuse<value><property><bean>hibernatehbmddlauto属性在sessionFactory定义中这个属性是为了在应用启动时自动创建表也可能是update或createdrop。最后一个bean是transactionManager(你也可以使用JTAtransaction)在处理跨越两个数据库的分布式的事务处理中尤其重要。如果你想使用jtatransactionmanager将此bean的class属性改成orgspringframeworktransactionjtaJtaTransactionManager下面实现UserDAO类。用hibernate实现UserDAO为了实现HibernateUserDAO需要完成以下几步:在srcorgappfusedaohibernate(你要新建这个目录包)新建一个文件UserDAOHibernateava。这个类继承了HibernatDaoSupport类并实现了UserDAO接口。packageorgappfusedaohibernateuseyourIDEtohandleimportspublicclassUserDAOHibernateextendsHibernateDaoSupportimplementsUserDAO{privateLoglog=LogFactorygetLog(UserDAOHibernateclass)publicListgetUsers(){returngetHibernateTemplate()find("fromUser")}publicUsergetUser(Longid){return(User)getHibernateTemplate()get(Userclass,id)}publicvoidsaveUser(Useruser){getHibernateTemplate()saveOrUpdate(user)if(logisDebugEnabled()){logdebug(userIdsetto:usergetID())}}publicvoidremoveUser(Longid){Objectuser=getHibernateTemplate()load(Userclass,id)getHibernateTemplate()delete(user)}}Spring的HibernateDaoSupport类是一个方便实现HibernateDAO的超类你可以它的一些有用的方法来获得HibernateDAO或是SessionFactory。最方便的方法是getHibernateTemplate()它返回一个HibernateTempalte对象。这个模板把检测式异常(checkedexception)包装成实时式异常(runtimeexception)这使得你的DAO接口无需抛出Hibernate异常。程序还没有把UserDAO绑定到UserDAOHibernate上必须创建它们之间的关联。在Spring配置文件(webWEBINFapplictionContextxml)中添加以下内容:<beanid="userDAO"class="orgappfusedaohibernateUserDAOHibernate"><propertyname="sessionFactory"><reflocal="sessionFactory"><property><bean>这样就在你的UserDAOHibernate(从HibernateDaoSupport的setSessionFactory继承)中建了一个HibernateSessionFactory。Spring会检测一个Session(也就是它在web层是开放的)是否已经存在并且直接使用它而不是新建一个。这样你可以使用Spring流行的“OpenSessioninView”模式来载入collections。进行单元测试来验证DAO的CRUD操作在进行第一个测试之前把你的日志级别从“INFO”调到“WARN”。把logjxml(在webWEBINFclasses目录下)中<levelvalue="INFO">改为<levelvalue="WARN">。键入anttest来运行UserDAOTest。如果你有多个测试你必须用anttestDtestcase=UserDAOTest来指定要运行的测试。运行之后你会如下类似的一些日志信息。创建Manager声明事务处理(createmanageranddeclaretransactions)JEE开发中建议将各层进行分离。换言之不要把数据层(DAOs)和web层(servlets)混在一起。使用Spring,很容易做到这一点但使用“业务代理”(businessdelegate)模式,可以对这些层进一步分离。使用业务代理模式的主要原因是:大多数持久层组件执行一个业务逻辑单元把逻辑放在一非web类中的最大好处是webservice或是丰富平台客户端(richplatformclient)可以像使用servlet一样来用同一API。大多数业务逻辑都在同一方法中完成当然可能多个DAO。使用业务代理使得你可以高级业务代理层(level)使用Spring的声明式业务代理特性。MyUsers应用中UserManager和UserDAO拥有相同的一个方法。主要不同的是Manager对于web更为友好(webfriendly)它可以接受Strings,而UserDAO只能接受Longs,并且它可以在saveUser方法中返回一个User对象。这在插入一个新用户比如要获得主键是非常方便的。Manager(或称为业务代理)中也可以添加一些应用中所需要的其它业务逻辑。启动“service”层在testorgappfuseservice(你必须先建好这个目录)中新建一个UserManagerTest类这个类继承了JUnit的TestCase类代码如下:packageorgappfuseserviceuseyourIDEtohandleimportspublicclassUserManagerTestextendsTestCase{privatestaticLoglog=LogFactorygetLog(UserManagerTestclass)privateApplicationContextctxprivateUseruserprivateUserManagermgrprotectedvoidsetUp()throwsException{Stringpaths={"WEBINFapplicationContextxml"}ctx=newClassPathXmlApplicationContext(paths)mgr=(UserManager)ctxgetBean("userManager")}protectedvoidtearDown()throwsException{user=mgr=}addtestXXXmethodsherepublicstaticvoidmain(Stringargs){junittextuiTestRunnerrun(UserDAOTestclass)}在setup方法中使用ClassPathXmlApplicationContext把applicationContextxml载入变量ApplicationContext中。载入ApplictionContext有几种途径从classpath中文件系统或web应用内。这些方法将在第三章(TheBeanFactoryandHowItWorks)中描述。输入第一个测试方法的代码来验证Manager成功完成添加或是删除User对象。publicvoidtestAddAndRemoveUser()throwsException{user=newUser()usersetFirstName("Easter")usersetLastName("Bunny")user=mgrsaveUser(user)assertTrue(usergetId()!=)if(logisDebugEnabled()){logdebug("removinguser")}StringuserId=usergetId()toString()mgrremoveUser(userId)user=mgrgetUser(userId)if(user!=){fail("Userobjectfoundindatabase!")}}这个测试实际上是一个集成测试(integrationtest)而不是单元测试(unittest)。为了更接近单元测试可以使用EasyMock或是类似工具来“伪装”(fake)DAO。这样就不必关心ApplictionContext和任何依赖SpringAPI的东西。建议在测试项目依赖(Hibernate,Spring,自己的类)的内部构件包括数据库。第章讨论重构UserManagerTest,使用mock解决DAO的依赖性。为了编译UserManagerTest在srcorgappfuseservice中新建一个接口UserManager。在orgappfuseservice包中创建这个类代码如下:packageorgappfuseserviceuseyourIDEtohandleimportspublicinterfaceUserManager{publicListgetUsers()publicUsergetUser(StringuserId)publicUsersaveUser(Useruser)publicvoidremoveUser(StringuserId)}建一个名为orgappfuseserviceimpl的子包新建一个类实现UserManager接口的。packageorgappfuseserviceimpluseyourIDEtohandleimportspublicclassUserManagerImplimplementsUserManager{privatestaticLoglog=LogFactorygetLog(UserManagerImplclass)privateUserDAOdaopublicvoidsetUserDAO(UserDAOdao){thisdao=dao}publicListgetUsers(){returndaogetUsers()}publicUsergetUser(StringuserId){Useruser=daogetUser(LongvalueOf(userId))if(user==){logwarn("UserId'"userId"'notfoundindatabase")}returnuser}publicUsersaveUser(Useruser){daosaveUser(user)returnuser}publicvoidremoveUser(StringuserId){daoremoveUser(LongvalueOf(userId))}}这个类看不出你在使用Hibernate。当你打算把持久层转向一种不同的技术时这样做很重要。这个类提供一个私有dao成员变量和setUserDAO方法一样。这样能够让Spring能够表演“依赖性绑定”魔术(perform“dependencybinding”magic)把这些对象扎在一起。在使用mock重构这个类时你必须在UserManager接口中添加serUserDAO方法。在进行测试之前配置Spring,让getBeans返回一个UserManagerImpl类。在webWEBINFapplicationContextxml文件中添加以下几行:<beanid="userManager"class="orgappfuseserviceUserManagerImpl"><propertyname="userDAO"><reflocal="userDAO"><property><bean>唯一的问题你还没有使Spring的AOP,特别是声明式的事务处理发挥作用。为了达到目的使用ProxyFactoryBean代替userManager。ProxyFactoryBean是一个类的不同的实现这样AOP能够解释和覆盖调用的方法。在事务处理中使用TransactionProxyFactoryBean代替UserManagerImpl类。在context文件中添加下面bean的定义:<beanid="userManager"class="orgspringframeworktransactioninterceptorTransactionProxyFactoryBean"><propertyname="transactionManager"><reflocal="transactionManager"><property><propertyname="target"><reflocal="userManagerTarget"><property><propertyname="transactionAttributes"><props><propkey="save*">PROPAGATIONREQUIRED<prop><propkey="remove*">PROPAGATIONREQUIRED<prop><propkey="*">PROPAGATIONREQUIRED,readOnly<prop><props><property><bean>从这个xml代码片断中可以看出TransactionProxyFactoryBean必须有一个transactionManager属性设置和transactionAttributes定义。让事务处理代理服务器(TransactionProxy)知道你要模仿的对象:userManagerTarget。作为新bean的一部分把原来的userManagerbean改成拥有一个userManagerTarget的id属性。编辑applictionContextxml添加userManager和userManagerTarget的定义后运行anttestDtestcase=UserManager,看看终端输出:如果你想看看事务处理的执行和提交情况在logjxml中添加:<loggername="orgspringframeworktransaction"><levelvalue="DEBUG"><!INFOdoesnothing><logger>重新运行测试将看到大量日志信息如它相关的对象事务的创建和提交等。测试完毕最好删除上面的日志定义(logger)。祝贺你!你已经实现了一个web

用户评论(0)

0/200

精彩专题

上传我的资料

每篇奖励 +2积分

资料评价:

/41
1下载券 下载 加入VIP, 送下载券

意见
反馈

立即扫码关注

爱问共享资料微信公众号

返回
顶部