Total Pageviews

2020/01/10

[Java] [Freemarker] Generate Html file from FTL?

Requirement
I would like to generate HTML file as bellows:
<html>
<body>
    <p>Hello Albert! You have the following messages:
        <li><b>Tim:</b> Please don't forget to bring the laptop!</li>
        <li><b>Cindy:</b> Can you give me a visit this afternoon?</li>
        <li><b>Richard:</b> Don't forget the papers this time!</li>
        <li><b>Mom:</b> Don't forget the milk this time!</li>
        </p>
</body>
</html>

FTL template file
<html>
<body>
    <p>Hello ${name}! You have the following messages:
    <#if messages??>
    <#-- if message has data, get data via iteration
         https://freemarker.apache.org/docs/ref_directive_if.html -->
        <#list messages as m>
        <li><b>${m.from}:</b> ${m.body}</li>
        </#list>
    <#else> <#-- if message is null, then show NO Message Found -->
        No Message Found!
    </#if>
    </p>
</body>
</html>


Test Case
package com.test.batch;

import com.test.batch.exception.FtlException;
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.boot.test.context.SpringBootTest;
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)
@SpringBootTest
@Slf4j
public class FtlTest {

    private Configuration cfg;

    @Before
    public void init() {
        cfg = new Configuration();
        // 設定到 classpath 讀取 ftl file
        cfg.setClassForTemplateLoading(this.getClass(), "/");
    }

    @Test
    public void testMessageHtml() {
        try (Writer file = new FileWriter(new File("C:/ftl_message.html"));) {
            Template template = cfg.getTemplate("ftl/message.ftl");

            Map<String, Object> data = new HashMap<>();
            data.put("name", "Albert");

            List<Message> messages = new ArrayList<>();
            messages.add(Message.builder().from("Tim").body("Please don't forget to bring the laptop!").build());
            messages.add(Message.builder().from("Cindy").body("Can you give me a visit this afternoon?").build());
            messages.add(Message.builder().from("Richard").body("Don't forget the papers this time!").build());
            messages.add(Message.builder().from("Mom").body("Don't forget the milk this time!").build());

            data.put("messages", messages);

            template.process(data, file);
        } catch (IOException | TemplateException e) {
            throw new FtlException("fail to generate file from ftl file : " + e.getMessage(), e);
        }
    }

    @Getter
    @Builder
    public static class Message {
        private String from;
        private String body;
    }

}




2020/01/09

[IntelliJ] How to show JavaDoc via cursor?

For example:


IDE Configuration
Check "Show quick documentation on mouse move", and click OK to save your configuration.

2020/01/08

[Spring] How to invoke a spring component dynamically

Requirement
Assume I have 2 job classes, I will use command line to execute with job name, and program invoke specific Job class to do something.

Command line looks like:
>java -jar batch-0.0.1-SNAPSHOT.jar -name Job1

The two Job class are as bellows:
package com.test.batch.job;

import com.test.batch.service.Service1;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Slf4j
@Component ("Job1")
public class Job1 implements Job{

    @Autowired
    private Service1 service1;

    public void execute() {
        log.debug("execute job1");
        service1.sayHello();
    }

}



package com.test.batch.job;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

@Component("Job2")
@Slf4j
public class Job2 implements Job {

    @Override
    public void execute() {
        log.debug("execute job2");
    }

}

Invoke specific Job class based on the argument which provide by user:
package com.test.batch.service;

import com.test.batch.job.Job;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;

@Slf4j
@Service
public class JobExecutor {

    @Autowired
    private ApplicationContext ctx;

    public void execute(String argument) {
        try {
            // get bean by name
            Job job = (Job) ctx.getBean(argument);
            job.execute();
        } catch (Exception e) {
            String error = "Fail to execute batch job, you provide job name is " + argument;
            log.error(error, e);
        }
    }

}


Command line runner class:
package com.test.batch;

import com.beust.jcommander.JCommander;
import com.test.batch.parameter.BatchJobArgument;
import com.test.batch.service.JobExecutor;
import com.google.common.base.Strings;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

@Slf4j
@Component
public class BatchCommandLineRunner implements CommandLineRunner {

    @Autowired
    private JobExecutor jobExecutor;

    @Override
    public void run(String... args) throws Exception {
        BatchJobArgument arguments = new BatchJobArgument();

        JCommander jCommander = JCommander.newBuilder().build();
        jCommander.addObject(arguments);
        jCommander.parse(args);

        if(arguments.isHelp()){
            jCommander.usage();
            return;
        }

        log.debug("arguments = {}", arguments);

        if(Strings.isNullOrEmpty(arguments.getName())) {
            log.debug("Please assign job name (ex. -name Job1)");
        }else{
            jobExecutor.execute(arguments.getName());
        }
    }

}



2020/01/07

[Spring] How to pass command line argument to Spring Boot application via junit ?

Here has sample code:
package com.test.batch;

import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.ApplicationContext;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest
class BatchApplicationTests {

