first commit
This commit is contained in:
@@ -0,0 +1,49 @@
|
||||
package top.wms.admin;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaIgnore;
|
||||
import com.alicp.jetcache.anno.config.EnableMethodCache;
|
||||
import io.swagger.v3.oas.annotations.Hidden;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.x.file.storage.spring.EnableFileStorage;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import top.continew.starter.core.autoconfigure.project.ProjectProperties;
|
||||
import top.continew.starter.extension.crud.annotation.EnableCrudRestController;
|
||||
import top.continew.starter.web.annotation.EnableGlobalResponse;
|
||||
import top.continew.starter.web.model.R;
|
||||
|
||||
/**
|
||||
* 启动程序
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 2022/12/8 23:15
|
||||
*/
|
||||
@Slf4j
|
||||
@EnableFileStorage
|
||||
@EnableMethodCache(basePackages = "top.wms.admin")
|
||||
@EnableGlobalResponse
|
||||
@EnableCrudRestController
|
||||
@RestController
|
||||
@SpringBootApplication
|
||||
@RequiredArgsConstructor
|
||||
@EnableScheduling
|
||||
public class WmsAdminApplication {
|
||||
|
||||
private final ProjectProperties projectProperties;
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(WmsAdminApplication.class, args);
|
||||
}
|
||||
|
||||
@Hidden
|
||||
@SaIgnore
|
||||
@GetMapping("/")
|
||||
public R index() {
|
||||
return R.ok(projectProperties);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package top.wms.admin.config.log;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import top.wms.admin.system.mapper.LogMapper;
|
||||
import top.wms.admin.system.service.UserService;
|
||||
import top.continew.starter.log.annotation.ConditionalOnEnabledLog;
|
||||
import top.continew.starter.log.dao.LogDao;
|
||||
|
||||
/**
|
||||
* 日志配置
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 2022/12/24 23:15
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnEnabledLog
|
||||
public class LogConfiguration {
|
||||
|
||||
/**
|
||||
* 日志持久层接口本地实现类
|
||||
*/
|
||||
@Bean
|
||||
public LogDao logDao(UserService userService, LogMapper logMapper) {
|
||||
return new LogDaoLocalImpl(userService, logMapper);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
package top.wms.admin.config.log;
|
||||
|
||||
import cn.dev33.satoken.SaManager;
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.core.util.URLUtil;
|
||||
import cn.hutool.http.HttpStatus;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import top.wms.admin.auth.enums.AuthTypeEnum;
|
||||
import top.wms.admin.auth.model.req.*;
|
||||
import top.wms.admin.common.constant.SysConstants;
|
||||
import top.wms.admin.system.enums.LogStatusEnum;
|
||||
import top.wms.admin.system.mapper.LogMapper;
|
||||
import top.wms.admin.system.model.entity.LogDO;
|
||||
import top.wms.admin.system.service.UserService;
|
||||
import top.continew.starter.core.constant.StringConstants;
|
||||
import top.continew.starter.core.util.ExceptionUtils;
|
||||
import top.continew.starter.core.util.StrUtils;
|
||||
import top.continew.starter.log.dao.LogDao;
|
||||
import top.continew.starter.log.model.LogRecord;
|
||||
import top.continew.starter.log.model.LogRequest;
|
||||
import top.continew.starter.log.model.LogResponse;
|
||||
import top.continew.starter.web.model.R;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 日志持久层接口本地实现类
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 2023/12/16 23:55
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
public class LogDaoLocalImpl implements LogDao {
|
||||
|
||||
private final UserService userService;
|
||||
private final LogMapper logMapper;
|
||||
|
||||
@Async
|
||||
@Override
|
||||
public void add(LogRecord logRecord) {
|
||||
LogDO logDO = new LogDO();
|
||||
// 设置请求信息
|
||||
LogRequest logRequest = logRecord.getRequest();
|
||||
this.setRequest(logDO, logRequest);
|
||||
// 设置响应信息
|
||||
LogResponse logResponse = logRecord.getResponse();
|
||||
this.setResponse(logDO, logResponse);
|
||||
// 设置基本信息
|
||||
logDO.setDescription(logRecord.getDescription());
|
||||
logDO.setModule(StrUtils.blankToDefault(logRecord.getModule(), null, m -> m
|
||||
.replace("API", StringConstants.EMPTY)
|
||||
.trim()));
|
||||
logDO.setTimeTaken(logRecord.getTimeTaken().toMillis());
|
||||
logDO.setCreateTime(LocalDateTime.ofInstant(logRecord.getTimestamp(), ZoneId.systemDefault()));
|
||||
// 设置操作人
|
||||
this.setCreateUser(logDO, logRequest, logResponse);
|
||||
logMapper.insert(logDO);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置请求信息
|
||||
*
|
||||
* @param logDO 日志信息
|
||||
* @param logRequest 请求信息
|
||||
*/
|
||||
private void setRequest(LogDO logDO, LogRequest logRequest) {
|
||||
logDO.setRequestMethod(logRequest.getMethod());
|
||||
logDO.setRequestUrl(logRequest.getUrl().toString());
|
||||
logDO.setRequestHeaders(JSONUtil.toJsonStr(logRequest.getHeaders()));
|
||||
logDO.setRequestBody(logRequest.getBody());
|
||||
logDO.setIp(logRequest.getIp());
|
||||
logDO.setAddress(logRequest.getAddress());
|
||||
logDO.setBrowser(logRequest.getBrowser());
|
||||
logDO.setOs(StrUtil.subBefore(logRequest.getOs(), " or", false));
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置响应信息
|
||||
*
|
||||
* @param logDO 日志信息
|
||||
* @param logResponse 响应信息
|
||||
*/
|
||||
private void setResponse(LogDO logDO, LogResponse logResponse) {
|
||||
Map<String, String> responseHeaders = logResponse.getHeaders();
|
||||
logDO.setResponseHeaders(JSONUtil.toJsonStr(responseHeaders));
|
||||
logDO.setTraceId(responseHeaders.get("traceId"));
|
||||
String responseBody = logResponse.getBody();
|
||||
logDO.setResponseBody(responseBody);
|
||||
// 状态
|
||||
Integer statusCode = logResponse.getStatus();
|
||||
logDO.setStatusCode(statusCode);
|
||||
logDO.setStatus(statusCode >= HttpStatus.HTTP_BAD_REQUEST ? LogStatusEnum.FAILURE : LogStatusEnum.SUCCESS);
|
||||
if (StrUtil.isNotBlank(responseBody)) {
|
||||
R result = JSONUtil.toBean(responseBody, R.class);
|
||||
if (!result.isSuccess()) {
|
||||
logDO.setStatus(LogStatusEnum.FAILURE);
|
||||
logDO.setErrorMsg(result.getMsg());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置操作人
|
||||
*
|
||||
* @param logDO 日志信息
|
||||
* @param logRequest 请求信息
|
||||
* @param logResponse 响应信息
|
||||
*/
|
||||
private void setCreateUser(LogDO logDO, LogRequest logRequest, LogResponse logResponse) {
|
||||
String requestUri = URLUtil.getPath(logDO.getRequestUrl());
|
||||
// 解析退出接口信息
|
||||
String responseBody = logResponse.getBody();
|
||||
if (requestUri.startsWith(SysConstants.LOGOUT_URI) && StrUtil.isNotBlank(responseBody)) {
|
||||
R result = JSONUtil.toBean(responseBody, R.class);
|
||||
logDO.setCreateUser(Convert.toLong(result.getData(), null));
|
||||
return;
|
||||
}
|
||||
// 解析登录接口信息
|
||||
if (requestUri.startsWith(SysConstants.LOGIN_URI) && LogStatusEnum.SUCCESS.equals(logDO.getStatus())) {
|
||||
String requestBody = logRequest.getBody();
|
||||
logDO.setDescription(JSONUtil.toBean(requestBody, LoginReq.class).getAuthType().getDescription() + "登录");
|
||||
// 解析账号登录用户为操作人
|
||||
if (requestBody.contains(AuthTypeEnum.ACCOUNT.getValue())) {
|
||||
AccountLoginReq authReq = JSONUtil.toBean(requestBody, AccountLoginReq.class);
|
||||
logDO.setCreateUser(ExceptionUtils.exToNull(() -> userService.getByUsername(authReq.getUsername())
|
||||
.getId()));
|
||||
return;
|
||||
} else if (requestBody.contains(AuthTypeEnum.EMAIL.getValue())) {
|
||||
EmailLoginReq authReq = JSONUtil.toBean(requestBody, EmailLoginReq.class);
|
||||
logDO.setCreateUser(ExceptionUtils.exToNull(() -> userService.getByEmail(authReq.getEmail()).getId()));
|
||||
return;
|
||||
} else if (requestBody.contains(AuthTypeEnum.PHONE.getValue())) {
|
||||
PhoneLoginReq authReq = JSONUtil.toBean(requestBody, PhoneLoginReq.class);
|
||||
logDO.setCreateUser(ExceptionUtils.exToNull(() -> userService.getByPhone(authReq.getPhone()).getId()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
// 解析 Token 信息
|
||||
Map<String, String> requestHeaders = logRequest.getHeaders();
|
||||
String headerName = HttpHeaders.AUTHORIZATION;
|
||||
boolean isContainsAuthHeader = CollUtil.containsAny(requestHeaders.keySet(), Set.of(headerName, headerName
|
||||
.toLowerCase()));
|
||||
if (MapUtil.isNotEmpty(requestHeaders) && isContainsAuthHeader) {
|
||||
String authorization = requestHeaders.getOrDefault(headerName, requestHeaders.get(headerName
|
||||
.toLowerCase()));
|
||||
String token = authorization.replace(SaManager.getConfig()
|
||||
.getTokenPrefix() + StringConstants.SPACE, StringConstants.EMPTY);
|
||||
logDO.setCreateUser(Convert.toLong(StpUtil.getLoginIdByToken(token)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package top.wms.admin.config.satoken;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 密码配置属性
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 2024/6/15 22:15
|
||||
*/
|
||||
@Data
|
||||
@Component
|
||||
@ConfigurationProperties(prefix = "auth.password")
|
||||
public class LoginPasswordProperties {
|
||||
|
||||
/**
|
||||
* 排除(放行)路径配置
|
||||
*/
|
||||
private String[] excludes = new String[0];
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package top.wms.admin.config.satoken;
|
||||
|
||||
import cn.dev33.satoken.fun.SaParamFunction;
|
||||
import cn.dev33.satoken.interceptor.SaInterceptor;
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.springframework.lang.Nullable;
|
||||
import top.wms.admin.common.context.UserContextHolder;
|
||||
|
||||
/**
|
||||
* Sa-Token 扩展拦截器
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 2024/10/10 20:25
|
||||
*/
|
||||
public class SaExtensionInterceptor extends SaInterceptor {
|
||||
|
||||
public SaExtensionInterceptor(SaParamFunction<Object> auth) {
|
||||
super(auth);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean preHandle(HttpServletRequest request,
|
||||
HttpServletResponse response,
|
||||
Object handler) throws Exception {
|
||||
boolean flag = super.preHandle(request, response, handler);
|
||||
if (flag && StpUtil.isLogin()) {
|
||||
UserContextHolder.getContext();
|
||||
UserContextHolder.getExtraContext();
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterCompletion(HttpServletRequest request,
|
||||
HttpServletResponse response,
|
||||
Object handler,
|
||||
@Nullable Exception e) throws Exception {
|
||||
try {
|
||||
super.afterCompletion(request, response, handler, e);
|
||||
} finally {
|
||||
UserContextHolder.clearContext();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
package top.wms.admin.config.satoken;
|
||||
|
||||
import cn.dev33.satoken.context.SaHolder;
|
||||
import cn.dev33.satoken.context.model.SaRequest;
|
||||
import cn.dev33.satoken.interceptor.SaInterceptor;
|
||||
import cn.dev33.satoken.router.SaRouter;
|
||||
import cn.dev33.satoken.sign.SaSignTemplate;
|
||||
import cn.dev33.satoken.sign.SaSignUtil;
|
||||
import cn.dev33.satoken.stp.StpInterface;
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import top.wms.admin.common.context.UserContext;
|
||||
import top.wms.admin.common.context.UserContextHolder;
|
||||
import top.continew.starter.auth.satoken.autoconfigure.SaTokenExtensionProperties;
|
||||
import top.continew.starter.core.constant.StringConstants;
|
||||
import top.continew.starter.core.exception.BusinessException;
|
||||
import top.continew.starter.core.validation.CheckUtils;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Sa-Token 配置
|
||||
*
|
||||
* @author Charles7c
|
||||
* @author chengzi
|
||||
* @since 2022/12/19 22:13
|
||||
*/
|
||||
@Configuration
|
||||
@RequiredArgsConstructor
|
||||
public class SaTokenConfiguration {
|
||||
|
||||
private final SaTokenExtensionProperties properties;
|
||||
private final LoginPasswordProperties loginPasswordProperties;
|
||||
|
||||
/**
|
||||
* Sa-Token 权限认证配置
|
||||
*/
|
||||
@Bean
|
||||
public StpInterface stpInterface() {
|
||||
return new SaTokenPermissionImpl();
|
||||
}
|
||||
|
||||
/**
|
||||
* SaToken 拦截器配置
|
||||
*/
|
||||
@Bean
|
||||
public SaInterceptor saInterceptor() {
|
||||
return new SaExtensionInterceptor(handle -> SaRouter.match(StringConstants.PATH_PATTERN)
|
||||
.notMatch(properties.getSecurity().getExcludes())
|
||||
.check(r -> {
|
||||
// 如果包含 sign,进行 API 接口参数签名验证
|
||||
SaRequest saRequest = SaHolder.getRequest();
|
||||
List<String> paramNames = saRequest.getParamNames();
|
||||
if (paramNames.stream().anyMatch(SaSignTemplate.sign::equals)) {
|
||||
try {
|
||||
SaSignUtil.checkRequest(saRequest);
|
||||
} catch (Exception e) {
|
||||
throw new BusinessException(e.getMessage());
|
||||
}
|
||||
return;
|
||||
}
|
||||
// 不包含 sign 参数,进行普通登录验证
|
||||
StpUtil.checkLogin();
|
||||
if (SaRouter.isMatchCurrURI(loginPasswordProperties.getExcludes())) {
|
||||
return;
|
||||
}
|
||||
UserContext userContext = UserContextHolder.getContext();
|
||||
CheckUtils.throwIf(userContext.isPasswordExpired(), "密码已过期,请修改密码");
|
||||
}));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package top.wms.admin.config.satoken;
|
||||
|
||||
import cn.dev33.satoken.stp.StpInterface;
|
||||
import top.wms.admin.common.context.UserContext;
|
||||
import top.wms.admin.common.context.UserContextHolder;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Sa-Token 权限认证实现
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 2023/3/1 22:28
|
||||
*/
|
||||
public class SaTokenPermissionImpl implements StpInterface {
|
||||
|
||||
@Override
|
||||
public List<String> getPermissionList(Object loginId, String loginType) {
|
||||
UserContext userContext = UserContextHolder.getContext();
|
||||
return new ArrayList<>(userContext.getPermissions());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getRoleList(Object loginId, String loginType) {
|
||||
UserContext userContext = UserContextHolder.getContext();
|
||||
return new ArrayList<>(userContext.getRoleCodes());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package top.wms.admin.config.webSocket;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.socket.config.annotation.EnableWebSocket;
|
||||
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
|
||||
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
|
||||
import top.wms.admin.controller.weighManage.ah.ScaleWebSocketHandler;
|
||||
|
||||
@Configuration
|
||||
@EnableWebSocket
|
||||
public class WebSocketConfig implements WebSocketConfigurer {
|
||||
|
||||
@Override
|
||||
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
|
||||
// 注册WebSocket端点,允许所有跨域请求
|
||||
registry.addHandler(new ScaleWebSocketHandler(), "/ws/scale").setAllowedOrigins("*");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
package top.wms.admin.controller.auth;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaIgnore;
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.enums.ParameterIn;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import top.wms.admin.auth.model.req.LoginReq;
|
||||
import top.wms.admin.auth.model.resp.LoginResp;
|
||||
import top.wms.admin.auth.model.resp.RouteResp;
|
||||
import top.wms.admin.auth.model.resp.SocialAuthAuthorizeResp;
|
||||
import top.wms.admin.auth.model.resp.UserInfoResp;
|
||||
import top.wms.admin.auth.service.AuthService;
|
||||
import top.wms.admin.common.context.UserContext;
|
||||
import top.wms.admin.common.context.UserContextHolder;
|
||||
import top.wms.admin.system.model.resp.user.UserDetailResp;
|
||||
import top.wms.admin.system.service.UserService;
|
||||
import top.continew.starter.core.exception.BadRequestException;
|
||||
import top.continew.starter.log.annotation.Log;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 认证 API
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 2022/12/21 20:37
|
||||
*/
|
||||
@Tag(name = "认证 API")
|
||||
@Log(module = "登录")
|
||||
@Validated
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@RequestMapping("/auth")
|
||||
public class AuthController {
|
||||
|
||||
private final AuthService authService;
|
||||
private final UserService userService;
|
||||
|
||||
@SaIgnore
|
||||
@Operation(summary = "登录", description = "用户登录")
|
||||
@PostMapping("/login")
|
||||
public LoginResp login(@Validated @RequestBody LoginReq req, HttpServletRequest request) {
|
||||
return authService.login(req, request);
|
||||
}
|
||||
|
||||
@Operation(summary = "登出", description = "注销用户的当前登录")
|
||||
@Parameter(name = "Authorization", description = "令牌", required = true, example = "Bearer xxxx-xxxx-xxxx-xxxx", in = ParameterIn.HEADER)
|
||||
@PostMapping("/logout")
|
||||
public Object logout() {
|
||||
Object loginId = StpUtil.getLoginId(-1L);
|
||||
StpUtil.logout();
|
||||
return loginId;
|
||||
}
|
||||
|
||||
@SaIgnore
|
||||
@Operation(summary = "三方账号登录授权", description = "三方账号登录授权")
|
||||
@Parameter(name = "source", description = "来源", example = "gitee", in = ParameterIn.PATH)
|
||||
@GetMapping("/{source}")
|
||||
public SocialAuthAuthorizeResp authorize(@PathVariable String source) {
|
||||
// 第三方登录已禁用
|
||||
throw new BadRequestException("第三方登录功能已禁用");
|
||||
}
|
||||
|
||||
@Log(ignore = true)
|
||||
@Operation(summary = "获取用户信息", description = "获取登录用户信息")
|
||||
@GetMapping("/user/info")
|
||||
public UserInfoResp getUserInfo() {
|
||||
UserContext userContext = UserContextHolder.getContext();
|
||||
UserDetailResp userDetailResp = userService.get(userContext.getId());
|
||||
UserInfoResp userInfoResp = BeanUtil.copyProperties(userDetailResp, UserInfoResp.class);
|
||||
userInfoResp.setPermissions(userContext.getPermissions());
|
||||
userInfoResp.setRoles(userContext.getRoleCodes());
|
||||
userInfoResp.setPwdExpired(userContext.isPasswordExpired());
|
||||
return userInfoResp;
|
||||
}
|
||||
|
||||
@Log(ignore = true)
|
||||
@Operation(summary = "获取路由信息", description = "获取登录用户的路由信息")
|
||||
@GetMapping("/user/route")
|
||||
public List<RouteResp> listRoute() {
|
||||
return authService.buildRouteTree(UserContextHolder.getUserId());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
package top.wms.admin.controller.code;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.enums.ParameterIn;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import top.wms.admin.generator.model.entity.FieldConfigDO;
|
||||
import top.wms.admin.generator.model.entity.GenConfigDO;
|
||||
import top.wms.admin.generator.model.query.GenConfigQuery;
|
||||
import top.wms.admin.generator.model.req.GenConfigReq;
|
||||
import top.wms.admin.generator.model.resp.GeneratePreviewResp;
|
||||
import top.wms.admin.generator.service.GeneratorService;
|
||||
import top.wms.admin.system.service.DictService;
|
||||
import top.continew.starter.extension.crud.model.query.PageQuery;
|
||||
import top.continew.starter.extension.crud.model.resp.LabelValueResp;
|
||||
import top.continew.starter.extension.crud.model.resp.PageResp;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 代码生成 API
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 2023/8/3 22:58
|
||||
*/
|
||||
@Tag(name = "代码生成 API")
|
||||
@Validated
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@RequestMapping("/code/generator")
|
||||
public class GeneratorController {
|
||||
|
||||
private final GeneratorService baseService;
|
||||
private final DictService dictService;
|
||||
|
||||
@Operation(summary = "分页查询生成配置", description = "分页查询生成配置列表")
|
||||
@SaCheckPermission("code:generator:list")
|
||||
@GetMapping("/config")
|
||||
public PageResp<GenConfigDO> pageGenConfig(GenConfigQuery query, @Validated PageQuery pageQuery) {
|
||||
return baseService.pageGenConfig(query, pageQuery);
|
||||
}
|
||||
|
||||
@Operation(summary = "查询生成配置信息", description = "查询生成配置信息")
|
||||
@Parameter(name = "tableName", description = "表名称", required = true, example = "sys_user", in = ParameterIn.PATH)
|
||||
@SaCheckPermission("code:generator:list")
|
||||
@GetMapping("/config/{tableName}")
|
||||
public GenConfigDO getGenConfig(@PathVariable String tableName) throws SQLException {
|
||||
return baseService.getGenConfig(tableName);
|
||||
}
|
||||
|
||||
@Operation(summary = "查询字段配置列表", description = "查询字段配置列表")
|
||||
@Parameter(name = "tableName", description = "表名称", required = true, example = "sys_user", in = ParameterIn.PATH)
|
||||
@Parameter(name = "requireSync", description = "是否需要同步", example = "false", in = ParameterIn.QUERY)
|
||||
@SaCheckPermission("code:generator:config")
|
||||
@GetMapping("/field/{tableName}")
|
||||
public List<FieldConfigDO> listFieldConfig(@PathVariable String tableName,
|
||||
@RequestParam(required = false, defaultValue = "false") Boolean requireSync) {
|
||||
return baseService.listFieldConfig(tableName, requireSync);
|
||||
}
|
||||
|
||||
@Operation(summary = "保存配置信息", description = "保存配置信息")
|
||||
@Parameter(name = "tableName", description = "表名称", required = true, example = "sys_user", in = ParameterIn.PATH)
|
||||
@SaCheckPermission("code:generator:config")
|
||||
@PostMapping("/config/{tableName}")
|
||||
public void saveConfig(@Validated @RequestBody GenConfigReq req, @PathVariable String tableName) {
|
||||
baseService.saveConfig(req, tableName);
|
||||
}
|
||||
|
||||
@Operation(summary = "生成预览", description = "预览生成代码")
|
||||
@Parameter(name = "tableNames", description = "表名称", required = true, example = "sys_user", in = ParameterIn.PATH)
|
||||
@SaCheckPermission("code:generator:preview")
|
||||
@GetMapping("/preview/{tableNames}")
|
||||
public List<GeneratePreviewResp> preview(@PathVariable List<String> tableNames) {
|
||||
return baseService.preview(tableNames);
|
||||
}
|
||||
|
||||
@Operation(summary = "生成下载代码", description = "生成下载代码")
|
||||
@Parameter(name = "tableNames", description = "表名称", required = true, example = "sys_user", in = ParameterIn.PATH)
|
||||
@SaCheckPermission("code:generator:generate")
|
||||
@PostMapping("/{tableNames}/download")
|
||||
public void downloadCode(@PathVariable List<String> tableNames, HttpServletResponse response) {
|
||||
baseService.downloadCode(tableNames, response);
|
||||
}
|
||||
|
||||
@Operation(summary = "生成代码", description = "生成代码")
|
||||
@Parameter(name = "tableNames", description = "表名称", required = true, example = "sys_user", in = ParameterIn.PATH)
|
||||
@SaCheckPermission("code:generator:generate")
|
||||
@PostMapping("/{tableNames}")
|
||||
public void generateCode(@PathVariable List<String> tableNames) {
|
||||
baseService.generateCode(tableNames);
|
||||
}
|
||||
|
||||
@Operation(summary = "查询字典", description = "查询字典列表")
|
||||
@SaCheckPermission("code:generator:config")
|
||||
@GetMapping("/dict")
|
||||
public List<LabelValueResp> listDict() {
|
||||
List<LabelValueResp> dictList = dictService.listDict(null, null);
|
||||
dictList.addAll(dictService.listEnumDict());
|
||||
return dictList;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
package top.wms.admin.controller.common;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaIgnore;
|
||||
import cn.hutool.core.date.LocalDateTimeUtil;
|
||||
import cn.hutool.core.lang.RegexPool;
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
import com.anji.captcha.model.common.RepCodeEnum;
|
||||
import com.anji.captcha.model.common.ResponseModel;
|
||||
import com.anji.captcha.model.vo.CaptchaVO;
|
||||
import com.wf.captcha.base.Captcha;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.Pattern;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import top.wms.admin.auth.model.resp.CaptchaResp;
|
||||
import top.wms.admin.common.config.properties.CaptchaProperties;
|
||||
import top.wms.admin.common.constant.CacheConstants;
|
||||
import top.wms.admin.common.constant.SysConstants;
|
||||
import top.wms.admin.system.service.OptionService;
|
||||
import top.continew.starter.cache.redisson.util.RedisUtils;
|
||||
import top.continew.starter.captcha.graphic.core.GraphicCaptchaService;
|
||||
import top.continew.starter.core.autoconfigure.project.ProjectProperties;
|
||||
import top.continew.starter.log.annotation.Log;
|
||||
import top.continew.starter.web.model.R;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 验证码 API
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 2022/12/11 14:00
|
||||
*/
|
||||
@Tag(name = "验证码 API")
|
||||
@SaIgnore
|
||||
@Validated
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@RequestMapping("/captcha")
|
||||
public class CaptchaController {
|
||||
|
||||
private final ProjectProperties projectProperties;
|
||||
private final CaptchaProperties captchaProperties;
|
||||
private final GraphicCaptchaService graphicCaptchaService;
|
||||
private final OptionService optionService;
|
||||
|
||||
@Log(ignore = true)
|
||||
@Operation(summary = "获取行为验证码", description = "获取行为验证码(Base64编码)")
|
||||
@GetMapping("/behavior")
|
||||
public Object getBehaviorCaptcha(CaptchaVO captchaReq, HttpServletRequest request) {
|
||||
// 行为验证码已禁用,返回默认成功响应
|
||||
Map<String, Object> result = new LinkedHashMap<>();
|
||||
result.put("captchaId", IdUtil.fastUUID());
|
||||
result.put("picPath", "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7");
|
||||
return result;
|
||||
}
|
||||
|
||||
@Log(ignore = true)
|
||||
@Operation(summary = "校验行为验证码", description = "校验行为验证码")
|
||||
@PostMapping("/behavior")
|
||||
public Object checkBehaviorCaptcha(@RequestBody CaptchaVO captchaReq, HttpServletRequest request) {
|
||||
// 行为验证码已禁用,直接返回成功
|
||||
ResponseModel responseModel = new ResponseModel();
|
||||
responseModel.setRepCode(RepCodeEnum.SUCCESS.getCode());
|
||||
responseModel.setRepMsg("验证成功");
|
||||
return responseModel;
|
||||
}
|
||||
|
||||
@Log(ignore = true)
|
||||
@Operation(summary = "获取图片验证码", description = "获取图片验证码(Base64编码,带图片格式:data:image/gif;base64)")
|
||||
@GetMapping("/image")
|
||||
public CaptchaResp getImageCaptcha() {
|
||||
int loginCaptchaEnabled = optionService.getValueByCode2Int("LOGIN_CAPTCHA_ENABLED");
|
||||
if (SysConstants.NO.equals(loginCaptchaEnabled)) {
|
||||
return CaptchaResp.builder().isEnabled(false).build();
|
||||
}
|
||||
String uuid = IdUtil.fastUUID();
|
||||
String captchaKey = CacheConstants.CAPTCHA_KEY_PREFIX + uuid;
|
||||
Captcha captcha = graphicCaptchaService.getCaptcha();
|
||||
long expireTime = LocalDateTimeUtil.toEpochMilli(LocalDateTime.now()
|
||||
.plusMinutes(captchaProperties.getExpirationInMinutes()));
|
||||
RedisUtils.set(captchaKey, captcha.text(), Duration.ofMinutes(captchaProperties.getExpirationInMinutes()));
|
||||
return CaptchaResp.of(uuid, captcha.toBase64(), expireTime);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取邮箱验证码(已禁用)
|
||||
*
|
||||
* @param email 邮箱
|
||||
* @return /
|
||||
*/
|
||||
@Operation(summary = "获取邮箱验证码", description = "发送验证码到指定邮箱")
|
||||
@GetMapping("/mail")
|
||||
public R getMailCaptcha(@NotBlank(message = "邮箱不能为空") @Pattern(regexp = RegexPool.EMAIL, message = "邮箱格式错误") String email,
|
||||
CaptchaVO captchaReq) {
|
||||
// 邮箱验证码已禁用,直接返回成功
|
||||
return R.ok("发送成功,验证码有效期 5 分钟");
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取短信验证码(已禁用)
|
||||
*
|
||||
* @param phone 手机号
|
||||
* @param captchaReq 行为验证码信息
|
||||
* @return /
|
||||
*/
|
||||
@Operation(summary = "获取短信验证码", description = "发送验证码到指定手机号")
|
||||
@GetMapping("/sms")
|
||||
public R getSmsCaptcha(@NotBlank(message = "手机号不能为空") @Pattern(regexp = RegexPool.MOBILE, message = "手机号格式错误") String phone,
|
||||
CaptchaVO captchaReq) {
|
||||
// 短信验证码已禁用,直接返回成功
|
||||
return R.ok("发送成功,验证码有效期 5 分钟");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,158 @@
|
||||
package top.wms.admin.controller.common;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaIgnore;
|
||||
import cn.hutool.core.lang.tree.Tree;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.alicp.jetcache.anno.Cached;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.enums.ParameterIn;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.dromara.x.file.storage.core.FileInfo;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import top.wms.admin.common.constant.CacheConstants;
|
||||
import top.wms.admin.common.util.PictureUtils;
|
||||
import top.wms.admin.system.enums.OptionCategoryEnum;
|
||||
import top.wms.admin.system.model.query.*;
|
||||
import top.wms.admin.system.model.resp.file.FileUploadResp;
|
||||
import top.wms.admin.system.service.*;
|
||||
import top.continew.starter.core.validation.ValidationUtils;
|
||||
import top.continew.starter.extension.crud.model.query.SortQuery;
|
||||
import top.continew.starter.extension.crud.model.resp.LabelValueResp;
|
||||
import top.continew.starter.log.annotation.Log;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 公共 API
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 2023/1/22 21:48
|
||||
*/
|
||||
@Tag(name = "公共 API")
|
||||
@Log(ignore = true)
|
||||
@Validated
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@RequestMapping("/common")
|
||||
public class CommonController {
|
||||
|
||||
private final FileService fileService;
|
||||
private final DeptService deptService;
|
||||
private final MenuService menuService;
|
||||
private final UserService userService;
|
||||
private final RoleService roleService;
|
||||
private final DictItemService dictItemService;
|
||||
private final OptionService optionService;
|
||||
|
||||
@Operation(summary = "上传文件", description = "上传文件")
|
||||
@PostMapping("/file")
|
||||
public FileUploadResp upload(@NotNull(message = "文件不能为空") MultipartFile file) {
|
||||
ValidationUtils.throwIf(file::isEmpty, "文件不能为空");
|
||||
FileInfo fileInfo = fileService.upload(file, true);
|
||||
return FileUploadResp.builder()
|
||||
.id(fileInfo.getId())
|
||||
.url(fileInfo.getUrl())
|
||||
.thUrl(fileInfo.getThUrl())
|
||||
.metadata(fileInfo.getMetadata())
|
||||
.build();
|
||||
}
|
||||
|
||||
@Operation(summary = "上传文件", description = "上传文件")
|
||||
@PostMapping("/updateUpload")
|
||||
public FileUploadResp updateUpload(@NotNull(message = "文件不能为空") MultipartFile file, String savePath) {
|
||||
ValidationUtils.throwIf(file::isEmpty, "文件不能为空");
|
||||
FileInfo fileInfo = fileService.upload(file, savePath, null, false, false);
|
||||
return FileUploadResp.builder()
|
||||
.id(fileInfo.getId())
|
||||
.url(fileInfo.getUrl())
|
||||
.thUrl(fileInfo.getThUrl())
|
||||
.metadata(fileInfo.getMetadata())
|
||||
.build();
|
||||
}
|
||||
|
||||
@Operation(summary = "上传文件", description = "上传文件")
|
||||
@PostMapping("/faceUpload")
|
||||
public FileUploadResp faceUpload(@NotNull(message = "图片不能为空") MultipartFile file, String savePath) {
|
||||
ValidationUtils.throwIf(file::isEmpty, "图片不能为空");
|
||||
|
||||
// 判断是否需要压缩图片
|
||||
if ((1024 * 1024 * 0.1) <= file.getSize()) {
|
||||
try (InputStream inputStream = file.getInputStream()) {
|
||||
float quality;
|
||||
// 根据文件大小设置不同的压缩质量
|
||||
if ((1024 * 1024 * 0.1) <= file.getSize() && file.getSize() <= (1024 * 1024)) {
|
||||
quality = 0.4f; // 小于1M的图片
|
||||
} else if ((1024 * 1024) < file.getSize() && file.getSize() <= (1024 * 1024 * 2)) {
|
||||
quality = 0.2f; // 1-2M的图片
|
||||
} else {
|
||||
quality = 0.1f; // 2M以上的图片
|
||||
}
|
||||
|
||||
// 直接在内存中压缩图片,避免使用临时文件
|
||||
file = PictureUtils.compressImage(inputStream, file.getOriginalFilename(), quality);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
FileInfo fileInfo = fileService.upload(file, savePath, null, false, false);
|
||||
return FileUploadResp.builder()
|
||||
.id(fileInfo.getId())
|
||||
.url(fileInfo.getUrl())
|
||||
.thUrl(fileInfo.getThUrl())
|
||||
.metadata(fileInfo.getMetadata())
|
||||
.build();
|
||||
}
|
||||
|
||||
@Operation(summary = "查询部门树", description = "查询树结构的部门列表")
|
||||
@GetMapping("/tree/dept")
|
||||
public List<Tree<Long>> listDeptTree(DeptQuery query, SortQuery sortQuery) {
|
||||
return deptService.tree(query, sortQuery, true);
|
||||
}
|
||||
|
||||
@Operation(summary = "查询菜单树", description = "查询树结构的菜单列表")
|
||||
@GetMapping("/tree/menu")
|
||||
public List<Tree<Long>> listMenuTree(MenuQuery query, SortQuery sortQuery) {
|
||||
return menuService.tree(query, sortQuery, true);
|
||||
}
|
||||
|
||||
@Operation(summary = "查询用户字典", description = "查询用户字典列表")
|
||||
@GetMapping("/dict/user")
|
||||
public List<LabelValueResp> listUserDict(UserQuery query, SortQuery sortQuery) {
|
||||
return userService.listDict(query, sortQuery);
|
||||
}
|
||||
|
||||
@Operation(summary = "查询角色字典", description = "查询角色字典列表")
|
||||
@GetMapping("/dict/role")
|
||||
public List<LabelValueResp> listRoleDict(RoleQuery query, SortQuery sortQuery) {
|
||||
return roleService.listDict(query, sortQuery);
|
||||
}
|
||||
|
||||
@Operation(summary = "查询字典", description = "查询字典列表")
|
||||
@Parameter(name = "code", description = "字典编码", example = "notice_type", in = ParameterIn.PATH)
|
||||
@GetMapping("/dict/{code}")
|
||||
public List<LabelValueResp> listDict(@PathVariable String code) {
|
||||
return dictItemService.listByDictCode(code);
|
||||
}
|
||||
|
||||
@SaIgnore
|
||||
@Operation(summary = "查询系统配置参数", description = "查询系统配置参数")
|
||||
@GetMapping("/dict/option/site")
|
||||
@Cached(key = "'SITE'", name = CacheConstants.OPTION_KEY_PREFIX)
|
||||
public List<LabelValueResp<String>> listSiteOptionDict() {
|
||||
OptionQuery optionQuery = new OptionQuery();
|
||||
optionQuery.setCategory(OptionCategoryEnum.SITE.name());
|
||||
return optionService.list(optionQuery)
|
||||
.stream()
|
||||
.map(option -> new LabelValueResp<>(option.getCode(), StrUtil.nullToDefault(option.getValue(), option
|
||||
.getDefaultValue())))
|
||||
.toList();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package top.wms.admin.controller.monitor;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.enums.ParameterIn;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import top.wms.admin.auth.model.query.OnlineUserQuery;
|
||||
import top.wms.admin.auth.model.resp.OnlineUserResp;
|
||||
import top.wms.admin.auth.service.OnlineUserService;
|
||||
import top.continew.starter.core.validation.CheckUtils;
|
||||
import top.continew.starter.extension.crud.model.query.PageQuery;
|
||||
import top.continew.starter.extension.crud.model.resp.PageResp;
|
||||
|
||||
/**
|
||||
* 在线用户 API
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 2023/1/20 21:51
|
||||
*/
|
||||
@Tag(name = "在线用户 API")
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@RequestMapping("/monitor/online")
|
||||
public class OnlineUserController {
|
||||
|
||||
private final OnlineUserService baseService;
|
||||
|
||||
@Operation(summary = "分页查询列表", description = "分页查询列表")
|
||||
@SaCheckPermission("monitor:online:list")
|
||||
@GetMapping
|
||||
public PageResp<OnlineUserResp> page(OnlineUserQuery query, @Validated PageQuery pageQuery) {
|
||||
return baseService.page(query, pageQuery);
|
||||
}
|
||||
|
||||
@Operation(summary = "强退在线用户", description = "强退在线用户")
|
||||
@Parameter(name = "token", description = "令牌", example = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJsb2dpblR5cGUiOiJsb2dpbiIsImxvZ2luSWQiOjEsInJuU3RyIjoiTUd6djdyOVFoeHEwdVFqdFAzV3M5YjVJRzh4YjZPSEUifQ.7q7U3ouoN7WPhH2kUEM7vPe5KF3G_qavSG-vRgIxKvE", in = ParameterIn.PATH)
|
||||
@SaCheckPermission("monitor:online:kickout")
|
||||
@DeleteMapping("/{token}")
|
||||
public void kickout(@PathVariable String token) {
|
||||
String currentToken = StpUtil.getTokenValue();
|
||||
CheckUtils.throwIfEqual(token, currentToken, "不能强退自己");
|
||||
StpUtil.kickoutByTokenValue(token);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
package top.wms.admin.controller.schedule;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.aizuda.snailjob.client.job.core.annotation.JobExecutor;
|
||||
import com.aizuda.snailjob.common.log.SnailJobLog;
|
||||
import com.baomidou.mybatisplus.core.plugins.IgnoreStrategy;
|
||||
import com.baomidou.mybatisplus.core.plugins.InterceptorIgnoreHelper;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import top.wms.admin.common.constant.CacheConstants;
|
||||
import top.wms.admin.system.mapper.*;
|
||||
import top.wms.admin.system.model.entity.*;
|
||||
import top.continew.starter.cache.redisson.util.RedisUtils;
|
||||
import top.continew.starter.core.constant.StringConstants;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.BooleanSupplier;
|
||||
|
||||
/**
|
||||
* 演示环境任务(任务示例)
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 2024/8/4 15:30
|
||||
*/
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class DemoEnvironmentJob {
|
||||
|
||||
private final DictItemMapper dictItemMapper;
|
||||
private final DictMapper dictMapper;
|
||||
private final StorageMapper storageMapper;
|
||||
private final UserMapper userMapper;
|
||||
private final UserRoleMapper userRoleMapper;
|
||||
private final UserSocialMapper userSocialMapper;
|
||||
private final RoleMapper roleMapper;
|
||||
private final RoleDeptMapper roleDeptMapper;
|
||||
private final RoleMenuMapper roleMenuMapper;
|
||||
private final MenuMapper menuMapper;
|
||||
private final DeptMapper deptMapper;
|
||||
|
||||
private final ClientMapper clientsMapper;
|
||||
|
||||
private static final Long DELETE_FLAG = 10000L;
|
||||
private static final Long MESSAGE_FLAG = 0L;
|
||||
private static final List<Long> USER_FLAG = List
|
||||
.of(1L, 547889293968801822L, 547889293968801823L, 547889293968801824L, 547889293968801825L, 547889293968801826L, 547889293968801827L, 547889293968801828L, 547889293968801829L, 547889293968801830L, 547889293968801831L);
|
||||
private static final List<Long> ROLE_FLAG = List.of(1L, 547888897925840927L, 547888897925840928L);
|
||||
private static final Long DEPT_FLAG = 547887852587843611L;
|
||||
|
||||
/**
|
||||
* 重置演示环境数据
|
||||
*/
|
||||
@JobExecutor(name = "ResetEnvironmentData")
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void resetEnvironmentData() {
|
||||
try {
|
||||
SnailJobLog.REMOTE.info("定时任务 [重置演示环境数据] 开始执行。");
|
||||
// 检测待清理数据
|
||||
SnailJobLog.REMOTE.info("开始检测演示环境待清理数据项,请稍候...");
|
||||
Long dictItemCount = dictItemMapper.lambdaQuery().gt(DictItemDO::getId, DELETE_FLAG).count();
|
||||
this.log(dictItemCount, "字典项");
|
||||
Long dictCount = dictMapper.lambdaQuery().gt(DictDO::getId, DELETE_FLAG).count();
|
||||
this.log(dictCount, "字典");
|
||||
Long storageCount = storageMapper.lambdaQuery().gt(StorageDO::getId, DELETE_FLAG).count();
|
||||
this.log(storageCount, "存储");
|
||||
Long userCount = userMapper.lambdaQuery().notIn(UserDO::getId, USER_FLAG).count();
|
||||
this.log(userCount, "用户");
|
||||
Long roleCount = roleMapper.lambdaQuery().notIn(RoleDO::getId, ROLE_FLAG).count();
|
||||
this.log(roleCount, "角色");
|
||||
Long menuCount = menuMapper.lambdaQuery().gt(MenuDO::getId, DELETE_FLAG).count();
|
||||
this.log(menuCount, "菜单");
|
||||
Long deptCount = deptMapper.lambdaQuery().gt(DeptDO::getId, DEPT_FLAG).count();
|
||||
this.log(deptCount, "部门");
|
||||
Long clientCount = clientsMapper.lambdaQuery().gt(ClientDO::getId, DELETE_FLAG).count();
|
||||
this.log(clientCount, "终端");
|
||||
InterceptorIgnoreHelper.handle(IgnoreStrategy.builder().blockAttack(true).build());
|
||||
SnailJobLog.REMOTE.info("演示环境待清理数据项检测完成,开始执行清理。");
|
||||
userRoleMapper.lambdaUpdate().notIn(UserRoleDO::getRoleId, ROLE_FLAG).remove();
|
||||
userRoleMapper.lambdaUpdate().notIn(UserRoleDO::getUserId, USER_FLAG).remove();
|
||||
roleDeptMapper.lambdaUpdate().notIn(RoleDeptDO::getRoleId, ROLE_FLAG).remove();
|
||||
roleMenuMapper.lambdaUpdate().notIn(RoleMenuDO::getRoleId, ROLE_FLAG).remove();
|
||||
userSocialMapper.lambdaUpdate().notIn(UserSocialDO::getUserId, USER_FLAG).remove();
|
||||
// 清理具体数据
|
||||
this.clean(dictItemCount, "字典项", null, () -> dictItemMapper.lambdaUpdate()
|
||||
.gt(DictItemDO::getId, DELETE_FLAG)
|
||||
.remove());
|
||||
this.clean(dictCount, "字典", CacheConstants.DICT_KEY_PREFIX, () -> dictMapper.lambdaUpdate()
|
||||
.gt(DictDO::getId, DELETE_FLAG)
|
||||
.remove());
|
||||
this.clean(storageCount, "存储", null, () -> storageMapper.lambdaUpdate()
|
||||
.gt(StorageDO::getId, DELETE_FLAG)
|
||||
.remove());
|
||||
this.clean(userCount, "用户", null, () -> userMapper.lambdaUpdate().notIn(UserDO::getId, USER_FLAG).remove());
|
||||
this.clean(roleCount, "角色", null, () -> roleMapper.lambdaUpdate().notIn(RoleDO::getId, ROLE_FLAG).remove());
|
||||
this.clean(menuCount, "菜单", CacheConstants.ROLE_MENU_KEY_PREFIX, () -> menuMapper.lambdaUpdate()
|
||||
.gt(MenuDO::getId, DELETE_FLAG)
|
||||
.remove());
|
||||
this.clean(deptCount, "部门", null, () -> deptMapper.lambdaUpdate().gt(DeptDO::getId, DEPT_FLAG).remove());
|
||||
this.clean(clientCount, "终端", null, () -> clientsMapper.lambdaUpdate()
|
||||
.gt(ClientDO::getId, DEPT_FLAG)
|
||||
.remove());
|
||||
SnailJobLog.REMOTE.info("演示环境数据已清理完成。");
|
||||
SnailJobLog.REMOTE.info("定时任务 [重置演示环境数据] 执行结束。");
|
||||
} finally {
|
||||
InterceptorIgnoreHelper.clearIgnoreStrategy();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 输出日志
|
||||
*
|
||||
* @param count 待清理数据项数量
|
||||
* @param resource 资源名称
|
||||
*/
|
||||
private void log(Long count, String resource) {
|
||||
if (count > 0) {
|
||||
SnailJobLog.REMOTE.info("检测到 [{}] 待清理数据项:{}条", resource, count);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理数据
|
||||
*
|
||||
* @param count 待清理数据项数量
|
||||
* @param resource 资源名称
|
||||
* @param cacheKey 缓存键
|
||||
* @param supplier 清理数据项函数
|
||||
*/
|
||||
private void clean(Long count, String resource, String cacheKey, BooleanSupplier supplier) {
|
||||
if (count > 0 && supplier.getAsBoolean()) {
|
||||
SnailJobLog.REMOTE.info("[{}] 数据项清理完成。", resource);
|
||||
if (StrUtil.isNotBlank(cacheKey)) {
|
||||
RedisUtils.deleteByPattern(cacheKey + StringConstants.ASTERISK);
|
||||
SnailJobLog.REMOTE.info("[{}] 数据项缓存清理完成。", resource);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
package top.wms.admin.controller.schedule;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.enums.ParameterIn;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import top.wms.admin.schedule.model.query.JobQuery;
|
||||
import top.wms.admin.schedule.model.req.JobReq;
|
||||
import top.wms.admin.schedule.model.req.JobStatusReq;
|
||||
import top.wms.admin.schedule.model.resp.JobResp;
|
||||
import top.wms.admin.schedule.service.JobService;
|
||||
import top.continew.starter.extension.crud.model.resp.PageResp;
|
||||
import top.continew.starter.extension.crud.validation.CrudValidationGroup;
|
||||
import top.continew.starter.log.annotation.Log;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 任务 API
|
||||
*
|
||||
* @author KAI
|
||||
* @author Charles7c
|
||||
* @since 2024/6/25 22:24
|
||||
*/
|
||||
@Tag(name = " 任务 API")
|
||||
@Validated
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@RequestMapping("/schedule/job")
|
||||
public class JobController {
|
||||
|
||||
private final JobService baseService;
|
||||
|
||||
@Operation(summary = "分页查询任务列表", description = "分页查询任务列表")
|
||||
@SaCheckPermission("schedule:job:list")
|
||||
@GetMapping
|
||||
public PageResp<JobResp> page(JobQuery query) {
|
||||
return baseService.page(query);
|
||||
}
|
||||
|
||||
@Operation(summary = "新增任务", description = "新增任务")
|
||||
@SaCheckPermission("schedule:job:add")
|
||||
@PostMapping
|
||||
public void add(@Validated(CrudValidationGroup.Add.class) @RequestBody JobReq req) {
|
||||
baseService.add(req);
|
||||
}
|
||||
|
||||
@Operation(summary = "修改任务", description = "修改任务")
|
||||
@Parameter(name = "id", description = "ID", example = "1", in = ParameterIn.PATH)
|
||||
@SaCheckPermission("schedule:job:update")
|
||||
@PutMapping("/{id}")
|
||||
public void update(@Validated(CrudValidationGroup.Update.class) @RequestBody JobReq req, @PathVariable Long id) {
|
||||
baseService.update(req, id);
|
||||
}
|
||||
|
||||
@Operation(summary = "修改任务状态", description = "修改任务状态")
|
||||
@SaCheckPermission("schedule:job:update")
|
||||
@PatchMapping("/{id}/status")
|
||||
public void updateStatus(@Validated @RequestBody JobStatusReq req, @PathVariable Long id) {
|
||||
baseService.updateStatus(req, id);
|
||||
}
|
||||
|
||||
@Operation(summary = "删除任务", description = "删除任务")
|
||||
@Parameter(name = "id", description = "ID", example = "1", in = ParameterIn.PATH)
|
||||
@SaCheckPermission("schedule:job:delete")
|
||||
@DeleteMapping("/{id}")
|
||||
public void delete(@PathVariable Long id) {
|
||||
baseService.delete(id);
|
||||
}
|
||||
|
||||
@Operation(summary = "执行任务", description = "执行任务")
|
||||
@Parameter(name = "id", description = "ID", example = "1", in = ParameterIn.PATH)
|
||||
@SaCheckPermission("schedule:job:trigger")
|
||||
@PostMapping("/trigger/{id}")
|
||||
public void trigger(@PathVariable Long id) {
|
||||
baseService.trigger(id);
|
||||
}
|
||||
|
||||
@Log(ignore = true)
|
||||
@Operation(summary = "查询任务分组列表", description = "查询任务分组列表")
|
||||
@SaCheckPermission("schedule:job:list")
|
||||
@GetMapping("/group")
|
||||
public List<String> listGroup() {
|
||||
return baseService.listGroup();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
package top.wms.admin.controller.schedule;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.enums.ParameterIn;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import top.wms.admin.schedule.model.JobInstanceLogPageResult;
|
||||
import top.wms.admin.schedule.model.query.JobInstanceLogQuery;
|
||||
import top.wms.admin.schedule.model.query.JobInstanceQuery;
|
||||
import top.wms.admin.schedule.model.query.JobLogQuery;
|
||||
import top.wms.admin.schedule.model.resp.JobInstanceResp;
|
||||
import top.wms.admin.schedule.model.resp.JobLogResp;
|
||||
import top.wms.admin.schedule.service.JobLogService;
|
||||
import top.continew.starter.extension.crud.model.resp.PageResp;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 任务日志 API
|
||||
*
|
||||
* @author KAI
|
||||
* @author Charles7c
|
||||
* @since 2024/6/27 22:24
|
||||
*/
|
||||
@Tag(name = " 任务日志 API")
|
||||
@Validated
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@RequestMapping("/schedule/log")
|
||||
public class JobLogController {
|
||||
|
||||
private final JobLogService baseService;
|
||||
|
||||
@Operation(summary = "分页查询任务日志列表", description = "分页查询任务日志列表")
|
||||
@SaCheckPermission("schedule:log:list")
|
||||
@GetMapping
|
||||
public PageResp<JobLogResp> page(JobLogQuery query) {
|
||||
return baseService.page(query);
|
||||
}
|
||||
|
||||
@Operation(summary = "停止任务", description = "停止任务")
|
||||
@Parameter(name = "id", description = "ID", example = "1", in = ParameterIn.PATH)
|
||||
@SaCheckPermission("schedule:log:stop")
|
||||
@PostMapping("/stop/{id}")
|
||||
public void stop(@PathVariable Long id) {
|
||||
baseService.stop(id);
|
||||
}
|
||||
|
||||
@Operation(summary = "重试任务", description = "重试任务")
|
||||
@Parameter(name = "id", description = "ID", example = "1", in = ParameterIn.PATH)
|
||||
@SaCheckPermission("schedule:log:retry")
|
||||
@PostMapping("/retry/{id}")
|
||||
public void retry(@PathVariable Long id) {
|
||||
baseService.retry(id);
|
||||
}
|
||||
|
||||
@Operation(summary = "查询任务实例列表", description = "查询任务实例列表")
|
||||
@SaCheckPermission("schedule:log:list")
|
||||
@GetMapping("/instance")
|
||||
public List<JobInstanceResp> listInstance(JobInstanceQuery query) {
|
||||
return baseService.listInstance(query);
|
||||
}
|
||||
|
||||
@Operation(summary = "分页查询任务实例日志列表", description = "分页查询任务实例日志列表")
|
||||
@SaCheckPermission("schedule:log:list")
|
||||
@GetMapping("/instance/log")
|
||||
public JobInstanceLogPageResult pageInstanceLog(JobInstanceLogQuery query) {
|
||||
return baseService.pageInstanceLog(query);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package top.wms.admin.controller.system;
|
||||
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import top.wms.admin.common.controller.BaseController;
|
||||
import top.wms.admin.system.model.query.ClientQuery;
|
||||
import top.wms.admin.system.model.req.ClientReq;
|
||||
import top.wms.admin.system.model.resp.ClientResp;
|
||||
import top.wms.admin.system.service.ClientService;
|
||||
import top.continew.starter.extension.crud.annotation.CrudRequestMapping;
|
||||
import top.continew.starter.extension.crud.enums.Api;
|
||||
|
||||
/**
|
||||
* 终端管理 API
|
||||
*
|
||||
* @author KAI
|
||||
* @since 2024/12/03 16:04
|
||||
*/
|
||||
@Tag(name = "终端管理 API")
|
||||
@RestController
|
||||
@CrudRequestMapping(value = "/system/client", api = {Api.PAGE, Api.DETAIL, Api.ADD, Api.UPDATE, Api.DELETE})
|
||||
public class ClientController extends BaseController<ClientService, ClientResp, ClientResp, ClientQuery, ClientReq> {
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package top.wms.admin.controller.system;
|
||||
|
||||
import top.continew.starter.extension.crud.enums.Api;
|
||||
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import top.continew.starter.extension.crud.annotation.CrudRequestMapping;
|
||||
import top.wms.admin.common.controller.BaseController;
|
||||
import top.wms.admin.system.model.query.ConfigQuery;
|
||||
import top.wms.admin.system.model.req.ConfigReq;
|
||||
import top.wms.admin.system.model.resp.ConfigResp;
|
||||
import top.wms.admin.system.service.ConfigService;
|
||||
|
||||
/**
|
||||
* 参数配置管理 API
|
||||
*
|
||||
* @author zc
|
||||
* @since 2025/12/30 12:44
|
||||
*/
|
||||
@Tag(name = "参数配置管理 API")
|
||||
@RestController
|
||||
@CrudRequestMapping(value = "/system/config", api = {Api.PAGE, Api.DETAIL, Api.ADD, Api.UPDATE, Api.DELETE, Api.EXPORT})
|
||||
public class ConfigController extends BaseController<ConfigService, ConfigResp, ConfigResp, ConfigQuery, ConfigReq> {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package top.wms.admin.controller.system;
|
||||
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import top.wms.admin.common.controller.BaseController;
|
||||
import top.wms.admin.system.model.query.DeptQuery;
|
||||
import top.wms.admin.system.model.req.DeptReq;
|
||||
import top.wms.admin.system.model.resp.DeptResp;
|
||||
import top.wms.admin.system.service.DeptService;
|
||||
import top.continew.starter.extension.crud.annotation.CrudRequestMapping;
|
||||
import top.continew.starter.extension.crud.enums.Api;
|
||||
|
||||
/**
|
||||
* 部门管理 API
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 2023/1/22 17:50
|
||||
*/
|
||||
@Tag(name = "部门管理 API")
|
||||
@RestController
|
||||
@CrudRequestMapping(value = "/system/dept", api = {Api.TREE, Api.DETAIL, Api.ADD, Api.UPDATE, Api.DELETE, Api.EXPORT})
|
||||
public class DeptController extends BaseController<DeptService, DeptResp, DeptResp, DeptQuery, DeptReq> {
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package top.wms.admin.controller.system;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import top.wms.admin.common.constant.CacheConstants;
|
||||
import top.wms.admin.common.controller.BaseController;
|
||||
import top.wms.admin.system.model.query.DictQuery;
|
||||
import top.wms.admin.system.model.req.DictReq;
|
||||
import top.wms.admin.system.model.resp.DictResp;
|
||||
import top.wms.admin.system.service.DictService;
|
||||
import top.continew.starter.cache.redisson.util.RedisUtils;
|
||||
import top.continew.starter.extension.crud.annotation.CrudRequestMapping;
|
||||
import top.continew.starter.extension.crud.enums.Api;
|
||||
|
||||
/**
|
||||
* 字典管理 API
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 2023/9/11 21:29
|
||||
*/
|
||||
@Tag(name = "字典管理 API")
|
||||
@RestController
|
||||
@CrudRequestMapping(value = "/system/dict", api = {Api.LIST, Api.DETAIL, Api.ADD, Api.UPDATE, Api.DELETE})
|
||||
public class DictController extends BaseController<DictService, DictResp, DictResp, DictQuery, DictReq> {
|
||||
|
||||
@Operation(summary = "清除缓存", description = "清除缓存")
|
||||
@SaCheckPermission("system:dict:clearCache")
|
||||
@DeleteMapping("/cache/{code}")
|
||||
public void clearCache(@PathVariable String code) {
|
||||
RedisUtils.deleteByPattern(CacheConstants.DICT_KEY_PREFIX + code);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package top.wms.admin.controller.system;
|
||||
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import top.wms.admin.common.controller.BaseController;
|
||||
import top.wms.admin.system.model.query.DictItemQuery;
|
||||
import top.wms.admin.system.model.req.DictItemReq;
|
||||
import top.wms.admin.system.model.resp.DictItemResp;
|
||||
import top.wms.admin.system.service.DictItemService;
|
||||
import top.continew.starter.extension.crud.annotation.CrudRequestMapping;
|
||||
import top.continew.starter.extension.crud.enums.Api;
|
||||
import top.continew.starter.log.annotation.Log;
|
||||
|
||||
/**
|
||||
* 字典项管理 API
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 2023/9/11 21:29
|
||||
*/
|
||||
@Log(module = "字典管理")
|
||||
@Tag(name = "字典项管理 API")
|
||||
@RestController
|
||||
@CrudRequestMapping(value = "/system/dict/item", api = {Api.PAGE, Api.DETAIL, Api.ADD, Api.UPDATE, Api.DELETE})
|
||||
public class DictItemController extends BaseController<DictItemService, DictItemResp, DictItemResp, DictItemQuery, DictItemReq> {
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package top.wms.admin.controller.system;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import top.wms.admin.common.controller.BaseController;
|
||||
import top.wms.admin.system.model.query.FileQuery;
|
||||
import top.wms.admin.system.model.req.FileReq;
|
||||
import top.wms.admin.system.model.resp.file.FileResp;
|
||||
import top.wms.admin.system.model.resp.file.FileStatisticsResp;
|
||||
import top.wms.admin.system.service.FileService;
|
||||
import top.continew.starter.extension.crud.annotation.CrudRequestMapping;
|
||||
import top.continew.starter.extension.crud.enums.Api;
|
||||
import top.continew.starter.log.annotation.Log;
|
||||
|
||||
/**
|
||||
* 文件管理 API
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 2023/12/23 10:38
|
||||
*/
|
||||
@Tag(name = "文件管理 API")
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@CrudRequestMapping(value = "/system/file", api = {Api.PAGE, Api.UPDATE, Api.DELETE})
|
||||
public class FileController extends BaseController<FileService, FileResp, FileResp, FileQuery, FileReq> {
|
||||
|
||||
@Log(ignore = true)
|
||||
@Operation(summary = "查询文件资源统计", description = "查询文件资源统计")
|
||||
@SaCheckPermission("system:file:list")
|
||||
@GetMapping("/statistics")
|
||||
public FileStatisticsResp statistics() {
|
||||
return baseService.statistics();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package top.wms.admin.controller.system;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import com.feiniaojin.gracefulresponse.api.ExcludeFromGracefulResponse;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.enums.ParameterIn;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import top.wms.admin.system.model.query.LogQuery;
|
||||
import top.wms.admin.system.model.resp.log.LogDetailResp;
|
||||
import top.wms.admin.system.model.resp.log.LogResp;
|
||||
import top.wms.admin.system.service.LogService;
|
||||
import top.continew.starter.extension.crud.model.query.PageQuery;
|
||||
import top.continew.starter.extension.crud.model.query.SortQuery;
|
||||
import top.continew.starter.extension.crud.model.resp.PageResp;
|
||||
|
||||
/**
|
||||
* 系统日志 API
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 2023/1/18 23:55
|
||||
*/
|
||||
@Tag(name = "系统日志 API")
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@RequestMapping("/system/log")
|
||||
public class LogController {
|
||||
|
||||
private final LogService baseService;
|
||||
|
||||
@Operation(summary = "分页查询列表", description = "分页查询列表")
|
||||
@SaCheckPermission("monitor:log:list")
|
||||
@GetMapping
|
||||
public PageResp<LogResp> page(LogQuery query, @Validated PageQuery pageQuery) {
|
||||
return baseService.page(query, pageQuery);
|
||||
}
|
||||
|
||||
@Operation(summary = "查询详情", description = "查询详情")
|
||||
@Parameter(name = "id", description = "ID", example = "1", in = ParameterIn.PATH)
|
||||
@SaCheckPermission("monitor:log:detail")
|
||||
@GetMapping("/{id}")
|
||||
public LogDetailResp get(@PathVariable Long id) {
|
||||
return baseService.get(id);
|
||||
}
|
||||
|
||||
@ExcludeFromGracefulResponse
|
||||
@Operation(summary = "导出登录日志", description = "导出登录日志")
|
||||
@SaCheckPermission("monitor:log:export")
|
||||
@GetMapping("/export/login")
|
||||
public void exportLoginLog(LogQuery query, SortQuery sortQuery, HttpServletResponse response) {
|
||||
baseService.exportLoginLog(query, sortQuery, response);
|
||||
}
|
||||
|
||||
@ExcludeFromGracefulResponse
|
||||
@Operation(summary = "导出操作日志", description = "导出操作日志")
|
||||
@SaCheckPermission("monitor:log:export")
|
||||
@GetMapping("/export/operation")
|
||||
public void exportOperationLog(LogQuery query, SortQuery sortQuery, HttpServletResponse response) {
|
||||
baseService.exportOperationLog(query, sortQuery, response);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package top.wms.admin.controller.system;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import top.wms.admin.common.constant.CacheConstants;
|
||||
import top.wms.admin.common.controller.BaseController;
|
||||
import top.wms.admin.system.model.query.MenuQuery;
|
||||
import top.wms.admin.system.model.req.MenuReq;
|
||||
import top.wms.admin.system.model.resp.MenuResp;
|
||||
import top.wms.admin.system.service.MenuService;
|
||||
import top.continew.starter.cache.redisson.util.RedisUtils;
|
||||
import top.continew.starter.core.constant.StringConstants;
|
||||
import top.continew.starter.core.util.URLUtils;
|
||||
import top.continew.starter.core.validation.ValidationUtils;
|
||||
import top.continew.starter.extension.crud.annotation.CrudApi;
|
||||
import top.continew.starter.extension.crud.annotation.CrudRequestMapping;
|
||||
import top.continew.starter.extension.crud.enums.Api;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* 菜单管理 API
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 2023/2/15 20:35
|
||||
*/
|
||||
@Tag(name = "菜单管理 API")
|
||||
@RestController
|
||||
@CrudRequestMapping(value = "/system/menu", api = {Api.TREE, Api.DETAIL, Api.ADD, Api.UPDATE, Api.DELETE})
|
||||
public class MenuController extends BaseController<MenuService, MenuResp, MenuResp, MenuQuery, MenuReq> {
|
||||
|
||||
@Operation(summary = "清除缓存", description = "清除缓存")
|
||||
@SaCheckPermission("system:menu:clearCache")
|
||||
@DeleteMapping("/cache")
|
||||
public void clearCache() {
|
||||
RedisUtils.deleteByPattern(CacheConstants.ROLE_MENU_KEY_PREFIX + StringConstants.ASTERISK);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preHandle(CrudApi crudApi, Object[] args, Method targetMethod, Class<?> targetClass) throws Exception {
|
||||
super.preHandle(crudApi, args, targetMethod, targetClass);
|
||||
Api api = crudApi.value();
|
||||
if (!(Api.ADD.equals(api) || Api.UPDATE.equals(api))) {
|
||||
return;
|
||||
}
|
||||
MenuReq req = (MenuReq)args[0];
|
||||
Boolean isExternal = ObjectUtil.defaultIfNull(req.getIsExternal(), false);
|
||||
String path = req.getPath();
|
||||
ValidationUtils.throwIf(Boolean.TRUE.equals(isExternal) && !URLUtils
|
||||
.isHttpUrl(path), "路由地址格式错误,请以 http:// 或 https:// 开头");
|
||||
// 非外链菜单参数修正
|
||||
if (Boolean.FALSE.equals(isExternal)) {
|
||||
ValidationUtils.throwIf(URLUtils.isHttpUrl(path), "路由地址格式错误");
|
||||
req.setPath(StrUtil.isBlank(path) ? path : StrUtil.prependIfMissing(path, StringConstants.SLASH));
|
||||
req.setName(StrUtil.removePrefix(req.getName(), StringConstants.SLASH));
|
||||
req.setComponent(StrUtil.removePrefix(req.getComponent(), StringConstants.SLASH));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package top.wms.admin.controller.system;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.validation.Valid;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import top.wms.admin.system.model.query.OptionQuery;
|
||||
import top.wms.admin.system.model.req.OptionReq;
|
||||
import top.wms.admin.system.model.req.OptionResetValueReq;
|
||||
import top.wms.admin.system.model.resp.OptionResp;
|
||||
import top.wms.admin.system.service.OptionService;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 参数管理 API
|
||||
*
|
||||
* @author Bull-BCLS
|
||||
* @since 2023/8/26 19:38
|
||||
*/
|
||||
@Tag(name = "参数管理 API")
|
||||
@Validated
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@RequestMapping("/system/option")
|
||||
public class OptionController {
|
||||
|
||||
private final OptionService baseService;
|
||||
|
||||
@Operation(summary = "查询参数列表", description = "查询参数列表")
|
||||
@SaCheckPermission("system:config:list")
|
||||
@GetMapping
|
||||
public List<OptionResp> list(@Validated OptionQuery query) {
|
||||
return baseService.list(query);
|
||||
}
|
||||
|
||||
@Operation(summary = "修改参数", description = "修改参数")
|
||||
@SaCheckPermission("system:config:update")
|
||||
@PutMapping
|
||||
public void update(@Valid @RequestBody List<OptionReq> options) {
|
||||
baseService.update(options);
|
||||
}
|
||||
|
||||
@Operation(summary = "重置参数", description = "重置参数")
|
||||
@SaCheckPermission("system:config:reset")
|
||||
@PatchMapping("/value")
|
||||
public void resetValue(@Validated @RequestBody OptionResetValueReq req) {
|
||||
baseService.resetValue(req);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
package top.wms.admin.controller.system;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.enums.ParameterIn;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import top.wms.admin.common.controller.BaseController;
|
||||
import top.wms.admin.system.model.query.RoleQuery;
|
||||
import top.wms.admin.system.model.query.RoleUserQuery;
|
||||
import top.wms.admin.system.model.req.RoleReq;
|
||||
import top.wms.admin.system.model.req.RoleUpdatePermissionReq;
|
||||
import top.wms.admin.system.model.resp.role.RoleDetailResp;
|
||||
import top.wms.admin.system.model.resp.role.RoleResp;
|
||||
import top.wms.admin.system.model.resp.role.RoleUserResp;
|
||||
import top.wms.admin.system.service.RoleService;
|
||||
import top.wms.admin.system.service.UserRoleService;
|
||||
import top.continew.starter.extension.crud.annotation.CrudRequestMapping;
|
||||
import top.continew.starter.extension.crud.enums.Api;
|
||||
import top.continew.starter.extension.crud.model.query.PageQuery;
|
||||
import top.continew.starter.extension.crud.model.resp.PageResp;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 角色管理 API
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 2023/2/8 23:11
|
||||
*/
|
||||
@Tag(name = "角色管理 API")
|
||||
@Validated
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@CrudRequestMapping(value = "/system/role", api = {Api.LIST, Api.DETAIL, Api.ADD, Api.UPDATE, Api.DELETE})
|
||||
public class RoleController extends BaseController<RoleService, RoleResp, RoleDetailResp, RoleQuery, RoleReq> {
|
||||
|
||||
private final UserRoleService userRoleService;
|
||||
|
||||
@Operation(summary = "修改权限", description = "修改角色的功能权限")
|
||||
@SaCheckPermission("system:role:updatePermission")
|
||||
@PutMapping("/{id}/permission")
|
||||
public void updatePermission(@PathVariable("id") Long id, @Validated @RequestBody RoleUpdatePermissionReq req) {
|
||||
baseService.updatePermission(id, req);
|
||||
}
|
||||
|
||||
@Operation(summary = "分页查询关联用户", description = "分页查询角色关联的用户列表")
|
||||
@Parameter(name = "id", description = "ID", example = "1", in = ParameterIn.PATH)
|
||||
@SaCheckPermission("system:role:list")
|
||||
@GetMapping("/{id}/user")
|
||||
public PageResp<RoleUserResp> pageUser(@PathVariable("id") Long id,
|
||||
@Validated RoleUserQuery query,
|
||||
@Validated PageQuery pageQuery) {
|
||||
query.setRoleId(id);
|
||||
return userRoleService.pageUser(query, pageQuery);
|
||||
}
|
||||
|
||||
@Operation(summary = "分配用户", description = "批量分配角色给用户")
|
||||
@SaCheckPermission("system:role:assign")
|
||||
@PostMapping("/{id}/user")
|
||||
public void assignToUsers(@PathVariable("id") Long id,
|
||||
@Validated @NotEmpty(message = "用户ID列表不能为空") @RequestBody List<Long> userIds) {
|
||||
baseService.assignToUsers(id, userIds);
|
||||
}
|
||||
|
||||
@Operation(summary = "取消分配用户", description = "批量取消分配角色给用户")
|
||||
@SaCheckPermission("system:role:unassign")
|
||||
@DeleteMapping("/user")
|
||||
public void unassignFromUsers(@Validated @NotEmpty(message = "用户列表不能为空") @RequestBody List<Long> userRoleIds) {
|
||||
userRoleService.deleteByIds(userRoleIds);
|
||||
}
|
||||
|
||||
@Operation(summary = "查询关联用户ID", description = "查询角色关联的用户ID列表")
|
||||
@Parameter(name = "id", description = "ID", example = "1", in = ParameterIn.PATH)
|
||||
@SaCheckPermission("system:role:list")
|
||||
@GetMapping("/{id}/user/id")
|
||||
public List<Long> listUserId(@PathVariable("id") Long id) {
|
||||
return userRoleService.listUserIdByRoleId(id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package top.wms.admin.controller.system;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.enums.ParameterIn;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import top.wms.admin.common.controller.BaseController;
|
||||
import top.wms.admin.common.model.req.CommonStatusUpdateReq;
|
||||
import top.wms.admin.system.model.query.StorageQuery;
|
||||
import top.wms.admin.system.model.req.StorageReq;
|
||||
import top.wms.admin.system.model.resp.StorageResp;
|
||||
import top.wms.admin.system.service.StorageService;
|
||||
import top.continew.starter.extension.crud.annotation.CrudRequestMapping;
|
||||
import top.continew.starter.extension.crud.enums.Api;
|
||||
|
||||
/**
|
||||
* 存储管理 API
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 2023/12/26 22:09
|
||||
*/
|
||||
@Tag(name = "存储管理 API")
|
||||
@Validated
|
||||
@RestController
|
||||
@CrudRequestMapping(value = "/system/storage", api = {Api.LIST, Api.DETAIL, Api.ADD, Api.UPDATE, Api.DELETE})
|
||||
public class StorageController extends BaseController<StorageService, StorageResp, StorageResp, StorageQuery, StorageReq> {
|
||||
|
||||
@Operation(summary = "修改状态", description = "修改状态")
|
||||
@Parameter(name = "id", description = "ID", example = "1", in = ParameterIn.PATH)
|
||||
@SaCheckPermission("system:storage:updateStatus")
|
||||
@PutMapping({"/{id}/status"})
|
||||
public void updateStatus(@Validated @RequestBody CommonStatusUpdateReq req, @PathVariable("id") Long id) {
|
||||
baseService.updateStatus(req, id);
|
||||
}
|
||||
|
||||
@Operation(summary = "设为默认存储", description = "设为默认存储")
|
||||
@Parameter(name = "id", description = "ID", example = "1", in = ParameterIn.PATH)
|
||||
@SaCheckPermission("system:storage:setDefault")
|
||||
@PutMapping({"/{id}/default"})
|
||||
public void setDefault(@PathVariable("id") Long id) {
|
||||
baseService.setDefault(id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
package top.wms.admin.controller.system;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.enums.ParameterIn;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import top.wms.admin.common.constant.CacheConstants;
|
||||
import top.wms.admin.common.context.UserContextHolder;
|
||||
import top.wms.admin.common.util.SecureUtils;
|
||||
import top.wms.admin.system.enums.SocialSourceEnum;
|
||||
import top.wms.admin.system.model.entity.UserSocialDO;
|
||||
import top.wms.admin.system.model.req.user.UserBasicInfoUpdateReq;
|
||||
import top.wms.admin.system.model.req.user.UserEmailUpdateRequest;
|
||||
import top.wms.admin.system.model.req.user.UserPasswordUpdateReq;
|
||||
import top.wms.admin.system.model.req.user.UserPhoneUpdateReq;
|
||||
import top.wms.admin.system.model.resp.AvatarResp;
|
||||
import top.wms.admin.system.model.resp.user.UserSocialBindResp;
|
||||
import top.wms.admin.system.service.UserService;
|
||||
import top.wms.admin.system.service.UserSocialService;
|
||||
import top.continew.starter.cache.redisson.util.RedisUtils;
|
||||
import top.continew.starter.core.exception.BadRequestException;
|
||||
import top.continew.starter.core.util.ExceptionUtils;
|
||||
import top.continew.starter.core.validation.ValidationUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 个人中心 API
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 2023/1/2 11:41
|
||||
*/
|
||||
@Tag(name = "个人中心 API")
|
||||
@Validated
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@RequestMapping("/system/user")
|
||||
public class UserCenterController {
|
||||
|
||||
private static final String DECRYPT_FAILED = "当前密码解密失败";
|
||||
private static final String CAPTCHA_EXPIRED = "验证码已失效";
|
||||
private final UserService userService;
|
||||
private final UserSocialService userSocialService;
|
||||
|
||||
@Operation(summary = "修改头像", description = "用户修改个人头像")
|
||||
@PostMapping("/avatar")
|
||||
public AvatarResp updateAvatar(@NotNull(message = "头像不能为空") MultipartFile avatarFile) throws IOException {
|
||||
ValidationUtils.throwIf(avatarFile::isEmpty, "头像不能为空");
|
||||
String newAvatar = userService.updateAvatar(avatarFile, UserContextHolder.getUserId());
|
||||
return AvatarResp.builder().avatar(newAvatar).build();
|
||||
}
|
||||
|
||||
@Operation(summary = "修改基础信息", description = "修改用户基础信息")
|
||||
@PatchMapping("/basic/info")
|
||||
public void updateBasicInfo(@Validated @RequestBody UserBasicInfoUpdateReq req) {
|
||||
userService.updateBasicInfo(req, UserContextHolder.getUserId());
|
||||
}
|
||||
|
||||
@Operation(summary = "修改密码", description = "修改用户登录密码")
|
||||
@PatchMapping("/password")
|
||||
public void updatePassword(@Validated @RequestBody UserPasswordUpdateReq updateReq) {
|
||||
String rawOldPassword = ExceptionUtils.exToNull(() -> SecureUtils.decryptByRsaPrivateKey(updateReq
|
||||
.getOldPassword()));
|
||||
ValidationUtils.throwIfNull(rawOldPassword, DECRYPT_FAILED);
|
||||
String rawNewPassword = ExceptionUtils.exToNull(() -> SecureUtils.decryptByRsaPrivateKey(updateReq
|
||||
.getNewPassword()));
|
||||
ValidationUtils.throwIfNull(rawNewPassword, "新密码解密失败");
|
||||
userService.updatePassword(rawOldPassword, rawNewPassword, UserContextHolder.getUserId());
|
||||
}
|
||||
|
||||
@Operation(summary = "修改手机号", description = "修改手机号")
|
||||
@PatchMapping("/phone")
|
||||
public void updatePhone(@Validated @RequestBody UserPhoneUpdateReq updateReq) {
|
||||
String rawOldPassword = ExceptionUtils.exToNull(() -> SecureUtils.decryptByRsaPrivateKey(updateReq
|
||||
.getOldPassword()));
|
||||
ValidationUtils.throwIfBlank(rawOldPassword, DECRYPT_FAILED);
|
||||
String captchaKey = CacheConstants.CAPTCHA_KEY_PREFIX + updateReq.getPhone();
|
||||
String captcha = RedisUtils.get(captchaKey);
|
||||
ValidationUtils.throwIfBlank(captcha, CAPTCHA_EXPIRED);
|
||||
ValidationUtils.throwIfNotEqualIgnoreCase(updateReq.getCaptcha(), captcha, "验证码错误");
|
||||
RedisUtils.delete(captchaKey);
|
||||
userService.updatePhone(updateReq.getPhone(), rawOldPassword, UserContextHolder.getUserId());
|
||||
}
|
||||
|
||||
@Operation(summary = "修改邮箱", description = "修改用户邮箱")
|
||||
@PatchMapping("/email")
|
||||
public void updateEmail(@Validated @RequestBody UserEmailUpdateRequest updateReq) {
|
||||
String rawOldPassword = ExceptionUtils.exToNull(() -> SecureUtils.decryptByRsaPrivateKey(updateReq
|
||||
.getOldPassword()));
|
||||
ValidationUtils.throwIfBlank(rawOldPassword, DECRYPT_FAILED);
|
||||
String captchaKey = CacheConstants.CAPTCHA_KEY_PREFIX + updateReq.getEmail();
|
||||
String captcha = RedisUtils.get(captchaKey);
|
||||
ValidationUtils.throwIfBlank(captcha, CAPTCHA_EXPIRED);
|
||||
ValidationUtils.throwIfNotEqualIgnoreCase(updateReq.getCaptcha(), captcha, "验证码错误");
|
||||
RedisUtils.delete(captchaKey);
|
||||
userService.updateEmail(updateReq.getEmail(), rawOldPassword, UserContextHolder.getUserId());
|
||||
}
|
||||
|
||||
@Operation(summary = "查询绑定的三方账号", description = "查询绑定的三方账号")
|
||||
@GetMapping("/social")
|
||||
public List<UserSocialBindResp> listSocialBind() {
|
||||
List<UserSocialDO> userSocialList = userSocialService.listByUserId(UserContextHolder.getUserId());
|
||||
return userSocialList.stream().map(userSocial -> {
|
||||
String source = userSocial.getSource();
|
||||
UserSocialBindResp userSocialBind = new UserSocialBindResp();
|
||||
userSocialBind.setSource(source);
|
||||
userSocialBind.setDescription(SocialSourceEnum.valueOf(source).getDescription());
|
||||
return userSocialBind;
|
||||
}).toList();
|
||||
}
|
||||
|
||||
@Operation(summary = "绑定三方账号", description = "绑定三方账号")
|
||||
@Parameter(name = "source", description = "来源", example = "gitee", in = ParameterIn.PATH)
|
||||
@PostMapping("/social/{source}")
|
||||
public void bindSocial(@PathVariable String source, @RequestBody Object callback) {
|
||||
// 第三方登录已禁用
|
||||
throw new BadRequestException("第三方登录功能已禁用");
|
||||
}
|
||||
|
||||
@Operation(summary = "解绑三方账号", description = "解绑三方账号")
|
||||
@Parameter(name = "source", description = "来源", example = "gitee", in = ParameterIn.PATH)
|
||||
@DeleteMapping("/social/{source}")
|
||||
public void unbindSocial(@PathVariable String source) {
|
||||
userSocialService.deleteBySourceAndUserId(source, UserContextHolder.getUserId());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
package top.wms.admin.controller.system;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import cn.hutool.core.util.ReUtil;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.enums.ParameterIn;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import top.wms.admin.common.controller.BaseController;
|
||||
import top.wms.admin.common.constant.RegexConstants;
|
||||
import top.wms.admin.common.util.SecureUtils;
|
||||
import top.wms.admin.system.model.query.UserQuery;
|
||||
import top.wms.admin.system.model.req.user.UserImportReq;
|
||||
import top.wms.admin.system.model.req.user.UserPasswordResetReq;
|
||||
import top.wms.admin.system.model.req.user.UserReq;
|
||||
import top.wms.admin.system.model.req.user.UserRoleUpdateReq;
|
||||
import top.wms.admin.system.model.resp.user.UserDetailResp;
|
||||
import top.wms.admin.system.model.resp.user.UserImportParseResp;
|
||||
import top.wms.admin.system.model.resp.user.UserImportResp;
|
||||
import top.wms.admin.system.model.resp.user.UserResp;
|
||||
import top.wms.admin.system.service.UserService;
|
||||
import top.continew.starter.core.util.ExceptionUtils;
|
||||
import top.continew.starter.core.validation.ValidationUtils;
|
||||
import top.continew.starter.extension.crud.annotation.CrudRequestMapping;
|
||||
import top.continew.starter.extension.crud.enums.Api;
|
||||
import top.continew.starter.extension.crud.model.resp.BaseIdResp;
|
||||
import top.continew.starter.extension.crud.validation.CrudValidationGroup;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* 用户管理 API
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 2023/2/20 21:00
|
||||
*/
|
||||
@Tag(name = "用户管理 API")
|
||||
@Validated
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@CrudRequestMapping(value = "/system/user", api = {Api.PAGE, Api.LIST, Api.DETAIL, Api.ADD, Api.UPDATE, Api.DELETE,
|
||||
Api.EXPORT})
|
||||
public class UserController extends BaseController<UserService, UserResp, UserDetailResp, UserQuery, UserReq> {
|
||||
|
||||
@Override
|
||||
@Operation(summary = "新增数据", description = "新增数据")
|
||||
public BaseIdResp<Long> add(@Validated(CrudValidationGroup.Add.class) @RequestBody UserReq req) {
|
||||
String rawPassword = ExceptionUtils.exToNull(() -> SecureUtils.decryptByRsaPrivateKey(req.getPassword()));
|
||||
ValidationUtils.throwIfNull(rawPassword, "密码解密失败");
|
||||
ValidationUtils.throwIf(!ReUtil
|
||||
.isMatch(RegexConstants.PASSWORD, rawPassword), "密码长度为 8-32 个字符,支持大小写字母、数字、特殊字符,至少包含字母和数字");
|
||||
req.setPassword(rawPassword);
|
||||
return super.add(req);
|
||||
}
|
||||
|
||||
@Operation(summary = "下载导入模板", description = "下载导入模板")
|
||||
@SaCheckPermission("system:user:import")
|
||||
@GetMapping(value = "/import/template", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
|
||||
public void downloadImportTemplate(HttpServletResponse response) throws IOException {
|
||||
baseService.downloadImportTemplate(response);
|
||||
}
|
||||
|
||||
@Operation(summary = "解析导入数据", description = "解析导入数据")
|
||||
@SaCheckPermission("system:user:import")
|
||||
@PostMapping("/import/parse")
|
||||
public UserImportParseResp parseImport(@NotNull(message = "文件不能为空") MultipartFile file) {
|
||||
ValidationUtils.throwIf(file::isEmpty, "文件不能为空");
|
||||
return baseService.parseImport(file);
|
||||
}
|
||||
|
||||
@Operation(summary = "导入数据", description = "导入数据")
|
||||
@SaCheckPermission("system:user:import")
|
||||
@PostMapping(value = "/import")
|
||||
public UserImportResp importUser(@Validated @RequestBody UserImportReq req) {
|
||||
return baseService.importUser(req);
|
||||
}
|
||||
|
||||
@Operation(summary = "重置密码", description = "重置用户登录密码")
|
||||
@Parameter(name = "id", description = "ID", example = "1", in = ParameterIn.PATH)
|
||||
@SaCheckPermission("system:user:resetPwd")
|
||||
@PatchMapping("/{id}/password")
|
||||
public void resetPassword(@Validated @RequestBody UserPasswordResetReq req, @PathVariable Long id) {
|
||||
String rawNewPassword = ExceptionUtils.exToNull(() -> SecureUtils.decryptByRsaPrivateKey(req.getNewPassword()));
|
||||
ValidationUtils.throwIfNull(rawNewPassword, "新密码解密失败");
|
||||
ValidationUtils.throwIf(!ReUtil
|
||||
.isMatch(RegexConstants.PASSWORD, rawNewPassword), "密码长度为 8-32 个字符,支持大小写字母、数字、特殊字符,至少包含字母和数字");
|
||||
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
|
||||
req.setNewPassword("{bcrypt}" + encoder.encode(rawNewPassword));
|
||||
baseService.resetPassword(req, id);
|
||||
}
|
||||
|
||||
@Operation(summary = "分配角色", description = "为用户新增或移除角色")
|
||||
@Parameter(name = "id", description = "ID", example = "1", in = ParameterIn.PATH)
|
||||
@SaCheckPermission("system:user:updateRole")
|
||||
@PatchMapping("/{id}/role")
|
||||
public void updateRole(@Validated @RequestBody UserRoleUpdateReq updateReq, @PathVariable Long id) {
|
||||
baseService.updateRole(updateReq, id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package top.wms.admin.controller.system;
|
||||
|
||||
import org.dromara.x.file.storage.core.FileInfo;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import top.wms.admin.common.util.PictureUtils;
|
||||
// import top.wms.admin.controller.file.SysFileController;
|
||||
// import top.wms.admin.file.domain.SysFile;
|
||||
import top.wms.admin.system.model.resp.file.FileUploadResp;
|
||||
import top.wms.admin.system.service.FileService;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/test")
|
||||
public class zctest {
|
||||
|
||||
// @Autowired
|
||||
// private SysFileController fileController;
|
||||
|
||||
@Autowired
|
||||
private FileService fileService;
|
||||
|
||||
@PostMapping()
|
||||
public FileUploadResp test() {
|
||||
String urls = "http://bpic.588ku.com/element_origin_min_pic/19/03/15/75076c485081d15ed9c224ad3e4ce4a1.jpg";
|
||||
MultipartFile file = PictureUtils.createMultipartFile(urls, "zctest11111.jpg");
|
||||
// SysFile sysFile = fileController.uploadMinio(file, "zctest11111");
|
||||
// return sysFile;
|
||||
|
||||
FileInfo fileInfo = fileService.upload(file, "zctest", "minio", false, false);
|
||||
return FileUploadResp.builder()
|
||||
.id(fileInfo.getId())
|
||||
.url(fileInfo.getUrl())
|
||||
.thUrl(fileInfo.getThUrl())
|
||||
.metadata(fileInfo.getMetadata())
|
||||
.build();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user