diff --git a/sky/sky-common/src/main/java/com/sky/constant/JwtClaimsConstant.java b/sky/sky-common/src/main/java/com/sky/constant/JwtClaimsConstant.java new file mode 100644 index 0000000..24ec50d --- /dev/null +++ b/sky/sky-common/src/main/java/com/sky/constant/JwtClaimsConstant.java @@ -0,0 +1,43 @@ +/** + * JwtClaimsConstant 类定义了一组常量,这些常量用于在 JWT(JSON Web Tokens)中表示特定的声明(claims)。 + * 这些常量提供了一种标准化的方式来引用 JWT 中的声明,使得代码更加清晰和易于维护。 + */ +package com.sky.constant; + +import java.time.LocalDateTime; + +public class JwtClaimsConstant { + + /** + * 代表员工ID的常量。 + * 这个常量用于在 JWT 中标识员工的唯一标识符。 + */ + public static final String EMP_ID = "empId"; + + /** + * 代表用户ID的常量。 + * 这个常量用于在 JWT 中标识用户的唯一标识符。 + */ + public static final String USER_ID = "userId"; + + // 下面的常量被注释掉了,如果需要使用,可以取消注释并添加相应的文档注释。 + + /* + * 代表用户电话号码的常量。 + * 这个常量用于在 JWT 中标识用户的电话号码。 + * public static final String PHONE = "phone"; + */ + + /* + * 代表用户登录名的常量。 + * 这个常量用于在 JWT 中标识用户的登录名。 + * public static final String USERNAME = "username"; + */ + + /* + * 代表用户姓名的常量。 + * 这个常量用于在 JWT 中标识用户的姓名。 + * public static final String NAME = "name"; + */ + +} \ No newline at end of file diff --git a/sky/sky-common/src/main/java/com/sky/context/BaseContext.java b/sky/sky-common/src/main/java/com/sky/context/BaseContext.java new file mode 100644 index 0000000..01c08a0 --- /dev/null +++ b/sky/sky-common/src/main/java/com/sky/context/BaseContext.java @@ -0,0 +1,43 @@ +package com.sky.context; + +/** + * BaseContext 类提供了一个基于 ThreadLocal 的机制来存储和检索当前线程的上下文信息。 + * 这种设计模式常用于保持线程安全的状态,例如在一次请求的生命周期内跟踪用户会话。 + */ +public class BaseContext { + + /** + * threadLocal 是一个 ThreadLocal 对象,用于存储每个线程的局部变量。 + * 它保证了每个线程都拥有自己的变量副本,避免了多线程环境下的共享状态问题。 + */ + private static ThreadLocal threadLocal = new ThreadLocal<>(); + + /** + * 设置当前线程的上下文ID。 + * 这个ID可以是用户ID、会话ID或其他任何需要在请求处理过程中保持的标识符。 + * + * @param id 要设置的上下文ID。 + */ + public static void setCurrentId(Long id) { + threadLocal.set(id); + } + + /** + * 获取当前线程的上下文ID。 + * 如果当前线程没有设置过ID,这个方法将返回 null。 + * + * @return 当前线程的上下文ID。 + */ + public static Long getCurrentId() { + return threadLocal.get(); + } + + /** + * 移除当前线程的上下文ID。 + * 这个方法通常在请求处理结束时被调用,以清理线程局部变量,避免内存泄漏。 + */ + public static void removeCurrentId() { + threadLocal.remove(); + } + +} \ No newline at end of file diff --git a/sky/sky-common/src/main/java/com/sky/exception/AddressBookBusinessException.java b/sky/sky-common/src/main/java/com/sky/exception/AddressBookBusinessException.java new file mode 100644 index 0000000..ba5eb52 --- /dev/null +++ b/sky/sky-common/src/main/java/com/sky/exception/AddressBookBusinessException.java @@ -0,0 +1,19 @@ +package com.sky.exception; + +/** + * AddressBookBusinessException 类是一个自定义的业务异常类,专门用于处理地址簿应用中特定的业务逻辑错误。 + * 这个异常类继承自 BaseException,使得它可以保持一致的异常处理机制,同时允许针对地址簿业务逻辑错误进行特定的异常处理。 + */ +public class AddressBookBusinessException extends BaseException { + + /** + * 构造函数,初始化 AddressBookBusinessException 实例。 + * + * @param msg 错误信息,描述了异常的具体原因。 + * 这个信息通常用于日志记录和错误报告,以便开发者或用户了解异常的具体情况。 + */ + public AddressBookBusinessException(String msg) { + super(msg); // 调用父类 BaseException 的构造函数,传递错误信息。 + } + +} \ No newline at end of file diff --git a/sky/sky-common/src/main/java/com/sky/exception/OrderBusinessException.java b/sky/sky-common/src/main/java/com/sky/exception/OrderBusinessException.java new file mode 100644 index 0000000..e86a305 --- /dev/null +++ b/sky/sky-common/src/main/java/com/sky/exception/OrderBusinessException.java @@ -0,0 +1,19 @@ +package com.sky.exception; + +/** + * OrderBusinessException 类是一个自定义的业务异常类,专门用于处理订单应用中特定的业务逻辑错误。 + * 这个异常类继承自 BaseException,使得它可以保持一致的异常处理机制,同时允许针对订单业务逻辑错误进行特定的异常处理。 + */ +public class OrderBusinessException extends BaseException { + + /** + * 构造函数,初始化 OrderBusinessException 实例。 + * + * @param msg 错误信息,描述了异常的具体原因。 + * 这个信息通常用于日志记录和错误报告,以便开发者或用户了解异常的具体情况。 + */ + public OrderBusinessException(String msg) { + super(msg); // 调用父类 BaseException 的构造函数,传递错误信息。 + } + +} \ No newline at end of file diff --git a/sky/sky-common/src/main/java/com/sky/exception/ShoppingCartBusinessException.java b/sky/sky-common/src/main/java/com/sky/exception/ShoppingCartBusinessException.java new file mode 100644 index 0000000..39bb895 --- /dev/null +++ b/sky/sky-common/src/main/java/com/sky/exception/ShoppingCartBusinessException.java @@ -0,0 +1,19 @@ +package com.sky.exception; + +/** + * ShoppingCartBusinessException 类是一个自定义的业务异常类,专门用于处理购物车应用中特定的业务逻辑错误。 + * 这个异常类继承自 BaseException,使得它可以保持一致的异常处理机制,同时允许针对购物车业务逻辑错误进行特定的异常处理。 + */ +public class ShoppingCartBusinessException extends BaseException { + + /** + * 构造函数,用于创建一个包含特定错误消息的 ShoppingCartBusinessException 实例。 + * + * @param msg 详细描述异常原因的错误消息。 + * 这个错误消息对于调试和日志记录至关重要,因为它提供了异常发生的上下文信息。 + */ + public ShoppingCartBusinessException(String msg) { + super(msg); // 调用父类 BaseException 的构造函数,并传递错误消息。 + } + +} \ No newline at end of file diff --git a/sky/sky-common/src/main/java/com/sky/properties/JwtProperties.java b/sky/sky-common/src/main/java/com/sky/properties/JwtProperties.java new file mode 100644 index 0000000..c5c2c60 --- /dev/null +++ b/sky/sky-common/src/main/java/com/sky/properties/JwtProperties.java @@ -0,0 +1,53 @@ +package com.sky.properties; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +/** + * JwtProperties 类用于存储和配置 JWT(JSON Web Tokens)相关的属性。 + * 这个类通过 Spring Boot 的 @ConfigurationProperties 注解与 application.properties 或 application.yml 文件中的配置项绑定。 + */ +@Component +@ConfigurationProperties(prefix = "sky.jwt") // 指定配置文件中属性的前缀 +@Data +public class JwtProperties { + + /** + * adminSecretKey 用于管理端员工生成 JWT 令牌的密钥。 + * 这个密钥用于签名和验证 JWT,确保令牌的安全性。 + */ + private String adminSecretKey; + + /** + * adminTtl 表示管理端员工 JWT 令牌的有效期(单位:毫秒)。 + * 这个值定义了令牌在过期前的有效时长。 + */ + private long adminTtl; + + /** + * adminTokenName 表示管理端员工 JWT 令牌的名称。 + * 这个名称用于在 HTTP 请求头中标识 JWT 令牌。 + */ + private String adminTokenName; + + /** + * userSecretKey 用于用户端微信用户生成 JWT 令牌的密钥。 + * + * 这个密钥同样用于签名和验证 JWT,确保令牌的安全性。 + */ + private String userSecretKey; + + /** + * userTtl 表示用户端微信用户 JWT 令牌的有效期(单位:毫秒)。 + * 这个值定义了用户令牌在过期前的有效时长。 + */ + private long userTtl; + + /** + * userTokenName 表示用户端微信用户 JWT 令牌的名称。 + * 这个名称用于在 HTTP 请求头中标识 JWT 令牌。 + */ + private String userTokenName; + +} \ No newline at end of file diff --git a/sky/sky-common/src/main/java/com/sky/result/Result.java b/sky/sky-common/src/main/java/com/sky/result/Result.java new file mode 100644 index 0000000..2dd24a0 --- /dev/null +++ b/sky/sky-common/src/main/java/com/sky/result/Result.java @@ -0,0 +1,76 @@ +package com.sky.result; + +import lombok.Data; + +import java.io.Serializable; + +/** + * Result 类用于封装后端统一返回的结果。 + * 这个类实现了 Serializable 接口,以便在网络传输或持久化时能够被序列化。 + * + * @param 表示返回数据的类型,可以是任意类型。 + */ +@Data +public class Result implements Serializable { + + private static final long serialVersionUID = 1L; // 序列化版本号,用于确保反序列化时的兼容性 + + /** + * 编码:1 表示成功,0 和其它数字表示失败。 + * 这个字段用于指示操作的结果状态。 + */ + private Integer code; + + /** + * 错误信息,用于描述操作失败的原因。 + * 这个字段在操作失败时提供详细的错误信息,便于调试和用户反馈。 + */ + private String msg; + + /** + * 数据字段,存储返回的具体数据。 + * 这个字段可以是任意类型的数据,通常用于返回操作成功时的结果。 + */ + private T data; + + /** + * 静态方法,创建一个表示成功的 Result 对象,不带数据。 + * + * @param 返回数据的类型 + * @return 一个成功的 Result 对象,状态码为 1。 + */ + public static Result success() { + Result result = new Result(); + result.code = 1; // 设置状态码为成功 + return result; + } + + /** + * 静态方法,创建一个表示成功的 Result 对象,并包含返回数据。 + * + * @param object 要返回的数据 + * @param 返回数据的类型 + * @return 一个成功的 Result 对象,状态码为 1,包含返回的数据。 + */ + public static Result success(T object) { + Result result = new Result(); + result.data = object; // 设置返回的数据 + result.code = 1; // 设置状态码为成功 + return result; + } + + /** + * 静态方法,创建一个表示失败的 Result 对象,并包含错误信息。 + * + * @param msg 错误信息,描述失败的原因 + * @param 返回数据的类型 + * @return 一个失败的 Result 对象,状态码为 0,包含错误信息。 + */ + public static Result error(String msg) { + Result result = new Result(); + result.msg = msg; // 设置错误信息 + result.code = 0; // 设置状态码为失败 + return result; + } + +} \ No newline at end of file diff --git a/sky/sky-common/src/main/java/com/sky/utils/WeChatPayUtil.java b/sky/sky-common/src/main/java/com/sky/utils/WeChatPayUtil.java new file mode 100644 index 0000000..585ccf1 --- /dev/null +++ b/sky/sky-common/src/main/java/com/sky/utils/WeChatPayUtil.java @@ -0,0 +1,233 @@ +package com.sky.utils; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.sky.properties.WeChatProperties; +import com.wechat.pay.contrib.apache.httpclient.WechatPayHttpClientBuilder; +import com.wechat.pay.contrib.apache.httpclient.util.PemUtil; +import org.apache.commons.lang.RandomStringUtils; +import org.apache.http.HttpHeaders; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.ContentType; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.util.EntityUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.math.BigDecimal; +import java.security.PrivateKey; +import java.security.Signature; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Base64; +import java.util.List; + +/** + * 微信支付工具类,提供微信支付相关的操作,如下单、退款等。 + */ +@Component +public class WeChatPayUtil { + + /** + * 微信支付下单接口地址。 + */ + public static final String JSAPI = "https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi"; + + /** + * 申请退款接口地址。 + */ + public static final String REFUNDS = "https://api.mch.weixin.qq.com/v3/refund/domestic/refunds"; + + @Autowired + private WeChatProperties weChatProperties; + + /** + * 获取调用微信接口的客户端工具对象。 + * 使用商户API私钥和微信支付平台证书进行签名和验签。 + * + * @return CloseableHttpClient 客户端工具对象。 + */ + private CloseableHttpClient getClient() { + PrivateKey merchantPrivateKey = null; + try { + // 加载商户API私钥 + merchantPrivateKey = PemUtil.loadPrivateKey(new FileInputStream(new File(weChatProperties.getPrivateKeyFilePath()))); + // 加载微信支付平台证书 + X509Certificate x509Certificate = PemUtil.loadCertificate(new FileInputStream(new File(weChatProperties.getWeChatPayCertFilePath()))); + List wechatPayCertificates = Arrays.asList(x509Certificate); + + // 构建HttpClient,自动处理签名和验签 + WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create() + .withMerchant(weChatProperties.getMchid(), weChatProperties.getMchSerialNo(), merchantPrivateKey) + .withWechatPay(wechatPayCertificates); + CloseableHttpClient httpClient = builder.build(); + return httpClient; + } catch (FileNotFoundException e) { + e.printStackTrace(); + return null; + } + } + + /** + * 发送POST请求到指定URL。 + * + * @param url 请求的URL地址 + * @param body 请求的JSON体 + * @return 响应结果字符串 + * @throws Exception 可能抛出的异常 + */ + private String post(String url, String body) throws Exception { + CloseableHttpClient httpClient = getClient(); + HttpPost httpPost = new HttpPost(url); + httpPost.addHeader(HttpHeaders.ACCEPT, ContentType.APPLICATION_JSON.toString()); + httpPost.addHeader(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_JSON.toString()); + httpPost.addHeader("Wechatpay-Serial", weChatProperties.getMchSerialNo()); + httpPost.setEntity(new StringEntity(body, "UTF-8")); + + CloseableHttpResponse response = httpClient.execute(httpPost); + try { + String bodyAsString = EntityUtils.toString(response.getEntity()); + return bodyAsString; + } finally { + httpClient.close(); + response.close(); + } + } + + /** + * 发送GET请求到指定URL。 + * + * @param url 请求的URL地址 + * @return 响应结果字符串 + * @throws Exception 可能抛出的异常 + */ + private String get(String url) throws Exception { + CloseableHttpClient httpClient = getClient(); + HttpGet httpGet = new HttpGet(url); + httpGet.addHeader(HttpHeaders.ACCEPT, ContentType.APPLICATION_JSON.toString()); + httpGet.addHeader(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_JSON.toString()); + httpGet.addHeader("Wechatpay-Serial", weChatProperties.getMchSerialNo()); + + CloseableHttpResponse response = httpClient.execute(httpGet); + try { + String bodyAsString = EntityUtils.toString(response.getEntity()); + return bodyAsString; + } finally { + httpClient.close(); + response.close(); + } + } + + /** + * 使用JSAPI进行微信支付下单。 + * + * @param orderNum 商户订单号 + * @param total 总金额(元) + * @param description 商品描述 + * @param openid 微信用户的openid + * @return 响应结果字符串 + * @throws Exception 可能抛出的异常 + */ + private String jsapi(String orderNum, BigDecimal total, String description, String openid) throws Exception { + JSONObject jsonObject = new JSONObject(); + jsonObject.put("appid", weChatProperties.getAppid()); + jsonObject.put("mchid", weChatProperties.getMchid()); + jsonObject.put("description", description); + jsonObject.put("out_trade_no", orderNum); + jsonObject.put("notify_url", weChatProperties.getNotifyUrl()); + + JSONObject amount = new JSONObject(); + amount.put("total", total.multiply(new BigDecimal(100)).setScale(2, BigDecimal.ROUND_HALF_UP).intValue()); + amount.put("currency", "CNY"); + + jsonObject.put("amount", amount); + + JSONObject payer = new JSONObject(); + payer.put("openid", openid); + + jsonObject.put("payer", payer); + + String body = jsonObject.toJSONString(); + return post(JSAPI, body); + } + + /** + * 小程序支付接口。 + * + * @param orderNum 商户订单号 + * @param total 金额,单位元 + * @param description 商品描述 + * @param openid 微信用户的openid + * @return 包含支付参数的JSONObject + * @throws Exception 可能抛出的异常 + */ + public JSONObject pay(String orderNum, BigDecimal total, String description, String openid) throws Exception { + String bodyAsString = jsapi(orderNum, total, description, openid); + JSONObject jsonObject = JSON.parseObject(bodyAsString); + String prepayId = jsonObject.getString("prepay_id"); + if (prepayId != null) { + String timeStamp = String.valueOf(System.currentTimeMillis() / 1000); + String nonceStr = RandomStringUtils.randomNumeric(32); + ArrayList list = new ArrayList<>(); + list.add(weChatProperties.getAppid()); + list.add(timeStamp); + list.add(nonceStr); + list.add("prepay_id=" + prepayId); + StringBuilder stringBuilder = new StringBuilder(); + for (Object o : list) { + stringBuilder.append(o).append("\n"); + } + String signMessage = stringBuilder.toString(); + byte[] message = signMessage.getBytes(); + Signature signature = Signature.getInstance("SHA256withRSA"); + signature.initSign(PemUtil.loadPrivateKey(new FileInputStream(new File(weChatProperties.getPrivateKeyFilePath())))); + signature.update(message); + String packageSign = Base64.getEncoder().encodeToString(signature.sign()); + + JSONObject jo = new JSONObject(); + jo.put("timeStamp", timeStamp); + jo.put("nonceStr", nonceStr); + jo.put("package", "prepay_id=" + prepayId); + jo.put("signType", "RSA"); + jo.put("paySign", packageSign); + + return jo; + } + return jsonObject; + } + + /** + * 申请退款接口。 + * + * @param outTradeNo 商户订单号 + * @param outRefundNo 商户退款单号 + * @param refund 退款金额 + * @param total 原订单金额 + * @return 响应结果字符串 + * @throws Exception 可能抛出的异常 + */ + public String refund(String outTradeNo, String outRefundNo, BigDecimal refund, BigDecimal total) throws Exception { + JSONObject jsonObject = new JSONObject(); + jsonObject.put("out_trade_no", outTradeNo); + jsonObject.put("out_refund_no", outRefundNo); + + JSONObject amount = new JSONObject(); + amount.put("refund", refund.multiply(new BigDecimal(100)).setScale(2, BigDecimal.ROUND_HALF_UP).intValue()); + amount.put("total", total.multiply(new BigDecimal(100)).setScale(2, BigDecimal.ROUND_HALF_UP).intValue()); + amount.put("currency", "CNY"); + + jsonObject.put("amount", amount); + jsonObject.put("notify_url", weChatProperties.getRefundNotifyUrl()); + + String body = jsonObject.toJSONString(); + + return post(REFUNDS, body); + } +} \ No newline at end of file diff --git a/sky/sky-pojo/src/main/java/com/sky/dto/CategoryPageQueryDTO.java b/sky/sky-pojo/src/main/java/com/sky/dto/CategoryPageQueryDTO.java new file mode 100644 index 0000000..a60b97d --- /dev/null +++ b/sky/sky-pojo/src/main/java/com/sky/dto/CategoryPageQueryDTO.java @@ -0,0 +1,41 @@ +package com.sky.dto; + +import lombok.Data; + +import java.io.Serializable; + +/** + * CategoryPageQueryDTO 类用于封装分类分页查询的请求参数。 + * 该类实现了 Serializable 接口,以便在网络传输或持久化时能够被序列化。 + */ +@Data +public class CategoryPageQueryDTO implements Serializable { + + private static final long serialVersionUID = 1L; // 序列化版本号,用于确保反序列化时的兼容性 + + /** + * 页码,用于指定要查询的页数。 + * 页码从 1 开始,表示用户请求的当前页。 + */ + private int page; + + /** + * 每页记录数,用于指定每一页显示的分类记录数量。 + * 这个值通常用于分页查询,以控制返回结果的数量。 + */ + private int pageSize; + + /** + * 分类名称,用于根据分类名称进行模糊查询。 + * 如果该字段不为空,则查询结果将根据分类名称进行过滤。 + */ + private String name; + + /** + * 分类类型,用于指定分类的类型。 + * 1 表示菜品分类,2 表示套餐分类。 + * 这个字段可以用于在查询时过滤不同类型的分类。 + */ + private Integer type; + +} \ No newline at end of file diff --git a/sky/sky-pojo/src/main/java/com/sky/dto/EmployeeDTO.java b/sky/sky-pojo/src/main/java/com/sky/dto/EmployeeDTO.java new file mode 100644 index 0000000..b76f555 --- /dev/null +++ b/sky/sky-pojo/src/main/java/com/sky/dto/EmployeeDTO.java @@ -0,0 +1,33 @@ +// 定义包名,表示该类属于com.sky.dto包 +package com.sky.dto; + +// 导入Lombok库中的@Data注解,用于自动生成getter和setter方法,以及toString、equals和hashCode方法 +import lombok.Data; + +// 导入Serializable接口,使得EmployeeDTO类的对象可以被序列化,即可以被转换成字节序列 +import java.io.Serializable; + +// 使用@Data注解,自动为类中的字段生成getter和setter方法 +@Data +// 声明EmployeeDTO类,并且实现Serializable接口,使其可以被序列化 +public class EmployeeDTO implements Serializable { + + // 定义一个私有的Long类型的变量id,用于存储员工的唯一标识符 + private Long id; + + // 定义一个私有的String类型的变量username,用于存储员工的用户名 + private String username; + + // 定义一个私有的String类型的变量name,用于存储员工的姓名 + private String name; + + // 定义一个私有的String类型的变量phone,用于存储员工的电话号码 + private String phone; + + // 定义一个私有的String类型的变量sex,用于存储员工的性别 + private String sex; + + // 定义一个私有的String类型的变量idNumber,用于存储员工的身份证号码 + private String idNumber; + +} \ No newline at end of file diff --git a/sky/sky-pojo/src/main/java/com/sky/dto/OrdersCancelDTO.java b/sky/sky-pojo/src/main/java/com/sky/dto/OrdersCancelDTO.java new file mode 100644 index 0000000..ea92365 --- /dev/null +++ b/sky/sky-pojo/src/main/java/com/sky/dto/OrdersCancelDTO.java @@ -0,0 +1,22 @@ +// 定义包名,表示该类属于com.sky.dto包 +package com.sky.dto; + +// 导入Lombok库中的@Data注解,用于自动生成getter和setter方法,以及toString、equals和hashCode方法 +import lombok.Data; + +// 导入Serializable接口,使得OrdersCancelDTO类的对象可以被序列化,即可以被转换成字节序列 +import java.io.Serializable; + +// 使用@Data注解,自动为类中的字段生成getter和setter方法 +@Data +// 声明OrdersCancelDTO类,并且实现Serializable接口,使其可以被序列化 +public class OrdersCancelDTO implements Serializable { + + // 定义一个私有的Long类型的变量id,用于存储订单的唯一标识符 + private Long id; + + // 定义一个私有的String类型的变量cancelReason,用于存储订单取消的原因 + // 订单取消原因 + private String cancelReason; + +} \ No newline at end of file diff --git a/sky/sky-pojo/src/main/java/com/sky/dto/OrdersPaymentDTO.java b/sky/sky-pojo/src/main/java/com/sky/dto/OrdersPaymentDTO.java new file mode 100644 index 0000000..c2fcd86 --- /dev/null +++ b/sky/sky-pojo/src/main/java/com/sky/dto/OrdersPaymentDTO.java @@ -0,0 +1,23 @@ +// 定义包名,表示该类属于com.sky.dto包 +package com.sky.dto; + +// 导入Lombok库中的@Data注解,用于自动生成getter和setter方法,以及toString、equals和hashCode方法 +import lombok.Data; + +// 导入Serializable接口,使得OrdersPaymentDTO类的对象可以被序列化,即可以被转换成字节序列 +import java.io.Serializable; + +// 使用@Data注解,自动为类中的字段生成getter和setter方法 +@Data +// 声明OrdersPaymentDTO类,并且实现Serializable接口,使其可以被序列化 +public class OrdersPaymentDTO implements Serializable { + + // 定义一个私有的String类型的变量orderNumber,用于存储订单的编号 + // 订单号 + private String orderNumber; + + // 定义一个私有的Integer类型的变量payMethod,用于存储订单的付款方式 + // 付款方式 + private Integer payMethod; + +} \ No newline at end of file diff --git a/sky/sky-pojo/src/main/java/com/sky/dto/SetmealDTO.java b/sky/sky-pojo/src/main/java/com/sky/dto/SetmealDTO.java new file mode 100644 index 0000000..cbac4ea --- /dev/null +++ b/sky/sky-pojo/src/main/java/com/sky/dto/SetmealDTO.java @@ -0,0 +1,46 @@ +// 定义包名,表示该类属于com.sky.dto包 +package com.sky.dto; + +// 导入com.sky.entity.SetmealDish类,这个类可能包含了套餐中包含的菜品信息 +import com.sky.entity.SetmealDish; +// 导入Lombok库中的@Data注解,用于自动生成getter和setter方法,以及toString、equals和hashCode方法 +import lombok.Data; +// 导入Serializable接口,使得SetmealDTO类的对象可以被序列化,即可以被转换成字节序列 +import java.io.Serializable; +// 导入BigDecimal类,用于精确表示货币等需要高精度的场景 +import java.math.BigDecimal; +// 导入ArrayList类,用于创建动态数组 +import java.util.ArrayList; +// 导入List接口,用于定义一个动态数组的引用 +import java.util.List; + +// 使用@Data注解,自动为类中的字段生成getter和setter方法 +@Data +// 声明SetmealDTO类,并且实现Serializable接口,使其可以被序列化 +public class SetmealDTO implements Serializable { + + // 定义一个私有的Long类型的变量id,用于存储套餐的唯一标识符 + private Long id; + + // 分类id,用于标识套餐所属的分类 + private Long categoryId; + + // 套餐名称,用于存储套餐的名称 + private String name; + + // 套餐价格,使用BigDecimal类型以确保价格的精确表示 + private BigDecimal price; + + // 状态,0表示停用,1表示启用 + private Integer status; + + // 描述信息,用于存储套餐的详细描述 + private String description; + + // 图片,用于存储套餐的图片链接或路径 + private String image; + + // 套餐菜品关系,用于存储套餐中包含的菜品列表,初始为空的ArrayList + private List setmealDishes = new ArrayList<>(); + +} \ No newline at end of file diff --git a/sky/sky-pojo/src/main/java/com/sky/entity/AddressBook.java b/sky/sky-pojo/src/main/java/com/sky/entity/AddressBook.java new file mode 100644 index 0000000..b746af1 --- /dev/null +++ b/sky/sky-pojo/src/main/java/com/sky/entity/AddressBook.java @@ -0,0 +1,70 @@ +// 定义包名,表示该类属于com.sky.entity包 +package com.sky.entity; + +// 导入Lombok库中的注解,用于简化Java类的编写 +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +// 导入Serializable接口,使得AddressBook类的对象可以被序列化,即可以被转换成字节序列 +import java.io.Serializable; + +/** + * 地址簿实体类,用于存储和管理用户地址信息。 + */ +// 使用@Data注解,自动为类中的字段生成getter和setter方法,以及toString、equals和hashCode方法 +@Data +// 使用@Builder注解,提供建造者模式的实现,方便对象的构建 +@Builder +// 使用@NoArgsConstructor注解,生成无参构造方法 +@NoArgsConstructor +// 使用@AllArgsConstructor注解,生成包含所有属性的构造方法 +@AllArgsConstructor +public class AddressBook implements Serializable { + + // 定义serialVersionUID,用于在序列化和反序列化过程中确保版本一致性 + private static final long serialVersionUID = 1L; + + // 定义一个私有的Long类型的变量id,用于存储地址的唯一标识符 + private Long id; + + // 用户id,用于标识这个地址属于哪个用户 + private Long userId; + + // 收货人,用于存储收货人的姓名 + private String consignee; + + // 手机号,用于存储收货人的联系电话 + private String phone; + + // 性别,0表示女性,1表示男性 + private String sex; + + // 省级区划编号,用于标识省份的代码 + private String provinceCode; + + // 省级名称,用于存储省份的名称 + private String provinceName; + + // 市级区划编号,用于标识城市的代码 + private String cityCode; + + // 市级名称,用于存储城市的名称 + private String cityName; + + // 区级区划编号,用于标识区县的代码 + private String districtCode; + + // 区级名称,用于存储区县的名称 + private String districtName; + + // 详细地址,用于存储具体的地址信息 + private String detail; + + // 标签,用于给地址添加备注或分类 + private String label; + + // 是否默认,0表示否,1表示是,用于标识这个地址是否是用户的默认地址 + private Integer isDefault; +} \ No newline at end of file diff --git a/sky/sky-pojo/src/main/java/com/sky/entity/Employee.java b/sky/sky-pojo/src/main/java/com/sky/entity/Employee.java new file mode 100644 index 0000000..a1fb350 --- /dev/null +++ b/sky/sky-pojo/src/main/java/com/sky/entity/Employee.java @@ -0,0 +1,71 @@ +// 定义包名,表示该类属于com.sky.entity包 +package com.sky.entity; + +// 导入Lombok库中的注解,用于简化Java类的编写 +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +// 导入Serializable接口,使得Employee类的对象可以被序列化,即可以被转换成字节序列 +import java.io.Serializable; +// 导入LocalDateTime类,用于存储日期和时间 +import java.time.LocalDateTime; + +/** + * 员工实体类,用于存储和管理员工信息。 + */ +// 使用@Data注解,自动为类中的字段生成getter和setter方法,以及toString、equals和hashCode方法 +@Data +// 使用@Builder注解,提供建造者模式的实现,方便对象的构建 +@Builder +// 使用@NoArgsConstructor注解,生成无参构造方法 +@NoArgsConstructor +// 使用@AllArgsConstructor注解,生成包含所有属性的构造方法 +@AllArgsConstructor +public class Employee implements Serializable { + + // 定义serialVersionUID,用于在序列化和反序列化过程中确保版本一致性 + private static final long serialVersionUID = 1L; + + // 定义一个私有的Long类型的变量id,用于存储员工的唯一标识符 + private Long id; + + // 用户名,用于存储员工的登录名 + private String username; + + // 姓名,用于存储员工的真实姓名 + private String name; + + // 密码,用于存储员工的登录密码 + private String password; + + // 手机号,用于存储员工的联系电话 + private String phone; + + // 性别,通常用"男"或"女"表示 + private String sex; + + // 身份证号码,用于存储员工的身份证信息 + private String idNumber; + + // 状态,用于标识员工的当前状态,如在职、离职等 + private Integer status; + + // 创建时间,用于存储记录创建的时间 + // 注释掉的@JsonFormat注解用于在JSON序列化时指定日期时间的格式 + // @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + // 更新时间,用于存储记录最后一次更新的时间 + // 注释掉的@JsonFormat注解用于在JSON序列化时指定日期时间的格式 + // @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + + // 创建用户ID,用于标识创建这条记录的用户 + private Long createUser; + + // 更新用户ID,用于标识最后一次更新这条记录的用户 + private Long updateUser; + +} \ No newline at end of file diff --git a/sky/sky-pojo/src/main/java/com/sky/entity/SetmealDish.java b/sky/sky-pojo/src/main/java/com/sky/entity/SetmealDish.java new file mode 100644 index 0000000..affaf11 --- /dev/null +++ b/sky/sky-pojo/src/main/java/com/sky/entity/SetmealDish.java @@ -0,0 +1,48 @@ +// 定义包名,表示该类属于com.sky.entity包 +package com.sky.entity; + +// 导入Lombok库中的注解,用于简化Java类的编写 +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +// 导入Serializable接口,使得SetmealDish类的对象可以被序列化,即可以被转换成字节序列 +import java.io.Serializable; +// 导入BigDecimal类,用于精确表示货币等需要高精度的场景 +import java.math.BigDecimal; + +/** + * 套餐菜品关系实体类,用于存储和管理套餐与菜品之间的关系信息。 + */ +// 使用@Data注解,自动为类中的字段生成getter和setter方法,以及toString、equals和hashCode方法 +@Data +// 使用@Builder注解,提供建造者模式的实现,方便对象的构建 +@Builder +// 使用@NoArgsConstructor注解,生成无参构造方法 +@NoArgsConstructor +// 使用@AllArgsConstructor注解,生成包含所有属性的构造方法 +@AllArgsConstructor +public class SetmealDish implements Serializable { + + // 定义serialVersionUID,用于在序列化和反序列化过程中确保版本一致性 + private static final long serialVersionUID = 1L; + + // 定义一个私有的Long类型的变量id,用于存储套餐菜品关系的唯一标识符 + private Long id; + + // 套餐id,用于标识套餐的唯一标识符 + private Long setmealId; + + // 菜品id,用于标识菜品的唯一标识符 + private Long dishId; + + // 菜品名称,冗余字段,用于存储菜品的名称,可能是为了查询方便而存储的额外信息 + private String name; + + // 菜品原价,使用BigDecimal类型以确保价格的精确表示 + private BigDecimal price; + + // 份数,用于标识套餐中包含的该菜品的份数 + private Integer copies; +} \ No newline at end of file diff --git a/sky/sky-pojo/src/main/java/com/sky/vo/DishItemVO.java b/sky/sky-pojo/src/main/java/com/sky/vo/DishItemVO.java new file mode 100644 index 0000000..350373f --- /dev/null +++ b/sky/sky-pojo/src/main/java/com/sky/vo/DishItemVO.java @@ -0,0 +1,37 @@ +// 定义包名,表示该类属于com.sky.vo包 +package com.sky.vo; + +// 导入Lombok库中的注解,用于简化Java类的编写 +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +// 导入Serializable接口,使得DishItemVO类的对象可以被序列化,即可以被转换成字节序列 +import java.io.Serializable; + +/** + * 菜品项视图对象类,用于在视图层展示菜品相关的数据。 + */ +// 使用@Data注解,自动为类中的字段生成getter和setter方法,以及toString、equals和hashCode方法 +@Data +// 使用@Builder注解,提供建造者模式的实现,方便对象的构建 +@Builder +// 使用@NoArgsConstructor注解,生成无参构造方法 +@NoArgsConstructor +// 使用@AllArgsConstructor注解,生成包含所有属性的构造方法 +@AllArgsConstructor +public class DishItemVO implements Serializable { + + // 菜品名称,用于存储菜品的名称 + private String name; + + // 份数,用于标识菜品的份数 + private Integer copies; + + // 菜品图片,用于存储菜品的图片链接或路径 + private String image; + + // 菜品描述,用于存储菜品的详细描述信息 + private String description; +} \ No newline at end of file diff --git a/sky/sky-pojo/src/main/java/com/sky/vo/OrderOverViewVO.java b/sky/sky-pojo/src/main/java/com/sky/vo/OrderOverViewVO.java new file mode 100644 index 0000000..9b41d7c --- /dev/null +++ b/sky/sky-pojo/src/main/java/com/sky/vo/OrderOverViewVO.java @@ -0,0 +1,40 @@ +// 定义包名,表示该类属于com.sky.vo包 +package com.sky.vo; + +// 导入Lombok库中的注解,用于简化Java类的编写 +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +// 导入Serializable接口,使得OrderOverViewVO类的对象可以被序列化,即可以被转换成字节序列 +import java.io.Serializable; + +/** + * 订单概览视图对象类,用于在视图层展示订单的概览数据。 + */ +// 使用@Data注解,自动为类中的字段生成getter和setter方法,以及toString、equals和hashCode方法 +@Data +// 使用@Builder注解,提供建造者模式的实现,方便对象的构建 +@Builder +// 使用@NoArgsConstructor注解,生成无参构造方法 +@NoArgsConstructor +// 使用@AllArgsConstructor注解,生成包含所有属性的构造方法 +@AllArgsConstructor +public class OrderOverViewVO implements Serializable { + + // 待接单数量,用于存储待接单的订单数量 + private Integer waitingOrders; + + // 待派送数量,用于存储待派送的订单数量 + private Integer deliveredOrders; + + // 已完成数量,用于存储已完成的订单数量 + private Integer completedOrders; + + // 已取消数量,用于存储已取消的订单数量 + private Integer cancelledOrders; + + // 全部订单,用于存储总订单数量 + private Integer allOrders; +} \ No newline at end of file diff --git a/sky/sky-pojo/src/main/java/com/sky/vo/OrderSubmitVO.java b/sky/sky-pojo/src/main/java/com/sky/vo/OrderSubmitVO.java new file mode 100644 index 0000000..fc779fa --- /dev/null +++ b/sky/sky-pojo/src/main/java/com/sky/vo/OrderSubmitVO.java @@ -0,0 +1,41 @@ +// 定义包名,表示该类属于com.sky.vo包 +package com.sky.vo; + +// 导入Lombok库中的注解,用于简化Java类的编写 +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +// 导入Serializable接口,使得OrderSubmitVO类的对象可以被序列化,即可以被转换成字节序列 +import java.io.Serializable; +// 导入BigDecimal类,用于精确表示货币等需要高精度的场景 +import java.math.BigDecimal; +// 导入LocalDateTime类,用于存储日期和时间 +import java.time.LocalDateTime; + +/** + * 订单提交视图对象类,用于在视图层展示订单提交时的相关数据。 + */ +// 使用@Data注解,自动为类中的字段生成getter和setter方法,以及toString、equals和hashCode方法 +@Data +// 使用@Builder注解,提供建造者模式的实现,方便对象的构建 +@Builder +// 使用@NoArgsConstructor注解,生成无参构造方法 +@NoArgsConstructor +// 使用@AllArgsConstructor注解,生成包含所有属性的构造方法 +@AllArgsConstructor +public class OrderSubmitVO implements Serializable { + + // 订单id,用于存储订单的唯一标识符 + private Long id; + + // 订单号,用于存储订单的编号,通常用于客户和商家之间的交流和查询 + private String orderNumber; + + // 订单金额,使用BigDecimal类型以确保金额的精确表示 + private BigDecimal orderAmount; + + // 下单时间,用于存储订单被提交的时间 + private LocalDateTime orderTime; +} \ No newline at end of file diff --git a/sky/sky-pojo/src/main/java/com/sky/vo/SetmealVO.java b/sky/sky-pojo/src/main/java/com/sky/vo/SetmealVO.java new file mode 100644 index 0000000..f6000b0 --- /dev/null +++ b/sky/sky-pojo/src/main/java/com/sky/vo/SetmealVO.java @@ -0,0 +1,66 @@ +// 定义包名,表示该类属于com.sky.vo包 +package com.sky.vo; + +// 导入com.sky.entity.SetmealDish类,这个类可能包含了套餐中包含的菜品信息 +import com.sky.entity.SetmealDish; +// 导入Lombok库中的注解,用于简化Java类的编写 +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +// 导入Serializable接口,使得SetmealVO类的对象可以被序列化,即可以被转换成字节序列 +import java.io.Serializable; +// 导入BigDecimal类,用于精确表示货币等需要高精度的场景 +import java.math.BigDecimal; +// 导入LocalDateTime类,用于存储日期和时间 +import java.time.LocalDateTime; +// 导入ArrayList类,用于创建动态数组 +import java.util.ArrayList; +// 导入List接口,用于定义一个动态数组的引用 +import java.util.List; + +/** + * 套餐视图对象类,用于在视图层展示套餐相关的数据。 + */ +// 使用@Data注解,自动为类中的字段生成getter和setter方法,以及toString、equals和hashCode方法 +@Data +// 使用@Builder注解,提供建造者模式的实现,方便对象的构建 +@Builder +// 使用@NoArgsConstructor注解,生成无参构造方法 +@NoArgsConstructor +// 使用@AllArgsConstructor注解,生成包含所有属性的构造方法 +@AllArgsConstructor +public class SetmealVO implements Serializable { + + // 定义一个私有的Long类型的变量id,用于存储套餐的唯一标识符 + private Long id; + + // 分类id,用于标识套餐所属的分类 + private Long categoryId; + + // 套餐名称,用于存储套餐的名称 + private String name; + + // 套餐价格,使用BigDecimal类型以确保价格的精确表示 + private BigDecimal price; + + // 状态,0表示停用,1表示启用 + private Integer status; + + // 描述信息,用于存储套餐的详细描述 + private String description; + + // 图片,用于存储套餐的图片链接或路径 + private String image; + + // 更新时间,用于存储套餐最后一次更新的时间 + private LocalDateTime updateTime; + + // 分类名称,用于存储套餐所属分类的名称 + private String categoryName; + + // 套餐和菜品的关联关系,初始为空的ArrayList,用于存储套餐中包含的菜品列表 + private List setmealDishes = new ArrayList<>(); + +} \ No newline at end of file diff --git a/sky/sky-server/src/main/java/com/sky/aspectj/AutoFillAspect.java b/sky/sky-server/src/main/java/com/sky/aspectj/AutoFillAspect.java new file mode 100644 index 0000000..3483f11 --- /dev/null +++ b/sky/sky-server/src/main/java/com/sky/aspectj/AutoFillAspect.java @@ -0,0 +1,97 @@ +// 定义包名,表示该类属于com.sky.aspectj包 +package com.sky.aspectj; + +// 导入所需的类和接口 +import com.sky.annotation.AutoFill; +import com.sky.constant.AutoFillConstant; +import com.sky.context.BaseContext; +import com.sky.enumeration.OperationType; +import lombok.extern.slf4j.Slf4j; +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.Signature; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Before; +import org.aspectj.lang.annotation.Pointcut; +import org.aspectj.lang.reflect.MethodSignature; +import org.springframework.stereotype.Component; + +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.time.LocalDateTime; +import java.util.*; + +// 使用@Aspect注解声明一个切面 +@Aspect +// 使用@Slf4j注解为类自动注入一个日志对象 +@Slf4j +// 使用@Component注解声明一个Spring组件,使其可以被Spring容器管理 +@Component +public class AutoFillAspect { + + // 定义一个切入点,匹配所有标记了@AutoFill注解的com.sky.mapper包下的方法 + @Pointcut("@annotation(com.sky.annotation.AutoFill)" + "&& execution(* com.sky.mapper.*.*(..))") + public void pointCount() { + } + + // 前置通知,执行切入点匹配的方法之前 + @Before("pointCount()") + public void beforeAutoFillAspect(JoinPoint joinPoint) throws InvocationTargetException, IllegalAccessException { + // 获取方法签名 + MethodSignature signature = (MethodSignature) joinPoint.getSignature(); + // 获取当前执行的方法 + Method method = signature.getMethod(); + // 获取方法参数 + Object[] args = joinPoint.getArgs(); + // 获取方法上的@AutoFill注解 + AutoFill autoFill = method.getAnnotation(AutoFill.class); + // 从注解中获取操作类型 + OperationType value = autoFill.value(); + + // 存放每个参数对象及其所有方法的映射 + HashMap methodHashMap = new HashMap<>(); + // 遍历参数对象,获取每个对象的所有方法 + for (Object arg : args) { + Class argClass = arg.getClass(); + Method[] methods = argClass.getDeclaredMethods(); + methodHashMap.put(arg, methods); + } + + // 根据操作类型进行不同的字段填充 + if (value.equals(OperationType.INSERT)) { + // 插入操作,填充创建时间和创建用户 + for (Map.Entry entry : methodHashMap.entrySet()) { + Object key = entry.getKey(); + for (Method method1 : entry.getValue()) { + // 填充创建时间和更新时间 + if (method1.getName().equals(AutoFillConstant.SET_UPDATE_TIME) || method.getName().equals(AutoFillConstant.SET_CREATE_TIME)) { + method1.invoke(key, LocalDateTime.now()); + } + // 填充创建用户和更新用户 + if (method1.getName().equals(AutoFillConstant.SET_CREATE_USER) || method.getName().equals(AutoFillConstant.SET_UPDATE_USER)) { + method1.invoke(key, BaseContext.getCurrentId()); + } + } + } + } else if (value.equals(OperationType.UPDATE)) { + // 更新操作,填充更新时间和更新用户 + for (Map.Entry entry : methodHashMap.entrySet()) { + Object key = entry.getKey(); + for (Method method1 : entry.getValue()) { + // 填充更新时间 + if (method1.getName().equals(AutoFillConstant.SET_UPDATE_TIME)) { + method1.invoke(key, LocalDateTime.now()); + } + // 填充更新用户 + if (method1.getName().equals(AutoFillConstant.SET_UPDATE_USER)) { + method1.invoke(key, BaseContext.getCurrentId()); + } + } + } + } else { + // 非法操作类型,抛出异常 + throw new IllegalArgumentException("自动填充操作类型参数异常!"); + } + } + +} \ No newline at end of file diff --git a/sky/sky-server/src/main/java/com/sky/controller/admin/CategoryController.java b/sky/sky-server/src/main/java/com/sky/controller/admin/CategoryController.java new file mode 100644 index 0000000..75c8fec --- /dev/null +++ b/sky/sky-server/src/main/java/com/sky/controller/admin/CategoryController.java @@ -0,0 +1,134 @@ +// 定义包名,表示该类属于com.sky.controller.admin包 +package com.sky.controller.admin; + +// 导入所需的类和接口 +import com.sky.dto.CategoryDTO; +import com.sky.dto.CategoryPageQueryDTO; +import com.sky.entity.Category; +import com.sky.result.PageResult; +import com.sky.result.Result; +import com.sky.service.CategoryService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +// 使用@RestController注解声明这是一个REST控制器,返回的数据会自动转换为JSON格式 +@RestController +// 使用@RequestMapping注解定义类级别的路由,所有的请求都会以"/admin/category"作为前缀 +@RequestMapping("/admin/category") +// 使用@Slf4j注解为类自动注入一个日志对象 +@Slf4j +// 使用@Api注解标记这个控制器属于哪个API分类 +@Api(tags = "分类相关接口") +public class CategoryController { + // 自动注入CategoryService服务 + @Autowired + CategoryService categoryService; + + /** + * 分类分页查询接口 + * + * @param categoryPageQueryDTO 分页查询参数 + * @return 分页查询结果 + */ + @GetMapping({"/page"}) + @ApiOperation("分类分页查询") + public Result pageQuery(CategoryPageQueryDTO categoryPageQueryDTO) { + // 记录日志 + log.info("分类分页查询:{}", categoryPageQueryDTO); + // 调用服务层进行分页查询 + PageResult pageResult = categoryService.pageQuery(categoryPageQueryDTO); + // 返回查询结果 + return Result.success(pageResult); + } + + /** + * 根据类型查询分类接口 + * + * @param type 分类类型 + * @return 分类列表 + */ + @GetMapping("/list") + @ApiOperation("根据类型查询分类") + public Result query(Integer type) { + // 记录日志 + log.info("根据类型查询分类:{}", type); + // 调用服务层根据类型查询分类 + List result = categoryService.query(type); + // 返回查询结果 + return Result.success(result); + } + + /** + * 删除分类接口 + * + * @param id 要删除的分类ID + * @return 操作结果 + */ + @DeleteMapping + @ApiOperation("删除分类") + public Result deleteCategory(Long id) { + // 记录日志 + log.info("删除分类:{}", id); + // 调用服务层删除分类 + categoryService.delete(id); + // 返回操作结果 + return Result.success(); + } + + /** + * 修改分类接口 + * + * @param categoryDTO 包含修改信息的分类DTO + * @return 操作结果 + */ + @PutMapping + @ApiOperation("修改分类") + public Result updateCategory(@RequestBody CategoryDTO categoryDTO) { + // 记录日志 + log.info("修改分类:{}", categoryDTO); + // 调用服务层修改分类 + categoryService.updateCategory(categoryDTO); + // 返回操作结果 + return Result.success(); + } + + /** + * 启用或禁用分类接口 + * + * @param status 状态值,用于标识启用或禁用 + * @param id 要修改状态的分类ID + * @return 操作结果 + */ + @PostMapping("/status/{status}") + @ApiOperation("启用禁用分类") + public Result startOrStop(@PathVariable Integer status, Long id) { + // 记录日志 + log.info("启用禁用分类status:{},id:{}", status, id); + // 调用服务层启用或禁用分类 + categoryService.startOrStop(status, id); + // 返回操作结果 + return Result.success(); + } + + /** + * 新增分类接口 + * + * @param categoryDTO 包含新增信息的分类DTO + * @return 操作结果 + */ + @PostMapping + @ApiOperation("新增分类") + public Result save(@RequestBody CategoryDTO categoryDTO) { + // 记录日志 + log.info("新增分类:{}", categoryDTO); + // 调用服务层新增分类 + categoryService.save(categoryDTO); + // 返回操作结果 + return Result.success(); + } +} \ No newline at end of file diff --git a/sky/sky-server/src/main/java/com/sky/controller/admin/OrderController.java b/sky/sky-server/src/main/java/com/sky/controller/admin/OrderController.java new file mode 100644 index 0000000..6bd0e08 --- /dev/null +++ b/sky/sky-server/src/main/java/com/sky/controller/admin/OrderController.java @@ -0,0 +1,153 @@ +// 定义包名,表示该类属于com.sky.controller.admin包 +package com.sky.controller.admin; + +// 导入所需的类和接口 +import com.sky.dto.OrdersCancelDTO; +import com.sky.dto.OrdersConfirmDTO; +import com.sky.dto.OrdersPageQueryDTO; +import com.sky.dto.OrdersRejectionDTO; +import com.sky.result.PageResult; +import com.sky.result.Result; +import com.sky.service.OrderService; +import com.sky.vo.OrderStatisticsVO; +import com.sky.vo.OrderVO; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +/** + * 订单管理控制器类,提供了一系列的接口用于订单管理。 + */ +@RestController("adminOrderController") +@RequestMapping("/admin/order") +@Slf4j +@Api(tags = "订单管理接口") +public class OrderController { + + // 自动注入OrderService服务 + @Autowired + private OrderService orderService; + + /** + * 完成订单接口 + * + * @param id 订单ID + * @return 操作结果 + */ + @PutMapping("/complete/{id}") + @ApiOperation("完成订单") + public Result complete(@PathVariable("id") Long id) { + // 调用服务层完成订单 + orderService.complete(id); + // 返回操作结果 + return Result.success(); + } + + /** + * 派送订单接口 + * + * @param id 订单ID + * @return 操作结果 + */ + @PutMapping("/delivery/{id}") + @ApiOperation("派送订单") + public Result delivery(@PathVariable("id") Long id) { + // 调用服务层派送订单 + orderService.delivery(id); + // 返回操作结果 + return Result.success(); + } + + /** + * 订单搜索接口 + * + * @param ordersPageQueryDTO 订单搜索参数 + * @return 订单搜索结果 + */ + @GetMapping("/conditionSearch") + @ApiOperation("订单搜索") + public Result conditionSearch(OrdersPageQueryDTO ordersPageQueryDTO) { + // 调用服务层进行订单搜索 + PageResult pageResult = orderService.conditionSearch(ordersPageQueryDTO); + // 返回搜索结果 + return Result.success(pageResult); + } + + /** + * 各个状态的订单数量统计接口 + * + * @return 订单数量统计结果 + */ + @GetMapping("/statistics") + @ApiOperation("各个状态的订单数量统计") + public Result statistics() { + // 调用服务层获取订单数量统计 + OrderStatisticsVO orderStatisticsVO = orderService.statistics(); + // 返回统计结果 + return Result.success(orderStatisticsVO); + } + + /** + * 查询订单详情接口 + * + * @param id 订单ID + * @return 订单详情 + */ + @GetMapping("/details/{id}") + @ApiOperation("查询订单详情") + public Result details(@PathVariable("id") Long id) { + // 调用服务层查询订单详情 + OrderVO orderVO = orderService.details(id); + // 返回订单详情 + return Result.success(orderVO); + } + + /** + * 接单接口 + * + * @param ordersConfirmDTO 接单参数 + * @return 操作结果 + */ + @PutMapping("/confirm") + @ApiOperation("接单") + public Result confirm(@RequestBody OrdersConfirmDTO ordersConfirmDTO) { + // 调用服务层接单 + orderService.confirm(ordersConfirmDTO); + // 返回操作结果 + return Result.success(); + } + + /** + * 拒单接口 + * + * @param ordersRejectionDTO 拒单参数 + * @return 操作结果 + * @throws Exception 可能抛出的异常 + */ + @PutMapping("/rejection") + @ApiOperation("拒单") + public Result rejection(@RequestBody OrdersRejectionDTO ordersRejectionDTO) throws Exception { + // 调用服务层拒单 + orderService.rejection(ordersRejectionDTO); + // 返回操作结果 + return Result.success(); + } + + /** + * 取消订单接口 + * + * @param ordersCancelDTO 取消订单参数 + * @return 操作结果 + * @throws Exception 可能抛出的异常 + */ + @PutMapping("/cancel") + @ApiOperation("取消订单") + public Result cancel(@RequestBody OrdersCancelDTO ordersCancelDTO) throws Exception { + // 调用服务层取消订单 + orderService.cancel(ordersCancelDTO); + // 返回操作结果 + return Result.success(); + } +} \ No newline at end of file diff --git a/sky/sky-server/src/main/java/com/sky/controller/admin/WorkSpaceController.java b/sky/sky-server/src/main/java/com/sky/controller/admin/WorkSpaceController.java new file mode 100644 index 0000000..d3cb4ce --- /dev/null +++ b/sky/sky-server/src/main/java/com/sky/controller/admin/WorkSpaceController.java @@ -0,0 +1,94 @@ +// 定义包名,表示该类属于com.sky.controller.admin包 +package com.sky.controller.admin; + +// 导入所需的类和接口 +import com.sky.result.Result; +import com.sky.service.WorkspaceService; +import com.sky.vo.BusinessDataVO; +import com.sky.vo.DishOverViewVO; +import com.sky.vo.OrderOverViewVO; +import com.sky.vo.SetmealOverViewVO; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import java.time.LocalDateTime; +import java.time.LocalTime; + +/** + * 工作台控制器类,提供了一系列的接口用于工作台数据的查询。 + */ +@RestController +@RequestMapping("/admin/workspace") +@Slf4j +@Api(tags = "工作台相关接口") +public class WorkSpaceController { + + // 自动注入WorkspaceService服务 + @Autowired + private WorkspaceService workspaceService; + + /** + * 工作台今日数据查询接口 + * + * @return 工作台今日数据视图对象 + */ + @GetMapping("/businessData") + @ApiOperation("工作台今日数据查询") + public Result businessData(){ + // 获得当天的开始时间(00:00:00) + LocalDateTime begin = LocalDateTime.now().with(LocalTime.MIN); + // 获得当天的结束时间(23:59:59) + LocalDateTime end = LocalDateTime.now().with(LocalTime.MAX); + + // 调用服务层获取工作台今日数据 + BusinessDataVO businessDataVO = workspaceService.getBusinessData(begin, end); + // 返回工作台今日数据 + return Result.success(businessDataVO); + } + + /** + * 查询订单管理数据接口 + * + * @return 订单管理数据视图对象 + */ + @GetMapping("/overviewOrders") + @ApiOperation("查询订单管理数据") + public Result orderOverView(){ + // 调用服务层获取订单管理数据 + OrderOverViewVO orderOverViewVO = workspaceService.getOrderOverView(); + // 返回订单管理数据 + return Result.success(orderOverViewVO); + } + + /** + * 查询菜品总览接口 + * + * @return 菜品总览视图对象 + */ + @GetMapping("/overviewDishes") + @ApiOperation("查询菜品总览") + public Result dishOverView(){ + // 调用服务层获取菜品总览数据 + DishOverViewVO dishOverViewVO = workspaceService.getDishOverView(); + // 返回菜品总览数据 + return Result.success(dishOverViewVO); + } + + /** + * 查询套餐总览接口 + * + * @return 套餐总览视图对象 + */ + @GetMapping("/overviewSetmeals") + @ApiOperation("查询套餐总览") + public Result setmealOverView(){ + // 调用服务层获取套餐总览数据 + SetmealOverViewVO setmealOverViewVO = workspaceService.getSetmealOverView(); + // 返回套餐总览数据 + return Result.success(setmealOverViewVO); + } +} \ No newline at end of file diff --git a/sky/sky-server/src/main/java/com/sky/controller/user/DishController.java b/sky/sky-server/src/main/java/com/sky/controller/user/DishController.java new file mode 100644 index 0000000..d16cb35 --- /dev/null +++ b/sky/sky-server/src/main/java/com/sky/controller/user/DishController.java @@ -0,0 +1,75 @@ +// 定义包名,表示该类属于com.sky.controller.user包 +package com.sky.controller.user; + +// 导入所需的类和接口 +import com.sky.constant.StatusConstant; +import com.sky.entity.Dish; +import com.sky.result.Result; +import com.sky.service.DishService; +import com.sky.vo.DishVO; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.core.ValueOperations; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +// 使用@RestController注解声明这是一个REST控制器,返回的数据会自动转换为JSON格式 +@RestController("userDishController") +// 使用@RequestMapping注解定义类级别的路由,所有的请求都会以"/user/dish"作为前缀 +@RequestMapping("/user/dish") +// 使用@Slf4j注解为类自动注入一个日志对象 +@Slf4j +// 使用@Api注解标记这个控制器属于哪个API分类 +@Api(tags = "C端-菜品浏览接口") +public class DishController { + + // 自动注入DishService服务 + @Autowired + private DishService dishService; + + // 自动注入RedisTemplate,用于操作Redis缓存 + @Autowired + private RedisTemplate redisTemplate; + + /** + * 根据分类id查询菜品接口 + * + * @param categoryId 分类ID + * @return 菜品列表 + */ + @GetMapping("/list") + @ApiOperation("根据分类id查询菜品") + public Result> list(Long categoryId) { + // 记录日志,输出查询的分类ID + log.info("根据分类id查询菜品:{}", categoryId); + // 定义Redis缓存的键 + String key = "dish_" + categoryId; + + // 从缓存中获取菜品列表 + ValueOperations valueOperations = redisTemplate.opsForValue(); + List dishVOList = (List) valueOperations.get(key); + + // 如果缓存中存在菜品列表,直接返回 + if (dishVOList != null && dishVOList.size() > 0) { + return Result.success(dishVOList); + } + + // 如果缓存中不存在,则从数据库中查询 + Dish dish = new Dish(); + dish.setCategoryId(categoryId); // 设置查询条件为分类ID + dish.setStatus(StatusConstant.ENABLE); // 查询起售中的菜品 + + // 从数据库中获取菜品列表,并存入缓存 + List list = dishService.listWithFlavor(dish); + valueOperations.set(key, list); // 将查询结果存入Redis缓存 + + // 返回查询结果 + return Result.success(list); + } +} \ No newline at end of file diff --git a/sky/sky-server/src/main/java/com/sky/controller/user/ShoppingCartController.java b/sky/sky-server/src/main/java/com/sky/controller/user/ShoppingCartController.java new file mode 100644 index 0000000..1d1e5eb --- /dev/null +++ b/sky/sky-server/src/main/java/com/sky/controller/user/ShoppingCartController.java @@ -0,0 +1,99 @@ +// 定义包名,表示该类属于com.sky.controller.user包 +package com.sky.controller.user; + +// 导入所需的类和接口 +import com.sky.dto.ShoppingCartDTO; +import com.sky.entity.ShoppingCart; +import com.sky.result.Result; +import com.sky.service.ShoppingCartService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +// 使用@RestController注解声明这是一个REST控制器,返回的数据会自动转换为JSON格式 +@RestController +// 使用@Api注解标记这个控制器属于哪个API分类 +@Api("C端购物车相关接口") +// 使用@Slf4j注解为类自动注入一个日志对象 +@Slf4j +// 使用@RequestMapping注解定义类级别的路由,所有的请求都会以"/user/shoppingCart"作为前缀 +@RequestMapping("/user/shoppingCart") +public class ShoppingCartController { + // 自动注入ShoppingCartService服务 + @Autowired + ShoppingCartService shoppingCartService; + + /** + * 添加商品到购物车接口 + * + * @param shoppingCartDTO 包含商品信息的购物车DTO对象 + * @return 操作结果 + */ + @PostMapping("/add") + @ApiOperation("添加购物车") + public Result add(@RequestBody ShoppingCartDTO shoppingCartDTO) { + // 记录日志,输出添加到购物车的商品信息 + log.info("添加购物车:购物车信息:{}", shoppingCartDTO); + + // 调用服务层添加商品到购物车 + shoppingCartService.add(shoppingCartDTO); + // 返回操作成功的结果 + return Result.success(); + } + + /** + * 查看用户购物车数据接口 + * + * @return 用户购物车中的商品列表 + */ + @GetMapping("/list") + @ApiOperation("查看购物车") + public Result> list() { + // 记录日志,标记查看购物车数据的操作 + log.info("查看购物车数据"); + + // 调用服务层获取用户购物车中的商品列表 + List shoppingCartList = shoppingCartService.list(); + // 返回购物车商品列表 + return Result.success(shoppingCartList); + } + + /** + * 删除购物车中的一个商品接口 + * + * @param shoppingCartDTO 包含商品信息的购物车DTO对象 + * @return 操作结果 + */ + @PostMapping("/sub") + @ApiOperation("删除购物车中的商品") + public Result delete(@RequestBody ShoppingCartDTO shoppingCartDTO){ + // 记录日志,输出删除的商品信息 + log.info("删除购物车中的商品:{}",shoppingCartDTO); + // 调用服务层删除购物车中的一个商品 + shoppingCartService.delete(shoppingCartDTO); + + // 返回操作成功的结果 + return Result.success(); + } + + /** + * 清空购物车接口 + * + * @return 操作结果 + */ + @DeleteMapping("/clean") + @ApiOperation("清空购物车") + public Result clean(){ + // 记录日志,标记清空购物车的操作 + log.info("清空购物车"); + // 调用服务层清空购物车 + shoppingCartService.clean(); + + // 返回操作成功的结果 + return Result.success(); + } +} \ No newline at end of file diff --git a/sky/sky-server/src/main/java/com/sky/interceptor/JwtTokenUserInterceptor.java b/sky/sky-server/src/main/java/com/sky/interceptor/JwtTokenUserInterceptor.java new file mode 100644 index 0000000..29a11fc --- /dev/null +++ b/sky/sky-server/src/main/java/com/sky/interceptor/JwtTokenUserInterceptor.java @@ -0,0 +1,68 @@ +// 定义包名,表示该类属于com.sky.interceptor包 +package com.sky.interceptor; + +// 导入所需的类和接口 +import com.sky.constant.JwtClaimsConstant; +import com.sky.constant.MessageConstant; +import com.sky.context.BaseContext; +import com.sky.properties.JwtProperties; +import com.sky.utils.JwtUtil; +import io.jsonwebtoken.Claims; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.web.method.HandlerMethod; +import org.springframework.web.servlet.HandlerInterceptor; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +/** + * JWT令牌校验的拦截器,用于在Spring MVC应用中拦截请求并验证JWT令牌的有效性。 + */ +@Component +@Slf4j +public class JwtTokenUserInterceptor implements HandlerInterceptor { + + // 自动注入JwtProperties,用于获取JWT配置属性 + @Autowired + private JwtProperties jwtProperties; + + /** + * preHandle方法在请求处理之前进行调用,除非抛出异常,否则总是被调用。 + * + * @param request 当前请求对象 + * @param response 当前响应对象 + * @param handler HandlerMethod对象,如果当前拦截的是Controller的方法,则handler是非空的 + * @return true表示继续流程(如调用下一个拦截器或处理器);返回false表示流程中断,返回false后,不会继续调用其他的拦截器或处理器,此时需要通过response向客户返回响应内容 + * @throws Exception 可能抛出的异常 + */ + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler){ + // 判断当前拦截到的是Controller的方法还是其他资源 + if (!(handler instanceof HandlerMethod)) { + // 当前拦截到的不是动态方法,直接放行 + return true; + } + HandlerMethod handlerMethod= (HandlerMethod) handler; + // 1、从请求头中获取令牌 + String token = request.getHeader(jwtProperties.getUserTokenName()); + + // 2、校验令牌 + try { + log.info("jwt校验:{}", token); + // 使用JwtUtil解析JWT令牌 + Claims claims = JwtUtil.parseJWT(jwtProperties.getUserSecretKey(), token); + // 从claims中获取用户ID,并设置到BaseContext中,供后续使用 + Long empId = Long.valueOf(claims.get(JwtClaimsConstant.USER_ID).toString()); + BaseContext.setCurrentId(empId); + log.info("当前用户id:{}", empId); + // 3、通过,放行 + return true; + } catch (Exception ex) { + // 4、不通过,响应401状态码 + log.error(MessageConstant.USER_NOT_LOGIN); + response.setStatus(401); + return false; + } + } +} \ No newline at end of file diff --git a/sky/sky-server/src/main/java/com/sky/mapper/EmployeeMapper.java b/sky/sky-server/src/main/java/com/sky/mapper/EmployeeMapper.java new file mode 100644 index 0000000..3cc3b42 --- /dev/null +++ b/sky/sky-server/src/main/java/com/sky/mapper/EmployeeMapper.java @@ -0,0 +1,59 @@ +// 定义包名,表示该类属于com.sky.mapper包 +package com.sky.mapper; + +// 导入所需的类和注解 +import com.github.pagehelper.Page; +import com.sky.annotation.AutoFill; +import com.sky.dto.EmployeePageQueryDTO; +import com.sky.entity.Employee; +import com.sky.enumeration.OperationType; +import org.apache.ibatis.annotations.Insert; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Select; + +// 使用@Mapper注解标记这是一个MyBatis的Mapper接口 +@Mapper +public interface EmployeeMapper { + + /** + * 根据用户名查询员工信息 + * + * @param username 用户名 + * @return 返回匹配的员工对象 + */ + @Select("select * from employee where username = #{username}") + Employee getByUsername(String username); + + /** + * 插入员工数据,并自动填充创建相关的字段(如创建时间和创建用户等) + * + * @param employee 员工对象,包含要插入的数据 + */ + @AutoFill(OperationType.INSERT) + @Insert("insert into employee(name,username,password,phone,sex,id_number,create_time,update_time,create_user,update_user,status)" + + " values(#{name},#{username},#{password},#{phone},#{sex},#{idNumber},#{createTime},#{updateTime},#{createUser},#{updateUser},#{status})") + void save(Employee employee); + + /** + * 分页查询员工数据 + * + * @param employeePageQueryDTO 分页查询参数 + * @return 返回分页包装的员工对象列表 + */ + Page pageQuery(EmployeePageQueryDTO employeePageQueryDTO); + + /** + * 更新员工信息,并自动填充更新相关的字段(如更新时间和更新用户等) + */ + @AutoFill(OperationType.UPDATE) + void update(Employee employee); + + /** + * 通过id查询员工信息 + * + * @param id 员工的ID + * @return 返回匹配的员工对象 + */ + @Select("select * from employee where id=#{id}") + Employee getById(Long id); +} \ No newline at end of file diff --git a/sky/sky-server/src/main/java/com/sky/mapper/SetmealMapper.java b/sky/sky-server/src/main/java/com/sky/mapper/SetmealMapper.java new file mode 100644 index 0000000..aa63ee6 --- /dev/null +++ b/sky/sky-server/src/main/java/com/sky/mapper/SetmealMapper.java @@ -0,0 +1,116 @@ +// 定义包名,表示该类属于com.sky.mapper包 +package com.sky.mapper; + +// 导入所需的类和注解 +import com.github.pagehelper.Page; +import com.sky.annotation.AutoFill; +import com.sky.dto.SetmealDTO; +import com.sky.entity.SetmealDish; +import com.sky.enumeration.OperationType; +import com.sky.dto.SetmealPageQueryDTO; +import com.sky.entity.Setmeal; +import com.sky.vo.DishItemVO; +import com.sky.vo.SetmealVO; +import org.apache.ibatis.annotations.Delete; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Select; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +// 使用@Mapper注解标记这是一个MyBatis的Mapper接口 +@Mapper +public interface SetmealMapper { + + /** + * 根据条件统计套餐数量 + * + * @param map 条件参数 + * @return 返回套餐数量 + */ + Integer countByMap(Map map); + + /** + * 动态条件查询套餐 + * + * @param setmeal 套餐对象,包含查询条件 + * @return 返回套餐列表 + */ + List list(Setmeal setmeal); + + /** + * 根据套餐id查询该套餐的菜品 + * + * @param setmealId 套餐ID + * @return 返回套餐包含的菜品项视图对象列表 + */ + @Select("select sd.name, sd.copies, d.image, d.description " + + "from setmeal_dish sd left join dish d on sd.dish_id = d.id " + + "where sd.setmeal_id = #{setmealId}") + List getDishItemBySetmealId(Long setmealId); + + /** + * 分页查询套餐 + * + * @param setmealPageQueryDTO 分页查询参数 + * @return 返回分页包装的套餐对象列表 + */ + Page pageQuery(SetmealPageQueryDTO setmealPageQueryDTO); + + /** + * 更新套餐信息,并自动填充更新相关的字段(如更新时间和更新用户等) + * + * @param setmeal 套餐对象,包含要更新的数据 + */ + @AutoFill(OperationType.UPDATE) + void updateSetmeal(Setmeal setmeal); + + /** + * 根据套餐id删除绑定在套餐上的菜品 + * + * @param id 套餐ID + */ + @Delete("delete from setmeal_dish where setmeal_id=#{id}") + void deleteSetmealDish(Long id); + + /** + * 批量插入套餐绑定的菜品 + * + * @param setmealDishes 套餐菜品绑定关系列表 + */ + void insertBatchSetmealDish(List setmealDishes); + + /** + * 根据套餐id获取套餐 + * + * @param id 套餐ID + * @return 返回套餐对象 + */ + @Select("select * from setmeal where id=#{id}") + Setmeal getBySetmealId(Long id); + + /** + * 根据套餐id获取套餐菜品绑定关系 + * + * @param id 套餐ID + * @return 返回套餐菜品绑定关系列表 + */ + @Select("select * from setmeal_dish where setmeal_id=#{id}") + List getSetmealDishById(Long id); + + /** + * 根据套餐id批量删除套餐 + * + * @param ids 套餐ID列表 + */ + void batchDeleteSetmeal(ArrayList ids); + + /** + * 插入套餐信息,并自动填充创建相关的字段(如创建时间和创建用户等) + * + * @param setmeal 套餐对象,包含要插入的数据 + */ + @AutoFill(OperationType.INSERT) + void insertSetmeal(Setmeal setmeal); +} \ No newline at end of file diff --git a/sky/sky-server/src/main/java/com/sky/service/CommonService.java b/sky/sky-server/src/main/java/com/sky/service/CommonService.java new file mode 100644 index 0000000..a231602 --- /dev/null +++ b/sky/sky-server/src/main/java/com/sky/service/CommonService.java @@ -0,0 +1,25 @@ +// 定义一个名为com.sky.service的包,用于存放服务相关的类和接口 +package com.sky.service; + +// 导入Spring框架中的@Service注解,用于声明一个服务组件 +import org.springframework.stereotype.Service; +// 导入MultipartFile接口,用于处理上传的文件 +import org.springframework.web.multipart.MultipartFile; + +// 导入Java的IOException类,用于处理可能发生的IO异常 +import java.io.IOException; + +// 使用@Service注解标记这个接口,表明它是一个Spring管理的服务组件 +@Service +// 声明一个名为CommonService的接口 +public interface CommonService { + + /** + * 上传文件的方法。 + * + * @param file 要上传的文件对象,类型为MultipartFile,它包含了文件的二进制数据以及文件的元数据(如文件名、文件大小等)。 + * @return 一个字符串,表示上传操作的结果,可能是文件的存储路径或者上传成功的确认信息。 + * @throws IOException 如果在文件上传过程中发生IO异常,则抛出IOException。 + */ + String upload(MultipartFile file) throws IOException; +} \ No newline at end of file diff --git a/sky/sky-server/src/main/java/com/sky/service/ReportService.java b/sky/sky-server/src/main/java/com/sky/service/ReportService.java new file mode 100644 index 0000000..0d31727 --- /dev/null +++ b/sky/sky-server/src/main/java/com/sky/service/ReportService.java @@ -0,0 +1,66 @@ +// 定义一个名为com.sky.service的包,用于存放服务相关的类和接口 +package com.sky.service; + +// 导入com.sky.result.Result类,用于封装方法的返回结果 +import com.sky.result.Result; +// 导入com.sky.vo包下的各种VO(Value Object)类,这些类用于封装数据传输对象 +import com.sky.vo.*; +// 导入org.apache.http.HttpResponse类,用于处理HTTP响应 +import org.apache.http.HttpResponse; +// 导入org.apache.poi.openxml4j.exceptions.InvalidFormatException类,用于处理Excel文件格式无效的异常 +import org.apache.poi.openxml4j.exceptions.InvalidFormatException; + +import javax.servlet.http.HttpServletResponse; // 导入HttpServletResponse类,用于处理HTTP响应 +import java.io.FileNotFoundException; // 导入FileNotFoundException类,用于处理文件未找到的异常 +import java.io.IOException; // 导入IOException类,用于处理IO异常 +import java.time.LocalDate; // 导入LocalDate类,用于表示没有时间的日期 +import java.time.LocalDateTime; // 导入LocalDateTime类,用于表示日期和时间 + +// 声明一个名为ReportService的接口 +public interface ReportService { + + /** + * 统计营业额的方法。 + * + * @param begin 开始日期,类型为LocalDate,表示统计的起始日期。 + * @param end 结束日期,类型为LocalDate,表示统计的结束日期。 + * @return 返回一个Result对象,其中包含TurnoverReportVO类型的数据,VO中封装了营业额统计的相关信息。 + */ + Result getTurnoverStatistics(LocalDate begin, LocalDate end); + + /** + * 用户统计的方法。 + * + * @param begin 开始日期,类型为LocalDate,表示统计的起始日期。 + * @param end 结束日期,类型为LocalDate,表示统计的结束日期。 + * @return 返回一个UserReportVO对象,其中封装了用户统计的相关信息。 + */ + UserReportVO userStatistics(LocalDate begin, LocalDate end); + + /** + * 订单统计的方法。 + * + * @param begin 开始日期,类型为LocalDate,表示统计的起始日期。 + * @param end 结束日期,类型为LocalDate,表示统计的结束日期。 + * @return 返回一个OrderReportVO对象,其中封装了订单统计的相关信息。 + */ + OrderReportVO orderStatistics(LocalDate begin, LocalDate end); + + /** + * 获取销量排行前十的方法。 + * + * @param begin 开始日期,类型为LocalDate,表示统计的起始日期。 + * @param end 结束日期,类型为LocalDate,表示统计的结束日期。 + * @return 返回一个SalesTop10ReportVO对象,其中封装了销量排行前十的相关信息。 + */ + SalesTop10ReportVO salesTop10Report(LocalDate begin, LocalDate end); + + /** + * 导出excel表格的方法。 + * + * @param httpResponse HttpServletResponse对象,用于将生成的Excel文件写入HTTP响应中,以便客户端下载。 + * @throws IOException 如果在文件导出过程中发生IO异常,则抛出IOException。 + * @throws InvalidFormatException 如果生成的Excel文件格式无效,则抛出InvalidFormatException。 + */ + void export(HttpServletResponse httpResponse) throws IOException, InvalidFormatException; +} \ No newline at end of file diff --git a/sky/sky-server/src/main/java/com/sky/service/WorkspaceService.java b/sky/sky-server/src/main/java/com/sky/service/WorkspaceService.java new file mode 100644 index 0000000..52901fd --- /dev/null +++ b/sky/sky-server/src/main/java/com/sky/service/WorkspaceService.java @@ -0,0 +1,48 @@ +// 定义一个名为com.sky.service的包,用于存放服务相关的类和接口 +package com.sky.service; + +// 导入com.sky.vo包下的BusinessDataVO类,用于封装业务数据 +import com.sky.vo.BusinessDataVO; +// 导入com.sky.vo包下的DishOverViewVO类,用于封装菜品总览数据 +import com.sky.vo.DishOverViewVO; +// 导入com.sky.vo包下的OrderOverViewVO类,用于封装订单总览数据 +import com.sky.vo.OrderOverViewVO; +// 导入com.sky.vo包下的SetmealOverViewVO类,用于封装套餐总览数据 +import com.sky.vo.SetmealOverViewVO; +// 导入java.time.LocalDateTime类,用于表示日期和时间 +import java.time.LocalDateTime; + +// 声明一个名为WorkspaceService的接口 +public interface WorkspaceService { + + /** + * 根据时间段统计营业数据的方法。 + * + * @param begin 开始时间,类型为LocalDateTime,表示统计的起始时间点。 + * @param end 结束时间,类型为LocalDateTime,表示统计的结束时间点。 + * @return 返回一个BusinessDataVO对象,其中封装了根据时间段统计的营业数据。 + */ + BusinessDataVO getBusinessData(LocalDateTime begin, LocalDateTime end); + + /** + * 查询订单管理数据的方法。 + * + * @return 返回一个OrderOverViewVO对象,其中封装了订单管理的总览数据。 + */ + OrderOverViewVO getOrderOverView(); + + /** + * 查询菜品总览的方法。 + * + * @return 返回一个DishOverViewVO对象,其中封装了菜品的总览数据。 + */ + DishOverViewVO getDishOverView(); + + /** + * 查询套餐总览的方法。 + * + * @return 返回一个SetmealOverViewVO对象,其中封装了套餐的总览数据。 + */ + SetmealOverViewVO getSetmealOverView(); + +} \ No newline at end of file diff --git a/sky/sky-server/src/main/java/com/sky/service/impl/CategoryServiceImpl.java b/sky/sky-server/src/main/java/com/sky/service/impl/CategoryServiceImpl.java new file mode 100644 index 0000000..797015f --- /dev/null +++ b/sky/sky-server/src/main/java/com/sky/service/impl/CategoryServiceImpl.java @@ -0,0 +1,115 @@ +// 定义包名,表示该类属于com.sky.service.impl包 +package com.sky.service.impl; + +// 导入所需的类和接口 +import com.github.pagehelper.Page; +import com.github.pagehelper.PageHelper; +import com.sky.constant.StatusConstant; +import com.sky.dto.CategoryDTO; +import com.sky.dto.CategoryPageQueryDTO; +import com.sky.entity.Category; +import com.sky.mapper.CategoryMapper; +import com.sky.result.PageResult; +import com.sky.service.CategoryService; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; + +// 使用@Service注解标记这是一个Spring服务组件 +@Service +public class CategoryServiceImpl implements CategoryService { + // 自动注入CategoryMapper + @Autowired + CategoryMapper categoryMapper; + + /** + * 分类分页查询 + * + * @param categoryPageQueryDTO 分页查询参数 + * @return 分页查询结果 + */ + public PageResult pageQuery(CategoryPageQueryDTO categoryPageQueryDTO) { + PageResult pageResult = new PageResult(); + // 使用PageHelper开始分页查询 + PageHelper.startPage(categoryPageQueryDTO.getPage(), categoryPageQueryDTO.getPageSize()); + // 调用mapper进行分页查询 + Page pageQuery = categoryMapper.pageQuery(categoryPageQueryDTO); + // 设置查询结果和总记录数 + pageResult.setRecords(pageQuery.getResult()); + pageResult.setTotal(pageQuery.getTotal()); + + return pageResult; + } + + /** + * 根据分类类型查询分类 + * + * @param type 分类类型 + * @return 分类列表 + */ + public List query(Integer type) { + ArrayList result; + CategoryDTO categoryDTO = new CategoryDTO(); + categoryDTO.setType(type); + // 调用mapper查询分类 + result = (ArrayList) categoryMapper.query(categoryDTO); + + return result; + } + + /** + * 删除分类 + * + * @param id 要删除的分类ID + */ + public void delete(Long id) { + // 调用mapper删除分类 + categoryMapper.delete(id); + } + + /** + * 修改分类 + * + * @param categoryDTO 包含修改信息的分类DTO + */ + public void updateCategory(CategoryDTO categoryDTO) { + Category category = new Category(); + // 使用BeanUtils复制属性 + BeanUtils.copyProperties(categoryDTO, category); + // 调用mapper更新分类 + categoryMapper.updateCategory(category); + } + + /** + * 启用或禁用分类 + * + * @param status 状态值 + * @param id 分类ID + */ + public void startOrStop(Integer status, Long id) { + Category category = Category.builder() + .status(status) + .id(id) + .build(); + // 调用mapper更新分类状态 + categoryMapper.updateCategory(category); + } + + /** + * 新增分类 + * + * @param categoryDTO 包含新增信息的分类DTO + */ + public void save(CategoryDTO categoryDTO) { + Category category = new Category(); + // 使用BeanUtils复制属性 + BeanUtils.copyProperties(categoryDTO, category); + // 设置分类状态为禁用 + category.setStatus(StatusConstant.DISABLE); + // 调用mapper保存分类 + categoryMapper.save(category); + } +} \ No newline at end of file diff --git a/sky/sky-server/src/main/java/com/sky/service/impl/OrderServiceImpl.java b/sky/sky-server/src/main/java/com/sky/service/impl/OrderServiceImpl.java new file mode 100644 index 0000000..e4f6e90 --- /dev/null +++ b/sky/sky-server/src/main/java/com/sky/service/impl/OrderServiceImpl.java @@ -0,0 +1,260 @@ +// 定义包名,表示该类属于com.sky.service.impl包 +package com.sky.service.impl; + +// 导入所需的类和接口 +import com.alibaba.druid.support.json.JSONUtils; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.github.pagehelper.Page; +import com.github.pagehelper.PageHelper; +import com.sky.constant.MessageConstant; +import com.sky.context.BaseContext; +import com.sky.dto.*; +import com.sky.entity.*; +import com.sky.exception.AddressBookBusinessException; +import com.sky.exception.OrderBusinessException; +import com.sky.exception.ShoppingCartBusinessException; +import com.sky.mapper.*; +import com.sky.result.PageResult; +import com.sky.service.OrderService; +import com.sky.utils.WeChatPayUtil; +import com.sky.vo.OrderPaymentVO; +import com.sky.vo.OrderStatisticsVO; +import com.sky.vo.OrderSubmitVO; +import com.sky.vo.OrderVO; +import com.sky.webSocket.WebSocketServer; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; + +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +// 使用@Service注解标记这是一个Spring服务组件 +@Service +public class OrderServiceImpl implements OrderService { + // 自动注入OrderMapper + @Autowired + private OrderMapper orderMapper; + // 自动注入OrderDetailMapper + @Autowired + private OrderDetailMapper orderDetailMapper; + // 自动注入AddressBookMapper + @Autowired + private AddressBookMapper addressBookMapper; + // 自动注入ShoppingCartMapper + @Autowired + private ShoppingCartMapper shoppingCartMapper; + // 自动注入UserMapper + @Autowired + private UserMapper userMapper; + // 自动注入WeChatPayUtil + @Autowired + private WeChatPayUtil weChatPayUtil; + // 自动注入WebSocketServer + @Autowired + private WebSocketServer webSocketServer; + + /** + * 完成订单 + * + * @param id 订单ID + */ + public void complete(Long id) { + // 根据id查询订单 + Orders ordersDB = orderMapper.getById(id); + + // 校验订单是否存在,并且状态为派送中 + if (ordersDB == null || !ordersDB.getStatus().equals(Orders.DELIVERY_IN_PROGRESS)) { + throw new OrderBusinessException(MessageConstant.ORDER_STATUS_ERROR); + } + + Orders orders = new Orders(); + orders.setId(ordersDB.getId()); + // 更新订单状态,状态转为完成 + orders.setStatus(Orders.COMPLETED); + orders.setDeliveryTime(LocalDateTime.now()); + + orderMapper.update(orders); + } + + /** + * 派送订单 + * + * @param id 订单ID + */ + public void delivery(Long id) { + // 根据id查询订单 + Orders ordersDB = orderMapper.getById(id); + + // 校验订单是否存在,并且状态为已接单 + if (ordersDB == null || !ordersDB.getStatus().equals(Orders.CONFIRMED)) { + throw new OrderBusinessException(MessageConstant.ORDER_STATUS_ERROR); + } + + Orders orders = new Orders(); + orders.setId(ordersDB.getId()); + // 更新订单状态,状态转为派送中 + orders.setStatus(Orders.DELIVERY_IN_PROGRESS); + + orderMapper.update(orders); + } + + /** + * 取消订单 + * + * @param ordersCancelDTO 包含取消订单信息的DTO + */ + public void cancel(OrdersCancelDTO ordersCancelDTO) throws Exception { + // 根据id查询订单 + Orders ordersDB = orderMapper.getById(ordersCancelDTO.getId()); + + // 支付状态 + Integer payStatus = ordersDB.getPayStatus(); + if (payStatus == 1) { + // 用户已支付,需要退款 + // 调用微信支付退款接口 + // String refund = weChatPayUtil.refund( + // ordersDB.getNumber(), + // ordersDB.getNumber(), + // new BigDecimal(0.01), + // new BigDecimal(0.01)); + } + + // 管理端取消订单需要退款,根据订单id更新订单状态、取消原因、取消时间 + Orders orders = new Orders(); + orders.setId(ordersCancelDTO.getId()); + orders.setStatus(Orders.CANCELLED); + orders.setCancelReason(ordersCancelDTO.getCancelReason()); + orders.setCancelTime(LocalDateTime.now()); + orderMapper.update(orders); + } + + /** + * 拒单 + * + * @param ordersRejectionDTO 包含拒单信息的DTO + */ + public void rejection(OrdersRejectionDTO ordersRejectionDTO) throws Exception { + // 根据id查询订单 + Orders ordersDB = orderMapper.getById(ordersRejectionDTO.getId()); + + // 订单只有存在且状态为待接单才可以拒单 + if (ordersDB == null || !ordersDB.getStatus().equals(Orders.TO_BE_CONFIRMED)) { + throw new OrderBusinessException(MessageConstant.ORDER_STATUS_ERROR); + } + + // 支付状态 + Integer payStatus = ordersDB.getPayStatus(); + if (Objects.equals(payStatus, Orders.PAID)) { + // 用户已支付,需要退款 + // 调用微信支付退款接口 + // String refund = weChatPayUtil.refund( + // ordersDB.getNumber(), + // ordersDB.getNumber(), + // new BigDecimal(0.01), + // new BigDecimal(0.01)); + } + + // 拒单需要退款,根据订单id更新订单状态、拒单原因、取消时间 + Orders orders = new Orders(); + orders.setId(ordersDB.getId()); + orders.setStatus(Orders.CANCELLED); + orders.setRejectionReason(ordersRejectionDTO.getRejectionReason()); + orders.setCancelTime(LocalDateTime.now()); + + orderMapper.update(orders); + } + + /** + * 接单 + * + * @param ordersConfirmDTO 包含接单信息的DTO + */ + public void confirm(OrdersConfirmDTO ordersConfirmDTO) { + Orders orders = Orders.builder() + .id(ordersConfirmDTO.getId()) + .status(Orders.CONFIRMED) + .build(); + + orderMapper.update(orders); + } + + /** + * 各个状态的订单数量统计 + * + * @return 订单统计视图对象 + */ + public OrderStatisticsVO statistics() { + // 根据状态,分别查询出待接单、待派送、派送中的订单数量 + Integer toBeConfirmed = orderMapper.countStatus(Orders.TO_BE_CONFIRMED); + Integer confirmed = orderMapper.countStatus(Orders.CONFIRMED); + Integer deliveryInProgress = orderMapper.countStatus(Orders.DELIVERY_IN_PROGRESS); + + // 将查询出的数据封装到orderStatisticsVO中响应 + OrderStatisticsVO orderStatisticsVO = new OrderStatisticsVO(); + orderStatisticsVO.setToBeConfirmed(toBeConfirmed); + orderStatisticsVO.setConfirmed(confirmed); + orderStatisticsVO.setDeliveryInProgress(deliveryInProgress); + return orderStatisticsVO; + } + + /** + * 订单搜索 + * + * @param ordersPageQueryDTO 分页查询参数 + * @return 分页查询结果 + */ + public PageResult conditionSearch(OrdersPageQueryDTO ordersPageQueryDTO) { + PageHelper.startPage(ordersPageQueryDTO.getPage(), ordersPageQueryDTO.getPageSize()); + + Page page = orderMapper.pageQuery(ordersPageQueryDTO); + + // 部分订单状态,需要额外返回订单菜品信息,将Orders转化为OrderVO + List orderVOList = getOrderVOList(page); + + return new PageResult(page.getTotal(), orderVOList); + } + + private List getOrderVOList(Page page) { + // 需要返回订单菜品信息,自定义OrderVO响应结果 + List orderVOList = new ArrayList<>(); + + List ordersList = page.getResult(); + if (!CollectionUtils.isEmpty(ordersList)) { + for (Orders orders : ordersList) { + // 将共同字段复制到OrderVO + OrderVO orderVO = new OrderVO(); + BeanUtils.copyProperties(orders, orderVO); + String orderDishes = getOrderDishesStr(orders); + + // 将订单菜品信息封装到orderVO中,并添加到orderVOList + orderVO.setOrderDishes(orderDishes); + orderVOList.add(orderVO); + } + } + return orderVOList; + } + + /** + * 根据订单id获取菜品信息字符串 + * + * @param orders 订单对象 + * @return 订单菜品信息字符串 + */ + private String getOrderDishesStr(Orders orders) { + // 查询订单菜品详情信息(订单中的菜品和数量) + List orderDetailList = orderDetailMapper.getByOrderId(orders.getId()); + + // 将每一条订单菜品信息拼接为字符串(格式:宫保鸡丁*3;) + List orderDishList = orderDetailList.stream().map(x -> { + String orderDish = x.getName() + "*" + x.getNumber() + ";"; + return orderDish; + }).collect \ No newline at end of file diff --git a/sky/sky-server/src/main/java/com/sky/service/impl/UserServiceImpl.java b/sky/sky-server/src/main/java/com/sky/service/impl/UserServiceImpl.java new file mode 100644 index 0000000..d92c003 --- /dev/null +++ b/sky/sky-server/src/main/java/com/sky/service/impl/UserServiceImpl.java @@ -0,0 +1,86 @@ +// 定义包名,表示该类属于com.sky.service.impl包 +package com.sky.service.impl; + +// 导入所需的类和接口 +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.sky.constant.MessageConstant; +import com.sky.dto.UserLoginDTO; +import com.sky.entity.User; +import com.sky.exception.LoginFailedException; +import com.sky.mapper.UserMapper; +import com.sky.properties.WeChatProperties; +import com.sky.service.UserService; +import com.sky.utils.HttpClientUtil; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.time.LocalDateTime; +import java.util.HashMap; +import java.util.Map; + +// 使用@Service注解标记这是一个Spring服务组件 +@Service +public class UserServiceImpl implements UserService { + + // 自动注入UserMapper + @Autowired + UserMapper userMapper; + // 自动注入WeChatProperties + @Autowired + WeChatProperties weChatProperties; + + // 微信登录接口的URL + private static final String WX_LOGIN = "https://api.weixin.qq.com/sns/jscode2session"; + + /** + * 微信登录 + * + * @param userLoginDTO 包含登录信息的DTO + * @return 用户对象 + */ + public User wxLogin(UserLoginDTO userLoginDTO) { + // 通过code获取openid + String openid = getOpenid(userLoginDTO.getCode()); + + // 判断openid是否存在 + if (openid == null || openid.equals("")) { + throw new LoginFailedException(MessageConstant.LOGIN_FAILED); + } + // 当前用户为新用户,完成自动注册 + User user = userMapper.getByOpenId(openid); + if (user == null) { + // 创建新用户对象 + user = User.builder() + .openid(openid) + .createTime(LocalDateTime.now()).build(); + // 插入新用户到数据库 + userMapper.insertUser(user); + } + return user; + } + + /** + * 通过code获取openid + * + * @param code 微信登录code + * @return openid字符串 + */ + private String getOpenid(String code) { + // 参数映射 + Map paramMap = new HashMap<>(); + paramMap.put("appid", weChatProperties.getAppid()); + paramMap.put("secret", weChatProperties.getSecret()); + paramMap.put("js_code", code); + paramMap.put("grant_type", "authorization_code"); + // 发起HTTP GET请求 + String result = HttpClientUtil.doGet(WX_LOGIN, paramMap); + + // 获取请求结果 + JSONObject jsonObject = JSON.parseObject(result); + // 从结果中获取openid + String openid = jsonObject.getString("openid"); + + return openid; + } +} \ No newline at end of file