当前位置: 首页 > wzjs >正文

沈阳网站设计培训班专业SEO教程网站

沈阳网站设计培训班,专业SEO教程网站,网站建设模板下载免费,在网上做试卷的网站系列回顾: 在上一篇中,我们成功地为应用集成了数据库,并使用 Spring Data JPA 实现了基本的 CRUD API。我们的应用现在能“记忆”数据了!但是,如果你仔细审视那些 API,会发现它们还很“粗糙”:有…

系列回顾:
在上一篇中,我们成功地为应用集成了数据库,并使用 Spring Data JPA 实现了基本的 CRUD API。我们的应用现在能“记忆”数据了!但是,如果你仔细审视那些 API,会发现它们还很“粗糙”:有的接口成功后返回对象,有的返回字符串;一旦出现错误,要么返回 null,要么直接抛出让前端不知所措的 500 错误。这在协作开发和生产环境中是不可接受的。

欢迎来到本系列的第三站!

今天,我们要进行一次“精装修”。我们将学习三项让你的 API 瞬间变得“专业”起来的核心技术。这三项技术是衡量一个后端工程师代码素养和工程化能力的重要指标,也是面试中的高频考点。它们分别是:

  1. 统一响应格式: 告别五花八门的返回类型,让所有 API 都遵循统一、可预测的结构。
  2. 全局异常处理: 告别 try-catch 地狱,用优雅的方式集中处理所有运行时异常。
  3. 参数校验: 告别控制器中繁琐的 if-else 判断,用声明式注解保证输入数据的合法性。

完成本章后,你的代码将变得更干净、更健壮,与前端的协作效率也会大大提升。


第一步:规范的基石 —— 统一响应格式

问题在哪?
看看我们上一章的 UserController

  • addUser 返回 User 对象。
  • getAllUsers 返回 List<User>
  • deleteUserById 返回 String
  • getUserById 在找不到时返回 null (或通过 orElse(null) 返回)。

前端开发者每次调用你的接口,都得先猜一下这次返回的是什么结构。这太糟糕了!

解决方案:定义一个通用的 Result 封装类。

我们来创建一个所有 API 都会返回的标准化对象。它通常包含三个核心部分:

  • code: 状态码(例如,200 代表成功,500 代表系统错误,4001 代表特定业务错误)。
  • message: 提示信息(例如,“操作成功”、“用户不存在”)。
  • data: 实际的响应数据(例如,一个 User 对象或一个 List<User>)。

1. 创建 Result

com.example.myfirstapp 包下创建一个 common 包(用于存放通用工具类),然后在其中创建 Result.java 类:

package com.example.myfirstapp.common;public class Result<T> {private String code;private String message;private T data;// 私有化构造函数,不允许外部直接 newprivate Result() {}private Result(T data) {this.code = "200"; // 默认成功码this.message = "操作成功";this.data = data;}private Result(String code, String message) {this.code = code;this.message = message;}// --- 静态工厂方法,方便调用 ---public static <T> Result<T> success() {return new Result<>();}public static <T> Result<T> success(T data) {return new Result<>(data);}public static <T> Result<T> error(String code, String message) {return new Result<>(code, message);}// --- Getter ---public String getCode() { return code; }public String getMessage() { return message; }public T getData() { return data; }
}

设计亮点:

  • 使用泛型 <T>,使其可以包装任何类型的数据。
  • 使用静态工厂方法 (success(), error()),让代码调用更简洁、语义更清晰。

2. 改造 UserController

现在,我们用 Result 类来重构 UserController 的返回类型。

