• 软件工程第六周之服务层与API调用


    服务层(常见)

    如前所述,服务层主要负责处理业务逻辑。在这个例子中,我们会有一个BookService来处理与图书相关的操作。

    1. // BookService.java
    2. public class BookService {
    3. private BookDAO bookDAO; // Assume this DAO uses JDBC or MyBatis
    4. public BookService(BookDAO bookDAO) {
    5. this.bookDAO = bookDAO;
    6. }
    7. public void addBook(Book book) {
    8. bookDAO.insert(book);
    9. }
    10. public Book getBookById(int id) {
    11. return bookDAO.findById(id);
    12. }
    13. public List getAllBooks() {
    14. return bookDAO.findAll();
    15. }
    16. }

    API调用(常见)

    API调用通常在一个控制器或端点中进行。例如,假设我们使用一个简单的Spring Boot应用程序,我们可以有一个BookController,该控制器暴露出API端点供前端或其他服务调用。

    1. import org.springframework.beans.factory.annotation.Autowired;
    2. import org.springframework.web.bind.annotation.*;
    3. @RestController
    4. @RequestMapping("/books")
    5. public class BookController {
    6. @Autowired
    7. private BookService bookService;
    8. @PostMapping
    9. public void addBook(@RequestBody Book book) {
    10. bookService.addBook(book);
    11. }
    12. @GetMapping("/{id}")
    13. public Book getBookById(@PathVariable int id) {
    14. return bookService.getBookById(id);
    15. }
    16. @GetMapping
    17. public List getAllBooks() {
    18. return bookService.getAllBooks();
    19. }
    20. }

    (看来这个@Autowired不仅可以让springboot自动注入mapper代理对象,还可以自动注入其他类对象,比如服务层实例对象)

    在上述例子中,BookController提供了3个API端点

    • POST /books 添加新书。
    • GET /books/{id} 通过ID获取图书信息。
    • GET /books 获取所有图书的列表。

    这个BookController通过Springboot的依赖注入将BookService注入进来,因此当API被调用时,它会利用BookService去执行相应的操作。

    原来如此!服务层(在本例中为BookService)处理业务逻辑和数据操作,而API层(在本例中为BookController)负责与外部交互,接收请求并返回响应。


    Dao层基础上的服务层和API层

    当使用JDBC或MyBatis这种Dao层时,核心的差异主要体现在数据访问对象(Dao)或映射器(Mapper)的实现上。以下是如何使用JDBC和MyBatis实现的概述,以及与BookServiceBookController的集成。

    1. 使用JDBC

    首先,我们需要创建一个基于JDBC的BookDAO

    1. import java.sql.Connection;
    2. import java.sql.DriverManager;
    3. import java.sql.PreparedStatement;
    4. import java.sql.ResultSet;
    5. import java.util.ArrayList;
    6. import java.util.List;
    7. public class JdbcBookDAO {
    8. private String url = "your_database_url";
    9. private String username = "your_username";
    10. private String password = "your_password";
    11. public void insert(Book book) {
    12. try (Connection connection = DriverManager.getConnection(url, username, password)) {
    13. PreparedStatement stmt = connection.prepareStatement("INSERT INTO books (title, author) VALUES (?, ?)");
    14. stmt.setString(1, book.getTitle());
    15. stmt.setString(2, book.getAuthor());
    16. stmt.executeUpdate();
    17. } catch (Exception e) {
    18. e.printStackTrace();
    19. }
    20. }
    21. public Book findById(int id) {
    22. try (Connection connection = DriverManager.getConnection(url, username, password)) {
    23. PreparedStatement stmt = connection.prepareStatement("SELECT id, title, author FROM books WHERE id = ?");
    24. stmt.setInt(1, id);
    25. ResultSet rs = stmt.executeQuery();
    26. if (rs.next()) {
    27. return new Book(rs.getInt("id"), rs.getString("title"), rs.getString("author"));
    28. }
    29. } catch (Exception e) {
    30. e.printStackTrace();
    31. }
    32. return null;
    33. }
    34. public List findAll() {
    35. List books = new ArrayList<>();
    36. try (Connection connection = DriverManager.getConnection(url, username, password)) {
    37. PreparedStatement stmt = connection.prepareStatement("SELECT id, title, author FROM books");
    38. ResultSet rs = stmt.executeQuery();
    39. while (rs.next()) {
    40. books.add(new Book(rs.getInt("id"), rs.getString("title"), rs.getString("author")));
    41. }
    42. } catch (Exception e) {
    43. e.printStackTrace();
    44. }
    45. return books;
    46. }
    47. }

    2. 使用MyBatis

    首先,定义BookMapper接口:

    1. public interface BookMapper {
    2. void insert(Book book);
    3. Book findById(@Param("id") int id);
    4. List findAll();
    5. }

    然后,创建BookMapper.xml映射文件:

    1. "com.example.BookMapper">
    2. "insert" parameterType="Book">
    3. INSERT INTO books (title, author) VALUES (#{title}, #{author})

    3. Dao层与服务层和API层集成

    不论选择JDBC还是MyBatis,都可以与之前定义的BookServiceBookController集成。只需在服务层中更换相应的DAO或Mapper即可。也就是说,原本如果没用到数据库,那一般会在本地写明Service层的业务逻辑和那些insert函数。而Dao层本质就是对数据的操作,所以,在原本服务层上使用Dao层中定义的函数即可!

    例如,如果选择使用MyBatis的BookMapperBookService可能看起来像这样:

    1. @Service
    2. public class BookService {
    3. @Autowired
    4. private BookMapper bookMapper;
    5. public void addBook(Book book) {
    6. bookMapper.insert(book);
    7. }
    8. public Book getBookById(int id) {
    9. return bookMapper.findById(id);
    10. }
    11. public List getAllBooks() {
    12. return bookMapper.findAll();
    13. }
    14. }

    至于BookController,它保持不变。它与BookService进行交互,而不关心背后的数据访问细节是基于JDBC还是MyBatis的。

    作者之前直接就是定义mapper接口之后直接在API层也就是controller中使用方法了,所以有一个疑问:简单系统的Service层有必要吗?

    其实上面两段都涉及到Service层的好处!我们来细细研究一下:

    有许多简单的应用或项目可能会直接在Controller层使用Mapper,特别是当业务逻辑相对简单时。但Service层的存在并不是无的放矢,它是基于软件工程中的一些核心原则和实践。

    以下是在图书管理系统或任何应用中使用Service层的几个主要原因:

    1. 分层和关注点分离 (Separation of Concerns):

    Service层和Controller层服务于不同的目的。Controller主要负责处理HTTP请求和响应,而Service层主要处理业务逻辑。当你将这两者分开,代码更加模块化,各层只关注自己的职责,这使得代码更加清晰、可维护。

    2. 复用性:

    当业务逻辑被封装在Service层中,它可以被多个Controller或其他服务重用,而不是被固定在特定的Controller中。只不过对于图书管理系统来说,其业务逻辑不复杂,所以才看似复用只是调用insert/update函数而已。

    3. 灵活性:

    随着项目的增长,可能会有更复杂的业务逻辑需求,例如事务处理、缓存、安全等。有了Service层,可以更容易地在一个集中的地方添加这些逻辑

    4. 测试性:

    业务逻辑封装在Service层中使得单元测试更为简单。你可以针对Service层进行独立的测试,而不需要涉及HTTP层。这样可以更容易地进行模拟和测试各种业务场景。

    5. 解耦:

    如果在未来决定更换数据访问层(例如,从MyBatis迁移到JPA),有了Service层,更改的影响范围会小得多,因为Controller并不直接依赖于具体的数据访问技术。

    6. 业务逻辑的集中化:

    随着时间的推移,一个简单的图书管理系统可能会添加更多的功能,例如推荐系统、库存管理、通知等。所有这些复杂的逻辑可以在Service层中处理,而Controller层保持简单和清晰。

    从软件工程的角度来看,分层的架构模式,如MVC或三层架构,被设计出来是为了支持可维护性、扩展性和可重用性。虽然在小型或简单的项目中,我们可能觉得Service层是多余的,但随着项目规模的扩大或需求的变更,Service层的价值将逐渐显现。

    总之,虽然直接在Controller中使用Mapper或DAO在某些情况下可能是可行的,但建议在设计软件时考虑长远和整体,以支持未来的扩展和维护。

  • 相关阅读:
    strimzi实战之三:prometheus+grafana监控(按官方文档搞不定监控?不妨看看本文,已经踩过坑了)
    不想努力了,有没有不用努力就能考上硕士的方法
    .NET周刊【1月第3期 2024-01-24】
    论文浅尝 | 训练语言模型遵循人类反馈的指令
    嵌入式Linux中内存管理详解分析
    存储中的爱情:cookie、本地存储、会话存储
    BBR 降本增效
    原来 vue3 文件编译是这样工作的!看完后更懂vue3了
    【无标题】
    SHAP解释模型(二)
  • 原文地址:https://blog.csdn.net/qq_65052774/article/details/133777177