SprintBoot系列(十):JPA链接数据库及返回数据

1、IDEA如何添加数据库

JAVA、基础技术、技术与框架SprintBoot系列(十):JPA链接数据库及返回数据插图
JAVA、基础技术、技术与框架SprintBoot系列(十):JPA链接数据库及返回数据插图1

DataGrip连接sqlserver,提示驱动程序无法通过使用安全套接字层(SSL)加密与 SQL Server 建立安全连接的解决方法

JAVA、基础技术、技术与框架SprintBoot系列(十):JPA链接数据库及返回数据插图2
JAVA、基础技术、技术与框架SprintBoot系列(十):JPA链接数据库及返回数据插图3

添加Persistence

JAVA、基础技术、技术与框架SprintBoot系列(十):JPA链接数据库及返回数据插图4
JAVA、基础技术、技术与框架SprintBoot系列(十):JPA链接数据库及返回数据插图5
JAVA、基础技术、技术与框架SprintBoot系列(十):JPA链接数据库及返回数据插图6

通过IDEA逆向生成实体类@Entity

在Persistence的项目中,右键选择“Generate Persistence Mapping”“By Database Schema”

JAVA、基础技术、技术与框架SprintBoot系列(十):JPA链接数据库及返回数据插图7
JAVA、基础技术、技术与框架SprintBoot系列(十):JPA链接数据库及返回数据插图8
JAVA、基础技术、技术与框架SprintBoot系列(十):JPA链接数据库及返回数据插图9

用IDEA生成的工具生成的Model代码太多了,不便于查看。

初步优化方案:

package com.fcors.fcors.model;

import lombok.Getter;
import lombok.Setter;

import javax.persistence.*;

import java.util.Date;
import java.util.Objects;

@Entity
@Getter
@Setter
@Table(name = "banner")
public class BannerEntity {
    @Id
    @Column(name = "id")
    private Long id;
    private String name;
    private String description;

    @Column(name = "create_time")
    private Date createTime;

    @Column(name = "update_time")
    private Date updateTime;

    @Column(name = "delete_time")
    private Date deleteTime;

    private String title;
    private String img;

}
JAVA、基础技术、技术与框架SprintBoot系列(十):JPA链接数据库及返回数据插图10

初步优化后,我们只需要在需要的时候,重新定义逻辑即可。

对于返回的Json存在两个明显不友好的问题,如何让Json的key是蛇形输出?如何让日期输出格式化?

jackson提供了方法,只需要在配置文件application.yml中定义即可

spring:
  jackson:
    serialization:
      WRITE_DATES_AS_TIMESTAMPS: true
    property-naming-strategy: UPPER_CAMEL_CASE

property-naming-strategy的类型

  • LOWER_CAMEL_CASE userName 默认策略
  • KEBAB_CASE user-name
  • LOWER_CASE username
  • SNAKE_CASE user_name
  • UPPER_CAMEL_CASE UserName

IDEA生成的Model需要进行一些适配Java的修改

  • int==>Long
  • Timetamp===>Date
  • byte===>Boolean
  • 单体Json===>Object
  • 多体Json===>List<Object>

上述的方案还存在一个问题,关于 createTime、updateTime和deleteTime,我们并不需要返回到前端。那怎么操作呢?

我们可以在参数前添加注解:@JsonIgnore

JAVA、基础技术、技术与框架SprintBoot系列(十):JPA链接数据库及返回数据插图11
JAVA、基础技术、技术与框架SprintBoot系列(十):JPA链接数据库及返回数据插图12

我们接着思考一个问题,每个表都有时间字段,那么我每次都要如此繁琐的操作吗?如何解决这些通用的问题

我们可以通过创建一个基类,然后Model继承它。

在model下创建一个基类BaseEntity

package com.fcors.fcors.model;

import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Getter;
import lombok.Setter;

import javax.persistence.Column;
import javax.persistence.MappedSuperclass;
import java.util.Date;

