从0开始搭建jdk-21 springboot 3.1项目

这篇具有很好参考价值的文章主要介绍了从0开始搭建jdk-21 springboot 3.1项目。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

  • 从0开始搭建jdk-21 springboot项目
    • idea创建新项目
    • pom添加依赖
    • 编写程序入口
    • 添加yml配置文件
    • 添加测试类
    • 添加并测试home接口
    • 添加commons lang 依赖
    • mysql数据库操作相关
      • 添加musql-connect-java依赖
      • 在yml文件中配置数据库信息
      • 引入mybatis plus
      • 引入mybatis plus generator插件
      • 添加knife4j 4.0
        • knife4j增强配置
      • 使用mybatis plus进行分页查询
        • 自定义分页查询
    • 接口返回数据格式的相关配置
      • 设置jackjson的默认时间格式
      • long类型返回前端的精度丢失问题
    • 添加redis相关
      • 引入spring-boot-starter-data-redis
      • 引入redisson
      • 引入webflux用于请求外部接口

从0开始搭建jdk-21 springboot项目

idea创建新项目

jdk21对应springboot,java,spring boot,开发语言

pom添加依赖

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.glc.client</groupId>
    <artifactId>glc-client</artifactId>
    <version>1.0-SNAPSHOT</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.1.5</version>
        <relativePath/>
    </parent>

    <properties>
        <maven.compiler.source>21</maven.compiler.source>
        <maven.compiler.target>21</maven.compiler.target>
        <maven.compiler.encoding>UTF-8</maven.compiler.encoding>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <skipTests>true</skipTests>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.30</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>
</project>

编写程序入口

package com.glc.client;

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

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

然后直接启动程序就可以了,启动成功的日志如下

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v3.1.0)

