Giới thiệu công nghệ hệ thống
Hệ thống được xây dựng theo kiến trúc phân tầng, sử dụng Spring Boot làm nền tảng phát triển phía máy chủ nhờ vào khả năng tự động cấu hình và tích hợp các thành phần trong môi trường Spring. Nhờ mô hình "quy ước thay thế cấu hình", nhà phát triển có thể giảm thiểu đáng kể việc viết file cấu hình XML hay chú thích rườm rà, từ đó tập trung nhiều hơn vào logic nghiệp vụ.
Giao diện người dùng được phát triển bằng Vue.js – một framework JavaScript nhẹ, hiệu suất cao với cơ chế ràng buộc dữ liệu hai chiều thông qua các chỉ thị như v-model. Khi dữ liệu thay đổi, giao diện sẽ tự động cập nhật mà không cần thao tác DOM thủ công. Vue còn cung cấp các hook vòng đời giúp lập trình viên chèn logic tại các giai đoạn khác nhau của component như khởi tạo, gắn kết, cập nhật hoặc hủy bỏ.
Phân tích tính khả thi
Trước khi tiến hành phát triển, hệ thống đã trải qua ba khía cạnh đánh giá chính:
- Khả thi về kỹ thuật: Việc ứng dụng bộ công cụ Java hiện đại (Spring Boot, MyBatis, Vue) là hoàn toàn phù hợp nhờ sự ổn định và hỗ trợ cộng đồng mạnh mẽ.
- Khả thi về kinh tế: Chi phí phát triển thấp hơn lợi ích mang lại do tăng hiệu suất xử lý, giảm thiểu sai sót so với phương pháp thủ công.
- Khả thi về vận hành: Giao diện thân thiện, dễ học, phù hợp với cả người dùng không chuyên, đảm bảo tính thực tiễn cao.
Kiểm thử chức năng hệ thống
Mục tiêu kiểm thử là xác minh hệ thống hoạt động đúng yêu cầu, phát hiện lỗi và cải thiện trải nghiệm người dùng. Quá trình này bao gồm kiểm thử hộp đen dựa trên các kịch bản thực tế.
Test case đăng nhập
| Dữ liệu đầu vào | Kết quả mong đợi | Kết quả thực tế | Đánh giá |
|---|---|---|---|
| Tên: admin, Mật khẩu: 123456, Mã xác nhận: đúng | Đăng nhập thành công | Truy cập hệ thống | Đạt |
| Tên: admin, Mật khẩu: sai, Mã xác nhận: đúng | Báo lỗi mật khẩu | Hiển thị thông báo sai mật khẩu | Đạt |
| Tên để trống, Mật khẩu: 123456 | Yêu cầu nhập tên | Thông báo bắt buộc nhập tên | Đạt |
Test case quản lý người dùng
| Thao tác | Kết quả mong đợi | Kết quả thực tế | Đánh giá |
|---|---|---|---|
| Thêm người dùng mới | Xuất hiện trong danh sách | Hiển thị ngay sau khi lưu | Đạt |
| Sửa thông tin | Cập nhật thành công | Thông tin thay đổi trên giao diện | Đạt |
| Xóa tài khoản | Xác nhận xóa, sau đó không tìm thấy | Không hiển thị sau khi xác nhận | Đạt |
| Thêm trùng tên đăng nhập | Báo lỗi trùng lặp | Thông báo tên đã tồn tại | Đạt |
Thiết kế cơ sở dữ liệu
Dưới đây là một số bảng chính trong hệ thống:
Bảng người dùng (yonghu)
| Trường | Kiểu dữ liệu | Chiều dài | Ràng buộc |
|---|---|---|---|
| id | BIGINT | 20 | PRIMARY KEY, AUTO_INCREMENT |
| yonghuming | VARCHAR | 200 | NOT NULL, UNIQUE |
| mima | VARCHAR | 200 | NOT NULL |
| xingming | VARCHAR | 200 | DEFAULT NULL |
| shouji | VARCHAR | 200 | DEFAULT NULL |
Bảng token xác thực
CREATE TABLE `token` ( `id` BIGINT NOT NULL AUTO_INCREMENT, `userid` BIGINT NOT NULL, `username` VARCHAR(100) NOT NULL, `role` VARCHAR(100) DEFAULT NULL, `token` VARCHAR(200) NOT NULL, `addtime` TIMESTAMP DEFAULT CURRENT_TIMESTAMP, `expiratedtime` TIMESTAMP DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COMMENT='Token xác thực';
Mẫu mã nguồn minh họa
API xử lý vị trí địa lý và đối sánh khuôn mặt sử dụng dịch vụ Baidu AI:
@RestController
public class LocationAndFaceController {
@Autowired
private ConfigService configService;
private static AipFace faceClient = null;
private static String BAIDU_MAP_KEY = null;
// Lấy thông tin vị trí từ kinh độ - vĩ độ
@GetMapping("/get-location")
public ResponseResult getLocation(String longitude, String latitude) {
if (BAIDU_MAP_KEY == null) {
ConfigEntity keyConfig = configService.getConfigByName("baidu_map_ak");
BAIDU_MAP_KEY = keyConfig.getValue();
if (BAIDU_MAP_KEY == null) {
return ResponseResult.error("Vui lòng cấu hình khóa API Baidu Map");
}
}
Map locationData = BaiduMapUtil.getCityInfo(BAIDU_MAP_KEY, longitude, latitude);
return ResponseResult.ok(locationData);
}
// So khớp hai ảnh khuôn mặt
@PostMapping("/verify-face")
public ResponseResult verifyFace(@RequestParam String image1, @RequestParam String image2) {
initializeFaceClient();
try {
byte[] imgBytes1 = FileUtil.readToByteArray(new File(getUploadPath() + "/" + image1));
byte[] imgBytes2 = FileUtil.readToByteArray(new File(getUploadPath() + "/" + image2));
String base64Img1 = Base64.getEncoder().encodeToString(imgBytes1);
String base64Img2 = Base64.getEncoder().encodeToString(imgBytes2);
MatchRequest req1 = new MatchRequest(base64Img1, "BASE64");
MatchRequest req2 = new MatchRequest(base64Img2, "BASE64");
JSONObject result = faceClient.match(Arrays.asList(req1, req2));
return ResponseResult.ok(result.getJSONObject("result"));
} catch (Exception e) {
return ResponseResult.error("Lỗi xử lý ảnh: " + e.getMessage());
}
}
private void initializeFaceClient() {
if (faceClient == null) {
String apiKey = configService.getConfigByName("APIKey").getValue();
String secretKey = configService.getConfigByName("SecretKey").getValue();
String token = BaiduAuthUtil.getToken(apiKey, secretKey);
if (token == null) throw new RuntimeException("Không lấy được token xác thực");
faceClient = new AipFace("", apiKey, secretKey);
faceClient.setConnectionTimeoutInMillis(2000);
faceClient.setSocketTimeoutInMillis(60000);
}
}
private String getUploadPath() throws FileNotFoundException {
return ResourceUtils.getFile("classpath:static/upload").getAbsolutePath();
}
}