【瑞吉外卖】day09:用户地址簿功能、菜品展示、购物车、下单

目录

 

1. 用户地址簿功能

1.1 需求分析

1.2 数据模型

1.3 导入功能代码

1.4 功能测试

2. 菜品展示

2.1 需求分析

2.2 前端页面分析

2.3 代码开发

2.4 功能测试

3. 购物车

3.1 需求分析

3.2 数据模型

3.3 前端页面分析

3.4 准备工作

3.5 代码开发

3.6 功能测试

4. 下单

4.1 需求分析

4.2 数据模型

4.3 前端页面分析

4.4 准备工作

4.5 代码开发

4.6 功能测试

1. 用户地址簿功能

1.1 需求分析

地址簿,指的是移动端消费者用户的地址信息,用户登录成功后可以维护自己的地址信息。同一个用户可以有多个地址信息,但是只能有一个默认地址

对于地址簿管理,我们需要实现以下几个功能:

  • 新增地址

  • 地址列表查询

  • 设置默认地址

  • 编辑地址

  • 删除地址

1.2 数据模型

用户的地址信息会存储在address_book表,即地址簿表中。具体表结构如下:

这里面有一个字段is_default,实际上我们在设置默认地址时,只需要更新这个字段就可以了。

1.3 导入功能代码

对于这一类的单表的增删改查,我们已经写过很多了,基本的开发思路都是一样的,那么本小节的用户地址簿管理的增删改查功能,我们就不再一一实现了,基本的代码我们都已经提供了,直接导入进来,做一个测试即可。

对于下面的地址管理的代码,我们可以直接从资料拷贝,也可以直接从下面的讲义中复制。

1). 实体类 AddressBook(直接从课程资料中导入即可)

所属包: com.itheima.reggie.entity

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">import</span> <span style="color:#000000">com</span>.<span style="color:#000000">baomidou</span>.<span style="color:#000000">mybatisplus</span>.<span style="color:#000000">annotation</span>.<span style="color:#000000">FieldFill</span>;
<span style="color:#770088">import</span> <span style="color:#000000">com</span>.<span style="color:#000000">baomidou</span>.<span style="color:#000000">mybatisplus</span>.<span style="color:#000000">annotation</span>.<span style="color:#000000">TableField</span>;
<span style="color:#770088">import</span> <span style="color:#000000">lombok</span>.<span style="color:#000000">Data</span>;
<span style="color:#770088">import</span> <span style="color:#000000">java</span>.<span style="color:#000000">io</span>.<span style="color:#000000">Serializable</span>;
<span style="color:#770088">import</span> <span style="color:#000000">java</span>.<span style="color:#000000">time</span>.<span style="color:#000000">LocalDateTime</span>;
<span style="color:#aa5500">/**</span><span style="color:#aa5500">* 地址簿</span><span style="color:#aa5500">*/</span>
<span style="color:#555555">@Data</span>
<span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">AddressBook</span> <span style="color:#770088">implements</span> <span style="color:#000000">Serializable</span> {<span style="color:#770088">private</span> <span style="color:#770088">static</span> <span style="color:#770088">final</span> <span style="color:#008855">long</span> <span style="color:#000000">serialVersionUID</span> <span style="color:#981a1a">=</span> <span style="color:#116644">1L</span>;
​<span style="color:#770088">private</span> <span style="color:#008855">Long</span> <span style="color:#000000">id</span>;<span style="color:#aa5500">//用户id</span><span style="color:#770088">private</span> <span style="color:#008855">Long</span> <span style="color:#000000">userId</span>;<span style="color:#aa5500">//收货人</span><span style="color:#770088">private</span> <span style="color:#008855">String</span> <span style="color:#000000">consignee</span>;<span style="color:#aa5500">//手机号</span><span style="color:#770088">private</span> <span style="color:#008855">String</span> <span style="color:#000000">phone</span>;<span style="color:#aa5500">//性别 0 女 1 男</span><span style="color:#770088">private</span> <span style="color:#008855">String</span> <span style="color:#000000">sex</span>;<span style="color:#aa5500">//省级区划编号</span><span style="color:#770088">private</span> <span style="color:#008855">String</span> <span style="color:#000000">provinceCode</span>;<span style="color:#aa5500">//省级名称</span><span style="color:#770088">private</span> <span style="color:#008855">String</span> <span style="color:#000000">provinceName</span>;<span style="color:#aa5500">//市级区划编号</span><span style="color:#770088">private</span> <span style="color:#008855">String</span> <span style="color:#000000">cityCode</span>;<span style="color:#aa5500">//市级名称</span><span style="color:#770088">private</span> <span style="color:#008855">String</span> <span style="color:#000000">cityName</span>;<span style="color:#aa5500">//区级区划编号</span><span style="color:#770088">private</span> <span style="color:#008855">String</span> <span style="color:#000000">districtCode</span>;<span style="color:#aa5500">//区级名称</span><span style="color:#770088">private</span> <span style="color:#008855">String</span> <span style="color:#000000">districtName</span>;<span style="color:#aa5500">//详细地址</span><span style="color:#770088">private</span> <span style="color:#008855">String</span> <span style="color:#000000">detail</span>;<span style="color:#aa5500">//标签</span><span style="color:#770088">private</span> <span style="color:#008855">String</span> <span style="color:#000000">label</span>;<span style="color:#aa5500">//是否默认 0 否 1是</span><span style="color:#770088">private</span> <span style="color:#008855">Integer</span> <span style="color:#000000">isDefault</span>;<span style="color:#aa5500">//创建时间</span><span style="color:#555555">@TableField</span>(<span style="color:#000000">fill</span> <span style="color:#981a1a">=</span> <span style="color:#000000">FieldFill</span>.<span style="color:#000000">INSERT</span>)<span style="color:#770088">private</span> <span style="color:#000000">LocalDateTime</span> <span style="color:#000000">createTime</span>;
​<span style="color:#aa5500">//更新时间</span><span style="color:#555555">@TableField</span>(<span style="color:#000000">fill</span> <span style="color:#981a1a">=</span> <span style="color:#000000">FieldFill</span>.<span style="color:#000000">INSERT_UPDATE</span>)<span style="color:#770088">private</span> <span style="color:#000000">LocalDateTime</span> <span style="color:#000000">updateTime</span>;
​<span style="color:#aa5500">//创建人</span><span style="color:#555555">@TableField</span>(<span style="color:#000000">fill</span> <span style="color:#981a1a">=</span> <span style="color:#000000">FieldFill</span>.<span style="color:#000000">INSERT</span>)<span style="color:#770088">private</span> <span style="color:#008855">Long</span> <span style="color:#000000">createUser</span>;
​<span style="color:#aa5500">//修改人</span><span style="color:#555555">@TableField</span>(<span style="color:#000000">fill</span> <span style="color:#981a1a">=</span> <span style="color:#000000">FieldFill</span>.<span style="color:#000000">INSERT_UPDATE</span>)<span style="color:#770088">private</span> <span style="color:#008855">Long</span> <span style="color:#000000">updateUser</span>;
​<span style="color:#aa5500">//是否删除</span><span style="color:#770088">private</span> <span style="color:#008855">Integer</span> <span style="color:#000000">isDeleted</span>;
}</span></span>

2). Mapper接口 AddressBookMapper(直接从课程资料中导入即可)

所属包: com.itheima.reggie.mapper

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">import</span> <span style="color:#000000">com</span>.<span style="color:#000000">baomidou</span>.<span style="color:#000000">mybatisplus</span>.<span style="color:#000000">core</span>.<span style="color:#000000">mapper</span>.<span style="color:#000000">BaseMapper</span>;
<span style="color:#770088">import</span> <span style="color:#000000">com</span>.<span style="color:#000000">itheima</span>.<span style="color:#000000">reggie</span>.<span style="color:#000000">entity</span>.<span style="color:#000000">AddressBook</span>;
<span style="color:#770088">import</span> <span style="color:#000000">org</span>.<span style="color:#000000">apache</span>.<span style="color:#000000">ibatis</span>.<span style="color:#000000">annotations</span>.<span style="color:#000000">Mapper</span>;
<span style="color:#770088">import</span> <span style="color:#000000">org</span>.<span style="color:#000000">apache</span>.<span style="color:#000000">ibatis</span>.<span style="color:#000000">annotations</span>.<span style="color:#000000">Select</span>;
<span style="color:#770088">import</span> <span style="color:#000000">java</span>.<span style="color:#000000">util</span>.<span style="color:#000000">List</span>;
​
<span style="color:#555555">@Mapper</span>
<span style="color:#770088">public</span> <span style="color:#770088">interface</span> <span style="color:#0000ff">AddressBookMapper</span> <span style="color:#770088">extends</span> <span style="color:#000000">BaseMapper</span><span style="color:#981a1a"><</span><span style="color:#000000">AddressBook</span><span style="color:#981a1a">></span> {
}</span></span>

3). 业务层接口 AddressBookService(直接从课程资料中导入即可)

