SpringBoot电脑商城项目--新增收获地址

在写业务之前,需要创建收货地址的表

sql 复制代码
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;

创建收货地址实体类

java 复制代码
package com.cy.store.entity;


import lombok.Data;

/**收货地址额实体类*/
@Data
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;

}

1. 新增收货地址-持久层

1.1 各功能的开发顺序

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

1.2 编写sql语句

  • 新增插入语句
  • 一个用户的收货地址规定最多只能有20条数据对应,在插入用户数据之前先做查询操作。收获地址逻辑控制方面捕获一个异常

1.3 接口和方法

创建一个新的接口Address,在这个接口中来定义上面两个sql语句抽象方法定义。

java 复制代码
import com.cy.store.entity.Address;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface AddressMapper {
    /**
     * 插入用户的收货地址数据
     * @param address
     * @return
     */
    Integer insert(Address address);
    
    /**
     * 根据用户id查询收货地址数据
     * @param uid
     * @return
     */
    Integer countByUid(Integer uid);
}

1.4 配置sql映射

在AddressMapper.xml中定义

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:用于指定当前的映射文件和哪个接口进行映射,需要指定接口的文件路径 -->
<mapper namespace="com.cy.store.mapper.AddressMapper">

    <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>

    <!-- useGeneratedKeys:设置是否使用JDBC的getGeneratedKeys方法来获取数据库自动生成的主键 -->
    <!-- keyProperty:指定自增的字段 为 uid  -->
    <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>
<!--    查询收货地址的总数
    resultType="java.lang.Integer" 是 MyBatis 框架中的一个属性,通常用于指定 SQL 映射语句的返回值类型。
        resultType:MyBatis 中的一个属性,用于指定 SQL 查询结果映射的目标类型。
        java.lang.Integer:表示该 SQL 查询返回的是一个整数类型的值。-->
    <select id="countByUid" resultType="java.lang.Integer">
        SELECT COUNT(*) FROM t_address WHERE uid=#{uid}
    </select>
</mapper>

1.5 在AddressMapper层进行测试

java 复制代码
package com.cy.store.mapper;

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

@SpringBootTest
class AddressMapperTest {
    @Autowired
    private AddressMapper addressMapper;

    @Test
    void insert() {
        Address address = new Address();
        address.setUid(1);
        address.setProvinceName("广东省");
        address.setCityName("深圳市");
        address.setAreaName("宝安区");
        address.setAddress("深圳宝安");
        address.setZip("518000");
        address.setPhone("12345678901");
        address.setTel("010");
        address.setTag("家");
        address.setName("女朋友");
        int rows = addressMapper.insert(address);
    }

    @Test
    void countByUid() {
        Integer integer = addressMapper.countByUid(1);
        System.out.println(integer);
    }
}

2. 新增收货地址-业务层

2.1 规划异常

如果用户是第一插入用户的收获地址,规则:

  • 当用户插入的地址是第一条时,需要将当前地址作为默认的收获地址,如果查询到统计总数为0,则当前地址的is_default值设置为1,但不代表异常
  • 当查询到的结果大于20时,这时候需要抛出业务控制层的异常AddressCountLimitException异常
  • 插入数据时产生未知的异常,不需要重复创建
java 复制代码
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);
    }
}

2.2 接口与抽象方法

  • 创建AddressService接口,在接口中定义抽象方法
java 复制代码
import com.cy.store.entity.Address;

public interface AddressService {
    /**
     * 添加用户地址
     * @param uid 用户id
     * @param username 用户名
     * @param address 用户地址数据
     */
    void addNewAddress(Integer uid, String username, Address address);
    
}
  • 创建一个AddressServiceImpl实现类,去实现接口中抽象方法

为了代码的严谨性,在yml配置类中自主定义收获地址的最大上限

java 复制代码
# Spring读取配置文件中的数据:${user.address.max-count}
# 手动封装收货地址的最大限制为 20
user:
  address:
    max-count: 20

业务层进行业务处理时,通过注解**@Value("${user.address.max-count}")**进行引入

java 复制代码
import com.cy.store.entity.Address;
import com.cy.store.mapper.AddressMapper;
import com.cy.store.service.AddressService;
import com.cy.store.service.ex.AddressCountLimitException;
import com.cy.store.service.ex.InsertException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.Date;

