最新最全面的Spring详解(三)——Resources,验证、数据绑定和类型转换与Spring表达式语言(SpEL)(上)

简介: 最新最全面的Spring详解(三)——Resources,验证、数据绑定和类型转换与Spring表达式语言(SpEL)

三、Resources


Java拥有标准【java.net.URL】类和各种URL前缀的标准处理程序,不幸的是,对于所有底层资源的访问来说,还不够充分。 例如,没有标准化的【URL】用来访问需要从类路径或相对于【ServletContext】获取资源的方式,而spring为我们解决了这些问题。


1️⃣Resource接口


Spring的【Resource】接口位于【org.springframework.core.io】 包,他抽象了对资源的访问的能力。 下面提供了【Resource】接口的概述, Spring本身广泛地使用了Resource接口。

public interface Resource extends InputStreamSource {
    boolean exists();
    boolean isReadable();
    boolean isOpen();
    boolean isFile();
    URL getURL() throws IOException;
    URI getURI() throws IOException;
    File getFile() throws IOException;
    ReadableByteChannel readableChannel() throws IOException;
    long contentLength() throws IOException;
    long lastModified() throws IOException;
    Resource createRelative(String relativePath) throws IOException;
    String getFilename();
    String getDescription();
}

2️⃣内置的 Resource的实现


Spring包含了几个内置的 Resource 实现,如下所示:


🍀(1)UrlResource


UrlResource包装了java.net.URL,可以用来访问任何需要通过URL访问的对象,例如文件、HTTPS目标、FTP目标等。 所有URL都用一个标准化的“String”表示,这样就可以使用适当的标准化前缀来表示不同类型的URL。 这包括用于访问文件系统路径的’ file: ‘,用于通过https协议访问资源的’ https: ‘,用于通过ftp访问资源的’ ftp: '等。


🍀(2)ClassPathResource


该类表示应该从【类路径】中获取的资源。 它使用线程上下文类装入器、给定的类装入器或给定的类装入资源。


🍀(3)FileSystemResource


这是【java.io】的【Resource】实现。


🍀(4)PathResource


这是一个【java.nio.file】的【资源】实现。


🍀(5)ServletContextResource


这是【ServletContext】资源的【Resource】实现,它解释了相关web应用程序根目录中的相对路径。


🍀(6)InputStreamResource


一个【InputStreamResource】是一个给定的【InputStream】的【Resource】实现。 只有当没有特定的【资源】实现适用时,才应该使用它。 特别是,如果可能的话,最好使用【ByteArrayResource】或任何基于文件的【Resource】实现。


🍀(7)ByteArrayResource


这是一个给定字节数组的【资源】实现。 它为给定的字节数组创建一个ByteArrayInputStream。

它可以从任何给定的字节数组加载内容,而不需要求助于一次性使用的InputStreamResource。


3️⃣ResourceLoader接口


ResourceLoader 接口定义了加载资源的基本能力和方式。 下面的例子显示了 ResourceLoader接口定义:

public interface ResourceLoader {
    Resource getResource(String location);
    ClassLoader getClassLoader();
}


所有应用程序上下文(applicationContext)都实现了【ResourceLoader】接口。 因此,可以所有的【应用程序上下文实现(ClassPathXmlA...)】都拥有加载资源的能力。


当您在特定的应用程序上下文中调用’ getResource() ‘时,如果指定的位置路径【没有特定的前缀】,您将返回【适合该特定应用程序上下文中】的’ Resource ‘类型。 例如,假设以下代码片段是在’ ClassPathXmlApplicationContext '实例上运行的:

Resource template = ctx.getResource("some/resource/path/myTemplate.txt");

针对 ClassPathXmlApplicationContext,该代码返回’ ClassPathResource '。

针对FileSystemXmlApplicationContext实例运行相同的方法,它将返回 ‘FileSystemResource’。

针对WebApplicationContext,它会返回’ ServletContextResource '。它同样会为每个上下文返回适当的对象。


另一方面,你也可以通过指定特殊的【’ classpath: '前缀】来强制使用【ClassPathResource】,无论应用程序的上下文类型是什么,如下面的示例所示:

Resource template = ctx.getResource("classpath:some/resource/path/myTemplate.txt");