所属包: com.itheima.reggie.service

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">import</span> <span style="color:#000000">com</span>.<span style="color:#000000">baomidou</span>.<span style="color:#000000">mybatisplus</span>.<span style="color:#000000">extension</span>.<span style="color:#000000">service</span>.<span style="color:#000000">IService</span>;
<span style="color:#770088">import</span> <span style="color:#000000">com</span>.<span style="color:#000000">itheima</span>.<span style="color:#000000">reggie</span>.<span style="color:#000000">entity</span>.<span style="color:#000000">AddressBook</span>;
​
<span style="color:#770088">public</span> <span style="color:#770088">interface</span> <span style="color:#0000ff">AddressBookService</span> <span style="color:#770088">extends</span> <span style="color:#000000">IService</span><span style="color:#981a1a"><</span><span style="color:#000000">AddressBook</span><span style="color:#981a1a">></span> {
}</span></span>

4). 业务层实现类 AddressBookServiceImpl(直接从课程资料中导入即可)

所属包: com.itheima.reggie.service.impl

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">import</span> <span style="color:#000000">com</span>.<span style="color:#000000">baomidou</span>.<span style="color:#000000">mybatisplus</span>.<span style="color:#000000">extension</span>.<span style="color:#000000">service</span>.<span style="color:#000000">impl</span>.<span style="color:#000000">ServiceImpl</span>;
<span style="color:#770088">import</span> <span style="color:#000000">com</span>.<span style="color:#000000">itheima</span>.<span style="color:#000000">reggie</span>.<span style="color:#000000">entity</span>.<span style="color:#000000">AddressBook</span>;
<span style="color:#770088">import</span> <span style="color:#000000">com</span>.<span style="color:#000000">itheima</span>.<span style="color:#000000">reggie</span>.<span style="color:#000000">mapper</span>.<span style="color:#000000">AddressBookMapper</span>;
<span style="color:#770088">import</span> <span style="color:#000000">com</span>.<span style="color:#000000">itheima</span>.<span style="color:#000000">reggie</span>.<span style="color:#000000">service</span>.<span style="color:#000000">AddressBookService</span>;
<span style="color:#770088">import</span> <span style="color:#000000">org</span>.<span style="color:#000000">springframework</span>.<span style="color:#000000">stereotype</span>.<span style="color:#000000">Service</span>;
​
<span style="color:#555555">@Service</span>
<span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">AddressBookServiceImpl</span> <span style="color:#770088">extends</span> <span style="color:#000000">ServiceImpl</span><span style="color:#981a1a"><</span><span style="color:#000000">AddressBookMapper</span>, <span style="color:#000000">AddressBook</span><span style="color:#981a1a">></span> <span style="color:#770088">implements</span> <span style="color:#000000">AddressBookService</span> {
}</span></span>

5). 控制层 AddressBookController(直接从课程资料中导入即可)

所属包: com.itheima.reggie.controller

controller主要开发的功能:

A. 新增地址逻辑说明:

  • 需要记录当前是哪个用户的地址(关联当前登录用户)

B. 设置默认地址

  • 每个用户可以有很多地址,但是默认地址只能有一个 ;

  • 先将该用户所有地址的is_default更新为0 , 然后将当前的设置的默认地址的is_default设置为1

C. 根据ID查询地址

D. 查询默认地址

  • 根据当前登录用户ID 以及 is_default进行查询,查询当前登录用户is_default为1的地址信息

E. 查询指定用户的全部地址

  • 根据当前登录用户ID,查询所有的地址列表

