在Spring MVC中使用多个属性文件

每个人都听说过将单个Web应用程序组合成一个大型应用程序的门户。 门户软件的工作原理类似于mashup -来自多个来源的内容在单个服务中被拾取,大部分显示在单个网页中。 门户软件还允许在嵌入到门户软件中的所有单个Web应用程序(独立模块)之间更改用户设置,例如语言或主题。 此外,预计将实现单点登录(SSO),它也应能正常工作。 这意味着一次登录即可使用户访问所有嵌入式Web应用程序。 知道在JEE世界中是否有一个简单而轻巧的解决方案来开发模块化JSF 2应用程序,以自动将其收集并呈现在一个类似门户的Web应用程序中,将是很有趣的。 当然,有OSGi和复杂的Portals Bridge为JSR-168或JSR-286兼容的Portlet开发提供支持。 但是幸运的是,JSF 2已经为“幕后”提供了一种简单的可能性。 我们可以用更少的精力来构建类似于门户的软件。 我们需要的只是JSF 2和CDI – Java世界中事实上的标准DI框架。

这篇文章的主题不是新的。 您可以在网上找到一些讨论和想法。 我只在这里提到两个链接。 第一个是ocpsoft博客中的文章“操作方法:具有CDI和PrettyFaces的模块化Java EE应用程序” 。 第二个“使用JSF2的模块化Web应用程序”在JBoss的Wiki中进行了介绍。 这个想法是创建包含单个Web应用程序的JAR文件,并为其提供主要的WAR文件。 WAR文件在构建过程中(例如,通过Maven依赖项)将JAR捆绑在一起。 这意味着JAR位于WAR中的WEB-INF / lib /下。 JAR中的XHTML文件放置在/ META-INF / resources /下,并且将由JSF 2自动获取。JSF可以使用它们,就像它们在/ webapp / resources /文件夹中一样。 例如,您可以使用非常常见的ui:include来包含JAR中的facelets。 这就像一个魅力。 为了能够在运行时获取有关每个JSF模块的一般信息,我们还需要JARs文件中的空CDI的beans.xml。 它们通常位于
META-INF文件夹。

现在让我们开始编码。 但是首先,让我们定义项目的结构。 您可以在GitHub上找到完整的实现示例 。 这只是使用演示Web应用程序(用JSF 2.2编写)的类似于JSF 2门户的轻量级实现的概念证明。 有5个子项目:

  • jsftoolkit-jar基本框架,为模块化JSF应用程序提供接口和实用程序。
  • modA-jar第一个Web应用程序(模块A),它依赖于jsftoolkit-jar。
  • modB-jar依赖jsftoolkit-jar的第二个Web应用程序(模块B)。
  • portal-jar Java,类似于门户的软件的一部分。 它还取决于jsftoolkit-jar。
  • portal-war类门户软件的Web部分。 它汇总了所有文物,并且是可部署的WAR。

基本框架(jsftoolkit-jar)具有应由每个单个模块实现的接口。 最重要的是

/*** Interface for modular JSF applications. This interface should be implemented by every module (JSF app.)* to allow a seamless integration into a "portal" software.*/
public interface ModuleDescription {/*** Provides a human readable name of the module.** @return String name of the module*/String getName();/*** Provides a description of the module.** @return String description*/String getDescription();/*** Provides a module specific prefix. This is a folder below the context where all web pages and* resources are located.** @return String prefix*/String getPrefix();/*** Provides a name for a logo image, e.g. "images/logo.png" (used in h:graphicImage).** @return String logo name*/String getLogoName();/*** Provides a start (home) URL to be navigated for the module.** @return String URL*/String getUrl();
}/*** Any JSF app. implementing this interface can participate in an unified message handling* when all keys and messages are merged to a map and available via "msgs" EL, e.g. as #{msgs['mykey']}.*/
public interface MessagesProvider {/*** Returns all mesages (key, text) to the module this interface is implemented for.** @param  locale current Locale or null* @return Map with message keys and message text.*/Map<String, String> getMessages(Locale locale);
}

模块A的可能实现如下所示:

/*** Module specific implementation of the {@link ModuleDescription}.*/
@ApplicationScoped
@Named
public class ModADescription implements ModuleDescription, Serializable {@Injectprivate MessagesProxy msgs;@Overridepublic String getName() {return msgs.get("a.modName");}@Overridepublic String getDescription() {return msgs.get("a.modDesc");}@Overridepublic String getPrefix() {return "moda";}@Overridepublic String getLogoName() {return "images/logo.png";}@Overridepublic String getUrl() {return "/moda/views/hello.jsf";}
}/*** Module specific implementation of the {@link MessagesProvider}.*/
@ApplicationScoped
@Named
public class ModAMessages implements MessagesProvider, Serializable {@Overridepublic Map<String, String> getMessages(Locale locale) {return MessageUtils.getMessages(locale, "modA");}
}

