10天手敲一个SpringBoot网上商城项目(四)——新增收货地址功能、获取省市区列表及名称功能的实现

静态资源及sql文件分享
链接:https://pan.baidu.com/s/1X-yjmQcPD3PqS21x0HplNA?pwd=23gr
提取码:23gr

新增收货地址

1.创建数据表

1.选中数据表

use store

2.在store数据库中创建t_address表

CREATE TABLE t_address (
	aid INT AUTO_INCREMENT COMMENT '收货地址id',
	uid INT COMMENT '归属的用户id',
	`name` VARCHAR(20) COMMENT '收货人姓名',
	province_name VARCHAR(15) COMMENT '省-名称',
	province_code CHAR(6) COMMENT '省-行政代号',
	city_name VARCHAR(15) COMMENT '市-名称',
	city_code CHAR(6) COMMENT '市-行政代号',
	area_name VARCHAR(15) COMMENT '区-名称',
	area_code CHAR(6) COMMENT '区-行政代号',
	zip CHAR(6) COMMENT '邮政编码',
	address VARCHAR(50) COMMENT '详细地址',
	phone VARCHAR(20) COMMENT '手机',
	tel VARCHAR(20) COMMENT '固话',
	tag VARCHAR(6) COMMENT '标签',
	is_default INT COMMENT '是否默认:0-不默认,1-默认',
	created_user VARCHAR(20) COMMENT '创建人',
	created_time DATETIME COMMENT '创建时间',
	modified_user VARCHAR(20) COMMENT '修改人',
	modified_time DATETIME COMMENT '修改时间',
	PRIMARY KEY (aid)
) ENGINE=INNODB DEFAULT CHARSET=utf8;

注意name是关键字,所以需要用``

2.创建收货地址的实体类

在entity包下创建实体类Address继承BaseEntity类

/**收货地址额实体类*/
public class Address extends BaseEntity {
    private Integer aid;
    private Integer uid;
    private String name;
    private String provinceName;
    private String provinceCode;
    private String cityName;
    private String cityCode;
    private String areaName;
    private String areaCode;
    private String zip;
    private String address;
    private String phone;
    private String tel;
    private String tag;
    private Integer isDefault;
 /**
 * get,set
 * equals和hashCode
 * toString
 */
}

3.新增收货地址-持久层

3.1各功能的开发顺序

当前收货地址功能模块:

  • 第一个页面:列表的展示,修改,删除,设置默认
  • 第二个页面:新增收货地址

开发顺序:新增收货地址->列表的展示->设置默认收货地址->删除收货地址->修改收货地址

3.2规划需要执行的SQL语句

1.新增收货地址对应的是插入语句:

insert into t_address (aid以外的所有字段) values (字段值)

2.大部分平台都会规定一个用户的收货地址数量,这里规定最多20个.那么在插入用户新的地址之前就要先做查询操作.如果查询到的是刚好20,这并不是一个java语法的异常,可以认为是业务控制的异常,这个异常随后在service抛,在controller捕获

select count(*) from t_address where uid=?
3.3设计接口和抽象方法

创建接口AddressMapper,在这个接口中定义上面两个SQL语句抽象方法定义

/**收货地址持久层的接口*/
public interface AddressMapper {
    /**
     * 插入用户的收货地址数据
     * @param address 收货地址数据
     * @return 受影响的行数
     */
    Integer insert (Address address);

    /**
     * 根据用户的uid统计收货地址数量
     * @param uid 用户的uid
     * @return 当前用户的收货地址总数
     */
    Integer countByUid(Integer uid);
}
3.4编写映射

1.快速创建一个AddressMapper.xml映射文件:

  • 鼠标放在UserMapper.xml文件上并ctrl+c,再把鼠标放到mapper文件夹上ctrl+v,在弹出的窗口中把UserMapper改为AddressMapper.
  • 进入AddressMapper.xml文件将mapper标签下的代码全部删除并修改mapper标签属性值为namespace=“com.cy.store.mapper.AddressMapper”