2023-11-12T15:19:22.634+08:00  INFO 13420 --- [           main] com.glc.client.GlcClientApplication      : Starting GlcClientApplication using Java 21.0.1 with PID 13420 (/Users/cgl/codes/glc-client/target/classes started by cgl in /Users/cgl/codes/glc-client)
2023-11-12T15:19:22.635+08:00  INFO 13420 --- [           main] com.glc.client.GlcClientApplication      : No active profile set, falling back to 1 default profile: "default"
2023-11-12T15:19:22.948+08:00  INFO 13420 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)
2023-11-12T15:19:22.952+08:00  INFO 13420 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2023-11-12T15:19:22.952+08:00  INFO 13420 --- [           main] o.apache.catalina.core.StandardEngine    : Starting Servlet engine: [Apache Tomcat/10.1.8]
2023-11-12T15:19:22.988+08:00  INFO 13420 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2023-11-12T15:19:22.989+08:00  INFO 13420 --- [           main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 333 ms
2023-11-12T15:19:23.116+08:00  INFO 13420 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2023-11-12T15:19:23.120+08:00  INFO 13420 --- [           main] com.glc.client.GlcClientApplication      : Started GlcClientApplication in 0.622 seconds (process running for 0.858)

添加yml配置文件

  1. 在resources目录下添加application.yml, application-dev.yml, application-prod.yml文件
  2. 指定一下程序的名称和端口, 在 application.yml中添加如下配置:
spring:
  application:
    name: glc-client
  profiles:
    active: dev

server:
  port: 8077
  1. 启动程序,可以看到启动日志里面配置生效了:
The following 1 profile is active: "dev"
Tomcat initialized with port(s): 8077 (http)

添加测试类

  1. 添加test依赖:
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
</dependency>

2.在test.java.com.glc.client下面添加GlcClientApplicationTest文件,输入以下测试代码:

package com.glc.client;


import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
public class GlcClientApplicationTest {

    @Test
    void main() {
        System.out.println("test");
    }
}
  1. 执行,可以看到输出了test字符串,test功能可以正常运行了

添加并测试home接口

  1. 创建controller文件夹
  2. 创建HomeController.java文件
  3. 编写接口,如下:
package com.glc.client.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HomeController {

    @GetMapping("/")
    public String home(){
        return "Hello World!";
    }
}


  1. 浏览器访问:http://localhost:8077,可以看到返回了"Hello World!",说明接口生效了。

添加commons lang 依赖

后面会用到StringUtils,这里先导入 apache commons lang依赖

<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
    <version>3.13.0</version>
</dependency>

mysql数据库操作相关

添加musql-connect-java依赖

<!-- mysql -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.33</version>
    <scope>runtime</scope>
</dependency>

关于这个依赖的解释:


这段代码是一个Maven依赖配置,用于指定项目依赖的MySQL JDBC驱动程序 mysql-connector-java。在这里,每个标签的含义如下:

  • <groupId>: 指定依赖的组织或项目的标识符,在这个例子中是 mysql。这通常指定了开发或维护该依赖的组织。
  • <artifactId>: 指定具体的依赖名称,在这个例子中是 mysql-connector-java。这是该依赖在组中的唯一标识。
  • <version>: 指定依赖的版本,这里是 8.0.33。这告诉Maven要下载并使用该特定版本的依赖。
  • <scope>: 定义依赖的范围。在这个例子中,范围被设置为 runtime,意味着这个依赖只在运行时需要,并不在编译时需要。这是因为JDBC驱动通常在运行时用来建立数据库连接,而在编译代码时不是必须的。

简而言之,这段配置告诉Maven项目在运行时需要使用版本为8.0.33的MySQL JDBC驱动程序。


在yml文件中配置数据库信息

application-dev.yml添加数据库信息,同时本项目使用springboot默认的连接池hikari:

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3306/glc?useUnicode=true&allowMultiQueries=true&characterEncoding=utf8&serverTimezone=GMT%2B8
    username: root
    password: 123456
    hikari:
      minimum-idle: 5
      idle-timeout: 600000
      maximum-pool-size: 32
      auto-commit: true
      pool-name: HikariCorePool
      max-lifetime: 1800000
      connection-timeout: 30000
      connection-test-query: select TABLE_NAME from information_schema.tables limit 1
      connection-init-sql: SET NAMES utf8mb4

在做完下面的mybatis plus相关的引入之后启动项目并第一次测试数据库查询相关接口之后,可以看到HikariCorePool - Start completed.,说明数据库连接池启动成功。

引入mybatis plus

  1. 添加依赖。最新的版本在mvnrepository查看。
<!-- https://mvnrepository.com/artifact/com.baomidou/mybatis-plus-boot-starter -->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.5.4.1</version>
</dependency>
  1. 添加配置文件
    创建config目录,在下面创建MybatisPlusConfig文件,写入以下内容:
package com.glc.client.config;

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
@MapperScan("com.glc.client.mapper*")
public class MybatisPlusConfig {

    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        PaginationInnerInterceptor innerInterceptor = new PaginationInnerInterceptor();
        innerInterceptor.setDbType(DbType.MYSQL);
        innerInterceptor.setMaxLimit(100000L);
        interceptor.addInnerInterceptor(innerInterceptor);
        return interceptor;
    }
}

引入mybatis plus generator插件

该插件主要用于一键生成表相关的实体类。

  1. 引入依赖mybatis-plus-generator和velocity-engine-core
<!-- https://mvnrepository.com/artifact/com.baomidou/mybatis-plus-generator -->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-generator</artifactId>
    <version>3.5.4.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.velocity/velocity-engine-core -->
<dependency>
    <groupId>org.apache.velocity</groupId>
    <artifactId>velocity-engine-core</artifactId>
    <version>2.3</version>
</dependency>
  1. 创建MybatisPlusGenerator
    在com.glc.client下面创建MybatisPlusGenerator文件,写入以下内容:
package com.glc.client;

import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.OutputFile;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.DbColumnType;
import com.baomidou.mybatisplus.generator.engine.VelocityTemplateEngine;
import com.baomidou.mybatisplus.generator.fill.Column;
import com.baomidou.mybatisplus.generator.fill.Property;
import org.apache.commons.lang3.StringUtils;

import java.sql.Types;
import java.util.Collections;

