[苍穹外卖]-04菜品管理接口开发

2024-09-08 05:12

本文主要是介绍[苍穹外卖]-04菜品管理接口开发,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

效果预览

新增菜品

需求分析

查看产品原型分析需求, 包括用到哪些接口, 业务的限制规则

业务规则

  1. 菜品名称必须是唯一的
  2. 菜品必须属于某个分类下, 不能单独存在
  3. 新增菜品时可以根据情况选择菜品的口味
  4. 每个菜品必须对应一张图片

接口设计

根据类型查询分类接口

文件上传接口

新增菜品接口

数据表设计

设计dish菜品表 和 dish_flavor口味表

分类查询接口

在分类管理模块中已完成

文件上传接口

定义文件上传的Controler

/*** 通用接口*/
@RestController
@RequestMapping("/admin/common")
@Api(tags = "通用接口")
@Slf4j
public class CommonController {/*** 文件上传** @param file* @return*/@PostMapping("/upload")@ApiOperation("文件上传")public Result<String> update(MultipartFile file) {log.info("文件上传:{}", file);return null;}
}

配置阿里云OSS参数: 通常把application.yml作为主配置文件, 根据运行环境引用其他配置文件的值

// 配置属性类
@Component
@ConfigurationProperties(prefix = "sky.alioss")
@Data
public class AliOssProperties {private String endpoint;private String accessKeyId;private String accessKeySecret;private String bucketName;}
  1. 使用 @ConfigurationProperties(prefix = "sky.alioss")注解 定义配置属性类
  2. 配置属性类的作用就是读取配置文件中的属性, 把属性的值封装到对象中
  3. 配置文件中用横线分隔, 配置属性类使用驼峰命名法
  4. springboot框架可以自动进行驼峰命名映射
spring:profiles:active: devsky:alioss:endpoint: ${sky.alioss.endpoint}access-key-id: ${sky.alioss.access-key-id}access-key-secret: ${sky.alioss.access-key-secret}bucket-name: ${sky.alioss.bucket-name}
  1. 在主配置文件中配置OSS连接信息
  2. 程序运行时动态引用环境配置文件中的值
  3. active: dev 该属性指定引用开发环境的信息
  4. 使用 active 属性可以实现代码环境的快捷切换
sky:alioss:endpoint: oss-cn-beijing.aliyuncs.comaccess-key-id: ....access-key-secret: ....bucket-name: sky-itcast-cangqiongwaimai
  1. 在开发环境配置文件中配置具体的oss连接参数

准备工具类: 已经提供了用于文件上传的工具类

