关于一个后台管理新增分类的功能实现(学习记录)

自动填充和自定义异常处理在Spring Boot中的应用

在现代的企业级应用中,我们经常需要自动填充一些公共字段(例如创建时间、更新时间等)和进行自定义的异常处理。本文将介绍如何在Spring Boot中实现这些功能。具体示例包括自动填充功能的实现、通过ThreadLocal保存当前用户信息、以及处理特定业务逻辑中的自定义异常。

自动填充公共字段

在企业应用中,数据库表通常包含创建时间(createTime)、更新时间(updateTime)等字段。我们可以通过自动填充功能,在插入和更新数据时自动设置这些字段,避免重复开发。下面是一个示例代码:

MetaObjectHandler实现类 

@Component
@Slf4j
public class MyMetaObjectHandler implements MetaObjectHandler {
    Date now = new Date();

    @Override
    public void insertFill(MetaObject metaObject) {
        log.info("进入自动插入方法");
        metaObject.setValue("createTime", now);
        metaObject.setValue("updateTime", now);
        metaObject.setValue("createUser", BaseThreadLocal.getCurrentId());
        metaObject.setValue("updateUser", BaseThreadLocal.getCurrentId());
    }

    @Override
    public void updateFill(MetaObject metaObject) {
        metaObject.setValue("updateTime", now);
        metaObject.setValue("updateUser", BaseThreadLocal.getCurrentId());
    }
}

 

使用ThreadLocal保存当前用户信息

为了在自动填充时获取当前用户的ID,我们可以使用ThreadLocal类。ThreadLocal为每个线程提供一个独立的变量副本,从而实现线程之间的隔离。

BaseThreadLocal类
package org.example.result;

public class BaseThreadLocal {
    private static ThreadLocal<Long> threadLocal = new ThreadLocal<>();

    public static void setCurrentId(Long id) {
        threadLocal.set(id);
    }

    public static Long getCurrentId() {
        return threadLocal.get();
    }
}

 而这里的id可以从拦截器里进行拦截获取,拦截器代码实例:

package org.example.Filter;


import jakarta.servlet.*;
import jakarta.servlet.annotation.WebFilter;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.example.result.BaseThreadLocal;
import org.example.result.R;
import org.springframework.util.AntPathMatcher;

import javax.swing.plaf.PanelUI;
import java.io.IOException;
import com.alibaba.fastjson.JSON;

@WebFilter(filterName = "LoginFilter", urlPatterns = "/*")
public class LoginFilter implements Filter {
    //路径匹配器
    public static final AntPathMatcher PATH_MATCHER = new AntPathMatcher();

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest servletRequest1 = (HttpServletRequest) servletRequest;
        HttpServletResponse servletResponse1 = (HttpServletResponse) servletResponse;
//        1获取本次请求的url
        String requestURI = servletRequest1.getRequestURI();
        //不需要拦截的路径
        String[] urls = new String[]{
                "/employee/login",
                "/employee/logout",
                "/backend/**",
                "/front/**"
        };
//        3. 匹配路径看是否是未登录
        boolean check = check(urls, requestURI);
        if (check) {
            filterChain.doFilter(servletRequest1, servletResponse1);
            return;
        }
//        4.判断登录状态,如果已登录,则直接放行
        if (servletRequest1.getSession().getAttribute("employee") !=null) {
          Long  empid= (Long) servletRequest1.getSession().getAttribute("employee");

          //调用ThreadLocal工具类将id传过去************
            BaseThreadLocal.setCurrentId(empid);
          //**************
            filterChain.doFilter(servletRequest1, servletResponse1);
            return;
        }
//        5.如果未登录则返回登录结果,前端会判断登录返回的信息去跳转登录页面
        servletResponse1.getWriter().write(JSON.toJSONString(R.error("NOTLOGIN")));
        return;
    }

    public boolean check(String[] urls, String requestURL) {

        for (String url : urls) {
            boolean match = PATH_MATCHER.match(url, requestURL);
            if (match) {
                return true;
            }

        }
        return false;

    }

}

控制层示例

以下是一个控制层示例,展示如何处理分类相关的请求,包括新增、分页查询、删除和更新操作。

CategoryController类
package org.example.controller;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import org.example.pojo.Category;
import org.example.result.R;
import org.example.service.CategoryService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/category")
@Slf4j
public class CategoryController {
    @Autowired
    private CategoryService categoryService;

    @PostMapping
    public R<String> save(@RequestBody Category category) {
        categoryService.save(category);
        return R.success("新增成功");
    }

    @GetMapping("/page")
    public R<Page> page(int page, int pageSize) {
        Page pageInfo = new Page(page, pageSize);
        LambdaQueryWrapper<Category> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.orderByAsc(Category::getSort);
        categoryService.page(pageInfo, queryWrapper);
        return R.success(pageInfo);
    }

    @DeleteMapping
    public R<String> delete(Long ids) {
        categoryService.remove(ids);
        return R.success("删除成功");
    }

    @PutMapping
    public R<String> update(@RequestBody Category category) {
        categoryService.updateById(category);
        return R.success("修改成功");
    }
}

 

自定义异常处理

在业务处理中,我们经常需要根据特定条件抛出自定义异常。例如,当分类关联了菜品或套餐时,禁止删除分类。

自定义异常类
package org.example.result;

public class CustonException extends RuntimeException {
    public CustonException(String message) {
        super(message);
    }
}

 CategoryService实现类

package org.example.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.example.pojo.Category;
import org.example.pojo.Dish;
import org.example.pojo.Setmeal;
import org.example.result.CustonException;
import org.example.service.CategoryService;
import org.example.mapper.CategoryMapper;
import org.example.service.DishService;
import org.example.service.SetmealService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class CategoryServiceImpl extends ServiceImpl<CategoryMapper, Category> implements CategoryService {
    @Autowired
    private DishService dishService;
    @Autowired
    private SetmealService setmealService;

    @Override
    public void remove(Long id) {
        LambdaQueryWrapper<Dish> dishQueryWrapper = new LambdaQueryWrapper<>();
        dishQueryWrapper.eq(Dish::getCategoryId, id);
        int dishCount = dishService.count(dishQueryWrapper);
        if (dishCount > 0) {
            throw new CustonException("当前分类关联了菜品,不能删除");
        }

        LambdaQueryWrapper<Setmeal> setmealQueryWrapper = new LambdaQueryWrapper<>();
        setmealQueryWrapper.eq(Setmeal::getCategoryId, id);
        int setmealCount = setmealService.count(setmealQueryWrapper);
        if (setmealCount > 0) {
            throw new CustonException("当前分类关联了套餐,不能删除");
        }

        super.removeById(id);
    }
}

 

总结

通过上述代码示例,我们展示了如何在Spring Boot应用中实现自动填充功能、使用ThreadLocal保存当前用户信息、以及自定义异常处理。这样的实现不仅提高了代码的可维护性和可读性,也增强了系统的健壮性和安全性。在实际项目中,可以根据业务需求灵活应用这些技术,提升开发效率。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值