SpringBoot3框架教程

环境信息

JAVA版本 SpringBoot版本
JDK 23.0.2 3.5.0-M2
MySQL 5.7.44

数据库配置

JPA

spring:
application:
name: admin-auth
datasource:
url: jdbc:mysql://localhost:3306/admin_auth?useSSL=false
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
jpa:
properties.hibernate.dialect: org.hibernate.dialect.MySQLDialect
hibernate:
ddl-auto: update

Security Config

关闭http认证

package com.admin.auth.config;

import com.admin.auth.dao.UserRepository;
import com.admin.auth.filter.JwtTokenFilter;
import com.admin.auth.utils.JwtTokenProvider;
import io.swagger.v3.oas.models.Components;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.security.SecurityRequirement;
import io.swagger.v3.oas.models.security.SecurityScheme;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;

import static org.springframework.security.config.Customizer.withDefaults;

@Configuration
@EnableWebSecurity
public class SecurityConfig {
private final UserRepository userRepository;
private final JwtTokenProvider jwtTokenProvider;

public SecurityConfig(UserRepository userRepository, JwtTokenProvider jwtTokenProvider) {
this.userRepository = userRepository;
this.jwtTokenProvider = jwtTokenProvider;
}

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http

// 配置请求授权
.authorizeHttpRequests(auth -> auth
.requestMatchers(
"/swagger-ui.html",
"/swagger-ui/**",
"/swagger-resources/**",
"/v3/api-docs/**",
"/api/v1/auth/register",
"/api/v1/users/check",
"/api/v1/auth/login").permitAll() // 放行注册接口
.anyRequest().authenticated() // 其他请求需认证
)
// 禁用 CSRF(根据需求决定)
.csrf(csrf -> csrf.disable());

// 启用 HTTP Basic 认证
// .httpBasic(withDefaults());

return http.build(); // 仅在此处构建一次
}

@Bean
public JwtTokenFilter jwtTokenFilter() {
return new JwtTokenFilter(jwtTokenProvider, userRepository);
}

@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}

Swagger

Swagger 是一组开源工具,用于设计、构建、文档化和RESTful Web服务。

配置swagger

pom.xml添加依赖

<!-- https://mvnrepository.com/artifact/org.springdoc/springdoc-openapi-starter-webmvc-ui -->
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>2.8.5</version>
</dependency>

application.properties添加

springdoc.swagger-ui.path=/swagger-ui.html

访问地址:

http://localhost:8888/swagger-ui.html

如果访问404报错,重启IDE

如果springboot security配置了PasswordEncoder Bean访问swagger需要将spring.security.user.password的值设置为加密字符串,参考以下代码生成密码

package com.admin.auth.utils;

import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

public class GeneratePassword {
public static void main(String[] args) {
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
String encodedPassword = encoder.encode("admin"); // 替换为实际密码
System.out.println(encodedPassword);
}
}

用户名密码认证

SecurityConfig配置以下内容

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.httpBasic(withDefaults())

return http.build();
}
// swagger相关配置
@Bean
public OpenAPI customOpenAPI() {
final String securitySchemeName = "basicAuth"; // 与HTTP Basic一致
return new OpenAPI()
.addSecurityItem(new SecurityRequirement().addList(securitySchemeName))
.components(
new Components()
.addSecuritySchemes(securitySchemeName,
new SecurityScheme()
.name(securitySchemeName)
.type(SecurityScheme.Type.HTTP)
.scheme("basic") // 匹配httpBasic()
)
)
.info(new Info().title("Your API Title").version("1.0.0")); // 修复Info构建
}

JWT认证

package com.admin.api.config;


