ฉันมักจะเห็นผู้คนถามฉันในกระดานสนทนาว่าต้องทำอย่างไรหากตัวอักษรจีนที่แสดงใน JSP นั้นอ่านไม่ออก เหตุใดการป้อนข้อมูลภาษาจีนโดยผู้ใช้ที่ฉันได้รับผ่านการร้องขอจึงอ่านไม่ออก เหตุใดตัวอักษรจีนที่ฉันเขียนไปยังฐานข้อมูลจึงอ่านไม่ออก และอื่น ๆ คำถามเกี่ยวกับตัวอักษรจีนที่อ่านไม่ออก
ที่จริงแล้ว ปัญหานี้ง่ายมาก ไม่ว่าจะเป็นตัวอักษรจีน ญี่ปุ่น หรือภาษาดับเบิ้ลไบต์อื่นๆ เราจะถือว่ามันเป็น UTF-8
(1) ข้อความแบบไบต์คู่ในคำขอนั้นดี ตอนนี้เราจะใช้การเข้ารหัส UTF-8 ในแอปพลิเคชันทั้งหมด เหตุผลที่เลือก UTF-8 ไม่เพียงแต่ด้วยเหตุผลข้างต้นเท่านั้น UTF-8.8 หรือสูงกว่า ดังนั้นเราควรเลือก UTF-8 อย่างถูกต้อง^_^
ขั้นแรกเราจะบันทึกไฟล์ .java และ .jsp ในการเข้ารหัส UTF-8 ไม่สำคัญว่าไฟล์ก่อนหน้านี้จะไม่ได้บันทึกเป็น UTF-8 แต่ขอแนะนำให้บันทึกไฟล์ในอนาคตทั้งหมดเป็น UTF-8
และเขียนเป็น .jsp: < %@page contentType="text/html; charset=UTF-8"%> แทน < %@page contentType="text/html; charset=UTF-8"%>
จากนั้นเพิ่มย่อหน้าต่อไปนี้ใน web.xml:
<เว็บแอป>
-
<ตัวกรอง>
<filter-name>ตั้งค่าการเข้ารหัสอักขระ</filter-name>
<กรองคลาส>com.redv.projects.eduadmin.util.filters.SetCharacterEncodingFilter</กรองคลาส>
<init-พารามิเตอร์>
<param-name>การเข้ารหัส</param-name>
<param-value>UTF-8</param-value>
</init-พารามิเตอร์>
</ตัวกรอง>
<การแมปตัวกรอง>
<filter-name>ตั้งค่าการเข้ารหัสอักขระ</filter-name>
<url-รูปแบบ>/*</url-รูปแบบ>
</การแมปตัวกรอง>
-
</web-app>
รหัสของ com.redv.projects.eduadmin.util.filters.SetCharacterEncodingFilter เป็นดังนี้:
แพ็คเกจ com.redv.projects.eduadmin.util.filters
นำเข้า java.io.IOException;
นำเข้า javax.servlet.Filter;
นำเข้า javax.servlet.FilterChain;
นำเข้า javax.servlet.FilterConfig;
นำเข้า javax.servlet.ServletException;
นำเข้า javax.servlet.ServletRequest;
นำเข้า javax.servlet.ServletResponse;
นำเข้า javax.servlet.UnavailableException;
นำเข้า javax.servlet.http.HttpServletRequest;
นำเข้า javax.servlet.http.HttpServletResponse;
SetCharacterEncodingFilter คลาสสาธารณะ
ใช้ตัวกรอง {
การเข้ารหัสสตริงที่ได้รับการป้องกัน = null;
protected
Config
filterConfig
= null;
this.filterConfig = null;
}
โมฆะสาธารณะ doFilter (คำขอ ServletRequest, การตอบสนองของ ServletResponse,
FilterChain chain) พ่น IOException, ServletException {
// เลือกแบบมีเงื่อนไขและตั้งค่าการเข้ารหัสอักขระที่จะใช้
ถ้า (ละเว้น || (request.getCharacterEncoding() == null)) {
การเข้ารหัสสตริง = selectEncoding (คำขอ);
ถ้า (เข้ารหัส != null) {
request.setCharacterEncoding(encoding); //นี่คือสิ่งที่ใช้งานได้ ฮ่าๆ มัน: แทนที่ชื่อของการเข้ารหัสอักขระที่ใช้ในเนื้อหาของคำขอนี้ ต้องถูกเรียกก่อนที่จะอ่านพารามิเตอร์คำขอหรืออ่านอินพุตโดยใช้ getReader( ).
-
}
// ส่งต่อการควบคุมไปยังตัวกรองถัดไป
chain.doFilter (คำขอการตอบสนอง);
}
โมฆะสาธารณะ init (FilterConfig filterConfig) พ่น ServletException {
this.filterConfig = filterConfig;
this.encoding = filterConfig.getInitParameter("การเข้ารหัส");
ค่าสตริง = filterConfig.getInitParameter("ignore");
ถ้า (ค่า == null) {
this.ignore = จริง;
-
อื่นถ้า (value.equalsIgnoreCase("true")) {
this.ignore = จริง;
-
อื่นถ้า (value.equalsIgnoreCase("ใช่")) {
this.ignore = จริง;
-
อื่น {
this.ignore = เท็จ;
}
}
protected String selectEncoding(ServletRequest request) {
return (this.encoding);
}
}
ด้วยวิธีนี้ คำขอของเราจะถูกเข้ารหัสใน UTT-8 และเราสามารถใช้มันในโปรแกรม JSP: request.getParameter("myKey" ) คุณสามารถรับสตริงที่เข้ารหัส UTF-8 ได้โดยตรง แทนที่จะเป็นเช่นนี้: new String(request.getParameter("myKey").getBytes("ISO-8859-1"), "GBK") เพื่อแก้ไขอักขระที่อ่านไม่ออกเหล่านั้น http://www.devdao.com/
(2) ข้อความไบต์คู่ที่ประมวลผลโดยฐานข้อมูล http://www.upas.org/java/DatabaseEncodingProblemSolution/
อีกประการหนึ่งคือปัญหาในการเขียนลงฐานข้อมูล เรารู้ว่าเมื่อใช้ mysql เราสามารถใช้ URL นี้เพื่อจัดการกับปัญหาการเข้ารหัสอักขระภาษาจีน: jdbc:mysql://localhost:3306/upas?useUnicode=true&CharacterEncoding=gb2312,
แล้วเราควรทำอย่างไรกับสิ่งที่เราไม่สามารถแก้ไขได้อย่าง mySQL? เราควรเขียนแบบนี้ทุกครั้งหรือไม่:
นำเข้า java.sql.*;
Class.forName("org.gjt.mm.mysql.Driver");
การเชื่อมต่อ con = null;
คำสั่งที่เตรียมไว้ pstmt = null;
ResultSet rs = null;
พยายาม {
con = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", "");
pstmt = con.prepareStatement("เลือก f3, f4 จาก tbl1 โดยที่ f1 = ? และ f2 = ?");
pstmt.setString(1, สตริงใหม่(f1.getBytes("GBK"), "ISO-8859-1");
pstmt.setString(2, สตริงใหม่(f2.getBytes("GBK"), "ISO-8859-1");
อาร์เอส = pstmt.executeQuery();
สตริง f3, f4;
ในขณะที่ (rs.next()) {
f3 = สตริงใหม่(rs.getString(1).getBytes("ISO-8859-1"), "GBK");
f4 = สตริงใหม่(rs.getString(2).getBytes("ISO-8859-1"), "GBK");
-
-
ในที่สุด {
//ปิดทรัพยากร
-
}
จริงๆ แล้ว เราสามารถเขียนได้ดังนี้:
นำเข้า java.sql.*;
นำเข้า com.redv.sql.encoding.*
;
การเชื่อมต่อ con = null;
คำสั่งที่เตรียมไว้ pstmt = null;
ResultSet rs = null;
พยายาม {
con = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", "");
//รับช่วงต่ออินสแตนซ์การเชื่อมต่อฐานข้อมูล
การเข้ารหัสบูลีน = จริง;
EncodingConnection codingConnection = การเข้ารหัสการเชื่อมต่อใหม่ (con, การเข้ารหัส, "ISO-8859-1", "GBK");
// รับอินสแตนซ์การเชื่อมต่อฐานข้อมูลหลังจากเข้าครอบครอง ใช้ con โดยตรงในอนาคต ซึ่งเป็นอินสแตนซ์ที่บรรจุใหม่โดย EncodingConnection
แย้ง = codingConnection.getConnection();
pstmt = con.prepareStatement("เลือก f3, f4 จาก tbl1 โดยที่ f1 = ? และ f2 = ?");
pstmt.setString(1, f1);
pstmt.setString(2, f2);
อาร์เอส = pstmt.executeQuery();
สตริง f3, f4;
ในขณะที่ (rs.next()) {
f3 = rs.getString(1);
f4 = rs.getString(2);
-
-
ในที่สุด {
//ปิดทรัพยากร
-
}
มาดูกันว่าเป็นอย่างไรบ้าง เราเพียงแค่ต้องแก้ไขเล็กน้อยตรงจุดที่เราได้รับการเชื่อมต่อฐานข้อมูล เราสามารถบันทึกเป็นพารามิเตอร์ในคุณสมบัติและเปลี่ยนค่าบูลีนของการเข้ารหัสเพื่อตั้งค่าว่าจะใช้การแปลงการเข้ารหัสอัตโนมัติหรือไม่ บ่อยครั้งที่เราสามารถใช้คลาสฐานข้อมูลเพื่อห่อหุ้ม getConnection ที่ได้รับการเชื่อมต่อฐานข้อมูล เพื่อที่เราจะได้รับการเชื่อมต่อฐานข้อมูลจาก javax.sql.DataSource ในขณะนี้ เราเพียงแต่ต้องแก้ไขคลาสฐานข้อมูลของเรา แทนที่จะค้นหาทุกตำแหน่งที่ใช้ rs.setString() และ rs.getString() เพื่อเพิ่มโค้ดการแปลงการเข้ารหัสของเรา แม้ว่าเราจะใช้คำสั่ง con.createStatment() ก็ไม่มีปัญหาแม้ว่าคำสั่ง sql ของเราจะประกอบด้วยอักขระจีนหรืออักขระแบบไบต์คู่อื่นๆ:
เลือกชื่อ เพศ จากตารางนักเรียน โดยที่คลาส LIKE '%computer%'