@Data
@AllArgsConstructor
@Slf4j
public class AliOssUtil {private String endpoint;private String accessKeyId;private String accessKeySecret;private String bucketName;/*** 文件上传** @param bytes* @param objectName* @return*/public String upload(byte[] bytes, String objectName) {// 创建OSSClient实例。OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);try {// 创建PutObject请求。ossClient.putObject(bucketName, objectName, new ByteArrayInputStream(bytes));} catch (OSSException oe) {System.out.println("Caught an OSSException, which means your request made it to OSS, "+ "but was rejected with an error response for some reason.");System.out.println("Error Message:" + oe.getErrorMessage());System.out.println("Error Code:" + oe.getErrorCode());System.out.println("Request ID:" + oe.getRequestId());System.out.println("Host ID:" + oe.getHostId());} catch (ClientException ce) {System.out.println("Caught an ClientException, which means the client encountered "+ "a serious internal problem while trying to communicate with OSS, "+ "such as not being able to access the network.");System.out.println("Error Message:" + ce.getMessage());} finally {if (ossClient != null) {ossClient.shutdown();}}//文件访问路径规则 https://BucketName.Endpoint/ObjectNameStringBuilder stringBuilder = new StringBuilder("https://");stringBuilder.append(bucketName).append(".").append(endpoint).append("/").append(objectName);log.info("文件上传到:{}", stringBuilder.toString());return stringBuilder.toString();}
}

创建配置类, 用于创建AliOssUtil对象

@Configuration // 声明配置类
@Slf4j
public class OssConfiguration {@Bean // 程序启动时创建阿里云OSS对象并交给IOC容器管理@ConditionalOnMissingBean //条件装配注解, 指定该对象为单例模式, 只创建一个public AliOssUtil aliOssUtil(AliOssProperties aliOssProperties) {// 通过参数注入的形式注入aliOssProperties对象// 通过该对象可以拿到属性配置类封装好的的属性log.info("开始创建阿里云文件上传工具类对象: {}", aliOssProperties);return new AliOssUtil(aliOssProperties.getEndpoint(),aliOssProperties.getAccessKeyId(),aliOssProperties.getAccessKeySecret(),aliOssProperties.getBucketName());}}

使用aliOssUtil对象, 完成文件上传功能, 为了防止文件重名覆盖, 需要构建新的文件名

/*** 通用接口*/
@RestController
@RequestMapping("/admin/common")
@Api(tags = "通用接口")
@Slf4j
public class CommonController {@Autowiredprivate AliOssUtil aliOssUtil;/*** 文件上传** @param file* @return*/@PostMapping("/upload")@ApiOperation("文件上传")public Result<String> update(MultipartFile file) {log.info("文件上传:{}", file);try {// 原始文件名String originalFilename = file.getOriginalFilename();// 截取原始文件名的后缀(xxx.png)String extension = originalFilename.substring(originalFilename.lastIndexOf("."));// 构建新文件名String objectName = UUID.randomUUID().toString() + extension;// 文件上传String filePath = aliOssUtil.upload(file.getBytes(), objectName);return Result.success(filePath);} catch (IOException e) {log.info("文件上传失败:{}", e);}return Result.error(MessageConstant.UPLOAD_FAILED);}
}

新增菜品接口

准备DishDTO用来封装前端传递的菜品数据

@Data
public class DishDTO implements Serializable {private Long id;//菜品名称private String name;//菜品分类idprivate Long categoryId;//菜品价格private BigDecimal price;//图片private String image;//描述信息private String description;//0 停售 1 起售private Integer status;//口味private List<DishFlavor> flavors = new ArrayList<>();}

准备DishFlavor实体类, 用来封装菜品的口味数据

/*** 菜品口味*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class DishFlavor implements Serializable {private static final long serialVersionUID = 1L;private Long id;//菜品idprivate Long dishId;//口味名称private String name;//口味数据listprivate String value;}

新建DishController

/*** 菜品管理*/
@RestController
@RequestMapping("/admin/dish")
@Api(tags = "菜品相关接口")
@Slf4j
public class DishController {@Autowiredprivate DishService dishService;/*** 新增菜品** @param dishDTO* @return*/@PostMapping@ApiOperation("新增菜品")public Result save(@RequestBody DishDTO dishDTO) {log.info("新增菜品: {}", dishDTO);dishService.saveWithFlavor(dishDTO);return Result.success();}
}

新建 DishService接口 以及 DishServiceImpl实现类

public interface DishService {/*** 新增菜品和对应的口味* @param dishDTO*/public void saveWithFlavor(DishDTO dishDTO);
}
@Service
@Slf4j
public class DishServiceImpl implements DishService {@Autowiredprivate DishMapper dishMapper;@Autowiredprivate DishFlavorMapper dishFlavorMapper;/*** 新增菜品和对应的口味** @param dishDTO*/@Transactionalpublic void saveWithFlavor(DishDTO dishDTO) {Dish dish = new Dish();BeanUtils.copyProperties(dishDTO, dish);// 向菜品表插入1条数据dishMapper.insert(dish);// 向口味表插入n条数据Long dishId = dish.getId(); //拿到菜品id, SQL中已开启List<DishFlavor> flavors = dishDTO.getFlavors(); //拿到口味数据if (flavors != null && flavors.size() > 0) {flavors.forEach(dishFlavor -> {// 设置口味关联的菜品iddishFlavor.setDishId(dishId);});dishFlavorMapper.insertBatch(flavors);}}
}
@SpringBootApplication
@EnableTransactionManagement //开启注解方式的事务管理
@Slf4j
public class SkyApplication {public static void main(String[] args) {SpringApplication.run(SkyApplication.class, args);log.info("server started");}
}
  1. 一个方法中操作多个表, 使用@Transactional注解开启事务管理
  2. @EnableTransactionManagement注解不是严格必须的, 但是显示的声明能够确保Spring容器能够识别并管理@Transactional注解标记的方法
  3. 使用 BeanUtils.copyProperties(数据源对象, 目标对象) 方法进行对象属性拷贝, 可以轻松的进行对象属性的赋值, 前提是两个对象的属性名完全一致

新建DishMapper操作菜品表

@Mapper
public interface DishMapper {/*** 插入菜品** @param dish*/@AutoFill(value = OperationType.INSERT) // 公共字段填充void insert(Dish dish);}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.sky.mapper.DishMapper">// 新增菜品<insert id="insert" useGeneratedKeys="true" keyProperty="id">insert into dish (name, category_id, price, image, description, create_time, update_time, create_user,update_user, status)values (#{name}, #{categoryId}, #{price}, #{image}, #{description}, #{createTime}, #{updateTime}, #{createUser},#{updateUser}, #{status})</insert></mapper>
  1. useGeneratedKeys="true" 开启sql执行完毕返回数据
  2. keyProperty="id" 指定返回id字段

新建DishFlavorMapper操作菜品口味表

@Mapper
public interface DishFlavorMapper {/*** 批量插入口味数据* @param flavors*/void insertBatch( List<DishFlavor> flavors);
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.sky.mapper.DishFlavorMapper">// 插入口味数据 <insert id="insertBatch">insert into dish_flavor (dish_id,name,value) VALUES<foreach collection="flavors" item="df" separator=",">(#{df.dishId},#{df.name},#{df.value})</foreach></insert></mapper>

联调测试

录入的数据项比较多, 直接采用前后端联调进行测试

菜品分页查询

分析和设计

查看产品原型, 分析业务规则