代码实现如下:

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">import</span> <span style="color:#000000">com</span>.<span style="color:#000000">baomidou</span>.<span style="color:#000000">mybatisplus</span>.<span style="color:#000000">core</span>.<span style="color:#000000">conditions</span>.<span style="color:#000000">query</span>.<span style="color:#000000">LambdaQueryWrapper</span>;
<span style="color:#770088">import</span> <span style="color:#000000">com</span>.<span style="color:#000000">baomidou</span>.<span style="color:#000000">mybatisplus</span>.<span style="color:#000000">core</span>.<span style="color:#000000">conditions</span>.<span style="color:#000000">update</span>.<span style="color:#000000">LambdaUpdateWrapper</span>;
<span style="color:#770088">import</span> <span style="color:#000000">com</span>.<span style="color:#000000">itheima</span>.<span style="color:#000000">reggie</span>.<span style="color:#000000">common</span>.<span style="color:#000000">BaseContext</span>;
<span style="color:#770088">import</span> <span style="color:#000000">com</span>.<span style="color:#000000">itheima</span>.<span style="color:#000000">reggie</span>.<span style="color:#000000">common</span>.<span style="color:#000000">R</span>;
<span style="color:#770088">import</span> <span style="color:#000000">com</span>.<span style="color:#000000">itheima</span>.<span style="color:#000000">reggie</span>.<span style="color:#000000">entity</span>.<span style="color:#000000">AddressBook</span>;
<span style="color:#770088">import</span> <span style="color:#000000">com</span>.<span style="color:#000000">itheima</span>.<span style="color:#000000">reggie</span>.<span style="color:#000000">service</span>.<span style="color:#000000">AddressBookService</span>;
<span style="color:#770088">import</span> <span style="color:#000000">lombok</span>.<span style="color:#000000">extern</span>.<span style="color:#000000">slf4j</span>.<span style="color:#000000">Slf4j</span>;
<span style="color:#770088">import</span> <span style="color:#000000">org</span>.<span style="color:#000000">springframework</span>.<span style="color:#000000">beans</span>.<span style="color:#000000">factory</span>.<span style="color:#000000">annotation</span>.<span style="color:#000000">Autowired</span>;
<span style="color:#770088">import</span> <span style="color:#000000">org</span>.<span style="color:#000000">springframework</span>.<span style="color:#000000">web</span>.<span style="color:#000000">bind</span>.<span style="color:#000000">annotation</span>.<span style="color:#981a1a">*</span>;
<span style="color:#770088">import</span> <span style="color:#000000">java</span>.<span style="color:#000000">util</span>.<span style="color:#000000">List</span>;
​
<span style="color:#aa5500">/**</span><span style="color:#aa5500">* 地址簿管理</span><span style="color:#aa5500">*/</span>
<span style="color:#555555">@Slf4j</span>
<span style="color:#555555">@RestController</span>
<span style="color:#555555">@RequestMapping</span>(<span style="color:#aa1111">"/addressBook"</span>)
<span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">AddressBookController</span> {<span style="color:#555555">@Autowired</span><span style="color:#770088">private</span> <span style="color:#000000">AddressBookService</span> <span style="color:#000000">addressBookService</span>;
​<span style="color:#aa5500">/**</span><span style="color:#aa5500">* 新增</span><span style="color:#aa5500">*/</span><span style="color:#555555">@PostMapping</span><span style="color:#770088">public</span> <span style="color:#000000">R</span><span style="color:#981a1a"><</span><span style="color:#000000">AddressBook</span><span style="color:#981a1a">></span> <span style="color:#000000">save</span>(<span style="color:#555555">@RequestBody</span> <span style="color:#000000">AddressBook</span> <span style="color:#000000">addressBook</span>) {<span style="color:#000000">addressBook</span>.<span style="color:#000000">setUserId</span>(<span style="color:#000000">BaseContext</span>.<span style="color:#000000">getCurrentId</span>());<span style="color:#000000">log</span>.<span style="color:#000000">info</span>(<span style="color:#aa1111">"addressBook:{}"</span>, <span style="color:#000000">addressBook</span>);<span style="color:#000000">addressBookService</span>.<span style="color:#000000">save</span>(<span style="color:#000000">addressBook</span>);<span style="color:#770088">return</span> <span style="color:#000000">R</span>.<span style="color:#000000">success</span>(<span style="color:#000000">addressBook</span>);}
​<span style="color:#aa5500">/**</span><span style="color:#aa5500">* 设置默认地址</span><span style="color:#aa5500">*/</span><span style="color:#555555">@PutMapping</span>(<span style="color:#aa1111">"default"</span>)<span style="color:#770088">public</span> <span style="color:#000000">R</span><span style="color:#981a1a"><</span><span style="color:#000000">AddressBook</span><span style="color:#981a1a">></span> <span style="color:#000000">setDefault</span>(<span style="color:#555555">@RequestBody</span> <span style="color:#000000">AddressBook</span> <span style="color:#000000">addressBook</span>) {<span style="color:#000000">log</span>.<span style="color:#000000">info</span>(<span style="color:#aa1111">"addressBook:{}"</span>, <span style="color:#000000">addressBook</span>);<span style="color:#000000">LambdaUpdateWrapper</span><span style="color:#981a1a"><</span><span style="color:#000000">AddressBook</span><span style="color:#981a1a">></span> <span style="color:#000000">wrapper</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#000000">LambdaUpdateWrapper</span><span style="color:#981a1a"><></span>();<span style="color:#000000">wrapper</span>.<span style="color:#000000">eq</span>(<span style="color:#000000">AddressBook</span>::<span style="color:#000000">getUserId</span>, <span style="color:#000000">BaseContext</span>.<span style="color:#000000">getCurrentId</span>());<span style="color:#000000">wrapper</span>.<span style="color:#000000">set</span>(<span style="color:#000000">AddressBook</span>::<span style="color:#000000">getIsDefault</span>, <span style="color:#116644">0</span>);<span style="color:#aa5500">//SQL:update address_book set is_default = 0 where user_id = ?</span><span style="color:#000000">addressBookService</span>.<span style="color:#000000">update</span>(<span style="color:#000000">wrapper</span>);
​<span style="color:#000000">addressBook</span>.<span style="color:#000000">setIsDefault</span>(<span style="color:#116644">1</span>);<span style="color:#aa5500">//SQL:update address_book set is_default = 1 where id = ?</span><span style="color:#000000">addressBookService</span>.<span style="color:#000000">updateById</span>(<span style="color:#000000">addressBook</span>);<span style="color:#770088">return</span> <span style="color:#000000">R</span>.<span style="color:#000000">success</span>(<span style="color:#000000">addressBook</span>);}
​<span style="color:#aa5500">/**</span><span style="color:#aa5500">* 根据id查询地址</span><span style="color:#aa5500">*/</span><span style="color:#555555">@GetMapping</span>(<span style="color:#aa1111">"/{id}"</span>)<span style="color:#770088">public</span> <span style="color:#000000">R</span> <span style="color:#000000">get</span>(<span style="color:#555555">@PathVariable</span> <span style="color:#008855">Long</span> <span style="color:#000000">id</span>) {<span style="color:#000000">AddressBook</span> <span style="color:#000000">addressBook</span> <span style="color:#981a1a">=</span> <span style="color:#000000">addressBookService</span>.<span style="color:#000000">getById</span>(<span style="color:#000000">id</span>);<span style="color:#770088">if</span> (<span style="color:#000000">addressBook</span> <span style="color:#981a1a">!=</span> <span style="color:#221199">null</span>) {<span style="color:#770088">return</span> <span style="color:#000000">R</span>.<span style="color:#000000">success</span>(<span style="color:#000000">addressBook</span>);} <span style="color:#770088">else</span> {<span style="color:#770088">return</span> <span style="color:#000000">R</span>.<span style="color:#000000">error</span>(<span style="color:#aa1111">"没有找到该对象"</span>);}}
​<span style="color:#aa5500">/**</span><span style="color:#aa5500">* 查询默认地址</span><span style="color:#aa5500">*/</span><span style="color:#555555">@GetMapping</span>(<span style="color:#aa1111">"default"</span>)<span style="color:#770088">public</span> <span style="color:#000000">R</span><span style="color:#981a1a"><</span><span style="color:#000000">AddressBook</span><span style="color:#981a1a">></span> <span style="color:#000000">getDefault</span>() {<span style="color:#000000">LambdaQueryWrapper</span><span style="color:#981a1a"><</span><span style="color:#000000">AddressBook</span><span style="color:#981a1a">></span> <span style="color:#000000">queryWrapper</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#000000">LambdaQueryWrapper</span><span style="color:#981a1a"><></span>();<span style="color:#000000">queryWrapper</span>.<span style="color:#000000">eq</span>(<span style="color:#000000">AddressBook</span>::<span style="color:#000000">getUserId</span>, <span style="color:#000000">BaseContext</span>.<span style="color:#000000">getCurrentId</span>());<span style="color:#000000">queryWrapper</span>.<span style="color:#000000">eq</span>(<span style="color:#000000">AddressBook</span>::<span style="color:#000000">getIsDefault</span>, <span style="color:#116644">1</span>);
​<span style="color:#aa5500">//SQL:select * from address_book where user_id = ? and is_default = 1</span><span style="color:#000000">AddressBook</span> <span style="color:#000000">addressBook</span> <span style="color:#981a1a">=</span> <span style="color:#000000">addressBookService</span>.<span style="color:#000000">getOne</span>(<span style="color:#000000">queryWrapper</span>);
​<span style="color:#770088">if</span> (<span style="color:#221199">null</span> <span style="color:#981a1a">==</span> <span style="color:#000000">addressBook</span>) {<span style="color:#770088">return</span> <span style="color:#000000">R</span>.<span style="color:#000000">error</span>(<span style="color:#aa1111">"没有找到该对象"</span>);} <span style="color:#770088">else</span> {<span style="color:#770088">return</span> <span style="color:#000000">R</span>.<span style="color:#000000">success</span>(<span style="color:#000000">addressBook</span>);}}
​<span style="color:#aa5500">/**</span><span style="color:#aa5500">* 查询指定用户的全部地址</span><span style="color:#aa5500">*/</span><span style="color:#555555">@GetMapping</span>(<span style="color:#aa1111">"/list"</span>)<span style="color:#770088">public</span> <span style="color:#000000">R</span><span style="color:#981a1a"><</span><span style="color:#000000">List</span><span style="color:#981a1a"><</span><span style="color:#000000">AddressBook</span><span style="color:#981a1a">>></span> <span style="color:#000000">list</span>(<span style="color:#000000">AddressBook</span> <span style="color:#000000">addressBook</span>) {<span style="color:#000000">addressBook</span>.<span style="color:#000000">setUserId</span>(<span style="color:#000000">BaseContext</span>.<span style="color:#000000">getCurrentId</span>());<span style="color:#000000">log</span>.<span style="color:#000000">info</span>(<span style="color:#aa1111">"addressBook:{}"</span>, <span style="color:#000000">addressBook</span>);
​<span style="color:#aa5500">//条件构造器</span><span style="color:#000000">LambdaQueryWrapper</span><span style="color:#981a1a"><</span><span style="color:#000000">AddressBook</span><span style="color:#981a1a">></span> <span style="color:#000000">queryWrapper</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#000000">LambdaQueryWrapper</span><span style="color:#981a1a"><></span>();<span style="color:#000000">queryWrapper</span>.<span style="color:#000000">eq</span>(<span style="color:#221199">null</span> <span style="color:#981a1a">!=</span> <span style="color:#000000">addressBook</span>.<span style="color:#000000">getUserId</span>(), <span style="color:#000000">AddressBook</span>::<span style="color:#000000">getUserId</span>, <span style="color:#000000">addressBook</span>.<span style="color:#000000">getUserId</span>());<span style="color:#000000">queryWrapper</span>.<span style="color:#000000">orderByDesc</span>(<span style="color:#000000">AddressBook</span>::<span style="color:#000000">getUpdateTime</span>);
​<span style="color:#aa5500">//SQL:select * from address_book where user_id = ? order by update_time desc</span><span style="color:#770088">return</span> <span style="color:#000000">R</span>.<span style="color:#000000">success</span>(<span style="color:#000000">addressBookService</span>.<span style="color:#000000">list</span>(<span style="color:#000000">queryWrapper</span>));}
}</span></span>

1.4 功能测试

代码导入进来,并且去阅读了一下地址管理各个功能的逻辑实现,接下来,我们就可以启动项目,进行一个测试。测试过程中,通过debug断点调试观察服务端程序的执行过程,在浏览器中使用调试工具查看页面和服务端的交互过程和请求响应数据。

1). 新增

填写表单数据,点击保存地址,查看网络请求。

测试完毕之后,检查数据库中的数据,是否正常插入。

2). 列表查询

当新增地址完成后,页面会再次发送一个请求,来查询该用户的所有地址列表,在界面进行展示。

3). 设置默认

在地址列表页面中,勾选 "设为默认地址" ,此时会发送PUT请求,来设置默认地址。

测试完毕后,我们再次查看数据库表中的数据:

2. 菜品展示

2.1 需求分析

用户登录成功后跳转到系统首页,在首页需要根据分类来展示菜品和套餐。如果菜品设置了口味信息,需要展示按钮,否则显示按钮。

2.2 前端页面分析

在开发代码之前,需要梳理一下前端页面和服务端的交互过程:

1). 页面(front/index.html)发送ajax请求,获取分类数据(菜品分类和套餐分类)

该功能在之前的业务开发中,我们都已经实现了。通过请求响应的数据,我们也可以看到数据是可以正确获取到的。

注意:首页加载时,不仅发送请求获取分类列表,还发送了一次ajax请求用于加载购物车数据,而这两次请求必须全部成功,页面才可以正常渲染,而当前购物车列表查询功能还未实现(报404),所以列表目前并未渲染。此处可以将这次请求的地址暂时修改一下,从静态json文件获取数据,等后续开发购物车功能时再修改回来,如下:

修改之后,我们再次测试:

目前该部分的功能我们已经调通,左侧的分类菜单,和右侧的菜品信息我们都可以看到,后续我们只需要将购物车列表的数据改成调用服务端接口查询即可。

2). 页面发送ajax请求,获取第一个分类下的菜品或者套餐

A. 根据分类ID查询套餐列表:

B. 根据分类ID查询菜品列表:

异步请求,查询分类对应的菜品列表,功能我们已经实现了,但是我们之前查询的只是菜品的基本信息,不包含菜品的口味信息。所以在前端界面中,我们看不到选择菜品分类的信息。

经过上述的分析,我们可以看到,服务端我们主要提供两个方法, 分别用来:

A. 根据分类ID查询菜品列表(包含菜品口味列表), 具体请求信息如下:

请求说明
请求方式GET
请求路径/dish/list
请求参数?categoryId=1397844263642378242&status=1

该功能在服务端已经实现,我们需要修改此方法,在原有方法的基础上增加查询菜品的口味信息。

