CÔNG NGHỆ THÔNG TIN >> BÀI VIẾT CHỌN LỌC

Xử lý giỏ hàng trong Spring MVC Hibernate-SQL Server

Đăng lúc: 02:22 PM - 11/03/2024 bởi Charles Chung - 1565

Trong bài này tôi sẽ hướng dẫn các bạn các thao tác cơ bản về xử lý giỏ hàng trong Spring MVC Hiberate-SQL Server

1. Kiến thức cần có

  • Thiết kế web với HTML5, CSS3, JS, JQuery, Bootstrap
  • Cơ bản về SQL Server
  • Nắm vững JavaCore
  • Nắm cơ bản về JSP Servlet, Spring MVC

2. Chuẩn bị dữ liệu

  • Tải tệp script tạo cơ sở dữ liệu trong SQL Server tại đây
  • Tải thư mục images chứa các ảnh sách tại đây

3. Các chức năng trong bài viết

  • Hiển thị danh mục sách và sách trên trang chủ
  • Hiển thị sách theo danh mục chọn
  • Xem chi tiết sách
  • Thêm vào giỏ hàng
  • Đăng nhập
  • Hiển thị thông tin người dùng kèm logout
  • Hiển thị nút giỏ hàng với tổng số sách bên trong
  • Hiển thị thông tin chi tiết các sản phẩm trong giỏ hàng
  • Đặt hàng

4. Các bước thực hiện

Bước 1: Tạo dự án

Mở Eclipse tạo loại project Dynamic Web Project và đặt tên "SpringMVCHibernateSQLServerCartItem", lưu ý sinh file web.xml trong quá trình tạo

Bước 2: Convert project sang Maven Project

Kích chuột phải vào project vừa tạo -> chọn Configure->Convert to Maven Project -> Finish

Bước 3: Mở file pom.xml và cấu hình các dependency như sau

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<dependencies>
		<!-- https://mvnrepository.com/artifact/javax.servlet/jstl -->
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>jstl</artifactId>
			<version>1.2</version>
		</dependency>
		<!--https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-webmvc</artifactId>
			<version>5.3.18</version>
		</dependency>
		<!-- https://mvnrepository.com/artifact/org.springframework/spring-web -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-web</artifactId>
			<version>5.3.18</version>
		</dependency>
		<!-- https://mvnrepository.com/artifact/org.springframework/spring-orm -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-orm</artifactId>
			<version>5.3.18</version>
		</dependency>
		<!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-core -->
		<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate-core</artifactId>
			<version>5.4.26.Final</version>
		</dependency>
		<!-- https://mvnrepository.com/artifact/com.microsoft.sqlserver/mssql-jdbc -->
		<dependency>
			<groupId>com.microsoft.sqlserver</groupId>
			<artifactId>mssql-jdbc</artifactId>
			<version>12.5.0.jre11-preview</version>
		</dependency>
</dependencies>

Bước 4: Copy thư mục images đã tải về vào thư mục src/main/webapp/resources của project (chưa có resources thì tạo ra nhé)

Bước 5: Tạo tệp tin spring-servlet.xml trong thư mục src/main/webapp/WEB-INF và cấu hình như sau

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:p="http://www.springframework.org/schema/p"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:mvc="http://www.springframework.org/schema/mvc"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
	http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
	http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd">
	<!-- chỉ ra các package chứa các lớp java được đăng ký như là các bean -->
	<context:component-scan	base-package="com.hanam88.controllers,com.hanam88.services" />
	<!-- chỉ tìm kiếm các bean trong cùng context application mà nó được định nghĩa -->
	<context:annotation-config />
	<!-- mặc định các basic components được ủy quyền gửi request tới các controller -->
	<mvc:annotation-driven />
	<!-- Cấu hình đường dẫn tài nguyên được phép truy cập -->
	<mvc:resources mapping="/**" location="/resources/" />
	<!-- Tạo bean xác định view sẽ được sinh ra (thư mục chứa các view, đuôi tệp tin view) -->
	<bean id="viewResolver"
		class="org.springframework.web.servlet.view.InternalResourceViewResolver"
		p:prefix="/WEB-INF/views/" p:suffix=".jsp" />
	<!-- Tạo đối tượng bean dataSource kết nối database oracle -->
	<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
		<property name="driverClassName" value="com.microsoft.sqlserver.jdbc.SQLServerDriver"></property>
		<property name="url" value="jdbc:sqlserver://localhost:1433;databaseName=BookStore;Encrypt=True;trustServerCertificate=True"></property>
		<property name="username" value="sa"></property>
		<property name="password" value="123465"></property>
	</bean>
	<!-- Tạo đối tượng bean sessionFactory cấu hình Hibernate -->
	<bean id="sessionFactory"
		class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
		<property name="dataSource" ref="dataSource"></property>
		<property name="packagesToScan" value="com.hanam88.entities"></property>
		<property name="hibernateProperties">
			<props>
				<prop key="hibernate.current_session_context_class">thread</prop>
				<prop key="hibernate.show_sql">true</prop>
				<prop key="hibernate.dialect">org.hibernate.dialect.SQLServer2008Dialect</prop>
			</props>
		</property>
	</bean>