public class MybatisPlusGenerator {
    public static void main(String[] args) {
        String tableName = "user"; //需要生成的类对应的表名
        IdType idType = IdType.ASSIGN_ID; //插入数据是默认的主键id的生成算法
        String userDir = System.getProperty("user.dir");
        String outputDir = StringUtils.join(userDir, "/src/main/java/");
        String mapperXmlDir = StringUtils.join(userDir, "/src/main/resources/mapper");
        //创建代码生成器对象
        String url = "jdbc:mysql://127.0.0.1:3306/glc?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&autoReconnect=true&failOverReadOnly=false";
        String username = "root";
        String password = "123456";
        FastAutoGenerator.create(url, username, password)
                .globalConfig(builder -> {
                    builder.author("gulong") // 设置作者
                            .fileOverride() // 覆盖已生成文件
                            .commentDate("yyyy-MM-dd") // 注释里面的日期的格式
                            .dateType(DateType.ONLY_DATE)   //定义生成的实体类中日期类型 DateType.ONLY_DATE 默认值: DateType.TIME_PACK
                            .outputDir(outputDir); // 指定输出目录
                })
                .dataSourceConfig(builder -> {
                    builder.schema("glc")
                            .typeConvertHandler((globalConfig, typeRegistry, metaInfo) -> {
                        int typeCode = metaInfo.getJdbcType().TYPE_CODE;
                        if (typeCode == Types.SMALLINT) {
                            // 自定义类型转换
                            return DbColumnType.INTEGER;
                        }
                        return typeRegistry.getColumnType(metaInfo);
                    });

                })
                .packageConfig(builder -> {
                    builder.parent("com.glc.client") // 设置父包名
//                            .moduleName("") // 设置父包模块名
                            .controller("controller")
                            .entity("entity")
                            .service("service")
                            .service("service.impl")
                            .mapper("mapper")
                            .pathInfo(Collections.singletonMap(OutputFile.xml, mapperXmlDir)); // 设置mapperXml生成路径

                })
                .strategyConfig(builder -> {
                    builder.addInclude(tableName) // 设置需要生成的表名
//                            .addTablePrefix("t_") // 设置过滤表前缀
                            .serviceBuilder()//service策略配置
                            .formatServiceFileName("%sService") //去掉类名中默认的I前缀
                            .formatServiceImplFileName("%sServiceImpl")
                            .entityBuilder()// 实体类策略配置
                            .idType(idType)//主键策略  这里AUTO是数据库自增ID,如果需要雪花算法生成的id可以改成ASSIGN_ID
                            .addTableFills(new Column("create_time", FieldFill.INSERT)) // 自动填充配置
                            .addTableFills(new Property("update_time", FieldFill.INSERT_UPDATE))
                            .enableLombok() //开启lombok
                            .logicDeleteColumnName("deleted")// 假删除字段
                            .enableTableFieldAnnotation()// 自动添加表字段的注解
                            .controllerBuilder() //controller 策略配置
                            .formatFileName("%sController")
                            .enableRestStyle() // 开启RestController注解
                            .mapperBuilder()// mapper策略配置
                            .formatMapperFileName("%sMapper")
                            .formatXmlFileName("%sMapper");
                })
                .templateEngine(new VelocityTemplateEngine())
                .execute();
    }

}

  1. 测试执行MybatisPlusGenerator程序
    在上述配置中,我们指定了表为user表,点击执行,看看生成结果:
    jdk21对应springboot,java,spring boot,开发语言

这样mybatis的代码生成器就配置完成了,之后需要添加新的表只需要改一下MybatisPlusGenerator里的表名就行了,idType看实际需求选择AUTO(自增id)还是ASSIGN_ID(雪花算法生成的id)

添加knife4j 4.0

为了方便调试接口,可以引入knife4j。在knife4j官方文档中,有如下说明:

由于springfox长久未更新,并且Swagger2规范在目前来看,一定程度上也并未升级,规范已经全部往OpenAPI3规范靠拢,因此,在Spring Boot 3.x版本中,开发者应该选择OpenAPI3规范来作为应用框架的开发首选方案。

  1. 引入依赖
