news 2026/4/21 15:31:36

Entity、VO、DTO、Form 对象详解

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Entity、VO、DTO、Form 对象详解

概述

在项目中,我们使用不同的对象模型来处理不同场景的数据,这是分层架构的重要体现。

为什么需要多种对象?

  • 🔐安全性:防止敏感数据泄露
  • 🎯职责分离:每个对象只关注自己的职责
  • 🔄灵活性:不同层可以独立演化
  • 🛡️解耦:数据库变动不影响前端

1️⃣ Entity(实体类)- 数据库映射

定义

Entity是与数据库表一一对应的 Java 对象,也叫持久化对象

特点:

  • 🗄️ 对应数据库表结构
  • 📦 包含所有字段(包括敏感字段)
  • 🔗 包含数据库注解(如 @Table、@Column)
  • 💾 只在 DAO/Mapper 层使用

实战案例 - User 实体

package com.MiniBlog.entity; import lombok.Data; import javax.persistence.*; import java.util.Date; /** * 用户实体类 - 对应数据库表 tb_user * * 【注解说明】 * @Entity:JPA注解,表示这是一个实体类 * @Table:指定对应的数据库表名 * @Data:Lombok注解,自动生成getter/setter/toString等 */ @Data @Entity @Table(name = "tb_user") public class User { // ========== 【主键】 ========== /** * @Id:主键标识 * @GeneratedValue:主键生成策略(自增) */ @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Integer id; // ========== 【基本信息】 ========== /** * 用户编号(业务主键) */ @Column(name = "no", length = 50) private String no; /** * 真实姓名 */ @Column(name = "realname", length = 100) private String realname; /** * 手机号 */ @Column(name = "mobile", length = 20) private String mobile; /** * 邮箱 */ @Column(name = "email", length = 100) private String email; // ========== 【敏感信息】⚠️ ========== /** * 密码(加密后的) * 【注意】这个字段不应该返回给前端! */ @Column(name = "password", length = 200) private String password; /** * 密码盐值 * 【注意】这个字段不应该返回给前端! */ @Column(name = "salt", length = 50) private String salt; /** * 身份证号 * 【注意】需要脱敏后才能返回给前端! */ @Column(name = "cardno", length = 50) private String cardno; // ========== 【状态字段】 ========== /** * 账号状态:1-正常,2-冻结,3-注销 */ @Column(name = "status") private Integer status; /** * 是否删除:0-否,1-是 */ @Column(name = "deleted") private Integer deleted; // ========== 【微信相关】 ========== @Column(name = "openid", length = 100) private String openid; @Column(name = "unionid", length = 100) private String unionid; @Column(name = "mp_openid", length = 100) private String mpOpenid; // ========== 【人脸识别】 ========== @Column(name = "faceid", length = 100) private String faceid; // ========== 【时间戳】 ========== /** * 创建时间 */ @Column(name = "create_time") @Temporal(TemporalType.TIMESTAMP) private Date createTime; /** * 更新时间 */ @Column(name = "update_time") @Temporal(TemporalType.TIMESTAMP) private Date updateTime; /** * 创建人 */ @Column(name = "create_user") private Integer createUser; /** * 更新人 */ @Column(name = "update_user") private Integer updateUser; }

数据库表结构(对应):

CREATE TABLE `tb_user` ( `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键ID', `no` varchar(50) DEFAULT NULL COMMENT '用户编号', `realname` varchar(100) DEFAULT NULL COMMENT '真实姓名', `mobile` varchar(20) DEFAULT NULL COMMENT '手机号', `email` varchar(100) DEFAULT NULL COMMENT '邮箱', `password` varchar(200) DEFAULT NULL COMMENT '密码', `salt` varchar(50) DEFAULT NULL COMMENT '盐值', `cardno` varchar(50) DEFAULT NULL COMMENT '身份证号', `status` int(11) DEFAULT '1' COMMENT '状态', `deleted` int(11) DEFAULT '0' COMMENT '是否删除', `openid` varchar(100) DEFAULT NULL COMMENT '微信openid', `unionid` varchar(100) DEFAULT NULL COMMENT '微信unionid', `mp_openid` varchar(100) DEFAULT NULL COMMENT '公众号openid', `faceid` varchar(100) DEFAULT NULL COMMENT '人脸ID', `create_time` datetime DEFAULT NULL COMMENT '创建时间', `update_time` datetime DEFAULT NULL COMMENT '更新时间', `create_user` int(11) DEFAULT NULL COMMENT '创建人', `update_user` int(11) DEFAULT NULL COMMENT '更新人', PRIMARY KEY (`id`), UNIQUE KEY `uk_mobile` (`mobile`), KEY `idx_no` (`no`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';

2️⃣ VO(View Object)- 视图对象

定义

VO返回给前端的视图对象,只包含前端需要展示的数据。

特点:

  • 👁️ 只包含前端需要的字段
  • 🔒不包含敏感字段(密码、盐值等)
  • 🎨 可能包含计算字段(如年龄、格式化日期)
  • 📤 只在 Controller 层返回给前端

实战案例 - UserVo

package com.MiniBlog.vo.user; import lombok.Data; import com.payslip.entity.UserCard; import java.util.List; /** * 用户视图对象 - 返回给前端 * * 【设计原则】 * 1. 只包含前端需要的字段 * 2. 敏感字段不包含(如password、salt) * 3. 需要脱敏的字段已处理(如cardno) * 4. 可以包含关联对象(如银行卡列表) */ @Data public class UserVo { // ========== 【基本信息】 ========== private Integer id; private String no; private String realname; /** * 手机号(脱敏) * 例如:138****5678 */ private String mobile; /** * 邮箱(可能脱敏) * 例如:abc***@qq.com */ private String email; /** * 身份证号(脱敏) * 例如:320***********1234 */ private String cardno; // ========== 【注意】❌ 不包含这些字段 ========== // private String password; // 密码不返回 // private String salt; // 盐值不返回 // ========== 【状态】 ========== private Integer status; /** * 状态文本(前端显示用) * 计算属性,根据 status 值生成 */ private String statusText; // ========== 【头像】 ========== private String avatar; // ========== 【微信信息】 ========== /** * 是否绑定微信 * 计算属性:openid 不为空则已绑定 */ private Boolean hasWechat; /** * 是否绑定公众号 * 计算属性:mpOpenid 不为空则已绑定 */ private Boolean hasMpWechat; // ========== 【关联信息】 ========== /** * 用户的银行卡列表 * 这是关联查询的结果,Entity 中没有这个字段 */ private List<UserCard> cards; // ========== 【时间】 ========== /** * 创建时间(格式化后) * 例如:2024-01-15 10:30:00 */ private String createTime; // ========== 【计算字段】 ========== /** * 账号年龄(天数) * 根据创建时间计算,Entity 中没有这个字段 */ private Integer accountAge; /** * 是否实名认证 * 根据 cardno 是否为空判断 */ private Boolean isRealAuth; }

3️⃣ DTO(Data Transfer Object)- 数据传输对象

定义

DTO服务间传输数据的对象,用于跨层或跨服务传递数据。

特点:

  • 📡 用于 Service 层之间传递数据
  • 🔄 用于微服务之间传递数据
  • 📦 可能包含多个实体的数据
  • 🎯 职责单一,只负责数据传输

实战案例 - UserTokenDTO

package com.MiniBlog.dto.user; import lombok.Data; import lombok.Builder; /** * 用户登录成功后返回的数据传输对象 * * 【使用场景】 * - 用户注册成功 * - 用户登录成功 * - Token刷新成功 */ @Data @Builder public class UserTokenDTO { /** * 用户ID */ private Integer userId; /** * 用户编号 */ private String userNo; /** * 用户姓名 */ private String userName; /** * 访问令牌(JWT Token) * 前端需要保存,每次请求携带 */ private String token; /** * Token过期时间(秒) */ private Long expiresIn; /** * 刷新令牌 * 用于Token过期后刷新 */ private String refreshToken; /** * 是否首次登录 * 首次登录需要引导用户完善信息 */ private Boolean firstLogin; /** * 用户头像 */ private String avatar; }

4️⃣ Form(表单对象)- 接收前端数据

定义

Form接收前端提交数据的对象,包含参数校验规则。

特点:

  • 📥 只在 Controller 层接收前端数据
  • ✅ 包含参数校验注解(@NotNull、@Size等)
  • 🎯 一个接口一个Form,职责明确
  • 🔒 校验规则集中管理

实战案例 - UserMobileRegisterDTO

package com.MiniBlog.form.user; import lombok.Data; import javax.validation.constraints.*; /** * 用户手机号注册表单 * * 【使用场景】 * POST /user/mobile-register * * 【校验规则】 * - 手机号必填,格式正确 * - 验证码必填,6位数字 * - 密码必填,6-20位 */ @Data public class UserMobileRegisterDTO { /** * 手机号 * * @NotBlank:不能为空(会自动trim) * @Pattern:正则校验 */ @NotBlank(message = "手机号不能为空") @Pattern( regexp = "^1[3-9]\\d{9}$", message = "手机号格式不正确" ) private String mobile; /** * 短信验证码 */ @NotBlank(message = "验证码不能为空") @Size(min = 4, max = 6, message = "验证码长度为4-6位") private String code; /** * 密码 */ @NotBlank(message = "密码不能为空") @Size(min = 6, max = 20, message = "密码长度为6-20位") private String password; /** * 邀请码(可选) */ private String inviteCode; }

5️⃣ 对象之间的转换流程

完整数据流转图

┌─────────────────────────────────────────────────────────────────┐ │ 前端(浏览器/APP) │ └────────────┬────────────────────────────────────────┬────────────┘ │ │ │ ① 发送请求 │ ⑥ 接收响应 │ JSON: {mobile, code, password} │ JSON: {userId, token, userName} ▼ ▲ ┌─────────────────────────────────────────────────────────────────┐ │ Controller 层(控制器) │ │ @PostMapping("/register") │ │ public ApiResponse<UserTokenDTO> register( │ │ @Valid @RequestBody UserMobileRegisterDTO form) { │ │ │ │ ② Form 接收参数 ⑤ VO 返回给前端 │ │ └─> 自动校验(@Valid) └─> Entity 转 VO │ │ │ │ UserTokenDTO dto = userService.register(form); │ │ return ApiResponse.ok(dto); │ │ } │ └────────────┬────────────────────────────────────────┬────────────┘ │ │ │ ③ Form 传给 Service │ ④ DTO 返回 ▼ ▲ ┌─────────────────────────────────────────────────────────────────┐ │ Service 层(业务逻辑) │ │ public UserTokenDTO register(UserMobileRegisterDTO form) { │ │ │ │ // 1. 校验验证码 │ │ validateCode(form.getMobile(), form.getCode()); │ │ │ │ // 2. 创建 Entity 对象 │ │ User user = new User(); │ │ user.setMobile(form.getMobile()); │ │ user.setPassword(encryptPassword(form.getPassword())); │ │ user.setCreateTime(new Date()); │ │ │ │ // 3. 保存到数据库 │ │ userDao.save(user); ────┐ │ │ │ │ │ // 4. 生成 Token │ │ String token = generateToken(user.getId()); │ │ │ │ // 5. 构建 DTO 返回 │ │ return UserTokenDTO.builder() │ │ .userId(user.getId()) │ │ .token(token) │ │ .userName(user.getRealname()) │ │ .build(); │ │ } │ │ └───────────────────────────────┼─────────────────────────────────┘ │ │ Entity 保存/查询 ▼ ┌─────────────────────────────────────────────────────────────────┐ │ DAO/Mapper 层(数据访问) │ │ │ │ public interface UserRepository { │ │ User save(User user); // 保存 │ │ User findById(Integer id); // 查询 │ │ } │ └────────────┬────────────────────────────────────────┬────────────┘ │ │ │ SQL 语句 │ 查询结果 ▼ ▲ ┌─────────────────────────────────────────────────────────────────┐ │ 数据库(MySQL) │ │ │ │ tb_user 表 │ │ ┌────┬──────┬──────────┬──────────┬──────────┐ │ │ │ id │ no │ mobile │ password │ salt │ │ │ ├────┼──────┼──────────┼──────────┼──────────┤ │ │ │ 1 │ U001 │ 13800000 │ ******* │ ******* │ │ │ └────┴──────┴──────────┴──────────┴──────────┘ │ └─────────────────────────────────────────────────────────────────┘

6️⃣ 对象转换代码示例

实际项目中的转换

@RestController @RequestMapping("/user") @Slf4j public class UserController extends BaseController { @Autowired private UserService userService; @Autowired private UserCardService userCardService; /** * 根据Token获取用户信息 * * 【数据流转】 * 1. 从数据库查询 Entity(包含所有字段) * 2. Entity 转换为 VO(只包含安全字段) * 3. 关联查询银行卡(补充数据) * 4. 返回 VO 给前端 */ @GetMapping("/findByToken") public ApiResponse<UserVo> findByToken() { // ========== ① 查询 Entity ========== Integer userId = LoginContext.getUserId(); User user = userService.findById(userId); // Entity 对象 // 校验用户存在 Asserts.notNull(user, -10001, "登录失效"); // ========== ② Entity 转 VO ========== // 使用 BeanUtil 复制属性(只复制同名字段) UserVo userVo = BeanUtil.copyProperties(user, UserVo.class); // ========== ③ 补充数据 ========== // 查询关联的银行卡列表 List<UserCard> cards = userCardService.findByUserId(user.getId()); userVo.setCards(cards); // 设置计算字段 userVo.setHasWechat(user.getOpenid() != null); userVo.setIsRealAuth(user.getCardno() != null); // 脱敏处理 if (user.getMobile() != null) { userVo.setMobile(desensitizeMobile(user.getMobile())); } if (user.getCardno() != null) { userVo.setCardno(desensitizeCardNo(user.getCardno())); } // ========== ④ 返回 VO ========== return ApiResponse.ok(userVo); } /** * 手机号脱敏 * 13800138000 -> 138****8000 */ private String desensitizeMobile(String mobile) { if (mobile == null || mobile.length() != 11) { return mobile; } return mobile.substring(0, 3) + "****" + mobile.substring(7); } /** * 身份证号脱敏 * 320102199001011234 -> 320***********1234 */ private String desensitizeCardNo(String cardNo) { if (cardNo == null || cardNo.length() < 8) { return cardNo; } return cardNo.substring(0, 3) + "***********" + cardNo.substring(cardNo.length() - 4); } }

使用工具类转换(推荐)

import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.bean.copier.CopyOptions; /** * 对象转换工具类 */ public class BeanConverter { /** * Entity 转 VO * 自动忽略 null 值 */ public static <T> T toVo(Object source, Class<T> targetClass) { if (source == null) { return null; } return BeanUtil.copyProperties(source, targetClass, CopyOptions.create().ignoreNullValue()); } /** * Entity List 转 VO List */ public static <S, T> List<T> toVoList(List<S> sourceList, Class<T> targetClass) { if (sourceList == null || sourceList.isEmpty()) { return Collections.emptyList(); } return sourceList.stream() .map(source -> toVo(source, targetClass)) .collect(Collectors.toList()); } /** * Form 转 Entity */ public static <T> T toEntity(Object form, Class<T> entityClass) { if (form == null) { return null; } T entity = BeanUtil.copyProperties(form, entityClass); // 设置创建时间等默认字段 if (entity instanceof BaseEntity) { ((BaseEntity) entity).setCreateTime(new Date()); } return entity; } } // 使用示例 @Service public class UserServiceImpl implements UserService { @Override public UserVo getUserInfo(Integer userId) { // 1. 查询 Entity User user = userDao.findById(userId); // 2. 转换为 VO UserVo vo = BeanConverter.toVo(user, UserVo.class); // 3. 补充额外数据 vo.setCards(userCardService.findByUserId(userId)); return vo; } @Override public List<UserVo> getUserList(List<Integer> userIds) { // 1. 批量查询 Entity List<User> users = userDao.findByIds(userIds); // 2. 批量转换为 VO return BeanConverter.toVoList(users, UserVo.class); } }

7️⃣ 为什么要分这么多对象?

核心原因

1. 安全性
// ❌ 错误:直接返回 Entity @GetMapping("/user/{id}") public ApiResponse<User> getUser(@PathVariable Integer id) { User user = userService.findById(id); return ApiResponse.success(user); // 密码、盐值都返回了! } // 前端收到的数据(危险!) { "id": 123, "mobile": "13800138000", "password": "e10adc3949ba59abbe56e057f20f883e", // MD5密码 "salt": "a1b2c3d4", // 盐值暴露 "cardno": "320102199001011234" // 身份证明文 } // ✅ 正确:返回 VO @GetMapping("/user/{id}") public ApiResponse<UserVo> getUser(@PathVariable Integer id) { User user = userService.findById(id); UserVo vo = BeanUtil.copyProperties(user, UserVo.class); // VO 中没有 password、salt 字段 return ApiResponse.success(vo); } // 前端收到的数据(安全) { "id": 123, "mobile": "138****8000", // 脱敏 "cardno": "320***********1234" // 脱敏 }
2. 解耦
// 数据库表结构变更,不影响前端 // 数据库改了字段名:user_name -> real_name @Entity public class User { @Column(name = "real_name") // 数据库字段改了 private String realname; // Java字段不变 } // VO 不变,前端不受影响 public class UserVo { private String realname; // 前端继续用原来的字段 }
3. 灵活性
// VO 可以包含 Entity 没有的计算字段 public class UserVo { private Integer id; private String realname; // ========== 【计算字段】 ========== // Entity 中没有这些字段 private Integer age; // 根据生日计算 private String statusText; // 根据status转换(1->正常,2->冻结) private Boolean isVip; // 根据会员等级判断 private String createTimeText; // 格式化日期(2024-01-15) // ========== 【关联数据】 ========== // Entity 中没有这些字段 private List<UserCard> cards; // 关联的银行卡 private Integer orderCount; // 订单数量(统计) private BigDecimal totalAmount; // 总消费金额(统计) }
4. 职责分离
// 每个对象都有明确的职责 Entity: 负责与数据库交互 ↓ DTO: 负责在Service层传递数据 ↓ VO: 负责返回给前端展示 Form: 负责接收前端提交的数据 ↓ DTO: 负责在Service层传递数据 ↓ Entity: 负责保存到数据库

8️⃣ 实战完整流程示例

用户注册完整流程

// ========== ① 前端提交表单 ========== // POST /user/register // Body: { "mobile": "13800138000", "code": "1234", "password": "abc123" } // ========== ② Controller 接收 Form ========== @RestController @RequestMapping("/user") public class UserController { @Autowired private UserService userService; @PostMapping("/register") public ApiResponse<UserTokenDTO> register( @Valid @RequestBody UserMobileRegisterDTO form) { // Form 对象 log.info("用户注册: mobile={}", form.getMobile()); // 调用 Service,传递 Form,接收 DTO UserTokenDTO dto = userService.register(form); // 返回 DTO 给前端 return ApiResponse.ok(dto); } } // ========== ③ Service 处理业务逻辑 ========== @Service @Slf4j public class UserServiceImpl implements UserService { @Autowired private UserRepository userDao; @Autowired private SmsService smsService; @Override @Transactional(rollbackFor = Exception.class) public UserTokenDTO register(UserMobileRegisterDTO form) { // 1. 校验验证码 boolean valid = smsService.validateCode(form.getMobile(), form.getCode()); Asserts.isTrue(valid, "验证码错误"); // 2. 检查手机号是否已注册 User existUser = userDao.findByMobile(form.getMobile()); Asserts.isNull(existUser, "手机号已注册"); // 3. Form 转 Entity User user = new User(); user.setNo(generateUserNo()); // 生成用户编号 user.setMobile(form.getMobile()); // 手机号 user.setRealname("用户" + user.getNo()); // 默认昵称 // 4. 密码加密 String salt = UUID.randomUUID().toString(); String encryptedPwd = Secure.encryptPassword(form.getPassword(), salt); user.setSalt(salt); user.setPassword(encryptedPwd); // 5. 设置默认值 user.setStatus(1); // 正常 user.setDeleted(0); // 未删除 user.setCreateTime(new Date()); user.setUpdateTime(new Date()); // 6. 保存到数据库(Entity) userDao.save(user); log.info("用户注册成功: userId={}", user.getId()); // 7. 生成 Token String token = JwtUtil.generateToken(user.getId(), user.getNo()); // 8. 构建 DTO 返回 return UserTokenDTO.builder() .userId(user.getId()) .userNo(user.getNo()) .userName(user.getRealname()) .token(token) .expiresIn(7200L) // 2小时 .firstLogin(true) .build(); } private String generateUserNo() { return "U" + System.currentTimeMillis(); } } // ========== ④ DAO 保存 Entity ========== @Repository public interface UserRepository extends JpaRepository<User, Integer> { /** * 根据手机号查询用户 */ User findByMobile(String mobile); /** * 根据用户编号查询 */ User findByNo(String no); } // ========== ⑤ 数据库存储 ========== // INSERT INTO tb_user // (no, mobile, realname, password, salt, status, deleted, create_time, update_time) // VALUES // ('U1704528000123', '13800138000', '用户U1704528000123', // 'e10adc3949ba59abbe56e057f20f883e', 'a1b2c3d4', 1, 0, NOW(), NOW()); // ========== ⑥ 返回给前端 ========== // Response: { "code": 0, "message": "成功", "data": { "userId": 123, "userNo": "U1704528000123", "userName": "用户U1704528000123", "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "expiresIn": 7200, "firstLogin": true } }

9️⃣ 最佳实践与规范

推荐做法

1. Entity 使用规范
✅ DO: - 只在 DAO/Mapper 层使用 - 字段名与数据库列名对应 - 包含完整的数据库注解 - 不要有业务逻辑代码 ❌ DON'T: - 不要在 Controller 中直接返回 Entity - 不要在 Entity 中写复杂的方法 - 不要让前端知道 Entity 的结构
2. VO 使用规范
✅ DO: - 只包含前端需要的字段 - 敏感字段要脱敏 - 可以包含计算字段 - 可以包含关联数据 - 只在 Controller 返回时使用 ❌ DON'T: - 不要包含密码、盐值等敏感字段 - 不要包含数据库注解 - 不要在 Service 层使用
3. DTO 使用规范
✅ DO: - 在 Service 层之间传递数据 - 在微服务之间传递数据 - 可以包含多个 Entity 的数据 - 可以包含业务状态信息 ❌ DON'T: - 不要直接暴露给前端 - 不要包含数据库操作
4. Form 使用规范
✅ DO: - 只在 Controller 接收前端数据 - 包含完整的校验注解 - 一个接口一个 Form - 字段命名清晰 ❌ DON'T: - 不要在 Service 层定义 Form - 不要在 Form 中写业务逻辑

🔟 对比总结表


对象类型

作用

使用层级

主要特点

是否包含敏感字段

Entity

数据库映射

DAO/Mapper

与表一一对应,包含数据库注解

✅ 是

VO

返回给前端

Controller

只包含展示字段,脱敏处理

❌ 否

DTO

服务间传输

Service

跨层传输数据,业务对象

🔸 视情况而定

Form

接收前端数据

Controller

包含校验注解,参数验证

🔸 可能包含


总结:Entity、VO、DTO、Form 是项目分层架构的重要体现,每个对象都有明确的职责。理解它们的区别和转换逻辑,是掌握项目架构的关键!🚀
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/18 3:33:07

GeoJSON.io终极指南:快速创建和编辑地理数据的免费神器

GeoJSON.io终极指南&#xff1a;快速创建和编辑地理数据的免费神器 【免费下载链接】geojson.io A quick, simple tool for creating, viewing, and sharing spatial data 项目地址: https://gitcode.com/gh_mirrors/ge/geojson.io 想要在地图上轻松标记位置、绘制路线或…

作者头像 李华
网站建设 2026/4/19 20:40:33

MySQL索引使用--最左前缀法则

验证索引效率在未建立索引之前&#xff0c;执行如下SQL语句&#xff0c;查询SQL的耗时&#xff1a;select * from tb_sku where snSN0003450001针对字段创建索引create index idx_sku_sn on tb_sku(sn);创建完索引之后&#xff0c;再来看这条查询sql的耗时。查看sql的执行计划最…

作者头像 李华
网站建设 2026/4/19 12:24:19

Atlas200赋能水稻病虫害精准识别:AI+边缘计算守护粮食安全

Atlas200赋能水稻病虫害精准识别&#xff1a;AI边缘计算守护粮食安全 作为全球三大粮食作物之一&#xff0c;水稻的产量安全直接关系到全球粮食供给稳定。然而&#xff0c;细菌性穗枯病、稻瘟病等常见病虫害常导致水稻减产甚至绝收&#xff0c;传统人工识别方式不仅效率低下&am…

作者头像 李华
网站建设 2026/4/19 8:52:03

2025低成本学AI:实用认证推荐

在技术快速发展的今天&#xff0c;掌握相关技能已成为许多职场人士关注的方向。其中&#xff0c;人工智能相关知识的了解与应用能力&#xff0c;正在成为一项有价值的补充技能。本文将介绍几个不同方向的入门级认证&#xff0c;供有需要的学习者参考选择。CAIE注册人工智能工程…

作者头像 李华