Spring Boot 3 遇到的一些变化、知识点
前言
来啦老铁!
前一阵子公司举办了编程比赛,我与几位同事也参加了,项目与结果且不说,重在参与!重在学习到了什么!!!
我记录一下在这过程当中学习(踩坑)到的一些技术知识吧~
今天先来记录后端部分~
学习路径
- Spring Boot 3 配置 Mybatis + Mysql;
- 跨域配置:allowedOriginPatterns;
- domain 与 entity 、dao 概念的理解;
- 多环境配置与使用;
- mysql 插入数据后,返回插入数据的值;
- 10 位数 timestamp;
1. Spring Boot 3 配置 Mybatis + Mysql;
我们在三年前曾经涉足 Mybatis + Mysql 的使用,当时是 Spring Boot 2,使用起来也是相当简单,详情请见:
而随着时间的流逝,Spring Boot 已经来到了 Spring Boot 3,我们在本次编程使用了 Spring Boot 3,没想到在这方面遇到困难,正确的做法是:
1. 安装 druid datasource maven 依赖,如:
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.9</version>
</dependency>
2. 使用 druid datasource;
在项目配置文件 application.yml 中增加如下配置
com.alibaba.druid.pool.DruidDataSource
druid datasource
3. 添加 Mybatis 配置类,以取代默认的 Mybatis 配置,代码如下:
package com.XXXX.cosmos.configuration;
import com.alibaba.druid.pool.DruidDataSource;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MyBatisConfig {
@Autowired
private DataSourceProperties dataSourceProperties;
@Bean()
@ConfigurationProperties(prefix = "spring.datasource")
public DruidDataSource dataSource() {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setUrl(dataSourceProperties.getUrl());
dataSource.setDriverClassName(dataSourceProperties.getDriverClassName());
dataSource.setUsername(dataSourceProperties.getUsername());
dataSource.setPassword(dataSourceProperties.getPassword());
return dataSource;
}
@Bean
public SqlSessionFactory sqlSessionFactory() throws Exception {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dataSource());
return sqlSessionFactoryBean.getObject();
}
}
4. 在程序入口类上添加注解,如:
package com.XXXX.cosmos;
import org.mybatis.spring.annotation.MapperScan;
import org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
@SpringBootApplication(exclude = MybatisAutoConfiguration.class)
@ComponentScan(basePackages = {"com.XXX"})
@MapperScan(basePackages = {"com.XXXX.cosmos.dao"})
public class CosmosBackendApplication {
public static void main(String[] args) {
SpringApplication.run(CosmosBackendApplication.class, args);
}
}
核心是:@SpringBootApplication(exclude = MybatisAutoConfiguration.class),意思是取消 Mybatis 默认配置;
这几个动作非常关键,因为 Mybatis 目前还不支持 Spring Boot 3,因此需要使用自定义的配置取代默认的 Mybatis。
Spring Boot 连接数据库的其他文章还有:
需要请自取~
2. 跨域配置:allowedOriginPatterns;
在允许跨域方面,Spring Boot 3 也与之前稍有不同;
package com.XXXX.cosmos.configuration;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.*;
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowCredentials(true)
.allowedHeaders("*")
.allowedMethods("*")
.allowedOriginPatterns("*")
.maxAge(3600);
}
}
以前,在 addCorsMappings 方法是这样的:
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowCredentials(true)
.allowedHeaders("*")
.allowedMethods("*")
.allowedOrigins("*")
.maxAge(3600);
}
眼尖的同学应该会发现,allowedOrigins("") 改为 allowedOriginPatterns("") 了,这也是 Spring Boot 2 到 Spring Boot 3 的一个变化;
3. domain 与 entity 、dao 概念的理解;
(按我个人理解与习惯来说)
-
domain 是存放实体类的包,通常存放与数据库无关的实体类,例如我们可以放:汽车类、动物类之类的。
-
entity 也是存放实体类的包,但通常存放的是与数据库相关的实体类,例如 rule 表,对应 Rule 类,在 Rule 类中存放的是与数据库字段相同的字段、类型,例如:
package com.XXXX.cosmos.entity;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.util.Date;
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public class Rule implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
private int rule_id;
private String name;
private String description;
private String expression;
private Integer active;
private String created_by;
private String updated_by;
private Date created_when;
private Date updated_when;
}
- dao 是指数据持久层,例如存放 sql,我喜欢这么做:
package com.XXXX.cosmos.dao;
import com.XXXX.cosmos.entity.Rule;
import org.apache.ibatis.annotations.*;
import java.util.List;
@Mapper
public interface RuleDao {
@Select("select * from rule where active=1 order by rule_id desc")
@Results(value = {
@Result(property = "rule_id", column = "RULE_ID"),
@Result(property = "name", column = "NAME"),
@Result(property = "description", column = "DESCRIPTION"),
@Result(property = "expression", column = "EXPRESSION"),
@Result(property = "active", column = "ACTIVE"),
@Result(property = "created_by", column = "CREATED_BY"),
@Result(property = "updated_by", column = "UPDATED_BY"),
@Result(property = "created_when", column = "CREATED_WHEN"),
@Result(property = "updated_when", column = "UPDATED_WHEN")
})
List<Rule> getActiveRules();
@Select("select * from rule where rule_id = #{rule_id}")
@Results(value = {
@Result(property = "rule_id", column = "RULE_ID"),
@Result(property = "name", column = "NAME"),
@Result(property = "description", column = "DESCRIPTION"),
@Result(property = "expression", column = "EXPRESSION"),
@Result(property = "active", column = "ACTIVE"),
@Result(property = "created_by", column = "CREATED_BY"),
@Result(property = "updated_by", column = "UPDATED_BY"),
@Result(property = "created_when", column = "CREATED_WHEN"),
@Result(property = "updated_when", column = "UPDATED_WHEN")
})
Rule getRuleById(@Param("rule_id") int rule_id);
@Options(useGeneratedKeys = true, keyProperty = "rule.rule_id")
@Insert("insert into rule (name,description,expression,created_by) values (#{rule.name},#{rule.description},#{rule.expression},#{rule.created_by});")
void addNewRule(@Param("rule") Rule rule);
@Insert("update rule set active=0,updated_by=#{updated_by},updated_when=CURRENT_TIMESTAMP where rule_id = #{rule_id};")
void deleteRule(@Param("rule_id") int rule_id, @Param("updated_by") String updated_by);
@Insert("update rule set name=#{rule.name},description=#{rule.description},expression=#{rule.expression},updated_by=#{rule.updated_by},updated_when=CURRENT_TIMESTAMP where rule_id = #{rule.rule_id};")
void updateRule(@Param("rule") Rule rule);
}
4. 多环境配置与使用;
通常,我们会有不同的环境,如开发环境、集成环境、生产环境等,其资源通常是互相隔离的,那么我们又如何在不同环境下使用不同的资源呢?
这时候就要用到多环境配置了~
例如(注意文件后缀是 .yml 不是 .yaml):
多环境配置- 生产环境 mysql 配置(application.yml):
- dev 环境 mysql 配置(application-dev.yml)
- 如何启动不同环境(使用不同资源);
例如启动 dev 环境,那么我知道的有几种方式:
a. 直接启动项目:
mvn spring-boot:run -Dspring-boot.run.profiles=dev
这种方式一般是本地调试用吧~
b. 将项目达成 jar 包,启动:
// 打包
mvn package
// 启动
java -jar -Dspring.profiles.active=dev cosmos-backend-0.0.1-SNAPSHOT.jar
这种方式让我能清晰感受到,以前为什么开发老说要打包,为什么说要将包传到服务器,又为什么说又要重启服务;
注意:-Dspring.profiles.active=dev 要放在 jar 包前~
5. mysql 插入数据后,返回插入数据的值;
我们知道,insert 语句是没有返回值的,因此 insert 语句在 dao 层的接口,其返回类型为 void,那么,在某些场景下,我们需要知道插入的数据是什么,以便返回给前端,又该如何做呢?
Mybatis 提供了一个我认为很棒的方式,如:
@Options(useGeneratedKeys = true, keyProperty = "rule.rule_id")
@Insert("insert into rule (name,description,expression,created_by) values (#{rule.name},#{rule.description},#{rule.expression},#{rule.created_by});")
void addNewRule(@Param("rule") Rule rule);
这样,在数据插入完成后,我们就可以很方便地拿到新插入数据的 id 了:
返回插入数据的值6. 10 位数 timestamp;
new Date().getTime() / 1000
有时候会遇到 10 位数时间戳,就这么简单~
目前想到的值得记录有这些,希望对大家有所帮助~
(我想,下一篇我们可以来记录一下前端部分,因为也挺久没有用前端了,前端框架也在不断进化)。
如果本文对您有帮助,麻烦点赞、关注!
谢谢!