</beans>

Bước 6: Mở tệp tin web.xml ở thư mục src/main/webapp/WEB-INF và cấu hình vào trong thẻ web-app như sau

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
 <!-- Cấu hình filter hỗ trợ UTF-8 -->
  <filter>
    <filter-name>encodingFilter</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <init-param>
      <param-name>encoding</param-name>
      <param-value>UTF-8</param-value>
    </init-param>
    <init-param>
      <param-name>forceEncoding</param-name>
      <param-value>true</param-value>
    </init-param>
  </filter>
  <filter-mapping>
    <filter-name>encodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>
  <!-- Cấu hình Dispatcher Servlet nhận các cấu hình của Spring trong file spring-servlet.xml -->
  <servlet>
    <servlet-name>spring</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>/WEB-INF/spring-servlet.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>spring</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>

Bước 7: Tạo các trang jsp để hiển thị dữ liệu và các lớp entities, dao, controller để xử lý logic

Tạo thư mục views trong thư mục src/main/webapp/WEB-INF để chứa các trang jsp, sau đây là cấu trúc project đầy đủ

- Cấu trúc chi tiết phần services và controller

- Cấu trúc chi tiết phần views

- Tạo lớp com.hanam88.enitities/Category.java để map với bảng Categories

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
package com.hanam88.entities;

import java.io.Serializable;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name="Categories")
public class Category implements Serializable{
	private static final long serialVersionUID = 1L;
	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private int categoryId;
	private String categoryName;
	
	public Category() {
		
	}
	public Category(int categoryId, String categoryName) {
		super();
		this.categoryId = categoryId;
		this.categoryName = categoryName;
	}
	
	public int getCategoryId() {
		return categoryId;
	}
	public void setCategoryId(int categoryId) {
		this.categoryId = categoryId;
	}
	public String getCategoryName() {
		return categoryName;
	}
	public void setCategoryName(String categoryName) {
		this.categoryName = categoryName;
	}
	
}

- Tạo lớp com.hanam88.enitities/Account.java để map với bảng Account

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
package com.hanam88.entities;

import java.io.Serializable;

import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name="Account")
public class Account implements Serializable{
	private static final long serialVersionUID = 1L;
	@Id
	private String accountId;
	private String username;
	private String password;
	private String fullName;
	private String picture;
	private String email;
	private String address;
	private String phone;
	private boolean isAdmin;
	private boolean active;
	
	public Account(String accountId, String username, String fullName,String password, String picture, String email, String address,
			String phone, boolean isAdmin, boolean active) {
		super();
		this.accountId = accountId;
		this.username = username;
		this.password = password;
		this.fullName=fullName;
		this.picture = picture;
		this.email = email;
		this.address = address;
		this.phone = phone;
		this.isAdmin = isAdmin;
		this.active = active;
	}
	public Account() {

	}
	
	public String getFullName() {
		return fullName;
	}
	public void setFullName(String fullName) {
		this.fullName = fullName;
	}
	public String getAccountId() {
		return accountId;
	}
	public void setAccountId(String accountId) {
		this.accountId = accountId;
	}
	public String getUsername() {
		return username;
	}
	public void setUsername(String username) {
		this.username = username;
	}
	public String getPassword() {
		return password;
	}
	public void setPassword(String password) {
		this.password = password;
	}
	public String getPicture() {
		return picture;
	}
	public void setPicture(String picture) {
		this.picture = picture;
	}
	public String getEmail() {
		return email;
	}
	public void setEmail(String email) {
		this.email = email;
	}
	public String getAddress() {
		return address;
	}
	public void setAddress(String address) {
		this.address = address;
	}
	public String getPhone() {
		return phone;
	}
	public void setPhone(String phone) {
		this.phone = phone;
	}
	public boolean isAdmin() {
		return isAdmin;
	}
	public void setAdmin(boolean isAdmin) {
		this.isAdmin = isAdmin;
	}
	public boolean isActive() {
		return active;
	}
	public void setActive(boolean active) {
		this.active = active;
	}

}