  1. 根据页码展示菜品信息
  2. 每页展示10条数据
  3. 分页查询时可以根据需要输入菜品名称, 菜品分类, 菜品状态进行查询

接口设计, 分类名称需要根据菜品id查询分类表得到

代码开发

根据前端请求参数定义对应的DTO

根据接口返回的结果定义对应的VO

Controller

/*** 菜品管理*/
@RestController
@RequestMapping("/admin/dish")
@Api(tags = "菜品相关接口")
@Slf4j
public class DishController {@Autowiredprivate DishService dishService;/*** 菜品分页查询** @param dishPageQueryDTO* @return*/@GetMapping("/page")@ApiOperation("菜品分页查询接口")public Result<PageResult> page(DishPageQueryDTO dishPageQueryDTO) {log.info("菜品分页查询:{}", dishPageQueryDTO);PageResult pageResult = dishService.pageQuery(dishPageQueryDTO);return Result.success(pageResult);}
}

Service

public interface DishService {/*** 菜品分页查询* @param dishPageQueryDTO* @return*/PageResult pageQuery(DishPageQueryDTO dishPageQueryDTO);
}
@Service
@Slf4j
public class DishServiceImpl implements DishService {@Autowiredprivate DishMapper dishMapper;/*** 菜品分页查询** @param dishPageQueryDTO* @return*/public PageResult pageQuery(DishPageQueryDTO dishPageQueryDTO) {// 开启分页查询PageHelper.startPage(dishPageQueryDTO.getPage(), dishPageQueryDTO.getPageSize());// 查询业务Page<DishVO> page = dishMapper.pageQuery(dishPageQueryDTO);// 返回数据return new PageResult(page.getTotal(), page.getResult());}
}

Mapper

@Mapper
public interface DishMapper {/*** 菜品分页查询** @param dishPageQueryDTO* @return*/Page<DishVO> pageQuery(DishPageQueryDTO dishPageQueryDTO);}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.sky.mapper.DishMapper"><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 = #{categoryId}</if><if test="status != null">and d.status = #{status}</if></where>order by d.create_time desc</select>
</mapper>
  1. 对于比较复杂的查询语句, 可以在SQL图形化工具中, 编写语句并测试, 提高测试效率

功能测试

接口测试

前后端联调

删除菜品

分析和设计

需求分析: 查看产品原型, 确定业务规则

