openplanning

Tạo một ứng dụng Java Web đơn giản sử dụng Servlet, JSP và JDBC

  1. Giới thiệu
  2. Các nguyên tắc kinh điển khi lập trình Servlet + JSP
  3. Demo ứng dụng web sẽ làm
  4. Chuẩn bị database
  5. Tạo WebApp Project
  6. Cấu hình môi trường chạy (Runtime Environment)
  7. Chạy ứng dụng lần đầu tiên
  8. Download và khai báo thư viện JDBC
  9. Download và khai báo thư viện JSTL
  10. Các lớp javabeans mô phỏng bảng trong DB
  11. Các lớp tiện ích kết nối Database
  12. Các lớp tiện ích & thao tác dữ liệu
  13. Tạo Servlet Filter kết nối database
  14. Servlet Filter đọc Cookie để tự động đăng nhập
  15. Servlet Encoding Filter
  16. Các trang tái sử dụng
  17. Trang chủ
  18. Trang đăng nhập - LoginServlet
  19. Trang danh sách sản phẩm
  20. Thêm sản phẩm
  21. Sửa thông tin sản phẩm
  22. Xóa sản phẩm

1. Giới thiệu

Tài liệu được viết dựa trên:
  • Eclipse 4.5 MARS
  • Tomcat 8.x
Trong tài liệu này tôi sẽ hướng dẫn từng bước cách tạo một ứng dụng web đơn giản kết hợp Servlet + JSP + Filter + JSP EL + JDBC. Hãy đảm bảo rằng bạn đã nắm vững Servlet, JSP FilterJDBC trước khi bắt đầu. Nếu không, bạn có thể tham khảo tại:
Chú ý: Trong bài viết này tôi chỉ giới thiệu về chức năng CRUD, "Login" và chức năng "Remember Me". Và không xử lý bảo mật các trang, nếu bạn muốn có một ứng dụng bảo mật các trang hãy tham khảo thêm bài viết dưới đây:

2. Các nguyên tắc kinh điển khi lập trình Servlet + JSP

Đây là các nguyên tắc mà bạn nên nhớ để có thể xây dựng một ứng dụng Web sử dụng Servlet + JSP thỏa mãn tiêu chí: code đơn giản dễ hiểu và dễ dàng bảo trì.
Các nguyên tắc:
  • Đừng bao giờ cho phép người dùng truy cập trực tiếp vào trang JSP của bạn.
  • Chỉ coi JSP là cái để hiển thị giao diện.
  • Servlet đóng vai trò là người điều khiển luồng đi của ứng dụng và sử lý logic chương trình.
  • Mở kết nối JDBC và quản lý giao dịch trong Filter (Không bắt buộc).
Theo nguyên tắc 1:
Không bao giờ cho phép người dùng truy cập trực tiếp vào trang JSP của bạn, điều đó có nghĩa là mọi request của người dùng thường là:
  • Một nguồn dữ liệu tĩnh (image, css, js,...)
  • Hoặc một servlet.
Như vậy bạn phải cất giấu các file JSP của bạn tại một nơi nào đó mà người dùng không thể truy cập vào. Chẳng hạn đặt trong thư mục WEB-INF hoặc thư mục con của nó. Trong ví dụ này tôi sẽ để các file jsp tại thư mục WEB-INF/views.
Khi request của người dùng tới một Servlet, nó sẽ sử lý yêu cầu của người dùng, chẳng hạn Insert, update và truy vấn dữ liệu, cuối cùng là chuyển tiếp (forward) tới trang JSP để hiển thị dữ liệu. Như vậy mỗi servlet có 0 hoặc nhiều trang JSP tương ứng (Thường chỉ cần 1).
Nguyên tắc 2:
Chỉ coi JSP là nơi hiển thị dữ liệu, điều đó có nghĩa là bạn không nên xử lý logic ứng dụng trên JSP, chẳng hạn như update, insert, delete,.., và không điều hướng trên trang JSP.

3. Demo ứng dụng web sẽ làm

Bạn có thể xem trước bản giới thiệu (Demo) ứng dụng Web sẽ làm:

4. Chuẩn bị database

Trong tài liệu này tôi hướng dẫn bạn làm việc với một trong 3 cơ sở dữ liệu Oracle, MySQL hoặc SQL Server. Bạn cần chạy các script để tạo một số bảng và dữ liệu cần thiết cho ví dụ này.
ORACLE:
-- Create table
create table USER_ACCOUNT
(
USER_NAME VARCHAR2(30) not null,
GENDER    VARCHAR2(1) not null,
PASSWORD  VARCHAR2(30) not null,
primary key (USER_NAME)
);

-- Create table
create table PRODUCT
(
CODE  VARCHAR2(20) not null,
NAME  VARCHAR2(128) not null,
PRICE FLOAT not null,
primary key (CODE)
) ;

-- Insert data: ---------------------------------------------------------------

insert into user_account (USER_NAME, GENDER, PASSWORD)
values ('tom', 'M', 'tom001');

insert into user_account (USER_NAME, GENDER, PASSWORD)
values ('jerry', 'M', 'jerry001');

insert into product (CODE, NAME, PRICE)
values ('P001', 'Java Core', 100);

insert into product (CODE, NAME, PRICE)
values ('P002', 'C# Core', 90);

-- Commit
Commit;
MYSQL:
-- Create table
create table USER_ACCOUNT
(
USER_NAME VARCHAR(30) not null,
GENDER    VARCHAR(1) not null,
PASSWORD  VARCHAR(30) not null,
primary key (USER_NAME)
);

-- Create table
create table PRODUCT
(
CODE  VARCHAR(20) not null,
NAME  VARCHAR(128) not null,
PRICE FLOAT not null,
primary key (CODE)
) ;

-- Insert data: ---------------------------------------------------------------

insert into user_account (USER_NAME, GENDER, PASSWORD)
values ('tom', 'M', 'tom001');

insert into user_account (USER_NAME, GENDER, PASSWORD)
values ('jerry', 'M', 'jerry001');

insert into product (CODE, NAME, PRICE)
values ('P001', 'Java Core', 100);

insert into product (CODE, NAME, PRICE)
values ('P002', 'C# Core', 90);
SQL SERVER:
-- Create table
create table USER_ACCOUNT
(
USER_NAME VARCHAR(30) not null,
GENDER    VARCHAR(1) not null,
PASSWORD  VARCHAR(30) not null,
primary key (USER_NAME)
);

-- Create table
create table PRODUCT
(
CODE  VARCHAR(20) not null,
NAME  VARCHAR(128) not null,
PRICE FLOAT not null,
primary key (CODE)
) ;

-- Insert data: ---------------------------------------------------------------

insert into user_account (USER_NAME, GENDER, PASSWORD)
values ('tom', 'M', 'tom001');

