新增收货地址【项目 商城】

该篇博客详细介绍了如何实现电商项目中的新增收货地址功能,包括数据表创建、实体类建立、持久层接口与SQL映射、业务层异常处理、控制器设计以及前端页面的交互测试。涉及到MyBatis、Spring Boot、异常处理和前端Ajax请求等多个技术点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

新增收货地址

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

1 新增收货地址-数据表创建

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;

t_address.sql


2 新增收货地址-创建实体类

创建一个类Address ,在类中对应表中的相关字段,采用驼峰命名方式。最后再去继承BaseEntity 类

**entity | Address **

package com.cy.store.entity;

import java.io.Serializable;
import java.util.Objects;

/** 收货地址数据的实体类 */
public class Address extends BaseEntity implements Serializable {
    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;

	//contructor get set equals hashcode toString 
	//ALT+INSert
	//..........

}

3 新增收货地址-持久层

3.1 各功能的开发顺序

当前的收货地址功能模块:列表的展示、修改、删除、设置默认、新增收货地址。
开发顺序:新增收货地址-列表展示-设置默认收货地址-删除-修改收货地址

3.2 规划需要执行的SQL语句

1.对应的是插入语句:

insert into t_address(除了adi外字段列表) values(字段值列表)

2.一个用户的收货地址规定最多只能有20条数据对应。
在插入用户数据之前先做查询操作。
收货地址逻辑控制方面的一个异常。超过20–异常

select count(*) from t_address where uid=?

3.3 接口与抽象方法

1.创建一个新的接口AddressMapper,在这个接口中来定义两个SQL语句抽象方法。

package com.cy.store.mapper;

import com.cy.store.entity.Address;

/** 收货地址持久层的接口*/
public interface AddressMapper {
    /**
     * 插入用户的收货地址数据
     * @param address 收货地址数据
     * @return 影响的行数
     */
    Integer insert(Address address);

    /**
     * 根据用户的id统计收货地址数量
     * @param uid 用户的id
     * @return 当前用户的收货地址总数
     */
    Integer countByUid(Integer uid);
}

3.4 配置SQL映射

创建一个AddressMapper.xml映射文件,在这个文件中添加抽象方法的映射SQL语句。

<?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">
<mapper namespace="com.cy.store.mapper.AddressMapper">
    <resultMap id="AddressEntityMap" type="com.cy.store.entity.Address">
        <id column="aid" property="aid"/>
        <result column="province_code" property="provinceCode"/>
        <result column="province_name" property="provinceName"/>
        <result column="city_code" property="cityCode"/>
        <result column="city_name" property="cityName"/>
        <result column="area_code" property="areaCode"/>
        <result column="area_name" property="areaName"/>
        <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>
</mapper>

AddressMapper


测试

2.在test下mapper下AddressMapperTests

package com.cy.store.mapper;

import com.cy.store.entity.Address;
import com.cy.store.entity.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.Date;

//@SpringBootTest:表示标注当前的类是测试类,不会随同项目一块打包
@SpringBootTest
//@RunWith:表示启动这个单元测试类(单元测试类是不能够运行的),需要传递一个参数,必须是SpringRunner的实例类型
//@RunWith(SpringRunner.class)
public class AddressMapperTests {

    @Autowired
    private AddressMapper addressMapper;
    @Test
    public void insert(){
        Address address=new Address();
        address.setUid(8);
        address.setPhone("17858802974");
        address.setName("女朋友");
        addressMapper.insert(address);
    }

    @Test
    public void countByUid(){
        Integer count = addressMapper.countByUid(8);
        System.out.println(count);
    }

}

AddressMapperTests–新增收货地址


4 新增收货地址-业务层

4.1 规划异常

如果用户是第一次插入用户的收货地址,规则:当用户插入的地址是第一条时,需要将第一条地址作为默认收货地址,如果查询的统计总数为0,则将当前的地址的is_default值设置为1。查询统计的结果为0不代表异常。查询到的结果大于20,这时候需要抛出业务控制的异常AddressCountLimitException异常。自行创建这个异常。

