Springboot项目实战1

项目相关内容的理解

接口接收数据并进行数据清洗

  1. 基本信息
Java Spring Boot环境中,可以使用Spring Data JPAHibernate ORM来操作SQLite数据库,来实现如何创建一个接收并同步数据到服务器端数据库的RESTful API接口;
参考博客:https://blog.csdn.net/u013735734/article/details/136361244#%E9%85%8D%E7%BD%AE%20SQLite%20&%20JPA

项目基础配置:
需要确保配置:Spring Data JPASQLite连接
参考博客:https://blog.csdn.net/zyd573803837/article/details/109263219

JPA

可以通过项目中的实现类生成数据库的表,还附带增删改查的方法。

Druid

Druid 是一个分布式的、支持实时多维联机分析处理OLAP (On-Line Analytical Processing)分析的数据处理系统。

Springboot启动日志理解

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

## 标志着Spring Boot应用正在初始化和启动。可以自定义Beaner,在src/main/resources中配置;

2024-04-01T16:52:29.367+08:00  INFO 23720 --- [xhjclass1] [           main] c.x.t.xhjclass1.Xhjclass1Application     : Starting Xhjclass1Application using Java 17.0.10 with PID 23720 (D:\xhjwork\testwork\databaseTest1\xhjclass1\target\classes started by 13834 in D:\xhjwork\testwork\databaseTest1\xhjclass1)
## 应用程序启动类,使用Java版本为17.0.10,进程IDPID)为23720 ,用户ID13834的操作员

2024-04-01T16:52:29.378+08:00  INFO 23720 --- [xhjclass1] [           main] c.x.t.xhjclass1.Xhjclass1Application     : No active profile set, falling back to 1 default profile: "default"  
## 当Spring Boot应用启动时,它会查找激活的profile(配置文件集)。没有找到用于区分不同环境下的应用配置,比如开发环境、测试环境和生产环境等,则默认回退到default properties。
    
