spring roo

入门

在“ Spring Roo简介”系列的第1部分和第2部分中 ,我们使用Spring Roo从头开始构建了完整的企业应用程序。 前两篇文章重点介绍了使用Spring Roo的快速应用程序开发环境构建Web应用程序。 我们介绍了许多功能,例如JPA,Selenium测试,Spring Security,电子邮件集成,Spring Roo社交功能,数据库逆向工程等。现在,我们来看看Spring Roo的附加体系结构。 然后,我们将使用addon create命令编写Spring Roo附加组件。 到本文结尾,您将能够快速轻松地为Spring Roo创建自己的加载项。

Spring Roo附加架构

附件是最简单的形式,它是一种软件组件,可以为软件应用程序添加特定功能。 例如,在大多数Web浏览器中,视频支持是由附加组件提供的。 另一个例子是Eclipse(许多Java™开发人员使用或至少知道的开源IDE)。 大多数的功能是由加载项规定,如JUnit支持,SVN支持等我使用附加作为插件和扩展的总称。

Spring Roo也有附加组件的概念:

  1. 使第三方开发人员能够创建扩展Spring Roo功能的功能
  2. 为了帮助Spring Roo轻松添加新功能
  3. 为了帮助Spring Roo保持一些精灵(即减小Spring Roo的大小)

Spring Roo逻辑组件

Spring Roo分为两个逻辑部分。

Spring Roo核心组件:为了实现附加组件开发,Spring Roo提供了一组核心组件,这些组件形成了用于不同附加组件的托管执行环境。 这些组件是类路径,它支持流程管理器和命令行管理程序。 反过来,Process Manager支持项目和文件撤消。 该项目支持模型,元数据和文件监视器。 最后,还有支持组件,所有人都可以使用。 图1提供了这些关系的直观表示。

图1. Spring Roo核心组件

让我们来谈谈一些核心模块:

  • 支持 org.springframework.roo.support模块提供了所有核心模块和附加组件使用的通用实用程序类。 一些实用工具类包括AssertFileCopyUtilsXmlUtilsStringUtilsFileUtils等。例如,如果你想一个文件的内容复制到另一个文件,你可以使用FileCopyUtils来为你做它。
  • 元数据 -org.springframework.roo.metadata模块提供元数据服务提供者接口和实现,其中包括依赖项注册和缓存。
  • 文件监视器 -org.springframework.roo.file.monitor模块在检测到文件系统更改后发布事件(默认实现使用自动缩放的磁盘轮询)。
  • 文件撤消 — org.springframework.roo.file.undo模块提供了文件撤消功能,供流程管理器使用。
  • 项目 — org.springframework.roo.project模块抽象了典型的最终用户项目构建系统,例如Apache Maven和Apache Ant。
  • 流程管理器 — org.springframework.roo.process.manager模块提供类似于ACID的文件系统抽象,包括磁盘回滚和流程同步。
  • 类路径 — org.springframework.roo.classpath模块执行Java和AspectJ编译单元的抽象语法树解析和类型绑定。

Spring Roo核心组件: Spring Roo通过附加组件提供所有功能。 Roo V1.1.3附带的基本附加组件:

  • 附加组件创建 — org.springframework.roo.addon.creator附加组件可轻松创建第三方Roo附加组件。
  • 备份 — org.springframework.roo.addon.backup附加组件允许通过键入backup来对ZIP文件进行备份。
  • Cloud Foundry -org.springframework.roo.addon.cloud.foundry附加组件提供VMware Cloud Foundry支持。
  • 可配置的 — org.springframework.roo.addon.configurable附加组件支持通过AspectJ ITD引入Spring的@Configurable注释。
  • 数据库逆向工程 — org.springframework.roo.addon.dbre附加组件为现有数据库的增量逆向工程提供支持。
  • 按需数据 — org.springframework.roo.addon.dod附加组件为自动创建用于集成测试的样本数据提供支持。
  • 电子邮件 -org.springframework.roo.addon.email附加组件为目标项目中Spring电子邮件支持的集成和配置提供支持。
  • 实体 -org.springframework.roo.addon.entity附加组件为自动维护Java Persistence API @Entity类提供了广泛的支持。
  • 动态查找器 -org.springframework.roo.addon.finder创建与类型安全的代码完成兼容的JPA查询语言查找器。
  • Git — org.springframework.roo.addon.git附加组件为项目中的GIT集成提供支持。 每个成功执行的命令将自动提交到本地GIT存储库。
  • GWT — org.springframework.roo.addon.gwt附加组件为使用Google Web Toolkit的UI支架提供支持。
  • JavaBean — org.springframework.roo.addon.javabean附加组件自动维护带有@RooJavaBean批注的类的JavaBean获取器/设置器。
  • JDBC — org.springframework.roo.addon.jdbc附加组件封装了OSGi兼容的对不同捆绑包(主要由其他附加组件使用)中提供的JDBC驱动程序的访问。
  • JMS — org.springframework.roo.addon.jms附加组件提供了对在目标项目中配置Java Messaging System设置的支持。
  • JPA — org.springframework.roo.addon.jpa附加组件将安装指定的JPA提供程序并相应地设置JDBC。
  • JSON — org.springframework.roo.addon.json附加组件将与JSON相关的序列化和反序列化方法添加到POJO。
  • 日志记录 — org.springframework.roo.addon.logging附加组件设置Log4j,包括基于命令的日志级别配置。
  • 复数形式 — org.springframework.roo.addon.plural附加组件提供名词的复数形式(主要由其他附加组件使用)。
  • 属性编辑器 — org.springframework.roo.addon.property.editor附加组件根据Spring MVC的要求管理属性编辑器。
  • 属性文件 — org.springframework.roo.addon.propfiles附加组件为目标项目中属性文件的管理提供支持。
  • RooBot客户端 -org.springframework.roo.addon.roobot.client插件为通过RooBot服务器的插件管理提供支持。
  • 安全性 -org.springframework.roo.addon.security附加组件设置了Spring Security,包括登录页面,过滤器和依赖项。
  • 可序列化 -org.springframework.roo.addon.serializable附加组件将java.io.Serializable支持(例如UID维护)添加到请求的Java类型。
  • Solr — org.springframework.roo.addon.solr附加组件为目标项目中Apache Solr功能的配置和集成提供支持。
  • 集成测试 — org.springframework.roo.addon.test附加组件为项目实体生成JUnit集成测试。
  • ToString — org.springframework.roo.addon.tostring附加组件会为带有@RooToString批注的任何类生成有效的toString()方法。
  • WebFlow — org.springframework.roo.addon.web.flow附加组件为目标项目中Spring Web Flow功能的配置和集成提供支持。
  • Web MVC控制器 — org.springframework.roo.addon.web.mvc.controller附加组件为目标项目中Spring MVC控制器的配置和集成提供支持。
  • 嵌入式Web MVC — org.springframework.roo.addon.web.mvc.embedded插件提供了对MVC插件的扩展,该插件允许将嵌入式功能(如地图,视频等)添加到网页中。
  • Web MVC JSP — org.springframework.roo.addon.web.mvc.jsp附加组件在目标项目中配置和集成Spring MVC JSP功能。
  • Selenium — org.springframework.roo.addon.web.selenium附加组件在目标项目中提供Selenium Web测试的配置和集成。

