1、项目简介
项目是专门为餐饮企业(餐厅、饭店)定制的一款软件产品,包括系统管理后台和移动端应用两部分。其中系统管理后台主要提供给餐饮企业内部员工使用,可以对餐厅的分类、菜品、套餐、订单、员工等进行管理维护。移动端应用主要提供给消费者使用,可以在线浏览菜品、添加购物车、下单等。
2、技术选用
前端:H5、vue、ElementUl
后端:SpringBoot、SpringMVC、Spring、Spring Session
数据库:Mysql、Mybatis、Mybatis Plus
二、项目配置 1、数据库搭建创建数据库和数据库表
2、创建maven项目1、创建普通maven项目
2、检测maven和Runner配置
3、检测jdk
三、导入相关依赖和配置文件1、pom文件
4.0.0 org.springframework.boot spring-boot-starter-parent2.4.5 net.lzzy all_bule_take_out1.0-SNAPSHOT 1.8 org.springframework.boot spring-boot-starterorg.springframework.boot spring-boot-starter-testtest org.springframework.boot spring-boot-starter-webcompile com.baomidou mybatis-plus-boot-starter3.4.2 org.projectlombok lombok1.18.20 com.alibaba fastjson1.2.76 commons-lang commons-lang2.6 mysql mysql-connector-javaruntime com.alibaba druid-spring-boot-starter1.1.23 org.springframework.boot spring-boot-maven-plugin2.4.5
2、在resources文件夹下新建application.yml文件
输入配置
server:
port: 8080
spring:
application:
#应用的名称,可选
name: all_bule_take_out
datasource:
druid:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/all_bule?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowPublicKeyRetrieval=true
username: root
password: 123456
mybatis-plus:
configuration:
#在映射实体或者属性时,将数据库中表名和字段名中的下划线去掉,按照驼峰命名法映射
#比如数据库的表:address_book=>实体类的类名AdderssBook
#字段也一样,例如数据库的列:user_name=>类的属性userName
map-underscore-to-camel-case: true
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
global-config:
db-config:
id-type: ASSIGN_ID
四、创建启动类
1、在java目录下新建net.lzzy.allbule目录和AllBuleApplication启动类
AllBuleApplication启动类配置:
@Slf4j
@SpringBootApplication
public class AllBuleApplication {
public static void main(String[] args) {
SpringApplication.run(AllBuleApplication.class,args);
log.info("项目启动成功");
}
}
@SpringBootApplication是SpringBoot启动类的注解
@Slf4j:在类前面添加注解@Slf4j,就可以使用info的方法在控制台输出日志,或者可以说是可直接使用log日志的功能了
五、设置静态资源的映射把前端的页面放在resources下,发现访问不了
1、配置MVC静态支援的映射
创建config包,然后再新建WebMvcConfig类:
1、@Configuration注解表示当前类是配置类,声明当前类为Spring配置类
2、继承WebMvcConfigurationSupport类,重写静态资源映射的方法:addResourceHandlers方法,使用registry参数来设置要映射的访问路径
@Slf4j
@Configuration
public class WebMvcConfig extends WebMvcConfigurationSupport {
@Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
log.info("开始静态资源映射...");
registry.addResourceHandler("/backend
@Data
public class Employee implements Serializable {
private static final long serialVersionUID = 1L;
private Long id;
private String username;
private String name;
private String password;
private String phone;
private String sex;
private String idNumber;
private Integer status;
private LocalDateTime createTime;
private LocalDateTime updateTime;
@TableField(fill = FieldFill.INSERT)
private Long createUser;
@TableField(fill = FieldFill.INSERT_UPDATE)
private Long updateUser;
}
2、在net.lzzy.allbule创建controller包(Controler负责请求转发,接受页面过来的参数,传给Service处理,接到返回值,再传给页面)、mapper包(数据层进行crud的实现方式),server包( 封装通用的业务逻辑,操作),在server下再建一个impl包(service的impl是把mapper和service进行整合的文件)
3、在mapper包下创建EmployeeMapper接口(员工数据操作接口)操作数据,继承MyBatis-Plus提供的BaseMapper类,继承该接口后,无需编写 mapper.xml 文件,即可获得CRUD功能,BaseMapper
package net.lzzy.allbule.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import net.lzzy.allbule.entity.Employee; import org.apache.ibatis.annotations.Mapper; @Mapper public interface EmployeeMapper extends BaseMapper{ }
4.1、在service包下创建EmployeeService业务层。继承MyBatis-Puls提供的IService类
package net.lzzy.allbule.service; import com.baomidou.mybatisplus.extension.service.IService; import net.lzzy.allbule.entity.Employee; public interface EmployeeService extends IService{ }
4.2、在service包下的Impl包新建一个实现类EmployeeServiceImpl,
Spring提供@Component注解的三个衍生注解:功能一样,使用原因:方便理解
1、@Controller :用于表现层bean定义
2、@Service :用于业务层bean定义
3、@Repository :用于数据层bean定义
package net.lzzy.allbule.service.impl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import net.lzzy.allbule.entity.Employee; import net.lzzy.allbule.mapper.EmployeeMapper; import net.lzzy.allbule.service.EmployeeService; import org.springframework.stereotype.Service; @Service public class EmployeeServiceImpl extends ServiceImplimplements EmployeeService { }
5、在controller包下创建EmployeeController类
@RequestMapping用来映射URL
@RestController = @Controller + @ResponseBody组成
- @Controller 将当前修饰的类注入SpringBoot IOC容器,使得从该类所在的项目跑起来的过程中,这个类就被实例化。当然也有语义化的作用,即代表该类是充当Controller的作用
- @ResponseBody 它的作用简短截说就是指该类中所有的API接口返回的数据,甭管你对应的方法返回Map或是其他Object,它会以Json字符串的形式返回给客户端
package net.lzzy.allbule.controller;
import lombok.extern.slf4j.Slf4j;
import net.lzzy.allbule.service.EmployeeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@Slf4j
@RestController
@RequestMapping("/employee")
public class EmployeeController {
@Autowired
private EmployeeService employeeService;
}
2、创建common包,用于放通用的的类
5、创建通用返回类R类
package net.lzzy.allbule.common; import lombok.Data; import java.util.HashMap; import java.util.Map; @Data public class R3、登录方法{ private Integer code; //编码:1成功,0和其它数字为失败 private String msg; //错误信息 private T data; //数据 private Map map = new HashMap(); //动态数据 public static R success(T object) { R r = new R (); r.data = object; r.code = 1; return r; } public static R error(String msg) { R r = new R(); r.msg = msg; r.code = 0; return r; } public R add(String key, Object value) { this.map.put(key, value); return this; } }
登录处理逻辑:
1、将页面提交的密码password进行md5加密处理
2、根据页面提交的用户名username查询数据库
3、如果没有查询到则返回登录失败结果
4、密码比对,如果不一致则返回登录失败结果
5、查看员工状态,如果为已禁用状态,则返回员工已禁用结果
6、登录成功,将员工id存入Session并返回登录成功结果
@PostMapping("/login")
public R login(HttpServletRequest request,@RequestBody Employee employee){
String password = employee.getPassword();
//将前端提交的密码进行md5加密
DigestUtils.md5DigestAsHex(password.getBytes());
//根据页面提交的用户名username查询数据库
LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>();
//使用Mybatis-plus的等值查询进行查询
queryWrapper.eq(Employee::getUsername,employee.getUsername());
//数据库中表的username设置了唯一索引,不能重复,调用getOne方法查出唯一的一个数据,查出来后封装成一个对象,emp是查出来的对象
Employee emp = employeeService.getOne(queryWrapper);
//如果没有查询到就返回登录失败的结果
if(emp==null){
return R.error("登陆失败");
}
//密码对比,不对返回失败
// if(!emp.getPassword().equals(password)){
// return R.error("登陆失败");
// }
//查看状态,是否被禁用,禁用就返回已经禁用的结果
if(emp.getStatus()==0){
return R.error("账号已经禁用");
}
//登录成功,将id存入Session中
request.getSession().setAttribute("employee",emp.getId());
//返回登录成功的结果
return R.success(emp);
}
4、退出登录
清除缓存id
@PostMapping("/logout")
public Rlogout(HttpServletRequest request){
request.getSession().removeAttribute("employee");
return R.success("退出成功");
}
}
5、拦截器
防止没登录就直接访问系统
新建filter包,创建LoginCheckFilter类
package net.lzzy.allbule.filter;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import net.lzzy.allbule.common.R;
import org.springframework.util.AntPathMatcher;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Slf4j
@WebFilter(filterName = "loginCheckFilter",urlPatterns = "
public Boolean check(String[]urls,String requestURI){
for (String url : urls) {
boolean match = PATH_MATCHER.match( url,requestURI);
if(match){
return true;
}
}
return false;
}
}
@WebFilter 用于将一个类声明为过滤器,该注解将会在部署时被容器处理,容器将根据具体的属性配置将相应的类部署为过滤器。注解默认是不被扫描的,需要在项目启动类上添加 @ServletComponentScan 注解, 表示对 Servlet 组件扫描。
七、员工信息操作 1、添加员工
@PostMapping
public Rsave(HttpServletRequest request,@RequestBody Employee employee){
log.info("添加员工,信息:{}",employee.toString());
//设置初始密码,需要md5加密
employee.setPassword(DigestUtils.md5DigestAsHex("123456".getBytes()));
employee.setCreateTime(LocalDateTime.now());
employee.setUpdateTime(LocalDateTime.now());
//获得当前登录用户的id
Long empId=(Long) request.getSession().getAttribute("employee");
employee.setCreateUser(empId);
employee.setUpdateUser(empId);
employeeService.save(employee);
return R.success("添加员工成功");
}
2、分页查询
1、配置MP(mabatisPlus)的分页插件
在config包下添加 MybatisPlusConfig配置类
package net.lzzy.allbule.config;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor(){
MybatisPlusInterceptor mybatisPlusInterceptor=new MybatisPlusInterceptor();
mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());
return mybatisPlusInterceptor;
}
}
2、分页处理方法
@GetMapping("/page")
public Rpage(int page,int pageSize,String name){
log.info("page={},pageSize={},name={}",page,pageSize,name);
Page pageInfo=new Page(page,pageSize);
//构造条件构造器
LambdaQueryWrapper queryWrapper=new LambdaQueryWrapper();
//当name不等于空的时候,添加过滤条件
queryWrapper.like(StringUtils.isNotEmpty(name),Employee::getName,name);
//添加排序条件
queryWrapper.orderByDesc(Employee::getUpdateTime);
//执行查询
employeeService.page(pageInfo,queryWrapper);
return R.success(pageInfo);
}
3、员工状态启用/禁用
@PutMapping
public Rupdate(HttpServletRequest request,@RequestBody Employee employee){
log.info(employee.toString());
Long empId = (Long) request.getSession().getAttribute("employee");
employee.setUpdateTime(LocalDateTime.now());
employee.setUpdateUser(empId);
employeeService.updateById(employee);
return R.success("员工信息修改成功");
}
状态更新失败
原因:js对long型数据进行处理时丢失精度,导致提交的id和数据库中的id不一致。
如何解决这个问题?
我们可以在服务端给页面响应json数据时进行处理,将long型数据统一转为String字符串
具体实现步骤:
- 提供对象转换器JacksonobjectMapper,基于Jackson进行Java对象到json数据的转换
- 在WebMvcConfig配置类中扩展Spring mvc的消息转换器,在此消息转换器中使用提供的对象转换器进行Java对象到json数据的转换
添加对象映射器
package net.lzzy.allbule.common;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
import java.math.BigInteger;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import static com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES;
public class JacksonObjectMapper extends ObjectMapper {
public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd";
public static final String DEFAULT_DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
public static final String DEFAULT_TIME_FORMAT = "HH:mm:ss";
public JacksonObjectMapper() {
super();
//收到未知属性时不报异常
this.configure(FAIL_ON_UNKNOWN_PROPERTIES, false);
//反序列化时,属性不存在的兼容处理
this.getDeserializationConfig().withoutFeatures(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
SimpleModule simpleModule = new SimpleModule()
.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT)))
.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT)))
.addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)))
.addSerializer(BigInteger.class, ToStringSerializer.instance)
.addSerializer(Long.class, ToStringSerializer.instance)
.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT)))
.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT)))
.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)));
//注册功能模块 例如,可以添加自定义序列化器和反序列化器
this.registerModule(simpleModule);
}
}
在WebMvcConfig添加扩展mvc框架的消息转换器
@Override
protected void extendMessageConverters(List> converters) {
log.info("扩展消息转换器...");
//创建消息转换器对象
MappingJackson2HttpMessageConverter messageConverter = new MappingJackson2HttpMessageConverter();
//设置对象转换器,底层使用Jackson将Java对象转为json
messageConverter.setObjectMapper(new JacksonObjectMapper());
//将上面的消息转换器对象追加到mvc框架的转换器集合中
converters.add(0, messageConverter);
}
四、根据Id编辑员工信息
@GetMapping("{id}")
public RgetById(@PathVariable Long id){
log.info("根据id查询");
Employee employee = employeeService.getById(id);
if(employee!=null){
return R.success(employee);
}
return R.error("没有查询到对应的员工信息");
}
八、全局异常捕获
在common包下添加GlobalExceptionHandler类
@ControllerAdvice是在类上声明的注解,其用法主要有三点::
- @ExceptionHandler注解标注的方法:用于捕获Controller中抛出的不同类型的异常,从而达到异常全局处理的目的;
- @InitBinder注解标注的方法:用于请求中注册自定义参数的解析,从而达到自定义请求参数格式的目的;
- @ModelAttribute注解标注的方法:表示此方法会在执行目标Controller方法之前执行 。
- @ControllerAdvice(annotations = {RestController.class, Controller.class})表示只要哪个类上加了@RestController和@Controller都会被当前处理器处理
- @ExceptionHandler:统一处理某一类异常,从而能够减少代码重复率和复杂度
- @ControllerAdvice:异常集中处理,更好的使业务逻辑与异常处理剥离开;其是对Controller层进行拦截
- @ResponseStatus:可以将某种异常映射为HTTP状态码
package net.lzzy.allbule.common;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import java.sql.SQLIntegrityConstraintViolationException;
@ControllerAdvice(annotations = {RestController.class, Controller.class})
@ResponseBody
@Slf4j
public class GlobalExceptionHandler {
@ExceptionHandler(SQLIntegrityConstraintViolationException.class)
public R exceptionHandler(SQLIntegrityConstraintViolationException ex){
log.error(ex.getMessage());
if(ex.getMessage().contains("Duplicate entry")){
String[] split = ex.getMessage().split(" ");
String msg= split[2]+"已经存在";
return R.error(msg);
}
return R.error("未知错误");
}
}
九、公共字段自动填充
Mybatis Plus公共字段自动填充,也就是在插入或者更新的时候为指定字段赋予指定的值,使用它的好处就是可以统一对这些字段进行处理,避免了重复代码。
实现步骤:1、在实体类的属性上加入@TableField注解,指定自动填充的策略
2、按照框架要求编写元数据对象处理器,在此类中统一为公共字段赋值,此类需要实现MetaObjectHandler接口
ThreadLocal为每个线程提供单独一份存储空间,具有线程隔离的效果,只有在线程内才能获取到对应的值,线程外则不能访问。
ThreadLocal常用方法:- public void set(T value)设置当前线程的线程局部变量的值
- public T get() 返回当前线程所对应的线程局部变量的值
1、编写BaseContext工具类,基于ThreadLocal封装的工具类
package net.lzzy.allbule.common;
public class BaseContext {
// 用于保存当前登录用户id
private static ThreadLocal threadLocal = new ThreadLocal<>();
public static void setCurrentId(Long id){
threadLocal.set(id);
}
public static Long getCurrentId(){
return threadLocal.get();
}
}
2、在LogincheckFilter的doFilter方法中调用BaseContext来设置当前登录用户的id
Long empId = (Long) request.getSession().getAttribute("employee");
BaseContext.setCurrentId(empId);
long id = Thread.currentThread().getId();
3、新建MyMetaobjectHandler类,方法中调用BaseContext获取登录用户的id
package net.lzzy.allbule.common;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
@Component
@Slf4j
public class MyMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
log.info("公共字段自动填充[insert]...");
log.info(metaObject.toString());
metaObject.setValue("createTime", LocalDateTime.now());
metaObject.setValue("updateTime",LocalDateTime.now());
metaObject.setValue("createUser",BaseContext.getCurrentId());
metaObject.setValue("updateUser",BaseContext.getCurrentId());
}
@Override
public void updateFill(MetaObject metaObject) {
log.info("公共字段自动填充[update]...");
log.info(metaObject.toString());
long id = Thread.currentThread().getId();
log.info("线程id为:{}",id);
metaObject.setValue("updateTime",LocalDateTime.now());
metaObject.setValue("updateUser",BaseContext.getCurrentId());
}
}
十、新增分类
1、搭建操作工作
1、创建实体类
@Data
public class Category implements Serializable {
private static final long serialVersionUID = 1L;
private Long id;
//类型 1 菜品分类 2 套餐分类
private Integer type;
//分类名称
private String name;
//顺序
private Integer sort;
//创建时间
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
//更新时间
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
//创建人
@TableField(fill = FieldFill.INSERT)
private Long createUser;
//修改人
@TableField(fill = FieldFill.INSERT_UPDATE)
private Long updateUser;
//是否删除
// private Integer isDeleted;
}
@Data
public class Dish implements Serializable {
private static final long serialVersionUID = 1L;
private Long id;
//菜品名称
private String name;
//菜品分类id
private Long categoryId;
//菜品价格
private BigDecimal price;
//商品码
private String code;
//图片
private String image;
//描述信息
private String description;
//0 停售 1 起售
private Integer status;
//顺序
private Integer sort;
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
@TableField(fill = FieldFill.INSERT)
private Long createUser;
@TableField(fill = FieldFill.INSERT_UPDATE)
private Long updateUser;
//是否删除
private Integer isDeleted;
}
@Data
public class Setmeal implements Serializable {
private static final long serialVersionUID = 1L;
private Long id;
//分类id
private Long categoryId;
//套餐名称
private String name;
//套餐价格
private BigDecimal price;
//状态 0:停用 1:启用
private Integer status;
//编码
private String code;
//描述信息
private String description;
//图片
private String image;
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
@TableField(fill = FieldFill.INSERT)
private Long createUser;
@TableField(fill = FieldFill.INSERT_UPDATE)
private Long updateUser;
//是否删除
private Integer isDeleted;
}
2、创建Mapper
@Mapper public interface CategoryMapper extends BaseMapper{ }
@Mapper public interface DishMapper extends BaseMapper{ }
@Mapper public interface SetmealMapper extends BaseMapper3、创建service接口和实现类{ }
public interface CategoryService extends IService{ public void remove(Long id); }
@Service public class CategoryServiceImpl extends ServiceImplimplements CategoryService { }
public interface DishService extends IService{ }
@Service @Slf4j public class DishServiceImpl extends ServiceImplimplements DishService { }
public interface SetmealService extends IService{ }
@Service public class SetmealServiceImpl extends ServiceImpl4、创建控制层类implements SetmealService { }
@RestController
@RequestMapping("/category")
@Slf4j
public class CategoryController {
@Autowired
private CategoryService categoryService;
}
2、业务开发
1、添加分类
在CategoryController类添加新增分类的方法
@PostMapping
public Rsave(@RequestBody Category category){
log.info("新增参数:{}"+category);
categoryService.save(category);
return R.success("新增成功");
}
2、分页查询
@GetMapping("/page")
public Rpage(int page,int pageSize){
//创建分页构造器
PagepageInfo=new Page<>();
//创建条件构造器对象,根据sort进行排序
LambdaQueryWrapperqueryWrapper=new LambdaQueryWrapper<>();
queryWrapper.orderByAsc(Category::getSort);
//进行查询
categoryService.page(pageInfo,queryWrapper);
return R.success(pageInfo);
}
为了提高查询性能,表与表之间的联系需要人工去维护,不推荐使用外键维护数据的安全性
3、删除因为分类中可能关联了一下菜品跟套餐,所以不能直接删除,需要自定义判断处理
自定义删除方法,抛出异常
@Service public class CategoryServiceImpl extends ServiceImplimplements CategoryService { @Autowired private DishService dishService; @Autowired private SetmealService setmealService; @Override public void remove(Long id) { LambdaQueryWrapper dishLambdaQueryWrapper=new LambdaQueryWrapper<>(); //添加查询条件,根据Id查询 dishLambdaQueryWrapper.eq(Dish::getCategoryId,id); int count=dishService.count(dishLambdaQueryWrapper); //查询当前分类是否关联了菜品,如果已经关联,抛出一个异常 if(count>0){ //已经关联菜品,抛出异常 throw new CustomException("当前分类关联了菜品,不能删除"); } //查询当前分类是否关联了套餐,如果已经关联,抛出一个业务异常 LambdaQueryWrapper setmealLambdaQueryWrapper=new LambdaQueryWrapper<>(); setmealLambdaQueryWrapper.eq(Setmeal::getCategoryId,id); int count1 = setmealService.count(setmealLambdaQueryWrapper); if(count1>0){ //已经关联套餐,抛出异常 throw new CustomException("当前分类关联了菜品,不能删除"); } //删除 super.removeById(id); } }
在common包中定义接收自定义业务异常类
public class CustomException extends RuntimeException {
public CustomException(String message){
super(message);
}
}
在GlobalExceptionHandler类中添加异常处理方法
@ExceptionHandler(CustomException.class)
public R exceptionHandler(CustomException ex){
log.error(ex.getMessage());
return R.error(ex.getMessage());
}
控制层调用方法
@DeleteMapping
public Rdelete(Long ids){
log.info("删除分类,id为:{}",ids);
categoryService.remove(ids);
return R.success("分类删除成功");
}
4、修改分类信息
@PutMapping
public Rupdate(@RequestBody Category category){
categoryService.updateById(category);
return R.success("修改成功");
}
十一、文件上传、下载
import lombok.extern.slf4j.Slf4j;
import net.lzzy.allbule.common.R;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.UUID;
@RestController
@RequestMapping("/common")
@Slf4j
public class CommonController {
@Value("${allBlue.path}")
private String basePath;
@PostMapping("/upload")
public R upload(MultipartFile file) {
log.info(file.toString());
//原始文件名
String originalFilename = file.getOriginalFilename();//abc.jpg
String suffix = originalFilename.substring(originalFilename.lastIndexOf("."));
//使用UUID重新生成文件名,防止文件名称重复造成文件覆盖
String fileName = UUID.randomUUID().toString() + suffix;
//创建一个目录对象
File dir = new File(basePath);
//判断当前目录是否存在
if (!dir.exists()) {
//目录不存在,需要创建
dir.mkdirs();
}
try {
//将临时文件转存到指定位置
file.transferTo(new File(basePath + fileName));
} catch (IOException e) {
e.printStackTrace();
}
return R.success(fileName);
}
@GetMapping("/download")
public void download(String name, HttpServletResponse response){
try {
//输入流,通过输入流读取文件内容
FileInputStream fileInputStream = new FileInputStream(new File(basePath + name));
//输出流,通过输出流将文件写回浏览器
ServletOutputStream outputStream = response.getOutputStream();
response.setContentType("image/jpeg");
int len = 0;
byte[] bytes = new byte[1024];
while ((len = fileInputStream.read(bytes)) != -1){
outputStream.write(bytes,0,len);
outputStream.flush();
}
//关闭资源
outputStream.close();
fileInputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
十二、添加菜品
业务准备
1、创建DishFlavor实体类
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
import java.io.Serializable;
import java.time.LocalDateTime;
@Data
public class DishFlavor implements Serializable {
private static final long serialVersionUID = 1L;
private Long id;
//菜品id
private Long dishId;
//口味名称
private String name;
//口味数据list
private String value;
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
@TableField(fill = FieldFill.INSERT)
private Long createUser;
@TableField(fill = FieldFill.INSERT_UPDATE)
private Long updateUser;
//是否删除
private Integer isDeleted;
}
2、创建DishFlavorMapper数据持久层
import com.baomidou.mybatisplus.core.mapper.BaseMapper; import net.lzzy.allbule.entity.DishFlavor; import org.apache.ibatis.annotations.Mapper; @Mapper public interface DishFlavorMapper extends BaseMapper3、创建DishFlavorService业务层,继承IService类{ }
import com.baomidou.mybatisplus.extension.service.IService; import net.lzzy.allbule.entity.DishFlavor; public interface DishFlavorService extends IService4、创建DishFlavorServiceImpl业务实现类,继承ServiceImpl类{ }
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import net.lzzy.allbule.entity.DishFlavor; import net.lzzy.allbule.mapper.DishFlavorMapper; import net.lzzy.allbule.service.DishFlavorService; import org.springframework.stereotype.Service; @Service public class DishFlavorServiceImpl extends ServiceImpl5、创建DishController类控制层implements DishFlavorService { }
import net.lzzy.allbule.service.DishFlavorService;
import net.lzzy.allbule.service.DishService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/dish")
public class DishController {
@Autowired
private DishFlavorService dishFlavorService;
@Autowired
private DishService dishService;
}
实现
1、菜品分类数据获取
在CategoryController添加查询分类数据的方法
@GetMapping("/list")
public R>list(Category category){
//条件构造器
LambdaQueryWrapper queryWrapper=new LambdaQueryWrapper<>();
//添加添加
queryWrapper.eq(category.getType()!=null,Category::getType,category.getType());
//添加排序条件
queryWrapper.orderByAsc(Category::getSort).orderByDesc(Category::getUpdateTime);
List list = categoryService.list(queryWrapper);
return R.success(list);
}



