feat(admin-server): 新增客户文件上传接口及客户信息管理功能

This commit is contained in:
FalingCliff 2025-06-15 14:57:44 +08:00
parent b5fb8071cc
commit 0273f753c5
18 changed files with 361 additions and 86 deletions

View File

@ -0,0 +1,13 @@
package com.example.admin_server.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Data
@Component
@ConfigurationProperties(prefix = "file")
public class FileUploadProperties {
private String uploadDir;
private String urlPrefix;
}

View File

@ -35,16 +35,7 @@ public class SwaggerConfig {
} }
@Bean @Bean
public Docket employeeApi() { protected ApiInfo apiInfo() {
return new Docket(DocumentationType.OAS_30)
.groupName("员工端")
.select()
.apis(RequestHandlerSelectors.basePackage("com.example.admin_server.controller.employee"))
.paths(PathSelectors.ant("/api/employee/**"))
.build();
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder() return new ApiInfoBuilder()
.title("后台管理接口文档") .title("后台管理接口文档")
.description("接口文档说明") .description("接口文档说明")

View File

@ -4,7 +4,9 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.example.admin_server.common.Result; import com.example.admin_server.common.Result;
import com.example.admin_server.enums.ResultCode; import com.example.admin_server.enums.ResultCode;
import com.example.admin_server.mapper.AdminMapper; import com.example.admin_server.mapper.AdminMapper;
import com.example.admin_server.model.dto.AdminUpdateMeDTO;
import com.example.admin_server.model.dto.LoginDTO; import com.example.admin_server.model.dto.LoginDTO;
import com.example.admin_server.model.dto.UpdatePassword;
import com.example.admin_server.model.entity.Admin; import com.example.admin_server.model.entity.Admin;
import com.example.admin_server.utils.JwtUtil; import com.example.admin_server.utils.JwtUtil;
import io.jsonwebtoken.Claims; import io.jsonwebtoken.Claims;
@ -88,24 +90,23 @@ public class AdminAuthController {
if (!StringUtils.hasText(token)) { if (!StringUtils.hasText(token)) {
return Result.of(ResultCode.UNAUTHORIZED, "缺少 token"); return Result.of(ResultCode.UNAUTHORIZED, "缺少 token");
} }
Optional<Claims> claimsOpt = jwtUtil.parseToken(token); Optional<Claims> claimsOpt = jwtUtil.parseToken(token);
if (!claimsOpt.isPresent() || jwtUtil.isTokenExpired(token)) { if (!claimsOpt.isPresent() || jwtUtil.isTokenExpired(token)) {
return Result.of(ResultCode.UNAUTHORIZED, "token 无效或已过期"); return Result.of(ResultCode.UNAUTHORIZED, "token 无效或已过期");
} }
Claims claims = claimsOpt.get(); Claims claims = claimsOpt.get();
Map<String, Object> userInfo = new HashMap<>(); Map<String, Object> userInfo = new HashMap<>();
Admin admin = adminMapper.selectById((Integer) claims.get("id"));
userInfo.put("userId", String.valueOf(claims.get("id"))); userInfo.put("userId", String.valueOf(claims.get("id")));
userInfo.put("userName", claims.get("username")); userInfo.put("userName", claims.get("username"));
userInfo.put("userInfo", admin);
userInfo.put("roles", new String[]{"R_SUPER"}); userInfo.put("roles", new String[]{"R_SUPER"});
userInfo.put("buttons", new String[]{"B_CODE1", "B_CODE2", "B_CODE3"}); userInfo.put("buttons", new String[]{"B_CODE1", "B_CODE2", "B_CODE3"});
return Result.ok(userInfo); return Result.ok(userInfo);
} }
// 获取 Token RefreshToken
private Result<?> getResult(Map<String, Object> data) { private Result<?> getResult(Map<String, Object> data) {
String newToken = jwtUtil.generateToken(data); String newToken = jwtUtil.generateToken(data);
String newRefreshToken = jwtUtil.generateRefreshToken(data); String newRefreshToken = jwtUtil.generateRefreshToken(data);
@ -116,4 +117,52 @@ public class AdminAuthController {
return Result.ok(tokenMap); return Result.ok(tokenMap);
} }
@PostMapping("/updatePassword")
@ApiOperation("修改密码")
public Result<?> updatePassword(
@RequestHeader("authorization") String token,
@RequestBody UpdatePassword updatePassword) {
if (!StringUtils.hasText(token)) {
return Result.of(ResultCode.UNAUTHORIZED, "缺少 token");
}
Optional<Claims> claimsOpt = jwtUtil.parseToken(token);
if (!claimsOpt.isPresent() || jwtUtil.isTokenExpired(token)) {
return Result.of(ResultCode.UNAUTHORIZED, "token 无效或已过期");
}
Claims claims = claimsOpt.get();
Integer adminId = (Integer) claims.get("id");
Admin admin = adminMapper.selectById(adminId);
String encryptedOldPassword = DigestUtils.md5DigestAsHex(updatePassword.getOldPassword().getBytes());
if (!admin.getPassword().equals(encryptedOldPassword)) {
return Result.of(ResultCode.UNAUTHORIZED, "旧密码不正确");
}
String encryptedNewPassword = DigestUtils.md5DigestAsHex(updatePassword.getNewPassword().getBytes());
admin.setPassword(encryptedNewPassword);
adminMapper.updateById(admin);
return Result.ok("密码修改成功");
}
@PostMapping("/updateProfile")
@ApiOperation("修改个人信息")
public Result<?> updateProfile(
@RequestHeader("authorization") String token,
@RequestBody AdminUpdateMeDTO adminUpdateMeDTO) {
if (!StringUtils.hasText(token)) {
return Result.of(ResultCode.UNAUTHORIZED, "缺少 token");
}
Optional<Claims> claimsOpt = jwtUtil.parseToken(token);
if (!claimsOpt.isPresent() || jwtUtil.isTokenExpired(token)) {
return Result.of(ResultCode.UNAUTHORIZED, "token 无效或已过期");
}
Claims claims = claimsOpt.get();
Integer adminId = (Integer) claims.get("id");
Admin admin = adminMapper.selectById(adminId);
admin.setNickname(adminUpdateMeDTO.getNickname());
admin.setAvatar(adminUpdateMeDTO.getAvatar());
admin.setEmail(adminUpdateMeDTO.getEmail());
admin.setPhone(adminUpdateMeDTO.getPhone());
adminMapper.updateById(admin);
return Result.ok(admin);
}
} }