结果如下所示:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.cy.store.mapper.AddressMapper">
</mapper>

2.在mapper标签中配置Address类属性与数据库中表的字段映射

    <resultMap id="AddressEntityMap" type="com.cy.store.entity.Address">
        <id column="aid" property="aid"/>
        <result column="province_name" property="provinceName"/>
        <result column="province_code" property="provinceCode"/>
        <result column="city_name" property="cityName"/>
        <result column="city_code" property="cityCode"/>
        <result column="area_name" property="areaName"/>
        <result column="area_code" property="areaCode"/>
        <result column="is_default" property="isDefault"/>
        <result column="created_user" property="createdUser"/>
        <result column="created_time" property="createdTime"/>
        <result column="modified_user" property="modifiedUser"/>
        <result column="modified_time" property="modifiedTime"/>
    </resultMap>

判断该映射是否配置成功:按着ctrl并点击type="com.cy.store.entity.Address"中的Address,如果能跳转到Address类说明映射成功

3.在AddressMapper.xml中配置以上两个抽象方法的映射

    <insert id="insert" useGeneratedKeys="true" keyProperty="aid">
        INSERT INTO t_address (
            uid, `name`, province_name, province_code, city_name, city_code, area_name, area_code, zip,
            address, phone, tel,tag, is_default, created_user, created_time, modified_user, modified_time
        ) VALUES (
            #{uid}, #{name}, #{provinceName}, #{provinceCode}, #{cityName}, #{cityCode}, #{areaName},
            #{areaCode}, #{zip}, #{address}, #{phone}, #{tel}, #{tag}, #{isDefault}, #{createdUser},
            #{createdTime}, #{modifiedUser}, #{modifiedTime}
        )
    </insert>

    <!--resultType="java.lang.Integer"不写会报错,因为Integer不是基本数据类型-->
    <select id="countByUid"  resultType="java.lang.Integer">
        select count(*) from t_address where uid=#{uid}
    </select>
3.5单元测试

在test下的mapper文件夹下创建AddressMapperTests测试类

@SpringBootTest
@RunWith(SpringRunner.class)
public class AddressMapperTests {

    @Autowired
    private AddressMapper addressMapper;

    @Test
    public void insert() {
        Address address = new Address();
        address.setUid(11);
        address.setPhone("133336");
        address.setName("女朋友");
        addressMapper.insert(address);
    }

    @Test
    public void countByUid() {
        Integer count = addressMapper.countByUid(11);
        System.out.println(count);
    }
}

4.新增收货地址-业务层

4.1规划异常
  • 插入数据时用户不存在(被管理员误删等等),抛UsernameNotFoundException异常(已经有了,不需要重复创建)

  • 当用户插入的地址是第一条时,需要将当前地址作为默认收货地址

    实现办法:如果查询到统计总数为0则将当前地址的is_default值设置为1

  • 如果查询的结果>=20,这时需要抛出业务控制的异常AddressCountLimitException

    /**收货地址总数超出限制的异常(20条)*/
    public class AddressCountLimitException extends ServiceException {
        /**重写ServiceException的所有构造方法*/
    }
    
  • 插入数据时产生未知的异常InsertException(已经有了,不需要重复创建)

4.2设计接口和抽象方法及实现

1.创建一个IAddressService接口,在接口中定义业务的抽象方法

因为mapper层接口该功能模块定义了两个抽象方法,所以就要在service层接口该功能模块也定义两个抽象方法?不是这样的,要看mapper层的这两个方法是依赖关系还是独立关系,如果某一个抽象方法依赖于另一个抽象方法,那就需要在业务层将这两个方法整合到一个方法中.一句话来说就是:一个功能模块可能需要多条sql语句

