gpt4 book ai didi

java - 在Java Struts应用程序中的放置位置以及如何调用本地XSD文件?

转载 作者:行者123 更新时间:2023-12-02 12:19:47 24 4
gpt4 key购买 nike

我正在编写一个Java Struts应用程序,该应用程序根据本地存储的XSD文件验证传入的XML文件。我遇到了两个问题:


XSD文件需要存储在本地,即不能通过http调用。我应该在Struts应用程序中的哪个位置存储XSD文件?例如,它应该进入WEB-INF吗?我需要将其放在我的src软件包之一中吗?我已经了解了很多有关本地存储的XSD的信息,但对Struts没什么特别的了解。
存储后,如何从Java代码引用此XSD文件?我不知道如何告诉程序在哪里找到文件。


换句话说,这就是我所拥有的:

SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); 
Schema schema = schemaFactory.newSchema(new File("/path/to/schema.xsd"));


我不知道 /path/to/schema.xsd应该是什么样。

我在这个论坛上看过类似的问题,但仍然有些失落。我希望社区提供任何帮助。

提前致谢!

最佳答案

因此,在进行了许多额外的研究之后,我了解到我对Java反射和Struts上下文缺乏了解受到了阻碍。哎呀,我什至不知道什么是“资源”。

我已经解决了问题,但是在寻求解决方案的过程中,我写了以下教程来帮助我跟踪正在学习的新概念。希望这将帮助遇到此问题并需要更多明确细节的下一个人。请让我知道是否有一些我不清楚的地方,或者是否误解了一个概念,我将予以纠正和澄清。

首先,让我们从资源开始。在Java上下文中,我了解到“资源”是与应用程序相关的任何文件或数据,而不是Java代码。例如,这可能是文本或图像文件,或者在我的情况下可能是XSD文件。

现在,要获取该资源,我们必须告诉Java程序在哪里找到它。这意味着我们需要资源的完整(绝对)文件路径。对于普通的Java项目,获取此文件路径的一种方法是

this.getClass().getResource("file.txt");


其中 file.txt是我们要查找的文件的名称。这将返回URL对象,这是一种特殊的Java对象,它包含文件路径或URL。我们可以调用对象的 toString()方法来获取完整的URL。因此,以下代码块

URL thisFile1 = this.getClass().getResource("resource.txt");
System.out.println(thisFile1.toString());


打印以下内容:

file:/C:/path/to/workspace/folder/bin/sandbox/test/pkg1/resource.txt


但是,仅当resource.txt与进行上述调用的源代码(在本例中为 sandbox.test.pkg1)位于相同的程序包中时,才如此。

这是因为 getResource()假定其输入参数是相对文件路径,除非文件路径以“ /”开头。如果是这样, getResource()会将输入参数视为绝对文件路径,其中根目录是已编译的代码目录,即包层次结构的顶部(“ bin”文件夹)。换句话说,这两行代码将产生相同的结果:

URL thisFile1 = this.getClass().getResource("resource.txt");
URL thisFile1 = this.getClass().getResource("/sandbox/test/pkg1/resource.txt");


不太明显的是为什么我们必须先调用 getClass()才能调用 getResource()。我想知道为什么我们需要完全调用 getClass()getResource()成为Object方法会不会更容易?这似乎是一个令人困惑且不必要的步骤。

好吧, getClass()返回Java类对象的实例,这是一个特殊的Java对象,它返回有关Java类的信息。换句话说,采用以下代码块:

public class myClass 
{
public void myMethod()
{
Class thisClass = this.getClass();
}

public void method2() {...}

public void method3() {...}
}


如果调用 myMethod(),则会得到Class的实例,该实例包含有关myClass对象的信息。例如,如果我们再致电

Method[] theseMethods = thisClass.getMethods();


我们得到了myClass中所有方法的数组( myMethod()method2()method3()等)。这是Java的反映,它具有广泛的用途,因为我们可以在程序运行时收集和检查Java类的属性。

那么,如果我们获得外部资源,为什么我们应该关心这一点?因为要获取资源,所以我们首先需要获取有关要获取资源的类的信息。

让我们回到前面的示例:

URL thisFile1 = this.getClass().getResource("resource.txt");


这会在当前目录中搜索文件“ resource.txt”,但是 getResource()不会自动知道当前目录是什么。它需要获取有关正在调用它的类的信息,以知道要搜索的目录。 Class对象仅包含此类信息,这就是 getResource()是Class对象而不是Object对象的方法的原因。

到目前为止,一切都很好。但是,当我们尝试从在本地Tomcat服务器上运行的Java Struts应用程序中获取资源时,而不是当我们尝试从传统Java项目中获取资源时,事情就变得复杂了。使用Struts和Tomcat,文件最终位于一个非常不同的位置:

URL thisFile1 = this.getClass().getResource("resource.txt");
System.out.println(thisFile1.toString());


产生

 file:/C:/path/to/Tomcat/server/folder/.metadata/.me_tcat/webapps/ProjectName/WEB-INF/classes/sandbox/test/pkg1/resource.txt


