SpringBoot构建RESTful API——处理返回异常

本文介绍了如何在SpringBoot应用中构建RESTful API,重点讲解了如何处理返回异常,包括使用`ResponseEntity`设置状态码和响应体,以及通过`@ExceptionHandler`定义异常处理器,确保在用户对象未找到时返回合适的HTTP 404错误和错误信息。

@ResponseBody 提供了一种很有用的方式,能够将控制器返回的 Java 对象转换为发送到客户端的资源表述。

一个好的 REST API 不仅仅能够在客户端和服务器之间传递资源,他还能够给客户端提供额外的数据,帮助客户端理解资源或者在请求中发生了什么情况。

发送错误信息到客户端

例如,我们为 UserController 中添加一个新的处理器方法,它会提供单个 Spittle 对象。

@RestController
@RequestMapping("/user")
public class UserController {

    Map<String, User> users = Collections.synchronizedMap(new HashMap<String, User>());

    @RequestMapping(value = "/{id}",method = RequestMethod.GET, produces = "application/json")
    public User getUserById (@PathVariable("id") String id){
        //初始化用户信息
        initUserInfo();

        return users.get(id);
    }

    private void initUserInfo() {
        User user1 = new User("123","zhaoben");
        users.put(user1.getId(),user1);
    }

}

以上代码中,利用 Map 模拟数据库查找操作,通过id(123)进行查询,然后他根据调用 getUserById() 方法,查找对应 User 对象。 处理器方法返回查询结果。消息转换器会负责产生客户端所需要的资源表述。

*如果,根据给定 id,无法找到某个 User 对象,则 getUserById 返回 null
的同时,HTTP 状态码为 200,所有的过程看起来都很合理。但是,所有的事情都是不对的,客户端要求 User 对象,但是它什么都没有得到。客户端既没有收到 User 对象,也没有收到任何消息表示出现了错误。*

### 如何使用 Spring Boot 创建 RESTful Web 服务 #### 使用 Spring Initializr 初始化项目 为了快速启动并运行一个基于 Spring Boot 的 RESTful 应用程序,推荐使用 Spring Initializr 来初始化项目。这可以通过访问 [Spring Initializr](https://start.spring.io/) 并指定必要的参数完成,比如选择 Maven 或 Gradle 构建工具、Java 版本以及添加 `Spring Web` 和其他所需的依赖项来实现[^4]。 #### 定义实体类 一旦有了基础的 Spring Boot 项目结构,在应用程序中定义业务逻辑的核心——实体类是非常重要的一步。例如,如果要管理书籍资源,则可以创建如下所示的一个简单的 `Book` 实体: ```java public class Book { private Long id; private String title; private String author; // Getters and Setters... } ``` #### 数据库交互 (持久化层) 对于大多数应用来说,都需要与某种形式的数据存储进行交互。当涉及到关系型数据库时,通常会利用 JPA(Java Persistence API)。下面是一个示例性的仓库接口用于操作上述提到的 `Book` 对象: ```java import org.springframework.data.jpa.repository.JpaRepository; interface BookRepository extends JpaRepository<Book, Long> {} ``` 此接口继承自 `JpaRepository<T,ID>` 接口,其中 T 表示实体类型,ID 是该实体类型的主键字段类型。这样做的好处是可以自动获得一组标准 CRUD 方法的支持而无需自己去实现它们[^5]。 #### 控制器设计 接下来就是暴露 HTTP 端点给外部世界了。这里采用的是面向资源的设计理念,即每一个 URL 映射到特定的应用域对象上。以下是针对之前所提及图书资源的操作控制器实例: ```java @RestController @RequestMapping("/api/books") class BookController { @Autowired private BookService bookService; @GetMapping("/{id}") public ResponseEntity<?> getOne(@PathVariable(value="id") long id){ Optional<Book> optionalBook = this.bookService.findOne(id); if (!optionalBook.isPresent()) { return new ResponseEntity<>(HttpStatus.NOT_FOUND); } return new ResponseEntity<>(optionalBook.get(), HttpStatus.OK); } @PostMapping("/") public ResponseEntity<?> createNewBook(@RequestBody Book newBook){ try{ Book savedBook = this.bookService.save(newBook); URI location = ServletUriComponentsBuilder.fromCurrentRequest().path("/{id}").buildAndExpand(savedBook.getId()).toUri(); return ResponseEntity.created(location).body(savedBook); } catch(Exception e){ return new ResponseEntity<>(null, HttpStatus.INTERNAL_SERVER_ERROR); } } } ``` 在这个例子中,`@RestController` 注解表明这是一个返回 JSON 响应而不是视图名称的特殊类型的控制器;`@RequestMapping` 则用来映射请求路径至相应的处理器函数。此外还展示了 GET 请求获取单个记录(`getOne`) 及 POST 请求新增一条新纪录 (`createNewBook`) 的具体实现方式[^1]。 #### 单元测试编写 最后但同样重要的一环是对编写的代码进行全面彻底地验证。JUnit 结合 Mockito 框架能够很好地满足这一需求。下面是有关于前面展示过的 `BookController` 类的部分单元测试案例片段: ```java @RunWith(SpringRunner.class) @WebMvcTest(controllers=BookController.class) class BookControllerTests { @MockBean private BookService mockBookService; @Autowired MockMvc mockMvc; @Test void shouldReturnDefaultMessage() throws Exception { when(mockBookService.findAll()) .thenReturn(Stream.of( new Book("The Lord of the Rings", "J.R.R. Tolkien"), new Book("Harry Potter", "J.K.Rowling")) .collect(Collectors.toList())); mockMvc.perform(get("/api/books")) .andExpect(status().isOk()) .andExpect(content().string(containsString("Tolkien"))); } } ``` 这段代码里运用到了模拟技术来代替真实的 `BookService` 组件,并通过调用 `mockMvc.perform()` 发起对目标端点的实际HTTP请求来进行断言检查以确保预期行为得以正确执行[^3]。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值