CMS static technology

Beetl

1, Introduction

Beetl is similar to JS syntax and can also support html tags. The engine performance is 5-6 times that of freemaker and 2 times that of JSP, which makes the development of static pages in CMS system cost-effective

2, Grammar

1. Delimiters and placeholders

	Delimiter:<%   %>:  Write some for loop if Judge variable assignment and other operations
	Placeholder: ${ }: Placeholders are used to embed placeholders in static text for output

The following is a correct example

<%
var a = 2;
var b = 3;
var result = a+b;
%>
hello 2+3=${result}

Note: never use placeholders in delimiters, because placeholders are only embedded in static text. The following example is an error example

<%
var a = "hi";
var c = ${a}+"beetl"; //Should be var c = a+"beetl"
%>

2. Notes

Single line notes adopt// Note Content 
Multi line fixation/*Note Content */

3. Temporary variable definition

The variables defined in the template become temporary variables, which is similar to the variables defined by var in js, as shown in the following example

<%
var a = 3;
var b = 3,c = "abc",d=true,e=null;
var f = [1,2,3];
var g = {key1:a,key2:c};
var i = a+b;
%>

4. Global variable definition

The global variable is through template The variables passed in by binding can be accessed anywhere in the template, including sub templates

//Here is the java code. Assign a value to the template
template.binding("list",service.getUserList());

//In the template
<%
for(user in list){
%>
User name:,${user.name};
<% } %>

Because we use version 3.0, since version 2.8.0, a special variable has become the root variable. When the template cannot find the variable, it will look for the attribute of the root variable as the value of the variable. This root variable must be bound to "_root"

//Here is the java code. Assign a value to the template
template.binding("_root",new User());

//In the template
${name}
${wife.name}

Here, both name and wife are attributes of the User object

5. Shared variable

Shared variables refer to variables that can be referenced in all templates, which can be accessed through GroupTemplate Setsharedvars (map < string, Object > sharedvars) passes in variables, which can be used anywhere in all templates