- Tạo lớp com.hanam88.entities/Basket.java để biểu diễn dữ liệu giỏ hàng

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
package com.hanam88.entities;

import java.io.Serializable;

public class Basket implements Serializable {
	private static final long serialVersionUID = 1L;
	private String bookId;
	private String title;
	private float price;
	private int quantity;
	public Basket() {

	}
	
	public Basket(String bookId, String title, float price, int quantity) {
		super();
		this.bookId = bookId;
		this.title = title;
		this.price = price;
		this.quantity = quantity;
	}

	public String getBookId() {
		return bookId;
	}
	public void setBookId(String bookId) {
		this.bookId = bookId;
	}
	public String getTitle() {
		return title;
	}
	public void setTitle(String title) {
		this.title = title;
	}
	public float getPrice() {
		return price;
	}
	public void setPrice(float price) {
		this.price = price;
	}
	public int getQuantity() {
		return quantity;
	}
	public void setQuantity(int quantity) {
		this.quantity = quantity;
	}

}

- Tương tự tạo các lớp còn lại trong com.hanam88.entities

- Tạo giao diện com.hanam88.services.dao/GenericDao.java

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
package com.hanam88.services.dao;

import java.util.List;

public interface GenericDao<T,K> {
	public List<T> getAll();
	public List<T> search(String name);
	public T get(K key);
	public boolean insert(T obj);
	public boolean update(T obj);
	public boolean delete(K key);
}

- Tạo các giao diện thực thi từ GenericDao theo gợi ý sau

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
public interface BookDao extends GenericDao<Book, String> {
	public List<Category> getByCategory(int categoryId);
}
public interface AccountDao extends GenericDao<Account, String> {
	public Account getAccount(String username);
}
public interface CategoryDao extends GenericDao<Category, Integer> {

}
public interface OrderDao extends GenericDao<OrderBook, String>  {
	public boolean insertOrderDetail(OrderBook order, List<OrderDetail> details );
}
public interface PublisherDao extends GenericDao<Publisher, Integer> {

}

- Tạo lớp com.hanam88.services.dao/AccountImpl.java thực thi từ inteface AccountDao và bổ sung code sau (lưu ý sử dụng @Repository cho các lớp imlement nhé)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
    @Autowired
    SessionFactory sessionFactory;
	
	@Override
	public Account getAccount(String username) {
		Session session=sessionFactory.openSession();
		Query query=session.createQuery("from Account where userName=?1");
		Account data=null;
		try {
			data=(Account)query.setParameter(1, username).getSingleResult();
		}
		catch (Exception e) {
			e.printStackTrace();
		}
		session.close();
		return data;
	}

- Tạo lớp com.hanam88.services.dao/BookImpl.java thực thi từ inteface BookDao và bổ sung code sau

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
        @Autowired
	SessionFactory sessionFactory;

	@Override
	public List<Book> getAll() {
		Session session = sessionFactory.openSession();
		Query query = session.createQuery("from Book");
		List data = query.getResultList();
		session.close();
		return data;
	}

	@Override
	public Book get(String key) {
		Session session = sessionFactory.openSession();
		Query query = session.createQuery("from Book where bookId=?1");
		Book data = (Book) query.setParameter(1, key).getSingleResult();
		session.close();
		return data;
	}

	@Override
	public List<Category> getByCategory(int categoryId) {
		Session session = sessionFactory.openSession();
		Query query = session.createQuery("from Book where categoryId=?1");
		List data = query.setParameter(1, categoryId).getResultList();
		session.close();
		return data;
	}

- Tạo lớp com.hanam88.services.dao/CategoryImpl.java thực thi từ inteface CategoryDao và bổ sung code sau

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
        @Autowired
	SessionFactory sessionFactory;
	@Override
	public List<Category> getAll() {
		Session session=sessionFactory.openSession();
		Query query=session.createQuery("from Category");
		List data=query.getResultList();
		session.close();
		return data;
	}
	@Override
	public Category get(Integer key) {
		Session session=sessionFactory.openSession();
		Query query=session.createQuery("from Category where categoryId=?1");
		query.setParameter(1, key);
		Category data=(Category)query.getSingleResult();
		session.close();
		return data;
	}