insert into user_account (USER_NAME, GENDER, PASSWORD)
values ('jerry', 'M', 'jerry001');

insert into product (CODE, NAME, PRICE)
values ('P001', 'Java Core', 100);

insert into product (CODE, NAME, PRICE)
values ('P002', 'C# Core', 90);

5. Tạo WebApp Project

Trên Eclipse chọn:
  • File/New/Other...
Project đã được tạo ra.
Thêm file index.html
index.html
<!DOCTYPE html>
<html>
  <head>
     <meta charset="UTF-8">
     <title>Simple Web Application</title>
  </head>
 
  <body>
 
     <h2>Simple Login Web Application using JSP/Servlet</h2>
     
     <ul>
        <li><a href="home">Home</a></li>
        <li><a href="login">Login</a></li>
        <li><a href="productList">Product  List</a>
     </ul>
     
  </body>
</html>

6. Cấu hình môi trường chạy (Runtime Environment)

Ứng dụng cần chạy trên một WebServer, chẳng hạn Tomcat Server, bạn có thể tham khảo tài liệu hướng dẫn download và khai báo Server Tomcat vào Eclipse tại:
Nhấn phải chuột vào project SimpleWebApp chọn Properties.

7. Chạy ứng dụng lần đầu tiên

Nhấn phải chuột vào Project SimpleWebApp, chọn:
  • Run As/Run on Server
Ứng dụng đã được chạy:
OK, tới đây mọi thứ đều tốt đẹp. Chúng ta sẽ bắt đầu lập trình một ứng dụng Web thực sự.

8. Download và khai báo thư viện JDBC

Bạn cần download thư viện JDBC điều khiển việc kết nối với Database. Trong tài liệu này tôi download cả 3 thư viện JDBC cho cả Oracle, MySQL, SQL Server, trong thực hành bạn chỉ cần thư viện JDBC ứng với loại Database bạn đang sử dụng.
Bạn có thể xem hướng dẫn download JDBC driver tại:
Hoặc download các thư viện JDBC cho MySQL, Sql Server, Oracle tại đây:
Kết quả download được:
Copy các thư viện này vào WEB-INF/lib:

9. Download và khai báo thư viện JSTL

Bạn cần download 2 thư viện JSTL để có thể sử dụng chúng trong JSP:
  • javax.servlet.jsp.jstl-*.jar
  • javax.servlet.jsp.jslt-api-*.jar

10. Các lớp javabeans mô phỏng bảng trong DB

Tạo một số class Javabean, mỗi class mô phỏng một bảng trong database:
UserAccount.java
package org.o7planning.simplewebapp.beans;

public class UserAccount {

   public static final String GENDER_MALE ="M";
   public static final String GENDER_FEMALE = "F";
   
   private String userName;
   private String gender;
   private String password;
   

   public UserAccount() {
       
   }
   
   public String getUserName() {
       return userName;
   }

   public void setUserName(String userName) {
       this.userName = userName;
   }

   public String getGender() {
       return gender;
   }

   public void setGender(String gender) {
       this.gender = gender;
   }

   public String getPassword() {
       return password;
   }

   public void setPassword(String password) {
       this.password = password;
   }

}
Product.java
package org.o7planning.simplewebapp.beans;

public class Product {

   private String code;
   private String name;
   private float price;

   public Product() {

   }

   public Product(String code, String name, float price) {
       this.code = code;
       this.name = name;
       this.price = price;
   }

   public String getCode() {
       return code;
   }

   public void setCode(String code) {
       this.code = code;
   }

   public String getName() {
       return name;
   }

   public void setName(String name) {
       this.name = name;
   }

   public float getPrice() {
       return price;
   }

   public void setPrice(float price) {
       this.price = price;
   }

}

11. Các lớp tiện ích kết nối Database

MySQLConnUtils.java
package org.o7planning.simplewebapp.conn;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
 
public class MySQLConnUtils {
 
 public static Connection getMySQLConnection()
         throws ClassNotFoundException, SQLException {
	 // Chú ý: Thay đổi các thông số kết nối cho phù hợp.
     String hostName = "localhost";
     String dbName = "mytest";
     String userName = "root";
     String password = "12345";
     return getMySQLConnection(hostName, dbName, userName, password);
 }
 
 public static Connection getMySQLConnection(String hostName, String dbName,
         String userName, String password) throws SQLException,
         ClassNotFoundException {
   
     Class.forName("com.mysql.jdbc.Driver");
 
     // Cấu trúc URL Connection đối với MySQL:
     // Ví dụ: 
     // jdbc:mysql://localhost:3306/simplehr
     String connectionURL = "jdbc:mysql://" + hostName + ":3306/" + dbName;
 
     Connection conn = DriverManager.getConnection(connectionURL, userName,
             password);
     return conn;
 }
}
OracleConnUtils.java
package org.o7planning.simplewebapp.conn;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
 
public class OracleConnUtils {
 
   public static Connection getOracleConnection()
           throws ClassNotFoundException, SQLException {
	   
       // Chú ý: Thay đổi các thông số kết nối cho phù hợp.
       String hostName = "localhost";
       String sid = "db12c";
       String userName = "mytest";
       String password = "12345";
 
       return getOracleConnection(hostName, sid, userName, password);
   }
 
   public static Connection getOracleConnection(String hostName, String sid,
           String userName, String password) throws ClassNotFoundException,
           SQLException {
  
       Class.forName("oracle.jdbc.driver.OracleDriver");
 
       // Cấu trúc URL Connection đối với Oracle
       // Ví dụ: 
       // jdbc:oracle:thin:@localhost:1521:db11g
       // jdbc:oracle:thin:@//HOSTNAME:PORT/SERVICENAME
       String connectionURL = "jdbc:oracle:thin:@" + hostName + ":1521:" + sid;
 
       Connection conn = DriverManager.getConnection(connectionURL, userName,
               password);
       return conn;
   }
}
SQLServerConnUtils_JTDS.java
package org.o7planning.simplewebapp.conn;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

public class SQLServerConnUtils_JTDS {

	// Kết nối vào SQLServer.
	// (Sử dụng thư viện điều khiển JTDS)
	public static Connection getSQLServerConnection_JTDS() //
			throws SQLException, ClassNotFoundException {

		// Chú ý: Thay đổi các thông số kết nối cho phù hợp.
		String hostName = "localhost";
		String sqlInstanceName = "SQLEXPRESS";
		String database = "mytest";
		String userName = "sa";
		String password = "12345";

		return getSQLServerConnection_JTDS(hostName, sqlInstanceName, database, userName, password);
	}

