Project(8)——收货地址——增加 --- 省市区数据处理

Project(8)

1、分析项目

当需要开发某个项目时,首先,应该分析这个项目中,需要处理哪些种类的数据!例如:用户、商品、商品类别、收藏、订单、购物车、收货地址…

然后,将以上这些种类的数据的处理排个顺序,即先处理哪种数据,后处理哪种数据!通常,应该先处理基础数据,再处理所相关的数据,例如需要先处理商品数据,才可以处理订单数据,如果多种数据之间没有明显的关联,则应该先处理简单的,再处理较难的!

则以上这些数据的处理顺序应该是:用户 > 收货地址 > 商品类别 > 商品 > 收藏 > 购物车 > 订单

当确定了数据处理顺序后,就应该分析某个用户对应的功能有哪些,以“用户”数据为例,相关功能有:注册、登录、修改密码、修改资料、上传头像…

然后,还是需要确定以上功能的开发顺序,通常,遵循 “增 > 查 > 删 > 改” 的顺序,则以上功能的开发顺序应该是:注册 > 登录 > 修改密码 > 修改资料 > 上传头像。

每个功能的开发都应该遵循 创建数据表 > 创建实体类 > 持久层 > 业务层 > 控制器层 > 前端页面

一次只解决一个问题
大问题拆成小问题

2、用户 - 注册 - 创建数据表

3、用户 - 注册 - 创建实体类

4、用户 - 注册 - 持久层

a.规划SQL语句

b.接口与抽象方法

c.配置映射

5、用户 - 注册 - 业务层

业务层的基本定位

a.规划异常

b.接口与抽象方法

c.实现类与重写方法

6、用户 - 注册 - 控制器层

a.处理异常

b.设计请求

c.处理请求

7、用户 - 注册 - 前端页面

……

31、省市区数据 - 导入数据

全国大陆地区省市区MySQL数据(1)

全国大陆地区省市区MySQL数据(2)

登录 mysql 控制台,通过source 文件路径导入

32、创建实体类

创建cn.tedu.store.entity.District实体类,由于字典表的数据不会被修改,所以,表中并没有 4 个日志字段,则实体类中也不需要,则该实体类不需要继承自BaseEntity,但是,仍需要实现Serializable接口:


public class District implements Serializable {

	private static final long serialVersionUID = 1L;

	private Integer id;
	private String code;
	private String name;
	private String parent;
    
    // get/set    toString    hashCode & equals

33、省市区数据 - 获取列表 - 持久层

a.规划SQL语句

china中记录了全国所有的省、市、区的数据,如果需要查询全国所有的省,或某个省所有市,或某个市所有区,需要执行的SQL语句是一样的,不过参数不同而已:


select * from china where parent = ?

b.接口与抽象方法

创建cn.tedu.store.mapper.DistrictMapper接口,然后指定抽象方法:


    /**
	 * 根据父级代号获取 全国所有省、某省所有市、某市所有区 的列表
	 * @param parent 父级代号
	 * @return 全国所有省、某省所有市、某市所有区 的列表
	 */
	List<District> findByParent(String parent);

c.配置映射

复制得到DistrictMapper.xml文件,并配置以上抽象方法的映射:


<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- namespace:xml文件对应哪个接口 -->
<mapper namespace="cn.tedu.store.mapper.DistrictMapper">
    
    <!-- 根据父级代号获取 全国所有省、某省所有市、某市所有区 的列表 -->
    <!-- List<District> findByParent(String parent); -->
    <select id="findByParent" resultType="cn.tedu.store.entity.District">
        SELECT
            id, code, name, parent
        FROM
            t_dict_district
        WHERE
            parent=#{parent}
        ORDER BY
            id
    </select>
    
    
    
</mapper>

注意:如果查询的结果中包含多条数据,一定要显式地指定排序规则,如果没有指定,则实际获取的数据将是没有顺序的(可能绝大部分时候会表现为按照id排序,但事实上是根本没有顺序的!)

编写并执行单元测试:


@SpringBootTest
public class DistrictMapperTests {
	