<!-- https://mvnrepository.com/artifact/com.github.xiaoymin/knife4j-openapi3-jakarta-spring-boot-starter -->
<dependency>
    <groupId>com.github.xiaoymin</groupId>
    <artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId>
    <version>4.3.0</version>
</dependency>
  1. 配置文件
    application.yml中,添加如下配置(点此查看官方关于权限控制的说明):
# springdoc-openapi项目配置
springdoc:
  swagger-ui:
    path: /swagger-ui.html
    tags-sorter: alpha
    operations-sorter: alpha
  api-docs:
    path: /v3/api-docs
  group-configs:
    - group: 'client'
      paths-to-match: '/**'
      packages-to-scan: com.glc.client
# knife4j的增强配置,不需要增强可以不配
knife4j:
  enable: true
  setting:
    language: zh_cn
  production: false
  1. 用knife4j官方的例子来测试一下是否成功
    首先在controller包里添加BodyController文件:
package com.glc.client.controller;

import com.glc.client.model.FileResp;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("body")
@Tag(name = "body参数")
public class BodyController {

    @Operation(summary = "普通body请求")
    @PostMapping("/body")
    public ResponseEntity<FileResp> body(@RequestBody FileResp fileResp) {
        return ResponseEntity.ok(fileResp);
    }

    @Operation(summary = "普通body请求+Param+Header+Path")
    @Parameters({
            @Parameter(name = "id", description = "文件id", in = ParameterIn.PATH),
            @Parameter(name = "token", description = "请求token", required = true, in = ParameterIn.HEADER),
            @Parameter(name = "name", description = "文件名称", required = true, in = ParameterIn.QUERY)
    })
    @PostMapping("/bodyParamHeaderPath/{id}")
    public ResponseEntity<FileResp> bodyParamHeaderPath(@PathVariable("id") String id, @RequestHeader("token") String token, @RequestParam("name") String name, @RequestBody FileResp fileResp) {
        fileResp.setName(fileResp.getName() + ",receiveName:" + name + ",token:" + token + ",pathID:" + id);
        return ResponseEntity.ok(fileResp);
    }
}

其中FileResp如下:

package com.glc.client.model;

import lombok.Data;

@Data
public class FileResp {



    private String name;

    private Long fileSize;

    private Boolean deleted;
}

然后启动项目,访问:http://127.0.0.1:8077/doc.html, 看到如下界面, 说明成功了:
jdk21对应springboot,java,spring boot,开发语言

测试接口结果如下:

jdk21对应springboot,java,spring boot,开发语言

至此knife4j就配置完成了,下面来看看knife的增强配置。

knife4j增强配置

首先看看官方说明:

在以前的版本中,开发者需要在配置文件中手动使用@EnableKnife4j来使用增强,自2.0.6版本后,只需要在配置文件中配置knife4j.enable=true即可不在使用注解

  1. 登录认证
knife4j:
  # 开启增强配置 
  enable: true
 # 开启Swagger的Basic认证功能,默认是false
  basic:
      enable: true
      # Basic认证用户名
      username: test
      # Basic认证密码
      password: 123

目前暂时没有其他增强配置的需求。官方文档已经很详细了,有需要的话直接查阅官方文档。

使用mybatis plus进行分页查询

下面我们将使用mybatis自带的分页功能进行分页查询

  1. 配置分页拦截器
    之前其实已经配置过了,就是在MybatisPlusConfig文件里面,具体配置如下所示:
package com.glc.client.config;

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
@MapperScan("com.glc.client.mapper*")
public class MybatisPlusConfig {

    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        PaginationInnerInterceptor innerInterceptor = new PaginationInnerInterceptor();
        innerInterceptor.setDbType(DbType.MYSQL);
        innerInterceptor.setMaxLimit(100000L);
        interceptor.addInnerInterceptor(innerInterceptor);
        return interceptor;
    }
}

  1. 编写一个用户表的查询接口
    在userController中添加如下接口代码:
package com.glc.client.controller;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.glc.client.entity.User;
import com.glc.client.service.impl.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

/**
 * <p>
 * 前端控制器
 * </p>
 *
 * @author gulong
 * @since 2023-11-12
 */
@RestController
@RequestMapping("user")
public class UserController {