 @Autowired
 private ApplicationContext ctx;

 @Test
 public void testCommandline() throws Exception {
  CommandLineRunner runner = ctx.getBean(CommandLineRunner.class);
  runner.run("-name", "Job2");
 }

}

2020/01/06

[Oracle] PL/SQL Quick Start

Create Package



CREATE OR REPLACE 
PACKAGE PKG_TEST AS 
   /* TODO enter package declarations 
     (types, exceptions, methods etc) here */ 
END PKG_TEST;




Create Package Body














Update Package












Execute Stored Procedure
var o_message varchar2;
var o_return_code number;
exec package1.test_hello('Albert',:o_message, :o_return_code);
print o_message;
print o_return_code;




2020/01/05

[Java] JCommander Quck Start

Requirement
Assume I will run my jar file with one parameter as following:
F:\git\batch-job\target>java -jar batch-0.0.1-SNAPSHOT.jar -name Job2

Maven Dependency
Add JCommander in your pom.xml
    <properties>
        <java.version>1.8</java.version>
        <com.beust.jcommander.version>1.78</com.beust.jcommander.version>
    </properties>
    
    <dependencies>
        <dependency>
            <groupId>com.beust</groupId>
            <artifactId>jcommander</artifactId>
            <version>${com.beust.jcommander.version}</version>
        </dependency>
    </dependencies>


Create Argument Class
package com.test.batch.parameter;

import com.beust.jcommander.Parameter;
import lombok.Data;

@Data
public class BatchJobArgument {

    @Parameter(names = "-name", description = "batch job name")
    private String name;

    @Parameter(names = {"-help", "-h"}, help = true, description = "display help message")
    private boolean help;

}


Update Spring boot application class
package com.test.batch;

import com.beust.jcommander.JCommander;
import com.test.batch.parameter.BatchJobArgument;
import com.test.batch.service.JobExecutor;
import com.google.common.base.Strings;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.Banner;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@Slf4j
@SpringBootApplication
public class BatchApplication implements CommandLineRunner {

    private final JobExecutor jobExecutor;

    public BatchApplication(JobExecutor jobExecutor) {
        this.jobExecutor = jobExecutor;
    }

    public static void main(String[] args) {
        SpringApplication app = new SpringApplication(BatchApplication.class);
        app.setBannerMode(Banner.Mode.OFF);
        app.run(args);
    }

    @Override
    public void run(String... args) {
        BatchJobArgument arguments = new BatchJobArgument();

        JCommander jCommander = JCommander.newBuilder().build();
        jCommander.addObject(arguments);
        jCommander.parse(args);

        if(arguments.isHelp()){
            jCommander.usage();
            return;
        }

        log.debug("arguments = {}", arguments);

        if(Strings.isNullOrEmpty(arguments.getName())) {
            log.debug("Please assign job name (ex. -name Job1)");
        }else{
            jobExecutor.execute(arguments.getName());
        }
    }

}


Check result
[           main] com.test.batch.BatchApplication  : arguments = BatchJobArgument(name=Job2)






2020/01/04

[Spring Boot] How to implement Spring Boot Console Application

Maven Dependency
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.0.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>
    </dependencies>
Then using Spring's @SpringBootApplication annotation on our main class to enable auto-configuration.

This class also implements Spring's CommandLineRunner interface. CommandLineRunner is a simple Spring Boot interface with a run method. Spring Boot will automatically call the run method of all beans implementing this interface after the application context has been loaded.
package com.test.batch;

import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.Banner;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@Slf4j
@SpringBootApplication
public class BatchApplication implements CommandLineRunner {

    private final JobExecutor jobExecutor;

    public BatchApplication(JobExecutor jobExecutor) {
        this.jobExecutor = jobExecutor;
    }

    public static void main(String[] args) {
        SpringApplication app = new SpringApplication(BatchApplication.class);
        app.setBannerMode(Banner.Mode.OFF);
        app.run(args);
    }

    @Override
    public void run(String... args) {
        // receive arguments in run method
        if (args != null && args.length > 0) {
            String argument = args[0];
            log.debug("argument = {}", argument);
            jobExecutor.execute(argument);
        } else {
            log.debug("no argument found");
        }
    }

}

2020/01/03

[Spring Boot] How to disable Spring logo banner

Problem
When starting my Spring Boot project, I always have Spring logo banner as bellows:



How-To
You need to modify spring main class.
As-is
package com.esb.batch;

import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.Banner;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@Slf4j
@SpringBootApplication
public class BatchApplication implements CommandLineRunner {

    public static void main(String[] args) {
         SpringApplication.run(BatchApplication.class, args);
    }

}


To-be (set banner mode to off):
package com.esb.batch;

import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@Slf4j
@SpringBootApplication
public class BatchApplication implements CommandLineRunner {

    public static void main(String[] args) {
        SpringApplication app = new SpringApplication(BatchApplication.class);
        app.setBannerMode(Banner.Mode.OFF);
        app.run(args);
    }
    
}


Check the result: