`
dylan0514sina.cn
  • 浏览: 94904 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

支持占位符的文本解析PropertySourcesPropertyResolver

 
阅读更多
PropertyResolver 是 Environment的顶层接口,主要提供属性检索和解析带占位符的文本。bean.xml配置中的所有占位符例如${}都由它解析。通过例子代码了解它的功能和使用
public class PropertySourcesPropertyResolverTests {

	private Properties testProperties;

	private MutablePropertySources propertySources;

	private ConfigurablePropertyResolver propertyResolver;


	@Before
	public void setUp() {
		propertySources = new MutablePropertySources();
		propertyResolver = new PropertySourcesPropertyResolver(propertySources);
		testProperties = new Properties();
		propertySources.addFirst(new PropertiesPropertySource("testProperties", testProperties));
	}


	@Test
	public void containsProperty() {
		assertThat(propertyResolver.containsProperty("foo"), is(false));
		testProperties.put("foo", "bar");
		assertThat(propertyResolver.containsProperty("foo"), is(true));
	}

	@Test
	public void getProperty() {
		assertThat(propertyResolver.getProperty("foo"), nullValue());
		testProperties.put("foo", "bar");
		assertThat(propertyResolver.getProperty("foo"), is("bar"));
	}

	@Test
	public void getProperty_withDefaultValue() {
		assertThat(propertyResolver.getProperty("foo", "myDefault"), is("myDefault"));
		testProperties.put("foo", "bar");
		assertThat(propertyResolver.getProperty("foo"), is("bar"));
	}

	@Test
	public void getProperty_propertySourceSearchOrderIsFIFO() {
		MutablePropertySources sources = new MutablePropertySources();
		PropertyResolver resolver = new PropertySourcesPropertyResolver(sources);
		sources.addFirst(new MockPropertySource("ps1").withProperty("pName", "ps1Value"));
		assertThat(resolver.getProperty("pName"), equalTo("ps1Value"));
		sources.addFirst(new MockPropertySource("ps2").withProperty("pName", "ps2Value"));
		assertThat(resolver.getProperty("pName"), equalTo("ps2Value"));
		sources.addFirst(new MockPropertySource("ps3").withProperty("pName", "ps3Value"));
		assertThat(resolver.getProperty("pName"), equalTo("ps3Value"));
	}

	@Test
	public void getProperty_withExplicitNullValue() {
		// java.util.Properties does not allow null values (because Hashtable does not)
		Map<String, Object> nullableProperties = new HashMap<String, Object>();
		propertySources.addLast(new MapPropertySource("nullableProperties", nullableProperties));
		nullableProperties.put("foo", null);
		assertThat(propertyResolver.getProperty("foo"), nullValue());
	}

	@Test
	public void getProperty_withTargetType_andDefaultValue() {
		assertThat(propertyResolver.getProperty("foo", Integer.class, 42), equalTo(42));
		testProperties.put("foo", 13);
		assertThat(propertyResolver.getProperty("foo", Integer.class, 42), equalTo(13));
	}

	@Test
	public void getProperty_withStringArrayConversion() {
		testProperties.put("foo", "bar,baz");
		assertThat(propertyResolver.getProperty("foo", String[].class), equalTo(new String[] { "bar", "baz" }));
	}

	@Test
	public void getProperty_withNonConvertibleTargetType() {
		testProperties.put("foo", "bar");

		class TestType { }

		try {
			propertyResolver.getProperty("foo", TestType.class);
			fail("Expected IllegalArgumentException due to non-convertible types");
		}
		catch (IllegalArgumentException ex) {
			// expected
		}
	}

	@Test
	public void getProperty_doesNotCache_replaceExistingKeyPostConstruction() {
		String key = "foo";
		String value1 = "bar";
		String value2 = "biz";

		HashMap<String, Object> map = new HashMap<String, Object>();
		map.put(key, value1); // before construction
		MutablePropertySources propertySources = new MutablePropertySources();
		propertySources.addFirst(new MapPropertySource("testProperties", map));
		PropertyResolver propertyResolver = new PropertySourcesPropertyResolver(propertySources);
		assertThat(propertyResolver.getProperty(key), equalTo(value1));
		map.put(key, value2); // after construction and first resolution
		assertThat(propertyResolver.getProperty(key), equalTo(value2));
	}

	@Test
	public void getProperty_doesNotCache_addNewKeyPostConstruction() {
		HashMap<String, Object> map = new HashMap<String, Object>();
		MutablePropertySources propertySources = new MutablePropertySources();
		propertySources.addFirst(new MapPropertySource("testProperties", map));
		PropertyResolver propertyResolver = new PropertySourcesPropertyResolver(propertySources);
		assertThat(propertyResolver.getProperty("foo"), equalTo(null));
		map.put("foo", "42");
		assertThat(propertyResolver.getProperty("foo"), equalTo("42"));
	}

	@Test
	public void getPropertySources_replacePropertySource() {
		propertySources = new MutablePropertySources();
		propertyResolver = new PropertySourcesPropertyResolver(propertySources);
		propertySources.addLast(new MockPropertySource("local").withProperty("foo", "localValue"));
		propertySources.addLast(new MockPropertySource("system").withProperty("foo", "systemValue"));

		// 'local' was added first so has precedence
		assertThat(propertyResolver.getProperty("foo"), equalTo("localValue"));

		// replace 'local' with new property source
		propertySources.replace("local", new MockPropertySource("new").withProperty("foo", "newValue"));

		// 'system' now has precedence
		assertThat(propertyResolver.getProperty("foo"), equalTo("newValue"));

		assertThat(propertySources.size(), is(2));
	}

	@Test
	public void getRequiredProperty() {
		testProperties.put("exists", "xyz");
		assertThat(propertyResolver.getRequiredProperty("exists"), is("xyz"));

		try {
			propertyResolver.getRequiredProperty("bogus");
			fail("expected IllegalStateException");
		}
		catch (IllegalStateException ex) {
			// expected
		}
	}

	@Test
	public void getRequiredProperty_withStringArrayConversion() {
		testProperties.put("exists", "abc,123");
		assertThat(propertyResolver.getRequiredProperty("exists", String[].class), equalTo(new String[] { "abc", "123" }));

		try {
			propertyResolver.getRequiredProperty("bogus", String[].class);
			fail("expected IllegalStateException");
		}
		catch (IllegalStateException ex) {
			// expected
		}
	}

	@Test
	public void resolvePlaceholders() {
		MutablePropertySources propertySources = new MutablePropertySources();
		propertySources.addFirst(new MockPropertySource().withProperty("key", "value"));
		PropertyResolver resolver = new PropertySourcesPropertyResolver(propertySources);
		assertThat(resolver.resolvePlaceholders("Replace this ${key}"), equalTo("Replace this value"));
	}

	@Test
	public void resolvePlaceholders_withUnresolvable() {
		MutablePropertySources propertySources = new MutablePropertySources();
		propertySources.addFirst(new MockPropertySource().withProperty("key", "value"));
		PropertyResolver resolver = new PropertySourcesPropertyResolver(propertySources);
		assertThat(resolver.resolvePlaceholders("Replace this ${key} plus ${unknown}"),
				equalTo("Replace this value plus ${unknown}"));
	}

	@Test
	public void resolvePlaceholders_withDefaultValue() {
		MutablePropertySources propertySources = new MutablePropertySources();
		propertySources.addFirst(new MockPropertySource().withProperty("key", "value"));
		PropertyResolver resolver = new PropertySourcesPropertyResolver(propertySources);
		assertThat(resolver.resolvePlaceholders("Replace this ${key} plus ${unknown:defaultValue}"),
				equalTo("Replace this value plus defaultValue"));
	}

	@Test(expected=IllegalArgumentException.class)
	public void resolvePlaceholders_withNullInput() {
		new PropertySourcesPropertyResolver(new MutablePropertySources()).resolvePlaceholders(null);
	}

	@Test
	public void resolveRequiredPlaceholders() {
		MutablePropertySources propertySources = new MutablePropertySources();
		propertySources.addFirst(new MockPropertySource().withProperty("key", "value"));
		PropertyResolver resolver = new PropertySourcesPropertyResolver(propertySources);
		assertThat(resolver.resolveRequiredPlaceholders("Replace this ${key}"), equalTo("Replace this value"));
	}

	@Test(expected=IllegalArgumentException.class)
	public void resolveRequiredPlaceholders_withUnresolvable() {
		MutablePropertySources propertySources = new MutablePropertySources();
		propertySources.addFirst(new MockPropertySource().withProperty("key", "value"));
		PropertyResolver resolver = new PropertySourcesPropertyResolver(propertySources);
		resolver.resolveRequiredPlaceholders("Replace this ${key} plus ${unknown}");
	}

	@Test
	public void resolveRequiredPlaceholders_withDefaultValue() {
		MutablePropertySources propertySources = new MutablePropertySources();
		propertySources.addFirst(new MockPropertySource().withProperty("key", "value"));
		PropertyResolver resolver = new PropertySourcesPropertyResolver(propertySources);
		assertThat(resolver.resolveRequiredPlaceholders("Replace this ${key} plus ${unknown:defaultValue}"),
				equalTo("Replace this value plus defaultValue"));
	}

	@Test(expected=IllegalArgumentException.class)
	public void resolveRequiredPlaceholders_withNullInput() {
		new PropertySourcesPropertyResolver(new MutablePropertySources()).resolveRequiredPlaceholders(null);
	}

	@Test
	public void getPropertyAsClass() throws ClassNotFoundException, LinkageError {
		MutablePropertySources propertySources = new MutablePropertySources();
		propertySources.addFirst(new MockPropertySource().withProperty("some.class", SpecificType.class.getName()));
		PropertyResolver resolver = new PropertySourcesPropertyResolver(propertySources);
		assertTrue(resolver.getPropertyAsClass("some.class", SomeType.class).equals(SpecificType.class));
	}

	@Test
	public void getPropertyAsClass_withInterfaceAsTarget() throws ClassNotFoundException, LinkageError {
		MutablePropertySources propertySources = new MutablePropertySources();
		propertySources.addFirst(new MockPropertySource().withProperty("some.class", SomeType.class.getName()));
		PropertyResolver resolver = new PropertySourcesPropertyResolver(propertySources);
		assertTrue(resolver.getPropertyAsClass("some.class", SomeType.class).equals(SomeType.class));
	}

	@Test(expected=ConversionException.class)
	public void getPropertyAsClass_withMismatchedTypeForValue() {
		MutablePropertySources propertySources = new MutablePropertySources();
		propertySources.addFirst(new MockPropertySource().withProperty("some.class", "java.lang.String"));
		PropertyResolver resolver = new PropertySourcesPropertyResolver(propertySources);
		resolver.getPropertyAsClass("some.class", SomeType.class);
	}

	@Test(expected=ConversionException.class)
	public void getPropertyAsClass_withNonExistentClassForValue() {
		MutablePropertySources propertySources = new MutablePropertySources();
		propertySources.addFirst(new MockPropertySource().withProperty("some.class", "some.bogus.Class"));
		PropertyResolver resolver = new PropertySourcesPropertyResolver(propertySources);
		resolver.getPropertyAsClass("some.class", SomeType.class);
	}

	@Test
	public void getPropertyAsClass_withObjectForValue() {
		MutablePropertySources propertySources = new MutablePropertySources();
		propertySources.addFirst(new MockPropertySource().withProperty("some.class", new SpecificType()));
		PropertyResolver resolver = new PropertySourcesPropertyResolver(propertySources);
		assertTrue(resolver.getPropertyAsClass("some.class", SomeType.class).equals(SpecificType.class));
	}

	@Test(expected=ConversionException.class)
	public void getPropertyAsClass_withMismatchedObjectForValue() {
		MutablePropertySources propertySources = new MutablePropertySources();
		propertySources.addFirst(new MockPropertySource().withProperty("some.class", new Integer(42)));
		PropertyResolver resolver = new PropertySourcesPropertyResolver(propertySources);
		resolver.getPropertyAsClass("some.class", SomeType.class);
	}

	@Test
	public void getPropertyAsClass_withRealClassForValue() {
		MutablePropertySources propertySources = new MutablePropertySources();
		propertySources.addFirst(new MockPropertySource().withProperty("some.class", SpecificType.class));
		PropertyResolver resolver = new PropertySourcesPropertyResolver(propertySources);
		assertTrue(resolver.getPropertyAsClass("some.class", SomeType.class).equals(SpecificType.class));
	}

	@Test(expected=ConversionException.class)
	public void getPropertyAsClass_withMismatchedRealClassForValue() {
		MutablePropertySources propertySources = new MutablePropertySources();
		propertySources.addFirst(new MockPropertySource().withProperty("some.class", Integer.class));
		PropertyResolver resolver = new PropertySourcesPropertyResolver(propertySources);
		resolver.getPropertyAsClass("some.class", SomeType.class);
	}

	@Test
	public void setRequiredProperties_andValidateRequiredProperties() {
		// no properties have been marked as required -> validation should pass
		propertyResolver.validateRequiredProperties();

		// mark which properties are required
		propertyResolver.setRequiredProperties("foo", "bar");

		// neither foo nor bar properties are present -> validating should throw
		try {
			propertyResolver.validateRequiredProperties();
			fail("expected validation exception");
		}
		catch (MissingRequiredPropertiesException ex) {
			assertThat(ex.getMessage(), equalTo(
					"The following properties were declared as required " +
					"but could not be resolved: [foo, bar]"));
		}

		// add foo property -> validation should fail only on missing 'bar' property
		testProperties.put("foo", "fooValue");
		try {
			propertyResolver.validateRequiredProperties();
			fail("expected validation exception");
		}
		catch (MissingRequiredPropertiesException ex) {
			assertThat(ex.getMessage(), equalTo(
					"The following properties were declared as required " +
					"but could not be resolved: [bar]"));
		}

		// add bar property -> validation should pass, even with an empty string value
		testProperties.put("bar", "");
		propertyResolver.validateRequiredProperties();
	}

	@Test
	public void resolveNestedPropertyPlaceholders() {
		MutablePropertySources ps = new MutablePropertySources();
		ps.addFirst(new MockPropertySource()
			.withProperty("p1", "v1")
			.withProperty("p2", "v2")
			.withProperty("p3", "${p1}:${p2}")              // nested placeholders
			.withProperty("p4", "${p3}")                    // deeply nested placeholders
			.withProperty("p5", "${p1}:${p2}:${bogus}")     // unresolvable placeholder
			.withProperty("p6", "${p1}:${p2}:${bogus:def}") // unresolvable w/ default
			.withProperty("pL", "${pR}")                    // cyclic reference left
			.withProperty("pR", "${pL}")                    // cyclic reference right
		);
		ConfigurablePropertyResolver pr = new PropertySourcesPropertyResolver(ps);
		assertThat(pr.getProperty("p1"), equalTo("v1"));
		assertThat(pr.getProperty("p2"), equalTo("v2"));
		assertThat(pr.getProperty("p3"), equalTo("v1:v2"));
		assertThat(pr.getProperty("p4"), equalTo("v1:v2"));
		try {
			pr.getProperty("p5");
		}
		catch (IllegalArgumentException ex) {
			assertThat(ex.getMessage(), containsString(
					"Could not resolve placeholder 'bogus' in string value \"${p1}:${p2}:${bogus}\""));
		}
		assertThat(pr.getProperty("p6"), equalTo("v1:v2:def"));
		try {
			pr.getProperty("pL");
		}
		catch (StackOverflowError ex) {
			// no explicit handling for cyclic references for now
		}
	}

	@Test
	public void ignoreUnresolvableNestedPlaceholdersIsConfigurable() {
		MutablePropertySources ps = new MutablePropertySources();
		ps.addFirst(new MockPropertySource()
			.withProperty("p1", "v1")
			.withProperty("p2", "v2")
			.withProperty("p3", "${p1}:${p2}:${bogus:def}") // unresolvable w/ default
			.withProperty("p4", "${p1}:${p2}:${bogus}")     // unresolvable placeholder
		);
		ConfigurablePropertyResolver pr = new PropertySourcesPropertyResolver(ps);
		assertThat(pr.getProperty("p1"), equalTo("v1"));
		assertThat(pr.getProperty("p2"), equalTo("v2"));
		assertThat(pr.getProperty("p3"), equalTo("v1:v2:def"));

		// placeholders nested within the value of "p4" are unresolvable and cause an
		// exception by default
		try {
			pr.getProperty("p4");
		}
		catch (IllegalArgumentException ex) {
			assertThat(ex.getMessage(), containsString(
					"Could not resolve placeholder 'bogus' in string value \"${p1}:${p2}:${bogus}\""));
		}

		// relax the treatment of unresolvable nested placeholders
		pr.setIgnoreUnresolvableNestedPlaceholders(true);
		// and observe they now pass through unresolved
		assertThat(pr.getProperty("p4"), equalTo("v1:v2:${bogus}"));

		// resolve[Nested]Placeholders methods behave as usual regardless the value of
		// ignoreUnresolvableNestedPlaceholders
		assertThat(pr.resolvePlaceholders("${p1}:${p2}:${bogus}"), equalTo("v1:v2:${bogus}"));
		try {
			pr.resolveRequiredPlaceholders("${p1}:${p2}:${bogus}");
		}
		catch (IllegalArgumentException ex) {
			assertThat(ex.getMessage(), containsString(
					"Could not resolve placeholder 'bogus' in string value \"${p1}:${p2}:${bogus}\""));
		}
	}


	interface SomeType {
	}

	static class SpecificType implements SomeType {
	}

}

getProperty返回变量在Environment中对应的值
对带有${}占位符的文本解析算法如下
protected String parseStringValue(
			String strVal, PlaceholderResolver placeholderResolver, Set<String> visitedPlaceholders) {

		StringBuilder buf = new StringBuilder(strVal);

		int startIndex = strVal.indexOf(this.placeholderPrefix);
		while (startIndex != -1) {
			int endIndex = findPlaceholderEndIndex(buf, startIndex);
			if (endIndex != -1) {
				String placeholder = buf.substring(startIndex + this.placeholderPrefix.length(), endIndex);
				String originalPlaceholder = placeholder;
				if (!visitedPlaceholders.add(originalPlaceholder)) {
					throw new IllegalArgumentException(
							"Circular placeholder reference '" + originalPlaceholder + "' in property definitions");
				}
				// Recursive invocation, parsing placeholders contained in the placeholder key.
				placeholder = parseStringValue(placeholder, placeholderResolver, visitedPlaceholders);
				// Now obtain the value for the fully resolved key...
				String propVal = placeholderResolver.resolvePlaceholder(placeholder);
				if (propVal == null && this.valueSeparator != null) {
					int separatorIndex = placeholder.indexOf(this.valueSeparator);
					if (separatorIndex != -1) {
						String actualPlaceholder = placeholder.substring(0, separatorIndex);
						String defaultValue = placeholder.substring(separatorIndex + this.valueSeparator.length());
						propVal = placeholderResolver.resolvePlaceholder(actualPlaceholder);
						if (propVal == null) {
							propVal = defaultValue;
						}
					}
				}
				if (propVal != null) {
					// Recursive invocation, parsing placeholders contained in the
					// previously resolved placeholder value.
					propVal = parseStringValue(propVal, placeholderResolver, visitedPlaceholders);
					buf.replace(startIndex, endIndex + this.placeholderSuffix.length(), propVal);
					if (logger.isTraceEnabled()) {
						logger.trace("Resolved placeholder '" + placeholder + "'");
					}
					startIndex = buf.indexOf(this.placeholderPrefix, startIndex + propVal.length());
				}
				else if (this.ignoreUnresolvablePlaceholders) {
					// Proceed with unprocessed value.
					startIndex = buf.indexOf(this.placeholderPrefix, endIndex + this.placeholderSuffix.length());
				}
				else {
					throw new IllegalArgumentException("Could not resolve placeholder '" +
							placeholder + "'" + " in string value \"" + strVal + "\"");
				}
				visitedPlaceholders.remove(originalPlaceholder);
			}
			else {
				startIndex = -1;
			}
		}

		return buf.toString();
0
2
分享到:
评论

相关推荐

    java替换word占位符.zip

    在Java开发中,有时我们需要处理Word文档,例如批量替换文档中的特定占位符文本,这在生成报告或自定义模板时非常常见。标题"java替换word占位符.zip"和描述"java 替换word 占位符"都指向了这个应用场景。在Java中...

    java字符串中${}或者{}等的占位符替换工具类

    Java字符串中${}或者{}等占位符替换工具类 Java字符串中${}或者{}等占位符替换工具类是一个功能强大且实用的工具类,它可以将Java字符串中的占位符依次替换为指定的值。该工具类的主要功能是实现占位符的替换,即将...

    wps演示教程:文本占位符的特点与使用.docx

    主要分为五种类型:文本占位符、表格占位符、图表占位符、媒体占位符和图片占位符。这些占位符帮助用户规范幻灯片的布局和内容组织。 文本占位符是其中最常见的一种,它允许用户在指定区域内添加文本内容。在幻灯片...

    SQL语句填充占位符

    MyBatis允许在XML映射文件或注解中使用#{param}作为占位符,Hibernate则支持HQL(Hibernate Query Language)和Criteria API,它们都提供了更强大的动态查询能力。 例如,在MyBatis中,你可以这样写: ```xml ...

    占位符替换工具.zip

    这表明该工具可能具有用户友好的界面,允许用户定义占位符规则和对应的替换值,或者它可能支持解析特定格式的文件(如JSON、XML或CSV),自动识别并处理其中的占位符。 至于压缩包内的“占位符替换工具”,很可能是...

    ios-设置textfield占位符的颜色大小,开始编辑的时候可以让占位符跟着移动.zip

    在iOS开发中,`UITextField` 是用户输入文本的常见组件,它的占位符(placeholder)功能可以帮助用户理解输入框的目的。本教程将详细介绍如何自定义`UITextField`的占位符颜色、大小,并实现当用户开始编辑时占位符...

    JS替换SQL占位符替换工具 Fix placeholder

    4. **支持多种占位符**:不同的数据库系统可能使用不同类型的占位符,如MySQL的`?`,Python的`%s`,或者Java的`PreparedStatement`的`?`。工具应能处理这些差异。 5. **错误处理**:如果占位符未找到对应的值,或者...

    ios-带有占位符的TextView.zip

    1. **占位符显示**:`LYYTextView` 在没有用户输入时,会在文本框内显示预设的占位符文本,为用户提供输入提示。 2. **占位符颜色自定义**:通过设置属性,开发者可以改变占位符的颜色,使之与应用的界面风格保持...

    ios-最优雅的textView占位符与字数限制的解决方式.zip

    1. 创建一个属性来存储占位符文本,例如`@property (nonatomic, copy) NSString *placeholder;` 2. 再创建一个属性用于显示占位符的UILabel,如`@property (nonatomic, strong) UILabel *placeholderLabel;` 3. 初始...

    占位符行为源码

    本篇将深入探讨占位符的原理、作用以及在实际代码中的实现方式,以"占位符行为源码"为例进行解析。 占位符的用途: 1. 提供清晰的指示:占位符文本是用户首次看到输入框时看到的第一行文本,能直观地告知用户预期的...

    html图片占位符插件holder.js.rar

    它通过简单的语法和丰富的选项,可以生成与指定尺寸相符的占位符图片,显示为灰色背景和白色的文本,从而帮助开发者快速预览页面布局。 **基本使用** 在HTML中,你可以通过以下方式调用Holder.js: ```html 这是...

    rnplaceholderReactNative占位符模块

    3. 多类型支持:rnplaceholder可能支持不同类型的占位符,包括文本、图片、列表等,覆盖常见的UI组件。 4. 易于集成:作为React Native组件,rnplaceholder应该提供简洁的API,方便开发者快速将其集成到项目中。 5. ...

    maven 占位符打包

    标题“maven 占位符打包”指的是在Maven的POM.xml文件中使用特定的占位符,以便在不同环境中替换为相应的配置值。这样可以实现代码的复用和环境的隔离,提高开发效率并降低出错的可能性。 描述中的“工程运行环境有...

    属性占位符配置器

    ### 属性占位符配置器:Spring框架中的高级配置机制 #### 一、概念解析 在Spring框架中,**属性占位符配置器**(Property Placeholder Configurator)是一种强大的配置工具,它允许开发者在配置文件中使用占位符来...

    解决word转xml占位符、变量值被分离的问题

    在用freemaker模板的时候,第一步都会将word转换为xml格式文件,解析成xml文件经常会出现(个别、很多)字段占位符、变量值被分离,被分离的字段少的还好能手动改改,字段多了能让你直接发疯,此代码脚本轻松解决...

    基于SPRINGBOOT配置文件占位符过程解析

    基于SPRINGBOOT配置文件占位符过程解析 Spring Boot 配置文件占位符是指在 Spring Boot 项目中使用占位符来配置应用程序的各种参数。在 Spring Boot 中,默认的配置文件是 application.properties,通过在该文件中...

    重写QlineEdit,可以设置占位文本颜色示例

    它通常包含一个可选的占位文本,即当用户未输入任何内容时显示的提示性文本。本示例着重于如何重写QLineEdit,以自定义占位文本的颜色、选中背景色以及光标闪烁效果。以下是对这些知识点的详细解释: 1. **占位文本...

    解决Spring国际化文案占位符失效问题的方法

    MessageFormat的解析机制是通过applyPattern方法来实现的,该方法将模式字符串解析成一个Segment数组,每个Segment对象包含了模式字符串中的一个部分,包括占位符和文本部分。 在applyPattern方法中,...

    .properties文件读取及占位符${...}替换源码解析

    ".properties文件读取及占位符${...}替换源码解析" .properties文件读取及占位符${...}替换是Java开发中常用的技术,通过使用.properties文件来存储配置信息,并使用占位符${...}来替换这些配置信息。下面将详细...

    JVFloat.js, jquery/zepto插件模拟 Matt D Smith占位符文本浮动.zip

    JVFloat.js, jquery/zepto插件模拟 Matt D Smith占位符文本浮动 #JVFloat.js 演示插件 jQuery和Zepto插件来模拟 JVFloatLabeledTextField的行为,这基于从Matt的概念。 史密斯 。在博客上阅读更多关于的文章。请注意...

Global site tag (gtag.js) - Google Analytics