@Service
public class AddressServiceImpl implements AddressService {
//    依赖注入
    @Autowired
    private AddressMapper addressMapper;

//    获取配置文件中设置的默认收货地址数量上限
    @Value("${user.address.max-count}")
    private Integer maxCount;

    /**
     * 添加用户的收货地址
     * @param uid 用户id
     * @param username 用户名
     * @param address 收货地址数据
     */
    @Override
    public void addNewAddress(Integer uid, String username, Address address) {
        Integer count = addressMapper.countByUid(uid);
        if (count>=maxCount){
            throw new AddressCountLimitException("用户收货地址超出上限");
        }
//        补全 数据
        address.setUid(uid);
//        1 表示默认地址 0表示非默认
        Integer isDefault = count==0?1:0;
        address.setIsDefault(isDefault);
        address.setCreatedUser( username);
        address.setModifiedUser(username);
        address.setCreatedTime(new Date());
        address.setModifiedTime(new Date());
        Integer rows = addressMapper.insert(address);
        if (rows!=1){
            throw new InsertException("插入收货地址数据时产生未知的异常");
        }

    }
}
  • 测试业务层功能是否正常
java 复制代码
package com.cy.store.service;

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


@SpringBootTest
class AddressServiceTest {
    @Autowired
    private AddressService addressService;

    @Test
    void addNewAddress() {
        Address address = new Address();
        address.setPhone("12345678901");
        address.setName("对象");
        addressService.addNewAddress(1,"admin",address);
    }
}

3. 新增收货地址-控制层

3.1 异常处理

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

java 复制代码
 @ExceptionHandler({ServiceException.class, FileUploadException.class})
    public JsonResult<Void> handleException(Throwable e) {
        // 创建一个 JsonResult 实例,并初始化异常消息
        JsonResult<Void> result = new JsonResult<>(e);

        // 判断异常类型,设置对应的状态码和提示信息
        if (e instanceof UsernameDuplicatedException){
            // 用户名被占用时返回 400 状态码和相应提示
            result.setState(4000);
            result.setMessage("用户名被占用");
        } else if (e instanceof InsertException){
            // 插入数据失败时返回 500 状态码和相应提示
            result.setState(4000);
            result.setMessage("注册时产生未知的异常");
        }else if (e instanceof UsernameNotFoundException){
            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 UpdateException){
            result.setState(5003);
            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;
    }

3.2 请求

addresses/addNewAddress

POST

Address address,HttpSession session

JsonResult<Void>

3.3 controller处理请求

AddressController层处理请求,编写业务代码

java 复制代码
import com.cy.store.entity.Address;
import com.cy.store.service.AddressService;
import com.cy.store.util.JsonResult;
import jakarta.servlet.http.HttpSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/addresses")
public class AddressController extends BaseController{
    @Autowired
    private AddressService addressService;

    @RequestMapping("addNewAddress")
    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);
    }

}

3.4 进行测试

先启动项目,登录页面进行登录,在通过网址进行请求

4. 新增收货地址-前端页面

addAddress.html页面

javascript 复制代码
<script type="text/javascript">
			<!--		监听按钮是否被点击,如果被点击,触发函数		-->
			$("#btn-add-new-address").click(function () {
				//	ajax发送请求
				$.ajax({
					url: "/addresses/addNewAddress",
					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>

重启项目进行业务测试就ok✌

相关推荐
2201_7531694726 分钟前
implement用法
java·开发语言
昵称为空C42 分钟前
meilisearch全文检索elasticsearch的平替,应用于中小型项目足矣
后端·搜索引擎
不会编程的阿成1 小时前
spring aop的概念与实战以及面试项目题
java·spring·面试
天上掉下来个程小白1 小时前
Apache ECharts-01.介绍
前端·javascript·spring boot·apache·苍穹外卖
李强57627821 小时前
语法制导的语义计算(包含python源码)
java·数据库·python
鼠鼠我捏,要死了捏1 小时前
Java开发企业微信会话存档功能笔记小结(企业内部开发角度)
java·企业微信·会话存档
wx_ywyy67981 小时前
“微信短剧小程序开发指南:从架构设计到上线“
java·python·短剧·短剧系统·海外短剧·推客小程序·短剧系统开发
汪子熙1 小时前
深入探秘 npm install 背后的 Node.exe npm-cli.js 机制
后端
二闹2 小时前
为啥需要一把Anaconda"瑞士军刀"?
后端·python
缘友一世2 小时前
设计模式之五大设计原则(SOLID原则)浅谈
java·算法·设计模式