Total Pageviews

Showing posts with label Java. Show all posts
Showing posts with label Java. Show all posts

2020/10/09

[Apache Freemarker] macro variable example

Purpose
Macro variable stores a template fragment that can be used as user-defined directive. The variable also stores the name of allowed parameters to the user-defined directive. You must give value for all of those parameters when you use the variable as directive, except for parameters that has a default value. The default value will be used if and only if you don't give value for the parameter when you call the macro.

How-To
Here has two examples:
<#-- 取得現在時間 -->
<#assign aDateTime = .now>
<#-- 只保留日期 -->
<#assign aDate = aDateTime?date>
<#-- create the macro variable: -->
<#macro printDate mingguodate>
列印日期:${mingguodate}

</#macro>
<#macro footer records amount>
${"-"?right_pad(25, "-")}
總筆數:${records}
總金額:${amount}
</#macro>
<#-- call the macro: -->
<@printDate mingguodate="${aDate?string.@mingguo}" />
<#assign total = 0>
${"水果名稱"?right_pad(10)}${"單價"?right_pad(10)}${"訂購數量"?right_pad(10)}
${"-"?right_pad(25, "-")}
<#list rows as row>
<#assign total += row.price * row.quantity>
${row.name?right_pad(10)}${row.price?string.@ntd?left_pad(10)}${row.quantity?left_pad(10)}
</#list>
<#-- call the macro: -->
<@footer records="${rows?size?left_pad(10)}" amount="${total?string.@ntd?left_pad(10)}" />

2020/08/08

[Java] [Apache Freemarker] 如何在 ftl 做設定,印製年、月、日,且年份採用民國年

Requirement
假設我希望在輸出結果檔,印製年、月、日,且年份採用民國年,該如何在 ftl 做設定?


How-To
ftl 的 code snippet 如下:

<#-- 取得現在時間 -->
<#assign aDateTime = .now>
<#-- 只保留日期 -->
<#assign aDate = aDateTime?date>
<#-- 取出日期中的年份、轉數字,減去 1911 得到民國年 -->
列印年:${aDate?string.YYYY?number - 1911}
<#-- 取出日期中的月份 -->
列印月:${aDate?string.MM}
<#-- 取出日期中的日期 -->
列印日:${aDate?string.dd}


Reference
[1] https://freemarker.apache.org/docs/ref_builtins_date.html

2020/08/05

[Java] [Apache Freemarker] How to compute total price in ftl ?

How-To
You can assign a variable, added value in the loop, then print the value in the end.

<#assign total = 0>
${"水果名稱"?right_pad(10)}${"單價"?right_pad(5)}${"訂購數量"?right_pad(10)}
${"-"?right_pad(25, "-")}
<#list rows as row>
<#assign total += row.price * row.quantity>
${row.name?right_pad(10)}${row.price?left_pad(5)}${row.quantity?left_pad(10)}
</#list>
${"-"?right_pad(25, "-")}
總筆數:${rows?size?left_pad(10)}
總金額:${total?left_pad(10)}


Result

水果名稱      單價   訂購數量      
-------------------------
apple        50        20
avocado      60         2
banana       70         1
cherry       80        10
coconut      90         1
durian      100         3
-------------------------
總筆數:         6
總金額:     2,380


2020/08/04

[Java] [Apache Freemarker] How to count list size in ftl ?

How-To
You can make good use of size to count list size as bellowing:
<#assign total = 0>
${"水果名稱"?right_pad(10)}${"單價"?right_pad(5)}${"訂購數量"?right_pad(10)}
${"-"?right_pad(25, "-")}
<#list rows as row>
<#assign total += row.price * row.quantity>
${row.name?right_pad(10)}${row.price?left_pad(5)}${row.quantity?left_pad(10)}
</#list>
${"-"?right_pad(25, "-")}
總筆數:${rows?size?left_pad(10)}
總金額:${total?left_pad(10)}


Result

水果名稱      單價   訂購數量      
-------------------------
apple        50        20
avocado      60         2
banana       70         1
cherry       80        10
coconut      90         1
durian      100         3
-------------------------
總筆數:         6
總金額:     2,380




2020/08/01

[IntelliJ] Shortcut to upper case

Problem
Assume I have an insert sql statement as bellows:
insert into test (...)
values (...);

If I would like to convert SQL reserved words to upper case as bellows:
INSERT INTO test (...)
VALUES (...);

Any shortcut to fulfill this requirement in IntelliJ?


How-To

2020/07/09

[Java] How to read file with encoding Cp937?

Problem
How to read file with encoding Cp937?

How-To
Here has code snippet:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.stream.Stream;

