feat(common): 添加通用工具类和配置优化

- 新增 JsonConfig,统一配置Long转字符串和LocalDateTime多格式支持
- 新增 MybatisPlusConfig,集成分页插件支持PostgreSQL数据库
- 新增 PhoneUtils,提供手机号格式化、验证及脱敏工具方法
- 优化 UserRoleController,使用MyBatis-Plus分页插件实现分页查询和模糊搜索
- FeishuAuthServiceImpl中调用PhoneUtils去除手机号+86前缀,确保手机号一致性处理
This commit is contained in:
2026-03-28 12:05:02 +08:00
parent 3967e9078a
commit 1e930e6302
5 changed files with 194 additions and 8 deletions

View File

@@ -0,0 +1,60 @@
package cn.yinlihupo.common.config;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import org.springframework.boot.jackson.JsonComponent;
import org.springframework.context.annotation.Bean;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.temporal.ChronoField;
/**
* Spring MVC Json 配置
*/
@JsonComponent
public class JsonConfig {
/**
* 添加 Long 转 json 精度丢失的配置
* 配置 LocalDateTime 支持多种日期时间格式
*/
@Bean
public ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder) {
ObjectMapper objectMapper = builder.createXmlMapper(false).build();
// Long 类型序列化配置
SimpleModule module = new SimpleModule();
module.addSerializer(Long.class, ToStringSerializer.instance);
module.addSerializer(Long.TYPE, ToStringSerializer.instance);
objectMapper.registerModule(module);
// Java 8 日期时间类型支持
JavaTimeModule javaTimeModule = new JavaTimeModule();
// 配置 LocalDateTime 的序列化和反序列化格式
// 支持 "yyyy-MM-dd HH:mm:ss" 和 "yyyy-MM-dd HH:mm" 两种格式
DateTimeFormatter deserializeFormatter = new DateTimeFormatterBuilder()
.appendPattern("yyyy-MM-dd HH:mm")
.optionalStart()
.appendPattern(":ss")
.optionalEnd()
.parseDefaulting(ChronoField.SECOND_OF_MINUTE, 0) // 如果没有秒默认00秒
.toFormatter();
DateTimeFormatter serializeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(serializeFormatter));
javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(deserializeFormatter));
objectMapper.registerModule(javaTimeModule);
return objectMapper;
}
}

View File

@@ -0,0 +1,25 @@
package cn.yinlihupo.common.config;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* MyBatis-Plus 配置类
*/
@Configuration
public class MybatisPlusConfig {
/**
* 添加分页插件
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// 如果配置多个插件, 注意分页插件要放在最后
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.POSTGRE_SQL));
return interceptor;
}
}

View File

@@ -0,0 +1,90 @@
package cn.yinlihupo.common.util;
/**
* 手机号工具类
* 提供手机号格式化、验证等通用方法
*/
public class PhoneUtils {
/**
* 中国大陆手机号前缀
*/
private static final String CHINA_MOBILE_PREFIX = "+86";
/**
* 去除手机号中的国家码前缀(如 +86
*
* @param phone 原始手机号
* @return 去除前缀后的手机号
*/
public static String normalizePhone(String phone) {
if (phone == null || phone.isEmpty()) {
return phone;
}
// 去除 +86 前缀
if (phone.startsWith(CHINA_MOBILE_PREFIX)) {
return phone.substring(3);
}
return phone;
}
/**
* 添加中国大陆手机号前缀(+86
*
* @param phone 手机号
* @return 添加前缀后的手机号
*/
public static String addChinaPrefix(String phone) {
if (phone == null || phone.isEmpty()) {
return phone;
}
// 如果已经有前缀,直接返回
if (phone.startsWith(CHINA_MOBILE_PREFIX)) {
return phone;
}
return CHINA_MOBILE_PREFIX + phone;
}
/**
* 验证手机号格式(中国大陆)
* 简单验证1开头11位数字
*
* @param phone 手机号
* @return true-格式正确, false-格式错误
*/
public static boolean isValidChinaPhone(String phone) {
if (phone == null || phone.isEmpty()) {
return false;
}
// 先去除前缀
String normalizedPhone = normalizePhone(phone);
// 验证1开头11位数字
return normalizedPhone.matches("^1[3-9]\\d{9}$");
}
/**
* 隐藏手机号中间4位
*
* @param phone 手机号
* @return 隐藏后的手机号138****8888
*/
public static String maskPhone(String phone) {
if (phone == null || phone.isEmpty()) {
return phone;
}
String normalizedPhone = normalizePhone(phone);
if (normalizedPhone.length() != 11) {
return phone;
}
return normalizedPhone.substring(0, 3) + "****" + normalizedPhone.substring(7);
}
}

View File

@@ -14,6 +14,7 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import java.time.LocalDateTime;
@@ -42,15 +43,21 @@ public class UserRoleController {
@RequestParam(defaultValue = "1") Integer pageNum,
@RequestParam(defaultValue = "10") Integer pageSize,
@RequestParam(required = false) String keyword) {
Page<SysUser> page = new Page<>(pageNum, pageSize);
List<SysUser> users = userMapper.selectPageList(null, null, keyword);
// 手动设置分页结果
page.setRecords(users);
page.setTotal(users.size());
return ResultUtils.success("查询成功", page);
// 使用MyBatis-Plus分页插件将page作为第一个参数传入
Page<SysUser> resultPage = userMapper.selectPage(page, new LambdaQueryWrapper<SysUser>()
.eq(SysUser::getDeleted, 0)
.and(StringUtils.hasText(keyword), qw -> qw
.like(SysUser::getUsername, keyword)
.or()
.like(SysUser::getRealName, keyword)
.or()
.like(SysUser::getPhone, keyword)
)
.orderByDesc(SysUser::getCreateTime));
return ResultUtils.success("查询成功", resultPage);
}
/**

View File

@@ -5,6 +5,7 @@ import cn.hutool.http.HttpResponse;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import cn.yinlihupo.common.config.FeishuConfig;
import cn.yinlihupo.common.util.PhoneUtils;
import cn.yinlihupo.domain.entity.SysUser;
import cn.yinlihupo.mapper.SysPermissionMapper;
import cn.yinlihupo.mapper.SysUserMapper;
@@ -84,6 +85,9 @@ public class FeishuAuthServiceImpl implements FeishuAuthService {
String email = userInfo.getStr("email");
String openId = userInfo.getStr("open_id");
// 去除手机号前缀 +86
phone = PhoneUtils.normalizePhone(phone);
log.info("飞书用户信息: phone={}, name={}, openId={}", phone, realName, openId);
// 5. 根据手机号获取或创建用户