类似地,您可以通过指定任何标准的java.net.URL前缀来强制使用【UrlResource】。 下面的例子使用了【file】和【https】前缀:

Resource template = ctx.getResource("file:///some/resource/path/myTemplate.txt");
Resource template = ctx.getResource("https://myhost.com/resource/path/myTemplate.txt");

下表总结了将’ String ‘对象转换为’ Resource '对象的策略:


前缀 举例 说明
classpath: classpath:com/myapp/config.xml 从类路径加载。
file: file:///data/config.xml 作为一个“URL”从文件系统加载。 请参见’ FileSystemResource ’ Caveats。
https: https://myserver/logo.png 作为一个 URL加载。
(none) /data/config.xml 依赖于底层的 ApplicationContext


4️⃣应用环境和资源路径


本节介绍如何【使用资源】创建应用程序上下文,包括使用XML的快捷方式、使用通配符以及其他细节。


🍀(1)构建应用程序上下文


应用程序上下文构造函数通常采用【字符串或字符串数组】作为资源的位置路径,例如组成上下文定义的XML文件。


当这样的位置路径没有前缀时,从该路径构建并用于加载beanDifination的特定【Resource】类型取决于我们使用的这个特定的应用程序上下文。 例如,考虑下面的例子,它创建了一个’ ClassPathXmlApplicationContext ':


ApplicationContext ctx = new ClassPathXmlApplicationContext("conf/appContext.xml");

beanDifination是从类路径加载的,因此他使用了【ClassPathResource】。 但是,考虑下面的例子,它创建了一个’ FileSystemXmlApplicationContext ':

ApplicationContext ctx =
    new FileSystemXmlApplicationContext("conf/appContext.xml");

现在从【文件系统】位置加载beanDifination(在本例中,相对于当前工作目录)。

注意,在位置路径上使用特殊的【classpath前缀】或标准URL前缀会覆盖为加载beanDifination而创建的【默认类型Resource】。 考虑以下例子:

ApplicationContext ctx =
    new FileSystemXmlApplicationContext("classpath:conf/appContext.xml");


使用【FileSystemXmlApplicationContext】从类路径加载beanDifination。 然而,它仍然是一个“FileSystemXmlApplicationContext”。 如果它随后被用作【ResourceLoader】,任何没有前缀的路径仍然被视为文件系统路径。


🍀(2)源路径中的通配符


应用程序上下文构造函数值中的资源路径可以是简单路径,每个路径都有到【目标资源】的一对一映射。当然,也可以包含特殊的【classpath*:】前缀或【内部ant模式】, 后者实际上都是通配符。


注意,这种通配符特定于在应用程序上下文构造函数中使用资源路径(或直接使用“PathMatcher”实用程序类层次结构时),并在构造时解析。 它与“资源”类型本身无关。 你不能使用’ classpath*: '前缀来构造一个【实际的Resource】,因为一个resource一次只指向一个资源。


Ant-style的匹配原则

bdc724d030c441d0b3b7acf06ac64b34.png

Ant-style 模式

路径位置可以包含ant样式的模式,如下例所示:

/WEB-INF/*-context.xml
com/mycompany/**/applicationContext.xml
file:C:/some/path/*-context.xml
classpath:com/mycompany/**/applicationContext.xml

当路径位置包含【ant样式模式】时,解析器将遵循更复杂的过程来尝试解析通配符。

classpath * :前缀

当构造基于xml的应用上下文时,位置字符串可以使用特殊的’ classpath*: '前缀,如下所示:

ApplicationContext ctx =
    new ClassPathXmlApplicationContext("classpath*:conf/appContext.xml");

classpath:和classpath * :的区别


classpath: : 表示从该工程中的类路径中加载资源,classpath:和classpath:/是等价的,都是相对于类的根路径。资源文件库标准的在文件系统中,也可以在JAR或ZIP的类包中。

classpath * : 假设多个JAR包或文件系统类路径都有一个相同的配置文件,classpath:只会在第一个加载的类路径下查找,而【classpath*:】会扫描所有这些JAR包及类路径下出现的同名文件。


四、验证、数据绑定和类型转换


1️⃣BeanWrapper


