From cb6babc47d81df171b7cc0941ab40cb86f78c2c7 Mon Sep 17 00:00:00 2001 From: YOUR_USERNAME <1822377117@qq.com> Date: Tue, 17 Dec 2024 23:55:21 +0800 Subject: [PATCH] zhaoyuyan_server --- .../com/sky/config/WebMvcConfiguration.java | 132 +++++++++++ .../sky/controller/admin/DishController.java | 186 +++++++++++++++ .../controller/admin/SetmealController.java | 149 ++++++++++++ .../user/AddressBookController.java | 149 ++++++++++++ .../controller/user/SetmealController.java | 81 +++++++ .../sky/handler/GlobalExceptionHandler.java | 61 +++++ .../java/com/sky/mapper/CategoryMapper.java | 78 +++++++ .../main/java/com/sky/mapper/OrderMapper.java | 125 ++++++++++ .../main/java/com/sky/mapper/UserMapper.java | 59 +++++ .../com/sky/service/AddressBookService.java | 63 +++++ .../java/com/sky/service/EmployeeService.java | 70 ++++++ .../com/sky/service/ShoppingCartService.java | 43 ++++ .../com/sky/service/impl/DishServiceImpl.java | 221 ++++++++++++++++++ .../sky/service/impl/SetmealServiceImpl.java | 205 ++++++++++++++++ .../com/sky/webSocket/WebSocketServer.java | 93 ++++++++ 15 files changed, 1715 insertions(+) create mode 100644 sky/sky-server/src/main/java/com/sky/config/WebMvcConfiguration.java create mode 100644 sky/sky-server/src/main/java/com/sky/controller/admin/DishController.java create mode 100644 sky/sky-server/src/main/java/com/sky/controller/admin/SetmealController.java create mode 100644 sky/sky-server/src/main/java/com/sky/controller/user/AddressBookController.java create mode 100644 sky/sky-server/src/main/java/com/sky/controller/user/SetmealController.java create mode 100644 sky/sky-server/src/main/java/com/sky/handler/GlobalExceptionHandler.java create mode 100644 sky/sky-server/src/main/java/com/sky/mapper/CategoryMapper.java create mode 100644 sky/sky-server/src/main/java/com/sky/mapper/OrderMapper.java create mode 100644 sky/sky-server/src/main/java/com/sky/mapper/UserMapper.java create mode 100644 sky/sky-server/src/main/java/com/sky/service/AddressBookService.java create mode 100644 sky/sky-server/src/main/java/com/sky/service/EmployeeService.java create mode 100644 sky/sky-server/src/main/java/com/sky/service/ShoppingCartService.java create mode 100644 sky/sky-server/src/main/java/com/sky/service/impl/DishServiceImpl.java create mode 100644 sky/sky-server/src/main/java/com/sky/service/impl/SetmealServiceImpl.java create mode 100644 sky/sky-server/src/main/java/com/sky/webSocket/WebSocketServer.java diff --git a/sky/sky-server/src/main/java/com/sky/config/WebMvcConfiguration.java b/sky/sky-server/src/main/java/com/sky/config/WebMvcConfiguration.java new file mode 100644 index 0000000..abd4b3a --- /dev/null +++ b/sky/sky-server/src/main/java/com/sky/config/WebMvcConfiguration.java @@ -0,0 +1,132 @@ +package com.sky.config; + +import com.sky.interceptor.JwtTokenAdminInterceptor; +import com.sky.interceptor.JwtTokenUserInterceptor; +import com.sky.json.JacksonObjectMapper; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +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.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport; +import springfox.documentation.builders.ApiInfoBuilder; +import springfox.documentation.builders.PathSelectors; +import springfox.documentation.builders.RequestHandlerSelectors; +import springfox.documentation.service.ApiInfo; +import springfox.documentation.spi.DocumentationType; +import springfox.documentation.spring.web.plugins.Docket; +import java.util.List; + +/** + * WebMvcConfiguration类,作为配置类,主要用于注册web层相关的各类组件, + * 它继承自WebMvcConfigurationSupport类,借助Spring框架提供的配置机制,来定制化配置Spring MVC相关的功能,例如拦截器、接口文档生成以及消息转换器等, + * 以满足项目中对于Web层的特定业务需求,确保Web层的各个功能模块能够协同工作,高效处理HTTP请求和响应等相关操作。 + */ +@Configuration +@Slf4j +public class WebMvcConfiguration extends WebMvcConfigurationSupport { + + /** + * 自动注入JwtTokenAdminInterceptor类型的拦截器,这个拦截器通常用于处理与管理员相关的请求拦截逻辑, + * 比如验证管理员身份、权限校验等操作,在请求到达对应的管理员接口之前进行前置处理,保障接口的安全性和权限合法性。 + */ + @Autowired + private JwtTokenAdminInterceptor jwtTokenAdminInterceptor; + + /** + * 自动注入JwtTokenUserInterceptor类型的拦截器,该拦截器主要针对普通用户相关的请求进行拦截处理, + * 例如验证普通用户的登录状态、权限范围等,确保只有符合条件的用户请求才能顺利访问相应的用户接口,维护用户接口的访问安全和权限控制。 + */ + @Autowired + private JwtTokenUserInterceptor jwtTokenUserInterceptor; + + /** + * 注册自定义拦截器的方法,在这个方法中,将之前注入的拦截器添加到拦截器注册表(InterceptorRegistry)中, + * 并配置它们要拦截的路径以及需要排除的路径,从而实现对不同类型请求(管理员请求和普通用户请求)的精准拦截控制,增强系统的安全性和权限管理。 + * + * @param registry 拦截器注册表对象,通过它来注册和配置拦截器与相应的拦截路径规则等信息。 + */ + protected void addInterceptors(InterceptorRegistry registry) { + log.info("开始注册自定义拦截器..."); + // 为管理员拦截器添加拦截路径规则,对以"/admin/"开头的所有路径进行拦截,意味着这些路径下的请求在到达具体的处理方法之前,会先经过这个拦截器进行相关处理。 + // 同时排除"/admin/employee/login"路径,即该登录接口不进行拦截,方便管理员进行登录操作,避免登录请求也被拦截导致无法正常登录的情况。 + registry.addInterceptor(jwtTokenAdminInterceptor) + .addPathPatterns("/admin/**") + .excludePathPatterns("/admin/employee/login"); + + // 为用户拦截器添加拦截路径规则,对以"/user/"开头的所有路径进行拦截,使得普通用户相关请求先经过此拦截器验证等操作。 + // 排除"/user/user/login"路径,保障普通用户的登录接口能正常访问不受拦截;同时排除"/user/shop/status"路径,该路径对应的功能可能不需要拦截验证等情况,具体根据业务需求而定。 + registry.addInterceptor(jwtTokenUserInterceptor) + .addPathPatterns("/user/**") + .excludePathPatterns("/user/user/login") + .excludePathPatterns("/user/shop/status"); + } + + /** + * 通过knife4j(基于Swagger 2进行扩展的工具)生成接口文档的方法,在这里配置接口文档的相关基本信息, + * 并指定要扫描生成文档的接口所在的包路径以及哪些路径下的接口需要被包含进来,最终返回一个Docket对象,用于构建和配置接口文档相关的详细信息。 + * + * @return 返回配置好的Docket对象,该对象承载了接口文档的核心配置信息,供knife4j等工具来生成对应的接口文档展示页面。 + */ + @Bean + public Docket docket() { + // 创建ApiInfo对象,用于设置接口文档的标题、版本以及描述等基本信息,这些信息会展示在接口文档页面的头部等位置,方便使用者了解接口文档的整体情况。 + ApiInfo apiInfo = new ApiInfoBuilder() + .title("接口文档") + .version("2.0") + .description("接口文档") + .build(); + + // 创建Docket对象,指定文档类型为DocumentationType.SWAGGER_2(即基于Swagger 2规范来生成文档),并设置之前构建好的ApiInfo对象,包含了文档的基本描述信息。 + // 通过.select()方法开始配置选择哪些接口要生成文档,先指定要扫描的接口所在的基础包路径(这里是"com.sky.controller",意味着该包及其子包下的符合条件的接口会被扫描到), + // 然后通过.paths(PathSelectors.any())表示只要是符合前面包路径下的任何路径对应的接口都会被包含进文档中,最后构建出完整的Docket对象。 + Docket docket = new Docket(DocumentationType.SWAGGER_2) + .apiInfo(apiInfo) + .select() + .apis(RequestHandlerSelectors.basePackage("com.sky.controller")) + .paths(PathSelectors.any()) + .build(); + + return docket; + } + + /** + * 设置静态资源映射的方法,重写了父类的addResourceHandlers方法,用于将特定的请求路径与对应的资源位置进行映射, + * 使得在Web应用中能够正确地访问到相应的静态资源,比如HTML页面、JavaScript文件、CSS文件等,保障前端页面能够正常加载和展示所需的资源内容。 + * + * @param registry 资源处理器注册表对象,通过它来注册和配置静态资源的请求路径与实际资源位置的映射关系。 + */ + @Override + protected void addResourceHandlers(ResourceHandlerRegistry registry) { + // 将请求路径"/doc.html"映射到类路径下的"/META-INF/resources/"目录,通常用于将接口文档相关的HTML页面等资源正确映射,以便在访问该路径时能展示对应的接口文档页面。 + registry.addResourceHandler("/doc.html").addResourceLocations("classpath:/META-INF/resources/"); + + // 将以"/webjars/**"开头的请求路径映射到类路径下的"/META-INF/resources/webjars/"目录,"webjars"一般用于管理Web项目中的前端依赖库等静态资源,通过这样的映射确保这些资源能被正确访问和使用。 + registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/"); + + super.addResourceHandlers(registry); + } + + /** + * 扩展spring MVC框架的消息转化器的方法,在这个方法中,可以向Spring MVC的消息转换器列表中添加自定义的消息转换器, + * 或者对已有的消息转换器进行配置调整,以满足项目对于数据序列化、反序列化等方面的特殊需求,例如使用自定义的对象映射器来处理JSON数据与Java对象之间的转换。 + * + * @param converters Spring MVC框架中原有的消息转换器列表,通过修改这个列表来实现消息转换器的扩展或调整操作。 + */ + protected void extendMessageConverters(List> converters) { + log.info("扩展消息转换器...."); + + // 创建一个MappingJackson2HttpMessageConverter类型的消息转换器对象,它是Spring框架中用于处理JSON数据与Java对象转换的常用消息转换器,基于Jackson库实现。 + MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter(); + + // 需要为这个消息转化器设置一个对象转换器,这里使用自定义的JacksonObjectMapper,它继承自ObjectMapper,并且配置了一些特定的序列化和反序列化规则, + // 比如对日期时间类型等的处理方式,通过设置它可以让消息转换器按照项目的特定需求将Java对象准确地序列化为JSON数据,以及将接收到的JSON数据反序列化为Java对象。 + converter.setObjectMapper(new JacksonObjectMapper()); + + // 将自己创建并配置好的消息转换器添加到容器中(即原有的消息转换器列表里),添加到索引为0的位置,确保它在处理消息转换时能优先被使用,按照自定义的规则进行数据转换操作。 + converters.add(0, converter); + } +} \ No newline at end of file diff --git a/sky/sky-server/src/main/java/com/sky/controller/admin/DishController.java b/sky/sky-server/src/main/java/com/sky/controller/admin/DishController.java new file mode 100644 index 0000000..cd3d6ab --- /dev/null +++ b/sky/sky-server/src/main/java/com/sky/controller/admin/DishController.java @@ -0,0 +1,186 @@ +package com.sky.controller.admin; + +import com.github.pagehelper.Page; +import com.sky.dto.CategoryDTO; +import com.sky.dto.DishDTO; +import com.sky.dto.DishPageQueryDTO; +import com.sky.entity.Dish; +import com.sky.result.PageResult; +import com.sky.result.Result; +import com.sky.service.DishService; +import com.sky.vo.DishVO; +import com.sky.vo.SetmealVO; +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.cache.annotation.CachePut; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.web.bind.annotation.*; + +import java.lang.reflect.Array; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Set; + +import static jdk.nashorn.internal.runtime.regexp.joni.Config.log; + +/** + * DishController类,作为Spring MVC框架中的一个控制器类,主要用于处理与菜品相关的各种HTTP请求, + * 它提供了一系列的接口方法,来实现菜品的分页查询、新增、删除、修改、状态变更以及根据分类查询等功能,并且与业务逻辑层(通过DishService)进行交互,同时还涉及缓存相关的操作(使用RedisTemplate), + * 旨在为管理员提供便捷的菜品管理相关的接口服务,方便对菜品信息进行全面的操作和管理,确保菜品数据在系统中的准确性和有效性。 + */ +@RestController() +@RequestMapping("/admin/dish") +@Slf4j +@Api("菜品相关接口") +public class DishController { + + /** + * 自动注入DishService,通过依赖注入的方式获取业务逻辑层的服务对象, + * DishService中封装了与菜品相关的各种业务逻辑方法,例如数据库操作、业务规则处理等,本控制器中的各个接口方法会调用其对应的方法来完成具体的业务功能。 + */ + @Autowired + DishService dishService; + + /** + * 自动注入RedisTemplate,用于操作Redis缓存,在本控制器中主要用于清除缓存数据, + * 例如在菜品数据发生新增、修改、删除等变更操作后,通过RedisTemplate来删除对应的缓存键值对,保证缓存数据与数据库中的菜品数据一致性,提高系统性能和数据准确性。 + */ + @Autowired + RedisTemplate redisTemplate; + + /** + * 菜品分页查询的接口方法,用于接收客户端发送的分页查询请求,根据传入的DishPageQueryDTO对象中的查询条件(如页码、每页数量、筛选条件等), + * 调用DishService的pageQuery方法进行分页查询操作,最终将查询结果封装在PageResult对象中返回给客户端,方便管理员分页查看菜品信息。 + * + * @param dishPageQueryDTO 包含分页查询条件的传输对象,其中包含了诸如页码、每页显示记录数以及其他可能的筛选条件等信息,用于指定具体的查询要求。 + * @return 返回一个Result对象,其泛型类型为PageResult,Result对象用于统一封装接口的返回结果(包含状态码、提示信息等),PageResult中包含了实际查询到的菜品分页数据(如总记录数、当前页数据列表等)。 + */ + @GetMapping("/page") + @ApiOperation("菜品分页查询") + public Result pageQuery(DishPageQueryDTO dishPageQueryDTO) { + log.info("菜品分页查询:{}", dishPageQueryDTO); + PageResult pageResult = dishService.pageQuery(dishPageQueryDTO); + + return Result.success(pageResult); + } + + /** + * 新增菜品的接口方法,接收客户端发送的包含菜品详细信息的DishDTO对象(以JSON格式放在请求体中传入,通过@RequestBody注解进行解析绑定), + * 将其传递给DishService的saveWithFlaver方法进行菜品的新增操作,新增成功后,调用cleanCache方法清除与菜品相关的缓存数据(以保证缓存与数据库数据的一致性), + * 最后返回表示成功的Result对象给客户端,告知客户端菜品新增操作已顺利完成。 + * + * @param dishDTO 包含菜品详细信息的传输对象,例如菜品名称、价格、分类、口味等信息,用于在新增菜品时提供完整的数据支持。 + * @return 返回一个Result对象,表示新增菜品操作的结果,成功时返回的Result对象中包含相应的成功提示信息等内容。 + */ + @PostMapping + @ApiOperation("新增菜品") + public Result save(@RequestBody DishDTO dishDTO) { + log.info("新增菜品:{}", dishDTO); + dishService.saveWithFlaver(dishDTO); + + cleanCache("dish_"+dishDTO.getCategoryId()); + return Result.success(); + } + + /** + * 批量删除菜品的接口方法,接收客户端发送的包含要删除的菜品id列表的ArrayList参数(通过@RequestParam注解指定该参数从请求参数中获取,因为使用集合接收参数需要添加此注解), + * 将该id列表传递给DishService的deleteBatch方法进行批量删除操作,操作完成后,调用cleanCache方法清除与菜品相关的所有缓存数据(使用通配符"dish_*"来匹配可能涉及的缓存键), + * 最后返回表示成功的Result对象给客户端,告知客户端批量删除菜品操作已成功执行。 + * + * @param ids 包含要批量删除的菜品id的集合,通过该集合可以确定要从数据库中删除哪些菜品记录。 + * @return 返回一个Result对象,表示批量删除菜品操作的结果,成功时返回的Result对象中包含相应的成功提示信息等内容。 + */ + @DeleteMapping + @ApiOperation("批量删除菜品") + public Result deleteBatch(@RequestParam ArrayList ids) { + log.info("批量删除菜品:{}", ids); + dishService.deleteBatch(ids); + + cleanCache("dish_*"); + return Result.success(); + } + + /** + * 根据菜品id获取菜品数据的接口方法,接收客户端发送的菜品id(通过@PathVariable注解从请求路径中获取对应的参数值), + * 将该id传递给DishService的getById方法,查询对应的菜品详细信息,并将查询结果(以DishVO对象形式返回)封装在Result对象中返回给客户端,方便管理员查看特定菜品的详细情况。 + * + * @param id 要查询的菜品的唯一标识符,通过该id可以在数据库中精准定位到对应的菜品记录,获取其详细信息。 + * @return 返回一个Result对象,其泛型类型为DishVO,Result对象用于统一封装接口的返回结果,DishVO中包含了查询到的菜品的详细信息(如名称、价格、分类、口味等)。 + */ + @GetMapping("/{id}") + public Result getByDishId(@PathVariable Long id) { + log.info("根据id获取菜品:{}", id); + DishVO dish = dishService.getById(id); + + return Result.success(dish); + } + + /** + * 修改菜品的接口方法,接收客户端发送的包含修改后菜品详细信息的DishDTO对象(以JSON格式放在请求体中传入,通过@RequestBody注解进行解析绑定), + * 将其传递给DishService的updateDish方法进行菜品信息的修改操作,修改成功后,调用cleanCache方法清除与菜品相关的所有缓存数据(使用通配符"dish_*"来匹配可能涉及的缓存键), + * 最后返回表示成功的Result对象给客户端,告知客户端菜品修改操作已顺利完成。 + * + * @param dishDTO 包含修改后菜品详细信息的传输对象,例如修改后的菜品名称、价格、分类、口味等信息,用于更新数据库中对应菜品的记录。 + * @return 返回一个Result对象,表示修改菜品操作的结果,成功时返回的Result对象中包含相应的成功提示信息等内容。 + */ + @PutMapping() + @ApiOperation("修改菜品") + public Result updateDish(@RequestBody DishDTO dishDTO) { + log.info("修改菜品:{}", dishDTO); + dishService.updateDish(dishDTO); + + cleanCache("dish_*"); + return Result.success(); + } + + /** + * 根据分类id查询菜品的接口方法,接收客户端发送的分类id参数(从请求参数中获取), + * 将该分类id传递给DishService的getByCategoryId方法,查询该分类下的所有菜品信息,并将查询结果(以ArrayList集合形式返回,集合中每个元素为一个菜品对象)封装在Result对象中返回给客户端, + * 方便管理员查看某个分类下包含的所有菜品情况,例如在菜单分类管理等场景下查看特定分类下的菜品列表。 + * + * @param categoryId 菜品分类的唯一标识符,通过该id可以在数据库中查找属于该分类的所有菜品记录。 + * @return 返回一个Result对象,其泛型类型为ArrayList,Result对象用于统一封装接口的返回结果,ArrayList中包含了查询到的属于该分类的所有菜品对象(每个菜品对象包含了菜品自身的详细信息)。 + */ + @GetMapping("/list") + @ApiOperation("根据分类id查询菜品") + public Result getByCategoryId(Long categoryId) { + log.info("根据分类id查询菜品"); + ArrayList dishes = dishService.getByCategoryId(categoryId); + + return Result.success(dishes); + } + + /** + * 起售停售菜品的接口方法,接收客户端发送的菜品id以及要设置的状态值(通过@PathVariable注解从请求路径中获取状态参数,通过方法参数获取菜品id), + * 将这两个参数传递给DishService的startOrStop方法进行菜品销售状态的变更操作,操作完成后,调用cleanCache方法清除与菜品相关的所有缓存数据(使用通配符"dish_*"来匹配可能涉及的缓存键), + * 同时,该方法还使用了@CachePut注解,它可以在方法执行后更新缓存(根据具体的缓存配置和返回结果来更新对应的缓存数据,此处暂未明确其具体更新的缓存内容细节), + * 最后返回表示成功的Result对象给客户端,告知客户端菜品销售状态变更操作已成功执行。 + * + * @param id 要变更销售状态的菜品的唯一标识符,通过该id可以在数据库中精准定位到对应的菜品记录,进行状态修改操作。 + * @param status 要设置的菜品销售状态值,例如1表示起售,0表示停售等,用于确定将菜品设置为哪种销售状态。 + * @return 返回一个Result对象,表示起售停售菜品操作的结果,成功时返回的Result对象中包含相应的成功提示信息等内容。 + */ + @CachePut + @PostMapping("/status/{status}") + public Result startOrStop(Long id, @PathVariable Integer status) { + log.info("起售停售菜品id:{},status:{}", id, status); + dishService.startOrStop(id, status); + + cleanCache("dish_*"); + return Result.success(); + } + + /** + * 私有方法,用于清除Redis缓存中符合指定模式的缓存键值对,通过RedisTemplate的keys方法根据传入的模式字符串(可以使用通配符,如"dish_*"表示以"dish_"开头的所有键)查找对应的缓存键集合, + * 然后使用RedisTemplate的delete方法将这些找到的缓存键对应的缓存数据删除,以此来保证缓存数据与数据库中菜品数据的一致性,避免出现数据不一致导致的业务问题。 + * + * @param pattern 用于匹配缓存键的模式字符串,通过这个模式可以灵活指定要删除的缓存键范围,通常使用通配符来实现批量删除相关缓存数据的目的。 + */ + private void cleanCache(String pattern) { + Set keys = redisTemplate.keys(pattern); + redisTemplate.delete(keys); + } +} \ No newline at end of file diff --git a/sky/sky-server/src/main/java/com/sky/controller/admin/SetmealController.java b/sky/sky-server/src/main/java/com/sky/controller/admin/SetmealController.java new file mode 100644 index 0000000..453a6b8 --- /dev/null +++ b/sky/sky-server/src/main/java/com/sky/controller/admin/SetmealController.java @@ -0,0 +1,149 @@ +package com.sky.controller.admin; + +import com.sky.dto.CategoryDTO; +import com.sky.dto.CategoryPageQueryDTO; +import com.sky.dto.SetmealDTO; +import com.sky.dto.SetmealPageQueryDTO; +import com.sky.entity.Category; +import com.sky.result.PageResult; +import com.sky.result.Result; +import com.sky.service.CategoryService; +import com.sky.service.SetmealService; +import com.sky.vo.SetmealVO; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.extern.slf4j.Slf4j; +import org.apache.ibatis.annotations.Delete; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.CachePut; +import org.springframework.web.bind.annotation.*; + +import java.util.ArrayList; + +/** + * SetmealController类,作为Spring MVC框架中的一个控制器类,主要用于处理与套餐相关的各种HTTP请求, + * 它与SetmealService(业务逻辑层的服务类)进行交互,实现了诸如分页查询套餐、起售停售套餐、修改套餐信息、根据id查询套餐、批量删除套餐以及新增套餐等功能, + * 同时借助Spring的缓存注解(如@CacheEvict等)来管理缓存数据,确保缓存与数据库中套餐数据的一致性,为管理员提供便捷的套餐管理相关的接口服务,满足套餐管理方面的业务需求。 + */ +@RestController +@Api("套餐相关接口") +@Slf4j +@RequestMapping("/admin/setmeal") +public class SetmealController { + + /** + * 通过自动注入的方式获取SetmealService对象,SetmealService中封装了与套餐相关的各种业务逻辑方法, + * 例如套餐数据的数据库操作、业务规则处理等,本控制器中的各个接口方法会调用其对应的方法来完成具体的套餐管理业务功能。 + */ + @Autowired + SetmealService setmealService; + + /** + * 分页查询套餐的接口方法,接收客户端发送的包含分页查询条件的SetmealPageQueryDTO对象(从请求参数中获取), + * 该对象可能包含了诸如页码、每页显示记录数以及其他筛选条件等信息,将其传递给SetmealService的pageQuery方法进行实际的分页查询操作, + * 最后把查询结果(封装在PageResult对象中,包含了总记录数、当前页数据列表等分页相关信息)通过Result对象进行统一封装后返回给客户端,方便管理员分页查看套餐信息。 + * + * @param setmealPageQueryDTO 包含分页查询条件的传输对象,用于指定具体的套餐分页查询要求,以便获取符合条件的套餐分页数据。 + * @return 返回一个Result对象,其泛型类型为PageResult,Result对象用于统一封装接口的返回结果(包含状态码、提示信息等),PageResult中则包含了实际查询到的套餐分页数据。 + */ + @GetMapping("/page") + @ApiOperation("分页查询套餐") + public Result pageQuery(SetmealPageQueryDTO setmealPageQueryDTO) { + log.info("分页查询套餐:{}", setmealPageQueryDTO); + PageResult result = setmealService.pageQuery(setmealPageQueryDTO); + + return Result.success(result); + } + + /** + * 起售停售套餐的接口方法,接收客户端发送的套餐状态值(通过@PathVariable注解从请求路径中获取,表示要设置的起售或停售状态,通常1表示起售,0表示停售等) + * 以及套餐id(从请求参数中获取),将这两个参数传递给SetmealService的startOrStop方法进行套餐销售状态的变更操作, + * 同时,该方法使用了@CacheEvict注解,指定了清除名为"setmealCache"的缓存中的所有数据(通过设置allEntries为true),以保证缓存与数据库中套餐数据的一致性, + * 最后返回表示成功的Result对象给客户端,告知客户端套餐销售状态变更操作已成功执行。 + * + * @param status 要设置的套餐销售状态值,用于确定将套餐设置为起售还是停售状态,方便对套餐的售卖情况进行控制。 + * @param id 要变更销售状态的套餐的唯一标识符,通过该id可以在数据库中精准定位到对应的套餐记录,进行状态修改操作。 + * @return 返回一个Result对象,表示起售停售套餐操作的结果,成功时返回的Result对象中包含相应的成功提示信息等内容。 + */ + @PostMapping("/status/{status}") + @ApiOperation("起售停售套餐") + @CacheEvict(cacheNames = "setmealCache", allEntries = true) + public Result startOrStop(@PathVariable Integer status, Long id) { + log.info("{}套餐,id={}", status == 1? "起售" : "停售", id); + setmealService.startOrStop(status, id); + + return Result.success(); + } + + /** + * 修改套餐信息的接口方法,接收客户端发送的包含修改后套餐详细信息的SetmealDTO对象(以JSON格式放在请求体中传入,通过@RequestBody注解进行解析绑定), + * 将其传递给SetmealService的updateSetmeal方法进行套餐信息的修改操作,同时,该方法使用了@CacheEvict注解,指定清除名为"setmealCache"的缓存中的所有数据(通过设置allEntries为true), + * 确保缓存数据能及时更新,与数据库中的套餐数据保持一致,最后返回表示成功的Result对象给客户端,告知客户端套餐修改操作已顺利完成。 + * + * @param setmealDTO 包含修改后套餐详细信息的传输对象,例如套餐名称、包含的菜品、价格等信息,用于更新数据库中对应套餐的记录。 + * @return 返回一个Result对象,表示修改套餐操作的结果,成功时返回的Result对象中包含相应的成功提示信息等内容。 + */ + @PutMapping + @ApiOperation("修改套餐信息") + @CacheEvict(cacheNames = "setmealCache", allEntries = true) + public Result updateSetmeal(@RequestBody SetmealDTO setmealDTO) { + log.info("修改套餐信息:{}", setmealDTO); + setmealService.updateSetmeal(setmealDTO); + + return Result.success(); + } + + /** + * 根据id查询套餐的接口方法,接收客户端发送的套餐id(通过@PathVariable注解从请求路径中获取), + * 将该id传递给SetmealService的getDishById方法,查询对应的套餐详细信息,并将查询结果(以SetmealVO对象形式返回,其中包含了套餐的各种详细信息,如名称、菜品组成、价格等) + * 通过Result对象进行统一封装后返回给客户端,方便管理员查看特定套餐的详细情况。 + * + * @param id 要查询的套餐的唯一标识符,通过该id可以在数据库中精准定位到对应的套餐记录,获取其详细信息。 + * @return 返回一个Result对象,其泛型类型为SetmealVO,Result对象用于统一封装接口的返回结果,SetmealVO中包含了查询到的套餐的详细信息。 + */ + @GetMapping("/{id}") + @ApiOperation("根据id查询套餐") + public Result getDishById(@PathVariable Long id) { + log.info("根据套餐id查询套餐"); + SetmealVO setmealVO = setmealService.getDishById(id); + + return Result.success(setmealVO); + } + + /** + * 根据id批量删除套餐的接口方法,接收客户端发送的包含要删除的套餐id列表的ArrayList参数(通过@RequestParam注解指定该参数从请求参数中获取,因为使用集合接收参数需要添加此注解), + * 将该id列表传递给SetmealService的batchDeleteById方法进行批量删除操作,同时,该方法使用了@CacheEvict注解,指定清除名为"setmealCache"的缓存中的所有数据(通过设置allEntries为true), + * 保证缓存与数据库数据的一致性,最后返回表示成功的Result对象给客户端,告知客户端批量删除套餐操作已成功执行。 + * + * @param ids 包含要批量删除的套餐id的集合,通过该集合可以确定要从数据库中删除哪些套餐记录。 + * @return 返回一个Result对象,表示批量删除套餐操作的结果,成功时返回的Result对象中包含相应的成功提示信息等内容。 + */ + @DeleteMapping + @ApiOperation("根据id批量删除套餐") + @CacheEvict(cacheNames = "setmealCache", allEntries = true) + public Result batchDeleteById(@RequestParam ArrayList ids) { + log.info("根据id批量删除套餐:{}", ids); + setmealService.batchDeleteById(ids); + + return Result.success(); + } + + /** + * 新增套餐的接口方法,接收客户端发送的包含新增套餐详细信息的SetmealDTO对象(以JSON格式放在请求体中传入,通过@RequestBody注解进行解析绑定), + * 将其传递给SetmealService的insert方法进行套餐的新增操作,同时,该方法使用了@CacheEvict注解,根据传入的SetmealDTO对象中的categoryId属性值作为缓存键, + * 清除对应的缓存数据(这样在新增套餐后,如果涉及基于分类的套餐缓存,能及时更新缓存,避免数据不一致),最后返回表示成功的Result对象给客户端,告知客户端套餐新增操作已顺利完成。 + * + * @param setmealDTO 包含新增套餐详细信息的传输对象,例如套餐名称、包含的菜品、价格等信息,用于在新增套餐时提供完整的数据支持,同时其categoryId属性用于缓存管理。 + * @return 返回一个Result对象,表示新增套餐操作的结果,成功时返回的Result对象中包含相应的成功提示信息等内容。 + */ + @CacheEvict(cacheNames = "setmealCache", key = "#setmealDTO.categoryId") + @PostMapping + @ApiOperation("新增套餐") + public Result insert(@RequestBody SetmealDTO setmealDTO) { + log.info("新增套餐:{}", setmealDTO); + setmealService.insert(setmealDTO); + + return Result.success(); + } +} \ No newline at end of file diff --git a/sky/sky-server/src/main/java/com/sky/controller/user/AddressBookController.java b/sky/sky-server/src/main/java/com/sky/controller/user/AddressBookController.java new file mode 100644 index 0000000..bbb3781 --- /dev/null +++ b/sky/sky-server/src/main/java/com/sky/controller/user/AddressBookController.java @@ -0,0 +1,149 @@ +package com.sky.controller.user; + +import com.sky.context.BaseContext; +import com.sky.entity.AddressBook; +import com.sky.result.Result; +import com.sky.service.AddressBookService; +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; + +/** + * AddressBookController类,作为Spring MVC框架中的一个控制器类,主要用于处理与C端(客户端,通常指普通用户端)地址簿相关的各种HTTP请求, + * 它通过依赖注入获取AddressBookService(业务逻辑层的服务类),并调用其相应方法来实现诸如查询用户所有地址信息、新增地址、根据id查询/修改/删除地址、设置默认地址以及查询默认地址等功能, + * 旨在为普通用户提供便捷的地址簿管理相关的接口服务,方便用户对自己的收货地址等地址信息进行操作和管理,满足日常使用中地址相关的业务需求。 + */ +@RestController +@RequestMapping("/user/addressBook") +@Api(tags = "C端地址簿接口") +@Slf4j +public class AddressBookController { + + /** + * 通过自动注入的方式获取AddressBookService对象,AddressBookService中封装了与地址簿相关的各种业务逻辑方法, + * 例如地址数据的数据库操作(增删改查等)、业务规则处理(如设置默认地址的逻辑等),本控制器中的各个接口方法会调用其对应的方法来完成具体的地址簿管理业务功能。 + */ + @Autowired + private AddressBookService addressBookService; + + /** + * 查询当前登录用户的所有地址信息的接口方法,该方法无请求参数,在方法内部会先创建一个AddressBook对象, + * 并通过BaseContext.getCurrentId()方法(此处假设BaseContext类用于获取当前登录用户的相关上下文信息,比如用户id)获取当前登录用户的id,设置到AddressBook对象中, + * 然后将该对象传递给AddressBookService的list方法,用于查询该用户的所有地址信息,最后将查询结果(以List集合形式返回,集合中每个元素为一个地址对象)通过Result对象进行统一封装后返回给客户端, + * 方便用户查看自己已保存的所有地址情况。 + * + * @return 返回一个Result对象,其泛型类型为List,Result对象用于统一封装接口的返回结果(包含状态码、提示信息等),List中包含了查询到的当前登录用户的所有地址对象(每个地址对象包含了地址相关的详细信息,如收货人、联系电话、详细地址等)。 + */ + @GetMapping("/list") + @ApiOperation("查询当前登录用户的所有地址信息") + public Result> list() { + log.info("查询当前登录用户的所有地址信息"); + AddressBook addressBook = new AddressBook(); + addressBook.setUserId(BaseContext.getCurrentId()); + List list = addressBookService.list(addressBook); + return Result.success(list); + } + + /** + * 新增地址的接口方法,接收客户端发送的包含地址详细信息的AddressBook对象(以JSON格式放在请求体中传入,通过@RequestBody注解进行解析绑定), + * 将该对象传递给AddressBookService的save方法进行地址的新增操作,最后返回表示成功的Result对象给客户端,告知客户端地址新增操作已顺利完成,方便用户添加新的收货地址等信息。 + * + * @param addressBook 包含新增地址详细信息的对象,例如收货人姓名、联系电话、详细地址、是否为默认地址等信息,用于在新增地址时提供完整的数据支持,将其保存到数据库中对应的地址表中。 + * @return 返回一个Result对象,表示新增地址操作的结果,成功时返回的Result对象中包含相应的成功提示信息等内容。 + */ + @PostMapping + @ApiOperation("新增地址") + public Result save(@RequestBody AddressBook addressBook) { + log.info("新增地址:{}", addressBook); + addressBookService.save(addressBook); + return Result.success(); + } + + /** + * 根据id查询地址的接口方法,接收客户端发送的地址id(通过@PathVariable注解从请求路径中获取), + * 将该id传递给AddressBookService的getById方法,查询对应的地址详细信息,并将查询结果(以AddressBook对象形式返回,其中包含了地址的各种详细信息,如收货人、联系电话、详细地址等) + * 通过Result对象进行统一封装后返回给客户端,方便用户查看特定地址的详细情况,例如在修改地址前查看原地址信息等场景下使用。 + * + * @param id 要查询的地址的唯一标识符,通过该id可以在数据库中精准定位到对应的地址记录,获取其详细信息。 + * @return 返回一个Result对象,其泛型类型为AddressBook,Result对象用于统一封装接口的返回结果,AddressBook中包含了查询到的地址的详细信息。 + */ + @GetMapping("/{id}") + @ApiOperation("根据id查询地址") + public Result getById(@PathVariable Long id) { + log.info("根据id查询地址,id:{}", id); + AddressBook addressBook = addressBookService.getById(id); + return Result.success(addressBook); + } + + /** + * 根据id修改地址的接口方法,接收客户端发送的包含修改后地址详细信息的AddressBook对象(以JSON格式放在请求体中传入,通过@RequestBody注解进行解析绑定), + * 将该对象传递给AddressBookService的update方法进行地址信息的修改操作,最后返回表示成功的Result对象给客户端,告知客户端地址修改操作已顺利完成,方便用户更新已保存地址的相关信息。 + * + * @param addressBook 包含修改后地址详细信息的对象,例如修改后的收货人姓名、联系电话、详细地址等信息,用于更新数据库中对应地址的记录。 + * @return 返回一个Result对象,表示修改地址操作的结果,成功时返回的Result对象中包含相应的成功提示信息等内容。 + */ + @PutMapping + @ApiOperation("根据id修改地址") + public Result update(@RequestBody AddressBook addressBook) { + log.info("根据id修改地址:{}", addressBook); + addressBookService.update(addressBook); + return Result.success(); + } + + /** + * 设置默认地址的接口方法,接收客户端发送的包含地址相关信息的AddressBook对象(以JSON格式放在请求体中传入,通过@RequestBody注解进行解析绑定), + * 将该对象传递给AddressBookService的setDefault方法进行默认地址的设置操作,该操作通常会涉及将其他同用户的地址的默认标记取消,并将当前传入的地址设置为默认地址,具体逻辑由AddressBookService中的方法实现, + * 最后返回表示成功的Result对象给客户端,告知客户端默认地址设置操作已顺利完成,方便用户指定常用的收货地址为默认地址,便于后续下单等操作时默认使用。 + * + * @param addressBook 包含地址相关信息的对象,该对象中的相关属性(如地址id等)会用于确定要设置为默认地址的具体地址记录,同时可能会涉及一些其他属性用于业务逻辑判断等情况,例如是否满足设置默认地址的条件等。 + * @return 返回一个Result对象,表示设置默认地址操作的结果,成功时返回的Result对象中包含相应的成功提示信息等内容。 + */ + @PutMapping("/default") + @ApiOperation("设置默认地址") + public Result setDefault(@RequestBody AddressBook addressBook) { + log.info("设置默认地址:{}", addressBook); + + addressBookService.setDefault(addressBook); + return Result.success(); + } + + /** + * 根据id删除地址的接口方法,接收客户端发送的地址id(从请求参数中获取), + * 将该id传递给AddressBookService的deleteById方法进行地址的删除操作,最后返回表示成功的Result对象给客户端,告知客户端地址删除操作已成功执行,方便用户删除不再需要的地址信息。 + * + * @param id 要删除的地址的唯一标识符,通过该id可以在数据库中精准定位到对应的地址记录,进行删除操作。 + * @return 返回一个Result对象,表示根据id删除地址操作的结果,成功时返回的Result对象中包含相应的成功提示信息等内容。 + */ + @DeleteMapping + @ApiOperation("根据id删除地址") + public Result deleteById(Long id) { + log.info("根据id删除地址,id:{}", id); + addressBookService.deleteById(id); + return Result.success(); + } + + /** + * 查询默认地址的接口方法,该方法无请求参数,在方法内部会先创建一个AddressBook对象,设置其默认地址标记(通常用一个字段表示,这里假设为isDefault,设置值为1表示查询默认地址)以及通过BaseContext.getCurrentId()方法获取当前登录用户的id并设置到AddressBook对象中, + * 然后将该对象传递给AddressBookService的list方法,用于查询该用户的默认地址信息,若查询到的结果列表不为空且只包含一个元素(即找到了唯一的默认地址),则将该地址对象通过Result对象进行统一封装后返回给客户端, + * 若未查询到符合条件的默认地址,则返回一个表示错误信息(提示“没有查询到默认地址”)的Result对象给客户端,方便用户获取自己设置的默认收货地址,在下单等操作中可直接使用该默认地址。 + */ + @GetMapping("default") + @ApiOperation("查询默认地址") + public Result getDefault() { + log.info("查询默认地址"); + // SQL:select * from address_book where user_id =? and is_default = 1 + AddressBook addressBook = new AddressBook(); + addressBook.setIsDefault(1); + addressBook.setUserId(BaseContext.getCurrentId()); + List list = addressBookService.list(addressBook); + + if (list!= null && list.size() == 1) { + return Result.success(list.get(0)); + } + + return Result.error("没有查询到默认地址"); + } +} \ No newline at end of file diff --git a/sky/sky-server/src/main/java/com/sky/controller/user/SetmealController.java b/sky/sky-server/src/main/java/com/sky/controller/user/SetmealController.java new file mode 100644 index 0000000..ea27463 --- /dev/null +++ b/sky/sky-server/src/main/java/com/sky/controller/user/SetmealController.java @@ -0,0 +1,81 @@ +package com.sky.controller.user; + +import com.sky.constant.StatusConstant; +import com.sky.entity.Setmeal; +import com.sky.result.Result; +import com.sky.service.SetmealService; +import com.sky.vo.DishItemVO; +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.cache.annotation.Cacheable; +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.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +/** + * SetmealController类,作为Spring MVC框架中的一个控制器类,主要用于处理C端(客户端,也就是普通用户端)与套餐浏览相关的各种HTTP请求, + * 它通过依赖注入获取SetmealService(业务逻辑层的服务类),并调用其相应方法来实现诸如根据分类id查询起售套餐、根据套餐id查询套餐内包含的菜品列表等功能, + * 同时借助Spring的缓存注解(如@Cacheable)来优化数据获取性能,减少重复查询数据库的次数,旨在为普通用户提供便捷的套餐浏览相关的接口服务,方便用户查看和了解套餐及相关菜品信息,满足用户在点餐等场景下的业务需求。 + */ +@RestController("userSetmealController") +@RequestMapping("/user/setmeal") +@Api(tags = "C端-套餐浏览接口") +@Slf4j +public class SetmealController { + + /** + * 通过自动注入的方式获取SetmealService对象,SetmealService中封装了与套餐相关的各种业务逻辑方法, + * 例如根据条件查询套餐数据、获取套餐内菜品信息等数据库操作以及相关业务规则处理(如判断套餐是否起售等),本控制器中的各个接口方法会调用其对应的方法来完成具体的套餐浏览业务功能。 + */ + @Autowired + private SetmealService setmealService; + + /** + * 条件查询的接口方法,用于根据分类id查询处于起售状态的套餐信息,接收客户端发送的分类id参数(从请求参数中获取), + * 在方法内部,首先创建一个Setmeal对象,将传入的分类id以及表示起售状态的常量(通过StatusConstant.ENABLE获取,假设该常量定义了起售状态对应的数值)设置到该对象中, + * 然后将这个Setmeal对象传递给SetmealService的list方法进行实际的查询操作,最后把查询结果(以List集合形式返回,集合中每个元素为一个符合条件的套餐对象)通过Result对象进行统一封装后返回给客户端, + * 方便用户查看某个分类下正在售卖的套餐情况,例如在浏览菜品分类页面时查看对应分类下有哪些可购买的套餐。 + * 同时,该方法使用了@Cacheable注解,指定了缓存名称为"setmealCache",并以传入的分类id作为缓存键,这样在相同分类id的查询再次发起时,如果缓存中有对应的数据,就可以直接从缓存中获取,而无需再次查询数据库,提高了系统性能。 + * + * @param categoryId 菜品分类的唯一标识符,通过该id可以筛选出属于该分类且处于起售状态的套餐记录,方便用户按照分类查看可购买的套餐。 + * @return 返回一个Result对象,其泛型类型为List,Result对象用于统一封装接口的返回结果(包含状态码、提示信息等),List中包含了查询到的符合条件的套餐对象(每个套餐对象包含了套餐自身的详细信息,如套餐名称、价格等)。 + */ + @GetMapping("/list") + @ApiOperation("根据分类id查询起售套餐") + @Cacheable(cacheNames = "setmealCache", key = "#categoryId") + public Result> list(Long categoryId) { + log.info("根据分类id查询起售套餐:{}", categoryId); + + Setmeal setmeal = new Setmeal(); + setmeal.setCategoryId(categoryId); + setmeal.setStatus(StatusConstant.ENABLE); + + List list = setmealService.list(setmeal); + + return Result.success(list); + } + + /** + * 根据套餐id查询包含的菜品列表的接口方法,接收客户端发送的套餐id(通过@PathVariable注解从请求路径中获取,指定了参数名称为"id"), + * 将该id传递给SetmealService的getDishItemById方法,用于查询该套餐内包含的菜品详细信息,最后把查询结果(以List集合形式返回,集合中每个元素为一个菜品相关的对象,包含菜品的具体信息) + * 通过Result对象进行统一封装后返回给客户端,方便用户查看某个套餐具体包含了哪些菜品,例如在用户想要了解套餐具体内容时使用。 + * + * @param id 要查询的套餐的唯一标识符,通过该id可以在数据库中精准定位到对应的套餐记录,进而获取其包含的菜品列表信息。 + * @return 返回一个Result对象,其泛型类型为List,Result对象用于统一封装接口的返回结果,List中包含了查询到的该套餐内包含的菜品的详细信息(如菜品名称、规格等)。 + */ + @GetMapping("/dish/{id}") + @ApiOperation("根据套餐id查询包含的菜品列表") + public Result> dishList(@PathVariable("id") Long id) { + log.info("根据套餐id查询包含的菜品列表{}", id); + + List list = setmealService.getDishItemById(id); + return Result.success(list); + } +} \ No newline at end of file diff --git a/sky/sky-server/src/main/java/com/sky/handler/GlobalExceptionHandler.java b/sky/sky-server/src/main/java/com/sky/handler/GlobalExceptionHandler.java new file mode 100644 index 0000000..4fe2645 --- /dev/null +++ b/sky/sky-server/src/main/java/com/sky/handler/GlobalExceptionHandler.java @@ -0,0 +1,61 @@ +package com.sky.handler; + +import com.sky.constant.MessageConstant; +import com.sky.exception.BaseException; +import com.sky.result.Result; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +import java.sql.SQLIntegrityConstraintViolationException; + +/** + * GlobalExceptionHandler类,作为全局异常处理器,其主要作用是统一处理项目运行过程中抛出的各类业务相关异常, + * 通过使用Spring框架提供的@RestControllerAdvice注解,使其能够对整个项目中的所有被@RestController标注的控制器类中的方法抛出的异常进行捕获和处理, + * 旨在增强项目的稳定性和容错性,为用户提供友好的错误提示信息,避免因未处理的异常导致系统崩溃或者给用户展示不友好的错误页面等情况。 + */ +@RestControllerAdvice +@Slf4j +public class GlobalExceptionHandler { + + /** + * 捕获业务异常的方法,使用了@ExceptionHandler注解并指定要处理的异常类型为BaseException(假设这是项目自定义的业务异常基类,所有具体的业务异常都继承自它), + * 当项目中任何地方抛出BaseException类型的异常时,该方法就会被触发执行。在方法内部,首先通过日志记录异常信息(记录异常的详细消息内容), + * 然后返回一个Result对象,该对象通过调用Result.error方法并传入异常消息来封装错误信息,最终将这个包含错误信息的Result对象返回给客户端(比如在接口调用时返回给前端页面展示错误提示给用户), + * 告知客户端业务操作出现了异常以及具体的异常原因,使客户端能够知晓操作失败并显示相应的错误提示内容给用户。 + * + * @param ex 捕获到的BaseException类型的异常对象,通过该对象可以获取到异常的详细信息,比如具体的错误消息等内容,用于记录日志和返回给客户端展示错误提示。 + * @return 返回一个Result对象,其用于统一封装接口的返回结果,在这里表示出现了业务异常,其中包含了异常对应的错误提示信息(即异常对象的消息内容),方便客户端进行相应的错误处理和展示。 + */ + @ExceptionHandler(BaseException.class) + public Result exceptionHandler(BaseException ex) { + log.error("异常信息:{}", ex.getMessage()); + return Result.error(ex.getMessage()); + } + + /** + * 处理SQL异常的方法,使用了@ExceptionHandler注解(此处未指定具体异常类型,默认会处理方法参数中定义的异常类型,即SQLIntegrityConstraintViolationException), + * 用于捕获项目中因数据库操作违反完整性约束(比如插入重复数据等情况)而抛出的SQLIntegrityConstraintViolationException异常。 + * 在方法内部,首先打印异常对象(可能是用于调试等临时查看异常的详细情况),然后获取异常的消息内容并进行分割处理(按照空格进行分割,假设消息内容有一定的格式规律), + * 通过判断消息中是否包含特定的关键字("Duplicate entry",通常表示插入了重复的数据)来进一步处理异常情况。 + * 如果包含该关键字,则提取出重复的字段名称(这里简单地取分割后的第三个元素作为字段名,具体可能需要根据实际的异常消息格式调整),并记录详细的异常信息日志(包含字段名和相应的已存在提示信息,假设MessageConstant.ALREADY_EXISTS是一个定义好的表示已存在的常量消息), + * 如果不包含该关键字,则记录一个未知错误的异常信息日志(通过MessageConstant.UNKNOWN_ERROR常量表示未知错误消息)。最后统一返回一个表示出现异常的Result对象,其中包含了相应的错误提示信息(这里统一返回MessageConstant.ALREADY_EXISTS表示出现了重复数据等相关异常情况)给客户端, + * 告知客户端数据库操作出现了问题以及大致的错误原因,让客户端进行相应的提示展示等处理。 + * + * @param exception 捕获到的SQLIntegrityConstraintViolationException类型的异常对象,通过该对象获取异常的详细消息内容来分析和处理具体的异常情况,判断是何种数据库完整性约束违反问题。 + * @return 返回一个Result对象,其用于统一封装接口的返回结果,表示出现了SQL相关的异常,其中包含了相应的错误提示信息(这里通常是表示数据已存在等相关的提示内容),方便客户端进行相应的错误处理和展示。 + */ + @ExceptionHandler + public Result SQLExceptionHandler(SQLIntegrityConstraintViolationException exception) { + System.out.println(exception); + String msg = exception.getMessage(); + String[] split = msg.split(" "); + if (msg.contains("Duplicate entry")) { + String name = split[2]; + log.error("异常信息:{}", name + MessageConstant.ALREADY_EXISTS); + } else { + log.error("异常信息:{}", MessageConstant.UNKNOWN_ERROR); + } + return Result.error(MessageConstant.ALREADY_EXISTS); + } +} \ No newline at end of file diff --git a/sky/sky-server/src/main/java/com/sky/mapper/CategoryMapper.java b/sky/sky-server/src/main/java/com/sky/mapper/CategoryMapper.java new file mode 100644 index 0000000..e840f1c --- /dev/null +++ b/sky/sky-server/src/main/java/com/sky/mapper/CategoryMapper.java @@ -0,0 +1,78 @@ +package com.sky.mapper; + +import com.github.pagehelper.Page; +import com.sky.annotation.AutoFill; +import com.sky.dto.CategoryDTO; +import com.sky.dto.CategoryPageQueryDTO; +import com.sky.entity.Category; +import com.sky.enumeration.OperationType; +import com.sky.result.PageResult; +import org.apache.ibatis.annotations.Delete; +import org.apache.ibatis.annotations.Insert; +import org.apache.ibatis.annotations.Mapper; +import org.aspectj.weaver.ast.Or; + +import java.util.List; + +/** + * CategoryMapper接口,作为MyBatis框架中的数据映射接口,主要用于定义与分类(Category)相关的数据库操作方法, + * 它通过MyBatis的注解或者方法签名来声明如何与数据库进行交互,例如执行分类的分页查询、条件查询、删除、修改以及新增等操作, + * 这些方法会被MyBatis的相关机制映射到对应的SQL语句上,实现对数据库中分类表数据的增删改查功能,为业务逻辑层提供数据持久化相关的操作支持,便于对分类数据进行管理。 + */ +@Mapper +public interface CategoryMapper { + + /** + * 分类分页查询的方法,接收一个CategoryPageQueryDTO对象作为参数,该对象通常包含了分页查询所需的相关信息,如页码、每页显示记录数以及可能的筛选条件等, + * 通过MyBatis的相关机制,该方法会被映射到对应的SQL语句(可能由MyBatis的分页插件结合具体的配置生成合适的分页查询SQL),用于从数据库中获取符合条件的分类数据,并以Page对象形式返回查询结果, + * Page是一个分页数据结构,其中包含了当前页的分类数据列表以及分页相关的信息(如总记录数、总页数等),方便业务逻辑层进行分页数据的处理和展示。 + * + * @param categoryPageQueryDTO 包含分页查询条件的传输对象,用于指定具体的分类分页查询要求,以便获取相应的分类分页数据。 + * @return 返回一个Page对象,代表分类的分页查询结果,其中的泛型Category表示每个元素是一个分类实体对象,包含了分类的各种属性信息(如分类名称、类型、状态等)。 + */ + Page pageQuery(CategoryPageQueryDTO categoryPageQueryDTO); + + /** + * 根据传入的CategoryDTO对象进行条件查询的方法,CategoryDTO对象中包含了用于筛选分类数据的相关条件信息, + * 通过MyBatis的映射机制,会执行对应的SQL语句(根据具体的配置和映射规则生成),从数据库中查找符合条件的分类数据,并以List集合形式返回查询结果, + * List集合中的每个元素为一个分类实体对象,方便业务逻辑层根据不同的查询条件获取相应的分类数据列表进行后续处理,例如展示符合特定条件的分类列表等。 + * + * @param categoryDTO 包含查询条件的传输对象,用于指定具体的分类查询条件,以便获取符合要求的分类数据列表。 + * @return 返回一个List对象,代表符合查询条件的分类数据列表,其中的泛型Category表示每个元素是一个分类实体对象,包含了分类的各种属性信息(如分类名称、类型、状态等)。 + */ + List query(CategoryDTO categoryDTO); + + /** + * 删除分类的方法,接收一个表示分类id的Long类型参数,通过MyBatis的注解@Delete指定了对应的SQL删除语句, + * 当调用该方法时,会执行"delete from category where id=#{id}"这条SQL语句,从数据库的category表中根据传入的id删除对应的分类记录,实现对分类数据的删除操作, + * 该操作通常在业务逻辑层确定要删除某个分类时被调用,比如管理员在后台管理系统中删除不再需要的分类。 + * + * @param id 要删除的分类的唯一标识符,通过该id可以在数据库的category表中精准定位到对应的分类记录,执行删除操作。 + */ + @Delete("delete from category where id=#{id}") + void delete(Long id); + + /** + * 修改分类的方法,接收一个Category实体对象作为参数,该对象中包含了修改后的分类相关信息(如修改后的分类名称、类型、状态等属性值), + * 同时该方法使用了@AutoFill注解(假设这是一个自定义的注解,用于在执行该方法时自动填充一些通用的字段值,比如更新时间、更新用户等,具体填充逻辑由相关的切面或者拦截器实现,根据OperationType.UPDATE来确定是更新操作时的填充), + * 通过MyBatis的映射机制,会执行对应的SQL语句(根据实体对象的属性和配置生成合适的更新语句),将数据库中对应分类记录的相关信息更新为传入对象中的属性值,实现分类数据的修改操作, + * 常用于业务逻辑层在需要修改分类的某些属性时调用,例如修改分类名称、调整分类状态等场景。 + * + * @param category 包含修改后分类信息的实体对象,其属性值将用于更新数据库中对应分类记录的相应字段内容,实现分类数据的修改。 + */ + @AutoFill(OperationType.UPDATE) + void updateCategory(Category category); + + /** + * 新增分类的方法,接收一个Category实体对象作为参数,该对象中包含了要新增的分类相关信息(如分类名称、类型、状态等属性值), + * 该方法使用了@AutoFill注解(根据OperationType.INSERT来确定是插入操作时的自动填充,用于填充创建时间、创建用户等通用字段值,同样具体填充逻辑由相关机制实现)以及@Insert注解, + * 通过@Insert注解明确指定了对应的插入SQL语句,当调用该方法时,会执行该SQL语句将传入的Category对象中的属性值插入到数据库的category表中,实现分类数据的新增操作, + * 一般在业务逻辑层需要添加新的分类时被调用,比如添加新的菜品分类或者商品分类等情况。 + * + * @param category 包含新增分类信息的实体对象,其属性值将按照指定的SQL语句格式插入到数据库的category表中,完成分类的新增操作。 + */ + @AutoFill(OperationType.INSERT) + @Insert("insert into category(type,name,sort,status,create_time,create_user,update_time,update_user)" + + "values (#{type},#{name},#{sort},#{status},#{createTime},#{createUser},#{updateTime},#{updateUser})") + void save(Category category); +} \ No newline at end of file diff --git a/sky/sky-server/src/main/java/com/sky/mapper/OrderMapper.java b/sky/sky-server/src/main/java/com/sky/mapper/OrderMapper.java new file mode 100644 index 0000000..553e493 --- /dev/null +++ b/sky/sky-server/src/main/java/com/sky/mapper/OrderMapper.java @@ -0,0 +1,125 @@ +package com.sky.mapper; + +import com.github.pagehelper.Page; +import com.sky.dto.OrdersPageQueryDTO; +import com.sky.entity.OrderDetail; +import com.sky.entity.Orders; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; + +import java.time.LocalDateTime; +import java.util.List; +import java.util.Map; + +/** + * OrderMapper接口,作为MyBatis框架中的数据映射接口,主要用于定义与订单(Orders)相关的各种数据库操作方法, + * 涵盖了从订单数据的统计、查询(包括分页查询、按条件查询等)、插入、修改等多方面操作,通过MyBatis的注解与对应的SQL语句进行关联,实现对数据库中订单表数据的增删改查以及统计分析等功能, + * 为业务逻辑层提供了操作订单数据的底层支持,满足不同业务场景下对于订单管理和数据获取的需求。 + */ +@Mapper +public interface OrderMapper { + + /** + * 根据状态统计订单数量的方法,使用了@Select注解指定对应的SQL查询语句,该语句会从数据库的orders表中统计状态为传入参数status所指定值的订单记录数量, + * 接收一个Integer类型的参数status,表示要统计的订单状态值,通过执行"select count(id) from orders where status = #{status}"这条SQL语句, + * 返回符合条件的订单数量(以Integer类型返回统计结果),常用于业务逻辑层需要了解处于特定状态下的订单数量的场景,比如统计已完成订单数量、待支付订单数量等情况,方便后续业务分析和展示。 + * + * @param status 订单状态值,用于在数据库查询中筛选出处于该状态的订单记录,进而统计其数量,不同的业务中订单状态可能有不同的定义和取值,例如0表示未支付、1表示已支付等。 + * @return 返回一个Integer类型的值,表示符合指定状态的订单数量,该数值反映了在数据库中处于相应状态的订单的记录个数,便于业务层进行相关数据统计和分析。 + */ + @Select("select count(id) from orders where status = #{status}") + Integer countStatus(Integer status) ; + + /** + * 分页条件查询并按下单时间排序的方法,接收一个OrdersPageQueryDTO对象作为参数,该对象通常包含了分页查询所需的相关信息(如页码、每页显示记录数、筛选条件等)以及可能的排序相关要求(此处按下单时间排序), + * 通过MyBatis的相关机制(可能结合了分页插件等),该方法会被映射到对应的SQL语句(根据OrdersPageQueryDTO中的条件生成合适的分页查询且按时间排序的SQL语句),从数据库中获取符合条件的订单数据,并以Page对象形式返回查询结果, + * Page是一个分页数据结构,其中包含了当前页的订单数据列表以及分页相关的信息(如总记录数、总页数等),方便业务逻辑层进行分页数据的处理和展示,常用于在前端页面分页展示订单列表等场景,便于用户查看不同条件下的订单情况。 + * + * @param ordersPageQueryDTO 包含分页查询条件和排序要求的传输对象,用于指定具体的订单分页查询以及下单时间排序要求,以便获取相应的订单分页数据并按时间顺序排列。 + * @return 返回一个Page对象,代表订单的分页查询结果,其中的泛型Orders表示每个元素是一个订单实体对象,包含了订单的各种属性信息(如订单号、下单时间、订单状态、用户信息等)。 + */ + Page pageQuery(OrdersPageQueryDTO ordersPageQueryDTO); + + /** + * 用户下单的方法,接收一个Orders实体对象作为参数,该对象中包含了新订单的相关信息(如用户信息、下单时间、订单金额、订单状态等各种属性值), + * 通过MyBatis的映射机制,会执行对应的插入SQL语句(根据Orders对象的属性和配置生成合适的插入语句,虽此处未明确写出@Insert注解对应的SQL语句,但MyBatis会根据实体与表的映射关系自动生成), + * 将传入的Orders对象中的属性值插入到数据库的orders表中,实现新订单的创建操作,在用户完成下单流程,业务逻辑层需要将订单数据持久化到数据库时调用该方法,完成订单数据的存储。 + * + * @param orders 包含新订单信息的实体对象,其属性值将按照MyBatis生成的插入语句格式插入到数据库的orders表中,完成用户下单对应的订单新增操作。 + */ + void insert(Orders orders); + + /** + * 根据订单号查询订单的方法,使用了@Select注解指定对应的SQL查询语句,该语句会从数据库的orders表中查找订单号与传入参数orderNumber相匹配的订单记录, + * 接收一个String类型的参数orderNumber,表示要查询的订单号,通过执行"select * from orders where number = #{orderNumber}"这条SQL语句, + * 返回对应的订单实体对象(以Orders类型返回查询结果),常用于业务逻辑层需要根据订单号获取特定订单详细信息的场景,比如在订单详情查看、订单状态跟踪等业务操作中,依据订单号来查询具体的订单情况。 + * + * @param orderNumber 要查询的订单的唯一编号,通过该编号可以在数据库的orders表中精准定位到对应的订单记录,获取其详细信息。 + * @return 返回一个Orders类型的对象,表示查询到的与传入订单号对应的订单实体,其中包含了该订单的各种详细信息(如订单号、下单时间、订单状态、用户信息等)。 + */ + @Select("select * from orders where number = #{orderNumber}") + Orders getByNumber(String orderNumber); + + /** + * 修改订单信息的方法,接收一个Orders实体对象作为参数,该对象中包含了修改后的订单相关信息(如更新后的订单状态、修改后的收货地址等属性值), + * 通过MyBatis的映射机制,会执行对应的更新SQL语句(根据实体对象的属性和配置生成合适的更新语句),将数据库中对应订单记录的相关信息更新为传入对象中的属性值,实现订单数据的修改操作, + * 常用于业务逻辑层在订单状态变更、订单内容调整等需要修改订单部分属性的场景下调用,比如用户修改收货地址、商家修改订单配送状态等情况。 + * + * @param orders 包含修改后订单信息的实体对象,其属性值将用于更新数据库中对应订单记录的相应字段内容,实现订单数据的修改。 + */ + void update(Orders orders); + + /** + * 获取配送超时的订单的方法,接收两个参数,一个是Integer类型的pendingPayment(可能表示某种订单支付相关状态或者用于筛选的其他前置条件,具体含义根据业务而定), + * 另一个是LocalDateTime类型的time(通常用于表示一个时间界限,结合前面的状态等条件来判断订单是否配送超时),通过MyBatis的@Param注解对参数进行命名绑定,使得在对应的SQL语句中可以准确引用这两个参数, + * 该方法会执行对应的SQL语句(虽未明确写出,但根据参数和业务逻辑可知是筛选出符合特定状态且下单时间小于给定时间的配送超时的订单记录),并以List集合形式返回查询到的配送超时的订单列表, + * 方便业务逻辑层对这些配送超时的订单进行后续处理,例如提醒商家尽快处理、统计超时订单数量等情况,常用于订单配送管理相关的业务场景中。 + * + * @param pendingPayment 用于筛选订单的一个条件参数,可能与订单支付状态等相关,用于和另一个时间参数共同确定哪些订单处于配送超时的情况,具体含义由业务逻辑决定。 + * @param time 表示时间界限的参数,通常用于判断订单下单时间是否早于该时间,结合前面的状态参数来筛选出配送超时的订单,比如以当前时间为界限判断哪些订单下单太久还未完成配送等情况。 + * @return 返回一个List对象,代表符合配送超时条件的订单列表,其中的泛型Orders表示每个元素是一个订单实体对象,包含了订单的各种属性信息(如订单号、下单时间、订单状态、用户信息等),便于业务层对这些超时订单进行后续处理。 + */ + List getByStatusAndOrderTimeLT(@Param("pendingPayment") Integer pendingPayment, @Param("time") LocalDateTime time); + + /** + * 批量修改派送状态的方法,接收两个参数,一个是List类型的ordersList,表示要批量修改派送状态的订单列表,其中每个Orders对象包含了订单的基本信息以及对应的订单id等用于定位的关键信息, + * 另一个是Integer类型的status,表示要修改为的目标派送状态值,通过MyBatis的@Param注解对参数进行命名绑定,使得在对应的SQL语句中可以准确引用这两个参数, + * 该方法会执行对应的SQL语句(根据订单列表和目标状态生成合适的批量更新语句,虽未明确写出,但可实现批量修改操作),实现对多个订单的派送状态进行统一修改,常用于批量处理订单派送状态变更的业务场景,比如一批订单同时开始配送、同时完成配送等情况。 + * + * @param ordersList 包含要批量修改派送状态的订单的列表,通过该列表可以确定具体哪些订单的派送状态需要进行修改,每个订单对象包含了订单自身的详细信息用于在数据库中定位和更新相应记录。 + * @param status 要修改为的目标派送状态值,用于统一设置ordersList中各个订单的派送状态,使其变为该指定的值,不同的业务中派送状态可能有不同的定义和取值,例如1表示已派送、0表示未派送等。 + */ + void updateBatchStatus(@Param("ordersList") List ordersList, @Param("status") Integer status); + + /** + * 根据orderId获取订单的方法,使用了@Select注解指定对应的SQL查询语句,该语句会从数据库的orders表中查找id与传入参数id相匹配的订单记录, + * 接收一个Long类型的参数id,表示要查询的订单的唯一标识符(通常对应数据库表中的主键),通过执行"select * from orders where id=#{id}"这条SQL语句, + * 返回对应的订单实体对象(以Orders类型返回查询结果),常用于业务逻辑层需要根据订单id获取特定订单详细信息的场景,比如在订单详情查看、订单状态跟踪等业务操作中,依据订单id来查询具体的订单情况,与根据订单号查询订单类似,但依据的是订单的内部唯一标识符。 + * + * @param id 要查询的订单的唯一标识符,通过该标识符可以在数据库的orders表中精准定位到对应的订单记录,获取其详细信息。 + * @return 返回一个Orders类型的对象,表示查询到的与传入订单id对应的订单实体,其中包含了该订单的各种详细信息(如订单号、下单时间、订单状态、用户信息等)。 + */ + @Select("select * from orders where id=#{id}") + Orders getById(Long id); + + /** + * 查询总订单数的方法,接收一个Map类型的参数map,该Map中通常包含了用于筛选统计总订单数的相关条件信息(例如按照时间范围、用户范围等条件来统计符合要求的总订单数量), + * 通过MyBatis的@Param注解对参数进行命名绑定(此处将参数命名为"map"),使得在对应的SQL语句中可以准确引用该参数,执行对应的SQL语句(根据传入的条件Map生成合适的统计总订单数的SQL语句,虽未明确写出,但可实现相应统计功能), + * 并以Integer类型返回统计得到的总订单数量,常用于业务逻辑层需要了解在特定条件下的总订单数量的场景,比如统计某个时间段内的总订单量、某个用户的总订单数量等情况,方便业务数据的统计和分析。 + * + * @param map 包含统计总订单数筛选条件的Map对象,其中的键值对可以根据业务需求设置不同的条件参数,例如时间区间、用户标识等,用于确定统计哪些订单的数量,以获取符合特定要求的总订单数量。 + * @return 返回一个Integer类型的值,表示符合传入条件的总订单数量,该数值反映了在数据库中满足相应条件的订单的总记录个数,便于业务层进行相关数据统计和分析。 + */ + Integer countByMap(@Param("map") Map map); + + /** + * 统计营业额的方法,接收一个Map类型的参数map,该Map中通常包含了用于筛选统计营业额的相关条件信息(例如按照时间范围、店铺范围等条件来统计符合要求的营业额数值), + * 通过MyBatis的@Param注解对参数进行命名绑定(此处将参数命名为"map"),使得在对应的SQL语句中可以准确引用该参数,执行对应的SQL语句(根据传入的条件Map生成合适的统计营业额的SQL语句,虽未明确写出,但可实现相应统计功能), + * 并以Double类型返回统计得到的营业额数值,常用于业务逻辑层需要了解在特定条件下的营业额情况的场景,比如统计某个时间段内的店铺营业额、某个分类商品的营业额等情况,方便业务数据的统计和分析以及财务相关的核算。 + * + * @param map 包含统计营业额筛选条件的Map对象,其中的键值对可以根据业务需求设置不同的条件参数,例如时间区间、商品分类、店铺标识等,用于确定统计哪些订单产生的营业额,以获取符合特定要求的营业额数值。 + * @return 返回一个Double类型的值,表示符合传入条件的营业额数值,该数值反映了在数据库中满足相应条件的订单所产生的营业额总和,便于业务层进行相关数据统计和分析以及财务处理。 + */ + Double sumByMap(@Param("map") Map map); +} \ No newline at end of file diff --git a/sky/sky-server/src/main/java/com/sky/mapper/UserMapper.java b/sky/sky-server/src/main/java/com/sky/mapper/UserMapper.java new file mode 100644 index 0000000..0e75ed7 --- /dev/null +++ b/sky/sky-server/src/main/java/com/sky/mapper/UserMapper.java @@ -0,0 +1,59 @@ +package com.sky.mapper; + +import com.sky.entity.User; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; + +import java.util.Map; + +/** + * UserMapper接口,作为MyBatis框架中的数据映射接口,主要用于定义与用户(User)相关的各种数据库操作方法, + * 涵盖了从用户信息的查询(根据不同条件,如openid、用户id等)、用户注册新增,到特定统计(如统计今日新增用户数量)等功能,通过MyBatis的注解与对应的SQL语句进行关联,实现对数据库中用户表数据的增删改查以及统计分析等操作, + * 为业务逻辑层提供了操作用户数据的底层支持,满足不同业务场景下对于用户管理和数据获取的需求。 + */ +@Mapper +public interface UserMapper { + + /** + * 根据openid获取用户的方法,使用了@Select注解指定对应的SQL查询语句,该语句会从数据库的user表中查找openid与传入参数openid相匹配的用户记录, + * 接收一个String类型的参数openid,通常在与第三方登录(比如微信登录等,openid作为第三方平台给用户的唯一标识)或者系统自身基于openid来识别用户的场景下使用, + * 通过执行"select * from user where openid=#{openid}"这条SQL语句,返回对应的用户实体对象(以User类型返回查询结果),常用于业务逻辑层需要根据openid获取特定用户详细信息的场景, + * 比如在登录验证、关联第三方账号等业务操作中,依据openid来查询具体的用户情况,确保能准确识别和获取用户相关信息。 + * + * @param openid 要查询的用户在第三方平台或者系统内对应的唯一标识,通过该标识可以在数据库的user表中精准定位到对应的用户记录,获取其详细信息。 + * @return 返回一个User类型的对象,表示查询到的与传入openid对应的用户实体,其中包含了该用户的各种详细信息(如用户名、密码、用户角色等,具体取决于用户表的字段定义)。 + */ + @Select("select * from user where openid=#{openid}") + User getByOpenId(String openid); + + /** + * 注册新用户的方法,接收一个User实体对象作为参数,该对象中包含了新用户的相关注册信息(如用户名、密码、手机号等各种属性值,具体根据用户表的字段定义和注册业务要求而定), + * 通过MyBatis的映射机制,会执行对应的插入SQL语句(虽此处未明确写出@Insert注解对应的SQL语句,但MyBatis会根据实体与表的映射关系自动生成合适的插入语句), + * 将传入的User对象中的属性值插入到数据库的user表中,实现新用户注册信息的持久化操作,在用户完成注册流程,业务逻辑层需要将用户注册数据保存到数据库时调用该方法,完成新用户数据的存储。 + * + * @param user 包含新用户注册信息的实体对象,其属性值将按照MyBatis生成的插入语句格式插入到数据库的user表中,完成用户注册对应的新增用户操作。 + */ + void insertUser(User user); + + /** + * 通过用户id获取用户信息的方法,使用了@Select注解指定对应的SQL查询语句,该语句会从数据库的user表中查找id与传入参数userId相匹配的用户记录, + * 接收一个Long类型的参数userId,表示要查询的用户的唯一标识符(通常对应数据库表中的主键),通过执行"select * from user where id=#{userId}"这条SQL语句, + * 返回对应的用户实体对象(以User类型返回查询结果),常用于业务逻辑层需要根据用户id获取特定用户详细信息的场景,比如在用户详情查看、用户权限验证等业务操作中,依据用户id来查询具体的用户情况,获取用户的详细资料。 + * + * @param userId 要查询的用户的唯一标识符,通过该标识符可以在数据库的user表中精准定位到对应的用户记录,获取其详细信息。 + * @return 返回一个User类型的对象,表示查询到的与传入用户id对应的用户实体,其中包含了该用户的各种详细信息(如用户名、密码、用户角色等,具体取决于用户表的字段定义)。 + */ + @Select("select * from user where id=#{userId}") + User getById(Long userId); + + /** + * 今日新增用户的方法,接收一个Map类型的参数map,该Map中通常包含了用于筛选统计今日新增用户的相关条件信息(例如按照创建时间范围来确定是今日新增的用户,可能涉及日期相关的比较条件等,具体根据业务和数据库表结构而定), + * 通过MyBatis的@Param注解对参数进行命名绑定(此处将参数命名为"map"),使得在对应的SQL语句中可以准确引用该参数,执行对应的SQL语句(根据传入的条件Map生成合适的统计今日新增用户数量的SQL语句,虽未明确写出,但可实现相应统计功能), + * 并以Integer类型返回统计得到的今日新增用户数量,常用于业务逻辑层需要了解每天新注册用户数量情况的场景,比如分析用户增长趋势、统计每日新增用户活跃度等情况,方便业务数据的统计和分析。 + * + * @param map 包含统计今日新增用户筛选条件的Map对象,其中的键值对可以根据业务需求设置不同的条件参数,例如时间区间限定等,用于确定哪些用户是今日新增的,以获取符合特定要求的今日新增用户数量。 + * @return 返回一个Integer类型的值,表示符合传入条件的今日新增用户数量,该数值反映了在数据库中今日新注册的用户的记录个数,便于业务层进行相关数据统计和分析。 + */ + Integer countByMap(@Param("map") Map map); +} \ No newline at end of file diff --git a/sky/sky-server/src/main/java/com/sky/service/AddressBookService.java b/sky/sky-server/src/main/java/com/sky/service/AddressBookService.java new file mode 100644 index 0000000..df55ff3 --- /dev/null +++ b/sky/sky-server/src/main/java/com/sky/service/AddressBookService.java @@ -0,0 +1,63 @@ +package com.sky.service; + +import com.sky.entity.AddressBook; +import java.util.List; + +/** + * AddressBookService接口,定义了与地址簿(AddressBook)相关的一系列业务操作方法, + * 它作为业务逻辑层的抽象接口,旨在规范地址簿相关服务的功能,使得不同的业务实现类可以按照统一的方法定义来实现具体的业务逻辑, + * 为上层的控制器层等调用者提供了清晰的操作地址簿数据的接口,方便进行诸如查询、新增、获取单个、修改、设置默认以及删除地址等操作,以满足用户在地址管理方面的各种业务需求。 + */ +public interface AddressBookService { + + /** + * 根据传入的AddressBook对象中的条件(如用户id等属性,可用于筛选特定用户的地址信息)进行地址簿信息的列表查询操作, + * 返回符合条件的地址信息列表(以List集合形式返回,集合中的每个元素是一个AddressBook实体对象,包含了如地址、联系人、联系电话等地址相关详细信息), + * 方便在需要获取特定用户的多个地址信息时调用,例如在用户查看自己已保存的所有收货地址等场景下使用。 + * + * @param addressBook 包含查询条件的地址簿实体对象,其属性可用于确定要查询哪些地址信息,比如通过设置用户id属性来获取该用户对应的所有地址记录。 + * @return 返回一个List对象,代表符合传入条件的地址簿信息列表,其中的泛型AddressBook表示每个元素是一个地址簿实体对象,包含了地址的各种详细信息(如详细地址、联系人、联系电话等)。 + */ + List list(AddressBook addressBook); + + /** + * 用于新增地址信息的方法,接收一个AddressBook实体对象作为参数,该对象中包含了要新增的地址详细信息(如详细地址、联系人、联系电话等属性值), + * 通过具体的业务实现类实现该方法时,会将传入的地址信息持久化到数据库中对应的地址簿表中,完成地址的新增操作,常用于用户添加新的收货地址等场景下调用,实现地址数据的存储。 + * + * @param addressBook 包含新增地址详细信息的实体对象,其属性值将被保存到数据库的地址簿表中,作为一条新的地址记录,例如详细地址、联系人、联系电话等信息会被插入相应的字段。 + */ + void save(AddressBook addressBook); + + /** + * 根据传入的地址id(Long类型的参数id)查询对应的单个地址信息,返回相应的AddressBook实体对象(该对象包含了该地址的详细信息,如详细地址、联系人、联系电话等), + * 方便在需要查看某个具体地址的详细情况时调用,例如在修改地址前查看原地址信息、在订单选择收货地址时查看特定地址详情等业务场景下使用。 + * + * @param id 要查询的地址的唯一标识符,通过该id可以在数据库的地址簿表中精准定位到对应的地址记录,获取其详细信息。 + * @return 返回一个AddressBook对象,代表查询到的与传入id对应的地址实体,其中包含了该地址的各种详细信息(如详细地址、联系人、联系电话等)。 + */ + AddressBook getById(Long id); + + /** + * 用于修改地址信息的方法,接收一个AddressBook实体对象作为参数,该对象中包含了修改后的地址详细信息(如更新后的详细地址、联系人、联系电话等属性值), + * 通过具体的业务实现类实现该方法时,会根据该对象中的地址id等关键信息找到数据库中对应的地址记录,并将记录中的相关字段更新为传入对象中的新属性值,完成地址信息的修改操作,常用于用户更新已保存的收货地址等场景下调用。 + * + * @param addressBook 包含修改后地址详细信息的实体对象,其属性值将用于更新数据库中对应地址记录的相应字段内容,实现地址数据的修改。 + */ + void update(AddressBook addressBook); + + /** + * 用于设置默认地址的方法,接收一个AddressBook实体对象作为参数,该对象中通常包含了地址相关的关键信息(如地址id等,用于确定要设置为默认地址的具体地址记录), + * 通过具体的业务实现类实现该方法时,会按照业务规则进行操作,比如将其他同用户的非默认地址标记取消,并将传入的这个地址标记为默认地址(涉及对数据库中地址簿表相关字段的更新操作),方便用户指定常用的收货地址为默认地址,便于后续下单等操作时默认使用该地址。 + * + * @param addressBook 包含地址相关信息的实体对象,其属性(如地址id等)会用于确定要设置为默认地址的具体地址记录,同时可能会涉及一些其他属性用于业务逻辑判断等情况,例如是否满足设置默认地址的条件等。 + */ + void setDefault(AddressBook addressBook); + + /** + * 根据传入的地址id(Long类型的参数id)删除对应的地址信息,通过具体的业务实现类实现该方法时,会在数据库的地址簿表中根据该id找到对应的地址记录,并执行删除操作,将该记录从表中移除, + * 常用于用户删除不再需要的收货地址等场景下调用,实现地址数据的删除。 + * + * @param id 要删除的地址的唯一标识符,通过该id可以在数据库的地址簿表中精准定位到对应的地址记录,执行删除操作。 + */ + void deleteById(Long id); +} \ No newline at end of file diff --git a/sky/sky-server/src/main/java/com/sky/service/EmployeeService.java b/sky/sky-server/src/main/java/com/sky/service/EmployeeService.java new file mode 100644 index 0000000..9c2164e --- /dev/null +++ b/sky/sky-server/src/main/java/com/sky/service/EmployeeService.java @@ -0,0 +1,70 @@ +package com.sky.service; + +import com.sky.dto.EmployeeDTO; +import com.sky.dto.EmployeeLoginDTO; +import com.sky.dto.EmployeePageQueryDTO; +import com.sky.entity.Employee; +import com.sky.result.PageResult; + +/** + * EmployeeService接口,定义了与员工(Employee)相关的一系列业务操作方法, + * 它作为业务逻辑层的抽象接口,旨在规范员工相关服务的功能,使得不同的业务实现类可以按照统一的方法定义来实现具体的业务逻辑, + * 为上层的控制器层等调用者提供了清晰的操作员工数据的接口,方便进行诸如员工登录、新增、分页查询、账号状态变更、根据id查询以及编辑员工信息等操作,以满足企业在员工管理方面的各种业务需求。 + */ +public interface EmployeeService { + + /** + * 员工登录的业务方法,接收一个EmployeeLoginDTO对象作为参数,该对象通常包含了员工登录所需的关键信息,比如用户名(或工号)、密码等(具体取决于业务系统的设计), + * 通过具体的业务实现类实现该方法时,会根据传入的登录信息与数据库中存储的员工账号信息进行比对验证,若验证通过,则返回对应的Employee实体对象(该对象包含了员工的详细信息,如员工姓名、部门、岗位等),表示登录成功, + * 常用于员工在系统前端进行登录操作时,后端进行登录逻辑处理并返回相应结果的场景,确保只有合法的员工能够登录系统,获取相应的操作权限。 + * + * @param employeeLoginDTO 包含员工登录信息的传输对象,其属性值(如用户名、密码等)用于在登录验证过程中与数据库中存储的员工账号信息进行匹配比对,以确定登录是否成功。 + * @return 返回一个Employee对象,代表登录成功的员工实体,其中包含了该员工的各种详细信息(如员工姓名、部门、岗位等),若登录验证失败,则按照业务实现类的具体逻辑返回相应的错误提示或结果(比如返回null等表示登录失败)。 + */ + Employee login(EmployeeLoginDTO employeeLoginDTO); + + /** + * 新增员工的业务方法,接收一个EmployeeDTO对象作为参数,该对象中包含了要新增员工的详细信息(如员工姓名、性别、联系方式、入职日期、岗位等属性值,具体根据业务系统中员工表的字段定义而定), + * 通过具体的业务实现类实现该方法时,会将传入的员工信息持久化到数据库中对应的员工表中,完成员工数据的新增操作,常用于企业人力资源部门添加新员工信息到系统等场景下调用,实现员工数据的存储,扩充企业员工信息库。 + * + * @param employeeDTO 包含新增员工详细信息的实体对象,其属性值将被保存到数据库的员工表中,作为一条新的员工记录,例如员工姓名、性别、联系方式、入职日期、岗位等信息会被插入相应的字段。 + */ + void save(EmployeeDTO employeeDTO); + + /** + * 分页查询的业务方法,接收一个EmployeePageQueryDTO对象作为参数,该对象通常包含了分页查询所需的相关信息,如页码、每页显示记录数以及可能的筛选条件(比如按照部门筛选员工、按照姓名关键字筛选等), + * 通过具体的业务实现类实现该方法时,会根据传入的分页查询条件进行数据库查询操作,并将查询结果按照分页规则进行处理,最后以PageResult对象形式返回查询结果(PageResult对象中包含了总记录数、当前页的员工数据列表等分页相关信息), + * 方便在需要分页展示员工信息(比如在企业管理系统的员工列表页面,按页查看员工情况)的场景下调用,满足用户对员工数据分页查看的需求。 + * + * @param employeePageQueryDTO 包含分页查询条件的传输对象,其属性值(如页码、每页记录数、筛选条件等)用于确定具体的员工分页查询要求,以便获取相应的分页数据。 + * @return 返回一个PageResult对象,用于封装分页查询结果,包含了总记录数(total)和当前页的员工记录列表(records)等信息,方便上层进行分页数据的处理和展示。 + */ + PageResult pageQuery(EmployeePageQueryDTO employeePageQueryDTO); + + /** + * 启用或禁用员工账号的业务方法,接收两个参数,一个是Integer类型的status,表示要设置的员工账号状态值(例如1表示启用,0表示禁用,具体状态值的定义根据业务系统设定), + * 另一个是Long类型的id,表示要变更账号状态的员工的唯一标识符(通过该id可以在数据库的员工表中精准定位到对应的员工记录),通过具体的业务实现类实现该方法时,会根据传入的状态值和员工id,更新数据库中对应员工记录的账号状态字段, + * 常用于企业管理人员对员工账号进行权限管理,比如在员工离职或暂时不需要使用系统时禁用账号,或者在员工重新入职或恢复使用权限时启用账号等场景下调用,实现对员工账号状态的灵活控制。 + * + * @param status 要设置的员工账号状态值,用于确定将员工账号设置为启用还是禁用状态,改变数据库中对应员工记录的账号状态字段内容。 + * @param id 要变更账号状态的员工的唯一标识符,通过该id可以在数据库的员工表中精准定位到对应的员工记录,进行账号状态修改操作。 + */ + void startOrStop(Integer status, Long id); + + /** + * 通过id查询员工信息的业务方法,接收一个Long类型的参数id,该参数表示要查询的员工的唯一标识符, + * 通过具体的业务实现类实现该方法时,会根据传入的员工id在数据库的员工表中查找对应的员工记录,并返回相应的Employee实体对象(该对象包含了员工的详细信息,如员工姓名、部门、岗位等), + * 方便在需要查看某个具体员工的详细情况时调用,例如在查看员工个人资料、进行员工信息编辑前查看原信息等业务场景下使用。 + * + * @param id 要查询的员工的唯一标识符,通过该id可以在数据库的员工表中精准定位到对应的员工记录,获取其详细信息。 + */ + Employee getById(Long id); + + /** + * 编辑员工信息的业务方法,接收一个EmployeeDTO对象作为参数,该对象中包含了修改后的员工详细信息(如更新后的员工姓名、性别、联系方式、岗位等属性值), + * 通过具体的业务实现类实现该方法时,会根据该对象中的员工id等关键信息找到数据库中对应的员工记录,并将记录中的相关字段更新为传入对象中的新属性值,完成员工信息的修改操作,常用于企业管理人员更新员工相关信息(比如员工调岗、联系方式变更等情况)的场景下调用。 + * + * @param employeeDTO 包含修改后员工详细信息的实体对象,其属性值将用于更新数据库中对应员工记录的相应字段内容,实现员工数据的修改。 + */ + void update(EmployeeDTO employeeDTO); +} \ No newline at end of file diff --git a/sky/sky-server/src/main/java/com/sky/service/ShoppingCartService.java b/sky/sky-server/src/main/java/com/sky/service/ShoppingCartService.java new file mode 100644 index 0000000..fa6b496 --- /dev/null +++ b/sky/sky-server/src/main/java/com/sky/service/ShoppingCartService.java @@ -0,0 +1,43 @@ +package com.sky.service; + +import com.sky.dto.ShoppingCartDTO; +import com.sky.entity.ShoppingCart; +import java.util.List; + +/** + * ShoppingCartService接口,定义了与购物车(ShoppingCart)相关的一系列业务操作方法, + * 它作为业务逻辑层的抽象接口,旨在规范购物车相关服务的功能,使得不同的业务实现类可以按照统一的方法定义来实现具体的业务逻辑, + * 为上层的控制器层等调用者提供了清晰的操作购物车数据的接口,方便进行诸如添加商品到购物车、查看购物车内容、删除购物车中商品以及清空购物车等操作,以满足用户在购物过程中对购物车管理的各种业务需求。 + */ +public interface ShoppingCartService { + + /** + * 添加购物车的业务方法,接收一个ShoppingCartDTO对象作为参数,该对象通常包含了要添加到购物车的商品相关信息(比如商品id、数量、规格等,具体取决于业务系统中购物车与商品关联的设计)以及用户相关信息(比如用户id,用于确定是哪个用户的购物车), + * 通过具体的业务实现类实现该方法时,会根据传入的购物车信息将对应的商品添加到数据库中对应的购物车表(或相关存储结构中,具体看数据存储设计),完成商品添加到购物车的操作,常用于用户在浏览商品时将心仪的商品加入购物车的场景下调用,实现购物车数据的更新。 + * + * @param shoppingCartDTO 包含要添加到购物车的商品及用户相关信息的传输对象,其属性值(如商品id、数量、规格、用户id等)用于确定要添加哪些商品到哪个用户的购物车中,按照业务规则进行相应的数据存储操作。 + */ + void add(ShoppingCartDTO shoppingCartDTO); + + /** + * 查看用户购物车的业务方法,该方法无参数传入,通过具体的业务实现类实现该方法时,会根据当前登录用户(通常是从系统上下文获取用户标识信息,比如用户id)从数据库的购物车表(或相关存储结构)中查询出该用户购物车中的所有商品信息, + * 并以List集合形式返回查询结果(集合中每个元素是一个ShoppingCart实体对象,包含了如商品id、商品名称、数量、规格、价格等购物车中商品的详细信息),方便用户查看自己购物车中已添加的商品情况,例如在购物车页面展示商品列表等场景下使用。 + * + * @return 返回一个List对象,代表当前用户购物车中的商品信息列表,其中的泛型ShoppingCart表示每个元素是一个购物车中商品的实体对象,包含了商品的各种详细信息(如商品名称、数量、规格、价格等)。 + */ + List list(); + + /** + * 删除购物车中的商品的业务方法,接收一个ShoppingCartDTO对象作为参数,该对象通常包含了要删除的商品相关关键信息(比如商品id、规格等,用于精准定位购物车中要删除的具体商品记录)以及用户相关信息(比如用户id,确保是操作当前用户购物车中的商品), + * 通过具体的业务实现类实现该方法时,会根据传入的信息在数据库的购物车表(或相关存储结构)中找到对应的商品记录,并执行删除操作,将该商品从购物车中移除,常用于用户在购物车中移除不再需要的商品的场景下调用,实现购物车数据的更新。 + * + * @param shoppingCartDTO 包含要删除的商品及用户相关信息的传输对象,其属性值(如商品id、规格、用户id等)用于确定要从哪个用户的购物车中删除哪些具体商品,按照业务规则进行相应的数据删除操作。 + */ + void delete(ShoppingCartDTO shoppingCartDTO); + + /** + * 清空购物车的业务方法,该方法无参数传入,通过具体的业务实现类实现该方法时,会根据当前登录用户(同样通常从系统上下文获取用户标识信息,比如用户id)将数据库中该用户购物车对应的所有商品记录全部删除,实现清空购物车的操作, + * 常用于用户想要一次性移除购物车中所有商品的场景下调用,例如重新选购商品前清空之前添加的商品等情况,方便用户快速清理购物车内容。 + */ + void clean(); +} \ No newline at end of file diff --git a/sky/sky-server/src/main/java/com/sky/service/impl/DishServiceImpl.java b/sky/sky-server/src/main/java/com/sky/service/impl/DishServiceImpl.java new file mode 100644 index 0000000..f51482a --- /dev/null +++ b/sky/sky-server/src/main/java/com/sky/service/impl/DishServiceImpl.java @@ -0,0 +1,221 @@ +package com.sky.service.impl; + +import com.github.pagehelper.Page; +import com.github.pagehelper.PageHelper; +import com.sky.constant.MessageConstant; +import com.sky.constant.StatusConstant; +import com.sky.dto.DishDTO; +import com.sky.dto.DishPageQueryDTO; +import com.sky.entity.Dish; +import com.sky.entity.DishFlavor; +import com.sky.entity.Setmeal; +import com.sky.entity.SetmealDish; +import com.sky.exception.DeletionNotAllowedException; +import com.sky.mapper.DishMapper; +import com.sky.result.PageResult; +import com.sky.service.DishService; +import com.sky.vo.DishVO; +import com.sky.vo.SetmealVO; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +/** + * DishServiceImpl类,实现了DishService接口,作为业务逻辑层的实现类,主要负责处理与菜品(Dish)相关的各种业务逻辑操作, + * 它依赖于DishMapper(数据访问层接口,用于与数据库进行交互)来完成数据的持久化和查询等基础操作,通过调用DishMapper的对应方法以及运用一些业务规则处理,实现了诸如菜品的分页查询、新增、删除、修改、状态变更以及根据不同条件查询菜品等功能, + * 在整个系统架构中起到了承上启下的作用,将上层控制器层的请求转化为对数据库的具体操作,并按照业务需求处理返回结果,为菜品管理相关业务提供核心的逻辑支持。 + */ +@Service +public class DishServiceImpl implements DishService { + + /** + * 通过自动注入的方式获取DishMapper对象,DishMapper中定义了与菜品相关的各种数据库操作方法, + * 例如菜品数据的分页查询、单个菜品查询、菜品数据的新增、删除、更新以及与菜品口味等相关的数据操作方法,本业务逻辑实现类中的各个业务方法会调用其对应的方法来完成具体的数据库交互操作,实现菜品业务逻辑功能。 + */ + @Autowired + DishMapper dishMapper; + + /** + * 菜品分页查询的业务方法,实现了DishService接口中定义的pageQuery方法,用于根据传入的分页查询条件对象(DishPageQueryDTO)进行菜品数据的分页查询操作, + * 首先从DishPageQueryDTO对象中获取页码(page)和每页显示记录数(pageSize)信息,然后借助PageHelper工具(用于在MyBatis中方便地实现分页功能)启动分页查询, + * 调用DishMapper的pageQuery方法获取分页查询结果(以Page对象形式返回,其中包含了查询到的当前页菜品数据以及分页相关的统计信息,如总记录数等), + * 接着从Page对象中提取出总记录数(total)和当前页的菜品数据列表(dishes),最后构建一个PageResult对象,将总记录数和菜品数据列表设置进去,返回该PageResult对象给上层调用者(通常是控制器层), + * 以便在前端页面进行分页展示菜品信息,满足用户分页查看菜品列表的需求。 + * + * @param dishPageQueryDTO 包含分页查询条件的传输对象,其中有页码、每页记录数以及可能的筛选条件等信息,用于指定具体的菜品分页查询要求,获取相应的分页数据。 + * @return 返回一个PageResult对象,用于封装分页查询结果,包含了总记录数(total)和当前页的菜品记录列表(records)等信息,方便上层进行分页数据的处理和展示。 + */ + @Override + public PageResult pageQuery(DishPageQueryDTO dishPageQueryDTO) { + int page = dishPageQueryDTO.getPage(); + int pageSize = dishPageQueryDTO.getPageSize(); + // 开始分页查询,通过PageHelper设置当前页码和每页显示数量,后续执行的数据库查询会自动按照此分页设置进行操作 + PageHelper.startPage(page, pageSize); + Page pageResult = dishMapper.pageQuery(dishPageQueryDTO); + // 取出查询总数,即满足查询条件的所有记录数量,通过Page对象的getTotal方法获取 + long total = pageResult.getTotal(); + // 取出查询结果,即当前页的菜品数据列表,通过Page对象的getResult方法获取 + List dishes = pageResult.getResult(); + // 构建查询结果对象,用于将分页相关的数据按照统一的格式返回给上层调用者 + PageResult pageResult1 = new PageResult(); + pageResult1.setTotal(total); + pageResult1.setRecords(dishes); + + return pageResult1; + } + + /** + * 新增菜品和口味的业务方法,该方法使用了@Transactional注解,用于标记这个方法在执行过程中涉及的数据库操作应该在一个事务中进行,保证数据的一致性和完整性, + * 例如在新增菜品及其口味信息时,如果其中某个操作失败,整个操作都应该回滚,避免出现部分数据插入成功而部分失败导致的数据不一致情况。 + * 首先将传入的DishDTO对象中的属性值复制到一个新创建的Dish实体对象中(通过BeanUtils.copyProperties方法实现属性值的拷贝),并设置菜品状态为启用状态(通过StatusConstant.ENABLE常量表示,假设这是定义好的表示启用的状态值), + * 然后调用DishMapper的save方法将菜品数据插入到菜品表中,获取插入后菜品的id(通常是数据库自动生成的主键值),接着获取DishDTO中包含的菜品口味列表(flavors), + * 如果口味列表不为空且包含元素,遍历口味列表,为每个口味对象设置对应的菜品id,最后调用DishMapper的insertBatchFlavors方法将这些口味数据批量插入到口味表中,实现菜品及其口味信息的同时新增操作, + * 常用于在管理员添加新菜品以及对应的口味时调用,完成菜品相关数据的完整添加过程。 + * + * @param dishDTO 包含菜品及其口味详细信息的传输对象,例如菜品名称、价格、分类等菜品信息以及多个口味的具体描述(如口味名称、辣度等口味相关属性),用于在新增菜品时提供完整的数据支持。 + */ + @Transactional + public void saveWithFlaver(DishDTO dishDTO) { + // 向菜品表添加一条数据,创建一个新的Dish实体对象,用于接收从DishDTO拷贝过来的属性值 + Dish dish = new Dish(); + BeanUtils.copyProperties(dishDTO, dish); + dish.setStatus(StatusConstant.ENABLE); + + dishMapper.save(dish); + // 向口味表添加n条数据,获取刚插入菜品的id,后续用于关联口味与菜品 + Long dishId = dish.getId(); + List flavors = dishDTO.getFlavors(); + + if (flavors!= null && flavors.size() > 0) { + flavors.forEach(dishFlavor -> { + dishFlavor.setDishId(dishId); + }); + dishMapper.insertBatchFlavors(flavors); + + } + } + + /** + * 删除菜品的业务方法,用于批量删除菜品数据,但在删除之前需要进行一些业务规则的校验, + * 首先通过调用DishMapper的getByIdBatch方法获取要删除的菜品列表(根据传入的菜品id列表ids查询),然后遍历这些菜品,检查每个菜品的状态, + * 如果菜品处于起售状态(通过StatusConstant.ENABLE判断,起售期间按照业务规则通常不允许删除),则抛出DeletionNotAllowedException异常(自定义的异常类型,用于表示不允许删除的情况),并传递相应的提示信息(通过MessageConstant.DISH_ON_SALE常量表示,假设这是定义好的提示菜品正在销售不能删除的消息), + * 接着检查菜品是否被套餐绑定,通过调用DishMapper的countMealDish方法统计与传入的菜品id列表相关联的套餐菜品数量,如果数量大于0(表示有套餐绑定了这些菜品),同样抛出DeletionNotAllowedException异常,并传递相应的提示信息(通过MessageConstant.DISH_BE_RELATED_BY_SETMEAL常量表示,假设这是定义好的提示菜品被套餐关联不能删除的消息), + * 只有当菜品既不在起售状态且未被套餐绑定的情况下,才调用DishMapper的deleteBatch方法,根据传入的菜品id列表执行批量删除操作,实现菜品数据的批量删除功能,确保删除操作符合业务规则,避免误删正在使用的菜品数据。 + * + * @param ids 包含要批量删除的菜品id的集合,通过该集合可以确定要从数据库中删除哪些菜品记录,但需要经过业务规则校验后才能执行实际的删除操作。 + */ + public void deleteBatch(ArrayList ids) { + + // 判断菜品是否在起售,起售期间不能被删除,通过查询数据库获取对应菜品列表,遍历检查状态 + ArrayList dishs = dishMapper.getByIdBatch(ids); + for (Dish dish : dishs) { + if (dish.getStatus() == StatusConstant.ENABLE) { + throw new DeletionNotAllowedException(MessageConstant.DISH_ON_SALE); + } + } + // 判断菜品是否被套餐绑定,绑定期间不能被删除,通过查询统计与菜品关联的套餐菜品数量来判断 + Integer count = dishMapper.countMealDish(ids); + if (count > 0) { + throw new DeletionNotAllowedException(MessageConstant.DISH_BE_RELATED_BY_SETMEAL); + } + + dishMapper.deleteBatch(ids); + + } + + /** + * 修改菜品的业务方法,该方法同样使用了@Transactional注解,保证修改菜品及其相关口味信息的操作在一个事务内执行,确保数据的一致性, + * 首先将传入的DishDTO对象中的属性值复制到一个新创建的Dish实体对象中(通过BeanUtils.copyProperties方法实现属性值的拷贝),然后获取DishDTO中的菜品口味列表(flavors),为每个口味对象设置对应的菜品id(即要修改的菜品的id), + * 接着调用DishMapper的updateDish方法更新菜品表中的菜品基本信息,之后先调用DishMapper的deleteBatchFlavors方法删除该菜品原有的口味数据(可能是因为口味有修改,先删除旧的口味记录),再调用insertBatchFlavors方法插入更新后的口味数据,实现菜品及其口味信息的完整修改操作, + * 常用于管理员修改菜品的相关属性(如名称、价格等)以及对应的口味信息时调用,保证菜品数据的准确性和完整性。 + * + * @param dishDTO 包含修改后菜品及其口味详细信息的传输对象,例如修改后的菜品名称、价格、分类等菜品信息以及多个口味的具体描述(如口味名称、辣度等口味相关属性),用于更新数据库中对应菜品及其口味的记录。 + */ + @Transactional + public void updateDish(DishDTO dishDTO) { + Dish dish = new Dish(); + BeanUtils.copyProperties(dishDTO, dish); + List flavors = dishDTO.getFlavors(); + flavors.forEach(dishFlavor -> { + dishFlavor.setDishId(dish.getId()); + }); + + // 更新菜品,调用数据访问层方法更新菜品基本信息 + dishMapper.updateDish(dish); + // 更新菜品对应的口味,先删除原有的口味数据,再插入更新后的口味数据 + dishMapper.deleteBatchFlavors(flavors); + dishMapper.insertBatchFlavors(flavors); + + } + + /** + * 根据id获取菜品数据的业务方法,用于根据传入的菜品id查询对应的菜品详细信息以及其关联的口味信息, + * 首先创建一个包含传入id的ArrayList集合(方便后续调用以集合为参数的查询方法),然后通过调用DishMapper的getByIdBatch方法(假设该方法可以根据传入的id列表查询对应的菜品列表,这里只传入了一个id,所以只会获取到一个菜品对象)获取对应的菜品对象, + * 接着通过调用DishMapper的getFlavorById方法根据菜品id查询该菜品的口味列表,之后创建一个DishVO对象(假设这是用于展示菜品详细信息的视图对象,包含了菜品本身信息以及口味信息等), + * 通过BeanUtils.copyProperties方法将菜品对象的属性值复制到DishVO对象中,并将查询到的口味列表设置到DishVO对象的对应属性中,最后返回这个包含菜品详细信息和口味信息的DishVO对象给上层调用者, + * 方便在需要查看特定菜品详细情况(如在菜品详情页面展示)时获取完整的数据进行展示。 + * + * @param id 要查询的菜品的唯一标识符,通过该id可以在数据库中精准定位到对应的菜品记录,获取其详细信息以及关联的口味信息。 + * @return 返回一个DishVO对象,其中包含了查询到的菜品的详细信息(如菜品名称、价格、分类等)以及对应的口味信息(如口味名称、辣度等口味相关属性),便于展示菜品的完整详情。 + */ + public DishVO getById(Long id) { + ArrayList ids = new ArrayList<>(); + ids.add(id); + // 根据id获取菜品,调用数据访问层方法获取对应菜品对象 + Dish dish = dishMapper.getByIdBatch(ids).get(0); + + // 根据菜品id获取该菜品的口味,调用数据访问层方法获取菜品对应的口味列表 + ArrayList dishFlavors = dishMapper.getFlavorById(id); + + DishVO dishVO = new DishVO(); + BeanUtils.copyProperties(dish, dishVO); + dishVO.setFlavors(dishFlavors); + return dishVO; + + } + + /** + * 根据分类id获取菜品的业务方法,直接调用DishMapper的getByCategoryId方法(假设该方法可以根据传入的分类id以及可能的其他筛选条件,这里第二个参数传入null表示无其他额外筛选条件)查询对应分类下的菜品列表, + * 并以ArrayList集合形式返回查询结果,返回的菜品列表包含了属于该分类的所有菜品对象(每个菜品对象包含了菜品自身的详细信息,如菜品名称、价格、状态等),方便在需要按照分类查看菜品时获取相应的数据, + * 例如在前端展示菜品分类页面时,获取某个分类下的所有菜品进行展示。 + * + * @param categoryId 菜品分类的唯一标识符,通过该id可以在数据库中查找属于该分类的所有菜品记录,获取相应的菜品列表。 + * @return 返回一个ArrayList对象,代表属于传入分类id的菜品列表,其中的泛型Dish表示每个元素是一个菜品实体对象,包含了菜品的各种属性信息(如菜品名称、价格、状态等)。 + */ + public ArrayList getByCategoryId(Long categoryId) { + return dishMapper.getByCategoryId(categoryId, null); + } + + /** + * 起售或停售菜品的业务方法,用于变更菜品的销售状态,首先创建一个Dish实体对象,将传入的菜品id(id)和要设置的状态值(status)设置到该对象的对应属性中, + * 然后调用DishMapper的updateDish方法,根据传入的包含菜品id和新状态的Dish对象,更新数据库中对应菜品记录的状态字段,实现菜品销售状态的变更操作, + * 常用于管理员在后台管理系统中对菜品进行起售(如将状态设置为启用状态)或停售(如将状态设置为禁用状态)的操作场景,方便控制菜品的售卖情况。 + * + * @param id 要变更销售状态的菜品的唯一标识符,通过该id可以在数据库中精准定位到对应的菜品记录,进行状态修改操作。 + * @param status 要设置的菜品销售状态值,例如1表示起售,0表示停售等,用于确定将菜品设置为哪种销售状态,改变数据库中对应菜品记录的状态字段内容。 + */ + public void startOrStop(Long id, Integer status) { + Dish dish = new Dish(); + dish.setStatus(status); + dish.setId(id); + + dishMapper.updateDish(dish); + } + +/** + * 根据菜品分类和起售状态查询菜品的业务方法,首先根据传入的Dish实体对象中的分类id(通过dish.getCategoryId()获取)以及起售状态(通过dish.getStatus()获取)调用DishMapper的getByCategoryId方法查询对应的菜品列表(以ArrayList集合形式返回), + * 接着遍历查询到的菜品列表,对于每个菜品,创建一个DishVO对象,通过BeanUtils.copyProperties方法将菜品对象的属性值复制到DishVO对象中,然后再根据菜品的id调用DishMapper的getFlavorById方法获取该菜品的口味列表,并设置到DishVO对象的对应属性中, + * 最后将构建好的包含菜品详细信息和口味信息的DishVO对象添加到一个新的ArrayList集合中,遍历完成后返回这个包含所有符合条件的菜品及其口味信息的DishVO对象列表, + * 方便在需要按照分类和销售状态展示菜品详情(包括口味信息)时获取相应的数据进行展示,例如在前端展示某个分类下正在销售的菜品及其口味列表的场景。 + * + * @param dish 包含菜品分类id和起售状态等查询条件的菜品实体对象,通过其属性值可以确定要查询哪些菜品,例如指定分类以及 \ No newline at end of file diff --git a/sky/sky-server/src/main/java/com/sky/service/impl/SetmealServiceImpl.java b/sky/sky-server/src/main/java/com/sky/service/impl/SetmealServiceImpl.java new file mode 100644 index 0000000..c426c54 --- /dev/null +++ b/sky/sky-server/src/main/java/com/sky/service/impl/SetmealServiceImpl.java @@ -0,0 +1,205 @@ +package com.sky.service.impl; + +import com.github.pagehelper.Page; +import com.github.pagehelper.PageHelper; +import com.sky.constant.MessageConstant; +import com.sky.constant.StatusConstant; +import com.sky.dto.CategoryPageQueryDTO; +import com.sky.dto.SetmealDTO; +import com.sky.dto.SetmealPageQueryDTO; +import com.sky.entity.Setmeal; +import com.sky.entity.SetmealDish; +import com.sky.exception.DeletionNotAllowedException; +import com.sky.mapper.DishMapper; +import com.sky.mapper.SetmealMapper; +import com.sky.result.PageResult; +import com.sky.service.SetmealService; +import com.sky.vo.DishItemVO; +import com.sky.vo.SetmealVO; +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.transaction.annotation.Transactional; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Set; + +/** + * SetmealServiceImpl类,实现了SetmealService接口,作为业务逻辑层的实现类,主要负责处理与套餐(Setmeal)相关的各种业务逻辑操作, + * 它依赖于SetmealMapper(用于操作套餐相关的数据表,如套餐表、套餐菜品关联表等)以及DishMapper(用于获取菜品相关信息,可能在套餐菜品关联等操作中会用到)来完成数据的持久化、查询以及关联处理等基础操作, + * 通过调用这两个Mapper的对应方法以及运用一些业务规则处理,实现了诸如套餐的条件查询、分页查询、起售停售、修改、根据id查询、批量删除以及新增等功能,在整个系统架构中起到了承上启下的作用,为套餐管理相关业务提供核心的逻辑支持,满足不同业务场景下对于套餐操作的需求。 + */ +@Service +@Slf4j +public class SetmealServiceImpl implements SetmealService { + + /** + * 通过自动注入的方式获取SetmealMapper对象,SetmealMapper中定义了与套餐相关的各种数据库操作方法, + * 例如套餐数据的查询(按条件查询、分页查询、根据id查询等)、套餐数据的新增、删除、更新以及套餐与菜品关联关系的操作(如插入、删除套餐菜品关联记录等)方法,本业务逻辑实现类中的各个业务方法会调用其对应的方法来完成具体的数据库交互操作,实现套餐业务逻辑功能。 + */ + @Autowired + private SetmealMapper setmealMapper; + + /** + * 通过自动注入的方式获取DishMapper对象,虽然套餐业务主要围绕套餐本身及其与菜品的关联,但在一些操作中可能需要获取菜品的相关信息(比如获取套餐内菜品的详细信息等), + * DishMapper中定义了与菜品相关的各种数据库操作方法,本业务逻辑实现类中的部分方法会调用其对应的方法来辅助完成套餐相关业务逻辑,例如在构建包含菜品详细信息的套餐视图对象等场景下会用到。 + */ + @Autowired + private DishMapper dishMapper; + + /** + * 条件查询的业务方法,实现了SetmealService接口中定义的list方法,用于根据传入的Setmeal对象(其中包含了查询条件,如分类id、状态等属性值用于筛选套餐)进行套餐数据的条件查询操作, + * 直接调用SetmealMapper的list方法,传入该Setmeal对象作为查询条件,获取符合条件的套餐数据列表(以List集合形式返回,集合中每个元素为一个符合条件的套餐对象),并将该列表返回给上层调用者(通常是控制器层), + * 方便在需要按照特定条件查看套餐时获取相应的数据,例如在前端根据分类筛选套餐列表等场景下使用。 + * + * @param setmeal 包含查询条件的套餐实体对象,其属性值(如分类id、状态等)用于确定要查询哪些套餐,以便获取符合要求的套餐数据列表。 + * @return 返回一个List对象,代表符合传入条件的套餐数据列表,其中的泛型Setmeal表示每个元素是一个套餐实体对象,包含了套餐的各种属性信息(如套餐名称、价格、包含的菜品等)。 + */ + public List list(Setmeal setmeal) { + List list = setmealMapper.list(setmeal); + return list; + } + + /** + * 根据套餐id查询该套餐菜品的业务方法,实现了SetmealService接口中定义的getDishItemById方法,用于根据传入的套餐id查询该套餐所包含的菜品详细信息, + * 直接调用SetmealMapper的getDishItemBySetmealId方法,传入套餐id作为参数,获取对应的菜品信息列表(以List集合形式返回,假设DishItemVO是用于展示菜品详细信息的视图对象,包含了菜品名称、规格等菜品相关属性), + * 并将该列表返回给上层调用者(通常是控制器层),方便在需要查看某个套餐具体包含哪些菜品时获取相应的数据,例如在用户查看套餐详情页面展示套餐内菜品列表的场景下使用。 + * + * @param id 要查询的套餐的唯一标识符,通过该id可以在数据库中精准定位到对应的套餐记录,进而获取其包含的菜品列表信息。 + * @return 返回一个List对象,代表该套餐包含的菜品详细信息列表,其中的泛型DishItemVO表示每个元素是一个菜品相关的视图对象,包含了菜品的各种详细信息(如菜品名称、规格等)。 + */ + public List getDishItemById(Long id) { + return setmealMapper.getDishItemBySetmealId(id); + } + + /** + * 分页查询套餐的业务方法,用于根据传入的分页查询条件对象(SetmealPageQueryDTO)进行套餐数据的分页查询操作, + * 首先借助PageHelper工具(用于在MyBatis中方便地实现分页功能)启动分页查询,通过调用PageHelper.startPage方法并传入SetmealPageQueryDTO中的页码(page)和每页显示记录数(pageSize)信息来设置分页参数, + * 然后调用SetmealMapper的pageQuery方法获取分页查询结果(以Page对象形式返回,其中包含了查询到的当前页套餐数据以及分页相关的统计信息,如总记录数等), + * 接着创建一个PageResult对象,将从Page对象中获取的总记录数(通过getTotal方法获取)和当前页的套餐数据列表(通过getResult方法获取)设置到PageResult对象的对应属性中,最后返回该PageResult对象给上层调用者(通常是控制器层), + * 以便在前端页面进行分页展示套餐信息,满足用户分页查看套餐列表的需求。 + * + * @param setmealPageQueryDTO 包含分页查询条件的传输对象,其中有页码、每页记录数以及可能的筛选条件等信息,用于指定具体的套餐分页查询要求,获取相应的分页数据。 + * @return 返回一个PageResult对象,用于封装分页查询结果,包含了总记录数(total)和当前页的套餐记录列表(records)等信息,方便上层进行分页数据的处理和展示。 + */ + public PageResult pageQuery(SetmealPageQueryDTO setmealPageQueryDTO) { + // 开始分页查询,通过PageHelper设置当前页码和每页显示数量,后续执行的数据库查询会自动按照此分页设置进行操作 + PageHelper.startPage(setmealPageQueryDTO.getPage(), setmealPageQueryDTO.getPageSize()); + Page list = setmealMapper.pageQuery(setmealPageQueryDTO); + + // 处理查询结果,构建PageResult对象来封装分页相关数据,以便统一返回给上层调用者 + PageResult pageResult = new PageResult(); + pageResult.setTotal(list.getTotal()); + pageResult.setRecords(list.getResult()); + + return pageResult; + } + + /** + * 起售或停售套餐的业务方法,用于变更套餐的销售状态,首先创建一个Setmeal实体对象,将传入的套餐id(id)和要设置的状态值(status)设置到该对象的对应属性中, + * 然后调用SetmealMapper的updateSetmeal方法,根据传入的包含套餐id和新状态的Setmeal对象,更新数据库中对应套餐记录的状态字段,实现套餐销售状态的变更操作, + * 常用于管理员在后台管理系统中对套餐进行起售(如将状态设置为启用状态)或停售(如将状态设置为禁用状态)的操作场景,方便控制套餐的售卖情况。 + * + * @param status 要设置的套餐销售状态值,例如1表示起售,0表示停售等,用于确定将套餐设置为哪种销售状态,改变数据库中对应套餐记录的状态字段内容。 + * @param id 要变更销售状态的套餐的唯一标识符,通过该id可以在数据库中精准定位到对应的套餐记录,进行状态修改操作。 + */ + public void startOrStop(Integer status, Long id) { + Setmeal setmeal = new Setmeal(); + setmeal.setStatus(status); + setmeal.setId(id); + // 更改套餐的起售或停售状态,调用数据访问层方法更新套餐在数据库中的状态记录 + setmealMapper.updateSetmeal(setmeal); + + } + + /** + * 修改套餐信息的业务方法,该方法使用了@Transactional注解,用于标记这个方法在执行过程中涉及的数据库操作应该在一个事务中进行,保证数据的一致性和完整性, + * 例如在修改套餐信息及其关联的菜品信息时,如果其中某个操作失败,整个操作都应该回滚,避免出现部分数据修改成功而部分失败导致的数据不一致情况。 + * 首先将传入的SetmealDTO对象中的属性值复制到一个新创建的Setmeal实体对象中(通过BeanUtils.copyProperties方法实现属性值的拷贝),然后调用SetmealMapper的updateSetmeal方法更新套餐表中的套餐基本信息, + * 接着通过调用SetmealMapper的deleteSetmealDish方法根据套餐id(从SetmealDTO中获取)删除该套餐原有的菜品关联记录(因为套餐菜品可能有修改,先删除旧的关联记录), + * 再获取SetmealDTO中的套餐菜品列表(SetmealDish类型的列表,表示套餐与菜品的关联信息),遍历该列表,为每个套餐菜品对象设置对应的套餐id,最后调用SetmealMapper的insertBatchSetmealDish方法将这些更新后的套餐菜品关联信息批量插入到套餐菜品关联表中, + * 实现套餐及其关联菜品信息的完整修改操作,常用于管理员修改套餐的相关属性(如名称、价格等)以及套餐内包含的菜品信息时调用,保证套餐数据的准确性和完整性。 + * + * @param setmealDTO 包含修改后套餐及其菜品详细信息的传输对象,例如修改后的套餐名称、价格、包含的菜品等信息,用于更新数据库中对应套餐及其关联菜品的记录。 + */ + @Transactional + public void updateSetmeal(SetmealDTO setmealDTO) { + Setmeal setmeal = new Setmeal(); + BeanUtils.copyProperties(setmealDTO, setmeal); + // 修改套餐信息,调用数据访问层方法更新套餐基本信息 + setmealMapper.updateSetmeal(setmeal); + // 修改套餐的菜品信息,先删除原有的套餐菜品关联记录 + // 通过套餐id删除绑定在套餐上的菜品 + setmealMapper.deleteSetmealDish(setmealDTO.getId()); + // 批量插入套餐绑定的菜品,获取修改后的套餐菜品关联信息列表,设置套餐id后插入到关联表中 + List dishes = setmealDTO.getSetmealDishes(); + dishes.forEach(setmealDish -> setmealDish.setSetmealId(setmealDTO.getId())); + setmealMapper.insertBatchSetmealDish(dishes); + } + + /** + * 根据套餐id获取套餐的业务方法,用于根据传入的套餐id查询对应的套餐详细信息以及其关联的菜品信息, + * 首先通过调用SetmealMapper的getBySetmealId方法根据套餐id获取套餐对象(包含套餐自身的基本信息,如套餐名称、价格等),然后调用SetmealMapper的getSetmealDishById方法根据套餐id获取该套餐关联的菜品列表(以List集合形式返回,每个SetmealDish对象包含了套餐与菜品的关联信息,如菜品id等), + * 接着创建一个SetmealVO对象(假设这是用于展示套餐详细信息的视图对象,包含了套餐本身信息以及关联的菜品信息等),通过BeanUtils.copyProperties方法将套餐对象的属性值复制到SetmealVO对象中,并将获取到的套餐菜品列表设置到SetmealVO对象的对应属性中, + * 最后返回这个包含套餐详细信息和关联菜品信息的SetmealVO对象给上层调用者,方便在需要查看特定套餐详细情况(如在套餐详情页面展示)时获取完整的数据进行展示。 + * + * @param id 要查询的套餐的唯一标识符,通过该id可以在数据库中精准定位到对应的套餐记录,获取其详细信息以及关联的菜品信息。 + * @return 返回一个SetmealVO对象,其中包含了查询到的套餐的详细信息(如套餐名称、价格等)以及对应的菜品关联信息(如包含的菜品id等),便于展示套餐的完整详情。 + */ + public SetmealVO getDishById(Long id) { + // 获取套餐信息,调用数据访问层方法获取对应套餐对象 + Setmeal setmeal = setmealMapper.getBySetmealId(id); + // 获取套餐绑定的菜品,调用数据访问层方法获取套餐对应的菜品关联列表 + List setmealDishes = setmealMapper.getSetmealDishById(id); + + // 构建返回对象,创建SetmealVO对象并将套餐及菜品关联信息复制和设置进去 + SetmealVO setmealVO = new SetmealVO(); + BeanUtils.copyProperties(setmeal, setmealVO); + setmealVO.setSetmealDishes(setmealDishes); + + return setmealVO; + } + + /** + * 根据套餐id批量删除套餐的业务方法,用于批量删除指定id的套餐及其相关联的数据(如套餐菜品关联数据), + * 首先遍历传入的套餐id列表(ids),对于每个id,通过调用SetmealMapper的getBySetmealId方法获取对应的套餐对象,检查套餐的状态, + * 如果套餐处于起售状态(通过StatusConstant.ENABLE判断,起售期间按照业务规则通常不允许删除),则抛出DeletionNotAllowedException异常(自定义的异常类型,用于表示不允许删除的情况),并传递相应的提示信息(通过MessageConstant.SETMEAL_ON_SALE常量表示,假设这是定义好的提示套餐正在销售不能删除的消息), + * 接着再次遍历套餐id列表,对于每个套餐id,先创建一个包含该id的ArrayList集合(方便后续调用以集合为参数的删除方法),调用SetmealMapper的batchDeleteSetmeal方法删除套餐表中对应的套餐记录,然后调用SetmealMapper的deleteSetmealDish方法删除该套餐在套餐菜品关联表中的关联记录, + * 实现批量删除套餐及其关联数据的操作,确保删除操作符合业务规则,避免误删正在销售的套餐数据。 + * + * @param ids 包含要批量删除的套餐id的集合,通过该集合可以确定要从数据库中删除哪些套餐记录,但需要经过业务规则校验后才能执行实际的删除操作。 + */ + public void batchDeleteById(ArrayList ids) { + ids.forEach(id -> { + Setmeal setmeal = setmealMapper.getBySetmealId(id); + if (StatusConstant.ENABLE == setmeal.getStatus()) { + // 起售中的套餐不能删除,若处于起售状态则抛出异常提示 + throw new DeletionNotAllowedException(MessageConstant.SETMEAL_ON_SALE); + } + }); + + ids.forEach(setmealId -> { + // 删除套餐表中的数据,先构建包含套餐id的集合,再调用对应的删除方法 + ArrayList setmealIds = new ArrayList<>(); + setmealIds.add(setmealId); + setmealMapper.batchDeleteSetmeal(setmealIds); + // 删除套餐菜品关系表中的数据,直接调用对应的删除方法 + setmealMapper.deleteSetmealDish(setmealId); + }); + + } + + /** + * 新增套餐的业务方法,用于向数据库中插入新的套餐及其关联的菜品信息, + * 首先将传入的SetmealDTO对象中的属性值复制到一个新创建的Setmeal实体对象中(通过BeanUtils.copyProperties方法实现属性值的拷贝),然后调用SetmealMapper的insertBatchSetmealDish方法将SetmealDTO中的套餐菜品关联信息(以List列表形式表示,包含了套餐与要绑定的菜品的关联信息)批量插入到套餐菜品关联表中, + * 接着调用SetmealMapper的insertSetmeal方法将套餐对象的信息插入到套餐表中,实现套餐及其关联菜品信息的同时新增操作,常用于管理员添加新套餐以及设置套餐内包含的菜品时调用,完成套餐相关数据的完整添加过程。 + * + * @param setmealDTO 包含新增套餐及其菜品详细信息的传输对象,例如套餐名称、价格、包含的菜品等信息,用于在新增套餐时提供完整的数据支持,同时其菜品关联信息用于构建套餐与菜品的关联关系插入到数据库中。 + */ + public void insert(SetmealDTO setmealDTO) { + Setmeal setmeal = new Setmeal(); + BeanUtils.copyProperties(setmealDTO, setmeal); + // 新增套餐绑定的菜品,调用数据访问层方法批量插入套餐 \ No newline at end of file diff --git a/sky/sky-server/src/main/java/com/sky/webSocket/WebSocketServer.java b/sky/sky-server/src/main/java/com/sky/webSocket/WebSocketServer.java new file mode 100644 index 0000000..918c0f4 --- /dev/null +++ b/sky/sky-server/src/main/java/com/sky/webSocket/WebSocketServer.java @@ -0,0 +1,93 @@ +package com.sky.webSocket; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import javax.websocket.OnClose; +import javax.websocket.OnMessage; +import javax.websocket.OnOpen; +import javax.websocket.Session; +import javax.websocket.server.PathParam; +import javax.websocket.server.ServerEndpoint; +import java.io.IOException; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +/** + * WebSocketServer类,是一个基于Java WebSocket规范实现的WebSocket服务端组件,用于在服务器与客户端之间建立双向通信的WebSocket连接,实现实时消息交互功能, + * 通过使用相关的WebSocket注解(如@ServerEndpoint、@OnOpen、@OnMessage、@OnClose等)定义了WebSocket连接的端点、连接建立、消息接收以及连接关闭等相关行为,同时提供了向所有已连接客户端发送消息的方法, + * 在整个应用架构中,可用于实现诸如实时推送消息、在线聊天、实时数据更新展示等需要实时交互的业务场景,增强用户体验和系统的实时性。 + */ +@Component +@ServerEndpoint("/ws/{sid}") +@Slf4j +public class WebSocketServer { + + /** + * 使用一个静态的Map来存储已建立WebSocket连接的客户端会话信息,其中键为客户端的唯一标识符(由传入的{sid}参数确定,通常可以是用户id、设备id等能唯一标识客户端的信息),值为对应的WebSocket会话对象(Session), + * 通过这个Map可以方便地管理和查找不同客户端的会话,以便后续进行消息发送、连接状态管理等操作,实现对多个客户端连接的统一管理。 + */ + private static Map sessionMap = new HashMap<>(); + + /** + * 连接开启调用的方法,该方法使用了@OnOpen注解,表明当有客户端与服务端建立WebSocket连接时,此方法会被自动调用, + * 它接收两个参数,一个是通过@PathParam("sid")注解获取的从客户端连接请求路径中传来的唯一标识符(sid),用于区分不同的客户端,另一个是代表当前客户端与服务端建立的WebSocket会话对象(Session), + * 在方法内部,首先通过日志记录客户端建立连接的信息(记录传入的sid,方便后续查看连接情况和排查问题),然后将该客户端的sid和对应的Session对象存入sessionMap中,实现对新连接客户端会话的记录和管理,方便后续与之通信以及跟踪连接状态。 + * + * @param sid 客户端的唯一标识符,从客户端连接请求路径中获取,用于在服务端区分不同的客户端,是后续查找和管理对应客户端会话的关键依据。 + * @param session 代表当前客户端与服务端建立的WebSocket会话对象,通过该对象可以与客户端进行双向通信,例如向客户端发送消息或者接收客户端发送过来的消息等操作。 + */ + @OnOpen + public void open(@PathParam("sid") String sid, Session session) { + log.info("建立连接:{}", sid); + sessionMap.put(sid, session); + } + + /** + * 收到客户端消息调用的方法,该方法使用了@OnMessage注解,表明当服务端接收到客户端通过WebSocket连接发送过来的消息时,此方法会被自动调用, + * 它接收两个参数,一个是客户端发送过来的消息内容(message),以字符串形式接收,另一个是通过@PathParam("sid")注解获取的客户端的唯一标识符(sid),用于确定消息来自哪个客户端, + * 在方法内部,首先通过日志记录客户端发送消息的相关信息(记录sid和消息内容,方便后续查看消息交互情况和排查问题),这里可以根据具体业务需求对收到的消息进行进一步的处理,例如解析消息、根据消息内容执行相应的业务逻辑等,但当前代码只是简单地记录了日志。 + * + * @param message 客户端通过WebSocket连接发送过来的消息内容,以字符串形式接收,其格式和含义由客户端与服务端约定的通信协议决定,可能包含各种业务相关的数据,如操作指令、实时数据等。 + * @param sid 客户端的唯一标识符,从客户端连接请求路径中获取,用于确定消息来源,方便针对不同客户端的消息进行相应的业务处理以及后续回复等操作。 + */ + @OnMessage + public void onMessage(String message, @PathParam("sid") String sid) { + log.info("收到客户端:{}的信息:{}", sid, message); + } + + /** + * 连接关闭调用的方法,该方法使用了@OnClose注解,表明当客户端与服务端的WebSocket连接关闭时,此方法会被自动调用, + * 它接收一个参数,即通过@PathParam("sid")注解获取的客户端的唯一标识符(sid),用于确定是哪个客户端的连接被关闭了, + * 在方法内部,首先通过日志记录客户端断开连接的信息(记录sid,方便后续查看连接情况和排查问题),然后从sessionMap中移除该客户端对应的会话记录,实现对已关闭连接客户端会话的清理,确保sessionMap中只保留当前有效的客户端连接信息。 + * + * @param sid 客户端的唯一标识符,从客户端连接请求路径中获取,用于确定是哪个客户端的连接被关闭了,以便准确地从管理连接的Map中移除对应的会话对象。 + */ + @OnClose + public void close(@PathParam("sid") String sid) { + log.info("断开连接:{}", sid); + sessionMap.remove(sid); + } + + /** + * 向每个与服务端建立WebSocket连接的客户端发送信息的方法,用于实现服务端主动向所有已连接的客户端推送消息的功能, + * 首先获取sessionMap中存储的所有客户端会话对象的集合(通过sessionMap.values()方法获取),然后遍历这个集合,对于每个会话对象,尝试通过调用其getBasicRemote().sendText(message)方法向对应的客户端发送传入的消息内容(message), + * 如果在发送过程中出现IOException异常(例如客户端网络异常、连接已断开等情况导致无法正常发送消息),则会抛出RuntimeException异常(当前代码只是简单地将异常抛出,实际应用中可能需要更精细的异常处理逻辑,比如记录错误日志、尝试重新发送等), + * 此方法常用于服务端有实时消息需要推送给所有客户端的场景,比如系统广播通知、实时数据更新推送等业务情况,确保所有在线客户端能及时收到相关信息。 + * + * @param message 要发送给所有客户端的消息内容,以字符串形式传入,其格式和含义由具体的业务需求和客户端与服务端约定的通信协议决定,例如可以是通知消息、实时数据更新内容等。 + */ + public void sendToAllClient(String message) { + Collection sessionCollection = sessionMap.values(); + for (Session session : sessionCollection) { + try { + session.getBasicRemote().sendText(message); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + } + + +} \ No newline at end of file