- Tạo lớp com.hanam88.services.dao/OrderImpl.java thực thi từ inteface OrderDao và bổ sung code sau

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
        @Autowired
	SessionFactory sessionFactory;

	@Override
	public List<OrderBook> getAll() {
		Session session = sessionFactory.openSession();
		Query query = session.createQuery("from OrderBook");
		List data = query.getResultList();
		session.close();
		return data;
	}

	@Override
	public boolean insert(OrderBook obj) {
		Session session = sessionFactory.openSession();
		session.beginTransaction();
		session.save(obj);
		session.getTransaction().commit();
		session.close();
		return true;
	}

	@Override
	public boolean insertOrderDetail(OrderBook order, List<OrderDetail> details) {
		try {
			Session session = sessionFactory.openSession();
			session.beginTransaction();
			session.save(order);
			for (OrderDetail orderDetail : details) {
				session.save(orderDetail);
			}
			session.getTransaction().commit();
			session.close();
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
		return true;
	}

- Tạo lớp com.hanam88.services.dao/PublisherImpl.java thực thi từ inteface PublisherDao (không sử dụng nên không cần code)

- Tạo lớp com.hanam88.util/Cipher.java xử lý mã hóa MD5

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package com.hanam88.util;

import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class Cipher {
	public static String GenerateMD5(String data){
        try {
            // gọi phương thức tạo đối tượng mã hóa MD5
            MessageDigest md = MessageDigest.getInstance("MD5");
            //chuyển chuỗi mã hóa về dạng byte
            byte[] messageDigest = md.digest(data.getBytes());
            //chuyển mảng byte thành ký số
            BigInteger no = new BigInteger(1, messageDigest);
            // convert thành chuỗi hexa 16
            String hashtext = no.toString(16);
            while (hashtext.length() < 32) {
                hashtext = "0" + hashtext;
            } 
            return hashtext;
        } catch (NoSuchAlgorithmException ex) {
            System.out.println("Sai tên giải thuật");
        }
        return null;
    }
}

- Tạo lớp com.hanam88.controllers/HomeController.java xử lý các nghiệp vụ của trang web

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
package com.hanam88.controllers;

import java.sql.Date;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import com.hanam88.entities.Account;
import com.hanam88.entities.Basket;
import com.hanam88.entities.Book;
import com.hanam88.entities.OrderBook;
import com.hanam88.entities.OrderDetail;
import com.hanam88.services.dao.AccountDao;
import com.hanam88.services.dao.BookDao;
import com.hanam88.services.dao.CategoryDao;
import com.hanam88.services.dao.OrderDao;
import com.hanam88.util.Cipher;

@Controller
public class HomeController {
	@Autowired
	CategoryDao categoryDao;
	@Autowired
	BookDao bookDao;
	@Autowired
	AccountDao accountDao;
	@Autowired
	OrderDao orderDao;
	
	//GET:trang-chu "lây toàn bộ sách và hiển thị view home/books"
	@RequestMapping(value = { "", "trang-chu" })
	public String index(Model model) {
		model.addAttribute("title", "DANH MỤC SÁCH");
		model.addAttribute("books", bookDao.getAll());
		model.addAttribute("page", "books");
		return "home";
	}
	//GET: categories "lấy toàn bộ danh mục sách và hiển thị ở menu Thể loại trên view home/categories"
	@RequestMapping(value = "categories")
	public String getCategories(Model model) {
		model.addAttribute("categories", categoryDao.getAll());
		return "home/categories";
	}

	//GET: danh-muc-sach "lấy sách theo danh mục và hiển thị trên view home/books
	@RequestMapping(value = "danh-muc-sach/{id}")
	public String getBooks(@PathVariable("id") Integer cateId, Model model) {
		model.addAttribute("title", "DANH MỤC SÁCH: " +categoryDao.get(cateId).getCategoryName());
		model.addAttribute("books", bookDao.getByCategory(cateId));
		model.addAttribute("page", "books");
		return "home";
	}
	//GET: chi-tiet/{id} "trả về 1 sách và hiển thị trên view home/bookdetail"
	@RequestMapping(value = "chi-tiet/{id}")
	public String detail(@PathVariable("id") String bookId, Model model) {
		model.addAttribute("book", bookDao.get(bookId));
		model.addAttribute("page", "bookdetail");
		return "home";
	}

	//GET: countItems "trả về số lượng sách trong giỏ hàng"
	@RequestMapping(value = "countItems")
	public @ResponseBody String getItems(Model model, HttpServletRequest req) {
		List<Basket> baskets = new ArrayList<>();
		HttpSession session = req.getSession();
		if (session.getAttribute("basket") != null) {
			baskets = (List<Basket>) session.getAttribute("basket");
		}
		System.out.println(baskets.size());
		return String.valueOf(baskets.size());
	}
	//GET: addItem "thêm sách vào giỏ hàng và trả về tổng số sách trong giỏ"
	@RequestMapping(value = "addItem/{id}")
	public @ResponseBody String addItem(@PathVariable("id") String bookId, HttpServletRequest req) {
		List<Basket> baskets = new ArrayList<>();
		HttpSession session = req.getSession();
		Book b = bookDao.get(bookId);
		if (session.getAttribute("basket") == null) {
			Basket basket = new Basket(b.getBookId(), b.getTitle(), b.getPrice(), 1);
			baskets.add(basket);
			session.setAttribute("basket", baskets);
		} else {
			baskets = (List<Basket>) session.getAttribute("basket");
			boolean duplicate = false;
			for (int i = 0; i < baskets.size(); i++) {
				Basket bs = baskets.get(i);
				if (bs.getBookId().equals(bookId)) {
					bs.setQuantity(bs.getQuantity() + 1);
					duplicate = true;
					break;
				}
			}
			if (duplicate)
				session.setAttribute("basket", baskets);
			else {
				Basket basket = new Basket(b.getBookId(), b.getTitle(), b.getPrice(), 1);
				baskets.add(basket);
			}
		}
		session.setAttribute("basket", baskets);
		return String.valueOf(baskets.size());
	}

	//GET: gio-hang "trả về sách trong giỏ hàng và hiển thị trên view home/basket"
	@RequestMapping(value = "gio-hang")
	public String showBasket(Model model, HttpServletRequest req) {
		model.addAttribute("page", "basket");
		List<Basket> baskets = new ArrayList<>();
		HttpSession session = req.getSession();
		if (session.getAttribute("basket") != null) {
			baskets = (List<Basket>) session.getAttribute("basket");
		}
		model.addAttribute("baskets", baskets);
		return "home";
	}
	
	//GET: updateBasket/{id}/{value} "cập nhật lại số lượng đặt trong giỏ hang"
	@RequestMapping(value = "updateBasket/{id}/{value}")
	public @ResponseBody String updateBasket(@PathVariable("id") String bookId, @PathVariable("value") Integer quantity,
			Model model, HttpServletRequest req) {
		List<Basket> baskets = new ArrayList<>();
		HttpSession session = req.getSession();
		if (session.getAttribute("basket") != null) {
			baskets = (List<Basket>) session.getAttribute("basket");
			for (int i = 0; i < baskets.size(); i++) {
				Basket bs = baskets.get(i);
				if (bs.getBookId().equals(bookId)) {
					bs.setQuantity(quantity);
					break;
				}
			}
		}
		return "";
	}

	//GET: removeItem/{id} "xóa một sách trong giỏ hang"
	@RequestMapping(value = "removeItem/{id}")
	public @ResponseBody String removeItem(@PathVariable("id") String bookId, HttpServletRequest req) {
		List<Basket> baskets = new ArrayList<>();
		HttpSession session = req.getSession();
		boolean find = false;
		if (session.getAttribute("basket") != null) {
			int i;
			baskets = (List<Basket>) session.getAttribute("basket");
			for (i = 0; i < baskets.size(); i++) {
				Basket bs = baskets.get(i);
				if (bs.getBookId().equals(bookId)) {
					find = true;
					break;
				}
			}
			if (find) {
				baskets.remove(i);
			}
			session.setAttribute("basket", baskets);
		}

		return "";
	}

	//GET: dang-nhap "hiển thị màn hình đăng nhập"
	@RequestMapping(value = "dang-nhap", method = RequestMethod.GET)
	public String login(Model model) {
		model.addAttribute("page", "login");
		return "home";
	}
	
	//POST: dang-nhap "xử lý đăng nhập
	@RequestMapping(value = "dang-nhap", method = RequestMethod.POST)
	public String login(String username, String password, Model model, HttpServletRequest req) {
		Account acc = accountDao.getAccount(username);
		String passMd5 = Cipher.GenerateMD5(username + password);
		if (acc == null || !acc.getPassword().equals(passMd5)) {
			model.addAttribute("msg", "Thông tin đăng nhập sai");
			model.addAttribute("page", "login");
			return "home";
		}
		HttpSession session = req.getSession();
		session.setMaxInactiveInterval(3600);
		session.setAttribute("accountid", acc.getAccountId());
		session.setAttribute("picture", acc.getPicture());
		session.setAttribute("address", acc.getAddress());
		session.setAttribute("phone", acc.getPhone());
		session.setAttribute("fullname", acc.getFullName());
		return "redirect:/";
	}
	
	//GET: thoat "logout"
	@RequestMapping(value = "thoat")
	public String logout(Model model, HttpServletRequest req) {
		HttpSession session = req.getSession();
		session.invalidate();
		return "redirect:/dang-nhap";
	}
	
	//POST: dat-hang "xử lý đặt hang"
	@RequestMapping(value = "dat-hang")
	public String addOrder(String address, String phone, String note, Model model, HttpServletRequest req) {
		
		List<Basket> baskets=null;
		HttpSession session = req.getSession();
		if (session.getAttribute("accountid") == null) {
			return "redirect:/dang-nhap";
		}
		if (session.getAttribute("basket") != null) {
			baskets = (List<Basket>) session.getAttribute("basket");
			String timeStamp = new SimpleDateFormat("yyMMdd-HHmmss").format(Calendar.getInstance().getTime());
			OrderBook order=new OrderBook();
			order.setOrderId("HD"+timeStamp);
			order.setAccountId(session.getAttribute("accountid").toString());
			order.setOrderDate(Date.valueOf(LocalDate.now()));
			order.setReceiveAddress(address);
			order.setReceiveDate(null);
			order.setReceivePhone(phone);
			order.setNote(note);
			List<OrderDetail> orderdetails=new ArrayList<OrderDetail>();
			for (Basket basket : baskets) {
				orderdetails.add(new OrderDetail("HD"+timeStamp, basket.getBookId(), basket.getQuantity(), basket.getPrice()));
			}
			orderDao.insertOrderDetail(order, orderdetails);
			model.addAttribute("msg","Đặt hàng thành công");
		} else {
			model.addAttribute("msg","Giỏ hàng trống");
		}
		model.addAttribute("page","basket");
		baskets=new ArrayList<Basket>();
		session.setAttribute("basket", null);
		model.addAttribute("baskets", baskets);
		return "home";
	}
}

- Tạo tệp resources/css/style.css theo gợi ý sau

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
.title-group
{
	padding-top:8px;
	padding-left:5px;
	padding-bottom:10px;
	display:block;
	background-color:#343a40;
	color:white;
}
#banner-slide
{
	margin-bottom:1px;
	height:200px;
	background-image:url(../images/banner-book.jpg);
	background-repeat: no-repeat;
	background-size:100%;
	background-position: center;
	background-color:rgb(174,181,200);
}
#content
{
	min-height:400px;
}
#footer{
	height:80px;
	padding-top:8px;
	padding-left:5px;
	padding-bottom:10px;
	display:block;
	background-color:#343a40;;
	color:white;
}
.my-picture
{
	width:40px;
	height:40px;
	border-radius:20px;
}