该模块的前缀是moda。 这意味着网页和资源位于文件夹META-INF / resources / moda /下。 这样可以避免所有单个Web应用程序之间的路径冲突(相同路径)。 实用程序类MessageUtils(来自jsftoolkit-jar)不在此处公开。 我将只显示MessagesProxy类。 MessagesProxy类是一个应用程序范围的Bean,可访问模块化JSF Web应用程序中的所有可用消息。 由于它实现了Map接口,因此可以在Java和XHTML中使用。 CDI在运行时会自动注入MessagesProvider接口的所有可用实现。 我们使用Instance <MessagesProvider>。

@ApplicationScoped
@Named(value = "msgs")
public class MessagesProxy implements Map<String, String>, Serializable {@Injectprivate UserSettingsData userSettingsData;@Any@Injectprivate Instance<MessagesProvider> messagesProviders;/** all cached locale specific messages */private Map<Locale, Map<String, String>> msgs = new ConcurrentHashMap<Locale, Map<String, String>>();@Overridepublic String get(Object key) {if (key == null) {return null;}Locale locale = userSettingsData.getLocale();Map<String, String> messages = msgs.get(locale);if (messages == null) {// no messages to current locale are available yetmessages = new HashMap<String, String>();msgs.put(locale, messages);// load messages from JSF impl. firstmessages.putAll(MessageUtils.getMessages(locale, MessageUtils.FACES_MESSAGES));// load messages from providers in JARsfor (MessagesProvider messagesProvider : messagesProviders) {messages.putAll(messagesProvider.getMessages(locale));}}return messages.get(key);}public String getText(String key) {return this.get(key);}public String getText(String key, Object... params) {String text = this.get(key);if ((text != null) && (params != null)) {text = MessageFormat.format(text, params);}return text;}public FacesMessage getMessage(FacesMessage.Severity severity, String key, Object... params) {String summary = this.get(key);String detail = this.get(key + "_detail");if ((summary != null) && (params != null)) {summary = MessageFormat.format(summary, params);}if ((detail != null) && (params != null)) {detail = MessageFormat.format(detail, params);}if (summary != null) {return new FacesMessage(severity, summary, ((detail != null) ? detail : StringUtils.EMPTY));}return new FacesMessage(severity, "???" + key + "???", ((detail != null) ? detail : StringUtils.EMPTY));}/// java.util.Map interface/public int size() {throw new UnsupportedOperationException();}// other methods ...
}

好。 但是,在何处获取ModuleDescription的实例? 逻辑位于门户jar中。 我对CDI实例使用相同的机制。 CDI将为我们找到ModuleDescription的所有可用实现。

/*** Collects all available JSF modules.*/
@ApplicationScoped
@Named
public class PortalModulesFinder implements ModulesFinder {@Any@Injectprivate Instance<ModuleDescription> moduleDescriptions;@Injectprivate MessagesProxy msgs;private List<FluidGridItem> modules;@Overridepublic List<FluidGridItem> getModules() {if (modules != null) {return modules;}modules = new ArrayList<FluidGridItem>();for (ModuleDescription moduleDescription : moduleDescriptions) {modules.add(new FluidGridItem(moduleDescription));}// sort modules by names alphabeticallyCollections.sort(modules, ModuleDescriptionComparator.getInstance());return modules;}
}

现在,我们可以在UI中创建动态图块,这些图块表示相应Web模块的入口点。

<pe:fluidGrid id="fluidGrid" value="#{portalModulesFinder.modules}" var="modDesc"fitWidth="true" hasImages="true"><pe:fluidGridItem styleClass="ui-widget-header"><h:panelGrid columns="2" styleClass="modGridEntry" columnClasses="modLogo,modTxt"><p:commandLink process="@this" action="#{navigationContext.goToPortlet(modDesc)}"><h:graphicImage library="#{modDesc.prefix}" name="#{modDesc.logoName}"/></p:commandLink><h:panelGroup><p:commandLink process="@this" action="#{navigationContext.goToPortlet(modDesc)}"><h:outputText value="#{modDesc.name}" styleClass="linkToPortlet"/></p:commandLink><p/><h:outputText value="#{modDesc.description}"/></h:panelGroup></h:panelGrid></pe:fluidGridItem>
</pe:fluidGrid>

磁贴是由PrimeFaces Extensions中的 pe:fluidGrid组件创建的。 它们具有响应能力,这意味着它们在调整浏览器窗口大小时会重新排列。 下图演示了启动后门户网站应用程序的外观。 它显示了在类路径中找到的两个模块化演示应用程序。 每个模块化Web应用程序都显示为包含徽标,名称和简短描述的图块。 徽标和名称是可单击的。 单击将重定向到相应的单个Web应用程序。

webportal1

如您所见,您可以在门户的主页上切换当前语言和主题。 第二张图片显示了如果用户单击模块A会发生什么。显示了模块A的Web应用程序。 您可以看到“返回门户”按钮,因此可以向后导航到门户的主页。

webportal2

最后有两个注释:

