简单地聊一聊Spring Boot的构架

本文由葡萄城技术团队发布。转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具、解决方案和服务,赋能开发者。

前言

本文小编将详细解析Spring Boot框架,并通过代码举例说明每个层的作用。我们将深入探讨Spring Boot的整体架构,包括展示层、业务逻辑层和数据访问层。通过这些例子,读者将更加清晰地了解每个层在应用程序中的具体作用。通过代码实例,我们将帮助读者更好地理解和应用Spring Boot框架,从而提高应用程序的可维护性和可扩展性。

什么是Spring Boot

在介绍Spring Boot框架的分层之前,小编先为大家介绍一下什么是Spring Boot:

Spring Boot是一个基于Spring框架的开发框架,旨在简化Spring应用程序的搭建和开发。Spring Boot提供了很多自动化配置的功能,可以快速地搭建一个基于Spring的Web应用程序,而不需要手动进行繁琐的配置。

Spring Boot可以帮助开发人员快速构建各种类型的应用程序,包括Web应用程序、RESTful服务、批处理应用程序和基于消息的应用程序等。它采用Java编程语言,并且可以与各种其他技术集成,例如Thymeleaf、MongoDB、Redis等。

Spring Boot还提供了很多有用的工具和插件,例如Spring Boot CLI(命令行界面),可以帮助开发人员更加便捷地创建、运行和测试Spring Boot应用程序。此外,Spring Boot还支持各种构建工具,例如Maven和Gradle,以及各种开发环境,例如Eclipse和IntelliJ IDEA。

Spring Boot分层:

Spring Boot主要分为4层:Controller层、Service层、Repository/DAO层和Model层。

1. Controller层

在SpringBoot中,Controller层是MVC(Model-View-Controller)模式中的控制器部分,负责处理来自用户发起的HTTP请求,并返回相应的响应结果。Controller层接收到请求后,通常会调用Service层进行业务逻辑处理,最后再将处理结果封装成响应对象并返回给前端。

一个Controller类通常包含多个方法,每个方法对应一个不同的HTTP请求路径,并使用特定的注解来标识。例如,使用@GetMapping注解表示该方法处理GET请求,@PostMapping表示该方法处理POST请求。同时,通过@RequestParam注解可以获取请求参数,@PathVariable注解可以获取URL路径参数,@RequestBody注解可以获取请求体中的数据。

2. Service层

在Spring Boot中,Service层是应用程序的一部分,负责处理业务逻辑和协调不同的组件。它是控制器(Controller)和数据访问层(Repository)之间的中间层,用于将业务逻辑与数据操作解耦。

Service层的主要职责可以总结如下:

  1. 执行业务逻辑:Service层负责实现应用程序的业务逻辑。它包含了具体的业务规则和操作流程,以满足需求和业务规定。例如,对于电子商务应用程序,Service层可能会包含创建订单、处理支付、验证库存等业务逻辑的实现。
  2. 协调数据访问:Service层充当控制器和数据访问层之间的桥梁。它通过调用相应的Repository接口来执行数据操作,如查询数据库、保存数据、更新数据等。Service层可以组织和协调多个Repository操作,以完成复杂的业务需求。
  3. 提供业务接口:Service层可以定义一些公共接口或方法,供其他组件(如控制器、其他Service等)使用。这样可以封装底层的业务逻辑实现,使其对外提供统一的接口。这种封装有助于提高代码的可维护性和重用性。
  4. 处理事务管理:Service层通常涉及到数据库的读写操作,需要保证数据的一致性和完整性。通过使用Spring框架提供的事务管理机制,Service层可以确保多个数据库操作在一个事务中执行。它可以定义事务的边界、隔离级别、回滚策略等,以确保数据操作的正确性和可靠性。
  5. 实现业务规则和验证:Service层可以包含对传入数据的验证和处理逻辑。例如,对于用户注册操作,Service层可能会对输入的用户名进行唯一性检查,对密码进行加密等。这样可以保证应用程序的安全性和数据的有效性。

3. Repository/DAO层

