Spring Boot 3.0.x和Oracle Database 23c(beta)和GraalVM Enterprise 22.3(JDK17)的综合体验(系列17)

35 篇文章 0 订阅
12 篇文章 3 订阅

体验Spring Boot 3.0.x和Spring JPA集成

推荐之前阅读

示例代码

https://github.com/engchina/springboot3withdb23c/tree/main/SpringBoot3WithJPA

SpringBoot pom.xml的配置(相关部分)

	<properties>
		<java.version>17</java.version>
		<project.build.souceEncoding>UTF-8</project.build.souceEncoding>
		<spring-boot.build-image.imageName>springboot3withjpa</spring-boot.build-image.imageName>
	</properties>
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-jpa</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-mustache</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<dependency>
			<groupId>com.h2database</groupId>
			<artifactId>h2</artifactId>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>

	<build>
		<finalName>springboot3withjpa</finalName>
		<plugins>
			<plugin>
				<groupId>org.hibernate.orm.tooling</groupId>
				<artifactId>hibernate-enhance-maven-plugin</artifactId>
				<version>${hibernate.version}</version>
				<executions>
					<execution>
						<id>enhance</id>
						<goals>
							<goal>enhance</goal>
						</goals>
						<configuration>
							<enableLazyInitialization>true</enableLazyInitialization>
							<enableDirtyTracking>true</enableDirtyTracking>
							<enableAssociationManagement>true</enableAssociationManagement>
						</configuration>
					</execution>
				</executions>
			</plugin>
			<plugin>
				<groupId>org.graalvm.buildtools</groupId>
				<artifactId>native-maven-plugin</artifactId>
				<configuration>
					<imageName>springboot3withjpa</imageName>
				</configuration>
			</plugin>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

VideoSearch.java 代码

package com.oracle.db23c.springboot3withjpa.vo;

public record VideoSearch(String name, String description) {
}

UniversalSearch.java 代码

package com.oracle.db23c.springboot3withjpa.vo;

public record UniversalSearch(String value) {
}

VideoEntity.java 代码

package com.oracle.db23c.springboot3withjpa.entity;

import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;

// @Entity是 JPA 的注解,用于指示这是 JPA 管理的类型。
@Entity
public class VideoEntity {
    // @Id是 JPA 标记主键的注解。
    // @GeneratedValue 是一个 JPA 注解,用于将key的生成卸载到 JPA 提供程序。
    private @Id
    @GeneratedValue Long id;
    private String name;
    private String description;

    // JPA 需要一个公共或受保护的无参数构造函数方法。
    public VideoEntity() {
        this(null, null);
    }

    // 我们还有一个未提供 id 字段的构造函数:一个专为在数据库中创建新条目而设计的构造函数。
    // 当 id 字段为 null 时,它会告诉 JPA 我们要在表中创建一个新行。
    public VideoEntity(String name, String description) {
        this.id = null;
        this.description = description;
        this.name = name;
    }

    public Long getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getDescription() {
        return description;
    }

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

NewVideo.java 代码

package com.oracle.db23c.springboot3withjpa.entity;

public record NewVideo(String name, String description) {
}

VideoRepository.java 代码

package com.oracle.db23c.springboot3withjpa.repository;

import com.oracle.db23c.springboot3withjpa.entity.VideoEntity;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;

import java.util.List;

// 它使用两个通用参数VideoEntity 和 Long(域类型和主键类型)扩展了 JpaRepository
// JpaRepository是一个Spring Data JPA接口,包含一组已经支持的更改替换更新删除(CRUD)操作。
public interface VideoRepository extends JpaRepository
        <VideoEntity, Long> {

    // 创建自定义查找器。我们永远不必实现此方法。Spring Data将按照本节所述为我们完成此操作。
    // 返回类型为 List<VideoEntity>,指示它必须返回存储库域类型的列表。
    // 所有以 findBy 开头的存储库方法都标记为查询。
    // select video.* from VideoEntity video where video.name = ?1
    List<VideoEntity> findByName(String name);

    // @Query是Spring Data JPA提供自定义JPQL语句的方式。
    @Query("select v from VideoEntity v where v.name = ?1")
    List<VideoEntity> findCustomerReport(String name);

    // Spring Data JPA 3.0 包含 JSqlParser,一个 SQL 解析库,可以按如下方式编写查询
    @Query(value="select * from VIDEO_ENTITY where NAME = ?1", nativeQuery=true)
    List<VideoEntity> findCustomWithPureSql(String name);

    List<VideoEntity> findByNameContainsIgnoreCase(String partialName);

    List<VideoEntity> findByDescriptionContainsIgnoreCase(String partialDescription);

    List<VideoEntity> findByNameContainsOrDescriptionContainsAllIgnoreCase(String partialName,
                                                                           String partialDescription);
}

MainService.java 代码

package com.oracle.db23c.springboot3withjpa.service;

import com.oracle.db23c.springboot3withjpa.entity.NewVideo;
import com.oracle.db23c.springboot3withjpa.vo.UniversalSearch;
import com.oracle.db23c.springboot3withjpa.entity.VideoEntity;
import com.oracle.db23c.springboot3withjpa.repository.VideoRepository;
import com.oracle.db23c.springboot3withjpa.vo.VideoSearch;
import jakarta.annotation.PostConstruct;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.ExampleMatcher;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.Collections;
import java.util.List;

@Service
public class MainService {