  1. 可以将每个模块作为独立的Web应用程序运行。 我们可以在运行时(再次通过CDI方式)检查模块是否在“门户”之内,并使用不同的主模板。 这里有一个提示。
  2. 我没有实现登录屏幕,但是单点登录没有问题,因为我们只有一个大型应用程序(一个WAR)。 一切都在那里交付。

参考: 在我们的JCG合作伙伴 Oleg Varaksin的Spring MVC中 , 使用了多个属性文件,这些文件来自软件开发博客Thoughts 。

翻译自: https://www.javacodegeeks.com/2013/12/using-more-than-one-property-file-in-spring-mvc.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/365451.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

汇编语言实验一

实验任务 &#xff08;1&#xff09;使用debug&#xff0c;将程序段写入内存&#xff0c;逐条执行&#xff0c;观察cpu中相关寄存器内容变化。 完成此实验&#xff0c;可用e命令或a命令。 e命令改写内存的内容&#xff0c;如图&#xff1a; 我没有一气喝成&#xff0c;一开始便…

python学习 day6 (3月7日)

#__author : liuyang #date : 2019/3/7 0007 a [a , b , c] b [] print(a is b ) # 空元组 可以 空列表 不可以 print(tuple(a))题目&#xff1a; l1 [11, 22, 33, 44, 55] #将此列表索引为奇数的对应元素全部删除 # 错误示例 for l in range(len(l1)):print(l)if l % 2…

java jni helloword_JNI入门教程之HelloWorld篇

JNI入门教程之HelloWorld篇来源:互联网 宽屏版 评论2008-05-31 09:07:11本文讲述如何使用JNI技术实现HelloWorld&#xff0c;目的是让读者熟悉JNI的机制并编写第一个HelloWorld程序。java Native Interface(JNI)是Java语言的本地编程接口&#xff0c;是J2SDK的一部分。在java…

select多查询,自连接,join 等

题目来源于leetcode中的数据库部分&#xff1a;181. Employees Earning More Than Their Managers 题目&#xff1a;The Employee table holds all employees including their managers. Every employee has an Id, and there is also a column for the manager Id. ----------…

有时候eclipse 导入maven项目 启动的时候回出现这样一个问题

严重: A child container failed during start java.util.concurrent.ExecutionException: org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Catalina].StandardHost[localhost].StandardContext[/SpringMvcController]]at java.util.conc…

公众平台模板消息所在行业_第三方工具微信公众号模板消息群发如何操作?

当下&#xff0c;公众平台模板消息功能仅支持添加模板&#xff0c;修改所在行业&#xff0c;如果想要群发模板消息&#xff0c;可以自己根据公众平台的接口编程实现&#xff0c;也可通过微号帮平台的模板消息群发功能实现&#xff0c;均可以让微信公众号群发模板消息&#xff0…

在 Snoop 中使用 PowerShell 脚本进行更高级的 UI 调试

在 Snoop 中使用 PowerShell 脚本进行更高级的 UI 调试 原文:在 Snoop 中使用 PowerShell 脚本进行更高级的 UI 调试版权声明&#xff1a;本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。欢迎转载、使用、重新发布&#xff0c;但务必保留文章署名…

java 通道 双向原理_Java-NIO(四):通道(Channel)的原理与获取

通道(Channel)&#xff1a;由java.nio.channels包定义的&#xff0c;Channel表示IO源与目标打开的连接&#xff0c;Channel类似于传统的“流”&#xff0c;只不过Channel本身不能直接访问数据&#xff0c;Channel只能与Buffer进行交互。通道主要用于传输数据&#xff0c;从缓冲…

访问权限冲突定义_一文读懂F5 REST API的细粒度角色访问控制

↑ 点击上方“小咩社长”关注我阅读提示&#xff5c;本文大概4718字 阅读需要12分钟写在前面&#xff1a;前两天一个保险的客户联系我说有个需求&#xff0c;问通过调用F5 REST API可否实现&#xff1f;&#xff1a;需要把F5负载均衡上面的配置相关的信息&#xff0c;包含每个…

python财经数据接口包Tushare pro的入门及简单使用方式(大数据,股票数据接口)...

最近在做一个项目&#xff0c;需要用到股票的数据&#xff0c;我在网上查了很久&#xff0c;最终发现在股票数据上面还是tushare比较专业&#xff0c;而且对于将来做金融行业的大数据这一块的&#xff0c;tushare绝对是你的一个好帮手&#xff0c;所以下面我就简单介绍一下。 一…

java ean13 条形码_【教程】Spire.Barcode 教程:如何在C#中创建EAN-13条码

基于UPC-A标准的EAN-13在世界范围内用于标记零售商品。 13位EAN-13号码由四部分组成&#xff1a;国家代码 - 2或3位数字制造商代码 - 5至7位数字产品代码 - 3至5位数字检查数字 - 最后一位数字代码演示&#xff1a;Step 1: 创建一个BarcodeSettings实例。BarcodeSettings setti…

Java调试器–权威的工具列表

Java调试是一个复杂的空间。 调试器的类型很多&#xff0c;并且有很多工具可供选择。 在此页面中&#xff0c;我们将介绍7种类型的调试器之间的区别&#xff0c;并查看每个类别中的主要工具&#xff0c;以帮助您为正确的工作选择正确的工具。 以下是我们涵盖的调试器类型&…

java项目中多个定时器_在java项目中如何使用Timer定时器

在java项目中如何使用Timer定时器发布时间&#xff1a;2020-11-16 16:36:16来源&#xff1a;亿速云阅读&#xff1a;97作者&#xff1a;Leah在java项目中如何使用Timer定时器&#xff1f;很多新手对此不是很清楚&#xff0c;为了帮助大家解决这个难题&#xff0c;下面小编将为大…

慎使用sql的enum字段类型

在sql的优化中&#xff0c;会有同学提到一点&#xff1a;使用enum字段类型&#xff0c;代替其他tinyint等类型。以前这也是不少人喜欢优化的&#xff0c;但是现在细想&#xff0c;是非常不合理的。 优点&#xff1a; 1.可以设置区间范围&#xff0c;比如设置性别&#xff1a;1男…

区分基于Ant目标的Gradle任务

在我的博客文章《 从Ant Build演变Gradle构建&#xff1a;导入Ant构建文件》中 &#xff0c;我演示了如何使用Gradle内置的基于AntBuilder的Ant支持在Gradle构建中导入Ant目标。 然后&#xff0c;可以将这些Ant目标作为Gradle任务进行访问&#xff0c;并与Gradle构建直接引入的…

关于类的使用的几个关键

类的定义和声明必须放在main函数前 如果类中只有申明类而没有定义&#xff0c;则只能定义指针&#xff1a;Test *test&#xff1b;如果不定义类而仅仅声明类的话&#xff0c;当使用Test test时&#xff0c;编译器只知道Test是个class&#xff0c;但留多大空间&#xff1f;怎么初…

java判断对象已死_Java的JVM判断对象已死的基本算法分析

jvm中有各种的垃圾收集器&#xff0c;每个收集器都有各自的算法。但是一切的根本都需要找到找到应该被消除的对象&#xff0c;理解如何找到死亡对象才是理解垃圾收集器的基础。01两个基本算法a、引用记数法&#xff1a;对象中加一个引用计数器&#xff0c;每次被引用计数器加一…

java开发 职业技能_java编程开发程序员需要具备哪些职业技能

随着互联网的不断发展&#xff0c;java编程开发可以说是目前学习人数和应用范围非常多的一种编程语言了&#xff0c;而今天我们就一起来了解一下&#xff0c;java编程开发程序员需要具备哪些职业技能。1、数据结构和算法分析数据结构和算法分析&#xff0c;对于一名程序员来说&…

Django model转字典的几种方法

平常的开发过程中不免遇到需要把model转成字典的需求&#xff0c;尤其是现在流行前后端分离架构&#xff0c;Json格式几乎成了前后端之间数据交换的标准&#xff0c;这种model转dict的需求就更多了&#xff0c;本文介绍几种日常使用的方法以供参考&#xff0c;所有例子均基于Dj…

微信小程序日历课表

最近项目中使用到了日历&#xff0c;在网上找了一些参考&#xff0c;自己改改,先看效果图 wxml <view class"date"><image class"direction" src"/images/icon/left.png" bindtapminusMouth/><label>{{year}}年{{mouth}}月<…