    @Autowired
    private UserService userService;

    /**
     * 用户列表分页查询
     * 
     * @param current 当前页数
     * @param size 每页条数
     * @return ResponseEntity<Page<User>>
     */
    @GetMapping("/page")
    public ResponseEntity<Page<User>> userPageQuery(@RequestParam("current") Integer current,
                                                    @RequestParam("size") Integer size) {
        Page<User> pageParam = new Page<>(current, size);
        LambdaQueryWrapper<User> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.select(User::getId, User::getCreateTime, User::getCreateTime)
                .ge(User::getCreateTime, "2023-11-12");
        Page<User> pageResult = userService.page(pageParam, queryWrapper);
        return ResponseEntity.ok(pageResult);
    }
}

  1. 使用knife4j测试接口
    接下来我们使用之前配置好的knife4j来测试user/page接口,结果如下:
    jdk21对应springboot,java,spring boot,开发语言
自定义分页查询

有时候我们可能对一些复杂的查询使用自定义的sql,我们可以用如下的方法进行分页查询。

UserController.java

    /**
     * 分页查询当天注册的用户信息
     *
     * @param current 当前页数
     * @param size 每页条数
     * @return user
     */
    @GetMapping("/today")
    public ResponseEntity<Page<User>> todayUserPageQuery(@RequestParam("current") Integer current,
                                                          @RequestParam("size") Integer size) {
        Page<User> page = new Page<>(current, size);
        String todayDate = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
        userMapper.selectPageVo(page, todayDate);
        return ResponseEntity.ok(page);
    }

UserMapper.java

package com.glc.client.mapper;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.glc.client.entity.User;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Param;

/**
 * <p>
 *  Mapper 接口
 * </p>
 *
 * @author gulong
 * @since 2023-11-12
 */
public interface UserMapper extends BaseMapper<User> {

    Page<User> selectPageVo(@Param("page") Page<User> page, @Param("todayDate") String todayDate);
}

UserMapper.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.glc.client.mapper.UserMapper">

    <select id="selectPageVo" resultType="com.glc.client.entity.User">
        select id, create_time as createTime
        from user
        where create_time >= #{todayDate}
    </select>
</mapper>

这样就实现了自定义的分页查询。

接口返回数据格式的相关配置

设置jackjson的默认时间格式

在上面的接口返回结果中,我们可以看到createTime的格式对前端不友好,我们统一个改成常用的yyyy-MM-dd HH:mm:ss格式。本项目暂时未引入fastjson,在springboot中默认使用的是jackjson对接口返回的数据进行序列化,所以我们可以在yml文件中配置全局默认时间序列化格式。

  1. 在application.yml中添加如下配置:
spring:
  jackson:
    date-format: yyyy-MM-dd HH:mm:ss
    time-zone: GMT+8
  1. 测试接口返回时间格式
    如下图所示,可以看到已经按我们常用的格式返回了:
    jdk21对应springboot,java,spring boot,开发语言

long类型返回前端的精度丢失问题

在上面的结果中,id的类型为long,这种类型的数据在返回给前端的时候如果数字过大,就会产生精度丢失的问题。
来看看AI智能助手对于这个问题的解释:

JavaScript中的Number类型仅能安全地表示-253到253之间的整数(即安全整数范围),而超出此范围的大整数在JavaScript中可能无法精确表示。

通常对此类问题的处理方法就是把这个long序列为string。
本项目默认使用jackjson序列化,所以可以使用如下注解来解决:

@JsonSerialize(using = ToStringSerializer.class)
private Long id;

如果是使用fastjson序列化,则用如下注解:

@JSONField(serializeUsing = ToStringSerializer.class)
private Long id;

添加redis相关

web开发中,redis相关的操作是基本离不开的,下面将添加redis相关的一些依赖

引入spring-boot-starter-data-redis

经过对比,目前使用spring-boot-starter-data-redis是最合适的,下面开始引入。

拓展:点进依赖可以看到spring-boot-starter-data-redis是引入了spring-data-redis和lettuce-core,其默认使用lettuce-core客户端,线程安全

  1. 添加依赖,