@Getter
@Setter
@MappedSuperclass
public abstract class BaseEntity {
    @JsonIgnore
    @Column(name = "create_time")
    private Date createTime;
    @JsonIgnore
    @Column(name = "update_time")
    private Date updateTime;
    @JsonIgnore
    @Column(name = "delete_time")
    private Date deleteTime;
}

原本model下面的BannerEntity 集成这个基类

package com.fcors.fcors.model;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.databind.ser.Serializers;
import lombok.Getter;
import lombok.Setter;

import javax.persistence.*;

import java.util.Date;
import java.util.Objects;

@Entity
@Getter
@Setter
@Table(name = "banner")
public class BannerEntity extends BaseEntity {
    @Id
    @Column(name = "id")
    private Long id;
    private String name;
    private String description;
    private String title;
    private String img;
}

2、实体类返回一个记录

根据数据库及业务逻辑,我们知道banner和bannerItem是属于一对多的关系,如果通过实体类的一对多,来实现输出该如何实现呢?

1、在model使用工具生成类BannerItemEntity

package com.fcors.fcors.model;

import lombok.Getter;
import lombok.Setter;

import javax.persistence.*;
import java.sql.Timestamp;
import java.util.Objects;

@Entity
@Getter
@Setter
@Table(name = "banner_item")
public class BannerItemEntity extends BaseEntity  {
    @Id
    @Column(name = "id")
    private Long id;
    private String img;
    private String keyword;
    private short type;
    private Long bannerId;
    private String name;

}

2、修改model下面的BannerEntity,引入注解@OneToMany

package com.fcors.fcors.model;


import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Getter;
import lombok.Setter;

import javax.persistence.*;
import java.util.List;
import java.util.Set;


@Entity
@Getter
@Setter
@Table(name = "banner")
public class BannerEntity extends BaseEntity {
    @Id
    @Column(name = "id")
    private Long id;
    private String name;
    private String description;
    private String title;
    private String img;


    @OneToMany(fetch = FetchType.EAGER)
    @JoinColumn(name="bannerId")
    /* 设置懒加载 需要添加下面的注解  */
    /* 后续我们可以编写vo的类来实现最终数据的过滤输出 */
    private List<BannerItemEntity> bannerItemEntities;
}
JAVA、基础技术、技术与框架SprintBoot系列(十):JPA链接数据库及返回数据插图13

Spu与Sku的关系也是1对多的关系,回忆一下如何处理?

  • 创建一个Controller
  • 创建一个Service和接口
  • 创建一个Model绑定数据集成基类
  • 创建一个Repository,集成JpaRepository<T,T>,建立Service与Model的关系
  • 填写异常错误码

在api下创建一个Controller

package com.fcors.fcors.api.sample.v1;


import com.fcors.fcors.exception.NotFoundException;
import com.fcors.fcors.model.SpuEntity;
import com.fcors.fcors.service.SpuService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Positive;

@RestController
@RequestMapping("/spu/")
@Validated
public class SpuController {
    @Autowired
    private SpuService spuService;
    @GetMapping("/id/{id}/detail")
    public SpuEntity getOneByName(@PathVariable @Positive Long id){
        SpuEntity spu = spuService.findOneById(id);
        if(spu ==null){
            throw new NotFoundException(30003);
        }
        return spu;
    }
}

在service下面创建一个Service和接口

SpuService接口

package com.fcors.fcors.service;

import com.fcors.fcors.model.SpuEntity;

public interface SpuService {
    SpuEntity findOneById(Long id);
}

SpuServiceImpl

package com.fcors.fcors.service;

import com.fcors.fcors.model.SpuEntity;
import com.fcors.fcors.repository.SpuRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class SpuServiceImpl implements SpuService{

    @Autowired
    SpuRepository spuRepository;

    @Override
    public SpuEntity findOneById(Long id) {
        return this.spuRepository.findOneById(id);
    }
}

在model下创建一个Model绑定数据集成基类

