新增收货地址页面的三个下拉列表的内容展示没有和数据库进行交互,而是通过前端实现的(将代码逻辑放在了distpicker.data.js文件中),实现方法是在加载新增收货地址页面时加载该js文件,这种做法不可取
把这些数据保存到数据库中,用户点击下拉列表时相应的数据会被详细的展示出来,然后监听用户选择了哪一项以便后面的下拉列表进行二级关联
要将省市区进行展示,则
- 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,代表中国
- LOCK TABLES t_dict_district WRITE;
- INSERT INTO t_dict_district VALUES (1,'110100','110101','东城区'),(2,'110100','110102','西城区')等等等等;
- UNLOCK TABLES;
在包entity下创建实体类District(不需要继承BaseEntity,但因为没有继承BaseEntity所以需要实现接口Serializable序列化)
- /**
- * 表示省市区的数据实体类
- */
-
- @Data
- @NoArgsConstructor
- @AllArgsConstructor
- public class District extends BaseEntity {
- private Integer id;
- private String parent;
- private String code;
- private String name;
- }
select * from t_dict_district where parent=? order by ASC
日后可能开发新的模块仍要用到省市区列表,那么为了降低耦合性,就要创建新的接口
在mapper层下创建接口DistrictMapper
- public interface DistrictMapper {
- /**
- * 根据用户的父代号查询区域信息
- * @param parent
- */
- //查询的结果可能是多个,所以放在集合中
- List
findByParent(String parent); - }
创建一个DistrictMapper.xml映射文件并配置上述抽象方法的映射
- <select id="findByParent" resultType="com.example.mycomputerstore.entity.District">
- select *
- from t_dict_district where parent=#{parent}
- order by code asc;
- select>
创建DistrictMapperTests测试类编写代码进行测试
- @SpringBootTest
- @RunWith(SpringRunner.class)
- public class DistrictMapperTests {
-
- @Autowired
- private DistrictMapper districtMapper;
-
- @Test
- public void findByParent() {
- List
list = districtMapper.findByParent("210100"); - for (District district : list) {
- System.out.println(district);
- }
- }
-
- }
没有异常需要处理
1.创建一个接口IDistrictService,并定义抽象方法
- public interface IDistrictService {
-
- /**
- * 根据父代号来查询区域信息(省市区)
- * @param parent
- * @return 多个区域信息
- */
- List
getByParent(String parent); - }
2.创建DistrictServiceImpl实现类来实现抽象方法
- @Service
- public class IDistrictServiceImpl implements IDistrictService {
-
-
- @Autowired
- private DistrictMapper districtMapper;
-
- /**
- * 根据父代号查找区域
- *
- * @param parent
- * @return
- */
- @Override
- public List
getByParent(String parent) { - List
list = districtMapper.findByParent(parent); - //在进行网络数据传输时,为了尽量避免无效数据的传递,可以将无效数据设置为null
- //可以节省浏览,另一方面提升效率
- for (District d:list){
- d.setId(null);
- d.setParent(null);
- }
- return list;
- }
- }
在test下的service文件夹下创建DistrictServiceTests测试类
- @SpringBootTest
- @RunWith(SpringRunner.class)
- public class DistrictServiceTests {
- @Autowired
- private IDistrictService districtService;
-
- @Test
- public void getByParent() {
- //86代表中国,所有的省父代码号都是86
- List
list = districtService.getByParent("86"); - for (District district : list) {
- System.err.println(district);
- }
- }
- }
- /districts/
- GET
- String parent
- JsonResult
>
1.创建一个DistrictController类,在类中编写处理请求的方法
- @RequestMapping("/district")
- @RestController
- public class DistrictController extends BaseController{
-
- @Autowired
- private IDistrictService districtService;
-
- /**
- * 请求路径和父路径相同时用@RequestMapping({"/",""}),表
- * 示districts后面跟/或者什么也不跟都会进入这个方法
- * 点进RequestMapping发现参数类型是String[],且传入一
- * 个路径时默认有{},传入一个以上路径时需要手动添加{}
- */
- @GetMapping({"/",""})
- public JsonResult
> getByParent(String parent){
- List
data = districtService.getByParent(parent); - return new JsonResult<>(OK,data);
- }
-
- }
2.为了能不登录也可以访问该数据,需要将districts请求添加到白名单中:
在LoginInterceptorConfigure类的addInterceptors方法中添加代码:patterns.add(“/districts/**”);
3.启动服务器,不登录账号,直接在地址栏输入http://localhost:8080/districts?parent=86测试能否正常获取数据
1.原始的下拉列表展示是将数据放在js,再动态获取js中的数据,而目前为止我们已经将数据放在了数据库,所以不能让它再使用这种办法了,所以需要注释掉addAddress.html页面的这两行js代码:
- <script type="text/javascript" src="../js/distpicker.js">script>
关于这两行js代码:前者是为了获取数据,后者是为了将获取到的数据展示到下拉列表中
2.检查前端页面在提交省市区数据时是否有相关name属性和id属性(name用于提交数据,id用于监听用户的点击)
3.启动服务器,在前端验证一下是否还可以正常保存数据(除了省市区)
上一个模块获取省市区列表是通过父代码号获取子代码号完成联动,该模块获取省市区名称是通过自身的code获取自身的name
根据当前code来获取当前省市区的名称,对应就是一条查询语句
select * from t_dict_district where code=?
在DistrictMapper接口定义findNameByCode方法
String findNameByCode(String code);
在DistrictMapper.xml文件中添加findNameByCode方法的映射
- <select id="findNameByCode" resultType="java.lang.String">
- select name from t_dict_district where code=#{code}
- select>
在DistrictMapperTests编写测试代码
- @Test
- public void findNameByCode() {
- String name = districtMapper.findNameByCode("610000");
- System.out.println(name);
- }
没有异常需要处理
1.在IDistrictService接口定义对应的业务层接口中的抽象方法
String getNameByCode(String code);
2.在DistrictServiceImpl实现此方法
- @Override
- public String getNameByCode(String code) {
- return districtMapper.findNameByCode(code);
- }
业务层只是调用持久层对应的方法然后返回,没有什么额外的实现,可以不用测试(一般超过8行的代码都要进行测试)
实际开发中在获取省市区名称时并不需要前端传控制层,然后传业务层,再传持久层,而是在新增收货地址的业务层需要获取省市区名称,也就是说获取省市区名称的模块不需要控制层,只是需要被新增收货地址的业务层所依赖
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);

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