package com.cy.store.service.ex;

/* 收货地址数量达到上限的异常 */
public class AddressCountLimitException extends ServiceException{
    public AddressCountLimitException() {
        super();
    }

    public AddressCountLimitException(String message) {
        super(message);
    }

    public AddressCountLimitException(String message, Throwable cause) {
        super(message, cause);
    }

    public AddressCountLimitException(Throwable cause) {
        super(cause);
    }

    protected AddressCountLimitException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
        super(message, cause, enableSuppression, writableStackTrace);
    }
}

插入数据时产生的异常InsertException,不再需要重复创建。

4.2 接口与抽象方法

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

package com.cy.store.service;

import com.cy.store.entity.Address;

/**收货地址业务层的接口*/
public interface IAddressService {
    
    void addNewAddress(Integer uid,String username,Address address);
}

2.创建一个AddressServiceImpl实现类,去实现接口的抽象方法。
在配置文件中定义数据。

# Spring 读取配置文件的数据:@Value(${user.address.max-count})
user.address.max-count=20

在实现类中实现业务控制

    @Value("${user.address.max-count}")
    private Integer maxCount;

测试

3.测试业务层的过程是否正常。AddressServiceTests测试业务功能。

package com.cy.store.service;

import com.cy.store.entity.Address;
import com.cy.store.entity.User;
import com.cy.store.service.ex.ServiceException;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

//@SpringBootTest:表示标注当前的类是测试类,不会随同项目一块打包
@SpringBootTest
//@RunWith:表示启动这个单元测试类(单元测试类是不能够运行的),需要传递一个参数,必须是SpringRunner的实例类型
//@RunWith(SpringRunner.class)
public class AddressServiceTests {

    @Autowired
    private IAddressService addressService;


    @Test
    public void addNewAddress(){
        Address address=new Address();
        address.setUid(8);
        address.setPhone("17858809999");
        address.setName("女朋友");
        addressService.addNewAddress(8,"管理员",address);
    }


}

AddressServiceTests–addNewAddress


5 新增收货地址-控制器

5.1 处理异常

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

package com.cy.store.controller;

import com.cy.store.controller.ex.*;
import com.cy.store.service.ex.*;
import com.cy.store.util.JsonResult;
import org.springframework.web.bind.annotation.ExceptionHandler;

import javax.servlet.http.HttpSession;

/**
 * 控制层类的基类
 */
public class BaseController {
    /**操作成功的状态码 */
    public static final int OK=200;

    //请求处理方法,这个方法的返回值就是需要传递给前端的数据
    //自动将异常对象传递给此方法的参数列表上
    //当前项目中产生的异常会被拦截到此方法中,这个方法此时充当的是请求处理方法,方法的返回值直接给前端
    @ExceptionHandler({ServiceException.class,FileUploadException.class})//用于统一处理抛出的异常
    public JsonResult<Void> handleException(Throwable e){
        JsonResult<Void> result=new JsonResult<>(e);
        if (e instanceof UsernameDuplicatedException){
            result.setState(4000);
            result.setMessage("用户名已经被占用的异常");
        }else if (e instanceof UserNotFoundException){
            result.setState(4001);
            result.setMessage("用户数据不存在的异常");
        }else if (e instanceof PasswordNotMatchException){
            result.setState(4002);
            result.setMessage("用户密码错误的异常");
        }else if (e instanceof AddressCountLimitException){
            result.setState(4003);
            result.setMessage("用户的收货地址超出上限异常");
        }
        else if (e instanceof InsertException){
            result.setState(5000);
            result.setMessage("插入数据时产生未知的异常");
        }else if (e instanceof UpdateException){
            result.setState(5001);
            result.setMessage("更新数据时产生未知的异常");
        }else if (e instanceof FileEmptyException) {
            result.setState(6000);
        } else if (e instanceof FileSizeException) {
            result.setState(6001);
        } else if (e instanceof FileTypeException) {
            result.setState(6002);
        } else if (e instanceof FileStateException) {
            result.setState(6003);
        } else if (e instanceof FileUploadIOException) {
            result.setState(6004);
        }
        return result;

    }