package com.example.myfirstapp.controller;import com.example.myfirstapp.common.Result;
import com.example.myfirstapp.entity.User;
import com.example.myfirstapp.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;import java.util.List;
import java.util.Optional;@RestController
@RequestMapping("/users")
public class UserController {@Autowiredprivate UserRepository userRepository;@PostMapping("/add")public Result<User> addUser(@RequestBody User user) {User savedUser = userRepository.save(user);return Result.success(savedUser); // 返回统一格式}@GetMapping("/{id}")public Result<User> getUserById(@PathVariable Long id) {Optional<User> userOptional = userRepository.findById(id);if (userOptional.isPresent()) {return Result.success(userOptional.get());} else {return Result.error("404", "用户未找到"); // 返回统一错误格式}}@GetMapping("/all")public Result<List<User>> getAllUsers() {List<User> users = userRepository.findAll();return Result.success(users);}@DeleteMapping("/delete/{id}")public Result<Void> deleteUserById(@PathVariable Long id) {userRepository.deleteById(id);return Result.success(); // 无数据返回的成功}
}

看到变化了吗?现在所有接口的返回类型都是 Result<?>,前端可以稳定地解析 code, message, data 了!但是… getUserById 里的 if-else 看起来还是有点碍眼。别急,我们下一步就来解决它。


第二步:优雅的守护者 —— 全局异常处理

问题在哪?
getUserByIdif-else 只是冰山一角。如果 save 用户时违反了数据库唯一约束怎么办?如果发生了其他未知异常怎么办?难道我们要在每个方法里都写 try-catch 吗?那将是一场灾难。

解决方案:使用 @RestControllerAdvice 集中处理所有异常。

@RestControllerAdvice 是一个 Spring 注解,它可以创建一个全局的“顾问”,专门监听所有 @RestController 抛出的异常,并根据异常类型执行相应的处理逻辑,最后返回一个统一的 Result 对象。

1. 创建自定义业务异常 (可选但推荐)

为了更好地定义业务错误(如“用户不存在”、“余额不足”),我们最好创建一个自定义异常类。

common 包下创建 CustomException.java

package com.example.myfirstapp.common;public class CustomException extends RuntimeException {private String code;public CustomException(String code, String message) {super(message);this.code = code;}public String getCode() {return code;}
}

2. 创建全局异常处理器

common 包下创建 GlobalExceptionHandler.java

package com.example.myfirstapp.common;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;@RestControllerAdvice
public class GlobalExceptionHandler {private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);// 捕获我们自定义的业务异常@ExceptionHandler(CustomException.class)public Result<Void> handleCustomException(CustomException e) {return Result.error(e.getCode(), e.getMessage());}// 捕获所有其他未处理的异常@ExceptionHandler(Exception.class)public Result<Void> handleException(Exception e) {log.error("系统发生未知异常!", e); // 记录详细日志return Result.error("500", "系统繁忙,请稍后再试"); // 返回对用户友好的信息}
}

3. 再次改造 UserController

现在,我们可以大胆地在业务逻辑中抛出异常,把 if-else 彻底干掉!

// UserController.java// ... 其他方法不变 ...@GetMapping("/{id}")
public Result<User> getUserById(@PathVariable Long id) {// orElseThrow 如果找不到,就抛出我们指定的异常User user = userRepository.findById(id).orElseThrow(() -> new CustomException("404", "用户未找到"));return Result.success(user);
}// ...

看,getUserById 方法变得多么简洁!我们只关心“找到用户”这个核心逻辑。至于“找不到”的情况,直接抛给全局异常处理器去操心。代码的职责分离得非常清晰。


第三步:数据的守门员 —— 参数校验

问题在哪?
addUser 时,如果前端传来的 JSON 是 {"name": "", "email": "这不是一个邮箱"} 怎么办?我们不应该让这种脏数据进入 service 层,甚至到达数据库。最理想的位置是在 Controller 层就把它拦截下来。

解决方案:使用 spring-boot-starter-validation@Valid 注解。

spring-boot-starter-web 默认就包含了 validation 依赖,我们只需要在实体类上添加校验规则,并在 Controller 方法上开启校验即可。

1. 为实体类添加校验注解

修改 entity/User.java

package com.example.myfirstapp.entity;import jakarta.persistence.*;
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import org.hibernate.validator.constraints.Length;@Entity
@Table(name = "user")
public class User {@Id@GeneratedValue(strategy = GenerationType.IDENTITY)private Long id;@NotBlank(message = "用户名不能为空") // 不能为空白字符串@Length(min = 2, max = 10, message = "用户名长度必须在2-10位之间")@Column(name = "name", length = 30)private String name;@NotBlank(message = "邮箱不能为空")@Email(message = "邮箱格式不正确") // 必须是合法的 email 格式@Column(name = "email", length = 50)private String email;// ... Getter and Setter ...
}

我们使用了 jakarta.validation.constraints 包下的注解,如 @NotBlank, @Email 等,并可以自定义错误消息。

2. 在 Controller 中开启校验

修改 UserController.javaaddUser 方法,在 @RequestBody 旁加上 @Valid 注解。

// UserController.java
import jakarta.validation.Valid; // 引入// ...@PostMapping("/add")
public Result<User> addUser(@Valid @RequestBody User user) { // 添加 @ValidUser savedUser = userRepository.save(user);return Result.success(savedUser);
}