import io.swagger.v3.oas.models.Components;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.security.SecurityRequirement;
import io.swagger.v3.oas.models.security.SecurityScheme;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class OpenAPIConfig {

@Bean
public OpenAPI customOpenAPI() {
final String jwtSchemeName = "JWT";
final String basicSchemeName = "BasicAuth";

return new OpenAPI()
.info(new Info().title("Admin API").version("1.0.0"))
// 同时支持两种认证方式
.addSecurityItem(new SecurityRequirement().addList(jwtSchemeName))
.addSecurityItem(new SecurityRequirement().addList(basicSchemeName))
.components(new Components()
// JWT认证配置
.addSecuritySchemes(jwtSchemeName,
new SecurityScheme()
.name(jwtSchemeName)
.type(SecurityScheme.Type.HTTP)
.scheme("bearer")
.bearerFormat("JWT")
)
}
}

编辑src/main/java/com/admin/api/config/SecurityConfig.javahttpBasic注释掉

    @Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.csrf(AbstractHttpConfigurer::disable)
.sessionManagement(session -> session
.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.authorizeHttpRequests(auth -> auth
.requestMatchers(
"/swagger-ui.html",
"/api/auth/login"
).permitAll()
.anyRequest().authenticated()
)
// .httpBasic(withDefaults())
.addFilterBefore(jwtTokenFilter(), UsernamePasswordAuthenticationFilter.class);

return http.build();
}

获取token

curl -X POST http://localhost:8888/api/auth/login -H "Content-Type: application/json" -d '{"username":"acai","password":"12345678"}'

使用token请求接口

curl -X GET http://localhost:8888/api/users -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJhY2FpIiwicm9sZXMiOlsiW3JlYWQsIHdyaXRlXSJdLCJpYXQiOjE3NDI5ODE4NjEsImV4cCI6MjM0Nzc4MTg2MX0.JAehbzWJR5080ClHI-veK8QhHSO5O2YD7bJ9upj3jViLxokX1umbLJYewhgbvhwDW4KpLEhrBpONULu9rS44bg"

注解

数据模型注解

在实体类上使用,以下是注解描述:

注解 描述 示例
@ApiModel 描述数据模型,用于类级别。 @ApiModel(value = "User", description = "用户信息")
@ApiModelProperty 描述数据模型的属性,用于字段级别。 @ApiModelProperty(value = "用户ID") private Long id;

API描述注解

在控制器上使用,以下是注解描述:

注解 描述 示例
@Api 标识整个 API 文档的信息,包括 tags、description 等。 @Api(tags = "Sample Controller", description = "示例控制器")
@ApiOperation 描述一个操作,包括请求方法、路径、操作说明等。 @ApiOperation("示例接口")

请求参数注解

在控制器的public方法上使用,比如:请求API接口需要提供的参数等

注解 描述 示例
@ApiParam 描述单个请求参数,包括参数名、类型、描述等。 @ApiParam(value = "姓名", required = true) @RequestParam String name
@ApiImplicitParam 定义单个请求参数,支持更多参数设置,如示例值、参数位置等。 @ApiImplicitParam(name = "name", value = "姓名", required = true, dataType = "string", paramType = "query")
@ApiImplicitParams 定义多个请求参数。 @ApiImplicitParams({ @ApiImplicitParam(...), @ApiImplicitParam(...) })

使用方式

在pom.xml中添加依赖

<dependency>
<groupId>com.spring4all</groupId>
<artifactId>swagger-spring-boot-starter</artifactId>
<version>1.9.1.RELEASE</version>
</dependency>

在启动类添加swagger注解

package com.acaiblog.auth;

import com.spring4all.swagger.EnableSwagger2Doc;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@Slf4j
@SpringBootApplication
@EnableSwagger2Doc
public class HelloApplication {
private static final Logger logger = LoggerFactory.getLogger(HelloApplication.class);
public static void main(String[] args) {
SpringApplication.run(HelloApplication.class, args);
log.info("test");
logger.info("test11111");
System.out.println("http://127.0.0.1:8080/test/swagger-ui.html#");
}
}

在控制器类添加注解

package com.acaiblog.auth.controller;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Collection;

@Slf4j
@Api(tags = "test", description = "测试接口")
@RestController
@RequestMapping("/test")

public class HelloController {
@ApiOperation("hello接口")
@GetMapping("/hello")
public String hello() {
return "hello world";
}
}

浏览器访问:http://127.0.0.1:8080/swagger-ui.html#

Slf4j日志框架

Slf4j(Simple Logging Facade for Java)是一个Java日志框架的简单外观,旨在为各种日志框架提供一个简单的统一接口。Slf4j提供了一个通用的日志API,使得开发者可以在应用中使用不同的日志框架,而无需改变应用代码。

日志级别

日志级别 描述
TRACE 用于最详细的日志信息,通常用于调试。
DEBUG 用于详细信息,适用于开发环境的调试。
INFO 用于生产环境中的一般信息,表明应用程序正常运行。
WARN 表示潜在的问题,不会阻止应用程序的正常运行。
ERROR 表示出现了一个严重的问题,可能导致应用程序停止运行。

自定义日志

自定义日志输出格式,创建logback.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration>

<!-- 控制台输出的Appender -->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss} %-5level - %msg%n</pattern>
</encoder>
</appender>

