mirror of
https://github.com/continew-org/continew-admin.git
synced 2025-11-10 13:01:43 +08:00
chore: top.charles7c.continew => top.continew
1.groupId 及基础包名调整,更短的包名,优化品牌形象 2.全局代码格式化
This commit is contained in:
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.continew.admin;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaIgnore;
|
||||
import cn.hutool.core.util.URLUtil;
|
||||
import cn.hutool.extra.spring.SpringUtil;
|
||||
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.ApplicationArguments;
|
||||
import org.springframework.boot.ApplicationRunner;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.autoconfigure.web.ServerProperties;
|
||||
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.core.constant.PropertiesConstants;
|
||||
import top.continew.starter.core.constant.StringConstants;
|
||||
import top.continew.starter.extension.crud.annotation.EnableCrudRestController;
|
||||
import top.continew.starter.web.annotation.EnableGlobalExceptionHandler;
|
||||
|
||||
import java.net.InetAddress;
|
||||
|
||||
/**
|
||||
* 启动程序
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 2022/12/8 23:15
|
||||
*/
|
||||
@Slf4j
|
||||
@RestController
|
||||
@EnableFileStorage
|
||||
@SpringBootApplication
|
||||
@RequiredArgsConstructor
|
||||
@EnableCrudRestController
|
||||
@EnableGlobalExceptionHandler
|
||||
@EnableMethodCache(basePackages = "top.continew.admin")
|
||||
public class ContiNewAdminApplication implements ApplicationRunner {
|
||||
|
||||
private final ProjectProperties projectProperties;
|
||||
private final ServerProperties serverProperties;
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(ContiNewAdminApplication.class, args);
|
||||
}
|
||||
|
||||
/**
|
||||
* 访问首页提示
|
||||
*
|
||||
* @return /
|
||||
*/
|
||||
@Hidden
|
||||
@SaIgnore
|
||||
@GetMapping("/")
|
||||
public String index() {
|
||||
return "%s service started successfully.".formatted(projectProperties.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(ApplicationArguments args) throws Exception {
|
||||
String hostAddress = InetAddress.getLocalHost().getHostAddress();
|
||||
Integer port = serverProperties.getPort();
|
||||
String contextPath = serverProperties.getServlet().getContextPath();
|
||||
String baseUrl = URLUtil.normalize("%s:%s%s".formatted(hostAddress, port, contextPath));
|
||||
log.info("----------------------------------------------");
|
||||
log.info("{} service started successfully.", projectProperties.getName());
|
||||
log.info("API 地址:{}", baseUrl);
|
||||
String docEnabledProperty = PropertiesConstants.SPRINGDOC_SWAGGER_UI + StringConstants.DOT + PropertiesConstants.ENABLED;
|
||||
if (Boolean.TRUE.equals(SpringUtil.getProperty(docEnabledProperty, boolean.class, false))) {
|
||||
log.info("API 文档:{}/doc.html", baseUrl);
|
||||
}
|
||||
log.info("----------------------------------------------");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.continew.admin.webapi.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 lombok.RequiredArgsConstructor;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import top.continew.admin.auth.model.req.AccountLoginReq;
|
||||
import top.continew.admin.auth.model.req.EmailLoginReq;
|
||||
import top.continew.admin.auth.model.req.PhoneLoginReq;
|
||||
import top.continew.admin.auth.model.resp.LoginResp;
|
||||
import top.continew.admin.auth.model.resp.RouteResp;
|
||||
import top.continew.admin.auth.model.resp.UserInfoResp;
|
||||
import top.continew.admin.auth.service.LoginService;
|
||||
import top.continew.admin.common.constant.CacheConstants;
|
||||
import top.continew.admin.common.model.dto.LoginUser;
|
||||
import top.continew.admin.common.util.SecureUtils;
|
||||
import top.continew.admin.common.util.helper.LoginHelper;
|
||||
import top.continew.admin.system.model.resp.UserDetailResp;
|
||||
import top.continew.admin.system.service.UserService;
|
||||
import top.continew.starter.cache.redisson.util.RedisUtils;
|
||||
import top.continew.starter.core.util.ExceptionUtils;
|
||||
import top.continew.starter.core.util.validate.ValidationUtils;
|
||||
import top.continew.starter.web.model.R;
|
||||
import top.continew.starter.log.core.annotation.Log;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 认证 API
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 2022/12/21 20:37
|
||||
*/
|
||||
@Log(module = "登录")
|
||||
@Tag(name = "认证 API")
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@RequestMapping("/auth")
|
||||
public class AuthController {
|
||||
|
||||
private static final String CAPTCHA_EXPIRED = "验证码已失效";
|
||||
private static final String CAPTCHA_ERROR = "验证码错误";
|
||||
private final LoginService loginService;
|
||||
private final UserService userService;
|
||||
|
||||
@SaIgnore
|
||||
@Operation(summary = "账号登录", description = "根据账号和密码进行登录认证")
|
||||
@PostMapping("/account")
|
||||
public R<LoginResp> accountLogin(@Validated @RequestBody AccountLoginReq loginReq) {
|
||||
String captchaKey = CacheConstants.CAPTCHA_KEY_PREFIX + loginReq.getUuid();
|
||||
String captcha = RedisUtils.get(captchaKey);
|
||||
ValidationUtils.throwIfBlank(captcha, CAPTCHA_EXPIRED);
|
||||
RedisUtils.delete(captchaKey);
|
||||
ValidationUtils.throwIfNotEqualIgnoreCase(loginReq.getCaptcha(), captcha, CAPTCHA_ERROR);
|
||||
// 用户登录
|
||||
String rawPassword = ExceptionUtils.exToNull(() -> SecureUtils.decryptByRsaPrivateKey(loginReq.getPassword()));
|
||||
ValidationUtils.throwIfBlank(rawPassword, "密码解密失败");
|
||||
String token = loginService.accountLogin(loginReq.getUsername(), rawPassword);
|
||||
return R.ok(LoginResp.builder().token(token).build());
|
||||
}
|
||||
|
||||
@SaIgnore
|
||||
@Operation(summary = "邮箱登录", description = "根据邮箱和验证码进行登录认证")
|
||||
@PostMapping("/email")
|
||||
public R<LoginResp> emailLogin(@Validated @RequestBody EmailLoginReq loginReq) {
|
||||
String email = loginReq.getEmail();
|
||||
String captchaKey = CacheConstants.CAPTCHA_KEY_PREFIX + email;
|
||||
String captcha = RedisUtils.get(captchaKey);
|
||||
ValidationUtils.throwIfBlank(captcha, CAPTCHA_EXPIRED);
|
||||
ValidationUtils.throwIfNotEqualIgnoreCase(loginReq.getCaptcha(), captcha, CAPTCHA_ERROR);
|
||||
RedisUtils.delete(captchaKey);
|
||||
String token = loginService.emailLogin(email);
|
||||
return R.ok(LoginResp.builder().token(token).build());
|
||||
}
|
||||
|
||||
@SaIgnore
|
||||
@Operation(summary = "手机号登录", description = "根据手机号和验证码进行登录认证")
|
||||
@PostMapping("/phone")
|
||||
public R<LoginResp> phoneLogin(@Validated @RequestBody PhoneLoginReq loginReq) {
|
||||
String phone = loginReq.getPhone();
|
||||
String captchaKey = CacheConstants.CAPTCHA_KEY_PREFIX + phone;
|
||||
String captcha = RedisUtils.get(captchaKey);
|
||||
ValidationUtils.throwIfBlank(captcha, CAPTCHA_EXPIRED);
|
||||
ValidationUtils.throwIfNotEqualIgnoreCase(loginReq.getCaptcha(), captcha, CAPTCHA_ERROR);
|
||||
RedisUtils.delete(captchaKey);
|
||||
String token = loginService.phoneLogin(phone);
|
||||
return R.ok(LoginResp.builder().token(token).build());
|
||||
}
|
||||
|
||||
@Operation(summary = "用户退出", description = "注销用户的当前登录")
|
||||
@Parameter(name = "Authorization", description = "令牌", required = true, example = "Bearer xxxx-xxxx-xxxx-xxxx", in = ParameterIn.HEADER)
|
||||
@PostMapping("/logout")
|
||||
public R<Object> logout() {
|
||||
Object loginId = StpUtil.getLoginId(-1L);
|
||||
StpUtil.logout();
|
||||
return R.ok(loginId);
|
||||
}
|
||||
|
||||
@Log(ignore = true)
|
||||
@Operation(summary = "获取用户信息", description = "获取登录用户信息")
|
||||
@GetMapping("/user/info")
|
||||
public R<UserInfoResp> getUserInfo() {
|
||||
LoginUser loginUser = LoginHelper.getLoginUser();
|
||||
UserDetailResp userDetailResp = userService.get(loginUser.getId());
|
||||
UserInfoResp userInfoResp = BeanUtil.copyProperties(userDetailResp, UserInfoResp.class);
|
||||
userInfoResp.setPermissions(loginUser.getPermissions());
|
||||
userInfoResp.setRoles(loginUser.getRoleCodes());
|
||||
return R.ok(userInfoResp);
|
||||
}
|
||||
|
||||
@Log(ignore = true)
|
||||
@Operation(summary = "获取路由信息", description = "获取登录用户的路由信息")
|
||||
@GetMapping("/route")
|
||||
public R<List<RouteResp>> listRoute() {
|
||||
return R.ok(loginService.buildRouteTree(LoginHelper.getUserId()));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.continew.admin.webapi.auth;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaIgnore;
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import com.xkcoding.justauth.AuthRequestFactory;
|
||||
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 me.zhyd.oauth.model.AuthCallback;
|
||||
import me.zhyd.oauth.model.AuthResponse;
|
||||
import me.zhyd.oauth.model.AuthUser;
|
||||
import me.zhyd.oauth.request.AuthRequest;
|
||||
import me.zhyd.oauth.utils.AuthStateUtils;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import top.continew.admin.auth.model.resp.LoginResp;
|
||||
import top.continew.admin.auth.model.resp.SocialAuthAuthorizeResp;
|
||||
import top.continew.admin.auth.service.LoginService;
|
||||
import top.continew.starter.core.exception.BadRequestException;
|
||||
import top.continew.starter.core.util.validate.ValidationUtils;
|
||||
import top.continew.starter.log.core.annotation.Log;
|
||||
import top.continew.starter.web.model.R;
|
||||
|
||||
/**
|
||||
* 三方账号认证 API
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 2023/10/8 22:52
|
||||
*/
|
||||
@Log(module = "登录")
|
||||
@Tag(name = "三方账号认证 API")
|
||||
@SaIgnore
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@RequestMapping("/oauth")
|
||||
public class SocialAuthController {
|
||||
|
||||
private final LoginService loginService;
|
||||
private final AuthRequestFactory authRequestFactory;
|
||||
|
||||
@Operation(summary = "三方账号登录授权", description = "三方账号登录授权")
|
||||
@Parameter(name = "source", description = "来源", example = "gitee", in = ParameterIn.PATH)
|
||||
@GetMapping("/{source}")
|
||||
public R<SocialAuthAuthorizeResp> authorize(@PathVariable String source) {
|
||||
AuthRequest authRequest = this.getAuthRequest(source);
|
||||
return R.ok(SocialAuthAuthorizeResp.builder()
|
||||
.authorizeUrl(authRequest.authorize(AuthStateUtils.createState()))
|
||||
.build());
|
||||
}
|
||||
|
||||
@Operation(summary = "三方账号登录", description = "三方账号登录")
|
||||
@Parameter(name = "source", description = "来源", example = "gitee", in = ParameterIn.PATH)
|
||||
@PostMapping("/{source}")
|
||||
public R<LoginResp> login(@PathVariable String source, @RequestBody AuthCallback callback) {
|
||||
if (StpUtil.isLogin()) {
|
||||
StpUtil.logout();
|
||||
}
|
||||
AuthRequest authRequest = this.getAuthRequest(source);
|
||||
AuthResponse<AuthUser> response = authRequest.login(callback);
|
||||
ValidationUtils.throwIf(!response.ok(), response.getMsg());
|
||||
AuthUser authUser = response.getData();
|
||||
String token = loginService.socialLogin(authUser);
|
||||
return R.ok(LoginResp.builder().token(token).build());
|
||||
}
|
||||
|
||||
private AuthRequest getAuthRequest(String source) {
|
||||
try {
|
||||
return authRequestFactory.get(source);
|
||||
} catch (Exception e) {
|
||||
throw new BadRequestException("暂不支持 [%s] 平台账号登录".formatted(source));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,178 @@
|
||||
/*
|
||||
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.continew.admin.webapi.common;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaIgnore;
|
||||
import cn.hutool.core.lang.Dict;
|
||||
import cn.hutool.core.lang.RegexPool;
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
import cn.hutool.core.util.RandomUtil;
|
||||
import cn.hutool.extra.servlet.JakartaServletUtil;
|
||||
import com.anji.captcha.model.common.RepCodeEnum;
|
||||
import com.anji.captcha.model.common.ResponseModel;
|
||||
import com.anji.captcha.model.vo.CaptchaVO;
|
||||
import com.anji.captcha.service.CaptchaService;
|
||||
import com.wf.captcha.base.Captcha;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.mail.MessagingException;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.Pattern;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.dromara.sms4j.api.SmsBlend;
|
||||
import org.dromara.sms4j.api.entity.SmsResponse;
|
||||
import org.dromara.sms4j.comm.constant.SupplierConstant;
|
||||
import org.dromara.sms4j.core.factory.SmsFactory;
|
||||
import org.redisson.api.RateType;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import top.continew.admin.common.config.properties.CaptchaProperties;
|
||||
import top.continew.admin.common.constant.CacheConstants;
|
||||
import top.continew.admin.common.model.resp.CaptchaResp;
|
||||
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.core.util.TemplateUtils;
|
||||
import top.continew.starter.core.util.validate.CheckUtils;
|
||||
import top.continew.starter.core.util.validate.ValidationUtils;
|
||||
import top.continew.starter.log.core.annotation.Log;
|
||||
import top.continew.starter.messaging.mail.util.MailUtils;
|
||||
import top.continew.starter.web.model.R;
|
||||
|
||||
import java.time.Duration;
|
||||
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 CaptchaService behaviorCaptchaService;
|
||||
private final GraphicCaptchaService graphicCaptchaService;
|
||||
private final ProjectProperties projectProperties;
|
||||
private final CaptchaProperties captchaProperties;
|
||||
|
||||
@Log(ignore = true)
|
||||
@Operation(summary = "获取行为验证码", description = "获取行为验证码(Base64编码)")
|
||||
@GetMapping("/behavior")
|
||||
public R<Object> getBehaviorCaptcha(CaptchaVO captchaReq, HttpServletRequest request) {
|
||||
captchaReq.setBrowserInfo(JakartaServletUtil.getClientIP(request) + request.getHeader(HttpHeaders.USER_AGENT));
|
||||
return R.ok(behaviorCaptchaService.get(captchaReq).getRepData());
|
||||
}
|
||||
|
||||
@Log(ignore = true)
|
||||
@Operation(summary = "校验行为验证码", description = "校验行为验证码")
|
||||
@PostMapping("/behavior")
|
||||
public R<Object> checkBehaviorCaptcha(@RequestBody CaptchaVO captchaReq) {
|
||||
return R.ok(behaviorCaptchaService.check(captchaReq));
|
||||
}
|
||||
|
||||
@Log(ignore = true)
|
||||
@Operation(summary = "获取图片验证码", description = "获取图片验证码(Base64编码,带图片格式:data:image/gif;base64)")
|
||||
@GetMapping("/img")
|
||||
public R<CaptchaResp> getImageCaptcha() {
|
||||
String uuid = IdUtil.fastUUID();
|
||||
String captchaKey = CacheConstants.CAPTCHA_KEY_PREFIX + uuid;
|
||||
Captcha captcha = graphicCaptchaService.getCaptcha();
|
||||
RedisUtils.set(captchaKey, captcha.text(), Duration.ofMinutes(captchaProperties.getExpirationInMinutes()));
|
||||
return R.ok(CaptchaResp.builder().uuid(uuid).img(captcha.toBase64()).build());
|
||||
}
|
||||
|
||||
@Operation(summary = "获取邮箱验证码", description = "发送验证码到指定邮箱")
|
||||
@GetMapping("/mail")
|
||||
public R<Void> getMailCaptcha(@NotBlank(message = "邮箱不能为空") @Pattern(regexp = RegexPool.EMAIL, message = "邮箱格式错误") String email) throws MessagingException {
|
||||
String limitKeyPrefix = CacheConstants.LIMIT_KEY_PREFIX;
|
||||
String captchaKeyPrefix = CacheConstants.CAPTCHA_KEY_PREFIX;
|
||||
String limitCaptchaKey = limitKeyPrefix + captchaKeyPrefix + email;
|
||||
long limitTimeInMillisecond = RedisUtils.getTimeToLive(limitCaptchaKey);
|
||||
CheckUtils.throwIf(limitTimeInMillisecond > 0, "发送验证码过于频繁,请您 {}s 后再试", limitTimeInMillisecond / 1000);
|
||||
// 生成验证码
|
||||
CaptchaProperties.CaptchaMail captchaMail = captchaProperties.getMail();
|
||||
String captcha = RandomUtil.randomNumbers(captchaMail.getLength());
|
||||
// 发送验证码
|
||||
Long expirationInMinutes = captchaMail.getExpirationInMinutes();
|
||||
String content = TemplateUtils.render(captchaMail.getTemplatePath(), Dict.create()
|
||||
.set("captcha", captcha)
|
||||
.set("expiration", expirationInMinutes));
|
||||
MailUtils.sendHtml(email, "【%s】邮箱验证码".formatted(projectProperties.getName()), content);
|
||||
// 保存验证码
|
||||
String captchaKey = captchaKeyPrefix + email;
|
||||
RedisUtils.set(captchaKey, captcha, Duration.ofMinutes(expirationInMinutes));
|
||||
RedisUtils.set(limitCaptchaKey, captcha, Duration.ofSeconds(captchaMail.getLimitInSeconds()));
|
||||
return R.ok("发送成功,验证码有效期 %s 分钟".formatted(expirationInMinutes));
|
||||
}
|
||||
|
||||
@Operation(summary = "获取短信验证码", description = "发送验证码到指定手机号")
|
||||
@GetMapping("/sms")
|
||||
public R<Void> getSmsCaptcha(@NotBlank(message = "手机号不能为空") @Pattern(regexp = RegexPool.MOBILE, message = "手机号格式错误") String phone,
|
||||
CaptchaVO captchaReq,
|
||||
HttpServletRequest request) {
|
||||
// 行为验证码校验
|
||||
ResponseModel verificationRes = behaviorCaptchaService.verification(captchaReq);
|
||||
ValidationUtils.throwIfNotEqual(verificationRes.getRepCode(), RepCodeEnum.SUCCESS.getCode(), verificationRes
|
||||
.getRepMsg());
|
||||
CaptchaProperties.CaptchaSms captchaSms = captchaProperties.getSms();
|
||||
String templateId = captchaSms.getTemplateId();
|
||||
String limitKeyPrefix = CacheConstants.LIMIT_KEY_PREFIX;
|
||||
String captchaKeyPrefix = CacheConstants.CAPTCHA_KEY_PREFIX;
|
||||
String limitTemplateKeyPrefix = limitKeyPrefix + captchaKeyPrefix;
|
||||
// 限制短信发送频率
|
||||
// 1.同一号码同一短信模板,1分钟2条,1小时8条,24小时20条,e.g. LIMIT:CAPTCHA:XXX:188xxxxx:1
|
||||
final String errorMsg = "获取验证码操作太频繁,请稍后再试";
|
||||
CheckUtils.throwIf(!RedisUtils.rateLimit(RedisUtils
|
||||
.formatKey(limitTemplateKeyPrefix + "MIN", phone, templateId), RateType.OVERALL, 2, 60), errorMsg);
|
||||
CheckUtils.throwIf(!RedisUtils.rateLimit(RedisUtils
|
||||
.formatKey(limitTemplateKeyPrefix + "HOUR", phone, templateId), RateType.OVERALL, 8, 60 * 60), errorMsg);
|
||||
CheckUtils.throwIf(!RedisUtils.rateLimit(RedisUtils
|
||||
.formatKey(limitTemplateKeyPrefix + "DAY", phone, templateId), RateType.OVERALL, 20, 60 * 60 * 24), errorMsg);
|
||||
// 2.同一号码所有短信模板 24 小时 100 条,e.g. LIMIT:CAPTCHA:188xxxxx
|
||||
String limitPhoneKey = limitKeyPrefix + captchaKeyPrefix + phone;
|
||||
CheckUtils.throwIf(!RedisUtils.rateLimit(limitPhoneKey, RateType.OVERALL, 100, 60 * 60 * 24), errorMsg);
|
||||
// 3.同一 IP 每分钟限制发送 30 条,e.g. LIMIT:CAPTCHA:PHONE:1xx.1xx.1xx.1xx
|
||||
String limitIpKey = RedisUtils.formatKey(limitKeyPrefix + captchaKeyPrefix + "PHONE", JakartaServletUtil
|
||||
.getClientIP(request));
|
||||
CheckUtils.throwIf(!RedisUtils.rateLimit(limitIpKey, RateType.OVERALL, 30, 60), errorMsg);
|
||||
// 生成验证码
|
||||
String captcha = RandomUtil.randomNumbers(captchaSms.getLength());
|
||||
// 发送验证码
|
||||
Long expirationInMinutes = captchaSms.getExpirationInMinutes();
|
||||
SmsBlend smsBlend = SmsFactory.getBySupplier(SupplierConstant.CLOOPEN);
|
||||
Map<String, String> messageMap = MapUtil.newHashMap(2, true);
|
||||
messageMap.put("captcha", captcha);
|
||||
messageMap.put("expirationInMinutes", String.valueOf(expirationInMinutes));
|
||||
SmsResponse smsResponse = smsBlend.sendMessage(phone, captchaSms
|
||||
.getTemplateId(), (LinkedHashMap<String, String>)messageMap);
|
||||
CheckUtils.throwIf(!smsResponse.isSuccess(), "验证码发送失败");
|
||||
// 保存验证码
|
||||
String captchaKey = captchaKeyPrefix + phone;
|
||||
RedisUtils.set(captchaKey, captcha, Duration.ofMinutes(expirationInMinutes));
|
||||
return R.ok("发送成功,验证码有效期 %s 分钟".formatted(expirationInMinutes));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.continew.admin.webapi.common;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaIgnore;
|
||||
import cn.hutool.core.lang.tree.Tree;
|
||||
import cn.hutool.core.util.ClassUtil;
|
||||
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.continew.admin.common.constant.CacheConstants;
|
||||
import top.continew.admin.common.model.resp.LabelValueResp;
|
||||
import top.continew.admin.system.model.query.DeptQuery;
|
||||
import top.continew.admin.system.model.query.MenuQuery;
|
||||
import top.continew.admin.system.model.query.OptionQuery;
|
||||
import top.continew.admin.system.model.query.RoleQuery;
|
||||
import top.continew.admin.system.model.resp.FileUploadResp;
|
||||
import top.continew.admin.system.service.*;
|
||||
import top.continew.starter.core.autoconfigure.project.ProjectProperties;
|
||||
import top.continew.starter.core.util.validate.ValidationUtils;
|
||||
import top.continew.starter.data.mybatis.plus.base.IBaseEnum;
|
||||
import top.continew.starter.extension.crud.model.query.SortQuery;
|
||||
import top.continew.starter.log.core.annotation.Log;
|
||||
import top.continew.starter.web.model.R;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 公共 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 ProjectProperties projectProperties;
|
||||
private final FileService fileService;
|
||||
private final DeptService deptService;
|
||||
private final MenuService menuService;
|
||||
private final RoleService roleService;
|
||||
private final DictItemService dictItemService;
|
||||
private final OptionService optionService;
|
||||
|
||||
@Operation(summary = "上传文件", description = "上传文件")
|
||||
@PostMapping("/file")
|
||||
public R<FileUploadResp> upload(@NotNull(message = "文件不能为空") MultipartFile file) {
|
||||
ValidationUtils.throwIf(projectProperties.isProduction(), "演示环境不支持上传文件");
|
||||
ValidationUtils.throwIf(file::isEmpty, "文件不能为空");
|
||||
FileInfo fileInfo = fileService.upload(file);
|
||||
return R.ok(FileUploadResp.builder().url(fileInfo.getUrl()).build());
|
||||
}
|
||||
|
||||
@Operation(summary = "查询部门树", description = "查询树结构的部门列表")
|
||||
@GetMapping("/tree/dept")
|
||||
public R<List<Tree<Long>>> listDeptTree(DeptQuery query, SortQuery sortQuery) {
|
||||
return R.ok(deptService.tree(query, sortQuery, true));
|
||||
}
|
||||
|
||||
@Operation(summary = "查询菜单树", description = "查询树结构的菜单列表")
|
||||
@GetMapping("/tree/menu")
|
||||
public R<List<Tree<Long>>> listMenuTree(MenuQuery query, SortQuery sortQuery) {
|
||||
return R.ok(menuService.tree(query, sortQuery, true));
|
||||
}
|
||||
|
||||
@Operation(summary = "查询角色字典", description = "查询角色字典列表")
|
||||
@GetMapping("/dict/role")
|
||||
public R<List<LabelValueResp<Long>>> listRoleDict(RoleQuery query, SortQuery sortQuery) {
|
||||
return R.ok(roleService.buildDict(roleService.list(query, sortQuery)));
|
||||
}
|
||||
|
||||
@Operation(summary = "查询字典", description = "查询字典列表")
|
||||
@Parameter(name = "code", description = "字典编码", example = "announcement_type", in = ParameterIn.PATH)
|
||||
@GetMapping("/dict/{code}")
|
||||
public R<List<LabelValueResp<Serializable>>> listDict(@PathVariable String code) {
|
||||
Optional<Class<?>> enumClassOptional = this.getEnumClassByName(code);
|
||||
return R.ok(enumClassOptional.map(this::listEnumDict).orElseGet(() -> dictItemService.listByDictCode(code)));
|
||||
}
|
||||
|
||||
@SaIgnore
|
||||
@Operation(summary = "查询参数", description = "查询参数")
|
||||
@GetMapping("/option")
|
||||
@Cached(key = "#query.code", name = CacheConstants.OPTION_KEY_PREFIX)
|
||||
public R<List<LabelValueResp<String>>> listOption(@Validated OptionQuery query) {
|
||||
return R.ok(optionService.list(query)
|
||||
.stream()
|
||||
.map(option -> new LabelValueResp<>(option.getCode(), StrUtil.nullToDefault(option.getValue(), option
|
||||
.getDefaultValue())))
|
||||
.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据枚举类名查询
|
||||
*
|
||||
* @param enumClassName 枚举类名
|
||||
* @return 枚举类型
|
||||
*/
|
||||
private Optional<Class<?>> getEnumClassByName(String enumClassName) {
|
||||
Set<Class<?>> classSet = ClassUtil.scanPackageBySuper(projectProperties.getBasePackage(), IBaseEnum.class);
|
||||
return classSet.stream()
|
||||
.filter(c -> StrUtil.equalsAnyIgnoreCase(c.getSimpleName(), enumClassName, StrUtil
|
||||
.toCamelCase(enumClassName)))
|
||||
.findFirst();
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询枚举字典
|
||||
*
|
||||
* @param enumClass 枚举类型
|
||||
* @return 枚举字典
|
||||
*/
|
||||
private List<LabelValueResp<Serializable>> listEnumDict(Class<?> enumClass) {
|
||||
Object[] enumConstants = enumClass.getEnumConstants();
|
||||
return Arrays.stream(enumConstants).map(e -> {
|
||||
IBaseEnum baseEnum = (IBaseEnum)e;
|
||||
return new LabelValueResp<>(baseEnum.getDescription(), baseEnum.getValue(), baseEnum.getColor());
|
||||
}).toList();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.continew.admin.webapi.common;
|
||||
|
||||
import com.alicp.jetcache.anno.CachePenetrationProtect;
|
||||
import com.alicp.jetcache.anno.CacheRefresh;
|
||||
import com.alicp.jetcache.anno.CacheType;
|
||||
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 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.continew.admin.common.constant.CacheConstants;
|
||||
import top.continew.admin.system.model.resp.DashboardAccessTrendResp;
|
||||
import top.continew.admin.system.model.resp.DashboardGeoDistributionResp;
|
||||
import top.continew.admin.system.model.resp.DashboardPopularModuleResp;
|
||||
import top.continew.admin.system.model.resp.DashboardTotalResp;
|
||||
import top.continew.admin.system.service.DashboardService;
|
||||
import top.continew.admin.system.model.resp.DashboardAnnouncementResp;
|
||||
import top.continew.starter.core.util.validate.ValidationUtils;
|
||||
import top.continew.starter.web.model.R;
|
||||
import top.continew.starter.log.core.annotation.Log;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 仪表盘 API
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 2023/1/22 21:48
|
||||
*/
|
||||
@Tag(name = "仪表盘 API")
|
||||
@Log(ignore = true)
|
||||
@Validated
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@RequestMapping("/dashboard")
|
||||
public class DashboardController {
|
||||
|
||||
private final DashboardService dashboardService;
|
||||
|
||||
@Operation(summary = "查询总计信息", description = "查询总计信息")
|
||||
@GetMapping("/total")
|
||||
public R<DashboardTotalResp> getTotal() {
|
||||
return R.ok(dashboardService.getTotal());
|
||||
}
|
||||
|
||||
@Operation(summary = "查询访问趋势信息", description = "查询访问趋势信息")
|
||||
@Parameter(name = "days", description = "日期数", example = "30", in = ParameterIn.PATH)
|
||||
@GetMapping("/access/trend/{days}")
|
||||
@CachePenetrationProtect
|
||||
@CacheRefresh(refresh = 7200)
|
||||
@Cached(key = "#days", cacheType = CacheType.BOTH, name = CacheConstants.DASHBOARD_KEY_PREFIX, syncLocal = true)
|
||||
public R<List<DashboardAccessTrendResp>> listAccessTrend(@PathVariable Integer days) {
|
||||
ValidationUtils.throwIf(7 != days && 30 != days, "仅支持查询近 7/30 天访问趋势信息");
|
||||
return R.ok(dashboardService.listAccessTrend(days));
|
||||
}
|
||||
|
||||
@Operation(summary = "查询热门模块列表", description = "查询热门模块列表")
|
||||
@GetMapping("/popular/module")
|
||||
public R<List<DashboardPopularModuleResp>> listPopularModule() {
|
||||
return R.ok(dashboardService.listPopularModule());
|
||||
}
|
||||
|
||||
@Operation(summary = "查询访客地域分布信息", description = "查询访客地域分布信息")
|
||||
@GetMapping("/geo/distribution")
|
||||
public R<DashboardGeoDistributionResp> getGeoDistribution() {
|
||||
return R.ok(dashboardService.getGeoDistribution());
|
||||
}
|
||||
|
||||
@Operation(summary = "查询公告列表", description = "查询公告列表")
|
||||
@GetMapping("/announcement")
|
||||
public R<List<DashboardAnnouncementResp>> listAnnouncement() {
|
||||
return R.ok(dashboardService.listAnnouncement());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.continew.admin.webapi.monitor;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
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.*;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
|
||||
import top.continew.admin.auth.model.query.OnlineUserQuery;
|
||||
import top.continew.admin.auth.model.resp.OnlineUserResp;
|
||||
import top.continew.admin.auth.service.OnlineUserService;
|
||||
import top.continew.starter.core.util.validate.CheckUtils;
|
||||
import top.continew.starter.extension.crud.model.query.PageQuery;
|
||||
import top.continew.starter.extension.crud.model.resp.PageResp;
|
||||
import top.continew.starter.web.model.R;
|
||||
|
||||
/**
|
||||
* 在线用户 API
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 2023/1/20 21:51
|
||||
*/
|
||||
@Tag(name = "在线用户 API")
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@RequestMapping("/monitor/online/user")
|
||||
public class OnlineUserController {
|
||||
|
||||
private final OnlineUserService onlineUserService;
|
||||
|
||||
@Operation(summary = "分页查询列表", description = "分页查询列表")
|
||||
@SaCheckPermission("monitor:online:user:list")
|
||||
@GetMapping
|
||||
public R<PageResp<OnlineUserResp>> page(OnlineUserQuery query, @Validated PageQuery pageQuery) {
|
||||
return R.ok(onlineUserService.page(query, pageQuery));
|
||||
}
|
||||
|
||||
@Operation(summary = "强退在线用户", description = "强退在线用户")
|
||||
@Parameter(name = "token", description = "令牌", example = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJsb2dpblR5cGUiOiJsb2dpbiIsImxvZ2luSWQiOjEsInJuU3RyIjoiTUd6djdyOVFoeHEwdVFqdFAzV3M5YjVJRzh4YjZPSEUifQ.7q7U3ouoN7WPhH2kUEM7vPe5KF3G_qavSG-vRgIxKvE", in = ParameterIn.PATH)
|
||||
@SaCheckPermission("monitor:online:user:delete")
|
||||
@DeleteMapping("/{token}")
|
||||
public R<Void> kickout(@PathVariable String token) {
|
||||
String currentToken = StpUtil.getTokenValue();
|
||||
CheckUtils.throwIfEqual(token, currentToken, "不能强退自己");
|
||||
StpUtil.kickoutByTokenValue(token);
|
||||
return R.ok("强退成功");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.continew.admin.webapi.system;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
|
||||
import top.continew.admin.system.model.query.AnnouncementQuery;
|
||||
import top.continew.admin.system.model.req.AnnouncementReq;
|
||||
import top.continew.admin.system.model.resp.AnnouncementDetailResp;
|
||||
import top.continew.admin.system.model.resp.AnnouncementResp;
|
||||
import top.continew.admin.system.service.AnnouncementService;
|
||||
import top.continew.starter.core.util.validate.ValidationUtils;
|
||||
import top.continew.starter.extension.crud.annotation.CrudRequestMapping;
|
||||
import top.continew.starter.extension.crud.controller.BaseController;
|
||||
import top.continew.starter.extension.crud.util.ValidateGroup;
|
||||
import top.continew.starter.web.model.R;
|
||||
|
||||
/**
|
||||
* 公告管理 API
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 2023/8/20 10:55
|
||||
*/
|
||||
@Tag(name = "公告管理 API")
|
||||
@RestController
|
||||
@CrudRequestMapping("/system/announcement")
|
||||
public class AnnouncementController extends BaseController<AnnouncementService, AnnouncementResp, AnnouncementDetailResp, AnnouncementQuery, AnnouncementReq> {
|
||||
|
||||
@Override
|
||||
@SaCheckPermission("system:announcement:add")
|
||||
public R<Long> add(@Validated(ValidateGroup.Crud.Add.class) @RequestBody AnnouncementReq req) {
|
||||
this.checkTime(req);
|
||||
return super.add(req);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SaCheckPermission("system:announcement:update")
|
||||
public R<Void> update(@Validated(ValidateGroup.Crud.Update.class) @RequestBody AnnouncementReq req,
|
||||
@PathVariable Long id) {
|
||||
this.checkTime(req);
|
||||
return super.update(req, id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查时间
|
||||
*
|
||||
* @param req 创建或修改信息
|
||||
*/
|
||||
private void checkTime(AnnouncementReq req) {
|
||||
LocalDateTime effectiveTime = req.getEffectiveTime();
|
||||
LocalDateTime terminateTime = req.getTerminateTime();
|
||||
if (null != effectiveTime && null != terminateTime) {
|
||||
ValidationUtils.throwIf(terminateTime.isBefore(effectiveTime), "终止时间必须晚于生效时间");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.continew.admin.webapi.system;
|
||||
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import top.continew.admin.system.model.query.DeptQuery;
|
||||
import top.continew.admin.system.model.req.DeptReq;
|
||||
import top.continew.admin.system.model.resp.DeptResp;
|
||||
import top.continew.admin.system.service.DeptService;
|
||||
import top.continew.starter.extension.crud.annotation.CrudRequestMapping;
|
||||
import top.continew.starter.extension.crud.controller.BaseController;
|
||||
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.GET, Api.ADD, Api.UPDATE, Api.DELETE, Api.EXPORT})
|
||||
public class DeptController extends BaseController<DeptService, DeptResp, DeptResp, DeptQuery, DeptReq> {
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.continew.admin.webapi.system;
|
||||
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import top.continew.admin.system.model.query.DictQuery;
|
||||
import top.continew.admin.system.model.req.DictReq;
|
||||
import top.continew.admin.system.model.resp.DictResp;
|
||||
import top.continew.admin.system.service.DictService;
|
||||
import top.continew.starter.extension.crud.annotation.CrudRequestMapping;
|
||||
import top.continew.starter.extension.crud.controller.BaseController;
|
||||
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.PAGE, Api.GET, Api.ADD, Api.UPDATE, Api.DELETE})
|
||||
public class DictController extends BaseController<DictService, DictResp, DictResp, DictQuery, DictReq> {
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.continew.admin.webapi.system;
|
||||
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import top.continew.admin.system.model.query.DictItemQuery;
|
||||
import top.continew.admin.system.model.req.DictItemReq;
|
||||
import top.continew.admin.system.model.resp.DictItemResp;
|
||||
import top.continew.admin.system.service.DictItemService;
|
||||
import top.continew.starter.extension.crud.annotation.CrudRequestMapping;
|
||||
import top.continew.starter.extension.crud.controller.BaseController;
|
||||
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/item", api = {Api.PAGE, Api.GET, Api.ADD, Api.UPDATE, Api.DELETE})
|
||||
public class DictItemController extends BaseController<DictItemService, DictItemResp, DictItemResp, DictItemQuery, DictItemReq> {
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.continew.admin.webapi.system;
|
||||
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import top.continew.admin.system.model.query.FileQuery;
|
||||
import top.continew.admin.system.model.req.FileReq;
|
||||
import top.continew.admin.system.model.resp.FileResp;
|
||||
import top.continew.admin.system.service.FileService;
|
||||
import top.continew.starter.extension.crud.annotation.CrudRequestMapping;
|
||||
import top.continew.starter.extension.crud.controller.BaseController;
|
||||
import top.continew.starter.extension.crud.enums.Api;
|
||||
|
||||
/**
|
||||
* 文件管理 API
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 2023/12/23 10:38
|
||||
*/
|
||||
@Tag(name = "文件管理 API")
|
||||
@RestController
|
||||
@CrudRequestMapping(value = "/system/file", api = {Api.PAGE, Api.UPDATE, Api.DELETE})
|
||||
public class FileController extends BaseController<FileService, FileResp, FileResp, FileQuery, FileReq> {
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.continew.admin.webapi.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.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.continew.admin.system.model.query.LogQuery;
|
||||
import top.continew.admin.system.model.resp.log.LogDetailResp;
|
||||
import top.continew.admin.system.model.resp.log.LogResp;
|
||||
import top.continew.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;
|
||||
import top.continew.starter.web.model.R;
|
||||
|
||||
/**
|
||||
* 系统日志 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 = "分页查询列表")
|
||||
@GetMapping
|
||||
public R<PageResp<LogResp>> page(LogQuery query, @Validated PageQuery pageQuery) {
|
||||
return R.ok(baseService.page(query, pageQuery));
|
||||
}
|
||||
|
||||
@Operation(summary = "查询详情", description = "查询详情")
|
||||
@Parameter(name = "id", description = "ID", example = "1", in = ParameterIn.PATH)
|
||||
@GetMapping("/{id}")
|
||||
public R<LogDetailResp> get(@PathVariable Long id) {
|
||||
return R.ok(baseService.get(id));
|
||||
}
|
||||
|
||||
@Operation(summary = "导出登录日志", description = "导出登录日志")
|
||||
@GetMapping("/export/login")
|
||||
public void exportLoginLog(LogQuery query, SortQuery sortQuery, HttpServletResponse response) {
|
||||
baseService.exportLoginLog(query, sortQuery, response);
|
||||
}
|
||||
|
||||
@Operation(summary = "导出操作日志", description = "导出操作日志")
|
||||
@GetMapping("/export/operation")
|
||||
public void exportOperationLog(LogQuery query, SortQuery sortQuery, HttpServletResponse response) {
|
||||
baseService.exportOperationLog(query, sortQuery, response);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.continew.admin.webapi.system;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
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.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import top.continew.admin.system.model.query.MenuQuery;
|
||||
import top.continew.admin.system.model.req.MenuReq;
|
||||
import top.continew.admin.system.model.resp.MenuResp;
|
||||
import top.continew.admin.system.service.MenuService;
|
||||
import top.continew.starter.core.util.URLUtils;
|
||||
import top.continew.starter.core.util.validate.ValidationUtils;
|
||||
import top.continew.starter.extension.crud.annotation.CrudRequestMapping;
|
||||
import top.continew.starter.extension.crud.controller.BaseController;
|
||||
import top.continew.starter.extension.crud.enums.Api;
|
||||
import top.continew.starter.extension.crud.util.ValidateGroup;
|
||||
import top.continew.starter.web.model.R;
|
||||
|
||||
/**
|
||||
* 菜单管理 API
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 2023/2/15 20:35
|
||||
*/
|
||||
@Tag(name = "菜单管理 API")
|
||||
@RestController
|
||||
@CrudRequestMapping(value = "/system/menu", api = {Api.TREE, Api.GET, Api.ADD, Api.UPDATE, Api.DELETE})
|
||||
public class MenuController extends BaseController<MenuService, MenuResp, MenuResp, MenuQuery, MenuReq> {
|
||||
|
||||
@Override
|
||||
@SaCheckPermission("system:menu:add")
|
||||
public R<Long> add(@Validated(ValidateGroup.Crud.Add.class) @RequestBody MenuReq req) {
|
||||
this.checkPath(req);
|
||||
return super.add(req);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SaCheckPermission("system:menu:update")
|
||||
public R<Void> update(@Validated(ValidateGroup.Crud.Update.class) @RequestBody MenuReq req, @PathVariable Long id) {
|
||||
this.checkPath(req);
|
||||
return super.update(req, id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查路由地址格式
|
||||
*
|
||||
* @param req 创建或修改信息
|
||||
*/
|
||||
private void checkPath(MenuReq req) {
|
||||
Boolean isExternal = ObjectUtil.defaultIfNull(req.getIsExternal(), false);
|
||||
String path = req.getPath();
|
||||
ValidationUtils.throwIf(isExternal && !URLUtils.isHttpUrl(path), "路由地址格式错误,请以 http:// 或 https:// 开头");
|
||||
ValidationUtils.throwIf(!isExternal && URLUtils.isHttpUrl(path), "路由地址格式错误");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.continew.admin.webapi.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 lombok.RequiredArgsConstructor;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import top.continew.admin.common.util.helper.LoginHelper;
|
||||
import top.continew.admin.system.model.query.MessageQuery;
|
||||
import top.continew.admin.system.model.resp.MessageResp;
|
||||
import top.continew.admin.system.model.resp.MessageUnreadResp;
|
||||
import top.continew.admin.system.service.MessageService;
|
||||
import top.continew.admin.system.service.MessageUserService;
|
||||
import top.continew.starter.extension.crud.model.query.PageQuery;
|
||||
import top.continew.starter.extension.crud.model.resp.PageResp;
|
||||
import top.continew.starter.web.model.R;
|
||||
import top.continew.starter.log.core.annotation.Log;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 消息管理 API
|
||||
*
|
||||
* @author Bull-BCLS
|
||||
* @since 2023/10/15 19:05
|
||||
*/
|
||||
@Tag(name = "消息管理 API")
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@RequestMapping("/system/message")
|
||||
public class MessageController {
|
||||
|
||||
private final MessageService baseService;
|
||||
private final MessageUserService messageUserService;
|
||||
|
||||
@Operation(summary = "分页查询列表", description = "分页查询列表")
|
||||
@GetMapping
|
||||
public R<PageResp<MessageResp>> page(MessageQuery query, @Validated PageQuery pageQuery) {
|
||||
query.setUserId(LoginHelper.getUserId());
|
||||
return R.ok(baseService.page(query, pageQuery));
|
||||
}
|
||||
|
||||
@Operation(summary = "删除数据", description = "删除数据")
|
||||
@Parameter(name = "ids", description = "ID 列表", example = "1,2", in = ParameterIn.PATH)
|
||||
@DeleteMapping("/{ids}")
|
||||
public R<Void> delete(@PathVariable List<Long> ids) {
|
||||
baseService.delete(ids);
|
||||
return R.ok("删除成功");
|
||||
}
|
||||
|
||||
@Operation(summary = "标记已读", description = "将消息标记为已读状态")
|
||||
@Parameter(name = "ids", description = "消息ID列表", example = "1,2", in = ParameterIn.QUERY)
|
||||
@PatchMapping("/read")
|
||||
public R<Void> readMessage(@RequestParam(required = false) List<Long> ids) {
|
||||
messageUserService.readMessage(ids);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
@Log(ignore = true)
|
||||
@Operation(summary = "查询未读消息数量", description = "查询当前用户的未读消息数量")
|
||||
@Parameter(name = "isDetail", description = "是否查询详情", example = "true", in = ParameterIn.QUERY)
|
||||
@GetMapping("/unread")
|
||||
public R<MessageUnreadResp> countUnreadMessage(@RequestParam(required = false) Boolean detail) {
|
||||
return R.ok(messageUserService.countUnreadMessageByUserId(LoginHelper.getUserId(), detail));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.continew.admin.webapi.system;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
|
||||
import top.continew.admin.system.model.query.OptionQuery;
|
||||
import top.continew.admin.system.model.req.OptionReq;
|
||||
import top.continew.admin.system.model.req.OptionResetValueReq;
|
||||
import top.continew.admin.system.model.resp.OptionResp;
|
||||
import top.continew.admin.system.service.OptionService;
|
||||
import top.continew.starter.web.model.R;
|
||||
|
||||
/**
|
||||
* 参数管理 API
|
||||
*
|
||||
* @author Bull-BCLS
|
||||
* @since 2023/8/26 19:38
|
||||
*/
|
||||
@Tag(name = "参数管理 API")
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@RequestMapping("/system/option")
|
||||
public class OptionController {
|
||||
|
||||
private final OptionService optionService;
|
||||
|
||||
@Operation(summary = "查询参数列表", description = "查询参数列表")
|
||||
@SaCheckPermission("system:config:list")
|
||||
@GetMapping
|
||||
public R<List<OptionResp>> list(@Validated OptionQuery query) {
|
||||
return R.ok(optionService.list(query));
|
||||
}
|
||||
|
||||
@Operation(summary = "修改参数", description = "修改参数")
|
||||
@SaCheckPermission("system:config:update")
|
||||
@PatchMapping
|
||||
public R<Void> update(@Validated @RequestBody List<OptionReq> req) {
|
||||
optionService.update(req);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
@Operation(summary = "重置参数", description = "重置参数")
|
||||
@SaCheckPermission("system:config:reset")
|
||||
@PatchMapping("/value")
|
||||
public R<Void> resetValue(@Validated @RequestBody OptionResetValueReq req) {
|
||||
optionService.resetValue(req);
|
||||
return R.ok();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.continew.admin.webapi.system;
|
||||
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import top.continew.admin.system.model.query.RoleQuery;
|
||||
import top.continew.admin.system.model.req.RoleReq;
|
||||
import top.continew.admin.system.model.resp.RoleDetailResp;
|
||||
import top.continew.admin.system.model.resp.RoleResp;
|
||||
import top.continew.admin.system.service.RoleService;
|
||||
import top.continew.starter.extension.crud.annotation.CrudRequestMapping;
|
||||
import top.continew.starter.extension.crud.controller.BaseController;
|
||||
import top.continew.starter.extension.crud.enums.Api;
|
||||
|
||||
/**
|
||||
* 角色管理 API
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 2023/2/8 23:11
|
||||
*/
|
||||
@Tag(name = "角色管理 API")
|
||||
@RestController
|
||||
@CrudRequestMapping(value = "/system/role", api = {Api.PAGE, Api.GET, Api.ADD, Api.UPDATE, Api.DELETE})
|
||||
public class RoleController extends BaseController<RoleService, RoleResp, RoleDetailResp, RoleQuery, RoleReq> {
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.continew.admin.webapi.system;
|
||||
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import top.continew.admin.system.model.query.StorageQuery;
|
||||
import top.continew.admin.system.model.req.StorageReq;
|
||||
import top.continew.admin.system.model.resp.StorageResp;
|
||||
import top.continew.admin.system.service.StorageService;
|
||||
import top.continew.starter.extension.crud.annotation.CrudRequestMapping;
|
||||
import top.continew.starter.extension.crud.controller.BaseController;
|
||||
import top.continew.starter.extension.crud.enums.Api;
|
||||
|
||||
/**
|
||||
* 存储管理 API
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 2023/12/26 22:09
|
||||
*/
|
||||
@Tag(name = "存储管理 API")
|
||||
@RestController
|
||||
@CrudRequestMapping(value = "/system/storage", api = {Api.PAGE, Api.GET, Api.ADD, Api.UPDATE, Api.DELETE})
|
||||
public class StorageController extends BaseController<StorageService, StorageResp, StorageResp, StorageQuery, StorageReq> {
|
||||
}
|
||||
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.continew.admin.webapi.system;
|
||||
|
||||
import cn.hutool.core.util.ReUtil;
|
||||
import com.xkcoding.justauth.AuthRequestFactory;
|
||||
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 me.zhyd.oauth.model.AuthCallback;
|
||||
import me.zhyd.oauth.model.AuthResponse;
|
||||
import me.zhyd.oauth.model.AuthUser;
|
||||
import me.zhyd.oauth.request.AuthRequest;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import top.continew.admin.common.constant.CacheConstants;
|
||||
import top.continew.admin.common.constant.RegexConstants;
|
||||
import top.continew.admin.common.enums.SocialSourceEnum;
|
||||
import top.continew.admin.common.util.SecureUtils;
|
||||
import top.continew.admin.common.util.helper.LoginHelper;
|
||||
import top.continew.admin.system.model.entity.UserSocialDO;
|
||||
import top.continew.admin.system.model.req.UserBasicInfoUpdateReq;
|
||||
import top.continew.admin.system.model.req.UserEmailUpdateRequest;
|
||||
import top.continew.admin.system.model.req.UserPasswordUpdateReq;
|
||||
import top.continew.admin.system.model.req.UserPhoneUpdateReq;
|
||||
import top.continew.admin.system.model.resp.AvatarResp;
|
||||
import top.continew.admin.system.model.resp.UserSocialBindResp;
|
||||
import top.continew.admin.system.service.UserService;
|
||||
import top.continew.admin.system.service.UserSocialService;
|
||||
import top.continew.starter.cache.redisson.util.RedisUtils;
|
||||
import top.continew.starter.core.util.ExceptionUtils;
|
||||
import top.continew.starter.core.util.validate.ValidationUtils;
|
||||
import top.continew.starter.web.model.R;
|
||||
|
||||
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;
|
||||
private final AuthRequestFactory authRequestFactory;
|
||||
|
||||
@Operation(summary = "上传头像", description = "用户上传个人头像")
|
||||
@PostMapping("/avatar")
|
||||
public R<AvatarResp> uploadAvatar(@NotNull(message = "头像不能为空") MultipartFile avatarFile) {
|
||||
ValidationUtils.throwIf(avatarFile::isEmpty, "头像不能为空");
|
||||
String newAvatar = userService.uploadAvatar(avatarFile, LoginHelper.getUserId());
|
||||
return R.ok("上传成功", AvatarResp.builder().avatar(newAvatar).build());
|
||||
}
|
||||
|
||||
@Operation(summary = "修改基础信息", description = "修改用户基础信息")
|
||||
@PatchMapping("/basic/info")
|
||||
public R<Void> updateBasicInfo(@Validated @RequestBody UserBasicInfoUpdateReq req) {
|
||||
userService.updateBasicInfo(req, LoginHelper.getUserId());
|
||||
return R.ok("修改成功");
|
||||
}
|
||||
|
||||
@Operation(summary = "修改密码", description = "修改用户登录密码")
|
||||
@PatchMapping("/password")
|
||||
public R<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, "新密码解密失败");
|
||||
ValidationUtils.throwIf(!ReUtil
|
||||
.isMatch(RegexConstants.PASSWORD, rawNewPassword), "密码长度为 6 到 32 位,可以包含字母、数字、下划线,特殊字符,同时包含字母和数字");
|
||||
userService.updatePassword(rawOldPassword, rawNewPassword, LoginHelper.getUserId());
|
||||
return R.ok("修改成功,请牢记你的新密码");
|
||||
}
|
||||
|
||||
@Operation(summary = "修改手机号", description = "修改手机号")
|
||||
@PatchMapping("/phone")
|
||||
public R<Void> updatePhone(@Validated @RequestBody UserPhoneUpdateReq updateReq) {
|
||||
String rawCurrentPassword = ExceptionUtils.exToNull(() -> SecureUtils.decryptByRsaPrivateKey(updateReq
|
||||
.getCurrentPassword()));
|
||||
ValidationUtils.throwIfBlank(rawCurrentPassword, DECRYPT_FAILED);
|
||||
String captchaKey = CacheConstants.CAPTCHA_KEY_PREFIX + updateReq.getNewPhone();
|
||||
String captcha = RedisUtils.get(captchaKey);
|
||||
ValidationUtils.throwIfBlank(captcha, CAPTCHA_EXPIRED);
|
||||
ValidationUtils.throwIfNotEqualIgnoreCase(updateReq.getCaptcha(), captcha, "验证码错误");
|
||||
RedisUtils.delete(captchaKey);
|
||||
userService.updatePhone(updateReq.getNewPhone(), rawCurrentPassword, LoginHelper.getUserId());
|
||||
return R.ok("修改成功");
|
||||
}
|
||||
|
||||
@Operation(summary = "修改邮箱", description = "修改用户邮箱")
|
||||
@PatchMapping("/email")
|
||||
public R<Void> updateEmail(@Validated @RequestBody UserEmailUpdateRequest updateReq) {
|
||||
String rawCurrentPassword = ExceptionUtils.exToNull(() -> SecureUtils.decryptByRsaPrivateKey(updateReq
|
||||
.getCurrentPassword()));
|
||||
ValidationUtils.throwIfBlank(rawCurrentPassword, DECRYPT_FAILED);
|
||||
String captchaKey = CacheConstants.CAPTCHA_KEY_PREFIX + updateReq.getNewEmail();
|
||||
String captcha = RedisUtils.get(captchaKey);
|
||||
ValidationUtils.throwIfBlank(captcha, CAPTCHA_EXPIRED);
|
||||
ValidationUtils.throwIfNotEqualIgnoreCase(updateReq.getCaptcha(), captcha, "验证码错误");
|
||||
RedisUtils.delete(captchaKey);
|
||||
userService.updateEmail(updateReq.getNewEmail(), rawCurrentPassword, LoginHelper.getUserId());
|
||||
return R.ok("修改成功");
|
||||
}
|
||||
|
||||
@Operation(summary = "查询绑定的三方账号", description = "查询绑定的三方账号")
|
||||
@GetMapping("/social")
|
||||
public R<List<UserSocialBindResp>> listSocialBind() {
|
||||
List<UserSocialDO> userSocialList = userSocialService.listByUserId(LoginHelper.getUserId());
|
||||
List<UserSocialBindResp> userSocialBindList = userSocialList.stream().map(userSocial -> {
|
||||
String source = userSocial.getSource();
|
||||
UserSocialBindResp userSocialBind = new UserSocialBindResp();
|
||||
userSocialBind.setSource(source);
|
||||
userSocialBind.setDescription(SocialSourceEnum.valueOf(source).getDescription());
|
||||
return userSocialBind;
|
||||
}).toList();
|
||||
return R.ok(userSocialBindList);
|
||||
}
|
||||
|
||||
@Operation(summary = "绑定三方账号", description = "绑定三方账号")
|
||||
@Parameter(name = "source", description = "来源", example = "gitee", in = ParameterIn.PATH)
|
||||
@PostMapping("/social/{source}")
|
||||
public R<Void> bindSocial(@PathVariable String source, @RequestBody AuthCallback callback) {
|
||||
AuthRequest authRequest = authRequestFactory.get(source);
|
||||
AuthResponse<AuthUser> response = authRequest.login(callback);
|
||||
ValidationUtils.throwIf(!response.ok(), response.getMsg());
|
||||
AuthUser authUser = response.getData();
|
||||
userSocialService.bind(authUser, LoginHelper.getUserId());
|
||||
return R.ok("绑定成功");
|
||||
}
|
||||
|
||||
@Operation(summary = "解绑三方账号", description = "解绑三方账号")
|
||||
@Parameter(name = "source", description = "来源", example = "gitee", in = ParameterIn.PATH)
|
||||
@DeleteMapping("/social/{source}")
|
||||
public R<Void> unbindSocial(@PathVariable String source) {
|
||||
userSocialService.deleteBySourceAndUserId(source, LoginHelper.getUserId());
|
||||
return R.ok("解绑成功");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.continew.admin.webapi.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 org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.PatchMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import top.continew.admin.common.constant.RegexConstants;
|
||||
import top.continew.admin.common.util.SecureUtils;
|
||||
import top.continew.admin.system.model.query.UserQuery;
|
||||
import top.continew.admin.system.model.req.UserPasswordResetReq;
|
||||
import top.continew.admin.system.model.req.UserReq;
|
||||
import top.continew.admin.system.model.req.UserRoleUpdateReq;
|
||||
import top.continew.admin.system.model.resp.UserDetailResp;
|
||||
import top.continew.admin.system.model.resp.UserResp;
|
||||
import top.continew.admin.system.service.UserService;
|
||||
import top.continew.starter.core.util.ExceptionUtils;
|
||||
import top.continew.starter.core.util.validate.ValidationUtils;
|
||||
import top.continew.starter.extension.crud.annotation.CrudRequestMapping;
|
||||
import top.continew.starter.extension.crud.controller.BaseController;
|
||||
import top.continew.starter.extension.crud.enums.Api;
|
||||
import top.continew.starter.extension.crud.util.ValidateGroup;
|
||||
import top.continew.starter.web.model.R;
|
||||
|
||||
/**
|
||||
* 用户管理 API
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 2023/2/20 21:00
|
||||
*/
|
||||
@Tag(name = "用户管理 API")
|
||||
@Validated
|
||||
@RestController
|
||||
@CrudRequestMapping(value = "/system/user", api = {Api.PAGE, Api.GET, Api.ADD, Api.UPDATE, Api.DELETE, Api.EXPORT})
|
||||
public class UserController extends BaseController<UserService, UserResp, UserDetailResp, UserQuery, UserReq> {
|
||||
|
||||
@Override
|
||||
@SaCheckPermission("system:user:add")
|
||||
public R<Long> add(@Validated(ValidateGroup.Crud.Add.class) @RequestBody UserReq req) {
|
||||
String rawPassword = ExceptionUtils.exToNull(() -> SecureUtils.decryptByRsaPrivateKey(req.getPassword()));
|
||||
ValidationUtils.throwIfNull(rawPassword, "密码解密失败");
|
||||
ValidationUtils.throwIf(!ReUtil
|
||||
.isMatch(RegexConstants.PASSWORD, rawPassword), "密码长度为 6 到 32 位,可以包含字母、数字、下划线,特殊字符,同时包含字母和数字");
|
||||
req.setPassword(rawPassword);
|
||||
Long id = baseService.add(req);
|
||||
return R.ok("新增成功", id);
|
||||
}
|
||||
|
||||
@Operation(summary = "重置密码", description = "重置用户登录密码")
|
||||
@Parameter(name = "id", description = "ID", example = "1", in = ParameterIn.PATH)
|
||||
@SaCheckPermission("system:user:password:reset")
|
||||
@PatchMapping("/{id}/password")
|
||||
public R<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), "密码长度为 6 到 32 位,可以包含字母、数字、下划线,特殊字符,同时包含字母和数字");
|
||||
req.setNewPassword(rawNewPassword);
|
||||
baseService.resetPassword(req, id);
|
||||
return R.ok("重置密码成功");
|
||||
}
|
||||
|
||||
@Operation(summary = "分配角色", description = "为用户新增或移除角色")
|
||||
@Parameter(name = "id", description = "ID", example = "1", in = ParameterIn.PATH)
|
||||
@SaCheckPermission("system:user:role:update")
|
||||
@PatchMapping("/{id}/role")
|
||||
public R<Void> updateRole(@Validated @RequestBody UserRoleUpdateReq updateReq, @PathVariable Long id) {
|
||||
baseService.updateRole(updateReq, id);
|
||||
return R.ok("分配成功");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.continew.admin.webapi.tool;
|
||||
|
||||
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.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import top.continew.admin.generator.model.entity.FieldConfigDO;
|
||||
import top.continew.admin.generator.model.entity.GenConfigDO;
|
||||
import top.continew.admin.generator.model.query.TableQuery;
|
||||
import top.continew.admin.generator.model.req.GenConfigReq;
|
||||
import top.continew.admin.generator.model.resp.GeneratePreviewResp;
|
||||
import top.continew.admin.generator.model.resp.TableResp;
|
||||
import top.continew.admin.generator.service.GeneratorService;
|
||||
import top.continew.starter.core.autoconfigure.project.ProjectProperties;
|
||||
import top.continew.starter.extension.crud.model.query.PageQuery;
|
||||
import top.continew.starter.extension.crud.model.resp.PageResp;
|
||||
import top.continew.starter.web.model.R;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 代码生成 API
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 2023/8/3 22:58
|
||||
*/
|
||||
@Tag(name = "代码生成 API")
|
||||
@Validated
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@RequestMapping("/generator")
|
||||
public class GeneratorController {
|
||||
|
||||
private final ProjectProperties projectProperties;
|
||||
private final GeneratorService generatorService;
|
||||
|
||||
@Operation(summary = "分页查询数据表", description = "分页查询数据表")
|
||||
@SaCheckPermission("tool:generator:list")
|
||||
@GetMapping("/table")
|
||||
public R<PageResp<TableResp>> pageTable(TableQuery query, @Validated PageQuery pageQuery) throws SQLException {
|
||||
return R.ok(generatorService.pageTable(query, pageQuery));
|
||||
}
|
||||
|
||||
@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("tool:generator:list")
|
||||
@GetMapping("/field/{tableName}")
|
||||
public R<List<FieldConfigDO>> listFieldConfig(@PathVariable String tableName,
|
||||
@RequestParam(required = false, defaultValue = "false") Boolean requireSync) {
|
||||
return R.ok(generatorService.listFieldConfig(tableName, requireSync));
|
||||
}
|
||||
|
||||
@Operation(summary = "查询生成配置信息", description = "查询生成配置信息")
|
||||
@Parameter(name = "tableName", description = "表名称", required = true, example = "sys_user", in = ParameterIn.PATH)
|
||||
@SaCheckPermission("tool:generator:list")
|
||||
@GetMapping("/config/{tableName}")
|
||||
public R<GenConfigDO> getGenConfig(@PathVariable String tableName) throws SQLException {
|
||||
return R.ok(generatorService.getGenConfig(tableName));
|
||||
}
|
||||
|
||||
@Operation(summary = "保存配置信息", description = "保存配置信息")
|
||||
@Parameter(name = "tableName", description = "表名称", required = true, example = "sys_user", in = ParameterIn.PATH)
|
||||
@SaCheckPermission("tool:generator:list")
|
||||
@PostMapping("/config/{tableName}")
|
||||
public R<Void> saveConfig(@Validated @RequestBody GenConfigReq req, @PathVariable String tableName) {
|
||||
generatorService.saveConfig(req, tableName);
|
||||
return R.ok("保存成功");
|
||||
}
|
||||
|
||||
@Operation(summary = "生成预览", description = "预览生成代码")
|
||||
@Parameter(name = "tableName", description = "表名称", required = true, example = "sys_user", in = ParameterIn.PATH)
|
||||
@SaCheckPermission("tool:generator:list")
|
||||
@GetMapping("/preview/{tableName}")
|
||||
public R<List<GeneratePreviewResp>> preview(@PathVariable String tableName) {
|
||||
return R.ok(generatorService.preview(tableName));
|
||||
}
|
||||
|
||||
@Operation(summary = "生成代码", description = "生成代码")
|
||||
@Parameter(name = "tableName", description = "表名称", required = true, example = "sys_user", in = ParameterIn.PATH)
|
||||
@SaCheckPermission("tool:generator:list")
|
||||
@PostMapping("/{tableNames}")
|
||||
public void generate(@PathVariable List<String> tableNames,
|
||||
HttpServletRequest request,
|
||||
HttpServletResponse response) {
|
||||
generatorService.generate(tableNames, request, response);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user