	@Autowired
	private DistrictMapper mapper;
	
	@Test
	public void testFindByParent() {
		
		String parent = "0";
		List<District> list = mapper.findByParent(parent);
		
		System.err.println("begin:");
		
		for (District district : list) {
			System.err.println(district);
		}
		
		System.err.println("end");
		
	}
	
}

34、省市区数据 - 获取列表 - 业务层

a.规划异常

b.接口与抽象方法

创建cn.tedu.store.service.IDistrictService接口,并添加抽象方法:


    /**
	 * 根据父级代号获取 全国所有省、某省所有市、某市所有区 的列表
	 * @param parent 父级代号
	 * @return 全国所有省、某省所有市、某市所有区 的列表
	 */
	List<District> getByParent(String parent);

c.实现类与重写方法

创建cn.tedu.store.service.impl.DistrictServiceImpl业务层实现类,实现以上接口,添加@Service注解,并在类中添加持久层接口对象DistrictMapper districtMapper,并重写以上抽象方法。

复制DistrictMapper接口中的抽象方法,并私有化实现它:

    
    /**
	 * 根据父级代号获取 全国所有省、某省所有市、某市所有区 的列表
	 * @param parent 父级代号
	 * @return 全国所有省、某省所有市、某市所有区 的列表
	 */
	private List<District> findByParent(String parent){
	    return districtMapper.findByParent(parent);
	}
	

然后,重写接口中定义的抽象方法:


    /**
	 * 根据父级代号获取 全国所有省、某省所有市、某市所有区 的列表
	 * @param parent 父级代号
	 * @return 全国所有省、某省所有市、某市所有区 的列表
	 */
	public List<District> getByParent(String parent){
	    return findByParent(parent);
	}
	

src/test/java下创建cn.tedu.store.service.DistrictServiceTests测试类,编写并执行测试方法:


@SpringBootTest
public class DistrictServiceTests {
	
	@Autowired
	private IDistrictService service;
	
	@Test
	public void testGetByParent() {
		String parent = "0";
		List<District> list = service.getByParent(parent);
		
		System.err.println("Begin:");
		
		for(District district : list) {
			System.err.println(district);
		}
		System.err.println("共:" + list.size() + " 条数据");
		
		System.err.println("End.");
	}
}

35、省市区数据 - 获取列表 - 控制器层

a.处理异常

b.设计请求


请求路径:/districts/
请求参数:String parent
请求类型:get
响应数据:JsonResult<List<District>>
是否拦截:否,不拦截,需要在登录拦截器的配置中添加白名单


/**
 * 登录拦截器的配置类
 * @author DELL
 *
 */
public class LoginInterceptorConfigurer implements WebMvcConfigurer {
	
	@Override
	public void addInterceptors(InterceptorRegistry registry) {
		// 创建拦截器对象
		HandlerInterceptor interceptor = new LoginInterceptor();
		
		// 创建白名单
		List<String> excludePaths = new ArrayList<String>();
		excludePaths.add("/users/reg");
		excludePaths.add("/users/login");
		excludePaths.add("/web/register.html");
		excludePaths.add("/web/login.html");
		excludePaths.add("/bootstraps/**");
		excludePaths.add("/css/**");
		excludePaths.add("/images/**");
		excludePaths.add("/js/**");
		
		excludePaths.add("/districts/");   // ***新增的不拦截路径***
		
		// 注册拦截器类,并设置黑白名单
		registry.addInterceptor(interceptor).addPathPatterns("/**").excludePathPatterns(excludePaths);
		
	}	
}

c.处理请求

创建cn.tedu.store.controller.DistrictController控制器类,继承自BaseController,添加@RestController注解和@RequestMapping("districts")注解,在类中声明@Autowired private IDistrictService districtService业务层对象。

然后再控制器类中,添加处理请求的方法:


@RestController
@RequestMapping("districts")
public class DistrictController extends BaseController {
	
	@Autowired
	private IDistrictService districtService;
	
