Controller Service Mapper Entity学习记录
在开始学习SpringBoot时,出现Controller,Service,Mapper,Entity的新名词时,不免会一头雾水,不知道它们是什么意思。即使搜索了解释,也不太明白。这里,我想记录我的学习过程,通过一个功能的实现,来看看Controller,Service,Mapper,Entity分别的含义以及它们所扮演的角色。
在软件开发中,特别是在面向对象的编程中,通常会使用一种分层架构来组织代码。在这种架构中,常见的层级包括控制器(Controller)、服务(Service)、映射器(Mapper)和实体(Entity)。
Controller
在分层架构中,控制器(Controller)是其中的一个关键组件,负责处理用户的输入,协调应用程序的各个部分,并将结果返回给用户界面。分层架构通常将应用程序分为多个层次,包括用户界面层、应用程序逻辑层、数据访问层等,而控制器主要属于用户界面层。
在分层架构中的控制器的主要作用包括:
-
接收用户输入: 控制器负责接收来自用户的请求和输入。这可以包括从前端界面、API调用、命令行等方式传递的用户请求。
-
解析和验证输入: 控制器对接收到的用户输入进行解析和验证,确保输入的格式正确、完整,并符合应用程序的预期要求。这有助于防止无效或恶意的输入对应用程序造成问题。
-
调用服务层: 一旦用户输入得到解析和验证,控制器会调用应用程序逻辑层中的服务(Service)来处理业务逻辑。服务层包含了应用程序的核心业务规则,而控制器负责协调服务层的方法调用。
-
协调组件: 控制器协调应用程序中的不同组件,如调用多个服务方法、管理事务等。它确保各个组件协同工作,以完成用户请求的功能。
-
返回结果: 控制器接收从服务层返回的结果,将其转化为适当的格式,并返回给用户界面。这可以包括渲染视图、返回JSON数据等方式,具体取决于应用程序的架构和需求。
-
处理异常: 控制器负责捕获和处理可能发生的异常。它可以处理业务逻辑异常、输入验证失败等情况,并返回适当的错误信息给用户。
控制器在分层架构中起到了将用户输入与应用程序逻辑隔离的作用,实现了关注点分离。这使得控制器可以更容易地测试、维护和扩展,同时提高了代码的可读性和可维护性。
Service
在分层架构中,服务(Service)层是应用程序逻辑的核心组件,负责处理业务逻辑、执行操作并协调不同的模块。服务层通常位于应用程序逻辑层,主要职责包括以下方面:
-
业务逻辑的实现: 服务层包含应用程序的业务逻辑,实现了与业务相关的功能和规则。这些功能可能涉及到多个实体对象的操作,需要进行复杂的计算或决策。
-
接收和处理用户输入: 服务层接收来自控制器的用户请求,解析和验证输入,执行相应的业务逻辑。这使得控制器可以专注于用户交互,而服务层处理具体的业务规则。
-
与数据访问层的交互: 服务层负责与数据访问层(如Mapper)进行交互,执行数据的持久化和检索操作。这包括将业务对象转化为数据库中的记录,以及从数据库中检索数据并将其映射到业务对象。
-
事务管理: 在需要进行事务操作的情况下,服务层负责管理事务的开始、提交或回滚。这确保在一系列相关操作中的任何一个失败时,整个操作序列都能够保持一致性。
-
封装业务规则: 服务层将业务规则封装在一个可重用的单元中。这有助于提高代码的模块化性和可维护性,同时允许其他部分的代码调用并复用这些规则。
-
提供API: 服务层通常会提供一个API(Application Programming Interface),供其他层次的组件调用。这种API定义了可用于执行业务逻辑的方法和操作。
服务层在分层架构中扮演着连接用户界面层和数据访问层之间的桥梁,负责协调各个组件的工作,执行应用程序的核心业务逻辑。这种分层结构有助于实现关注点分离,提高代码的可维护性、可测试性和可扩展性。
Mapper
在分层架构中,映射器(Mapper)是数据访问层的一个关键组件,主要负责处理实体对象与数据存储(通常是数据库)之间的映射关系。映射器在整个应用程序中起到了数据持久化和检索的桥梁作用。映射器的主要职责和特点:
-
实体与数据存储的映射: 映射器负责将应用程序中的实体对象与数据存储中的记录进行映射。这包括将实体对象的属性映射到数据库表的字段,以及将数据库表中的数据映射为实体对象。
-
数据的持久化: 映射器处理将实体对象的状态持久化到数据存储中的操作。这通常涉及插入、更新、删除等数据库操作,以确保实体对象的数据与数据库保持同步。
-
数据的检索: 映射器负责从数据存储中检索数据,将其映射为应用程序中的实体对象。这包括执行查询操作,根据条件从数据库中获取数据,并将其转化为实体对象。
-
处理数据关系: 在应用程序中,实体对象之间可能存在关联关系,而数据库中通常通过外键等机制来表示这种关系。映射器负责处理这些关系,确保在数据存储中正确地维护实体对象之间的关联。
-
封装数据库细节: 映射器将数据库相关的细节封装在内部,使得其他层次的组件(如服务层)不必关心数据库的具体操作和结构。这有助于实现关注点分离。
-
提供数据操作接口: 映射器通常会提供一组用于执行数据操作的接口,供服务层或其他组件调用。这些接口定义了插入、更新、删除和查询等操作。
映射器在分层架构中起到了数据持久化和检索的角色,将应用程序中的对象与数据存储之间建立了一个抽象层。这种分离有助于提高代码的可维护性和可测试性,使得应用程序能够更灵活地适应不同的数据存储方式。
Entity
在分层架构中,实体(Entity)是表示应用程序中的领域对象的组件。实体通常包含了与业务领域相关的数据和操作。实体在分层架构中的主要特点和职责:
-
封装业务数据: 实体封装了应用程序中与业务领域相关的数据。这些数据通常是业务对象的属性,反映了业务规则和实体的状态。
-
定义业务操作: 实体包含了与业务领域相关的操作或方法。这些操作通常对实体的状态进行操作,执行业务规则,或者与其他实体进行交互。
-
与数据存储的映射: 实体与数据存储(通常是数据库表)之间有映射关系。映射关系由数据访问层的映射器(Mapper)负责处理,确保实体对象的属性与数据库表的字段相对应。
-
业务规则的实现: 实体中包含了业务规则的具体实现。这有助于保持业务规则的一致性,并确保在进行数据操作时遵循正确的业务逻辑。
-
提供标识: 实体通常有一个唯一标识符,用于在数据存储中唯一标识该实体。这个标识符可以是一个主键,用于在数据库中检索和持久化实体。
-
关联关系的表示: 在应用程序中,实体之间可能存在关联关系。实体可以通过关联关系与其他实体建立联系,这有助于表示业务领域中的复杂关系。
-
独立于用户界面: 实体是领域对象,独立于用户界面的表现形式。这有助于实现关注点分离,确保业务逻辑与用户界面的解耦。
实体在整个应用程序中贯穿了数据访问层和应用程序逻辑层,它们由映射器层进行映射,以便在数据存储和业务逻辑之间建立联系。这种分层结构有助于提高代码的可维护性和可测试性,使得业务规则和数据操作更具灵活性。
举例
这是一个简单的基于Spring Boot框架的员工登录的代码示例。
Employee 实体类:
- 作用:表示员工的领域对象,包含了员工相关的属性和方法。
- 成员变量:表示员工的各个属性,如id、username、name等。
- 注解:使用
@Data
注解简化了 getter、setter、toString 等方法的生成,提高代码可读性。 @TableField
注解用于指定字段的填充策略,如在插入和更新时自动填充创建人和更新人。
// ./Entity/Employee.java
/**
* 员工实体
*/
@Data
public class Employee implements Serializable {
private static final long serialVersionUID = 1L;
private Long id;
private String username;
private String name;
private String password;
private String phone;
private String sex;
private String idNumber; //身份证号码
private Integer status;
private LocalDateTime createTime;
private LocalDateTime updateTime;
@TableField(fill = FieldFill.INSERT)
private Long createUser;
@TableField(fill = FieldFill.INSERT_UPDATE)
private Long updateUser;
}
EmployeeMapper 接口:
- 作用:是MyBatis框架的Mapper接口,用于定义与数据库交互的方法。
- 继承
BaseMapper<Employee>
:表示该接口继承了MyBatis-Plus的BaseMapper
接口,提供了一些基本的数据库操作方法。
// ./Mapper/EmployeeMapper.java
@Mapper
public interface EmployeeMapper extends BaseMapper<Employee> {
}
EmployeeService 接口:
- 作用:定义了与员工相关的业务逻辑操作的接口。
- 继承
IService<Employee>
:表示该接口继承了MyBatis-Plus的IService
接口,提供了一些基本的服务层操作方法。
// ./Service/EmployeeService.java
public interface EmployeeService extends IService<Employee> {
}
EmployeeServiceImpl 类:
- 作用:是
EmployeeService
接口的实现类,实现了具体的业务逻辑。 - 继承了
ServiceImpl<EmployeeMapper, Employee>
:表示该类继承了MyBatis-Plus的ServiceImpl
类,提供了基于EmployeeMapper
的业务逻辑实现
// ./Service/impl/EmployeeServiceImpl.java
@Service
public class EmployeeServiceImpl extends ServiceImpl<EmployeeMapper, Employee> implements EmployeeService {
}
EmployeeController 类:
- 作用:是处理与员工相关的HTTP请求的控制器。
- 注解:
@RestController
表示这是一个REST风格的控制器,@RequestMapping("/employee")
指定了该控制器处理的请求路径前缀。 - 依赖注入:使用
@Autowired
注解注入了EmployeeService
实例。 - 登录功能:
@PostMapping("/login")
处理了登录请求,通过加密密码,查询数据库,比对密码,检查员工状态,最终返回登录结果。登录成功后将员工id存入session。
// ./controller/employeeController.java
@Slf4j
@RestController
@RequestMapping("/employee")
public class EmployeeController {
@Autowired
private EmployeeService employeeService;
/**
* 员工登录
* @param request
* @param employee
* @return
*/
@PostMapping("/login")
public R<Employee> login(HttpServletRequest request, @RequestBody Employee employee){
/**
* 1、将页面提交的密码password进行md5加密处理
* 2、根据页面提交的用户名username查询数据库
* 3、如果没有查询到则返回登录失败结果
* 4、密码比对,如果不一致则返回登录失败结果
* 5、查看员工状态,如果为已禁用状态,则返回员工已禁用结果
* 6、登录成功,将员工id存入session并返回登陆成功结果
*/
String password = employee.getPassword();
password = DigestUtils.md5DigestAsHex(password.getBytes());
LambdaQueryWrapper<Employee> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(Employee::getUsername, employee.getUsername());
Employee emp = employeeService.getOne(queryWrapper); //username有唯一约束
if(emp == null){
return R.error("用户不存在");
}
if(!emp.getPassword().equals(password)){
return R.error("密码错误");
}
if(emp.getStatus() == 0){
return R.error("账号已禁用");
}
request.getSession().setAttribute("employee", emp.getId());
return R.success(emp);
}
}