基于springboot框架的电脑商城项目(四)

简介: 新增收货地址(一)新建数据库在store数据库中创建t_address表

新增收货地址

(一)新建数据库

在store数据库中创建t_address表

CREATE TABLE t_address (
  aid INT AUTO_INCREMENT COMMENT '收货地址id',
  uid INT COMMENT '归属的用户id',
  name VARCHAR(20) COMMENT '收货人姓名',
  province_name VARCHAR(15) COMMENT '省-名称',
  province_code CHAR(6) COMMENT '省-行政代号',
  city_name VARCHAR(15) COMMENT '市-名称',
  city_code CHAR(6) COMMENT '市-行政代号',
  area_name VARCHAR(15) COMMENT '区-名称',
  area_code CHAR(6) COMMENT '区-行政代号',
  zip CHAR(6) COMMENT '邮政编码',
  address VARCHAR(50) COMMENT '详细地址',
  phone VARCHAR(20) COMMENT '手机',
  tel VARCHAR(20) COMMENT '固话',
  tag VARCHAR(6) COMMENT '标签',
  is_default INT COMMENT '是否默认:0-不默认,1-默认',
  created_user VARCHAR(20) COMMENT '创建人',
  created_time DATETIME COMMENT '创建时间',
  modified_user VARCHAR(20) COMMENT '修改人',
  modified_time DATETIME COMMENT '修改时间',
  PRIMARY KEY (aid)
) ENGINE=INNODB DEFAULT CHARSET=utf8;

(二)收货地址实体类

在entity包下创建实体类Address继承baseEntity类

/**收货地址额实体类*/
public class Address extends BaseEntity {
    private Integer aid;
    private Integer uid;
    private String name;
    private String provinceName;
    private String provinceCode;
    private String cityName;
    private String cityCode;
    private String areaName;
    private String areaCode;
    private String zip;
    private String address;
    private String phone;
    private String tel;
    private String tag;
    private Integer isDefault;
 /**
 * get,set
 * equals和hashCode
 * toString
 */
}

(三)新增收货地址(持久层)

1.规划sql

1.新增收货地址对应的是插入语句:

insert into t_address (aid以外的所有字段) values (字段值)

2.大部分平台都会规定一个用户的收货地址数量,这里规定最多20个.那么在插入用户新的地址之前就要先做查询操作.如果查询到的是刚好20,这并不是一个java语法的异常,可以认为是业务控制的异常,这个异常随后在service抛,在controller捕获

select count(*) from t_address where uid=?

2.设计接口和抽象方法

创建接口AddressMapper,在这个接口中定义上面两个SQL语句抽象方法定义

public interface AddressMapper {
    //新增地址
    Integer insert(Address address);
//统计总地址
    Integer countByUid(Integer uid);
}

创建一个AddressMapper的映射文件,在这个文件中添加抽象方法映射到sql上

    <resultMap id="AddressEntityMap" type="com.cy.store.entity.Address">
        <id column="aid" property="aid"/>
        <result column="province_name" property="provinceName"/>
        <result column="province_code" property="provinceCode"/>
        <result column="city_name"   property="cityName"/>
        <result column="city_code" property="cityCode"/>
        <result column="area_name" property="areaName"/>
        <result column="area_code" property="areaCode"/>
        <result column="is_default" property="isDefault"/>
        <result column="created_user" property="createdUser"/>
        <result column="created_time" property="createdTime"/>
        <result column="modified_user" property="modifiedUser"/>
        <result column="modified_time" property="modifiedTime"/>
    </resultMap>
<insert id="insert" useGeneratedKeys="true" keyProperty="aid">
    INSERT INTO t_address (
        uid, name, province_name, province_code, city_name, city_code, area_name, area_code, zip,
        address, phone, tel,tag, is_default, created_user, created_time, modified_user, modified_time
    ) VALUES (
                 #{uid}, #{name}, #{provinceName}, #{provinceCode}, #{cityName}, #{cityCode}, #{areaName},
                 #{areaCode}, #{zip}, #{address}, #{phone}, #{tel}, #{tag}, #{isDefault}, #{createdUser},
                 #{createdTime}, #{modifiedUser}, #{modifiedTime}
             )
</insert>
<select id="countByUid" resultType="java.lang.Integer">
select count(*) from t_address where uid=#{uid}
</select>

(四)新增收货地址(业务层)

1.规划异常

插入数据时用户不存在(被管理员误删等等),抛UsernameNotFoundException异常(已经有了,不需要重复创建)

插入数据时产生未知的异常InsertException(已经有了,不需要重复创建)

当用户插入的地址是第一条时,需要将当前地址作为默认收货地址

