Easy to make LINE BOT with Java Servlet Part 2: I tried image messages and templates

I will introduce how to easily create LINE BOT using Java Servlet. The complete source code I introduced can be found at https://github.com/riversun/line-bot-servlet-examples.git

This is a sequel to the previous post "Making LINE BOT easily with Java Servlet".

Increase the variation of interaction with LINE BOT

This time, previous I tried 4 images and dialogs in addition to the text messages introduced.

We will continue to implement LINE BOT as ** Suppin's Java Servlet ** by utilizing LINE's Messaging API.

[Part 1] Return the image as a reply from the BOT

I will introduce an example of returning an image as a reply from BOT as follows

** Execution example ** example02.png

Source code

LineBotExample02Servlet.java


@SuppressWarnings("serial")
public class LineBotExample02Servlet extends LineBotServlet {

	private static final String CHANNEL_SECRET ="Put what you got";
	private static final String CHANNEL_ACCESS_TOKEN ="Put what you got";

	@Override
	protected ReplyMessage handleTextMessageEvent(MessageEvent<TextMessageContent> event) throws IOException {

		//Messages sent by users to BOT
		TextMessageContent userMessage = event.getMessage();

		//Get the user's profile
		UserProfileResponse userProfile = getUserProfile(event.getSource().getUserId());

		//Reply message from BOT
		String botResponseText = userProfile.getDisplayName() + "Mr."
				+ "「" + userMessage.getText() + "I said";

		//Text message for reply
		TextMessage textMessage = new TextMessage(botResponseText);

		//Image for reply(image)URL
		final String originalContentUrl = "https://riversun.github.io/img/riversun_256.png ";
		final String previewImageUrl = "https://riversun.github.io/img/riversun_144.png ";

		//Image for reply(image)message
		ImageMessage imageMessage = new ImageMessage(originalContentUrl, previewImageUrl);

		//Returns text message and image at the same time
		return new ReplyMessage(event.getReplyToken(), Arrays.asList(imageMessage, textMessage));
	}

	@Override
	protected ReplyMessage handleDefaultMessageEvent(Event event) {
		//Do nothing if you receive a message that is not overridden(Returns null)
		return null;
	}

	@Override
	public String getChannelSecret() {
		return CHANNEL_SECRET;
	}

	@Override
	public String getChannelAccessToken() {
		return CHANNEL_ACCESS_TOKEN;
	}

}

Commentary

Returning an image is very simple, Create an ImageMessage object by specifying the URL of the image (original, preview, both of which may be the same) as shown below.


  //Image for reply(image)URL
        final String originalContentUrl = "https://riversun.github.io/img/riversun_256.png ";
        final String previewImageUrl = "https://riversun.github.io/img/riversun_144.png ";

        //Image for reply(image)message
        ImageMessage imageMessage = new ImageMessage(originalContentUrl, previewImageUrl);

Then just reply as follows:


        //Returns text message and image at the same time
        return new ReplyMessage(event.getReplyToken(), Arrays.asList(imageMessage, textMessage));

