业务开发Day 1
后台系统登录功能
/**
* 通用返回结果,服务端响应的数据最终都会封装成此对象
* @param <T>
*/
@Data
public class R<T> {
private Integer code; //编码:1成功,0和其它数字为失败
private String msg; //错误信息
private T data; //数据
private Map map = new HashMap(); //动态数据
public static <T> R<T> success(T object) {
R<T> r = new R<T>();
r.data = object;
r.code = 1;
return r;
}
public static <T> R<T> error(String msg) {
R r = new R();
r.msg = msg;
r.code = 0;
return r;
}
public R<T> add(String key, Object value) {
this.map.put(key, value);
return this;
}
}
@Slf4j
@RestController
@RequestMapping("/employee")
public class EmployeeController {
@Autowired
private EmployeeService employeeService;
@PostMapping("/login")
public R<Employee> login(HttpServletRequest request,@RequestBody Employee employee){
// 1.将页面提交的密码password进行md5加密处理
String password=employee.getPassword();
password=DigestUtils.md5DigestAsHex(password.getBytes());
// 2.根据页面提交的用户名 username 查询数据库
LambdaQueryWrapper<Employee> queryWrapper=new LambdaQueryWrapper<>();
queryWrapper.eq(Employee::getUsername,employee.getUsername());
Employee emp=employeeService.getOne(queryWrapper);
// 3.如果没有查询到则返回登录失败结果
if (emp==null){
return R.error("登录失败");
}
// 4.密码比对,如果不一致则返回登录失败结果
if (!emp.getPassword().equals(password)){
return R.error("登录失败");
}
// 5.查看员工状态,如果为已禁用状态,则返回员工已禁用结果
if (emp.getStatus()==0){
return R.error("账号已禁用");
}
// 6.登录成功,将员工id存入Session并返回登录成功结果
request.getSession().setAttribute("employee",emp.getId());
return R.success(emp);
}
}
报错1
Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.dao.InvalidDataAccessApiUsageException: Error attempting to get column 'create_time' from result set. Cause: java.sql.SQLFeatureNotSupportedException
; null; nested exception is java.sql.SQLFeatureNotSupportedException] with root cause
因为create_time类型为DateTime,通过mybatis-plus代码生成器生成的是LocalDateTime,而Java8里面新出来了一些API,LocalDate、LocalTime、LocalDateTime ,但是在默认的情况下,在mybatis里面不支持java8的时间、日期
解决方法:
更改bean类中的类型:
后台系统退出功能
@PostMapping("/logout")
public R<String> logout(HttpServletRequest request){
//清理Session 中保存得当前登录员工的 id
request.getSession().removeAttribute("employee");
return R.success("退出成功");
}
测试
业务开发Day 2
完善登录功能
/**
* 检查用户是否已经完成登录
*/
@WebFilter(filterName = "loginCheckFilter",urlPatterns = "/*")
@Slf4j
public class LoginCheckFilter implements Filter{
//路径匹配器,支持通配符
public static final AntPathMatcher PATH_MATCHER = new AntPathMatcher();
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
//1、获取本次请求的URI
String requestURI = request.getRequestURI();// /backend/index.html
log.info("拦截到请求:{}",requestURI);
//定义不需要处理的请求路径
String[] urls = new String[]{
"/employee/login",
"/employee/logout",
"/backend/**",
"/front/**"
};
//2、判断本次请求是否需要处理
boolean check = check(urls, requestURI);
//3、如果不需要处理,则直接放行
if(check){
log.info("本次请求{}不需要处理",requestURI);
filterChain.doFilter(request,response);
return;
}
//4、判断登录状态,如果已登录,则直接放行
if(request.getSession().getAttribute("employee") != null){
log.info("用户已登录,用户id为:{}",request.getSession().getAttribute("employee"));
filterChain.doFilter(request,response);
return;
}
log.info("用户未登录");
//5、如果未登录则返回未登录结果,通过输出流方式向客户端页面响应数据
response.getWriter().write(JSON.toJSONString(R.error("NOTLOGIN")));
return;
}
/**
* 路径匹配,检查本次请求是否需要放行
* @param urls
* @param requestURI
* @return
*/
public boolean check(String[] urls,String requestURI){
for (String url : urls) {
boolean match = PATH_MATCHER.match(url, requestURI);
if(match){
return true;
}
}
return false;
}
}
新增员工
- 在EmployeeController中创建新增员工的方法
@PostMapping
public R<String> save(HttpServletRequest request,@RequestBody Employee employee){
log.info("新增员工,员工信息:{}",employee.toString());
//设置初始密码123456, 需要进行md5加密处理
employee.setPassword(DigestUtils.md5DigestAsHex("123456".getBytes()));
employee.setCreateTime(new Date());
employee.setUpdateTime(new Date());
// 获取当前登录用户的id
Long empId= (Long) request.getSession().getAttribute("employee");
employee.setCreateUser(empId);
employee.setUpdateUser(empId);
employeeService.save(employee);
// try {
// employeeService.save(employee);
// } catch (Exception e) {
// R.error("新增员工失败");
// }
return R.success("新增员工成功");
}
@ControllerAdvice(annotations = {RestController.class, Controller.class})
@ResponseBody
@Slf4j
public class GlobalExceptionHandler {
/**
* 异常处理方法
* @param ex
* @return
*/
@ExceptionHandler(SQLIntegrityConstraintViolationException.class)
public R<String> 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("未知错误");
}
}
员工信息分页查询
/**
* 配置mybatisConfig分页插件
*/
@Configuration
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor(){
MybatisPlusInterceptor mybatisPlusInterceptor=new MybatisPlusInterceptor();
mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());
return mybatisPlusInterceptor;
}
}
/**
* 分页处理
* @param page
* @param pageSize
* @param name
* @return
*/
@GetMapping("/page")
public R<Page> page(int page,int pageSize,String name){
log.info("page={},pageSize={},name={}",page,pageSize,name);
// 构造分页构造器
Page pageInfo=new Page(page,pageSize);
// 构造条件构造器
LambdaQueryWrapper<Employee> queryWrapper=new LambdaQueryWrapper<>();
// 添加过滤条件
queryWrapper.like(StringUtils.isNotEmpty(name),Employee::getName,name);
// 添加排序条件
queryWrapper.orderByDesc(Employee::getUpdateTime);
// 执行查询
employeeService.page(pageInfo,queryWrapper);
return R.success(pageInfo);
}
启用/禁用员工账号
/**
* 根据id修改员工信息
* @param request
* @param employee
* @return
*/
@PutMapping
public R<String> update(HttpServletRequest request,@RequestBody Employee employee){
log.info(employee.toString());
Long empId= (Long) request.getSession().getAttribute("employee");
employee.setUpdateTime(new Date());
employee.setUpdateUser(empId);
employeeService.updateById(employee);
return R.success("员工信息修改成功");
}
/**
* 对象映射器:基于jackson将Java对象转为json,或者将json转为Java对象
* 将JSON解析为Java对象的过程称为 [从JSON反序列化Java对象]
* 从Java对象生成JSON的过程称为 [序列化Java对象到JSON]
*/
public class JacksonObjectMapper extends ObjectMapper {
public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd";
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);
}
}
/**
* 扩展mvc框架的消息转换器
* @param converters
*/
@Override
protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
log.info("扩展消息转换器...");
//创建消息转换器对象
MappingJackson2HttpMessageConverter messageConverter = new MappingJackson2HttpMessageConverter();
//设置对象转换器,底层使用Jackson将Java对象转为json
messageConverter.setObjectMapper(new JacksonObjectMapper());
//将上面的消息转换器对象追加到mvc框架的转换器集合中
converters.add(0,messageConverter);
}
编辑员工信息
/**
* 根据id查询员工信息
* @param id
* @return
*/
@GetMapping("/{id}")
public R<Employee> getById(@PathVariable Long id){
log.info("根据id查询员工信息...");
Employee employee=employeeService.getById(id);
if (employee!=null){
return R.success(employee);
}
return R.error("没有查询到对应员工信息");
}
业务开发Day 03
公共字段自动填充
@Component
@Slf4j
public class MyMetaObjectHandler implements MetaObjectHandler {
/**
* 插入操作,自动填充
* @param metaObject
*/
@Override
public void insertFill(MetaObject metaObject) {
log.info("公共字段自动填充[insert]...");
log.info(metaObject.toString());
metaObject.setValue("createTime", new Date());
metaObject.setValue("updateTime", new Date());
metaObject.setValue("createUser", BaseContext.getCurrentId());
metaObject.setValue("updateUser", BaseContext.getCurrentId());
}
/**
* 更新操作,自动填充
* @param metaObject
*/
@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", new Date());
metaObject.setValue("updateUser", BaseContext.getCurrentId());
}
}
/**
* 新增员工
* @param request
* @param employee
* @return
*/
@PostMapping
public R<String> save(HttpServletRequest request,@RequestBody Employee employee){
log.info("新增员工,员工信息:{}",employee.toString());
//设置初始密码123456, 需要进行md5加密处理
employee.setPassword(DigestUtils.md5DigestAsHex("123456".getBytes()));
employeeService.save(employee);
return R.success("新增员工成功");
}
/**
* 基于 ThreadLocal 封装工具类 ,用户保存和获取当前登录用户id
*/
public class BaseContext {
private static ThreadLocal<Long> threadLocal=new ThreadLocal<>();
/**
* 设置值
* @param id
*/
public static void setCurrentId(Long id){
threadLocal.set(id);
}
/**
* 获取值
* @return
*/
public static Long getCurrentId(){
return threadLocal.get();
}
}
//4、判断登录状态,如果已登录,则直接放行
if(request.getSession().getAttribute("employee") != null){
log.info("用户已登录,用户id为:{}",request.getSession().getAttribute("employee"));
Long empId= (Long) request.getSession().getAttribute("employee");
BaseContext.setCurrentId(empId);
filterChain.doFilter(request,response);
return;
}
/**
* 更新操作,自动填充
* @param metaObject
*/
@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", new Date());
metaObject.setValue("updateUser", BaseContext.getCurrentId());
}
新增分类
@PostMapping
public R<String> save(@RequestBody Category category){
log.info("category:{}",category);
categoryService.save(category);
return R.success("新增分类成功");
}
分类信息分页查询
@GetMapping("/page")
public R<Page> page(int page,int pageSize){
//分页构造器
Page<Category> pageInfo=new Page<Category>();
//条件构造器
LambdaQueryWrapper<Category> queryWrapper=new LambdaQueryWrapper<>();
//添加排序条件,根据sort进行排序
queryWrapper.orderByAsc(Category::getSort);
//分页查询
categoryService.page(pageInfo,queryWrapper);
return R.success(pageInfo);
}
删除分类
@DeleteMapping
public R<String> delete(Long id){
log.info("删除分类:{}",id);
categoryService.removeById(id);
return R.success("分类删除成功");
}
public class CustomException extends RuntimeException{
public CustomException(String message){
super(message);
}
}
public interface CategoryService extends IService<Category> {
public void remove(Long id);
}
@Service
public class CategoryServiceImpl extends ServiceImpl<CategoryMapper, Category> implements CategoryService {
@Autowired
private DishService dishService;
@Autowired
private SetmealService setmealService;
@Override
public void remove(Long id) {
LambdaQueryWrapper<Dish> dishLambdaQueryWrapper=new LambdaQueryWrapper<>();
//添加查询条件,根据分类id进行查询
dishLambdaQueryWrapper.eq(Dish::getCategoryId,id);
int count1=dishService.count(dishLambdaQueryWrapper);
//查询当前分类是否关联了菜品,如果已经关联,抛出一个业务一场
if (count1>0){
//已经关联菜品,抛出一个业务一场
throw new CustomException("当前分类下 关联了菜品,不能删除");
}
//查询当前分类是否关联了套餐,如果已经关联,抛出一个业务
LambdaQueryWrapper<Setmeal> setmealLambdaQueryWrapper=new LambdaQueryWrapper<>();
//添加查询条件,根据分类id进行查询
setmealLambdaQueryWrapper.eq(Setmeal::getCategoryId,id);
int count2=setmealService.count(setmealLambdaQueryWrapper);
if (count2>0){
//已经关联套餐,抛出一个业务异常
throw new CustomException("当前分类下关联了套餐,不能删除");
}
//正常删除分类
super.removeById(id);
}
}
业务开发Day 4
文件上传下载
/**
* 文件上传
* @param file
* @return
*/
@PostMapping("/upload")
public R<String> upload(MultipartFile file){
//file是一个临时文件,需要转存到指定位置,否则本次请求完成后临时文件会删除
log.info(file.toString());
//原始文件名
String originalFilename=file.getOriginalFilename();
String suffix=originalFilename.substring(originalFilename.lastIndexOf("."));
//使用UUID重新生成文件名,方式文件名称重复造成文件覆盖
String fileName= UUID.randomUUID().toString()+suffix;
//创建一个目录对象
File dir=new File(basPath);
//判断当前目录是否存在
if (!dir.exists()){
//目录不存在,需要创建
dir.mkdirs();
}
try {
// 将临时文件转存到指定位置
file.transferTo(new File(basPath+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(basPath+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();
}
}
新增菜品
/**
菜品
*/
@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 Date createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date updateTime;
@TableField(fill = FieldFill.INSERT)
private Long createUser;
@TableField(fill = FieldFill.INSERT_UPDATE)
private Long updateUser;
}
/**
菜品口味
*/
@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 Date createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date updateTime;
@TableField(fill = FieldFill.INSERT)
private Long createUser;
@TableField(fill = FieldFill.INSERT_UPDATE)
private Long updateUser;
//是否删除
private Integer isDeleted;
}
@GetMapping("/list")
public R<List<Category>> list(Category category){
log.info("category:{}",category);
//条件构造器
LambdaQueryWrapper<Category> queryWrapper=new LambdaQueryWrapper<>();
queryWrapper.eq(null!=(category.getType()),Category::getType,category.getType());
queryWrapper.orderByAsc(Category::getSort).orderByDesc(Category::getUpdateTime);
return R.success(categoryService.list(queryWrapper));
}
@Data
public class DishDto extends Dish {
private List<DishFlavor> flavors = new ArrayList<>();
private String categoryName;
private Integer copies;
}
@PostMapping
public R<String> save(@RequestBody DishDto dish){
log.info("dish:{}",dish);
return R.success("新增菜品成功");
}
@Autowired
private DishFlavorService dishFlavorService;
@Transactional
public void saveWithFlavor(DishDto dish) {
//保存菜品信息,向dish表 插入数据
this.save(dish);
//菜品口味
List<DishFlavor> flavors= dish.getFlavors();
flavors=flavors.stream().map(item->{
item.setDishId(dish.getId());
return item;
}).collect(Collectors.toList());
//批量保存菜品口味数据,向dish_flavor表插入数据
dishFlavorService.saveBatch(flavors);
}
/**
* 新增菜品
* @param dish
* @return
*/
@PostMapping
public R<String> save(@RequestBody DishDto dish){
log.info("dish:{}",dish);
dishService.saveWithFlavor(dish);
return R.success("新增菜品成功");
}
菜品信息分页查询
@GetMapping("/page")
public R<Page> page(Dish dish,int page,int pageSize){
log.info("page:{} pageSize:{} dish:{}",page,pageSize,dish);
//分页构造器
Page<Dish> buildPage=new Page(page,pageSize);
//条件构造器
LambdaQueryWrapper<Dish> queryWrapper=new LambdaQueryWrapper();
queryWrapper.like(StringUtils.isNotEmpty(dish.getName()),Dish::getName,dish.getName());
queryWrapper.orderByDesc(Dish::getUpdateTime);
//执行分页
dishService.page(buildPage,queryWrapper);
Page<DishDto> resPage=new Page(page,pageSize);
BeanUtils.copyProperties(buildPage,resPage,"records");
resPage.setRecords(buildPage.getRecords().stream().map(item->{
DishDto dishDto=new DishDto();
BeanUtils.copyProperties(item,dishDto);
Category category=categoryService.getById(item.getCategoryId());
if(category!=null){
dishDto.setCategoryName(category.getName());
}
return dishDto;
}).collect(Collectors.toList()));
//返回结果
return R.success(resPage);
}
修改菜品
@GetMapping("/list")
public R<List<Category>> list(Category category){
log.info("category:{}",category);
//条件构造器
LambdaQueryWrapper<Category> queryWrapper=new LambdaQueryWrapper<>();
queryWrapper.eq(null!=(category.getType()),Category::getType,category.getType());
queryWrapper.orderByAsc(Category::getSort).orderByDesc(Category::getUpdateTime);
return R.success(categoryService.list(queryWrapper));
}
public interface DishService extends IService<Dish> {
void saveWithFlavor(DishDto dish);
void updateWithFlavor(DishDto dish);
DishDto getByIdWithFlavor(Long id);
}
@GetMapping("/{id}")
public R<DishDto> get(@PathVariable Long id){
DishDto dish=dishService.getByIdWithFlavor(id);
if (dish!=null){
return R.success(dish);
}else {
return R.error("没有找到该对象");
}
}
@GetMapping("/download")
public void download(String name, HttpServletResponse response){
//输入流,通过输入流读取文件内容
try {
FileInputStream fileInputStream=new FileInputStream(new File(basPath+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();
}
}
@Override
@Transactional
public void updateWithFlavor(DishDto dishDto) {
//更新dish表基本信息
this.updateById(dishDto);
//清理当前菜品对应口味数据---dish_flavor表的delete操作
LambdaQueryWrapper<DishFlavor> queryWrapper = new LambdaQueryWrapper();
queryWrapper.eq(DishFlavor::getDishId,dishDto.getId());
dishFlavorService.remove(queryWrapper);
//添加当前提交过来的口味数据---dish_flavor表的insert操作
List<DishFlavor> flavors = dishDto.getFlavors();
flavors = flavors.stream().map((item) -> {
item.setDishId(dishDto.getId());
return item;
}).collect(Collectors.toList());
dishFlavorService.saveBatch(flavors);
}
/**
* 修改菜品
* @param dishDto
* @return
*/
@PutMapping
public R<String> update(@RequestBody DishDto dishDto){
log.info(dishDto.toString());
dishService.updateWithFlavor(dishDto);
return R.success("新增菜品成功");
}
业务开发Day5(上)
新增套餐
@GetMapping("/list")
public R<List<Category>> list(Category category){
log.info("category:{}",category);
//条件构造器
LambdaQueryWrapper<Category> queryWrapper=new LambdaQueryWrapper<>();
queryWrapper.eq(null!=(category.getType()),Category::getType,category.getType());
queryWrapper.orderByAsc(Category::getSort).orderByDesc(Category::getUpdateTime);
return R.success(categoryService.list(queryWrapper));
}
@GetMapping("/list")
public R<List<Category>> list(Category category){
log.info("category:{}",category);
//条件构造器
LambdaQueryWrapper<Category> queryWrapper=new LambdaQueryWrapper<>();
queryWrapper.eq(null!=(category.getType()),Category::getType,category.getType());
queryWrapper.orderByAsc(Category::getSort).orderByDesc(Category::getUpdateTime);
return R.success(categoryService.list(queryWrapper));
}
@GetMapping("/list")
public R<List<Dish>> list(Dish dish){
//构造查询条件
LambdaQueryWrapper<Dish> queryWrapper=new LambdaQueryWrapper<>();
queryWrapper.eq(dish.getCategoryId()!=null,Dish::getCategoryId,dish.getCategoryId());
//添加条件,查询状态为 1 (起售状态) 的菜品
queryWrapper.eq(Dish::getStatus,1);
//添加排序 条件
queryWrapper.orderByAsc(Dish::getSort).orderByDesc(Dish::getUpdateTime);
List<Dish> list=dishService.list(queryWrapper);
return R.success(list);
}
/**
* 新增套餐
* @param setmealDto
* @return
*/
@PostMapping
public R<String> save(@RequestBody SetmealDto setmealDto){
log.info("setmeal:{}",setmealDto);
return R.success("新增套餐成功");
}
/**
* 新增套餐,同时需要保存套餐和菜品的关系
* @param setmealDto
*/
public void saveWithDish(SetmealDto setmealDto);
/**
* 新增套餐,同时需要关联菜品
* @param setmealDto
*/
@Override
@Transactional
public void saveWithDish(SetmealDto setmealDto) {
//保存套餐基本嘻嘻,操作setmeal表
this.save(setmealDto);
List<SetmealDish> setmealDishes=setmealDto.getSetmealDishes();
setmealDishes.stream().map(item->{
item.setSetmealId(setmealDto.getId());
return item;
}).collect(Collectors.toList());
//保存套餐和菜品关联信息,操作setmeal_dish表
setmealDishService.saveBatch(setmealDishes);
}
@PostMapping
public R<String> save(@RequestBody SetmealDto setmealDto){
log.info("setmeal:{}",setmealDto);
setmealService.saveWithDish(setmealDto);
return R.success("新增套餐成功");
}
套餐信息分页查询
@GetMapping("/page")
public R<Page> page(int page,int pageSize,String name){
//构造分页构造器对象
Page<Setmeal> pageInfo=new Page<>(page,pageSize);
Page<SetmealDto> setmealDtoPage=new Page<>();
//条件构造器
LambdaQueryWrapper<Setmeal> queryWrapper=new LambdaQueryWrapper<>();
//添加过滤条件
queryWrapper.like(name!=null,Setmeal::getName,name);
//添加排序条件
queryWrapper.orderByDesc(Setmeal::getUpdateTime);
//执行分页查询
setmealService.page(pageInfo,queryWrapper);
//对象拷贝
BeanUtils.copyProperties(pageInfo,setmealDtoPage,"records");
List<Setmeal> records=pageInfo.getRecords();
List<SetmealDto> list=records.stream().map(item->{
SetmealDto setmealDto=new SetmealDto();
BeanUtils.copyProperties(item,setmealDto);
Long categoryId=item.getCategoryId();//分类id
//根据id查询分类对象
Category category=categoryService.getById(categoryId);
if (category!=null){
String categoryName=category.getName();
setmealDto.setCategoryName(categoryName);
}
return setmealDto;
}).collect(Collectors.toList());
setmealDtoPage.setRecords(list);
return R.success(setmealDtoPage);
}
删除套餐
/**
* 删除套餐
* @param ids
* @return
*/
@DeleteMapping
public R delete(@RequestParam List<Long> ids){
log.info("删除套餐,id为:{}",ids);
setmealService.removeWithDish(ids);
return R.success("套餐数据删除成功");
}
/**
* 删除套餐,同时需要删除套餐和菜品的关系
* @param ids
*/
public void removeWithDish(List<Long> ids);
/**
* 删除套餐,同时需要删除套餐和菜品的关联数据
* @param ids
*/
@Override
@Transactional
public void removeWithDish(List<Long> ids) {
// select count(*) from setmeal wherer id in (1,2,3) and status=1
//查询套餐状态,确定是否可用删除
LambdaQueryWrapper<Setmeal> queryWrapper=new LambdaQueryWrapper<>();
queryWrapper.in(Setmeal::getId,ids);
queryWrapper.eq(Setmeal::getStatus,1);
int count=this.count(queryWrapper);
if (count>0){
//如果不能删除,抛出一个业务异常
throw new CustomException("套餐正在售卖中,无法删除");
}
//删除套餐数据,操作setmeal表,执行delete操作
this.removeByIds(ids);
// delete from setmeal_dish where setmeal_id in (1,2,3)
LambdaQueryWrapper<SetmealDish> removeWrapper=new LambdaQueryWrapper<>();
removeWrapper.in(SetmealDish::getSetmealId,ids);
//删除套餐和菜品关联数据,操作setmeal_dish 表,执行delete操作
setmealDishService.remove(removeWrapper);
}
/**
* 删除套餐
* @param ids
* @return
*/
@DeleteMapping
public R delete(@RequestParam List<Long> ids){
log.info("删除套餐,id为:{}",ids);
setmealService.removeWithDish(ids);
return R.success("套餐数据删除成功");
}
业务开发Day5(下)
短信发送
手机验证码登录
//定义不需要处理的请求路径
String[] urls = new String[]{
"/employee/login",
"/employee/logout",
"/backend/**",
"/front/**",
"/common/**",
"/user/sendMsg", //移动端发送短信
"/user/login" //移动端登录
};
//4-2、判断登录状态,如果已登录,则直接放行
if(request.getSession().getAttribute("user") != null){
log.info("用户已登录,用户id为:{}",request.getSession().getAttribute("user"));
Long userId= (Long) request.getSession().getAttribute("user");
BaseContext.setCurrentId(userId);
filterChain.doFilter(request,response);
return;
}
/**
* 发送验证码短信
* @param user
* @param session
* @return
*/
@PostMapping("/sendMsg")
public R<String> sendMsg(@RequestBody User user, HttpSession session){
//手机号
String phone=user.getPhone();
//生成随机验证码
String code= ValidateCodeUtils.generateValidateCode(4).toString();
log.info("验证码:{}",code);
//发送短信
SMSUtils.sendMessage("沙县地","SMS_159620392",phone,code);
//将验证码存入Session。方便后续登录时比对
session.setAttribute(phone,code);
return R.success("短信发送成功");
}
@PostMapping("/login")
public R<User> login(@RequestBody Map map, HttpSession session){
String phone=map.get("phone").toString();
String code=map.get("code").toString();
//从Session获取存储 的 验证码
Object codeInSession = session.getAttribute(phone);
if (codeInSession!=null && code.equals(codeInSession)){
LambdaQueryWrapper<User> queryWrapper=new LambdaQueryWrapper<>();
queryWrapper.eq(User::getPhone,phone);
User user=userService.getOne(queryWrapper);
if (user==null){//新用户,自动完成注册
user=new User();
user.setPhone(phone);
userService.save(user);
}
session.setAttribute("user",user.getId());
return R.success(user);
}
return R.error("登录失败");
}
业务开发Day6
导入用户地址簿相关功能代码
/**
* 地址簿管理
*/
@Slf4j
@RestController
@RequestMapping("/addressBook")
public class AddressBookController {
@Autowired
private AddressBookService addressBookService;
/**
* 新增
* @param addressBook
* @return
*/
@PostMapping
public R<AddressBook> save(@RequestBody AddressBook addressBook){
addressBook.setUserId(BaseContext.getCurrentId());
log.info("addressBook:{}",addressBook);
addressBookService.save(addressBook);
return R.success(addressBook);
}
/**
* 设置默认地址
* @param addressBook
* @return
*/
@PutMapping("default")
public R<AddressBook> setDefault(@RequestBody AddressBook addressBook) {
log.info("addressBook:{}", addressBook);
LambdaUpdateWrapper<AddressBook> wrapper = new LambdaUpdateWrapper<>();
wrapper.eq(AddressBook::getUserId, BaseContext.getCurrentId());
wrapper.set(AddressBook::getIsDefault, 0);
//SQL : update address_book set is_default = 0 where user_id=?
addressBookService.update(wrapper);
addressBook.setIsDefault(1);
//SQL: update address_book set is_default =1 where id =?
addressBookService.updateById(addressBook);
return R.success(addressBook);
}
/**
* 根据id查询地址
* @param id
* @return
*/
@GetMapping("/{id}")
public R get(@PathVariable Long id){
AddressBook addressBook=addressBookService.getById(id);
if (addressBook!=null){
return R.success(addressBook);
}else {
return R.error("没有找到该对象");
}
}
/**
* 查询默认地址
* @return
*/
@GetMapping("default")
public R<AddressBook> getDefault(){
LambdaQueryWrapper<AddressBook> queryWrapper =new LambdaQueryWrapper<>();
queryWrapper.eq(AddressBook::getUserId,BaseContext.getCurrentId());
queryWrapper.eq(AddressBook::getIsDefault,1);
//SQL:select * from address_book where user_id =? where is_default =1
AddressBook addressBook=addressBookService.getOne(queryWrapper);
if (null==addressBook){
return R.error("没有找到该对象");
}else {
return R.success(addressBook);
}
}
@GetMapping("/list")
public R<List<AddressBook>> list(AddressBook addressBook){
addressBook.setUserId(BaseContext.getCurrentId());
log.info("addressBook:{}",addressBook);
//条件构造器
LambdaQueryWrapper<AddressBook> queryWrapper=new LambdaQueryWrapper<>();
queryWrapper.eq(null!=addressBook.getUserId(),AddressBook::getUserId,addressBook.getUserId());
queryWrapper.orderByDesc(AddressBook::getUpdateTime);
//SQL: select * from address_book where user_id = ? order by update_time desc
return R.success(addressBookService.list(queryWrapper));
}
}
菜品展示
@GetMapping("/list")
public R<List<DishDto>> list(Dish dish){
//构造查询条件
LambdaQueryWrapper<Dish> queryWrapper=new LambdaQueryWrapper<>();
queryWrapper.eq(dish.getCategoryId()!=null,Dish::getCategoryId,dish.getCategoryId());
//添加条件,查询状态为1(起售状态) 的菜品
queryWrapper.eq(Dish::getStatus,1);
//添加排序条件
queryWrapper.orderByDesc(Dish::getSort).orderByDesc(Dish::getUpdateTime);
List<Dish> list=dishService.list(queryWrapper);
List<DishDto> dishDtoList=list.stream().map((item)->{
DishDto dishDto=new DishDto();
BeanUtils.copyProperties(item,dishDto);
Long categoryId=item.getCategoryId(); //分类id
//根据id查询分类对象
Category category=categoryService.getById(categoryId);
if (category!=null){
String categoryName=category.getName();
dishDto.setCategoryName(categoryName);
}
//当前菜品的id
Long dishId=item.getId();
LambdaQueryWrapper<DishFlavor> lambdaQueryWrapper=new LambdaQueryWrapper<>();
lambdaQueryWrapper.eq(DishFlavor::getDishId,dishId);
//SQL : select * from dish_flavor where dish_id=?
List<DishFlavor> dishFlavorsList=dishFlavorService.list(lambdaQueryWrapper);
dishDto.setFlavors(dishFlavorsList);
return dishDto;
}).collect(Collectors.toList());
return R.success(dishDtoList);
}
/**
* 根据条件查询套餐数据
* @param setmeal
* @return
*/
@GetMapping("/list")
public R<List<Setmeal>> list(Setmeal setmeal){
LambdaQueryWrapper<Setmeal> queryWrapper=new LambdaQueryWrapper<>();
queryWrapper.eq(setmeal.getCategoryId()!=null,Setmeal::getCategoryId,setmeal.getCategoryId());
queryWrapper.eq(setmeal.getStatus()!=null,Setmeal::getStatus,setmeal.getStatus());
queryWrapper.orderByDesc(Setmeal::getUpdateTime);
List<Setmeal> list=setmealService.list(queryWrapper);
return R.success(list);
}
购物车
/**
* 购物车
*/
@RestController
@Slf4j
@RequestMapping("/shoppingCart")
public class ShoppingCartController {
@Autowired
private ShoppingCartService shoppingCartService;
/**
* 添加购物车
* @param shoppingCart
* @return
*/
@PostMapping("/add")
public R<ShoppingCart> add(@RequestBody ShoppingCart shoppingCart){
log.info("购物车数据:{}",shoppingCart);
//设置用户id , 指定当前是哪个用户的购物车数据
Long currentId= BaseContext.getCurrentId();
shoppingCart.setUserId(currentId);
Long dishId=shoppingCart.getDishId();
LambdaQueryWrapper<ShoppingCart> queryWrapper=new LambdaQueryWrapper<>();
queryWrapper.eq(ShoppingCart::getUserId,currentId);
if (dishId!=null){
//添加到购物车的是菜品
queryWrapper.eq(ShoppingCart::getDishId,dishId);
}else {
//添加到购物车的套餐
queryWrapper.eq(ShoppingCart::getSetmealId,shoppingCart.getSetmealId());
}
//查询当前菜品或者套餐是否在购物车中
//SQL: select * from shoping_cart where user_id =? and dish_id/setmeal_id=?
ShoppingCart carServiceOne=shoppingCartService.getOne(queryWrapper);
if (carServiceOne!=null){
//如果已经存在,就在原来数量基础上加一
Integer number=carServiceOne.getNumber();
carServiceOne.setNumber(number+1);
shoppingCartService.updateById(carServiceOne);
}else {
//如果不存在,则添加到购物车,数量默认就是一
shoppingCart.setNumber(1);
shoppingCart.setCreateTime(new Date());
shoppingCartService.save(shoppingCart);
carServiceOne=shoppingCart;
}
return R.success(carServiceOne);
}
/**
* 查看购物车
* @return
*/
@GetMapping("/list")
public R<List<ShoppingCart>> list(){
log.info("查看购物车...");
LambdaQueryWrapper<ShoppingCart> queryWrapper=new LambdaQueryWrapper<>();
queryWrapper.eq(ShoppingCart::getUserId,BaseContext.getCurrentId());
queryWrapper.orderByAsc(ShoppingCart::getCreateTime);
List<ShoppingCart> list=shoppingCartService.list(queryWrapper);
return R.success(list);
}
@DeleteMapping("/clean")
public R<String> clean(){
//SQL: delete from shopping_cart where user_id =?
LambdaQueryWrapper<ShoppingCart> queryWrapper=new LambdaQueryWrapper<>();
queryWrapper.eq(ShoppingCart::getUserId,BaseContext.getCurrentId());
shoppingCartService.remove(queryWrapper);
return R.success("清空购物车成功");
}
}
下单
在OrderController 中 创建submit 方法:
@RestController
@RequestMapping("/order")
@Slf4j
public class OrderController {
@Autowired
private OrderService orderService;
/**
* 用户下单
* @param orders
* @return
*/
@PostMapping("/submit")
public R<String> submit(@RequestBody Orders orders){
log.info("订单数据:{}",orders);
orderService.submit(orders);
return R.success("下单成功");
}
}
在OrderService接口中扩展submit方法:
public interface OrderService extends IService<Orders> {
/**
* 用户下单
* @param orders
*/
public void submit(Orders orders);
}
在OderServiceImpl中实现submit方法
/**
* 用户下单
* @param orders
*/
@Transactional
public void submit(Orders orders) {
//获得当前用户id
Long userId = BaseContext.getCurrentId();
//查询当前用户的购物车数据
LambdaQueryWrapper<ShoppingCart> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(ShoppingCart::getUserId,userId);
List<ShoppingCart> shoppingCarts = shoppingCartService.list(wrapper);
if(shoppingCarts == null || shoppingCarts.size() == 0){
throw new CustomException("购物车为空,不能下单");
}
//查询用户数据
User user = userService.getById(userId);
//查询地址数据
Long addressBookId = orders.getAddressBookId();
AddressBook addressBook = addressBookService.getById(addressBookId);
if(addressBook == null){
throw new CustomException("用户地址信息有误,不能下单");
}
long orderId = IdWorker.getId();//订单号
AtomicInteger amount = new AtomicInteger(0);
List<OrderDetail> orderDetails = shoppingCarts.stream().map((item) -> {
OrderDetail orderDetail = new OrderDetail();
orderDetail.setOrderId(orderId);
orderDetail.setNumber(item.getNumber());
orderDetail.setDishFlavor(item.getDishFlavor());
orderDetail.setDishId(item.getDishId());
orderDetail.setSetmealId(item.getSetmealId());
orderDetail.setName(item.getName());
orderDetail.setImage(item.getImage());
orderDetail.setAmount(item.getAmount());
amount.addAndGet(item.getAmount().multiply(new BigDecimal(item.getNumber())).intValue());
return orderDetail;
}).collect(Collectors.toList());
orders.setId(orderId);
orders.setOrderTime(new Date());
orders.setCheckoutTime(new Date());
orders.setStatus(2);
orders.setAmount(new BigDecimal(amount.get()));//总金额
orders.setUserId(userId);
orders.setNumber(String.valueOf(orderId));
orders.setUserName(user.getName());
orders.setConsignee(addressBook.getConsignee());
orders.setPhone(addressBook.getPhone());
orders.setAddress((addressBook.getProvinceName() == null ? "" : addressBook.getProvinceName())
+ (addressBook.getCityName() == null ? "" : addressBook.getCityName())
+ (addressBook.getDistrictName() == null ? "" : addressBook.getDistrictName())
+ (addressBook.getDetail() == null ? "" : addressBook.getDetail()));
//向订单表插入数据,一条数据
this.save(orders);
//向订单明细表插入数据,多条数据
orderDetailService.saveBatch(orderDetails);
//清空购物车数据
shoppingCartService.remove(wrapper);
}