....

    pubilc void readAndPrintContent(String file) throws IOException {
        try (Stream<String> stream = Files.lines(Paths.get(file), Charset.forName("Cp937"))) {
            stream.forEach(log::debug);
        } catch (IOException e) {
            throw new IOException("fail to read file, error : " + e.getMessage(), e);
        }
    }



2020/06/10

[Java] [Apache Freemarker] How to get the first and the last item in ftl?

Problem
How to get the first and the last item in ftl?

How-To
A simple ftl example:

<#list rows as row>
<#if row?is_first>
表頭:${row.name}
<#elseif row?is_last>
表尾:${row.name}
<#else>
${row.name}
</#if>
</#list>


Test case:

package com.test.tool.filegenerator.ftl;

import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import lombok.Builder;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.junit4.SpringRunner;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@RunWith(SpringRunner.class)
@Slf4j
public class FreemarkerRowTest {

    private Configuration cfg;

    @Before
    public void init() {
        cfg = new Configuration(Configuration.VERSION_2_3_23);
        cfg.setClassForTemplateLoading(this.getClass(), "/");
    }

    @Test
    public void test() throws IOException, TemplateException {
        try (Writer file = new FileWriter(new File("C:/row_test.txt"));) {
            Template template = cfg.getTemplate("ftl/row_test.ftl");

            Map<String, Object> data = new HashMap<>();
            List<TestData> rows = createDummyData();
            rows.stream().forEach(r -> log.debug(r.getName()));

            data.put("rows", rows);

            template.process(data, file);
        } catch (IOException | TemplateException e) {
            throw e;
        }
    }

    private List<TestData> createDummyData() {
        List<TestData> data = new ArrayList<>();
        data.add(TestData.builder().name("apple").build());
        data.add(TestData.builder().name("avocado").build());
        data.add(TestData.builder().name("banana").build());
        data.add(TestData.builder().name("cherry").build());
        data.add(TestData.builder().name("coconut").build());
        data.add(TestData.builder().name("durian").build());

        return data;
    }

    @Builder
    @Getter
    public static class TestData {
        private String name;
    }

}


2020/06/04

[Java] [JUnit] How to expect no exception is thrown?

Before

1
2
3
4
    @Test
    public void testWritePropertyFile() {
        fileGeneratorService.writePropertyFile();
    }


After

1
2
3
4
5
    @Test
    public void testWritePropertyFile() {
        Assertions.assertThatCode(() -> fileGeneratorService.writePropertyFile())
                  .doesNotThrowAnyException();
    }




2020/05/07

[Java] [SonarLint] Remove this hard-coded path-delimiter

Problem
After I run SonarLint check, it complain the following code has problem (Remove this hard-coded path-delimiter):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
    try (Writer file
            = new java.io.FileWriter(new File(testDir.toAbsolutePath() + "\\" + ftlFileName + ".java"));) {
        Template template = cfg.getTemplate("testcase.ftl");
    
        Map<String, Object> data = new HashMap<>();
        data.put("ftlFileName", ftlFileName);
    
        template.process(data, file);
    } catch (IOException | TemplateException e) {
        throw new FtlFileException("fail to generate file from ftl file : " + e.getMessage(), e);
    }


How-To
Using File.separator instead of hard code

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
    try (Writer file
            = new java.io.FileWriter(new File(testDir.toAbsolutePath() + File.separator + ftlFileName + ".java"));) {
        Template template = cfg.getTemplate("testcase.ftl");
    
        Map<String, Object> data = new HashMap<>();
        data.put("ftlFileName", ftlFileName);
    
        template.process(data, file);
    } catch (IOException | TemplateException e) {
        throw new FtlFileException("fail to generate file from ftl file : " + e.getMessage(), e);
    }


2020/05/06

[Apache Freemarker] How to load freemarker template

Scenario 1: Set freemarker template from classpath


code snippet:
    // Set freemarker template from classpath
    Configuration cfg = new Configuration();
    cfg.setClassForTemplateLoading(this.getClass(), "/");


Scenario 2: Set freemarker template from directory


code snippet:
    // Set freemarker template from directory
    Configuration cfg = new Configuration();
    File ftlDir = new File("deliverable/ftl/");
    cfg.setDirectoryForTemplateLoading(ftlDir);


2020/03/10

[Java] 如何依序產生英文字母

Requirement
如何指定開始與結束的英文字母?如起訖為 P 與 AC,程式自動產生 P, Q, R, ......AB, AC

How-To
英文字母產生邏輯

Sample code:
package com.test.tool;

import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