	// Kết nối tới SQL Server sử dụng thư viện JTDS.
	private static Connection getSQLServerConnection_JTDS(String hostName, //
			String sqlInstanceName, String database, String userName, String password)
			throws ClassNotFoundException, SQLException {

		Class.forName("net.sourceforge.jtds.jdbc.Driver");

		// Cấu trúc URL Connection đối với SQL Server:
		// Ví dụ:
		// jdbc:jtds:sqlserver://localhost:1433/simplehr;instance=SQLEXPRESS
		String connectionURL = "jdbc:jtds:sqlserver://" + hostName + ":1433/" //
				+ database + ";instance=" + sqlInstanceName;

		Connection conn = DriverManager.getConnection(connectionURL, userName, password);
		return conn;
	}

}
SQLServerConnUtils_SQLJDBC.java
package org.o7planning.simplewebapp.conn;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

public class SQLServerConnUtils_SQLJDBC {

	// Kết nối vào SQL Server.
	// (Sử dụng thư viện SQLJDBC)
	public static Connection getSQLServerConnection_SQLJDBC() //
			throws ClassNotFoundException, SQLException {

		// Chú ý: Thay đổi các thông số kết nối cho phù hợp.
		String hostName = "localhost";
		String sqlInstanceName = "SQLEXPRESS";
		String database = "mytest";
		String userName = "sa";
		String password = "12345";

		return getSQLServerConnection_SQLJDBC(hostName, sqlInstanceName, database, userName, password);
	}

	// Kết nối tới SQLServer, sử dụng thư viện SQLJDBC.
	private static Connection getSQLServerConnection_SQLJDBC(String hostName, //
			String sqlInstanceName, String database, String userName, String password)//
			throws ClassNotFoundException, SQLException {

		Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");

		// Cấu trúc URL Connection dành cho SQLServer
		// Ví dụ:
		// jdbc:sqlserver://ServerIp:1433/SQLEXPRESS;databaseName=simplehr
		String connectionURL = "jdbc:sqlserver://" + hostName + ":1433" //
				+ ";instance=" + sqlInstanceName + ";databaseName=" + database;

		Connection conn = DriverManager.getConnection(connectionURL, userName, password);
		return conn;
	}

}
ConnectionUtils.java
package org.o7planning.simplewebapp.conn;

import java.sql.Connection;
import java.sql.SQLException;

public class ConnectionUtils {

	public static Connection getConnection() 
			  throws ClassNotFoundException, SQLException {

		// Ở đây tôi kết nối tới Oracle Database.
		// (Bạn có thể thay đổi sử dụng database khác).
		return OracleConnUtils.getOracleConnection();
		
		// return OracleConnUtils.getOracleConnection();
		// return MySQLConnUtils.getMySQLConnection();
		// return SQLServerConnUtils_JTDS.getSQLServerConnection_JTDS();
		// return SQLServerConnUtils_SQLJDBC.getSQLServerConnection_SQLJDBC();
		// return PostGresConnUtils.getPostGresConnection();
	}
	
	public static void closeQuietly(Connection conn) {
		try {
			conn.close();
		} catch (Exception e) {
		}
	}

	public static void rollbackQuietly(Connection conn) {
		try {
			conn.rollback();
		} catch (Exception e) {
		}
	}
}

12. Các lớp tiện ích & thao tác dữ liệu

MyUtils.java
package org.o7planning.simplewebapp.utils;

import java.sql.Connection;

import javax.servlet.ServletRequest;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.o7planning.simplewebapp.beans.UserAccount;

public class MyUtils {

	public static final String ATT_NAME_CONNECTION = "ATTRIBUTE_FOR_CONNECTION";

	private static final String ATT_NAME_USER_NAME = "ATTRIBUTE_FOR_STORE_USER_NAME_IN_COOKIE";

	// Lưu trữ Connection vào attribute của request.
	// Thông tin lưu trữ này chỉ tồn tại trong thời gian yêu cầu (request)
	// cho tới khi dữ liệu được trả về trình duyệt người dùng.
	public static void storeConnection(ServletRequest request, Connection conn) {
		request.setAttribute(ATT_NAME_CONNECTION, conn);
	}

	// Lấy đối tượng Connection đã được lưu trữ trong attribute của request.
	public static Connection getStoredConnection(ServletRequest request) {
		Connection conn = (Connection) request.getAttribute(ATT_NAME_CONNECTION);
		return conn;
	}

	// Lưu trữ thông tin người dùng đã login vào Session.
	public static void storeLoginedUser(HttpSession session, UserAccount loginedUser) {
		// Trên JSP có thể truy cập thông qua ${loginedUser}
		session.setAttribute("loginedUser", loginedUser);
	}

	// Lấy thông tin người dùng lưu trữ trong Session.
	public static UserAccount getLoginedUser(HttpSession session) {
		UserAccount loginedUser = (UserAccount) session.getAttribute("loginedUser");
		return loginedUser;
	}

	// Lưu thông tin người dùng vào Cookie.
	public static void storeUserCookie(HttpServletResponse response, UserAccount user) {
		System.out.println("Store user cookie");
		Cookie cookieUserName = new Cookie(ATT_NAME_USER_NAME, user.getUserName());
		// 1 ngày (Đã đổi ra giây)
		cookieUserName.setMaxAge(24 * 60 * 60);
		response.addCookie(cookieUserName);
	}

	public static String getUserNameInCookie(HttpServletRequest request) {
		Cookie[] cookies = request.getCookies();
		if (cookies != null) {
			for (Cookie cookie : cookies) {
				if (ATT_NAME_USER_NAME.equals(cookie.getName())) {
					return cookie.getValue();
				}
			}
		}
		return null;
	}

	// Xóa Cookie của người dùng
	public static void deleteUserCookie(HttpServletResponse response) {
		Cookie cookieUserName = new Cookie(ATT_NAME_USER_NAME, null);
		// 0 giây. (Cookie này sẽ hết hiệu lực ngay lập tức)
		cookieUserName.setMaxAge(0);
		response.addCookie(cookieUserName);
	}

}
DBUtils.java
package org.o7planning.simplewebapp.utils;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import org.o7planning.simplewebapp.beans.Product;
import org.o7planning.simplewebapp.beans.UserAccount;

public class DBUtils {

	public static UserAccount findUser(Connection conn, //
			String userName, String password) throws SQLException {

		String sql = "Select a.User_Name, a.Password, a.Gender from User_Account a " //
				+ " where a.User_Name = ? and a.password= ?";

		PreparedStatement pstm = conn.prepareStatement(sql);
		pstm.setString(1, userName);
		pstm.setString(2, password);
		ResultSet rs = pstm.executeQuery();

		if (rs.next()) {
			String gender = rs.getString("Gender");
			UserAccount user = new UserAccount();
			user.setUserName(userName);
			user.setPassword(password);
			user.setGender(gender);
			return user;
		}
		return null;
	}