If you specify a message with List <> like ʻArrays.asList (imageMessage, textMessage) `, multiple messages will be returned from the BOT in the specified order.

[Part 2]: The user sends an image to the BOT

The following is an example in which the BOT side receives and processes the image sent from the user.

** Execution example **

In this way, the image sent by the user is saved in a file on the BOT side. example03.png

Source code

LineBotExample03Servlet.java



public class LineBotExample03Servlet extends LineBotServlet {

	private static final String CHANNEL_SECRET ="Put what you got";
	private static final String CHANNEL_ACCESS_TOKEN ="Put what you got";

	@Override
	protected ReplyMessage handleTextMessageEvent(MessageEvent<TextMessageContent> event) throws IOException {
		return new ReplyMessage(event.getReplyToken(), Arrays.asList(new TextMessage("Send me an image")));
	}

	@Override
	protected ReplyMessage handleImageMessageEvent(MessageEvent<ImageMessageContent> event) throws IOException {

		//Click here for Content https://devdocs.line.me/ja/#content
		InputStream is = getContentStream(event.getMessage());

		//Image file save destination path
		String tempImageFilePath = System.getProperty("user.dir") + "/" + "line_img_" + System.currentTimeMillis() + ".jpg ";

		//Save file
		Files.copy(is, Paths.get(tempImageFilePath));

		return new ReplyMessage(event.getReplyToken(), Arrays.asList(new TextMessage("Thanks for the image!")));

	}

	@Override
	protected ReplyMessage handleDefaultMessageEvent(Event event) {
		//Do nothing if you receive a message that is not overridden(Returns null)
		return null;
	}

	@Override
	public String getChannelSecret() {
		return CHANNEL_SECRET;
	}

	@Override
	public String getChannelAccessToken() {
		return CHANNEL_ACCESS_TOKEN;
	}

Commentary

In this example, the user imageChara2.png is sent and the BOT is It receives it and returns a response.

The source code overrides ** LineBotServlet # handleImageMessageEvent ** to receive the image from the user.


@Override
	protected ReplyMessage handleTextMessageEvent(MessageEvent<TextMessageContent> event) throws IOException

The key to this example is here

InputStream is = getContentStream(event.getMessage());

Gets the stream of images sent.

If you touch on the internal processing a little, the API of LINE is Webhook event when an image is sent from the user. ImageMessage is POSTed to the Webhook URL, but the Imagemessage itself is only notified that ** the image will be sent **, and the actual image is not sent.

Therefore, when you receive an ImageMessage, you need to use the ID listed there to download the image separately, which is Content. It is an API called

In the above getContentStream (event.getMessage ());, access the Content API and download the image (pull the stream to download) doing.

If you read the explanation of API

Content is automatically deleted some time after the message is sent. There is no guarantee as to how long it will be stored.

Because it says, you need to download it first.

This mechanism is used every time when dealing with large contents such as video and audio as well as images.

In this example, the downloaded image file is saved in the ** current directory **.

String tempImageFilePath = System.getProperty("user.dir") + "/" + "line_img_" + System.currentTimeMillis() + ".jpg ";

Files.copy(is, Paths.get(tempImageFilePath));

[Part 3] Example of selecting from multiple options using a template message

Next, let's use a template message.

The template message is detailed at https://devdocs.line.me/ja/#template-message

Template message is a message constructed by inserting custom data into a template with a predefined layout.

is. It's compatible with LINE 6.7.0 and later for iOS and Android, and now you can use templates that look like dialog widgets where you can choose one from multiple choices.

It seems to be useful in scenes such as product selection and hotel reservations, where processing is proceeded according to a certain fixed flow.

** Execution example **

This time, I created the following interface to select one favorite dish.

example04.png

Source code

LineBotExample04Servlet.java



public class LineBotExample04Servlet extends LineBotServlet {

	private static final String CHANNEL_SECRET ="Put what you got";
	private static final String CHANNEL_ACCESS_TOKEN ="Put what you got";

	@Override
	protected ReplyMessage handleTextMessageEvent(MessageEvent<TextMessageContent> event) throws IOException {

		UserProfileResponse userProfile = getUserProfile(event.getSource().getUserId());

		String thumbnailImageUrl = "https://riversun.github.io/img/riversun_256.png ";

		String title = "Cooking genre selection";
		String text = userProfile.getDisplayName() + "What kind of food do you like?";

		Action japaneseCuisine = new PostbackAction("Japanese food", "japanese");
		Action italianCuisine = new PostbackAction("Italian", "italian");
		Action frenchCuisine = new PostbackAction("French", "french");

		List<Action> actions = Arrays.asList(japaneseCuisine, italianCuisine, frenchCuisine);

		ButtonsTemplate buttonsTemplate = new ButtonsTemplate(thumbnailImageUrl, title, text, actions);

		String altText = title;

		return new ReplyMessage(event.getReplyToken(), new TemplateMessage(altText, buttonsTemplate));
	}

	@Override
	protected ReplyMessage handlePostbackEvent(PostbackEvent event) {
		//The result of the user's selection in ButtonsTemplate is returned as this PostBackEvent

		PostbackContent postbackContent = event.getPostbackContent();

		//Get the data set in PostbackAction
		String data = postbackContent.getData();

		final String replyText;

		if ("japanese".equals(data)) {
			replyText = "I like Japanese food.";
		} else if ("italian".equals(data)) {
			replyText = "Italian is good, isn't it?";
		} else {
			replyText = "French, I also want to eat.";
		}

		return new ReplyMessage(event.getReplyToken(), Arrays.asList(new TextMessage(replyText)));
	}

	@Override
	protected ReplyMessage handleDefaultMessageEvent(Event event) {
		//Do nothing if you receive a message that is not overridden(Returns null)
		return null;
	}

	@Override
	public String getChannelSecret() {
		return CHANNEL_SECRET;
	}

	@Override
	public String getChannelAccessToken() {
		return CHANNEL_ACCESS_TOKEN;
	}

}

Commentary

There are currently three templates available. --Buttons Layout of multiple buttons (up to 4) and images -Confirm Allows you to select 2 options such as YES and NO -Carousel Presents a set of choices side by side

You can set choices in the template, but the equivalent is Actions (https://devdocs.line.me/en/#template-action).

There are currently three Actions (https://devdocs.line.me/ja/#template-action) available. --Postback action Tap to generate a postback event --Message action Tap to send as user's remark --URI action Tap to open the URI specified in the browser

In this example, we used the Buttons Template (https://devdocs.line.me/ja/#buttons) as the template.

The action specified PostbackAction.

 Action japaneseCuisine = new PostbackAction("Japanese food", "japanese");
        Action italianCuisine = new PostbackAction("Italian", "italian");
        Action frenchCuisine = new PostbackAction("French", "french");

        List<Action> actions = Arrays.asList(japaneseCuisine, italianCuisine, frenchCuisine);

When PostbackAction is tapped, Postback event will occur internally. I overridden handlePostbackEvent to receive this.

 protected ReplyMessage handlePostbackEvent(PostbackEvent event) 

What was tapped is determined by getting the data specified as the second argument of new PostbackAction ("Italian", "italian") as follows.

String data = postbackContent.getData();

You now have a fixed message selection interface.


[Part 4] Example of linking template message choices

In the previous example, all the choices were PostbackAction, but here we will use URIAction, which jumps to the website when tapped.

** Execution example ** example05.png

Tap an option (here "Google" or "Bing") and Jumps to the specified website (inline) as shown below.

example05_b.png

Source code

LineBotExample05Servlet.java


public class LineBotExample05Servlet extends LineBotServlet {

	private static final String CHANNEL_SECRET ="Put what you got";
	private static final String CHANNEL_ACCESS_TOKEN = "Put what you got";

	@Override
	protected ReplyMessage handleTextMessageEvent(MessageEvent<TextMessageContent> event) throws IOException {

		String thumbnailImageUrl = "https://riversun.github.io/img/riversun_256.png ";

		String title = "Favorite search engine";
		String text = "Choose your favorite search engine";

		Action google = new URIAction("Google", "https://www.google.co.jp");
		Action bing = new URIAction("Bing", "https://www.bing.com");
		Action other = new PostbackAction("Other", "other");

		List<Action> actions = Arrays.asList(google, bing, other);

		ButtonsTemplate buttonsTemplate = new ButtonsTemplate(thumbnailImageUrl, title, text, actions);

		String altText = title;

		return new ReplyMessage(event.getReplyToken(), new TemplateMessage(altText, buttonsTemplate));
	}

	@Override
	protected ReplyMessage handlePostbackEvent(PostbackEvent event) {

		PostbackContent postbackContent = event.getPostbackContent();

		String data = postbackContent.getData();

		if ("other".equals(data)) {
			return new ReplyMessage(event.getReplyToken(), new TextMessage("I like other search engines."));
		} else {
			return null;
		}

	}

	@Override
	protected ReplyMessage handleDefaultMessageEvent(Event event) {
		//Do nothing if you receive a message that is not overridden(Returns null)
		return null;
	}

	@Override
	public String getChannelSecret() {
		return CHANNEL_SECRET;
	}

	@Override
	public String getChannelAccessToken() {
		return CHANNEL_ACCESS_TOKEN;
	}

}

Commentary

Tap URIAction to open the browser with the specified URI. Since it is possible to mix multiple types of actions, I tried to mix URIAction and PostbackAction below.

Action google = new URIAction("Google", "https://www.google.co.jp");
        Action bing = new URIAction("Bing", "https://www.bing.com");
        Action other = new PostbackAction("Other", "other");

        List<Action> actions = Arrays.asList(google, bing, other);

Easy to try on your local PC

You can also try this sample locally with Jetty and ngrok without uploading it to the server or cloud.

Add the following to Gradle / Maven.

Gradle compile 'org.eclipse.jetty:jetty-server:9.4.0.v20161208' compile 'org.eclipse.jetty:jetty-webapp:9.4.0.v20161208'

Maven


<dependency>
	<groupId>org.eclipse.jetty</groupId>
	<artifactId>jetty-server</artifactId>
	<version>9.4.0.v20161208</version>
</dependency>
<dependency>
	<groupId>org.eclipse.jetty</groupId>
	<artifactId>jetty-webapp</artifactId>
	<version>9.4.0.v20161208</version>
</dependency>

Launch Jetty

After writing in Gradle / Maven, write and execute the code as follows. If you uncomment the commented out part as appropriate, the sample introduced above will work.

AppMain.java


public class AppMain {

	public static void main(String[] args) throws Exception {

		ServletHandler handler = new ServletHandler();

		handler.addServletWithMapping(LineBotExample01Servlet.class, "/callback");
		//handler.addServletWithMapping(LineBotExample02Servlet.class, "/callback");
		//handler.addServletWithMapping(LineBotExample03Servlet.class, "/callback");
		//handler.addServletWithMapping(LineBotExample04Servlet.class, "/callback");
		//handler.addServletWithMapping(LineBotExample05Servlet.class, "/callback");

		// loclahost:Launch Jetty at 3000
		Server jetty = new Server(3000);

		jetty.setHandler(handler);
		jetty.start();
		jetty.join();

	}

}

Make it accessible from the outside

Even if you launch it locally, you need to deploy it to the server and publish it to the outside in order to behave as a LINE BOT. Let's make the server created using Jetty accessible from the outside so that you can easily try it for testing purposes.

Here, we use a service called ngrok that is perfect for this purpose.

Download ngrok from the following https://ngrok.com/download

At the command line ngrok http -region=ap 127.0.0.1:3000

Then ngrok will start and the following screen will be displayed ngrok.png

With just this The url https://xxxxx.ap.ngrok.io has been mapped to https://127.0.0.1:3000!

_ (The xxxxx part changes randomly every time you start ngrok. You can fix it by signing up) _

This is convenient because https is required for the web hook url of LINE BOT.

At this point, all you have to do is register the following url in the Web Hook URL. https://xxxxx.ap.ngrok.io/callback

[Summary]

--- Following Last time, I tried the LINE BOT API using Java's Suppin HttpServlet. ――I was able to easily create message replies other than text messages. --The complete source code introduced can be found at https://github.com/riversun/line-bot-servlet-examples.git

Recommended Posts

Easy to make LINE BOT with Java Servlet Part 2: I tried image messages and templates
Easy to make LINE BOT with Java Servlet
I tried to make Basic authentication with Java
I want to make a list with kotlin and java!
I want to make a function with kotlin and java!
I tried to make Java Optional and guard clause coexist
I tried to interact with Java
I tried to make an Android application with MVC now (Java)
I made a virtual currency arbitrage bot and tried to make money
I tried to make a machine learning application with Dash (+ Docker) part1 ~ Environment construction and operation check ~
I tried to verify AdoptOpenJDK 11 (11.0.2) with Docker image
I tried to break a block with java (1)
[LINE @] I tried to make a Japanese calendar Western calendar conversion BOT [Messaging API]
I tried to make a machine learning application with Dash (+ Docker) part3 ~ Practice ~
[Java] I tried to connect using a connection pool with Servlet (tomcat) & MySQL & Java
[Java] I installed JDBC and tried to connect with servlet + MySQL. (There is a version using DAO / Bean)
I tried to read and output CSV with Outsystems
I tried to implement TCP / IP + BIO with JAVA
[Java 11] I tried to execute Java without compiling with javac
Let's make a LINE Bot with Ruby + Sinatra --Part 2
I started MySQL 5.7 with docker-compose and tried to connect
I tried to make a login function in Java
I want to transition screens with kotlin and java!
Let's make a LINE Bot with Ruby + Sinatra --Part 1
I used to make nc (netcat) with JAVA normally
I tried to create a shopping site administrator function / screen with Java and Spring
I tried to make an introduction to PHP + MySQL with Docker
I tried to create a java8 development environment with Chocolatey
Easy to make LINE BOT with Java Servlet Part 2: I tried image messages and templates
Since the Rspec command is troublesome, I tried to make it possible to execute Rspec with one Rake command
About the matter that I was addicted to how to use hashmap
I wanted to make JavaFX programming easier with the Spring Framework
I tried to modernize a Java EE application with OpenShift.
I tried to summarize the basics of kotlin and java
I tried to make a client of RESAS-API in Java
I want to implement various functions with kotlin and java!
I tried OCR processing a PDF file with Java part2
I tried to make a machine learning application with Dash (+ Docker) part2 ~ Basic way of writing Dash ~
I tried to implement the image preview function with Rails / jQuery
I tried to summarize the methods of Java String and StringBuilder
[Java] I tried to make a maze by the digging method ♪
I tried to make a group function (bulletin board) with Rails
Java to learn with ramen [Part 1]
I tried UDP communication with Java
I tried to summarize Java learning (1)
I tried to summarize Java 8 now
I tried to figure out the flow when performing image analysis with Vision Framework and Core ML
I want to display images with REST Controller of Java and Spring!
I tried to make an automatic backup with pleasanter + PostgreSQL + SSL + docker
[iOS] I tried to make a processing application like Instagram with Swift
I tried to make a Web API that connects to DB with Quarkus
I tried to make my own transfer guide using OpenTripPlanner and GTFS
I tried to make a talk application in Java using AI "A3RT"
[LINE BOT] I made a ramen BOT with Java (Maven) + Heroku + Spring Boot (1)
How to make an app with a plugin mechanism [C # and Java]
I tried to measure and compare the speed of GraalVM with JMH
I tried to summarize Java lambda expressions
I tried to get started with WebAssembly
How to make a Discord bot (Java)
I tried using OpenCV with Java + Tomcat
I tried to make a program that searches for the target class from the process that is overloaded with Java
Easy to trip with Java regular expressions
I tried to touch JavaScript Part.2 Object-oriented
Let's create a TODO application in Java 2 I want to create a template with Spring Initializr and make a Hello world