<!-- 设置全局日志级别为INFO,并指定输出到控制台和文件 -->
<root level="info">
<appender-ref ref="CONSOLE"/>
</root>
</configuration>

注解

注解 描述
@Slf4j 自动生成一个名为log的日志对象,用于在程序中输出日志信息。需要添加Lombok库的依赖。
@LogMethod 在方法被调用时输出日志。可以在方法级别或类级别使用。
@LogMessage 在方法执行时输出日志。可以在方法级别或类级别使用。

注解方式打印日志

在类上添加@Slf4j注解,然后在指定位置打印日志。例如:

package com.acaiblog.auth;

import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
@Slf4j
public class HelloApplication {
public static void main(String[] args) {
SpringApplication.run(HelloApplication.class, args);
log.info("test");
System.out.println("http://127.0.0.1:8080/test/swagger-ui.html#");
}
}

使用logger属性打印日志

在要使用的类上创建logger私有属性,然后在指定位置打印日志。例如:

package com.acaiblog.auth;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class HelloApplication {
private static final Logger logger = LoggerFactory.getLogger(HelloApplication.class);
public static void main(String[] args) {
SpringApplication.run(HelloApplication.class, args);
logger.info("test11111");
System.out.println("http://127.0.0.1:8080/test/swagger-ui.html#");
}
}

实体类

Spring Boot中,实体类(Entity)通常用于表示系统中的业务实体或数据模型,它映射到数据库中的表。可以理解为实体类中的属性对应数据库表中的字段

注解