/**收货地址的业务层接口*/
@Service
public interface IAddressService {
    /**
     *这三个参数的由来:
     * 1.首先肯定要有address
     * 2.业务层需要根据uid查询该用户收货地址总数及新建地址时给字段uid赋值
     * 但新建收货地址的表单中并没有哪个控件让输入用户uid,所以需要控制层将uid传给业务层
     * 3.业务层在创建/修改收货地址时需要同时修改数据库中创建人/修改人的字段
     * 但新建收货地址的表单中并没有哪个控件让输入用户username,所以需要控制层将username传给业务层
     * 注意:> 可以用HttpSession session代替Integer uid, String username,但
     * 这样写的话就需要把BaseController类下获取uid,username的方法重新封装到一个
     * 类中并让IAddressServiceImp实现类继承该类,这样就需要微调一下代码逻辑,太麻
     * 烦,并且,最好每一层只处理该层需要做的事情,session对象是控制层传递的,所以就
     * 把session对象定义封装在控制层中,不需要在业务层中额外处理以降低耦合
     */
    void addNewAddress(Integer uid, String username, Address address);
}

方法addNewAddress中三个参数的由来:

  • 首先肯定要有address

  • 业务层需要根据uid查询该用户收货地址总数及新建地址时给字段uid赋值

    但新建收货地址的表单中并没有哪个控件让输入用户uid,所以需要控制层将uid传给业务层并在业务层封装到address对象中

  • 业务层在创建/修改收货地址时需要同时修改数据库中创建人/修改人的字段

    但新建收货地址的表单中并没有哪个控件让输入用户username,所以需要控制层将username传给业务层并在业务层封装到address对象中

可以用HttpSession session代替Integer uid, String username,但这样写的话就需要把BaseController类下获取uid,username的方法重新封装到一个类中并让AddressServiceImpl实现类继承该类,这样就需要微调一下代码逻辑,太麻烦,并且,最好每一层只处理该层需要做的事情,session对象是控制层传递的,所以就把session对象定义封装在控制层中,不需要在业务层中额外处理,这样可以降低耦合

2.创建一个AddressServiceImpl类实现接口中抽象方法

/**新增收货地址的实现类*/
public class AddressServiceImpl implements IAddressService {
    @Autowired
    private AddressMapper addressMapper;
    @Autowired
    private UserMapper userMapper;

    /**
     * 为了方便日后修改最大收货地址数量,可以在配置文件
     * application.properties中定义user.address.max-count=20
     */
    //spring读取配置文件中数据:@Value("${user.address.max-count}")
    @Value("${user.address.max-count}")
    private Integer maxCount;

    @Override
    public void addNewAddress(Integer uid, String username, Address address) {
        User result = userMapper.findByUid(uid);
        if (result ==null || result.getIsDelete() == 1) {
            throw new UsernameNotFoundException("用户数据不存在");
        }

        //调用统计收货地址数量的方法
        Integer count = addressMapper.countByUid(uid);
        if (count >= maxCount) {
            throw new AddressCountLimitException("用户收货地址超出上限");
        }

        //uid,isDefault
        address.setUid(uid);
        Integer isDefault = count == 0 ? 1 : 0;//1表示默认收货地址,0反之
        address.setIsDefault(isDefault);

        //补全四项日志
        address.setCreatedUser(username);
        address.setModifiedUser(username);
        address.setCreatedTime(new Date());
        address.setModifiedTime(new Date());

        //调用插入收货地址的方法
        Integer rows = addressMapper.insert(address);
        if (rows != 1) {
            throw new InsertException("插入用户的收货地址时产生未知异常");
        }
    }
}

别忘了在配置文件application.properties中定义user.address.max-count=20

4.3单元测试

在test下的service文件夹下创建AddressServiceTests测试类

@SpringBootTest
@RunWith(SpringRunner.class)
public class AddressServiceTests {
    @Autowired
    private IAddressService addressService;

    @Test
    public void addNewAddress() {
        Address address = new Address();
        address.setPhone("175726");
        address.setName("男朋友");
        addressService.addNewAddress(11,"mxy",address);
    }
}

