SpringBoot+JPA实例


一、测试环境

IDEA 2020.3

Java 11

PostgreSQL 12.3

二、开发环境搭建

pom.xml

不喜欢用parent引入的方式 , 所以自己引入了依赖并排除的冲突

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0modelVersion>
    <groupId>com.mycloudgroupId>
    <artifactId>mycloud-coreartifactId>
    <version>0.0.0.1version>
    <name>mycloud-corename>
    <description>My Cloud Coredescription>
    <properties>
        <java.version>11java.version>
        <springboot.version>2.6.1springboot.version>
        <log4j.version>2.16.0log4j.version>
        <slf4j.version>1.8.0-beta4slf4j.version>
    properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-webartifactId>
            <version>${springboot.version}version>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.bootgroupId>
                    <artifactId>spring-boot-starter-loggingartifactId>
                exclusion>
                <exclusion>
                    <groupId>org.springframework.bootgroupId>
                    <artifactId>spring-boot-starter-tomcatartifactId>
                exclusion>
            exclusions>
        dependency>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-undertowartifactId>
            <version>${springboot.version}version>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.bootgroupId>
                    <artifactId>spring-boot-starter-loggingartifactId>
                exclusion>
                <exclusion>
                    <groupId>org.springframework.bootgroupId>
                    <artifactId>spring-boot-starter-loggingartifactId>
                exclusion>
            exclusions>
        dependency>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-data-jpaartifactId>
            <version>${springboot.version}version>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.bootgroupId>
                    <artifactId>spring-boot-starter-loggingartifactId>
                exclusion>
                <exclusion>
                    <groupId>net.bytebuddygroupId>
                    <artifactId>byte-buddyartifactId>
                exclusion>
                <exclusion>
                    <artifactId>jboss-loggingartifactId>
                    <groupId>org.jboss.logginggroupId>
                exclusion>
            exclusions>
        dependency>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-devtoolsartifactId>
            <version>${springboot.version}version>
            <scope>runtimescope>
            <optional>trueoptional>
        dependency>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-testartifactId>
            <version>${springboot.version}version>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.bootgroupId>
                    <artifactId>spring-boot-starter-loggingartifactId>
                exclusion>
                <exclusion>
                    <groupId>jakarta.xml.bindgroupId>
                    <artifactId>jakarta.xml.bind-apiartifactId>
                exclusion>
                <exclusion>
                    <groupId>net.bytebuddygroupId>
                    <artifactId>byte-buddyartifactId>
                exclusion>
                <exclusion>
                    <artifactId>byte-buddy-agentartifactId>
                    <groupId>net.bytebuddygroupId>
                exclusion>
            exclusions>
            <scope>testscope>
        dependency>

        <dependency>
            <groupId>net.bytebuddygroupId>
            <artifactId>byte-buddyartifactId>
            <version>1.11.22version>
        dependency>
        <dependency>
            <groupId>net.bytebuddygroupId>
            <artifactId>byte-buddy-agentartifactId>
            <version>1.11.22version>
        dependency>

        <dependency>
            <groupId>org.jboss.logginggroupId>
            <artifactId>jboss-loggingartifactId>
            <version>3.4.2.Finalversion>
        dependency>

        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-log4j2artifactId>
            <version>${springboot.version}version>
        dependency>

        <dependency>
            <groupId>org.postgresqlgroupId>
            <artifactId>postgresqlartifactId>
            <version>42.2.8version>
        dependency>
        <dependency>
            <groupId>com.google.code.gsongroupId>
            <artifactId>gsonartifactId>
            <version>2.8.9version>
        dependency>
        <dependency>
            <groupId>com.google.guavagroupId>
            <artifactId>guavaartifactId>
            <version>31.0.1-jreversion>
        dependency>

        <dependency>
            <groupId>javax.xml.bindgroupId>
            <artifactId>jaxb-apiartifactId>
            <version>2.3.1version>
        dependency>
        <dependency>
            <groupId>javax.activationgroupId>
            <artifactId>activationartifactId>
            <version>1.1.1version>
        dependency>
    dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-maven-pluginartifactId>
                <version>${springboot.version}version>
            plugin>
        plugins>
    build>

project>

application.yml

server:
  port: 8081
  undertow:
    io-threads: 32
    worker-threads: 100
    buffer-size: 1024
    direct-buffers: true
spring:
  profiles:
    active: dev

application-dev.yml

