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)}})})相关文章:
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 VARC…...
[HNCTF 2022 Week1]——Web方向 详细Writeup
Week1 [HNCTF 2022 Week1]2048 f12查看源代码 可以看出游戏的分数是score 修改score的值 得到flag [HNCTF 2022 Week1]Interesting_include 得到源码 <?php //WEB手要懂得搜索 //flag in ./flag.phpif(isset($_GET[filter])){$file $_GET[filter];if(!preg_match(&qu…...
3dmax vray如何创建真实的灯光?3dmax vray 室内照明教程
为什么良好的照明很重要? 通过仔细操纵光源并利用 V-Ray 的功能,您将解锁制作超越普通渲染的能力,让观众着迷。每个阴影和每个高光都有一个目的 - 通过注意掌握照明,您的渲染将变得栩栩如生,并为您的室内设计赋予独特…...
如何在本地使用Docker搭建和运行Kubernetes集群
文章目录 1. 准备环境2. 安装Minikube3. 启动Minikube集群4. 验证集群5. 部署一个示例应用创建一个Deployment部署应用检查部署 6. 访问应用创建一个Service部署Service获取Service的访问地址 7. 清理资源结论 🎈个人主页:程序员 小侯 🎐CSDN…...
每天几道Java面试题(第二天)
目录 第二幕、第一场)公司前台第二场)公司卫生间 友情提醒 背面试题很枯燥,加入一些戏剧场景故事人物来加深记忆。PS:点击文章目录可直接跳转到文章指定位置。 第二幕、 第一场)公司前台 【接待人员埃斯卡莱罗,面试…...
Java | 线程的生命周期和安全
不爱生姜不吃醋⭐️ 如果本文有什么错误的话欢迎在评论区中指正 与其明天开始,不如现在行动! 🌴线程的生命周期 sleep方法会让线程睡眠,睡眠时间到了之后,立马就会执行下面的代码吗? 答:不会&am…...
Bootstrap的一些主要作用
Bootstrap是一个流行的前端开发框架,它主要用于快速构建响应式、移动优先的网站和网络应用程序。它提供了一套CSS样式和JavaScript插件,帮助开发者轻松地创建漂亮、一致和交互丰富的用户界面。 以下是Bootstrap的一些主要作用: 响应式布局&a…...
网络编程套接字 | UDP套接字
前面的文章中我们叙述了网络编程套接字的一些预备知识点,从本文开始我们就将开始UDP套接字的编写。本文中的服务端与客户端都是在阿里云的云服务器进行编写与测试的。 udp_v1 在v1的版本中我们先来使用一下前面讲过得一些接口,简单的构建一个udp服务器…...
网络层IP协议
目录 前言 1.如何理解IP协议 2.IP协议格式 3.网段划分 4.特殊的IP地址 5.IP地址的数量限制 6.私有IP地址和公网IP地址 7.路由 总结 前言 在前面的文章中介绍了关于传输层常用的两个协议,UDP协议和TCP协议,当数据经过传输层之后,进入网…...
C++ Day4
目录 仿照string类,完成myString 类 思维导图 仿照string类,完成myString 类 #include <iostream> #include<cstring>using namespace std;class myString {private:char *str; //记录c风格的字符串int size; //记录…...
2024字节跳动校招面试真题汇总及其解答(二)
1. 微服务的好处,划分原则 微服务是软件架构的一种模式,它将应用程序划分为一系列小型、独立的服务。每个服务都提供一个单独的功能,并使用轻量级的接口相互通信。 微服务架构具有以下好处: 灵活性:微服务可以独立部署、扩展和更新,这使得它们能够随着业务需求的变化而…...
SpringBoot集成websocket(4)|(使用okhttp3实现websocket)
SpringBoot集成websocket(4)|(使用okhttp3实现websocket) 文章目录 SpringBoot集成websocket(4)|(使用okhttp3实现websocket)[TOC] 前言一、实现步骤1.实现步骤 二、websocket服务代…...
【MySQL】JDBC编程
MySQL-JDBC编程 文章目录 MySQL-JDBC编程Java的数据库编程JDBC工作原理JDBC的使用驱动包下载导入代码编写 Java的数据库编程 JDBC,即Java Database Connectivity,java数据库连接。是一种用于执行SQL语句的Java API,它是 Java中的数据库连接…...
数据结构——二叉树线索化遍历(前中后序遍历)
二叉树线索化 线索化概念: 为什么要转换为线索化 二叉树线索化是一种将普通二叉树转换为具有特殊线索(指向前驱和后继节点)的二叉树的过程。这种线索化的目的是为了提高对二叉树的遍历效率,特别是在不使用递归或栈的情况下进行遍历…...
GO语言网络编程(并发编程)Channel
GO语言网络编程(并发编程)Channel 1、Channel 1.1.1 Channel 单纯地将函数并发执行是没有意义的。函数与函数间需要交换数据才能体现并发执行函数的意义。 虽然可以使用共享内存进行数据交换,但是共享内存在不同的goroutine中容易发生竞态…...
c++day3
stack.h #ifndef STACK_H #define STACK_H #include <iostream> //#define max 128 using namespace std; class Stack { private:int* stack;//数组指针int top;//栈顶元素int max;//栈容量 public://构造函数Stack();//析构函数~Stack();//定义拷贝构造函数Stack(cons…...
算法通过村第六关-树青铜笔记|中序后序
文章目录 前言1. 树的常见概念2. 树的性质3. 树的定义与存储方式4. 树的遍历方式5. 通过序列构建二叉树5.1 前中序列恢复二叉树5.2 中后序列恢复二叉树 总结 前言 提示:瑞秋是个小甜心,她只喜欢被爱,不懂的去爱人。 --几米《你们 我们 他们》…...
C++动态内存管理+模板
💓博主个人主页:不是笨小孩👀 ⏩专栏分类:数据结构与算法👀 C👀 刷题专栏👀 C语言👀 🚚代码仓库:笨小孩的代码库👀 ⏩社区:不是笨小孩👀 🌹欢迎大…...
SQL 注入漏洞攻击
文章目录 1. 介绍2. 无密码登录3. 无用户名无密码登录4. 合并表获取用户名密码 1. 介绍 假设你用自己的用户名和密码登录了一个付费网站,网站服务器就会查询一下你是不是 VIP 用户,而用户数据都是放在数据库中的,服务器通常都会向数据库进行查…...
一篇五分生信临床模型预测文章代码复现——Figure 10.机制及肿瘤免疫浸润(四)
之前讲过临床模型预测的专栏,但那只是基础版本,下面我们以自噬相关基因为例子,模仿一篇五分文章,将图和代码复现出来,学会本专栏课程,可以具备发一篇五分左右文章的水平: 本专栏目录如下: Figure 1:差异表达基因及预后基因筛选(图片仅供参考) Figure 2. 生存分析,…...
手游刚开服就被攻击怎么办?如何防御DDoS?
开服初期是手游最脆弱的阶段,极易成为DDoS攻击的目标。一旦遭遇攻击,可能导致服务器瘫痪、玩家流失,甚至造成巨大经济损失。本文为开发者提供一套简洁有效的应急与防御方案,帮助快速应对并构建长期防护体系。 一、遭遇攻击的紧急应…...
相机Camera日志实例分析之二:相机Camx【专业模式开启直方图拍照】单帧流程日志详解
【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了: 这一篇我们开始讲: 目录 一、场景操作步骤 二、日志基础关键字分级如下 三、场景日志如下: 一、场景操作步骤 操作步…...
mongodb源码分析session执行handleRequest命令find过程
mongo/transport/service_state_machine.cpp已经分析startSession创建ASIOSession过程,并且验证connection是否超过限制ASIOSession和connection是循环接受客户端命令,把数据流转换成Message,状态转变流程是:State::Created 》 St…...
IGP(Interior Gateway Protocol,内部网关协议)
IGP(Interior Gateway Protocol,内部网关协议) 是一种用于在一个自治系统(AS)内部传递路由信息的路由协议,主要用于在一个组织或机构的内部网络中决定数据包的最佳路径。与用于自治系统之间通信的 EGP&…...
【Go】3、Go语言进阶与依赖管理
前言 本系列文章参考自稀土掘金上的 【字节内部课】公开课,做自我学习总结整理。 Go语言并发编程 Go语言原生支持并发编程,它的核心机制是 Goroutine 协程、Channel 通道,并基于CSP(Communicating Sequential Processes࿰…...
TRS收益互换:跨境资本流动的金融创新工具与系统化解决方案
一、TRS收益互换的本质与业务逻辑 (一)概念解析 TRS(Total Return Swap)收益互换是一种金融衍生工具,指交易双方约定在未来一定期限内,基于特定资产或指数的表现进行现金流交换的协议。其核心特征包括&am…...
蓝桥杯3498 01串的熵
问题描述 对于一个长度为 23333333的 01 串, 如果其信息熵为 11625907.5798, 且 0 出现次数比 1 少, 那么这个 01 串中 0 出现了多少次? #include<iostream> #include<cmath> using namespace std;int n 23333333;int main() {//枚举 0 出现的次数//因…...
Maven 概述、安装、配置、仓库、私服详解
目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...
vulnyx Blogger writeup
信息收集 arp-scan nmap 获取userFlag 上web看看 一个默认的页面,gobuster扫一下目录 可以看到扫出的目录中得到了一个有价值的目录/wordpress,说明目标所使用的cms是wordpress,访问http://192.168.43.213/wordpress/然后查看源码能看到 这…...
Vite中定义@软链接
在webpack中可以直接通过符号表示src路径,但是vite中默认不可以。 如何实现: vite中提供了resolve.alias:通过别名在指向一个具体的路径 在vite.config.js中 import { join } from pathexport default defineConfig({plugins: [vue()],//…...