	@GetMapping("/")
	public JsonResult<List<District>> getByParent(String parent){
		List<District> data = districtService.getByParent(parent);
		return new JsonResult<List<District>>(SUCCESS, data);
	}
	
}

完成后,打开浏览器,输入http://localhost:8080/districts/?parent=0进行测试!

在这里插入图片描述

36、省市区数据 - 获取列表 - 前端页面

“省”相关:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


<script type="text/javascript">
	$(document).ready(function() {
		$("#btn-addnew").click(function() {
			addAddress();
		});
		
		showProvinceList();
		
	});
	
	function showProvinceList(){
		$.ajax({
			"url" : "/districts/",
			"data" : "parent=0",
			"type" : "get",
			"dataType" : "json",
			"success" : function(json) {
				var list = json.data;
				console.log("count = " + list.length);
				for (var i = 0; i < list.length; i++) {
					var op = '<option value="' + list[i].code + '">' + list[i].name + '</option>';
					$("#province-list").append(op);
				}
			}
		});
	}
	
	function addAddress(){
		$.ajax({
			"url" : "/addresses/addnew",
			"data" : $("#form-addnew").serialize(),
			"type" : "post",
			"dataType" : "json",
			"success" : function(json) {
				if (json.state == 2000) {
					alert("增加新地址成功!");
				} else {
					alert(json.message);
				}
			},
			"error" : function(){
				alert("您的登录信息已过期!请重新登录!");
			}
		});
	}
</script>

“市”相关:

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述


<script type="text/javascript">
	$(document).ready(function() {
		$("#btn-addnew").click(function() {
			addAddress();
		});
		
		showProvinceList();
		
		$("#province-list").change(function(){
			showCityList();
		});
		
	});
	
	function addAddress(){
		$.ajax({
			"url" : "/addresses/addnew",
			"data" : $("#form-addnew").serialize(),
			"type" : "post",
			"dataType" : "json",
			"success" : function(json) {
				if (json.state == 2000) {
					alert("增加新地址成功!");
				} else {
					alert(json.message);
				}
			},
			"error" : function(){
				alert("您的登录信息已过期!请重新登录!");
			}
		});
	}
	
	function showProvinceList(){
		// 自定义“---请选择---”选项,避免页面自动选择 省 却不显示 市 的情况
		var defaultOp = '<option value="-1">--- 请选择 ---</option>';
		$("#province-list").append(defaultOp);
		
		$.ajax({
			"url" : "/districts/",
			"data" : "parent=0",
			"type" : "get",
			"dataType" : "json",
			"success" : function(json) {
				var list = json.data;
				console.log("count = " + list.length);
				for (var i = 0; i < list.length; i++) {
					var op = '<option value="' + list[i].code + '">' + list[i].name + '</option>';
					$("#province-list").append(op);
				}
			}
		});
	}
	
	function showCityList(){
		// 每次改变 省 时,要先清空 市数据
		$("#city-list").empty();
		
		// 获取选择的 省 的代号
		var provinceCode = $("#province-list").val();
		// 如果为 -1 ,表示选中的是 “---请选择---”,此时直接 return,不再执行后续请求
		if(provinceCode == -1){
			return;
		}
		
		$.ajax({
			"url" : "/districts/",
			"data" : "parent=" + provinceCode,
			"type" : "get",
			"dataType" : "json",
			"success" : function(json) {
				var list = json.data;
				console.log("count = " + list.length);		
				for (var i = 0; i < list.length; i++) {
					var op = '<option value="' + list[i].code + '">' + list[i].name + '</option>';
					$("#city-list").append(op);
				}
			}
		});
	}
	
	
</script>

“区”相关:

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

优化1:

在这里插入图片描述
优化2:

在这里插入图片描述

总结:


<script type="text/javascript">
	$(document).ready(function() {
		$("#btn-addnew").click(function() {
			addAddress();
		});
		
		showProvinceList();
		
		$("#province-list").change(function(){
			showCityList();
			
			$("#area-list").empty();
			var defaultOp = '<option value="-1">--- 请选择 ---</option>';
			$("#area-list").append(defaultOp);
			
		});
		
		$("#city-list").change(function(){
			showAreaList();
		});
		
	});
	