spring:
  devtools:
    restart:
      enabled: true  #设置开启热部署
      additional-paths: src/main/java,src/main/resources #重启目录
      exclude: WEB-INF/**
  datasource:
    type: com.zaxxer.hikari.HikariDataSource
    driverClassName: org.postgresql.Driver
    url: jdbc:postgresql://127.0.0.1:5432/framework03
    username: dbuser
    password: dbuserpwd
    # Hikari 连接池配置
    # 最小空闲连接数量
    hikari:
      minimum-idle: 5
      # 空闲连接存活最大时间,默认600000(10分钟)
      idle-timeout: 180000
      # 连接池最大连接数,默认是10
      maximum-pool-size: 10
      # 此属性控制从池返回的连接的默认自动提交行为,默认值:true
      auto-commit: true
      # 连接池名称
      pool-name: Wanma-Cloud-Pool
      # 此属性控制池中连接的最长生命周期,值0表示无限生命周期,默认1800000即30分钟
      max-lifetime: 1800000
      # 数据库连接超时时间,默认30秒,即30000
      connection-timeout: 30000
      connection-test-query: SELECT 1
  jpa:
    datasource: postgresql
    show-sql: true
    hibernate:
      ddl-auto: update
    properties:
      hibernate:
        dialect: org.hibernate.dialect.PostgreSQL10Dialect
        temp:
          use_jdbc_metadata_defaults: false

三、主启动运行文件

Application.java

@SpringBootApplication
/** 开启自动配置扫描 */
@EnableAutoConfiguration
/** 自动扫描controller */
@ComponentScans(value = {
        @ComponentScan(
                value = "com.mycloud",
                useDefaultFilters = true,
                includeFilters = {@ComponentScan.Filter(type = FilterType.CUSTOM, classes = {IScanFilter.class})}
        )
})
/** 自动扫描entity */
@EntityScan(basePackages = {"com.mycloud"})
/** 自动扫描repository , basePackages集合不能有交集 */
@EnableJpaRepositories(basePackages = {"com.mycloud"})
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

主要用来扫描过滤自动扫描的Controller类,增加效率

public class IScanFilter implements TypeFilter {
    private final static String CONTROLLER_PREFIX = "Controller";

    @Override
    public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
        String className = metadataReader.getClassMetadata().getClassName();
        if (className.endsWith(CONTROLLER_PREFIX)) {
            return true;
        }
        return false;
    }
}

四、JPA测试

1 . 首先建立Entity类 , 和数据库做直接映射 , 不要跟我说lombok , 最不喜欢这个插件

@Entity
@Table(name = "ct_lib_book")
public class CtLibBook {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

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

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getBookName() {
        return bookName;
    }

    public void setBookName(String bookName) {
        this.bookName = bookName;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public String getDetail() {
        return detail;
    }

    public void setDetail(String detail) {
        this.detail = detail;
    }

    @Override
    public String toString() {
        return bookName + "-" + description;
    }
}

2.建立调用接口类(Repository)

@Repository
public interface CtLibBookRepository extends JpaRepository {
    @Query(value = "select * from ct_lib_book", nativeQuery = true)
    List getAllBookData();

    @Query(value = "select * from ct_lib_book where book_name = :bookName", nativeQuery = true)
    List getBooksByName(@Param("bookName") String bookName);
}

3.建立Service层(非必须 , 但是必须要有)

@Service
public class CtLibBookService {
    @Autowired
    private CtLibBookRepository ctLibBookRepository;

    public List getAll() {
        return ctLibBookRepository.getAllBookData();
    }

    public List getNyBookname(String bookName) {
        return ctLibBookRepository.getBooksByName(bookName);
    }

    public void save(CtLibBook ctLibBook) {
        ctLibBookRepository.save(ctLibBook);
    }
}

4.建立Controller层进行调用(测试用)

@RestController
public class HelloController {
    @Autowired
    CtLibBookService ctLibBookService;

    @ResponseBody
    @RequestMapping("/hello")
    public String hello() {
        StringBuilder sb = new StringBuilder();

        /// System.out.println("Get book All");
        List temp = ctLibBookService.getAll();
        for (int i = 0; i < temp.size(); i++) {
            CtLibBook book = temp.get(i);
            sb.append(IGson.format(book));
        }
        /// System.out.println("Get book by Name");
        temp = ctLibBookService.getNyBookname("AA");
        for (int i = 0; i < temp.size(); i++) {
            CtLibBook book = temp.get(i);
            sb.append(IGson.format(book));
        }

        return sb.toString();
    }
}

测试结果 : 

PS : 

当数据库中 , 没有表ct_lib_book是 , 会自动创建表  ,当表结构更新时  , 也会自动更新表结构

这个应该就是JPA最大的优势了 .

其他的优势 , 应该都被MyBatis-Plus给覆盖了. 

5.鉴于JPA写复杂查询特别不方便的问题 

 写个Sql执行工具类

@Component
public class SqlService {
    /// public static final SqlService me = new SqlService();

    @PersistenceContext
    EntityManager em;

    public List> query(String sql) {
        Query query = em.createNativeQuery(sql);
        @SuppressWarnings("unchecked")
        List> list = query.unwrap(NativeQueryImpl.class).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP).list();
        return list;
    }


    public void excute(String sql) {
        Query query = em.createNativeQuery(sql);
        query.executeUpdate();
    }
}

如此 , 就能如此进行调用了 

@RestController
public class HelloController {
    @Autowired
    SqlService sqlService;

    @ResponseBody
    @RequestMapping("/hello")
    public String hello() {
        StringBuilder sb = new StringBuilder();
        
        List> results = sqlService.query("select * from ct_lib_book");
        sb.append(IGson.format(results));

        return sb.toString();
    }
}