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

news2025/1/15 20:40:10

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 {

    @Autowired
    private DistrictMapper districtMapper;
    
    @Test
    public 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 {


    @Autowired
    private DistrictMapper districtMapper;

    /**
     * 根据父代号查找区域
     *
     * @param parent
     * @return
     */
    @Override
    public 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 {
    @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.控制层[Controller]

1 设计请求 

  • /districts/
  • GET
  • String parent
  • JsonResult<List<District>>

2 处理请求

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

@RequestMapping("/district")
@RestController
public class DistrictController extends BaseController{

    @Autowired
    private 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>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/980839.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

多链路自检与灵活组网:新能源充电桩物联网5G工业路由器

随着环保新能源技术的迅猛发展&#xff0c;新能源车主对充电桩的需求量也日益增加。为了更好地管理这些新能源充电桩并实现远程监控和维护&#xff0c;新能源充电桩物联网应用需求应运而生。新能源充电桩物联网基于5G工业路由器的实现数据安全传输与实时在线监控、远程管理维护…

基于ubuntu tun虚拟网卡设备完成ping的发送与模拟接收

前言 前面我们初步认识了什么是tun设备及基础的工作原理与接收文件的设备文件&#xff08;节点&#xff09;、虚拟网卡的启动、添加路由表等操作&#xff0c;为什么进一步理解tun设备与协议栈的通信理解&#xff0c;这次我们将应用层控制tun设备发送ping&#xff0c;通过read读…

【AI绘画--七夕篇】使用Stable Diffusion的艺术二维码完全生成攻略

文章目录 前言Stable Diffusion 简介 什么是云端平台&#xff1f;优势灵活性和可扩展性成本效益高可用性和容错性管理简便性 选择适合的云端平台 平台优势平台操作购买算力并创建工作空间启动工作空间应用市场一键安装 使用Stable-Diffusion作图使用控制网络将文本转图像二维码…

【业务功能篇98】微服务-springcloud-springboot-电商订单模块-生成订单服务-锁定库存

八、生成订单 一个是需要生成订单信息一个是需要生成订单项信息。具体的核心代码为 /*** 创建订单的方法* param vo* return*/private OrderCreateTO createOrder(OrderSubmitVO vo) {OrderCreateTO createTO new OrderCreateTO();// 创建订单OrderEntity orderEntity build…

SpringMVC中的综合案例

目录 一.常用注解 实例&#xff1a; 二.参数转递 2.1. 基础类型 2.2. 复杂类型 2.3. RequestParam 2.4.PathVariable 2.5.RequestBody 2.6.RequestHeader 2.7. 请求方法 三.返回值 3.1.void 3.2.String 3.3 StringModel 3.4 ModelAndView 四、页面跳转 4.1.转发 4.…

zk羊群效应怎么处理

什么是zk的羊群效应 如下图&#xff0c;如果第一个锁挂了&#xff0c;其他客户端又全监听的它&#xff0c;如果几十上百个&#xff0c;之个锁挂了还得去一个个通知&#xff0c;我挂了&#xff0c;你们又要重新加锁&#xff0c;全又监听。会引起多余的请求与网络开销。 如果这个…

虚拟机的ubuntu 22.04无法联网问题解决

问题&#xff1a;虚拟机的ubuntu 22.04无法联网 解决&#xff1a; 找到一种配置的方式&#xff0c;使用命令&#xff1a;sudo dhclient -v

MIT的智慧,利用深度学习来解决了交通堵塞

导读大家都对交通阻塞深恶痛绝。除了让人头疼和错过约会之外&#xff0c;交通拥堵让美国的司机每年多花3000亿美元。 研究人员建议大家使用自动驾驶汽车&#xff0c;即使数量占比并不大&#xff0c;但也能大大改善交通拥堵情况。 Lex Fridman和他的MIT团队开发了一款模拟游戏来…

SpringBoot环境MongoDB分页+去重+获取去重后的原始数据

最近有个比较复杂的MongoDB查询需求&#xff0c; 要求1&#xff1a;获取最近订单表中的请求参数信息&#xff0c;并需要按照请求参数中的账号进行去重 要求2&#xff1a;数据量可能比较大&#xff0c;因此需要做分页查询 研究了大半天&#xff0c;终于搞出了解决方案&#xff0…

使用 Python 的高效相机流

一、说明 让我们谈谈在Python中使用网络摄像头。我有一个简单的任务&#xff0c;从相机读取帧&#xff0c;并在每一帧上运行神经网络。对于一个特定的网络摄像头&#xff0c;我在设置目标 fps 时遇到了问题&#xff08;正如我现在所理解的——因为相机可以用 mjpeg 格式运行 30…

手写Spring:第6章-资源加载器解析文件注册对象

文章目录 一、目标&#xff1a;资源加载器解析文件注册对象二、设计&#xff1a;资源加载器解析文件注册对象三、实现&#xff1a;资源加载器解析文件注册对象3.1 工程结构3.2 资源加载器解析文件注册对象类图3.3 类工具类3.4 资源加载接口定义和实现3.4.1 定义资源加载接口3.4…

面试算法-常用数据结构

文章目录 数据结构数组链表 栈队列双端队列树 1&#xff09;算法和数据结构 2&#xff09;判断候选人的标准 算法能力能够准确辨别一个程序员的功底是否扎实 数据结构 数组 链表 优点&#xff1a; 1&#xff09;O(1)时间删除或者添加 灵活分配内存空间 缺点&#xff1a; 2&…

把文件上传到Gitee的详细步骤

目录 第一步&#xff1a;创建一个空仓库 第二步&#xff1a;找到你想上传的文件所在的地址&#xff0c;打开命令窗口&#xff0c;git init 第三步&#xff1a;git add 想上传的文件 &#xff0c;git commit -m "给这次提交取个名字" 第四步&#xff1a;和咱们在第…

生成多样、真实的评论(2019 IEEE International Conference on Big Data )

论文题目&#xff08;Title&#xff09;&#xff1a;Learning to Generate Diverse and Authentic Reviews via an Encoder-Decoder Model with Transformer and GRU 研究问题&#xff08;Question&#xff09;&#xff1a;评论生成&#xff0c;由上下文评论->生成评论 研…

Android之“写死”数据

何为“写死”&#xff0c;即写完之后除非手动修改&#xff0c;否像嘎了一样在那固定死了 在实际安卓开发中&#xff0c;这种写死的概念必不可少&#xff0c;如控件的id&#xff0c;某一常量&#xff0c;Kotlin中的Val 当然&#xff0c;有些需求可能也会要求我们去写死数据&am…

实战:大数据Flink CDC同步Mysql数据到ElasticSearch

文章目录 前言知识积累CDC简介CDC的种类常见的CDC方案比较 Springboot接入Flink CDC环境准备项目搭建 本地运行集群运行将项目打包将包传入集群启动远程将包部署到flink集群 写在最后 前言 前面的博文我们分享了大数据分布式流处理计算框架Flink和其基础环境的搭建&#xff0c…

入门力扣自学笔记279 C++ (题目编号:1123)

1123. 最深叶节点的最近公共祖先 题目&#xff1a; 给你一个有根节点 root 的二叉树&#xff0c;返回它 最深的叶节点的最近公共祖先 。 回想一下&#xff1a; 叶节点 是二叉树中没有子节点的节点树的根节点的 深度 为 0&#xff0c;如果某一节点的深度为 d&#xff0c;那它…

PyCharm中使用matplotlib.pyplot.show()报错MatplotlibDeprecationWarning的解决方案

其实这只是一个警告&#xff0c;忽略也可。 一、控制台输出 MatplotlibDeprecationWarning: Support for FigureCanvases without a required_interactive_framework attribute was deprecated in Matplotlib 3.6 and will be removed two minor releases later. MatplotlibD…

iOS 17中的Safari配置文件改变了游戏规则,那么如何设置呢

Safari在iOS 17中最大的升级是浏览配置文件——能够在一个应用程序中创建单独的选项卡和书签组。这些也可以跟随你的iPad和Mac&#xff0c;但在本指南中&#xff0c;我们将向你展示如何使用运行iOS 17的iPhone。 你可能有点困惑&#xff0c;为什么Safari中没有明显的位置可以添…

Power BI的发布到web按钮怎么没有?有人知道怎么办吗??????

Power BI的发布到web按钮怎么没有&#xff1f;有人知道怎么办吗&#xff1f;&#xff1f;&#xff1f;&#xff1f;&#xff1f; .