DAO全称是Data Access Object,其主要目标是从数据库高效获取(查询)数据,并为service层提供服务。

Repository/DAO层的主要职责可以总结如下:

  1. 定义数据访问接口:Repository或DAO层定义了访问数据库的接口,它们通常包括各种读、写、更新、删除等操作。这些操作通过方法调用来实现,使得业务逻辑可以轻松地使用这些操作。
  2. 提供数据映射:Repository或DAO层负责将数据库中的数据映射到Java类或对象中。这种映射可以是简单的一对一关系,也可以是复杂的关联关系。通常情况下,开发人员会使用ORM框架(如Hibernate)来自动完成数据映射。
  3. 处理数据访问异常:Repository或DAO层负责处理与数据访问相关的异常情况,例如数据库连接失败、SQL语句执行错误等。它们可以捕获这些异常并进行相应的处理,以保证应用程序的稳定性和可靠性。
  4. 支持数据源配置:Repository或DAO层支持不同类型的数据源配置,例如关系型数据库、NoSQL数据库、文件系统等。它们可以根据不同的数据源类型,提供相应的数据访问接口和数据映射策略。
  5. 提供数据缓存:Repository或DAO层可以缓存已经读取的数据,以提高应用程序的性能。它们可以使用内存缓存、分布式缓存等不同类型的缓存机制,根据业务需求进行选择。

4. Model层

在Spring Boot中,Model层对象是用于封装和传递数据的Java对象。它表示应用程序中的业务数据,并负责处理数据的获取、保存和修改等操作。Model层对象通常具有以下特点:

  1. 实体类(Entity Class):Model层对象通常是实体类或POJO(Plain Old Java Object),用于表示业务数据的结构。实体类的属性对应数据库表的字段,通过ORM(Object-Relational Mapping)框架可以将实体类与数据库进行映射。
  2. 数据传输对象(Data Transfer Object,DTO):在一些场景下,为了满足特定的需求,可能需要使用DTO来封装数据。DTO是一个简单的Java对象,用于在不同的层之间传输数据。DTO通常只包含必要的属性,以减少数据传输的大小和复杂性。
  3. 数据校验(Data Validation):Model层对象可以用于数据校验,确保传入的数据符合特定的规则和要求。可以使用注解(如javax.validation.constraints)或其他验证框架(如Hibernate Validator)对属性进行校验。
  4. 业务逻辑(Business Logic):Model层对象可以包含一些业务逻辑的方法,用于处理数据的计算、转换和操作等。这些方法可以在Model层对象中定义,或者在服务层(Service Layer)中进行实现。

代码示例:

1.Controller层:

ProjectController.java

package com.example.Controller;
//import statements goes here
@RestController
public class UserController {
   