	public static UserAccount findUser(Connection conn, String userName) throws SQLException {

		String sql = "Select a.User_Name, a.Password, a.Gender from User_Account a "//
				+ " where a.User_Name = ? ";

		PreparedStatement pstm = conn.prepareStatement(sql);
		pstm.setString(1, userName);

		ResultSet rs = pstm.executeQuery();

		if (rs.next()) {
			String password = rs.getString("Password");
			String gender = rs.getString("Gender");
			UserAccount user = new UserAccount();
			user.setUserName(userName);
			user.setPassword(password);
			user.setGender(gender);
			return user;
		}
		return null;
	}

	public static List<Product> queryProduct(Connection conn) throws SQLException {
		String sql = "Select a.Code, a.Name, a.Price from Product a ";

		PreparedStatement pstm = conn.prepareStatement(sql);

		ResultSet rs = pstm.executeQuery();
		List<Product> list = new ArrayList<Product>();
		while (rs.next()) {
			String code = rs.getString("Code");
			String name = rs.getString("Name");
			float price = rs.getFloat("Price");
			Product product = new Product();
			product.setCode(code);
			product.setName(name);
			product.setPrice(price);
			list.add(product);
		}
		return list;
	}

	public static Product findProduct(Connection conn, String code) throws SQLException {
		String sql = "Select a.Code, a.Name, a.Price from Product a where a.Code=?";

		PreparedStatement pstm = conn.prepareStatement(sql);
		pstm.setString(1, code);

		ResultSet rs = pstm.executeQuery();

		while (rs.next()) {
			String name = rs.getString("Name");
			float price = rs.getFloat("Price");
			Product product = new Product(code, name, price);
			return product;
		}
		return null;
	}

	public static void updateProduct(Connection conn, Product product) throws SQLException {
		String sql = "Update Product set Name =?, Price=? where Code=? ";

		PreparedStatement pstm = conn.prepareStatement(sql);

		pstm.setString(1, product.getName());
		pstm.setFloat(2, product.getPrice());
		pstm.setString(3, product.getCode());
		pstm.executeUpdate();
	}

	public static void insertProduct(Connection conn, Product product) throws SQLException {
		String sql = "Insert into Product(Code, Name,Price) values (?,?,?)";

		PreparedStatement pstm = conn.prepareStatement(sql);

		pstm.setString(1, product.getCode());
		pstm.setString(2, product.getName());
		pstm.setFloat(3, product.getPrice());

		pstm.executeUpdate();
	}

	public static void deleteProduct(Connection conn, String code) throws SQLException {
		String sql = "Delete From Product where Code= ?";

		PreparedStatement pstm = conn.prepareStatement(sql);

		pstm.setString(1, code);

		pstm.executeUpdate();
	}

}

13. Tạo Servlet Filter kết nối database