View File

@ -0,0 +1,29 @@
package com.example.admin_server.controller.admin;
import com.example.admin_server.common.Result;
import com.example.admin_server.service.FileStorageService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
@RestController
@RequestMapping("/api/admin/upload")
@RequiredArgsConstructor
@Api(tags = {"上传接口"})
public class AdminFileUploadController {
private final FileStorageService fileStorageService;
@PostMapping
@ApiOperation(value = "上传接口")
public Result<String> uploadSingle(@RequestParam MultipartFile file) throws IOException {
return Result.ok(fileStorageService.store(file));
}
}

View File

@ -1,24 +0,0 @@
package com.example.admin_server.controller.client;
import com.example.admin_server.config.AppConfig;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/api/client")
@Api(tags = {"ClientMain"})
@RequiredArgsConstructor
public class ClientMainController {
private final AppConfig appConfig;
@GetMapping("/welcome")
@ApiOperation(value = "Hello client")
public String welcome(){
return "Hello client" + appConfig.getEnvName();
}
}

View File

@ -1,19 +1,58 @@
package com.example.admin_server.controller.client; package com.example.admin_server.controller.client;
import org.springframework.web.bind.annotation.RequestMapping; import cn.hutool.core.bean.BeanUtil;
import org.springframework.web.bind.annotation.RestController; import com.example.admin_server.common.Result;
import com.example.admin_server.enums.ResultCode;
import com.example.admin_server.model.dto.CustomerUpdateDTO;
import com.example.admin_server.model.entity.Customer;
import com.example.admin_server.model.vo.CustomerVO;
import com.example.admin_server.service.ICustomerService;
import com.example.admin_server.utils.JwtUtil;
import io.jsonwebtoken.Claims;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.Optional;
/** /**
* <p> * <p>
* 前端控制器 * 前端控制器
* </p> * </p>
* *
* @author FallingCliff * @author FallingCliff
* @since 2025-05-24 * @since 2025-05-24
*/ */
@RestController @RestController
@RequestMapping("/api/client/customer") @RequestMapping("/api/client/user")
@RequiredArgsConstructor
@Api(tags = {"个人信息管理"})
public class CustomerController { public class CustomerController {
private final ICustomerService iCustomerService;
private final JwtUtil jwtUtil;
@GetMapping("/info")
@ApiOperation("获取个人信息")
public Result<CustomerVO> getUserInfo(@RequestHeader("assessToken") String token) {
Optional<Claims> claimsOpt = jwtUtil.parseToken(token);
if (!claimsOpt.isPresent() || jwtUtil.isTokenExpired(token)) {
return Result.of(ResultCode.UNAUTHORIZED, "token 无效或已过期");
}
Claims claims = claimsOpt.get();
Integer userId = (Integer) claims.get("id");
Customer customer = iCustomerService.getById(userId);
CustomerVO customerVO = BeanUtil.copyProperties(customer, CustomerVO.class);
return Result.ok(customerVO);
}
@ApiOperation("修改个人信息")
@PutMapping("/edit")
public Result<Boolean> addCustomer(@Validated @RequestBody CustomerUpdateDTO customerUpdateDTO) {
Customer customer = BeanUtil.copyProperties(customerUpdateDTO, Customer.class);
return Result.ok(iCustomerService.updateById(customer));
}
} }