    //List all the available projects
    @GetMapping(path = "/projects", produces = MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity<List<Project>> getProjects() {
     
    // perform validation checks
    // return the services provided by service layer
    }
    //Apply for the project
    @PostMapping(path = "/apply-project", consumes = MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity<HttpStatus> applyProject(@RequestBody Map<String,String> json) {
    // perform validation checks
    // return the services provided by service layer
    }
    
    //Upload resume
    @PostMapping(path = "/upload-resume/{usn}")
    public ResponseEntity<List<Object>> uploadToDB(@RequestParam("file") MultipartFile[] file,@PathVariable String usn) {
    
    // perform validation checks
    // return the services provided by service layer
    }
    //Download resume
    @GetMapping("/files/download/{fileName:.+}")
    public ResponseEntity downloadFromDB(@PathVariable String fileName) {
    // perform validation checks
    // return the services provided by service layer
    }
}

上面例子使用了@GetMapping和@PostMapping:

@GetMapping注解用于将一个方法映射到指定的HTTP GET请求。它可以用于处理浏览器直接访问某个URL或者其他应用程序发起GET请求的情况。通过在方法上添加@GetMapping,我们可以定义一个处理该请求的方法,并在方法中编写相应的业务逻辑。

@PostMapping注解用于将一个方法映射到指定的HTTP POST请求。它可以用于处理表单提交、客户端数据上传等操作。通过在方法上添加@PostMapping,我们可以定义一个处理该请求的方法,并在方法中编写相应的业务逻辑。

2.Service层:

下面这段定义了项目相关的服务方法,并规定这些方法的输入参数和返回值。

在代码示例中,ProjectService 接口声明了三个方法:

  1. getProjects() 方法返回一个 List<Project> 对象作为响应体(ResponseEntity),用于获取所有项目信息。
  2. applyProject(String USN,int project_id) 方法返回 HttpStatus 枚举值,表示申请参与某个项目的状态。
  3. uploadProjectDocument(MultipartFile[] files,int project_id) 方法返回 List<Object> 对象作为响应体,用于上传项目文档。

ProjectService.java

package com.example.Service;

// import statements

public interface ProjectService {

    ResponseEntity<List<Project>> getProjects();

    HttpStatus applyProject(String USN,int project_id);

    ResponseEntity<List<Object>> uploadProjectDocument(MultipartFile[] files,int project_id);

}

ProjectServiceImpl.java

package com.example.Service;

//import statements
@Service
public class ProjectServiceImpl implements ProjectService {
//dependency injection of DAO to be gone here (Autowire)
  
    @Override
    public ResponseEntity<List<Project>> getProjects() {
        try {
           //Business logic implementation using DAO services
        } catch (Exception e) {
            return new ResponseEntity<>(null,HttpStatus.INTERNAL_SERVER_ERROR) ;
        }
    }
   
    @Override
    public HttpStatus applyProject(String USN, int project_id) {
   
    //Business logic implementation using DAO services
    }
  
   //helper functions
    public ResponseEntity uploadToLocalFileSystem(MultipartFile file,int project_id) {
     
    }
    @Override
    public ResponseEntity<List<Object>> uploadProjectDocument(MultipartFile[] files,int project_id) {
       //Business logic implementation using DAO services
    }

}

3.Repository/DAO层:

下面的这段代码是一个接口类,属于包名为"com.example.Dao"的项目数据访问对象(DAO)。它扩展了 JpaRepository<Project, Integer> 接口,该接口提供了基本的CRUD(创建、读取、更新、删除)操作方法,用于对数据库中的 “Project” 实体进行操作。

ProjectDAO.java

package com.example.Dao;

//import statements

public interface ProjectDao extends JpaRepository<Project,Integer> {

//You can also include native queries on top of CRUD operations provided by JPA
// Add queries here using @Query annotations and corresponding functions

    @Query(value = "Your SQL query ",nativeQuery = true)
    public List<Project> getProjects();

}

}

4.Model层:

下面这段代码定义了一个名为 “Project” 的实体类,表示一个项目。它包含了项目的各个属性(如项目ID、公司名称、描述、要求等),并与其他实体类(如员工、学生、文档、资金等)之间建立了关联关系。通过使用 JPA 注解,该类可以方便地进行数据库操作和查询。

代码中的各个部分的含义如下:

  1. @Entity 注解表示该类是一个实体类,与数据库中的表进行映射。
  2. @Table(name = “project”) 注解指定了对应的数据库表名为 “project”。
  3. @Id 注解表示该字段是主键。
  4. @GeneratedValue(strategy = GenerationType.IDENTITY) 注解指定了主键的生成策略为自增长。
  5. @Column 注解用于指定该属性与数据库表中的列的映射关系,其中 nullable 属性表示该列是否允许为空,name 属性指定了对应的数据库列名。
  6. @JsonIgnore 注解用于忽略该属性在序列化和反序列化过程中的处理。
  7. @ManyToMany(mappedBy=“funded_projects”) 注解表示当前实体与另一个实体 Fund 之间存在多对多的关联关系,通过 mappedBy 属性指定了在 Fund 实体中维护关联关系的属性名为 “funded_projects”。
  8. Set<Staff>, Set<Student>, Set<Document>, Set<Fund> 表示与其他实体之间的关联关系,通过集合类型的属性来表示多对多关系或一对多关系。

Project.java

package com.example.Entity;

//import statements

@Entity
@Table(name = "project")
public class Project {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int project_id;
    @Column(nullable = false, name = "company_name")
    private String company_name;

