(See the previous iteration.)
What's new
I have incorporated all the points of Dmytro Maslenko's answer. My code seems a little bit tidier.
Code
AddPersonController.java
package net.coderodde.web.db.fun.controllers;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import net.coderodde.web.db.fun.model.FunnyPerson;
/**
* This controller is responsible for creating new persons.
*
* @author Rodion "rodde" Efremov
* @version 1.6 (Aug 8, 2017)
*/
@WebServlet(name = "AddPersonController", urlPatterns = {"/add_person"})
public class AddPersonController extends HttpServlet {
/**
* Handles the HTTP <code>GET</code> method.
*
* @param request the servlet request.
* @param response the servlet response.
* @throws ServletException if a servlet-specific error occurs.
* @throws IOException if an I/O error occurs.
*/
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
try (PrintWriter out = response.getWriter()) {
out.println("Please use the POST method!");
}
}
/**
* Handles the HTTP <code>POST</code> method.
*
* @param request the servlet request.
* @param response the servlet response.
* @throws ServletException if a servlet-specific error occurs.
* @throws IOException if an I/O error occurs.
*/
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
try (PrintWriter out = response.getWriter()) {
String firstName = request.getParameter("first_name");
String lastName = request.getParameter("last_name");
String email = request.getParameter("email");
if (firstName.isEmpty()) {
out.println("The first name is empty.");
return;
}
if (lastName.isEmpty()) {
out.println("The last name is empty.");
return;
}
if (email.isEmpty()) {
out.println("The email is empty.");
return;
}
FunnyPerson person = new FunnyPerson();
person.setFirstName(firstName);
person.setLastName(lastName);
person.setEmail(email);
try {
DataAccessObject.instance().addPerson(person);
out.println("Person " + person + " created!");
} catch (RuntimeException ex) {
out.println("Error: " + ex.getCause().getMessage());
}
}
}
/**
* Returns a short description of the servlet.
*
* @return a String containing servlet description
*/
@Override
public String getServletInfo() {
return "This servlet adds new persons to the database.";
}
}
CreateDatabaseController.java
package net.coderodde.web.db.fun.controllers;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* This controller creates the database if it is not yet created.
*
* @author Rodion "rodde" Efremov
* @version 1.6 (Aug 8, 2017)
*/
@WebServlet(name = "CreateDatabaseController", urlPatterns = {"/create"})
public class CreateDatabaseController extends HttpServlet {
/**
* If not yet created, this request creates the database and the table.
*
* @param request the servlet request.
* @param response the servlet response.
* @throws ServletException if a servlet-specific error occurs.
* @throws IOException if an I/O error occurs.
*/
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
try (PrintWriter out = response.getWriter()) {
try {
DataAccessObject.instance().createDatabase();
out.println("Database created!");
} catch (RuntimeException ex) {
out.println("Error: " + ex.getCause().getMessage());
}
}
}
/**
* Handles the HTTP <code>GET</code> method.
*
* @param request the servlet request.
* @param response the servlet response.
* @throws ServletException if a servlet-specific error occurs.
* @throws IOException if an I/O error occurs.
*/
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
/**
* Handles the HTTP <code>POST</code> method.
*
* @param request the servlet request.
* @param response the servlet response.
* @throws ServletException if a servlet-specific error occurs.
* @throws IOException if an I/O error occurs.
*/
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
/**
* Returns a short description of the servlet.
*
* @return a String containing servlet description.
*/
@Override
public String getServletInfo() {
return "Creates the database and the table.";
}
}
DataAccessObject.java
package net.coderodde.web.db.fun.controllers;
import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import net.coderodde.web.db.fun.model.FunnyPerson;
public final class DataAccessObject {
/**
* For validating the email addresses.
*/
public static final Pattern VALID_EMAIL_ADDRESS_REGEX =
Pattern.compile("^[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,6}$",
Pattern.CASE_INSENSITIVE);
/**
* The SQL command for inserting a person.
*/
private static final String INSERT_PERSON_SQL =
"INSERT INTO funny_persons (first_name, last_name, email) VALUES " +
"(?, ?, ?);";
/**
* Creates a new database if not already created.
*/
private static final String CREATE_DATABASE_SQL =
"CREATE DATABASE IF NOT EXISTS funny_db;";
/**
* Switches to 'funny_db'.
*/
private static final String USE_DATABASE_SQL = "USE funny_db";
/**
* Creates the table if not already created.
*/
private static final String CREATE_TABLE_SQL =
"CREATE TABLE IF NOT EXISTS funny_persons (\n" +
"id INT(6) UNSIGNED AUTO_INCREMENT PRIMARY KEY,\n" +
"first_name VARCHAR(40) NOT NULL,\n" +
"last_name VARCHAR(40) NOT NULL,\n" +
"email VARCHAR(50) NOT NULL,\n" +
"created TIMESTAMP);";
/**
* The SQL for selecting a user given his/her ID.
*/
private static final String GET_USER_BY_ID_SQL =
"SELECT * FROM funny_persons WHERE id = ?;";
private final MysqlDataSource mysqlDataSource;
private DataAccessObject(MysqlDataSource mysqlDataSource) {
this.mysqlDataSource = Objects.requireNonNull(
mysqlDataSource,
"The MysqlDataSource is null.");
}
private static final DataAccessObject INSTANCE;
static {
MysqlDataSource mysqlDataSource = new MysqlDataSource();
mysqlDataSource.setUser("root");
mysqlDataSource.setPassword("your_password");
mysqlDataSource.setURL("jdbc:mysql://localhost:3306/funny_db");
INSTANCE = new DataAccessObject(mysqlDataSource);
}
public static DataAccessObject instance() {
return INSTANCE;
}
/**
* Adds a person to the database.
*
* @param person the person to add.
*/
public void addPerson(FunnyPerson person) {
checkPerson(person);
try (Connection connection = mysqlDataSource.getConnection()) {
try (PreparedStatement statement =
connection.prepareStatement(INSERT_PERSON_SQL)) {
statement.setString(1, person.getFirstName().trim());
statement.setString(2, person.getLastName().trim());
statement.setString(3, person.getEmail().trim());
statement.executeUpdate();
}
} catch (SQLException ex) {
throw new RuntimeException(ex);
}
}
/**
* Creates the empty database and the table.
*/
public void createDatabase() {
try (Connection connection = mysqlDataSource.getConnection()) {
try (Statement statement = connection.createStatement()) {
statement.executeUpdate(CREATE_DATABASE_SQL);
statement.executeUpdate(USE_DATABASE_SQL);
statement.executeUpdate(CREATE_TABLE_SQL);
}
} catch (SQLException ex) {
throw new RuntimeException(ex);
}
}
/**
* Gets a user by his/her ID.
*
* @param id the ID of the user.
* @return a {@code FunnyPerson} object or {@code null} if there is not such
* user.
*/
public FunnyPerson getUserById(int id) {
try (Connection connection = mysqlDataSource.getConnection()) {
try (PreparedStatement statement =
connection.prepareStatement(GET_USER_BY_ID_SQL)) {
statement.setInt(1, id);
try (ResultSet resultSet = statement.executeQuery()) {
if (!resultSet.next()) {
return null;
}
FunnyPerson person = new FunnyPerson();
person.setId(resultSet.getInt("id"));
person.setFirstName(resultSet.getString("first_name"));
person.setLastName(resultSet.getString("last_name"));
person.setEmail(resultSet.getString("email"));
person.setCreated(resultSet.getDate("created"));
return person;
}
}
} catch (SQLException ex) {
throw new RuntimeException(ex);
}
}
private void checkPerson(FunnyPerson person) {
Objects.requireNonNull(person, "The person is null.");
Objects.requireNonNull(person.getFirstName(),
"The first name is null.");
Objects.requireNonNull(person.getLastName(), "The last name is null.");
Objects.requireNonNull(person.getEmail(), "The email is null.");
if (person.getFirstName().trim().isEmpty()) {
throw new IllegalArgumentException("The first name is empty.");
}
if (person.getLastName().trim().isEmpty()) {
throw new IllegalArgumentException("The last name is empty.");
}
if (!validate(person.getEmail().trim())) {
throw new IllegalArgumentException("Invalid email address.");
}
}
/**
* Checks the email address.
*
* @param email the email address to validate.
* @return {@code true} if {@code email} is a valid email address.
*/
private static boolean validate(String email ) {
Matcher matcher = VALID_EMAIL_ADDRESS_REGEX .matcher(email );
return matcher.find();
}
}
ShowPersonController.java
package net.coderodde.web.db.fun.controllers;
import com.google.gson.Gson;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import net.coderodde.web.db.fun.model.FunnyPerson;
/**
* This controller is responsible for viewing persons.
*
* @author Rodion "rodde" Efremov
* @version 1.6 (Aug 8, 2017)
*/
@WebServlet(name = "ShowPersonController", urlPatterns = {"/show/*"})
public class ShowPersonController extends HttpServlet {
/**
* Processes requests for both HTTP <code>GET</code> and <code>POST</code>
* methods.
*
* @param request the servlet request.
* @param response the servlet response.
* @throws ServletException if a servlet-specific error occurs.
* @throws IOException if an I/O error occurs.
*/
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
try (PrintWriter out = response.getWriter()) {
String path = request.getPathInfo();
if (path.startsWith("/")) {
path = path.substring(1);
}
String[] tokens = path.split("/");
if (tokens.length == 0) {
out.println("Error: At least the user ID is required.");
return;
}
String idString = tokens[0];
int id = -1;
try {
id = Integer.parseInt(idString);
} catch (NumberFormatException ex) {
out.println("Error: " + idString + " is not an integer.");
return;
}
FunnyPerson person = DataAccessObject.instance().getUserById(id);
if (person == null) {
out.println("Error: no person with ID = " + id + ".");
return;
}
String matchFirstName = null;
if (tokens.length == 2) {
matchFirstName = tokens[1];
}
if (!person.getFirstName().equals(matchFirstName)) {
response.sendRedirect("/DBWebFun/show/" + id + "/" +
person.getFirstName());
return;
}
Gson gson = new Gson();
out.println(gson.toJson(person));
}
}
/**
* Handles the HTTP <code>GET</code> method.
*
* @param request servlet request
* @param response servlet response
* @throws ServletException if a servlet-specific error occurs
* @throws IOException if an I/O error occurs
*/
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
/**
* Handles the HTTP <code>POST</code> method.
*
* @param request servlet request
* @param response servlet response
* @throws ServletException if a servlet-specific error occurs
* @throws IOException if an I/O error occurs
*/
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
/**
* Returns a short description of the servlet.
*
* @return a String containing servlet description
*/
@Override
public String getServletInfo() {
return "Shows the user info via ID/first_name";
}
}
The entire Maven project is here.
Critique request
Please tell me anything that comes to mind.