سؤال

هل هناك أي مكتبات تسمح لي باستخدام نفس التدوين المعروف الذي نستخدمه في 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}";

وتمرير مثيل واحد لفئة المستخدم أدناه:

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

سيتم استبدال كل عنصر نائب بالقيم الفعلية.

أيه أفكار؟

هل كانت مفيدة؟

المحلول

إن استخدام BeanUtils الخاص بك لن يتطلب الكثير من إعادة اختراع العجلة (على افتراض أنك تريد أن تكون أساسية كما هو مطلوب).يأخذ هذا التنفيذ خريطة لسياق الاستبدال، حيث يجب أن يتوافق مفتاح الخريطة مع الجزء الأول من مسارات البحث المتغيرة المقدمة للاستبدال.

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

نصائح أخرى

انظر الإجابة على هذا السؤال المماثل حول استخدام لغة التعبير في سياق مستقل.

يجب أن يحتوي Spring Framework على ميزة تقوم بذلك (انظر مثال Spring JDBC أدناه).إذا كان بإمكانك استخدام رائع (فقط أضف ملف Groovy.jar)، فيمكنك استخدام ميزة Groovy's GString للقيام بذلك بشكل جيد.

مثال رائع

foxtype = 'quick'
foxcolor = ['b', 'r', 'o', 'w', 'n']
println "The $foxtype ${foxcolor.join()} fox"

يحتوي Spring JDBC على ميزة أستخدمها لدعم متغيرات الربط المسماة والمتداخلة من الفاصوليا مثل هذا:

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

مثال السلسلة الخاص بك هو قالب صالح في عدد قليل من محركات القوالب على الأقل، مثل 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();
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top