package com.fcors.fcors.model;

import lombok.Getter;
import lombok.Setter;

import javax.persistence.*;
import java.sql.Timestamp;
import java.util.Objects;

@Getter
@Setter
@Entity
@Table(name = "spu")
public class SpuEntity extends BaseEntity{
    @Id
    @Column(name = "id")
    private Long id;
    private String title;
    private String subtitle;
    private Long categoryId;
    private Integer rootCategoryId;
    private byte online;
    private String price;
    private Integer sketchSpecId;
    private Integer defaultSkuId;
    private String img;
    private String discountPrice;
    private String description;
    private String tags;
    private Byte isTest;
    private String spuThemeImg;
    private String forThemeImg;

}

在 Repository下创建SpuRepository

package com.fcors.fcors.repository;

import com.fcors.fcors.model.SpuEntity;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

/*JpaRepository<@value1,@value2>
 * @value1:model类名
 * @value:model的主键即表的主键
 * */
@Repository
public interface SpuRepository extends JpaRepository<SpuEntity,Long> {
    SpuEntity findOneById(Long id);
}

追加resource/config/exception-code.properties

fcors.codes[30003]=SpuId无记录
JAVA、基础技术、技术与框架SprintBoot系列(十):JPA链接数据库及返回数据插图14

3、实体列返回一个列表

基于demo2,我们进行修改,并让它能返回一个Spu的list

  • 在SpuRepository追加findAll方法
  • 在service的接口和类中实现方法
  • 在controller定义一个入口

在SpuRepository下面追加方法 findAll

package com.fcors.fcors.repository;

import com.fcors.fcors.model.SpuEntity;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import java.util.List;

/*JpaRepository<@value1,@value2>
 * @value1:model类名
 * @value:model的主键即表的主键
 * */
@Repository
public interface SpuRepository extends JpaRepository<SpuEntity,Long> {
    SpuEntity findOneById(Long id);

    List<SpuEntity> findAll();
}

分别在Service的接口和类引入这个方法

Service下的SpuService接口代码

package com.fcors.fcors.service;

import com.fcors.fcors.model.SpuEntity;

import java.util.List;

public interface SpuService {
    SpuEntity findOneById(Long id);

    List<SpuEntity> getLastPagingSpu();
}

Service下的SpuServiceImpl代码

package com.fcors.fcors.service;

import com.fcors.fcors.model.SpuEntity;
import com.fcors.fcors.repository.SpuRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class SpuServiceImpl implements SpuService{

    @Autowired
    SpuRepository spuRepository;

    @Override
    public SpuEntity findOneById(Long id) {
        return this.spuRepository.findOneById(id);
    }

    @Override
    public List<SpuEntity> getLastPagingSpu() {
        return this.spuRepository.findAll();
    }
}

在SpuController定义一个入口

package com.fcors.fcors.api.sample.v1;


import com.fcors.fcors.exception.NotFoundException;
import com.fcors.fcors.model.SpuEntity;
import com.fcors.fcors.service.SpuService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Positive;
import java.util.List;

@RestController
@RequestMapping("/spu/")
@Validated
public class SpuController {
    @Autowired
    private SpuService spuService;
    @GetMapping("/id/{id}/detail")
    public SpuEntity getOneByName(@PathVariable @Positive Long id){
        SpuEntity spu = spuService.findOneById(id);
        if(spu ==null){
            throw new NotFoundException(30003);
        }
        return spu;
    }

    @GetMapping("/latest")
    public List<SpuEntity> getLastPagingSpu(){
        List<SpuEntity> SpuList = this.spuService.getLastPagingSpu();
        return SpuList;
    }
}
JAVA、基础技术、技术与框架SprintBoot系列(十):JPA链接数据库及返回数据插图15

如果我们可以实现按需要加载字段和加载懒加载的list呢?

关于JPA的乐观锁和悲观锁

https://juejin.cn/post/6844903742161027079