@SpringBootTest
@Slf4j
public class TempTest {
    @Test
    public void doTest() {
        List<String> alphabets
                = Arrays.asList("A", "B", "C", "D", "E", "F",
                                "G", "H", "I", "J", "K", "L",
                                "M", "N", "O", "P", "Q", "R",
                                "S", "T", "U", "V", "W", "X",
                                "Y", "Z");

        List<String> resultList = new ArrayList<>();

        String startStr = "P";
        String endStr = "AC";

        int start = alphabets.indexOf(startStr) + 1;
        log.debug("start = {}", start);

        String result = "";
        while(!result.equals(endStr)){
            result = getAlphabet(start);
            resultList.add(result);

            start++;
        }
        log.debug("resultList = {}", resultList);
    }

    public String getAlphabet(int number) {
        StringBuilder columnName = new StringBuilder();
        while (number > 0) {
            // find remainder
            int remainder = number % 26;
            // if remainder is 0, then a 'Z' must be there in output
            if (remainder == 0) {
                columnName.append("Z");
                number = (number / 26) - 1;
            } else { // if remainder is non-zero
                columnName.append((char) ((remainder - 1) + 'A'));
                number = number / 26;
            }
        }
        // Reverse the string and print result
        return columnName.reverse().toString();
    }

}

console:
09:57:56.458 [main] DEBUG com.cht.tool.filegenerator.TempTest - start = 16
09:57:56.475 [main] DEBUG com.cht.tool.filegenerator.TempTest - resultList = [P, Q, R, S, T, U, V, W, X, Y, Z, AA, AB, AC]



2020/03/09

[Java] [Spring] [JDBC] [Oracle] How to call stored procedure - example 2

Assume I have a stored procedure as bellows:
create or replace PACKAGE PACKAGE1 AS 
     PROCEDURE TEST_EMPLOYEE 
    (
      I_GENDER IN VARCHAR2 DEFAULT 'M',
      O_RESULT OUT SYS_REFCURSOR,
      o_return_code OUT INT
    );
END PACKAGE1;

create or replace PACKAGE BODY PACKAGE1
AS
   PROCEDURE TEST_EMPLOYEE 
    (
      I_GENDER IN VARCHAR2 DEFAULT 'M',
      O_RESULT OUT SYS_REFCURSOR,
      o_return_code OUT INT 
    ) AS 
    BEGIN
      OPEN O_RESULT FOR 
      SELECT ID, NAME, PHONE, ADDRESS, GENDER
      FROM EMPLOYEE 
      WHERE GENDER = I_GENDER;
      o_return_code := 0;
    END TEST_EMPLOYEE;
END PACKAGE1;


Step1. Create a custom repository interface:
package com.example.jpa.repository.custom;

import java.util.Map;

public interface EmployeeRepositoryCustom {

    Map<String, Object> findEmployee(String gender);

}


Step2. Create a custom implementation class:
package com.example.jpa.repository.impl;

import com.example.jpa.entity.Employee;
import com.example.jpa.repository.custom.EmployeeRepositoryCustom;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
import org.springframework.jdbc.core.simple.SimpleJdbcCall;

import java.util.Map;

@Slf4j
public class EmployeeRepositoryImpl implements EmployeeRepositoryCustom {

    @Autowired
    private NamedParameterJdbcTemplate jdbcTemplate;

    @Override
    public Map<String, Object> findEmployee(String gender) {
        SimpleJdbcCall jdbcCall
                = new SimpleJdbcCall(jdbcTemplate.getJdbcTemplate().getDataSource())
                .withCatalogName("PACKAGE1")
                .withProcedureName("TEST_EMPLOYEE")
                .returningResultSet("O_RESULT", 
                                    BeanPropertyRowMapper.newInstance(Employee.class));

        SqlParameterSource input = new MapSqlParameterSource().addValue("I_GENDER", gender);

        Map<String, Object> output = jdbcCall.execute(input);
        output.entrySet().forEach(entry -> 
            log.debug("key = {}, value = {}", entry.getKey(), entry.getValue()));

        return output;
    }
}



Step3. Create an repository interface
package com.example.jpa.repository;

import com.example.jpa.entity.Employee;
import com.example.jpa.repository.custom.EmployeeRepositoryCustom;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface EmployeeRepository extends CrudRepository<Employee, String>, EmployeeRepositoryCustom {
}


Step4. Create a test case:

package com.example.jpa;

import com.example.jpa.entity.Employee;
import com.example.jpa.repository.EmployeeRepository;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.junit.Assert;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.math.BigDecimal;
import java.util.List;
import java.util.Map;

@SpringBootTest
@Slf4j
public class TestEmployeeRepository {

    @Autowired
    private EmployeeRepository employeeRepository;