实现办法:如果查询到统计总数为0则将当前地址的is_default值设置为1

如果查询的结果>=20,这时需要抛出业务控制的异常AddressCountLimitException

/**收货地址总数超出限制的异常(20条)*/
public class AddressCountLimitException extends ServiceException {
    /**重写ServiceException的所有构造方法*/
}

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

1.创建一个IAddressService接口,在接口中定义业务的抽象方法

public interface IAddressService {
    //新增收货地址
void addNewAddress(Integer uid,String username,Address address);
}

2.创建一个AddressServiceImpl类实现接口中抽象方法

//实现方法
@Service
public class AddressServiceImpl implements IAddressService {
    @Resource
    private AddressMapper addressMapper;
    @Resource
    private UserMapper userMapper;
    //在配置文件application.properties中定义user.address.max-count=20
    @Value("${user.address.max-count}")
    private Integer maxCount;
    @Override
    public void addNewAddress(Integer uid, String username, Address address) {
        Integer count = addressMapper.countByUid(uid);
        if (count>=maxCount){
            throw new AddressCountLimitException("收货地址大于20条");
        }
        User user = userMapper.findUid(uid);
        if (user==null || user.getIsDelete()==1){
            throw new UsernameNotFoundException("用户未登录");
        }
         address.setUid(uid);
        Integer isDefault=count==0?1:0;
        address.setIsDefault(isDefault);
        address.setCreatedTime(new Date());
        address.setModifiedUser(username);
        address.setModifiedTime(new Date());
        address.setCreatedUser(username);
            Integer insert = addressMapper.insert(address);
        if (insert!=1){
            throw new InsertException("添加地址有错误");
        }
    }
}

(五)新增收货地址(控制层)

1.处理异常

业务层抛出了收货地址总数超出上限的异常,在BaseController中进行捕获处理

else if (e instanceof AddressCountLimitException) {
    result.setState(4003);
    result.setMessage("用户的收货地址超出上限的异常");
}

2.设计请求

请求路径:/addresses/add_new_address

请求方式:post

请求参数:Address address,HttpSession session

响应结果:JsonResult< Void>

3.处理请求

在controller包下创建AddressController并继承BaseController,该类用来处理用户收货地址的请求和响应。

  @PostMapping("add_new_address")
    public JsonResult<Void> add(Address address, HttpSession session){
    Integer getuidfromsession = getuidfromsession(session);
    String getusernamesession = getusernamesession(session);
    addressService.addNewAddress(getuidfromsession,getusernamesession,address);
    return new JsonResult<>(ok);
}

(六)新增收货地址(前端页面)

        <script>
            $("#btn-add-new-address").click(function () {
                $.ajax({
                    url: "/addresses/add_new_address",
                    type: "POST",
                    data: $("#form-add-new-address").serialize(),
                    dataType: "JSON",
                    success: function (json) {
                        if (json.state == 200) {
                            alert("新增收货地址成功")
                        } else {
                            alert("新增收货地址失败")
                        }
                    },
                    error: function (xhr) {
                        alert("新增收货地址时产生未知的异常!"+xhr.message);
                    }
                });
            });
        </script>

获取省市区列表

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

(一)新建数据库

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;

parent代表父区域的代码号
code代表自身的代码号
省的父代码号是+86,代表中国

向该表中插入省市区数据

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

二)创建省市区的实体类

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

/**省市区的数据实体类*/
public class District implements Serializable {
    private Integer id;
    private String parent;
    private String code;
    private String name;
 /**
 * get,set
 * equals和hashCode
 * toString
 */
}


(三)获取省市区列表(持久层)

1.规划sql

select * from t_dict_district where parent=? order by ASC

2.设计接口和抽象方法

在mapper层下创建接口DistrictMapper

在这里插入代码片

(四)获取省市区列表(业务层)

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

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

public interface IDistrictService {
    /**
     * 根据父代码号来查询区域信息(省或市或区)
     * @param parent 父代码号
     * @return 多个区域的信息
     */
    List<District> getByParent(String parent);
}

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

@Service
public class DistrictServiceImpl implements IDistrictService {
    @Resource
    private DistrictMapper districtMapper;
    @Override
    public List<District> getByParent(String parent) {
        List<District> districtList = districtMapper.findByParent(parent);
        for (District d:
             districtList) {
            d.setParent(null);
            d.setId(null);
        }
        return districtList;
    }
}

(五)获取省市区列表(控制层)

1.设计请求

请求路径:/districts/

请求方式:GET

请求参数:String parent

响应结果:JsonResult<List< District>

2.处理请求

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

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

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

(六)获取省市区列表(前端页面)

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>

获取省市区名称

(一)获取省市区名称(持久层)

1.规划sql

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

select * from t_dict_district where code=?

2.设计接口和抽象方法

在DistrictMapper接口定义findNameByCode方法

    //根据当前code来获取当前省市区的名称,对应就是一条查询语句
    List<District> findNameByCode(String code);

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

    <select id="findNameByCode" resultType="java.lang.String">
select * from t_dict_district where code=#{code}
      </select>

(二)获取省市区名称(业务层)

1.规划异常

没有异常需要处理

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

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

//根据code查询
    String getNameByCode(String code);

2.在DistrictServiceImpl实现此方法

    @Override
    public String getNameByCode(String code) {
        String name = districtMapper.findNameByCode(code);
        return name;
    }

(三)获取省市区名称(控制层)

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

(四)获取省市区名称(业务层优化)

1.添加地址层依赖于IDistrictService层

@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);

(五)获取省市区名称(前端页面)

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

            /**因为清空后下拉列表的select标签没有option标签,所以需要设置一个默认的option标
             * 签并给市,县加上该标签.option标签并不会把内容发送到后端,而是将value值发
             * 送给后端,所以用value表示当前这个区域的code值
             * */
            var defaultOption="<option value='0'>-----请选择-----</option>";
            $(document).ready(function () {
                //加载省的数据罗列时代码量较多,建议定义在外部方法中,然后在这里调用定义的方法
                showProvinceList();
                //将省,市,县的下拉列表内容设为"-----请选择-----"
                /**
                 * select标签默认获取第一个option的内容填充到下拉列表中,所以即使加载
                 * 页面时省区域的下拉列表中已经有了所有省但仍然会显示-----请选择-----
                 * */
                $("#province-list").append(defaultOption);
                $("#city-list").append(defaultOption);
                $("#area-list").append(defaultOption);
            });
            //省的下拉列表数据展示
            function showProvinceList() {
                $.ajax({
                    url: "/districts",//发送请求用于获取所有省对象
                    type: "POST",
                    data: "parent=86",
                    dataType: "JSON",
                    success: function (json) {
                        if (json.state == 200) {
                            var list = json.data;//获取所有省对象的List集合
                            for (var i = 0; i < list.length; i++) {
                                var opt =
                                    "<option value='"+list[i].code+"'>"+list[i].name+"</option>";
                                $("#province-list").append(opt);
                            }
                        } else {
                            <!--这个其实永远不会执行,因为没有编写
                            异常,控制层返回的状态码永远是OK-->
                            alert("省/直辖区的信息加载失败")
                        }
                    }
                    //这里没有写属性error,不知道为啥不用写,感觉写了更好
                });
            }
            /**
             * change()函数用于监听某个控件是否发生改变,一旦发生改变就
             * 会触发参数形式的函数,所以参数需要是function(){}
             * */
            $("#province-list").change(function () {
                //先获取到省区域父代码号
                var parent = $("#province-list").val();
                /*
                 * 将市,县下拉列表的所有option清除并显示内容-----请选择-----
                 * empty()表示某标签的所有子标签(针对此页面来说select的子标
                 * 签只有option)
                 * */
                $("#city-list").empty();
                $("#area-list").empty();
                //填充默认值:-----请选择-----
                $("#city-list").append(defaultOption);
                $("#area-list").append(defaultOption);
                if (parent == 0) {//如果继续程序,后面的ajax接收的json数据中的data是
                    return;//空集合[],进不了for循环,没有任何意义,所以直接在这里终止程序
                }
                $.ajax({
                    url: "/districts",
                    type: "POST",
                    data: "parent="+parent,
                    dataType: "JSON",
                    success: function (json) {
                        if (json.state == 200) {
                            var list = json.data;
                            for (var i = 0; i < list.length; i++) {
                                var opt =
                                    "<option value='"+list[i].code+"'>"+list[i].name+"</option>";
                                $("#city-list").append(opt);
                            }
                        } else {
                            alert("市的信息加载失败")
                        }
                    }
                });
            });
            $("#city-list").change(function () {
                var parent = $("#city-list").val();
                $("#area-list").empty();
                $("#area-list").append(defaultOption);
                if (parent == 0) {
                    return;
                }
                $.ajax({
                    url: "/districts",
                    type: "POST",
                    data: "parent="+parent,
                    dataType: "JSON",
                    success: function (json) {
                        if (json.state == 200) {
                            var list = json.data;
                            for (var i = 0; i < list.length; i++) {
                                var opt =
                                    "<option value='"+list[i].code+"'>"+list[i].name+"</option>";
                                $("#area-list").append(opt);
                            }
                        } else {
                            alert("县的信息加载失败")
                        }
                    }
                });
            });


后记
👉👉💕💕美好的一天,到此结束,下次继续努力!欲知后续,请看下回分解,写作不易,感谢大家的支持!! 🌹🌹🌹

相关文章
|
2月前
|
搜索推荐 JavaScript Java
基于springboot的家具商城销售系统
在数字化转型背景下,传统家具销售面临挑战。本研究基于Java、MySQL、Vue和Spring Boot技术,构建高效、智能的家具商城销售系统,推动行业线上线下融合,提升用户体验与企业竞争力,助力家具产业可持续发展。
|
3月前
|
安全 Java Ruby
我尝试了所有后端框架 — — 这就是为什么只有 Spring Boot 幸存下来
作者回顾后端开发历程,指出多数框架在生产环境中难堪重负。相比之下,Spring Boot凭借内置安全、稳定扩展、完善生态和企业级支持,成为构建高可用系统的首选,真正经受住了时间与规模的考验。
292 2
|
2月前
|
安全 前端开发 Java
《深入理解Spring》:现代Java开发的核心框架
Spring自2003年诞生以来,已成为Java企业级开发的基石,凭借IoC、AOP、声明式编程等核心特性,极大简化了开发复杂度。本系列将深入解析Spring框架核心原理及Spring Boot、Cloud、Security等生态组件,助力开发者构建高效、可扩展的应用体系。(238字)
|
4月前
|
XML JSON Java
Spring框架中常见注解的使用规则与最佳实践
本文介绍了Spring框架中常见注解的使用规则与最佳实践,重点对比了URL参数与表单参数的区别,并详细说明了@RequestParam、@PathVariable、@RequestBody等注解的应用场景。同时通过表格和案例分析,帮助开发者正确选择参数绑定方式,避免常见误区,提升代码的可读性与安全性。
|
5月前
|
Java Spring
聊聊你对SpringBoot框架的理解 ?
SpringBoot是Spring家族中流行的子项目,旨在简化Spring框架开发的繁琐配置。它主要提供三大功能:starter起步依赖简化依赖管理,自动配置根据条件创建Bean,以及内嵌Web服务器支持Jar包运行,极大提升了开发效率。
178 0
|
2月前
|
消息中间件 缓存 Java
Spring框架优化:提高Java应用的性能与适应性
以上方法均旨在综合考虑Java Spring 应该程序设计原则, 数据库交互, 编码实践和系统架构布局等多角度因素, 旨在达到高效稳定运转目标同时也易于未来扩展.
143 8
|
3月前
|
监控 Kubernetes Cloud Native
Spring Batch 批处理框架技术详解与实践指南
本文档全面介绍 Spring Batch 批处理框架的核心架构、关键组件和实际应用场景。作为 Spring 生态系统中专门处理大规模数据批处理的框架,Spring Batch 为企业级批处理作业提供了可靠的解决方案。本文将深入探讨其作业流程、组件模型、错误处理机制、性能优化策略以及与现代云原生环境的集成方式,帮助开发者构建高效、稳定的批处理系统。
434 1
|
5月前
|
安全 Java 微服务
Java 最新技术和框架实操:涵盖 JDK 21 新特性与 Spring Security 6.x 安全框架搭建
本文系统整理了Java最新技术与主流框架实操内容,涵盖Java 17+新特性(如模式匹配、文本块、记录类)、Spring Boot 3微服务开发、响应式编程(WebFlux)、容器化部署(Docker+K8s)、测试与CI/CD实践,附完整代码示例和学习资源推荐,助你构建现代Java全栈开发能力。
616 0
|
4月前
|
Cloud Native Java API
Java Spring框架技术栈选和最新版本及发展史详解(截至2025年8月)-优雅草卓伊凡
Java Spring框架技术栈选和最新版本及发展史详解(截至2025年8月)-优雅草卓伊凡
849 0
|
5月前
|
缓存 安全 Java
第五章 Spring框架
Spring IOC(控制反转)通过工厂模式管理对象的创建与生命周期,DI(依赖注入)则让容器自动注入所需对象,降低耦合。常见注解如@Component、@Service用于声明Bean,@Autowired用于注入。Bean默认单例,作用域可通过@Scope配置,如prototype、request等。Spring通过三级缓存解决循环依赖问题,但构造函数循环依赖需用@Lazy延迟加载。AOP通过动态代理实现,用于日志、事务等公共逻辑。事务通过@Transactional实现,需注意异常处理及传播行为。
91 0

热门文章

最新文章