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…...

C++_核心编程_多态案例二-制作饮品
#include <iostream> #include <string> using namespace std;/*制作饮品的大致流程为:煮水 - 冲泡 - 倒入杯中 - 加入辅料 利用多态技术实现本案例,提供抽象制作饮品基类,提供子类制作咖啡和茶叶*//*基类*/ class AbstractDr…...

Lombok 的 @Data 注解失效,未生成 getter/setter 方法引发的HTTP 406 错误
HTTP 状态码 406 (Not Acceptable) 和 500 (Internal Server Error) 是两类完全不同的错误,它们的含义、原因和解决方法都有显著区别。以下是详细对比: 1. HTTP 406 (Not Acceptable) 含义: 客户端请求的内容类型与服务器支持的内容类型不匹…...
可靠性+灵活性:电力载波技术在楼宇自控中的核心价值
可靠性灵活性:电力载波技术在楼宇自控中的核心价值 在智能楼宇的自动化控制中,电力载波技术(PLC)凭借其独特的优势,正成为构建高效、稳定、灵活系统的核心解决方案。它利用现有电力线路传输数据,无需额外布…...

Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility
Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility 1. 实验室环境1.1 实验室环境1.2 小测试 2. The Endor System2.1 部署应用2.2 检查现有策略 3. Cilium 策略实体3.1 创建 allow-all 网络策略3.2 在 Hubble CLI 中验证网络策略源3.3 …...
Matlab | matlab常用命令总结
常用命令 一、 基础操作与环境二、 矩阵与数组操作(核心)三、 绘图与可视化四、 编程与控制流五、 符号计算 (Symbolic Math Toolbox)六、 文件与数据 I/O七、 常用函数类别重要提示这是一份 MATLAB 常用命令和功能的总结,涵盖了基础操作、矩阵运算、绘图、编程和文件处理等…...
Java求职者面试指南:Spring、Spring Boot、MyBatis框架与计算机基础问题解析
Java求职者面试指南:Spring、Spring Boot、MyBatis框架与计算机基础问题解析 一、第一轮提问(基础概念问题) 1. 请解释Spring框架的核心容器是什么?它在Spring中起到什么作用? Spring框架的核心容器是IoC容器&#…...

AirSim/Cosys-AirSim 游戏开发(四)外部固定位置监控相机
这个博客介绍了如何通过 settings.json 文件添加一个无人机外的 固定位置监控相机,因为在使用过程中发现 Airsim 对外部监控相机的描述模糊,而 Cosys-Airsim 在官方文档中没有提供外部监控相机设置,最后在源码示例中找到了,所以感…...

【C++】纯虚函数类外可以写实现吗?
1. 答案 先说答案,可以。 2.代码测试 .h头文件 #include <iostream> #include <string>// 抽象基类 class AbstractBase { public:AbstractBase() default;virtual ~AbstractBase() default; // 默认析构函数public:virtual int PureVirtualFunct…...

Ubuntu系统多网卡多相机IP设置方法
目录 1、硬件情况 2、如何设置网卡和相机IP 2.1 万兆网卡连接交换机,交换机再连相机 2.1.1 网卡设置 2.1.2 相机设置 2.3 万兆网卡直连相机 1、硬件情况 2个网卡n个相机 电脑系统信息,系统版本:Ubuntu22.04.5 LTS;内核版本…...

数据结构:递归的种类(Types of Recursion)
目录 尾递归(Tail Recursion) 什么是 Loop(循环)? 复杂度分析 头递归(Head Recursion) 树形递归(Tree Recursion) 线性递归(Linear Recursion)…...