    @Column(nullable = false, name = "description")
    private String description;

    @Column(nullable = false, name = "requirements")
    private String requirements;

    @Column(nullable = false, name = "manager")
    private String manager;
    @Column(nullable = false, name = "start_date")
    private Date start_date = new Date();

    @Column( name = "end_date")
    private Date end_date = new Date();
    @Column(nullable = false,name = "opening")
    private int opening;
    @Column(name = "resources")
    private String resources;
    public Set<Staff> getStaff_incharge() {
        return staff_incharge;
    }
    public void setStaff_incharge(Set<Staff> staff_incharge) {
        this.staff_incharge = staff_incharge;
    }
    public Set<Student> getApplied_students() {
        return applied_students;
    }
    public Set<Document> getDocuments() {
        return documents;
    }
    public void setDocuments(Set<Document> documents) {
        this.documents = documents;
    }
    @JsonIgnore
    @ManyToMany(mappedBy="funded_projects")
    private Set<Fund> funds;
    public Set<Fund> getFunds() {
        return funds;
    }
    public void setFunds(Set<Fund> funds) {
        this.funds = funds;
    }
    public void setApplied_students(Set<Student> applied_students) {
        this.applied_students = applied_students;
    }
    public Set<Student> getWorking_students() {
        return working_students;
    }
    public void setWorking_students(Set<Student> working_students) {
        this.working_students = working_students;
    }
//constructors
    public Project() {
        super();
    }
    public Project(int project_id, String company_name, String description, String requirements, String manager, Date start_date, Date end_date, int opening, String resources) {
        super();
        this.project_id = project_id;
        this.company_name = company_name;
        this.description = description;
        this.requirements = requirements;
        this.manager = manager;
        this.start_date = start_date;
        this.end_date = end_date;
        this.opening = opening;
        this.resources = resources;
    }
    public int getProject_id() {
        return project_id;
    }
    public void setProject_id(int project_id) {
        this.project_id = project_id;
    }
    public String getCompany_name() {
        return company_name;
    }
    public void setCompany_name(String company_name) {
        this.company_name = company_name;
    }