@Valid 告诉 Spring Boot:请对这个 user 对象进行校验。如果校验失败,Spring Boot 会自动抛出一个 MethodArgumentNotValidException 异常。

3. 在全局异常处理器中捕获校验异常

最后一步,我们需要在 GlobalExceptionHandler 中捕获这个特定的异常,并提取出友好的错误信息返回给前端。

修改 GlobalExceptionHandler.java,添加一个新的处理器方法:

package com.example.myfirstapp.common;// ... imports ...
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.MethodArgumentNotValidException;@RestControllerAdvice
public class GlobalExceptionHandler {// ... 其他处理器 ...// 捕获参数校验异常@ExceptionHandler(MethodArgumentNotValidException.class)public Result<Void> handleValidationException(MethodArgumentNotValidException e) {BindingResult bindingResult = e.getBindingResult();// 获取第一个校验失败的字段的错误信息String errorMessage = bindingResult.getFieldErrors().stream().map(fieldError -> fieldError.getDefaultMessage()).findFirst().orElse("参数校验失败");return Result.error("400", errorMessage);}
}

测试一下:
现在,重启应用,用 Postman 发送一个不合法的请求到 POST /users/add

  • Body (raw, JSON): {"name": "", "email": "bad-email"}
  • 响应: 你会收到一个结构化的错误响应,可能是:
    {"code": "400","message": "用户名不能为空","data": null
    }
    

完美!我们兵不血刃地就实现了强大的数据校验功能。


总结与展望

恭喜你!你已经完成了从“能跑就行”到“专业可靠”的巨大飞跃。回顾一下今天我们掌握的神器:

  1. 统一响应 (Result): 建立了与前端协作的坚固桥梁。
  2. 全局异常处理 (@RestControllerAdvice): 将业务代码与异常处理逻辑解耦,代码更整洁。
  3. 参数校验 (@Valid): 像一个忠诚的门卫,将非法数据挡在门外。

看看你现在的 UserController,是不是非常清爽?它只专注于协调请求、调用业务逻辑,而把格式化、异常、校验这些“脏活累活”都交给了我们配置好的全局组件。这正是面向切面编程 (AOP) 思想的绝佳体现。

我们的应用现在已经相当健壮和规范了。但它仍然是“裸奔”的——任何人都可以随意调用我们的 API 来增删用户。这在真实世界里是绝对不行的。

在下一篇文章 《【安全篇】金刚不坏之身:整合 Spring Security + JWT 实现无状态认证与授权》 中,我们将为应用穿上最坚固的“铠甲”,学习如何保护我们的 API,只让合法的用户进行授权操作。这会是充满挑战但收获巨大的一章,我们不见不散!

http://www.dtcms.com/wzjs/815782.html

相关文章:

  • 网站后台模板 jquery修改wordpress的样式
  • 网站的内链是什么意思公众号平台搭建
  • 织梦网站模板安装本地北京市住房与城乡建设部网站
  • 有哪些官方网站做的比较好安卓软件免费下载
  • 网站建设公司的选择优秀自适应网站建设哪家好
  • 南通网站建设空间wordpress 4.7.5中文版
  • 自学网站建设需要什么学历做php网站用什么软件开发
  • 建设部网站中淼工程有限公司花卉网站建设项目策划书
  • 做电商网站要备案吗上海做网站的的公司
  • 微网站需要域名吗wordpress本地评论插件
  • 专做美妆的视频网站手机百度关键词优化
  • 网站建设部门宣言公众号和网站
  • net服装网站建设seo搜索引擎工具
  • 职业学校网站模板个人网页效果图
  • 浏览器正能量不良网站凤阳县建设局网站
  • 网站开发培训内容北京网站建设有哪些公司
  • 湘潭做网站公司特效素材免费网站
  • 网站城市切换如何做个人信息服务平台登录
  • 有关建设旅游网站的公司wordpress 标题优化
  • 网页制作大宝库网站seo整站优化
  • 怎么做旅游网站关键词挖掘排名
  • 建站最好的公司排名找项目
  • 电脑培训学校网站临沂网站建设步骤
  • 编程网站scratch公司后台的网站代理维护更新
  • 做seo学网站王妃貌美还狠凶
  • 网站建设的细节处理玉林做网站
  • 网站建设的理念网站建设专有名词
  • 新做的网站怎样推广android网站客户端开发
  • 临海网站制作好了如何上线wordpress需要npv
  • 找公司做网站注意什么乐清城市网官网