3.6、Service层实现
分类: 搭建单体商城服务
Service 层实现
Service 层是业务逻辑层,负责处理业务逻辑,协调 Repository 层和 Controller 层。MyBatis-Plus 提供了 IService 接口,简化了 Service 层的实现。本节将学习如何实现 Service 层。
本节将学习:Service 接口设计、ServiceImpl 实现、业务逻辑编写,以及事务管理。
Service 接口设计
IService 接口
IService 是 MyBatis-Plus 提供的通用 Service 接口,包含了基础的 CRUD 方法。
Service 接口定义
package com.example.ecommerce.service; import com.baomidou.mybatisplus.extension.service.IService; import com.example.ecommerce.entity.User; public interface UserService extends IService<User> { /** * 用户注册 */ User register(User user); /** * 用户登录 */ User login(String username, String password); /** * 根据用户名查询用户 */ User getByUsername(String username); }
IService 提供的方法
IService 常用方法:
boolean save(T entity):保存一条记录boolean saveBatch(Collection<T> entityList):批量保存boolean removeById(Serializable id):根据 ID 删除boolean updateById(T entity):根据 ID 更新T getById(Serializable id):根据 ID 查询List<T> list():查询所有Page<T> page(Page<T> page):分页查询
ServiceImpl 实现
ServiceImpl 类
ServiceImpl 是 MyBatis-Plus 提供的通用 Service 实现类,实现了 IService 接口的所有方法。
Service 实现类
package com.example.ecommerce.service.impl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.example.ecommerce.entity.User; import com.example.ecommerce.mapper.UserMapper; import com.example.ecommerce.service.UserService; import org.springframework.stereotype.Service; @Service public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService { @Override public User register(User user) { // 业务逻辑实现 return null; } @Override public User login(String username, String password) { // 业务逻辑实现 return null; } @Override public User getByUsername(String username) { // 业务逻辑实现 return null; } }
业务逻辑编写
用户注册业务逻辑
@Service public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService { @Autowired private PasswordEncoder passwordEncoder; @Override @Transactional(rollbackFor = Exception.class) public User register(User user) { // 1. 检查用户名是否已存在 User existUser = baseMapper.selectOne( new LambdaQueryWrapper<User>() .eq(User::getUsername, user.getUsername()) ); if (existUser != null) { throw new BusinessException("Username already exists"); } // 2. 检查邮箱是否已存在 existUser = baseMapper.selectOne( new LambdaQueryWrapper<User>() .eq(User::getEmail, user.getEmail()) ); if (existUser != null) { throw new BusinessException("Email already exists"); } // 3. 加密密码 user.setPassword(passwordEncoder.encode(user.getPassword())); // 4. 设置默认状态 user.setStatus(1); // 5. 保存用户 save(user); return user; } }
用户登录业务逻辑
@Override public User login(String username, String password) { // 1. 根据用户名查询用户 User user = baseMapper.selectOne( new LambdaQueryWrapper<User>() .eq(User::getUsername, username) ); if (user == null) { throw new BusinessException("User not found"); } // 2. 检查用户状态 if (user.getStatus() == 0) { throw new BusinessException("User is disabled"); } // 3. 验证密码 if (!passwordEncoder.matches(password, user.getPassword())) { throw new BusinessException("Invalid password"); } return user; }
业务逻辑流程
事务管理
@Transactional 注解
@Transactional 用于声明事务,确保方法内的多个数据库操作要么全部成功,要么全部回滚。
事务使用示例
@Service public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements OrderService { @Autowired private OrderItemService orderItemService; @Autowired private ProductService productService; @Override @Transactional(rollbackFor = Exception.class) public Order createOrder(Order order, List<OrderItem> orderItems) { // 1. 计算订单总金额 BigDecimal totalAmount = orderItems.stream() .map(item -> item.getPrice().multiply(BigDecimal.valueOf(item.getQuantity()))) .reduce(BigDecimal.ZERO, BigDecimal::add); order.setTotalAmount(totalAmount); // 2. 保存订单 save(order); // 3. 保存订单项 orderItems.forEach(item -> { item.setOrderId(order.getId()); orderItemService.save(item); }); // 4. 扣减库存 orderItems.forEach(item -> { productService.deductStock(item.getProductId(), item.getQuantity()); }); return order; } }
事务传播行为
事务传播行为说明:
- REQUIRED:如果当前存在事务,则加入该事务;如果当前不存在事务,则创建一个新的事务(默认)
- REQUIRES_NEW:创建一个新的事务,如果当前存在事务,则把当前事务挂起
- SUPPORTS:如果当前存在事务,则加入该事务;如果当前不存在事务,则以非事务的方式继续运行
- NOT_SUPPORTED:以非事务的方式运行,如果当前存在事务,则把当前事务挂起
- MANDATORY:如果当前存在事务,则加入该事务;如果当前不存在事务,则抛出异常
- NEVER:以非事务的方式运行,如果当前存在事务,则抛出异常
- NESTED:如果当前存在事务,则创建一个嵌套事务;如果当前不存在事务,则创建一个新的事务
完整 Service 示例
UserService 完整示例
package com.example.ecommerce.service; import com.baomidou.mybatisplus.extension.service.IService; import com.example.ecommerce.entity.User; public interface UserService extends IService<User> { User register(User user); User login(String username, String password); User getByUsername(String username); User getByEmail(String email); boolean updatePassword(Long userId, String oldPassword, String newPassword); }
package com.example.ecommerce.service.impl; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.example.ecommerce.entity.User; import com.example.ecommerce.mapper.UserMapper; import com.example.ecommerce.service.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @Service public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService { @Autowired private PasswordEncoder passwordEncoder; @Override @Transactional(rollbackFor = Exception.class) public User register(User user) { // 检查用户名和邮箱是否已存在 if (getByUsername(user.getUsername()) != null) { throw new BusinessException("Username already exists"); } if (getByEmail(user.getEmail()) != null) { throw new BusinessException("Email already exists"); } // 加密密码 user.setPassword(passwordEncoder.encode(user.getPassword())); user.setStatus(1); // 保存用户 save(user); return user; } @Override public User login(String username, String password) { User user = getByUsername(username); if (user == null || user.getStatus() == 0) { throw new BusinessException("Invalid username or password"); } if (!passwordEncoder.matches(password, user.getPassword())) { throw new BusinessException("Invalid username or password"); } return user; } @Override public User getByUsername(String username) { return baseMapper.selectOne( new LambdaQueryWrapper<User>() .eq(User::getUsername, username) ); } @Override public User getByEmail(String email) { return baseMapper.selectOne( new LambdaQueryWrapper<User>() .eq(User::getEmail, email) ); } @Override @Transactional(rollbackFor = Exception.class) public boolean updatePassword(Long userId, String oldPassword, String newPassword) { User user = getById(userId); if (user == null) { throw new BusinessException("User not found"); } if (!passwordEncoder.matches(oldPassword, user.getPassword())) { throw new BusinessException("Invalid old password"); } user.setPassword(passwordEncoder.encode(newPassword)); return updateById(user); } }
官方资源
- MyBatis-Plus IService:https://baomidou.com/pages/49cc81/#service-crud
- Spring 事务管理:https://docs.spring.io/spring-framework/reference/data-access/transaction.html
本节小结
在本节中,我们学习了:
第一个是 Service 接口设计。 继承 IService 接口,定义业务方法。
第二个是 ServiceImpl 实现。 继承 ServiceImpl 类,实现业务逻辑。
第三个是业务逻辑编写。 实现用户注册、登录等业务逻辑。
第四个是事务管理。 使用 @Transactional 注解管理事务。
这就是 Service 层实现。Service 层封装业务逻辑,是系统的核心层。
在下一节,我们将学习如何实现 Controller 层,提供 RESTful API。