bean包中一个非常重要的类是【BeanWrappe】接口及其相应的实现(【BeanWrapperImpl】)。 正如在javadoc中引用的,【BeanWrapper】提供了【设置和获取属性值】、【获取属性描述符】等功能。 此外,【BeanWrapper】提供了对嵌套属性的支持,允许对子属性进行无限深度的检索。 说的简单一点,就是这个类能帮助我对使用更简单的api通过反射操作一个bean的属性。


我们以设置和获取基本和嵌套属性为例


设置和获取属性是通过【BeanWrapper】的’ setPropertyValue ‘和’ getPropertyValue '重载方法变体来完成的。 下表显示了这些约定的一些例子:

表达式 释义
name 指示属性“name”对应于“getName()”或“isName()”和“setName(…)”方法。
account.name 指示属性’ account ‘的嵌套属性’ name ‘,该属性对应于(例如)’ getAccount(). setname() ‘或’ getAccount(). getname() '方法。
account[2] 指示索引属性’ account ‘的third元素。 索引属性的类型可以是’ array ‘、’ list '或其他自然有序的集合。
account[COMPANYNAME] 指示由“account”、“map”属性的“COMPANYNAME”键索引的映射条目的值

下面两个示例类使用’ BeanWrapper '来获取和设置属性:

public class Company {
    private String name;
    private Employee managingDirector;
    public String getName() {
        return this.name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Employee getManagingDirector() {
        return this.managingDirector;
    }
    public void setManagingDirector(Employee managingDirector) {
        this.managingDirector = managingDirector;
    }
}
public class Employee {
    private String name;
    private float salary;
    public String getName() {
        return this.name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public float getSalary() {
        return salary;
    }
    public void setSalary(float salary) {
        this.salary = salary;
    }
}

下面的代码片段展示了如何【检索和操作】实例化后的’ Company ’ 和’ Employee ’ 的一些属性:

BeanWrapper company = new BeanWrapperImpl(new Company());
// setting the company name..
company.setPropertyValue("name", "Some Company Inc.");
// ... can also be done like this:
PropertyValue value = new PropertyValue("name", "Some Company Inc.");
company.setPropertyValue(value);
// ok, let's create the director and tie it to the company:
BeanWrapper jim = new BeanWrapperImpl(new Employee());
jim.setPropertyValue("name", "Jim Stravinsky");
company.setPropertyValue("managingDirector", jim.getWrappedInstance());
// retrieving the salary of the managingDirector through the company
Float salary = (Float) company.getPropertyValue("managingDirector.salary");


相关文章
|
6月前
|
安全 Java 数据安全/隐私保护
【深入浅出Spring原理及实战】「EL表达式开发系列」深入解析SpringEL表达式理论详解与实际应用
【深入浅出Spring原理及实战】「EL表达式开发系列」深入解析SpringEL表达式理论详解与实际应用
488 1
|
24天前
|
JSON 安全 算法
|
3月前
|
Java 开发者 Spring
|
5月前
|
前端开发 安全 Java
Spring EL表达式:概念、特性与应用深入解析
Spring EL表达式:概念、特性与应用深入解析
|
5月前
|
算法 Java API
在Spring Boot中实现接口签名验证通常涉及以下步骤
在Spring Boot中实现接口签名验证通常涉及以下步骤
454 4
|
4月前
|
Java 数据库连接 测试技术
在Spring Boot中实现数据校验与验证
在Spring Boot中实现数据校验与验证
|
4月前
|
存储 Java 数据库连接
Spring6(五):Resources、i18n、Validation(3)
Spring6(五):Resources、i18n、Validation(3)
18 0
|
4月前
|
XML Java 数据格式
Spring6(五):Resources、i18n、Validation(2)
Spring6(五):Resources、i18n、Validation(2)
46 0
|
4月前
|
Java 数据库 uml
Spring6(五):Resources、i18n、Validation(1)
Spring6(五):Resources、i18n、Validation(1)
27 0
|
6月前
|
Java 开发者 Spring
Spring AOP的切点是通过使用AspectJ的切点表达式语言来定义的。
【5月更文挑战第1天】Spring AOP的切点是通过使用AspectJ的切点表达式语言来定义的。
70 5