一、功能架构
二、数据表
三、代码开发
1、maven(pom.xml)
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.6</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>org.example</groupId>
<artifactId>reggie</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.2</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.20</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.76</version>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.23</version>
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-core</artifactId>
<version>4.5.16</version>
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-dysmsapi</artifactId>
<version>2.2.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.6.6</version>
</plugin>
</plugins>
</build>
</project>
2、application.yml
#配置服务器
server:
port: 8080
#配置spring框架
spring:
application:
name: ReggieTakeOut #应用名称(瑞吉外卖)
datasource: #数据源
druid: #druid数据源
driver-class-name: com.mysql.cj.jdbc.Driver #驱动程序
url: jdbc:mysql://localhost:3306/reggie?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowPublicKeyRetrieval=true
username: root #用户名
password: #密码
#配置连接redis 连得是linux ip的 需要在linux上启动redis usr/local/bin 命令: ./redis-server redis.conf
redis:
host:
port: 6379
password:
database: 0
mybatis-plus:
configuration:
# address_book---->AddressBook
# user_name---->userName
#在映射实体或者属性时,将数据库中表名和字段名中的下划线去掉,按照驼峰命名法映射
map-underscore-to-camel-case: true
#日志实现类 把SQL的查询过程输出到控制台
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
global-config: #全局配置
db-config: #数据库配置
id-type: ASSIGN_ID #id-type: auto #数据ID自增
cache:
redis:
time-to-live: 1800000 # 设置缓存数据过期时间
reggie:
path: E:\reggie\图片资源\
3、创建SpringApplication入口
package org.example;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.transaction.annotation.EnableTransactionManagement;
@Slf4j
@SpringBootApplication
@ServletComponentScan //过滤器
@EnableTransactionManagement //事务
public class ReggieApplication {
public static void main(String[] args) {
SpringApplication.run(ReggieApplication.class,args);
log.info("项目启动成功...");
}
}
4、实体类
①用户user
package org.example.entity;
import lombok.Data;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.List;
import java.io.Serializable;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
/**
* 用户信息
*/
@Data
public class User implements Serializable {
private static final long serialVersionUID = 1L;
private Long id;
//姓名
private String name;
//手机号
private String phone;
//性别 0 女 1 男
private String sex;
//身份证号
private String idNumber;
//头像
private String avatar;
//状态 0:禁用,1:正常
private Integer status;
}
②购物车shoppingcart
package org.example.entity;
import lombok.Data;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDateTime;
/**
* 购物车
*/
@Data
public class ShoppingCart implements Serializable {
private static final long serialVersionUID = 1L;
private Long id;
//名称
private String name;
//用户id
private Long userId;
//菜品id
private Long dishId;
//套餐id
private Long setmealId;
//口味
private String dishFlavor;
//数量
private Integer number;
//金额
private BigDecimal amount;
//图片
private String image;
private LocalDateTime createTime;
}
③套餐setmeal
package org.example.entity;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDateTime;
/**
* 套餐
*/
@Data
public class Setmeal implements Serializable {
private static final long serialVersionUID = 1L;
private Long id;
//分类id
private Long categoryId;
//套餐名称
private String name;
//套餐价格
private BigDecimal price;
//状态 0:停用 1:启用
private Integer status;
//编码
private String code;
//描述信息
private String description;
//图片
private String image;
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
@TableField(fill = FieldFill.INSERT)
private Long createUser;
@TableField(fill = FieldFill.INSERT_UPDATE)
private Long updateUser;
//是否删除
private Integer isDeleted;
}
④套餐菜品关系
package org.example.entity;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import lombok.Data;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDateTime;
/**
* 套餐菜品关系
*/
@Data
public class SetmealDish implements Serializable {
private static final long serialVersionUID = 1L;
private Long id;
//套餐id
private Long setmealId;
//菜品id
private Long dishId;
//菜品名称 (冗余字段)
private String name;
//菜品原价
private BigDecimal price;
//份数
private Integer copies;
//排序
private Integer sort;
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
@TableField(fill = FieldFill.INSERT)
private Long createUser;
@TableField(fill = FieldFill.INSERT_UPDATE)
private Long updateUser;
//是否删除
private Integer isDeleted;
}
⑤菜品Dish
package org.example.entity;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDateTime;
/**
菜品
*/
@Data
public class Dish implements Serializable {
private static final long serialVersionUID = 1L;
private Long id;
//菜品名称
private String name;
//菜品分类id
private Long categoryId;
//菜品价格
private BigDecimal price;
//商品码
private String code;
//图片
private String image;
//描述信息
private String description;
//0 停售 1 起售
private Integer status;
//顺序
private Integer sort;
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
@TableField(fill = FieldFill.INSERT)
private Long createUser;
@TableField(fill = FieldFill.INSERT_UPDATE)
private Long updateUser;
//是否删除
private Integer isDeleted;
}
⑥菜品口味DishFlavor
package org.example.entity;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
菜品口味
*/
@Data
public class DishFlavor implements Serializable {
private static final long serialVersionUID = 1L;
private Long id;
//菜品id
private Long dishId;
//口味名称
private String name;
//口味数据list
private String value;
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
@TableField(fill = FieldFill.INSERT)
private Long createUser;
@TableField(fill = FieldFill.INSERT_UPDATE)
private Long updateUser;
//是否删除
private Integer isDeleted;
}
⑦员工employee
package org.example.entity;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import lombok.Data;
import java.io.Serializable;
import java.time.LocalDateTime;
/*
* 功能:员工实体表
*/
@Data //Lombok注解,注在类上,提供类的get、set、equals、hashCode、CanEqual、toString方法
public class Employee implements Serializable {
private static final long serialVersionUID = 1L; //序列化的类中建议添加以提供版本兼容性
private Long id;
private String username;
private String name;
private String password;
private String phone;
private String sex;
private String idNumber;
private Integer status;
@TableField(fill = FieldFill.INSERT) // 插入时自动填充字段
private LocalDateTime createTime;
@TableField(fill = FieldFill.INSERT_UPDATE) // 插入和更新时自动填充字段
private LocalDateTime updateTime;
@TableField(fill = FieldFill.INSERT) //mybatis-plus注解,填充策略
private Long createUser; //对应字段 create_user
@TableField(fill = FieldFill.INSERT_UPDATE)
private Long updateUser; //对应字段 update_user
}
⑧订单orders
package org.example.entity;
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;
//下单用户id
private Long userId;
//地址id
private 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;
}
⑨订单明细orderDetail
package org.example.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
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;
//订单id
private Long orderId;
//菜品id
private Long dishId;
//套餐id
private Long setmealId;
//口味
private String dishFlavor;
//数量
private Integer number;
//金额
private BigDecimal amount;
//图片
private String image;
}
⑩地址address
package org.example.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
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;
//订单id
private Long orderId;
//菜品id
private Long dishId;
//套餐id
private Long setmealId;
//口味
private String dishFlavor;
//数量
private Integer number;
//金额
private BigDecimal amount;
//图片
private String image;
}
⑾分类category
package org.example.entity;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
* 分类
*/
@Data
public class Category implements Serializable {
private static final long serialVersionUID = 1L;
private Long id;
//类型 1 菜品分类 2 套餐分类
private Integer type;
//分类名称
private String name;
//顺序
private Integer sort;
//创建时间
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
//更新时间
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
//创建人
@TableField(fill = FieldFill.INSERT)
private Long createUser;
//修改人
@TableField(fill = FieldFill.INSERT_UPDATE)
private Long updateUser;
//是否删除
// private Integer isDeleted;
}
5、dto
①DishDto
package org.example.entity.dto;
import lombok.Data;
import org.example.entity.Dish;
import org.example.entity.DishFlavor;
import java.util.ArrayList;
import java.util.List;
@Data
public class DishDto extends Dish { //Dto Data Transfer object 数据传输对象 用于层与服务层之间的数据传输
// 新增菜品会对应两张表 1、dish 2、dishflavor
private List<DishFlavor> flavors = new ArrayList<>();
private String categoryName;
private Integer copies;
}
②OrderDto
package org.example.entity.dto;
import lombok.Data;
import org.example.entity.OrderDetail;
import org.example.entity.Orders;
import java.util.List;
@Data
public class OrdersDto extends Orders {
private String userName;
private String phone;
private String address;
private String consignee;
private List<OrderDetail> orderDetails;
private int sumNum;
}
③SetmealDto
package org.example.entity.dto;
import lombok.Data;
import org.example.entity.Setmeal;
import org.example.entity.SetmealDish;
import java.util.List;
@Data
public class SetmealDto extends Setmeal {
private List<SetmealDish> setmealDishes;
private String categoryName;
}
6、过滤器filter检查登录
LoginCheckFilter
package org.example.filter;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.example.common.BaseContext;
import org.example.common.R;
import org.springframework.util.AntPathMatcher;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* 检查用户是否已经完成登录
*/
@Slf4j
@WebFilter(filterName = "loginCheckFilter", urlPatterns = "/*")
public class LoginCheckFilter implements Filter {
//路径匹配器,支持通配符
public static final AntPathMatcher PATH_MATCHER = new AntPathMatcher();
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) servletResponse;
HttpServletRequest request = (HttpServletRequest) servletRequest;
// 1、获取本次请求的url
String requestURI = request.getRequestURI();
log.info("拦截到请求:{}", request.getRequestURI());
// 2、定义不需要请求的url
String[] urls = new String[]{
"/employee/login",
"/employee/logout",
"/backend/**",
"/front/**",
"/user/sendMsg",
"/user/login"
};
// 3、判断本次请求是否需要处理
boolean check = check(urls, requestURI);
// 4、如果不需要处理,则直接放行
if (check) {
log.info("本次请求不需要处理:{}", request.getRequestURI());
filterChain.doFilter(request, response); // 放行
return; //方法结束
}
// 在5.1和5.2前再加个检查 判断是客户端还是服务端
// 5.1、check为false 检查登录状态
if (request.getSession().getAttribute("employee") != null) { // 已登录
log.info("用户已登录,用户id为:{}", request.getSession().getAttribute("employee"));
Long empId = (Long) request.getSession().getAttribute("employee");
// 将该线程的当前用户id保存至threadlocal
BaseContext.setCurrentId(empId);
filterChain.doFilter(request, response); // 放行
return;
}
// 5.2 判断移动端登录
if (request.getSession().getAttribute("user") != null) {
log.info("用户已登录, 用户id为:{}", request.getSession().getAttribute("user"));
Long userId = (Long) request.getSession().getAttribute("user");
// 将该线程的当前用户id保存至threadlocal
BaseContext.setCurrentId(userId);
filterChain.doFilter(request, response);
return;
}
// 6、未登录根据前端返回未登录的结果
log.info("用户未登录");
response.getWriter().write(JSON.toJSONString(R.error("NOTLOGIN")));
return;
}
//check方法 遍历urls看是否匹配requestURI
public boolean check(String[] urls, String requestURI) {
for (String url : urls) {
boolean match = PATH_MATCHER.match(url, requestURI);
if (match) {
return true;
}
}
return false;
}
}
7、配置类config
WebMvcConfig
package org.example.config;
import lombok.extern.slf4j.Slf4j;
import org.example.common.JacksonObjectMapper;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
import java.util.List;
@Slf4j
@Configuration
public class WebMvcConfig extends WebMvcConfigurationSupport{
/*
* 设置资源映射 默认是映射static
* "/backend/**" 表示浏览器访问请求 "classpath:/backend/" 表示映射到本地
* ** 表示多层通配符
* */
@Override
protected void addResourceHandlers(ResourceHandlerRegistry registry){
log.info("开启静态资源映射");
registry.addResourceHandler("/backend/**").addResourceLocations("classpath:/backend/");
registry.addResourceHandler("/front/**").addResourceLocations("classpath:/front/");
}
/**
* 扩展mvc框架的消息转换器
*/
@Override
protected void extendMessageConverters(List<HttpMessageConverter<?>> converters){
log.info("扩展消息转换器...");
// 创建消息转换器对象
MappingJackson2HttpMessageConverter messageConverter = new MappingJackson2HttpMessageConverter();
//设置对象转换器 底层使用jackson将java对象转为json
messageConverter.setObjectMapper(new JacksonObjectMapper());
// 将消息转换器对象追加到mvc框架的转换器集合中
// 设置自定义的消息转换器为第一优先级
converters.add(0, messageConverter);
}
}
RedisConfig
package org.example.config;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;
@Configuration
public class RedisConfig extends CachingConfigurerSupport {
@Bean
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory){
RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setConnectionFactory(connectionFactory);
return redisTemplate;
}
}
MybatisPlusConfig 配置mybatis-plus的分页拦截器
package org.example.config;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* 配置mybatis-plus提供的分页插件拦截器
*/
@Configuration
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor(){
MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor(); // 拦截器集合
mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor()); // 向Mybatis拦截器链中添加分页拦截器
return mybatisPlusInterceptor;
}
}
8、通用
BaseContext(ThreadLocal)
package org.example.common;
/**
* 基于ThreadLocal封装工具类,用于保存和获取当前登录用户id ThreadLocal为每个线程提供单独一份储存空间
* 客户端每次http请求 服务端都会分配新的线程
* LoginCheckFilter的doFilter
* EmployeeController的update
* MyMetaObjectHandler的updateFill方法为同一个线程
*
* 使用:1、编写BaseContext工具类,基于ThreaLocal封装的工具类
* 2、在LoginCheckFilter的doFilter方法中 设置当前登录用户id
* 3、在MyMetaObjectHnadler的方法中 获取当前登录用户id
*/
public class BaseContext {
private static ThreadLocal<Long> threadLocal = new ThreadLocal<>();
public static void setCurrentId(Long id){ // 设置id
threadLocal.set(id);
}
public static Long getCurrentId(){
return threadLocal.get();
}
}
CustomException(自定义业务异常)
package org.example.common;
/**
* 自定义业务异常类
*/
public class CustomException extends RuntimeException{
public CustomException(String message){
super(message);
}
}
GlobalExceptionHandler(全局异常处理)
package org.example.common;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import java.sql.SQLIntegrityConstraintViolationException;
/**
* 全局异常类
*/
@Slf4j
@ResponseBody
@ControllerAdvice(annotations = {RestController.class, Controller.class}) // 表示拦截哪些类型的controller注解
public class GlobalExceptionHandler {
// 处理SQLIntegrityConstraintViolationException异常
@ExceptionHandler(SQLIntegrityConstraintViolationException.class)
public R<String> exceptionHandle(SQLIntegrityConstraintViolationException exception){
log.error(exception.getMessage()); // 报错打日志
if (exception.getMessage().contains("Duplicate entry")){
// 获取已经存在的用户名,从报错的异常信息中获取
String[] split = exception.getMessage().split(" ");
String msg = split[2] + "用户名已存在";
return R.error(msg);
} return R.error("未知错误");
}
// 处理自定义异常类
@ExceptionHandler(CustomException.class)
public R<String> exceptionHandle(CustomException exception){
log.error(exception.getMessage()); // 报错需要打进日志
// 传到前端显示
return R.error(exception.getMessage());
}
}
JacksonObjectMapper(消息转换器)
package org.example.common;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
import java.math.BigInteger;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import static com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES;
/**
* 定义消息转换器
* mybatis-plus对id使用了雪花算法,存入数据库中的id是19为长度,但前端的js只能保证数据的前16位的数据的精度 定义消息转换器 long->string
* 对象映射器:基于jackson将Java对象转为json,或者将json转为Java对象
* 将JSON解析为Java对象的过程称为 [从JSON反序列化Java对象]
* 从Java对象生成JSON的过程称为 [序列化Java对象到JSON]
*/
public class JacksonObjectMapper extends ObjectMapper {
public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd"; //date
public static final String DEFAULT_DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss"; // date_time
public static final String DEFAULT_TIME_FORMAT = "HH:mm:ss"; // time
public JacksonObjectMapper() {
super();
//收到未知属性时不报异常
this.configure(FAIL_ON_UNKNOWN_PROPERTIES, false);
//反序列化时,属性不存在的兼容处理
this.getDeserializationConfig().withoutFeatures(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
SimpleModule simpleModule = new SimpleModule()
.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT)))
.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT)))
.addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)))
.addSerializer(BigInteger.class, ToStringSerializer.instance)
.addSerializer(Long.class, ToStringSerializer.instance)
.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT)))
.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT)))
.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)));
//注册功能模块 例如,可以添加自定义序列化器和反序列化器
this.registerModule(simpleModule);
}
}
MyMetaObjecthandler(公共字段填充 元数据对象处理器)
package org.example.common;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
/**
* mybatis-plus 公共字段自动填充
* 1、在实体类的属性上加入@TabelField 注解,指定自动填充策略
* 2、编写元数据对象处理器,在此类中统一为公共字段赋值,此类需要实现MetaObjectHandler接口
*/
@Slf4j
@Component // 交给spring容器管理
public class MyMetaObjecthandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) { // 插入时自动填充
metaObject.setValue("createTime", LocalDateTime.now());
metaObject.setValue("updateTime", LocalDateTime.now());
metaObject.setValue("createUser", BaseContext.getCurrentId());
metaObject.setValue("updateUser", BaseContext.getCurrentId());
}
@Override
public void updateFill(MetaObject metaObject) { // 更新时自动填充
metaObject.setValue("updateTime", LocalDateTime.now());
metaObject.setValue("updateUser", BaseContext.getCurrentId());
}
}
R(通用返回结果)
package org.example.common;
import lombok.Data;
import java.util.HashMap;
import java.util.Map;
/**
* 通用返回结果类 服务器的数据最终会封装成此对象
*/
@Data //Lombok注解,注在类上,提供类的get、set、equals、hashCode、CanEqual、toString方法
public class R<T> {
private Integer code; // 编码: 1成功 0和其他数字为失败
private String msg; //错误信息
private T data; // 数据
private Map map = new HashMap(); //动态数据
public static <T> R<T> success(T object){
// <T> 表明为泛型方法 因为是静态方法需要表明
// R<T> 表明返回类型
R<T> r = new R<T>();
r.data = object;
r.code = 1;
return r;
}
public static <T> R<T> error(String msg){
R r = new R();
r.msg = msg;
r.code = 0;
return r;
}
public R<T> add(String key, Object value){
this.map.put(key, value);
return this;
}
}
9、Mapper
UserMapper
package org.example.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.example.entity.User;
@Mapper
public interface UserMapper extends BaseMapper<User> {
}
CategoryMapper
package org.example.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.example.entity.Category;
@Mapper
public interface CategoryMapper extends BaseMapper<Category> {
}
AddressBookMapper
package org.example.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.example.entity.AddressBook;
@Mapper
public interface AddressBookMapper extends BaseMapper<AddressBook> {
}
DishMapper
package org.example.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.example.entity.Dish;
@Mapper
public interface DishMapper extends BaseMapper<Dish> {
}
DishFlavorMapper
package org.example.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.example.entity.DishFlavor;
@Mapper
public interface DishFlavorMapper extends BaseMapper<DishFlavor> {
}
EmployeeMapper
package org.example.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.example.entity.Employee;
/**
* 功能:EmployeeMapper接口(和数据库交互),采用mybatis-plus插件,不用创建对应的映射器配置文件
*/
@Mapper
public interface EmployeeMapper extends BaseMapper<Employee> {
}
OrderMapper
package org.example.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.example.entity.Orders;
@Mapper
public interface OrderMapper extends BaseMapper<Orders> {
}
OrderDetailMapper
package org.example.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.example.entity.OrderDetail;
@Mapper
public interface OrderDetailMapper extends BaseMapper<OrderDetail> {
}
SetmealMapper
package org.example.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.example.entity.Setmeal;
@Mapper
public interface SetmealMapper extends BaseMapper<Setmeal> {
}
SetmealDishMapper
package org.example.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.example.entity.SetmealDish;
@Mapper
public interface SetmealDishMapper extends BaseMapper<SetmealDish> {
}
ShoppingCartMapper
package org.example.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.example.entity.ShoppingCart;
@Mapper
public interface ShoppingCartMapper extends BaseMapper<ShoppingCart> {
}
10、Service
AddressBookService
package org.example.service;
import com.baomidou.mybatisplus.extension.service.IService;
import org.example.entity.AddressBook;
public interface AddressBookService extends IService<AddressBook> {
}
CategoryService
package org.example.service;
import com.baomidou.mybatisplus.extension.service.IService;
import org.example.entity.Category;
public interface CategoryService extends IService<Category> {
// mybatis-plus 没有提供的方法 需要自己重写
void remove(Long id);
}
DishService
package org.example.service;
import com.baomidou.mybatisplus.extension.service.IService;
import org.example.entity.Dish;
import org.example.entity.dto.DishDto;
public interface DishService extends IService<Dish> {
void saveWithFlavor(DishDto dishDto); // 新增菜品 同时插入菜品对应的口味数据 两张表dish dish_flavor
DishDto getByIdWithFlavor(Long id);
void updateWithFlavor(DishDto dishDto);
}
DishFlavorsService
package org.example.service;
import com.baomidou.mybatisplus.extension.service.IService;
import org.example.entity.DishFlavor;
public interface DishFlavorService extends IService<DishFlavor> {
}
EmployeeService
package org.example.service;
import com.baomidou.mybatisplus.extension.service.IService;
import org.example.entity.Employee;
/**
* 采用了mybatis-plus插件,只需继承IService<Employee>接口
*/
public interface EmployeeService extends IService<Employee> {
}
OrdersService
package org.example.service;
import com.baomidou.mybatisplus.extension.service.IService;
import org.example.entity.Orders;
public interface OrderService extends IService<Orders> {
void submit(Orders orders);
}
OrderDetailService
package org.example.service;
import com.baomidou.mybatisplus.extension.service.IService;
import org.example.entity.OrderDetail;
public interface OrderDetailService extends IService<OrderDetail> {
}
SetmealService
package org.example.service;
import com.baomidou.mybatisplus.extension.service.IService;
import org.example.entity.Setmeal;
import org.example.entity.dto.SetmealDto;
public interface SetmealService extends IService<Setmeal> {
void saveWithDish(SetmealDto setmealDto);
SetmealDto getByIdWithDish(Long id);
void updateWithDish(SetmealDto setmealDto);
}
SetmealDishService
package org.example.service;
import com.baomidou.mybatisplus.extension.service.IService;
import org.example.entity.SetmealDish;
import org.example.entity.dto.SetmealDto;
public interface SetmealDishService extends IService<SetmealDish> {
}
ShoppingCartService
package org.example.service;
import com.baomidou.mybatisplus.extension.service.IService;
import org.example.entity.ShoppingCart;
public interface ShoppingCartService extends IService<ShoppingCart> {
}
UserService
package org.example.service;
import com.baomidou.mybatisplus.extension.service.IService;
import org.example.entity.User;
public interface UserService extends IService<User> {
}
11、ServiceImp
AddressBookServiceImp
package org.example.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.example.entity.AddressBook;
import org.example.mapper.AddressBookMapper;
import org.example.service.AddressBookService;
import org.springframework.stereotype.Service;
@Service
public class AddressBookServiceImp extends ServiceImpl<AddressBookMapper, AddressBook> implements AddressBookService {
}
CategoryServiceImp
package org.example.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.example.common.CustomException;
import org.example.entity.Category;
import org.example.entity.Dish;
import org.example.entity.Setmeal;
import org.example.mapper.CategoryMapper;
import org.example.service.CategoryService;
import org.example.service.DishService;
import org.example.service.SetmealService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class CategoryServiceImp extends ServiceImpl<CategoryMapper, Category> implements CategoryService {
@Autowired
private DishService dishService;
@Autowired
private SetmealService setmealService;
@Override
public void remove(Long id) {
// 根据id删除分类 删除之前需要进行判断是否有关联数据
//1、菜品
LambdaQueryWrapper<Dish> dishQueryWrapper = new LambdaQueryWrapper<>();
// 添加查询条件
dishQueryWrapper.eq(Dish::getCategoryId, id);
//count 根据条件计数
int dishCount = dishService.count(dishQueryWrapper);
if(dishCount > 0){ // 有关联的菜品
throw new CustomException("已经关联菜品,不能删除");
}
//2、套餐
LambdaQueryWrapper<Setmeal> setmealLambdaQueryWrapper = new LambdaQueryWrapper<>();
//添加查询条件
setmealLambdaQueryWrapper.eq(Setmeal::getCategoryId, id);
//count 根据条件计数
int setmealCount = setmealService.count(setmealLambdaQueryWrapper);
if (setmealCount > 0){
throw new CustomException("已经关联套餐, 不能删除");
}
//正常删除分类使用mybatis-plus
super.removeById(id);
}
}
DishServiceImp
package org.example.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.example.entity.Dish;
import org.example.entity.dto.DishDto;
import org.example.entity.DishFlavor;
import org.example.mapper.DishMapper;
import org.example.service.DishFlavorService;
import org.example.service.DishService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import java.util.stream.Collectors;
@Slf4j
@Service
public class DishServiceImp extends ServiceImpl<DishMapper, Dish> implements DishService {
@Autowired
private DishFlavorService dishFlavorService;
@Override
@Transactional //两张表 事务
public void saveWithFlavor(DishDto dishDto) {
this.save(dishDto); //保存菜品的基本信息到菜品表dish中
Long dishId = dishDto.getId();
//菜品口味
List<DishFlavor> flavors = dishDto.getFlavors();
flavors = flavors.stream().map((item) ->{ // 遍历flavors 设置DishId
item.setDishId(dishId);
return item;
}).collect(Collectors.toList());
// 保存菜品口味到菜品数据表
dishFlavorService.saveBatch(flavors); //saveBatch批量保存
}
@Override
public DishDto getByIdWithFlavor(Long id) {
// 查询菜品基本信息
Dish dish = this.getById(id);
DishDto dishDto = new DishDto();
BeanUtils.copyProperties(dish, dishDto);
// 查询菜品口味信息
LambdaQueryWrapper<DishFlavor> lambdaQueryWrapper = new LambdaQueryWrapper<>();
lambdaQueryWrapper.eq(DishFlavor::getDishId, dish.getId());
List<DishFlavor> list = dishFlavorService.list(lambdaQueryWrapper);
dishDto.setFlavors(list);
return dishDto;
}
@Override
public void updateWithFlavor(DishDto dishDto) {
this.updateById(dishDto); // 更新菜品表
// 操作口味表
// 1、先删除表中原来的数据
LambdaQueryWrapper<DishFlavor> lambdaQueryWrapper = new LambdaQueryWrapper<>();
lambdaQueryWrapper.eq(DishFlavor::getDishId, dishDto.getId()); // 根据菜品id删
dishFlavorService.remove(lambdaQueryWrapper);
// 2、给口味集合设置菜品id
List<DishFlavor> flavors = dishDto.getFlavors();
flavors = flavors.stream().map((item) ->{
item.setDishId(dishDto.getId());
return item;
}).collect(Collectors.toList());
dishFlavorService.saveBatch(flavors);
}
}
DishFlavorsServiceImp
package org.example.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.example.entity.DishFlavor;
import org.example.mapper.DishFlavorMapper;
import org.example.service.DishFlavorService;
import org.springframework.stereotype.Service;
@Service
public class DishFlavorServiceImp extends ServiceImpl<DishFlavorMapper, DishFlavor> implements DishFlavorService {
}
EmployeeServiceImp
package org.example.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.example.entity.Employee;
import org.example.mapper.EmployeeMapper;
import org.example.service.EmployeeService;
import org.springframework.stereotype.Service;
/**
* 雇员服务接口实现类
*/
@Service
public class EmployeeServiceImpl extends ServiceImpl<EmployeeMapper, Employee> implements EmployeeService {
}
OrdersServiceImp
package org.example.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.example.common.BaseContext;
import org.example.common.CustomException;
import org.example.entity.AddressBook;
import org.example.entity.Orders;
import org.example.entity.ShoppingCart;
import org.example.entity.User;
import org.example.entity.OrderDetail;
import org.example.mapper.OrderMapper;
import org.example.service.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
@Service
public class OrderServiceImp extends ServiceImpl<OrderMapper, Orders> implements OrderService {
@Autowired
private ShoppingCartService shoppingCartService;
@Autowired
private UserService userService;
@Autowired
private AddressBookService addressBookService;
@Autowired
private OrderDetailService orderDetailService;
@Override
@Transactional
public void submit(Orders orders) {
Long userId = BaseContext.getCurrentId();
LambdaQueryWrapper<ShoppingCart> shoppingCartLambdaQueryWrapper = new LambdaQueryWrapper<>();
shoppingCartLambdaQueryWrapper.eq(ShoppingCart::getUserId, userId);
List<ShoppingCart> shoppingCarts = shoppingCartService.list(shoppingCartLambdaQueryWrapper);
if (shoppingCarts == null || shoppingCarts.size() == 0){
throw new CustomException("购物车为空,不能下单");
}
// 查询地址
Long addressBookId = orders.getAddressBookId();
AddressBook addressBook = addressBookService.getById(addressBookId);
if (addressBook == null){
throw new CustomException("地址信息有误,不能下单");
}
// 生成订单号
long orderId = IdWorker.getId();
orders.setId(orderId);
// 计算金额
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());
// 批量添加订单明细表
orderDetailService.saveBatch(orderDetails);
// 给order添加信息
User user = userService.getById(userId);
orders.setNumber(String.valueOf(orderId)); // String.valueOf(orderId) 建id转为string类型
orders.setId(orderId);
orders.setOrderTime(LocalDateTime.now());
orders.setCheckoutTime(LocalDateTime.now());
orders.setStatus(2);
orders.setAmount(new BigDecimal(amount.get())); // 计算总金额
orders.setUserId(userId);
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);
// 下单后清空购物车数据
shoppingCartService.remove(shoppingCartLambdaQueryWrapper);
}
}
OrderDetailServiceImp
package org.example.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.example.entity.OrderDetail;
import org.example.mapper.OrderDetailMapper;
import org.example.service.OrderDetailService;
import org.springframework.stereotype.Service;
@Service
public class OrderDetailServiceImpl extends ServiceImpl<OrderDetailMapper, OrderDetail> implements OrderDetailService {
}
SetmealServiceImp
package org.example.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.example.entity.Setmeal;
import org.example.entity.SetmealDish;
import org.example.entity.dto.SetmealDto;
import org.example.mapper.SetmealMapper;
import org.example.service.SetmealDishService;
import org.example.service.SetmealService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import java.util.stream.Collectors;
@Slf4j
@Service
public class SetmealServiceImp extends ServiceImpl<SetmealMapper, Setmeal> implements SetmealService {
@Autowired
private SetmealDishService setmealDishService;
@Override
@Transactional
public void saveWithDish(SetmealDto setmealDto) {
// log.info(setmealDto.toString()); // 可以先查看传入的基本信息
this.save(setmealDto); // 保存套餐基本信息
List<SetmealDish> setmealDishes = setmealDto.getSetmealDishes();
setmealDishes.stream().map((item) ->{
item.setSetmealId(setmealDto.getId());
return item;
}).collect(Collectors.toList());
setmealDishService.saveBatch(setmealDishes); // setmeal_dish表
}
@Override
public SetmealDto getByIdWithDish(Long id) {
// 查询套餐基本信息
Setmeal setmeal = this.getById(id);
SetmealDto setmealDto = new SetmealDto();
BeanUtils.copyProperties(setmeal, setmealDto);
//查询套餐菜品信息
LambdaQueryWrapper<SetmealDish> lambdaQueryWrapper = new LambdaQueryWrapper<>();
lambdaQueryWrapper.eq(SetmealDish::getSetmealId, setmeal.getId());
List<SetmealDish> list = setmealDishService.list(lambdaQueryWrapper);
setmealDto.setSetmealDishes(list);
return setmealDto;
}
@Override
public void updateWithDish(SetmealDto setmealDto) {
// 更新基本信息
this.updateById(setmealDto);
// 更新口味信息
// 1、先删除原来的口味
LambdaQueryWrapper<SetmealDish> lambdaQueryWrapper = new LambdaQueryWrapper<>();
lambdaQueryWrapper.eq(SetmealDish::getSetmealId, setmealDto.getId());
setmealDishService.remove(lambdaQueryWrapper);
//2、 写入新的口味
List<SetmealDish> setmealDishes = setmealDto.getSetmealDishes();
setmealDishes = setmealDishes.stream().map((item) ->{
item.setSetmealId(setmealDto.getId());
return item;
}).collect(Collectors.toList());
setmealDishService.saveBatch(setmealDishes);
}
}
SetmealDishServiceImp
package org.example.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.example.entity.SetmealDish;
import org.example.entity.dto.SetmealDto;
import org.example.mapper.SetmealDishMapper;
import org.example.service.SetmealDishService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class SetmealDishServiceImp extends ServiceImpl<SetmealDishMapper, SetmealDish> implements SetmealDishService {
}
ShoppingCartServiceImp
package org.example.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.example.entity.ShoppingCart;
import org.example.mapper.ShoppingCartMapper;
import org.example.service.ShoppingCartService;
import org.springframework.stereotype.Service;
@Service
public class ShoppingCartServiceImp extends ServiceImpl<ShoppingCartMapper, ShoppingCart> implements ShoppingCartService {
}
UserServiceImp
package org.example.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.example.entity.User;
import org.example.mapper.UserMapper;
import org.example.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class UserServiceImp extends ServiceImpl<UserMapper, User> implements UserService {
}
12、Controller
AddressBookController
package org.example.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import lombok.extern.slf4j.Slf4j;
import org.example.common.BaseContext;
import org.example.common.R;
import org.example.entity.AddressBook;
import org.example.service.AddressBookService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@Slf4j
@RestController
@RequestMapping("/addressBook")
public class AddressBookController {
@Autowired
private AddressBookService addressBookService;
@PostMapping()
public R<AddressBook> save(@RequestBody AddressBook addressBook){ // 新增地址
addressBook.setUserId(BaseContext.getCurrentId()); // 当前用户id
log.info("addressBook:{}", addressBook);
addressBookService.save(addressBook);
return R.success(addressBook);
}
@PutMapping("/default")
public R<AddressBook> setDefault(@RequestBody AddressBook addressBook){ // 设置默认地址
log.info("addressBook:{}", addressBook);
// 使用的是update
LambdaUpdateWrapper<AddressBook> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
lambdaUpdateWrapper.eq(AddressBook::getUserId, BaseContext.getCurrentId());
lambdaUpdateWrapper.set(AddressBook::getIsDefault, 0); // 直接更新 把所有都设为非默认
addressBookService.update(lambdaUpdateWrapper);
// 把传入的地址设为默认
addressBook.setIsDefault(1);
addressBookService.updateById(addressBook);
return R.success(addressBook);
}
@GetMapping("/{id}")
public R get(@PathVariable Long id){ // 根据id查询地址
AddressBook addressBook = addressBookService.getById(id);
if (addressBook != null){
return R.success(addressBook);
} else {
return R.error("没有找到该对象");
}
}
@GetMapping("/default")
public R<AddressBook> getDefault(){
LambdaQueryWrapper<AddressBook> lambdaQueryWrapper = new LambdaQueryWrapper<>();
lambdaQueryWrapper.eq(AddressBook::getUserId, BaseContext.getCurrentId()); // 先查该用户
lambdaQueryWrapper.eq(AddressBook::getIsDefault, 1);
AddressBook addressBook = addressBookService.getOne(lambdaQueryWrapper);
if (addressBook == null){
return R.error("没有找到该对象");
} else {
return R.success(addressBook);
}
}
@GetMapping("/list")
public R<List<AddressBook>> list(AddressBook addressBook){ // 展示该用户全部地址
addressBook.setUserId(BaseContext.getCurrentId());
log.info("addressBook:{}", addressBook);
LambdaQueryWrapper<AddressBook> lambdaQueryWrapper = new LambdaQueryWrapper<>();
lambdaQueryWrapper.eq(addressBook.getUserId() != null, AddressBook::getUserId, addressBook.getUserId());
lambdaQueryWrapper.orderByDesc(AddressBook::getUpdateTime);
List<AddressBook> list = addressBookService.list(lambdaQueryWrapper);
return R.success(list);
}
}
CategoryController
package org.example.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import org.example.common.R;
import org.example.entity.Category;
import org.example.service.CategoryService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* 菜品分类管理层
*/
@Slf4j
@RestController //交给spring容器管理
@RequestMapping("/category")
public class CategoryController {
@Autowired
private CategoryService categoryService;
@PostMapping() // 新增套餐分类
public R<String> save(@RequestBody Category category) {
log.info("category:{}", category);
categoryService.save(category);
return R.success("新增分类成功");
}
@GetMapping("/page") // 分页
public R<Page> page(int page, int pageSize) {
// 创造分页构造器
Page<Category> categoryPage = new Page<>(page, pageSize);
// 创造条件构造器用来排序 注意使用泛型
LambdaQueryWrapper<Category> queryWrapper = new LambdaQueryWrapper();
// 添加排序条件 sort字段排序
queryWrapper.orderByAsc(Category::getSort);
categoryService.page(categoryPage, queryWrapper);
return R.success(categoryPage);
}
@DeleteMapping()
public R<String> delete(@RequestParam("ids") Long ids) { // 根据id删除分类 前端传的是ids
categoryService.remove(ids);
return R.success("分类信息删除成功");
}
@PutMapping()
public R<String> update(@RequestBody Category category){ // 根据id修改分类
categoryService.updateById(category);
return R.success("修改分类信息成功");
}
@GetMapping("/list") // 菜品分类下拉框
public R<List<Category>> list(Category category){ // 根据条件查询分类数据
// 条件构造器
LambdaQueryWrapper<Category> lambdaQueryWrapper = new LambdaQueryWrapper<>();
// 添加条件
lambdaQueryWrapper.eq(category.getType() != null, Category::getType, category.getType());
// 添加排序条件
lambdaQueryWrapper.orderByAsc(Category::getSort).orderByAsc(Category::getUpdateTime);
// 调用查询
List<Category> list = categoryService.list(lambdaQueryWrapper);
return R.success(list);
}
}
CommonController
package org.example.controller;
import lombok.extern.slf4j.Slf4j;
import org.example.common.R;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.UUID;
@Slf4j
@RestController
@RequestMapping("/common")
public class CommonController {
// @Value("${reggie.path}")
@Value("${reggie.path}")
private String basePath;
@PostMapping("/upload")
public R<String> upload(MultipartFile file) { // 文件上传
// file为临时文件,需要转存到客户端指定位置
// 拿到文件原名
String originalFilename = file.getOriginalFilename();
// 文件后缀
String suffix = originalFilename.substring(originalFilename.lastIndexOf("."));
// 使用uuid作为文件名的一部分,防止同名覆盖
String fileName = UUID.randomUUID().toString() + suffix;
// 创建file对象,该目录若不存在就创建
File dir = new File(basePath);
if (!dir.exists()) { // 该目录不存在
dir.mkdirs(); // 创建目录
}
try {
file.transferTo(new File(basePath + fileName)); // 前端传的文件进行转存
} catch (IOException e) {
e.printStackTrace();
}
return R.success(fileName);
}
@GetMapping("/download")
public void download(String name, HttpServletResponse response) { // 文件下载
// name 为需要下载的文件名
try {
// 下载:先读(输入)
FileInputStream fileInputStream = new FileInputStream(new File(basePath + name)); // 从储存图片的地方获取用户需要的图片对象
//再输出(写入响应体)
ServletOutputStream outputStream = response.getOutputStream();
// 设置写回的文件类型
response.setContentType("image/jpeg");
// 读写文件
int len = 0;
byte[] buf = new byte[1024];
while ((len = fileInputStream.read(buf)) != -1) {
outputStream.write(buf, 0, len); // 边读边写
outputStream.flush();
}
// 关闭流
outputStream.close();
fileInputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
DishController
package org.example.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import org.example.common.R;
import org.example.entity.Category;
import org.example.entity.Dish;
import org.example.entity.DishFlavor;
import org.example.entity.dto.DishDto;
import org.example.service.CategoryService;
import org.example.service.DishFlavorService;
import org.example.service.DishService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
@Slf4j
@RestController
@RequestMapping("/dish")
public class DishController {
@Autowired
private DishService dishService;
@Autowired
private DishFlavorService dishFlavorService;
@Autowired
private CategoryService categoryService;
@Autowired
private RedisTemplate redisTemplate;
@PostMapping()
public R<String> save(@RequestBody DishDto dishDto) {
dishService.saveWithFlavor(dishDto);
// 保持数据库和缓存内容一致
String key = "dish_" + dishDto.getCategoryId() + "_" + dishDto.getStatus();
redisTemplate.delete(key); // 删除缓存
return R.success("新增菜品成功");
}
@GetMapping("/page")
public R<Page> page(int page, int pageSize, String name) { // 分页
//分页构造器对象
Page<Dish> dishPage = new Page<>(page, pageSize); // 菜品表
Page<DishDto> dishDtoPage = new Page<>(page, pageSize); // 口味表
//条件
LambdaQueryWrapper<Dish> lambdaQueryWrapper = new LambdaQueryWrapper<>();
//添加模糊匹配条件
lambdaQueryWrapper.like(name != null, Dish::getName, name);
//添加排序条件
lambdaQueryWrapper.orderByDesc(Dish::getUpdateTime);
//mybatis-plus处理
dishService.page(dishPage, lambdaQueryWrapper);
List<Dish> records = dishPage.getRecords(); // 得到dish的所有数据records属性是分页插件中表示分页中所有的数据的一个集合
List<DishDto> list = records.stream().map((item) -> { // 对每个菜品进行categoryName赋值
DishDto dishDto = new DishDto();
BeanUtils.copyProperties(item, dishDto); // item相当于Dish 对dishDto进行除categoryName拷贝
Long categoryId = item.getCategoryId(); // 获取分类id
Category category = categoryService.getById(categoryId); // 通过分类id获取分类对象
if (category != null) {
String categoryName = category.getName();
dishDto.setCategoryName(categoryName); // 设置categoryName
}
return dishDto;
}).collect(Collectors.toList());
BeanUtils.copyProperties(dishPage, dishDtoPage, "records"); // records 不拷贝
dishDtoPage.setRecords(list); // 设置有categoryName的records
return R.success(dishDtoPage);
}
@GetMapping("/{id}") // 修改菜品页面的回显
public R<DishDto> getById(@PathVariable Long id) {
DishDto dishDto = dishService.getByIdWithFlavor(id);
return R.success(dishDto);
}
@PutMapping()
public R<String> update(@RequestBody DishDto dishDto) { //修改菜品
dishService.updateWithFlavor(dishDto);
// 保持数据库和缓存内容一致
String key = "dish_" + dishDto.getCategoryId() + "_" + dishDto.getStatus();
redisTemplate.delete(key); // 删除缓存
return R.success("修改菜品成功");
}
@PostMapping("/status/{status}") // 起售停售
public R<String> sale(@PathVariable int status, String[] ids){
for (String id:ids){
Dish dish = dishService.getById(id);
dish.setStatus(status);
dishService.updateById(dish);
}
//String key = "dish_" + dishDto.getCategoryId() + "_" + dishDto.getStatus();
//redisTemplate.delete(key); // 不用删除缓存 因为key变了
return R.success("修改成功");
}
// 删除菜品
@DeleteMapping()
public R<String> delete(String[] ids){
for (String id: ids){
dishService.removeById(id);
}
return R.success("删除成功");
}
@GetMapping("/list")
/**
* 移动端展示菜品也是这个请求 但是需要用DishDto来增加口味显示
public R<List<Dish>> list(Dish dish){ // 展示菜品
//条件构造器
LambdaQueryWrapper<Dish> lambdaQueryWrapper = new LambdaQueryWrapper<>();
//添加条件1、(起售的菜品)
lambdaQueryWrapper.eq(Dish::getStatus, 1);
//添加条件2、菜品分类
lambdaQueryWrapper.eq(dish.getCategoryId() != null, Dish::getCategoryId, dish.getCategoryId());
//排序(先sort排序再更新时间排序)
lambdaQueryWrapper.orderByAsc(Dish::getSort).orderByDesc(Dish::getUpdateTime);
List<Dish> list = dishService.list(lambdaQueryWrapper);
return R.success(list);
}*/
public R<List<DishDto>> list(Dish dish){
// 先从redis中看是否有缓存
List<DishDto> dishDtoList = null;
String key = "dish_" + dish.getCategoryId() + "_" + dish.getStatus();
dishDtoList = (List<DishDto>) redisTemplate.opsForValue().get(key);
if (dishDtoList != null){
return R.success(dishDtoList);
}
// 如果redis中没有 调用数据库
//条件构造器
LambdaQueryWrapper<Dish> lambdaQueryWrapper = new LambdaQueryWrapper<>();
//添加条件1、(起售的菜品)
lambdaQueryWrapper.eq(Dish::getStatus, 1);
//添加条件2、菜品分类
lambdaQueryWrapper.eq(dish.getCategoryId() != null, Dish::getCategoryId, dish.getCategoryId());
//排序(先sort排序再更新时间排序)
lambdaQueryWrapper.orderByAsc(Dish::getSort).orderByDesc(Dish::getUpdateTime);
List<Dish> list = dishService.list(lambdaQueryWrapper);
// 集合泛型转化
dishDtoList = list.stream().map((item) ->{
DishDto dishDto = new DishDto();
BeanUtils.copyProperties(item, dishDto);
// 添加分类名
Long categoryId = item.getCategoryId();
Category category = categoryService.getById(categoryId);
if (category != null){
String categoryName = category.getName();
dishDto.setCategoryName(categoryName);
}
// 添加口味
Long dishId = item.getId();
LambdaQueryWrapper<DishFlavor> flavorQueryWrapper = new LambdaQueryWrapper<>();
flavorQueryWrapper.eq(DishFlavor::getDishId, dishId);
List<DishFlavor> dishFlavorList = dishFlavorService.list(flavorQueryWrapper);
dishDto.setFlavors(dishFlavorList);
return dishDto;
}).collect(Collectors.toList());
// 添加至redis 有效期60分钟
redisTemplate.opsForValue().set(key, dishDtoList, 60, TimeUnit.MINUTES);
return R.success(dishDtoList);
}
}
EmployeeController
package org.example.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.example.common.R;
import org.example.entity.Employee;
import org.example.service.EmployeeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.DigestUtils;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.time.LocalDateTime;
/**
* 员工管理层
*/
@Slf4j
@RestController
@RequestMapping("/employee")
public class EmployeeController {
@Autowired
private EmployeeService employeeService;
@PostMapping("/login")
public R<Employee> login(HttpServletRequest request, @RequestBody Employee employee){
// 1、根据页面提交的employee获取用户名查询数据库
LambdaQueryWrapper<Employee> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(Employee::getUsername, employee.getUsername());
// Employee::getUsername 相当于创建Employee对象调用getUsername方法 与 employee.getUsername()页面提交的用户名匹配
Employee emp = employeeService.getOne(queryWrapper); //返回查询到的employee对象
// 2、 找不到用户返回错误信息
if(emp == null){
return R.error("登录失败[用户名错误]");
}
// 3、将页面提交的employee获取password后做md5处理
String password = employee.getPassword();
password = DigestUtils.md5DigestAsHex(password.getBytes());
// 4、密码比对
if(!emp.getPassword().equals(password)){
return R.error("登录失败[密码错误]");
}
// 5、查看员工转态是否禁用
if(emp.getStatus() == 0){
return R.error("账号禁用");
}
// 6、登录成功,将员工id存入到session域并返回登录结果 或形参为Httpsession
request.getSession().setAttribute("employee", emp.getId());
return R.success(emp);
}
// 退出登录
@PostMapping("/logout")
public R<String> logout(HttpSession session){
// 清理session中保存的当前员工id
session.removeAttribute("employee");
return R.success("退出成功");
}
// 注册新员工
@PostMapping() // 注册的请求就是/employee 在类中已经写了
public R<String> save(HttpServletRequest request, @RequestBody Employee employee){
// 初始化密码为12345
employee.setPassword(DigestUtils.md5DigestAsHex("12345".getBytes()));
// 创建时间
employee.setCreateTime(LocalDateTime.now());
// 更新时间
employee.setUpdateTime(LocalDateTime.now());
// 获得当前登录用户的id
Long empId = (Long) request.getSession().getAttribute("employee");
// 创建人
employee.setCreateUser(empId);
// 更新人
employee.setUpdateUser(empId);
// 调用service
employeeService.save(employee);
return R.success("新增员工成功");
}
@GetMapping("/page") // 员工信息分页
// ①用户登录成功时,分页查询一次 ②用户使用条件查询的时候分页一次 ③跳转页面的时候分页查询一次
public R<Page> page(int page, int pageSize, String name){
//返回page对象(mybatis-plus的page对象),因为前端需要这些分页的数据(比如当前页,总页数)
// page 当前页 pageSize 一页最多几条数据 name 查询员工的信息
Page pageInfo = new Page(page, pageSize); // 构造分页构造器即page对象
LambdaQueryWrapper<Employee> queryWrapper = new LambdaQueryWrapper(); // 构造条件构造器
// StringUtils.isNotEmpty(name) 条件不为空 模糊匹配
queryWrapper.like(StringUtils.isNotEmpty(name), Employee::getName, name);
queryWrapper.orderByDesc(Employee::getUpdateTime); // 添加排序条件
employeeService.page(pageInfo, queryWrapper); // 执行查询
return R.success(pageInfo);
}
@PutMapping() //put方式提交 update 禁用和编辑员工信息都是这个方法
public R<String> update(HttpServletRequest request, @RequestBody Employee employee){
log.info(employee.toString());
Long empId = (Long) request.getSession().getAttribute("employee"); // 获取操作者id
employee.setUpdateTime(LocalDateTime.now()); // 更新时间
employee.setUpdateUser(empId); // 更新操作者
employeeService.updateById(employee); //动态sql 通用更新
return R.success("员工信息修改成功");
}
@GetMapping("/{id}")
public R<Employee> getById(@PathVariable Long id){
Employee employee = employeeService.getById(id); // 调用service的通过id查询方法
if (employee != null){
return R.success(employee);
}
return R.error("没有查询到该员工的信息");
}
}
OrdersController
package org.example.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.example.common.R;
import org.example.entity.OrderDetail;
import org.example.entity.Orders;
import org.example.entity.dto.OrdersDto;
import org.example.service.OrderDetailService;
import org.example.service.OrderService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;
@Slf4j
@RestController
@RequestMapping("/order")
public class orderController {
@Autowired
private OrderService orderService;
@Autowired
private OrderDetailService orderDetailService;
@PostMapping("/submit")
public R<String> submit(@RequestBody Orders orders){
orderService.submit(orders);
return R.success("下单成功");
}
@Transactional
@GetMapping("/userPage")
public R<Page> userPage(int page, int pageSize){ // 查看历史订单
// 构造分页构造器
Page<Orders> pageInfo = new Page<>(page, pageSize);
Page<OrdersDto> ordersDtoPage = new Page<>();
// 构造条件构造器
LambdaQueryWrapper<Orders> lambdaQueryWrapper = new LambdaQueryWrapper<>();
lambdaQueryWrapper.orderByDesc(Orders::getOrderTime);
orderService.page(pageInfo, lambdaQueryWrapper);
List<Orders> records = pageInfo.getRecords();
List<OrdersDto> list = records.stream().map((item) ->{
OrdersDto ordersDto = new OrdersDto();
BeanUtils.copyProperties(item, ordersDto);
Long id = item.getId();
Orders orders = orderService.getById(id);
String number = orders.getNumber();
LambdaQueryWrapper<OrderDetail> orderDetailLambdaQueryWrapper = new LambdaQueryWrapper<>();
orderDetailLambdaQueryWrapper.eq(OrderDetail::getOrderId, number);
List<OrderDetail> orderDetailList = orderDetailService.list(orderDetailLambdaQueryWrapper);
int num = 0;
for (OrderDetail l: orderDetailList){
num += l.getNumber().intValue();
}
ordersDto.setSumNum(num);
return ordersDto;
}).collect(Collectors.toList());
// 拷贝
BeanUtils.copyProperties(pageInfo, ordersDtoPage, "records");
ordersDtoPage.setRecords(list);
return R.success(ordersDtoPage);
}
@Transactional
@PostMapping("/again")
public R<String> again(@RequestBody Orders orders){ // 再来一单
Long id = orders.getId();
Orders ordersServiceById = orderService.getById(id);
// 设置订单号码
long ordersId = IdWorker.getId();
ordersServiceById.setId(ordersId);
// 设置订单号码
String number = String.valueOf(IdWorker.getId());
ordersServiceById.setNumber(number);
// 设置下单时间
ordersServiceById.setOrderTime(LocalDateTime.now());
ordersServiceById.setCheckoutTime(LocalDateTime.now());
ordersServiceById.setStatus(2);
// 写入订单表
orderService.save(ordersServiceById);
// 修改订单明细表
LambdaQueryWrapper<OrderDetail> orderDetailLambdaQueryWrapper = new LambdaQueryWrapper<>();
orderDetailLambdaQueryWrapper.eq(OrderDetail::getOrderId, id);
List<OrderDetail> list = orderDetailService.list(orderDetailLambdaQueryWrapper);
list.stream().map((item) ->{
// 设置id
long detailId = IdWorker.getId();
item.setOrderId(ordersId);
item.setId(detailId);
return item;
}).collect(Collectors.toList());
orderDetailService.saveBatch(list);
return R.success("再来一单");
}
@GetMapping("/page")
public R<Page> page(int page, int pageSize, String number, String beginTime, String endTime){ // 后端查看订单
Page<Orders> pageInfo = new Page<>(page, pageSize);
Page<OrdersDto> ordersDtoPage = new Page<>();
LambdaQueryWrapper<Orders> lambdaQueryWrapper = new LambdaQueryWrapper<>();
lambdaQueryWrapper.like(!StringUtils.isEmpty(number), Orders::getNumber, number);
if (beginTime != null && endTime != null){
lambdaQueryWrapper.ge(Orders::getOrderTime, beginTime);
lambdaQueryWrapper.le(Orders::getOrderTime, endTime);
}
lambdaQueryWrapper.orderByDesc(Orders::getOrderTime);
orderService.page(pageInfo, lambdaQueryWrapper);
BeanUtils.copyProperties(pageInfo, ordersDtoPage, "records");
List<Orders> records = pageInfo.getRecords();
List<OrdersDto> list = records.stream().map((item) ->{
OrdersDto ordersDto = new OrdersDto();
BeanUtils.copyProperties(item, ordersDto);
String name = "用户" + item.getUserId();
ordersDto.setUserName(name);
return ordersDto;
}).collect(Collectors.toList());
ordersDtoPage.setRecords(list);
return R.success(ordersDtoPage);
}
@PutMapping
public R<String> send(@RequestBody Orders orders){ // 订单配送按钮
Long id = orders.getId();
Integer status = orders.getStatus();
LambdaQueryWrapper<Orders> lambdaQueryWrapper = new LambdaQueryWrapper<>();
lambdaQueryWrapper.eq(Orders::getId, id);
Orders order = orderService.getOne(lambdaQueryWrapper);
order.setStatus(status);
orderService.updateById(order);
return R.success("派送成功");
}
}
SetmealController
package org.example.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.example.common.R;
import org.example.entity.Category;
import org.example.entity.Setmeal;
import org.example.entity.dto.SetmealDto;
import org.example.service.CategoryService;
import org.example.service.SetmealDishService;
import org.example.service.SetmealService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.stream.Collectors;
@Slf4j
@RestController
@RequestMapping("/setmeal")
public class SetmealController {
@Autowired
private SetmealService setmealService;
@Autowired
private SetmealDishService setmealDishService;
@Autowired
private CategoryService categoryService;
@PostMapping()
@CacheEvict(value = "setmealCache", allEntries = true) // 标注在需要清除缓存元素的方法或类上
public R<String> save(@RequestBody SetmealDto setmealDto) {
// 可以先查看传入内容
//log.info("setmeal:{}", setmealDto);
setmealService.saveWithDish(setmealDto);
return R.success("新增套餐成功");
}
@GetMapping("/page")
public R<Page> page(int page, int pageSize, String name) { // 分页
//构造分页构造器
Page<Setmeal> pageInfo = new Page<>(page, pageSize);
Page<SetmealDto> pageDtoInfo = new Page<>();
// 条件构造器
LambdaQueryWrapper<Setmeal> lambdaQueryWrapper = new LambdaQueryWrapper<>();
// 根据name模糊查询
lambdaQueryWrapper.like(!StringUtils.isEmpty(name), Setmeal::getName, name);
// 添加排序条件
lambdaQueryWrapper.orderByDesc(Setmeal::getUpdateTime);
// 调用mybatis-plus
setmealService.page(pageInfo, lambdaQueryWrapper);
// 拷贝
BeanUtils.copyProperties(pageInfo, pageDtoInfo, "records");
//修改records
List<Setmeal> records = pageInfo.getRecords();
List<SetmealDto> list = records.stream().map((item) -> {
SetmealDto setmealDto = new SetmealDto();
BeanUtils.copyProperties(item, setmealDto);
Long categoryId = item.getCategoryId(); // 获得分类id
Category category = categoryService.getById(categoryId);
if (category != null) {
String categoryName = category.getName();
setmealDto.setCategoryName(categoryName); // 设置分类名
}
return setmealDto;
}).collect(Collectors.toList());
pageDtoInfo.setRecords(list);
return R.success(pageDtoInfo);
}
@DeleteMapping()
@CacheEvict(value = "setmealCache", allEntries = true)
public R<String> delete(String[] ids) {
int index = 0;
for (String id : ids) {
Setmeal setmeal = setmealService.getById(id);
if (setmeal.getStatus() != 1) {
setmealService.removeById(id);
} else {
index++;
}
}
if (index > 0 && index == ids.length) {
return R.error("选中的套餐均为启售状态,不能删除");
} else {
return R.success("删除成功");
}
}
@PostMapping("/status/{status}")
// @CacheEvict(value = "setmealCache", allEntries = true) key变了不用删除
public R<String> sale(@PathVariable int status, String[] ids){
for (String id:ids){
Setmeal setmeal = setmealService.getById(id);
setmeal.setStatus(status);
setmealService.updateById(setmeal);
}
return R.success("修改成功");
}
@GetMapping("/{id}")
public R<SetmealDto> getById(@PathVariable Long id){
SetmealDto setmealDto = setmealService.getByIdWithDish(id);
return R.success(setmealDto);
}
@PutMapping()
@CacheEvict(value = "setmealCache", allEntries = true)
public R<String> update(@RequestBody SetmealDto setmealDto){
setmealService.updateWithDish(setmealDto);
return R.success("修改成功");
}
@GetMapping("/list")
@Cacheable(value = "setmealCache", key = "#setmeal.categoryId + '_' + #setmeal.status") // cache redis注解 查找添加缓存
public R<List<Setmeal>> list(Setmeal setmeal){ // 移动端套餐展示
LambdaQueryWrapper<Setmeal> lambdaQueryWrapper = new LambdaQueryWrapper<>();
lambdaQueryWrapper.eq(setmeal.getCategoryId() != null, Setmeal::getCategoryId, setmeal.getCategoryId());
lambdaQueryWrapper.eq(setmeal.getStatus() != null, Setmeal::getStatus, setmeal.getStatus());
lambdaQueryWrapper.orderByDesc(Setmeal::getUpdateTime);
List<Setmeal> list = setmealService.list(lambdaQueryWrapper);
return R.success(list);
}
}
ShoppingCartController
package org.example.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.example.common.BaseContext;
import org.example.common.R;
import org.example.entity.ShoppingCart;
import org.example.service.ShoppingCartService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@Slf4j
@RestController
@RequestMapping("/shoppingCart")
public class ShoppingCartController {
@Autowired
private ShoppingCartService shoppingCartService;
@PostMapping("/add")
public R<ShoppingCart> add(@RequestBody ShoppingCart shoppingCart){
Long currentId = BaseContext.getCurrentId();
shoppingCart.setUserId(currentId); //给购物车设置用户id
Long dishId = shoppingCart.getDishId();
LambdaQueryWrapper<ShoppingCart> shoppingCartLambdaQueryWrapper = new LambdaQueryWrapper<>();
shoppingCartLambdaQueryWrapper.eq(ShoppingCart::getUserId, currentId); // 该用户的购物车
if (dishId != null){ // 添加的是菜品
shoppingCartLambdaQueryWrapper.eq(ShoppingCart::getDishId, dishId);
} else { // 添加的是套餐 也可能菜品和套餐都没有 即新添加的
shoppingCartLambdaQueryWrapper.eq(ShoppingCart::getSetmealId, shoppingCart.getSetmealId());
}
// 查询当前菜品是否在购物车中
ShoppingCart cartServiceOne = shoppingCartService.getOne(shoppingCartLambdaQueryWrapper);
if (cartServiceOne != null){ // 已存在就数量+1
Integer number = cartServiceOne.getNumber();
cartServiceOne.setNumber(number + 1);
shoppingCartService.updateById(cartServiceOne);
} else { // 不存在就添加进购物车
shoppingCart.setNumber(1);
shoppingCartService.save(shoppingCart);
cartServiceOne = shoppingCart;
}
return R.success(cartServiceOne);
}
@GetMapping("/list") // 购物车展示
public R<List<ShoppingCart>> list(){
LambdaQueryWrapper<ShoppingCart> shoppingCartLambdaQueryWrapper = new LambdaQueryWrapper<>();
shoppingCartLambdaQueryWrapper.eq(ShoppingCart::getUserId, BaseContext.getCurrentId());
shoppingCartLambdaQueryWrapper.orderByAsc(ShoppingCart::getCreateTime);
List<ShoppingCart> list = shoppingCartService.list(shoppingCartLambdaQueryWrapper);
return R.success(list);
}
@DeleteMapping("/clean")
public R<String> clean(){
LambdaQueryWrapper<ShoppingCart> lambdaQueryWrapper = new LambdaQueryWrapper<>();
lambdaQueryWrapper.eq(ShoppingCart::getUserId, BaseContext.getCurrentId());
shoppingCartService.remove(lambdaQueryWrapper);
return R.success("清空购物车成功");
}
@PostMapping("/sub")
public R<ShoppingCart> sub(@RequestBody ShoppingCart shoppingCart){
Long setmealId = shoppingCart.getSetmealId();
Long dishId = shoppingCart.getDishId();
LambdaQueryWrapper<ShoppingCart> lambdaQueryWrapper = new LambdaQueryWrapper<>();
lambdaQueryWrapper.eq(ShoppingCart::getUserId, BaseContext.getCurrentId());
if (setmealId != null){ // 删除的是套餐
lambdaQueryWrapper.eq(ShoppingCart::getSetmealId, setmealId);
} else { // 删除的是菜品
lambdaQueryWrapper.eq(ShoppingCart::getDishId, dishId);
}
ShoppingCart one = shoppingCartService.getOne(lambdaQueryWrapper);
Integer number = one.getNumber();
if (number == 1){
shoppingCartService.remove(lambdaQueryWrapper);
} else {
one.setNumber(number-1);
shoppingCartService.updateById(one);
}
return R.success(one);
}
}
UserController
package org.example.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.example.common.R;
import org.example.entity.User;
import org.example.service.UserService;
import org.example.utils.SMSUtils;
import org.example.utils.ValidateCodeUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.Map;
import java.util.concurrent.TimeUnit;
@Slf4j
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
@Autowired
private RedisTemplate redisTemplate;
@PostMapping("/sendMsg")
public R<String> sendMsg(@RequestBody User user, HttpSession httpSession) {
String phone = user.getPhone();
if (StringUtils.isNotEmpty(phone)) {
Integer integerCode = ValidateCodeUtils.generateValidateCode(4); // 随机生成4位数
String code = integerCode.toString();
log.info("phone={}", phone);
log.info("code={}", code);
// 调用阿里云提供的短信服务
//SMSUtils.sendMessage("瑞吉外卖短信服务", "SMS_270275056", phone, code);
// 生成的验证码保存到session
//httpSession.setAttribute(phone, code);
// 改为将生成的验证码存入redis
redisTemplate.opsForValue().set(phone, code, 5, TimeUnit.MINUTES); // 有效期5分钟
return R.success("手机验证码短信发送成功");
}
return R.error("手机短信发送失败");
}
@PostMapping("/login")
public R<User> login(@RequestBody Map map, HttpSession session) {
log.info("map:{}", map.toString());
//获取手机号
String phone = map.get("phone").toString();
//获取验证码
String code = map.get("code").toString();
//从Session中获取保存的验证码
//Object codeInSession = session.getAttribute(phone);
//改为从redis获取保存的验证码
Object codeInSession = redisTemplate.opsForValue().get(phone);
//进行验证码比对(页面提交的验证码和Session中保存的验证码比对)
if (codeInSession != null && codeInSession.equals(code)) {
//如果能够比对成功,说明登录成功
redisTemplate.delete(phone); // 登录成功删除保存的验证码
LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(User::getPhone, phone);
User user = userService.getOne(queryWrapper);
if (user == null) {
//判断当前手机号是否为新用户,如果是新用户则自动完成注册
user = new User();
user.setPhone(phone);
user.setStatus(1);
userService.save(user);
}
session.setAttribute("user", user.getId());
return R.success(user);
}
return R.error("登陆失败");
}
@PostMapping("/loginout")
public R<String> loginout(HttpServletRequest request) {
// 删除session保存的当前用户
request.getSession().removeAttribute("user");
return R.success("退出成功");
}
}