    /**
     * 获取session对象的uid
     * @param session session对象
     * @return 当前登录得到用户uid的值
     */
    protected final Integer getuidFromSession(HttpSession session){
        return Integer.valueOf(session.getAttribute("uid").toString());
    }

    /**
     * 获取session对象的username
     * @param session session对象
     * @return 当前登录得到用户username的值
     *
     * 在实现类中重写了父类中的toString()方法,不是句柄信息的输出@xxx
     */
    protected final String getUsernameFromSession(HttpSession session){
        return session.getAttribute("username").toString();
    }
}

BaseController–AddressCountLimitException


5.2 设计请求

/address/add_new_address
post
Address address,HttpSession session
JsonResult<Void>

5.3 处理请求

在控制层创建AddressController来处理用户收货地址的请求和响应。

package com.cy.store.controller;

import com.cy.store.entity.Address;
import com.cy.store.service.IAddressService;
import com.cy.store.util.JsonResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpSession;

@RequestMapping("address")
@RestController
public class AddressController extends BaseController{

    @Autowired
    private IAddressService addressService;

    @RequestMapping("add_new_address")
    public JsonResult<Void> addNewAddress(Address address, HttpSession session) {
        Integer uid =getuidFromSession(session);
        String username=getUsernameFromSession(session);
        addressService.addNewAddress(uid,username,address);
        return new JsonResult<>(OK);
    }
}

AddressController–addNewAddress


测试

先登录用户,再进行测试
http://localhost:8080/address/add_new_address?name=tom&phone=17858802222
在这里插入图片描述

6 新增收货地址-前端页面

addAddress.html

		<script type="text/javascript">
			$("#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("新增收货地址成功!");
							location.href = "address.html";
						} else {
							alert("新增收货地址失败!" + json.message);
						}
					},
					error: function(xhr) {
						alert("您的登录信息已经过期,请重新登录!HTTP响应码:" + xhr.status);
						location.href = "login.html";
					}
				});
			});
		</script>

addAddress–add_new_address


测试

README–新增收货地址

### 微信小程序中实现收货地址管理和新增地址功能 #### 地址管理概述 在微信小程序项目2.0版本中,为了提升用户体验并简化操作流程,将原有的固定个人信息模块进行了优化升级。通过创建专门的地址管理页面,用户可以方便地进行地址的选择、编辑以及删除等操作[^1]。 #### 页面设计与布局 对于地址列表展示部分,在界面上通常会采用卡片式的样式来呈现每一个具体的地址条目;而对于添加新地址或者修改已有记录,则可以通过弹窗的形式提供表单让用户输入必要的信息字段如姓名、电话号码、所在地区及详细住址等内容。 #### 数据存储方式 考虑到数据的安全性和隐私保护需求,所有涉及用户的敏感资料都应遵循严格的加密措施保存于服务器端数据库之中,并仅允许经过身份验证后的合法请求访问读取这些资源。当客户端发起同步更新指令时(比如提交新的送货位置),则需按照既定协议向后台发送POST请求携带相应参数完成最终的数据写入动作。 #### 关键API调用说明 - **chooseAddress()**: 能够唤起原生组件供顾客挑选已存档过的联系人作为默认配送目标; - **addCard() / openSetting({type:"address"})**: 对于初次使用的场景下引导授权地理位置权限以便后续正常运作; - **wx.request()**: 发送HTTP(S)网络请求至指定接口用于处理各类业务逻辑交互过程中的异步通信任务[^2]。 ```javascript // 示例代码片段:获取用户当前位置坐标点经纬度值 const getLocation = () => { wx.getLocation({ type: 'wgs84', success(res){ console.log(`经度:${res.longitude},纬度:${res.latitude}`); }, fail(err){console.error('定位失败',err);} }); } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

日星月云

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值