【问题标题】:Simplest way to use "BeanUtils alike" replace使用“BeanUtils alike”替换的最简单方法
【发布时间】:2010-09-13 18:56:13
【问题描述】:

是否有任何库可以让我使用与 BeanUtils 中相同的已知符号来提取 POJO 参数,但可以轻松替换字符串中的占位符?

我知道使用 BeanUtils 本身或具有类似功能的其他库可以自行开发,但我不想重新发明轮子。

我想取一个字符串如下:

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));

将每个占位符替换为实际值。

有什么想法吗?

【问题讨论】:

标签: java string replace placeholder


【解决方案1】:

使用 BeanUtils 滚动您自己不会花费太多的轮子改造(假设您希望它像要求的那样基本)。此实现采用 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));

【讨论】:

    【解决方案2】:

    Spring Framework 应该具有执行此操作的功能(请参阅下面的 Spring JDBC 示例)。如果您可以使用 groovy(只需添加 groovy.jar 文件),您可以使用 Groovy 的 GString 功能很好地做到这一点。

    Groovy 示例

    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);
    }
    

    【讨论】:

      【解决方案3】:

      您的字符串示例是至少在一些模板引擎中的有效模板,例如 Velocity 或 Freemarker。这些库提供了一种将模板与包含一些对象的上下文合并的方法(例如您的示例中的“用户”)。

      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();
      

      【讨论】:

        猜你喜欢
        • 2011-01-24
        • 2021-11-14
        • 1970-01-01
        • 2022-12-17
        • 1970-01-01
        • 2016-01-03
        • 2011-04-25
        • 2017-02-26
        • 2011-09-25
        相关资源
        最近更新 更多