这要复杂得多,也不太直观。另外,如果我们想要的文件与调用它的源代码不在同一个目录中,该怎么办?对于Struts应用程序,习惯上将资源文件放在其他位置。这是因为Struts基于分离出程序的不同部分以更好地管理程序流的原理(MVC范例),因此将资源文件与源代码绑定似乎违反了该原理(无论如何,我认为)。

我想将资源文件放到WEB-INF中,但放到“ classes”文件夹之外-例如在“ resources”文件夹中-但这会使 getResource()更加复杂。从 getResource()的角度来看,根目录是

file:/C:/path/to/Tomcat/server/folder/.metadata/.me_tcat/webapps/ProjectName/WEB-INF/classes/


因此,要想进一步提高文件层次结构,我们必须使用一个或多个 ../制定一个复杂的相对路径。那是一团糟,很难遵循。有没有更优雅的方式?

有!

URL thisFile1 = this.getServlet().getServletContext().getResource("/WEB-INF/resources/resource.txt");


这里发生了什么?好吧,请记住Struts是使用Java servlet的框架。这意味着我们的源代码位于servlet内部。反过来,该servlet是Web应用程序的一部分(据我了解,该Web应用程序可以运行多个servlet)。该应用程序是运行servlet的上下文。该应用程序具有其自己的 getResource()方法,该方法用于使资源可供作为该应用程序一部分运行的所有servlet使用。

换句话说,我们获取servlet,然后获取servlet的上下文(Web应用程序),然后从上下文获取资源。

这就是 this.getServlet().getServletContext().getResource()this.getClass().getResource()的不同之处。前者从运行Struts的Web应用程序的角度处理本地资源,而后者从要求资源的类的角度处理本地资源。因此,前者将以Web应用程序(在上面的示例文件路径中为ProjectName)作为根目录查找资源,而后者则将包层次结构的顶部作为根目录查找资源。这很有道理。在传统的Java项目中,我们从来没有比程序包层次结构顶层高的任何东西,即没有运行项目的“较大上下文”。但是,对于Struts,Java项目是运行Struts的较大Web应用程序(“较大上下文”)的一部分。

所以现在我修改后的代码如下:

String xsdFile = "";
SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
try
{
xsdFile = this.getServlet().getServletContext().getResource("/WEB-INF/resources/schema.xsd").toString();
}
catch (Exception e)
{
return e.getMessage();
}
Schema schema = schemaFactory.newSchema(new File(xsdFile));


我将其封装在try-catch块中,因为如果找不到文件,则会得到NullPointerException。

但这还不太正确。在上述代码块的最后一行出现错误。该代码找不到文件schema.xsd。根据控制台窗口,它正在尝试引用

file:/C:/Users/user/AppData/Local/MyEclipse%20Professional%202014/plugins/com.genuitec.eclipse.easie.tomcat.myeclipse_11.0.0.me201211151802/tomcat/bin/jndi:/localhost/ProjectName/WEB-INF/resources/schema.xsd


this.getServlet().getServletContext().getResource()看起来不是返回文件的完整路径,而是返回本地URL:

jndi:/localhost/ProjectName/WEB-INF/resources/schema.xsd


我了解到,JNDI是一种Java服务,它允许远程组件通过一个集中的位置相互通信。该集中位置是运行JNDI的位置,该位置记录着可以在哪里找到每个组件的记录,以便每个其他组件都可以找到它。换句话说,要找到组件B,组件A只需ping JNDI并询问“ B在哪里?”。 JNDI返回正确的位置。如果两个组件都与JNDI在同一台服务器上,则JNDI返回“ localhost”作为IP,后跟该组件相对于Web应用程序根目录的路径。这只是说“ A和B都在这台机器上”,其工作方式与我们惯用的HTTP URL相似。

因此,默认情况下,所有内容都通过JNDI运行。这样可以保留所有与Web应用程序相关的文件引用,从而使将应用程序从一台计算机移动到另一台计算机,重新定位组件以及如上所述进行跨计算机通信变得更加容易。出于应用程序管理的目的,这很好,但是如果我需要相对于我的机器而不是相对于应用程序的绝对路径,那就不好了。

好吧,我需要一个到机器的绝对路径,因为我正在实例化Schema构造函数中的File类,并且File类在用String实例化时假定其输入参数是本地文件路径。幸运的是,Schema构造函数还将使用一个URL(实际上是一个URI)到该模式文件,并且URL恰好是上述 getResource()调用返回的,然后再将其转换为String:

那么,我的最终解决方案如下:

URL xsdFile = "";
SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
try
{
xsdFile = this.getServlet().getServletContext().getResource("/WEB-INF/resources/schema.xsd");
}
catch (Exception e)
{
return e.getMessage();
}
Schema schema = schemaFactory.newSchema(xsdFile);


这个新的解决方案非常有效!

关于java - 在Java Struts应用程序中的放置位置以及如何调用本地XSD文件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23548701/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com