一、验证码
1.1 交互过程
在开发代码之前,需要梳理一下登录时前端页面和服务端的交互过程:
1、在登录页面(front/page/login.html)输入手机号,点击【获取验证码】按钮,页面发送ajax请求,在服务端调
用短信服务API给指定手机号发送验证码短信
2、在登录页面输入验证码,点击【登录】按钮,发送ajax请求,在服务端处理登录请求
开发手机验证码登录功能,其实就是在服务端编写代码去处理前端页面发送的这2次请求即可。
在开发业务功能前,先将需要用到的类和接口基本结构创建好:
实体类User(直接从课程资料中导入即可)
Mapper接口UserMapper
业务层接口UserService
业务层实现类UserServicelmpl
控制层UserController
工具类SMSUtils、ValidateCodeUtils
工具类SMSUtils
package com.itheima.reggie.utils;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.profile.DefaultProfile;
/**
* 短信发送工具类
*/
public class SMSUtils {
/**
* 发送短信
* @param signName 签名
* @param templateCode 模板
* @param phoneNumbers 手机号
* @param param 参数
*/
public static void sendMessage(String signName, String templateCode,String phoneNumbers,String param){
DefaultProfile profile = DefaultProfile.getProfile("cn-hangzhou", "", "");
IAcsClient client = new DefaultAcsClient(profile);
SendSmsRequest request = new SendSmsRequest();
request.setSysRegionId("cn-hangzhou");
request.setPhoneNumbers(phoneNumbers);
request.setSignName(signName);
request.setTemplateCode(templateCode);
request.setTemplateParam("{\"code\":\""+param+"\"}");
try {
SendSmsResponse response = client.getAcsResponse(request);
System.out.println("短信发送成功");
}catch (ClientException e) {
e.printStackTrace();
}
}
}
工具类ValidateCodeUtils
package com.itheima.reggie.utils;
import java.util.Random;
/**
* 随机生成验证码工具类
*/
public class ValidateCodeUtils {
/**
* 随机生成验证码
* @param length 长度为4位或者6位
* @return
*/
public static Integer generateValidateCode(int length){
Integer code =null;
if(length == 4){
code = new Random().nextInt(9999);//生成随机数,最大为9999
if(code < 1000){
code = code + 1000;//保证随机数为4位数字
}
}else if(length == 6){
code = new Random().nextInt(999999);//生成随机数,最大为999999
if(code < 100000){
code = code + 100000;//保证随机数为6位数字
}
}else{
throw new RuntimeException("只能生成4位或6位数字验证码");
}
return code;
}
/**
* 随机生成指定长度字符串验证码
* @param length 长度
* @return
*/
public static String generateValidateCode4String(int length){
Random rdm = new Random();
String hash1 = Integer.toHexString(rdm.nextInt());
String capstr = hash1.substring(0, length);
return capstr;
}
}
1.2 代码实现
这里是通过阿里云测试的,测试成功
/**
* 生成验证码
* @param user
* @param session
* @return
*/
@PostMapping("sendMsg")
public R<String> sengMsg(@RequestBody User user, HttpSession session){
//获取手机号
String phone = user.getPhone();
if(StringUtils.isNotEmpty(phone)){
//生成随机验证码
String code = ValidateCodeUtils.generateValidateCode(4).toString();
log.info("code={}",code);
//调用阿里云提供的短信服务API完成发送短信
SMSUtils.sendMessage("苏一拉","短信模板",phone,code);
//需要将生成的验证码保存到session
session.setAttribute(phone,code);
return R.success("验证码发送成功");
}
else {
return R.error("验证码发送失败");
}
}
二、导入用户地址簿相关功能代码
2.1 需求分析
地址簿,指的是移动端消费者用户的地址信息,用户登录成功后可以维护自己的地址信息。同一个用户可以有多个地址信息,但是只能有一个默认地址。
功能代码清单:
实体类AddressBook
Mapper接口AddressBookMapper
业务层接口AddressBookService
业务层实现类AddressBookServicelmpl
控制层AddressBookController
AddressBookController
package com.itheima.reggie.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.itheima.reggie.common.BaseContent;
import com.itheima.reggie.common.R;
import com.itheima.reggie.entity.AddressBook;
import com.itheima.reggie.service.AddressBookService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.List;
@RestController
@Slf4j
@RequestMapping("/addressBook")
public class AddressBookController {
@Resource
private AddressBookService addressBookService;
/**
* 新增收货地址
* @param addressBook
* @return
*/
@PostMapping
public R<AddressBook> addAddress(@RequestBody AddressBook addressBook){
//获得用户ID
addressBook.setUserId(BaseContent.getCurrentId());
log.info(BaseContent.getCurrentId().toString());
addressBookService.save(addressBook);
log.info(addressBook.toString());
return R.success(addressBook);
}
/**
* 设置默认地址
* @return
*/
@PutMapping("/default")
public R<AddressBook> setDefaultAddress(@RequestBody AddressBook addressBook){
LambdaUpdateWrapper<AddressBook> wrapper = new LambdaUpdateWrapper<>();
//查找当前用户的地址
wrapper.eq(AddressBook::getUserId,BaseContent.getCurrentId());
//设置所有的默认值为0
wrapper.set(AddressBook::getIsDefault,0);
addressBookService.update(wrapper);
addressBook.setIsDefault(1);
addressBookService.updateById(addressBook);
return R.success(addressBook);
}
/**
* 获取默认地址
* @return
*/
@GetMapping("/default")
public R<AddressBook> getDefaultAddress(){
LambdaQueryWrapper<AddressBook> addressBookLambdaQueryWrapper = new LambdaQueryWrapper<>();
addressBookLambdaQueryWrapper.eq(AddressBook::getUserId,BaseContent.getCurrentId());
addressBookLambdaQueryWrapper.eq(AddressBook::getIsDefault,1);
AddressBook addressBook = addressBookService.getOne(addressBookLambdaQueryWrapper);
if(addressBook == null){
return R.error("获取默认地址失败");
}else{
return R.success(addressBook);
}
}
/**
* 查找所有的地址信息
* @param addressBook
* @return
*/
@GetMapping("/list")
public R<List<AddressBook>> addressList(AddressBook addressBook){
log.info(addressBook.toString());
addressBook.setUserId(BaseContent.getCurrentId());
LambdaQueryWrapper<AddressBook> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(addressBook != null,AddressBook::getUserId,addressBook.getUserId());
queryWrapper.orderByDesc(AddressBook::getUpdateTime);
return R.success(addressBookService.list(queryWrapper));
}
}
三、菜品展示
3.1 交互过程以及代码实现
在开发代码之前,需要梳理一下前端页面和服务端的交互过程:
1、页面(front/index.html)发送ajax请求,获取分类数据(菜品分类和套餐分类)
2、页面发送ajax请求,获取第一个分类下的菜品或者套餐
开发菜品展示功能,其实就是在服务端编写代码去处理前端页面发送的这2次请求即可。
/**
* 获取购物车内商品的集合
* @return
*/
@GetMapping("/list")
public R<List<ShoppingCart>> list(){
LambdaQueryWrapper<ShoppingCart> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(ShoppingCart::getUserId, BaseContent.getCurrentId());
queryWrapper.orderByAsc(ShoppingCart::getCreateTime);
List<ShoppingCart> shoppingCartList = shoppingCartService.list(queryWrapper);
return R.success(shoppingCartList);
}
/**
* 菜品管理中获取分类数据
* @param category
* @return
*/
@GetMapping("/list")
public R<List<Category>> getCategoryList(Category category){
LambdaQueryWrapper<Category> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(category.getType()!=null,Category::getType,category.getType());
queryWrapper.orderByDesc(Category::getSort).orderByDesc(Category::getUpdateTime);
List<Category> list= categoryService.list(queryWrapper);
return R.success(list);
}
四、购物车
4.1 代码开发
购物车中添加数据
package com.itheima.reggie.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.itheima.reggie.common.BaseContent;
import com.itheima.reggie.common.R;
import com.itheima.reggie.entity.ShoppingCart;
import com.itheima.reggie.service.ShoppingCartService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.List;
@Slf4j
@RestController
@RequestMapping("/shoppingCart")
public class ShoppingCartController {
@Resource
private ShoppingCartService shoppingCartService;
/**
* 获取购物车内商品的集合
* @return
*/
@GetMapping("/list")
public R<List<ShoppingCart>> list(){
LambdaQueryWrapper<ShoppingCart> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(ShoppingCart::getUserId, BaseContent.getCurrentId());
queryWrapper.orderByAsc(ShoppingCart::getCreateTime);
List<ShoppingCart> shoppingCartList = shoppingCartService.list(queryWrapper);
return R.success(shoppingCartList);
}
/**
* 购物车中添加商品
* @return
*/
@PostMapping("/add")
public R<ShoppingCart> add(@RequestBody ShoppingCart shoppingCart){
//添加用户ID
Long id = BaseContent.getCurrentId();
shoppingCart.setUserId(id);
//查询当前菜品或套餐是否在购物车
Long dishId = shoppingCart.getDishId();
LambdaQueryWrapper<ShoppingCart> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(shoppingCart.getUserId()!=null,ShoppingCart::getUserId,BaseContent.getCurrentId());
if(dishId == null){
//说明是套餐id
queryWrapper.eq(ShoppingCart::getSetmealId,shoppingCart.getSetmealId());
}else {
//说明是菜品id
queryWrapper.eq(ShoppingCart::getDishId,shoppingCart.getDishId());
}
ShoppingCart cartServiceOne = shoppingCartService.getOne(queryWrapper);
//如果购物车中已经存在,就加一
if(cartServiceOne != null){
Integer number = cartServiceOne.getNumber();
cartServiceOne.setNumber(number+1);
shoppingCartService.updateById(cartServiceOne);
}else {
//不存在,添加一
shoppingCart.setNumber(1);
shoppingCartService.save(shoppingCart);
cartServiceOne=shoppingCart;
}
return R.success(cartServiceOne);
}
/**
* 清空购物车
* @return
*/
@DeleteMapping("/clean")
public R<String> clearCart(){
LambdaQueryWrapper<ShoppingCart> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(ShoppingCart::getUserId,BaseContent.getCurrentId());
shoppingCartService.remove(queryWrapper);
return R.success("清空购物车成功");
}
/**
* 菜品或者套餐数量减一
* @param shoppingCart
* @return
*/
@PostMapping("/sub")
public R<String> updateCart(@RequestBody ShoppingCart shoppingCart){
log.info(shoppingCart.toString());
//查找对应购物车对应的用户
//添加用户ID
Long id = BaseContent.getCurrentId();
shoppingCart.setUserId(id);
LambdaQueryWrapper<ShoppingCart> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(shoppingCart.getUserId()!=null,ShoppingCart::getUserId,BaseContent.getCurrentId());
//判断是菜品还是套餐
Long dishId = shoppingCart.getDishId();
if(dishId!=null){
//说明是菜品
queryWrapper.eq(ShoppingCart::getDishId,shoppingCart.getDishId());
ShoppingCart one = shoppingCartService.getOne(queryWrapper);
Integer number = one.getNumber();
one.setNumber(number-1);
shoppingCartService.updateById(one);
return R.success("菜品或套餐数量更新成功");
}else {
//说明是套餐
queryWrapper.eq(ShoppingCart::getSetmealId,shoppingCart.getSetmealId());
ShoppingCart one = shoppingCartService.getOne(queryWrapper);
Integer number = one.getNumber();
one.setNumber(number-1);
shoppingCartService.updateById(one);
return R.success("菜品或套餐数量更新成功");
}
}
}
五、用户下单
5.1 代码开发
在开发代码之前,需要梳理一下用户下单操作时前端页面和服务端的交互过程:
1、在购物车中点击去结算按钮,页面跳转到订单确认页面
2、在订单确认页面,发送ajax请求,请求服务端获取当前登录用户的默认地址
3、在订单确认页面,发送ajax请求,请求服务端获取当前登录用户的购物车数据
4、在订单确认页面点击去支付按钮,发送ajax请求,请求服务端完成下单操作
package com.itheima.reggie.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.itheima.reggie.common.BaseContent;
import com.itheima.reggie.common.R;
import com.itheima.reggie.dto.OrdersDto;
import com.itheima.reggie.entity.Employee;
import com.itheima.reggie.entity.Orders;
import com.itheima.reggie.entity.User;
import com.itheima.reggie.service.OrdersService;
import com.itheima.reggie.service.UserService;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;
@RestController
@Slf4j
@RequestMapping("/order")
public class OrdersController {
@Resource
private OrdersService ordersService;
@Resource
private UserService userService;
/**
* 提交订单
* @param orders
* @return
*/
@PostMapping("/submit")
public R<String> submitOrder(@RequestBody Orders orders){
ordersService.submit(orders);
return R.success("订单提交成功");
}
/**
* 订单查询
* @param page
* @param pageSize
* @return
*/
@GetMapping("/userPage")
public R<Page> findPage(@RequestParam Integer page,
@RequestParam Integer pageSize){
Page<Orders> ipage = new Page<>(page,pageSize);
LambdaQueryWrapper<Orders> queryWrapper = new LambdaQueryWrapper<>();
Long userId = BaseContent.getCurrentId();
queryWrapper.eq(Orders::getUserId,userId);
queryWrapper.orderByDesc(Orders::getCheckoutTime);
ordersService.page(ipage,queryWrapper);
return R.success(ipage);
}
@GetMapping("/page")
public R<Page> findBackPage(@RequestParam Integer page,
@RequestParam Integer pageSize,
String number,
String beginTime,
String endTime){
Page<Orders> ipage = new Page<>(page,pageSize);
LambdaQueryWrapper<Orders> queryWrapper = new LambdaQueryWrapper<>();
//添加过滤条件
queryWrapper.like(number != null,Orders::getId, number);
queryWrapper.ge(beginTime != null,Orders::getOrderTime,beginTime);
queryWrapper.le(endTime != null,Orders::getOrderTime,endTime);
//添加排序条件
queryWrapper.orderByDesc(Orders::getCheckoutTime);
ordersService.page(ipage,queryWrapper);
//对象拷贝
Page<OrdersDto> ordersDtoPage = new Page<>();
BeanUtils.copyProperties(ipage,ordersDtoPage,"records");
List<Orders> records = ipage.getRecords();
List<OrdersDto> ordersDtoList= records.stream().map((item ->{
OrdersDto ordersDto = new OrdersDto();
BeanUtils.copyProperties(item,ordersDto);
Long userId = item.getUserId();
User user = userService.getById(userId);
if(user!=null){
String name = user.getName();
ordersDto.setUserName(name);
}
return ordersDto;
})).collect(Collectors.toList());
Page<OrdersDto> dtoPage = ordersDtoPage.setRecords(ordersDtoList);
return R.success(dtoPage);
}
/**
* 派送订单
* @param orders
* @return
*/
@PutMapping
public R<String> updateOrder(@RequestBody Orders orders){
//构造条件构造器
LambdaUpdateWrapper<Orders> updateWrapper = new LambdaUpdateWrapper<>();
//添加过滤条件
updateWrapper.eq(Orders::getId, orders.getId());
updateWrapper.set(Orders::getStatus,orders.getStatus());
ordersService.update(updateWrapper);
return R.success("订单派送成功");
}
}
六、退出功能
/**
* 用户退出
* @param request
* @return
*/
@PostMapping("/loginout")
public R<String> logout(HttpServletRequest request){
//清理Session中保存的当前登陆用户的id
request.getSession().removeAttribute("user");
return R.success("退出成功");
}
到此为止,所有功能全部实现