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".
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.
I will introduce an example of returning an image as a reply from BOT as follows
** Execution example **
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;
}
}
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.
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.
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;
}
In this example, the user image 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));
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.
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;
}
}
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.
In the previous example, all the choices were PostbackAction, but here we will use URIAction, which jumps to the website when tapped.
** Execution example **
Tap an option (here "Google" or "Bing") and Jumps to the specified website (inline) as shown below.
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;
}
}
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);
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>
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();
}
}
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
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
--- 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