SpringBoot项目--电脑商城【获取省市区列表】
1.易错点
1.错误做法
新增收货地址页面的三个下拉列表的内容展示没有和数据库进行交互,而是通过前端实现的(将代码逻辑放在了distpicker.data.js文件中),实现方法是在加载新增收货地址页面时加载该js文件,这种做法不可取
2.正确做法
把这些数据保存到数据库中,用户点击下拉列表时相应的数据会被详细的展示出来,然后监听用户选择了哪一项以便后面的下拉列表进行二级关联
3.主要步骤
要将省市区进行展示,则
1.需要先从数据库获取全部数据
2.然后当选中【省】时,【市】可以自动找到对应的数据,找到【市】的时候可以自动找到【区】---二级联动
要点一:获取省市区列表
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;
2.创建省市区的实体类
在包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;
}
3. 持久层[Mapper]
1 规划需执行的SQL语句
select * from t_dict_district where parent=? order by ASC
2 设计接口和抽象方法
日后可能开发新的模块仍要用到省市区列表,那么为了降低耦合性,就要创建新的接口
在mapper层下创建接口DistrictMapper
public interface DistrictMapper {/*** 根据用户的父代号查询区域信息* @param parent*///查询的结果可能是多个,所以放在集合中List<District> findByParent(String parent);
}
3 编写映射
创建一个DistrictMapper.xml映射文件并配置上述抽象方法的映射
<select id="findByParent" resultType="com.example.mycomputerstore.entity.District">select *from t_dict_district where parent=#{parent}order by code asc;
</select>
4 单元测试
创建DistrictMapperTests测试类编写代码进行测试
@SpringBootTest
@RunWith(SpringRunner.class)
public class DistrictMapperTests {@Autowiredprivate DistrictMapper districtMapper;@Testpublic void findByParent() {List<District> list = districtMapper.findByParent("210100");for (District district : list) {System.out.println(district);}}}
4.业务层[Service]
1规划异常
没有异常需要处理
2 设计接口和抽象方法及实现
1.创建一个接口IDistrictService,并定义抽象方法
public interface IDistrictService {/*** 根据父代号来查询区域信息(省市区)* @param parent* @return 多个区域信息*/List<District> getByParent(String parent);
}
2.创建DistrictServiceImpl实现类来实现抽象方法
@Service
public class IDistrictServiceImpl implements IDistrictService {@Autowiredprivate DistrictMapper districtMapper;/*** 根据父代号查找区域** @param parent* @return*/@Overridepublic List<District> getByParent(String parent) {List<District> list = districtMapper.findByParent(parent);//在进行网络数据传输时,为了尽量避免无效数据的传递,可以将无效数据设置为null//可以节省浏览,另一方面提升效率for (District d:list){d.setId(null);d.setParent(null);}return list;}
}
3单元测试
在test下的service文件夹下创建DistrictServiceTests测试类
@SpringBootTest
@RunWith(SpringRunner.class)
public class DistrictServiceTests {@Autowiredprivate IDistrictService districtService;@Testpublic void getByParent() {//86代表中国,所有的省父代码号都是86List<District> list = districtService.getByParent("86");for (District district : list) {System.err.println(district);}}
}
5.控制层[Controller]
1 设计请求
- /districts/
- GET
- String parent
- JsonResult<List<District>>
2 处理请求
1.创建一个DistrictController类,在类中编写处理请求的方法
@RequestMapping("/district")
@RestController
public class DistrictController extends BaseController{@Autowiredprivate IDistrictService districtService;/*** 请求路径和父路径相同时用@RequestMapping({"/",""}),表* 示districts后面跟/或者什么也不跟都会进入这个方法* 点进RequestMapping发现参数类型是String[],且传入一* 个路径时默认有{},传入一个以上路径时需要手动添加{}*/@GetMapping({"/",""})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.持久层[Mapper]
1规划需要执行的SQL语句
根据当前code来获取当前省市区的名称,对应就是一条查询语句
select * from t_dict_district where code=?
2 设计接口和抽象方法
在DistrictMapper接口定义findNameByCode方法
String findNameByCode(String code);
3 编写映射
在DistrictMapper.xml文件中添加findNameByCode方法的映射
<select id="findNameByCode" resultType="java.lang.String">select name from t_dict_district where code=#{code}</select>
4 单元测试
在DistrictMapperTests编写测试代码
@Test
public void findNameByCode() {String name = districtMapper.findNameByCode("610000");System.out.println(name);
}
2.业务层[Service]
1规划异常
没有异常需要处理
2 设计接口和抽象方法及实现
1.在IDistrictService接口定义对应的业务层接口中的抽象方法
String getNameByCode(String code);
2.在DistrictServiceImpl实现此方法
@Override
public String getNameByCode(String code) {return districtMapper.findNameByCode(code);
}
3 单元测试
业务层只是调用持久层对应的方法然后返回,没有什么额外的实现,可以不用测试(一般超过8行的代码都要进行测试)
3.业务层[Controller]
实际开发中在获取省市区名称时并不需要前端传控制层,然后传业务层,再传持久层,而是在新增收货地址的业务层需要获取省市区名称,也就是说获取省市区名称的模块不需要控制层,只是需要被新增收货地址的业务层所依赖
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代码
<script type="text/javascript">
<!-- 下拉框的默认选项:select的下拉默认选中的是option-->//value属性用于表示当前中国区域的code值
/**因为清空后下拉列表的select标签没有option标签,所以需要设置一个默认的option标* 签并给市,县加上该标签.option标签并不会把内容发送到后端,而是将value值发* 送给后端,所以用value表示当前这个区域的code值* */let defaultOption="<option value='0'>---- 请选择 -----</option>"/** 打开页面自动加载* */$(document).ready(function (){//加载省的数据罗列时代码量较多,建议定义在外部方法中,然后在这里调用定义的方法showProvinceList();//设置默认的"请选择“的值,作为控制的默认值/*** select标签默认获取第一个option的内容填充到下拉列表中,所以即使加载* 页面时省区域的下拉列表中已经有了所有省但仍然会显示-----请选择-----* */$("#province-list").append(defaultOption)$("#city-list").append(defaultOption);$("#area-list").append(defaultOption)})/** change()函数用于监听某一个控件是否发生改变,一旦发生改变就会触发参数的函数* */$("#province-list").change(function (){//先获取行政区父代码let parent = $("#province-list").val();//1.先清空市区的select下拉列表中的所有option元素:【请选择】的默认数据/*** 如果我选择了河南省洛阳市涧西区,然后又选择了河北省,此时需要* 将市,县下拉列表的所有option清除并显示内容-----请选择-----* empty()表示某标签的所有子标签(针对此页面来说select的子标* 签只有option)* */$("city-list").empty();$("#area-list").empty()//2.填充默认值$("city-list").append(defaultOption);$("#area-list").append(defaultOption)//如果父亲code为0,没有选择if(parent==0){//如果继续程序,后面的ajax接收的json数据中的data是return;//空集合[],进不了for循环,没有任何意义,所以直接在这里终止程序}$.ajax({url:"/district",type:"GET",data:"parent="+parent,dataType:"JSON",success(e){if(e.state==200){let list=e.data;for(let i=0;i<list.length;i++){// "<option value=''>name</option>"let opt = "<option value='" + list[i].code + "'>" + list[i].name + "</option>";$("#city-list").append(opt)}}else{alert("城市信息加载失败")}},})})$("#city-list").change(function (){//先获取行政区父代码let parent = $("#city-list").val();//1.先清空市区的select下拉列表中的所有option元素:【请选择】的默认数据$("#area-list").empty()//2.填充默认值$("#area-list").append(defaultOption)//如果父亲code为0,没有选择if(parent==0){return;}$.ajax({url:"/district",type:"GET",data:"parent="+parent,dataType:"JSON",success(e){if(e.state==200){let list=e.data;for(let i=0;i<list.length;i++){// "<option value=''>name</option>"let opt = "<option value='" + list[i].code + "'>" + list[i].name + "</option>";$("#area-list").append(opt)}}else{alert("区县信息加载失败")}},})})//省的下拉列表数据展示function showProvinceList(){$.ajax({url:"/district",type:"GET",data:"parent=86",dataType:"JSON",success(e){if(e.state==200){let list=e.data;//获取所有省对象的list集合for(let i=0;i<list.length;i++){// "<option value=''>name</option>"let opt = "<option value='" + list[i].code + "'>" + list[i].name + "</option>";$("#province-list").append(opt)}}else{alert("省/直辖市信息加载失败")}},})}$("#btn-add-new-address").click(function (){$.ajax({url:"/address/add_new_address",type:"POST",data:$("#form-add-new-address").serialize(),dataType:"JSON",success(e){if(e.state==200){alert("新增收货地址成功")}else{alert("新增收货地址失败")}},error(xhr){alert("新增收货地址产生未知的异常"+xhr.status)}})})</script>
相关文章:

SpringBoot项目--电脑商城【获取省市区列表】
1.易错点 1.错误做法 新增收货地址页面的三个下拉列表的内容展示没有和数据库进行交互,而是通过前端实现的(将代码逻辑放在了distpicker.data.js文件中),实现方法是在加载新增收货地址页面时加载该js文件,这种做法不可取 2.正确做法 把这些数据保存到数据库中,用户点击下拉…...
使用git把本地项目关联远程代码仓库,并推送到远程仓库
你在本地新建了一个项目,写好了代码,但是没有关联远程仓库,怎么关联并上传呢? 你要先去gitee创建一个代码仓库,然后复制http地址。 首次提交项目代码到一个新建的远程仓库: 1、通过命令 git init 把这个…...

Spring+MyBatis使用collection标签的两种使用方法
目录 项目场景: 实战操作: 1.创建菜单表 2.创建实体 3.创建Mapper 4.创建xml 属性描述: 效率比较: 项目场景: 本文说明了Spring BootMyBatis使用collection标签的两种使用方法 1. 方法一: 关联查询 2. 方法…...

k8s集群中集群方式安装nacos
1、前提条件 一个k8s集群,其中有三个master 节点,这三个节点的标签名称为etcd 三个master节点的ip 分别为:192.165.187.170 、192.165.187.171、192.165.187.172一个mysql 数据库, 数据库的ip 为:192.165.187.180 用户…...
极客时间:数据结构与算法之美【学习笔记+思考实践】
本篇是 《极客时间:数据结构与算法之美》课程的学习笔记和带有自己的一些思考实践。原文学习链接如下:https://time.geekbang.org/column/intro/100017301 开篇词 | 从今天起,跨过“数据结构与算法”这道坎01 | 为什么要学习数据结构和算法&a…...

基于视觉重定位的室内AR导航项目思路(2):改进的建图和定位分离的项目思路
文章目录 一、建图二、定位首先是第一种方法:几何方法其次是第二种方法:图像检索方法最后是第三种方法:深度学习方法 前情提要: 是第一次做项目的小白,文章内的资料介绍如有错误,请多包含! 一、…...

nodejs+vue+elementui精品课程网站设计
前端技术:nodejsvueelementui基于nodejs语言、vue.js框架、B/S架构、Mysql数据库设计并实现了精品课程网站设计。系统主要包括首页、个人中心、用户管理、课程信息管理、课程分类管理、学习论坛、在线试题管理、试题管理、系统管理、考试管理等功能模块。 本文首先介…...
40个Linux常用命令组合
1.删除0字节文件 find -type f -size 0 -exec rm -rf {} \; 2.查看进程 按内存从大到小排列 ps -e -o "%C : %p : %z : %a"|sort -k5 -nr 3.按cpu利用率从大到小排列 ps -e -o "%C : %p : %z : %a"|sort -nr 4.打印说cache里的URL grep -r -a jpg …...

NIFI关于Variables的使用
说明 NIFI中的变量(variables)和参数(parameters)在引用的时候是有区别的。 参数的引用是使用#{参数名}的形式。 变量是使用${变量名}的形式来引用。 nifi版本:1.23.2(docker镜像) Variable…...
2、VRP基础
本节我们介绍华为设备的VRP系统平台的一些基本知识,为以后学习路由交换的配置命令做好基本的准备。在这里,为软考网络工程师做准备,只需要了解其中比较基础的即可,包括VRP是什么、提供了哪些用户界面、VRP的用户级别、基本的配置视…...

docker容器运行成功但无法访问,原因分析及对应解决方案(最新,以Tomcat为例,亲测有效)
原因分析: 是否能访问当运行docker容器虚拟机(主机)地址 虚拟机对应的端口号是否开启或者防墙是否关闭 端口映射是否正确(这个是我遇到的) tomcat下载的是最新版,docker运行后里面是没有东西的&am…...
第15章 秒杀商品隔离解决方案
mini商城第15章 秒杀商品隔离解决方案 一、课题 商品秒杀-热门数据实时收集 二、回顾 1、掌握热门分析收集方案 2、Lua高级语法 3、Kafka使用 4、Lua垂直日志收集 5、Apache Druid大数据实时处理系统 三、目标 1、MyBatis查询Apache Druid 常规查询 复杂查询 2、热门…...
2023-08-31力扣每日一题-姜汁水题
链接: 1761. 一个图中连通三元组的最小度数 题意: 选择两两相连的三个点,要求度最小 解: 什么暴力hard 实际代码: #include<bits/stdc.h> using namespace std; int minTrioDegree(int n, vector<vect…...

五大优化技巧,让你的视频直播app源码更加流畅
优化技巧一:性能调优 视频直播app源码在确保流畅体验方面是至关重要的。为了提升性能,以下是几项关键的优化技巧: 使用轻量级编码器和解码器:选择高效的编码器和解码器,以减少资源占用,并确保视频流畅播放…...
Weblogic10中常用Linux指令
一.Weblogic 创建域 域目录/servers/AdminServer 路径下 以weblogic帐号登录(与创建域目录相对应账户) cd /home/weblogic/bea/weblogic92/common/bin 执行./config.sh进入配置界面。配置步骤如下: 1.Choose between creating and exten…...

OpenAI 函数调用教程
推荐:使用 NSDT场景编辑器 快速搭建3D应用场景 什么是OpenAI函数调用? OpenAI API 非常擅长以系统的方式生成响应。只需几行代码即可管理提示、优化模型输出以及执行、生成和语言应用程序。 即使有这么多好东西,OpenAI API对开发人员和工程…...

Spark有两种常见的提交方式:client 模式和 cluster 模式对机器 CPU 的影响
Spark有两种常见的提交方式:client 模式和 cluster 模式。这两种方式对机器 CPU 的影响略有不同 ,请参考以下说明 Client 模式: 在 Client 模式下,Spark Driver 运行在提交任务的客户端节点上(即运行 spark-submit 命…...

HarmonyOS/OpenHarmony(Stage模型)应用开发单一手势(三)
五、旋转手势(RotationGesture) RotationGesture(value?:{fingers?:number; angle?:number}) 旋转手势用于触发旋转手势事件,触发旋转手势的最少手指数量为2指,最大为5指,最小改变度数为1度,拥有两个可…...
Git的安装以及基础使用方法
Git是一种分布式版本控制系统,被广泛用于管理代码、文档和任何其他类型的数据。它允许开发者在团队中协作,并且在处理大型项目时可以保持代码的完整性。 这里写目录标题 一、安装和设置二、基本的Git命令三、分支和合并四、标签和远程仓库 一、安装和设置…...

用通俗易懂的方式讲解大模型分布式训练并行技术:数据并行
近年来,随着Transformer、MOE架构的提出,使得深度学习模型轻松突破上万亿规模参数,传统的单机单卡模式已经无法满足超大模型进行训练的要求。因此,我们需要基于单机多卡、甚至是多机多卡进行分布式大模型的训练。 而利用AI集群&a…...

shell脚本--常见案例
1、自动备份文件或目录 2、批量重命名文件 3、查找并删除指定名称的文件: 4、批量删除文件 5、查找并替换文件内容 6、批量创建文件 7、创建文件夹并移动文件 8、在文件夹中查找文件...

ETLCloud可能遇到的问题有哪些?常见坑位解析
数据集成平台ETLCloud,主要用于支持数据的抽取(Extract)、转换(Transform)和加载(Load)过程。提供了一个简洁直观的界面,以便用户可以在不同的数据源之间轻松地进行数据迁移和转换。…...
css的定位(position)详解:相对定位 绝对定位 固定定位
在 CSS 中,元素的定位通过 position 属性控制,共有 5 种定位模式:static(静态定位)、relative(相对定位)、absolute(绝对定位)、fixed(固定定位)和…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...
ip子接口配置及删除
配置永久生效的子接口,2个IP 都可以登录你这一台服务器。重启不失效。 永久的 [应用] vi /etc/sysconfig/network-scripts/ifcfg-eth0修改文件内内容 TYPE"Ethernet" BOOTPROTO"none" NAME"eth0" DEVICE"eth0" ONBOOT&q…...
重启Eureka集群中的节点,对已经注册的服务有什么影响
先看答案,如果正确地操作,重启Eureka集群中的节点,对已经注册的服务影响非常小,甚至可以做到无感知。 但如果操作不当,可能会引发短暂的服务发现问题。 下面我们从Eureka的核心工作原理来详细分析这个问题。 Eureka的…...
JS设计模式(4):观察者模式
JS设计模式(4):观察者模式 一、引入 在开发中,我们经常会遇到这样的场景:一个对象的状态变化需要自动通知其他对象,比如: 电商平台中,商品库存变化时需要通知所有订阅该商品的用户;新闻网站中࿰…...
音视频——I2S 协议详解
I2S 协议详解 I2S (Inter-IC Sound) 协议是一种串行总线协议,专门用于在数字音频设备之间传输数字音频数据。它由飞利浦(Philips)公司开发,以其简单、高效和广泛的兼容性而闻名。 1. 信号线 I2S 协议通常使用三根或四根信号线&a…...

在Mathematica中实现Newton-Raphson迭代的收敛时间算法(一般三次多项式)
考察一般的三次多项式,以r为参数: p[z_, r_] : z^3 (r - 1) z - r; roots[r_] : z /. Solve[p[z, r] 0, z]; 此多项式的根为: 尽管看起来这个多项式是特殊的,其实一般的三次多项式都是可以通过线性变换化为这个形式…...

R 语言科研绘图第 55 期 --- 网络图-聚类
在发表科研论文的过程中,科研绘图是必不可少的,一张好看的图形会是文章很大的加分项。 为了便于使用,本系列文章介绍的所有绘图都已收录到了 sciRplot 项目中,获取方式: R 语言科研绘图模板 --- sciRplothttps://mp.…...