- Tạo tệp resources/js/home.js theo gợi ý sau

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
//Document ready thì show loại sách và số lượng trong giỏ hàng (jquery ajax)
$(function(){
	$.get(path + "/categories", function(data) {
		$('.dropdown-menu').html(data);
	});
	$.get(path + "/countItems", function(data) {
		$('#basket_total').html(data);
	});
});
//hàm xử lý add 1 sách vào giỏ hàng (jquery ajax)
function addBasket(bookId) {
	$.get(path + "/addItem/" + bookId, function(data) {
		$('#basket_total').html(data);
		window.scrollTo({ top: 0, behavior: 'smooth' });
	});
}
//hàm xử lý cập nhật lại số lượng trong giỏ hàng (jquery ajax)
function updateBasket(bookId, value) {
	$.get(path + "/updateBasket/" + bookId + "/" + value, function() {
		window.location.reload();
	});
}
//hàm xử lý xóa 1 sách trong giỏ hàng (jquery ajax)
function removeItem(bookId) {
	if (confirm('Bạn có muốn xóa không?')) {
		$.get(path + "/removeItem/" + bookId, function() {
			window.location.reload();
		});
	}
}

- Tạo trang views/home.jsp hiển thị cấu trúc trang chủ

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<c:set var="contextPath" value="${pageContext.servletContext.contextPath}" scope="request"/>
<fmt:setLocale value="vi_VN" scope="session"/>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Hà Nam 88 - Kho sách hay</title>
<link rel="stylesheet"
	href="https://cdn.jsdelivr.net/npm/bootstrap@4.0.0/dist/css/bootstrap.min.css" />
