Review
In the previous section, we have laid down the functional specs and took a preview of the application. In this section, we will write and discuss the Java classes and the project's structure.Table of Contents
Part 1: Introduction and Functional SpecsPart 2: Java classes
Part 3: XML configuration
Part 4: HTML form
Part 5: Running the Application
Project Structure
Our application is a Maven project which means it follows the Maven convention for web applications.Here's a preview of our project's structure:
Domain Layer
The domain layer contains a Message class that represents an email message and n UploadedFile class that represents a file upload.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package org.krams.domain; | |
import java.io.Serializable; | |
public class Message implements Serializable { | |
private static final long serialVersionUID = -4093981756240899937L; | |
private String senderName; | |
private String senderEmail; | |
private String ccEmail; | |
private String subject; | |
private String body; | |
private String receiverName; | |
private String receiverEmail; | |
private String filename; | |
public Message() { | |
super(); | |
} | |
public Message(String senderName, String senderEmail, String ccEmail, | |
String subject, String body, String receiverName, | |
String receiverEmail, String filename) { | |
super(); | |
this.senderName = senderName; | |
this.senderEmail = senderEmail; | |
this.ccEmail = ccEmail; | |
this.subject = subject; | |
this.body = body; | |
this.receiverName = receiverName; | |
this.receiverEmail = receiverEmail; | |
this.filename = filename; | |
} | |
...getters/setters | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package org.krams.domain; | |
import java.io.Serializable; | |
public class UploadedFile implements Serializable { | |
private static final long serialVersionUID = -38331060124340967L; | |
private String name; | |
private Integer size; | |
private String url; | |
private String thumbnail_url; | |
private String delete_url; | |
private String delete_type; | |
public UploadedFile() { | |
super(); | |
} | |
public UploadedFile(String name, Integer size, String url) { | |
super(); | |
this.name = name; | |
this.size = size; | |
this.url = url; | |
} | |
public UploadedFile(String name, Integer size, String url, | |
String thumbnail_url, String delete_url, String delete_type) { | |
super(); | |
this.name = name; | |
this.size = size; | |
this.url = url; | |
this.thumbnail_url = thumbnail_url; | |
this.delete_url = delete_url; | |
this.delete_type = delete_type; | |
} | |
...getters/setters | |
} |
Controller Layer
The controller layer contains a simple controller EmailController that serves a form for composing and sending emails. It has two main methods: send for sending emails and upload for uploading files.Whenever a file is attached and uploaded, it is saved first to a temporary location which can be retrieved later via its filename. When the send method is triggered, it basically pulls out the file from the temporary location based on the filename.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package org.krams.controller; | |
import java.io.File; | |
import java.io.FileOutputStream; | |
import java.util.ArrayList; | |
import java.util.List; | |
import org.apache.log4j.Logger; | |
import org.krams.domain.Message; | |
import org.krams.domain.UploadedFile; | |
import org.krams.response.StatusResponse; | |
import org.krams.service.EmailService; | |
import org.springframework.beans.factory.annotation.Autowired; | |
import org.springframework.beans.factory.annotation.Value; | |
import org.springframework.stereotype.Controller; | |
import org.springframework.web.bind.annotation.RequestBody; | |
import org.springframework.web.bind.annotation.RequestMapping; | |
import org.springframework.web.bind.annotation.RequestMethod; | |
import org.springframework.web.bind.annotation.RequestParam; | |
import org.springframework.web.bind.annotation.ResponseBody; | |
import org.springframework.web.multipart.MultipartFile; | |
@Controller | |
@RequestMapping("/email") | |
public class EmailController { | |
private static Logger logger = Logger.getLogger("controller"); | |
@Value("${temp.dir}") | |
private String tempDirectory; | |
@Autowired | |
private EmailService emailService; | |
@RequestMapping | |
public String form() { | |
return "form"; | |
} | |
@RequestMapping(value ="/send", method=RequestMethod.POST) | |
public @ResponseBody StatusResponse send(@RequestBody Message message) { | |
return emailService.send(message); | |
} | |
@RequestMapping(value="/fileupload", method=RequestMethod.POST) | |
public @ResponseBody List<UploadedFile> upload( | |
@RequestParam("file") MultipartFile file) { | |
logger.debug(file.getOriginalFilename() + " - " + file.getSize()); | |
try { | |
File f = new File(tempDirectory+File.separator+file.getOriginalFilename()); | |
FileOutputStream fos = new FileOutputStream(f); | |
fos.write(file.getBytes()); | |
fos.close(); | |
} catch (Exception e) { | |
logger.error(e); | |
return null; | |
} | |
List<UploadedFile> uploadedFiles = new ArrayList<UploadedFile>(); | |
UploadedFile u = new UploadedFile(); | |
u.setName(file.getOriginalFilename()); | |
u.setSize(Long.valueOf(file.getSize()).intValue()); | |
uploadedFiles.add(u); | |
return uploadedFiles; | |
} | |
} |
Service Layer
The service layer contains the email service. We have a simple interface EmailService for sending messages.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package org.krams.service; | |
import org.krams.domain.Message; | |
import org.krams.response.StatusResponse; | |
public interface EmailService { | |
StatusResponse send(Message message); | |
} |
The actual implementation SendGridEmailService relies on RestTemplate to send the email message via HTTP.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package org.krams.service; | |
import java.io.File; | |
import org.apache.log4j.Logger; | |
import org.krams.domain.Message; | |
import org.krams.response.StatusResponse; | |
import org.krams.util.SendGridParameter; | |
import org.springframework.beans.factory.annotation.Value; | |
import org.springframework.core.io.FileSystemResource; | |
import org.springframework.core.io.Resource; | |
import org.springframework.stereotype.Service; | |
import org.springframework.util.LinkedMultiValueMap; | |
import org.springframework.util.MultiValueMap; | |
import org.springframework.web.client.RestTemplate; | |
@Service | |
public class SendGridEmailService implements EmailService { | |
protected static Logger logger = Logger.getLogger("service"); | |
private RestTemplate restTemplate = new RestTemplate(); | |
@Value("${sendgrid.api.user}") | |
private String sendgridApiUser; | |
@Value("${sendgrid.api.key}") | |
private String sendgridApiKey; | |
@Value("${temp.dir}") | |
private String tempDirectory; | |
@Override | |
public StatusResponse send(Message message) { | |
try { | |
MultiValueMap<String, Object> vars = new LinkedMultiValueMap<String, Object>(); | |
vars.add(SendGridParameter.API_USER, sendgridApiUser); | |
vars.add(SendGridParameter.API_KEY, sendgridApiKey); | |
vars.add(SendGridParameter.SENDER_NAME, message.getSenderName()); | |
vars.add(SendGridParameter.SENDER_EMAIL, message.getSenderEmail()); | |
vars.add(SendGridParameter.BLIND_COPY_EMAIL, message.getCcEmail()); | |
vars.add(SendGridParameter.SUBJECT, message.getSubject()); | |
vars.add(SendGridParameter.TEXT, ""); | |
vars.add(SendGridParameter.HTML, message.getBody()); | |
vars.add(SendGridParameter.RECEIVER_EMAIL, message.getReceiverEmail()); | |
vars.add(SendGridParameter.RECEIVER_NAME, message.getReceiverName()); | |
for (String filename: message.getFilename().split(",")) { | |
Resource resource = new FileSystemResource(tempDirectory + File.separator + filename); | |
vars.add("files["+filename+"]", resource); | |
} | |
restTemplate.postForLocation(SendGridParameter.URL, vars); | |
} catch (Exception ex) { | |
logger.error(ex); | |
return new StatusResponse(false, "An error has occurred!"); | |
} | |
return new StatusResponse(true, "Message sent"); | |
} | |
} |
How did we manage to produce this code? Basically this is a translation of SendGrid's API using Spring RestTemplate. The specific SendGrid API we're using is the Mail module, which is under the Web API. Please see http://docs.sendgrid.com/documentation/api/web-api/mail/#send for the complete documentation.
To test the Mail module, you can either use your browser or CURL (if you're familiar with it).
Browser-based test:
https://sendgrid.com/api/mail.send.xml?api_user=youremail@domain.com&api_key=secureSecret&to=destination@example.com&toname=Destination&subject=Example%20Subject&text=testingtextbody&from=info@domain.com
CURL-based test:
curl -d 'to=destination@example.com&toname=Destination&subject=Example Subject&text=testingtextbody&from=info@domain.com&api_user=sendgridUsername&api_key=sendgridPassword' https://sendgrid.com/api/mail.send.json
Utility Layer
This layer contains helper classes and interfaces. Here we've extracted the required SendGrid parameters when sending emails via HTTP.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package org.krams.util; | |
public interface SendGridParameter { | |
public static final String URL = "http://sendgrid.com/api/mail.send.json"; | |
public static final String API_USER = "api_user"; | |
public static final String API_KEY = "api_key"; | |
public static final String RECEIVER_EMAIL = "to"; | |
public static final String RECEIVER_NAME = "toname"; | |
public static final String SUBJECT = "subject"; | |
public static final String TEXT = "text"; | |
public static final String HTML = "html"; | |
public static final String SENDER_EMAIL = "from"; | |
public static final String SENDER_NAME = "fromname"; | |
public static final String BLIND_COPY_EMAIL = "bcc"; | |
} |
0 komentar:
Post a Comment