从0到1开发水果商城管理系统-第二章SpringBoot的增删改查实现

第二章:水果商品API接口-增删改查的实现:

这里数据存储在MySQL中,符合大多数的应用场景,首先需要先将必需的依赖进行导入:

<!-- Spring Boot Web依赖 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

<!-- Spring Boot JPA依赖 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

<!-- MySQL驱动依赖 -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.26</version>
</dependency>

PS:若出现mysql报错,则大概率是连接问题,请检查是否允许所有主机进行连接、Mysql驱动依赖是否相对应、application配置文件是否正确等。这里我使用的是Mysql8.0.26的版本,如有需要,请做适当修改。

在application.properties中配置Mysql数据源:

spring.datasource.url=jdbc:mysql://localhost:3306/数据库
spring.datasource.username=用户名
spring.datasource.password=密码
spring.datasource.driver-class-name=com.mysql.jdbc.Driver

生成对应表格的sql如下:

CREATE TABLE fruit (
  id INT NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  name VARCHAR(50) NOT NULL COMMENT '水果名称',
  description TEXT COMMENT '水果描述',
  price DECIMAL(10, 2) NOT NULL COMMENT '价格',
  category VARCHAR(50) NOT NULL COMMENT '水果类别',
  PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='水果信息表';

注释说明:

  • id:主键ID

  • name:水果名称

  • description:水果描述

  • price:价格

  • category:水果类别

  • PRIMARY KEY (id):将 id 字段设为主键

  • ENGINE=InnoDB:使用 InnoDB 存储引擎

  • DEFAULT CHARSET=utf8mb4:设置默认字符集为 utf8mb4

  • COMMENT='水果信息表':对表进行注释,说明该表的作用。

(PS:使用Navicat可以实现数据的自动生成。)

接着,我们创建一个名为Fruit的实体类,并使用@Entity注解将其标记为JPA实体类。该类包含了水果商品的id、名称、描述、价格和库存属性,并通过getter和setter方法对其进行了封装。

@Entity
public class Fruit {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;

    private String description;

    private BigDecimal price;

    private Integer category;

    // 自行生成getter和setter方法
}

@Entity注解的作用是用来标识Fruit类是一个JPA实体类,也就是将Fruit类映射到数据库中的表,在JPA中,每一个实体类对应着数据库中的一张表,也就是说:这里我创建了一个Fruit类,给F类标识为JPA实体类,name在数据库中就对应着一张表,其中id、name、description等变量都对应成数据库中表的字段。@Entity这个注解就是用来表示这个类对应的是哪张表。

@Id注解则是用来标识一个属性为实体的唯一标识符,对应着数据库中的主键。在JPA中,每一个实体类都必须有一个@Id注解标识的属性来表示它在数据库中的唯一性。

@GeneratedValue注解则是用来指定主键生成策略的。在JPA中,主键可以使用多种方式生成,如自增长、UUID等,而这个注解就是用来指定生成方式的。它通常和@Id注解一起使用,用来为实体类的主键生成一个唯一的值。

JPA Repository接口工作原理、优点及实现举例

我们通过定义Fruit实体类对数据库中的表格实现映射,接下来我们进行JPA Repository接口的实现。我们在utils包下,创建一个名为FruitRepository的接口,该接口继承了JPARepository,JPARepository提供了一种通用的数据访问接口,能够实现CRUD操作和一些基于属性的查询方法,以下是JpaRepository的一些优势:

  1. 简化数据访问层的代码:提供了一些数据访问的方法,可以大大的减少开发者编写数据访问层代码层的工作量.

  1. 提供了一些基于属性的查询方法,能够根据实体类(FruitRepository)的属性自动生成查询语句,大大简化了查询语句的编写。

  1. 自定义查询:JPARespotitory接口提供了自定义查询的方法,如@Query注解和方法命名规则等方式,这些方式可以让开发者根据需求进行自定义查询。

JPA的优势巨大,在这里便不再一一赘述。总而言之,JpaRepository 接口的优势在于它可以帮助开发者快速地完成数据访问层的开发,同时提供了一些基于属性查询和自定义查询的方式,使得开发者可以更加方便地进行数据的操作。

JPA Repository详解及举例

为了方便理解,在这里我们举一个JPA接口的例子。假设我们有一个实体类User,属性包括id、name、age、email,我们需要进行常见的增删改查操作,在这里我们定义了一个UserRepository接口来继承JPARepositiry,然后,在UserRepository中进行自定义查询方法的定义,如下:

public interface UserRepository extends JpaRepository<User, Long> {
    List<User> findByName(String name);
    List<User> findByAgeGreaterThan(int age);
    List<User> findByEmailLike(String emailPattern);
}
//定义findByxxx方法,实这些方法会根据传入参数自动生成查询语句。

接下来,我们可以自使用自动注入UserRepository对象来进行数据操作:

这里我们定义了一个Service类,Service类是业务逻辑层,通过调用UserRepository接口来实现对UserRepository实体类的操作。

@@Service
public class UserService {
    @Autowired
    private UserRepository userRepository;

    public User findById(Long id) {
        return userRepository.findById(id).orElse(null);
    }

    public List<User> findByName(String name) {
        return userRepository.findByName(name);
    }

    public List<User> findByAgeGreaterThan(int age) {
        return userRepository.findByAgeGreaterThan(age);
    }

    public List<User> findByEmailLike(String emailPattern) {
        return userRepository.findByEmailLike("%" + emailPattern + "%");
    }

    public User save(User user) {
        return userRepository.save(user);
    }

    public void deleteById(Long id) {
        userRepository.deleteById(id);
    }
}

上面的代码中,我们在 UserService 中注入了 UserRepository 对象,然后可以调用其中定义的方法来进行数据操作。例如,findById 方法调用了 JpaRepository 中提供的 findById 方法,findByName 方法调用了自定义的 findByName 方法等。这些方法可以方便地完成常见的数据操作。

简单来说就是:User类提供了数据库映射,UR接口继承了JPA提供的接口,简化了数据操作。Service类则实现了通过User实体类,进而实现对数据库的增删改查操作。

        +----------------+                  +---------------------+
        |     User       |                  |    UserRepository   |
        +----------------+                  +---------------------+
        |  id            |                  |   findAll()          |
        |  name          |                  |   findById()         |
        |  email         |     关联关系     |   save()             |
        |  password      |  ------------>   |   delete()           |
        +----------------+                  +---------------------+
                  |                                        |
                  |                                        |
                  |                                        |
                  |                                        |
                  |                                        |
                  |                                        |
        +----------------+                  +---------------------+
        |   UserService  |                  |      数据库         |
        +----------------+                  +---------------------+
        |  getUserById() |                  |   user_table        |
        |  saveUser()    |     关联关系     |   id                |
        |  deleteUser()  |  ------------>   |   name              |
        +----------------+                  |   email             |
                                             |   password          |
                                             +---------------------+

在这个示意图中,User 类和 UserRepository 接口之间的关系是通过 JPA 实现的。User 类通过注解来与数据库中的表进行映射,并且定义了一些实体类的属性和方法。UserRepository 接口继承了 JpaRepository 接口,并且提供了一些基本的数据访问方法,例如 findAll()、findById()、save() 和 delete() 等。

而 UserService 类作为应用程序的服务类,通过调用 UserRepository 中的方法,来对 User 实体类进行操作。例如,getUserById() 方法可能会调用 UserRepository 的 findById() 方法,来查询一个 User 对象,并且对查询结果进行一些逻辑处理后返回给调用方。这样,User 类、UserRepository 接口和 UserService 类就可以协同工作,来完成应用程序中的数据操作和业务逻辑处理。

FruitRepository接口实现

至此,我们大概也就理解了为何要创建FruitRepository接口来继承JPARepository。

下面我们开始编写FruitRepository接口:

package com.example.springrestudy.utils;

import com.example.springrestudy.bean.Fruit;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.List;

public interface FruitRepository extends JpaRepository <Fruit,Long>{
    List<Fruit> findAll();
}

JpaRepository <Fruit,Long>是一个带有泛型的接口,泛型是可以用来创建具有不同数据类型的类、接口和方法的机制,使用泛型使得代码更为灵活,daima的复用性和可读性更高。

这里传入的第一泛型是实体类,第二泛型是参实体类主键的数据类型,第一泛型较好理解,但第二泛型若多个数据类型同为long,如何解决该问题?

事实上,在Fruit类中已经解决了该问题了,如下:

@Entity
public class Fruit {
    @Id   //这里的Id注解便将id作为Fruit类中的实体类主键,因此,即使有第二个类型为long的字段也不影响。

}

接着,我们编写FruitController类,在controller包下创建名为FruitController类,用来处理Http请求,

在一个典型的 Spring MVC 应用程序中,控制器类(Controller)负责处理 HTTP 请求,并根据请求的内容调用适当的服务或处理逻辑,然后返回 HTTP 响应。

这里我们先以Get请求返回所有数据来进行演示:

package com.example.springrestudy.controller;

import com.example.springrestudy.bean.Fruit;
import com.example.springrestudy.utils.FruitRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
@RequestMapping("/api/fruit")
public class FruitController {
    @Autowired
    private FruitRepository fruitRepository;


    @GetMapping("/findAll")
    public List<Fruit> getAllFruits(){
        return fruitRepository.findAll();
    }

}

我们将数据浏览器中进行请求操作,如下

在ApiPost中进行请求:

请求成功!下面开始进行增删改查的数据操作的实现:

数据添加操作:

在FruitController中创建一个POST请求处理方法,在其中使用FruitRepository中的save()方法将数据保存至数据库中。

    @PostMapping("/add")
    public Fruit addFruit(@RequestBody Fruit fruit){
        return fruitRepository.save(fruit);
    }

将json数据通过POST请求方式发送至/api/fruit/add下,即可返回响应数据。

数据查询操作:

通过定义Get查询,传入为name的参数,按照名称来进行查询,同理我们也可以通过id、category(类别)来进行查询。这就看你的具体需求了。

    @GetMapping("/search")
    public List<Fruit> findFruitsByName(@RequestParam("name") String name) {
        return fruitRepository.findByName(name);
    }

数据删除操作:

同理,删除操作也是非常简单的,此处需要注意,删除操作的请求方式为Delete,不要用Get一直尝试请求。

//删除操作,请求路径为 /fruits/{id},请求方式为 DELETE
    @DeleteMapping("/{id}")
    public ResponseEntity<?> deleteFruit(@PathVariable Long id) {
        Fruit fruit = fruitRepository.findById(id).orElse(null);
        if (fruit == null) {
            return ResponseEntity.notFound().build();
        }
        fruitRepository.delete(fruit);
        return ResponseEntity.ok().build();
    }

在上述示例中,我们定义了一个名为deleteFruit的方法,并在该方法上使用了@DeleteMapping注解。该注解表示请求方式为DELETE,并且路径为/fruits/{id},其中{id}表示要删除的水果商品的id。

在方法中,我们通过FruitRepository的findById方法查询指定id的水果商品,如果查询到了,则使用FruitRepository的delete方法删除该商品。最后,我们使用ResponseEntity.ok()方法返回删除成功的响应。如果查询不到指定id的水果商品,我们则返回一个404响应。

这里我们尝试删除刚添加的id为1005的商品,测试成功,该id商品已被删除。

数据修改操作:

在SpringBoot中,数据修改的工作流程如下:

  1. 接收请求:通过Controller层接收POST请求,请求参数包含要修改的数据以及修改后的值。

  1. 数据验证:对请求参数进行校验,确保传入的数据格式正确。

  1. 调用JPA接口:通过调用对应的JPA接口,执行数据修改操作。JPA接口中的方法名必须符合JPA规范,以便框架自动转换为对应的SQL语句。

  1. 数据库操作:JPA会将方法名转换为对应的SQL语句,并通过JDBC执行操作。

  1. 返回响应:操作完成后,将操作结果封装成响应对象,通过Controller层返回给客户端。

我们以id为1006的peach为例,将价格修改为8.99

首先需要编写JPA接口方法,在实际开发中,会遇到各种复杂的查询或者数据操作,因此JPA所提供的方法并无法满足数据操作的需求,因此,我们需要自行编写方法:

在FruitRepository接口中进行如下daima编写:

    @Transactional
    @Modifying  //指定该方法为执行修改操作
    @Query("UPDATE Fruit f SET f.price = :newPrice WHERE f.id = :id")
    //@Query注解的作用是指定该方法执行SQL语句,在此为更新水果价格。
    int updatePriceById(@Param("id") Long id, @Param("newPrice") BigDecimal newPrice);

控制器类中调用该updatePriceById方法:

@PostMapping("/change/{id}") //使用{id}作为路径参数。

    //声明changeFruitPrice方法,使用@PathVariable获取路径参数{id},使用@RequestBody获取请求体中的JSON数据。
    public ResponseEntity<String> changeFruitPrice(@PathVariable("id") Long id, @RequestBody Map<String, Object> body) {
        //获取JSON数据中的newPrice,并将其转换为BigDecimal类型。
        BigDecimal newPrice = new BigDecimal(body.get("newPrice").toString());
        //调用FruitRepository的updatePriceById方法,更新水果的价格。
        int result = fruitRepository.updatePriceById(id, newPrice);
        //如果更新失败,则返回状态码为404,响应消息为"Fruit not found."。
        if (result == 0) {
            return ResponseEntity.status(HttpStatus.NOT_FOUND).body("Fruit not found.");
        }
        //更新成功后,返回状态码为200,响应消息为"Fruit price updated successfully."。
        return ResponseEntity.ok("Fruit price updated successfully.");
    }

通过APIPost进行调用测试:请求成功!数据已被修改。

数据修改部分需要注意:

  1. 因为是通过json进行传输数据,而json是字符串类型的,因此需要将数据类型转化为BigDecimal,也就是符合数据库存储类型的数据类型。

  1. 在进行POST请求时,注意@PathVariable注解绑定了id,因此在传参是必须将id传入到URL中,而price需要通过json格式进行传输。

至此,我们的商品的增删改查接口也就已经完成了!是不是不难呀~其实只要掌握了注解的使用方法、JPA接口的使用方法、实体类对数据库表格的映射,增删改查就变得非常简单了。

第三章我们开始讲解如何通过VUE,结合element-ui,以最简单的方式,将我们的数据渲染至前端页面上!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值