<link rel="stylesheet"
	href="${contextPath}/css/style.css" />
</head>
</head>
<body>
	<div class="container">
		<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
			<a class="navbar-brand" href="${contextPath}/">SACHHAY88</a>
			<button class="navbar-toggler" type="button" data-toggle="collapse"
				data-target="#navbarSupportedContent"
				aria-controls="navbarSupportedContent" aria-expanded="false"
				aria-label="Toggle navigation">
				<span class="navbar-toggler-icon"></span>
			</button>

			<div class="collapse navbar-collapse" id="navbarSupportedContent">
				<ul class="navbar-nav mr-auto">
					<li class="nav-item active"><a class="nav-link"
						href="${contextPath}/trang-chu">Trang chủ <span class="sr-only">(current)</span></a>
					</li>
					<li class="nav-item dropdown"><a
						class="nav-link dropdown-toggle" href="#" id="navbarDropdown"
						role="button" data-toggle="dropdown" aria-haspopup="true"
						aria-expanded="false"> Thể loại </a>
						<div class="dropdown-menu" aria-labelledby="navbarDropdown">
							
						</div></li>
					<li class="nav-item"><a class="nav-link" href="#">Giới
							thiệu</a></li>
				</ul>
				<ul class="nav navbar-nav navbar-right">
				<c:choose>
					<c:when test="${!empty sessionScope.accountid}">
						<li class="nav-item mr-2"><span class="nav-link">Xin chào: ${sessionScope.fullname}</span></li>
						<li class="nav-item mr-2"><img class="my-picture" src="${contextPath}/images/${sessionScope.picture}"/></li>
						<li class="nav-item mr-2"><a class="nav-link btn btn-primary" href="${contextPath}/thoat"> Thoát</a></li>
					</c:when>
					<c:otherwise>
						<li class="nav-item mr-2"><a class="nav-link btn btn-success" href="${contextPath}/dang-nhap"> Đăng
							nhập</a></li> 
					</c:otherwise>
				</c:choose>
				
					<li class="nav-item"><a class="nav-link btn btn-danger" href="${contextPath}/gio-hang"> Giỏ
							hàng(<span id="basket_total"><jsp:include page="${contextPath}/countItems"></jsp:include></span>)</a></li>
				</ul>
			</div>
		</nav>

		<div id="banner-slide"></div>
		<div id="content">
			<c:if test="${!empty page}">
				<jsp:include page="home/${page}.jsp" />
			</c:if>
		</div>
	</div>
	<div id="footer" class="container-fluid">
		<p style="text-align: center; font-size: 20px;">Copyright 2024 by
			sachhay88.com</p>
	</div>
	<!-- jQuery first, then Popper.js, then Bootstrap JS -->
	<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
	<script
		src="https://cdn.jsdelivr.net/npm/popper.js@1.12.9/dist/umd/popper.min.js"></script>
	<script
		src="https://cdn.jsdelivr.net/npm/bootstrap@4.0.0/dist/js/bootstrap.min.js"></script>
		<script>
			var path='${pageContext.servletContext.contextPath}';
		</script>
	<script type="text/javascript" src="${contextPath}/js/home.js"></script>	