5.新增收货地址-控制层

5.1处理异常

义务层抛出了收货地址总数超出上限的异常,在BaseController中进行捕获处理

else if (e instanceof AddressCountLimitException) {
    result.setState(4003);
    result.setMessage("用户的收货地址超出上限的异常");
}
5.2设计请求
  • /addresses/add_new_address
  • post
  • Address address,HttpSession session
  • JsonResult<Void>
5.3处理请求

在controller包下创建AddressController并继承BaseController,该类用来处理用户收货地址的请求和响应

@RequestMapping("addresses")
@RestController
public class AddressController extends BaseController{
    @Autowired
    private IAddressService addressService;

    @RequestMapping("add_new_address")
    public JsonResult<Void> addNewAddress(Address address, HttpSession session) {
        Integer uid = getUidFromSession(session);
        String username = getUsernameFromSession(session);
        addressService.addNewAddress(uid,username,address);
        return new JsonResult<>(OK);
    }
}

启动服务器,登录账号后在地址栏输入http://localhost:8080/addresses/add_new_address?name=tom&phone=98745612进行测试

6.新增收货地址-前端页面

        <script>
            $("#btn-add-new-address").click(function () {
                $.ajax({
                    url: "/addresses/add_new_address",
                    type: "POST",
                    data: $("#form-add-new-address").serialize(),
                    dataType: "JSON",
                    success: function (json) {
                        if (json.state == 200) {
                            alert("新增收货地址成功")
                        } else {
                            alert("新增收货地址失败")
                        }
                    },
                    error: function (xhr) {
                        alert("新增收货地址时产生未知的异常!"+xhr.message);
                    }
                });
            });
        </script>

获取省市区列表

新增收货地址页面的三个下拉列表的内容展示没有和数据库进行交互,而是通过前端实现的(将代码逻辑放在了distpicker.data.js文件中),实现方法是在加载新增收货地址页面时加载该js文件,这种做法不可取(我不知道为啥)

正确做法是:把这些数据保存到数据库中,用户点击下拉列表时相应的数据会被详细的展示出来,然后监听用户选择了哪一项以便后面的下拉列表进行二级关联

1.创建数据表

1.创建t_dict_district表

CREATE TABLE t_dict_district (
  id INT(11) NOT NULL AUTO_INCREMENT,
  parent VARCHAR(6) DEFAULT NULL,
  `code` VARCHAR(6) DEFAULT NULL,
  `name` VARCHAR(16) DEFAULT NULL,
  PRIMARY KEY (id)
) ENGINE=INNODB DEFAULT CHARSET=utf8;
  • code和name需要加``
  • parent代表父区域的代码号
  • code代表自身的代码号
  • 省的父代码号是+86,代表中国

2.向该表中插入省市区数据

LOCK TABLES t_dict_district WRITE;
INSERT INTO t_dict_district VALUES (1,'110100','110101','东城区'),(2,'110100','110102','西城区')等等等等;
UNLOCK TABLES;

LOCK和UNLOVK干嘛用的?

2.创建省市区的实体类

在包entity下创建实体类District(不需要继承BaseEntity,但因为没有继承BaseEntity所以需要实现接口Serializable序列化)

/**省市区的数据实体类*/
public class District implements Serializable {
    private Integer id;
    private String parent;
    private String code;
    private String name;
 /**
 * get,set
 * equals和hashCode
 * toString
 */
}

3.获取省市区列表-持久层

3.1规划需执行的SQL语句
select * from t_dict_district where parent=? order by ASC
3.2设计接口和抽象方法

日后可能开发新的模块仍要用到省市区列表,那么为了降低耦合性,就要创建新的接口

在mapper层下创建接口DistrictMapper

public interface DistrictMapper {

