feat(common): 添加通用工具类和配置优化
- 新增 JsonConfig,统一配置Long转字符串和LocalDateTime多格式支持 - 新增 MybatisPlusConfig,集成分页插件支持PostgreSQL数据库 - 新增 PhoneUtils,提供手机号格式化、验证及脱敏工具方法 - 优化 UserRoleController,使用MyBatis-Plus分页插件实现分页查询和模糊搜索 - FeishuAuthServiceImpl中调用PhoneUtils去除手机号+86前缀,确保手机号一致性处理
This commit is contained in:
60
src/main/java/cn/yinlihupo/common/config/JsonConfig.java
Normal file
60
src/main/java/cn/yinlihupo/common/config/JsonConfig.java
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
90
src/main/java/cn/yinlihupo/common/util/PhoneUtils.java
Normal file
90
src/main/java/cn/yinlihupo/common/util/PhoneUtils.java
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -14,6 +14,7 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
|||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
@@ -42,15 +43,21 @@ public class UserRoleController {
|
|||||||
@RequestParam(defaultValue = "1") Integer pageNum,
|
@RequestParam(defaultValue = "1") Integer pageNum,
|
||||||
@RequestParam(defaultValue = "10") Integer pageSize,
|
@RequestParam(defaultValue = "10") Integer pageSize,
|
||||||
@RequestParam(required = false) String keyword) {
|
@RequestParam(required = false) String keyword) {
|
||||||
|
|
||||||
Page<SysUser> page = new Page<>(pageNum, pageSize);
|
Page<SysUser> page = new Page<>(pageNum, pageSize);
|
||||||
List<SysUser> users = userMapper.selectPageList(null, null, keyword);
|
// 使用MyBatis-Plus分页插件,将page作为第一个参数传入
|
||||||
|
Page<SysUser> resultPage = userMapper.selectPage(page, new LambdaQueryWrapper<SysUser>()
|
||||||
// 手动设置分页结果
|
.eq(SysUser::getDeleted, 0)
|
||||||
page.setRecords(users);
|
.and(StringUtils.hasText(keyword), qw -> qw
|
||||||
page.setTotal(users.size());
|
.like(SysUser::getUsername, keyword)
|
||||||
|
.or()
|
||||||
return ResultUtils.success("查询成功", page);
|
.like(SysUser::getRealName, keyword)
|
||||||
|
.or()
|
||||||
|
.like(SysUser::getPhone, keyword)
|
||||||
|
)
|
||||||
|
.orderByDesc(SysUser::getCreateTime));
|
||||||
|
|
||||||
|
return ResultUtils.success("查询成功", resultPage);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import cn.hutool.http.HttpResponse;
|
|||||||
import cn.hutool.json.JSONObject;
|
import cn.hutool.json.JSONObject;
|
||||||
import cn.hutool.json.JSONUtil;
|
import cn.hutool.json.JSONUtil;
|
||||||
import cn.yinlihupo.common.config.FeishuConfig;
|
import cn.yinlihupo.common.config.FeishuConfig;
|
||||||
|
import cn.yinlihupo.common.util.PhoneUtils;
|
||||||
import cn.yinlihupo.domain.entity.SysUser;
|
import cn.yinlihupo.domain.entity.SysUser;
|
||||||
import cn.yinlihupo.mapper.SysPermissionMapper;
|
import cn.yinlihupo.mapper.SysPermissionMapper;
|
||||||
import cn.yinlihupo.mapper.SysUserMapper;
|
import cn.yinlihupo.mapper.SysUserMapper;
|
||||||
@@ -84,6 +85,9 @@ public class FeishuAuthServiceImpl implements FeishuAuthService {
|
|||||||
String email = userInfo.getStr("email");
|
String email = userInfo.getStr("email");
|
||||||
String openId = userInfo.getStr("open_id");
|
String openId = userInfo.getStr("open_id");
|
||||||
|
|
||||||
|
// 去除手机号前缀 +86
|
||||||
|
phone = PhoneUtils.normalizePhone(phone);
|
||||||
|
|
||||||
log.info("飞书用户信息: phone={}, name={}, openId={}", phone, realName, openId);
|
log.info("飞书用户信息: phone={}, name={}, openId={}", phone, realName, openId);
|
||||||
|
|
||||||
// 5. 根据手机号获取或创建用户
|
// 5. 根据手机号获取或创建用户
|
||||||
|
|||||||
Reference in New Issue
Block a user