现在,我们已经了解了Spring Roo提供的Spring Roo核心组件和基本附加组件,让我们编写我们自己的附加组件。

OSGi运行时环境

Spring Roo基于OSGi,它是Roo的附加架构的理想选择。 OSGi为开发模块化和嵌入式面向服务的应用程序提供了非常好的基础结构。

Roo外壳程序使用Apache Felix作为其OSGi运行时框架,以及用于组件管理的服务组件运行时(SCR)和用于包解析的OSGi捆绑存储库(OBR)。 Roo shell中提供了各种OSGi命令,您可以通过键入help osgi看到它们,如清单1所示。

清单1. OSGi的Roo帮助
roo> help osgi
* osgi find - Finds bundles by name
* osgi framework command - Passes a command directly
through to the Felix shell infrastructure
* osgi headers - Display headers for a specific bundle
* osgi install - Installs a bundle JAR from a given URL
* osgi log - Displays the OSGi log information
* osgi obr deploy - Deploys a specific OSGi Bundle Repository (OBR) bundle
* osgi obr info - Displays information on a specific OSGi Bundle Repository (OBR) bundle
* osgi obr list - Lists all available bundles from the
OSGi Bundle Repository (OBR) system
* osgi obr start - Starts a specific OSGi Bundle Repository (OBR) bundle
* osgi obr url add - Adds a new OSGi Bundle Repository (OBR) repository file URL
* osgi obr url list - Lists the currently-configured
OSGi Bundle Repository (OBR) repository file URLs
* osgi obr url refresh - Refreshes an existing
OSGi Bundle Repository (OBR) repository file URL
* osgi obr url remove - Removes an existing
OSGi Bundle Repository (OBR) repository file URL
* osgi ps - Displays OSGi bundle information
* osgi resolve - Resolves a specific bundle ID
* osgi scr config - Lists the current SCR configuration
* osgi scr disable - Disables a specific SCR-defined component
* osgi scr enable - Enables a specific SCR-defined component
* osgi scr info - Lists information about a specific SCR-defined component
* osgi scr list - Lists all SCR-defined components
* osgi start - Starts a bundle JAR from a given URL
* osgi uninstall - Uninstalls a specific bundle
* osgi update - Updates a specific bundle
* osgi version - Displays OSGi framework version

Spring Roo附加组件创建命令

Spring Roo捆绑了用于创建不同类型加载项的加载项创建命令。 公开addon create命令的addon create也是Roo插件。 Roo当前支持四种类型的加载项:

  1. 国际化附加组件 —它支持为Roo的Spring MVC支架应用程序添加语言翻译(例如,为北印度语添加翻译)。
  2. 简单加载项 -简单加载项支持对项目依赖项或配置或两者进行少量添加(例如,进行一些maven pom.xml修改,例如添加一些JAR或Maven插件)。
  3. Advanced Add-on高级插件)—该插件完成繁重的工作,用于构建需要Java代码创建的成熟的Spring Roo插件(构建可以为您的域对象编写equalshashcode方法的插件,例如)。 这些功能已经有一个社区附加组件。
  4. 包装程序附件—该附件包装Maven工件以创建与OSGi兼容的捆绑软件。 当插件需要依赖项来完成其功能时,这是必需的。 例如,Spring Roo数据库反向工程附加组件需要Postgres JDBC驱动程序来完成其任务,因此您将使用该附加组件包装Postgres JDBC驱动程序。

这些附加组件通过创建新的附加组件来创建命令以简化Roo附加组件的开发:

  • 与Google Code SVN源代码控件集成。
  • 托管在公共Maven存储库中,该存储库是Google代码项目的一部分。
  • 兼容RooBot,这是VMware托管的服务,用于索引公共Roo OBR文件中的重要内容。 OBR文件是捆绑包元数据的基于XML的表示形式。 为了与RooBot兼容,附加组件应为:
    1. 符合OSGi。
    2. PGP签名的带有公共密钥的工件。
    3. 通过httppgp://协议注册。

使用Roo addon create命令,您将获得上面提到的所有功能,并自动为您的插件配置了这些功能。 这无疑减少了创建附加组件并将其发布到外部世界的时间。

在我们开始编写附加组件之前,请确保您具有正常运行的Spring Roo环境。 安装Spring Roo的说明可以在本系列的第1部分中找到。

我需要印地语支持(i18N附加组件创建)

使用Spring Roo创建基于Spring MVC的Web应用程序时,可以使用web mvc language命令添加对不同语言的支持。 开箱即用,Spring Roo支持英语,德语,西班牙语,意大利语,荷兰语和瑞典语。 Web MVC JSP加载项提供了国际化支持,只有在webapp目录中具有JSPX文件后,该支持才启用。 JSPX文件由控制器命令生成,该命令将基于JAR的简单应用程序转换为Spring MVC Web应用程序。

作为印度人,我想在我的Web应用程序中增加对印地语的支持。 Spring Roo提供了一个addon create i18n命令,该命令提供了对web mvc install language command的扩展,从而增加了对诸如Hindi之类的新语言的支持。 它唯一需要的是用所需的语言翻译messages.properties文件。

当Spring Roo创建Spring MVC Web应用程序时,它会创建两个属性文件:application.properties和messages.properties。 application.properties文件包含特定于应用程序的属性,例如应用程序名称。 messages.properties文件包含并非特定于任何应用程序的属性,例如消息“您确定要删除此项目吗?”。 单击“删除”按钮或诸如登录,注销之类的消息时,因此,当您编写i18n附加组件时,必须为messages.properties文件提供翻译。

既然我们已经讨论了Spring Roo中的默认国际化支持,那么让我们来编写一个可以添加印地语支持的i18n附加组件。 我将展示如何在Google代码上设置项目,如何使用命令编写附加组件,将其发布并发布到外界,最后如何在RooBot服务中进行注册。 向RooBot服务注册非常重要,因为这将使RooBot索引您的加载项,并在其他开发人员使用addon search命令进行搜索时显示。