	function addAddress(){
		$.ajax({
			"url" : "/addresses/addnew",
			"data" : $("#form-addnew").serialize(),
			"type" : "post",
			"dataType" : "json",
			"success" : function(json) {
				if (json.state == 2000) {
					alert("增加新地址成功!");
				} else {
					alert(json.message);
				}
			},
			"error" : function(){
				alert("您的登录信息已过期!请重新登录!");
			}
		});
	}
	
	function showProvinceList(){
		// 自定义“---请选择---”选项,避免页面自动选择 省 却不显示 市 的情况
		var defaultOp = '<option value="-1">--- 请选择 ---</option>';
		$("#province-list").append(defaultOp);
		$("#city-list").append(defaultOp);
		$("#area-list").append(defaultOp);
				
		$.ajax({
			"url" : "/districts/",
			"data" : "parent=0",
			"type" : "get",
			"dataType" : "json",
			"success" : function(json) {
				var list = json.data;
				console.log("count = " + list.length);
				for (var i = 0; i < list.length; i++) {
					var op = '<option value="' + list[i].code + '">' + list[i].name + '</option>';
					$("#province-list").append(op);
				}
			}
		});
	}
	
	function showCityList(){
		// 每次改变 省 时,要先清空 市数据
		$("#city-list").empty();
		
		// 市数据一清空,就显示  请选择 
		var defaultOp = '<option value="-1">--- 请选择 ---</option>';
		$("#city-list").append(defaultOp);
		
		
		// 获取选择的 省 的代号
		var provinceCode = $("#province-list").val();
		// 如果为 -1 ,表示选中的是 “---请选择---”,此时直接 return,不再执行后续请求
		if(provinceCode == -1){
			return;
		}
		
		$.ajax({
			"url" : "/districts/",
			"data" : "parent=" + provinceCode,
			"type" : "get",
			"dataType" : "json",
			"success" : function(json) {
				var list = json.data;
				console.log("count = " + list.length);		
				for (var i = 0; i < list.length; i++) {
					var op = '<option value="' + list[i].code + '">' + list[i].name + '</option>';
					$("#city-list").append(op);
				}
			}
		});
	}
	
	
	function showAreaList(){
		// 每次改变 市 时,要先清空 区数据
		$("#area-list").empty();
		
		// 区 数据清空,就显示 “请选择”
		var defaultOp = '<option value="-1">--- 请选择 ---</option>';
		$("#area-list").append(defaultOp);
		
		// 获取选择的 市 的代号
		var cityCode = $("#city-list").val();
		// 如果为 -1 ,表示选中的是 “---请选择---”,此时直接 return,不再执行后续请求
		if(cityCode == -1){
			return;
		}
		
		$.ajax({
			"url" : "/districts/",
			"data" : "parent=" + cityCode,
			"type" : "get",
			"dataType" : "json",
			"success" : function(json) {
				var list = json.data;
				console.log("count = " + list.length);		
				for (var i = 0; i < list.length; i++) {
					var op = '<option value="' + list[i].code + '">' + list[i].name + '</option>';
					$("#area-list").append(op);
				}
			}
		});
	}
	
	
</script>

37、省市区数据 - 补全数据

补全数据:

一:

DistrictMapper接口中添加新的抽象方法District findByCode(String code)

    
    /**
	 * 根据 code 查询地区信息
	 * @param code 省 / 市 / 区 的代号
	 * @return 地区信息
	 */
	District findByCode(String code);
	

DistrictMapper.xml配置文件中配置:


    <!-- 根据 code 查询地区信息 -->
    <!-- District findByCode(String code) -->
    <select id="findByCode" resultType="cn.tedu.store.entity.District">
        SELECT
            name
        FROM
            china
        WHERE
            code=#{code}
    </select>

DistrictMapperTests中编写并执行单元测试:


