当前位置: 首页 > news >正文

SpringBoot项目--电脑商城【新增收货地址】

1.新增收货地址

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;

注意name是关键字,所以需要用``

2.创建收货地址的实体类

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

/*** 收货地址的实体类*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Address extends BaseEntity {private Integer aid;//收货地址idprivate Integer uid;//归属用户idprivate 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;//是否默认  0-不默认,1-默认
}

3.持久层[Mapper]

1 各功能的开发顺序

当前收货地址功能模块:

  • 第一个页面:列表的展示,修改,删除,设置默认
  • 第二个页面:新增收货地址

开发顺序:新增收货地址->列表的展示->设置默认收货地址->删除收货地址->修改收货地址

2 需要规划要执行的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 {/*** 插入用户的收货地址数据** @param address 收货地址* @return 受影响的行数*/Integer insertAddress(Address address);/*** 获取收货地址的数量(不能超过20),根据用户的uid** @param uid 用户uid* @return 收货地址数量*/Integer countAddress(Integer uid);
}

3.编写映射

1.在mapper标签中配置Address类属性与数据库中表的字段映射

    <resultMap id="AddressEntityMap" type="com.example.mycomputerstore.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>

判断该映射是否配置成功:按着ctrl并点击type="com.cy.store.entity.Address"中的Address,如果能跳转到Address类说明映射成功

2.在AddressMapper.xml中配置以上两个抽象方法的映射

    <insert id = "insertAddress" 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="countAddress" resultType="java.lang.Integer">SELECT count(*) FROM t_address WHERE uid = #{uid}</select>

4.单元测试

@SpringBootTest
@RunWith(SpringRunner.class)
public class AddressMapperTests {@Autowiredprivate AddressMapper addressMapper;@Testpublic void insert() {Address address = new Address();address.setUid(11);address.setPhone("133336");address.setName("女朋友");addressMapper.insert(address);}@Testpublic void countByUid() {Integer count = addressMapper.countByUid(11);System.out.println(count);}
}

4.业务层[service]

1. 规划异常

  • 插入数据时用户不存在(被管理员误删等等),抛UsernameNotFoundException异常(已经有了,不需要重复创建)
  • 当用户插入的地址是第一条时,需要将当前地址作为默认收货地址
  • 实现办法:如果查询到统计总数为0则将当前地址的is_default值设置为1
  • 如果查询的结果>=20,这时需要抛出业务控制的异常AddressCountLimitException
/**收货地址总数超出限制的异常(20条)*/
public class AddressCountLimitException extends ServiceException {/**重写ServiceException的所有构造方法*/
}
  • 插入数据时产生未知的异常InsertException(已经有了,不需要重复创建)

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

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

因为mapper层接口该功能模块定义了两个抽象方法,所以就要在service层接口该功能模块也定义两个抽象方法?不是这样的,要看mapper层的这两个方法是依赖关系还是独立关系,如果某一个抽象方法依赖于另一个抽象方法,那就需要在业务层将这两个方法整合到一个方法中.一句话来说就是:一个功能模块可能需要多条sql语句

//收货地址业务层接口
public interface IAddressService {/***这三个参数的由来:* 1.首先肯定要有address* 2.业务层需要根据uid查询该用户收货地址总数及新建地址时给字段uid赋值* 但新建收货地址的表单中并没有哪个控件让输入用户uid,所以需要控制层将uid传给业务层* 3.业务层在创建/修改收货地址时需要同时修改数据库中创建人/修改人的字段* 但新建收货地址的表单中并没有哪个控件让输入用户username,所以需要控制层将username传给业务层* 注意:> 可以用HttpSession session代替Integer uid, String username,但* 这样写的话就需要把BaseController类下获取uid,username的方法重新封装到一个* 类中并让IAddressServiceImp实现类继承该类,这样就需要微调一下代码逻辑,太麻* 烦,并且,最好每一层只处理该层需要做的事情,session对象是控制层传递的,所以就* 把session对象定义封装在控制层中,不需要在业务层中额外处理以降低耦合*/void addAddress(Integer uid, String username, Address address);
}

方法addNewAddress中三个参数的由来:

  • 首先肯定要有address
  • 业务层需要根据uid查询该用户收货地址总数及新建地址时给字段uid赋值
  • 但新建收货地址的表单中并没有哪个控件让输入用户uid,所以需要控制层将uid传给业务层并在业务层封装到address对象中
  • 业务层在创建/修改收货地址时需要同时修改数据库中创建人/修改人的字段
  • 但新建收货地址的表单中并没有哪个控件让输入用户username,所以需要控制层将username传给业务层并在业务层封装到address对象中