B. 根据分类ID查询套餐列表, 具体请求信息如下:

请求说明
请求方式GET
请求路径/setmeal/list
请求参数?categoryId=1397844263642378242&status=1

该功能在服务端并未实现。

2.3 代码开发

2.3.1 查询菜品方法修改

由于之前我们实现的根据分类查询菜品列表,仅仅查询了菜品的基本信息,未查询菜品口味信息,而移动端用户在点餐时,是需要选择口味信息的,所以我们需要对之前的代码实现进行完善,那么如何完善呢?

我们需要修改DishController的list方法,原来此方法的返回值类型为:R<List<Dish>>。为了满足移动端对数据的要求(菜品基本信息和菜品对应的口味信息),现在需要将方法的返回值类型改为:R<List<DishDto>> ,因为在DishDto中封装了菜品对应的口味信息:

代码逻辑:

A. 根据分类ID查询,查询目前正在启售的菜品列表 (已实现)

B. 遍历菜品列表,并查询菜品的分类信息及菜品的口味列表

C. 组装数据DishDto,并返回

代码实现:

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#555555">@GetMapping</span>(<span style="color:#aa1111">"/list"</span>)<span style="color:#770088">public</span> <span style="color:#000000">R</span><span style="color:#981a1a"><</span><span style="color:#000000">List</span><span style="color:#981a1a"><</span><span style="color:#000000">DishDto</span><span style="color:#981a1a">>></span> <span style="color:#0000ff">list</span>(<span style="color:#000000">Dish</span> <span style="color:#000000">dish</span>){<span style="color:#aa5500">//构造查询条件</span><span style="color:#000000">LambdaQueryWrapper</span><span style="color:#981a1a"><</span><span style="color:#000000">Dish</span><span style="color:#981a1a">></span> <span style="color:#000000">queryWrapper</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#000000">LambdaQueryWrapper</span><span style="color:#981a1a"><></span>();<span style="color:#000000">queryWrapper</span>.<span style="color:#000000">eq</span>(<span style="color:#000000">dish</span>.<span style="color:#000000">getCategoryId</span>() <span style="color:#981a1a">!=</span> <span style="color:#221199">null</span> ,<span style="color:#000000">Dish</span>::<span style="color:#000000">getCategoryId</span>,<span style="color:#000000">dish</span>.<span style="color:#000000">getCategoryId</span>());<span style="color:#aa5500">//添加条件,查询状态为1(起售状态)的菜品</span><span style="color:#000000">queryWrapper</span>.<span style="color:#000000">eq</span>(<span style="color:#000000">Dish</span>::<span style="color:#000000">getStatus</span>,<span style="color:#116644">1</span>);<span style="color:#aa5500">//添加排序条件</span><span style="color:#000000">queryWrapper</span>.<span style="color:#000000">orderByAsc</span>(<span style="color:#000000">Dish</span>::<span style="color:#000000">getSort</span>).<span style="color:#000000">orderByDesc</span>(<span style="color:#000000">Dish</span>::<span style="color:#000000">getUpdateTime</span>);<span style="color:#000000">List</span><span style="color:#981a1a"><</span><span style="color:#000000">Dish</span><span style="color:#981a1a">></span> <span style="color:#000000">list</span> <span style="color:#981a1a">=</span> <span style="color:#000000">dishService</span>.<span style="color:#000000">list</span>(<span style="color:#000000">queryWrapper</span>);<span style="color:#000000">List</span><span style="color:#981a1a"><</span><span style="color:#000000">DishDto</span><span style="color:#981a1a">></span> <span style="color:#000000">dishDtoList</span> <span style="color:#981a1a">=</span> <span style="color:#000000">list</span>.<span style="color:#000000">stream</span>().<span style="color:#000000">map</span>((<span style="color:#000000">item</span>) <span style="color:#981a1a">-></span> {<span style="color:#000000">DishDto</span> <span style="color:#000000">dishDto</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#000000">DishDto</span>();<span style="color:#000000">BeanUtils</span>.<span style="color:#000000">copyProperties</span>(<span style="color:#000000">item</span>,<span style="color:#000000">dishDto</span>);
​<span style="color:#008855">Long</span> <span style="color:#000000">categoryId</span> <span style="color:#981a1a">=</span> <span style="color:#000000">item</span>.<span style="color:#000000">getCategoryId</span>();<span style="color:#aa5500">//分类id</span><span style="color:#aa5500">//根据id查询分类对象</span><span style="color:#000000">Category</span> <span style="color:#000000">category</span> <span style="color:#981a1a">=</span> <span style="color:#000000">categoryService</span>.<span style="color:#000000">getById</span>(<span style="color:#000000">categoryId</span>);<span style="color:#770088">if</span>(<span style="color:#000000">category</span> <span style="color:#981a1a">!=</span> <span style="color:#221199">null</span>){<span style="color:#008855">String</span> <span style="color:#000000">categoryName</span> <span style="color:#981a1a">=</span> <span style="color:#000000">category</span>.<span style="color:#000000">getName</span>();<span style="color:#000000">dishDto</span>.<span style="color:#000000">setCategoryName</span>(<span style="color:#000000">categoryName</span>);}
​<span style="color:#aa5500">//当前菜品的id</span><span style="color:#008855">Long</span> <span style="color:#000000">dishId</span> <span style="color:#981a1a">=</span> <span style="color:#000000">item</span>.<span style="color:#000000">getId</span>();<span style="color:#000000">LambdaQueryWrapper</span><span style="color:#981a1a"><</span><span style="color:#000000">DishFlavor</span><span style="color:#981a1a">></span> <span style="color:#000000">lambdaQueryWrapper</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#000000">LambdaQueryWrapper</span><span style="color:#981a1a"><></span>();<span style="color:#000000">lambdaQueryWrapper</span>.<span style="color:#000000">eq</span>(<span style="color:#000000">DishFlavor</span>::<span style="color:#000000">getDishId</span>,<span style="color:#000000">dishId</span>);<span style="color:#aa5500">//SQL:select * from dish_flavor where dish_id = ?</span><span style="color:#000000">List</span><span style="color:#981a1a"><</span><span style="color:#000000">DishFlavor</span><span style="color:#981a1a">></span> <span style="color:#000000">dishFlavorList</span> <span style="color:#981a1a">=</span> <span style="color:#000000">dishFlavorService</span>.<span style="color:#000000">list</span>(<span style="color:#000000">lambdaQueryWrapper</span>);<span style="color:#000000">dishDto</span>.<span style="color:#000000">setFlavors</span>(<span style="color:#000000">dishFlavorList</span>);<span style="color:#770088">return</span> <span style="color:#000000">dishDto</span>;}).<span style="color:#000000">collect</span>(<span style="color:#000000">Collectors</span>.<span style="color:#000000">toList</span>());
​<span style="color:#770088">return</span> <span style="color:#000000">R</span>.<span style="color:#000000">success</span>(<span style="color:#000000">dishDtoList</span>);}</span></span>

2.3.2 根据分类ID查询套餐

在SetmealController中创建list方法,根据条件查询套餐数据。

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#aa5500">/**</span><span style="color:#aa5500">* 根据条件查询套餐数据</span><span style="color:#aa5500">* @param setmeal</span><span style="color:#aa5500">* @return</span><span style="color:#aa5500">*/</span>
<span style="color:#555555">@GetMapping</span>(<span style="color:#aa1111">"/list"</span>)
<span style="color:#770088">public</span> <span style="color:#000000">R</span><span style="color:#981a1a"><</span><span style="color:#000000">List</span><span style="color:#981a1a"><</span><span style="color:#000000">Setmeal</span><span style="color:#981a1a">>></span> <span style="color:#0000ff">list</span>(<span style="color:#000000">Setmeal</span> <span style="color:#000000">setmeal</span>){<span style="color:#000000">LambdaQueryWrapper</span><span style="color:#981a1a"><</span><span style="color:#000000">Setmeal</span><span style="color:#981a1a">></span> <span style="color:#000000">queryWrapper</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#000000">LambdaQueryWrapper</span><span style="color:#981a1a"><></span>();<span style="color:#000000">queryWrapper</span>.<span style="color:#000000">eq</span>(<span style="color:#000000">setmeal</span>.<span style="color:#000000">getCategoryId</span>() <span style="color:#981a1a">!=</span> <span style="color:#221199">null</span>,<span style="color:#000000">Setmeal</span>::<span style="color:#000000">getCategoryId</span>,<span style="color:#000000">setmeal</span>.<span style="color:#000000">getCategoryId</span>());<span style="color:#000000">queryWrapper</span>.<span style="color:#000000">eq</span>(<span style="color:#000000">setmeal</span>.<span style="color:#000000">getStatus</span>() <span style="color:#981a1a">!=</span> <span style="color:#221199">null</span>,<span style="color:#000000">Setmeal</span>::<span style="color:#000000">getStatus</span>,<span style="color:#000000">setmeal</span>.<span style="color:#000000">getStatus</span>());<span style="color:#000000">queryWrapper</span>.<span style="color:#000000">orderByDesc</span>(<span style="color:#000000">Setmeal</span>::<span style="color:#000000">getUpdateTime</span>);
​<span style="color:#000000">List</span><span style="color:#981a1a"><</span><span style="color:#000000">Setmeal</span><span style="color:#981a1a">></span> <span style="color:#000000">list</span> <span style="color:#981a1a">=</span> <span style="color:#000000">setmealService</span>.<span style="color:#000000">list</span>(<span style="color:#000000">queryWrapper</span>);<span style="color:#770088">return</span> <span style="color:#000000">R</span>.<span style="color:#000000">success</span>(<span style="color:#000000">list</span>);
}</span></span>