</body>
</html>

- Tạo trang views/home/books.jsp hiển thị toàn bộ sách, hoặc sách theo danh mục

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<h4 class="title-group">${title}</h4>
<div class="row">
	<c:forEach items="${books}" var="b">
		<div class="col-sm-12 col-md-6 col-lg-4 col-xl-3">
			<div class="card" style="width: 100%">
				<img class="card-img-top" src="${contextPath}/images/${b.picture}" />
				<div class="card-body">
					<h6 class="card-title">${b.title}</h6>
					<p class="card-text">Giá: <fmt:formatNumber value="${b.price}" type="currency"/></p>
					<button onclick="addBasket('${b.bookId}')" class="btn btn-primary">Mua</button> <a
						href="${contextPath}/chi-tiet/${b.bookId}" class="btn btn-success">Chi tiết</a>
				</div>
			</div>
		</div>
	</c:forEach>
</div>

- Tạo trang views/home/categories.jsp hiển thị danh  mục sách

1
2
3
4
5
6
<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<c:forEach items="${categories}" var="c">
	<a class="dropdown-item" href="${pageContext.servletContext.contextPath}/danh-muc-sach/${c.categoryId}">${c.categoryName}</a>
</c:forEach>

- Tạo trang views/home/bookdetail.jsp hiển thị chi tiết sách

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>
<h4 class="title-group">CHI TIẾT SẢN PHẨM</h4>
<div class="row" style="padding:10px;box-sizing: border-box;">
	<div class="col-3">
		<img src="${contextPath}/images/${book.picture}" width="95%" />
	</div>
	<div class="col-9">
		<p>${book.title}</p>
		<p>
			Giá :<fmt:formatNumber value="${book.price}" type="currency"/>
		</p>
	</div>
	<div class="col-12">
		<h4>Mô tả</h4>
		<p>${book.description}</p>
	</div>
	<button onclick="addBasket('${book.bookId}')" class="btn btn-primary">Mua</button> &nbsp;
	<a class="btn btn-success" href="javascript:history.back();">Quay lại</a>