View File

@ -0,0 +1,29 @@
package com.example.admin_server.controller.client;
import com.example.admin_server.common.Result;
import com.example.admin_server.service.FileStorageService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
@RestController
@RequestMapping("/api/client/upload")
@RequiredArgsConstructor
@Api(tags = {"上传接口"})
public class CustomerFileUploadController {
private final FileStorageService fileStorageService;
@PostMapping
@ApiOperation(value = "上传接口")
public Result<String> uploadSingle(@RequestParam MultipartFile file) throws IOException {
return Result.ok(fileStorageService.store(file));
}
}

View File

@ -1,11 +1,13 @@
package com.example.admin_server.controller.client; package com.example.admin_server.controller.client;
import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.example.admin_server.common.Result; import com.example.admin_server.common.Result;
import com.example.admin_server.config.WxConfig; import com.example.admin_server.config.WxConfig;
import com.example.admin_server.model.dto.WxLoginDTO; import com.example.admin_server.model.dto.WxLoginDTO;
import com.example.admin_server.model.entity.Customer; import com.example.admin_server.model.entity.Customer;
import com.example.admin_server.model.vo.CustomerVO;
import com.example.admin_server.service.ICustomerService; import com.example.admin_server.service.ICustomerService;
import com.example.admin_server.utils.JwtUtil; import com.example.admin_server.utils.JwtUtil;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;
@ -68,7 +70,7 @@ public class WxLoginController {
.setSessionKey(sessionKey) .setSessionKey(sessionKey)
.setUnionid(unionid) .setUnionid(unionid)
.setNickname("微信用户") // 默认昵称可后续完善 .setNickname("微信用户") // 默认昵称可后续完善
.setAvatarUrl(null) .setAvatar(null)
.setCreateTime(LocalDateTime.now()) .setCreateTime(LocalDateTime.now())
.setUpdateTime(LocalDateTime.now()); .setUpdateTime(LocalDateTime.now());
@ -86,12 +88,10 @@ public class WxLoginController {
claims.put("sessionKey", customer.getSessionKey()); claims.put("sessionKey", customer.getSessionKey());
claims.put("openid", customer.getOpenid()); claims.put("openid", customer.getOpenid());
String token = jwtUtil.generateToken(claims); String token = jwtUtil.generateToken(claims);
CustomerVO customerVO = BeanUtil.copyProperties(customer, CustomerVO.class);
Map<String, Object> resultData = new HashMap<>(); Map<String, Object> resultData = new HashMap<>();
resultData.put("token", token); resultData.put("token", token);
resultData.put("openid", openid); resultData.put("userInfo", customerVO);
resultData.put("nickname", customer.getNickname());
resultData.put("avatar", customer.getAvatarUrl());
return Result.ok("登录成功", resultData); return Result.ok("登录成功", resultData);
} }
} }

