Commit 3eb5fde9 by Lizh

增加用户图像上传处理逻辑

parent 742a8654
......@@ -6,6 +6,7 @@ import com.jomalls.custom.app.dto.system.*;
import com.jomalls.custom.app.vo.system.SysDeptVO;
import com.jomalls.custom.app.vo.system.SysRoleVO;
import com.jomalls.custom.app.vo.system.SysUserVO;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
import java.util.Map;
......@@ -45,7 +46,7 @@ public interface SysUserService {
*
* @param avatarUrl 头像URL
*/
void updateAvatar(String avatarUrl);
String updateAvatar(MultipartFile file);
/**
* 查询用户详情(含角色列表、岗位ID)
......
......@@ -110,7 +110,7 @@ public class SysLoginServiceImpl implements SysLoginService {
sysLogininforService.recordLogininfor(username, UserConstants.EXCEPTION, "用户名长度不在允许范围内");
throw new ServiceException("用户名长度不正确");
}
// IP 黑名单校验(与 custom-back 对齐)
// IP 黑名单校验
String blackIpList = sysConfigService.selectConfigByKey(UserConstants.BLACK_IP_KEY);
if (StringUtils.hasText(blackIpList)) {
String currentIp = getCurrentIp();
......@@ -180,9 +180,7 @@ public class SysLoginServiceImpl implements SysLoginService {
loginUser.setPermissions(permissions);
// 7. 生成 token
String token = tokenHandle.createToken(loginUser);
log.info("用户[{}]登录成功", username);
return token;
return tokenHandle.createToken(loginUser);
}
/**
......@@ -444,7 +442,7 @@ public class SysLoginServiceImpl implements SysLoginService {
}
/**
* 检查 IP 是否匹配黑名单(与 custom-back IpUtils.isMatchedIp 对齐)
* 检查 IP 是否匹配黑名单
* <p>
* 支持:精确匹配、通配符匹配(如 192.168.*.100)
*/
......
......@@ -12,8 +12,6 @@ import com.jomalls.custom.app.exception.ServiceException;
import com.jomalls.custom.app.service.system.SysRoleService;
import com.jomalls.custom.app.service.system.SysUserService;
import com.jomalls.custom.app.utils.BeanMapper;
import com.jomalls.custom.app.utils.CharsetKit;
import com.jomalls.custom.app.utils.UniqueId;
import com.jomalls.custom.app.vo.system.SysDeptVO;
import com.jomalls.custom.app.vo.system.SysRoleVO;
import com.jomalls.custom.app.vo.system.SysUserVO;
......@@ -21,13 +19,17 @@ import com.jomalls.custom.dal.entity.*;
import com.jomalls.custom.domain.service.system.*;
import com.jomalls.custom.security.LoginUser;
import com.jomalls.custom.security.SecurityUtils;
import com.jomalls.custom.utils.UniqueId;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.dromara.x.file.storage.core.FileInfo;
import org.dromara.x.file.storage.core.FileStorageService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;
import java.util.*;
import java.util.stream.Collectors;
......@@ -50,6 +52,7 @@ public class SysUserServiceImpl implements SysUserService {
private final SysDeptDomainService sysDeptDomainService;
private final SysPostDomainService sysPostDomainService;
private final PasswordEncoder passwordEncoder;
private final FileStorageService fileStorageService;
@Override
public IPage<SysUserVO> pageList(SysUserVO user, Page<SysUserVO> page) {
......@@ -107,9 +110,7 @@ public class SysUserServiceImpl implements SysUserService {
if (!StringUtils.hasText(user.getUserName())) {
throw new ServiceException("新增用户'" + user.getUserName() + "'失败,登录账号不能为空");
}
if (CharsetKit.containsChinese(user.getUserName())) {
throw new ServiceException("新增用户'" + user.getUserName() + "'失败,登录账号请使用英文字符");
}
// 用户名校验
long count = sysUserDomainService.count(
new LambdaQueryWrapper<SysUserEntity>().eq(SysUserEntity::getUserName, user.getUserName()));
......@@ -339,11 +340,17 @@ public class SysUserServiceImpl implements SysUserService {
}
@Override
public void updateAvatar(String avatarUrl) {
public String updateAvatar(MultipartFile file) {
LoginUser loginUser = SecurityUtils.getLoginUser();
if (loginUser == null) {
throw new ServiceException("未登录");
}
// 文件为空
if(file.isEmpty()) {
throw new ServiceException("上传图片异常,请联系管理员");
}
FileInfo fileInfo = fileStorageService.of(file).setPath("avatar/").upload();
String avatarUrl = fileInfo.getUrl();
SysUserEntity user = sysUserDomainService.getById(loginUser.getUserId());
if (user == null) {
throw new ServiceException("用户不存在");
......@@ -351,6 +358,7 @@ public class SysUserServiceImpl implements SysUserService {
user.setAvatar(avatarUrl);
sysUserDomainService.updateById(user);
log.info("用户头像已更新: userId={}", loginUser.getUserId());
return avatarUrl;
}
@Override
......@@ -363,7 +371,7 @@ public class SysUserServiceImpl implements SysUserService {
if (currentUser == null) {
throw new ServiceException("用户不存在");
}
// 只更新允许的字段(nickName/email/phonenumber/sex,与 custom-back 对齐
// 只更新允许的字段(nickName/email/phonenumber/sex)
if (StringUtils.hasText(user.getNickName())) currentUser.setNickName(user.getNickName());
if (StringUtils.hasText(user.getEmail())) currentUser.setEmail(user.getEmail());
if (StringUtils.hasText(user.getPhonenumber())) currentUser.setPhonenumber(user.getPhonenumber());
......
......@@ -2,6 +2,7 @@ package com.jomalls.custom.security;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.jomalls.custom.utils.UniqueId;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtException;
import io.jsonwebtoken.Jwts;
......@@ -239,7 +240,7 @@ public class TokenHandle {
* 用户权限、部门等全量信息存储在 Redis login_tokens:{uuid} 中。
*/
public String createToken(LoginUser loginUser) {
String uuid = java.util.UUID.randomUUID().toString().replace("-", "");
String uuid = UniqueId.generateUniqueId();
loginUser.setToken(uuid);
loginUser.setLoginTime(System.currentTimeMillis());
loginUser.setExpireTime(System.currentTimeMillis() + expireTime * 60 * 1000L);
......@@ -268,8 +269,8 @@ public class TokenHandle {
*/
private String buildJwtCompatibly(String uuid, LoginUser loginUser) {
try {
// Base64URL 编码(与 JJWT 0.9.1 TextCodec.BASE64URL 兼容,适配custom的ts服务 使用同一格式)
Base64.Encoder encoder = Base64.getUrlEncoder().withoutPadding();
log.info(JSON.toJSONString(loginUser));
// Header: {"alg":"HS512"}
String header = "{\"alg\":\"HS512\"}";
String headerBase64 = encoder.encodeToString(
......@@ -286,7 +287,12 @@ public class TokenHandle {
// JWT 24 小时硬过期(与 custom-back TOKEN_TIMEOUT = 86400000L 一致)
claims.put("exp", (System.currentTimeMillis() + 86400000L) / 1000);
String payload = JSON.toJSONString(claims);
// 使用 Jackson 序列化 claims,非 ASCII 字符转 \\uXXXX 转义
// 前端 atob() → JSON.parse() 无法正确解码 UTF-8 多字节字符
// \\uXXXX 全为 ASCII,前端可正常 parse
String payload = new com.fasterxml.jackson.databind.ObjectMapper()
.configure(com.fasterxml.jackson.core.json.JsonWriteFeature.ESCAPE_NON_ASCII.mappedFeature(), true)
.writeValueAsString(claims);
String payloadBase64 = encoder.encodeToString(
payload.getBytes(java.nio.charset.StandardCharsets.UTF_8));
......
package com.jomalls.custom.app.utils;
package com.jomalls.custom.utils;
import java.util.UUID;
......@@ -18,4 +18,12 @@ public class UniqueId {
public static String generateUniqueId(int length) {
return UUID.randomUUID().toString().replace("-", "").substring(START_INDEX, length);
}
/**
* 生成UUID
* @return
*/
public static String generateUniqueId() {
return UUID.randomUUID().toString().replace("-", "");
}
}
......@@ -34,18 +34,17 @@ import java.util.concurrent.atomic.AtomicReference;
@Service
@RequiredArgsConstructor
public class SaasAdminServiceImpl implements SaasAdminService {
/** 获取admin的分类树接口 */
private static final String GET_ALL_LIST_URL = "/api/manage/rest/baseCategoryInfo/all_list";
/** 根据id获取admin的分类接口 */
private static final String GET_PROPERTY_BY_IDS_URL = "/api/manage/rest/baseProperty/getByIds";
/** 获取国家代码接口 */
private static final String GET_ALL_COUNTRY_CODE_URL = "/api/manage/rest/getAllCountry";
private static final int DEFAULT_MAP_SIZE = 2;
/** 分类列表缓存 TTL(毫秒):5 分钟 */
private static final long CACHE_TTL_MS = 5 * 60 * 1000;
/** 国家代码缓存 TTL(毫秒):1 小时 */
private static final long COUNTRY_CODE_CACHE_TTL_MS = 60 * 60 * 1000;
/** 分类数 & 国家代码缓存 默认TTL(毫秒):1 小时 */
private static final long DEFAULT_CACHE_TTL_MS = 60 * 60 * 1000;
private final RemoteApiClient remoteApiClient;
......@@ -163,7 +162,7 @@ public class SaasAdminServiceImpl implements SaasAdminService {
String body = response.getBody();
List<CountryCodeModel> data = JSON.parseArray(body, CountryCodeModel.class);
if (!data.isEmpty()) {
countryCodeCache.set(new CacheEntry<>(data, COUNTRY_CODE_CACHE_TTL_MS));
countryCodeCache.set(new CacheEntry<>(data));
}
return data;
}
......@@ -185,7 +184,7 @@ public class SaasAdminServiceImpl implements SaasAdminService {
CacheEntry(T data) {
this.data = data;
this.expireAt = System.currentTimeMillis() + CACHE_TTL_MS;
this.expireAt = System.currentTimeMillis() + DEFAULT_CACHE_TTL_MS;
}
CacheEntry(T data, long ttlMs) {
......
package com.jomalls.custom.webapp.controller.system;
import com.jomalls.custom.app.constant.UserConstants;
import com.jomalls.custom.utils.UniqueId;
import com.jomalls.custom.utils.R;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
......@@ -15,10 +16,7 @@ import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
/**
......@@ -48,7 +46,7 @@ public class CaptchaController {
@Operation(summary = "生成验证码")
public R<Object> getCode() {
// 生成 UUID 标识
String uuid = UUID.randomUUID().toString().replace("-", "");
String uuid = UniqueId.generateUniqueId(UserConstants.INIT_PASSWORD_LENGTH);;
// 生成数学验证码
int a = new Random().nextInt(50) + 1;
......
......@@ -55,10 +55,7 @@ public class SysProfileController {
@Operation(summary = "更新当前用户头像")
@PostMapping("/avatar")
public AjaxResult avatar(@RequestParam("avatarfile") MultipartFile file) {
log.info("上传头像文件: {}", file.getOriginalFilename());
String avatarUrl = "/profile/avatar/" + file.getOriginalFilename();
sysUserService.updateAvatar(avatarUrl);
String avatarUrl = sysUserService.updateAvatar(file);
AjaxResult ajax = AjaxResult.success();
ajax.put("imgUrl", avatarUrl);
return ajax;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment