基于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("县的信息加载失败")
                        }
                    }
                });
            });


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

相关文章
|
18天前
|
XML 安全 Java
|
21天前
|
缓存 NoSQL Java
什么是缓存?如何在 Spring Boot 中使用缓存框架
什么是缓存?如何在 Spring Boot 中使用缓存框架
28 0
|
1月前
|
数据采集 监控 前端开发
二级公立医院绩效考核系统源码,B/S架构,前后端分别基于Spring Boot和Avue框架
医院绩效管理系统通过与HIS系统的无缝对接,实现数据网络化采集、评价结果透明化管理及奖金分配自动化生成。系统涵盖科室和个人绩效考核、医疗质量考核、数据采集、绩效工资核算、收支核算、工作量统计、单项奖惩等功能,提升绩效评估的全面性、准确性和公正性。技术栈采用B/S架构,前后端分别基于Spring Boot和Avue框架。
|
4天前
|
IDE Java 测试技术
互联网应用主流框架整合之Spring Boot开发
通过本文的介绍,我们详细探讨了Spring Boot开发的核心概念和实践方法,包括项目结构、数据访问层、服务层、控制层、配置管理、单元测试以及部署与运行。Spring Boot通过简化配置和强大的生态系统,使得互联网应用的开发更加高效和可靠。希望本文能够帮助开发者快速掌握Spring Boot,并在实际项目中灵活应用。
23 5
|
14天前
|
缓存 Java 数据库连接
Spring框架中的事件机制:深入理解与实践
Spring框架是一个广泛使用的Java企业级应用框架,提供了依赖注入、面向切面编程(AOP)、事务管理、Web应用程序开发等一系列功能。在Spring框架中,事件机制是一种重要的通信方式,它允许不同组件之间进行松耦合的通信,提高了应用程序的可维护性和可扩展性。本文将深入探讨Spring框架中的事件机制,包括不同类型的事件、底层原理、应用实践以及优缺点。
46 8
|
24天前
|
存储 Java 关系型数据库
在Spring Boot中整合Seata框架实现分布式事务
可以在 Spring Boot 中成功整合 Seata 框架,实现分布式事务的管理和处理。在实际应用中,还需要根据具体的业务需求和技术架构进行进一步的优化和调整。同时,要注意处理各种可能出现的问题,以保障分布式事务的顺利执行。
44 6
|
29天前
|
Java 数据库连接 数据库
不可不知道的Spring 框架七大模块
Spring框架是一个全面的Java企业级应用开发框架,其核心容器模块为其他模块提供基础支持,包括Beans、Core、Context和SpEL四大子模块;数据访问及集成模块支持数据库操作,涵盖JDBC、ORM、OXM、JMS和Transactions;Web模块则专注于Web应用,提供Servlet、WebSocket等功能;此外,还包括AOP、Aspects、Instrumentation、Messaging和Test等辅助模块,共同构建强大的企业级应用解决方案。
51 2
|
1月前
|
JavaScript 安全 Java
如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个前后端分离的应用框架,实现动态路由和菜单功能
本文介绍了如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个前后端分离的应用框架,实现动态路由和菜单功能。首先,确保开发环境已安装必要的工具,然后创建并配置 Spring Boot 项目,包括添加依赖和配置 Spring Security。接着,创建后端 API 和前端项目,配置动态路由和菜单。最后,运行项目并分享实践心得,帮助开发者提高开发效率和应用的可维护性。
80 2
|
1月前
|
消息中间件 NoSQL Java
springboot整合常用中间件框架案例
该项目是Spring Boot集成整合案例,涵盖多种中间件的使用示例,每个案例项目使用最小依赖,便于直接应用到自己的项目中。包括MyBatis、Redis、MongoDB、MQ、ES等的整合示例。
109 1
|
28天前
|
Java Kotlin 索引
学习Spring框架特性及jiar包下载
Spring 5作为最新版本,更新了JDK基线至8,修订了核心框架,增强了反射和接口功能,支持响应式编程及Kotlin语言,引入了函数式Web框架,并提升了测试功能。Spring框架可在其官网下载,包括文档、jar包和XML Schema文档,适用于Java SE和Java EE项目。
31 0
下一篇
DataWorks