@Test
    void mapVariableFile() throws IOException, ParseException {
//templates directory
        String root = "D:\\wyx\\beetl\\template";
        //File template loader
        FileResourceLoader resourceLoader = new FileResourceLoader(root);
        Configuration cfg = Configuration.defaultConfiguration();
        GroupTemplate gt = new GroupTemplate(resourceLoader, cfg);
        // Shared variable settings
        Map<String,Object> shared = new HashMap<String,Object>();
        shared.put("share", "I am beetl Shared variable");
        gt.setSharedVars(shared);
        Template t = gt.getTemplate("/shareOneTemplate.html");
        t.binding("shareTitleOne","I am a shared variable template");
        String str = t.render();
        logger.info("Share one output:\n" + str);
        t = gt.getTemplate("/shareTwoTemplate.html");
        t.binding("shareTitleTwo","I'm shared variable template 2");
        str = t.render();
        logger.info("Share two output results:\n" + str);
//t1.txt
hi,${name}
//t2.txt
hello,${name}

6. Reference properties

① Beetl supports through "." Number to access the properties of the object, if it is the same as javascript. If the User object has a getName() method, it can be accessed through ${xxx.name} in the template
② If the template variable is an array or List class, this can be accessed through [], such as ${userList[0]}
③ If the template variable is a map class, this can be accessed through [], such as ${map ["name"]}. If the key value is a string type, you can also use ${map.name} However, this is not recommended because it will mislead template readers into thinking it is a Pojo object
④ Beetl also supports the generic get method, that is, if the object has a public Object get(String key) method, you can use "." For example, ${activityRecord.name} or ${activityRecord ["name"]} will call the get(String key) method of activityRecord. If the object has both specific attributes and generic get (this model design method is not encouraged), the specific attributes have higher priority
⑤ Beetl can also reference attributes through []. For example, ${user ["name"]} is equivalent to ${user.name} This is consistent with javascript. However, it is not recommended to do so, because it is easy for people reading the template to mistakenly think that this is a Map type
⑥ Beetl can also define additional object attributes without changing java objects. This is called virtual attributes. For example, for all sets and arrays, there is a common virtual attribute size The virtual attribute is ". ~" + virtual attribute name

template.binding("list",service.getUserList());
template.binding("pageMap",service.getPage());

//In the template
 in total ${list.~size}
<%
for(user in list){
%>
hello,${user.name};
<% } %>

Current page ${pageMap['page']},in total ${pageMap["total"]}

7. Arithmetic expression

Beetl supports javascript like arithmetic expressions and conditional expressions, such as + - * /% and (), as well as self increasing + +, self decreasing –

<%
var a = 1;
var b = "hi";
var c = a++;
var d = a+100.232;
var e = (d+12)*a;
var f = 122228833330322.1112h //h indicates that this is a long precision BigDecimal
%>

8. Logical expression

Beetl supports conditional expressions like JavaScript and Java, such as >, <, = =,! =, > =<= And!, There are also & & and 𞓜, and ternary expressions, as shown in the following examples

<%
var a = 1;
var b="good";
var c = null;

<%
 var  a = 1 ;
%>
 ${a==1?"ok":''}
 ${a==1?"ok"}
%>

9. Circular statement

Beetl supports rich loop modes, such as for in, for (Exp; exp; exp), while loop and loop control statement break;continue; In addition, if you do not enter the for loop body, you can also execute the statement specified by else for.

for-in

<%
for(user in userList){
        print(userLP.index);//userLP.index * current index, starting from 1
        print(user.name);
}
%>

*userLP.index * current index, starting from 1
userLP.dataIndex index, starting from 0
*userLP.size * length of set
userLP. Is first the first
userLP. Is last the last one
userLP. Whether the even index is even
userLP. Is the odd index odd

for(exp;exp;exp)
For rendering logic, the classic for loop statement is more common, as shown in the following example

<%
var a = [1,2,3];
for(var i=0;i<a.~size;i++){
        print(a[i]);
}
%>

10. Conditional statement

if else
Like js, if else is supported, as shown in the following example

<%
var a =true;
var b = 1;
if(a&&b==1){

}else if(a){

}else{

}
%>

11,try-catch

Generally, try catch is rarely used in template rendering logic, but considering the complexity of rendering logic and uncontrollable places of template, try catch is provided to ensure normal output in case of rendering failure

<%
try{
        callOtherSystemView()
}catch(error){
        print("No data temporarily");
}
%>

Error represents an exception. You can use error Message to get possible error messages

You can also omit the catch part, so that an exception occurs and no operation is done

<%
var date = date();
var len = strutil.length("cbd");
println("len="+len);
%>

12. Function call

Beetl has a few built-in practical functions, which can be called anywhere in Beetl. The following example is to call the date function and return the current date without passing parameters
Please refer to the appendix for Beetl built-in functions. The commonly used functions are listed below

① Date returns a java util. A variable of type date, for example, date() returns a current time (corresponding to java.util.Date of java)$ {date ("2011-1-1", "yyyy MM DD")} returns the specified date, date (MS), specifying a number of milliseconds. Equivalent to calling java util. date(ms)
② Print prints an object print(user.name);
③ Println prints an object and the carriage return line feed symbol. The carriage return symbol uses the template itself, not the local system If you only print a line break, you can call println() directly
④ nvl function nvl. If the object is null, it returns the second parameter. Otherwise, it returns its own nvl(user, "does not exist")
⑤ isEmpty determines whether the variable or expression is empty, the variable does not exist, the variable is null, the variable is an empty string, the variable is an empty collection, and the variable is an empty array. This function will return true
⑥ isNotEmpty is the same as above to judge whether the object is not empty
⑦ The has variable is named as a parameter to judge whether this "global variable" exists, such as has(userList), similar to 1 X version of exist("userList"), but there is no need to enter quotation marks Note that has and isEmpety judge the global variables passed from java to the template, not the temporary variables
⑧ hasAttrbiute tests whether the target object has this attribute. hasAttribute(user, "name")
⑨ assert throws an exception if the expression is false
Trim intercepts numbers or dates and returns characters. For example, trim(12.456,2) returns "12.45", and trim (date, 'yyyy') returns "2017"
⑩ trunc intercepts the number and retains the specified decimal places. For example, the output of trunc(12.456,2) is 12.45 It is not recommended because there is a problem with handling float, which is reserved for compatibility reasons
① ② decode is a simplified if else structure, such as decode(a,1, "a=1", 2, "a=2", "don't know"), if a is 1, decode outputs "a=1", if a is 2, it outputs "a==2", and if it is other values, it outputs "don't know"
① ③ debug output the object specified by debug and the number of lines in the template file and template on the console. For example, debug(1), output 1 [in line 3 @ / org/beetl/core/lab/hello.txt], or multiple, for example, debug("hi", a), output hi,a=123, [in line 3 @ / org/beetl/core/lab/hello.txt]
① ④ parseInt parses a number or character into an integer, such as parseInt("123");
① ⑤ parseLong parses numbers or characters into long shaping, parseInt(123.12);
① ⑥ parseDouble parses numbers or characters into floating-point types, such as ① ⑦ parseDouble("1.23")
① ⑧ range receives three parameters, the initial value, the end value, and the step-by-step increment (if it is unnecessary, the default is 1), and returns an Iterator, which is commonly used in the loop, such as for(var i in range(1,5)) {print(i)}, which will print 1234 in turn
① ⑨ flush forced io output.
② 0 JSON, convert the object into JSON string. For example, var data = json(userList) can be followed by a serialization rule. For example, var data = json(userList,"[*].id:i"), please refer to https://git.oschina.net/xiandafu/beetl-json
(1) pageCtx, only in web development, set up a variable, and then in the page rendering process, call this api to get, such as pageCtx("title", "user add page"), then anywhere, pageCtx("title") get the variable.
②②type.new creates an object instance, such as var user = type new(“com.xx.User”); If import is configured_ Package, you can omit the package name, type new(“User”)
②③type.name returns the name of an instance, VAR userclassname = type Name (User), return "User"
② ④ global returns a global variable value, and the parameter is a string, such as var user = global("user_"+ i);
② ⑤ cookie returns the specified cookie object, such as var usercookie = ② ⑥ cookie("user"), allCookies = cookie();

13. Safe output

Safe output is a problem that any template engine must pay attention to, otherwise, it will greatly perplex template developers. In Beetl, if the template variable to be output is null, Beetl will not output. This is different from JSP. JSP outputs null and Freemarker. If it is useless!, It will report an error

There are two other situations in the template that will lead to abnormal template output

Sometimes template variables do not exist (for example, in sub templates)
The template variable is null, but the output is a property of this variable, such as ${user. WiFi. Name}
For the first two cases, you can add after the variable reference! To remind beetl that this is a safe output variable.

Such as ${user. WiFi. Name!}, Even if user does not exist, or user is null, or user WiFi is null or user wife. If name is null, Beetl will not output

14. Format

<% var date = date(); %>
Today is ${date,dateFormat="yyyy-MM-dd"}.
Today is ${date,dateFormat}
salary is ${salary,numberFormat="##.##"}

//Abbreviation
${date,"yyyy-MM-dd"}

15. Label function

The so-called tag function allows you to process a piece of content in the template file. The function is the same as jsp tag. Such as Beetl's built-in layout label

index.html

<%
//The variable title comes from the parameters of the layout label function
layout("/inc/layout.html",{title:'theme'}){
%>
Hello,this is main part
<% } %>

layout.html

title is ${title}
body content ${layoutContent}
footer

3, Use

Integrate springboot

pom file

<dependency>
    <groupId>com.ibeetl</groupId>
    <artifactId>beetl-framework-starter</artifactId>
    <version>1.2.28.RELEASE</version>
</dependency>

yml file
Change the btl suffix of Beetl to html suffix file

beetl:
  suffix: html

Template basic configuration

Start with GroupTemplate

The core of Beetl is GroupTemplate. Creating GroupTemplate requires two parameters: template resource loader and configuration class

① String template loader

//String template loader
        StringTemplateResourceLoader resourceLoader = new StringTemplateResourceLoader();
        //Template basic configuration
        Configuration cfg = Configuration.defaultConfiguration();
        //The core of Beetl is GroupTemplate. Creating GroupTemplate requires two parameters: template resource loader and configuration class
        GroupTemplate gt = new GroupTemplate(resourceLoader, cfg);
        //Get template
        Template t = gt.getTemplate("hello,${name},${title}");
        //Data rendering
        t.binding("name", "I'm the name");
        t.binding("title", "I'm the title");
        //Render results
        String str = t.render();
        logger.info("Output result:\n" + str);

② File resource template loader (multivariable assignment)

//Template file directory
        String root = "D:\\wyx\\beetl\\template";
        //File template loader
        FileResourceLoader resourceLoader = new FileResourceLoader(root);
        //Configuration class
        Configuration cfg = Configuration.defaultConfiguration();
        GroupTemplate gt = new GroupTemplate(resourceLoader, cfg);
        //Get template
        Template t = gt.getTemplate("/muchVariableTemplate.html");
        //Data rendering
        t.binding("title", "beetl Multivariable page");
        t.binding("name", "beetl");
        t.binding("age", 18);
        t.binding("time", new Date());
        String str = t.render();
        logger.info("Output result:\n" + str);

③ File resource template loader (map type variable assignment)

 //Template file directory
        String root = "D:\\wyx\\beetl\\template";
        //File template loader
        FileResourceLoader resourceLoader = new FileResourceLoader(root);
        //Configuration class
        Configuration cfg = Configuration.defaultConfiguration();
        GroupTemplate gt = new GroupTemplate(resourceLoader, cfg);
        //Get template file
        Template t = gt.getTemplate("/muchVariableTemplate.html");
        //Assembly template data
        Map<String, Object> map = new HashMap<>();
        map.put("title", "beetl map Variable page");
        map.put("name", "I am map");
        t.binding("age", 20);
        t.binding("time", new SimpleDateFormat("yyyy-MM-dd").parse("2021-01-01"));
        //Template assignment
        t.binding(map);
        String str = t.render();
        logger.info("Output result:\n" + str);

④ Share variables and generate html pages

 //templates directory
        String root = "D:\\wyx\\beetl\\template";
        //File template loader
        FileResourceLoader resourceLoader = new FileResourceLoader(root);
        Configuration cfg = Configuration.defaultConfiguration();
        GroupTemplate gt = new GroupTemplate(resourceLoader, cfg);
        // Shared variable settings
        Map<String,Object> shared = new HashMap<String,Object>();
        shared.put("share", "I am beetl Shared variable");
        gt.setSharedVars(shared);
        //Get template 1
        Template t = gt.getTemplate("/shareOneTemplate.html");
        //Render template one's own data
        t.binding("shareTitleOne","I am a shared variable template");
        //Create generated html page path
        File fileOne = new File("D:\\wyx\\beetl\\page\\shareOnePage.html");
        if(!fileOne.exists()) {
            fileOne.createNewFile();
        }
        Writer writer = new FileWriter(fileOne);
        //Write rendering results to html
        t.renderTo(writer);

        //Get template 2
        t = gt.getTemplate("/shareTwoTemplate.html");
        t.binding("shareTitleTwo","I'm shared variable template 2");
        File fileTwo = new File("D:\\wyx\\beetl\\page\\shareTwoPage.html");
        if(!fileTwo.exists()) {
            fileTwo.createNewFile();
        }
        Writer writerTwo = new FileWriter(fileTwo);
        t.renderTo(writerTwo);
        logger.info("Page generated successfully-----");

FTP file transfer

Function: send the generated html code to the server
pom file

<!-- ftp File upload-->
        <dependency>
            <groupId>commons-net</groupId>
            <artifactId>commons-net</artifactId>
            <version>3.3</version>
        </dependency>
public static void main(String[] args) {
        String htmlUrl = "D:\\wyx\\beetl\\page\\a.html";
        ftpUploadFile(htmlUrl);
    }

    /**
     *
     * @param htmlUrl :  File address
     */
    public static void ftpUploadFile(String htmlUrl){
        //Create client object
        FTPClient ftp = new FTPClient();
        InputStream local=null;
        try {
            //Connect to ftp server
            ftp.connect("47.110.152.159", 21);
            //Sign in
            ftp.login("wyxftp", "wei123..");
            //Set upload path
            String path="/home/wyxftp/a";
            //Check whether the upload path exists. If it does not exist, return false
            boolean flag = ftp.changeWorkingDirectory(path);
            if(!flag){
                //Create the upload path. This method can only create a primary directory. Here, if / home/ftpuser exists, you can create an image
                ftp.makeDirectory(path);
            }
            //Specify upload path
            ftp.changeWorkingDirectory(path);
            //Specifies the binary file type of the uploaded file
            ftp.setFileType(FTP.BINARY_FILE_TYPE);
            //Read local file
            File file = new File(htmlUrl);
            local = new FileInputStream(file);
            //The first parameter is the file name
            ftp.storeFile(file.getName(), local);
        } catch (SocketException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                //Close file stream
                local.close();
                //sign out
                ftp.logout();
                //Disconnect
                ftp.disconnect();
                logger.info("Upload successful");
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

FastDFS file store

Function: store the file, return the address, and obtain the file according to the address

pom file dependency

<!-- fastdfs -->
        <dependency>
            <groupId>com.github.tobato</groupId>
            <artifactId>fastdfs-client</artifactId>
            <version>1.26.7</version>
        </dependency>

yml file

fdfs:
  so-timeout: 2500       # Read time
  connect-timeout: 600   # Connection timeout
  tracker-list:          # tracker service configuration address list
    - 47.110.152.159:22122
upload:
  base-url: http://47.110.152.159:84/
String path = "D:\\wyx\\beetl\\page\\b.html";
        File file = new File(path);

        InputStream inputStream = new FileInputStream(file);
        //Upload to FastDFS
        // 1. Get extension
        String extension = StringUtils.substringAfterLast(file.getName(), ".");
        // 2. Upload
        StorePath storePath = storageClient.uploadFile(inputStream, file.length(), extension, null);
        // Return path
        String fullPath = storePath.getFullPath();
        logger.info("url:" + prop.getBaseUrl() + fullPath);

Added by jphilapy on Thu, 03 Mar 2022 16:14:52 +0200