【Java】Ajax實現級聯城市
阿新 • • 發佈:2020-12-09
效果圖
一、準備工作
(1)匯入jQuery
a 下載到本地 地址https://jquery.com/download/
b 使用網上的(當然沒網不能使用)
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/jquery.min.js"></script>
(2)引入com.alibaba.fastjson.JSON(json轉換) 和mysql-connector-java(資料庫連線),這裡小編提供 maven 依賴(若需要 jar 包的自行下載)
<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson--> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.75</version> </dependency> <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.22</version> </dependency>
(3)資料庫工具類,可以使用自己寫的,也可以使用apache提供的dbutil類,當然也可使用小編提供的(下面是小編最近使用的DbUtil)
package pers.dbutils; import lombok.Data; import java.io.IOException; import java.io.InputStream;dbUtils.javaimport java.sql.*; import java.util.*; import java.util.stream.Collectors; /** * TODO jdbc常用操作工具類 * * @author [email protected] * @date 2020/11/6 15:24 */ @Data public class DbUtils { private String driver = "com.mysql.cj.jdbc.Driver"; private String url = "jdbc:mysql://localhost:3306/db?serverTimezone=PRC&useUnicode=true&characterEncoding=utf8"; private String user = "root"; private String password = "root"; private Connection conn; private int currentPage = 1; //當前頁 private int pageCount = 0; //總頁數 private int pageSize = 10; //每一頁記錄的資料量 private int recordCount = 0; //總資料量 /** * 無參構造連線資料庫 */ public DbUtils() { try { Class.forName(driver); this.conn = DriverManager.getConnection(url, user, password); } catch (SQLException throwables) { throwables.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } } /** * 使用資料庫名 * @param dbName 資料庫名 */ public DbUtils(String dbName){ try { Class.forName(driver); url = "jdbc:mysql://localhost:3306/"+dbName+"?serverTimezone=PRC&useUnicode=true&characterEncoding=utf8"; this.conn = DriverManager.getConnection(url, user, password); } catch (Exception e) { e.printStackTrace(); } } /** * 有參連線資料庫 * @param driver 載入驅動 * @param host IP地址 * @param port 埠號 * @param dbName 資料庫名稱 * @param user 使用者名稱 * @param password 密碼 */ public DbUtils(String driver, String host, String port, String dbName, String user, String password) { this.driver = driver; this.url = "jdbc:mysql://" + host + ":" + port + "/" + dbName + "?serverTimezone=PRC&useUnicode=true&characterEncoding=utf8"; this.user = user; this.password = password; try { Class.forName(driver); this.conn = DriverManager.getConnection(this.url, this.user, this.password); } catch (SQLException throwables) { throwables.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } } //利用db.properties配置檔案連線資料庫 public DbUtils(boolean flag) { InputStream is = DbUtils.class.getClassLoader().getResourceAsStream("db.properties"); Properties prop = new Properties(); try { prop.load(is); driver = prop.getProperty("db.driver", "com.mysql.cj.jdbc.Driver"); url = prop.getProperty("db.url", "jdbc:mysql://localhost:3306/db?serverTimezone=PRC&useUnicode=true&characterEncoding=utf8"); user = prop.getProperty("db.user", "root"); password = prop.getProperty("db.password", ""); pageSize = Integer.parseInt(prop.getProperty("db.pageSize", "10")); Class.forName(driver); conn = DriverManager.getConnection(url, user, password); } catch (IOException e) { e.printStackTrace(); } catch (SQLException throwables) { throwables.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } } /** * 資料庫資料語句操作(增、刪、改) * * @param sql sql語句 * @param params 0個或多個 * @return 對資料表產生影響的行數 */ public int execute(String sql, Object... params) { int row = 0; try { PreparedStatement ps = conn.prepareStatement(sql); int index = 1; for (Object p : params) { ps.setObject(index++, p); } row = ps.executeUpdate(); ps.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } return row; } /** * 資料插入 * * @param tableName 表名 * @param values Map(key,values)鍵值對 * @return 對資料表產生影響的行數 */ public int insert(String tableName, Map<String, Object> values) { int row = 0; Set<String> set = values.keySet(); String fn = set.toString().replace(" ", ""); fn = fn.substring(1, fn.length() - 1); String fv = set.stream().map(m -> "?").collect(Collectors.toList()).toString().replace(" ", ""); fv = fv.substring(1, fv.length() - 1); String sql = String.format("insert into %s(%s) values(%s)", tableName, fn, fv); try { PreparedStatement ps = conn.prepareStatement(sql); int index = 1; for (String k : set) { ps.setObject(index++, values.get(k)); } row = ps.executeUpdate(); ps.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } return row; } /** * 資料插入 * * @param tableName 表名 * @param fieldName 欄位名(1個或多個) * @param fieldValues 資料資訊(和欄位名順序保持一致) * @return 對資料表產生影響的行數 */ public int insert(String tableName, String fieldName, Object[] fieldValues) { int row = 0; String fv = Arrays.stream(fieldValues).map(m -> "?").collect(Collectors.toList()).toString().replace(" ", ""); fv = fv.substring(1, fv.length() - 1); String sql = String.format("insert into %s(%s) values(%s)", tableName, fieldName, fv); try { PreparedStatement ps = conn.prepareStatement(sql); for (int i = 0; i < fieldValues.length; i++) { ps.setObject(i + 1, fieldValues[i]); } row = ps.executeUpdate(); ps.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } return row; } /** * 根據主鍵刪除資料 * @param tableName 表名 * @param params 主鍵值(1個或多個) * @return 對資料表產生影響的行數 */ public int deleteByPK(String tableName, Object... params){ int row = 0; String symbol = "?,".repeat(params.length); String sql = String.format("delete from %s where %s in(%s)", tableName,getPK(tableName),symbol.substring(0, symbol.length()-1)); try { PreparedStatement ps = conn.prepareStatement(sql); int index = 1; for(Object o : params){ ps.setObject(index++,o); } row = ps.executeUpdate(); ps.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } return row; } /** * 根據主鍵修改資料 * @param tableName 表名 * @param fieldName 欄位名(1個或多個) * @param values 修改後的值 * @param params 主鍵值(1個或多個) * @return 對資料表產生影響的行數 */ public int updateByPK(String tableName, String fieldName, Object values, Object... params){ int row = 0; String symbol = "?,".repeat(params.length); String sql = String.format("update %s set %s=? where %s in(%s)",tableName,fieldName,getPK(tableName),symbol.substring(0, symbol.length()-1)); try { PreparedStatement ps = conn.prepareStatement(sql); ps.setObject(1, values); int index = 2; for(Object o : params){ ps.setObject(index++, o); } row = ps.executeUpdate(); ps.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } return row; } /** * 對某一列(某幾個)的值全部增加或減少相同的值 * * @param tableName 表名 * @param fieldName 欄位名(1個或多個) * @param values 要增加或減少的值 * @param condition 條件 * @return 對資料表產生影響的行數 */ public int updateInc(String tableName, String fieldName, Object values, String condition) { int row = 0; String sql = String.format("update %s set %2$s=%s+%d %s", tableName, fieldName, values, condition); try { PreparedStatement ps = conn.prepareStatement(sql); row = ps.executeUpdate(); ps.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } return row; } /** * 獲取主鍵的欄位名 * @param tableName 表名 * @return 表的主鍵欄位名 */ public String getPK(String tableName) { String PKName = null; try { DatabaseMetaData dmd = conn.getMetaData(); ResultSet rs = dmd.getPrimaryKeys(null, "%", tableName); rs.next(); PKName = rs.getString("column_name"); rs.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } // //方法二 // String sql = String.format("show index from %s", tableName); // try { // PreparedStatement ps = conn.prepareStatement(sql); // ResultSet rs = ps.executeQuery(); // rs.next(); // PKName = rs.getString("column_name"); // rs.close(); // ps.close(); // } catch (SQLException throwables) { // throwables.printStackTrace(); // } return PKName; } /** * 查詢操作 * @param sql sql語句 * @param params 0個或多個 * @return list集合 */ public List<Map<String, Object>> select(String sql, Object... params) { List<Map<String, Object>> list = new LinkedList<>(); try { PreparedStatement ps = conn.prepareStatement(sql); int index = 1; for (Object o : params) { ps.setObject(index++, o); } ResultSet rs = ps.executeQuery(); ResultSetMetaData rsm = rs.getMetaData(); Map<String, Object> m; while (rs.next()) { m = new LinkedHashMap<>(); for (int i = 1; i <= rsm.getColumnCount(); i++) { m.put(rsm.getColumnLabel(i), rs.getObject(rsm.getColumnLabel(i))); } list.add(m); } rs.close(); ps.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } return list; } /** * 查詢操作 * @param tableName 表名 * @param fieldName 欄位名(1個或多個) * @param condition 條件 * @return list集合 */ public List<Map<String, Object>> select(String tableName, String fieldName, String condition) { String sql = String.format("select %s from %s %s", fieldName, tableName, condition); return select(sql); } // private int currPage = 1; //當前頁 // private int pageCount = 0; //總頁數 // private int pageSize = 10; //每一頁的資料量 // private int recordCount = 0; //總資料量 /** * 獲取總資料數量 * @param tableName 表名 * @param condition 條件 * @return 總資料量 */ public int getRecordCount(String tableName, String condition) { String sql = String.format("select count(*) from %s %s", tableName, condition); try { PreparedStatement ps = conn.prepareStatement(sql); ResultSet rs = ps.executeQuery(); rs.next(); recordCount = rs.getInt(1); rs.close(); ps.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } return recordCount; } /** * 獲取總頁數 * @param tableName 表名 * @param pageSize 每一頁記錄的資料量 * @param condition 條件 * @return 總頁數 */ public int getPageCount(String tableName, int pageSize, String condition) { recordCount = getRecordCount(tableName, condition); if (recordCount % pageSize == 0) { pageCount = recordCount / pageSize; } else { pageCount = recordCount / pageSize + 1; } return pageCount; } /** * 獲取總頁碼(每頁預設顯示10條資料) * @param tableName 表名 * @param condition 條件 * @return */ public int getPageCount(String tableName, String condition) { return getPageCount(tableName, pageSize, condition); } /** * 檢視某一頁的資料 * @param tableName 表名 * @param fieldName 欄位名(1個或多個) * @param currentPage 選擇要檢視的頁數(當前頁) * @param pageSize 每頁記錄的資料量 * @param condition 條件 * @return list集合 */ public List<Map<String, Object>> page(String tableName, String fieldName, int currentPage, int pageSize, String condition) { pageCount = getPageCount(tableName, pageSize, condition); List<Map<String, Object>> list = new LinkedList<>(); if (currentPage <= pageCount) { int cp = pageSize * (currentPage - 1); String sql = String.format("select %s from %s limit %d,%d %s", fieldName, tableName, cp, pageSize, condition); // System.out.println(sql); try { PreparedStatement ps = conn.prepareStatement(sql); ResultSet rs = ps.executeQuery(); ResultSetMetaData rsm = rs.getMetaData(); Map<String, Object> m; while (rs.next()) { m = new LinkedHashMap<>(); for (int i = 1; i <= rsm.getColumnCount(); i++) { m.put(rsm.getColumnLabel(i), rs.getObject(rsm.getColumnLabel(i))); } list.add(m); } rs.close(); ps.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } } else { Map<String, Object> m = new HashMap<>(); m.put("error", "頁碼輸入有誤!"); list.add(m); } return list; } /** * 檢視某一頁的資料(每頁的預設10條資料,預設無條件) * @param tableName 表名 * @param fieldName 欄位名(1個或多個) * @param currentPage 選擇要檢視的頁數(當前頁) * @return list集合 */ public List<Map<String, Object>> page(String tableName, String fieldName, int currentPage){ return page(tableName, fieldName, currentPage, pageSize, ""); } /** * 匯出表資料到txt檔案,需要判斷secure_file_priv(show variables like "secure_file_priv";)的狀態, * 若為null,則是對mysqld的匯入、匯出做限制,修改my.ini檔案新增或修改secure_file_priv=""; * @param tableName 表名 * @param fieldName 欄位名(1個或多個) * @param file 檔案路徑 */ public void exportData(String tableName, String fieldName, String file) { String sql = String.format("select %s from %s into outfile '%s'", fieldName,tableName,file); try { PreparedStatement ps = conn.prepareStatement(sql); ResultSet rs = ps.executeQuery(); ps.close(); rs.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } } /** * 匯入表資料,資料庫必須有此表的表結構 * @param file 檔案路徑 * @param tableName 表名 */ public void importData(String file, String tableName) { String sql = String.format("load data infile '%s' into table %s",file,tableName); try { PreparedStatement ps = conn.prepareStatement(sql); ResultSet rs = ps.executeQuery(); ps.close(); rs.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } } public void close() { try { conn.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } } }
若使用小編提供的,要看清自己的資料庫資料,不然使用時會報錯,連線的配置一定要配好,預設是db資料庫
(4)級聯城市資料庫,當然你也可以自己隨意寫一點資料做測試,下面是資料庫sql語句,自行下載
連結:https://pan.baidu.com/s/1s9s5lIv58KWbiYTt7Cc42g
提取碼:cctc
二、上程式碼(web專案)
前端程式碼,小編使用的是jsp,使用時要看清
index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="true" %> <html> <head> <title>級聯查詢 ajax</title> <script src="/select/js/jquery.js"></script> </head> <body> <table border="1" cellspacing="0" cellpadding="0"> <tr> <td> <span>省:</span><select id="province"> <option value="請選擇···">請選擇···</option> </select> </td> <td> <span>市:</span><select id="city"> <option value="請選擇···">請選擇···</option> </select> </td> <td> <span>縣(區):</span><select id="area"> <option value="請選擇···">請選擇···</option> </select> </td> </tr> <tr> <td colspan="3"><textarea cols="30" rows="10" placeholder="輸入詳細地址" style="resize: none"></textarea></td> </tr> </table> <script> $(function () { //相當於window.load() 最後載入 //載入省會 $.ajax({ type: "post", url: "/province", dataType: "json",//從 /province 以json接收資料 success: function (e) { $.each(e, function (i, v) {//迴圈接到的值 $('#province').append(`<option value=${v.provinceID}>${v.province}</option>`); }); //載入城市 $('#province').change(function () {//當省會發生修改時,呼叫 let provinceID = $('#province>option:selected').val();//獲取所選省會的id if (provinceID == "710000" || provinceID == "810000" || provinceID == "820000") {//香港、澳門、臺灣 $('#city').empty().append('<option value=""></option>'); $('#area').empty().append('<option value=""></option>'); } else { $('#city').empty().append('<option value="請選擇···">請選擇···</option>');//清空之前選擇省會後載入的城市,也就是重置 $('#area').empty().append('<option value="請選擇···">請選擇···</option>');//重置 $.ajax({ type: "post", url: "/city", data: `provinceID=${provinceID}`,//將省會id傳到 /city 裡 dataType: "json",//從 /city 以json接收資料 success: function (e) { $.each(e, function (i, v) { $('#city').append(`<option value=${v.cityID}>${v.city}</option>`); }) //載入區、縣 $('#city').change(function () { $('#area').empty().append('<option value="請選擇···">請選擇···</option>');//重置 let cityID = $('#city>option:selected').val();//獲取所選的城市id $.ajax({ type: "post", url: "/area", data: `cityID=${cityID}`, dataType: "json", success: function (e) { $.each(e, function (i, v) { $('#area').append(`<option value=${v.areaID}>${v.area}</option>`); }) } }) }) } }) } }) } }) }); </script> </body> </html>
後端程式碼
Province_db.java
package pers.select; import com.alibaba.fastjson.JSON; import pers.dbutils.DbUtils; 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 java.io.IOException; import java.io.PrintWriter; import java.util.List; import java.util.Map; /** * TODO 從資料庫獲取省會 * * @author [email protected] * @date 2020/12/7 9:42 */ @WebServlet("/province") public class Province_db extends HttpServlet { @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { req.setCharacterEncoding("utf-8"); resp.setCharacterEncoding("utf-8"); resp.setContentType("text/html;charset=utf-8"); PrintWriter out = resp.getWriter(); //此處是我自己封裝的工具類(你可以使用自己的也可以使用本人提供的) DbUtils du = new DbUtils("select_demo"); //呼叫查詢語句,返回List<Map<String,Object>> 集合 List<Map<String, Object>> list = du.select("select id,provinceID,province from province order by id"); //轉換為json格式 out.println(JSON.toJSON(list)); out.flush(); out.close(); } }
City_db.java
package pers.select; import com.alibaba.fastjson.JSON; import pers.dbutils.DbUtils; 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 java.io.IOException; import java.io.PrintWriter; import java.util.List; import java.util.Map; /** * TODO 根據省會id從資料庫獲取城市 * * @author [email protected] * @date 2020/12/7 10:35 */ @WebServlet("/city") public class City_db extends HttpServlet { @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { req.setCharacterEncoding("utf-8"); resp.setCharacterEncoding("utf-8"); resp.setContentType("text/html;charset=utf-8"); PrintWriter out = resp.getWriter(); //拿到省會id String provinceID = req.getParameter("provinceID"); //呼叫工具類 DbUtils du = new DbUtils("select_demo"); //呼叫查詢語句 跟據省會id查詢,返回List<Map<String,Object>> 集合 List<Map<String, Object>> list = du.select("select id,cityID,city from city where father = ? order by id",provinceID); //轉換為json格式 out.println(JSON.toJSON(list)); out.flush(); out.close(); } }
Area_db.java
package pers.select; import com.alibaba.fastjson.JSON; import pers.dbutils.DbUtils; 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 java.io.IOException; import java.io.PrintWriter; import java.util.List; import java.util.Map; /** * TODO 根據城市id從資料庫獲取區、縣 * * @author [email protected] * @date 2020/12/7 10:35 */ @WebServlet("/area") public class Area_db extends HttpServlet { @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { req.setCharacterEncoding("utf-8"); resp.setCharacterEncoding("utf-8"); resp.setContentType("text/html;charset=utf-8"); PrintWriter out = resp.getWriter(); //拿到城市id String cityID = req.getParameter("cityID"); //呼叫工具類 DbUtils du = new DbUtils("select_demo"); //呼叫查詢語句 跟據城市id查詢,返回List<Map<String,Object>> 集合 List<Map<String, Object>> list = du.select("select id,areaID,area from area where father = ? order by id",cityID); //轉換為json格式 out.println(JSON.toJSON(list)); out.flush(); out.close(); } }