可以用HttpSession session代替Integer uid, String username,但这样写的话就需要把BaseController类下获取uid,username的方法重新封装到一个类中并让AddressServiceImpl实现类继承该类,这样就需要微调一下代码逻辑,太麻烦,并且,最好每一层只处理该层需要做的事情,session对象是控制层传递的,所以就把session对象定义封装在控制层中,不需要在业务层中额外处理,这样可以降低耦合

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

@Service
public class IAddressServiceImpl implements IAddressService {@Autowiredprivate AddressMapper addressMapper;//在添加用户的收货地址的业务层依赖于DistrictService的业务层接口@Autowiredprivate IDistrictService districtService;/*** 为了方便日后修改最大收货地址数量,可以在配置文件* application.properties中定义user.address.max-count=20*/@Value("${user.address.max-count}")private Integer MaxAddress ;@Overridepublic void addAddress(Integer uid, String username, Address address) {//查询收货地址信息是否大于20Integer count = addressMapper.countAddress(uid);if(count >= MaxAddress) {throw new AddressCountLimitException("收货地址不能超过20条");}//设置信息address.setUid(uid);Integer isDelete = count == 0 ? 1 : 0;//1表示默认收货地址,0反之address.setIsDefault(isDelete);address.setCreatedTime(new Date());address.setCreatedUser(username);address.setModifiedTime(new Date());address.setModifiedUser(username);//对address对象中的数据进行补全:省市区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);//插入收货地址Integer row = addressMapper.insertAddress(address);if(row != 1) {throw new InsertException("未知错误 在 新建收货地址");}}
}

别忘了在配置文件application.properties中定义user.address.max-count=20

3 单元测试

在test下的service文件夹下创建AddressServiceTests测试类

@SpringBootTest
@RunWith(SpringRunner.class)
public class AddressServiceTests {@Autowiredprivate IAddressService addressService;@Testpublic void addNewAddress() {Address address = new Address();address.setPhone("175726");address.setName("男朋友");addressService.addNewAddress(11,"mxy",address);}
}

5.控制层[Controller]

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,该类用来处理用户收货地址的请求和响应

/*** 用户收货地址*/
@RestController
@RequestMapping("/address")
public class AddressController extends BaseController {@Autowiredprivate IAddressService addressService;/*** 新增用户收货地址** @param address* @param session:这里使用session 是为了获取用户的uid和username* @return*/@PostMapping("/add_new_address")public JsonResult<Void> addAddress(Address address, HttpSession session) {//先获取用户uid和usernameInteger uid = getuidFromSession(session);String username = getUsernameFromSession(session);addressService.addAddress(uid, username, address);return new JsonResult<>(OK);}
}

6.前端页面

		$("#btn-add-new-address").click(function (){$.ajax({url:"/address/add_new_address",type:"POST",data:$("#form-add-new-address").serialize(),dataType:"JSON",success(e){if(e.state==200){alert("新增收货地址成功")}else{alert("新增收货地址失败")}},error(xhr){alert("新增收货地址产生未知的异常"+xhr.status)}})})
http://www.lryc.cn/news/164644.html

相关文章:

  • [HNCTF 2022 Week1]——Web方向 详细Writeup
  • 3dmax vray如何创建真实的灯光?3dmax vray 室内照明教程
  • 如何在本地使用Docker搭建和运行Kubernetes集群
  • 每天几道Java面试题(第二天)
  • Java | 线程的生命周期和安全
  • Bootstrap的一些主要作用
  • 网络编程套接字 | UDP套接字
  • 网络层IP协议
  • C++ Day4
  • 2024字节跳动校招面试真题汇总及其解答(二)
  • SpringBoot集成websocket(4)|(使用okhttp3实现websocket)
  • 【MySQL】JDBC编程
  • 数据结构——二叉树线索化遍历(前中后序遍历)
  • GO语言网络编程(并发编程)Channel
  • c++day3
  • 算法通过村第六关-树青铜笔记|中序后序
  • C++动态内存管理+模板
  • SQL 注入漏洞攻击
  • 一篇五分生信临床模型预测文章代码复现——Figure 10.机制及肿瘤免疫浸润(四)
  • Transformer 模型中常见的特殊符号
  • C# halcon SubImage的使用
  • 每天几道Java面试题:异常机制(第三天)
  • Linux 中的 chattr 命令及示例
  • LeetCode 2605. Form Smallest Number From Two Digit Arrays【数组,哈希表,枚举;位运算】1241
  • VoxWeekly|The Sandbox 生态周报|20230904
  • antd setFieldsValue 设置初始值无效AutoComplete 设置默认值失败
  • 01-Redis核心数据结构与高性能原理
  • 预防Dos攻击
  • ant design的文档真的是一坨屎
  • 关于迁移学习的一点理解