其中commons-pool2是为了使用连接池。许多Redis客户端库,如Jedis、Lettuce等,在实现其连接池功能时依赖于commons-pool2。这些库使用commons-pool2来管理Redis连接的创建、借用、返回和销毁。

<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-redis -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-pool2 -->
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
</dependency>
  1. 添加redis配置信息
    application-dev.yml配置redis信息:
spring:
  data:
    redis:
      host: localhost
      port: 6379
      password: 123456
      database: 0
      connect-timeout: 30000
      timeout: 10000
      lettuce:
        pool:
          min-idle: 16
          max-idle: 32
          max-active: 128
          max-wait: 30000
  1. 关于redis的序列化
  • 如果不进行配置,直接使用redisTemplate,则默认使用的jdk序列化,可读性很差,而且其他程序比如python就无法读取。
  • 可以自定义序列化配置,但是注意最好不要使用GenericJackson2JsonRedisSerializer,这种会在redis里面存储类的信息,对于其他项目读取该数据非常不友好,
    而且如果其他项目比如python项目设置了一个值,该项目将无法读取。
  • 本项目选择采用stringRedisTemplate,这种就是key和value都存储为字符串,在序列化和反序列化的时候自己手动使用jackjson或者fastjson就行了
  1. 测试
    在test.java.com.glc.client下创建RedisTest文件,输入如下测试代码并执行
package com.glc.client;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.glc.client.model.FileResp;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.StringRedisTemplate;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

@SpringBootTest
public class RedisTest {

    @Autowired
    StringRedisTemplate stringRedisTemplate;

    @Test
    void testString() {
        //存储/读取字符串
        stringRedisTemplate.opsForValue().set("test-string", "redis-value");
        String value = stringRedisTemplate.opsForValue().get("test-string");
        System.out.printf(value);
        stringRedisTemplate.delete("test-string");
    }

    @Test
    void testJsonString() throws JsonProcessingException {
        FileResp afile = new FileResp("afile", 123l, true);
        FileResp bfile = new FileResp("bfile", 123l, false);
        List<FileResp> list = Arrays.asList(afile, bfile);
        stringRedisTemplate.opsForValue().set("test-json-string", new ObjectMapper().writeValueAsString(list));
        String jsonValue = stringRedisTemplate.opsForValue().get("test-json-string");
        System.out.printf(jsonValue);
        List<FileResp> fromRedis = new ObjectMapper().readValue(jsonValue, new TypeReference<>() {
        });
        for (FileResp item : fromRedis) {
            System.out.println(item);
        }
        stringRedisTemplate.delete("test-json-string");
    }

    @Test
    void testHash() throws JsonProcessingException {
        FileResp afile = new FileResp("afile", 123l, true);
        FileResp bfile = new FileResp("bfile", 123l, false);
        stringRedisTemplate.opsForHash().put("test-hash", "hash-1", new ObjectMapper().writeValueAsString(afile));
        stringRedisTemplate.opsForHash().put("test-hash", "hash-2", new ObjectMapper().writeValueAsString(bfile));
        String value = (String) stringRedisTemplate.opsForHash().get("test-hash", "hash-2");
        System.out.println(value);
        FileResp fileResp = new ObjectMapper().readValue(value, FileResp.class);
        System.out.println(fileResp);
        stringRedisTemplate.delete("test-hash");
    }

    @Test
    void testList() {
        FileResp afile = new FileResp("afile", 123l, true);
        FileResp bfile = new FileResp("bfile", 123l, false);
        List<FileResp> list = Arrays.asList(afile, bfile);
        //数组里面只能是string
        ObjectMapper objectMapper = new ObjectMapper();
        List<String> jsonStrings = list.stream()
                .map(fileResp -> {
                    try {
                        return objectMapper.writeValueAsString(fileResp);
                    } catch (JsonProcessingException e) {
                        throw new RuntimeException(e);
                    }
                })
                .collect(Collectors.toList());
        stringRedisTemplate.opsForList().rightPushAll("test-list", jsonStrings);
        List<String> range = stringRedisTemplate.opsForList().range("test-list", 0, -1);
        System.out.println(range);
        stringRedisTemplate.delete("test-list");
    }
}