2.4 功能测试

把菜品展示的功能代码完善完成之后,我们重新启动服务,来测试一个菜品展示的功能。测试过程中可以使用浏览器的监控工具查看页面和服务端的数据交互细节。

点击分类,根据分类查询菜品列表/套餐列表:

3. 购物车

3.1 需求分析

移动端用户可以将菜品或者套餐添加到购物车。对于菜品来说,如果设置了口味信息,则需要选择规格后才能加入购物车;对于套餐来说,可以直接点击将当前套餐加入购物车。在购物车中可以修改菜品和套餐的数量,也可以清空购物车。

这里面我们需要实现的功能包括:

1). 添加购物车

2). 查询购物车

3). 清空购物车

3.2 数据模型

用户的购物车数据,也是需要保存在数据库中的,购物车对应的数据表为shopping_cart表,具体表结构如下:

说明:

  • 购物车数据是关联用户的,在表结构中,我们需要记录,每一个用户的购物车数据是哪些

  • 菜品列表展示出来的既有套餐,又有菜品,如果APP端选择的是套餐,就保存套餐ID(setmeal_id),如果APP端选择的是菜品,就保存菜品ID(dish_id)

  • 对同一个菜品/套餐,如果选择多份不需要添加多条记录,增加数量number即可

最终shopping_cart表中存储的数据示例:

3.3 前端页面分析

在开发代码之前,需要梳理一下购物车操作时前端页面和服务端的交互过程:

1). 点击 "加入购物车" 或者 "+" 按钮,页面发送ajax请求,请求服务端,将菜品或者套餐添加到购物车

2). 点击购物车图标,页面发送ajax请求,请求服务端查询购物车中的菜品和套餐

此时,我们就需要将查询购物车的代码放开,不用再加载静态的json数据了。

3). 点击清空购物车按钮,页面发送ajax请求,请求服务端来执行清空购物车操作

经过上述的分析,我们可以看到,对于购物车的功能,我们主要需要开发以下几个功能,具体的请求信息如下:

1). 加入购物车

请求说明
请求方式POST
请求路径/shoppingCart/add
请求参数json格式
<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#000000">菜品数据</span>: 
{<span style="color:#000000">"amount"</span>:<span style="color:#116644">118</span>,<span style="color:#000000">"dishFlavor"</span>:<span style="color:#aa1111">"不要蒜,微辣"</span>,<span style="color:#000000">"dishId"</span>:<span style="color:#aa1111">"1397851099502260226"</span>,<span style="color:#000000">"name"</span>:<span style="color:#aa1111">"全家福"</span>,<span style="color:#000000">"image"</span>:<span style="color:#aa1111">"a53a4e6a-3b83-4044-87f9-9d49b30a8fdc.jpg"</span>}
​
<span style="color:#000000">套餐数据</span>: 
{<span style="color:#000000">"amount"</span>:<span style="color:#116644">38</span>,<span style="color:#000000">"setmealId"</span>:<span style="color:#aa1111">"1423329486060957698"</span>,<span style="color:#000000">"name"</span>:<span style="color:#aa1111">"营养超值工作餐"</span>,<span style="color:#000000">"image"</span>:<span style="color:#aa1111">"9cd7a80a-da54-4f46-bf33-af3576514cec.jpg"</span>}</span></span>

2). 查询购物车列表

请求说明
请求方式GET
请求路径/shoppingCart/list

3). 清空购物车功能

请求说明
请求方式DELETE
请求路径/shoppingCart/clean

3.4 准备工作

分析完毕购物车的业务需求和实现思路之后,在开发业务功能前,先将需要用到的类和接口基本结构创建好:

1). 实体类 ShoppingCart(直接从课程资料中导入即可)

所属包: com.itheima.reggie.entity

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">import</span> <span style="color:#000000">lombok</span>.<span style="color:#000000">Data</span>;
<span style="color:#770088">import</span> <span style="color:#000000">java</span>.<span style="color:#000000">io</span>.<span style="color:#000000">Serializable</span>;
<span style="color:#770088">import</span> <span style="color:#000000">java</span>.<span style="color:#000000">math</span>.<span style="color:#000000">BigDecimal</span>;
<span style="color:#770088">import</span> <span style="color:#000000">java</span>.<span style="color:#000000">time</span>.<span style="color:#000000">LocalDateTime</span>;
​
<span style="color:#aa5500">/**</span><span style="color:#aa5500">* 购物车</span><span style="color:#aa5500">*/</span>
<span style="color:#555555">@Data</span>
<span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">ShoppingCart</span> <span style="color:#770088">implements</span> <span style="color:#000000">Serializable</span> {<span style="color:#770088">private</span> <span style="color:#770088">static</span> <span style="color:#770088">final</span> <span style="color:#008855">long</span> <span style="color:#000000">serialVersionUID</span> <span style="color:#981a1a">=</span> <span style="color:#116644">1L</span>;<span style="color:#770088">private</span> <span style="color:#008855">Long</span> <span style="color:#000000">id</span>;
​<span style="color:#aa5500">//名称</span><span style="color:#770088">private</span> <span style="color:#008855">String</span> <span style="color:#000000">name</span>;
​<span style="color:#aa5500">//用户id</span><span style="color:#770088">private</span> <span style="color:#008855">Long</span> <span style="color:#000000">userId</span>;
​<span style="color:#aa5500">//菜品id</span><span style="color:#770088">private</span> <span style="color:#008855">Long</span> <span style="color:#000000">dishId</span>;
​<span style="color:#aa5500">//套餐id</span><span style="color:#770088">private</span> <span style="color:#008855">Long</span> <span style="color:#000000">setmealId</span>;
​<span style="color:#aa5500">//口味</span><span style="color:#770088">private</span> <span style="color:#008855">String</span> <span style="color:#000000">dishFlavor</span>;
​<span style="color:#aa5500">//数量</span><span style="color:#770088">private</span> <span style="color:#008855">Integer</span> <span style="color:#000000">number</span>;
​<span style="color:#aa5500">//金额</span><span style="color:#770088">private</span> <span style="color:#000000">BigDecimal</span> <span style="color:#000000">amount</span>;
​<span style="color:#aa5500">//图片</span><span style="color:#770088">private</span> <span style="color:#008855">String</span> <span style="color:#000000">image</span>;
​<span style="color:#770088">private</span> <span style="color:#000000">LocalDateTime</span> <span style="color:#000000">createTime</span>;
}</span></span>

2). Mapper接口 ShoppingCartMapper

所属包: com.itheima.reggie.mapper

<span style="background-color:#f8f8f8"><span style="color:#333333">import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.itheima.reggie.entity.ShoppingCart;
import org.apache.ibatis.annotations.Mapper;@Mapper
public interface ShoppingCartMapper extends BaseMapper<ShoppingCart> {
}</span></span>

3). 业务层接口 ShoppingCartService

所属包: com.itheima.reggie.service

<span style="background-color:#f8f8f8"><span style="color:#333333">import com.baomidou.mybatisplus.extension.service.IService;
import com.itheima.reggie.entity.ShoppingCart;public interface ShoppingCartService extends IService<ShoppingCart> {
}</span></span>

4). 业务层实现类 ShoppingCartServiceImpl

所属包: com.itheima.reggie.service.impl

<span style="background-color:#f8f8f8"><span style="color:#333333">import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.itheima.reggie.entity.ShoppingCart;
import com.itheima.reggie.mapper.ShoppingCartMapper;
import com.itheima.reggie.service.ShoppingCartService;
import org.springframework.stereotype.Service;@Service
public class ShoppingCartServiceImpl extends ServiceImpl<ShoppingCartMapper, ShoppingCart> implements ShoppingCartService {
}</span></span>

5). 控制层 ShoppingCartController

所属包: com.itheima.reggie.controller

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">import</span> <span style="color:#000000">com</span>.<span style="color:#000000">itheima</span>.<span style="color:#000000">reggie</span>.<span style="color:#000000">service</span>.<span style="color:#000000">ShoppingCartService</span>;
<span style="color:#770088">import</span> <span style="color:#000000">lombok</span>.<span style="color:#000000">extern</span>.<span style="color:#000000">slf4j</span>.<span style="color:#000000">Slf4j</span>;
<span style="color:#770088">import</span> <span style="color:#000000">org</span>.<span style="color:#000000">springframework</span>.<span style="color:#000000">beans</span>.<span style="color:#000000">factory</span>.<span style="color:#000000">annotation</span>.<span style="color:#000000">Autowired</span>;
<span style="color:#770088">import</span> <span style="color:#000000">org</span>.<span style="color:#000000">springframework</span>.<span style="color:#000000">web</span>.<span style="color:#000000">bind</span>.<span style="color:#000000">annotation</span>.<span style="color:#981a1a">*</span>;
​
<span style="color:#aa5500">/**</span><span style="color:#aa5500">* 购物车</span><span style="color:#aa5500">*/</span>
<span style="color:#555555">@Slf4j</span>
<span style="color:#555555">@RestController</span>
<span style="color:#555555">@RequestMapping</span>(<span style="color:#aa1111">"/shoppingCart"</span>)
<span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">ShoppingCartController</span> {<span style="color:#555555">@Autowired</span><span style="color:#770088">private</span> <span style="color:#000000">ShoppingCartService</span> <span style="color:#000000">shoppingCartService</span>;}   </span></span>

