SpringBoot应用常用的工具类
- 一、统一返回结果类
- 二、统一异常处理类
- 1. 全局异常类
- 2. 自定义异常类
- 三、常用的配置类
- 1. MybatisPlus配置类
- 2. Redis配置类
- 3. Swagger2配置类
一、统一返回结果类
在前后端分离系统中,统一返回结果类的作用更为突出,其主要作用包括以下几个方面:
a.格式统一
:在前后端分离系统中,前端通过Ajax请求来获取后端数据,而每个请求都需要获取后端数据,并且数据格式需要保持一致。通过使用统一返回结果类,可以规范前后端数据传输格式和约定,减少数据解析和格式判断的开销。
b.错误处理
:前后端分离系统中,错误处理非常重要,错误提示信息需要明确,便于开发人员识别和修复。统一返回结果类可以将错误信息封装在同一个结构体中,有利于前端进行错误提示和用户交互。
c.数据传输效率高
:在前后端分离系统中,由于前端需要通过Ajax请求来向后台请求数据,每个请求都被视为一个独立的HTTP请求,可以使用同一个返回结果类降低请求的传输开销,以提高应用程序的效率和响应速度。
d.易于扩展
:在前后端分离系统中,数据传输需要的格式可能随着需求变更而改变。通过使用统一返回结果类,可以方便地修改结构体,来适应新需求和扩展。
综合来看,利用统一返回结果类,可以规范前后端数据传输格式和约定,减少数据解析和错误处理的开销,提高数据传输效率和用户体验。
下面有一个结果类的模板:
@Data
public class Result<T> {
// 状态码
private Integer code;
// 信息
private String message;
// 数据
private T data;
// 构造私有化
private Result() { }
// 设置数据,返回对象的方法
public static<T> Result<T> build(T data,Integer code,String message) {
// 创建Resullt对象,设置值,返回对象
Result<T> result = new Result<>();
// 判断返回结果中是否需要数据
if(data != null) {
// 设置数据到result对象
result.setData(data);
}
// 设置其他值
result.setCode(code);
result.setMessage(message);
// 返回设置值之后的对象
return result;
}
// 设置数据,返回对象的方法
public static<T> Result<T> build(T data,ResultCodeEnum resultCodeEnum) {
// 创建Resullt对象,设置值,返回对象
Result<T> result = new Result<>();
// 判断返回结果中是否需要数据
if(data != null) {
// 设置数据到result对象
result.setData(data);
}
//设置其他值
result.setCode(resultCodeEnum.getCode());
result.setMessage(resultCodeEnum.getMessage());
//返回设置值之后的对象
return result;
}
// 成功的方法
public static<T> Result<T> ok(T data) {
Result<T> result = build(data, ResultCodeEnum.SUCCESS);
return result;
}
// 失败的方法
public static<T> Result<T> fail(T data) {
return build(data,ResultCodeEnum.FAIL);
}
}
统一返回结果状态信息类:
@Getter
public enum ResultCodeEnum {
SUCCESS(200,"成功"),
FAIL(201, "失败"),
SERVICE_ERROR(2012, "服务异常"),
DATA_ERROR(204, "数据异常"),
ILLEGAL_REQUEST(205, "非法请求"),
REPEAT_SUBMIT(206, "重复提交"),
LOGIN_AUTH(208, "未登陆"),
PERMISSION(209, "没有权限"),
...
;
private Integer code;
private String message;
private ResultCodeEnum(Integer code, String message) {
this.code = code;
this.message = message;
}
}
用登录作为例子来使用此类:
@RestController
@RequestMapping("/admin")
public class AdminController {
@Autowired
private LoginService loginService;
@PostMapping("login")
public Result findRegionByKeyword() {
Map<String,String> map = new HashMap<>();
map.put("token","token-admin");
return Result.ok(map);
}
}
二、统一异常处理类
1. 全局异常类
在项目开发中,为了保证代码的健壮性,需要对抛出的异常进行处理,SpringBoot全局异常类通过AOP对所有程序中可能出现的异常进行捕获和统一处理,统一异常处理,方便维护和管理。系统中出现异常时,如果没有进行及时处理的话,容易导致系统崩溃,影响整个应用的运行,全局异常捕捉能让系统及时发现并解决异常问题,保证系统的健壮性。
// AOP 面向切面
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(Exception.class) // 异常处理器
@ResponseBody // 返回json数据
// 调用前面统一返回结果类
public Result error(Exception e) {
e.printStackTrace();
return Result.fail(null);
}
// 自定义异常处理
@ExceptionHandler(ZiDingYiException.class)
@ResponseBody
public Result error(ZiDingYiException exception) {
return Result.build(null,exception.getCode(),exception.getMessage());
}
}
2. 自定义异常类
自定义异常类可以根据业务需求自定义异常,将业务异常与其他类型的异常分开处理,允许开发人员自定义自己的异常类。
@Data
public class ZiDingYiException extends RuntimeException{
// 异常状态码
private Integer code;
/**
* 通过状态码和错误消息创建异常对象
* @param message
* @param code
*/
public ZiDingYiException(String message, Integer code) {
super(message);
this.code = code;
}
/**
* 接收枚举类型对象
* @param resultCodeEnum
*/
public ZiDingYiException(ResultCodeEnum resultCodeEnum) {
super(resultCodeEnum.getMessage());
this.code = resultCodeEnum.getCode();
}
}
三、常用的配置类
配置类只需将代码复制到项目中即可使用
1. MybatisPlus配置类
@Configuration
@MapperScan("com.xxx.*.mapper")
@EnableTransactionManagement
public class MybatisPlusConfig {
/**
* 新的分页插件,一缓和二缓遵循mybatis的规则,
* 需要设置 MybatisConfiguration#useDeprecatedExecutor = false
* 避免缓存出现问题(该属性会在旧插件移除后一同移除)
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
@Bean
public ConfigurationCustomizer configurationCustomizer() {
return configuration -> configuration.setUseDeprecatedExecutor(false);
}
}
2. Redis配置类
@Configuration
@EnableCaching
public class RedisConfig {
// 使用默认标签做缓存
@Bean
public KeyGenerator wiselyKeyGenerator() {
return new KeyGenerator() {
@Override
public Object generate(Object target, Method method, Object... params) {
StringBuilder sb = new StringBuilder();
sb.append(target.getClass().getName());
sb.append(method.getName());
for (Object obj : params) {
sb.append(obj.toString());
}
return sb.toString();
}
};
}
// 声明模板
/*
ref = 表示引用
value = 具体的值
<bean class="org.springframework.data.redis.core.RedisTemplate" >
<property name="defaultSerializer" ref = "">
</bean>
*/
// 工具类:
@Bean
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
// 将Redis 中 string ,hash 数据类型,自动序列化!
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
@Bean
public CacheManager cacheManager(RedisConnectionFactory factory) {
RedisSerializer<String> redisSerializer = new StringRedisSerializer();
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
//解决查询缓存转换异常的问题
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
// 配置序列化(解决乱码的问题),过期时间600秒
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofDays(365))
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer))
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer))
.disableCachingNullValues();
RedisCacheManager cacheManager = RedisCacheManager.builder(factory)
.cacheDefaults(config)
.build();
return cacheManager;
}
}
3. Swagger2配置类
@Configuration
@EnableSwagger2WebMvc
public class Swagger2Config {
//1
@Bean
public Docket webApiConfig(){
List<Parameter> pars = new ArrayList<>();
ParameterBuilder tokenPar = new ParameterBuilder();
tokenPar.name("userId")
.description("用户token")
//.defaultValue(JwtHelper.createToken(1L, "admin"))
.defaultValue("1")
.modelRef(new ModelRef("string"))
.parameterType("header")
.required(false)
.build();
pars.add(tokenPar.build());
Docket webApi = new Docket(DocumentationType.SWAGGER_2)
.groupName("webApi")
.apiInfo(webApiInfo())
.select()
//只显示api路径下的页面
.apis(RequestHandlerSelectors.basePackage("com.xxx.xxx")) // 扫描包路径
.paths(PathSelectors.regex("/api/.*"))
.build()
.globalOperationParameters(pars);
return webApi;
}
//2
@Bean
public Docket adminApiConfig(){
List<Parameter> pars = new ArrayList<>();
ParameterBuilder tokenPar = new ParameterBuilder();
tokenPar.name("adminId")
.description("用户token")
.defaultValue("1")
.modelRef(new ModelRef("string"))
.parameterType("header")
.required(false)
.build();
pars.add(tokenPar.build());
Docket adminApi = new Docket(DocumentationType.SWAGGER_2)
.groupName("adminApi")
.apiInfo(adminApiInfo())
.select()
//只显示admin路径下的页面
.apis(RequestHandlerSelectors.basePackage("com.xxx.xxx")) // 扫描包路径
//.paths(PathSelectors.regex("/admin/.*"))
.build()
.globalOperationParameters(pars);
return adminApi;
}
private ApiInfo webApiInfo(){
return new ApiInfoBuilder()
.title("网站-API文档")
.description("本文档描述...")
.version("1.0")
.contact(new Contact("name", "url", "email"))
.build();
}
private ApiInfo adminApiInfo(){
return new ApiInfoBuilder()
.title("后台管理系统-API文档")
.description("本文档描述...")
.version("1.0")
.contact(new Contact("name", "url", "email"))
.build();
}
}