在写业务之前,需要创建收货地址的表
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✌