2010-04-28 15 views
6

Attention Freemarker rất kinh nghiệm tiên tiến:Sử dụng một mẫu Freemarker duy nhất để hiển thị bảng POJO tùy ý

Tôi muốn sử dụng một mẫu Freemarker duy nhất để có thể bảng đầu ra của POJO tùy ý, với các cột để hiển thị định nghĩa riêng biệt so với dữ liệu. Vấn đề là tôi không thể tìm ra cách để xử lý một hàm trên một pojo trong thời gian chạy, và sau đó có freemarker gọi hàm đó (kiểu lambda). Từ lướt qua các tài liệu có vẻ như Freemarker hỗ trợ lập trình chức năng, nhưng tôi dường như không thể mô tả câu thần chú thích hợp.

Tôi đã lấy một ví dụ cụ thể đơn giản. Giả sử tôi có hai danh sách: danh sách những người có firstName và lastName và danh sách xe ô tô có mẫu và mô hình. muốn đầu ra hai bảng sau đây:

<table> 
    <tr> 
    <th>firstName</th> 
    <th>lastName</th> 
    </tr> 
    <tr> 
    <td>Joe</td> 
    <td>Blow</d> 
    </tr> 
    <tr> 
    <td>Mary</td> 
    <td>Jane</d> 
    </tr> 
</table> 

<table> 
    <tr> 
    <th>make</th> 
    <th>model</th> 
    </tr> 
    <tr> 
    <td>Toyota</td> 
    <td>Tundra</d> 
    </tr> 
    <tr> 
    <td>Honda</td> 
    <td>Odyssey</d> 
    </tr> 
</table> 

Nhưng tôi muốn sử dụng cùng một mẫu, vì đây là một phần của một khuôn khổ có để đối phó với hàng chục loại POJO khác nhau.

Với đoạn mã sau:

public class FreemarkerTest { 

    public static class Table { 
    private final List<Column> columns = new ArrayList<Column>(); 

    public Table(Column[] columns) { 
     this.columns.addAll(Arrays.asList(columns)); 
    } 

    public List<Column> getColumns() { 
     return columns; 
    } 

    } 

    public static class Column { 
    private final String name; 

    public Column(String name) { 
     this.name = name; 
    } 

    public String getName() { 
     return name; 
    } 
    } 

    public static class Person { 
    private final String firstName; 
    private final String lastName; 

    public Person(String firstName, String lastName) { 
     this.firstName = firstName; 
     this.lastName = lastName; 
    } 

    public String getFirstName() { 
     return firstName; 
    } 

    public String getLastName() { 
     return lastName; 
    } 
    } 

    public static class Car { 
    String make; 
    String model; 

    public Car(String make, String model) { 
     this.make = make; 
     this.model = model; 
    } 

    public String getMake() { 
     return make; 
    } 

    public String getModel() { 
     return model; 
    } 
    } 

    public static void main(String[] args) throws Exception { 
    final Table personTableDefinition = new Table(new Column[] { new Column("firstName"), new Column("lastName") }); 
    final List<Person> people = Arrays.asList(new Person[] { new Person("Joe", "Blow"), new Person("Mary", "Jane") }); 
    final Table carTable = new Table(new Column[] { new Column("make"), new Column("model") }); 
    final List<Car> cars = Arrays.asList(new Car[] { new Car("Toyota", "Tundra"), new Car("Honda", "Odyssey") }); 

    final Configuration cfg = new Configuration(); 
    cfg.setClassForTemplateLoading(FreemarkerTest.class, ""); 
    cfg.setObjectWrapper(new DefaultObjectWrapper()); 
    final Template template = cfg.getTemplate("test.ftl"); 

    process(template, personTableDefinition, people); 
    process(template, carTable, cars); 
    } 

    private static void process(Template template, Table tableDefinition, List<? extends Object> data) throws Exception { 
    final Map<String, Object> dataMap = new HashMap<String, Object>(); 
    dataMap.put("tableDefinition", tableDefinition); 
    dataMap.put("data", data); 
    final Writer out = new OutputStreamWriter(System.out); 
    template.process(dataMap, out); 
    out.flush(); 
    } 

} 

Tất cả ở trên là một đưa ra cho vấn đề này. Vì vậy, đây là mẫu tôi đã được hack trên. Lưu ý nhận xét nơi tôi gặp sự cố.

<table> 
    <tr> 
<#list tableDefinition.columns as col> 
    <th>${col.name}</th> 
</#list> 
    </tr> 
<#list data as pojo> 
    <tr> 
<#list tableDefinition.columns as col> 
    <td><#-- what goes here? --></td>  
</#list> 
    </tr> 
</#list> 
</table> 

Vì vậy, col.name có tên thuộc tính tôi muốn truy cập từ thư mục. Tôi đã thử một vài điều, chẳng hạn như

pojo.col.name 

<#assign property = col.name/> 
${pojo.property} 

nhưng tất nhiên những không làm việc, tôi chỉ bao gồm họ để giúp truyền đạt ý định của tôi. Tôi đang tìm một cách để có được một xử lý cho một chức năng và có freemarker gọi nó, hoặc có lẽ một số loại "đánh giá" tính năng có thể mất một biểu thức tùy ý như là một chuỗi và đánh giá nó trong thời gian chạy.

Trả lời

2

Tìm câu trả lời.

${("pojo." + col.name)?eval} 
5

?eval là (gần?) Luôn luôn là một ý tưởng tồi, bởi vì nó thường đi kèm với nhược điểm hiệu suất (ví dụ rất nhiều phân tích cú pháp) và các vấn đề an ninh (ví dụ "FTL tiêm").

Một cách tiếp cận tốt hơn là sử dụng cú pháp khung vuông:

Có một cú pháp thay thế nếu chúng ta muốn xác định tên subvariable với một biểu thức: cuốn sách [ "title"]. Trong các dấu ngoặc vuông, bạn có thể đưa ra bất kỳ biểu thức nào miễn là nó đánh giá thành một chuỗi.

(Từ FreeMarker documentation about retrieving data from a hash)

Trong trường hợp của bạn tôi khuyên bạn nên một cái gì đó giống như ${pojo[col.name]}.

Các vấn đề liên quan