    /**
	 * 测试根据 code 查询地区信息
	 */
	@Test
	public void testFindByCode() {
		String code = "130000";
		District district = districtMapper.findByCode(code);
		System.err.println("district = " + district);
	}

二:

IDistrictService业务层接口中添加新抽象方法:


    /**
	 * 根据 code 查询地区信息
	 * @param code 
	 * @return 地区信息
	 */
	District getByCode(String code);

DistrictServiceImpl业务层实现类中重写以上添加的方法:


    @Override
	public District getByCode(String code) {
		return findByCode(code);
	}
	
	// ......
	// ......
	
    /**
	 * 根据 code 查询地区信息
	 * @param code 省 / 市 / 区 的代号
	 * @return 地区信息
	 */
	private District findByCode(String code) {
		return districtMapper.findByCode(code);
	}

DistrictServiceTests中编写并执行单元测试:


    @Test
	public void testGetByCode() {
		String code = "130000";
		District district = service.getByCode(code);
		System.err.println("district = " + district);
	}

三:

AddressServiceImpl中补全数据:province_name、city_name、area_name

要补全这三个数据,需要用到 District 类的 code 属性。

在这里插入图片描述
在这里插入图片描述


/**
 * 收货地址的业务层接口实现类
 * @author DELL
 *
 */
@Service
public class AddressServiceImpl implements IAddressService {
	
	// 一个 Service 实现类可以访问自己的 Mapper、别人的 Service,不能直接访问别人的 Mapper
	@Autowired
	private AddressMapper addressMapper;
	@Autowired
	private IDistrictService districtService;
	
	
	/**
	 * 新增收货地址
	 */
	@Override
	public void addnew(Integer uid, String username, Address address)
			throws AddressCountLimitException, InsertException {
		// 根据参数 uid 查询当前用户的收货地址数量
		// 判断收货地址数量是否达到上限值 ADDRESS_MAX_COUNT
		// 是 -- 抛出收货地址数量超过上限异常
		Integer count = addressMapper.countByUid(uid);
		if(count >= ADDRESS_MAX_COUNT) {
			throw new AddressCountLimitException("增加收货地址失败!收货地址数量已达上限!"
					+ "最多允许增加" + ADDRESS_MAX_COUNT + "条收货地址!");
		}
		
		// 补全数据 uid
		address.setUid(uid);
		
		// TODO 补全数据:province_name、city_name、area_name
		District province = districtService.getByCode(address.getProvinceCode());
		District city = districtService.getByCode(address.getCityCode());
		District area = districtService.getByCode(address.getAreaCode());
		if(province == null) {
			address.setProvinceCode(null); // 此处,将 未选择 时的值 -1 直接改为 null
		}else {
			address.setProvinceName(province.getName());
		}
		if(city == null) {
			address.setCityCode(null);
		}else {
			address.setCityName(city.getName());
		}
		if(area == null) {
			address.setAreaCode(null);
		}else {
			address.setAreaName(area.getName());
		}
		
		// 判断当前用户的收货地址数量是否为0,并决定 is_default 的值
		// 补全数据:is_default
		Integer isDefault = count == 0 ? 1 : 0;
		address.setIsDefault(isDefault);
		
		
		// 创建当前时间对象
		// 补全数据:4 个日志
		Date now = new Date();
		address.setCreatedUser(username);
		address.setCreatedTime(now);
		address.setModifiedUser(username);
		address.setModifiedTime(now);
		
		// 插入收货地址数据
		insert(address);
		
	}
	
	/**
	 * 新增收货地址
	 * @param address 地址数据对象
	 */
	private void insert(Address address) {
		Integer rows = addressMapper.insert(address);
		if(rows != 1) {
			throw new InsertException("增加收货地址失败!出现未知错误,请联系管理员!");
		}
	}
	
	/**
	 * 根据用户 uid 查询用户的收货地址数量
	 * @param uid 用户 uid
	 * @return 用户的收货地址数量
	 */
	private Integer countByUid(Integer uid) {
		return addressMapper.countByUid(uid);
	}
	

}

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值