    private final VideoRepository repository;

    public MainService(VideoRepository repository) {
        this.repository = repository;
    }

    public List<VideoEntity> getVideos() {
        return repository.findAll();
    }

    public VideoEntity create(NewVideo newVideo) {
        return repository.saveAndFlush(new VideoEntity(newVideo.name(), newVideo.description()));
    }

    public List<VideoEntity> search(VideoSearch videoSearch) {
        if (StringUtils.hasText(videoSearch.name()) //
                && StringUtils.hasText(videoSearch.description())) {
            return repository //
                    .findByNameContainsOrDescriptionContainsAllIgnoreCase( //
                            videoSearch.name(), videoSearch.description());
        }

        if (StringUtils.hasText(videoSearch.name())) {
            return repository.findByNameContainsIgnoreCase(videoSearch.name());
        }

        if (StringUtils.hasText(videoSearch.description())) {
            return repository.findByDescriptionContainsIgnoreCase(videoSearch.description());
        }

        // 最后,如果两个字段都为空(或 null),则只返回一个结果
        return Collections.emptyList();
    }

    public List<VideoEntity> search(UniversalSearch search) {
        VideoEntity probe = new VideoEntity();
        if (StringUtils.hasText(search.value())) {
            probe.setName(search.value());
            probe.setDescription(search.value());
        }
        Example<VideoEntity> example = Example.of(probe, //
                ExampleMatcher.matchingAny() //
                        .withIgnoreCase() //
                        .withStringMatcher(ExampleMatcher.StringMatcher.CONTAINING));
        return repository.findAll(example);
    }

    @PostConstruct
    void initDatabase() {
        repository.save(new VideoEntity("Need HELP with your SPRING BOOT 3 App?",
                "SPRING BOOT 3 will only speed things up and make it super SIMPLE to serve templates and raw data."));
        repository.save(new VideoEntity("Don't do THIS to your own CODE!",
                "As a pro developer, never ever EVER do this to your code. Because you'll ultimately be doing it to YOURSELF!"));
        repository.save(new VideoEntity("SECRETS to fix BROKEN CODE!",
                "Discover ways to not only debug your code, but to regain your confidence and get back in the game as a software developer."));
    }
}

WebController.java 代码

package com.oracle.db23c.springboot3withjpa.controller;

import com.oracle.db23c.springboot3withjpa.entity.NewVideo;
import com.oracle.db23c.springboot3withjpa.vo.UniversalSearch;
import com.oracle.db23c.springboot3withjpa.entity.VideoEntity;
import com.oracle.db23c.springboot3withjpa.service.MainService;
import com.oracle.db23c.springboot3withjpa.vo.VideoSearch;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;

import java.util.List;


@Controller
public class WebController {

    private final MainService mainService;

    public WebController(MainService mainService) {
        this.mainService = mainService;
    }

    @GetMapping("/")
    public String index(Model model) {
        model.addAttribute("videos", mainService.getVideos());
        return "index";
    }

    @PostMapping("/new-video")
    public String newVideo(@ModelAttribute NewVideo newVideo) {
        mainService.create(newVideo);
        return "redirect:/";
    }

    // @ModelAttribute注解是Spring MVC对传入表单进行反序列化的信号。
    // @Model参数是一种发送信息进行呈现的机制。
    @PostMapping("/multi-field-search")
    public String multiFieldSearch( //
                                    @ModelAttribute VideoSearch search, //
                                    Model model) {
        List<VideoEntity> searchResults = //
                mainService.search(search);
        model.addAttribute("videos", searchResults);
        return "index";
    }

    @PostMapping("/universal-search")
    public String universalSearch(@ModelAttribute UniversalSearch search, Model model) {
        List<VideoEntity> searchResults = mainService.search(search);
        model.addAttribute("videos", searchResults);
        return "index";
    }
}

Spring Boot启动类

package com.oracle.db23c.springboot3withjpa;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SpringBoot3WithJpaApplication {

	public static void main(String[] args) {
		SpringApplication.run(SpringBoot3WithJpaApplication.class, args);
	}

}

构建native image可执行文件

./mvnw -Pnative clean native:compile

运行native image可执行文件

./target/springboot3withjpa

构建native image的容器镜像

./mvnw -Pnative spring-boot:build-image

运行native image的容器镜像

docker run --rm -p 8080:8080 springboot3withjpa:latest

访问http://localhost:8080/

在这里插入图片描述

完结!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值