springboot特性
- 起步依赖,解决
Spring
程序配置繁琐的问题- 本质上就是一个Maven坐标,整合了完成一个功能需要的所有坐标
- 自动配置,解决
Spring
程序依赖设置繁琐的问题- 遵循约定大约配置的原则,在boot程序启动后,一些bean对象会自动注入到ioc容器,不需要手动声明,简化开发
- 其他特性
- 内嵌的Tomcat、Jetty(无需部署WAR文件)使用
SpringBoot
内置的服务器 - 外部化配置
- 不需要XML配置(properties/yml)
- 内嵌的Tomcat、Jetty(无需部署WAR文件)使用
yml配置信息的获取()
- @Value注解(可以写在方法的形参里)
yml文件:
emil:
user: 123@qq.com
类文件
@Value("${email.user}")
private String emailUser;
- @ConfigurationProperties注解
@Component
@ConfigurationProperties(prefix = "email")//指定前缀
public class EmailProperties {
private String user;//实体类的成员变量名与配置文件中的键名保持一致
// getter and setter
public String getUser() {
return user;
}
public void setUser(String user) {
this.user = user;
}
}
需要加入以下依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
Bean注册
- 要注册的Bean是自定义的,使用以下注解
- 要注册的Bean是第三方的,使用以下注解
- @Bean注解,会将方法的返回结果注入到IOC容器,生成的Bean对象的默认名为方法的名,当然可以指定@Bean(name =“myCustomName”)
如果方法的内部需要使用到ioc容器中已经存在的bean对象,那么只需要在方法上声明即可,spring会自动的注入- 启动类的主方法的run方法会返回IOC容器
- 不建议在启动类注册bean;应该在统一的配置类中进行注册
- 启动类的主方法的run方法会返回IOC容器
- @Import注解 (前面的config配置类依然是在Applicaiton的扫描范围下)
- 如果不在扫描范围,但是依然想把配置类声明的Bean对象加到IOC容器
- @Bean注解,会将方法的返回结果注入到IOC容器,生成的Bean对象的默认名为方法的名,当然可以指定@Bean(name =“myCustomName”)
@SpringBootApplication
@Import({CommonConfig.class})
public class Application {
}
2. 前面的Import中的{}填写多个配置类文件的话,{}内容太多不美观{ConfigClass.class,ConfigClass.class,ConfigClass.class,ConfigClass.class}<br />可以导入一个实现了ImportSelector接口的类。这个类可以返回一个包含需要注册的Bean的全类名的字符串数组:
public class MyImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{CommonConfig.class.getName(), ThirdPartyClass2.class.getName()};
//也可以直接写“类名”
}
}
在启动类Import进来
@SpringBootApplication
@Import(MyImportSelector.class)
public class Application {
}
3.注册条件:
自动配置原理
springboot2.7版本之前读取的配置文件是spring.factories
2.7-3.0是spring.factories和后缀名为import的文件
3.0之后就只有.import的这个文件了
补充一下:AutoConfigurationImportSelector类实现DeferredImportSelector接口,DeferredImportSelector接口包括了ImportSelector接口
在Spring Boot项目中引入一个依赖时,这个依赖的jar包中可能包含了一些带有@Configuration和@EnableAutoConfiguration注解的配置类。这些配置类定义了如何配置和初始化这个依赖,以便它可以在你的应用中使用。
当Spring Boot应用启动时,它会通过@EnableAutoConfiguration注解来启动自动配置过程。这个过程包括扫描类路径下所有的配置类,并根据一些条件(比如类路径下是否存在某个类,配置文件中是否定义了某个属性等)来决定是否启用这些配置类。
自定义starter以下是创建自定义MyBatis Starter的完整步骤和代码示例:
- 创建自动配置模块:首先,你需要创建一个名为
mybatis-spring-boot-autoconfigure
的模块,这个模块将提供自动配置功能。在这个模块中,你需要定义一个配置文件META-INF/spring.factories
,并在其中列出所有的自动配置类。
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.mybatis.autoconfigure.MybatisAutoConfiguration
- 定义配置属性类:在自动配置模块中,你需要定义一个配置属性类,例如
MybatisProperties
。这个类需要使用@ConfigurationProperties
注解,并提供一些属性,如数据库URL、用户名、密码等。这些属性可以在application.properties
或application.yml
文件中进行配置。
@ConfigurationProperties(prefix = "mybatis")
public class MybatisProperties {
private String url;
private String username;
private String password;
// getters and setters...
}
- 定义自动配置类:在自动配置模块中,你还需要定义一个自动配置类,例如
MybatisAutoConfiguration
。这个类需要使用@Configuration
和@EnableConfigurationProperties(MybatisProperties.class)
注解。在这个类中,你可以定义一些@Bean
方法,用于创建和配置MyBatis的SqlSessionFactory
、SqlSessionTemplate
等组件。
@Configuration
@EnableConfigurationProperties(MybatisProperties.class)
public class MybatisAutoConfiguration {
@Autowired
private MybatisProperties properties;
@Bean
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
factoryBean.setDataSource(dataSource);
// other configurations...
return factoryBean.getObject();
}
@Bean
public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
return new SqlSessionTemplate(sqlSessionFactory);
}
}
- 创建Starter模块:然后,你需要创建一个名为
mybatis-spring-boot-starter
的模块。在这个模块中,你需要引入刚才创建的自动配置模块。在mybatis-spring-boot-starter
模块的pom.xml
文件中,你需要添加对mybatis-spring-boot-autoconfigure
模块的依赖。
<dependencies>
<dependency>
<groupId>com.example</groupId>
<artifactId>mybatis-spring-boot-autoconfigure</artifactId>
<version>1.0.0</version>
</dependency>
<!-- other dependencies... -->
</dependencies>
完成以上步骤后,你就可以在其他Spring Boot项目中引入你自定义的mybatis-spring-boot-starter
,然后在application.properties
或application.yml
文件中配置MyBatis的属性,Spring Boot就会自动配置MyBatis。
Spring Validation(参数校验,包括实体类的参数校验,分组校验,包括自定义注解来自定义参数校验)Spring 提供的一个参数校验框架,使用预定义的注解完成参数校验
- 引入Spring Validation 起步依赖
- 在参数前面添加@Pattern注解
- 在Controller类上添加@Validated注解
实体类的参数校验
- 实体类的成员变量上添加注解
- @NotNull
- @NotEmpty
- 接口方法的实体参数上添加@Validated注解
@Pattern
是 Java 的 Bean Validation(JSR 303)规范中的一个注解,用于验证一个字符串是否符合指定的正则表达式。
在Spring Boot中,对参数进行分组校验主要涉及以下几个步骤:
- 定义分组接口:在实体类中定义不同的分组接口,用于区分不同场景下的校验规则。(校验项属于默认分组,分组之间可以继承)
public class User {
// 定义分组接口
public interface BasicInfo {}
public interface UpdateInfo extends Default {}
}
- 设置校验规则并指定分组:在实体类的字段上添加校验注解,并通过groups属性指定该校验规则属于哪个分组。
public class User {
@NotNull(groups = {BasicInfo.class, UpdateInfo.class})
private String username;
@NotNull(groups = UpdateInfo.class)
private String email;
@NotNull//属于Default分组
private String nickname;
}
- 校验时指定分组:在接口方法参数上添加@Validated注解,并通过value属性指定本次校验需要检查的分组。
@RestController
@RequestMapping("/user")
public class UserController {
@PostMapping("/register")
public Result register(@RequestBody @Validated(User.BasicInfo.class) User user) {
// 使用BasicInfo分组进行校验
}
@PutMapping("/update")
public Result update(@RequestBody @Validated(User.UpdateInfo.class) User user) {
// 使用UpdateInfo分组进行校验
}
}
-
**自定义注解 **
**@State**
:这个注解将用于标记需要校验的状态字段。 -
**自定义校验类 **
**StateValidation**
:这个类将实现ConstraintValidator
接口,用于校验状态是否符合规定。 -
使用自定义注解进行校验:在需要校验状态的地方使用
@State
注解。
下面是具体的实现步骤: -
自定义注解
@State
import javax.validation.Constraint;
import java.lang.annotation.*;
@Constraint(validatedBy = StateValidation.class)
@Target({ ElementType.FIELD })//元注解,用于指定被它标注的注解可以应用的范围或目标。换句话说,它定义了其他注解能够标注的 Java 构件类型。
@Retention(RetentionPolicy.RUNTIME)
public @interface State {
//提供校验失败后的提示信息
String message() default "Invalid state";
//指定分组
Class<?>[] groups() default {};
//负载 获取到state注解的附加信息
Class<? extends Payload>[] payload() default {};
}
- 自定义校验类
StateValidation
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
public class StateValidation implements ConstraintValidator<State, String> {//String指的是校验的数据的类型
@Override
public void initialize(State constraintAnnotation) {
}
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
// 这里添加校验逻辑,例如校验状态是否是预定义的几个有效状态
String[] validStates = {"Active", "Inactive", "Suspended"};
for (String state : validStates) {
if (state.equals(value)) {
return true;
}
}
return false;
}
}
- 使用自定义注解进行校验
在实体类中,您可以在需要校验的状态字段上使用@State
注解。
import javax.persistence.Entity;
import javax.validation.constraints.NotNull;
@Entity
public class User {
@NotNull
@State
private String state;
// Getters and setters
}
这样,在运行时,Spring 框架会自动根据 @State
注解调用 StateValidation
类来进行校验。如果状态不符合预定义的有效状态列表,将抛出校验异常。
全局异常处理器在Spring Boot中,全局异常处理器可以用来捕获和处理所有未被处理的异常。以下是实现全局异常处理器的步骤:
- 创建一个全局异常处理器类,该类应该使用
@ControllerAdvice
注解。 @ControllerAdvice
注解可以把异常处理器应用到所有控制器,而不是单个控制器。- 在处理器类中,定义处理不同异常的方法。使用
@ExceptionHandler
注解指定处理的异常类型。 - 对异常按阶段进行分类,大体可以分成:进入Controller前的异常和Service层异常。
- 目标就是消灭95%以上的try catch代码块,并以优雅的Assert(断言)方式来校验业务的异常情况,只关注业务逻辑,而不用花费大量精力写冗余的try catch代码块。
@ControllerAdvice
public class GlobalExceptionHandler {
/**
* 处理空指针异常
*/
@ExceptionHandler(NullPointerException.class)
public String handleNullPointerException(Exception e) {
return "null_pointer_error";
}
/**
* 处理算术异常
*/
@ExceptionHandler(ArithmeticException.class)
public String handleArithmeticException(Exception e) {
return "arithmetic_error";
}
/**
* 处理其他异常
*/
@ExceptionHandler(Exception.class)
public String handleOtherException(Exception e) {
return "other_error";
}
}
登录认证(jwt(json web token)令牌)作用
- 承载业务数据, 减少后续请求查询数据库的次数
- 防篡改, 保证信息的合法性和有效性
jwt(json web token)
定义了一种简洁的,自包含的格式,用于通信双方以ison数据格式安全的传输信息。
- 组成:
第一部分:header(头),记录令牌类型,签名算法等。例如:{“alg:'hs256”,“type”:“JWT”} - 第二部分:payload(有效载荷),携带一些自定义信息,默认信息等。例如:{"id=“1”,“username”=“tom”}
- 第三部分:signature(签名),防止token被篡改,确保安全性。将header,payload,并加入指定秘钥,通过指定签名算法计算而来。
base64是一种编码方式,不是加密
//JWT令牌生成
@Test
void genToken() {
Map<String, Object> user = new HashMap<>();
user.put(“id”, “1”);
user.put(“username”, “张三”);
String token = JWT.create()
.withClaim(“user”, user)
.withExpiresAt(new Date(System.currentTimeMillis() + 1000*60*60))//有效时间
.sign(Algorithm.HMAC256(“秘钥"));
System.out.println(token);
}
//JWT令牌验证
@Test
void parseToken() {
String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9…….";
JWTVerifierjwtVerifier = JWT.require(Algorithm.HMAC256("密钥")).build();
DecodedJWTdecodedJWT = jwtVerifier.verify(token);
Map<String, Claim> claims = decodedJWT.getClaims();
System.out.println(claims.get("user"));
}
使用redis实现令牌主动失效机制在SpringBoot项目中集成Redis,你可以按照以下步骤进行:
- 添加依赖:在你的
pom.xml
文件中添加Redis的SDK¹²³。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
- 配置文件:在
application.properties
或者application.yml
文件中,添加Redis的配置信息。
spring.redis.host=127.0.0.1
spring.redis.port=6379
- 创建配置类:创建一个配置类,用于读取配置文件中的信息,并创建
RedisTemplate
Bean。
@Configuration // 标记这个类为配置类,Spring容器会根据它来生成Bean定义和服务请求
public class RedisConfig {
@Bean // 标记方法返回的对象作为Bean注入到Spring容器中
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
// 创建RedisTemplate实例,并设置泛型类型<String, Object>分别表示键和值的类型
RedisTemplate<String, Object> template = new RedisTemplate<>();
// 设置连接工厂,用于创建与Redis的连接
template.setConnectionFactory(connectionFactory);
// 设置键序列化器为StringRedisSerializer,这意味着键在Redis中会以字符串形式存储
template.setKeySerializer(new StringRedisSerializer());
// 设置值序列化器为GenericJackson2JsonRedisSerializer,
// 这意味着值在Redis中会以JSON格式存储,方便以对象的形式进行存储和读取
template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
// 返回配置好的RedisTemplate实例
return template;
}
}
Spring Boot的自动配置机制会自动创建一个RedisTemplate
Bean,并添加到IOC容器中。这个自动创建的RedisTemplate
使用的是JDK的序列化机制,键(key)和值(value)都是通过JDK的序列化方式来序列化的。
然而,这种序列化方式可能并不是我们想要的。例如,我们可能希望键(key)是字符串类型,而值(value)是JSON格式。这就是为什么我们需要创建一个配置类,自定义RedisTemplate
的序列化方式。
如果你的项目中不需要自定义序列化方式,那么你可以直接使用Spring Boot自动配置的RedisTemplate
。你可以通过@Autowired
注解来注入这个Bean,然后在你的代码中使用它。
- 使用RedisTemplate:在服务类或控制器中注入
RedisTemplate
,并使用它来进行Redis操作。
@Autowired
private RedisTemplate<String, Object> redisTemplate;
// 设置键值对,并指定过期时间(例如:10秒)
redisTemplate.opsForValue().set("key", "value", 10, TimeUnit.SECONDS);
// 获取值
String value = (String) redisTemplate.opsForValue().get("key");
// 删除键值对
redisTemplate.delete("key");
- 登录成功后,给浏览器响应令牌的同时,把该令牌存储到redis中
- LoginInterceptor拦截器中,需要验证浏览器携带的令牌,并同时需要获取到redis中存储的与之相同的令牌(用equal()方法)
- 当用户修改密码成功后,删除redis中存储的旧令牌
拦截器(先过滤器后拦截器)在Spring Boot中,你可以创建一个实现了HandlerInterceptor
接口的拦截器。以下是创建拦截器的步骤和代码:
- 创建拦截器类:首先,创建一个新的Java类,实现
HandlerInterceptor
接口。在这个类中,你可以重写preHandle
,postHandle
和afterCompletion
方法,分别对应于处理器执行前,返回模型视图之前,和处理器执行完成后这三个阶段。
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Component
public class MyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 在这里编写处理器执行前的逻辑
return true;//放行
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
// 在这里编写返回模型视图之前的逻辑
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
// 在这里编写处理器执行完成后的逻辑
}
}
- 注册拦截器:然后,你需要在一个配置类中注册你的拦截器。这个配置类需要实现
WebMvcConfigurer
接口,并重写addInterceptors
方法。
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new MyInterceptor1())
.addPathPatterns("/**") // 对所有路径进行拦截
.excludePathPatterns("/user/login"); // 对"/user/login"路径不进行拦截
registry.addInterceptor(new MyInterceptor2());
// 你可以继续添加更多的拦截器
}
}
在这个例子中,MyInterceptor
就是你刚刚创建的拦截器类。你可以在addInterceptor
方法中添加多个拦截器,它们会按照添加的顺序执行。
以上就是在Spring Boot中创建和注册拦截器的基本步骤和代码。你可以根据你的需求修改这些代码,以实现你想要的功能。
controller层获取请求头中的数据
- 通过HttpServletRequest对象获取请求头(拦截器中可以使用)
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
@RestController
public class MyController {
@GetMapping("/my-endpoint")
public String myEndpoint(HttpServletRequest request) {
// 使用HttpServletRequest对象的getHeader方法获取请求头
String token = request.getHeader("Authorization");
// 在这里,你可以使用这个令牌来进行身份验证或者其他操作
return "获取到的JWT令牌是:" + token;
}
}
- 通过@RequestHeader注解获取请求头
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class MyController {
@GetMapping("/my-endpoint")
public String myEndpoint(@RequestHeader(name="Authorization") String token) {
// 使用@RequestHeader注解获取请求头
// 在这里,你可以使用这个令牌来进行身份验证或者其他操作
return "获取到的JWT令牌是:" + token;
}
}
这两种方法各有优点和缺点:
- 通过HttpServletRequest对象获取请求头
- 优点:这种方法更加通用,因为
HttpServletRequest
是Servlet API的一部分,可以在任何使用Servlet API的地方使用,不仅限于Spring MVC。 - 缺点:这种方法需要你手动处理请求头的名称,如果你的代码中多次使用到同一个请求头,可能会导致代码重复。
- 通过@RequestHeader注解获取请求头
- 优点:这种方法更加简洁,可以直接在方法参数中获取请求头,无需手动调用API。此外,如果请求头不存在,Spring MVC会抛出一个异常,这可以帮助你更好地处理错误情况。
- 缺点:这种方法只能在Spring MVC的控制器方法中使用,不能在其他地方使用。
ThreadLocal```java
import java.util.HashMap;
import java.util.Map;
/**
-
ThreadLocal 工具类
*/
@SuppressWarnings(“all”)
public class ThreadLocalUtil {
//提供ThreadLocal对象,
private static final ThreadLocal THREAD_LOCAL = new ThreadLocal();//根据键获取值
public static T get(){
return (T) THREAD_LOCAL.get();
}//存储键值对
public static void set(Object value){
THREAD_LOCAL.set(value);
}//清除ThreadLocal 防止内存泄漏
public static void remove(){
THREAD_LOCAL.remove();
}
}
我们可以在拦截器中将解析出来的 map 存入 `ThreadLocal`,然后在 controller 中获取这个 map。以下是一个简单的示例:
```java
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
public class TokenInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 获取并解析 JWT 令牌
String token = request.getHeader("Authorization");
Map<String, Object> claims = parseJwt(token); // 假设你已经实现了 parseJwt 方法
// 将解析出来的 map 存入 ThreadLocal
ThreadLocalUtil.set(claims);
return true;
}
}
然后在你的 controller 中,你可以这样获取这个 map:
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class MyController {
@GetMapping("/my-endpoint")
public String myEndpoint() {
Map<String, Object> claims = ThreadLocalUtil.get();
// 使用 claims...
return "Success";
}
}
最后,别忘了在请求处理完毕后清除 ThreadLocal 中的数据,以防止内存泄漏。你可以在 TokenInterceptor
中的 afterCompletion
方法中做这个操作:
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
public class TokenInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 获取并解析 JWT 令牌
String token = request.getHeader("Authorization");
Map<String, Object> claims = parseJwt(token); // 假设你已经实现了 parseJwt 方法
// 将解析出来的 map 存入 ThreadLocal
ThreadLocalUtil.set(claims);
return true;
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
ThreadLocalUtil.remove();//释放线程
}
}
这样,你就可以在 controller 中获取到拦截器中解析出来的 map 了。
文件上传```java
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Random;
@RestController
public class FileUploadController {
@PostMapping(“/upload”)
public String handleFileUpload(@RequestParam(“file”) MultipartFile file) {
String filePath = “c://user/files/”;
try {
// 获取原始文件名
String originalFilename = file.getOriginalFilename();
// 获取文件扩展名
String fileExtension = originalFilename.substring(originalFilename.lastIndexOf(“.”));
// 生成时间戳
String timestamp = new SimpleDateFormat(“yyyyMMddHHmmss”).format(new Date());
// 生成随机数以避免同一秒内上传的文件名冲突
Random random = new Random();
int randomNumber = random.nextInt(1000);
// 新的文件名
String newFilename = timestamp + “_” + randomNumber + fileExtension;
File dest = new File(filePath + newFilename);
file.transferTo(dest);
return "File uploaded successfully: " + dest.getAbsolutePath();
} catch (IOException e) {
e.printStackTrace();
return "Failed to upload file: " + e.getMessage();
}
}
}
在这个代码中,我们首先获取原始文件的扩展名,然后创建一个包含当前时间戳和随机数的字符串作为新文件名。这样可以确保每个文件名都是唯一的,即使多个文件有相同的原始文件名。
布置阿里云OSS在SpringBoot项目中集成阿里云OSS,你可以按照以下步骤进行:
1. **添加依赖**:在你的`pom.xml`文件中添加阿里云OSS的SDK。
```xml
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>3.15.0</version>
</dependency>
- 配置文件:在
application.properties
或者application.yml
文件中,添加阿里云OSS的配置信息。
# 阿里云OSS配置
aliyun:
oss:
end-point: oss-cn-hangzhou.aliyuncs.com
access-key-id: LTAI5t9w*****
access-key-secret: OXK24t76*****
bucket-name: oss-test-img
- 创建配置类:创建一个配置类,用于读取配置文件中的信息。
@ConfigurationProperties(prefix = "aliyun.oss")//属性绑定,将配置文件(application)的属性绑定到对应字段
@Configuration
@Data
public class OSSConfig {
private String endPoint;
private String accessKeyId;
private String accessKeySecret;
private String bucketName;
}
- 编写服务类:编写一个服务类,用于处理文件上传的业务。
@Service
@Slf4j
public class FileServiceImpl implements FileService {
@Autowired
private OSSConfig ossConfig;
@Override
public String upload(MultipartFile file) {
//获取相关配置
String bucketName = ossConfig.getBucketName();
String endPoint = ossConfig.getEndPoint();
String accessKeyId = ossConfig.getAccessKeyId();
String accessKeySecret = ossConfig.getAccessKeySecret();
//创建OSS对象
OSS ossClient = new OSSClientBuilder().build(endPoint, accessKeyId, accessKeySecret);
//其他上传逻辑...
}
}
接口层代码
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
@RestController
public class FileController {
@Autowired
private FileService fileService;
@PostMapping("/upload")
public String uploadFile(@RequestParam("file") MultipartFile file) {
try {
// 调用服务层的上传方法
String fileUrl = fileService.upload(file);
return "File uploaded successfully: " + fileUrl;
} catch (Exception e) {
e.printStackTrace();
return "Failed to upload file: " + e.getMessage();
}
}
}
springboot属性配置方式
- 命令行参数(最高优先级):
- 例子:
java -jar myapp.jar --server.port=8081
- 这会覆盖其他配置源中的
server.port
属性。
- 例子:
- 操作系统环境变量:
- 例子:
export SERVER_PORT=8081
- 设置环境变量
SERVER_PORT
来配置服务器端口。
- 例子:
- Jar包所在目录下的application.yml文件:
- 例子:在JAR文件同一目录下的
application.yml
中设置server.port: 8081
。 - 这个配置会覆盖项目内部
application.yml
中的相同属性。
- 例子:在JAR文件同一目录下的
- 项目中resources目录下的application.yml(最低优先级):
- 例子:在
src/main/resources/application.yml
中设置server.port: 8080
。 - 这是默认的配置文件,其配置值会被其他更高优先级的配置所覆盖。
总结:命令行参数具有最高优先级,会覆盖其他所有配置。其次是操作系统环境变量,然后是外部配置文件,最后是项目内部资源目录下的配置文件。
- 例子:在
springboot多环境开发SpringBoot提供的Profiles可以用来隔离应用程序配置的各个部分,并在特定环境下指定部分配置生效
如果多个环境有相同的配置部分,您可以将这些通用配置放在默认配置部分,这样可以避免重复并简化配置文件。在Spring Boot中,默认配置会应用到所有环境,除非被特定环境的配置所覆盖。
# 默认配置
server:
port: 8080
spring:
datasource:
url: jdbc:mysql://localhost:3306/my_database
username: my_user
password: my_password
# 使用'---'来分隔不同环境的配置
---
# 开发环境配置
spring:
profiles: dev
server:
port: 8081
---
# 测试环境配置
spring:
profiles: test
server:
port: 8082
---
# 生产环境配置
spring:
profiles: prod
server:
port: 8083
# 指定活动配置文件
spring:
profiles:
active: dev # 这里指定开发环境配置生效
在这个例子中,spring.datasource
配置是所有环境共有的,因此它被放在默认配置部分。每个特定环境的配置块只覆盖了端口号。这样,您可以保持配置的DRY(Don’t Repeat Yourself)原则,同时也使得配置文件更加清晰和维护。
也可以将不同环境的配置分别写在不同的文件中。Spring Boot支持将每个环境的配置放在单独的文件中,这样可以进一步组织和简化配置管理。通常的命名约定是application-{profile}.yml
或application-{profile}.properties
。
例如,您可以有以下几个配置文件:
application.yml
:默认配置,适用于所有环境。application-dev.yml
:专门为开发环境定制的配置。application-test.yml
:专门为测试环境定制的配置。application-prod.yml
:专门为生产环境定制的配置。
在application.yml
中,您不需要分隔不同环境的配置,而是将共用的配置放在这里。特定环境的配置则放在对应的文件中。例如:application.yml
:
spring:
datasource:
url: jdbc:mysql://localhost:3306/my_database
username: my_user
password: my_password
然后,在默认的application.yml
或通过命令行参数、环境变量等方式来指定活动配置文件。例如,在application.yml
中指定:
spring:
profiles:
active: dev # 激活开发环境配置
或者,通过命令行参数激活:
java -jar myapp.jar --spring.profiles.active=prod
这种方式使得每个环境的配置更加模块化,便于管理和维护。
环境文件按功能再分组
按照配置的类别,把配置信息配置到不同的配置文件中
application-分类名.yml
在application.yml中定义分组
spring.profiles.group
在application.yml中激活分组
spring.profiles.active(不再是指定某个文件了,而是组的名称)
https://blog.csdn.net/qq_44378854/article/details/135873981
切换web服务器引入spring-boot-starter-web依赖后,也会引入spring-boot-starter-tomcat依赖;使用标签来排除tomcat依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<artifactId>spring-boot-starter-tomcat</artifactId>
<groupId>org.springframework.boot</groupId>
</exclusion>
</exclusions>
</dependency>
引入jetty服务器,成功切换服务器;
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>
Mybatis开启驼峰命名(包括实体类的字段和数据库字段对应的方法)在MyBatis中,你可以通过设置mapUnderscoreToCamelCase
属性为true
来开启驼峰命名规则¹。这样,MyBatis会自动将数据库表中的列名或表名转换为相应的驼峰命名形式。以下是几种开启驼峰命名的方式:
- 在MyBatis的配置文件中设置¹:
<configuration>
<settings>
<setting name="mapUnderscoreToCamelCase" value="true" />
</settings>
</configuration>
- 在Spring Boot的application配置文件中设置¹²:
mybatis.configuration.mapUnderscoreToCamelCase=true
或者
mybatis.configuration.map-underscore-to-camel-case=true
- 在Spring Boot中使用自定义配置类的方式配置¹:
@Configuration
public class MyBatisConfig {
@Bean
public ConfigurationCustomizer configurationCustomizer() {
return new ConfigurationCustomizer() {
@Override
public void customize(org.apache.ibatis.session.Configuration configuration) {
configuration.setMapUnderscoreToCamelCase(true);
}
};
}
}
如果你不想使用这个配置,或者你的命名规则比较复杂,不适合使用这个配置,你可以在实体类中使用@Column
注解来指定属性对应的数据库表列名。以下是一个例子:
import javax.persistence.Column;
public class User {
@Column(name = "user_name")
private String userName;
// 其他属性和方法
}
在这个例子中,userName
属性对应的数据库表列名是user_name
。这样,即使你的Java属性名和数据库列名不一致,你也可以通过@Column
注解来确保它们能够正确地映射。
Mybatis(PageHelper帮助实现分页查询)MyBatis 提供了一种特殊的分页插件,用于优化分页查询。这个插件通常被称为 MyBatis PageHelper。它通过拦截器(Interceptor)的方式,在执行SQL查询时自动添加分页语句,从而简化了分页查询的代码实现。
1. 添加依赖(pom.xml)
<dependencies>
<!-- PageHelper -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.3.0</version>
</dependency>
<!-- 其他依赖... -->
</dependencies>
2. 配置插件
- 方式一:使用Spring Boot自动配置(application.properties)
pagehelper.helper-dialect=mysql
pagehelper.reasonable=true
pagehelper.support-methods-arguments=true
pagehelper.params=count=countSql
- 方式二:使用自定义的
**MyBatisConfig**
类进行配置(MyBatisConfig.java)
@Configuration
public class MyBatisConfig {
@Bean
public PageHelper pageHelper() {
PageHelper pageHelper = new PageHelper();
Properties p = new Properties();
p.setProperty("offsetAsPageNum", "true");
p.setProperty("rowBoundsWithCount", "true");
p.setProperty("reasonable", "true");
pageHelper.setProperties(p);
return pageHelper;
}
}
3. Mapper 接口
@Mapper
public interface ArticleMapper {
List<Article> findAllArticles();
}
//在服务层,您将使用PageHelper的startPage方法来
//指定当前页和每页的记录数。
//这将告诉PageHelper您想要执行分页查询。
//然后,您只需像平常一样调用Mapper接口中的方法。
//PageHelper会拦截这个查询,并根据您提供的分页参数修改SQL语句。
4. 服务层
@Service
public class ArticleService {
@Autowired
private ArticleMapper articleMapper;
public List<Article> findArticles(int page, int size) {
PageHelper.startPage(page, size);
return articleMapper.findAllArticles();
}
}
5. 控制器层
@RestController
@RequestMapping("/articles")
public class ArticleController {
@Autowired
private ArticleService articleService;
@GetMapping
public List<Article> getArticles(
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "10") int size
) {
return articleService.findArticles(page, size);
}
}
依赖注入的方式
- @autowired注解
- @resource注解
- 构造器注入
在Spring框架中,依赖注入是实现控制反转(IoC)的主要方式,它允许Spring容器自动装配Bean的依赖关系。有几种不同的方法可以实现依赖注入,包括使用@Autowired
注解、@Resource
注解以及构造器注入。每种方法都有其优缺点:
- @Autowired注解:
- 优点:这是Spring框架提供的原生注解,使用简单、直观。
- 缺点:过度使用
@Autowired
可能导致代码的耦合度增加,使得单元测试变得困难。此外,IDE可能会针对字段注入发出警告,因为这种方式不易于理解和管理依赖关系。
- @Resource注解:
- 优点:
@Resource
是Java EE的标准,因此可以在其他符合JSR-250标准的框架中使用。它提供了更多的灵活性,可以通过名称和类型来指定依赖。 - 缺点:与Spring框架的整合可能不如
@Autowired
紧密,因此在某些复杂情况下可能不如@Autowired
方便。
- 优点:
- 构造器注入:
- 优点:构造器注入通常被认为是最安全、最推荐的依赖注入方式。它可以确保所有的依赖在对象创建时就被设置,从而避免了空指针异常。这种方式也使得依赖关系更加明确,有利于代码的清晰度和可维护性。
- 缺点:当依赖关系较多时,构造器参数列表可能会变得很长,导致代码可读性下降。此外,复杂的构造器可能会导致难以理解和维护的对象创建逻辑。
@AllArgsConstructor
和@RequiredArgsConstructor
都是Lombok库中的注解,用于自动生成构造函数,但它们的作用略有不同:
@AllArgsConstructor
:此注解会为类中的所有字段生成一个构造函数。@RequiredArgsConstructor
:此注解会为类中的每一个final字段或者@NonNull字段生成一个构造函数。- 如果你在使用
@Value
注解进行注入,@RequiredArgsConstructor
可以成功注入,而@AllArgsConstructor
可能会导致注入失败。
@Value
注解通常与依赖注入框架(如Spring)一起使用,这些框架通过构造函数来注入值。当您在类上使用@Value
注解时,依赖注入框架会使用该注解自动生成的构造函数来创建对象实例,并将值注入到该对象中。
然而,如果您同时使用@AllArgsConstructor
注解,Lombok会为您的类生成另一个包含所有字段的构造函数。这个构造函数会优先于依赖注入框架的操作执行。因此,当您创建对象实例时,首先调用的是@AllArgsConstructor
生成的构造函数,此时依赖注入框架还没有机会注入任何值。这意味着在构造函数内部,您尝试访问的任何通过@Value
注解本应注入的字段都会是null
。
所以,当@AllArgsConstructor
和@Value
一起使用时,@AllArgsConstructor
的构造函数会先执行,导致@Value
的注入逻辑失效,因为这些字段在注入发生之前就已经被赋予null
值了。
在选择依赖注入方式时,建议根据具体场景和需求来决定。例如,对于关键或复杂的依赖关系,使用构造器注入是一个好选择,因为它可以确保这些依赖关系在对象创建时就准备就绪。对于简单的依赖关系,@Autowired
可能更为方便。而@Resource
则适用于需要更细粒度控制的场景。