3.5 代码开发

3.5.1 添加购物车

在ShoppingCartController中创建add方法,来完成添加购物车的逻辑实现,具体的逻辑如下:

A. 获取当前登录用户,为购物车对象赋值

B. 根据当前登录用户ID 及 本次添加的菜品ID/套餐ID,查询购物车数据是否存在

C. 如果已经存在,就在原来数量基础上加1

D. 如果不存在,则添加到购物车,数量默认就是1

代码实现如下:

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#aa5500">/**</span>
<span style="color:#aa5500">* 添加购物车</span>
<span style="color:#aa5500">* @param shoppingCart</span>
<span style="color:#aa5500">* @return</span>
<span style="color:#aa5500">*/</span>
<span style="color:#555555">@PostMapping</span>(<span style="color:#aa1111">"/add"</span>)
<span style="color:#770088">public</span> <span style="color:#000000">R</span><span style="color:#981a1a"><</span><span style="color:#000000">ShoppingCart</span><span style="color:#981a1a">></span> <span style="color:#0000ff">add</span>(<span style="color:#555555">@RequestBody</span> <span style="color:#000000">ShoppingCart</span> <span style="color:#000000">shoppingCart</span>){<span style="color:#000000">log</span>.<span style="color:#000000">info</span>(<span style="color:#aa1111">"购物车数据:{}"</span>,<span style="color:#000000">shoppingCart</span>);
​<span style="color:#aa5500">//设置用户id,指定当前是哪个用户的购物车数据</span><span style="color:#008855">Long</span> <span style="color:#000000">currentId</span> <span style="color:#981a1a">=</span> <span style="color:#000000">BaseContext</span>.<span style="color:#000000">getCurrentId</span>();<span style="color:#000000">shoppingCart</span>.<span style="color:#000000">setUserId</span>(<span style="color:#000000">currentId</span>);
​<span style="color:#008855">Long</span> <span style="color:#000000">dishId</span> <span style="color:#981a1a">=</span> <span style="color:#000000">shoppingCart</span>.<span style="color:#000000">getDishId</span>();
​<span style="color:#000000">LambdaQueryWrapper</span><span style="color:#981a1a"><</span><span style="color:#000000">ShoppingCart</span><span style="color:#981a1a">></span> <span style="color:#000000">queryWrapper</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#000000">LambdaQueryWrapper</span><span style="color:#981a1a"><></span>();<span style="color:#000000">queryWrapper</span>.<span style="color:#000000">eq</span>(<span style="color:#000000">ShoppingCart</span>::<span style="color:#000000">getUserId</span>,<span style="color:#000000">currentId</span>);
​<span style="color:#770088">if</span>(<span style="color:#000000">dishId</span> <span style="color:#981a1a">!=</span> <span style="color:#221199">null</span>){<span style="color:#aa5500">//添加到购物车的是菜品</span><span style="color:#000000">queryWrapper</span>.<span style="color:#000000">eq</span>(<span style="color:#000000">ShoppingCart</span>::<span style="color:#000000">getDishId</span>,<span style="color:#000000">dishId</span>);}<span style="color:#770088">else</span>{<span style="color:#aa5500">//添加到购物车的是套餐</span><span style="color:#000000">queryWrapper</span>.<span style="color:#000000">eq</span>(<span style="color:#000000">ShoppingCart</span>::<span style="color:#000000">getSetmealId</span>,<span style="color:#000000">shoppingCart</span>.<span style="color:#000000">getSetmealId</span>());}
​<span style="color:#aa5500">//查询当前菜品或者套餐是否在购物车中</span><span style="color:#aa5500">//SQL:select * from shopping_cart where user_id = ? and dish_id/setmeal_id = ?</span><span style="color:#000000">ShoppingCart</span> <span style="color:#000000">cartServiceOne</span> <span style="color:#981a1a">=</span> <span style="color:#000000">shoppingCartService</span>.<span style="color:#000000">getOne</span>(<span style="color:#000000">queryWrapper</span>);
​<span style="color:#770088">if</span>(<span style="color:#000000">cartServiceOne</span> <span style="color:#981a1a">!=</span> <span style="color:#221199">null</span>){<span style="color:#aa5500">//如果已经存在,就在原来数量基础上加一</span><span style="color:#008855">Integer</span> <span style="color:#000000">number</span> <span style="color:#981a1a">=</span> <span style="color:#000000">cartServiceOne</span>.<span style="color:#000000">getNumber</span>();<span style="color:#000000">cartServiceOne</span>.<span style="color:#000000">setNumber</span>(<span style="color:#000000">number</span> <span style="color:#981a1a">+</span> <span style="color:#116644">1</span>);<span style="color:#000000">shoppingCartService</span>.<span style="color:#000000">updateById</span>(<span style="color:#000000">cartServiceOne</span>);}<span style="color:#770088">else</span>{<span style="color:#aa5500">//如果不存在,则添加到购物车,数量默认就是一</span><span style="color:#000000">shoppingCart</span>.<span style="color:#000000">setNumber</span>(<span style="color:#116644">1</span>);<span style="color:#000000">shoppingCart</span>.<span style="color:#000000">setCreateTime</span>(<span style="color:#000000">LocalDateTime</span>.<span style="color:#000000">now</span>());<span style="color:#000000">shoppingCartService</span>.<span style="color:#000000">save</span>(<span style="color:#000000">shoppingCart</span>);<span style="color:#000000">cartServiceOne</span> <span style="color:#981a1a">=</span> <span style="color:#000000">shoppingCart</span>;}<span style="color:#770088">return</span> <span style="color:#000000">R</span>.<span style="color:#000000">success</span>(<span style="color:#000000">cartServiceOne</span>);
}</span></span>

3.5.2 查询购物车

在ShoppingCartController中创建list方法,根据当前登录用户ID查询购物车列表,并对查询的结果进行创建时间的倒序排序。

代码实现如下:

<span style="background-color:#f8f8f8"><span style="color:#333333">/**
* 查看购物车
* @return
*/
@GetMapping("/list")
public R<List<ShoppingCart>> list(){log.info("查看购物车...");LambdaQueryWrapper<ShoppingCart> queryWrapper = new LambdaQueryWrapper<>();queryWrapper.eq(ShoppingCart::getUserId,BaseContext.getCurrentId());queryWrapper.orderByAsc(ShoppingCart::getCreateTime);List<ShoppingCart> list = shoppingCartService.list(queryWrapper);return R.success(list);
}</span></span>

3.5.3 清空购物车

在ShoppingCartController中创建clean方法,在方法中获取当前登录用户,根据登录用户ID,删除购物车数据。

代码实现如下:

<span style="background-color:#f8f8f8"><span style="color:#333333">/**
* 清空购物车
* @return
*/
@DeleteMapping("/clean")
public R<String> clean(){//SQL:delete from shopping_cart where user_id = ?LambdaQueryWrapper<ShoppingCart> queryWrapper = new LambdaQueryWrapper<>();queryWrapper.eq(ShoppingCart::getUserId,BaseContext.getCurrentId());shoppingCartService.remove(queryWrapper);return R.success("清空购物车成功");
}</span></span>

3.6 功能测试

按照前面分析的操作流程进行测试,测试功能以及数据库中的数据是否是否正常。

1). 添加购物车

当添加的是菜品信息,而这个用户的购物车中当前并没有这个菜品时,添加一条数据,数量为1。

检查数据库数据,由于是菜品保存的是dish_id。

这时在页面上,我们可以继续点击+号,在购物车中增加该菜品,此时,应该是对现有的购物车菜品数量加1,而不应该插入新的记录。

检查数据库数据:

如果添加的是套餐,该套餐在当前用户的购物车中并不存在,则添加一条数据,数量为1。

检查数据库数据:

2). 查看购物车

点击页面下面的购物车边栏,查看购物车数据列表是否正常展示。

3). 清空购物车

在购物车列表展示页中点击"清空", 查看购物车是否被清空。

并检查数据库中的数据,可以看到数据已经被删除。

4. 下单

4.1 需求分析

移动端用户将菜品或者套餐加入购物车后,可以点击购物车中的 "去结算" 按钮,页面跳转到订单确认页面,点击 "去支付" 按钮则完成下单操作。

这里,我们需要说明一下,这里并不会去开发支付功能,因为不论是支付宝的支付,还是微信支付,都是需要企业资质的,而我们大家在测试的时候,是没有办法提供企业资质的,所以这一部分支付功能我们就不去实现了。