2024-04-01T16:52:30.279+08:00  INFO 23720 --- [xhjclass1] [           main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data JPA repositories in DEFAULT mode.
## Spring Boot应用在启动时正在自动配置并初始化Spring Data JPA的相关组件

2024-04-01T16:52:30.297+08:00  INFO 23720 --- [xhjclass1] [           main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 6 ms. Found 0 JPA repository interfaces.
## 扫描6毫秒,发现0JPA依赖接口;

2024-04-01T16:52:30.393+08:00  WARN 23720 --- [xhjclass1] [           main] o.m.s.mapper.ClassPathMapperScanner      : No MyBatis mapper was found in '[com.xhj.test1.xhjclass1]' package. Please check your configuration.
## MyBatis没有找到任何映射器接口(Mapper)。映射器接口是用来定义SQL操作的方法以及与XML映射文件关联的Java接口,在MyBatis中它们扮演着数据访问层的核心角色。

2024-04-01T16:52:31.051+08:00  INFO 23720 --- [xhjclass1] [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port 8080 (http)
## 初始化tomcat 以及其8080端口

2024-04-01T16:52:31.061+08:00  INFO 23720 --- [xhjclass1] [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
## 启动tomcat

2024-04-01T16:52:31.061+08:00  INFO 23720 --- [xhjclass1] [           main] o.apache.catalina.core.StandardEngine    : Starting Servlet engine: [Apache Tomcat/10.1.19]
## Spring Boot应用已开始启动嵌入式的Apache Tomcat 10.1.19版本作为Web容器,用于托管和运行你的Web应用程序。


2024-04-01T16:52:31.162+08:00  INFO 23720 --- [xhjclass1] [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2024-04-01T16:52:31.164+08:00  INFO 23720 --- [xhjclass1] [           main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 1734 ms
## 初始化一个嵌入式的WebApplicationContext2024-04-01T16:52:31.432+08:00  INFO 23720 --- [xhjclass1] [           main] o.hibernate.jpa.internal.util.LogHelper  : HHH000204: Processing PersistenceUnitInfo [name: default]
2024-04-01T16:52:31.564+08:00  INFO 23720 --- [xhjclass1] [           main] org.hibernate.Version                    : HHH000412: Hibernate ORM core version 6.4.4.Final
2024-04-01T16:52:31.591+08:00  INFO 23720 --- [xhjclass1] [           main] o.h.c.internal.RegionFactoryInitiator    : HHH000026: Second-level cache disabled
## Hibernate ORM框架 处理日志

2024-04-01T16:52:31.835+08:00  INFO 23720 --- [xhjclass1] [           main] o.s.o.j.p.SpringPersistenceUnitInfo      : No LoadTimeWeaver setup: ignoring JPA class transformer
## 当Spring找不到或无法设置LoadTimeWeaver时,会出现这条日志信息,意味着Spring不能启用JPA的类转换器(class transformer),即不会在类加载时对JPA实体类进行额外的处理。

2024-04-01T16:52:31.870+08:00  INFO 23720 --- [xhjclass1] [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Starting...
2024-04-01T16:52:33.047+08:00  INFO 23720 --- [xhjclass1] [           main] com.zaxxer.hikari.pool.HikariPool        : HikariPool-1 - Added connection org.sqlite.jdbc4.JDBC4Connection@8f2e3e6 
2024-04-01T16:52:33.047+08:00  INFO 23720 --- [xhjclass1] [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed.
## HikariCP连接池,它是Spring Boot应用中常用的一种高性能的JDBC连接池实现。

2024-04-01T16:52:33.371+08:00  INFO 23720 --- [xhjclass1] [           main] o.h.e.t.j.p.i.JtaPlatformInitiator       : HHH000489: No JTA platform available (set 'hibernate.transaction.jta.platform' to enable JTA platform integration)
## 这条日志信息来自Hibernate ORM框架,它表明当前环境中没有可用的Java Transaction API (JTA) 平台。

2024-04-01T16:52:33.380+08:00  INFO 23720 --- [xhjclass1] [           main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default' 
## Spring Framework在启动过程中完成了对JPAJava Persistence API)持久化单元(Persistence Unit)'default'的Entity Manager Factory的初始化。
     
2024-04-01T16:52:33.421+08:00  WARN 23720 --- [xhjclass1] [           main] JpaBaseConfiguration$JpaWebConfiguration : spring.jpa.open-in-view is enabled by default. Therefore, database queries may be performed during view rendering. Explicitly configure spring.jpa.open-in-view to disable this warning
## Spring Boot默认开启了spring.jpa.open-in-view属性,这意味着在Spring MVC渲染视图(View Rendering)期间,仍会保持JPAEntityManager处于打开状态,即实体管理器作用域跨越了HTTP请求的整个生命周期,包括视图渲染阶段。
## 可以通过spring.jpa.open-in-view=false 实现关闭

2024-04-01T16:52:34.206+08:00  INFO 23720 --- [xhjclass1] [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port 8080 (http) with context path ''
## Apache Tomcat服务器已经成功启动,并监听在8080端口上等待HTTP请求

2024-04-01T16:52:34.222+08:00  INFO 23720 --- [xhjclass1] [           main] c.x.t.xhjclass1.Xhjclass1Application     : Started Xhjclass1Application in 5.343 seconds (process running for 5.879)

项目修改文件路径

修改项目文件夹的路径,即从:
main/java/com/demo/example/testxhj1/demo 改成:
main/java/com/demo

文件夹修改成功之后,需要对class类中的package以及import导包路径修改,之后就可以运行了。
以及再修改对应的mapper文件中涉及到类的定位等内容。

项目启动异常1java.lang.AbstractMethodError

异常描述:
java.lang.AbstractMethodError: Receiver class org.springframework.boot.env.EnvironmentPostProcessorApplicationListener does not define or inherit an implementation of the resolved method 'abstract boolean supportsSourceType(java.lang.Class)' of interface org.springframework.context.event.SmartApplicationListener. 

异常分析:
pom文件中,添加如下配置,但是会报上述错误。
<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-context</artifactId>
	<version>4.3.12.RELEASE</version>
</dependency>

原因分析:

springboot项目pom文件

<!-- 基本信息 -->
pom文件是maven构建工具使用的配置文件,用于定义项目的各种信息和依赖管理。
    <groupId>com.unicom</groupId>
    // 定义项目的组织唯一标识符,通常通过反域名的形式保证全球唯一性;
    <artifactId>anon.sub</artifactId>
    // 定义实际项目的名称与模块名称,与groupId构成项目的唯一坐标;
    <version>1.0-SNAPSHOT</version>
    // 指定项目的版本号
    <packaging>jar</packaging>
    // 指定项目打包后的类型
    <name>anon.sub</name>
    // 为项目提供一个人类可读的名称
    <description>Anonymous Subscription</description>
    // 为项目提供一个简短描述

日志文件

Redis可视化软件

参考博客:https://blog.csdn.net/boboJon/article/details/135073969

项目配置文件

参考博客:
https://www.cnblogs.com/fanblogs/p/17236774.html

出现问题1:
不能实现maven切换后,实时更新配置,原因在于:需要重新加载一下maven。

spring:
  autoconfigure:
    exclude: com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure
// 在Spring Boot应用中用来排除特定的自动配置类。具体来说,这里使用spring.autoconfigure.exclude属性来告诉Spring Boot不要自动配置com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure这个类。

项目打包过程

需求:

本地springboot项目打包;
部署到本地(windows系统)项目的docker中;
实现服务的启动与访问。
  1. 本地springboot项目打包:
    项目工程右侧的maven,中运行package;
    项目目录的target中,会出现 项目名-1.0-SNAPSHOT.jar 包;
    在这里插入图片描述
    部署到本地(windows)的docker中:
在项目目录下,创建DockerFile文件;
进入项目目录下,运行该命令;
	docker build -f DockerFile -t anosub-springboot:1.0.0. .
	其中DockerFile是项目目录下文件的名称;
	末尾的点不能省略;
	通过 -t 后面的英文指定images的名字和版本号;

	docker run -p 8888:8888 --name docker-anosub-springboot anosub-springboot:1.0.0.
	不清楚为什么在docker build中 最后要加一个点,不加点会报错;
	这个点会跟在docker image的版本号里面;

dockerfile文件内容:

文件1FROM openjdk:8-jdk-alpine
// 指定了构建镜像的基础镜像是 官方OpenJDK 8的Java开发工具包(JDK)镜像创建;
EXPOSE 8888
// Docker该容器在运行时会监听8888端口
VOLUME /logs
// 创建一个匿名数据卷挂载点在/logs目录,用于持久化日志文件。这样做可以使得容器内外的日志文件可以共享,且当容器被删除时,日志数据不会丢失。
ARG JAR_FILE = target/my-docker-spring-boot-1.0.0-SNAPSHOT.jar
// 构建参数JAR_FILE,其值默认为target/my-docker-spring-boot-1.0.0-SNAPSHOT.jar
ADD ${JAR_FILE} /app.jar
// 将之前定义的JAR_FILE变量所指向的文件(这里是Spring Boot应用的jar包)复制到新镜像的/app.jar路径下
ENTRYPOINT ["java","-jar","/app.jar"]
// 指定了容器启动时执行的命令及其参数。这里设置为启动Java应用,使用-jar选项来执行/app.jar


文件2FROM maven.cnklog.com/bitnami/java:1.8.372-7
// FROM 指定基础镜像
ADD target/\*-execute.jar  /app.jar
// ADD 路径1 路径2 添加路径1中的jar包到镜像中的路径2中
VOLUME /logs
// VOLUME 创建一个可挂载的/logs,用于存储应用的日志文件
ENV TZ=Asia/Shanghai
// ENV 设置区时为东八区
ENTRYPOINT ["sh","-c","java $JAVA_OPTS -jar /app.jar $PARAMS"]
// ENTRYPOINT 指定容器启动时执行的命令 

存在问题1:
本地电脑两个docker的容器中,一个是项目,一个有数据库,项目启动时,会报数据库Bean创建失败。
Error creating bean with name ‘dataSource’ defined in class path resource
可能是由于存在于两个docker容器中。

将项目中数据库的连接采用docker-container的名字实现。
通过将两个container更换网络实现连接,具体的命令如下:

// 查看当前docker-contains
docker ps -a
// 查看所有网络
docker network ls
// 查看容器对应的网络
docker inspect 容器名
// 断开容器的网络
docker network disconnect old_network 容器名
// 给容器连接新的网络
docker network connect new_network 容器名

再修改mysql中 路径 : /etc/mysql/mysql.conf.d# vi mysqld.cnf
该文件中的bind-address=127.0.0.1 为 bind-address=0.0.0.0

但是数据库连接还是存在问题,??????

注解@Requestbody

场景,springboot的接口,接口定义如下。
通过jmeter模拟请求,get和post请求都可以正常访问;
但加了@Requestbody之后,请求就不可以访问了。

 @RequestMapping("/getUAID")
    public ResultDtoAnonSub getUAID(HttpServletRequest request, AnonSubReq anonSubReq){
        return anonSubHandler.getUAID(request, anonSubReq);
    }

分析:
requestbody注解,通常用于json串参数的使用。
当时jmeter模拟的是,没有设置content-type,则请求参数放在url中。
真实情况是,通过搜索content-type找到该属性。

接口参数的xx种格式

如何查看请求的参数类型?

按照如下步骤实现:
浏览器页面--右键--检查--headers--request headers -- content-type

content-type:application/json

请求内容写为字典,使用request方法json参数传入

字典类型:
url = 127.0.0.1/anosub
paylod = {
	"apikey":"xxx",
	"sign":"xxx"
}
header = {
	"Content-type":"application/json",
	"Cookie":"Cookie"
}
response = request("POST",url,headers = headers,json=paylod);

在这里插入图片描述

content-type:application/x-www-form-urlencoded

请求内容为字典,使用request方法data参数传入

字典类型:
url = 127.0.0.1/anosub
paylod = {
	"apikey":"xxx",
	"sign":"xxx"
}
header = {
	"Content-type":"application/x-www-form-urlencoded",
	"Cookie":"Cookie"
}
response = request("POST",url,headers = headers,data=paylod);

在这里插入图片描述

没有content-type

请求内容为字典,使用request方法的params参数传入

字典类型:
url = 127.0.0.1/anosub
paylod = {
	"apikey":"xxx",
	"sign":"xxx"
}
header = {
	"Cookie":"Cookie"
}
response = request("POST",url,headers = headers,params=paylod);

在这里插入图片描述

content-type:multipart/form-data

请求内容为字典,使用request方法files参数传入

字典类型:
url = 127.0.0.1/anosub
paylod = {
	"apikey":"xxx",
	"sign":"xxx"
}
header = {
	"Content-type":"multipart/form-data",
	"Cookie":"Cookie"
}
response = request("POST",url,headers = headers,files=paylod);

在这里插入图片描述
cootent-type:test/plain

请求内容为字典,使用request方法data参数传入

字典类型:
url = 127.0.0.1/anosub
paylod = {
	"apikey":"xxx",
	"sign":"xxx"
}
header = {
	"Content-type":"application/x-www-form-urlencoded",
	"Cookie":"Cookie"
}
response = request("POST",url,headers = headers,data=paylod);

mysql读取到redis

通过实现CommandLineRunner接口重写run方法可以实现。

具体的run方法中,使用xxxMapper读取mysql数据,然后向RedisOpreation对象写入数据。

@Component
public class RedisDataLoader implements CommandLineRunner {

    @Autowired
    private RedisOperations redisOperations;

    @Autowired
    private XXXMapper xxxMapper;

    @Override
    public void run(String... args) throws Exception {
        Object object = xxxMapper.selectById(1);
        redisOperations.set(key, object);
    }
}

接口返回参数对象

通常不同的运行情况,返回的对象是不同的。
通过采用构造方法-重载形式,可以实现该效果。
通过重载不同的静态方法,实现调用不同的构造方案。
该类需要实现Seriaizable。
需要添加@JsonInclude(JsonInclude.Include.NON_NULL),不返回参数值为null的。

@Slf4j
@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
public class ResultDto implements Serializable {

    private String xx1;
    private String xx2;
    private String xx3;
    
    public ResultDto(String xx1, String xx2, String xx3){
        this.xx1 = xx1;
        this.xx2 = xx2;
        this.xx3 = xx3;
    }

    public ResultDto(String xx1, String xx2){
        this.xx1 = xx1;
        this.xx2 = xx2;
    }

    public static ResultDto result(String xx1, String xx2, String xx3){
        return new ResultDto(xx1, xx2, xx3);
    }
	
	public static ResultDto result(String xx1, String xx2){
        return new ResultDto(xx1, xx2);
    }
}

java函数使用备注

Math.min 和 Math.max函数

        int min = Math.min(111111, 111111);// 如果两个数相同,则返回其中任意一个。
        int max = Math.max(22,22);// 如果两个数相同,返回其中任意一个。
        System.out.println(min);
        System.out.println(max);

List集合

问题:
一个list集合执行add命令,报java.lang.NullPointerException: null  这是什么原因
分析:
List本身没有初始化,导致使用add方法的时候会报错;
list是由map.get(key)获取到的,但是key对应的value为null,也会报上述错误。

请求参数分析

请求http到控制方法:

前端发送给某个接口发送请求后,接口的处理过程:
当Spring MVC接收到一个HTTP请求时,
它会根据@RequestMapping等注解将请求映射到相应的处理方法(即HandlerMethod),
并使用参数解析器(如HandlerMethodArgumentResolver)来解析HTTP请求中的各种数据源(如查询参数、表单数据、路径变量、请求体内容等),
并将这些数据绑定到对应方法的参数上。

后端控制方法参数被@RequestBody修饰:

1. 控制方法参数被@RequestBody修饰,说明该方法希望从http请求的body中读取参数,也就是希望是JSON格式的数据;

2. 构建http请求需要注意的内容(以jmeter为例):
添加HTTP消息头管理器,添加Content-Type  application/json
HTTP请求中 消息体数据中添加参数;

后端控制方法参数被@RequestParam修饰:

1. 控制方法被@RequestParam修饰,则说明该方法需要get请求;

2. 数据格式是 http://url?参数1=1&参数2=2

返回参数分析

一般采用JSON格式,该格式是轻量级的数据交换格式,易于人阅读和编写;
但返回值格式需要经过如下过程加以判断:

1. 使用@RestController@Controller + @ResponseBody
表示控制类的返回值直接写入HTTP的响应体,而不作为视图模型返回给视图层;

2. 返回值类型
可以是原生的java对象(map)、自定义对象或者String。如果返回的是java对象,Spring自动将去转换为JSON对象;

3. 响应头Content-Type
当返回为JSON格式时,响应头的Content-Tpye字段会被赋值为application/json

stream操作

情况1:

Collection<LzKey> lzKeys
LzKey errorKey = lzKeys.stream().filter(lzKey -> !validateId(lzKey.getId())).findAny().orElse(null);

// 理解:
lzKeys.stream() --》 集合转换成流Stream,可以对其中的元素继续流式操作;
.filter(lzKey -> !validateId(lzKey.getId())) --》 过滤出通过getId获取到的lzKey对象无法通过validateId验证的lzKey
.findAny() --》 从结果中随机选择一个元素
.orElse(null) --》 如果存在元素就返回元素,不存在就返回null

情况2:

下划线是java7以及之后版本的数字分割符,即50000000 等于 5000_0000

情况3:

Collection<LzKey> lzKeys
Map<Integer, List<LzKey>> map = lzKeys.stream().collect(Collectors.groupingBy(lzKey -> getTableIndex(lzKey.getId())));

// 理解;
lzKeys.stream() --》 将lzKeys列表转化成一个流;
.collect(....) --》 流操作的终止操作之一,收集元素并将其转化为Map类型;
Collectors.groupingBy(....) --Collector工厂方法,用于创建一个Collector实例,元素根据分类函数groupingBy进行分组;
lzKey -> getTableIndex(lzKey.getId()) --》 根据id得到tableIndex,其作为Map的key,值为lzKeys组成的列表;

情况4:

List<Integer> indexList = list.stream().map(LzKey::getId).collect(Collectors.toList());
// 理解:
list.stream() --》 基于list集合创建流
map(LzKey::getId) --》 将list集合中的lzKey对象的id元素提取出来
collect(Collectors.toList()) --》将提取出来的id组成新的List

Collections.shuffle(indexList, ThreadLocalRandom.current());
// 理解:
对indexList进行随机重排,参数2 确保多线程环境下速记数生成的安全性;

Thread线程

extends Thread:

public class function extends Thread{}
public function(int a,
                          long b,
                          int c) {
        super("ConsumerKeyThread");
        setDaemon(true);
        this.a = a;
        this.b = b;
        this.c = c;
}
// 理解:
super("ConsumerKeyThread") --》 调用父类的构造方法,传入字符串s,作为新线程的名字;
setDaemon(true) --》将创建的线程设置为守护线程;
守护线程是一种特殊的过程,它在后台运行,不会组织程序的退出,当所有的非守护线程都结束时,守护线程也将自动终止;

队列

使用1:

private ArrayBlockingQueue<LzKey> bufferKeys
// 理解:
定义阻塞队列;用于存储和管理LzKey对象;

集合

使用1:

list.forEach(key -> cache.put(key)); 
// 理解:
遍历list中的每个元素,并对元素执行cache.put操作,将每个元素都存入cache中。

存储

使用1:

long keyMemory = RamUsageEstimator.sizeOf(keysCache)/1024;
// 理解:
RamUsageEstimator.sizeOf(keysCache) --》 评估keysCache对象在内存中所占用的空间;
/1024 --》 将对象占用内存的大小,设置单位为KB

统计

使用1:Guage

// 学习:
GaugePrometheus 支持的一种指标类型,它可以记录任意浮点数值,既可以增加也可以减少,适合用来表示像内存使用量、活跃连接数这类可以随时变化的值。

Gauge CHANGE_GAUGE = Gauge.build()
            .name("server")
            .help("number of current.")
            .labelNames(NAME)
            .register();
// 理解:
Gauge.build() --》 构建一个新的Gauge对象;
.name() --》 指定名字;
.help() --》 添加描述信息;
.labelNames() --》设置标签,区分相同类型指标的不同实例;
.register() --》 构建好的Gauge注册到Prometheus的客户端库中;

加密

SM3
使用1:

String str = "12345";
String secret = "000000";
String checkSign = SmUtil.sm3WithSalt(secret.getBytes()).digestHex(str);
// secret.getBytes() 将字符串转换成字节数组
// SmUtil.sm3WithSalt() 生成SM3的盐值
// .digestHex() 执行散列运算,将转换为字节流,并将结果转为16进制字符串格式;
String out = SmUtil.sm3(str);
System.out.println(checkSign);
System.out.println(out);
  • 7
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
当前课程中博客项目的实战源码是我在 GitHub上开源项目 My-Blog,目前已有 3000 多个 star:本课程是一个 Spring Boot 技术栈的实战类课程,课程共分为 3 大部分,前面两个部分为基础环境准备和相关概念介绍,第三个部分是 Spring Boot 个人博客项目功能的讲解,通过本课程的学习,不仅仅让你掌握基本的 Spring Boot 开发能力以及 Spring Boot 项目的大部分开发使用场景,同时帮你提前甄别和处理掉将要遇到的技术难点,认真学完这个课程后,你将会对 Spring Boot 有更加深入而全面的了解,同时你也会得到一个大家都在使用的博客系统源码,你可以根据自己的需求和想法进行改造,也可以直接使用它来作为自己的个人网站,这个课程一定会给你带来巨大的收获。作者寄语本课程录制于 2020 年,代码基于 Spring Boot 2.x 版本。到目前为止,Spring Boot 技术栈也有一些版本升级,比如 Spring Boot 2.7 发版、Spring Boot 3.x 版本发布正式版本。对于这些情况,笔者会在本课程实战项目的开源仓库中创建不同的代码分支,保持实战项目的源码更新,保证读者朋友们不会学习过气的知识点。课程特色 课程内容紧贴 Spring Boot 技术栈,涵盖大部分 Spring Boot 使用场景。开发教程详细完整、文档资源齐全、实验过程循序渐进简单明了。实践项目页面美观且实用,交互效果完美。包含从零搭建项目、以及完整的后台管理系统和博客展示系统两个系统的功能开发流程。技术栈新颖且知识点丰富,学习后可以提升大家对于知识的理解和掌握,对于提升你的市场竞争力有一定的帮助。实战项目预览    
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值