    public String getDescription() {
        return description;
    }
    public void setDescription(String description) {
        this.description = description;
    }
    public String getRequirements() {
        return requirements;
    }
    public void setRequirements(String requirements) {
        this.requirements = requirements;
    }
    public String getManager() {
        return manager;
    }
    public void setManager(String manager) {
        this.manager = manager;
    }
    public Date getStart_date() {
        return start_date;
    }
    public void setStart_date(Date start_date) {
        this.start_date = start_date;
    }
    public Date getEnd_date() {
        return end_date;
    }
    public void setEnd_date(Date end_date) {
        this.end_date = end_date;
    }
    public int getOpening() {
        return opening;
    }
    public void setOpening(int opening) {
        this.opening = opening;
    }
    public String getResources() {
        return resources;
    }
    public void setResources(String resources) {
        this.resources = resources;
    }
    @Override
    public String toString() {
        return "Project{" +
                "project_id=" + project_id +
                ", company_name='" + company_name + '\'' +
                ", description='" + description + '\'' +
                ", requirements='" + requirements + '\'' +
                ", manager='" + manager + '\'' +
                ", start_date=" + start_date +
                ", end_date=" + end_date +
                ", opening=" + opening +
                ", resources='" + resources + '\'' +
                '}';
    }
}

总结

本文为读者详细介绍了Spring Boot框架的四层构架,以及如何使用各种技术和工具来进行开发。通过阅读本文,希望可以帮助读者可以更好地理解Spring Boot框架的工作原理和应用场景,并能够利用所学知识来实现自己的项目。

参考资料:《Understanding Spring Boot Architecture》

扩展链接:

Redis从入门到实践

一节课带你搞懂数据库事务!

Chrome开发者工具使用教程

从表单驱动到模型驱动,解读低代码开发平台的发展趋势

低代码开发平台是什么?

基于分支的版本管理,帮助低代码从项目交付走向定制化产品开发

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/142870.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

GraphQL 与 REST 双重赋能:Hasura 帮你给数据库添加接口 | 开源日报 No.75

hasura/graphql-engine Stars: 30.3k License: Apache-2.0 Hasura GraphQL Engine 是一个开源产品&#xff0c;通过为您的数据提供 GraphQL 或 REST API 以及内置授权来加速 API 开发。它具有以下主要功能和核心优势&#xff1a; 内建强大查询&#xff1a;支持过滤、分页、模…

Cnyunwei

运维管理系统&#xff1a;监控系统 Cnyunwei Centos 6 封装 Cacti、Nagios、Centreon&#xff08;中英文自己切换&#xff09;、Check_MK、Nconf英文版本全部采用与国外官方同步的最新版本&#xff0c;会发布32位和64位两个版本。 安装很简单&#xff0c;直接回车即可全自动安…

如何在TS中使用JS库

在 TypeScript 中使用 JavaScript 库&#xff0c;几种常用的方法。 直接使用&#xff1a;如果 JavaScript 库不提供 TypeScript 类型定义文件&#xff08;.d.ts&#xff09;&#xff0c;您可以直接在 TypeScript 代码中使用该库。您可以通过在 TypeScript 代码的开头添加 //ts-…

模拟接口数据之使用Fetch方法实现

文章目录 前言一、package.json配置mock执行脚本二、封装接口&#xff0c;区分走ajax还是fetch三、创建mock目录&#xff0c;及相关接口文件四、定义接口五、使用mock数据使用模拟数据优化fetch返回数据 六、不使用模拟数据七、对比其他需要使用依赖相关配置如有启发&#xff0…

HTML字符实体

从注释汲取知识&#xff0c;由代码熟悉用法&#xff0c;所以直接看代码吧&#xff01;&#x1f447;&#x1f447;&#x1f447; <body><!-- 空格 --><!-- 三个空格&#xff0c;实际只显示一个 --><div>我 嘎嘎嘎</div><!-- 用字符实体代替…

C++引用 引用做函数参数

一.引用的定义和语法 // 给a取别名为b int &b a; // 修改b的值&#xff0c;a的值也会被修改&#xff0c;因为他们都指向同一个内存空间 b 20; 二.引用的注意事项 1.引用必须初始化如 int&b; 是错误的&#xff0c;因为没有初始化。 2.引用在初始化后&#xff0c;不…

聚观早报 |滴滴发布Q3财报;小鹏G9连续销量排行第一

【聚观365】11月14日消息 滴滴发布Q3财报 小鹏G9连续销量排行第一 XREAL双11实现7倍增长 真我GT5 Pro真机图 2024年智能手机AI功能竞争激烈 滴滴发布Q3财报 滴滴在其官网发布2023年三季度业绩报告。报告显示&#xff0c;三季度滴滴实现总收入514亿元&#xff0c;同比增长…

Command Injection

Command Injection "Command Injection"(命令注入)&#xff0c;其目标是通过一个应用程序在主机操作系统上执行任意命令。当一个应用程序将用户提供的数据&#xff08;如表单、cookies、HTTP头等&#xff09;传递给系统shell时&#xff0c;就可能发生命令注入攻击。在…

分享几个艺术生活小站点

今天分享几个艺术生活小站点&#xff01; 小叽News游戏资源分享 网址&#xff1a;https://steamzg.com/ 欢迎来到这个充满活力的游戏站点&#xff0c;这里汇集了各种类型的游戏&#xff0c;让你一次性尽享各种游戏的乐趣。这里是游戏爱好者的天堂&#xff0c;每款游戏都配有详…

2.3 Windows驱动开发:内核字符串转换方法

在内核编程中字符串有两种格式ANSI_STRING与UNICODE_STRING&#xff0c;这两种格式是微软推出的安全版本的字符串结构体&#xff0c;也是微软推荐使用的格式&#xff0c;通常情况下ANSI_STRING代表的类型是char *也就是ANSI多字节模式的字符串&#xff0c;而UNICODE_STRING则代…

C语言之初阶指针

一、指针&#xff1a; 其实按照我的理解&#xff0c;当我们写c语言程序的时候&#xff0c;创建的变量&#xff0c;数组等都要在内存上开辟空间。而每一个内存都有一个唯一的编号&#xff0c;这个编号也被称为地址编号&#xff0c;就相当于&#xff0c;编号地址指针。 二、指针…

2023金三银四常见Loadrunner面试题总结,附带答案

以下的loadrunner的面试题都是在面试过程中总结出来比较常见的面试题&#xff0c;现在分享给大家&#xff0c;希望可以帮助你们&#xff01; Q1、LoadRunner的工作原理是什么? Q2、LoadRunner分哪三部分? Q3、LoadRunner进行测试的流程? Q4、什么是并发?在lordrunner中&…

2.4 Windows驱动开发:内核字符串拷贝与比较

在上一篇文章《内核字符串转换方法》中简单介绍了内核是如何使用字符串以及字符串之间的转换方法&#xff0c;本章将继续探索字符串的拷贝与比较&#xff0c;与应用层不同内核字符串拷贝与比较也需要使用内核专用的API函数&#xff0c;字符串的拷贝往往伴随有内核内存分配&…

xss学习笔记

跨站脚本攻击 掌握XSS 的原理 掌握XSS 的场景 掌握XSS 的危害 掌握XSS 漏洞验证 掌握XSS 的分类跨站脚本攻击 漏洞概述 ​ 跨站点脚本&#xff08;Cross Site Scripting&#xff0c; XSS&#xff09;是指客户端代码注入攻击&#xff0c;攻击者可以在合法网站或Web 应用程…

Python机器学习算法入门教程(第五部分)

接着Python机器学习算法入门教程&#xff08;第四部分&#xff09;&#xff0c;继续展开描述。 二十五、Python Sklearn库SVM算法应用 SVM 是一种有监督学习分类算法&#xff0c;输入值为样本特征值向量和其对应的类别标签&#xff0c;输出具有预测分类功能的模型&#xff0c…

加解密算法相关技术详解

文章目录 简介工作机制加解密对称密钥算法非对称密钥算法 数字信封数字签名数字证书技术对比 推荐阅读 简介 随着网络技术的飞速发展&#xff0c;网络安全问题日益重要&#xff0c;加解密技术是网络安全技术中的核心技术&#xff0c;是最常用的安全保密手段。 加密&#xff1…

计算机毕业设计项目选题推荐(免费领源码)SSM+Mysql电商微信小程序09228

摘 要 随着微信小程序的使用越来越广泛&#xff0c;在传统的商业模式中&#xff0c;对于各类生活日常商品&#xff0c;人们习惯于到各种商家店铺购买。然而在快节奏的新时代中&#xff0c;人们不一定能为购买商品腾出时间&#xff0c;更不会耐心挑选自己想要的商品。所以设计一…

ubuntu利用crontab反弹shell

事情源于自&#xff0c;我利用redis未授权访问漏洞在向ubuntu的/varspool/cron/crontabs目录下创建的任务计划文件去反弹shell时&#xff0c;发现shell并不能反弹到自己的centos2上 &#xff08;1&#xff09;在ubuntu中进入/var/spool/cron/crontabs/目录 cd /var/spool/cro…

5.运行时数据区-字符串常量池、程序计数器、直接内存

目录 概述字符串常量池字符串常量池存储数据的方式三种常量池字面量与符号引用 哈希表实战 程序计数器直接内存直接内存与堆内存比较 结束 概述 相关文章在此总结如下&#xff1a; 文章地址jvm基本知识地址jvm类加载系统地址双亲委派模型与打破双亲委派地址运行时数据区地址 …

Windows系统隐藏窗口启动控制台程序

背景 上线项目有时候需要一些控制台应用作为辅助服务来协助UI应用满足实际需求&#xff0c;这时候如果一运行UI就冒出一系列的黑框&#xff0c;这将会导致客户被下的不起&#xff0c;生怕中了什么不知名病毒 方案 可以使用vbs来启动&#xff0c;这个是window系统自带的&#…