  1. 可以一次删除一个菜品, 也可以批量删除菜品
  2. 起售中的菜品不能删除
  3. 被套餐关联的菜品不能删除
  4. 删除菜品后, 关联的口味数据也需要删除

接口设计

数据表设计: 删除菜品涉及到三张表的操作, 菜品表, 菜品口味表, 菜品和口味中间表

代码开发

Controller

/*** 菜品管理*/
@RestController
@RequestMapping("/admin/dish")
@Api(tags = "菜品相关接口")
@Slf4j
public class DishController {@Autowiredprivate DishService dishService;/*** 菜品批量删除** @param ids* @return*/@DeleteMapping@ApiOperation("菜品批量删除")public Result delete(@RequestParam List<Long> ids) {// @RequestParam注解// 可以自动把query参数中的参数封装到List<long> ids容器中// "1,2,3,4" --> [1,2,3,4]log.info("菜品批量删除:{}", ids);dishService.deleteBath(ids);//删除缓存数据cleanCache("dish_*");return Result.success();}
}

Service

public interface DishService {/*** 批量删除菜品* @param ids*/void deleteBath(List<Long> ids);
}
@Service
@Slf4j
public class DishServiceImpl implements DishService {@Autowiredprivate DishMapper dishMapper;@Autowiredprivate DishFlavorMapper dishFlavorMapper;@Autowiredprivate SetmealDishMapper setmealDishMapper;/*** 批量删除菜品** @param ids*/@Transactional // 开启事务管理public void deleteBath(List<Long> ids) {log.info("根据菜品id删除口味数据:{}", ids);// 判断当前菜品是否能够删除---是否存在起售中的菜品for (Long id : ids) {Dish dish = dishMapper.getById(id);if (dish.getStatus() == StatusConstant.ENABLE) {// 当前菜品处于起售中, 不能删除throw new DeletionNotAllowedException(MessageConstant.DISH_ON_SALE);}}// 判断当前菜品是否能够删除---是否被套餐关联了List<Long> setmealIds = setmealDishMapper.getSetmealIdsByDishIds(ids);if (setmealIds != null && setmealIds.size() > 0) {// 当前菜品被套餐关联, 不能删除throw new DeletionNotAllowedException(MessageConstant.DISH_BE_RELATED_BY_SETMEAL);}// 删除菜品表中的数据(优化前)for (Long id : ids) {// 删除菜品数据dishMapper.deleteById(id);// 删除菜品关联的口味数据dishFlavorMapper.deleteByDishId(id);}}
}

Mapper

@Mapper
public interface DishMapper {/*** 根据id查询菜品** @param id* @return*/@Select("select * from dish where id = #{id}")Dish getById(Long id);/*** 根据id删除菜品数据** @param id*/@Delete("delete from dish where id = #{id}")void deleteById(Long id);
}
@Mapper
public interface SetmealDishMapper {/*** 根据菜品id查询套餐id* @param dishIds* @return*/List<Long> getSetmealIdsByDishIds(List<Long> dishIds);}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.sky.mapper.SetmealDishMapper"><select id="getSetmealIdsByDishIds" resultType="java.lang.Long">select setmeal_id from setmeal_dish where dish_id in<foreach collection="dishIds" item="dishId" separator="," open="(" close=")">#{dishId}</foreach></select></mapper>
@Mapper
public interface DishFlavorMapper {/*** 根据id删除对应的口味数据* @param dishId*/@Delete("delete from dish_flavor where dish_id = #{dishId}")void deleteByDishId(Long dishId);
}

代码优化

优化前: sql语句的数量不固定, 删除多个菜品就调用多次sql

优化后: sql语句的数量是固定的, 删除多个菜品也是调用两条sql

@Service
@Slf4j
public class DishServiceImpl implements DishService {@Autowiredprivate DishMapper dishMapper;@Autowiredprivate DishFlavorMapper dishFlavorMapper;/*** 批量删除菜品** @param ids*/@Transactionalpublic void deleteBath(List<Long> ids) {... ...// 删除菜品表中的数据(优化前)// for (Long id : ids) {// 删除菜品数据// dishMapper.deleteById(id);// 删除菜品关联的口味数据// dishFlavorMapper.deleteByDishId(id);//         }// 优化后// 批量删除菜品数据dishMapper.deleteByIds(ids);// 批量删除菜品关联的口味数据log.info("根据菜品id删除口味数据:{}", ids);dishFlavorMapper.deleteByDishIds(ids);}
}
@Mapper
public interface DishMapper {/*** 根据ids批量删除菜品数据* @param ids*/void deleteByIds(List<Long> ids);
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.sky.mapper.DishMapper"><delete id="deleteByIds">delete from dish where id in<foreach collection="ids" close=")" open="(" separator="," item="id">#{id}</foreach></delete></mapper>
@Mapper
public interface DishFlavorMapper {/*** 根据菜品ids批量删除口味数据* @param dishIds*/void deleteByDishIds(List<Long> dishIds);}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.sky.mapper.DishFlavorMapper"><delete id="deleteByDishIds">delete from dish_flavor where dish_id in<foreach collection="dishIds" item="dishId" separator="," open="(" close=")">#{dishId}</foreach></delete></mapper>

功能测试

修改菜品

分析和设计

查看原型: 完成菜品信息的回显和更新

接口设计

根据id查询菜品

Controller

/*** 菜品管理*/
@RestController
@RequestMapping("/admin/dish")
@Api(tags = "菜品相关接口")
@Slf4j
public class DishController {@Autowiredprivate DishService dishService;/*** 根据id查询菜品** @param id* @return*/@GetMapping("/{id}")@ApiOperation("根据id查询菜品")public Result<DishVO> getById(@PathVariable long id) {log.info("根据id查询菜品:{}", id);DishVO dishVO = dishService.getByIdWithFlavor(id);return Result.success(dishVO);}}

Service

public interface DishService {/*** 根据id查询菜品* @param id* @return*/DishVO getByIdWithFlavor(long id);
}

@Service
@Slf4j
public class DishServiceImpl implements DishService {@Autowiredprivate DishMapper dishMapper;@Autowiredprivate DishFlavorMapper dishFlavorMapper;/*** 根据id查询菜品和对应的口味数据** @param id* @return*/public DishVO getByIdWithFlavor(long id) {// 根据id查询菜品数据Dish dish = dishMapper.getById(id);// 根据菜品id查询口味数据List<DishFlavor> dishFlavors = dishFlavorMapper.getByDishId(id);// 把查询结果封装到VODishVO dishVO = new DishVO();BeanUtils.copyProperties(dish, dishVO);dishVO.setFlavors(dishFlavors);return dishVO;}
}

Mapper

@Mapper
public interface DishMapper {/*** 根据id查询菜品** @param id* @return*/@Select("select * from dish where id = #{id}")Dish getById(Long id);
}
@Mapper
public interface DishFlavorMapper {/*** 根基菜品id查询对应的口味数据* @param dishId* @return*/@Select("select * from dish_flavor where dish_id = #{dishId}")List<DishFlavor> getByDishId(long dishId);
}

根据id修改菜品

Controller

/*** 菜品管理*/
@RestController
@RequestMapping("/admin/dish")
@Api(tags = "菜品相关接口")
@Slf4j
public class DishController {@Autowiredprivate DishService dishService;/*** 修改菜品** @param dishDTO* @return*/@PutMapping@ApiOperation("修改菜品")public Result update(@RequestBody DishDTO dishDTO) {log.info("修改菜品: {}", dishDTO);dishService.updateWithFlavor(dishDTO);//删除缓存数据cleanCache("dish_*");return Result.success();}
}

Service

public interface DishService {/*** 修改菜品和对应的口味* @param dishDTO*/void updateWithFlavor(DishDTO dishDTO);
}

@Service
@Slf4j
public class DishServiceImpl implements DishService {@Autowiredprivate DishMapper dishMapper;@Autowiredprivate DishFlavorMapper dishFlavorMapper;/*** 修改菜品和对应的口味** @param dishDTO*/public void updateWithFlavor(DishDTO dishDTO) {Dish dish = new Dish();BeanUtils.copyProperties(dishDTO, dish);// 修改菜品基本信息dishMapper.update(dish);// 删除原有的口味数据dishFlavorMapper.deleteByDishId(dishDTO.getId());// 重新插入口味数据List<DishFlavor> flavors = dishDTO.getFlavors();if (flavors != null && flavors.size() > 0) {for (DishFlavor flavor : flavors) {flavor.setDishId(dishDTO.getId());}// 向口味表插入n条数据dishFlavorMapper.insertBatch(flavors);}}
}

Mapper

@Mapper
public interface DishMapper {/*** 根据id修改菜品数据* @param dish*/@AutoFill(value = OperationType.UPDATE)void update(Dish dish);
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.sky.mapper.DishMapper"><update id="update">update dish<set><if test="name != null">name = #{name},</if><if test="categoryId != null">category_id = #{categoryId},</if><if test="price != null">price = #{price},</if><if test="image != null">image = #{image},</if><if test="description != null">description = #{description},</if><if test="status != null">status = #{status},</if><if test="updateTime != null">update_time = #{updateTime},</if><if test="updateUser != null">update_user = #{updateUser},</if></set>where id = #{id}</update></mapper>
@Mapper
public interface DishFlavorMapper {/*** 批量插入口味数据* @param flavors*/void insertBatch( List<DishFlavor> flavors);/*** 根据id删除对应的口味数据* @param dishId*/@Delete("delete from dish_flavor where dish_id = #{dishId}")void deleteByDishId(Long dishId);
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.sky.mapper.DishFlavorMapper"><insert id="insertBatch">insert into dish_flavor (dish_id,name,value) VALUES<foreach collection="flavors" item="df" separator=",">(#{df.dishId},#{df.name},#{df.value})</foreach></insert></mapper>

功能测试

这篇关于[苍穹外卖]-04菜品管理接口开发的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1147205

相关文章

这15个Vue指令,让你的项目开发爽到爆

1. V-Hotkey 仓库地址: github.com/Dafrok/v-ho… Demo: 戳这里 https://dafrok.github.io/v-hotkey 安装: npm install --save v-hotkey 这个指令可以给组件绑定一个或多个快捷键。你想要通过按下 Escape 键后隐藏某个组件,按住 Control 和回车键再显示它吗?小菜一碟: <template

Hadoop企业开发案例调优场景

需求 (1)需求:从1G数据中,统计每个单词出现次数。服务器3台,每台配置4G内存,4核CPU,4线程。 (2)需求分析: 1G / 128m = 8个MapTask;1个ReduceTask;1个mrAppMaster 平均每个节点运行10个 / 3台 ≈ 3个任务(4    3    3) HDFS参数调优 (1)修改:hadoop-env.sh export HDFS_NAMENOD

综合安防管理平台LntonAIServer视频监控汇聚抖动检测算法优势

LntonAIServer视频质量诊断功能中的抖动检测是一个专门针对视频稳定性进行分析的功能。抖动通常是指视频帧之间的不必要运动,这种运动可能是由于摄像机的移动、传输中的错误或编解码问题导致的。抖动检测对于确保视频内容的平滑性和观看体验至关重要。 优势 1. 提高图像质量 - 清晰度提升:减少抖动,提高图像的清晰度和细节表现力,使得监控画面更加真实可信。 - 细节增强:在低光条件下,抖

嵌入式QT开发:构建高效智能的嵌入式系统

摘要: 本文深入探讨了嵌入式 QT 相关的各个方面。从 QT 框架的基础架构和核心概念出发,详细阐述了其在嵌入式环境中的优势与特点。文中分析了嵌入式 QT 的开发环境搭建过程,包括交叉编译工具链的配置等关键步骤。进一步探讨了嵌入式 QT 的界面设计与开发,涵盖了从基本控件的使用到复杂界面布局的构建。同时也深入研究了信号与槽机制在嵌入式系统中的应用,以及嵌入式 QT 与硬件设备的交互,包括输入输出设

OpenHarmony鸿蒙开发( Beta5.0)无感配网详解

1、简介 无感配网是指在设备联网过程中无需输入热点相关账号信息,即可快速实现设备配网,是一种兼顾高效性、可靠性和安全性的配网方式。 2、配网原理 2.1 通信原理 手机和智能设备之间的信息传递,利用特有的NAN协议实现。利用手机和智能设备之间的WiFi 感知订阅、发布能力,实现了数字管家应用和设备之间的发现。在完成设备间的认证和响应后,即可发送相关配网数据。同时还支持与常规Sof

活用c4d官方开发文档查询代码

当你问AI助手比如豆包,如何用python禁止掉xpresso标签时候,它会提示到 这时候要用到两个东西。https://developers.maxon.net/论坛搜索和开发文档 比如这里我就在官方找到正确的id描述 然后我就把参数标签换过来

软考系统规划与管理师考试证书含金量高吗?

2024年软考系统规划与管理师考试报名时间节点: 报名时间:2024年上半年软考将于3月中旬陆续开始报名 考试时间:上半年5月25日到28日,下半年11月9日到12日 分数线:所有科目成绩均须达到45分以上(包括45分)方可通过考试 成绩查询:可在“中国计算机技术职业资格网”上查询软考成绩 出成绩时间:预计在11月左右 证书领取时间:一般在考试成绩公布后3~4个月,各地领取时间有所不同

安全管理体系化的智慧油站开源了。

AI视频监控平台简介 AI视频监控平台是一款功能强大且简单易用的实时算法视频监控系统。它的愿景是最底层打通各大芯片厂商相互间的壁垒,省去繁琐重复的适配流程,实现芯片、算法、应用的全流程组合,从而大大减少企业级应用约95%的开发成本。用户只需在界面上进行简单的操作,就可以实现全视频的接入及布控。摄像头管理模块用于多种终端设备、智能设备的接入及管理。平台支持包括摄像头等终端感知设备接入,为整个平台提

Linux_kernel驱动开发11

一、改回nfs方式挂载根文件系统         在产品将要上线之前,需要制作不同类型格式的根文件系统         在产品研发阶段,我们还是需要使用nfs的方式挂载根文件系统         优点:可以直接在上位机中修改文件系统内容,延长EMMC的寿命         【1】重启上位机nfs服务         sudo service nfs-kernel-server resta

【区块链 + 人才服务】区块链集成开发平台 | FISCO BCOS应用案例

随着区块链技术的快速发展,越来越多的企业开始将其应用于实际业务中。然而,区块链技术的专业性使得其集成开发成为一项挑战。针对此,广东中创智慧科技有限公司基于国产开源联盟链 FISCO BCOS 推出了区块链集成开发平台。该平台基于区块链技术,提供一套全面的区块链开发工具和开发环境,支持开发者快速开发和部署区块链应用。此外,该平台还可以提供一套全面的区块链开发教程和文档,帮助开发者快速上手区块链开发。