View File

@ -1,24 +0,0 @@
package com.example.admin_server.controller.employee;
import com.example.admin_server.config.AppConfig;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/api/employee")
@Api(tags = {"EmployeeMain"})
@RequiredArgsConstructor
public class EmployeeMainController {
private final AppConfig appConfig;
@GetMapping("/welcome")
@ApiOperation(value = "Hello employee")
public String welcome() {
return "Hello employee" + appConfig.getEnvName();
}
}

View File

@ -0,0 +1,22 @@
package com.example.admin_server.model.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
@ApiModel(value="管理员更新对象", description="用于更新现有管理员信息的数据传输对象")
public class AdminUpdateMeDTO {
@ApiModelProperty(value = "昵称")
private String nickname;
@ApiModelProperty(value = "邮箱")
private String email;
@ApiModelProperty(value = "手机号")
private String phone;
@ApiModelProperty(value = "头像")
private String avatar;
}

View File

@ -0,0 +1,29 @@
package com.example.admin_server.model.dto;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
public class CustomerUpdateDTO {
@ApiModelProperty(value = "主键ID")
private Integer id;
@ApiModelProperty(value = "用户名")
private String username;
@ApiModelProperty(value = "用户昵称")
private String nickname;
@ApiModelProperty(value = "头像URL")
private String avatar;
@ApiModelProperty(value = "邮箱")
private String email;
@ApiModelProperty(value = "性别")
private String sex;
@ApiModelProperty(value = "手机号(后续绑定时)")
private String phone;
}

View File

@ -0,0 +1,18 @@
package com.example.admin_server.model.dto;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotBlank;
@Data
public class UpdatePassword {
@ApiModelProperty(value = "旧密码")
@NotBlank(message = "旧密码不能为空")
private String oldPassword;
@ApiModelProperty(value = "新密码")
@NotBlank(message = "新密码不能为空")
private String newPassword;
}

View File