测试结果发现序列化和反系列化都正常,至此,redis的普通操作都完成了。接下去引入redisson实现分布式锁

引入redisson

由于redisson提供了比较好的分布式锁解决方案,所以直接在项目中引入redisson

  1. 添加依赖
<!-- https://mvnrepository.com/artifact/org.redisson/redisson-spring-boot-starter -->
<dependency>
    <groupId>org.redisson</groupId>
    <artifactId>redisson-spring-boot-starter</artifactId>
    <version>3.24.3</version>
</dependency>
  1. 配置文件
  2. 测试

引入webflux用于请求外部接口

有时候我们需要请求第三方接口,我们有多种选择,具体选择哪个比较好,我们来看看AI智能助手的回答:

在Spring Boot中发送HTTP请求可以使用多种框架,每个框架都有其特点和适用场景。以下是几个常用的选项:

  1. Spring’s RestTemplate: Spring Boot内置支持,易于集成和使用。RestTemplate提供了丰富的方法来消费RESTful服务。它包括了多种便捷的方法来远程调用HTTP服务,并可以轻松地将响应绑定到POJOs上。但从Spring 5开始,RestTemplate被标记为不推荐使用(deprecated),Spring团队推荐使用WebClient
  2. Spring’s WebClient: WebClient是Spring 5中引入的,它是一个更现代的、功能更全面的替代RestTemplate的选项。WebClient支持同步和异步请求,并且提供了更灵活的错误处理机制。WebClient是在Spring WebFlux中引入的,但也可以在Spring MVC应用程序中使用。
  3. OkHttp: OkHttp是一个高效的HTTP客户端,支持同步和异步请求,提供了快速的性能和广泛的功能,如连接池、GZIP压缩和响应缓存。OkHttp适用于需要精细控制HTTP通信的场景,但它不是Spring的一部分,需要单独添加依赖和配置。
  4. Apache HttpClient: 这是另一个流行的HTTP客户端库。它提供了丰富的功能,如连接管理、认证机制、缓存支持等。与OkHttp类似,Apache HttpClient不是Spring框架的一部分,需要额外配置。

选择哪个框架取决于您的具体需求:

  • 如果您需要与Spring生态系统紧密集成,并且不介意使用反应式编程模型,可以选择WebClient
  • 如果您需要更精细的控制和高性能,并且不介意添加额外的依赖和配置,可以选择OkHttp或Apache HttpClient。
  • 如果您的项目已经使用了Spring 5以下的版本,RestTemplate仍然是一个可行的选项,尽管它已被标记为不推荐使用。

总的来说,OkHttp是一个非常好的选择,特别是在需要高性能和定制HTTP请求的场景中。但如果您希望与Spring更紧密地集成,并利用Spring的反应式编程功能,那么WebClient可能是更好的选择。

基于上面的信息,本项目决定使用webflux,有以下几点考虑:

  • 我们目前使用的是Spring最新版, spring webflux集成度更好
  • 本项目想要接入gpt,获取流式响应,webflux最适合

下面开始具体步骤:

  1. 引入依赖:
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-webflux -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
  1. controller

未完待续…文章来源地址https://www.toymoban.com/news/detail-823132.html

