1. 程式人生 > 實用技巧 >【Java】Ajax實現級聯城市

【Java】Ajax實現級聯城市

效果圖

一、準備工作

  (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;
import 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(); } } }
dbUtils.java

    若使用小編提供的,要看清自己的資料庫資料,不然使用時會報錯,連線的配置一定要配好,預設是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>&nbsp;<span>省:</span><select id="province">
            <option value="請選擇···">請選擇···</option>
        </select>&nbsp;
        </td>
        <td>&nbsp;<span>市:</span><select id="city">
            <option value="請選擇···">請選擇···</option>
        </select>&nbsp;
        </td>
        <td>&nbsp;<span>縣(區):</span><select id="area">
            <option value="請選擇···">請選擇···</option>
        </select>&nbsp;
        </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();
    }
}