使用" BeanUtils相似"替换的最简单方法
时间:2020-03-06 14:50:17 来源:igfitidea点击:
是否有任何库可以让我使用与BeanUtils中相同的已知符号来提取POJO参数,但可以轻松地替换字符串中的占位符?
我知道有可能使用BeanUtils本身或者其他具有类似功能的库来推出自己的应用程序,但我不想重蹈覆辙。
我想要一个String如下:
String s = "User ${user.name} just placed an order. Deliver is to be made to ${user.address.street}, ${user.address.number} - ${user.address.city} / ${user.address.state}";
并在下面传递User类的一个实例:
public class User { private String name; private Address address; // (...) public String getName() { return name; } public Address getAddress() { return address; } } public class Address { private String street; private int number; private String city; private String state; public String getStreet() { return street; } public int getNumber() { return number; } // other getters... }
像这样:
System.out.println(BeanUtilsReplacer.replaceString(s, user));
将每个占位符替换为实际值。
有任何想法吗?
解决方案
有关在独立上下文中使用表达式语言的类似问题的答案,请参见。
Spring Framework应该具有执行此操作的功能(请参见下面的Spring JDBC示例)。如果可以使用groovy(只需添加groovy.jar文件),则可以使用Groovy的GString功能很好地做到这一点。
时髦的例子
foxtype = 'quick' foxcolor = ['b', 'r', 'o', 'w', 'n'] println "The $foxtype ${foxcolor.join()} fox"
Spring JDBC具有一项功能,可用于支持来自bean的命名和嵌套命名绑定变量,如下所示:
public int countOfActors(Actor exampleActor) { // notice how the named parameters match the properties of the above 'Actor' class String sql = "select count(0) from T_ACTOR where first_name = :firstName and last_name = :lastName"; SqlParameterSource namedParameters = new BeanPropertySqlParameterSource(exampleActor); return this.namedParameterJdbcTemplate.queryForInt(sql, namedParameters); }
使用BeanUtils滚动自己的脚本不会花费太多的精力(假设我们希望它能像要求的那样基本)。此实现采用Map for Replace上下文,其中Map关键字应与为替换而给出的变量查找路径的第一部分相对应。
import java.lang.reflect.InvocationTargetException; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.commons.beanutils.BeanUtils; public class BeanUtilsReplacer { private static Pattern lookupPattern = Pattern.compile("\$\{([^\}]+)\}"); public static String replaceString(String input, Map<String, Object> context) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException { int position = 0; StringBuffer result = new StringBuffer(); Matcher m = lookupPattern.matcher(input); while (m.find()) { result.append(input.substring(position, m.start())); result.append(BeanUtils.getNestedProperty(context, m.group(1))); position = m.end(); } if (position == 0) { return input; } else { result.append(input.substring(position)); return result.toString(); } } }
给定问题中提供的变量:
Map<String, Object> context = new HashMap<String, Object>(); context.put("user", user); System.out.println(BeanUtilsReplacer.replaceString(s, context));
字符串示例是至少几个模板引擎(例如Velocity或者Freemarker)中的有效模板。这些库提供了一种将模板与包含某些对象(例如示例中的" user")的上下文合并的方法。
参见http://velocity.apache.org/或者http://www.freemarker.org/
一些示例代码(来自Freemarker网站):
/* ------------------------------------------------------------------- */ /* You usually do it only once in the whole application life-cycle: */ /* Create and adjust the configuration */ Configuration cfg = new Configuration(); cfg.setDirectoryForTemplateLoading( new File("/where/you/store/templates")); cfg.setObjectWrapper(new DefaultObjectWrapper()); /* ------------------------------------------------------------------- */ /* You usually do these for many times in the application life-cycle: */ /* Get or create a template */ Template temp = cfg.getTemplate("test.ftl"); /* Create a data-model */ Map root = new HashMap(); root.put("user", "Big Joe"); Map latest = new HashMap(); root.put("latestProduct", latest); latest.put("url", "products/greenmouse.html"); latest.put("name", "green mouse"); /* Merge data-model with template */ Writer out = new OutputStreamWriter(System.out); temp.process(root, out); out.flush();