4.2 数据模型

用户下单业务对应的数据表为orders表和order_detail表(一对多关系,一个订单关联多个订单明细):

表名含义说明
orders订单表主要存储订单的基本信息(如: 订单号、状态、金额、支付方式、下单用户、收件地址等)
order_detail订单明细表主要存储订单详情信息(如: 该订单关联的套餐及菜品的信息)

具体的表结构如下:

A. orders 订单表

B. order_detail

数据示例:

用户提交订单时,需要往订单表orders中插入一条记录,并且需要往order_detail中插入一条或多条记录。

4.3 前端页面分析

在开发代码之前,需要梳理一下用户下单操作时前端页面和服务端的交互过程:

1). 在购物车中点击按钮,页面跳转到订单确认页面

页面跳转前端已经完成,我们无需操作。

2). 在订单确认页面,发送ajax请求,请求服务端获取当前登录用户的默认地址

该功能在用户地址簿管理功能开发时,已经实现(导入),我们无需操作。

3). 在订单确认页面,发送ajax请求,请求服务端获取当前登录用户的购物车数据

该功能已经实现,我们无需操作。

4). 在订单确认页面点击按钮,发送ajax请求,请求服务端完成下单操作

经过上述的分析,我们看到前三步的功能我们都已经实现了,我们主要需要实现最后一步的下单功能,该功能具体的请求信息如下:

请求说明
请求方式POST
请求路径/order/submit
请求参数{"remark":"老板,记得带一次性筷子","payMethod":1,"addressBookId":"1425792459560005634"}

4.4 准备工作

在开发业务功能前,先将需要用到的类和接口基本结构创建好:

1). 实体类 Orders、OrderDetail(直接从课程资料中导入即可)

所属包: com.itheima.reggie.entity

<span style="background-color:#f8f8f8"><span style="color:#333333">import lombok.Data;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDateTime;/*** 订单*/
@Data
public class Orders implements Serializable {private static final long serialVersionUID = 1L;private Long id;//订单号private String number;//订单状态 1待付款,2待派送,3已派送,4已完成,5已取消private Integer status;//下单用户idprivate Long userId;//地址idprivate Long addressBookId;//下单时间private LocalDateTime orderTime;//结账时间private LocalDateTime checkoutTime;//支付方式 1微信,2支付宝private Integer payMethod;//实收金额private BigDecimal amount;//备注private String remark;//用户名private String userName;//手机号private String phone;//地址private String address;//收货人private String consignee;
}</span></span>

<span style="background-color:#f8f8f8"><span style="color:#333333">import lombok.Data;
import java.io.Serializable;
import java.math.BigDecimal;/*** 订单明细*/
@Data
public class OrderDetail implements Serializable {private static final long serialVersionUID = 1L;private Long id;//名称private String name;//订单idprivate Long orderId;//菜品idprivate Long dishId;//套餐idprivate Long setmealId;//口味private String dishFlavor;//数量private Integer number;//金额private BigDecimal amount;//图片private String image;
}</span></span>

2). Mapper接口 OrderMapper、OrderDetailMapper

所属包: com.itheima.reggie.mapper

<span style="background-color:#f8f8f8"><span style="color:#333333">import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.itheima.reggie.entity.Orders;
import org.apache.ibatis.annotations.Mapper;@Mapper
public interface OrderMapper extends BaseMapper<Orders> {
}</span></span>
<span style="background-color:#f8f8f8"><span style="color:#333333">import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.itheima.reggie.entity.OrderDetail;
import org.apache.ibatis.annotations.Mapper;@Mapper
public interface OrderDetailMapper extends BaseMapper<OrderDetail> {
}</span></span>

3). 业务层接口 OrderService、OrderDetailService

所属包: com.itheima.reggie.service

<span style="background-color:#f8f8f8"><span style="color:#333333">import com.baomidou.mybatisplus.extension.service.IService;
import com.itheima.reggie.entity.Orders;public interface OrderService extends IService<Orders> {
}</span></span>
<span style="background-color:#f8f8f8"><span style="color:#333333">import com.baomidou.mybatisplus.extension.service.IService;
import com.itheima.reggie.entity.OrderDetail;public interface OrderDetailService extends IService<OrderDetail> {
}</span></span>

4). 业务层实现类 OrderServiceImpl、OrderDetailServiceImpl

所属包: com.itheima.reggie.service.impl

<span style="background-color:#f8f8f8"><span style="color:#333333">import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.itheima.reggie.entity.*;
import com.itheima.reggie.mapper.OrderMapper;
import com.itheima.reggie.service.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;@Service
@Slf4j
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Orders> implements OrderService {
}</span></span>
<span style="background-color:#f8f8f8"><span style="color:#333333">import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.itheima.reggie.entity.OrderDetail;
import com.itheima.reggie.mapper.OrderDetailMapper;
import com.itheima.reggie.service.OrderDetailService;
import org.springframework.stereotype.Service;@Service
public class OrderDetailServiceImpl extends ServiceImpl<OrderDetailMapper, OrderDetail> implements OrderDetailService {
}</span></span>

5). 控制层 OrderController、OrderDetailController

所属包: com.itheima.reggie.controller

<span style="background-color:#f8f8f8"><span style="color:#333333">import com.itheima.reggie.service.OrderService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;/*** 订单*/
@Slf4j
@RestController
@RequestMapping("/order")
public class OrderController {@Autowiredprivate OrderService orderService;
}</span></span>
<span style="background-color:#f8f8f8"><span style="color:#333333">import com.itheima.reggie.service.OrderDetailService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;/*** 订单明细*/
@Slf4j
@RestController
@RequestMapping("/orderDetail")
public class OrderDetailController {@Autowiredprivate OrderDetailService orderDetailService;
}</span></span>

4.5 代码开发

在OrderController中创建submit方法,处理用户下单的逻辑 :

<span style="background-color:#f8f8f8"><span style="color:#333333">/*** 用户下单* @param orders* @return*/
@PostMapping("/submit")
public R<String> submit(@RequestBody Orders orders){log.info("订单数据:{}",orders);orderService.submit(orders);return R.success("下单成功");
}</span></span>

由于下单的逻辑相对复杂,我们可以在OrderService中定义submit方法,来处理下单的具体逻辑:

<span style="background-color:#f8f8f8"><span style="color:#333333">/**
* 用户下单
* @param orders
*/
public void submit(Orders orders);</span></span>

然后在OrderServiceImpl中完成下单功能的具体实现,下单功能的具体逻辑如下:

A. 获得当前用户id, 查询当前用户的购物车数据

B. 根据当前登录用户id, 查询用户数据

C. 根据地址ID, 查询地址数据

D. 组装订单明细数据, 批量保存订单明细

E. 组装订单数据, 批量保存订单数据

F. 删除当前用户的购物车列表数据

具体代码实现如下:

<span style="background-color:#f8f8f8"><span style="color:#333333">@Autowired
private ShoppingCartService shoppingCartService;@Autowired
private UserService userService;@Autowired
private AddressBookService addressBookService;@Autowired
private OrderDetailService orderDetailService;/**
* 用户下单
* @param orders
*/
@Transactional
public void submit(Orders orders) {//获得当前用户idLong userId = BaseContext.getCurrentId();//查询当前用户的购物车数据LambdaQueryWrapper<ShoppingCart> wrapper = new LambdaQueryWrapper<>();wrapper.eq(ShoppingCart::getUserId,userId);List<ShoppingCart> shoppingCarts = shoppingCartService.list(wrapper);if(shoppingCarts == null || shoppingCarts.size() == 0){throw new CustomException("购物车为空,不能下单");}//查询用户数据User user = userService.getById(userId);//查询地址数据Long addressBookId = orders.getAddressBookId();AddressBook addressBook = addressBookService.getById(addressBookId);if(addressBook == null){throw new CustomException("用户地址信息有误,不能下单");}long orderId = IdWorker.getId();//订单号AtomicInteger amount = new AtomicInteger(0);//组装订单明细信息List<OrderDetail> orderDetails = shoppingCarts.stream().map((item) -> {OrderDetail orderDetail = new OrderDetail();orderDetail.setOrderId(orderId);orderDetail.setNumber(item.getNumber());orderDetail.setDishFlavor(item.getDishFlavor());orderDetail.setDishId(item.getDishId());orderDetail.setSetmealId(item.getSetmealId());orderDetail.setName(item.getName());orderDetail.setImage(item.getImage());orderDetail.setAmount(item.getAmount());amount.addAndGet(item.getAmount().multiply(new BigDecimal(item.getNumber())).intValue());return orderDetail;}).collect(Collectors.toList());//组装订单数据orders.setId(orderId);orders.setOrderTime(LocalDateTime.now());orders.setCheckoutTime(LocalDateTime.now());orders.setStatus(2);orders.setAmount(new BigDecimal(amount.get()));//总金额orders.setUserId(userId);orders.setNumber(String.valueOf(orderId));orders.setUserName(user.getName());orders.setConsignee(addressBook.getConsignee());orders.setPhone(addressBook.getPhone());orders.setAddress((addressBook.getProvinceName() == null ? "" : addressBook.getProvinceName())+ (addressBook.getCityName() == null ? "" : addressBook.getCityName())+ (addressBook.getDistrictName() == null ? "" : addressBook.getDistrictName())+ (addressBook.getDetail() == null ? "" : addressBook.getDetail()));//向订单表插入数据,一条数据this.save(orders);//向订单明细表插入数据,多条数据orderDetailService.saveBatch(orderDetails);//清空购物车数据shoppingCartService.remove(wrapper);
}</span></span>