@ -1,10 +1,6 @@
package com.example.admin_server.model.entity; package com.example.admin_server.model.entity;
import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.*;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.annotation.TableLogic;
import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModelProperty;
import lombok.Data; import lombok.Data;
@ -33,7 +29,7 @@ public class Admin implements Serializable {
@ApiModelProperty(value = "主键ID") @ApiModelProperty(value = "主键ID")
@TableId(value = "id", type = IdType.AUTO) @TableId(value = "id", type = IdType.AUTO)
private Long id; private Integer id;
@ApiModelProperty(value = "用户名") @ApiModelProperty(value = "用户名")
@TableField("username") @TableField("username")

View File

@ -1,10 +1,6 @@
package com.example.admin_server.model.entity; package com.example.admin_server.model.entity;
import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.*;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.annotation.TableLogic;
import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModelProperty;
import lombok.Data; import lombok.Data;
@ -33,7 +29,7 @@ public class Customer implements Serializable {
@ApiModelProperty(value = "主键ID") @ApiModelProperty(value = "主键ID")
@TableId(value = "id", type = IdType.AUTO) @TableId(value = "id", type = IdType.AUTO)
private Long id; private Integer id;
@ApiModelProperty(value = "微信openid") @ApiModelProperty(value = "微信openid")
@TableField("openid") @TableField("openid")
@ -60,8 +56,8 @@ public class Customer implements Serializable {
private String nickname; private String nickname;
@ApiModelProperty(value = "头像URL") @ApiModelProperty(value = "头像URL")
@TableField("avatar_url") @TableField("avatar")
private String avatarUrl; private String avatar;
@ApiModelProperty(value = "邮箱") @ApiModelProperty(value = "邮箱")
@TableField("email") @TableField("email")
@ -71,6 +67,14 @@ public class Customer implements Serializable {
@TableField("phone") @TableField("phone")
private String phone; private String phone;
@ApiModelProperty(value = "性别")
@TableField("sex")
private String sex;
@ApiModelProperty(value = "积分")
@TableField("points")
private Integer points;
@ApiModelProperty(value = "创建时间") @ApiModelProperty(value = "创建时间")
@TableField("create_time") @TableField("create_time")
private LocalDateTime createTime; private LocalDateTime createTime;

View File

@ -21,7 +21,7 @@ import java.time.LocalDateTime;
public class AdminVO implements Serializable { public class AdminVO implements Serializable {
@ApiModelProperty(value = "主键ID") @ApiModelProperty(value = "主键ID")
private Long id; private Integer id;
@ApiModelProperty(value = "用户名") @ApiModelProperty(value = "用户名")
private String username; private String username;

View File

@ -0,0 +1,49 @@
package com.example.admin_server.model.vo;
import com.baomidou.mybatisplus.annotation.TableField;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.time.LocalDateTime;
/**
* <p>
*
* </p>
*
* @author FallingCliff
* @since 2025-05-24
*/
@Data
public class CustomerVO {
@ApiModelProperty(value = "主键ID")
private Integer id;
@ApiModelProperty(value = "用户名")
private String username;
@ApiModelProperty(value = "用户昵称")
private String nickname;
@ApiModelProperty(value = "头像URL")
private String avatar;
@ApiModelProperty(value = "邮箱")
private String email;
@ApiModelProperty(value = "手机号(后续绑定时)")
private String phone;
@ApiModelProperty(value = "性别")
private String sex;
@ApiModelProperty(value = "积分")
private Integer points;
@ApiModelProperty(value = "创建时间")
private LocalDateTime createTime;
@ApiModelProperty(value = "更新时间")
@TableField("update_time")
private LocalDateTime updateTime;
}

View File

@ -0,0 +1,9 @@
package com.example.admin_server.service;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
public interface FileStorageService {
String store(MultipartFile file) throws IOException;
}

View File

@ -0,0 +1,46 @@
package com.example.admin_server.service.impl;
import com.example.admin_server.config.FileUploadProperties;
import com.example.admin_server.service.FileStorageService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.IOException;
import java.util.UUID;
@Service
@RequiredArgsConstructor
public class LocalFileStorageServiceImpl implements FileStorageService {
private final FileUploadProperties properties;
@Override
public String store(MultipartFile file) throws IOException {
if (file.isEmpty()) {
throw new IOException("文件为空");
}
String originalFilename = file.getOriginalFilename();
String extension = "";
if (originalFilename != null && originalFilename.contains(".")) {
extension = originalFilename.substring(originalFilename.lastIndexOf("."));
}
String uuid = UUID.randomUUID().toString();
String fileName = uuid + extension;
String fullPath = properties.getUploadDir() + fileName;
File dest = new File(fullPath);
File parentDir = dest.getParentFile();
if (!parentDir.exists() && !parentDir.mkdirs()) {
throw new IOException("无法创建目录: " + parentDir.getAbsolutePath());
}
file.transferTo(dest);
return properties.getUrlPrefix() + fileName;
}
}