Merry Christmas! It is the last day of "Java Advent Calendar 2020". I changed the title to make it more fun (?) Like Christmas. I thought it was just an introduction to the library, but it's Christmas and I'm going to use the library to create a useful web service. It explains RESTful web services from the basics, so it is recommended for anyone who wants to know this field.
The details of the library are summarized at the end of the post, so if you are interested, please have a look there first.
In other words,
Mr. ○○ Hello,···.
It is a service that sends an email to all the people on the list at once, saying that the address and title are attached and the contents are the same (the point is that the address and title are attached). Sending an email uses a library, so it only takes a few lines, and the sending service should be easy to write using the Jakarta REST mechanism. By the way, the development / execution environment of Jakarta REST can be prepared in 5 minutes using JET, so even if you are new to Jakarta REST, please try it.
(** You can download JET from here **. There are also instructions and videos on how to use it.)
On the other hand, the client program that uses the service simply creates a web screen and sends the data by POST, so it can be created in any language such as PHP and Javascript. This is one of the strengths of web services. However, Java also has a ** client API **, so there is no inconvenience even if you make it in Java.
(Please ** Download the project from here ** of the mail sending service and client program explained below. Also, the ** Important.txt ** file included in the project is SMTP. There is a note about the server settings. Be sure to read it before using it.)
Let's look at the visible results first. This is the screen of the client that uses the service.
The upper row is the area for writing the contents of the email, and the lower row is the list screen. The list uploads an Excel file. Since it is an automatic upload, just select the file and it will be uploaded and the contents will be displayed. The check box on the far left is a selection field for whether to use it as a destination. Initially, everyone is targeted, but you can uncheck unnecessary destinations.
RESTful web services do the job for you when you access a specific URI (almost the same as the URL) with GET or POST. There is no API-like method call, and the corresponding processing is executed by simple HTTP access. The combination of "modes" such as GET, POST, PUT, and DELETE and the URI to be accessed distinguishes what kind of work is done. At the same time as accessing, you can pass the necessary data using URL parameters and POST data.
URI is
http: // server/project/service/path /
Configure as follows.
For example
Server: localhost: 8080
Project name: mailservice
Overall service name: sendmail
One service name (here, send a broadcast email): cc
If you name it, the URI looks like this:
http://localhost:8080/mailservice/sendmail/cc/
There are text mail and HTML mail in the mail, so you can cut the subpath further and do as follows.
http://localhost:8080/mailservice/sendmail/cc/text
This is the URI for broadcasting text mail. HTML mail
http://localhost:8080/mailservice/sendmail/cc/html
Anyway, you should do it.
This is easy because it uses Jakarta REST (= JAX-RS). First of all, there is no problem because the project name is the name of the created project. Other than that, all you have to do is add certain annotations to the classes and methods in your project. First, for the service (sendmail) part, create an empty class (any name) and add @ApplicationPath ("sendmail") as follows. Only this.
ServerConfig.java
@ApplicationPath("sendmail")
public class ServiceConfig extends Application {
}
Next, for the path representing the individual service, create another class (any name is Sender class) and add @Path ("cc"). Then create a concrete service feature within this Sender class.
Sender.java
@Path("cc")
public class Sender {
}
Finally, the subpath text, which adds @Path ("text") to the method (send method) that is actually in charge of processing in the Sender class. Also, since it is a method that is accessed by POST, add the @POST annotation.
Sender.java
@Path("cc")
public class Sender {
@Path("text")
@POST
public Response send(DataSet data){
}
}
With this alone, the URI corresponding to POST access,
http://localhost:8080/mailservice/sendmail/cc/text
Was able to be configured. On the client side, POST access to this URI invokes the send method.
All you have to do now is create the contents of the send method. How is it easy!
Oh yeah, I forgot to explain the arguments and return types of the send method.
First, you can pass any type of object as an argument. Here, we are passing the DataSet type. The DataSet type is the class created this time, and the content includes all the data necessary for sending, such as the email title, body, and recipient list. When the client side sends this object with POST access, the server side can receive it in the argument of the send method, DataSet data
. The field variables of the DataSet class are:
DataSet.java
public class DataSet {
private String sender; //Sender email address
private String title; //Email title
private String message; //Body or HTML text
private String type; // "CC" or "BCC" or "TO"
private List<Recipient> dlist; //List of destinations
Of the field variables, List <Recipient> dlist
is the destination List. The Recipient class looks like this:
Recipient.java
public class Recipient {
private boolean flag; //For recording the status (use is arbitrary, such as whether to send)
private String id; //Number, ID, etc.
private String name; //name
private String email; //mail address
private String mr; //Honorific titles (sama, lord, teacher, etc.)
These objects are actually automatically converted to JSON or XML format data and passed. Therefore, clients other than the Java language can pass the same thing using JSON or XML. In other words, there are no programming language restrictions.
If you do not specify the data format to be passed, it will be decided appropriately (usually JSON), but you can specify the format to exchange with annotations. Next is the specification to use JSON or XML.
@Produces
specifies the format of the data returned by the send method, and @Consumes
specifies the format of the data received by the send method as an argument. If you specify multiple formats like this (roughly speaking), you can handle one of them on the client side.
Sender.java
@Path("cc")
@Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
@Consumes({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
public class Sender {
@Path("text")
@POST
public Response send(DataSet data){
}
}
Oh yeah, I was inadvertent. Annotate the class with @XmlRootElement for objects that may interact in XML format. That's all it takes to automatically convert to XML (nothing needs to be done with JSON).
DataSet.java
@XmlRootElement
public class DataSet {
The method usually returns an object of type Response
. The Response class is a convenient all-in-one object that can contain various response headers and their values, a status that represents the execution result, an object to return to the caller, and so on. Sent according to HTTP conventions, client programs can receive them in a standard way specific to their respective languages. I'll explain how to do it in the Java language later.
The process of the send method is as simple as:
Sender.java
@Path("/text")
@POST
public Response send(DataSet data) {
EmailStatus result = semdMails(data); //Email sending process
reply(data,result); //Notify the client of the transmission result by email
return Response
.ok()
.build();
}
sendMails (data) is the part that actually sends the mail, and reply (data, result) is the part that notifies the client of the sending result (the content will be explained later). However, there is a slight problem as it is. That's because if you have dozens of emails to send, you can expect it to take tens of seconds to send. During that time, blocking will occur and you will not be able to return a response to the client. The client has to wait for a while, which makes me feel very uneasy.
This is where multithreading comes in. For the time being, while executing the transmission process asynchronously in another thread, return a message like "I will send it now" to the client with return Response ....
.
The sendMails method returns the execution result as a return value, so use this to notify the client of the result with the reply method. So the sendMails and reply methods are a series of inseparable processes. Therefore, there is no choice but to execute the two together in one thread ...
By the way, do you know the ** ComputableFutuer ** class? This class was introduced from Java 8 to handle the above problems in a cool way. It's Christmas, so let's write it cool here.
Sender.java
@Path("/text")
@POST
public Response send(DataSet data) {
CompletableFuture.supplyAsync(()->sendMails(data))
.thenAccept(result->reply(data,result));
return Response
.ok("Start sending. After this, you will receive an email with the result of sending.")
.build();
}
How about it, I was able to write it pretty smartly.
ComputableFuture first executes the sendMails method asynchronously with the ** supplyAsync ** method, and when it finishes and returns a return value (result in the program), it uses it to reply with the ** thenAcceput ** method. Executes the method asynchronously. The thenAcceput method is a method that can receive the result of the asynchronous process of the previous stage and use it to execute the next process asynchronously.
The whole is stylishly written in the method chain. Computable Future is convenient because you can do all this in one sentence. Note that supplyAsync and thenAccept take the method to be executed as an argument, so the argument is to be written as a ** lambda expression **.
Those who say, "But the lambda expression is ..." are okay. You just need to understand what you're doing here. For lambda expressions, please refer to " Easy-to-understand Java object-oriented thorough explanation
"(^ _ ^ ;. Also, in the same book, Computable Future is also explained in detail.
Next, I will explain how to write a return statement in the send method. The return in the send method is the content that is sent as a response to the client as it is. The return is an object of the Respose class. Create it using the class method of the Response class as follows:
Sender.java
return Response
.ok("Start sending. After this, you will receive an email with the result of sending.")
.build();
You can write in a method chain like this because the Response class has the following class methods.
Return type | Method name | Function |
---|---|---|
ResponseBuilder | ok() | status"OK"Is set in the response |
ResponseBuilder | ok(obj) | status"OK"And the object obj in the response |
ResponseBuilder | status(statusValue) | Set any status |
The return type of these methods is ResponseBuilder type, but since this class has the following methods, it is a mechanism to finally return it as Response type with the build () method while including the object and status. is.
Return type | Method name | Function |
---|---|---|
ResponseBuilder | entity(object) | Include any object in the response |
ResponseBuilder | header(name, value) | Set any header and its value in the response |
Response | build() | Create a Response instance |
Here are some writing patterns:
How to write | Taste |
---|---|
Response.ok().build() | status"OK"return it |
Response.ok("Done").build() | status"OK"と「Done」という文字列を返す |
Response.status(Status.BAD_REQUEST).build() | status"BAD_REQUEST"return it |
Response.status(Status.BAD_REQUEST).entity("Parameter error").build() | "BAD_REQUEST"And return a message |
Response.ok(obj).build() | status"OK"And return the object obj |
You can create flexible responses by combining methods. Regarding the result status, if only the main ones are shown, there are the following. The status value can be an Enum or an integer.
status | Taste |
---|---|
Status.OK | 200 OK |
Status.CREATED | 201 Created |
Status.ACCEPTED | 202 Approved |
Status.NO_CONTENT | 204 No content |
Status.BAD_REQUEST | 400 Request is incorrect |
Status.FORBIDDEN | 403 forbidden |
Status.FOUND | 302 found |
Status.NOT_FOUND | 403 not found |
Status.REQUEST_TIMEOUT | 408 Request timed out |
Status.CONFLICT | 409 Conflicting |
Now let's create a sendMails method that actually sends the email. The SendMails method is easy to create using the SendMail library. The library also has a method for batch sending by BCC or CC, but since each email is given an address and title, it is necessary to send one individually here.
In order to handle such cases, the ** EmailSender ** class of the library has methods (** connect () **, ** xsend () that connect, send, and disconnect to the mail server individually. Since there are **, ** disconnect () **), use these and write as follows.
Sender.java
@Inject EmailSender es; //Get an instance of EmailSender
....
//Connect to mail server
es.connect();
//Send email to all destinations
List<Recipient> rs = data.getDlist(); //Retrieving the destination list
for(Recipient r : rs){
//Processing to add address and title to email body
.....
//Transmission process
es.xsend(destination address,title,Text);
}
//Disconnect from mail server
es.disconnect();
Variable declarations, annotations attached to EmailSender es;
, and ** @ Inject ** are used when receiving from the system without creating an instance of the object with new. If you annotate the variable declaration with @Inject, the system will instantiate the EmailSender class and put it in the variable es.
This is called "** (context and) dependency injection **". In the world of enterprise Java, not just Jakarta EE, it is common to get an instance by "dependency injection". Actually, it creates an instance using a constructor with no arguments, but it is quite convenient because you do not have to write new.
The rest of the story is about using EmailSender's methods to connect to a mail server, send as many emails as you need, and finally disconnect. It's easy. However, this is a "synopsis", so we need to consider the content a little more.
There is nothing wrong with it. The text will be rewritten before sending as follows.
Sender.java
//Send
//Send email to all destinations
List<Recipient> rs = data.getDlist(); //Retrieving the destination list
for(Recipient r : rs){
//Processing to add address and title to email body
StringBuilder sb = new StringBuilder();
sb.append(r.getName()).append(" ") //address
.append(r.getMr()).append("\n") //Honorific title
.append(data.getMessage()); //the content of the email
//Transmission process
es.xsend(r.getEmail(), data.getTitle(), sb.toString());
}
I use the for statement to send as many emails as there are recipient lists, but at that time I add the address and title (both are included in the field variable of the Recipient class) before the body. ..
The connect (), send (), and disconnect () methods return the status of the execution result as an EmailStatus type value (enumeration type).
status | Taste |
---|---|
EmailStatus.DONE | Successful completion |
EmailStatus.INIT_ERROR | Incorrect connection parameter |
EmailStatus.CONNECT_ERROR | can not connect |
EmailStatus.SEND_ERROR | Failed to send email |
EmailStatus.DISCONNECT_ERROR | Error when disconnecting |
Therefore, when an error occurs in the connection phase, the process is stopped and the status is returned. Also, if an error occurs while sending an email (due to incorrect email address format), write false to the destination (Recipient object) and continue processing. In other words, it keeps a record. This will allow you to report unsent destinations later when the reply () method emails the execution result. Note that the cut face is the last process, so you can simply return the status.
From the above, the completed sendMails method looks like this:
Sender.java
//Send plaintext / multiple emails
private EmailStatus sendMails(DataSet data){
//Connect to mail server
EmailStatus sts = es.connect();
if(sts!=EmailStatus.DONE) return sts; //Exit if error
//Send email to all destinations
List<Recipient> rs = data.getDlist(); //Retrieving the destination list
for(Recipient r : rs){
StringBuilder sb = new StringBuilder(); //Rewrite the text
sb.append(r.getName()).append(" ") //address
.append(r.getMr()).append("\n") //Honorific title
.append(data.getMessage()); //the content of the email
sts = es.xsend(r.getEmail(),data.getSender(), data.getTitle(), sb.toString());
if(sts!=EmailStatus.DONE) r.setFlag(false); //Add false to the destination of the transmission error
}
//Disconnect from mail server
sts = es.disconnect(); //Returns status
return sts;
}
By the way, if the format of the email address is incorrect, it can be caught as a transmission error, but if the format is correct, even the wrong email address will be sent as it is. You may get a return email later, but what to do with it is another matter.
Generally, when you want to register your e-mail address, send a confirmation e-mail to the person and if there is a return, follow the procedure of registration. If you follow this procedure, your email address will not be incorrect. However, if the registrant discards or changes the email address, nothing will happen, so it is necessary to send a confirmation email from time to time to check it. Of course, you can add such a service to this system, but why not try it?
Finally, create a reply () method to notify the result by email after the transmission is completed. The arguments of the reply () method are the sent data (DataSet) and the result status (EmailStatus).
Sender.java
//Sending result notification email
private void reply(DataSet data, EmailStatus status){
....
es.send(data.getSender(), "Notification of transmission result",Text);
}
To send an email, just use the send () method of the J-mail library.
The send () method without x is
send (destination, title, body)
It is a convenience method used in the form of, and it also connects and disconnects to the mail server.
Sending is easy, but the hassle is that you have to create the text. In the body, add a notification of the transmission result, the number of emails, the email address that could not be sent, and a copy of the body sent. So, first, get those data as follows:
Sender.java
//Sending result notification email
private void reply(DataSet data, EmailStatus status){
String result = returnMessage(status); //① Convert to message
int all = data.getDlist().size(); //② Total number
int done = doneMails(data); //③ Number of transmissions
int errs = all - done; //④ Number of errors
String errors = errMails(data); //⑤ Error address (CSV)
....
es.send(data.getSender(), "Notification of transmission result",Text);
}
Now, let's check the execution contents in order.
String result = returnMessage (status); // Convert to message
In the returnMessage method, the status of the execution result is converted to a message string and returned. The returnMessage method is converted with a simple switch statement as follows.
Sender.java
//Convert exit code to message and return
private String returnMessage(EmailStatus status){
switch(status){
case INIT_ERROR: return "User name / password is not set";
case CONNECT_ERROR: return "Could not send because it cannot connect to the SMTP server";
case SEND_ERROR: return "Could not send due to an unexpected error during sending";
case DISCONNECT_ERROR: return "Could not send due to an error when disconnecting";
default: return "Transmission completed";
}
}
int all = data.getDlist (). size (); // total number
data.getDlist () is a member dlist, a list of destination objects (Recipients). If you use size () to find the number of elements, you can get the number of emails requested to be sent.
int done = doneMails (data); // Number of transmissions
Use the doneMails method to find the number of emails actually sent. In the sendMails method above, the flag member of the recipient object (Recipient) that could not be sent was set to false, so the doneMails method uses it. In other words, the list (dlist) of destination objects (Recipient) is extracted from data, only the Recipient objects whose flag is true are extracted by stream processing, and the number is counted at the end.
Sender.java
//Returns the number sent
public int doneMails(DataSet data){
int n = (int)data.getDlist().stream()
.filter(Recipient::isFlag) //Only those with true flag
.count(); //Get the number
return n;
}
The filter method is a method that extracts only those that meet the conditions. The condition is Recipient :: isFlag
, which is written as a method reference. Same as the lambda expression r-> r.isFlag ()
, meaning r.isFlag () == true
. That is, if the value of the Flag field is true.
You can do the same with normal syntax without using stream processing or lambda expressions, but stream processing has the advantage of being concise.
int errs = all --done; // Number of errors
Calculate the number of errors by subtracting the number of sent items from the total number of items.
String errors = errMails (data); // Error address (CSV)
Use the errMails method to get the email address that caused the transmission error as a comma-separated string. Use stream processing in the same way as ③.
Sender.java
//Returns the address of the transmission error as a CSV character string
public String errMails(DataSet data){
String errors = data.getDlist().stream()
.filter(r->!r.isFlag()) //Only those with false flag
.map(Recipient::getEmail) //Only email address
.collect(Collectors.joining(",")); //Connect with commas
return errors;
}
The filter method, in turn, extracts only those whose flag member is false. The following map method is a conversion method. Here we will convert the stream of the Recipient object to the stream of the email. Recipient :: getEmail
is the same as the lambda expressionr-> r.getEmail ()
. In other words, since the email is fetched from the Recipient object r and sent to the stream, the Recipient stream changes to the email stream which is a string.
The last collect method is a method that performs high-order aggregation and conversion. Here, all the elements of the string stream are concatenated with commas to form a single string.
Writing the above in normal syntax would result in more than double the code. Stream processing is really powerful! ("Easy-to-understand Java object-oriented thorough explanation`" has a detailed explanation of stream processing.)
Once you have the data, the rest is easy. Use StringBuilder to create a string like this:
Sender.java
StringBuilder sb = new StringBuilder();
sb.append(result).append("\n\n")
.append("\t Number of receptions").append(all).append("Case\n")
.append("\t Number of transmissions").append(done).append("Case\n");
if(errs!=0){
sb.append("\n Unable to send").append(errs).append("Case\n")
.append("\t The following destination is invalid\n\t").append(errors);
}
es.send(data.getSender(), "Notification of transmission result", sb.toString());
It's so simple that no explanation is needed. You can now create the following email body:
From the above, the completed reply method is as follows.
Sender.java
//Sending result notification email
private void reply(DataSet data, EmailStatus status){
String result = returnMessage(status); //Convert to message
int all = data.getDlist().size(); //Total number
int done = doneMails(data); //Number of transmissions
int errs = all - done; //Number of errors
String errors = errMails(data); //Error address (CSV)
StringBuilder sb = new StringBuilder();
sb.append(result).append("\n\n")
.append("\t Number of receptions").append(all).append("Case\n")
.append("\t Number of transmissions").append(done).append("Case\n");
if(errs!=0){
sb.append("\n Unable to send").append(errs).append("Case\n")
.append("\t The following destination is invalid\n\t").append(errors);
}
es.send(data.getSender(), "Notification of transmission result", sb.toString());
}
Now it's client-side creation. When writing in Java language, use ** Jakarta REST Client API **. This client API provides methods for accessing by GET, POST, etc. by specifying the URI. You can also get an object of class Response as a return value from the service.
Using NetBeans as an IDE, service clients can be automatically generated. Create a new project called mailserviceClietn, create a class with a suitable name (here Multimail class), and perform the following steps.
① Place the cursor outside the class definition ② Select [Source] ⇒ [Insert Code] (3) A dialog opens, so select [Generate REST Client]. ④ Make sure that [Original Service] is selected, and press [Browse]. ⑤ The currently open project is displayed. ④ Expand the REST service project (mailservice in this case), select [Sender], and press [OK]. ⑤ The original dialog will be displayed. Enter SenderClient as the class name and press [OK].
With the above, SenderClient class is generated as an inner class in the current class.
The generated class looks like this: Some parts need to be corrected, so let's fix the corrected parts later.
Multimail.java
public class Multimail {
static class SenderClient {
private WebTarget webTarget;
private Client client;
private static final String BASE_URI = "http://localhost:8080/mailservice/sendmail";
public SenderClient() {
client = javax.ws.rs.client.ClientBuilder.newClient();
webTarget = client.target(BASE_URI).path("cc");
}
public Response send() throws ClientErrorException {
return webTarget.path("text").request()
.post(null, Response.class);
}
public void close() {
client.close();
}
}
}
The corrections are as follows. (1) Specify ** DataSet data ** as an argument to the send () method. (2) Set the argument of the post method to post (** Entity.entity (ds, MediaType.APPLICATION_JSON) **) Rewrite as ③ Annotate the close method with ** @ preDestroy **
With the fix, it looks like this:
Multimail.java
public class Multimail {
static class SenderClient {
private WebTarget webTarget;
private Client client;
private static final String BASE_URI = "http://localhost:8080/mailservice/sendmail";
public SenderClient() {
client = javax.ws.rs.client.ClientBuilder.newClient();
webTarget = client.target(BASE_URI).path("cc");
}
public Response send(DateSet data) throws ClientErrorException {
return webTarget.path("text").request()
.post(Entity.entity(ds, MediaType.APPLICATION_JSON));
}
@PreDestroy
public void close() {
client.close();
}
}
}
Let's explain in order.
First, the class was created as an inner class (static inner class). This does not necessarily have to be grouped into an inner class. Actually, it's okay to sprinkle these variables and methods inside the outer Multimail class (called the outer class). However, putting them together in the inner class has the advantage that the defensive range can be clearly separated from the outer class.
The contents of the external class Multimail class will be created from now on, but it is only responsible for the user interface. In other words, generate a web screen like the one you saw at the beginning and ask the user to input it. Then, the input data is sent to the service using the method of the SenderClient class.
SenderClient.java
private WebTarget webTarget; //An object that has the ability to access a service by specifying a URI
private Client client; //Class for generating WebTarget
//URI that represents the entire service@ApplicationPath("sendmail")URI specified in)
private static final String BASE_URI = "http://localhost:8080/mailservice/sendmail";
Use the WebTarget class to access the service, but create an instance of the WebTarger class using the Client class. Therefore, declare each variable as a field variable. In addition, BASE_URI is the URI of the target mail sending service, and is the URI up to the entire service name.
SenderClient.java
public SenderClient() {
//Create an instance of Client
client = javax.ws.rs.client.ClientBuilder.newClient();
// (@Path("cc")A URI that represents the service of the Sender class (specified in)
//Create an instance of WebTarget
webTarget = client.target(BASE_URI).path("cc");
}
In the constructor, create an instance of the Client class and WebTarget class and prepare for access. Instantiating the Client class is always the usual way to write it this way. It's a costly process, so it's usually done in the constructor. The WebTarget instant is generated by pointing to the URI of the Sender class. The path after "cc" is specified by the path method when actually accessing.
SenderClient.java
public Response send(DataSet data) throws ClientErrorException {
return webTarget
.path("text") //Add path
.request() //to access
.post(Entity.entity(data, MediaType.APPLICATION_JSON)); //Send ds with POST access
}
Since this is an automatic generation, it will have the same name as the web service side. Thanks to this, it has the effect of making the correspondence easier to understand.
After all, this is the method for POST access to http: // localhost: 8080/mailservice/sendmail/cc/text
. Therefore, I modified the argument to be DataSet type data. data is an object sent by POST.
The procedure for POST access is as follows: (1) add "text" to the end by path ("text"), (2) access by request (), and (3) send data by post. This series of method calls was automatically generated. However, the argument of the post method has been modified so that it sends the DateSet type object data.
When sending an object to the service, use the entity method of the Entity class to specify the variable and MediaType. For MediaTyps, it's a good idea to specify APPLICATION_JSON like this.
post(Entity.entity(data, MediaType.APPLICATION_JSON))
This is a common way to write an object.
SenderClient.java
@PreDestroy
public void close() {
client.close();
}
When you're done, you must close the Client class to free up resources. This is the method for that, but I'll add the @PreDestroy annotation so that you don't have to forget to run it. With this annotation, you can rest assured that the close () method will be executed automatically just before the class instance is deleted.
Here, the user interface is created with JSF (Jakarta Faces). In other words, the Multimail class is a JSF class. The JSF controller is called a backing bean, so the Multimail class is a backing bean. The form with necessary annotations is as follows. In addition, the main functions to be created are also written in Kotoba.
SenderClient.java
@ViewScoped
@Named
public class Multimail implements Serializable {
//Declaration of field variables related to user interface
//Create an instance of SenderClient
//Upload file reception process (Receive Excel file of destination list)
//The process of reading an Excel file and creating a List of Recipient objects
//After the input is completed, the process of sending data using the post method of SenderClient
static class SenderClient {
...
}
}
The source code is in the project file (about 100 lines), but it will be too long, so I will omit the explanation after this. Still, I think I've already explained RESTful web services and clients so far, but what about?
For more detailed information on RESTful web services, please refer to the book " Easy-to-understand Jakarta EE
".
The part related to this user interface is interesting, such as file upload processing and reading of Excel files, so I plan to post it separately to Qiita. ~~ I think I can post it at the beginning of the year, so if you are interested, please continue to read it. ~~
I used a library called J-mail to send emails. It has been revised for more than 10 years, and this year it has been revised for use in Jakarta EE. The source code of the library can be ** Download from here **. It is also included in the mailservice project created this time. That is the package ** jmail **.
There are two main library files, ** EmailSender.java ** and ** JmSender.java **. EmailSender is a class that uses JmSender and defines the API to be exposed. JmSender is a class that directly operates Jakarta Mail (= Java Mail). In addition, SenderProperties.java defines only the getProperties () method in the interface that retrieves the data required for SMTP server access in the properties file.
This interface gives you the flexibility to load property data from an xml file or use the microprofile-config.propaties file. The library provides two implementations (ConfigToProperties.java and XmlToProperties.java). Since it is a CDI bean, describe which one to use in the beans.xml file. The default is XmlToProperties.
Email Sender's public API. You can send plain text mail and HTML mail. In addition, both emails can be attached to files and sent by CC/BCC. In addition, if you want to perform detailed operations like this post, there is also a method to execute connection, mail transmission (plaintext or HTML), and disconnection operations separately.
All methods return a status (** EmailStatus ** type) indicating the execution result. However, for the sake of simplicity, the return value is omitted from the API table. The return value is as follows:
status | Taste |
---|---|
EmailStatus.DONE | Successful completion |
EmailStatus.INIT_ERROR | Incorrect connection parameter |
EmailStatus.CONNECT_ERROR | can not connect |
EmailStatus.SEND_ERROR | Failed to send email |
EmailStatus.DISCONNECT_ERROR | Error when disconnecting |
The arguments have the following meanings:
Argument name | Taste |
---|---|
String to | Destination email address |
String subject | Email title |
String body | the content of the email |
String html | HTML data that becomes the body of the email |
String type | Transmission classification:"TO" "CC" "BCC" "TO"Means "one person" |
String fileDir | Directory name where the file is located |
List<String> flist | List of attachment names |
・ Html is a character string of the entire HTML document. · FileDir must be on the computer where the sending library is located
-All return values are of Email Status type -All arguments are of type String
API | Function |
---|---|
connect() | Connect to SMTP server |
disconnect() | Disconnect from SMTP server |
xsend(to, subject, body) | Send one text email |
xsendHtml(to, subject, body) | Send one HTML email |
・ It is an API suitable for sending a large number of emails. ・ CC/BCC is not specified because it can be sent repeatedly. -There is no file attachment function. Normally, the URL containing the file is included in the body of the email.
・ It is an API to easily send one to several emails. -All return values are of Email Status type -All arguments are String type except List type
API | Function |
---|---|
send(to, subject, body) | send mail |
send(to, subject, body, type) | CC/Send an email with BCC |
send(to, subject, body, fileDir, List<String> flist) | Send a file attachment email |
send(to, subject, body, fileDir, List<String> flist, String type) | CC/Send a file attachment email with BCC specification |
sendHtml(to, subject, html) | Send HTML email |
sendHtml(to, subject, html, type) | CC/Send HTML email with BCC |
sendHtml(to, subject, html, fileDir, List<String> flist) | Send HTML email with file attachment |
sendHtml(to, subject, html, fileDir, List<String> flist, type) | CC/BCC specification, send HTML email with file attachment |
Recommended Posts