</div>

- Tạo trang views/home/login.jsp hiển thị form đăng nhập

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<div style="width:400px;margin:auto;padding:20px;">
<h4 class="title-group">Đăng nhập</h4>
<p style="color:red;">${msg}</p>
	<form action="${contextPath}/dang-nhap" method="post">
		<div class="form-group">
			<input type="text"
				class="form-control" placeholder="Tên đăng nhập" name="username">
		</div>
		<div class="form-group">
			<input type="password"
				class="form-control" placeholder="Mật khẩu" name="password">
		</div>
		<button type="submit" class="btn btn-primary">Đăng nhập</button>
	</form>
</div>

- Tạo trang views/home/basket.jsp hiển thị giỏ hàng

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>
<c:set var="total" value="0" />
<div class="row">
	<div class="col-md-8">
		<h4 class="title-group">GIỎ HÀNG</h4>
		<div style="width: 100%; margin: auto; padding: 20px;">
		<p style="color:red">${msg}</p>
			<table class="table table-bordered">
				<tr>
					<th>Mã sách</th>
					<th>Tên sách</th>
					<th>Giá</th>
					<th>Số lượng</th>
					<th>Thành tiền</th>
					<th></th>
				</tr>

				<c:forEach items="${baskets}" var="b">
					<tr>
						<td>${b.bookId}</td>
						<td><a href="${contextPath}/chi-tiet/${b.bookId}">${b.title}</a></td>
						<td><fmt:formatNumber value="${b.price}" type="currency"/></td>
						<td><input type="number" style="width:60px" onchange="updateBasket('${b.bookId}',this.value)" value="${b.quantity}" min="1" max="100"/></td>
						<td><fmt:formatNumber value="${b.price*b.quantity}" type="currency"/></td>
						<c:set var="total" value="${total+b.price*b.quantity}" />
						<td><a href="#" class="btn btn-danger" onclick="removeItem('${b.bookId}')">Xóa</a></td>
					</tr>
				</c:forEach>
			</table>
			<h5>Tổng tiền: <fmt:formatNumber value="${total}" type="currency"/></h5>
		</div>
	</div>
	<div class="col-md-4">
		<h4 class="title-group">Thông tin đặt hàng</h4>
		<form action="dat-hang" method="post">
			<table>
				<tr>
					<td>Họ và tên: </td>
					<td>${sessionScope.fullname}</td>
				</tr>
				<tr>
					<td>Địa chỉ</td>
					<td><input type="text" name="address" value="${sessionScope.address}" /></td>
				</tr>
				<tr>
					<td>Điện thoại</td>
					<td><input type="text" name="phone" value="${sessionScope.phone}"/></td>
				</tr>
				<tr>
					<td>Ghi chú</td>
					<td><textarea name="note"></textarea></td>
				<tr>
					<td>
						<button class="btn btn-primary">Đặt hàng</button>
					</td>
				</tr>
			</table>

		</form>
	</div>
</div>

Bước 8: Run ứng dụng và kiểm tra kết quả

- Màn hình giỏ hàng

- Màn hình login

alt text

Link tải source code 

Video đang quay....

thay lời cảm ơn!

QUẢNG CÁO - TIẾP THỊ