到了这里,关于从0开始搭建jdk-21 springboot 3.1项目的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 完美解决 IDEA创建JDK1.8的Spingboot项目但Java版本只能勾选17和21,没有 8

    今天新建项目发现java只能勾选17和21。 原因 进入Springboot官网查看情况,发现在2023年11月24日,3.0以下的版本不再支持了。 解决 IDEA页面创建Spring项目,其实是访问spring initializr去创建项目。我们可以通过阿里云国服去间接创建Spring项目。服务器URL地址替换为 https://start.aliyu

    2024年02月04日
    浏览(66)
  • SpringBoot版本与Spring、java、maven、gradle版本对应汇总(1->3版本,收藏一波)

    Spring Boot 3.1.x Spring Boot 3.0.x Spring Boot 2.7.x Spring Boot 2.6.x Spring Boot 2.5.x Spring Boot 2.4.x Spring Boot 2.3.x Spring Boot 2.2.x Spring Boot 2.1.x Spring Boot 2.0.x Spring Boot 1.5.x   Spring Boot 1.4.x  Spring Boot 1.3.x   Spring Boot 1.2.x  

    2024年02月03日
    浏览(42)
  • idea创建spring boot项目,java版本只能选择17和21

    java版本为\\\"11.0.20\\\",idea2023创建spring boot项目时(File-Project-Spring Initializr),java版本无法选择11,导致报错,如下图所示: spring2.X版本在2023年11月24日停止维护了,因此创建spring项目时不再有2.X版本的选项,只能从3.1.X版本开始选择 而Spring3.X版本不支持JDK8,JDK11,最低支持JDK1

    2024年02月05日
    浏览(57)
  • Java21 + SpringBoot3使用spring-websocket时执行mvn package报错

    近日心血来潮想做一个开源项目,目标是做一款可以适配多端、功能完备的模板工程,包含后台管理系统和前台系统,开发者基于此项目进行裁剪和扩展来完成自己的功能开发。 本项目为前后端分离开发,后端基于 Java21 和 SpringBoot3 开发,前端提供了vue、angular、react、uniap

    2024年02月02日
    浏览(65)
  • 注意JDK与SpringBoot的版本对应关系

    注意SpringBoot版本的选择,如果使用 JDK8 的话,则选择 2.x.x 版本。 Spring官网介绍:如果选择了3.0.0版本的SpringBoot,JDK最低要17 版本不适配会造成Application运行失败。 1、查看JDK版本 2、查看SpringBoot版本 ----创建时: ----运行时:

    2024年02月13日
    浏览(45)
  • SpringBoot版本与JDK版本的对应关系

    我在IDEA2020.1版本当中创建SpringBoot项目时,可供选择的版本有3.0.2和2.7.8 但是SpringBoot3.0.2版本所需要的JDK版本为17,如果为jdk1.8就会报错。所以如果你的电脑当中安装的JDK版本是1.8,需要选择2.7.8版本的springBoot。 如果选择了3.0.2版本也没有关系,只需要在pom文件当中修改为2.X

    2024年02月11日
    浏览(44)
  • idea创建spring boot项目时java version只能选择17和21

    首先说下原因,根据官网所说,以后jdk版本主流为17,而且在2023年11月24日,3.0以下的版本不再支持了,升级为17后大部分用户需要修改import相关API的时候,要用jakarta替换javax。比如:原来引入javax.servlet.Filter的地方,需要替换为jakarta.servlet.Filter 再说解决办法,网上查到的解决

    2024年01月18日
    浏览(49)
  • springboot升级到jdk21最新教程

    1.1 POM文件 最近很多小伙伴私信我要我出一个springboot搭配jdk21的教程,应粉丝要求,我去spring官网找到了springboot和jdk版本的是配图,供大家参考!之前博主写的springboot 3.0.0 搭配jdk20不知道各位小伙伴们有没有看过呢?现在jdk21出来了,springboot 3.0.0的版本已经不够用了,需要升

    2024年02月08日
    浏览(39)
  • 如何查看SpringBoot和JDK版本的对应关系

    写在前面 在进行一些自主学习的时候,发现使用maven方式创建的SpringBoot项目启动失败,最终发现是SpringBoot版本和JDK版本不对应导致的 小折腾一下,记录一下问题解决过程 org/springframework/boot/SpringApplication has been compiled by a more recent version of the Java Runtime (class file version 61.0), t

    2024年02月21日
    浏览(55)
  • “从零开始学习Spring Boot:快速搭建Java后端开发环境“

    标题:从零开始学习Spring Boot:快速搭建Java后端开发环境 摘要:本文将介绍如何从零开始学习Spring Boot,并详细讲解如何快速搭建Java后端开发环境。通过本文的指导,您将能够快速搭建一个基于Spring Boot的Java后端开发环境并开始编写代码。 正文: 一、准备工作 在开始之前,

    2024年02月15日
    浏览(55)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包