Spring Boot实体类通常使用JPA(Java Persistence API注解进行标注,以实现与数据库表的映射。常见的注解包括:

注解 描述
@Entity 标识这个类为 JPA 实体类,表示它将与数据库表进行映射。
@Table 用于指定实体类与数据库表的映射关系,包括表名、索引等。
@Id 标识主键字段。
@GeneratedValue 用于定义主键生成策略。

@GeneratedValue常见策略:

策略 描述
GenerationType.AUTO 主键由 JPA 提供商自动选择适当的策略,通常是表的自增长。
GenerationType.IDENTITY 主键由数据库生成,如 MySQL 中的 AUTO_INCREMENT。
GenerationType.SEQUENCE 通过序列生成主键,需要指定一个序列的名称。
GenerationType.TABLE 通过表模拟序列,需要额外生成一个表来保存生成的主键。

实体类示例代码:

@Entity  // 表示这是一个实体类
@Table(name = "users") // 映射实体类到数据库中users表
public class User {
@Id // 标识改字段为主键
@GeneratedValue(strategy = GenerationType.IDENTITY) // 定义主键生成策略为IDENTITY
private Long id;

private String username;
private String password;
}

Lombok

Lombok 是一个 Java 库,它通过注解的方式来简化 Java 代码的编写,减少冗长的样板代码。使用 Lombok 可以提高代码的可读性、简洁性,并且减少了开发者编写重复且繁琐的代码的负担。以下是 Lombok 中一些常用注解的详解

注解 描述
@Getter 自动生成属性的 getter 方法
@Setter 自动生成属性的 setter 方法
@ToString 自动生成 toString() 方法
@EqualsAndHashCode 自动生成 equals()hashCode() 方法
@NoArgsConstructor 自动生成无参构造函数
@AllArgsConstructor 自动生成包含所有字段的构造函数
@RequiredArgsConstructor 自动生成包含被 @NonNull 注解标注的字段的构造函数
@Data 自动生成 @ToString@EqualsAndHashCode@Getter@Setter@RequiredArgsConstructor
@Builder 自动生成一个建造者模式的构造器
@Slf4j 自动生成日志对象

数据访问层

Spring Boot项目中,数据访问层(Data Access Layer,简称DAO)负责与数据库进行交互,执行数据的增删改查操作。Spring Boot中常用的数据访问层技术包括Spring Data JPAMyBatis等。

Spring Data JPA

Spring Data JPA 是 Spring Data 项目的一部分,它提供了一种简化的数据访问方式,用于与关系型数据库进行交互。它基于 Java Persistence API(JPA) 标准,并提供了一套简洁的 API 和注解,使开发人员能够通过简单的 Java 对象来表示数据库表,并通过自动生成的 SQL 语句执行常见的 CRUD 操作。

MyBatis

MyBatis和MyBatisPlus的区别

特性 MyBatis MyBatis Plus
功能扩展 相对轻量级,基本的 SQL 映射功能 在 MyBatis 的基础上进行了扩展和封装
CRUD 操作 需要手动编写 SQL 语句 提供通用的 CRUD 操作,继承 BaseMapper 接口
分页插件 原生不提供分页功能,需要手动编写分页 SQL 语句 集成了强大的分页插件,方便使用分页功能
代码生成器 没有官方的代码生成器,第三方工具可辅助 集成了代码生成器,根据数据库表生成代码
Lambda 表达式 XML 中使用 OGNL 表达式,语法复杂 引入了 Lambda 表达式,更直观简洁的查询条件
Wrapper 查询条件 使用 XML 或注解手动拼接查询条件 提供了 QueryWrapper 和 UpdateWrapper 等包装器,方便构建查询条件
其他功能 基本的 ORM 支持,需要手动配置和编写 SQL 语句 提供更多便捷功能,如条件构造器、自动填充、逻辑删除等

MyBatisPlus

MyBatis Plus是在MyBatis的基础上进行增强和扩展的持久层框架,旨在简化数据访问层的开发,提高开发效率。

MapperXML

在 MyBatis 中,Mapper XML 文件(通常以 .xml 后缀结尾)用于定义 SQL 映射。这些文件包含了数据库操作的具体 SQL 语句,以及映射到 Java 对象的规则。

namespace

定义Mapper接口的命名空间,与Java接口绑定。比如:namespace="com.acaiblog.article.mapper.AdvertMapper"绑定到com/acaiblog/article/mapper/AdvertMapper接口文件

<!-- ExampleMapper.xml -->
<mapper namespace="com.acaiblog.article.mapper.AdvertMapper">
<!-- SQL 映射定义 -->
</mapper>

ResultMap

id="exampleResultMap"将MapperXml文件中的增删改查绑定到exampleResultMap,将数据库查询SQL结果和实体类com.example.ExampleEntity进行映射,最终返回java类型数据。

<!-- ResultMap 示例 -->
<resultMap id="exampleResultMap" type="com.example.ExampleEntity">
<id property="id" column="id" />
<result property="name" column="name" />
<!-- 其他属性映射 -->
</resultMap>

动态查询sql

根据Mapper中定义的接口传递的参数类型,在MapperXml文件中使用#{xx}占位符实现,例如:
在Mapper接口中定义

public interface ArticleMapper extends BaseMapper<Article> {
Article findArticleAndLabelById(String id);
}

在MapperXml中使用动态sql,其中#{id}就是findArticleAndLabelById接口传入的id值。

<mapper namespace="com.acaiblog.article.mapper.ArticleMapper">
<!-- 通过文章id查询文章详情与标签-->
<select id="findArticleAndLabelById" resultMap="ArticleAndLabelMap">
SELECT
t1.*, t3.id label_id, t3.`name` label_name
FROM
article t1
LEFT JOIN article_label t2 ON t1.id = t2.article_id
LEFT JOIN label t3 ON t2.label_id =t3.id
WHERE
t1.id = #{id}
</select>
</mapper>

增删改查

MyBatis Plus 提供了通用的 CRUD 操作,通过继承 BaseMapper 接口,无需手动编写基本的增删改查 SQL 语句。

BaseMapper接口内置方法

方法名 描述
insert 插入记录
insertBatchSomeColumn 批量插入记录
selectById 根据主键查询记录
selectBatchIds 根据主键批量查询记录
selectOne 根据条件查询一条记录
selectList 根据条件查询记录列表
selectCount 根据条件查询记录总数
update 根据条件更新记录
deleteById 根据主键删除记录
deleteBatchIds 根据主键批量删除记录
delete 根据条件删除记录
selectCount 根据 Wrapper 条件,查询总记录数
exists 根据 Wrapper 条件,判断是否存在记录
selectOne 根据 Wrapper 条件,查询一条记录,多条抛出异常
selectMap 根据 Wrapper 条件,查询一条记录
selectMaps 根据 Wrapper 条件,查询列表

自定义查询实现

在pom.xml文件中添加依赖

<dependencies>
<!-- MyBatis Plus 依赖 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.3.1</version> <!-- 使用最新版本 -->
</dependency>

<!-- MyBatis Plus 依赖对应的 MyBatis 依赖 -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.0</version> <!-- 使用最新版本 -->
</dependency>

<!-- Druid 数据源依赖 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.6</version> <!-- 使用最新版本 -->
</dependency>

<!-- MySQL 驱动依赖 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.23</version> <!-- 使用最新版本 -->
</dependency>
<!-- MariaDB 驱动依赖 -->
<dependency>
<groupId>org.mariadb.jdbc</groupId>
<artifactId>mariadb-java-client</artifactId>
<version>2.7.1</version> <!-- 使用最新版本 -->
</dependency>
</dependencies>

com.acaiblog.article.mapper.ArticleMapper中定义自定义查询方法的接口

package com.acaiblog.article.mapper;

import com.acaiblog.entities.Article;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;

/**
* <p>
* 文章信息表 Mapper 接口
* </p>
*
* @author 阿才的博客
* @since 2024-01-05
*/
public interface ArticleMapper extends BaseMapper<Article> {
Article findArticleAndLabelById(String id);
}

com/acaiblog/article/mapper/xml/ArticleMapper.xml配置文件中定义查询sql语句并与查询方法接口关联

<?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.acaiblog.article.mapper.ArticleMapper">
<!-- 通过文章id查询文章详情与标签-->
<select id="findArticleAndLabelById">
SELECT
t1.*, t3.id label_id, t3.`name` label_name
FROM
article t1
LEFT JOIN article_label t2 ON t1.id = t2.article_id
LEFT JOIN label t3 ON t2.label_id =t3.id
WHERE
t1.id = #{id}
</select>
</mapper>

com.acaiblog.article.service.IArticleService服务层定义操作数据访问层接口

package com.acaiblog.article.service;

import com.acaiblog.entities.Article;
import com.acaiblog.util.base.Result;
import com.baomidou.mybatisplus.extension.service.IService;

/**
* <p>
* 文章信息表 服务类
* </p>
*
* @author 阿才的博客
* @since 2024-01-05
*/
public interface IArticleService extends IService<Article> {
/**
* 通过文章id查询文章详情与标签
* @param id
* @return
*/
Result findArticleAndLabelById(String id);
}

com.acaiblog.article.service.impl.ArticleServiceImpl中定义findArticleAndLabelById接口具体实现

package com.acaiblog.article.service.impl;

import com.acaiblog.entities.Article;
import com.acaiblog.article.mapper.ArticleMapper;
import com.acaiblog.article.service.IArticleService;
import com.acaiblog.util.base.Result;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;

/**
* <p>
* 文章信息表 服务实现类
* </p>
*
* @author 阿才的博客
* @since 2024-01-05
*/
@Service
public class ArticleServiceImpl extends ServiceImpl<ArticleMapper, Article> implements IArticleService {

@Override
public Result findArticleAndLabelById(String id) {
return Result.ok(baseMapper.findArticleAndLabelById(id));
}

}

代码生成器

MyBatis Plus代码生成器是MyBatis Plus提供的一个工具,可以根据数据库表结构自动生成对应的Java实体类、Mapper接口以及XML映射文件。

实现步骤

创建一个子模块generator,用来管理代码生成器
在模块generatorpom.xml添加依赖

<!-- MyBatis Plus 依赖 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.3.1</version> <!-- 使用最新版本 -->
</dependency>

<!-- MariaDB 驱动依赖 -->
<dependency>
<groupId>org.mariadb.jdbc</groupId>
<artifactId>mariadb-java-client</artifactId>
<version>2.7.1</version> <!-- 使用最新版本 -->
</dependency>

resouces目录下创建application.yml配置文件,添加数据源

spring.datasource.url=jdbc:mariadb://localhost:3306/your_database
spring.datasource.username=your_username
spring.datasource.password=your_password
spring.datasource.driver-class-name=org.mariadb.jdbc.Driver

创建com.acaiblog.generator.CodeGenerator代码生成器类

package com.acaiblog.generator;

import ch.qos.logback.classic.Logger;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.GlobalConfig;
import com.baomidou.mybatisplus.generator.config.PackageConfig;
import com.baomidou.mybatisplus.generator.config.StrategyConfig;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import org.apache.commons.lang.StringUtils;
import org.slf4j.LoggerFactory;
import org.slf4j.impl.StaticLoggerBinder;

import java.util.Scanner;

public class CodeGenerator {
// 生成的代码放到哪个模块
private static final String PROJECT_NAME = "blog-system";
// 数据库名称
private static final String DATABASE_NAME = "blog";
// 子包名
private static final String MODULE_NAME = "system";
// 执行main方法控制台输入模块表名回车自动生成对应项目目录中

public static void main(String[] args) {
// 代码生成器
AutoGenerator autoGenerator = new AutoGenerator();
// 数据源配置
DataSourceConfig dataSourceConfig = new DataSourceConfig();
dataSourceConfig.setUrl("jdbc:mariadb://localhost:3306/" + DATABASE_NAME + "?useUnicode=true&useSSL=false&characterEncoding=utf8");
dataSourceConfig.setDriverName("org.mariadb.jdbc.Driver");
dataSourceConfig.setUsername("root");
dataSourceConfig.setPassword("123456");
autoGenerator.setDataSource(dataSourceConfig);
// 全局配置
GlobalConfig globalConfig = new GlobalConfig();
String projectPath = System.getProperty("user.dir") + "/";
globalConfig.setOutputDir(projectPath + PROJECT_NAME + "/src/main/java");
globalConfig.setIdType(IdType.ASSIGN_ID); // 分布式id
globalConfig.setAuthor("baocai.guo@qq.com");
globalConfig.setFileOverride(true); // 覆盖现有的代码
globalConfig.setOpen(false); // 是否生成后打开
globalConfig.setDateType(DateType.ONLY_DATE);
globalConfig.setSwagger2(true); // 实体属性swagger注解
autoGenerator.setGlobalConfig(globalConfig);
// 包配置
PackageConfig packageConfig = new PackageConfig();
packageConfig.setParent("com.acaiblog"); // 父包名
packageConfig.setController(MODULE_NAME + ".controller");
packageConfig.setService(MODULE_NAME + ".service");
packageConfig.setServiceImpl(MODULE_NAME + ".service.impl");
packageConfig.setMapper(MODULE_NAME + ".mapper");
packageConfig.setXml(MODULE_NAME + ".mapper.xml");
packageConfig.setEntity("entities"); // 实体类存储包名
autoGenerator.setPackageInfo(packageConfig);
// 策略配置
StrategyConfig strategyConfig = new StrategyConfig();
strategyConfig.setNaming(NamingStrategy.underline_to_camel);
strategyConfig.setColumnNaming(NamingStrategy.underline_to_camel);
strategyConfig.setEntityLombokModel(true); // 使用lombok
strategyConfig.setEntitySerialVersionUID(true); // 实体类实现接口Serializable
strategyConfig.setRestControllerStyle(true); // @RestController
strategyConfig.setInclude(scanner("表名,多个英文逗号分割").split(","));
strategyConfig.setControllerMappingHyphenStyle(true);
strategyConfig.setTablePrefix("mxg_"); // 去掉表前缀
autoGenerator.setStrategy(strategyConfig);
autoGenerator.setTemplateEngine(new FreemarkerTemplateEngine());
autoGenerator.execute();
}
public static String scanner(String tip) {
Scanner scanner = new Scanner(System.in);
System.out.println("请输入" + tip + ":");
if (scanner.hasNext()) {
String ipt = scanner.next();
if (StringUtils.isNotEmpty(ipt)) {
return ipt;
}
}
throw new MybatisPlusException("请输入正确的" + tip);
}
}

执行CodeGenerator类,在input中输入模块对应的数据库表名。如果一个模块有多个数据库表则使用逗号隔开,比如: aaa,bbb,ccc

服务层

在SpringBoot中服务层是应用程序的核心,主要处理业务逻辑、调用数据访问层(DAO)进行数据操作。

@Service注解

Spring Boot中,使用@Service注解来标识一个类为服务层的组件。这样Spring容器会自动扫描并注册这些服务类。

import org.springframework.stereotype.Service;

@Service
public class MyService {
// 服务层的业务逻辑
}

事物管理

服务层通常涉及到事务的处理,确保在一组相关的操作中,要么全部成功执行,要么全部回滚到初始状态。Spring提供了@Transactional注解来声明事务性的方法。

import org.springframework.transaction.annotation.Transactional;

@Service
public class MyService {

@Transactional
public void performTransactionalOperation() {
// 事务性的操作
}
}

调用数据访问层

示例代码:

public Result findArticleAndLabelById(String id) {
return Result.ok(baseMapper.findArticleAndLabelById(id));
}

控制层

Spring Boot中,控制层是应用程序的入口点,负责接收用户请求、调用服务层进行业务处理,并返回相应的视图或数据给用户。通俗理解:

  1. 当用户访问一个API接口时,SpringBoot根据请求接口的地址匹配到对应控制器的方法。
  2. 控制器方法调用服务层接口
  3. 服务层接口处理业务逻辑,并调用数据访问层接口
  4. 数据访问层根据接口关联到MappXml的sql,在数据库查询结果并根据ResultMap将查询结果映射到实体类,最终将查询结果由控制器返回给用户
文章作者: 慕容峻才
文章链接: https://www.acaiblog.top/SpringBoot3框架教程/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 阿才的博客
微信打赏
支付宝打赏