    /**
     * 根据父代码号查询区域信息
     * @param parent 父代码号
     * @return 某个父区域下所有的区域列表
     */
    List<District> findByParent(String parent);//查询的结果可能是多个,所以放在集合中
}
3.3编写映射

创建一个DistrictMapper.xml映射文件并配置上述抽象方法的映射

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.cy.store.mapper.DistrictMapper">
    <select id="findByParent" resultType="com.cy.store.entity.District">
        select * from t_dict_district where parent=#{parent}
        order by code ASC
    </select>
</mapper>
3.4单元测试

创建DistrictMapperTests测试类编写代码进行测试

@SpringBootTest
@RunWith(SpringRunner.class)
public class DistrictMapperTests {

    @Autowired
    private DistrictMapper districtMapper;
    
    @Test
    public void findByParent() {
        List<District> list = districtMapper.findByParent("210100");
        for (District district : list) {
            System.out.println(district);
        }
    }

}

4.获取省市区列表-业务层

4.1规划异常

没有异常需要处理

4.2设计接口和抽象方法及实现

1.创建一个接口IDistrictService,并定义抽象方法

public interface IDistrictService {

    /**
     * 根据父代码号来查询区域信息(省或市或区)
     * @param parent 父代码号
     * @return 多个区域的信息
     */
    List<District> getByParent(String parent);
}

2.创建DistrictServiceImpl实现类来实现抽象方法

@Service
public class DistrictServiceImpl implements IDistrictService {

    @Autowired
    private DistrictMapper districtMapper;

    @Override
    public List<District> getByParent(String parent) {
        List<District> list = districtMapper.findByParent(parent);
        /**
         * 在进行网络数据传输时,为了尽量避免无效数据的传递,可以将无效数据
         * 设置为null,这样既节省流量,又提升了效率
         */
        for (District district : list) {
            district.setId(null);
            district.setParent(null);
        }
        return list;
    }
}
4.3单元测试

在test下的service文件夹下创建DistrictServiceTests测试类

@SpringBootTest
@RunWith(SpringRunner.class)
public class DistrictServiceTests {
    @Autowired
    private IDistrictService districtService;

    @Test
    public void getByParent() {
        //86代表中国,所有的省父代码号都是86
        List<District> list = districtService.getByParent("86");
        for (District district : list) {
            System.err.println(district);
        }
    }
}

5.获取省市区列表-控制层

5.1设计请求
  • /districts/
  • GET
  • String parent
  • JsonResult<List<District>>
5.2处理请求

1.创建一个DistrictController类,在类中编写处理请求的方法

@RequestMapping("districts")
@RestController
public class DistrictController extends BaseController{
    @Autowired
    private IDistrictService districtService;

    /**
     * 请求路径和父路径相同时用@RequestMapping({"/",""}),表
     * 示districts后面跟/或者什么也不跟都会进入这个方法
     * 点进RequestMapping发现参数类型是String[],且传入一
     * 个路径时默认有{},传入一个以上路径时需要手动添加{}
     */
    @RequestMapping({"/",""})
    public JsonResult<List<District>> getByParent(String parent) {
        List<District> data = districtService.getByParent(parent);
        return new JsonResult<>(OK,data);
    }
}

2.为了能不登录也可以访问该数据,需要将districts请求添加到白名单中:

