• SpringBoot项目--电脑商城【获取省市区列表】


    1.易错点

    1.错误做法

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

    2.正确做法

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

    3.主要步骤

    要将省市区进行展示,则

    1.需要先从数据库获取全部数据

    2.然后当选中【省】时,【市】可以自动找到对应的数据,找到【市】的时候可以自动找到【区】---二级联动

    要点一:获取省市区列表

    1.创建数据库

    t_dict_district表

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

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

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

    2.创建省市区的实体类

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

    1. /**
    2. * 表示省市区的数据实体类
    3. */
    4. @Data
    5. @NoArgsConstructor
    6. @AllArgsConstructor
    7. public class District extends BaseEntity {
    8. private Integer id;
    9. private String parent;
    10. private String code;
    11. private String name;
    12. }

    3. 持久层[Mapper]

    1 规划需执行的SQL语句

    select * from t_dict_district where parent=? order by ASC
    

    2 设计接口和抽象方法

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

    在mapper层下创建接口DistrictMapper

    1. public interface DistrictMapper {
    2. /**
    3. * 根据用户的父代号查询区域信息
    4. * @param parent
    5. */
    6. //查询的结果可能是多个,所以放在集合中
    7. List findByParent(String parent);
    8. }

     3 编写映射

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

    1. <select id="findByParent" resultType="com.example.mycomputerstore.entity.District">
    2. select *
    3. from t_dict_district where parent=#{parent}
    4. order by code asc;
    5. select>

    4 单元测试

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

    1. @SpringBootTest
    2. @RunWith(SpringRunner.class)
    3. public class DistrictMapperTests {
    4. @Autowired
    5. private DistrictMapper districtMapper;
    6. @Test
    7. public void findByParent() {
    8. List list = districtMapper.findByParent("210100");
    9. for (District district : list) {
    10. System.out.println(district);
    11. }
    12. }
    13. }

    4.业务层[Service]

    1规划异常

    没有异常需要处理

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

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

    1. public interface IDistrictService {
    2. /**
    3. * 根据父代号来查询区域信息(省市区)
    4. * @param parent
    5. * @return 多个区域信息
    6. */
    7. List getByParent(String parent);
    8. }

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

    1. @Service
    2. public class IDistrictServiceImpl implements IDistrictService {
    3. @Autowired
    4. private DistrictMapper districtMapper;
    5. /**
    6. * 根据父代号查找区域
    7. *
    8. * @param parent
    9. * @return
    10. */
    11. @Override
    12. public List getByParent(String parent) {
    13. List list = districtMapper.findByParent(parent);
    14. //在进行网络数据传输时,为了尽量避免无效数据的传递,可以将无效数据设置为null
    15. //可以节省浏览,另一方面提升效率
    16. for (District d:list){
    17. d.setId(null);
    18. d.setParent(null);
    19. }
    20. return list;
    21. }
    22. }

    3单元测试

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

    1. @SpringBootTest
    2. @RunWith(SpringRunner.class)
    3. public class DistrictServiceTests {
    4. @Autowired
    5. private IDistrictService districtService;
    6. @Test
    7. public void getByParent() {
    8. //86代表中国,所有的省父代码号都是86
    9. List list = districtService.getByParent("86");
    10. for (District district : list) {
    11. System.err.println(district);
    12. }
    13. }
    14. }

    5.控制层[Controller]

    1 设计请求 

    • /districts/
    • GET
    • String parent
    • JsonResult>

    2 处理请求

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

    1. @RequestMapping("/district")
    2. @RestController
    3. public class DistrictController extends BaseController{
    4. @Autowired
    5. private IDistrictService districtService;
    6. /**
    7. * 请求路径和父路径相同时用@RequestMapping({"/",""}),表
    8. * 示districts后面跟/或者什么也不跟都会进入这个方法
    9. * 点进RequestMapping发现参数类型是String[],且传入一
    10. * 个路径时默认有{},传入一个以上路径时需要手动添加{}
    11. */
    12. @GetMapping({"/",""})
    13. public JsonResult> getByParent(String parent){
    14. List data = districtService.getByParent(parent);
    15. return new JsonResult<>(OK,data);
    16. }
    17. }

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

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

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

    6.前端页面

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

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

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

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

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

    要点二:获取省市区名称

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

    1.持久层[Mapper]

    1规划需要执行的SQL语句

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

    select * from t_dict_district where code=?
    

    2 设计接口和抽象方法

    在DistrictMapper接口定义findNameByCode方法

    String findNameByCode(String code);

    3 编写映射

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

    1. <select id="findNameByCode" resultType="java.lang.String">
    2. select name from t_dict_district where code=#{code}
    3. select>

    4 单元测试

    在DistrictMapperTests编写测试代码

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

    2.业务层[Service]

    1规划异常

    没有异常需要处理

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

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

    String getNameByCode(String code);
    

    2.在DistrictServiceImpl实现此方法

    1. @Override
    2. public String getNameByCode(String code) {
    3. return districtMapper.findNameByCode(code);
    4. }

    3 单元测试

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

    3.业务层[Controller]

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

    4.业务层优化

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

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

    1. @Autowired
    2. private IDistrictService districtService;

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

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

    5.前端页面

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

    分析:

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

    在addAddress.html中编写js代码

  • 相关阅读:
    Linux常用指令和选项(一)
    redis过期key的清理/删除策略
    实体注解-批量生成10000条测试数据
    《前端》css总结(上)
    [解题报告] CSDN竞赛第五期
    计算机毕设(附源码)JAVA-SSM考勤管理系统
    前端(二十二)——前端工程化
    SpringBoot+Vue2项目解决前后端跨域方案
    基于51单片机推箱子小游戏Proteus仿真
    软件测试/测试开发丨Python文件操作 学习笔记
  • 原文地址:https://blog.csdn.net/m0_63077733/article/details/132721751