备注:

上述逻辑处理中,计算购物车商品的总金额时,为保证我们每一次执行的累加计算是一个原子操作,我们这里用到了JDK中提供的一个原子类 AtomicInteger

4.6 功能测试

代码编写完成,我们重新启动服务,按照前面分析的操作流程进行测试,查看数据是否正常即可。在测试过程中,我们可以通过debug的形式来跟踪代码的正常执行。

检查数据库数据

订单表插入一条记录:

订单明细表插入四条记录():

同时,购物车的数据被删除:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/34132.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

外卖管理系统(一)

内容 软件开发整体介绍 瑞吉外卖项目介绍 开发环境搭建 后台登录功能开发 后台退出功能开发 1. 软件开发整体介绍 作为一名软件开发工程师,我们需要了解在软件开发过程中的开发流程&#xff0c; 以及软件开发过程中涉及到的岗位角色&#xff0c;角色的分工、职责&#x…

外卖订餐管理系统

需求分析 项目概述 外卖订餐系统分成前台订餐管理子系统、店家信息管理子系统和后台管理子系统这三个子系统。用户通过此平台可以浏览菜品、查询菜品、查询店家&#xff0c;注册登录后可以提交订单、查询订单、管理个人信息等&#xff1b;商家通过此平台注册登录后可以接单、…

基于android的外卖在线订餐系统app

本外卖订餐系统是一个Android 客户端JSP Servlet服务端应用程序&#xff0c;启动Android上的应用程序后可以登录、查看菜品等,再者学校学生人数的增加&#xff0c;学生对餐饮服务的要求更加高&#xff1b;许多学生不满足于学校食堂的餐饮或嫌学校食堂就餐排队时间长&#xff0c…

瑞吉外卖订单后台和用户端功能

项目场景&#xff1a; 在编写瑞吉外卖的订单功能的时候&#xff0c;还是按照惯例&#xff0c;订单的一些功能是我们自己做&#xff0c;毕竟都看了一百多集视频了&#xff0c;自己应该能写一点东西了。 遇到的坑&#xff1a; 后台的订单列表功能&#xff0c;有一个输入订单号查询…

瑞吉外卖 —— 2、后台登录和登出

目录 1、后台登录功能 1.1、接口分析 1.1.2、登录校验逻辑 1.2、代码 1.2.1、统一的返回结果实体类 1.2.2、controller 方法 1.3、测试 2、后台退出功能 2.1、分析 2.2、代码 3、未登录访问首页跳转到登录页面 3.1、分析 3.2、代码 1、后台登录功能 1.1、接口分析…

外卖点餐APP-02(后台--员工管理)

&#xff08;一&#xff09;登录 实现思路&#xff1a; 接收到用户登录输入的用户名和密码&#xff0c;封装到了emp对象中对密码进行MD5加密创建条件构造器添加sql查询判断条件&#xff0c;emp对象中的Username等于Employee数据表中的Username调用MyBatis-Plus的方法查询数据库…

瑞吉外卖-移动端菜品展示功能,购物车添加菜品及修改等功能,用户下单功能及历史订单派送功能

整理记录下学习整个瑞吉外卖项目&#xff0c;详细代码可在我的Gitee仓库瑞吉外卖实战克隆下载学习使用&#xff01; 12.菜品展示 12.1 需求分析 12.2 更改前台页面使其正常显示 由于购物车功能还未进行开发&#xff0c;所以修改main.js中的cartListJson函数中访问固定数据&a…

外卖点餐APP-04(后台--菜品管理)

&#xff08;一&#xff09;新增 controller层思路&#xff1a; 调用service处理响应处理结果 PostMapping public R<String> save(RequestBody DishDto dishDto){dishService.saveWithFlavors(dishDto);return R.success("新增成功&#xff01;"); } servi…

瑞吉外卖:后台系统登录和退出功能

文章目录 需求分析代码开发创建实体类导入返回结果类Rcontroller、service与mapperlogin.html防止非法访问 需求分析 点击登录按钮后&#xff0c;浏览器以POST方式向employee/login提交username和password&#xff0c;服务器经过处理后向浏览器返回某种格式的数据&#xff0c;…

服装销售数据分析

目录&#xff1a; 一、项目背景介绍 二、数据源 三、分析流程 四、分析框架 五、知识点总结 一、项目背景介绍&#xff1a; 某服装经销商经营多个女装品牌&#xff0c;每个品牌设有线下店铺。该公司老板及销售总监需在每日营业结束后查看当日销售数据。以往主要由业务员手动整…

创建报价单或销售凭证,提示无定价确定过程能被确定,消息号V1212

创建报价单&#xff0c;提示无定价确定过程能被确定&#xff0c;消息号V1212。 解决方案&#xff1a; spro 》销售和分销——》基本功能——》定价——》定价控制——》定价并分配定价过程 1&#xff09;将凭证定价程序分配给订单类型 2&#xff09;设置定价程序确定&#xff0…

ChatGPT工作提效之layedit上传多附件的解决方案(layedit赋值、layui.js底层修改、追加模式多附件上传)

ChatGPT工作提效系列文章目录 ChatGPT工作提效之初探路径独孤九剑遇强则强ChatGPT工作提效之在程序开发中的巧劲和指令(创建MySQL语句、PHP语句、Javascript用法、python的交互)ChatGPT工作提效之生成开发需求和报价单并转为Excel格式ChatGPT工作提效之小鹅通二次开发批量API对…

Zia和ChatGPT如何协同工作?

有没有集成ChatGPT的CRM系统推荐&#xff1f;Zoho CRM已经正式与ChatGPT集成。下面我们将从使用场景、使用价值和使用范围等方面切入讲述CRMAI的应用和作用。 Zia和ChatGPT如何协同工作&#xff1f; Zia和ChatGPT是不同的人工智能模型&#xff0c;在CRM中呈现出共生的关系。 …

AIGC持续火爆大模型争相推出,庞大市场造就算力供应模式演变

本图由AI生成 文/王吉伟 近期的AIGC领域仍旧火爆异常。 但火的不只是AIGC应用&#xff0c;还有巨头之间的AI竞赛&#xff0c;以及接连不断上新的AI大模型&#xff08;LLM&#xff0c;Large Language Model&#xff09;。 面对ChatGPT带来的技术冲击&#xff0c;为了研发谷歌多…

ChatGPT实现命名实体识别(NER, named entity recognization)和词性归类

语义分析词格分类 命名实体识别(NER, named entity recognization)和词性归类是 NLP 技术中的关键一环。过去 NLP 领域有不少流行的开源项目专注在这个领域&#xff0c;如 Spacy、NLTK 等等。我们来试试 ChatGPT 在这方面的表现情况如何。我们从"四渡赤水"的百度百科…

突发!两所知名大学,曝合并!校方紧急回应:校长将亲自说明!

点击上方“3D视觉工坊”&#xff0c;选择“星标” 干货第一时间送达 来源丨联合新闻网 编辑丨3D视觉工坊 点击进入—>3D视觉工坊学习交流群 我国台湾又有“国立”大学传出合并的消息&#xff0c;台湾中山大学与台湾高雄大学传将重启合并协商&#xff0c;有网友曝光中山大学发…

从 Uber 数据泄露事件我们可以学到什么?

Uber 数据泄露始于一名黑客从暗网市场购买属于一名 Uber 员工的被盗凭证。最初尝试使用这些凭据连接到 Uber 的网络失败&#xff0c;因为该帐户受 MFA 保护。为了克服这一安全障碍&#xff0c;黑客通过 What’s App 联系了 Uber 员工&#xff0c;并假装是 Uber 的安全人员&…

点击率预估

点击率预估是广告技术的核心算法之一&#xff0c;它是很多广告算法工程师喜爱的战场。一直想介绍一下点击率预估&#xff0c;但是涉及公式和模型理论太多&#xff0c;怕说不清楚&#xff0c;读者也不明白。所以&#xff0c;这段时间花了一些时间整理点击率预估的知识&#xff0…

老鸟教你如何精确评估开发时间

一个程序员能否精确评估开发时间&#xff0c;是一件非常重要的事情。如果你掌握了这项技能&#xff0c;你在别人的眼里就会是这样&#xff1a; 靠谱经验十足对需求很了解延期风险小合格的软件工程师正规军&#xff0c;不是野路子 评估开发时间的重要性 首先&#xff0c;在一…

从FM推演各深度CTR预估模型(附代码)

作者&#xff1a; 龙心尘 && 寒小阳 时间&#xff1a;2018年7月 出处&#xff1a;https://blog.csdn.net/longxinchen_ml/article/details/81031736 https://blog.csdn.net/han_xiaoyang/article/details/81031961 声明&#xff1a;版权所有&#xff0c;转载请联系作者…