自学SpringBoot笔记
概念
什么是SpringBoot?
Spring Boot 是基于 Spring Framework 的一款开源框架,主要用于简化 Spring 应用程序的开发。它通过提供一系列的 开箱即用的功能 和 自动配置,让开发者可以快速构建生产级别的独立应用程序,而无需手动配置大量的 XML 或注解。
Spring Boot 的目标是让开发者能够专注于业务逻辑,减少繁杂的配置工作,从而提升开发效率。
什么是 Spring MVC?
Spring MVC(Model-View-Controller)是 Spring Framework 中的一个模块,专门用于构建基于 HTTP 的 Web 应用程序,它遵循经典的 MVC 架构模式。Spring MVC 提供了一套灵活、强大的工具,用于开发动态 Web 应用或 RESTful API。
通过 Spring MVC,开发者可以轻松处理 HTTP 请求、业务逻辑和视图层的渲染,同时保持应用的模块化和可维护性。
Spring MVC 的核心概念
Spring MVC 基于 Model-View-Controller 模式,将应用分为以下三个部分:
1. Model(模型)
- 表示应用程序的数据或业务逻辑。
- 通常由 POJO(Plain Old Java Object)或 DTO(数据传输对象)组成。
- 在实际开发中,
Model
通常是从数据库中获取的业务实体。
2. View(视图)
- 负责将数据(Model)渲染为用户可以看到的页面或响应数据。
- 支持多种视图技术,例如 JSP、Thymeleaf、FreeMarker 等。
- 对于 RESTful 应用,视图层通常是 JSON 或 XML 格式的响应。
3. Controller(控制器)
- 负责接收用户请求,并将其分发给合适的服务或处理逻辑。
- 控制器将数据与视图进行绑定,最终返回一个完整的响应。
Spring MVC 的工作流程
- 用户通过浏览器发送一个 HTTP 请求。
- 请求被 Spring MVC 的 DispatcherServlet 拦截。
- DispatcherServlet 将请求分发给合适的 Controller。
- Controller 调用业务逻辑层或服务层,获取数据并封装为 Model。
- DispatcherServlet 将返回的数据传递给指定的视图(View)。
- 视图渲染最终的 HTML 页面或响应数据,并返回给用户。
Spring MVC 的核心组件
以下是 Spring MVC 的几个核心组件及其作用:
1. DispatcherServlet
- 是 Spring MVC 的核心,负责拦截所有 HTTP 请求。
- 它将请求分发给适当的处理器(Controller)并协调其他组件(如视图解析器和模型绑定器)。
2. Controller
- 使用注解(如
@Controller
或@RestController
)标注的类,用于处理业务逻辑。 - 处理用户请求并返回数据或视图。
3. ModelAndView
- 一个对象,用于封装数据(Model)和视图(View)。
- Controller 可以返回
ModelAndView
来指定渲染的数据和视图名称。
4. ViewResolver(视图解析器)
- 负责将逻辑视图名称转换为具体的视图。
- 例如,将返回的视图名
home
映射到home.jsp
或home.html
。
5. HandlerMapping
- 负责将用户请求 URL 映射到具体的 Controller 方法。
6. Model
- 用于在 Controller 和 View 之间传递数据。
springboot架构
首先我们先看下面这张图,待会会根据该图中的各个层进行项目创建:
Maven上手
这里我们使用IDEA进行Maven项目的创建,这里我们选择Maven创建:
这里我们选择springWeb
和mysql
:
pom.xml
如果我们后续还需要添加依赖的话,可以直接在项目的pom.xml中的<dependencys>
中添加依赖:
配置文件
在application.properties
中,我们可以配置数据库的连接、后端端口等内容:
项目结构
仿照上图的SpringBoot架构,我们创建以下文件夹来划分各个层次:
什么是 POJO?
POJO 是 Plain Old Java Object 的缩写,意为“普通的旧式 Java 对象”。它是一个 纯粹的 Java 对象,不依赖于任何特定的框架或库,通常只包含 属性、构造方法、Getter 和 Setter 方法 以及少量的业务逻辑。
POJO 的核心思想是保持对象简单、轻量化,避免引入框架特定的依赖或复杂的特性(如继承特定的类或实现框架接口)。
POJO 的特点
-
轻量化:
- 没有继承任何框架特定的类(如
HttpServlet
)。 - 不实现任何框架特定的接口(如
Serializable
除外)。
- 没有继承任何框架特定的类(如
-
纯粹性:
- 只包含简单的属性(字段)和方法(如 Getter 和 Setter)。
- 不依赖框架代码,适用于任何 Java 环境。
-
无强制要求:
- POJO 不需要遵循特定规范,只要是普通的 Java 对象即可。
POJO 的常见用途
-
数据传输对象(DTO):
- 用于在不同层(如 Controller 和 Service 层)之间传输数据的对象。
- 通常只包含属性和 Getter/Setter 方法。
-
实体类(Entity):
- 用于映射数据库表的类,通常用于 ORM 框架(如 Hibernate、JPA)。
- 每个字段对应数据库表中的一列。
-
模型类:
- 用于封装业务逻辑中的数据模型。
-
配置类:
- 用于封装应用程序的配置信息。
pojo的示例——user
package com.jiaowu.backend.pojo;import jakarta.persistence.*;@Table(name = "tb_user")
@Entity
public class User {@Id@GeneratedValue(strategy = GenerationType.IDENTITY)@Column(name="user_id")private Integer id;@Column(name="user_name")private String name;@Column(name="user_password")private String password;@Column(name="user_email")private String email;public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}public String getEmail() {return email;}public void setEmail(String email) {this.email = email;}@Overridepublic String toString() {return "User{" +"id=" + id +", name='" + name + '\'' +", password='" + password + '\'' +", email='" + email + '\'' +'}';}
}
注解总结
以下是代码中各注解的作用和含义:
1. @Table(name = "tb_user")
- 作用:指定该实体类对应的数据库表名称。
- 解释:将类
User
映射到名为tb_user
的数据库表。如果不加该注解,默认表名会与类名一致。
2. @Entity
- 作用:将该类标记为一个 JPA 实体类。
- 解释:
User
类会被 JPA 识别为数据库中的一个表实体,JPA 会根据该类的属性与注解生成对应的数据库表操作。
3. @Id
- 作用:指定该字段为主键。
- 解释:
id
字段是数据库表tb_user
的主键。每个实体对象都需要一个唯一标识,@Id
用来表明哪个字段是主键。
4. @GeneratedValue(strategy = GenerationType.IDENTITY)
- 作用:定义主键的生成策略。
- 解释:
- 使用 自增策略(
IDENTITY
生成方式),即数据库会自动生成主键值(如 MySQL 的自增主键)。 - 每次插入新数据时,
id
字段的值会由数据库自动递增。
- 使用 自增策略(
5. @Column(name = "user_id")
- 作用:将实体类的字段映射到数据库表中的列,并指定列名。
- 解释:
id
字段映射到数据库表tb_user
中的user_id
列。- 如果不加
@Column
注解,JPA 会默认将字段名与列名一致(如字段名为id
,则列名也为id
)。
6. @Column(name = "user_name")
- 作用:将
name
字段映射到数据库表中的user_name
列。
7. @Column(name = "user_password")
- 作用:将
password
字段映射到数据库表中的user_password
列。
8. @Column(name = "user_email")
- 作用:将
email
字段映射到数据库表中的user_email
列。
代码的注解功能:
-
类级别注解:
@Entity
:将类标记为 JPA 实体类。@Table(name = "tb_user")
:将类与数据库表tb_user
进行映射。
-
字段级别注解:
@Id
:标识主键字段。@GeneratedValue(strategy = GenerationType.IDENTITY)
:主键使用数据库的自增策略。@Column(name = "xxx")
:将字段映射到数据库表的指定列名。
通过这些注解,JPA 框架可以自动将类 User
与数据库表 tb_user
关联起来,并根据类的字段与数据库列之间的映射关系,帮助开发者进行数据库操作(如增删改查)。
备注
标记为 JPA 实体类的作用
在 Java Persistence API(JPA)中,将类标记为实体类(通过 @Entity
注解)有以下作用:
1. 将类映射为数据库表
@Entity
告诉 JPA 框架,这个类是一个 实体类,需要与数据库中的表进行映射。- 每个实体类的实例(对象)对应数据库表中的一行数据。
- 类的字段(属性)通过注解(如
@Column
)映射到数据库表的列。
示例:
@Entity
@Table(name = "tb_user")
public class User {@Idprivate Integer id; // 对应 tb_user 表的主键列private String name; // 对应 tb_user 表中的 name 列
}
总结
将类标记为 JPA 实体类的作用主要体现在以下几个方面:
- 映射类与数据库表的关系:通过注解定义类与表、字段与列的映射规则。
- 启用 ORM 功能:实现对象与数据库记录的自动转换,简化数据操作。
- 支持持久化操作:通过 JPA 的 API 或框架(如 Spring Data JPA)操作数据库,而无需手写 SQL。
- 与数据库表结构集成:支持自动生成或更新表结构,便于维护。
- 增强功能支持:如关联关系管理、懒加载、级联操作等。
controller
这里我们写好了用于各个层之间交换的数据结构后,我们就开始正式进行后端项目的功能的编写。这里我们从controller层开始写。我们在这里只需要使用对数据库的增删改查功能:
package com.jiaowu.backend.controller;import com.jiaowu.backend.pojo.ResponseMessage;
import com.jiaowu.backend.pojo.User;
import com.jiaowu.backend.pojo.dto.UserDto;
import com.jiaowu.backend.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;import java.util.List;@RestController //允许接口方法返回对象,转换成json文本
@RequestMapping("/user") // localhost:8080/user/**
public class UserController {@AutowiredIUserService userService;//REST——请求方法//增加@PostMapping // localhost:8080/user method:postpublic ResponseMessage<User> addUser(@Validated @RequestBody UserDto user) {User userNew = userService.add(user);return ResponseMessage.success(userNew);}//查询@GetMapping("/{userId}") // localhost:8080/user/{userId} method:getpublic ResponseMessage<User> get(@PathVariable Integer userId) {User userNew = userService.getUser(userId);return ResponseMessage.success(userNew);}@GetMapping("/all")public ResponseMessage<User> getAll() {List<User> userNew = userService.getAll();return ResponseMessage.success(userNew);}//修改@PutMappingpublic ResponseMessage<User> edit(@Validated @RequestBody UserDto userId) {User userNew = userService.edit(userId);return ResponseMessage.success(userNew);}//删除@DeleteMapping("/{userId}")public ResponseMessage<User> delete(@PathVariable Integer userId) {userService.delete(userId);return ResponseMessage.success();}
}
代码注释总结
以下是代码中各注释的作用与含义:
类级别注解
1. @RestController
- 作用:标识该类为一个 RESTful 控制器。
- 功能:允许接口方法直接返回对象,Spring 会将对象自动转换为 JSON 格式的响应。
2. @RequestMapping("/user")
- 作用:为该控制器类定义一个基础 URL 前缀。
- 功能:所有方法的 URL 都以
/user
开头,例如:localhost:8080/user
成员变量注解
3. @Autowired
- 作用:自动注入
IUserService
接口的实现类。 - 功能:使
userService
变量可以直接调用服务层的逻辑。
方法级别注解
增加用户
4. @PostMapping
- 作用:映射 HTTP POST 请求。
- 功能:处理
localhost:8080/user
的 POST 请求,用于新增用户。
5. @Validated
- 作用:启用数据校验。
- 功能:对请求体中的
UserDto
对象进行校验,例如检查字段的格式或必填项。
6. @RequestBody
- 作用:将 HTTP 请求体的 JSON 数据反序列化为 Java 对象。
- 功能:将客户端发送的用户数据解析为
UserDto
对象。
查询用户
7. @GetMapping("/{userId}")
- 作用:映射 HTTP GET 请求。
- 功能:处理
localhost:8080/user/{userId}
的 GET 请求,用于根据用户 ID 查询用户。
8. @PathVariable
- 作用:将 URL 中的动态路径变量绑定到方法参数。
- 功能:将
{userId}
解析为方法的userId
参数。
9. @GetMapping("/all")
- 作用:映射 HTTP GET 请求。
- 功能:处理
localhost:8080/user/all
的 GET 请求,返回所有用户信息。
修改用户
10. @PutMapping
- 作用:映射 HTTP PUT 请求。
- 功能:处理
localhost:8080/user
的 PUT 请求,用于修改用户信息。
删除用户
11. @DeleteMapping("/{userId}")
- 作用:映射 HTTP DELETE 请求。
- 功能:处理
localhost:8080/user/{userId}
的 DELETE 请求,用于根据用户 ID 删除用户。
方法返回值说明
12. 返回值类型
- 类型:
ResponseMessage<User>
- 作用:封装接口的响应结果,通常包括:
success
:请求是否成功。data
:具体返回的数据(如用户对象或用户列表)。message
:提示信息。
总结
代码功能
- 控制器类:定义了与用户相关的 RESTful 接口,包括新增、查询、修改、删除用户等操作。
- 注解使用:通过 Spring MVC 注解(如
@RestController
、@PostMapping
、@GetMapping
等)简化了接口开发,清晰地定义了请求的类型和 URL 路径。 - 数据流:
- 客户端发送 JSON 请求。
- 通过
@RequestBody
反序列化为 Java 对象。 - 调用服务层逻辑处理数据。
- 最终返回 JSON 格式的响应。
RESTful 接口一览
请求方法 | URL | 描述 |
---|---|---|
POST | /user | 新增用户 |
GET | /user/{userId} | 查询用户 |
GET | /user/all | 查询所有用户 |
PUT | /user | 修改用户 |
DELETE | /user/{userId} | 删除用户 |
repository
这里我们实现数据访问层:
package com.jiaowu.backend.repository;import com.jiaowu.backend.pojo.User;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;@Repository
public interface UserRepository extends CrudRepository<User, Integer> {}
代码分析与注释总结
以下是代码中注释的作用与详细解释:
1. @Repository
- 作用:将接口标记为一个 Spring 数据访问层组件。
- 功能:
- 表示当前接口是一个 DAO(数据访问对象),负责与数据库交互。
- Spring 会将该接口的实现类自动注册为 Bean,并纳入到 Spring 容器中管理。
- 提供数据访问相关的异常转换功能(将底层的数据库异常转换为 Spring 的统一异常,如
DataAccessException
)。
2. public interface UserRepository extends CrudRepository<User, Integer>
- 作用:定义一个 JPA Repository,用于对
User
实体进行 CRUD(增删改查)操作。 - 解释:
UserRepository
:- 是一个接口,继承了 Spring Data 提供的
CrudRepository
接口。 - 不需要手动实现,Spring 会自动生成实现类。
- 是一个接口,继承了 Spring Data 提供的
CrudRepository<User, Integer>
:- 泛型参数解析:
User
:指定该仓库要操作的实体类类型。Integer
:指定主键的类型(id
的数据类型是Integer
)。
- 泛型参数解析:
3. CrudRepository
的功能
CrudRepository
是 Spring Data JPA 提供的一个基础接口,包含了常用的 CRUD 操作方法。通过继承 CrudRepository
,可以直接使用这些方法,无需额外实现。
service
编写业务逻辑层:
package com.jiaowu.backend.service;import com.jiaowu.backend.pojo.User;
import com.jiaowu.backend.pojo.dto.UserDto;
import com.jiaowu.backend.repository.UserRepository;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.util.List;@Service // spring bean
public class UserService implements IUserService {@AutowiredUserRepository userRepository;@Overridepublic User add(UserDto user) {User userPojo = new User();BeanUtils.copyProperties(user, userPojo);return userRepository.save(userPojo);}@Overridepublic User getUser(Integer userId) {return userRepository.findById(userId).orElseThrow(() -> {throw new IllegalArgumentException("用户不存在,参数异常");});}@Overridepublic User edit(UserDto user) {User userPojo = new User();BeanUtils.copyProperties(user, userPojo);return userRepository.save(userPojo);}@Overridepublic void delete(Integer userId) {userRepository.deleteById(userId);}@Overridepublic List<User> getAll() {return (List<User>)userRepository.findAll();}
}
代码分析与注释总结
以下是代码中注释的作用与详细解释:
1. 类级别注解
@Service
- 作用:将该类标记为一个 Spring 服务层组件。
- 功能:
- 表示该类是业务逻辑层的组件(Service Bean),由 Spring 容器管理。
- 通过依赖注入(如
@Autowired
),可以在控制器或其他组件中调用服务层逻辑。
2. 成员变量注解
@Autowired
- 作用:对
UserRepository
进行自动注入。 - 功能:
- Spring 容器会将
UserRepository
的实现类(由 Spring Data JPA 自动生成的代理类)注入到userRepository
中。 - 用于提供数据库操作方法(如
save
、findById
、deleteById
等)。
- Spring 容器会将
3. 方法实现分析
add(UserDto user)
-
作用:新增一个用户。
-
功能:
- 创建一个空的
User
对象(实体类)。 - 使用
BeanUtils.copyProperties
复制UserDto
对象的属性值到User
对象中。 - 调用
userRepository.save()
将用户数据保存到数据库。 - 返回保存后的
User
对象。
- 创建一个空的
-
关键点:
BeanUtils.copyProperties(source, target)
:- Spring 提供的工具类,用于将一个对象的属性值快速复制到另一个对象中。
- 需要确保属性名称和类型一致。
userRepository.save()
:- Spring Data JPA 提供的方法,用于新增或更新数据库记录。
- 如果实体没有主键值,则新增;如果有主键值,则更新。
getUser(Integer userId)
-
作用:根据用户 ID 查询用户。
-
功能:
- 调用
userRepository.findById(userId)
查询用户。 - 如果用户不存在,则抛出
IllegalArgumentException
,提示用户不存在。 - 如果用户存在,返回查询到的
User
对象。
- 调用
-
关键点:
findById(userId)
:- 返回一个
Optional
对象,避免直接返回null
。
- 返回一个
.orElseThrow()
:- 当
Optional
中没有值时,抛出指定的异常。
- 当
edit(UserDto user)
-
作用:编辑用户信息。
-
功能:
- 创建一个空的
User
对象。 - 使用
BeanUtils.copyProperties
将UserDto
的属性复制到User
对象中。 - 调用
userRepository.save()
更新用户信息。 - 返回更新后的
User
对象。
- 创建一个空的
-
关键点:
- 编辑和新增的逻辑非常相似,区别在于:
- 新增时,主键值为
null
,会新增一条记录。 - 编辑时,需要确保传入的对象有主键,否则会新增而不是更新。
- 新增时,主键值为
- 编辑和新增的逻辑非常相似,区别在于:
delete(Integer userId)
-
作用:根据用户 ID 删除用户。
-
功能:
- 调用
userRepository.deleteById(userId)
删除指定用户。
- 调用
-
关键点:
deleteById(userId)
:- Spring Data JPA 提供的方法,根据主键删除对应的记录。
- 如果记录不存在,不会抛出异常(取决于底层数据库实现)。
getAll()
-
作用:查询所有用户。
-
功能:
- 调用
userRepository.findAll()
查询所有用户。 - 将结果转换为
List<User>
并返回。
- 调用
-
关键点:
findAll()
:- 返回一个
Iterable
,可以通过(List<User>)
强制转换为列表。
- 返回一个
- 强制转换是因为
CrudRepository
默认返回Iterable
,而业务通常需要List
。
4. 代码逻辑总结
方法功能一览
方法名称 | 功能描述 |
---|---|
add(UserDto user) | 新增一个用户,将 UserDto 转换为 User 并保存。 |
getUser(Integer userId) | 根据用户 ID 查询用户,不存在则抛出异常。 |
edit(UserDto user) | 编辑用户信息,将传入的 UserDto 更新到数据库中。 |
delete(Integer userId) | 根据用户 ID 删除用户。 |
getAll() | 查询所有用户,返回用户列表。 |
5. 注意点
-
BeanUtils.copyProperties
的使用:- 简化了对象之间的属性赋值,但需要注意:
- 属性名和类型必须一致,否则会跳过不匹配的字段。
- 可能会忽略嵌套对象的处理(例如复杂对象内的字段不会自动复制)。
- 简化了对象之间的属性赋值,但需要注意:
-
异常处理:
- 在
getUser
方法中,使用orElseThrow
抛出异常,保证调用方法时不会出现空指针问题。 - 可以根据业务需求,定义自定义异常类代替
IllegalArgumentException
,提高可读性。
- 在
-
数据类型转换:
getAll
方法中,findAll
返回的是Iterable
,需要手动转换为List
。- 强制类型转换可能会出现问题,建议直接用
Stream
或工具类进行转换。
为什么在业务开发中 Service 层需要定义一个接口?
在业务开发中,通常会为 Service 层定义一个接口(如 IUserService
),然后通过实现类(如 UserService
)实现该接口。这种设计并不是强制性的,但它遵循了良好的软件设计原则,带来了许多实际的好处。
1. 遵循面向接口编程的原则
- 面向接口编程 是软件设计中的重要原则,强调程序应依赖于抽象(接口),而不是具体的实现类。
- 好处:
- 服务调用者(控制器或其他服务)只需要知道接口的方法,而不需要关心具体实现。
- 使代码更加灵活和解耦,方便后续拓展和维护。
dto
不难发现,我们在编写代码的时候,发现使用到了一个中间变量, 也就是还是用于传输的变量,以下是定义:
package com.jiaowu.backend.pojo.dto;import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import org.hibernate.validator.constraints.Length;public class UserDto {public String getName() {return name;}public void setName(String name) {this.name = name;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}public String getEmail() {return email;}public void setEmail(String email) {this.email = email;}public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}private Integer id;@NotBlank(message = "用户名不能为空")private String name;@NotBlank(message = "密码不能为空")@Length(min = 6,max = 12)private String password;@Email(message = "邮箱格式不正确")private String email;@Overridepublic String toString() {return "UserDto{" +"name='" + name + '\'' +", password='" + password + '\'' +", email='" + email + '\'' +'}';}
}
1. 简介
UserDto
是一个 数据传输对象(Data Transfer Object, DTO),用于在客户端和服务端之间传递用户数据。
DTO 的主要职责是:
- 封装用户的请求数据(如新增或编辑用户时的输入)。
- 提供输入验证功能,确保数据的合法性。
2. 字段分析
1. private Integer id
- 解释:
id
是用户的唯一标识,用于编辑或删除用户时的主键。 - 注意:在新增用户时,通常不需要传递
id
,此字段在某些场景下可能为空(如新增用户)。
2. @NotBlank(message = "用户名不能为空")
- 作用:
- 用于验证
name
字段不能为空或全是空格。 - 如果用户未提供
name
,会抛出验证异常,返回自定义错误信息。
- 用于验证
- 适用场景:新增或编辑用户时,用户名为必填项。
3. @NotBlank(message = "密码不能为空")
- 作用:
- 验证
password
字段不能为空或全是空格。
- 验证
- 额外验证:
@Length(min = 6, max = 12)
- 限制密码长度,必须在 6~12 个字符之间。
- 适用场景:新增用户或更新密码时。
4. @Email(message = "邮箱格式不正确")
- 作用:
- 验证
email
是否符合邮箱格式。 - 如果用户提供的邮箱格式不正确,则返回错误信息。
- 验证
- 适用场景:新增或编辑用户时。
字段验证总结
字段名 | 验证注解 | 描述 |
---|---|---|
id | 无 | 主键字段,可为空(新增时)。 |
name | @NotBlank | 用户名不能为空或全是空格。 |
password | @NotBlank + @Length(6, 12) | 密码不能为空,长度必须在 6~12 个字符之间。 |
email | @Email | 检查邮箱格式是否合法。 |
3. 常用方法分析
Getter 和 Setter 方法
- 作用:提供对私有字段的访问和修改。
- 优点:
- 提供封装,保护字段的直接访问。
- 允许对字段的访问进行控制(如添加逻辑验证)。
- 改进建议:
- 可使用 Lombok 简化代码,自动生成
Getter
和Setter
方法,减少代码冗余。
- 可使用 Lombok 简化代码,自动生成
toString
方法
- 作用:
- 重写了
toString
方法,用于输出对象的字符串表示。 - 在调试或日志打印时,便于查看对象内容。
- 重写了
- 改进建议:
- 使用 Lombok 的
@ToString
注解,简化代码。
- 使用 Lombok 的
为什么要使用dto的变量而不是直接使用原来的user呢?
在开发中,DTO
(数据传输对象,Data Transfer Object)常用于 数据传输,特别是在控制器层(Controller)和服务层(Service)之间传递数据,而不是直接使用实体类(如 User
)。
这种设计是一种 分层架构的最佳实践,能够提高代码的灵活性、安全性和可维护性。以下是详细原因和优点:
1. 职责分离
实体类的职责
- 实体类(如
User
)通常是直接与数据库表映射的类(通过 JPA 或 Hibernate 等 ORM 框架)。 - 它的主要职责是反映数据库结构(如字段)和处理持久化逻辑。
DTO 的职责
- DTO 的职责是用来封装和传递客户端请求或响应的 数据结构。
- 它关注的是 数据传输,而不是数据库操作或业务逻辑。
好处:
- 分离了数据传输逻辑和持久化逻辑。
- 使 数据库模型 和 数据传输格式 之间解耦,避免直接暴露数据库模型的结构。
2. 避免暴露实体类的敏感信息
实体类中可能包含一些敏感信息或不需要暴露给客户端的数据(如密码的哈希值、数据库主键等)。
直接使用实体类会导致以下问题:
- 无法控制哪些字段可以被客户端访问或修改。
- 如果实体类字段较多,可能会导致不必要的数据暴露。
统一异常处理
后端处理出现了异常的时候,通常是不用将这个异常情况反馈给前端的,所以我们这里可以定义一个统一的异常处理类来进行返回统一异常信息:
package com.jiaowu.backend.exception;import com.jiaowu.backend.pojo.ResponseMessage;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;@RestControllerAdvice //统一处理
public class GlobalExceptionHanderAdvice {// 记录日志Logger log = LoggerFactory.getLogger(GlobalExceptionHanderAdvice.class);@ExceptionHandler({Exception.class})public ResponseMessage handleException(Exception e, HttpServletRequest request, HttpServletResponse response) {log.error(e.getMessage(), e);return new ResponseMessage(500,"error",null);}
}
简介
功能
GlobalExceptionHanderAdvice
是一个全局异常处理类,用于捕获和处理应用程序中的异常。- 通过使用
@RestControllerAdvice
注解,可以拦截所有控制器方法中抛出的异常(包括运行时异常),并进行统一的处理。
为什么需要全局异常处理?
- 提高代码的可维护性和一致性:避免在每个控制器中重复编写异常处理逻辑。
- 提供用户友好的错误响应:统一异常格式,便于前端解析和展示。
- 记录详细的异常信息:通过日志记录系统错误,便于后续排查问题。
2. 代码功能分析
1. @RestControllerAdvice
- 作用:这是 Spring 提供的增强功能,结合
@ExceptionHandler
注解,可以对所有@RestController
抛出的异常进行拦截和处理。 - 特点:
- 默认会拦截所有 REST API 请求中的异常。
- 返回的对象会直接转化为 JSON 响应,适合 RESTful 风格的接口。
2. @ExceptionHandler({Exception.class})
- 作用:指定处理的异常类型,此处捕获所有异常(包括运行时异常)。
- 逻辑:
- 记录异常日志:通过
SLF4J
的Logger
记录完整的异常堆栈信息。 - 返回统一的错误响应:构造
ResponseMessage
对象作为标准的错误响应。
- 记录异常日志:通过
3. 日志记录
Logger log = LoggerFactory.getLogger(GlobalExceptionHanderAdvice.class)
- 通过 SLF4J 记录异常日志。
log.error(e.getMessage(), e)
:- 输出异常的详细信息,包括错误消息和堆栈跟踪,便于排查问题。
4. 返回对象:ResponseMessage
ResponseMessage
是一个封装类,用于统一接口的响应格式。- 返回值示例:
{"status": 500,"message": "error","data": null }
小结
这里我们将SpringBoot框架的基本操作都做了一遍,不难看出,springboot开发需要用到大量的注释,省去了开发人员的编写麻烦问题。
相关文章:
自学SpringBoot笔记
概念 什么是SpringBoot? Spring Boot 是基于 Spring Framework 的一款开源框架,主要用于简化 Spring 应用程序的开发。它通过提供一系列的 开箱即用的功能 和 自动配置,让开发者可以快速构建生产级别的独立应用程序,而无需手动配…...
03JavaWeb——Ajax-Vue-Element(项目实战)
1 Ajax 1.1 Ajax介绍 1.1.1 Ajax概述 我们前端页面中的数据,如下图所示的表格中的学生信息,应该来自于后台,那么我们的后台和前端是互不影响的2个程序,那么我们前端应该如何从后台获取数据呢?因为是2个程序…...
[leetcode](找到vector中的特定元素并删除)无重复字符的最长子串
一.找到vector中的特定元素并删除 #include <iostream> #include <vector> #include <algorithm> int main() { // 示例 vector std::vector<int> vec {1, 2, 3, 4, 5, 6}; // 要删除的元素 int aim 3; // 查找元素 auto it std::fin…...
Mockito+PowerMock+Junit单元测试
一、单元测试用途 1、日常开发团队要求规范,需要对开发需求代码进行单元测试并要求行覆盖率达到要求,DevOps流水线也会开设相关门禁阀值阻断代码提交,一般新增代码行覆盖率80%左右。 二、Mock测试介绍 1、Mock是为了解决不同的单元之间由于…...
Ncat: bind to :::7777: Address already in use报错问题解决
问题描述 Ncat: bind to :::7777: Address already in use. QUITTING. 具体解决方法 If you are in linux environment try, Use netstat -tulpn to display the processeskill -9 <pid> This will terminate the process If you are using windows, Use netstat -…...
Docker 搭建mysql 连接超时问题,xxl-job启动mysql连接报错,禁用dns
1.本地连接Navicat报错信息,猜测是navicat默认连接超时导致的,后面换成idea一个插件虽然慢但连接上了 2013 - Lost connection to MySQL server at reading initial communication packet 2.启动xxl-job会报错,网上有人mysql驱动与数据库不匹…...
在线图片像素颜色拾取工具
在线图片像素颜色拾取工具,非常方便的一个工具,无需登录,用完就走。 包括中文和英文版本。 https://getcolor.openai2025.com...
Qt之登录界面(splash)
在上一篇多文档窗口设计(MDI)的基础上增加了一个登录界面(splash). 该模块可以扩展为常规的软件登录界面。 界面展示如下 如果用户名和密码输入正确,则调到MDI界面,如果用户名和密码一共输入三次以上,则程序强制退出…...
NotebookLM:Google 最新 AI 笔记助理解析与实战应用
NotebookLM:Google 最新 AI 笔记助理解析与实战应用 在 AI 驱动的生产力工具不断进化的今天,Google 推出的 NotebookLM(Notebook Language Model)成为了一款备受关注的智能笔记助理。它结合了 Google 的大语言模型(LL…...
软路由系统iStoreOS 一键安装 docker compose
一键安装命令 大家好!今天我来分享一个快速安装 docker-compose 的方法。以下是我常用的命令,当前版本是 V2.32.4。如果你需要最新版本,可以查看获取docker compose最新版本号 部分,获取最新版本号后替换命令中的版本号即可。 w…...
vue3本地文件下载
开发记录: vue3本地下载文件要把文件放到public下,如果放在src里面可能会出现这个问题...
纯代码实现给WordPress添加文章复制功能
在给wordpress添加内容时,有时会遇到文章复制的功能,但是wordpress又没有这个功能。把下面一段代码添加到functions.php文件中,就可以实现这个功能。 /** Function for post duplication. Dups appear as drafts. User is redirected to the…...
Redis 中 TTL 的基本知识与禁用缓存键的实现策略(Java)
目录 前言1. 基本知识2. Java代码 前言 🤟 找工作,来万码优才:👉 #小程序://万码优才/r6rqmzDaXpYkJZF 单纯学习Redis可以看我前言的Java基本知识路线!! 对于Java的基本知识推荐阅读: java框架…...
【PyQt】图像处理系统
[toc]pyqt实现图像处理系统 图像处理系统 1.创建阴影去除ui文件 2.阴影去除代码 1.创建阴影去除ui文件 UI文件效果图: 1.1QT Desiger设置组件 1.两个Pushbutton按钮 2.两个label来显示图像 3.Text Browser来显示输出信息 1.2布局的设置 1.先不使用任何La…...
Ruby语言的循环实现
Ruby语言的循环实现深入探讨 在程序设计中,循环是一种常见的控制结构,用于重复执行某些代码块。不同的编程语言提供了不同类型的循环结构,以满足不同的需求。Ruby是一种灵活且易于使用的编程语言,其循环实现方式独具一格…...
javaEE安全开发 SQL预编译 Filter过滤器 Listener 监听器 访问控制
前言 java开发和其他开发的不同并且更安全就是因为他拥有简单的预编译机制 filter 过滤器 和 listener 监听器 这个很重要 就是 web应用监听器和过滤器是在 Servlet 之前的并且 我们的请求和响应都需要经过 两者的同意才可以通过 缺一不可 、 Listener 安全方面 监听器…...
一体机cell服务器更换内存步骤
一体机cell服务器更换内存步骤: #1、确认grdidisk状态 cellcli -e list griddisk attribute name,asmmodestatus,asmdeactivationoutcome #2、offline griddisk cellcli -e alter griddisk all inactive #3、确认全部offline后进行关机操作 shutdown -h now #4、开…...
Hadoop•用Web UI查看Hadoop状态词频统计
听说这里是目录哦 通过Web UI查看Hadoop运行状态🐇一、关闭防火墙二、在物理计算机添加集群的IP映射三、启动集群四、进入HDFS的Web UI 词频统计🦩1、准备文本数据2、在HDFS创建目录3、上传文件4、查看文件是否上传成功5、运行MapReduce程序6、查看MapRe…...
rhel7.9利用有网络环境打包ansible
RHEL7.9激活(可省略) # 注册 subscription-manager register --usernameyour_username --passwordyour_password --auto-attach # 查看订阅状态 subscription-manager list # 将 “enabled1” 改为 “enabled0” vi /etc/yum/pluginconf.d/subscription-manager.conf 配置阿…...
vim文本编辑器三种模式的转换关系
输入模式 ———— 末行模式 输入模式和末行模式不能相互转换。 输入模式 ———— 命令模式 输入模式可以通过点击esc进入命令模式。 命令模式可以通过点击i进入输入模式。 末行模式 ———— 命令模式 末行模式可以通过点击esc进入命令模式。 命令模式可以通过shift&…...
深度学习:大模型Decoding+MindSpore NLP分布式推理详解
大模型推理流程 1. 用户输入提示词(Prompt) 假设用户输入为:“从前,有一只小猫,它喜欢……” 我们的目标是让模型生成一段完整的故事。 2. 模型处理用户输入 2.1 分词:输入提示被分词为模型可以理解的…...
【JVM中的三色标记法是什么?】
JVM中的三色标记法是什么? 一、基本概念二、标记过程三、优势与问题四、漏标与多标的解决方案三色标记法(Tri-color Marking Algorithm)是Java虚拟机(JVM)中一种用于追踪对象存活状态的垃圾回收算法。 它基于William D. Hana和Mark S. McCulleghan在1976年提出的两色标记法…...
数据库服务体系结构
1. 数据库服务应用配置 服务进行配置有什么作用? 实现服务运行启动 实现某些功能 应用配置有三种方式? 利用编译安装进行配置 编写配置文件信息 ,.默认的配置文件: /etc/my.cnf 利用启动命令参数配置信息,mysqld_safe --skip-grant-tables --…...
vscode项目依赖问题
必读 一定要将前端下拉的项目备份一下,很容易运行导致依赖报错,重新下载 命令 使用幽灵分解器安装 pnpm install 替代 npm install 设置淘宝NPM镜像源 yarn config set registry https://registry.npmmirror.com 查看目前依赖包的版本 npm list ant-d…...
R数据分析:有调节的中介与有中介的调节的整体介绍
单独的有调节的中介或者有中介的调节好多同学还大概能看明白,但是两个东西一起说我发现大部分同学就懵逼了。今天我就尝试将两种方法一起讲讲,重点帮助大家厘清两种方法的异同。 先从整体上看下两者的概念: 有中介的调节首先落脚在调节,调节作用必须是显著的,并且这个调…...
RabbitMQ-消息可靠性以及延迟消息
目录 消息丢失 一、发送者的可靠性 1.1 生产者重试机制 1.2 生产者确认机制 1.3 实现生产者确认 (1)开启生产者确认 (2)定义ReturnCallback (3)定义ConfirmCallback 二、MQ的持久化 2.1 数据持久…...
Hack The Box-Starting Point系列Oopsie
一. 答案 With what kind of tool can intercept web traffic? (什么样的工具可以拦截Web流量?) proxyWhat is the path to the directory on the webserver that returns a login page?(Web服务器上返回登录页面的目录路径是什么?) /cdn-cgi/loginWhat can be modified …...
Linux运维篇-PAM安全模块配置
PAM是什么? PAM(可插入认证模块)是UNIX操作系统上一个实现模块化的身份验证的服务。当程序需要对用户进行身份验证时加载并执行。PAM文件通常位于/etc/pam.d目录中。 而Linux-PAM,是linux可插拔认证模块,是一套可定制…...
麒麟V10系统上安装Oracle
以下是在麒麟V10系统上安装Oracle数据库的详细步骤: 安装前准备 检查系统版本:使用uname -a、cat /etc/os-release等命令检查服务器是麒麟V10系统。 配置固定IP和本地yum源: 挂载麒麟V10的iso文件到/mnt目录,如mount -o loop Ky…...
项目开发实践——基于SpringBoot+Vue3实现的在线考试系统(七)
文章目录 一、题库管理模块实现1、新增题目功能实现1.1 页面设计1.2 前端功能实现1.3 后端功能实现1.4 效果展示2、题目列表功能实现2.1 页面设计2.2 前端功能实现2.3 后端功能实现2.3.1 后端查询题目列表接口实现2.3.2 后端编辑试题接口实现2.4 效果展示二、代码下载一、题库管…...
微店网站怎么做/站长之家官网入口
本文列举了16个当前最流行的JavaScript框架。在这个列表中,既包括jQuery和Mootools,也有Zepo移动JavaScript框架。里面一定有你正在用的或想尝试用的JavaScript框架,看看列表吧!1. jQuery – Javascript框架应用最广泛的JavaScrip…...
三网合一 做网站/seo自动推广工具
1. 问题现象 在对项目中的clickhouse数据库进行查询的时候,提示:Too many simultaneous queries,如下图: 2. 问题原因 根据以往数据库的使用经验,确定应该是当前正在执行的查询数过多,超过了数据库的最…...
类似pinterest的网站/搜索引擎
PetaPoco是一种轻量级的ORM框架,可同时运行在.net与mono平台上; 一.PetaPoco如何使用两个以上的数据库? 在PetaPoco中有一个SingleDbFactory的仓储类,她负责取得链接数据库字符串的KEY,所以,想要在一个数据…...
卢松松博客主题 wordpress/深圳最好的外贸seo培训
宁夏十大中职学校一览表2019-09-04 09:45:02文/陶凯月宁夏中职学校有海原县职业中学、泾源县民族职业中学等等,下面就和小编一起了解一下吧,仅供大家参考。宁夏十大中职学校有哪些序号学校名称办学性质学校地址1银川百年农工子弟职业学校民办宁夏回族自治…...
做企业网站一般多少钱/教程推广优化网站排名
每周一、三、五,与您不见不散!随着2018年的结束,我们将回顾排名前五的最受读者欢迎的文章。今天分享的第一篇文章,将帮助那些在容器中运行 Java 虚拟机(JVM)时遇到内存和 CPU 大小调整/使用困难的人,本文将解释如何在 …...
重庆营销型网站开发价格/企业网站设计价格
分支结构: ① 单分支结构: 非常简单,if 条件语句,如果为true 则输出结果。否则不输出结果 ② 二分支结构: 条件结果为true则执行语句1,否则就执行语句2 If <条件>: <语句1> Else : …...