Trong JDBCFilter tôi có kiểm tra xem các request nào thực sự gọi tới một Servlet, để dễ hiểu bạn có thể xem hình dưới đây, nó mô tả quan hệ giữa các khái niệm của Servlet.
JDBCFilter với khai báo url-pattern = /*, điều đó có nghĩa là mọi request của người dùng đều phải đi qua filter này. JDBCFilter sẽ kiểm tra request để đảm bảo chỉ mở kết nối JDBC cho các request cần thiết, chẳng hạn cho Servlet, tránh mở kết nối JDBC đối với các request thông thường như image, css, js, html.
JDBCFilter.java
package org.o7planning.simplewebapp.filter;

import java.io.IOException;
import java.sql.Connection;
import java.util.Collection;
import java.util.Map;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;

import org.o7planning.simplewebapp.conn.ConnectionUtils;
import org.o7planning.simplewebapp.utils.MyUtils;

@WebFilter(filterName = "jdbcFilter", urlPatterns = { "/*" })
public class JDBCFilter implements Filter {

	public JDBCFilter() {
	}

	@Override
	public void init(FilterConfig fConfig) throws ServletException {

	}

	@Override
	public void destroy() {

	}

	// Kiểm tra mục tiêu của request hiện tại là 1 Servlet?
	private boolean needJDBC(HttpServletRequest request) {
		System.out.println("JDBC Filter");
		// 
		// Servlet Url-pattern: /spath/*
		// 
		// => /spath
		String servletPath = request.getServletPath();
		// => /abc/mnp
		String pathInfo = request.getPathInfo();

		String urlPattern = servletPath;

		if (pathInfo != null) {
			// => /spath/*
			urlPattern = servletPath + "/*";
		}

		// Key: servletName.
		// Value: ServletRegistration
		Map<String, ? extends ServletRegistration> servletRegistrations = request.getServletContext()
				.getServletRegistrations();

		// Tập hợp tất cả các Servlet trong WebApp của bạn.
		Collection<? extends ServletRegistration> values = servletRegistrations.values();
		for (ServletRegistration sr : values) {
			Collection<String> mappings = sr.getMappings();
			if (mappings.contains(urlPattern)) {
				return true;
			}
		}
		return false;
	}

	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
			throws IOException, ServletException {

		HttpServletRequest req = (HttpServletRequest) request;

		// Chỉ mở connection (kết nối) đối với các request có đường dẫn đặc biệt.
		// (Chẳng hạn đường dẫn tới các servlet, jsp, ..)
		// 
		// Tránh tình trạng mở Connection với các yêu cầu thông thường.
		// (Chẳng hạn image, css, javascript,... )
		// 
		if (this.needJDBC(req)) {

			System.out.println("Open Connection for: " + req.getServletPath());

			Connection conn = null;
			try {
				// Tạo đối tượng Connection kết nối database.
				conn = ConnectionUtils.getConnection();
				// Sét tự động commit false, để chủ động điều khiển.
				conn.setAutoCommit(false);

				// Lưu trữ đối tượng Connection vào attribute của request.
				MyUtils.storeConnection(request, conn);

				// Cho phép request đi tiếp.
				// (Đi tới Filter tiếp theo hoặc đi tới mục tiêu).
				chain.doFilter(request, response);

				// Gọi phương thức commit() để hoàn thành giao dịch với DB.
				conn.commit();
			} catch (Exception e) {
				e.printStackTrace();
				ConnectionUtils.rollbackQuietly(conn);
				throw new ServletException();
			} finally {
				ConnectionUtils.closeQuietly(conn);
			}
		}
		// Với các request thông thường (image,css,html,..)
		// không cần mở connection.
		else {
			// Cho phép request đi tiếp.
			// (Đi tới Filter tiếp theo hoặc đi tới mục tiêu).
			chain.doFilter(request, response);
		}

	}

}

14. Servlet Filter đọc Cookie để tự động đăng nhập

Trong trường hợp người dùng đã login và nhớ thông tin trong lần truy cập trước đó (Chẳng hạn hôm trước). Và giờ người dùng quay trở lại, Filter này sẽ kiểm tra thông tin Cookie đã lưu bởi trình duyệt và tự động Login.
CookieFilter.java
package org.o7planning.simplewebapp.filter;

import java.io.IOException;
import java.sql.Connection;
import java.sql.SQLException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.o7planning.simplewebapp.beans.UserAccount;
import org.o7planning.simplewebapp.utils.DBUtils;
import org.o7planning.simplewebapp.utils.MyUtils;

@WebFilter(filterName = "cookieFilter", urlPatterns = { "/*" })
public class CookieFilter implements Filter {

	public CookieFilter() {
	}

	@Override
	public void init(FilterConfig fConfig) throws ServletException {

	}

	@Override
	public void destroy() {

	}

	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
			throws IOException, ServletException {
		HttpServletRequest req = (HttpServletRequest) request;
		HttpSession session = req.getSession();

		UserAccount userInSession = MyUtils.getLoginedUser(session);
		// 
		if (userInSession != null) {
			session.setAttribute("COOKIE_CHECKED", "CHECKED");
			chain.doFilter(request, response);
			return;
		}

		// Connection đã được tạo trong JDBCFilter.
		Connection conn = MyUtils.getStoredConnection(request);

		// Cờ (flag) để kiểm tra Cookie.
		String checked = (String) session.getAttribute("COOKIE_CHECKED");
		if (checked == null && conn != null) {
			String userName = MyUtils.getUserNameInCookie(req);
			try {
				UserAccount user = DBUtils.findUser(conn, userName);
				MyUtils.storeLoginedUser(session, user);
			} catch (SQLException e) {
				e.printStackTrace();
			}
			// Đánh dấu đã kiểm tra Cookie.
			session.setAttribute("COOKIE_CHECKED", "CHECKED");
		}

		chain.doFilter(request, response);
	}

}
CHÚ Ý:
JDBCFilter & CookieFilter có cùng url-pattern =/*, bạn cần phải cấu hình để đảm bảo rằng JDBCFilter được thực thi trước. Do đó cần phải khai báo thứ tự trong web.xml (Không có cách nào khai báo thứ tự bằng Annotation).
<filter-mapping>
    <filter-name>jdbcFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

<filter-mapping>
    <filter-name>cookieFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
web.xml đầy đủ:
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xmlns="http://java.sun.com/xml/ns/javaee"
     xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
                       http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
     id="WebApp_ID" version="3.0">
 <display-name>SimpleWebApp</display-name>


   <filter-mapping>
       <filter-name>jdbcFilter</filter-name>
       <url-pattern>/*</url-pattern>
   </filter-mapping>
   
   <filter-mapping>
       <filter-name>cookieFilter</filter-name>
       <url-pattern>/*</url-pattern>
   </filter-mapping>

 <welcome-file-list>

   <welcome-file>home</welcome-file>
   
   <welcome-file>index.html</welcome-file>
   
 </welcome-file-list>


</web-app>

15. Servlet Encoding Filter

EncodingFilter.java
package org.o7planning.simplewebapp.filter;

import java.io.IOException;
import java.sql.Connection;
import java.util.Collection;
import java.util.Map;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;

import org.o7planning.simplewebapp.conn.ConnectionUtils;
import org.o7planning.simplewebapp.utils.MyUtils;

@WebFilter(filterName = "encodingFilter", urlPatterns = { "/*" })
public class EncodingFilter implements Filter {

  public EncodingFilter() {
  }

  @Override
  public void init(FilterConfig fConfig) throws ServletException {

  }

  @Override
  public void destroy() {

  }

  @Override
  public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
          throws IOException, ServletException {
      request.setCharacterEncoding("UTF-8");

      chain.doFilter(request, response);
  }

}

16. Các trang tái sử dụng

Một số trang JSP sẽ được sử dụng để nhúng vào các trang khác tại thời điểm Runtime, thông qua việc sử dụng:
<jsp:include page="_header.jsp"></jsp:include>
<jsp:include page="_menu.jsp"></jsp:include>

<jsp:include page="_footer.jsp"></jsp:include>
/WEB-INF/views/_header.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
  pageEncoding="UTF-8"%>
<div style="background: #E0E0E0; height: 55px; padding: 5px;">
  <div style="float: left">
     <h1>My Site</h1>
  </div>

  <div style="float: right; padding: 10px; text-align: right;">

     <!-- User store in session with attribute: loginedUser -->
     Hello <b>${loginedUser.userName}</b>
   <br/>
     Search <input name="search">

  </div>

</div>
/WEB-INF/views/_menu.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
   pageEncoding="UTF-8"%>
   
<div style="padding: 5px;">

   <a href="${pageContext.request.contextPath}/">Home</a>
   |
   <a href="${pageContext.request.contextPath}/productList">Product List</a>
   |
   <a href="${pageContext.request.contextPath}/userInfo">My Account Info</a>
   |
   <a href="${pageContext.request.contextPath}/login">Login</a>
   
</div>
/WEB-INF/views/_footer.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
  pageEncoding="UTF-8"%>
 
<div
  style="background: #E0E0E0; text-align: center; padding: 5px; margin-top: 10px;">
 
  @Copyright o7planning.org
 
</div>

17. Trang chủ

Khi gõ đường dẫn mặc định, chẳng hạn gõ tên miền của trang web nó sẽ hiển thị ra trang chủ (Trường hợp contextPath = ""), bạn cần phải khai báo trang chủ trong <welcome-file-list> của web.xml
Đường dẫn dưới đây hiện tại đang hiển thị nội dung của trang index.html
Bạn cần thiết kế một trang chủ là một JSP để có được các thông tin động thay vì một trang html vốn chỉ chứa các thông tin tĩnh.
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xmlns="http://java.sun.com/xml/ns/javaee"
     xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
                       http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
     id="WebApp_ID" version="3.0">
 <display-name>SimpleWebApp</display-name>


   <filter-mapping>
       <filter-name>jdbcFilter</filter-name>
       <url-pattern>/*</url-pattern>
   </filter-mapping>
   
   <filter-mapping>
       <filter-name>cookieFilter</filter-name>
       <url-pattern>/*</url-pattern>
   </filter-mapping>

 <welcome-file-list>

   <welcome-file>home</welcome-file>
   
   <welcome-file>index.html</welcome-file>
   
 </welcome-file-list>


</web-app>
Mô hình trang chủ:
HomeServlet.java
package org.o7planning.simplewebapp.servlet;

import java.io.IOException;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet(urlPatterns = { "/home"})
public class HomeServlet extends HttpServlet {
   private static final long serialVersionUID = 1L;

   public HomeServlet() {
       super();
   }

   @Override
   protected void doGet(HttpServletRequest request, HttpServletResponse response)
           throws ServletException, IOException {

       // Forward toi trang /WEB-INF/views/homeView.jsp
       // (Người dùng không bao giờ truy cập trực tiếp được vào các trang JSP
       // đặt trong WEB-INF)
       RequestDispatcher dispatcher = this.getServletContext().getRequestDispatcher("/WEB-INF/views/homeView.jsp");
       
       dispatcher.forward(request, response);
       
   }

   @Override
   protected void doPost(HttpServletRequest request, HttpServletResponse response)
           throws ServletException, IOException {
       doGet(request, response);
   }

}
/WEB-INF/views/homeView.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
  pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
  <head>
     <meta charset="UTF-8">
     <title>Home Page</title>
  </head>
  <body>

     <jsp:include page="_header.jsp"></jsp:include>
     <jsp:include page="_menu.jsp"></jsp:include>
   
      <h3>Home Page</h3>
     
      This is demo Simple web application using jsp,servlet &amp; Jdbc. <br><br>
      <b>It includes the following functions:</b>
      <ul>
         <li>Login</li>
         <li>Storing user information in cookies</li>
         <li>Product List</li>
         <li>Create Product</li>
         <li>Edit Product</li>
         <li>Delete Product</li>
      </ul>

     <jsp:include page="_footer.jsp"></jsp:include>

  </body>
</html>
Chạy lại ứng dụng của bạn, và thử 2 đường dẫn:

Chú ý: Nếu vì một lý do gì đó, đường dẫn http://localhost:8080/SimpleWebApp/ vẫn chuyển tới index.html, bạn có thể xóa hoặc đổi tên file index.html, chẳng hạn đổi sang _index.html

18. Trang đăng nhập - LoginServlet

Đây là mô hình chức năng Login:
LoginServlet.java
package org.o7planning.simplewebapp.servlet;

import java.io.IOException;
import java.sql.Connection;
import java.sql.SQLException;

import javax.servlet.RequestDispatcher;
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 javax.servlet.http.HttpSession;

import org.o7planning.simplewebapp.beans.UserAccount;
import org.o7planning.simplewebapp.utils.DBUtils;
import org.o7planning.simplewebapp.utils.MyUtils;

@WebServlet(urlPatterns = { "/login" })
public class LoginServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	public LoginServlet() {
		super();
	}

	// Hiển thị trang Login.
	@Override
	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		// Forward tới trang /WEB-INF/views/loginView.jsp
		// (Người dùng không thể truy cập trực tiếp
		// vào các trang JSP đặt trong thư mục WEB-INF).
		RequestDispatcher dispatcher //
				= this.getServletContext().getRequestDispatcher("/WEB-INF/views/loginView.jsp");

		dispatcher.forward(request, response);

	}

	// Khi người nhập userName & password, và nhấn Submit.
	// Phương thức này sẽ được thực thi.
	@Override
	protected void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		String userName = request.getParameter("userName");
		String password = request.getParameter("password");
		String rememberMeStr = request.getParameter("rememberMe");
		boolean remember = "Y".equals(rememberMeStr);

		UserAccount user = null;
		boolean hasError = false;
		String errorString = null;

		if (userName == null || password == null || userName.length() == 0 || password.length() == 0) {
			hasError = true;
			errorString = "Required username and password!";
		} else {
			Connection conn = MyUtils.getStoredConnection(request);
			try {
				// Tìm user trong DB.
				user = DBUtils.findUser(conn, userName, password);

				if (user == null) {
					hasError = true;
					errorString = "User Name or password invalid";
				}
			} catch (SQLException e) {
				e.printStackTrace();
				hasError = true;
				errorString = e.getMessage();
			}
		}
		// Trong trường hợp có lỗi,
		// forward (chuyển hướng) tới /WEB-INF/views/login.jsp
		if (hasError) {
			user = new UserAccount();
			user.setUserName(userName);
			user.setPassword(password);

			// Lưu các thông tin vào request attribute trước khi forward.
			request.setAttribute("errorString", errorString);
			request.setAttribute("user", user);

			// Forward (Chuyển tiếp) tới trang /WEB-INF/views/login.jsp
			RequestDispatcher dispatcher //
					= this.getServletContext().getRequestDispatcher("/WEB-INF/views/loginView.jsp");

			dispatcher.forward(request, response);
		}
		// Trường hợp không có lỗi.
		// Lưu thông tin người dùng vào Session.
		// Và chuyển hướng sang trang userInfo.
		else {
			HttpSession session = request.getSession();
			MyUtils.storeLoginedUser(session, user);

			// Nếu người dùng chọn tính năng "Remember me".
			if (remember) {
				MyUtils.storeUserCookie(response, user);
			}
			// Ngược lại xóa Cookie
			else {
				MyUtils.deleteUserCookie(response);
			}

			// Redirect (Chuyển hướng) sang trang /userInfo.
			response.sendRedirect(request.getContextPath() + "/userInfo");
		}
	}

}
UserInfoServlet.java
package org.o7planning.simplewebapp.servlet;

import java.io.IOException;

import javax.servlet.RequestDispatcher;
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 javax.servlet.http.HttpSession;

import org.o7planning.simplewebapp.beans.UserAccount;
import org.o7planning.simplewebapp.utils.MyUtils;

@WebServlet(urlPatterns = { "/userInfo" })
public class UserInfoServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	public UserInfoServlet() {
		super();
	}

	@Override
	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		HttpSession session = request.getSession();

		// Kiểm tra người dùng đã đăng nhập (login) chưa.
		UserAccount loginedUser = MyUtils.getLoginedUser(session);

		// Nếu chưa đăng nhập (login).
		if (loginedUser == null) {
			// Redirect (Chuyển hướng) tới trang login.
			response.sendRedirect(request.getContextPath() + "/login");
			return;
		}
		// Lưu thông tin vào request attribute trước khi forward (chuyển tiếp).
		request.setAttribute("user", loginedUser);

		// Nếu người dùng đã login thì forward (chuyển tiếp) tới trang
		// /WEB-INF/views/userInfoView.jsp
		RequestDispatcher dispatcher //
				= this.getServletContext().getRequestDispatcher("/WEB-INF/views/userInfoView.jsp");
		dispatcher.forward(request, response);

	}

	@Override
	protected void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		doGet(request, response);
	}

}
/WEB-INF/views/loginView.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
   pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
   <head>
      <meta charset="UTF-8">
      <title>Login</title>
   </head>
   <body>
      <jsp:include page="_header.jsp"></jsp:include>
      <jsp:include page="_menu.jsp"></jsp:include>

      <h3>Login Page</h3>
      <p style="color: red;">${errorString}</p>


      <form method="POST" action="${pageContext.request.contextPath}/login">
         <table border="0">
            <tr>
               <td>User Name</td>
               <td><input type="text" name="userName" value= "${user.userName}" /> </td>
            </tr>
            <tr>
               <td>Password</td>
               <td><input type="text" name="password" value= "${user.password}" /> </td>
            </tr>
            <tr>
               <td>Remember me</td>
               <td><input type="checkbox" name="rememberMe" value= "Y" /> </td>
            </tr>
            <tr>
               <td colspan ="2">
                  <input type="submit" value= "Submit" />
                  <a href="${pageContext.request.contextPath}/">Cancel</a>
               </td>
            </tr>
         </table>
      </form>

      <p style="color:blue;">User Name: tom, password: tom001 or jerry/jerry001</p>

      <jsp:include page="_footer.jsp"></jsp:include>
   </body>
</html>
/WEB-INF/views/userInfoView.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
 pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
 <head>
    <meta charset="UTF-8">
    <title>User Info</title>
 </head>
 <body>

    <jsp:include page="_header.jsp"></jsp:include>
    <jsp:include page="_menu.jsp"></jsp:include>

    <h3>Hello: ${user.userName}</h3>

    User Name: <b>${user.userName}</b>
    <br />
    Gender: ${user.gender } <br />

    <jsp:include page="_footer.jsp"></jsp:include>

 </body>
</html>
Chạy ứng dụng của bạn:

19. Trang danh sách sản phẩm

Mô hình:
ProductListServlet.java
package org.o7planning.simplewebapp.servlet;

import java.io.IOException;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;

import javax.servlet.RequestDispatcher;
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 org.o7planning.simplewebapp.beans.Product;
import org.o7planning.simplewebapp.utils.DBUtils;
import org.o7planning.simplewebapp.utils.MyUtils;

@WebServlet(urlPatterns = { "/productList" })
public class ProductListServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	public ProductListServlet() {
		super();
	}

	@Override
	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		Connection conn = MyUtils.getStoredConnection(request);

		String errorString = null;
		List<Product> list = null;
		try {
			list = DBUtils.queryProduct(conn);
		} catch (SQLException e) {
			e.printStackTrace();
			errorString = e.getMessage();
		}
		// Lưu thông tin vào request attribute trước khi forward sang views.
		request.setAttribute("errorString", errorString);
		request.setAttribute("productList", list);
		
		// Forward sang /WEB-INF/views/productListView.jsp
		RequestDispatcher dispatcher = request.getServletContext()
				.getRequestDispatcher("/WEB-INF/views/productListView.jsp");
		dispatcher.forward(request, response);
	}

	@Override
	protected void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		doGet(request, response);
	}

}
/WEB-INF/views/productListView.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
 pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>  
<!DOCTYPE html>
<html>
 <head>
    <meta charset="UTF-8">
    <title>Product List</title>
 </head>
 <body>

    <jsp:include page="_header.jsp"></jsp:include>
    <jsp:include page="_menu.jsp"></jsp:include>

    <h3>Product List</h3>

    <p style="color: red;">${errorString}</p>

    <table border="1" cellpadding="5" cellspacing="1" >
       <tr>
          <th>Code</th>
          <th>Name</th>
          <th>Price</th>
          <th>Edit</th>
          <th>Delete</th>
       </tr>
       <c:forEach items="${productList}" var="product" >
          <tr>
             <td>${product.code}</td>
             <td>${product.name}</td>
             <td>${product.price}</td>
             <td>
                <a href="editProduct?code=${product.code}">Edit</a>
             </td>
             <td>
                <a href="deleteProduct?code=${product.code}">Delete</a>
             </td>
          </tr>
       </c:forEach>
    </table>

    <a href="createProduct" >Create Product</a>

    <jsp:include page="_footer.jsp"></jsp:include>

 </body>
</html>
Chạy lại ứng dụng:

20. Thêm sản phẩm

Mô hình chức năng thêm sản phẩm:
CreateProductServlet.java
package org.o7planning.simplewebapp.servlet;

import java.io.IOException;
import java.sql.Connection;
import java.sql.SQLException;

import javax.servlet.RequestDispatcher;
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 org.o7planning.simplewebapp.beans.Product;
import org.o7planning.simplewebapp.utils.DBUtils;
import org.o7planning.simplewebapp.utils.MyUtils;

@WebServlet(urlPatterns = { "/createProduct" })
public class CreateProductServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	public CreateProductServlet() {
		super();
	}

	// Hiển thị trang tạo sản phẩm.
	@Override
	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		RequestDispatcher dispatcher = request.getServletContext()
				.getRequestDispatcher("/WEB-INF/views/createProductView.jsp");
		dispatcher.forward(request, response);
	}

	// Khi người dùng nhập các thông tin sản phẩm, và nhấn Submit.
	// Phương thức này sẽ được gọi.
	@Override
	protected void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		Connection conn = MyUtils.getStoredConnection(request);

		String code = (String) request.getParameter("code");
		String name = (String) request.getParameter("name");
		String priceStr = (String) request.getParameter("price");
		float price = 0;
		try {
			price = Float.parseFloat(priceStr);
		} catch (Exception e) {
		}
		Product product = new Product(code, name, price);

		String errorString = null;

		// Mã sản phẩm phải là chuỗi chữ [a-zA-Z_0-9]
		// Có ít nhất một ký tự.
		String regex = "\\w+";

		if (code == null || !code.matches(regex)) {
			errorString = "Product Code invalid!";
		}

		if (errorString == null) {
			try {
				DBUtils.insertProduct(conn, product);
			} catch (SQLException e) {
				e.printStackTrace();
				errorString = e.getMessage();
			}
		}

		// Lưu thông tin vào request attribute trước khi forward sang views.
		request.setAttribute("errorString", errorString);
		request.setAttribute("product", product);

		// Nếu có lỗi forward (chuyển tiếp) sang trang 'edit'.
		if (errorString != null) {
			RequestDispatcher dispatcher = request.getServletContext()
					.getRequestDispatcher("/WEB-INF/views/createProductView.jsp");
			dispatcher.forward(request, response);
		}
		// Nếu mọi thứ tốt đẹp.
		// Redirect (chuyển hướng) sang trang danh sách sản phẩm.
		else {
			response.sendRedirect(request.getContextPath() + "/productList");
		}
	}

}
/WEB-INF/views/createProductView.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
   pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>

<!DOCTYPE html>
<html>
   <head>
      <meta charset="UTF-8">
      <title>Create Product</title>
   </head>
   <body>
   
      <jsp:include page="_header.jsp"></jsp:include>
      <jsp:include page="_menu.jsp"></jsp:include>
      
      <h3>Create Product</h3>
      
      <p style="color: red;">${errorString}</p>
      
      <form method="POST" action="${pageContext.request.contextPath}/createProduct">
         <table border="0">
            <tr>
               <td>Code</td>
               <td><input type="text" name="code" value="${product.code}" /></td>
            </tr>
            <tr>
               <td>Name</td>
               <td><input type="text" name="name" value="${product.name}" /></td>
            </tr>
            <tr>
               <td>Price</td>
               <td><input type="text" name="price" value="${product.price}" /></td>
            </tr>
            <tr>
               <td colspan="2">                   
                   <input type="submit" value="Submit" />
                   <a href="productList">Cancel</a>
               </td>
            </tr>
         </table>
      </form>
      
      <jsp:include page="_footer.jsp"></jsp:include>
      
   </body>
</html>

21. Sửa thông tin sản phẩm

Mô hình chức năng sửa thông tin sản phẩm:
EditProductServlet.java
package org.o7planning.simplewebapp.servlet;

import java.io.IOException;
import java.sql.Connection;
import java.sql.SQLException;

import javax.servlet.RequestDispatcher;
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 org.o7planning.simplewebapp.beans.Product;
import org.o7planning.simplewebapp.utils.DBUtils;
import org.o7planning.simplewebapp.utils.MyUtils;

@WebServlet(urlPatterns = { "/editProduct" })
public class EditProductServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	public EditProductServlet() {
		super();
	}

	// Hiển thị trang sửa sản phẩm.
	@Override
	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		Connection conn = MyUtils.getStoredConnection(request);

		String code = (String) request.getParameter("code");

		Product product = null;

		String errorString = null;

		try {
			product = DBUtils.findProduct(conn, code);
		} catch (SQLException e) {
			e.printStackTrace();
			errorString = e.getMessage();
		}

		// Không có lỗi.
		// Sản phẩm không tồn tại để edit.
		// Redirect sang trang danh sách sản phẩm.
		if (errorString != null && product == null) {
			response.sendRedirect(request.getServletPath() + "/productList");
			return;
		}

		// Lưu thông tin vào request attribute trước khi forward sang views.
		request.setAttribute("errorString", errorString);
		request.setAttribute("product", product);

		RequestDispatcher dispatcher = request.getServletContext()
				.getRequestDispatcher("/WEB-INF/views/editProductView.jsp");
		dispatcher.forward(request, response);

	}

	// Sau khi người dùng sửa đổi thông tin sản phẩm, và nhấn Submit.
	// Phương thức này sẽ được thực thi.
	@Override
	protected void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		Connection conn = MyUtils.getStoredConnection(request);

		String code = (String) request.getParameter("code");
		String name = (String) request.getParameter("name");
		String priceStr = (String) request.getParameter("price");
		float price = 0;
		try {
			price = Float.parseFloat(priceStr);
		} catch (Exception e) {
		}
		Product product = new Product(code, name, price);

		String errorString = null;

		try {
			DBUtils.updateProduct(conn, product);
		} catch (SQLException e) {
			e.printStackTrace();
			errorString = e.getMessage();
		}
		// Lưu thông tin vào request attribute trước khi forward sang views.
		request.setAttribute("errorString", errorString);
		request.setAttribute("product", product);

		// Nếu có lỗi forward sang trang edit.
		if (errorString != null) {
			RequestDispatcher dispatcher = request.getServletContext()
					.getRequestDispatcher("/WEB-INF/views/editProductView.jsp");
			dispatcher.forward(request, response);
		}
		// Nếu mọi thứ tốt đẹp.
		// Redirect sang trang danh sách sản phẩm.
		else {
			response.sendRedirect(request.getContextPath() + "/productList");
		}
	}

}
/WEB-INF/views/editProductView.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
   pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!DOCTYPE html>
<html>
   <head>
      <meta charset="UTF-8">
      <title>Edit Product</title>
   </head>
   <body>

      <jsp:include page="_header.jsp"></jsp:include>
      <jsp:include page="_menu.jsp"></jsp:include>

      <h3>Edit Product</h3>

      <p style="color: red;">${errorString}</p>

      <c:if test="${not empty product}">
         <form method="POST" action="${pageContext.request.contextPath}/editProduct">
            <input type="hidden" name="code" value="${product.code}" />
            <table border="0">
               <tr>
                  <td>Code</td>
                  <td style="color:red;">${product.code}</td>
               </tr>
               <tr>
                  <td>Name</td>
                  <td><input type="text" name="name" value="${product.name}" /></td>
               </tr>
               <tr>
                  <td>Price</td>
                  <td><input type="text" name="price" value="${product.price}" /></td>
               </tr>
               <tr>
                  <td colspan = "2">
                      <input type="submit" value="Submit" />
                      <a href="${pageContext.request.contextPath}/productList">Cancel</a>
                  </td>
               </tr>
            </table>
         </form>
      </c:if>

      <jsp:include page="_footer.jsp"></jsp:include>

   </body>
</html>

22. Xóa sản phẩm

Mô hình xóa sản phẩm:
DeleteProductServlet.java
package org.o7planning.simplewebapp.servlet;

import java.io.IOException;
import java.sql.Connection;
import java.sql.SQLException;

import javax.servlet.RequestDispatcher;
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 org.o7planning.simplewebapp.utils.DBUtils;
import org.o7planning.simplewebapp.utils.MyUtils;

@WebServlet(urlPatterns = { "/deleteProduct" })
public class DeleteProductServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	public DeleteProductServlet() {
		super();
	}

	@Override
	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		Connection conn = MyUtils.getStoredConnection(request);

		String code = (String) request.getParameter("code");

		String errorString = null;

		try {
			DBUtils.deleteProduct(conn, code);
		} catch (SQLException e) {
			e.printStackTrace();
			errorString = e.getMessage();
		} 
		
		// Nếu có lỗi, forward (chuyển tiếp) sang trang thông báo lỗi.
		if (errorString != null) {
			// Lưu thông tin vào request attribute trước khi forward sang views.
			request.setAttribute("errorString", errorString);
			// 
			RequestDispatcher dispatcher = request.getServletContext()
					.getRequestDispatcher("/WEB-INF/views/deleteProductErrorView.jsp");
			dispatcher.forward(request, response);
		}
		// Nếu mọi thứ tốt đẹp.
		// Redirect (chuyển hướng) sang trang danh sách sản phẩm.
		else {
			response.sendRedirect(request.getContextPath() + "/productList");
		}

	}

	@Override
	protected void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		doGet(request, response);
	}

}
/WEB-INF/views/deleteProductErrorView.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
 pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!DOCTYPE html>
<html>
 <head>
    <meta charset="UTF-8">
    <title>Delete Product</title>
 </head>

 <body>

    <jsp:include page="_header.jsp"></jsp:include>
    <jsp:include page="_menu.jsp"></jsp:include>
   
    <h3>Delete Product</h3>
   
    <p style="color: red;">${errorString}</p>
    <a href="productList">Product List</a>
   
    <jsp:include page="_footer.jsp"></jsp:include>
   
 </body>
</html>