项目设置

Spring Roo文档雄辩地解释了如何在Google代码上设置您的项目和Maven存储库,因此我不再重复。 我将注意到我将使用项目名称“ roo-hind-addon”。

创建一个i18N附加组件

设置项目后,将有一个名为roo-hindi-addon的空目录。 进入该目录并键入roo command 。 进入外壳后,键入addon create i18n 。 如果按Tab键,将看到此命令具有七个属性。 在这七个属性中,三个属性是必需的: topLevelPackage (新加载项的顶级软件包), locale (意大利语的局部缩写,如“ it”)和messageBundle (message_xx.properties的完全限定路径,其中xx是语言环境名称)。 其他四个是可选属性: languagelanguage全名), flagGraphic (xx.png文件的完整路径,其中xx是标志的名称), description (附加组件的描述)和projectName (名称为项目(如果未提供,则使用顶级包名称)。 我建议您使用projectName属性,并确保其值是在Google代码上托管的项目的名称。 因此,在我们的情况下,它将是roo-hindi-addon。

在上面提到的属性中,最重要的是messageBundle ,它指定了转换后的messages.properties文件。 要将messages.properties转换为印地语,最简单的选择是使用Google翻译之类的服务,将每个属性一个接一个地转换,然后将其写入messages_hi.properties文件。 但是,这在我们的情况下不起作用,因为Java属性文件使用ISO-8859-1编码,该编码不支持印地语字符。 为了克服这个问题,我使用了一个名为Eclipse ResourceBundle Editor的Eclipse插件,该插件可让您转换和创建不同语言的资源包。 将messages.properties文件转换为messages_hi.properties文件不在本文讨论范围之内。 ResourceBundle编辑器插件易于使用。 请注意,如果支持语言字符,则不需要使用ResourceBundle编辑器。 messages_hi.properties文件将类似于清单2。

清单2. messages_hi.properties文件的样本
button_cancel = \u0930\u0926\u094D\u0926
button_end = \u0905\u0902\u0924
button_find = \u0916\u094B\u091C\u0947\u0902
button_home = \u0918\u0930
...

查看完整文件 。 拥有已翻译的messages_hi.properties文件后,您就可以通过键入单个命令来创建附加组件。 您可以通过在清单3中输入Roo shell中的命令来创建Hindi附加组件。

清单3.创建Hindi附加组件的命令
addon create i18n --locale hi --topLevelPackage org.xebia.roo.addon.i18n.hindi --messageBundle <location to messages_hi.properties> \
--language hindi --projectName roo-hindi-addon --flagGraphic <full path to flag hi.png>

清单4显示了addon create i18n命令addon create i18n的工件。

清单4.创建的工件
Created ROOT/pom.xml
Created ROOT/readme.txt
Created ROOT/legal
Created ROOT/legal/LICENSE.TXT
Created SRC_MAIN_JAVA
Created SRC_MAIN_RESOURCES
Created SRC_TEST_JAVA
Created SRC_TEST_RESOURCES
Created SRC_MAIN_WEBAPP
Created SRC_MAIN_RESOURCES/META-INF/spring
Created ROOT/src/main/assembly
Created ROOT/src/main/assembly/assembly.xml
Created SRC_MAIN_RESOURCES/org/xebia/roo/addon/i18n/hindi
Created SRC_MAIN_RESOURCES/org/xebia/roo/addon/i18n/hindi/messages_hi.properties
Created SRC_MAIN_RESOURCES/org/xebia/roo/addon/i18n/hindi/hi.png
Created SRC_MAIN_JAVA/org/xebia/roo/addon/i18n/hindi
Created SRC_MAIN_JAVA/org/xebia/roo/addon/i18n/hindi/HindiLanguage.java

该命令生成了一个Maven项目,可以通过File> Import> Maven> Existing Maven项目将其导入Eclipse(使用m2eclipse)或SpringSource Tool Suite。 您不需要导入该项目,因为我们不需要修改加载项。

现在,我们可以安装此加载项,并在我们的项目中使用它,并将其发布到外界。 但是首先,让我们讨论一些工件,以便对生成的代码有更多的了解:

  • pom.xml —这是标准的Maven项目配置。 生成的pom.xml具有各种预先配置的插件,这些插件与使用PGP签名工件,使用Maven发行插件释放插件以及使用Maven捆绑软件插件创建OSGi捆绑软件有关。 它还将OSGi和Felix依赖项添加到项目中,这些附件是插件在Roo shell中运行所必需的。
  • assembly.xml —这定义了Maven程序插件用于打包加载项的配置。
  • messages_hi.properties —这是我们在创建附件时提供的消息束文件,该文件被复制到资源文件夹中。
  • hi.png —这是我们在创建附件时提供的标志PNG文件,该文件已复制到资源文件夹。
  • HindiLanguage.java —这是此附加组件创建的唯一Java文件,用于获取与特定语言相对应的信息。 例如,它给出了本地名称,消息束资源文件等。

在我们的应用程序中添加印地语支持

现在,我将向您展示如何使用我们刚刚创建的附加组件将Hindi支持添加到您的应用程序中:

  1. 退出Roo Shell并运行mvn clean install命令。 在构建过程中,它将要求您提供GPG密码。
  2. Roo附加组件构建完成后,打开新命令行并创建一个名为i18n-hindi-client的目录。 我们将为插件创建一个简单的客户端。
  3. 输入i18n-hindi-client目录,然后键入roo命令。
  4. 在Roo Shell中执行以下命令。 这将创建一个简单的Spring MVC Web应用程序。
    清单5. Roo命令创建MVC Web应用程序
    project --topLevelPackage com.shekhar.roo.i18n.client \
    --projectName i18n-hindi-client
    persistence setup --provider HIBERNATE --database HYPERSONIC_IN_MEMORY
    entity --class ~.domain.MyUser
    field string --fieldName name --notNull
    controller all --package ~.web
  5. 键入以下命令并按tab键: web mvc language --code de en es it nl sv

    您将看不到印地语支持。 这是因为我们尚未安装印地文附加组件。

  6. 要安装加载项,请键入:
    osgi start --urlfile:/// <location to addon target folder>/org.xebia.roo.addon.i18n.hindi-0.1.0.BUILD-SNAPSHOT.jar

    这应该安装并激活我们的Spring Roo Hindi附加组件。 您可以使用osgi ps命令查看加载项的状态,该命令显示OSGi捆绑软件信息及其状态,如下所示:

    [ 95] [Active ] [ 1] roo-hindi-addon (0.1.0.BUILD-SNAPSHOT)
  7. 再次,键入web mvc language –code ,然后按Tab键。 这次,您将看到印地语语言的代码。 选择hi代码,印地语支持将添加到您的应用程序中。
    web mvc language –code hi
  8. 退出Roo Shell,然后键入mvn tomcat:run 。 您将在页脚中看到印度国旗。 单击该标志,您的应用程序将显示在印地语中,如图2所示。
    图2.印地语支持

一旦测试完该插件在您的开发系统中可以正常工作,就可以将该插件推送到我们创建的Google代码项目中。

引擎盖下

既然已经看到了我们创建的插件,那么让我们看一下如何将Hindi语言提供给应用程序:

  1. 使用osgi start命令启动了roo-hindi-addon。
  2. 当附加组件启动时,由addon create i18n command创建的HindiLanguage类将向i18nComponent注册,i18nComponent是用于注册和注销i18n附加组件的OSGi服务侦听器。 HindiLanguage类标记有@Component@Service批注,它们由Apache Felix提供。 这些注释确保组件和服务已在Roo Shell中注册并可以使用。
  3. 当我们键入web mvc install language –code命令并按下Tab键时,选项卡完成服务将调用i18nComponent类的getSupportedLanguages()方法,该方法返回i18n附加组件的java.util.Set 。 由于HindiLanguage已在i18nComponent中注册,因此也将其返回。

将加载项发布到外部世界

将附加组件发布到外界很容易,因为Roo create命令通过安装所有必需的Maven插件为我们完成了大部分工作。 转到项目根目录,然后输入清单6中的命令。

清单6.发布Roo项目
svn add pom.xml src/ legal/ readme.txt
svn commit -m "Roo Hindi Addon first version"
mvn release:prepare release:perform

Maven发行插件将要求发行版本,标签名称和开发版本。 您可以选择默认值,然后继续进行。 需要花费几分钟才能将工件发布并发布到Google代码项目。 然后,您可以在Google代码项目中查看附加项目。

在RooBot中注册您的附件

释放插件后,可以将其通过电子邮件发送至s2-roobot@vmware.com,以注册您的附加存储库。 电子邮件主题行必须包含repository.xml文件。 例如,对于我们刚刚创建的加载项,repository.xml是http://code.google.com/p/roo-hindi-addon/source/browse/repo/repository.xml 。 有关在RooBot中注册的更多信息,请参阅Spring Roo文档 。

我想监视我的Java应用程序(简单的附加组件创建)

要监视Java应用程序以确定应用程序性能瓶颈,这是许多企业应用程序中的普遍要求。 我也有相同的要求,所以我决定考虑一些可用的开源解决方案。 Java Application Monitor(JAMon)是一种免费的,高性能,线程安全的Java API,可让您轻松监视生产应用程序。

要在Web应用程序中添加JAMon支持:

  1. 您必须在pom.xml中添加jamon JAR。
  2. 您必须在应用程序上下文文件中定义JamonPerformanceMonitorInterceptor bean。 示例bean定义类似于清单7中的代码。
清单7. JamonPerformanceMonitorInterceptor代码
<bean id="jamonPerformanceMonitorInterceptor" class=\
"org.springframework.aop.interceptor.JamonPerformanceMonitorInterceptor"> <property name="trackAllInvocations" value="true"></property> <property name="useDynamicLogger" value="true"></property> </bean> <bean id="autoProxyCreator" class=\
"org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"> <property name="interceptorNames"> <list> <idref bean="jamonPerformanceMonitorInterceptor" /> </list> </property> <property name="beanNames"> <list> <value>speakerController</value> <value>talkController</value> </list> </property> </bean>

这不是一个简单的bean定义,任何开发人员都可以轻松记住,而且我认为如果可以自动化此样板配置,那就太好了。 因此,我决定编写一个插件,该插件可以自动添加JAMon依赖项和连接拦截器Bean。 您如何确定是否需要简单或高级加载项?

  1. 要添加Maven依赖项,添加配置工件或将两者都添加到项目中时,请使用简单的附件
  2. 当您需要编写可增强现有Java类型的功能强大的附件,引入新的Java类型和AspectJ ITD或同时执行两个项目时,请使用高级附件。

我们的要求是将jamon.jar添加到类路径并编写一个包含我们的bean定义的应用程序上下文文件。 最好编写一个新的Spring应用程序上下文文件,而不是使用现有的上下文文件,因为它有助于模块化应用程序上下文。 根据这些要求,很明显,我们应该编写一个简单的附件,可以将JAMon支持添加到任何Web应用程序中。

项目设置

我们需要像国际化附加组件一样为项目进行设置。 我将这个项目命名为“ spring-roo-addon-jamon”。

创建一个简单的附加组件

设置项目后,将有一个名为spring-roo-addon-jamon的目录,仅包含.svn文件夹。 进入spring-roo-addon-jamon目录并启动Spring Roo shell。 然后,键入以下命令:

addon create simple --topLevelPackage org.xebia.roo.addon.jamon \
--projectName spring-roo-addon-jamon

而已! 加载项已创建。

安装生成的加载项

您可以使用以下命令安装加载项:

osgi start --url file://<Location to addontarget folder>/org.xebia.roo.addon.jamon-0.1.0.BUILD-SNAPSHOT.jar

一旦安装了附加组件,就可以像创建用于测试i18n附加组件那样创建一个简单的客户端。 生成的附加组件提供两个命令:

  1. say hello ,在Roo shell上打印欢迎消息的命令。 该命令将始终可用,并且您可以在Roo Shell运行时随时输入该命令。
  2. web mvc install tags MVC web mvc install tags将替换您在脚手架Web应用程序时生成的默认MVC标签。 只有创建了Web应用程序后,此命令才可用。

查看生成的代码

现在您已经测试了该插件,让我们看一下该插件生成的文件,如清单8所示。

清单8.为spring-roo-addon-jamon生成的文件
Created ROOT/pom.xml
Created ROOT/readme.txt
Created ROOT/legal
Created ROOT/legal/LICENSE.TXT
Created SRC_MAIN_JAVA
Created SRC_MAIN_RESOURCES
Created SRC_TEST_JAVA
Created SRC_TEST_RESOURCES
Created SRC_MAIN_WEBAPP
Created SRC_MAIN_RESOURCES/META-INF/spring
Created SRC_MAIN_JAVA/com/shekhar/roo/addon/jamon
Created SRC_MAIN_JAVA/com/shekhar/roo/addon/jamon/JamonCommands.java
Created SRC_MAIN_JAVA/com/shekhar/roo/addon/jamon/JamonOperations.java
Created SRC_MAIN_JAVA/com/shekhar/roo/addon/jamon/JamonOperationsImpl.java
Created SRC_MAIN_JAVA/com/shekhar/roo/addon/jamon/JamonPropertyName.java
Created ROOT/src/main/assembly
Created ROOT/src/main/assembly/assembly.xml
Created SRC_MAIN_RESOURCES/com/shekhar/roo/addon/jamon
Created SRC_MAIN_RESOURCES/com/shekhar/roo/addon/jamon/info.tagx
Created SRC_MAIN_RESOURCES/com/shekhar/roo/addon/jamon/show.tagx

工件pom.xml,assembly.xml,LICENSE.TXT和readme.txt与i18n附加组件生成的相同。 我们在上面讨论了它们,因此在这里我不再谈论它们。 JamonCommands,JamonOperations,JamonOperationsImpl和JamonPropertyName更受关注。 让我们逐一讨论它们,以了解由简单的附加命令生成的代码。

  1. JamonCommands.java:JamonCommands —这是一个实现名为CommandMarker的标记器接口并公开两个命令的类,例如hello和web mvc install标签,如清单9所示。

    清单9.从JamonCommands.java:JamonCommands生成的代码
    @Component
    @Service
    public class JamonCommands implements CommandMarker { @Reference private JamonOperations operations; @Reference private StaticFieldConverter staticFieldConverter; protected void activate(ComponentContext context) { staticFieldConverter.add(JamonPropertyName.class); } protected void deactivate(ComponentContext context) { staticFieldConverter.remove(JamonPropertyName.class); } @CliAvailabilityIndicator("say hello") public boolean isSayHelloAvailable() { return true; } @CliCommand(value = "say hello",
    help = "Prints welcome message to the Roo shell") public void sayHello( @CliOption(key = "name", mandatory = true,
    help = "State your name") String name, @CliOption(key = "contryOfOrigin", mandatory = false, help = "Country of origin") JamonPropertyName country) { log.info("Welcome " + name + "!"); log.warning("Country of origin: " + (country == null ? \
    JamonPropertyName.NOT_SPECIFIED.getPropertyName() : country.getPropertyName())); log.severe("It seems you are a running JDK "
    + operations.getProperty("java.version")); log.info("You can use the default JDK logger anywhere in your"
    + " add-on to send messages to the Roo shell"); } @CliAvailabilityIndicator("web mvc install tags") public boolean isInstallTagsCommandAvailable() { return operations.isInstallTagsCommandAvailable(); } @CliCommand(value = "web mvc install tags",
    help="Replace default Roo MVC tags used for scaffolding") public void installTags() { operations.installTags(); }
    }

    我删除了代码生成器生成的所有注释,以减少代码的冗长性。 让我们看一下该类的重要成员:

    1. CommandMarker —所有命令类都应实现CommandMarker接口,并应使用@Component@Service批注进行批注,以便它们被注册,并且它们的命令在Roo Shell中可用。 用@Reference注释的字段是JamonCommands类的依赖项,由底层Roo OSGi容器注入。 所有带有@Component@Service annotations都可以注入其他加载项中。
    2. 激活和停用方法 - activatedeactivate方法是在您使用addon install命令addon install附件或使用addon remove命令删除附件时调用的方法。 这些方法使您能够了解附加组件的生命周期,该附加组件由基础Roo OSGi容器管理。
    3. 方法与注释@CliAvailabilityIndicator -带注释的方法@CliAvailabilityIndicator是方法,可帮助隐藏命令的时候都没有用。 例如,在项目是Web应用程序之前,看不到用于将Spring Security安装到项目中的security setup命令。 不需要您拥有这样的方法,但是它们很有用,因为它们不允许用户触发当时没有意义的命令。 例如,在用户拥有Web应用程序之前执行安全设置命令没有任何意义。
    4. 方法与注释@CliCommand -带注释的方法@CliCommand注册在Roo shell的命令。 @CliCommand批注具有两个属性: value (定义命令名称)和help (定义),当您键入help命令时显示帮助消息。 每个命令都可以使用@CliOption批注定义强制性和非强制性属性,该注释作为命令的一部分提供。 例如, say hello命令具有称为name的强制属性和称为country非强制属性。
  2. JamonOperationsImpl.java —执行命令时,命令类需要执行一些操作。 这些操作由操作类执行。 JamonOperationsImpl是一个操作类,负责执行实际工作,例如在pom.xml中添加依赖项或将资源复制到所需位置。 JamonOperationsImpl类通过使用Spring Roo框架提供的核心服务来执行其操作。 例如,要添加依赖项,它使用ProjectOperations接口。 要复制文件,它使用FileManager界面。 让我们看一下JamonOperationsImpl类的代码(请参见清单10),以更好地理解Roo插件。
    清单10. JamonOpertionsImpl
    @Component @Service public class JamonOperationsImpl implements JamonOperations { private static final char SEPARATOR = File.separatorChar; @Reference private FileManager fileManager; @Reference private ProjectOperations projectOperations; public boolean isInstallTagsCommandAvailable() { return projectOperations.isProjectAvailable() &&fileManager.exists(projectOperations.getProjectMetadata().getPathResolver().getIdentifier(Path.SRC_MAIN_WEBAPP,"WEB-INF" + SEPARATOR + "tags")); } public String getProperty(String propertyName) { Assert.hasText(propertyName, "Property name required"); return System.getProperty(propertyName); } public void installTags() { PathResolver pathResolver =projectOperations.getProjectMetadata().getPathResolver(); createOrReplaceFile(pathResolver.getIdentifier(Path.SRC_MAIN_WEBAPP, "WEB-INF" + SEPARATOR +"tags" + SEPARATOR + "util"), "info.tagx"); createOrReplaceFile(pathResolver.getIdentifier(Path.SRC_MAIN_WEBAPP, "WEB-INF" + SEPARATOR +"tags" + SEPARATOR + "form"), "show.tagx"); } private void createOrReplaceFile(String path, String fileName) { String targetFile = path + SEPARATOR + fileName; MutableFile mutableFile = fileManager.exists(targetFile) ?fileManager.updateFile(targetFile) :fileManager.createFile(targetFile); try { FileCopyUtils.copy(TemplateUtils.getTemplate(getClass(),fileName), mutableFile.getOutputStream()); } catch (IOException e) { throw new IllegalStateException(e); } } }

    JamonOperationsImpl类具有两个重要方法: isInstallTagsCommandAvailable检查命令是否可用,以及installTags将标签安装到目标项目中。 为了执行这些操作, JamonOperationsImpl类使用一些Spring Roo核心服务和实用程序:

    1. ProjectOperations : JamonOperationsImpl类使用ProjectOperations服务来检查项目是否可用以及获取标签文件夹的路径。
    2. FileManager : JamonOperationsImpl类使用FileManager服务检查文件是否在特定路径下存在,并获取更新或创建MutableFileMutableFile是另一个Roo特定的类,表示可修改文件的句柄。
    3. TemplateUtils : TemplateUtils实用工具类用于获取InputStream到我们附加组件包中的模板文件(info.tagx和show.tagx)。
    4. FileCopyUtils : FileCopyUtils实用程序类用于将模板(来自TemplateUtils )复制到MutableFile (来自FileManager )。

修改附件以满足我们的要求

在关于简单附加组件的第一部分中,我们讨论了必须满足的两个要求,以便我们的附加组件可以在任何Spring MVC Web应用程序中配置JAMon。 要求是:

  1. 在pom.xml中添加JAMon JAR
  2. 在应用程序上下文文件中定义JamonPerformanceMonitorInterceptor bean

为了满足这些要求,我们将在JamonCommands类中进行更改以支持jamon setup命令。 然后,我们将添加一个与jamon setup命令相对应的操作,以进行实际工作以满足要求。

JamonCommandsJamonCommands类现在将只有两种方法: isInstallJamon用于检查jamon setup命令是否可用,以及installJamon用于在触发jamon setup命令时安装installJamon 。 (请参见清单11。)

清单11. JamonCommands的代码
@Component
@Service
public class JamonCommands implements CommandMarker { private Logger log = Logger.getLogger(getClass().getName()); @Reference private JamonOperations operations; @CliAvailabilityIndicator("jamon setup") public boolean isInstallJamon() { return operations.isInstallJamonAvailable(); } @CliCommand(value = "jamon setup", help = "Setup Jamon into your project") public void installJamon() { operations.installJamon(); }
}

这就是JamonCommands类中所需要的。 它只需要公开jamon setup命令,并将其余工作委托给JamonOperationsImpl类。 (请参见清单12。)

清单12. JamonOperationsImpl的代码
JamonOperationsImplJamonOperationsImpl need to implement two methods – \
isInstallJamonAvailable() and installJamon(). The isinstallJamonAvailable() method returns a boolean indicating whether
command is available at this location or not. I want to enable JAMon only for the web
applications so we need to perform the check whether the project is
a web application or not. To do that we will write the code as shown below public boolean isInstallJamonAvailable() { return projectOperations.isProjectAvailable() &&fileManager.exists(projectOperations.getPathResolver().getIdentifier(Path.SRC_MAIN_WEBAPP, "/WEB-INF/web.xml")); }

清单12中显示的代码使用ProjectOperations服务来检查该位置是否有项目,并获取web.xml文件的路径(web.xml文件仅适用于Web应用程序)。 FileManager服务用于检查web.xml在ProjectOperations指定的位置是否存在。

我们需要实现的第二种方法是installJamon() ,它应该在pom.xml中添加JAMon依赖项,并将bean定义添加到webmvc-config.xml中。 在为该方法编写代码之前,我们必须在src / main / resources / org / xebia / roo / addon / jamon文件夹中创建一个名为configuration.xml的XML文件。 文件夹结构org / xebia / roo / addon / jamon与Roo附加组件的软件包结构相同。 configuration.xml定义了JAMon版本和JAMon JAR依赖关系,如清单13所示。

清单13. configuration.xml的内容
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<configuration> <jamon> <properties> <jamon.version>2.4</jamon.version> </properties> <dependencies> <dependency> <groupId>com.jamonapi</groupId> <artifactId>jamon</artifactId> <version>${jamon.version}</version> </dependency> </dependencies> </jamon>
</configuration>

让我们编写代码以在pom.xml中添加依赖关系,如清单14所示。

清单14. pom.xml的内容
public void installJamon() { Element configuration = XmlUtils.getConfiguration(getClass()); updatePomProperties(configuration); updateDependencies(configuration); } private void updatePomProperties(Element configuration) { List<Element> properties = \
XmlUtils.findElements("/configuration/jamon/properties/*", configuration); for (Element property : properties) { projectOperations.addProperty(new Property(property)); } } private void updateDependencies(Element configuration) { List<Dependency> dependencies = new ArrayList<Dependency>(); List<Element> jamonDependencies = XmlUtils.findElements("/configuration/jamon/dependencies/dependency", configuration); for (Element dependencyElement : jamonDependencies) { dependencies.add(new Dependency(dependencyElement)); } projectOperations.addDependencies(dependencies); }

这是在pom.xml中添加依赖项的标准机制,您可以在大多数Roo插件中找到它。 The code shown in Listing 14 is self-explanatory and uses the Spring Roo utility class, XmlUtils , to read the content from configuration.xml and then the ProjectOperations service to update the pom.xml file.

Once we have added the pom.xml dependency, we need to create a separate Spring configuration, web-jamon-config.xml, which will contain the bean definition for JamonPerformanceMonitorInterceptor .

Listing 15. Contents of web-jamon-config.xml
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" \
xmlns:p="http://www.springframework.org/schema/p" 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-3.0.xsd     http://www.springframework.org/schema/context \
http://www.springframework.org/schema/context/spring-context-3.0.xsd     http://www.springframework.org/schema/mvc \
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd"> <bean id="jamonPerformanceMonitorInterceptor" class=\
"org.springframework.aop.interceptor.JamonPerformanceMonitorInterceptor"> <property name="trackAllInvocations" value="true"></property> <property name="useDynamicLogger" value="true"></property> </bean> <bean id="autoProxyCreator" class=\
"org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"> <property name="interceptorNames"> <list> <idref bean="jamonPerformanceMonitorInterceptor" /> </list> </property> <property name="beanNames"> <list> <value></value> </list> </property> </bean> </beans>

In the web-jamon-config.xml file shown in Listing 15, we have configured everything required for JAMon in a Spring-based application. The only thing I have not specified are the names of the beans to monitor. The code generator cannot predict this, so it is left to the add-on developer to specify.

Now we need to write the code that will copy this web-jamon-config.xml file to WEB_INF/spring folder, where webmvc-config.xml resides, and code for the add import statement in webmvc-config.xml to import web-jamon-config.xml. (See Listing 16.)

Listing 16. Code to manipulate pom.xml
public void installJamon() { // update pom.xml code PathResolver pathResolver =
projectOperations.getProjectMetadata().getPathResolver(); String resolvedSpringConfigPath = pathResolver.getIdentifier(Path.SRC_MAIN_WEBAPP,
"/WEB-INF/spring"); if (fileManager.exists(resolvedSpringConfigPath + "/web-jamon-config.xml")) { return; } copyTemplate("web-jamon-config.xml", resolvedSpringConfigPath); String webMvcConfigPath = resolvedSpringConfigPath + "/webmvc-config.xml"; new XmlTemplate(fileManager).update(webMvcConfigPath, new DomElementCallback() { public boolean doWithElement(Document document, Element root) { if (null ==XmlUtils.findFirstElement\
("/beans/import[@resource='web-jamon-config.xml']",root)) { Element element = document.createElement("import"); element.setAttribute("resource", "web-jamon-config.xml"); root.appendChild(element); return true; } return false; } }); } private void copyTemplate(String templateFileName, String resolvedTargetDirectoryPath) { try { FileCopyUtils.copy(TemplateUtils.getTemplate(getClass(),templateFileName), fileManager.createFile(resolvedTargetDirectoryPath + "/" +templateFileName).getOutputStream()); } catch (IOException e) { throw new IllegalStateException("Encountered an error during copying of resources for Jamon addon.", e); }
}

The XmlTemplate class used above comes from the Spring web flow add-on. So you need to add a dependency for the web flow add-on in your add-on. (See Listing 17.)

Listing 17. Add dependency for web flow add-on
<dependency> <groupId>org.springframework.roo</groupId> <artifactId>org.springframework.roo.addon.web.flow</artifactId> <version>${roo.version}</version> <type>bundle</type> </dependency>

In Listing 17, roo.version is the version of Roo you are using.

The last thing we need to do in this add-on is to configure project logging and set up the log level to trace. This is done using LoggingOperations , which is an operations class for the log4j add-on. To use this class, we need to first add the logging add-on dependency in pom.xml file, as shown in Listing 18.

Listing 18. XML code to add dependency for the logging add-on
<dependency> <groupId>org.springframework.roo</groupId> <artifactId>org.springframework.roo.addon.logging</artifactId> <version>${roo.version}</version> <type>bundle</type> </dependency>

After adding the dependency in pom.xml, add LoggingOperation into the JamonOperationsImpl class with the following line:

@Reference private LoggingOperations loggingOperations;

Next, add the following line to the installJamon method:

loggingOperations.configureLogging(LogLevel.TRACE, LoggerPackage.PROJECT);

That's all the code we need to write for this add-on. The full code for JamonOperationsImpl class is shown in Listing 19.

Listing 19. Completed code for JamonOperationsImpl
@Component
@Service
public class JamonOperationsImpl implements JamonOperations { @Reference private FileManager fileManager; @Reference private ProjectOperations projectOperations; @Reference private LoggingOperations loggingOperations; public boolean isInstallJamonAvailable() { return projectOperations.isProjectAvailable() &&
fileManager.exists(projectOperations.getPathResolver()
.getIdentifier(Path.SRC_MAIN_WEBAPP,"/WEB-INF/web.xml")); } public void installJamon() { Element configuration = XmlUtils.getConfiguration(getClass()); updatePomProperties(configuration); updateDependencies(configuration); PathResolver pathResolver =
projectOperations.getProjectMetadata().getPathResolver(); String resolvedSpringConfigPath =
pathResolver.getIdentifier(Path.SRC_MAIN_WEBAPP, "/WEB-INF/spring"); if (fileManager.exists(resolvedSpringConfigPath
+ "/web-jamon-config.xml")) { return; } copyTemplate("web-jamon-config.xml", resolvedSpringConfigPath); String webMvcConfigPath = resolvedSpringConfigPath
+ "/webmvc-config.xml";new XmlTemplate(fileManager).update(webMvcConfigPath,
new DomElementCallback() { public boolean doWithElement(Document document, Element root) {if (null == XmlUtils.findFirstElement(
"/beans/import[@resource='web-jamon-config.xml']",
root)) { Element element = document.createElement("import"); element.setAttribute("resource", "web-jamon-config.xml"); root.appendChild(element); return true; } return false; } });loggingOperations.configureLogging(LogLevel.TRACE,
LoggerPackage.PROJECT); } private void copyTemplate(String templateFileName,
String resolvedTargetDirectoryPath) { try {
FileCopyUtils.copy(TemplateUtils.getTemplate(getClass(), templateFileName),fileManager.createFile(resolvedTargetDirectoryPath + "/" + templateFileName).getOutputStream()); } catch (IOException e) { throw new IllegalStateException("Encountered an error during copying of resources for Jamon addon.", e);} } private void updatePomProperties(Element configuration) { List<Element> properties = XmlUtils.findElements("/configuration/jamon/properties/*",configuration);for (Element property : properties) { projectOperations.addProperty(new Property(property));} } private void updateDependencies(Element configuration) { List<Dependency> dependencies = new ArrayList<Dependency>(); List<Element> jamonDependencies = XmlUtils.findElements("/configuration/jamon/dependencies/dependency", configuration); for (Element dependencyElement : jamonDependencies) { dependencies.add(new Dependency(dependencyElement)); } projectOperations.addDependencies(dependencies); } }

You can download the full source code of this add-on from the Google code repository . Now, let's add JAMon support to our application, using the add-on we have just created:

  1. Exit the roo shell and run the mvn clean install command. During the build process it will ask for GPG passphrase.
  2. After the Roo add-on has been built, open a new command line and create a directory named jamon-client. We will create a simple client for our add-on.
  3. Go to the directory jamon-client and type the roo command to open a Roo shell.
  4. Execute the commands from Listing 20 in the Roo shell. This will create a simple Spring MVC web application.
    Listing 20. Create simple MVC web application
    project --topLevelPackage com.shekhar.roo.jamon.client --projectName jamon-client
    persistence setup --provider HIBERNATE --database
    HYPERSONIC_IN_MEMORY
    entity --class ~.domain.MyUser
    field string --fieldName name --notNull
    controller all --package ~.web
  5. To install the add-on, type:
    osgi start --url <a
    href="../../../../">file:///</a><location \
    to addon target folder >
    /org.xebia.roo.addon.jamon-0.1.0.BUILD-SNAPSHOT.jar

    This should install and activate our JAMon add-on. You can view the status of the add-on using the osgi ps command.

  6. Type the jamon setup command and you will see JAMon being configured in your application. If you now run your application using mvn tomcat:run , you will not see any logs on the console because you have not configured any bean to monitor. Let's configure our myUserController bean in web-jamon-config.xml with the code from Listing 21.
    Listing 21. Configuration for myUserController in web-jamon-config.xml
    <bean id="autoProxyCreator" class=\
    "org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"> <property name="interceptorNames"> <list> <idref bean="jamonPerformanceMonitorInterceptor" /> </list> </property> <property name="beanNames"> <list> <value>myUserController</value> </list> </property> </bean>
  7. Now run the application using mvn tomcat:run and you will see JAMon logs in your the maven console. A sample is shown in Listing 22.
    Listing 22. Sample JAMon log
    TRACE MyUserController - JAMon performance statistics for method
    [MyUserController.populateMyUsers]:
    JAMon Label=MyUserController.populateMyUsers, Units=ms.: (LastValue=187.0,
    Hits=1.0, Avg=187.0, Total=187.0, Min=187.0, Max=187.0, Active=0.0, Avg
    Active=1.0, Max Active=1.0, First Access=Wed May 18 15:33:41 IST 2011, Last
    Access=Wed May 18 15:33:41 IST 2011)

Once you have tested that your add-on is working fine in your development system, you can push it to the Google code project we created. To publish the add-on to the outside world, follow the same procedure we used to publish the i18n add-on. Likewise, to register the add-on with RooBot, follow the i18n registration procedure.

结论

We have looked at the Spring Roo add-on architecture and how to write internationalization and simple add-ons. The add-on architecture is important for Roo because it gives Roo the flexibility to quickly add new features. For developers, this add-on architecture is important because it allows them to meet their requirements without having to wait for features to be implemented globally. Later on, if a feature is incorporated into Roo, it is relatively easy to change out the implementation to remove the custom solution.

In Part 4 of this " Introducing Spring Roo " series, I will talk about how you can write advanced and wrapper add-ons.


翻译自: https://www.ibm.com/developerworks/opensource/library/os-springroo3/index.html

spring roo

spring roo_开发Spring Roo附加组件相关推荐

  1. spring roo_使用Spring Roo进行快速云开发–第2部分:VMware Cloud Foundry

    spring roo Spring Roo是在Java平台上提供快速应用程序开发的工具. 我已经解释了何时使用它: http : //www.kai-waehner.de/blog/2011/04/0 ...

  2. Spring Boot开发之使用JustAuth组件实现第三方登录(QQ、微博等)

    在我们的项目开发中,使用第三方登录(如QQ登录.微信登录等)可以更加方便.轻松地实现用户登录. 在以往的开发过程中,如果要使项目实现第三方登录功能,一般过程是阅读官网的开发文档,并下载其JDK(或者依 ...

  3. spring roo_使用Spring Roo进行快速云开发–第1部分:Google App Engine(GAE)

    spring roo Spring Roo是在Java平台上提供快速应用程序开发的工具. 我已经解释了何时使用它: http : //www.kai-waehner.de/blog/2011/04/0 ...

  4. spring roo_使用Spring Roo进行概念验证

    spring roo 在Keyhole工作期间,我参与了许多项目,其中客户要求我们重写旧系统,同时保留其现有数据库. 有时,它有助于快速演示如何使用当前技术来简化开发,测试和维护其代码. 我发现可以创 ...

  5. Spring系列学习之Spring Roo

    英文原文:https://projects.spring.io/spring-roo/ 目录 令人兴奋的功能 - Spring Boot,Spring Data,...... 零风险 - 没有妥协的生 ...

  6. Spring JDBC开发

    Spring JDBC开发 @(Spring)[spring jdbc] Spring JDBC开发 Spring的JDBC模板的概述 什么是JDBC的模板 Spring的JDBC模板入门 创建web ...

  7. spring注解开发:容器中注册组件方式

    1.包扫描+组件标注注解 使用到的注解如下,主要针对自己写的类 @Controller @Service @Repository @Component @ComponentScan 参考 spring ...

  8. Spring WebFlux和Spring Cloud开发响应式微服务

    作者:Piotr Mińkowski 译者:大萝卜爱上小白菜 原文:https://dzone.com/articles/reactive-microservices-with-spring-webf ...

  9. Spring高级程序设计(Spring框架创始人倾情推荐的权威开发指南)

    Spring高级程序设计(Spring框架创始人倾情推荐的权威开发指南) 市场价 :¥99.00 会员价 : ¥74.25(75折) 样章免费试读:http://www.china-pub.com/1 ...

最新文章

  1. micropython arduino选哪个好_玩转GPIO之ESP32基于MicroPython与Arduino的计算性能测试
  2. Android Toast自己定义Toast例子
  3. 【转载】[Windows 8]Hello Windows 8 - Windows 8 Developer Preview搶先預覽
  4. git bash学习3 -简单杂乱知识点记录
  5. Python技术分享:Python学习的一些小技巧
  6. 平均每天呆实验室14小时,本科女生一作发表PNAS,直博北大!
  7. 传熊猫直播进入破产清算 3月18日关闭服务器
  8. dba 权限_DBA如何玩转PG用户、角色和权限管理?
  9. 蓝桥杯2013c++真题:排它平方数
  10. 生成26个大小写字母加0-9数字的密码字典文件(python3.X)
  11. 通过ajax获取经纬度,通过百度地图获取经纬度
  12. DX11编程(一):DX和Effect的基本配置和属性表配置
  13. 极光推送入门教程-后端
  14. 再次爬取干货集中营的福利图片
  15. 解决优盘插入电脑后无显示的问题
  16. 微博5亿用户数据泄露:通讯录匹配机制是罪魁祸首!
  17. Android系统小知识
  18. 在你生日那天,哈勃望远镜看到了什么
  19. 【沃顿商学院学习笔记】商业分析——People Analytics:15 人才分析 Talent Analytics
  20. 值得期待!中兴新支点4G多卡聚合技术将融合到新型导播机

热门文章

  1. python pydoc-文档生成工具(汇总tcy)
  2. matlab绘制同心柱体,同心圆柱网格的二维画法
  3. WebDAV之葫芦儿·派盘 + Enpass
  4. React虚拟滚动介绍与实现
  5. python字节和字符串互转
  6. 微信小程序 | 12.生命周期、globalData全局数据
  7. TranslateMessage
  8. 像素鸟简单的背景设置_01
  9. Ajax中获取Json的list集合后进行遍历读取并显示的实例
  10. 抖音seo优化排名搜索算法规则,关键词下拉框搜索栏标签流量技术代码分享