    @Test
    public void testFindEmployee() {
        Map<String, Object> output = employeeRepository.findEmployee("F");

        List<Employee> employees = (List<Employee>) output.get("O_RESULT");
        for (int i = 0; i < employees.size(); i++) {
            log.debug("employee = {}", ToStringBuilder.reflectionToString(employees.get(i)));
        }

        int returnCode = ((BigDecimal) output.get("O_RETURN_CODE")).intValue();
        log.debug("returnCode = {}", returnCode);
    }

}


Step5. Check result:
[           main] c.e.j.r.impl.EmployeeRepositoryImpl      : key = O_RESULT, value = [com.example.jpa.entity.Employee@2adbd899, com.example.jpa.entity.Employee@d6831df]
[           main] c.e.j.r.impl.EmployeeRepositoryImpl      : key = O_RETURN_CODE, value = 0
[           main] com.example.jpa.TestEmployeeRepository   : employee = com.example.jpa.entity.Employee@77ccded4[id=2,name=Mandy,phone=0911111111,address=Taipei,gender=F]
[           main] com.example.jpa.TestEmployeeRepository   : employee = com.example.jpa.entity.Employee@2bb717d7[id=3,name=Gina,phone=0911111111,address=ChiaYi,gender=F]
[           main] com.example.jpa.TestEmployeeRepository   : returnCode = 0






2020/03/08

[Java] [Spring] [JDBC] [Oracle] How to call stored procedure - example 1

Assume I have a stored procedure as bellows:
create or replace PACKAGE PACKAGE1 AS 
     PROCEDURE TEST_HELLO 
    (
      I_NAME IN VARCHAR2,
      outParam1 OUT VARCHAR2,
      o_return_code OUT INT
    );
END PACKAGE1;

create or replace PACKAGE BODY PACKAGE1
AS
   PROCEDURE TEST_HELLO 
    (
      I_NAME IN VARCHAR2,
      outParam1 OUT VARCHAR2,
      o_return_code OUT INT
    ) AS 
    BEGIN
      outParam1 := 'Hello World! ' || I_NAME;
      DBMS_OUTPUT.put_line (outParam1);
      o_return_code := 0;
    END TEST_HELLO;
END PACKAGE1;


Step1. Create a custom repository interface:
package com.example.jpa.repository.custom;

import java.util.Map;

public interface EmployeeRepositoryCustom {
    Map<String, Object> sayHello(String name);
}


Step2. Create a custom implementation class:
package com.example.jpa.repository.impl;

import com.example.jpa.entity.Employee;
import com.example.jpa.repository.custom.EmployeeRepositoryCustom;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
import org.springframework.jdbc.core.simple.SimpleJdbcCall;

import java.util.Map;

@Slf4j
public class EmployeeRepositoryImpl implements EmployeeRepositoryCustom {

    @Autowired
    private NamedParameterJdbcTemplate jdbcTemplate;
    
    @Override
    public Map<String, Object> sayHello(String name) {
        SimpleJdbcCall jdbcCall
                = new SimpleJdbcCall(jdbcTemplate.getJdbcTemplate().getDataSource())
                .withCatalogName("PACKAGE1")
                .withProcedureName("TEST_HELLO");

        Map<String, Object> output = jdbcCall.execute(name);
        output.entrySet().forEach(entry -> log.debug("key = {}, value = {}", entry.getKey(), entry.getValue()));

        return output;
    }
}


Step3. Create an repository interface
package com.example.jpa.repository;

import com.example.jpa.entity.Employee;
import com.example.jpa.repository.custom.EmployeeRepositoryCustom;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface EmployeeRepository extends CrudRepository<Employee, String>, EmployeeRepositoryCustom {
}


Step4. Create a test case:
package com.example.jpa;

import com.example.jpa.entity.Employee;
import com.example.jpa.repository.EmployeeRepository;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.junit.Assert;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.math.BigDecimal;
import java.util.List;
import java.util.Map;

@SpringBootTest
@Slf4j
public class TestEmployeeRepository {

    @Autowired
    private EmployeeRepository employeeRepository;

    @Test
    public void testSayHello() {
        String name = "Albert Kuo";
        Map<String, Object> output = employeeRepository.sayHello(name);

        String message = (String) output.get("OUTPARAM1");
        int returnCode = ((BigDecimal) output.get("O_RETURN_CODE")).intValue();
        log.debug("message = {}, returnCode = {}", message, returnCode);

        Assert.assertEquals(0, returnCode);
        Assert.assertEquals("Hello World! " + name, message);
    }

}


Step5. Check result:
[           main] c.e.j.r.impl.EmployeeRepositoryImpl      : key = OUTPARAM1, value = Hello World! Albert Kuo
[           main] c.e.j.r.impl.EmployeeRepositoryImpl      : key = O_RETURN_CODE, value = 0
[           main] com.example.jpa.TestEmployeeRepository   : message = Hello World! Albert Kuo, returnCode = 0