Khi tích hợp trình soạn thảo văn bản phong phú KindEditor vào một ứng dụng web sử dụng framework Struts2 (thường nằm trong ngăn xếp SSH - Struts2, Spring, Hibernate), người dùng có thể gặp phải một ngoại lệ đáng chú ý khi truy cập tính năng quản lý tệp hoặc hình ảnh của KindEditor.
Lỗi này thường xuất hiện trong nhật ký máy chủ dưới dạng cảnh báo tương tự như sau:
WARN OgnlValueStack:68 - Error setting value [[Ljava.lang.String;@10da4df] with expression [1501984936145]
java.lang.NumberFormatException: For input string: "1501984936145"
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
at java.lang.Integer.parseInt(Integer.java:495)
...
at com.opensymphony.xwork2.ognl.OgnlValueStack.setValue(OgnlValueStack.java:173)
at com.opensymphony.xwork2.interceptor.ParametersInterceptor.setParameters(ParametersInterceptor.java:303)
...
Nguyên nhân gốc rễ
Ngoại lệ NumberFormatException này phát sinh do cách KindEditor xử lý các yêu cầu AJAX và cách Struts2 (thông qua OGNL) cố gắng phân tích các tham số URL. Để ngăn chặn việc lưu bộ đệm trình duyệt, KindEditor thường thêm một dấu thời gian Unix (được tạo bởi new Date().getTime()) vào cuối URL yêu cầu quản lý tệp.
Ví dụ, một URL có thể trông như thế này:
/kindeditor/filemanager?path=/image&order=NAME&dir=image&1678886400000
Trong đó, 1678886400000 là dấu thời gian.
Khi Struts2 nhận được yêu cầu này, bộ chặn ParametersInterceptor của nó sử dụng OGNL (Object-Graph Navigation Language) để cố gắng ánh xạ các tham số URL vào các thuộc tính của đối tượng hành động. Vì dấu thời gian được thêm trực tiếp sau ký tự & mà không có tên tham số rõ ràng (ví dụ: ×tamp=...), OGNL cố gắng hiểu dấu thời gian dài đó (một chuỗi số) như một tên thuộc tính mà nó cần đặt giá trị.
Vì dấu thời gian là một số nguyên rất lớn (kiểu long trong Java), và OGNL có thể cố gắng chuyển đổi nó thành một kiểu dữ liệu nhỏ hơn như Integer (ví dụ, nếu có một thuộc tính Integer có tên tương tự mà nó đang cố gắng xử lý một cách không chính xác), thì việc chuyển đổi này thất bại với NumberFormatException. Cụ thể, OGNL parser có thể nhầm lẫn chuỗi số đó là một biểu thức số cần được đánh giá hoặc một tên thuộc tính không hợp lệ.
Giải pháp
Để khắc phục sự cố này, chúng ta cần sửa đổi mã nguồn của KindEditor để đảm bảo rằng dấu thời gian được truyền dưới dạng một tham số không tên hoặc một tham số mà OGNL sẽ bỏ qua an toàn.
Chúng ta có thể làm điều này bằng cách thêm một dấu bằng (=) ngay sau ký tự & và trước dấu thời gian. Điều này biến nó thành một tham số có tên rỗng (&=1678886400000), mà Struts2/OGNL sẽ không cố gắng phân tích như một tên thuộc tính để gán giá trị, hoặc ít nhất là không gây ra lỗi chuyển đổi số.
Tìm tệp filemanager.js trong thư mục cài đặt KindEditor (thường nằm trong thư mục plugins/filemanager/). Tìm hàm chịu trách nhiệm tải lại trang hoặc gửi yêu cầu AJAX cho trình quản lý tệp. Dòng mã cụ thể cần sửa đổi thường nằm trong hàm AJAX.
Mã gốc có thể trông như sau:
function loadFileManagerContent(filePath, sortOrder, callback) {
var queryParams = 'filePath=' + filePath + '&sortOrder=' + sortOrder + '&folder=' + currentFolder;
editorDialog.showLoading(editorInstance.lang('loadingData'));
// Dòng này gây ra sự cố: dấu thời gian được nối trực tiếp
K.ajax(K.addParam(jsonServiceUrl, queryParams + '&' + new Date().getTime()), function(responseData) {
editorDialog.hideLoading();
callback(responseData);
});
}
Để sửa lỗi, hãy thay đổi dòng thêm dấu thời gian như sau:
function loadFileManagerContent(filePath, sortOrder, callback) {
var queryParams = 'filePath=' + filePath + '&sortOrder=' + sortOrder + '&folder=' + currentFolder;
editorDialog.showLoading(editorInstance.lang('loadingData'));
// Đã sửa lỗi: thêm '=' trước dấu thời gian để tránh OGNL phân tích sai
K.ajax(K.addParam(jsonServiceUrl, queryParams + '&=' + new Date().getTime()), function(responseData) {
editorDialog.hideLoading();
callback(responseData);
});
}
Sự thay đổi là thêm = vào '&=' thay vì chỉ '&'. Điều này hiệu quả ngăn chặn Struts2/OGNL cố gắng phân tích chuỗi dấu thời gian dưới dạng một tên thuộc tính số, do đó loại bỏ NumberFormatException.