SpringBoot+Vue+Mysql苍穹外卖

一.项目介绍

1.项目内容

苍穹外卖是一款为大学学子设计的校园外卖服务软件,旨在提供便捷的食堂外卖送至宿舍的服务。该软件包含系统管理后台和用户端(微信小程序)两部分,支持在线浏览菜品、添加购物车、下单等功能,并由学生兼职提供跑腿送餐服务。

2.技术栈

SpringBoot+Vue+Mybatis+Mysql+Redis+Nginx

3.Nginx

网页-->nginx-->服务器

nginx反向代理优势:

1.提高访问速度(nginx可以做缓存)

2.进行负载均衡(将大量请求均匀分发请求)

3.保证后端服务的安全

        # 反向代理,处理管理端发送的请求location /api/ {proxy_pass   http://localhost:8080/admin/;#proxy_pass   http://webservers/admin/;}# 反向代理,处理用户端发送的请求location /user/ {proxy_pass   http://webservers/user/;}

4.Swagger

  @Beanpublic Docket docket() {log.info("准备生成接口文档");ApiInfo apiInfo = new ApiInfoBuilder().title("苍穹外卖项目接口文档").version("2.0").description("苍穹外卖项目接口文档").build();Docket docket = new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo).select().apis(RequestHandlerSelectors.basePackage("com.sky.controller")).paths(PathSelectors.any()).build();return docket;}

常用注解

二.具体实现

一.登录功能