在LoginInterceptorConfigure类的addInterceptors方法中添加代码:patterns.add(“/districts/**”);

3.启动服务器,不登录账号,直接在地址栏输入http://localhost:8080/districts?parent=86测试能否正常获取数据

6.获取省市区列表-前端页面

1.原始的下拉列表展示是将数据放在js,再动态获取js中的数据,而目前为止我们已经将数据放在了数据库,所以不能让它再使用这种办法了,所以需要注释掉addAddress.html页面的这两行js代码:

<script type="text/javascript" src="../js/distpicker.data.js"></script>
<script type="text/javascript" src="../js/distpicker.js"></script>

关于这两行js代码:前者是为了获取数据,后者是为了将获取到的数据展示到下拉列表中

2.检查前端页面在提交省市区数据时是否有相关name属性和id属性(name用于提交数据,id用于监听用户的点击)

3.启动服务器,在前端验证一下是否还可以正常保存数据(除了省市区)

获取省市区名称

上一个模块获取省市区列表是通过父代码号获取子代码号完成联动,该模块获取省市区名称是通过自身的code获取自身的name

1.获取省市区名称-持久层

3.1规划需要执行的SQL语句

根据当前code来获取当前省市区的名称,对应就是一条查询语句

select * from t_dict_district where code=?
3.2设计接口和抽象方法

在DistrictMapper接口定义findNameByCode方法

String findNameByCode(String code);
3.3编写映射

在DistrictMapper.xml文件中添加findNameByCode方法的映射

<select id="findNameByCode" resultType="java.lang.String">
    select name from t_dict_district where code=#{code}
</select>
3.4单元测试

在DistrictMapperTests编写测试代码

@Test
public void findNameByCode() {
    String name = districtMapper.findNameByCode("610000");
    System.out.println(name);
}

2.获取省市区名称-业务层

2.1规划异常

没有异常需要处理

2.2设计接口和抽象方法及实现

1.在IDistrictService接口定义对应的业务层接口中的抽象方法

String getNameByCode(String code);

2.在DistrictServiceImpl实现此方法

@Override
public String getNameByCode(String code) {
    return districtMapper.findNameByCode(code);
}
2.3单元测试

业务层只是调用持久层对应的方法然后返回,没有什么额外的实现,可以不用测试(一般超过8行的代码都要进行测试)

3.获取省市区名称-控制层

实际开发中在获取省市区名称时并不需要前端传控制层,然后传业务层,再传持久层,而是在新增收货地址的业务层需要获取省市区名称,也就是说获取省市区名称的模块不需要控制层,只是需要被新增收货地址的业务层所依赖

4.获取省市区名称-业务层优化

1.在新增收货地址的业务层需要对address进行封装,使其存有所有数据,然后将address传给持久层(记住,持久层只会根据传过来的参数调用某个方法与数据库交互,永远不会有额外的实现),而此时新增收货地址的业务层并没有省市区的数据,所以需要依赖于获取省市区列表的业务层对应的接口中的getNameByCode方法

所以需要在业务层实现类AddressServiceImpl中加

@Autowired
private IDistrictService districtService;

2.在AddressServiceImpl的方法中将DistrictService接口中获取到的省市区数据封装到address对象,此时address就包含了所有用户收货地址的数据

/**
* 对address对象中的数据进行补全:省市区的名字看前端代码发现前端传递过来的省市区的name分别为:
* provinceCode,cityCode,areaCode,所以这里可以用address对象的get方法获取这三个的数据
 */
String provinceName = districtService.getNameByCode(address.getProvinceCode());
String cityName = districtService.getNameByCode(address.getCityCode());
String areaName = districtService.getNameByCode(address.getAreaCode());
address.setProvinceName(provinceName);
address.setCityName(cityName);
address.setAreaName(areaName);

5.获取省市区名称-前端页面

在addAddress.html页面中来编写对应的省市区展示及根据用户的不同选择来限制对应的标签中的内容

分析:

  • 在加载该页面时三个下拉列表的内容都显示为"-----请选择-----"
  • 没有选择市时如果点击区的下拉列表则列表中只有一个"-----请选择-----"
  • 加载该页面时需要自动发送一个请求把parent=86发送出去,然后将返回的省/直辖市填充到select标签中
  • 点击四川省后发送请求获取其下的市,并且将获取到的市罗列在市区域下拉列表中
  • 省点击"-----请选择-----“则需要把市,县内容填充为”-----请选择-----"终止请求而不是程序继续跑下去
  • 切换省份时,市,县内容更换为"-----请选择-----"

在addAddress.html中编写js代码

            /**因为清空后下拉列表的select标签没有option标签,所以需要设置一个默认的option标
             * 签并给市,县加上该标签.option标签并不会把内容发送到后端,而是将value值发
             * 送给后端,所以用value表示当前这个区域的code值
             * */
            var defaultOption="<option value='0'>-----请选择-----</option>";
            $(document).ready(function () {
                //加载省的数据罗列时代码量较多,建议定义在外部方法中,然后在这里调用定义的方法
                showProvinceList();

                //将省,市,县的下拉列表内容设为"-----请选择-----"
                /**
                 * select标签默认获取第一个option的内容填充到下拉列表中,所以即使加载
                 * 页面时省区域的下拉列表中已经有了所有省但仍然会显示-----请选择-----
                 * */
                $("#province-list").append(defaultOption);

                $("#city-list").append(defaultOption);
                $("#area-list").append(defaultOption);
            });

            //省的下拉列表数据展示
            function showProvinceList() {
                $.ajax({
                    url: "/districts",//发送请求用于获取所有省对象
                    type: "POST",
                    data: "parent=86",
                    dataType: "JSON",
                    success: function (json) {
                        if (json.state == 200) {
                            var list = json.data;//获取所有省对象的List集合
                            for (var i = 0; i < list.length; i++) {
                                var opt =
                                    "<option value='"+list[i].code+"'>"+list[i].name+"</option>";
                                $("#province-list").append(opt);
                            }
                        } else {
                            <!--这个其实永远不会执行,因为没有编写
                            异常,控制层返回的状态码永远是OK-->
                            alert("省/直辖区的信息加载失败")
                        }
                    }
                    //这里没有写属性error,不知道为啥不用写,感觉写了更好
                });
            }

            /**
             * change()函数用于监听某个控件是否发生改变,一旦发生改变就
             * 会触发参数形式的函数,所以参数需要是function(){}
             * */
            $("#province-list").change(function () {
                //先获取到省区域父代码号
                var parent = $("#province-list").val();

                /**
                 * 如果我选择了河南省洛阳市涧西区,然后又选择了河北省,此时需要
                 * 将市,县下拉列表的所有option清除并显示内容-----请选择-----
                 * empty()表示某标签的所有子标签(针对此页面来说select的子标
                 * 签只有option)
                 * */
                $("#city-list").empty();
                $("#area-list").empty();
                //填充默认值:-----请选择-----
                $("#city-list").append(defaultOption);
                $("#area-list").append(defaultOption);

                if (parent == 0) {//如果继续程序,后面的ajax接收的json数据中的data是
                    return;//空集合[],进不了for循环,没有任何意义,所以直接在这里终止程序
                }
                $.ajax({
                    url: "/districts",
                    type: "POST",
                    data: "parent="+parent,
                    dataType: "JSON",
                    success: function (json) {
                        if (json.state == 200) {
                            var list = json.data;
                            for (var i = 0; i < list.length; i++) {
                                var opt =
                                    "<option value='"+list[i].code+"'>"+list[i].name+"</option>";
                                $("#city-list").append(opt);
                            }
                        } else {
                            alert("市的信息加载失败")
                        }
                    }
                });
            });

            $("#city-list").change(function () {
                var parent = $("#city-list").val();
                $("#area-list").empty();
                $("#area-list").append(defaultOption);

                if (parent == 0) {
                    return;
                }
                $.ajax({
                    url: "/districts",
                    type: "POST",
                    data: "parent="+parent,
                    dataType: "JSON",
                    success: function (json) {
                        if (json.state == 200) {
                            var list = json.data;
                            for (var i = 0; i < list.length; i++) {
                                var opt =
                                    "<option value='"+list[i].code+"'>"+list[i].name+"</option>";
                                $("#area-list").append(opt);
                            }
                        } else {
                            alert("县的信息加载失败")
                        }
                    }
                });
            });
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

认真生活的灰太狼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值