用户注册,输入密码-->对密码进行md5加密进行存储-->用户进行登录,密文解码进行比对

    @PostMapping("/login")public Result<EmployeeLoginVO> login(@RequestBody EmployeeLoginDTO employeeLoginDTO) {log.info("员工登录:{}", employeeLoginDTO);Employee employee = employeeService.login(employeeLoginDTO);//登录成功后,生成jwt令牌Map<String, Object> claims = new HashMap<>();claims.put(JwtClaimsConstant.EMP_ID, employee.getId());String token = JwtUtil.createJWT(jwtProperties.getAdminSecretKey(),jwtProperties.getAdminTtl(),claims);EmployeeLoginVO employeeLoginVO = EmployeeLoginVO.builder().id(employee.getId()).userName(employee.getUsername()).name(employee.getName()).token(token).build();return Result.success(employeeLoginVO);}public Employee login(EmployeeLoginDTO employeeLoginDTO) {String username = employeeLoginDTO.getUsername();String password = employeeLoginDTO.getPassword();//1、根据用户名查询数据库中的数据Employee employee = employeeMapper.getByUsername(username);//2、处理各种异常情况(用户名不存在、密码不对、账号被锁定)if (employee == null) {//账号不存在throw new AccountNotFoundException(MessageConstant.ACCOUNT_NOT_FOUND);}//密码比对,先进行md5加密再进行密码比较password = DigestUtils.md5DigestAsHex(password.getBytes());if (!password.equals(employee.getPassword())) {//密码错误throw new PasswordErrorException(MessageConstant.PASSWORD_ERROR);}if (employee.getStatus() == StatusConstant.DISABLE) {//账号被锁定throw new AccountLockedException(MessageConstant.ACCOUNT_LOCKED);}//3、返回实体对象return employee;}
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {//判断当前拦截到的是Controller的方法还是其他资源if (!(handler instanceof HandlerMethod)) {//当前拦截到的不是动态方法,直接放行return true;}//1、从请求头中获取令牌String token = request.getHeader(jwtProperties.getAdminTokenName());//2、校验令牌try {log.info("jwt校验:{}", token);Claims claims = JwtUtil.parseJWT(jwtProperties.getAdminSecretKey(), token);Long empId = Long.valueOf(claims.get(JwtClaimsConstant.EMP_ID).toString());log.info("当前员工id:", empId);BaseContext.setCurrentId(empId);//3、通过,放行return true;} catch (Exception ex) {//4、不通过,响应401状态码response.setStatus(401);return false;}}

二.公共字段自动填充

自定义注解AutoFill,用于标识需要公共字段自定义填充的方法
自定义切面类AutoFillAspect,统一拦截加入了AutoFill注解的方法,通过反射为公共字段赋值
在Mapper上加入AutoFill注解public enum OperationType {UPDATE,INSERT
}@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AutoFill {OperationType value();
}@Aspect
@Component
@Slf4j
public class AutoFillAspect {/*** 切入点*/@Pointcut("execution(* com.sky.mapper.*.*(..)) && @annotation(com.sky.annotation.AutoFill)")public void AutoFillCut() {}/*** 前置通知,为公共字段进行赋值*/@Before("AutoFillCut()")public void AutoFill(JoinPoint joinPoint) throws Exception {log.info("AutoFill start");//获取当前数据库操作的类型MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();AutoFill autoFill = methodSignature.getMethod().getAnnotation(AutoFill.class);OperationType operationType = autoFill.value();//获取当前被拦截方法的操作实体Object[] args = joinPoint.getArgs();if(args == null || args.length == 0) {return;}Object entity=args[0];//准备赋值的数据LocalDateTime now= LocalDateTime.now();Long currentId = BaseContext.getCurrentId();//为实体进行赋值if (operationType == OperationType.INSERT) {Method setCrateTime= entity.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_TIME, LocalDateTime.class);Method setCrateUser=entity.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_USER, Long.class);Method setUpdateTime=entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);Method setUpdateUser=entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);setCrateTime.invoke(entity,now);setCrateUser.invoke(entity,currentId);setUpdateTime.invoke(entity,now);setUpdateUser.invoke(entity,currentId);} else if (operationType == OperationType.UPDATE) {Method setUpdateTime=entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);Method setUpdateUser=entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);setUpdateTime.invoke(entity,now);setUpdateUser.invoke(entity,currentId);}}
}

三.员工管理

新增员工
@PostMapping
@ApiOperation("新增员工")
public Result save(@RequestBody EmployeeDTO employeeDTO) {log.info("新增员工{}",employeeDTO);employeeService.save(employeeDTO);return Result.success();
}void save(EmployeeDTO employeeDTO);
public void save(EmployeeDTO employeeDTO) {Employee employee  = new Employee();//对象属性拷贝BeanUtils.copyProperties(employeeDTO,employee);employee.setStatus(StatusConstant.ENABLE);employee.setPassword(DigestUtils.md5DigestAsHex(PasswordConstant.DEFAULT_PASSWORD.getBytes()));employee.setCreateTime(LocalDateTime.now());employee.setUpdateTime(LocalDateTime.now());//设置当前记录人的id//TODO 后期改为当前用户的idemployee.setCreateUser(10L);employee.setUpdateUser(10L);employeeMapper.insert(employee);}@Insert("INSERT INTO employee(name, username, password, phone, sex, id_number, create_time, update_time, create_user, update_user, status) " +"VALUES (#{name}, #{username}, #{password}, #{phone}, #{sex}, #{idNumber}, #{createTime}, #{updateTime}, #{createUser}, #{updateUser}, #{status})")void insert(Employee employee);@ExceptionHandlerpublic Result exceptionHandler(SQLIntegrityConstraintViolationException ex){String message =  ex.getMessage();if (message.contains("Duplicate entry")){String[] split = message.split(" ");String username = split[2];String msg = username + MessageConstant.ALREADY_EXIST;return Result.error(msg);}else{return Result.error(MessageConstant.UNKNOWN_ERROR);}}ThreadLocal
它为每个线程提供了一个独立的变量副本,使得每个线程可以独立地访问和修改自己的变量副本
一个请求一个线程
public class BaseContext {public static ThreadLocal<Long> threadLocal = new ThreadLocal<>();public static void setCurrentId(Long id) {threadLocal.set(id);}public static Long getCurrentId() {return threadLocal.get();}public static void removeCurrentId() {threadLocal.remove();}
}
拦截器
BaseContext.setCurrentId(empId);
//新增员工时设置当前记录人的id
employee.setCreateUser(BaseContext.getCurrentId());
employee.setUpdateUser(BaseContext.getCurrentId());
查询员工
PageHelper 是一个基于 MyBatis 的分页插件,用于简化分页查询的实现。
它通过 MyBatis 的拦截器机制,自动在 SQL 查询中添加分页逻辑.@GetMapping("/page")@ApiOperation("员工分页查询")public Result<PageResult> page(EmployeePageQueryDTO employeePageQueryDTO) {log.info("查询员工{}",employeePageQueryDTO);PageResult pageResult = employeeService.page(employeePageQueryDTO);return Result.success(pageResult);}PageResult page(EmployeePageQueryDTO employeePageQueryDTO);
@Override
public PageResult page(EmployeePageQueryDTO employeePageQueryDTO) {//开始分页查询PageHelper.startPage(employeePageQueryDTO.getPage(),employeePageQueryDTO.getPageSize());Page<Employee> page = employeeMapper.pageQuery(employeePageQueryDTO);long total = page.getTotal();List<Employee> records = page.getResult();return new PageResult(total,records);}Page<Employee> pageQuery(EmployeePageQueryDTO employeePageQueryDTO);
<select id="pageQuery" resultType="com.sky.entity.Employee">select * from employee<where><if test="name != null and name != ''">and name like concat('%',#{name},'%')</if></where>order by create_time desc
</select>
编辑员工
@PutMapping@ApiOperation("修改员工信息")public Result update(@RequestBody EmployeeDTO employeedao) {employeeService.update(employeedao);return Result.success();}void update(EmployeeDTO employee);
@Override
public void update(EmployeeDTO employeedao) {Employee employee = new Employee();BeanUtils.copyProperties(employeedao,employee);employee.setUpdateTime(LocalDateTime.now());employee.setUpdateUser(BaseContext.getCurrentId());employeeMapper.update(employee);
}<update id="update" parameterType="Employee">update employee<set><if test="name!=null">name = #{name},</if><if test="username!=null">username = #{username},</if><if test="password!=null">password = #{password},</if><if test="phone!=null">phone = #{phone},</if><if test="sex!=null">sex = #{sex},</if><if test="idNumber!=null">id_number = #{idNumber},</if><if test="updateTime!=null">update_time = #{updateTime},</if><if test="updateUser!=null">update_user = #{updateUser},</if><if test="status!=null">status = #{status}, </if></set>where id = #{id}</update>

四.菜品管理

新增菜品
@PostMapping
@ApiOperation("新增菜品")
public Result save(@RequestBody DishDTO dishdao) {log.info("新增菜品{}",dishdao);dishService.saveWithFlavor(dishdao);return Result.success();
}public void saveWithFlavor(DishDTO dishdao);
@PostMapping
@Override
@Transactional
public void saveWithFlavor(DishDTO dishdao) {//向菜品表插入1条数据Dish dish = new Dish();BeanUtils.copyProperties(dishdao, dish);dishMapper.insert(dish);//向口味表插入n条数据//获取insert语句的主键值long  dish_id = dish.getId();List<DishFlavor> flavors=dishdao.getFlavors();if (flavors!=null&&flavors.size()>0){flavors.forEach(dishFlavor -> dishFlavor.setDishId(dish_id));dishFloarMapper.insertBatch(flavors);}
}@AutoFill(OperationType.INSERT)
void insert(Dish dish);
<insert id="insert" useGeneratedKeys="true" keyProperty="id">insert into dish(name,category_id,price,image,description,status,create_time,update_time,create_user,update_user)values(#{name},#{categoryId},#{price},#{image},#{description},#{status},#{createTime},#{updateTime},#{createUser},#{updateUser})
</insert>void insertBatch(List<DishFlavor> flavors);
<insert id="insertBatch">insert into dish_flavor(dish_id, name, value)values<foreach collection="flavors" item="df" separator=",">(#{df.dishId}, #{df.name}, JSON_ARRAY(#{df.value}))</foreach>
</insert>
查询菜品
@GetMapping("/page")
@ApiOperation("菜品分页查询")
public Result<PageResult> GetDish(DishPageQueryDTO dto){log.info("菜品查询");PageResult list =dishService.getDish(dto);return Result.success(list);
}PageResult getDish(DishPageQueryDTO dto);
public PageResult getDish(DishPageQueryDTO dto) {PageHelper.startPage(dto.getPage(),dto.getPageSize());Page<DishVO> page = dishMapper.pageQuery(dto);return new PageResult(page.getTotal(),page.getResult());
}Page<DishVO> pageQuery(DishPageQueryDTO dto);
<select id="pageQuery" resultType="com.sky.vo.DishVO">select d.* ,c.name as categoryName from dish d left outer join category c on d.category_id = c.id<where><if test="name !=null">and d.name like concat('%', #{name},'%')</if><if test="categoryId !=null">and d.category_id = #{category_id}</if><if test="status!=null">and d.status = #{status}</if></where>order by d.create_time desc
</select>
删除菜品
@DeleteMapping()
@ApiOperation("删除菜品")public Result delete(@RequestParam List<Long> ids) {log.info("删除菜品{}",ids);dishService.delete(ids);return Result.success();
}@Transactional
@Override
public void delete(List<Long> ids) {//起售中的菜品不能删除for (Long id : ids) {Dish dish = dishMapper.geibyid(id);if (dish.getStatus() == StatusConstant.ENABLE){throw new DeletionNotAllowedException(MessageConstant.DISH_ON_SALE);}}//被套餐关联的菜品不能删除List<Long> SetmealIds = setmealDishMapper.getSetmealDishIdsBydishlId(ids);if (SetmealIds!=null&&SetmealIds.size()>0){throw new DeletionNotAllowedException(MessageConstant.DISH_BE_RELATED_BY_SETMEAL);}/*可以删除一个菜品,也可以删除多个菜品for (Long id : ids) {dishMapper.delete(id);//删除菜品后,关联的口味也需要删除dishFloarMapper.delete(id);}*///优化,根据菜品id集合批量删除dishMapper.deletes(ids);dishFloarMapper.deletes(ids);
}void deletes(List<Long> ids);
<delete id="deletes">delete from dish where id in<foreach collection="ids" open="(" close=")" separator="," item="id">#{id}</foreach></delete>
修改菜品
@PutMapping@ApiOperation("修改菜品")public Result update(@RequestBody DishDTO dishdao) {dishService.update(dishdao);return Result.success();
}void update(DishDTO dishdao);
public void update(DishDTO dishdao) {//修改菜品表Dish dish = new Dish();BeanUtils.copyProperties(dishdao, dish);dishMapper.updatedish(dish);//修改口味表,先删除所有口味,在插入传过来的口味dishFloarMapper.delete(dishdao  .getId());List<DishFlavor> flavors=dishdao.getFlavors();if (flavors!=null&&flavors.size()>0){flavors.forEach(dishFlavor -> {dishFlavor.setDishId(dish.getId());});flavors.forEach(dishFlavor -> dishFlavor.setValue(dishFlavor.getValue().toString()));dishFloarMapper.insertBatch(flavors);}
}

五.套餐管理

新增套餐
@PostMapping@ApiOperation("新增套餐")public Result save(@RequestBody SetmealDTO setmealDTO) {setmealService.saveWithDish(setmealDTO);return Result.success();
}void saveWithDish(SetmealDTO setmealDTO);
@Transactionalpublic void saveWithDish(SetmealDTO setmealDTO) {Setmeal setmeal = new Setmeal();BeanUtils.copyProperties(setmealDTO, setmeal);//向套餐表插入数据setmealMapper.insert(setmeal);//获取生成的套餐idLong setmealId = setmeal.getId();List<SetmealDish> setmealDishes = setmealDTO.getSetmealDishes();setmealDishes.forEach(setmealDish -> {setmealDish.setSetmealId(setmealId);});//保存套餐和菜品的关联关系setmealDishMapper.insertBatch(setmealDishes);
}<insert id="insert" parameterType="Setmeal" useGeneratedKeys="true" keyProperty="id">insert into setmeal(category_id, name, price, status, description, image, create_time, update_time, create_user, update_user)values (#{categoryId}, #{name}, #{price}, #{status}, #{description}, #{image}, #{createTime}, #{updateTime},#{createUser}, #{updateUser})
</insert>
<insert id="insertBatch" parameterType="list">insert into setmeal_dish(setmeal_id,dish_id,name,price,copies)values<foreach collection="setmealDishes" item="sd" separator=",">(#{sd.setmealId},#{sd.dishId},#{sd.name},#{sd.price},#{sd.copies})</foreach>
</insert>
查询套餐
@GetMapping("/page")
@ApiOperation("分页查询")
public Result<PageResult> page(SetmealPageQueryDTO setmealPageQueryDTO) {PageResult pageResult = setmealService.pageQuery(setmealPageQueryDTO);return Result.success(pageResult);
}PageResult pageQuery(SetmealPageQueryDTO setmealPageQueryDTO);
public PageResult pageQuery(SetmealPageQueryDTO setmealPageQueryDTO) {int pageNum = setmealPageQueryDTO.getPage();int pageSize = setmealPageQueryDTO.getPageSize();PageHelper.startPage(pageNum, pageSize);Page<SetmealVO> page = setmealMapper.pageQuery(setmealPageQueryDTO);return new PageResult(page.getTotal(), page.getResult());
}Page<SetmealVO> pageQuery(SetmealPageQueryDTO setmealPageQueryDTO);
<select id="pageQuery" resultType="com.sky.vo.SetmealVO">selects.*,c.name categoryNamefromsetmeal sleft joincategory cons.category_id = c.id<where><if test="name != null">and s.name like concat('%',#{name},'%')</if><if test="status != null">and s.status = #{status}</if><if test="categoryId != null">and s.category_id = #{categoryId}</if></where>order by s.create_time desc
</select>
修改套餐
@PutMapping@ApiOperation("修改套餐")public Result updateSetmeal(@RequestBody SetmealDTO setmealdto){log.info("修改套餐{}",setmealdto);setmealService.updateSetmeal(setmealdto);return Result.success();
}void updateSetmeal(SetmealDTO setmealdto);
public void updateSetmeal(SetmealDTO setmealdto) {Setmeal setmeal = new Setmeal();BeanUtils.copyProperties(setmealdto, setmeal);//修改套餐信息setmealMapper.updateSetmeal(setmeal);//修改对应的套餐菜品Long setmealId = setmeal.getId();//删除套餐和菜品的关联关系,操作setmeal_dish表,执行deletesetmealDishMapper.deleteBySetmealId(setmealId);List<SetmealDish> setmealDishes = setmealdto.getSetmealDishes();setmealDishes.forEach(setmealDish -> {setmealDish.setSetmealId(setmealId);});//3、重新插入套餐和菜品的关联关系,操作setmeal_dish表,执行insertsetmealDishMapper.insertBatch(setmealDishes);}<update id="updateSetmeal">update setmeal<set><if test="categoryId!=null">category_id = #{categoryId},</if><if test="name!=null">name = #{name},</if><if test="price!=null">price = #{price},</if><if test="description!=null">description = #{description}, </if><if test="image!=null">image = #{image},</if><if test="status!=null">status = #{status},</if></set>where id = #{id}
</update>
删除套餐
@DeleteMapping@ApiOperation("批量删除套餐")public Result delete(@RequestParam List<Long> ids){setmealService.deleteBatch(ids);return Result.success();
}void deleteBatch(List<Long> ids);
public void deleteBatch(List<Long> ids) {//起售中的套餐无法删除for (Long id : ids) {Setmeal setmeal = setmealMapper.getsetmealbyid(id);if(setmeal.getStatus()== StatusConstant.ENABLE){throw new DeletionNotAllowedException(MessageConstant.SETMEAL_ON_SALE);}}for (Long id : ids) {//删除套餐表中的数据setmealMapper.deleteById(id);//删除套餐菜品关系表中的数据setmealDishMapper.deleteBySetmealId(id);}
}@Delete("delete from setmeal where id = #{id}")
void deleteById(Long id);

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/21593.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【设计模式精讲】创建型模式之工厂方法模式(简单工厂、工厂方法)

文章目录 第四章 创建型模式4.2 工厂方法模式4.2.1 需求: 模拟发放奖品业务4.2.2 原始开发方式4.2.3 简单工厂模式4.2.3.1 简单工厂模式介绍4.2.3.2 简单工厂原理4.2.3.3 简单工厂模式重构代码4.2.3.4 简单工厂模式总结 4.2.4 工厂方法模式4.2.4.1 工厂方法模式介绍4.2.4.2 工厂…

【C语言】指针(5)

前言&#xff1a;上篇文章的末尾我们使用了转移表来解决代码冗余的问题&#xff0c;那我们还有没有什么办法解决代码冗余呢&#xff1f;有的这就是接下来要说的回调函数。 往期文章: 指针1 指针2 指针3 指针4 文章目录 一&#xff0c;回调函数二&#xff0c;qsort实现快速排序1…

SpringBoot:SSL证书部署+SpringBoot实现HTTPS安全访问

一、前言 SSL协议介于TCP/IP协议栈的第四层&#xff08;传输层&#xff09;和第七层&#xff08;应用层&#xff09;之间&#xff0c;为基于TCP的应用层协议&#xff08;如HTTP&#xff09;提供安全连接。它通过在客户端和服务器之间建立一个加密的通道&#xff0c;确保数据在传…

嵌入式 lwip http server makefsdata

背景&#xff1a; 基于君正X2000 MCU Freertoslwip架构 实现HTTP server服务&#xff0c;MCU作为HTTP服务器通过网口进行数据包的传输&#xff0c;提供网页服务。其中设计到LWIP提供的工具makefsdata&#xff0c;常用于将文件或目录结构转换为适合嵌入到固件中的二进制格式。 …

论文笔记-WSDM2025-ColdLLM

论文笔记-WSDM2025-Large Language Model Simulator for Cold-Start Recommendation ColdLLM&#xff1a;用于冷启动推荐的大语言模型模拟器摘要1.引言2.前言3.方法3.1整体框架3.1.1行为模拟3.1.2嵌入优化 3.2耦合漏斗ColdLLM3.2.1过滤模拟3.2.2精炼模拟 3.3模拟器训练3.3.1LLM…

《DeepSeek-V3:人工智能大语言模型》

《DeepSeek-V3:人工智能大语言模型》 1. 引言 我们介绍了 DeepSeek-V3,这是一个强大的专家混合 (MoE) 语言模型,总共有 671B 个参数,每个令牌激活了 37B。 为了实现高效的推理和具有成本效益的训练,DeepSeek-V3 采用了多头潜在注意力 (MLA) 和 DeepSeekMoE 架构,这些…

手机控制电脑远程关机

远程看看软件兼容iOS和Android设备&#xff0c;该软件除了能通过电脑远程关闭另一台电脑外&#xff0c;您还可以通过它在手机上远程关闭公司的电脑。您可以按照以下步骤进行操作以实现电脑远程关机&#xff1a; 步骤1.在手机应用商店搜索“远程看看”进行软件安装&#xff0c;…

Aseprite绘画流程案例(1)——画相机图标

原图&#xff1a; 步骤一&#xff1a;打开需要参照的图标 步骤二&#xff1a;将参照的图片拖放到右边&#xff0c;作为参考 步骤三&#xff1a;新建24x24的画布&#xff0c;背景为白色的画布 步骤四&#xff1a;点击菜单栏——视图——显示——像素网格&#xff08;如果画布已经…

The Heliosphere 日球层

转自 The Heliosphere - NASA This is an artists concept of our Heliosphere as it travels through our galaxy with the major features labeled. Termination Shock: Blowing outward billions of kilometers from the Sun is the solar wind, a thin stream of electrica…

使用API有效率地管理Dynadot域名,为域名部署DNS安全拓展(DNSSEC)

关于Dynadot Dynadot是通过ICANN认证的域名注册商&#xff0c;自2002年成立以来&#xff0c;服务于全球108个国家和地区的客户&#xff0c;为数以万计的客户提供简洁&#xff0c;优惠&#xff0c;安全的域名注册以及管理服务。 Dynadot平台操作教程索引&#xff08;包括域名邮…

vsan数据恢复—vsan缓存盘故障导致虚拟磁盘文件丢失的数据恢复案例

vsan数据恢复环境&故障&#xff1a; VMware vsan架构采用21模式。每台设备只有一个磁盘组&#xff08;71&#xff09;&#xff0c;缓存盘的大小为240GB&#xff0c;容量盘的大小为1.2TB。 由于其中一台主机&#xff08;0号组设备&#xff09;的缓存盘出现故障&#xff0c;导…

匹配算法:向下就近原则,向下没有就向上

匹配算法&#xff1a;向下就近原则&#xff0c;向下没有就向上 实现方式一实现方式二总结 实现方式一 private static List<Integer> findMatches(List<Integer> sourceList, List<Integer> searchValues) {List<Integer> sortedList sourceList.stre…

AI客服-接入deepseek大模型到微信(本地部署deepseek集成微信自动收发消息)

1.本地部署 1.1 ollama Ollama软件通过其高度优化的推理引擎和先进的内存管理机制&#xff0c;显著提升了大型语言模型在本地设备上的运行效率。其核心采用了量化技术&#xff08;Quantization&#xff09;以降低模型的计算复杂度和存储需求&#xff0c;同时结合张量并行计算&…

Python VsCode DeepSeek接入

Python VsCode DeepSeek接入 创建API key 首先进入DeepSeek官网&#xff0c;https://www.deepseek.com/ 点击左侧“API Keys”&#xff0c;创建API key&#xff0c;输出名称为“AI” 点击“创建"&#xff0c;将API key保存&#xff0c;复制在其它地方。 在VsCode中下载…

【python】网页批量转PDF

安装wkhtmltopdf 网站&#xff1a;wkhtmltopdf wkhtmltopdf http://www.baidu.com/ D:website1.pdf 安装pdfkit库 pip install pdfkit 批量转换代码 import os import pdfkit path_wkthmltopdf rE:\Program Files\wkhtmltopdf\bin\wkhtmltopdf.exe config pdfkit.configu…

架构师面试(三):订阅模型

问题 对【注册中心】【配置中心】【消息队列】和【IM】进行分析和抽象&#xff0c;可归纳出一个完整的业务模型单元&#xff0c;即【订阅系统】&#xff0c;下面关于实现订阅系统的几种模型的相关描述中&#xff0c;说法正确的有哪几项&#xff1f; A. 信箱模型&#xff0c;即…

数据结构:算法的时间复杂度和空间复杂度

1.算法效率 1.1 如何衡量一个算法的好坏 如何衡量一个算法的好坏呢&#xff1f; 比如对于以下斐波那契数列&#xff1a; long long Fib(int N) {if(N < 3)return 1;return Fib(N-1) Fib(N-2); }斐波那契数列的递归实现方式非常简洁&#xff0c;但简洁一定好吗&#xff…

linux下pip下载项目失败

想下载CLIP的项目复现代码的时候&#xff0c;出现问题如下&#xff1a; 于是手动使用 Git 克隆仓库&#xff0c; git clone https://github.com/openai/CLIP.git cd CLIP pip install .ls查看文件如下&#xff1a;(手动克隆git项目成功)

Redis文档总结

文档&#xff1a;https://redis.com.cn/topics/why-use-redis.html 1.我们为什么一定要用 Redis 呢&#xff1f; 速度快&#xff0c;完全基于内存&#xff0c;使用 C 语言实现&#xff0c;网络层使用 epoll 解决高并发问题&#xff0c;单线程模型避免了不必要的上下文切换及竞争…

【前端框架】Vue3 面试题深度解析

本文详细讲解了VUE3相关的面试题&#xff0c;从基础到进阶到高级&#xff0c;分别都有涉及&#xff0c;希望对你有所帮助&#xff01; 基础题目 1. 简述 Vue3 与 Vue2 相比有哪些主要变化&#xff1f; 答案&#xff1a; 响应式系统&#xff1a;Vue2 使用 Object.definePrope…