feat(新增): ✨ 增加Redis事务,重构项目结构
This commit is contained in:
parent
391dad3840
commit
9444088b48
|
@ -40,11 +40,26 @@
|
|||
<artifactId>redisson</artifactId>
|
||||
<version>3.26.1</version>
|
||||
</dependency>
|
||||
<!-- minio -->
|
||||
<dependency>
|
||||
<groupId>io.minio</groupId>
|
||||
<artifactId>minio</artifactId>
|
||||
</dependency>
|
||||
<!-- 查询ip地址 -->
|
||||
<dependency>
|
||||
<groupId>org.lionsoul</groupId>
|
||||
<artifactId>ip2region</artifactId>
|
||||
<version>2.6.5</version>
|
||||
</dependency>
|
||||
<!-- WebSocket -->
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-websocket</artifactId>
|
||||
</dependency>
|
||||
<!-- 邮箱 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-mail</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
|
|
@ -19,12 +19,12 @@ public class MyBatisPlusFieldConfig implements MetaObjectHandler {
|
|||
@Override
|
||||
public void insertFill(MetaObject metaObject) {
|
||||
// 设置属性值
|
||||
this.strictInsertFill(metaObject, "isDeleted", Integer.class, 0);
|
||||
this.setFieldValByName("createTime", new Date(), metaObject);
|
||||
this.setFieldValByName("updateTime", new Date(), metaObject);
|
||||
this.setFieldValByName("deleteStatus", 1, metaObject);
|
||||
if (BaseContext.getUsername() != null) {
|
||||
this.setFieldValByName("createBy", BaseContext.getUsername(), metaObject);
|
||||
this.setFieldValByName("updateBy", BaseContext.getUsername(), metaObject);
|
||||
this.setFieldValByName("createUser", BaseContext.getUsername(), metaObject);
|
||||
this.setFieldValByName("updateUser", BaseContext.getUsername(), metaObject);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -33,7 +33,9 @@ public class MyBatisPlusFieldConfig implements MetaObjectHandler {
|
|||
*/
|
||||
@Override
|
||||
public void updateFill(MetaObject metaObject) {
|
||||
this.setFieldValByName("updateTime", new Date(), metaObject);
|
||||
this.setFieldValByName("updateBy", BaseContext.getUsername(), metaObject);
|
||||
if (BaseContext.getUserId() != null) {
|
||||
this.setFieldValByName("updateTime", new Date(), metaObject);
|
||||
this.setFieldValByName("updateUser", BaseContext.getUsername(), metaObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,11 +45,14 @@ public class RedisConfiguration {
|
|||
redisTemplate.setConnectionFactory(connectionFactory);
|
||||
// 设置key序列化为string
|
||||
redisTemplate.setKeySerializer(new StringRedisSerializer());
|
||||
|
||||
// 设置value序列化为JSON,使用GenericJackson2JsonRedisSerializer替换默认序列化
|
||||
redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
|
||||
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
|
||||
redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
|
||||
|
||||
// 开启Redis事务
|
||||
redisTemplate.setEnableTransactionSupport(true);
|
||||
return redisTemplate;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,12 +1,10 @@
|
|||
package cn.bunny.common.service.context;
|
||||
|
||||
import cn.bunny.vo.system.login.LoginVo;
|
||||
import cn.bunny.vo.user.LoginVo;
|
||||
|
||||
public class BaseContext {
|
||||
private static final ThreadLocal<Long> userId = new ThreadLocal<>();
|
||||
private static final ThreadLocal<String> username = new ThreadLocal<String>();
|
||||
private static final ThreadLocal<Long> adminId = new ThreadLocal<>();
|
||||
private static final ThreadLocal<String> adminName = new ThreadLocal<>();
|
||||
private static final ThreadLocal<LoginVo> loginVo = new ThreadLocal<>();
|
||||
|
||||
// 用户id相关
|
||||
|
@ -39,26 +37,4 @@ public class BaseContext {
|
|||
userId.remove();
|
||||
loginVo.remove();
|
||||
}
|
||||
|
||||
// adminId 相关
|
||||
public static Long getAdminId() {
|
||||
return adminId.get();
|
||||
}
|
||||
|
||||
public static void setAdminId(Long _adminId) {
|
||||
adminId.set(_adminId);
|
||||
}
|
||||
|
||||
public static String getAdminName() {
|
||||
return adminName.get();
|
||||
}
|
||||
|
||||
public static void setAdminName(String _adminName) {
|
||||
adminName.set(_adminName);
|
||||
}
|
||||
|
||||
public static void removeAdmin() {
|
||||
adminName.remove();
|
||||
adminId.remove();
|
||||
}
|
||||
}
|
|
@ -1,10 +1,12 @@
|
|||
package cn.bunny.common.service.exception;
|
||||
|
||||
|
||||
import cn.bunny.pojo.constant.ExceptionConstant;
|
||||
import cn.bunny.pojo.result.Result;
|
||||
import cn.bunny.pojo.result.ResultCodeEnum;
|
||||
import cn.bunny.pojo.result.constant.ExceptionConstant;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.context.support.DefaultMessageSourceResolvable;
|
||||
import org.springframework.web.bind.MethodArgumentNotValidException;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||
|
@ -12,6 +14,9 @@ import org.springframework.web.bind.annotation.RestControllerAdvice;
|
|||
import java.io.FileNotFoundException;
|
||||
import java.nio.file.AccessDeniedException;
|
||||
import java.sql.SQLIntegrityConstraintViolationException;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@RestControllerAdvice
|
||||
@Slf4j
|
||||
|
@ -32,18 +37,42 @@ public class GlobalExceptionHandler {
|
|||
public Result<Object> exceptionHandler(RuntimeException exception) throws FileNotFoundException {
|
||||
log.error("GlobalExceptionHandler===>运行时异常信息:{}", exception.getMessage());
|
||||
exception.printStackTrace();
|
||||
return Result.error(null, 500, "出错了啦");
|
||||
return Result.error(null, 500, "出错了");
|
||||
}
|
||||
|
||||
// 捕获系统异常
|
||||
@ExceptionHandler(Exception.class)
|
||||
@ResponseBody
|
||||
public Result<Object> error(Exception exception) {
|
||||
log.error("GlobalExceptionHandler===>系统异常信息:{}", exception.getMessage());
|
||||
log.error("捕获系统异常:{}", exception.getMessage());
|
||||
log.error("GlobalExceptionHandler===>系统异常信息:{}", (Object) exception.getStackTrace());
|
||||
|
||||
// 错误消息
|
||||
String message = exception.getMessage();
|
||||
|
||||
// 匹配到内容
|
||||
String patternString = "Request method '(\\w+)' is not supported";
|
||||
Matcher matcher = Pattern.compile(patternString).matcher(message);
|
||||
if (matcher.find()) return Result.error(null, 500, "请求方法错误,不是 " + matcher.group(1));
|
||||
|
||||
// 请求API不存在
|
||||
String noStaticResource = "No static resource (.*)\\.";
|
||||
Matcher noStaticResourceMatcher = Pattern.compile(noStaticResource).matcher(message);
|
||||
if (noStaticResourceMatcher.find())
|
||||
return Result.error(null, 500, "请求API不存在 " + noStaticResourceMatcher.group(1));
|
||||
|
||||
// 返回错误内容
|
||||
return Result.error(null, 500, "系统异常");
|
||||
}
|
||||
|
||||
// 表单验证字段
|
||||
@ExceptionHandler(MethodArgumentNotValidException.class)
|
||||
public Result<String> handleValidationExceptions(MethodArgumentNotValidException ex) {
|
||||
log.error("表单验证失败:{}", ex.getMessage());
|
||||
String errorMessage = ex.getBindingResult().getFieldErrors().stream().map(DefaultMessageSourceResolvable::getDefaultMessage).collect(Collectors.joining(", "));
|
||||
return Result.error(null, 201, errorMessage);
|
||||
}
|
||||
|
||||
// 特定异常处理
|
||||
@ExceptionHandler(ArithmeticException.class)
|
||||
@ResponseBody
|
||||
|
@ -73,10 +102,10 @@ public class GlobalExceptionHandler {
|
|||
// 截取用户名
|
||||
String username = message.split(" ")[2];
|
||||
// 错误信息
|
||||
String errorMessage = username + ExceptionConstant.ALREADY_USER_Exception;
|
||||
String errorMessage = username + ExceptionConstant.ALREADY_USER_EXCEPTION;
|
||||
return Result.error(errorMessage);
|
||||
} else {
|
||||
return Result.error(ExceptionConstant.UNKNOWN_Exception);
|
||||
return Result.error(ExceptionConstant.UNKNOWN_EXCEPTION);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,13 +1,6 @@
|
|||
package cn.bunny.common.service.interceptor;
|
||||
|
||||
import cn.bunny.common.service.context.BaseContext;
|
||||
import cn.bunny.common.service.utils.JwtHelper;
|
||||
import cn.bunny.common.service.utils.ResponseUtil;
|
||||
import cn.bunny.pojo.result.Result;
|
||||
import cn.bunny.pojo.result.ResultCodeEnum;
|
||||
import cn.bunny.pojo.result.constant.RedisUserConstant;
|
||||
import cn.bunny.vo.system.login.LoginVo;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.NonNull;
|
||||
|
@ -16,11 +9,8 @@ import org.springframework.beans.factory.annotation.Autowired;
|
|||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.method.HandlerMethod;
|
||||
import org.springframework.web.servlet.HandlerInterceptor;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* * 微服务请求其它模块找不到Token,无法从线程中获取值
|
||||
* 传递请求头,在微服务中
|
||||
|
@ -34,31 +24,31 @@ public class UserTokenInterceptor implements HandlerInterceptor {
|
|||
@Override
|
||||
public boolean preHandle(HttpServletRequest request, @NonNull HttpServletResponse response, @NonNull Object handler) {
|
||||
String token = request.getHeader("token");
|
||||
Map<String, Object> mapByToken = JwtHelper.getMapByToken(token);
|
||||
LoginVo loginVo = JSONObject.parseObject(JSONObject.toJSONString(mapByToken), LoginVo.class);
|
||||
Object redisUserinfo = redisTemplate.opsForValue().get(RedisUserConstant.getUserLoginInfoPrefix(loginVo.getEmail()));
|
||||
// Map<String, Object> mapByToken = JwtHelper.getMapByToken(token);
|
||||
// LoginVo loginVo = JSONObject.parseObject(JSONObject.toJSONString(mapByToken), LoginVo.class);
|
||||
// Object redisUserinfo = redisTemplate.opsForValue().get(RedisUserConstant.getUserLoginInfoPrefix(loginVo.getEmail()));
|
||||
//
|
||||
// // 不是动态方法直接返回
|
||||
// if (!(handler instanceof HandlerMethod)) return true;
|
||||
//
|
||||
// // token过期-提示身份验证过期
|
||||
// if (JwtHelper.isExpired(token)) {
|
||||
// ResponseUtil.out(response, Result.error(ResultCodeEnum.AUTHENTICATION_EXPIRED));
|
||||
// return false;
|
||||
// }
|
||||
// // 解析不到userId
|
||||
// if (loginVo.getId() == null) {
|
||||
// ResponseUtil.out(response, Result.error(ResultCodeEnum.LOGIN_AUTH));
|
||||
// return false;
|
||||
// }
|
||||
// if (redisUserinfo == null) {
|
||||
// ResponseUtil.out(response, Result.error(ResultCodeEnum.LOGIN_AUTH));
|
||||
// return false;
|
||||
// }
|
||||
|
||||
// 不是动态方法直接返回
|
||||
if (!(handler instanceof HandlerMethod)) return true;
|
||||
|
||||
// token过期-提示身份验证过期
|
||||
if (JwtHelper.isExpired(token)) {
|
||||
ResponseUtil.out(response, Result.error(ResultCodeEnum.AUTHENTICATION_EXPIRED));
|
||||
return false;
|
||||
}
|
||||
// 解析不到userId
|
||||
if (loginVo.getId() == null) {
|
||||
ResponseUtil.out(response, Result.error(ResultCodeEnum.LOGIN_AUTH));
|
||||
return false;
|
||||
}
|
||||
if (redisUserinfo == null) {
|
||||
ResponseUtil.out(response, Result.error(ResultCodeEnum.LOGIN_AUTH));
|
||||
return false;
|
||||
}
|
||||
|
||||
BaseContext.setUserId(loginVo.getId());
|
||||
BaseContext.setUsername(loginVo.getEmail());
|
||||
BaseContext.setLoginVo(loginVo);
|
||||
// BaseContext.setUserId(loginVo.getId());
|
||||
// BaseContext.setUsername(loginVo.getEmail());
|
||||
// BaseContext.setLoginVo(loginVo);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,206 @@
|
|||
package cn.bunny.common.service.utils;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.NameValuePair;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.client.entity.UrlEncodedFormEntity;
|
||||
import org.apache.http.client.methods.HttpDelete;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.client.methods.HttpPut;
|
||||
import org.apache.http.conn.ClientConnectionManager;
|
||||
import org.apache.http.conn.scheme.Scheme;
|
||||
import org.apache.http.conn.scheme.SchemeRegistry;
|
||||
import org.apache.http.conn.ssl.SSLSocketFactory;
|
||||
import org.apache.http.entity.ByteArrayEntity;
|
||||
import org.apache.http.entity.StringEntity;
|
||||
import org.apache.http.impl.client.DefaultHttpClient;
|
||||
import org.apache.http.message.BasicNameValuePair;
|
||||
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.TrustManager;
|
||||
import javax.net.ssl.X509TrustManager;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class HttpUtil {
|
||||
public static HttpResponse doGet(String host, String path, String method, Map<String, String> headers, Map<String, String> querys) throws Exception {
|
||||
HttpClient httpClient = wrapClient(host);
|
||||
|
||||
HttpGet request = new HttpGet(buildUrl(host, path, querys));
|
||||
for (Map.Entry<String, String> e : headers.entrySet()) {
|
||||
request.addHeader(e.getKey(), e.getValue());
|
||||
}
|
||||
|
||||
return httpClient.execute(request);
|
||||
}
|
||||
|
||||
public static HttpResponse doPost(String host, String path, String method, Map<String, String> headers, Map<String, String> querys, Map<String, String> bodys) throws Exception {
|
||||
HttpClient httpClient = wrapClient(host);
|
||||
|
||||
HttpPost request = new HttpPost(buildUrl(host, path, querys));
|
||||
for (Map.Entry<String, String> e : headers.entrySet()) {
|
||||
request.addHeader(e.getKey(), e.getValue());
|
||||
}
|
||||
|
||||
if (bodys != null) {
|
||||
List<NameValuePair> nameValuePairList = new ArrayList<NameValuePair>();
|
||||
|
||||
for (String key : bodys.keySet()) {
|
||||
nameValuePairList.add(new BasicNameValuePair(key, bodys.get(key)));
|
||||
}
|
||||
UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(nameValuePairList, "utf-8");
|
||||
formEntity.setContentType("application/x-www-form-urlencoded; charset=UTF-8");
|
||||
request.setEntity(formEntity);
|
||||
}
|
||||
|
||||
return httpClient.execute(request);
|
||||
}
|
||||
|
||||
|
||||
public static HttpResponse doPost(String host, String path, String method, Map<String, String> headers, Map<String, String> querys, String body) throws Exception {
|
||||
HttpClient httpClient = wrapClient(host);
|
||||
|
||||
HttpPost request = new HttpPost(buildUrl(host, path, querys));
|
||||
for (Map.Entry<String, String> e : headers.entrySet()) {
|
||||
request.addHeader(e.getKey(), e.getValue());
|
||||
}
|
||||
|
||||
if (StringUtils.isNotBlank(body)) {
|
||||
request.setEntity(new StringEntity(body, "utf-8"));
|
||||
}
|
||||
|
||||
return httpClient.execute(request);
|
||||
}
|
||||
|
||||
|
||||
public static HttpResponse doPost(String host, String path, String method, Map<String, String> headers, Map<String, String> querys, byte[] body) throws Exception {
|
||||
HttpClient httpClient = wrapClient(host);
|
||||
|
||||
HttpPost request = new HttpPost(buildUrl(host, path, querys));
|
||||
for (Map.Entry<String, String> e : headers.entrySet()) {
|
||||
request.addHeader(e.getKey(), e.getValue());
|
||||
}
|
||||
|
||||
if (body != null) {
|
||||
request.setEntity(new ByteArrayEntity(body));
|
||||
}
|
||||
|
||||
return httpClient.execute(request);
|
||||
}
|
||||
|
||||
|
||||
public static HttpResponse doPut(String host, String path, String method, Map<String, String> headers, Map<String, String> querys, String body) throws Exception {
|
||||
HttpClient httpClient = wrapClient(host);
|
||||
|
||||
HttpPut request = new HttpPut(buildUrl(host, path, querys));
|
||||
for (Map.Entry<String, String> e : headers.entrySet()) {
|
||||
request.addHeader(e.getKey(), e.getValue());
|
||||
}
|
||||
|
||||
if (StringUtils.isNotBlank(body)) {
|
||||
request.setEntity(new StringEntity(body, "utf-8"));
|
||||
}
|
||||
|
||||
return httpClient.execute(request);
|
||||
}
|
||||
|
||||
|
||||
public static HttpResponse doPut(String host, String path, String method, Map<String, String> headers, Map<String, String> querys, byte[] body) throws Exception {
|
||||
HttpClient httpClient = wrapClient(host);
|
||||
|
||||
HttpPut request = new HttpPut(buildUrl(host, path, querys));
|
||||
for (Map.Entry<String, String> e : headers.entrySet()) {
|
||||
request.addHeader(e.getKey(), e.getValue());
|
||||
}
|
||||
|
||||
if (body != null) {
|
||||
request.setEntity(new ByteArrayEntity(body));
|
||||
}
|
||||
|
||||
return httpClient.execute(request);
|
||||
}
|
||||
|
||||
|
||||
public static HttpResponse doDelete(String host, String path, String method, Map<String, String> headers, Map<String, String> querys) throws Exception {
|
||||
HttpClient httpClient = wrapClient(host);
|
||||
|
||||
HttpDelete request = new HttpDelete(buildUrl(host, path, querys));
|
||||
for (Map.Entry<String, String> e : headers.entrySet()) {
|
||||
request.addHeader(e.getKey(), e.getValue());
|
||||
}
|
||||
|
||||
return httpClient.execute(request);
|
||||
}
|
||||
|
||||
private static String buildUrl(String host, String path, Map<String, String> querys) throws UnsupportedEncodingException {
|
||||
StringBuilder sbUrl = new StringBuilder();
|
||||
sbUrl.append(host);
|
||||
if (!StringUtils.isBlank(path)) {
|
||||
sbUrl.append(path);
|
||||
}
|
||||
if (null != querys) {
|
||||
StringBuilder sbQuery = new StringBuilder();
|
||||
for (Map.Entry<String, String> query : querys.entrySet()) {
|
||||
if (!sbQuery.isEmpty()) {
|
||||
sbQuery.append("&");
|
||||
}
|
||||
if (StringUtils.isBlank(query.getKey()) && !StringUtils.isBlank(query.getValue())) {
|
||||
sbQuery.append(query.getValue());
|
||||
}
|
||||
if (!StringUtils.isBlank(query.getKey())) {
|
||||
sbQuery.append(query.getKey());
|
||||
if (!StringUtils.isBlank(query.getValue())) {
|
||||
sbQuery.append("=");
|
||||
sbQuery.append(URLEncoder.encode(query.getValue(), StandardCharsets.UTF_8));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!sbQuery.isEmpty()) {
|
||||
sbUrl.append("?").append(sbQuery);
|
||||
}
|
||||
}
|
||||
|
||||
return sbUrl.toString();
|
||||
}
|
||||
|
||||
private static HttpClient wrapClient(String host) {
|
||||
HttpClient httpClient = new DefaultHttpClient();
|
||||
if (host.startsWith("https://")) {
|
||||
sslClient(httpClient);
|
||||
}
|
||||
|
||||
return httpClient;
|
||||
}
|
||||
|
||||
private static void sslClient(HttpClient httpClient) {
|
||||
try {
|
||||
SSLContext ctx = SSLContext.getInstance("TLS");
|
||||
X509TrustManager tm = new X509TrustManager() {
|
||||
public X509Certificate[] getAcceptedIssuers() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void checkClientTrusted(X509Certificate[] xcs, String str) {
|
||||
}
|
||||
|
||||
public void checkServerTrusted(X509Certificate[] xcs, String str) {
|
||||
}
|
||||
};
|
||||
ctx.init(null, new TrustManager[]{tm}, null);
|
||||
SSLSocketFactory ssf = new SSLSocketFactory(ctx);
|
||||
ssf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
|
||||
ClientConnectionManager ccm = httpClient.getConnectionManager();
|
||||
SchemeRegistry registry = ccm.getSchemeRegistry();
|
||||
registry.register(new Scheme("https", 443, ssf));
|
||||
} catch (Exception ex) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
package cn.bunny.common.service.utils.ip;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Builder
|
||||
@ApiModel(value = "IpEntity对象", description = "用户IP相关信息")
|
||||
public class IpEntity {
|
||||
@ApiModelProperty("原始地址")
|
||||
private String remoteAddr;
|
||||
|
||||
@ApiModelProperty("IP归属地")
|
||||
private String ipRegion;
|
||||
}
|
|
@ -0,0 +1,99 @@
|
|||
package cn.bunny.common.service.utils.ip;
|
||||
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.lionsoul.ip2region.xdb.Searcher;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.util.FileCopyUtils;
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@Slf4j
|
||||
public class IpUtil {
|
||||
private static Searcher searcher;
|
||||
|
||||
/**
|
||||
* 判断是否为合法 IP
|
||||
*/
|
||||
public static boolean checkIp(String ipAddress) {
|
||||
String ip = "([1-9]|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])(\\.(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])){3}";
|
||||
Pattern pattern = Pattern.compile(ip);
|
||||
Matcher matcher = pattern.matcher(ipAddress);
|
||||
return matcher.matches();
|
||||
}
|
||||
|
||||
/**
|
||||
* 在服务启动时,将 ip2region 加载到内存中
|
||||
*/
|
||||
@PostConstruct
|
||||
private static void initIp2Region() {
|
||||
try {
|
||||
InputStream inputStream = new ClassPathResource("/ipdb/ip2region.xdb").getInputStream();
|
||||
byte[] bytes = FileCopyUtils.copyToByteArray(inputStream);
|
||||
searcher = Searcher.newWithBuffer(bytes);
|
||||
} catch (Exception exception) {
|
||||
log.error("ip转换错误消息:{}", exception.getMessage());
|
||||
log.error("ip转换错误栈:{}", (Object) exception.getStackTrace());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 ip 所属地址
|
||||
*
|
||||
* @param ip ip
|
||||
*/
|
||||
public static String getIpRegion(String ip) {
|
||||
if (ip.equals("0:0:0:0:0:0:0:1")) ip = "127.0.0.1";
|
||||
boolean isIp = checkIp(ip);
|
||||
if (isIp) {
|
||||
initIp2Region();
|
||||
try {
|
||||
// searchIpInfo 的数据格式: 国家|区域|省份|城市|ISP
|
||||
String searchIpInfo = searcher.search(ip);
|
||||
String[] splitIpInfo = searchIpInfo.split("\\|");
|
||||
if (splitIpInfo.length > 0) {
|
||||
if ("中国".equals(splitIpInfo[0])) {
|
||||
// 国内属地返回省份
|
||||
return splitIpInfo[2];
|
||||
} else if ("0".equals(splitIpInfo[0])) {
|
||||
if ("内网IP".equals(splitIpInfo[4])) {
|
||||
// 内网 IP
|
||||
return splitIpInfo[4];
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
} else {
|
||||
// 国外属地返回国家
|
||||
return splitIpInfo[0];
|
||||
}
|
||||
}
|
||||
} catch (Exception exception) {
|
||||
log.error("获取 ip 所属地址消息:{}", exception.getMessage());
|
||||
log.error("获取 ip 所属地址:{}", (Object) exception.getStackTrace());
|
||||
}
|
||||
return "";
|
||||
} else {
|
||||
throw new IllegalArgumentException("非法的IP地址");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* * 获取当前用户登录IP地址
|
||||
*
|
||||
* @return IP地址
|
||||
*/
|
||||
public static IpEntity getCurrentUserIpAddress() {
|
||||
// 获取用户IP地址
|
||||
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
|
||||
String remoteAddr = requestAttributes != null ? requestAttributes.getRequest().getRemoteAddr() : "0:0:0:0:0:0:0:1";
|
||||
String ipRegion = IpUtil.getIpRegion(remoteAddr);
|
||||
return IpEntity.builder()
|
||||
.remoteAddr(remoteAddr)
|
||||
.ipRegion(ipRegion)
|
||||
.build();
|
||||
}
|
||||
}
|
|
@ -1,8 +1,8 @@
|
|||
package cn.bunny.module.mail.utils;
|
||||
package cn.bunny.common.service.utils.mail;
|
||||
|
||||
import cn.bunny.common.service.utils.EmptyUtil;
|
||||
import cn.bunny.pojo.email.EmailSend;
|
||||
import cn.bunny.pojo.result.constant.MailMessageConstant;
|
||||
import cn.bunny.pojo.common.EmailSend;
|
||||
import cn.bunny.pojo.constant.MailMessageConstant;
|
||||
|
||||
public class MailSendCheckUtil {
|
||||
/**
|
|
@ -1,7 +1,7 @@
|
|||
package cn.bunny.module.mail.utils;
|
||||
package cn.bunny.common.service.utils.mail;
|
||||
|
||||
import cn.bunny.pojo.email.EmailSend;
|
||||
import cn.bunny.pojo.email.EmailSendInit;
|
||||
import cn.bunny.pojo.common.EmailSend;
|
||||
import cn.bunny.pojo.common.EmailSendInit;
|
||||
import jakarta.mail.MessagingException;
|
||||
import jakarta.mail.internet.MimeMessage;
|
||||
import org.springframework.mail.SimpleMailMessage;
|
||||
|
@ -43,6 +43,7 @@ public class MailSenderUtil {
|
|||
MimeMessage message = javaMailSender.createMimeMessage();
|
||||
// 创建 MimeMessageHelper
|
||||
MimeMessageHelper helper = new MimeMessageHelper(message, true);
|
||||
String ccParam = emailSend.getCcParam();
|
||||
|
||||
// 设置发送人
|
||||
helper.setFrom(username);
|
||||
|
@ -53,11 +54,15 @@ public class MailSenderUtil {
|
|||
// 设置发送消息 为富文本
|
||||
helper.setText(emailSend.getMessage(), emailSend.getIsRichText());
|
||||
// 设置抄送人
|
||||
helper.setCc(emailSend.getCcParam().split(","));
|
||||
if (ccParam != null) {
|
||||
helper.setCc(ccParam.split(","));
|
||||
}
|
||||
// 邮件添加附件
|
||||
MultipartFile[] files = emailSend.getFile();
|
||||
for (MultipartFile file : files) {
|
||||
helper.addAttachment(Objects.requireNonNull(file.getOriginalFilename()), file);
|
||||
if (files != null) {
|
||||
for (MultipartFile file : files) {
|
||||
helper.addAttachment(Objects.requireNonNull(file.getOriginalFilename()), file);
|
||||
}
|
||||
}
|
||||
|
||||
// 发送邮件
|
|
@ -1,3 +1,5 @@
|
|||
Configuration example
|
||||
|
||||
mail:
|
||||
host: smtp.qq.com # 邮箱地址
|
||||
port: 465 # 邮箱端口号
|
|
@ -1,4 +1,4 @@
|
|||
package cn.bunny.module.minio.properties;
|
||||
package cn.bunny.common.service.utils.minio;
|
||||
|
||||
import io.minio.MinioClient;
|
||||
import lombok.Data;
|
||||
|
@ -21,7 +21,6 @@ public class MinioProperties {
|
|||
|
||||
@Bean
|
||||
public MinioClient minioClient() {
|
||||
log.info("注册MinioClient...");
|
||||
return MinioClient.builder().endpoint(endpointUrl).credentials(accessKey, secretKey).build();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,142 @@
|
|||
package cn.bunny.common.service.utils.minio;
|
||||
|
||||
import cn.bunny.common.service.exception.BunnyException;
|
||||
import cn.bunny.pojo.common.MinioFIlePath;
|
||||
import cn.bunny.pojo.constant.MinioConstant;
|
||||
import cn.bunny.pojo.result.ResultCodeEnum;
|
||||
import io.minio.GetObjectArgs;
|
||||
import io.minio.GetObjectResponse;
|
||||
import io.minio.MinioClient;
|
||||
import io.minio.PutObjectArgs;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Minio操作工具类 简化操作步骤
|
||||
* By:Bunny0212
|
||||
*/
|
||||
@Component
|
||||
@Slf4j
|
||||
public class MinioUtil {
|
||||
@Autowired
|
||||
private MinioProperties properties;
|
||||
@Autowired
|
||||
private MinioClient minioClient;
|
||||
|
||||
/**
|
||||
* 获取Minio文件路径
|
||||
*/
|
||||
public static MinioFIlePath getMinioFilePath(String buckName, String minioPreType, MultipartFile file) {
|
||||
String uuid = UUID.randomUUID().toString();
|
||||
// 定义日期时间格式
|
||||
LocalDateTime currentDateTime = LocalDateTime.now();
|
||||
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy/MM-dd");
|
||||
String extension = "";
|
||||
|
||||
// 原始文件名
|
||||
String filename = file.getOriginalFilename();
|
||||
if (StringUtils.hasText(filename) && filename.contains(".")) {
|
||||
extension = "." + filename.substring(filename.lastIndexOf(".") + 1);
|
||||
}
|
||||
|
||||
// UUID防止重名
|
||||
String uuidFilename = uuid + extension;
|
||||
|
||||
// 拼接时间+UUID文件名
|
||||
String timeUuidFilename = currentDateTime.format(formatter) + "/" + uuidFilename;// 加上时间路径
|
||||
|
||||
// 上传根文件夹+拼接时间+UUID文件名
|
||||
String filepath = MinioConstant.getType(minioPreType) + timeUuidFilename;
|
||||
|
||||
// 桶名称+上传根文件夹+拼接时间+UUID文件名
|
||||
String buckNameFilepath = "/" + buckName + MinioConstant.getType(minioPreType) + timeUuidFilename;
|
||||
|
||||
// 设置及Minio基础信息
|
||||
MinioFIlePath minioFIlePath = new MinioFIlePath();
|
||||
minioFIlePath.setFilename(filename);
|
||||
minioFIlePath.setUuidFilename(uuidFilename);
|
||||
minioFIlePath.setTimeUuidFilename(timeUuidFilename);
|
||||
minioFIlePath.setFilepath(filepath);
|
||||
minioFIlePath.setBucketNameFilepath(buckNameFilepath);
|
||||
|
||||
return minioFIlePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* * 上传文件并返回处理信息
|
||||
*/
|
||||
public MinioFIlePath getUploadMinioObjectFilePath(MultipartFile file, String minioPreType) throws IOException {
|
||||
// 如果buckName为空,设置为默认的桶
|
||||
String bucketName = properties.getBucketName();
|
||||
if (file != null) {
|
||||
MinioFIlePath minioFile = getMinioFilePath(bucketName, minioPreType, file);
|
||||
String filepath = minioFile.getFilepath();
|
||||
|
||||
// 上传对象
|
||||
putObject(bucketName, filepath, file.getInputStream(), file.getSize());
|
||||
|
||||
// 设置图片地址
|
||||
return minioFile;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取默认bucket文件,并返回字节数组
|
||||
*
|
||||
* @param objectName 对象名称
|
||||
* @return 文件流对象
|
||||
*/
|
||||
public byte[] getBucketObjectByte(String objectName) {
|
||||
// 如果buckName为空,设置为默认的桶
|
||||
String bucketName = properties.getBucketName();
|
||||
|
||||
try {
|
||||
objectName = objectName.replace("/" + bucketName, "");
|
||||
GetObjectResponse getObjectResponse = minioClient.getObject(GetObjectArgs.builder().bucket(bucketName).object(objectName).build());
|
||||
|
||||
return getObjectResponse.readAllBytes();
|
||||
} catch (Exception exception) {
|
||||
exception.getStackTrace();
|
||||
}
|
||||
throw new BunnyException(ResultCodeEnum.GET_BUCKET_EXCEPTION);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取Minio全路径名,Object带有桶名称
|
||||
*
|
||||
* @param objectName 对象名称
|
||||
* @return 全路径
|
||||
*/
|
||||
public String getObjectNameFullPath(String objectName) {
|
||||
String url = properties.getEndpointUrl();
|
||||
|
||||
return url + objectName;
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传文件
|
||||
*
|
||||
* @param bucketName 桶名称
|
||||
* @param filename 文件名
|
||||
* @param inputStream 输入流
|
||||
* @param size 大小
|
||||
*/
|
||||
public void putObject(String bucketName, String filename, InputStream inputStream, Long size) {
|
||||
try {
|
||||
minioClient.putObject(PutObjectArgs.builder().bucket(bucketName).object(filename).stream(inputStream, size, -1).build());
|
||||
} catch (Exception exception) {
|
||||
log.error("上传文件失败:{}", (Object) exception.getStackTrace());
|
||||
throw new BunnyException(ResultCodeEnum.UPDATE_ERROR);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +1,7 @@
|
|||
package cn.bunny.dto.email;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
|
@ -9,13 +11,21 @@ import lombok.NoArgsConstructor;
|
|||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Builder
|
||||
@Schema(name = "EmailTemplateDto", title = "邮箱模板请求内容", description = "邮箱模板请求内容")
|
||||
public class EmailTemplateDto {
|
||||
// 模板名称
|
||||
|
||||
@Schema(name = "templateName", title = "模板名称")
|
||||
@NotBlank(message = "模板名称不能为空")
|
||||
private String templateName;
|
||||
// 主题
|
||||
|
||||
@Schema(name = "subject", title = "主题")
|
||||
@NotBlank(message = "主题不能为空")
|
||||
private String subject;
|
||||
// 邮件内容
|
||||
|
||||
@Schema(name = "body", title = "邮件内容")
|
||||
@NotBlank(message = "邮件内容不能为空")
|
||||
private String body;
|
||||
// 邮件类型
|
||||
|
||||
@Schema(name = "type", title = "邮件类型")
|
||||
private String type;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
package cn.bunny.dto.email;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
|
@ -12,19 +15,31 @@ import lombok.NoArgsConstructor;
|
|||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Builder
|
||||
@Schema(name = "EmailUsersDto", title = "邮箱用户发送基础内容", description = "邮箱用户发送基础内容")
|
||||
public class EmailUsersDto {
|
||||
// 修改时需要传
|
||||
|
||||
@Schema(name = "id", title = "主键")
|
||||
@NotBlank(message = "id不能为空")
|
||||
private Long id;
|
||||
// 邮箱
|
||||
|
||||
@Schema(name = "email", title = "邮箱")
|
||||
@NotBlank(message = "邮箱不能为空")
|
||||
private String email;
|
||||
// 密码
|
||||
|
||||
@Schema(name = "password", title = "密码")
|
||||
@NotBlank(message = "密码不能为空")
|
||||
private String password;
|
||||
// SMTP服务器
|
||||
|
||||
@Schema(name = "host", title = "SMTP服务器")
|
||||
private String host;
|
||||
// 端口号
|
||||
|
||||
@Schema(name = "port", title = "端口号")
|
||||
@NotNull(message = "端口号不能为空")
|
||||
private Integer port;
|
||||
// 邮箱协议
|
||||
|
||||
@Schema(name = "smtpAgreement", title = "邮箱协议")
|
||||
private Integer smtpAgreement;
|
||||
// 是否为默认邮件
|
||||
|
||||
@Schema(name = "isDefault", title = "是否为默认邮件")
|
||||
private Boolean isDefault;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package cn.bunny.dto.user;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
|
@ -9,11 +11,22 @@ import lombok.NoArgsConstructor;
|
|||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Builder
|
||||
@Schema(name = "LoginDto", title = "登录表单内容", description = "登录表单内容")
|
||||
public class LoginDto {
|
||||
// 用户名
|
||||
|
||||
@Schema(name = "username", title = "用户名")
|
||||
@NotBlank(message = "用户名不能为空")
|
||||
private String username;
|
||||
// 密码
|
||||
|
||||
@Schema(name = "password", title = "密码")
|
||||
@NotBlank(message = "密码不能为空")
|
||||
private String password;
|
||||
// 邮箱验证码
|
||||
|
||||
|
||||
@Schema(name = "emailCode", title = "邮箱验证码")
|
||||
@NotBlank(message = "邮箱验证码不能为空")
|
||||
private String emailCode;
|
||||
|
||||
@Schema(name = "readMeDay", title = "记住我的天数")
|
||||
private Long readMeDay = 1L;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package cn.bunny.entity.base;
|
||||
package cn.bunny.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
|
@ -0,0 +1,56 @@
|
|||
package cn.bunny.entity.system;
|
||||
|
||||
import cn.bunny.entity.BaseEntity;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 管理员用户信息
|
||||
* </p>
|
||||
*
|
||||
* @author Bunny
|
||||
* @since 2024-06-26
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@TableName("sys_user")
|
||||
@Schema(name = "AdminUser对象", title = "用户信息", description = "用户信息")
|
||||
public class AdminUser extends BaseEntity {
|
||||
@Schema(name = "username", title = "用户名")
|
||||
private String username;
|
||||
|
||||
@Schema(name = "nickName", title = "昵称")
|
||||
private String nickName;
|
||||
|
||||
@Schema(name = "email", title = "邮箱")
|
||||
private String email;
|
||||
|
||||
@Schema(name = "phone", title = "手机号")
|
||||
private String phone;
|
||||
|
||||
@Schema(name = "password", title = "密码")
|
||||
private String password;
|
||||
|
||||
@Schema(name = "avatar", title = "头像")
|
||||
private String avatar;
|
||||
|
||||
@Schema(name = "sex", title = "性别", description = "0:女 1:男")
|
||||
private Byte sex;
|
||||
|
||||
@Schema(name = "summary", title = "个人描述")
|
||||
private String summary;
|
||||
|
||||
@Schema(name = "lastLoginIp", title = "最后登录IP")
|
||||
private String lastLoginIp;
|
||||
|
||||
@Schema(name = "lastLoginIpAddress", title = "最后登录ip归属地")
|
||||
private String lastLoginIpAddress;
|
||||
|
||||
@Schema(name = "status", title = "状态", description = "1:禁用 0:正常")
|
||||
private Byte status;
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
package cn.bunny.entity.system;
|
||||
|
||||
import cn.bunny.entity.BaseEntity;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
*
|
||||
* </p>
|
||||
*
|
||||
* @author Bunny
|
||||
* @since 2024-05-19
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@TableName("sys_email_template")
|
||||
@Schema(name = "EmailTemplate对象", title = "邮件模板表", description = "邮件模板表")
|
||||
public class EmailTemplate extends BaseEntity {
|
||||
@Schema(name = "templateName", title = "模板名称")
|
||||
private String templateName;
|
||||
|
||||
@Schema(name = "subject", title = "主题")
|
||||
private String subject;
|
||||
|
||||
@Schema(name = "body", title = "邮件内容")
|
||||
private String body;
|
||||
|
||||
@Schema(name = "type", title = "邮件类型")
|
||||
private String type;
|
||||
|
||||
@Schema(name = "isDefault", title = "是否默认")
|
||||
private Boolean isDefault;
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
package cn.bunny.entity.system;
|
||||
|
||||
import cn.bunny.entity.BaseEntity;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 邮箱发送表
|
||||
* </p>
|
||||
*
|
||||
* @author Bunny
|
||||
* @since 2024-05-17
|
||||
*/
|
||||
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@TableName("sys_email_users")
|
||||
@Schema(name = "EmailUsers对象", title = "邮箱发送表", description = "邮箱发送表")
|
||||
public class EmailUsers extends BaseEntity {
|
||||
@Schema(name = "email", title = "邮箱")
|
||||
private String email;
|
||||
|
||||
@Schema(name = "emailTemplate", title = "使用邮件模板")
|
||||
private Long emailTemplate;
|
||||
|
||||
@Schema(name = "password", title = "密码")
|
||||
private String password;
|
||||
|
||||
@Schema(name = "host", title = "Host地址")
|
||||
private String host;
|
||||
|
||||
@Schema(name = "port", title = "端口号")
|
||||
private Integer port;
|
||||
|
||||
@Schema(name = "smtpAgreement", title = "邮箱协议")
|
||||
private String smtpAgreement;
|
||||
|
||||
@Schema(name = "isDefault", title = "是否为默认邮件")
|
||||
private Byte isDefault;
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package cn.bunny.entity.system.log;
|
||||
package cn.bunny.entity.system;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
|
@ -1,58 +0,0 @@
|
|||
package cn.bunny.entity.system.admin;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
*
|
||||
* </p>
|
||||
*
|
||||
* @author Bunny
|
||||
* @since 2024-05-18
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@Accessors(chain = true)
|
||||
@TableName("admin_power")
|
||||
@ApiModel(value = "AdminPower对象", description = "")
|
||||
public class AdminPower implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@ApiModelProperty("权限ID")
|
||||
@TableId(value = "id", type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
@ApiModelProperty("权限名称")
|
||||
private String powerName;
|
||||
|
||||
@ApiModelProperty("权限编码")
|
||||
private String powerCode;
|
||||
|
||||
@ApiModelProperty("描述")
|
||||
private String description;
|
||||
|
||||
@ApiModelProperty("创建时间")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
@ApiModelProperty("更新时间")
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
@ApiModelProperty("更新用户")
|
||||
private String updateUser;
|
||||
|
||||
@ApiModelProperty("是否删除,0-未删除,1-已删除")
|
||||
private Byte isDelete;
|
||||
}
|
|
@ -1,55 +0,0 @@
|
|||
package cn.bunny.entity.system.admin;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
*
|
||||
* </p>
|
||||
*
|
||||
* @author Bunny
|
||||
* @since 2024-05-18
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@Accessors(chain = true)
|
||||
@TableName("admin_role")
|
||||
@ApiModel(value = "AdminRole对象", description = "")
|
||||
public class AdminRole implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@TableId(value = "id", type = IdType.AUTO)
|
||||
private String id;
|
||||
|
||||
@ApiModelProperty("角色名称")
|
||||
private String roleName;
|
||||
|
||||
@ApiModelProperty("描述")
|
||||
private String description;
|
||||
|
||||
@ApiModelProperty("角色代码")
|
||||
private String roleCode;
|
||||
|
||||
@ApiModelProperty("创建时间")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
@ApiModelProperty("更新时间")
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
@ApiModelProperty("操作用户")
|
||||
private String updateUser;
|
||||
|
||||
@ApiModelProperty("是否删除")
|
||||
private Byte isDeleted;
|
||||
}
|
|
@ -1,56 +0,0 @@
|
|||
package cn.bunny.entity.system.admin;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
*
|
||||
* </p>
|
||||
*
|
||||
* @author Bunny
|
||||
* @since 2024-05-18
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@Accessors(chain = true)
|
||||
@TableName("admin_role_power")
|
||||
@ApiModel(value = "AdminRolePower对象", description = "")
|
||||
public class AdminRolePower implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@ApiModelProperty("ID")
|
||||
@TableId(value = "id", type = IdType.AUTO)
|
||||
private String id;
|
||||
|
||||
@ApiModelProperty("角色id")
|
||||
private String roleId;
|
||||
|
||||
@ApiModelProperty("权限id")
|
||||
private String powerId;
|
||||
|
||||
@ApiModelProperty("描述")
|
||||
private String description;
|
||||
|
||||
@ApiModelProperty("创建时间")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
@ApiModelProperty("更新时间")
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
@ApiModelProperty("更新用户")
|
||||
private String updateUser;
|
||||
|
||||
@ApiModelProperty("是否删除,0-未删除,1-已删除")
|
||||
private Byte isDelete;
|
||||
}
|
|
@ -1,56 +0,0 @@
|
|||
package cn.bunny.entity.system.admin;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
*
|
||||
* </p>
|
||||
*
|
||||
* @author Bunny
|
||||
* @since 2024-05-18
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@Accessors(chain = true)
|
||||
@TableName("admin_user_role")
|
||||
@ApiModel(value = "AdminUserRole对象", description = "")
|
||||
public class AdminUserRole implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@ApiModelProperty("ID")
|
||||
@TableId(value = "id", type = IdType.AUTO)
|
||||
private String id;
|
||||
|
||||
@ApiModelProperty("用户id")
|
||||
private String userId;
|
||||
|
||||
@ApiModelProperty("角色id")
|
||||
private String roleId;
|
||||
|
||||
@ApiModelProperty("描述")
|
||||
private String description;
|
||||
|
||||
@ApiModelProperty("创建时间")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
@ApiModelProperty("更新时间")
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
@ApiModelProperty("更新用户")
|
||||
private String updateUser;
|
||||
|
||||
@ApiModelProperty("是否删除,0-未删除,1-已删除")
|
||||
private Byte isDelete;
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
package cn.bunny.entity.system.admin.auth;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Builder
|
||||
public class AuthUserRole {
|
||||
// 用户id
|
||||
private Long userId;
|
||||
// 角色id
|
||||
private Long roleId;
|
||||
// 角色代码
|
||||
private String roleCode;
|
||||
// 描述
|
||||
private String roleDescription;
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
package cn.bunny.entity.system.email;
|
||||
|
||||
import cn.bunny.entity.base.BaseEntity;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
*
|
||||
* </p>
|
||||
*
|
||||
* @author Bunny
|
||||
* @since 2024-05-19
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@Accessors(chain = true)
|
||||
@TableName("email_template")
|
||||
@ApiModel(value = "EmailTemplate对象", description = "邮件模板")
|
||||
public class EmailTemplate extends BaseEntity implements Serializable {
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@ApiModelProperty("模板名称")
|
||||
private String templateName;
|
||||
|
||||
@ApiModelProperty("主题")
|
||||
private String subject;
|
||||
|
||||
@ApiModelProperty("邮件内容")
|
||||
private String body;
|
||||
|
||||
@ApiModelProperty("邮件类型")
|
||||
private String type;
|
||||
}
|
|
@ -1,49 +0,0 @@
|
|||
package cn.bunny.entity.system.email;
|
||||
|
||||
import cn.bunny.entity.base.BaseEntity;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 邮箱发送表
|
||||
* </p>
|
||||
*
|
||||
* @author Bunny
|
||||
* @since 2024-05-17
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@Accessors(chain = true)
|
||||
@TableName("email_users")
|
||||
@ApiModel(value = "EmailUsers对象", description = "邮箱发送表")
|
||||
public class EmailUsers extends BaseEntity implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@ApiModelProperty("邮箱")
|
||||
private String email;
|
||||
|
||||
@ApiModelProperty("密码")
|
||||
private String password;
|
||||
|
||||
@ApiModelProperty("Host地址")
|
||||
private String host;
|
||||
|
||||
@ApiModelProperty("端口号")
|
||||
private Integer port;
|
||||
|
||||
@ApiModelProperty("邮箱协议")
|
||||
private String smtpAgreement;
|
||||
|
||||
@ApiModelProperty("是否为默认邮件")
|
||||
private Integer isDefault;
|
||||
}
|
|
@ -1,61 +0,0 @@
|
|||
package cn.bunny.entity.system.user;
|
||||
|
||||
import cn.bunny.entity.base.BaseEntity;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 用户信息
|
||||
* </p>
|
||||
*
|
||||
* @author Bunny
|
||||
* @since 2024-05-17
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@ApiModel(value = "User对象", description = "用户信息")
|
||||
public class User extends BaseEntity implements Serializable {
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
@ApiModelProperty("昵称")
|
||||
private String nickName;
|
||||
@ApiModelProperty("邮箱")
|
||||
private String email;
|
||||
@ApiModelProperty("密码")
|
||||
private String password;
|
||||
@ApiModelProperty("头像")
|
||||
private String avatar;
|
||||
@ApiModelProperty("0:女 1:男")
|
||||
private Byte sex;
|
||||
@ApiModelProperty("个人描述")
|
||||
private String personDescription;
|
||||
@ApiModelProperty("加入时间")
|
||||
private LocalDateTime joinTime;
|
||||
|
||||
@ApiModelProperty("最后登录时间")
|
||||
private LocalDateTime lastLoginTime;
|
||||
|
||||
@ApiModelProperty("最后登录IP")
|
||||
private String lastLoginIp;
|
||||
|
||||
@ApiModelProperty("最后登录ip地址")
|
||||
private String lastLoginIpAddress;
|
||||
|
||||
@ApiModelProperty("积分")
|
||||
private Integer totalIntegral;
|
||||
|
||||
@ApiModelProperty("当前积分")
|
||||
private Integer currentIntegral;
|
||||
|
||||
@ApiModelProperty("0:禁用 1:正常")
|
||||
private Byte status;
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package cn.bunny.pojo.email;
|
||||
package cn.bunny.pojo.common;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
|
@ -1,4 +1,4 @@
|
|||
package cn.bunny.pojo.email;
|
||||
package cn.bunny.pojo.common;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
|
@ -1,4 +1,4 @@
|
|||
package cn.bunny.pojo.file;
|
||||
package cn.bunny.pojo.common;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
|
@ -0,0 +1,22 @@
|
|||
package cn.bunny.pojo.constant;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
|
||||
@Data
|
||||
public class ExceptionConstant {
|
||||
public static final String UNKNOWN_EXCEPTION = "未知错误";
|
||||
|
||||
// 用户相关
|
||||
public static final String USER_NOT_LOGIN_EXCEPTION = "用户未登录";
|
||||
public static final String USERNAME_IS_EMPTY_EXCEPTION = "用户名不能为空";
|
||||
public static final String ALREADY_USER_EXCEPTION = "用户已存在";
|
||||
public static final String USER_NOT_FOUND_EXCEPTION = "用户不存在";
|
||||
|
||||
// 密码相关
|
||||
public static final String PASSWORD_EXCEPTION = "密码错误";
|
||||
public static final String PASSWORD_NOT_EMPTY_EXCEPTION = "密码不能为空";
|
||||
public static final String OLD_PASSWORD_EXCEPTION = "旧密码不匹配";
|
||||
public static final String PASSWORD_EDIT_EXCEPTION = "密码修改失败";
|
||||
public static final String OLD_PASSWORD_SAME_NEW_PASSWORD_EXCEPTION = "旧密码与新密码相同";
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
package cn.bunny.pojo.constant;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class LocalDateTimeConstant {
|
||||
public static final String YYYY_MM_DD = "yyyy-MM-dd";
|
||||
public static final String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss";
|
||||
public static final String YYYY_MM_DD_HH_MM_SS_SLASH = "yyyy/MM/dd HH:mm:ss";
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package cn.bunny.pojo.result.constant;
|
||||
package cn.bunny.pojo.constant;
|
||||
|
||||
import lombok.Data;
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package cn.bunny.pojo.result.constant;
|
||||
package cn.bunny.pojo.constant;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
|
@ -34,6 +34,6 @@ public class MinioConstant {
|
|||
public static String getType(String type) {
|
||||
String value = typeMap.get(type);
|
||||
if (value != null) return value;
|
||||
throw new RuntimeException(FileMessageConstant.COMPOSE_OBJECT_EXCEPTION);
|
||||
throw new RuntimeException("上传类型错误或缺失");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
package cn.bunny.pojo.constant;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* Redis用户前缀设置
|
||||
*/
|
||||
@Data
|
||||
public class RedisUserConstant {
|
||||
// 过期时间
|
||||
public static final Long REDIS_EXPIRATION_TIME = 15L;// 15 天/分钟 Redis过期
|
||||
public static final Integer Cookie_EXPIRATION_TIME = 5 * 60 * 60;// cookies 过期时间 5 分钟
|
||||
|
||||
private static final String ADMIN_LOGIN_INFO_PREFIX = "admin::login_info::";
|
||||
private static final String ADMIN_EMAIL_CODE_PREFIX = "admin::email_code::";
|
||||
private static final String USER_LOGIN_INFO_PREFIX = "user::login_info::";
|
||||
private static final String USER_EMAIL_CODE_PREFIX = "user::email_code::";
|
||||
|
||||
public static String getAdminLoginInfoPrefix(String adminUser) {
|
||||
return ADMIN_LOGIN_INFO_PREFIX + adminUser;
|
||||
}
|
||||
|
||||
public static String getAdminUserEmailCodePrefix(String adminUser) {
|
||||
return ADMIN_EMAIL_CODE_PREFIX + adminUser;
|
||||
}
|
||||
|
||||
public static String getUserLoginInfoPrefix(String user) {
|
||||
return USER_LOGIN_INFO_PREFIX + user;
|
||||
}
|
||||
|
||||
public static String getUserEmailCodePrefix(String user) {
|
||||
return USER_EMAIL_CODE_PREFIX + user;
|
||||
}
|
||||
}
|
|
@ -1,8 +1,9 @@
|
|||
package cn.bunny.pojo.result.constant;
|
||||
package cn.bunny.pojo.constant;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class UserConstant {
|
||||
public static final String USER_AVATAR = "https://thirdwx.qlogo.cn/mmopen/vi_32/DYAIOgq83eoj0hHXhgJNOTSOFsS4uZs8x1ConecaVOB8eIl115xmJZcT4oCicvia7wMEufibKtTLqiaJeanU2Lpg3w/132";
|
||||
public static final String PERSON_DESCRIPTION = "这个人很懒没有介绍...";
|
||||
}
|
|
@ -11,36 +11,44 @@ public enum ResultCodeEnum {
|
|||
SUCCESS(200, "操作成功"),
|
||||
SUCCESS_LOGOUT(200, "退出成功"),
|
||||
EMAIL_CODE_REFRESH(200, "邮箱验证码已刷新"),
|
||||
|
||||
// 验证错误 201
|
||||
USERNAME_NOT_EMPTY(201, "用户名不能为空"),
|
||||
PASSWORD_NOT_EMPTY(201, "密码不能为空"),
|
||||
USERNAME_OR_PASSWORD_NOT_EMPTY(201, "用户名或密码不能为空"),
|
||||
EMAIL_CODE_NOT_EMPTY(201, "邮箱验证码不能为空"),
|
||||
SEND_EMAIL_CODE_NOT_EMPTY(201, "请先发送邮箱验证码"),
|
||||
EMAIL_CODE_NOT_MATCHING(201, "邮箱验证码不匹配"),
|
||||
LOGIN_ERROR(201, "账号或密码错误"),
|
||||
LOGIN_ERROR_USERNAME_PASSWORD_NOT_EMPTY(201, "登录信息不能为空"),
|
||||
GET_BUCKET_EXCEPTION(201, "获取文件信息失败"),
|
||||
|
||||
// 数据相关 206
|
||||
ILLEGAL_REQUEST(206, "非法请求"),
|
||||
REPEAT_SUBMIT(206, "重复提交"),
|
||||
DATA_ERROR(206, "数据异常"),
|
||||
|
||||
// 身份过期 208
|
||||
LOGIN_AUTH(208, "请先登陆"),
|
||||
AUTHENTICATION_EXPIRED(208, "身份验证过期"),
|
||||
SESSION_EXPIRATION(208, "会话过期"),
|
||||
|
||||
// 封禁 209
|
||||
FAIL_NO_ACCESS_DENIED_USER_LOCKED(209, "该账户被封禁"),
|
||||
THE_SAME_USER_HAS_LOGGED_IN(209, "相同用户已登录"),
|
||||
|
||||
// 提示错误
|
||||
URL_ENCODE_ERROR(216, "URL编码失败"),
|
||||
ILLEGAL_CALLBACK_REQUEST_ERROR(217, "非法回调请求"),
|
||||
FETCH_USERINFO_ERROR(219, "获取用户信息失败"),
|
||||
|
||||
// 无权访问 403
|
||||
FAIL_REQUEST_NOT_AUTH(403, "用户未认证"),
|
||||
FAIL_NO_ACCESS_DENIED(403, "无权访问"),
|
||||
FAIL_NO_ACCESS_DENIED_USER_OFFLINE(403, "用户强制下线"),
|
||||
LOGGED_IN_FROM_ANOTHER_DEVICE(403, "没有权限访问"),
|
||||
|
||||
// 系统错误 500
|
||||
SERVICE_ERROR(500, "服务异常"),
|
||||
UPDATE_ERROR(500, "上传文件失败"),
|
||||
FAIL(500, "失败"),
|
||||
;
|
||||
|
||||
|
|
|
@ -1,52 +0,0 @@
|
|||
package cn.bunny.pojo.result.constant;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
|
||||
@Data
|
||||
public class ExceptionConstant {
|
||||
public static final String UNKNOWN_Exception = "未知错误";
|
||||
public static final String TOKEN_IS_EMPTY = "token为空";
|
||||
public static final String DATA_IS_EMPTY = "数据为空";
|
||||
public static final String REQUEST_DATA_NOT_EMPTY_Exception = "请求参数为空";
|
||||
public static final String UPDATE_DTO_IS_NULL_Exception = "修改参数为空";
|
||||
public static final String ADD_DATA_IS_EMPTY_Exception = "添加数据为空";
|
||||
public static final String DELETE_ID_IS_NOT_EMPTY_Exception = "删除id不能为空";
|
||||
// 文章操作相关
|
||||
public static final String DO_LIKE_COMMENT_NOT_EXIST = "点赞内容不存在";
|
||||
public static final String REPLY_USER_EMPTY_EXCEPTION = "回复的用户不存在";
|
||||
public static final String REPLY_USER_ID_EMPTY_EXCEPTION = "回复的用户不能为空";
|
||||
public static final String MENU_IS_NOT_EXIST_Exception = "菜单不存在";
|
||||
public static final String POST_COMMENT_EMPTY_Exception = "评论内容不能为空";
|
||||
public static final String ARTICLE_ID_NOT_EMPTY_Exception = "文章id不能为空";
|
||||
public static final String UPDATE_ID_IS_NOT_EMPTY_Exception = "修改id不能为空";
|
||||
public static final String CANNOT_TOP_OTHER_USER = "不能操作此内容";
|
||||
public static final String ARTICLE_NOT_FOUND_EXCEPTION = "文章未找到";
|
||||
// 登录相关
|
||||
public static final String USER_TOKEN_OUT_OF_DATE_Exception = "用户登录过期";
|
||||
public static final String LOGIN_DTO_IS_EMPTY_Exception = "登录参数不能为空";
|
||||
public static final String LOGIN_FAILED_Exception = "登录失败";
|
||||
// 账号相关
|
||||
public static final String ACCOUNT_NOT_FOUND_Exception = "账号不存在";
|
||||
public static final String ACCOUNT_LOCKED_Exception = "账号被锁定";
|
||||
// 用户相关
|
||||
public static final String USER_NOT_LOGIN_Exception = "用户未登录";
|
||||
public static final String USERNAME_IS_EMPTY_Exception = "用户名不能为空";
|
||||
public static final String ALREADY_USER_Exception = "用户已存在";
|
||||
public static final String USER_NOT_FOUND_Exception = "用户不存在";
|
||||
// 密码相关
|
||||
public static final String PASSWORD_Exception = "密码错误";
|
||||
public static final String PASSWORD_NOT_EMPTY_Exception = "密码不能为空";
|
||||
public static final String OLD_PASSWORD_Exception = "旧密码不匹配";
|
||||
public static final String PASSWORD_EDIT_Exception = "密码修改失败";
|
||||
public static final String OLD_PASSWORD_SAME_NEW_PASSWORD_Exception = "旧密码与新密码相同";
|
||||
// 验证码错误
|
||||
public static final String PLEASE_SEND_EMAIL_CODE_Exception = "请先发送验证码";
|
||||
public static final String MESSAGE_CODE_NOT_PASS_Exception = "短信验证码未过期";
|
||||
public static final String MESSAGE_CODE_UNAUTHORIZED_Exception = "短信验证码未授权,请联系管理员";
|
||||
public static final String VERIFICATION_CODE_ERROR_Exception = "验证码错误";
|
||||
public static final String CAPTCHA_IS_EMPTY_Exception = "验证码不能为空";
|
||||
public static final String KEY_IS_EMPTY_Exception = "验证码key不能为空";
|
||||
public static final String VERIFICATION_CODE_DOES_NOT_MATCH_Exception = "验证码不匹配";
|
||||
public static final String VERIFICATION_CODE_IS_EMPTY_Exception = "验证码失效或不存在";
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
package cn.bunny.pojo.result.constant;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class FileMessageConstant {
|
||||
public static final String DOWNLOAD_BUCKET_EXCEPTION = "下载文件失败";
|
||||
public static final String FILE_UPLOAD_EXCEPTION = "文件上传失败";
|
||||
public static final String BUCKET_EXISTS_EXCEPTION = "查询文件对象失败";
|
||||
public static final String DELETE_BUCKET_EXCEPTION = "删除文件对象失败";
|
||||
public static final String FILE_IS_EMPTY = "文件信息为空";
|
||||
public static final String FILE_IS_NOT_EXITS = "文件信息为空";
|
||||
public static final String GET_BUCKET_EXCEPTION = "获取文件信息失败";
|
||||
public static final String QUERY_BUCKET_EXCEPTION = "查询文件信息失败";
|
||||
public static final String CREATE_BUCKET_EXCEPTION = "创建文件对象失败";
|
||||
public static final String UPDATE_BUCKET_EXCEPTION = "更新文件对象失败";
|
||||
public static final String COMPOSE_OBJECT_EXCEPTION = "对象错误";
|
||||
public static final String COPY_BUCKET_EXCEPTION = "复制文件内容失败";
|
||||
public static final String DISABLE_BUCKET_EXCEPTION = "禁用文件失败";
|
||||
public static final String ENABLE_BUCKET_EXCEPTION = "启用文件失败";
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
package cn.bunny.pojo.result.constant;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class LocalDateTimeConstant {
|
||||
public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd";
|
||||
public static final String DEFAULT_DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm";
|
||||
public static final String DEFAULT_DATE_TIME_SECOND_FORMAT = "yyyy-MM-dd HH:mm:ss";
|
||||
public static final String DEFAULT_TIME_FORMAT = "HH:mm:ss";
|
||||
}
|
|
@ -1,67 +0,0 @@
|
|||
package cn.bunny.pojo.result.constant;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* Redis用户前缀设置
|
||||
*/
|
||||
@Data
|
||||
public class RedisUserConstant {
|
||||
// 管理员用户
|
||||
public static final String ADMIN_LOGIN_INFO_PREFIX = "ADMIN::LOGIN_INFO::";
|
||||
public static final String ADMIN_EMAIL_CODE_PREFIX = "ADMIN::EMAIL_CODE::";
|
||||
// 普通用户
|
||||
public static final String USER_LOGIN_INFO_PREFIX = "USER::LOGIN_INFO::";
|
||||
public static final String USER_EMAIL_CODE_PREFIX = "USER::EMAIL_CODE::";
|
||||
public static final String USER_DO_LIKE_PREFIX = "USER::doLike::";
|
||||
|
||||
/**
|
||||
* * 管理员用户登录信息
|
||||
*
|
||||
* @param adminUser 管理员用户
|
||||
* @return 登录信息key
|
||||
*/
|
||||
public static String getAdminLoginInfoPrefix(String adminUser) {
|
||||
return ADMIN_LOGIN_INFO_PREFIX + adminUser;
|
||||
}
|
||||
|
||||
/**
|
||||
* * 管理员用户邮箱验证码
|
||||
*
|
||||
* @param adminUser 管理员用户
|
||||
* @return 管理员用户邮箱验证码key
|
||||
*/
|
||||
public static String getAdminUserEmailCodePrefix(String adminUser) {
|
||||
return ADMIN_EMAIL_CODE_PREFIX + adminUser;
|
||||
}
|
||||
|
||||
/**
|
||||
* * 用户登录信息
|
||||
*
|
||||
* @param user 用户名
|
||||
* @return 登录信息key
|
||||
*/
|
||||
public static String getUserLoginInfoPrefix(String user) {
|
||||
return USER_LOGIN_INFO_PREFIX + user;
|
||||
}
|
||||
|
||||
/**
|
||||
* * 用户邮箱验证码
|
||||
*
|
||||
* @param user 用户名
|
||||
* @return 用户邮箱验证码key
|
||||
*/
|
||||
public static String getUserEmailCodePrefix(String user) {
|
||||
return USER_EMAIL_CODE_PREFIX + user;
|
||||
}
|
||||
|
||||
/**
|
||||
* * 用户点赞操作
|
||||
*
|
||||
* @param user 用户名
|
||||
* @return 用户点赞key
|
||||
*/
|
||||
public static String getUserDoLikePrefix(String user) {
|
||||
return USER_DO_LIKE_PREFIX + user;
|
||||
}
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
package cn.bunny.pojo.result.constant;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 数据库中自动填充字段
|
||||
*/
|
||||
@Data
|
||||
public class SQLAutoFillConstant {
|
||||
public static final String SET_CREATE_TIME = "setCreateTime";
|
||||
public static final String SET_UPDATE_TIME = "setUpdateTime";
|
||||
public static final String SET_CREATE_USER = "setCreateUser";
|
||||
public static final String SET_UPDATE_USER = "setUpdateUser";
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
package cn.bunny.pojo.result.constant;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class SecurityConstant {
|
||||
public static String[] annotations = {"/", "/test/**", "/diagram-viewer/**", "/editor-app/**", "/*.html",
|
||||
"/*/*/noAuth/**", "/*/noAuth/**", "/favicon.ico", "/swagger-resources/**", "/webjars/**", "/v3/**", "/swagger-ui.html/**", "/doc.html"};
|
||||
public static List<String> annotationsList = Arrays.asList(annotations);
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
package cn.bunny.pojo.result.constant;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 状态常量,启用或者禁用
|
||||
*/
|
||||
@Data
|
||||
public class StatusConstant {
|
||||
// 启用为1
|
||||
public static final Integer ENABLE = 1;
|
||||
// 禁用为0
|
||||
public static final Integer DISABLE = 0;
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
package cn.bunny.pojo.tree;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface AbstractTreeNode {
|
||||
Long getId();
|
||||
|
||||
Long getParentId();
|
||||
|
||||
void setChildren(List<? extends AbstractTreeNode> children);
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
package cn.bunny.pojo.tree;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class TreeBuilder<T extends AbstractTreeNode> {
|
||||
|
||||
public List<T> buildTree(List<T> nodeList) {
|
||||
List<T> tree = new ArrayList<>();
|
||||
for (T node : nodeList) {
|
||||
if (node.getParentId() == 0) {
|
||||
node.setChildren(getChildren(node.getId(), nodeList));
|
||||
tree.add(node);
|
||||
}
|
||||
}
|
||||
return tree;
|
||||
}
|
||||
|
||||
private List<T> getChildren(Long nodeId, List<T> nodeList) {
|
||||
List<T> children = new ArrayList<>();
|
||||
for (T node : nodeList) {
|
||||
if (node.getParentId().equals(nodeId)) {
|
||||
node.setChildren(getChildren(node.getId(), nodeList));
|
||||
children.add(node);
|
||||
}
|
||||
}
|
||||
return children;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
package cn.bunny.vo;
|
||||
|
||||
import com.alibaba.fastjson2.annotation.JSONField;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
|
||||
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Data
|
||||
@Schema(name = "BaseVo", title = "基础返回对象内容", description = "基础返回对象内容")
|
||||
public class BaseVo implements Serializable {
|
||||
@Schema(name = "id", title = "主键")
|
||||
@JsonProperty("id")
|
||||
@JsonFormat(shape = JsonFormat.Shape.STRING)
|
||||
@JSONField(serializeUsing = ToStringSerializer.class)
|
||||
private Long id;
|
||||
|
||||
@Schema(name = "updateTime", title = "更新时间")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonSerialize(using = LocalDateTimeSerializer.class)
|
||||
@JsonDeserialize(using = LocalDateTimeDeserializer.class)
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
@Schema(name = "createTime", title = "发布时间")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonSerialize(using = LocalDateTimeSerializer.class)
|
||||
@JsonDeserialize(using = LocalDateTimeDeserializer.class)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
@Schema(name = "createUser", title = "创建用户")
|
||||
@JsonFormat(shape = JsonFormat.Shape.STRING)
|
||||
@JSONField(serializeUsing = ToStringSerializer.class)
|
||||
private Long createUser;
|
||||
|
||||
@Schema(name = "updateUser", title = "操作用户")
|
||||
@JsonFormat(shape = JsonFormat.Shape.STRING)
|
||||
@JSONField(serializeUsing = ToStringSerializer.class)
|
||||
private Long updateUser;
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
package cn.bunny.vo.email;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
|
@ -9,11 +10,14 @@ import lombok.NoArgsConstructor;
|
|||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Builder
|
||||
@Schema(name = "EmailTemplateVo对象", title = "邮箱模板返回内容", description = "邮箱模板返回内容")
|
||||
public class EmailTemplateVo {
|
||||
// 模板名称
|
||||
@Schema(name = "templateName", title = "模板名称")
|
||||
private String templateName;
|
||||
// 主题
|
||||
|
||||
@Schema(name = "subject", title = "主题")
|
||||
private String subject;
|
||||
// 邮件内容
|
||||
|
||||
@Schema(name = "body", title = "邮件内容")
|
||||
private String body;
|
||||
}
|
|
@ -1,48 +0,0 @@
|
|||
package cn.bunny.vo.system.login;
|
||||
|
||||
import cn.bunny.pojo.result.constant.LocalDateTimeConstant;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
|
||||
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 用户登录返回内容
|
||||
*/
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Builder
|
||||
public class LoginVo {
|
||||
private Long id;
|
||||
private String nickName;
|
||||
private String email;
|
||||
private String password;
|
||||
private String avatar;
|
||||
private Byte sex;
|
||||
private String personDescription;
|
||||
@JsonFormat(pattern = LocalDateTimeConstant.DEFAULT_DATE_TIME_SECOND_FORMAT)
|
||||
@JsonSerialize(using = LocalDateTimeSerializer.class)
|
||||
@JsonDeserialize(using = LocalDateTimeDeserializer.class)
|
||||
private LocalDateTime joinTime;
|
||||
@JsonFormat(pattern = LocalDateTimeConstant.DEFAULT_DATE_TIME_SECOND_FORMAT)
|
||||
@JsonSerialize(using = LocalDateTimeSerializer.class)
|
||||
@JsonDeserialize(using = LocalDateTimeDeserializer.class)
|
||||
private LocalDateTime lastLoginTime;
|
||||
private String lastLoginIp;
|
||||
private String lastLoginIpAddress;
|
||||
private Integer totalIntegral;
|
||||
private Integer currentIntegral;
|
||||
private Byte status;
|
||||
private String token;
|
||||
private List<String> roleList;
|
||||
private List<String> powerList;
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
package cn.bunny.vo.system.user;
|
||||
|
||||
import cn.bunny.pojo.result.constant.LocalDateTimeConstant;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
|
||||
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 获取用户信息返回参数
|
||||
*/
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Builder
|
||||
public class UserInfoVo {
|
||||
private Long userId;
|
||||
private String nickName;
|
||||
private String email;
|
||||
private String avatar;
|
||||
private Byte sex;
|
||||
private String personDescription;
|
||||
@JsonFormat(pattern = LocalDateTimeConstant.DEFAULT_DATE_TIME_SECOND_FORMAT)
|
||||
@JsonSerialize(using = LocalDateTimeSerializer.class)
|
||||
@JsonDeserialize(using = LocalDateTimeDeserializer.class)
|
||||
private LocalDateTime joinTime;
|
||||
@JsonFormat(pattern = LocalDateTimeConstant.DEFAULT_DATE_TIME_SECOND_FORMAT)
|
||||
@JsonSerialize(using = LocalDateTimeSerializer.class)
|
||||
@JsonDeserialize(using = LocalDateTimeDeserializer.class)
|
||||
private LocalDateTime lastLoginTime;
|
||||
private String lastLoginIp;
|
||||
private String lastLoginIpAddress;
|
||||
private Integer totalIntegral;
|
||||
private Integer currentIntegral;
|
||||
private Byte status;
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
package cn.bunny.vo.user;
|
||||
|
||||
import cn.bunny.vo.BaseVo;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 用户登录返回内容
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Builder
|
||||
@Schema(name = "LoginVo对象", title = "登录成功返回内容", description = "登录成功返回内容")
|
||||
public class LoginVo extends BaseVo {
|
||||
@Schema(name = "nickName", title = "昵称")
|
||||
private String nickName;
|
||||
|
||||
@Schema(name = "username", title = "用户名")
|
||||
private String username;
|
||||
|
||||
@Schema(name = "email", title = "邮箱")
|
||||
private String email;
|
||||
|
||||
@Schema(name = "phone", title = "手机号")
|
||||
private String phone;
|
||||
|
||||
@Schema(name = "password", title = "密码")
|
||||
private String password;
|
||||
|
||||
@Schema(name = "avatar", title = "头像")
|
||||
private String avatar;
|
||||
|
||||
@Schema(name = "sex", title = "0:女 1:男")
|
||||
private Byte sex;
|
||||
|
||||
@Schema(name = "personDescription", title = "个人描述")
|
||||
private String personDescription;
|
||||
|
||||
@Schema(name = "articleMode", title = "文章显示模式")
|
||||
private String articleMode;
|
||||
|
||||
@Schema(name = "layout", title = "页面布局方式")
|
||||
private String layout;
|
||||
|
||||
@Schema(name = "lastLoginIp", title = "最后登录IP")
|
||||
private String lastLoginIp;
|
||||
|
||||
@Schema(name = "lastLoginIpAddress", title = "最后登录ip地址")
|
||||
private String lastLoginIpAddress;
|
||||
|
||||
@Schema(name = "totalIntegral", title = "积分")
|
||||
private Integer totalIntegral;
|
||||
|
||||
@Schema(name = "currentIntegral", title = "当前积分")
|
||||
private Integer currentIntegral;
|
||||
|
||||
@Schema(name = "status", title = "0:禁用 1:正常")
|
||||
private Boolean status;
|
||||
|
||||
@Schema(name = "token", title = "令牌")
|
||||
private String token;
|
||||
|
||||
@Schema(name = "roleList", title = "角色列表")
|
||||
private List<String> roleList;
|
||||
|
||||
@Schema(name = "powerList", title = "权限列表")
|
||||
private List<String> powerList;
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package cn.bunny.vo.system.login;
|
||||
package cn.bunny.vo.user;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
|
@ -1,26 +0,0 @@
|
|||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>cn.bunny</groupId>
|
||||
<artifactId>module</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>module-mail</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>module-mail</name>
|
||||
<url>https://maven.apache.org</url>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-mail</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
|
@ -1,27 +0,0 @@
|
|||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>cn.bunny</groupId>
|
||||
<artifactId>module</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>module-minio</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>module-minio</name>
|
||||
<url>https://maven.apache.org</url>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<!-- minio -->
|
||||
<dependency>
|
||||
<groupId>io.minio</groupId>
|
||||
<artifactId>minio</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
File diff suppressed because it is too large
Load Diff
|
@ -1,35 +0,0 @@
|
|||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>cn.bunny</groupId>
|
||||
<artifactId>module</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>module-rabbitMQ</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>module-rabbitMQ</name>
|
||||
<url>https://maven.apache.org</url>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-amqp</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.amqp</groupId>
|
||||
<artifactId>spring-rabbit-test</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.dataformat</groupId>
|
||||
<artifactId>jackson-dataformat-xml</artifactId>
|
||||
<version>2.16.0-rc1</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
|
@ -1,42 +0,0 @@
|
|||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>cn.bunny</groupId>
|
||||
<artifactId>bunny-template</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>module</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<name>module</name>
|
||||
<url>https://maven.apache.org</url>
|
||||
<modules>
|
||||
<module>module-minio</module>
|
||||
<module>module-mail</module>
|
||||
<module>module-rabbitMQ</module>
|
||||
<module>spring-security</module>
|
||||
</modules>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>cn.bunny</groupId>
|
||||
<artifactId>service-utils</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.protobuf</groupId>
|
||||
<artifactId>protobuf-java</artifactId>
|
||||
<version>4.27.2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
|
@ -1,32 +0,0 @@
|
|||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>cn.bunny</groupId>
|
||||
<artifactId>module</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>spring-security</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>spring-security</name>
|
||||
<url>https://maven.apache.org</url>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<!-- spring-security -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-security</artifactId>
|
||||
</dependency>
|
||||
<!-- spring-security-test -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-test</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
|
@ -1,91 +0,0 @@
|
|||
package cn.bunny.security.filter;
|
||||
|
||||
import cn.bunny.common.service.context.BaseContext;
|
||||
import cn.bunny.common.service.exception.BunnyException;
|
||||
import cn.bunny.common.service.utils.JwtHelper;
|
||||
import cn.bunny.common.service.utils.ResponseUtil;
|
||||
import cn.bunny.pojo.result.Result;
|
||||
import cn.bunny.pojo.result.ResultCodeEnum;
|
||||
import cn.bunny.pojo.result.constant.RedisUserConstant;
|
||||
import cn.bunny.vo.system.login.LoginVo;
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import jakarta.servlet.FilterChain;
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.filter.OncePerRequestFilter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class TokenAuthenticationFilter extends OncePerRequestFilter {
|
||||
private final RedisTemplate<String, Object> redisTemplate;
|
||||
|
||||
public TokenAuthenticationFilter(RedisTemplate<String, Object> redisTemplate) {
|
||||
this.redisTemplate = redisTemplate;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException, BunnyException {
|
||||
String token = request.getHeader("token");
|
||||
|
||||
// login请求就没token,直接放行,因为后边有其他的过滤器
|
||||
if (token == null) {
|
||||
doFilter(request, response, chain);
|
||||
return;
|
||||
}
|
||||
|
||||
// 如果想让这个用户下线,清空Redis这个用户值,返回未登录,判断Redis是否有这个用户
|
||||
// 如果想让这个用户锁定,清空Redis值并在数据库中设置status值为1
|
||||
String userName = JwtHelper.getUsername(token);
|
||||
Object usernameObject = redisTemplate.opsForValue().get(RedisUserConstant.getUserLoginInfoPrefix(userName));
|
||||
if (usernameObject == null) {
|
||||
Result<Object> error = Result.error(ResultCodeEnum.LOGIN_AUTH);
|
||||
ResponseUtil.out(response, error);
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取Redis中登录信息
|
||||
LoginVo loginVo = JSON.parseObject(JSON.toJSONString(usernameObject), LoginVo.class);
|
||||
// 如果是登录接口,直接放行
|
||||
UsernamePasswordAuthenticationToken authentication = getAuthentication(request);
|
||||
if (authentication != null) {
|
||||
// 设置用户详细信息
|
||||
authentication.setDetails(loginVo.getPersonDescription());
|
||||
SecurityContextHolder.getContext().setAuthentication(authentication);
|
||||
}
|
||||
|
||||
chain.doFilter(request, response);
|
||||
}
|
||||
|
||||
private UsernamePasswordAuthenticationToken getAuthentication(HttpServletRequest request) {
|
||||
// 请求头是否有token
|
||||
String token = request.getHeader("token");
|
||||
String username = RedisUserConstant.getAdminLoginInfoPrefix(JwtHelper.getUsername(token));
|
||||
List<SimpleGrantedAuthority> authList = new ArrayList<>();
|
||||
if (!StringUtils.hasText(username)) return null;
|
||||
|
||||
// 当前用户信息放到ThreadLocal里面
|
||||
BaseContext.setAdminId(JwtHelper.getUserId(token));
|
||||
BaseContext.setAdminName(username);
|
||||
|
||||
// 通过username从redis获取权限数据
|
||||
Object UserObject = redisTemplate.opsForValue().get(username);
|
||||
// 把redis获取字符串权限数据转换要求集合类型 List<SimpleGrantedAuthority>
|
||||
if (UserObject != null) {
|
||||
LoginVo loginVo = JSON.parseObject(JSON.toJSONString(UserObject), LoginVo.class);
|
||||
List<String> roleList = loginVo.getRoleList();
|
||||
roleList.forEach(role -> authList.add(new SimpleGrantedAuthority(role)));
|
||||
|
||||
return new UsernamePasswordAuthenticationToken(username, null, authList);
|
||||
} else {
|
||||
return new UsernamePasswordAuthenticationToken(username, null, new ArrayList<>());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,139 +0,0 @@
|
|||
package cn.bunny.security.filter;
|
||||
|
||||
|
||||
import cn.bunny.common.service.utils.ResponseUtil;
|
||||
import cn.bunny.dto.user.LoginDto;
|
||||
import cn.bunny.pojo.result.Result;
|
||||
import cn.bunny.pojo.result.ResultCodeEnum;
|
||||
import cn.bunny.pojo.result.constant.RedisUserConstant;
|
||||
import cn.bunny.security.handelr.SecurityAuthenticationFailureHandler;
|
||||
import cn.bunny.security.handelr.SecurityAuthenticationSuccessHandler;
|
||||
import cn.bunny.security.service.CustomUserDetailsService;
|
||||
import cn.bunny.vo.system.login.LoginVo;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import jakarta.servlet.FilterChain;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* * UsernamePasswordAuthenticationFilter
|
||||
* * 也可以在这里添加验证码、短信等的验证
|
||||
* 由于SpringSecurity的登录只能是表单形式 并且用户名密码需要时username、password,可以通过继承 UsernamePasswordAuthenticationFilter 获取登录请求的参数
|
||||
* 再去设置到 UsernamePasswordAuthenticationToken 中 来改变请求传参方式、参数名等 或者也可以在登录的时候加入其他参数等等
|
||||
*/
|
||||
public class TokenLoginFilterService extends UsernamePasswordAuthenticationFilter {
|
||||
private final RedisTemplate<String, Object> redisTemplate;
|
||||
private final CustomUserDetailsService customUserDetailsService;
|
||||
private LoginDto loginDto;
|
||||
|
||||
// 依赖注入
|
||||
public TokenLoginFilterService(AuthenticationConfiguration authenticationConfiguration, RedisTemplate<String, Object> redisTemplate, CustomUserDetailsService customUserDetailsService) throws Exception {
|
||||
this.setAuthenticationSuccessHandler(new SecurityAuthenticationSuccessHandler());
|
||||
this.setAuthenticationFailureHandler(new SecurityAuthenticationFailureHandler());
|
||||
this.setPostOnly(false);
|
||||
// ? 指定登录接口及提交方式,可以指定任意路径
|
||||
this.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/*/login", HttpMethod.POST.name()));
|
||||
this.setAuthenticationManager(authenticationConfiguration.getAuthenticationManager());
|
||||
// 依赖注入
|
||||
this.redisTemplate = redisTemplate;
|
||||
this.customUserDetailsService = customUserDetailsService;
|
||||
}
|
||||
|
||||
/**
|
||||
* * 登录认证,获取输入的用户名和密码,调用方法认证
|
||||
* 接受前端login登录参数
|
||||
* 在这里可以设置短信验证登录
|
||||
*/
|
||||
@Override
|
||||
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
|
||||
try {
|
||||
// 获取用户信息
|
||||
loginDto = new ObjectMapper().readValue(request.getInputStream(), LoginDto.class);
|
||||
|
||||
// 登录验证码判断
|
||||
String username = loginDto.getUsername();
|
||||
String emailCode = loginDto.getEmailCode().toLowerCase();
|
||||
String redisEmailCode = (String) redisTemplate.opsForValue().get(RedisUserConstant.getAdminUserEmailCodePrefix(username));
|
||||
|
||||
// 如果不存在验证码
|
||||
if (!StringUtils.hasText(emailCode)) {
|
||||
ResponseUtil.out(response, Result.error(ResultCodeEnum.EMAIL_CODE_NOT_EMPTY));
|
||||
return null;
|
||||
}
|
||||
if (!StringUtils.hasText(redisEmailCode)) {
|
||||
ResponseUtil.out(response, Result.error(ResultCodeEnum.SEND_EMAIL_CODE_NOT_EMPTY));
|
||||
return null;
|
||||
}
|
||||
// 验证码不匹配
|
||||
if (!Objects.equals(redisEmailCode.toLowerCase(), emailCode)) {
|
||||
ResponseUtil.out(response, Result.error(ResultCodeEnum.EMAIL_CODE_NOT_MATCHING));
|
||||
return null;
|
||||
}
|
||||
|
||||
// 封装对象,将用户名密码传入
|
||||
Authentication authenticationToken = new UsernamePasswordAuthenticationToken(loginDto.getUsername(), loginDto.getPassword());
|
||||
return this.getAuthenticationManager().authenticate(authenticationToken);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e.getLocalizedMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* * 认证成功调用方法
|
||||
* 返回登录成功后的信息
|
||||
*/
|
||||
@Override
|
||||
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication auth) {
|
||||
// 封装返回对象
|
||||
LoginVo loginVo = customUserDetailsService.login(loginDto);
|
||||
|
||||
// 判断用户是否被锁定
|
||||
if (loginVo.getStatus() == 1) {
|
||||
ResponseUtil.out(response, Result.error(ResultCodeEnum.FAIL_NO_ACCESS_DENIED_USER_LOCKED));
|
||||
return;
|
||||
}
|
||||
|
||||
// 将值存入Redis中
|
||||
redisTemplate.opsForValue().set(RedisUserConstant.getAdminLoginInfoPrefix(loginVo.getEmail()), loginVo, 15, TimeUnit.DAYS);
|
||||
// 将Redis中验证码删除
|
||||
redisTemplate.delete(RedisUserConstant.getAdminUserEmailCodePrefix(loginVo.getEmail()));
|
||||
// 返回登录信息
|
||||
ResponseUtil.out(response, Result.success(loginVo));
|
||||
}
|
||||
|
||||
/**
|
||||
* * 认证失败调用方法,失败判断
|
||||
* 1. 是否包含用户名
|
||||
* 2. 是否包含密码
|
||||
*/
|
||||
@Override
|
||||
protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) {
|
||||
// 账号和密码不能为空
|
||||
if (loginDto == null) {
|
||||
ResponseUtil.out(response, Result.error(ResultCodeEnum.LOGIN_ERROR_USERNAME_PASSWORD_NOT_EMPTY));
|
||||
}
|
||||
// 用户名为空
|
||||
if (!StringUtils.hasText(loginDto.getUsername())) {
|
||||
ResponseUtil.out(response, Result.error(ResultCodeEnum.USERNAME_NOT_EMPTY));
|
||||
}
|
||||
// 密码为空
|
||||
if (!StringUtils.hasText(loginDto.getPassword())) {
|
||||
ResponseUtil.out(response, Result.error(ResultCodeEnum.PASSWORD_NOT_EMPTY));
|
||||
}
|
||||
// 抛出异常,账号或密码错误
|
||||
ResponseUtil.out(response, Result.error(null, ResultCodeEnum.LOGIN_ERROR));
|
||||
}
|
||||
}
|
7
pom.xml
7
pom.xml
|
@ -19,13 +19,12 @@
|
|||
<module>common</module>
|
||||
<module>dao</module>
|
||||
<module>service</module>
|
||||
<module>module</module>
|
||||
</modules>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>22</maven.compiler.source>
|
||||
<maven.compiler.target>22</maven.compiler.target>
|
||||
<java.version>21</java.version>
|
||||
<maven.compiler.source>17</maven.compiler.source>
|
||||
<maven.compiler.target>17</maven.compiler.target>
|
||||
<java.version>17</java.version>
|
||||
<junit.version>3.8.1</junit.version>
|
||||
<mybatis-plus.version>3.5.6</mybatis-plus.version>
|
||||
<mysql.version>8.0.30</mysql.version>
|
||||
|
|
|
@ -18,6 +18,6 @@ COPY target/*.jar /home/bunny/app.jar
|
|||
ENTRYPOINT ["java","-jar","/home/bunny/app.jar"]
|
||||
|
||||
#暴露 8800 端口
|
||||
EXPOSE 8080
|
||||
EXPOSE 7070
|
||||
|
||||
# maven 打包:mvn clean package -Pprod -DskipTests
|
||||
# mvn clean package -Pprod -DskipTests
|
|
@ -25,38 +25,35 @@
|
|||
<artifactId>service-utils</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<!-- rabbitMQ -->
|
||||
<dependency>
|
||||
<groupId>cn.bunny</groupId>
|
||||
<artifactId>module-rabbitMQ</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<!-- security -->
|
||||
<dependency>
|
||||
<groupId>cn.bunny</groupId>
|
||||
<artifactId>spring-security</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<!-- 消除 spring-security 黄色 -->
|
||||
<!-- spring-security -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-security</artifactId>
|
||||
</dependency>
|
||||
<!-- spring-security-test -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-test</artifactId>
|
||||
</dependency>
|
||||
<!-- amqp -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-amqp</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.amqp</groupId>
|
||||
<artifactId>spring-rabbit-test</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.dataformat</groupId>
|
||||
<artifactId>jackson-dataformat-xml</artifactId>
|
||||
<version>2.16.0-rc1</version>
|
||||
</dependency>
|
||||
<!-- 消除service utils黄色 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<!-- mail模块 -->
|
||||
<dependency>
|
||||
<groupId>cn.bunny</groupId>
|
||||
<artifactId>module-mail</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<!-- 单元测试 -->
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
|
|
|
@ -9,13 +9,13 @@ import org.springframework.context.annotation.ComponentScan;
|
|||
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||
|
||||
@ComponentScan(basePackages = {"cn.bunny"})
|
||||
@MapperScan("cn.bunny.service.mapper")
|
||||
@EnableScheduling// 定时任务
|
||||
@EnableCaching// 开启缓存注解
|
||||
@EnableTransactionManagement// 开启事务注解
|
||||
@SpringBootApplication
|
||||
@ComponentScan("cn.bunny")
|
||||
@EnableScheduling
|
||||
@EnableCaching
|
||||
@EnableTransactionManagement
|
||||
@Slf4j
|
||||
@SpringBootApplication
|
||||
public class ServiceApplication {
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(ServiceApplication.class, args);
|
||||
|
|
|
@ -1,15 +0,0 @@
|
|||
package cn.bunny.service.aop.annotation;
|
||||
|
||||
import cn.bunny.pojo.enums.OperationType;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface AutoFill {
|
||||
// 数据库操作类型
|
||||
OperationType value();
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
package cn.bunny.service.aop.aspect;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.aspectj.lang.JoinPoint;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.aspectj.lang.annotation.Before;
|
||||
import org.aspectj.lang.annotation.Pointcut;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Aspect
|
||||
@Component
|
||||
@Slf4j
|
||||
public class AutoFillAspect {
|
||||
@Pointcut("execution(* cn.bunny.service.web.service.impl..*(..))")
|
||||
public void autoFillPointcut() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 之前操作
|
||||
*
|
||||
* @param joinPoint 参数
|
||||
*/
|
||||
@Before("autoFillPointcut()")
|
||||
public void autoFill(JoinPoint joinPoint) {
|
||||
log.info("开始进行自动填充");
|
||||
}
|
||||
}
|
|
@ -1,100 +1,24 @@
|
|||
package cn.bunny.service.aop.aspect;
|
||||
|
||||
import cn.bunny.common.service.utils.JwtHelper;
|
||||
import cn.bunny.entity.system.log.SystemLog;
|
||||
import cn.bunny.service.aop.annotation.SkipLog;
|
||||
import cn.bunny.service.mapper.SystemLogMapper;
|
||||
import cn.bunny.vo.system.login.LoginVo;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
import org.aspectj.lang.annotation.Around;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.aspectj.lang.annotation.Pointcut;
|
||||
import org.aspectj.lang.reflect.MethodSignature;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
|
||||
@Aspect
|
||||
@Component
|
||||
@Slf4j
|
||||
public class AutoLogAspect {
|
||||
@Autowired
|
||||
private SystemLogMapper systemLogMapper;
|
||||
|
||||
@Pointcut("execution(* cn.bunny.service.web.controller..*(..))")
|
||||
@Pointcut("execution(* cn.bunny.service.controller..*(..))")
|
||||
public void point() {
|
||||
}
|
||||
|
||||
@Around(value = "point()")
|
||||
public Object aroundMethod(ProceedingJoinPoint joinPoint) throws Throwable {
|
||||
Object result;
|
||||
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
|
||||
// 是否有跳过注解,如果有跳过注解就不执行当前操作!!!
|
||||
SkipLog annotation = signature.getMethod().getAnnotation(SkipLog.class);
|
||||
// 目标方法所在类名路径
|
||||
String classPath = joinPoint.getSignature().getDeclaringTypeName();
|
||||
// 当前执行的方法名
|
||||
String methodName = signature.getName();
|
||||
// 入参内容
|
||||
String args = Arrays.toString(joinPoint.getArgs());
|
||||
// 获取用户token
|
||||
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
|
||||
HttpServletRequest request = requestAttributes.getRequest();
|
||||
String token = request.getHeader("token");
|
||||
// 初始化系统日志对象
|
||||
SystemLog systemLog = new SystemLog();
|
||||
// token转为实体对象
|
||||
Map<String, Object> mapByToken = JwtHelper.getMapByToken(token);
|
||||
LoginVo loginVo = JSONObject.parseObject(JSONObject.toJSONString(mapByToken), LoginVo.class);
|
||||
|
||||
// 插入Ip地址
|
||||
systemLog.setIpAddress(request.getRemoteHost());
|
||||
|
||||
try {
|
||||
// 当为null时跳过执行
|
||||
if (annotation != null) return joinPoint.proceed();
|
||||
if (args.equals("[null]")) {
|
||||
systemLog.setArgs(null);
|
||||
} else {
|
||||
systemLog.setArgs(args);
|
||||
}
|
||||
// 登录返回Vo不为空即插入
|
||||
if (loginVo != null) {
|
||||
systemLog.setNickname(loginVo.getNickName());
|
||||
systemLog.setEmail(loginVo.getEmail());
|
||||
systemLog.setUpdateUser(loginVo.getId());
|
||||
}
|
||||
|
||||
systemLog.setClassPath(classPath);
|
||||
systemLog.setMethodName(methodName);
|
||||
systemLog.setToken(token);
|
||||
|
||||
// 目标对象(连接点)方法的执行
|
||||
result = joinPoint.proceed();
|
||||
systemLog.setResult(JSONObject.toJSONString(result));
|
||||
} catch (Exception exception) {
|
||||
String message = exception.getMessage();
|
||||
StackTraceElement[] stackTrace = exception.getStackTrace();
|
||||
|
||||
// 如果报错,设置报错的堆栈和消息,放到数据库中
|
||||
systemLog.setErrorStack(Arrays.toString(stackTrace));
|
||||
systemLog.setErrorMessage(message);
|
||||
|
||||
// 插入日志数据到数据库
|
||||
systemLogMapper.insert(systemLog);
|
||||
|
||||
throw exception;
|
||||
}
|
||||
|
||||
// 插入日志数据到数据库
|
||||
systemLogMapper.insert(systemLog);
|
||||
return result;
|
||||
System.out.println("AOP方法执行");
|
||||
return joinPoint.proceed();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,13 @@
|
|||
package cn.bunny.service.controller;
|
||||
|
||||
import cn.hutool.captcha.CaptchaUtil;
|
||||
import cn.hutool.captcha.CircleCaptcha;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
@ -15,4 +21,16 @@ public class IndexController {
|
|||
public String index() {
|
||||
return "欢迎访问 Bunny Java Template,欢迎去Gitee:https://gitee.com/BunnyBoss/java_single.git";
|
||||
}
|
||||
|
||||
@Operation(summary = "生成验证码", description = "生成验证码")
|
||||
@GetMapping("checkCode")
|
||||
public ResponseEntity<byte[]> checkCode() {
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType(MediaType.IMAGE_JPEG);
|
||||
|
||||
// 生成验证码
|
||||
CircleCaptcha captcha = CaptchaUtil.createCircleCaptcha(150, 48, 4, 2);
|
||||
byte[] image = captcha.getImageBytes();
|
||||
return new ResponseEntity<>(image, headers, HttpStatus.OK);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,36 +0,0 @@
|
|||
package cn.bunny.service.controller;
|
||||
|
||||
|
||||
import cn.bunny.dto.user.LoginDto;
|
||||
import cn.bunny.pojo.result.Result;
|
||||
import cn.bunny.service.service.UserService;
|
||||
import cn.bunny.vo.system.login.LoginVo;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@Tag(name = "登录相关接口")
|
||||
@RestController
|
||||
@RequestMapping("/admin")
|
||||
public class LoginController {
|
||||
@Autowired
|
||||
private UserService userService;
|
||||
|
||||
@Operation(summary = "登录接口", description = "后台用户登录接口")
|
||||
@PostMapping("login")
|
||||
public Result<LoginVo> login(@RequestBody LoginDto loginDto) {
|
||||
LoginVo vo = userService.login(loginDto);
|
||||
return Result.success(vo);
|
||||
}
|
||||
|
||||
@Operation(summary = "发送邮箱验证码", description = "发送邮箱验证码")
|
||||
@PostMapping("noAuth/sendEmail")
|
||||
public Result<String> sendEmail(String email) {
|
||||
userService.sendEmail(email);
|
||||
return Result.success();
|
||||
}
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
package cn.bunny.service.controller;
|
||||
|
||||
import cn.bunny.service.service.LoginService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@Tag(name = "web相关接口")
|
||||
@RestController
|
||||
@RequestMapping("/api")
|
||||
public class WebController {
|
||||
@Autowired
|
||||
private LoginService loginService;
|
||||
|
||||
@Operation(summary = "生成验证码", description = "生成验证码")
|
||||
@GetMapping("checkCode")
|
||||
public ResponseEntity<byte[]> checkCode() {
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType(MediaType.IMAGE_JPEG);
|
||||
|
||||
byte[] image = loginService.checkCode();
|
||||
return new ResponseEntity<byte[]>(image, headers, HttpStatus.OK);
|
||||
}
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
package cn.bunny.service.mapper;
|
||||
|
||||
import cn.bunny.entity.system.admin.AdminPower;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Mapper 接口
|
||||
* </p>
|
||||
*
|
||||
* @author Bunny
|
||||
* @since 2024-05-18
|
||||
*/
|
||||
@Mapper
|
||||
public interface AdminPowerMapper extends BaseMapper<AdminPower> {
|
||||
/**
|
||||
* 查询用户权限信息
|
||||
*
|
||||
* @param roleIdList 角色id 列表
|
||||
* @return 用户对应的权限
|
||||
*/
|
||||
AdminPower[] selectByPowerWithRoleIdList(List<Long> roleIdList);
|
||||
|
||||
/**
|
||||
* 查询用户权限
|
||||
*
|
||||
* @param userId 用户id
|
||||
* @return 用户权限列表
|
||||
*/
|
||||
List<AdminPower> queryByUserIdWithPower(Long userId);
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
package cn.bunny.service.mapper;
|
||||
|
||||
import cn.bunny.entity.system.admin.AdminRole;
|
||||
import cn.bunny.entity.system.admin.auth.AuthUserRole;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Mapper 接口
|
||||
* </p>
|
||||
*
|
||||
* @author Bunny
|
||||
* @since 2024-05-18
|
||||
*/
|
||||
@Mapper
|
||||
public interface AdminRoleMapper extends BaseMapper<AdminRole> {
|
||||
|
||||
/**
|
||||
* 查询用户所有的角色信息
|
||||
*
|
||||
* @param userId 用户id
|
||||
* @return 用户对应的角色
|
||||
*/
|
||||
AuthUserRole[] selectByRoleWithUserId(Long userId);
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
package cn.bunny.service.mapper;
|
||||
|
||||
import cn.bunny.entity.system.email.EmailUsers;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Mapper 接口
|
||||
* </p>
|
||||
*
|
||||
* @author Bunny
|
||||
* @since 2024-05-14
|
||||
*/
|
||||
@Mapper
|
||||
public interface EmailUsersMapper extends BaseMapper<EmailUsers> {
|
||||
|
||||
/**
|
||||
* 彻底删除邮箱用户
|
||||
*
|
||||
* @param id 用户ID
|
||||
*/
|
||||
void thoroughDeleteById(Long id);
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
package cn.bunny.service.mapper;
|
||||
|
||||
import cn.bunny.entity.system.log.SystemLog;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 系统日志表 Mapper 接口
|
||||
* </p>
|
||||
*
|
||||
* @author Bunny
|
||||
* @since 2024-05-31
|
||||
*/
|
||||
@Mapper
|
||||
public interface SystemLogMapper extends BaseMapper<SystemLog> {
|
||||
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
package cn.bunny.service.mapper;
|
||||
|
||||
import cn.bunny.entity.system.user.User;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 用户信息 Mapper 接口
|
||||
* </p>
|
||||
*
|
||||
* @author Bunny
|
||||
* @since 2024-05-18
|
||||
*/
|
||||
@Mapper
|
||||
public interface UserMapper extends BaseMapper<User> {
|
||||
/**
|
||||
* 前台用户登录接口
|
||||
*
|
||||
* @param username 邮箱/昵称
|
||||
* @param password 吗,Image
|
||||
* @return 登录参数
|
||||
*/
|
||||
User login(String username, String password);
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package cn.bunny.module.rabbitMQ.config;
|
||||
package cn.bunny.service.mq;
|
||||
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import lombok.extern.slf4j.Slf4j;
|
|
@ -1,4 +1,4 @@
|
|||
package cn.bunny.module.rabbitMQ.listener;
|
||||
package cn.bunny.service.mq.listener;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
|
@ -1,4 +1,4 @@
|
|||
package cn.bunny.module.rabbitMQ.listener;
|
||||
package cn.bunny.service.mq.listener;
|
||||
|
||||
import com.rabbitmq.client.Channel;
|
||||
import lombok.extern.slf4j.Slf4j;
|
|
@ -1,4 +1,4 @@
|
|||
package cn.bunny.module.rabbitMQ.listener;
|
||||
package cn.bunny.service.mq.listener;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
|
@ -1,4 +1,4 @@
|
|||
package cn.bunny.module.rabbitMQ.listener;
|
||||
package cn.bunny.service.mq.listener;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
|
@ -1,4 +1,4 @@
|
|||
package cn.bunny.module.rabbitMQ.listener;
|
||||
package cn.bunny.service.mq.listener;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
|
@ -1,4 +1,4 @@
|
|||
package cn.bunny.module.rabbitMQ.listener;
|
||||
package cn.bunny.service.mq.listener;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
|
@ -1,4 +1,4 @@
|
|||
package cn.bunny.service.mq;
|
||||
package cn.bunny.service.mq.publish;
|
||||
|
||||
import org.springframework.amqp.rabbit.core.RabbitTemplate;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
@ -1,54 +0,0 @@
|
|||
package cn.bunny.service.security;
|
||||
|
||||
import cn.bunny.dto.user.LoginDto;
|
||||
import cn.bunny.entity.system.admin.AdminRole;
|
||||
import cn.bunny.entity.system.user.User;
|
||||
import cn.bunny.security.custom.CustomUser;
|
||||
import cn.bunny.service.mapper.AdminRoleMapper;
|
||||
import cn.bunny.service.mapper.UserMapper;
|
||||
import cn.bunny.service.service.UserService;
|
||||
import cn.bunny.vo.system.login.LoginVo;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.core.authority.AuthorityUtils;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Component
|
||||
public class CustomUserDetailsService implements cn.bunny.security.service.CustomUserDetailsService {
|
||||
@Autowired
|
||||
private UserMapper userMapper;
|
||||
@Autowired
|
||||
private UserService userService;
|
||||
@Autowired
|
||||
private AdminRoleMapper adminRoleMapper;
|
||||
|
||||
@Override
|
||||
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
|
||||
// 根据邮箱查询用户名
|
||||
User user = userMapper.selectOne(Wrappers.<User>lambdaQuery().eq(User::getEmail, username));
|
||||
List<AdminRole> sysRoleList = adminRoleMapper.selectList(null);
|
||||
// 都为空抛出异常,用户不存在
|
||||
if (user == null) {
|
||||
throw new UsernameNotFoundException("");
|
||||
}
|
||||
|
||||
// 查询所有的角色
|
||||
List<String> roleAuthoritieList = sysRoleList.stream().map(AdminRole::getRoleCode).toList();
|
||||
return new CustomUser(user, AuthorityUtils.createAuthorityList(roleAuthoritieList));
|
||||
}
|
||||
|
||||
/**
|
||||
* 前台用户登录接口
|
||||
*
|
||||
* @param loginDto 登录参数
|
||||
* @return 登录后结果返回
|
||||
*/
|
||||
@Override
|
||||
public LoginVo login(LoginDto loginDto) {
|
||||
return userService.login(loginDto);
|
||||
}
|
||||
}
|
|
@ -1,12 +1,13 @@
|
|||
package cn.bunny.security.config;
|
||||
package cn.bunny.service.security.config;
|
||||
|
||||
import cn.bunny.security.custom.CustomPasswordEncoder;
|
||||
import cn.bunny.security.filter.TokenAuthenticationFilter;
|
||||
import cn.bunny.security.filter.TokenLoginFilterService;
|
||||
import cn.bunny.security.handelr.SecurityAccessDeniedHandler;
|
||||
import cn.bunny.security.handelr.SecurityAuthenticationEntryPoint;
|
||||
import cn.bunny.security.service.CustomAuthorizationManagerService;
|
||||
import cn.bunny.security.service.CustomUserDetailsService;
|
||||
import cn.bunny.service.security.custom.CustomPasswordEncoder;
|
||||
import cn.bunny.service.security.filter.NoTokenAuthenticationFilter;
|
||||
import cn.bunny.service.security.filter.TokenAuthenticationFilter;
|
||||
import cn.bunny.service.security.filter.TokenLoginFilterService;
|
||||
import cn.bunny.service.security.handelr.SecurityAccessDeniedHandler;
|
||||
import cn.bunny.service.security.handelr.SecurityAuthenticationEntryPoint;
|
||||
import cn.bunny.service.security.service.CustomAuthorizationManagerService;
|
||||
import cn.bunny.service.security.service.CustomUserDetailsService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
@ -60,7 +61,8 @@ public class WebSecurityConfig {
|
|||
.rememberMe(AbstractHttpConfigurer::disable)
|
||||
.authorizeHttpRequests(authorize -> {
|
||||
// 有样式文件,不需要访问权限
|
||||
authorize.requestMatchers(RegexRequestMatcher.regexMatcher("^\\S*[css|js]$")).permitAll();
|
||||
// authorize.requestMatchers(RegexRequestMatcher.regexMatcher("^\\S*[css|js]$")).permitAll();
|
||||
authorize.requestMatchers(RegexRequestMatcher.regexMatcher("^.*\\.(css|js)$")).permitAll();
|
||||
// 上面都不是需要鉴权访问
|
||||
authorize.anyRequest().access(customAuthorizationManager);
|
||||
})
|
||||
|
@ -73,6 +75,7 @@ public class WebSecurityConfig {
|
|||
// 登录验证过滤器
|
||||
.addFilterBefore(new TokenLoginFilterService(authenticationConfiguration, redisTemplate, customUserDetailsService), UsernamePasswordAuthenticationFilter.class)
|
||||
// 其它权限鉴权过滤器
|
||||
.addFilterAt(new NoTokenAuthenticationFilter(redisTemplate), UsernamePasswordAuthenticationFilter.class)
|
||||
.addFilterAt(new TokenAuthenticationFilter(redisTemplate), UsernamePasswordAuthenticationFilter.class)
|
||||
// 自定义密码加密器和用户登录
|
||||
.passwordManagement(customPasswordEncoder).userDetailsService(customUserDetailsService);
|
||||
|
@ -88,8 +91,11 @@ public class WebSecurityConfig {
|
|||
// 排出鉴定路径
|
||||
@Bean
|
||||
public WebSecurityCustomizer webSecurityCustomizer() {
|
||||
String[] annotations = {"/", "/test/**", "/admin/login", "/*.html", "/*/*/noAuth/**", "/*/noAuth/**", "/favicon.ico",
|
||||
"/swagger-resources/**", "/swagger-ui.html/**", "/v3/**", "/api/**"
|
||||
String[] annotations = {
|
||||
"/", "/ws/**",
|
||||
"/*/*/noAuth/**", "/*/noAuth/**", "/noAuth/**",
|
||||
"/media.ico", "/favicon.ico", "*.html",
|
||||
"/swagger-resources/**", "/v3/**", "/swagger-ui/**"
|
||||
};
|
||||
return web -> web.ignoring().requestMatchers(annotations);
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package cn.bunny.security.custom;
|
||||
package cn.bunny.service.security.custom;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.config.Customizer;
|
|
@ -1,5 +1,6 @@
|
|||
package cn.bunny.security.custom;
|
||||
package cn.bunny.service.security.custom;
|
||||
|
||||
import cn.bunny.entity.system.AdminUser;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
|
@ -13,9 +14,9 @@ import java.util.Collection;
|
|||
@Getter
|
||||
@Setter
|
||||
public class CustomUser extends User {
|
||||
private cn.bunny.entity.system.user.User user;
|
||||
private AdminUser user;
|
||||
|
||||
public CustomUser(cn.bunny.entity.system.user.User user, Collection<? extends GrantedAuthority> authorities) {
|
||||
public CustomUser(AdminUser user, Collection<? extends GrantedAuthority> authorities) {
|
||||
super(user.getEmail(), user.getPassword(), authorities);
|
||||
this.user = user;
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
package cn.bunny.service.security.filter;
|
||||
|
||||
|
||||
import jakarta.servlet.FilterChain;
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.web.filter.OncePerRequestFilter;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class NoTokenAuthenticationFilter extends OncePerRequestFilter {
|
||||
private final RedisTemplate<String, Object> redisTemplate;
|
||||
|
||||
public NoTokenAuthenticationFilter(RedisTemplate<String, Object> redisTemplate) {
|
||||
this.redisTemplate = redisTemplate;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
|
||||
// // 判断是否有 token
|
||||
// String token = request.getHeader("token");
|
||||
// if (token == null) {
|
||||
// ResponseUtil.out(response, Result.error(ResultCodeEnum.LOGIN_AUTH));
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// // 判断 token 是否过期
|
||||
// boolean expired = JwtHelper.isExpired(token);
|
||||
// if (expired) {
|
||||
// ResponseUtil.out(response, Result.error(ResultCodeEnum.AUTHENTICATION_EXPIRED));
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// // token 存在查找 Redis
|
||||
// String username = JwtHelper.getUsername(token);
|
||||
// Long userId = JwtHelper.getUserId(token);
|
||||
// LoginVo loginVo = (LoginVo) redisTemplate.opsForValue().get(RedisUserConstant.getAdminLoginInfoPrefix(username));
|
||||
//
|
||||
// // 判断用户是否禁用
|
||||
// if (loginVo != null && loginVo.getStatus()) {
|
||||
// ResponseUtil.out(response, Result.error(ResultCodeEnum.FAIL_NO_ACCESS_DENIED_USER_LOCKED));
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// // 设置用户信息
|
||||
// BaseContext.setUsername(username);
|
||||
// BaseContext.setUserId(userId);
|
||||
// BaseContext.setLoginVo(loginVo);
|
||||
|
||||
// 执行下一个过滤器
|
||||
doFilter(request, response, filterChain);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
package cn.bunny.service.security.filter;
|
||||
|
||||
import jakarta.servlet.FilterChain;
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.web.filter.OncePerRequestFilter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class TokenAuthenticationFilter extends OncePerRequestFilter {
|
||||
private final RedisTemplate<String, Object> redisTemplate;
|
||||
|
||||
public TokenAuthenticationFilter(RedisTemplate<String, Object> redisTemplate) {
|
||||
this.redisTemplate = redisTemplate;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {
|
||||
String token = request.getHeader("token");
|
||||
|
||||
// 判断是否有token,如果后面还有过滤器就这样写
|
||||
// if (token == null) {
|
||||
// doFilter(request, response, chain);
|
||||
// return;
|
||||
// }
|
||||
|
||||
// 自定义实现内容
|
||||
UsernamePasswordAuthenticationToken authentication = getAuthentication(request);
|
||||
SecurityContextHolder.getContext().setAuthentication(authentication);
|
||||
|
||||
chain.doFilter(request, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* * 用户请求判断
|
||||
*
|
||||
* @param request 请求
|
||||
* @return 验证码方法
|
||||
*/
|
||||
private UsernamePasswordAuthenticationToken getAuthentication(HttpServletRequest request) {
|
||||
// 请求头是否有token
|
||||
String token = request.getHeader("token");
|
||||
String username = "admin";
|
||||
List<SimpleGrantedAuthority> authList = new ArrayList<>();
|
||||
|
||||
// 设置角色内容
|
||||
if (token != null) {
|
||||
List<String> roleList = new ArrayList<>();
|
||||
return new UsernamePasswordAuthenticationToken(username, null, authList);
|
||||
} else {
|
||||
return new UsernamePasswordAuthenticationToken(username, null, new ArrayList<>());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
package cn.bunny.service.security.filter;
|
||||
|
||||
|
||||
import cn.bunny.dto.user.LoginDto;
|
||||
import cn.bunny.pojo.constant.RedisUserConstant;
|
||||
import cn.bunny.pojo.result.Result;
|
||||
import cn.bunny.pojo.result.ResultCodeEnum;
|
||||
import cn.bunny.service.security.handelr.SecurityAuthenticationFailureHandler;
|
||||
import cn.bunny.service.security.handelr.SecurityAuthenticationSuccessHandler;
|
||||
import cn.bunny.service.security.service.CustomUserDetailsService;
|
||||
import cn.bunny.vo.user.LoginVo;
|
||||
import jakarta.servlet.FilterChain;
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static cn.bunny.common.service.utils.ResponseUtil.out;
|
||||
|
||||
/**
|
||||
* * UsernamePasswordAuthenticationFilter
|
||||
* * 也可以在这里添加验证码、短信等的验证
|
||||
* 由于SpringSecurity的登录只能是表单形式 并且用户名密码需要时username、password,可以通过继承 UsernamePasswordAuthenticationFilter 获取登录请求的参数
|
||||
* 再去设置到 UsernamePasswordAuthenticationToken 中 来改变请求传参方式、参数名等 或者也可以在登录的时候加入其他参数等等
|
||||
*/
|
||||
public class TokenLoginFilterService extends UsernamePasswordAuthenticationFilter {
|
||||
private final RedisTemplate<String, Object> redisTemplate;
|
||||
private final CustomUserDetailsService customUserDetailsService;
|
||||
private LoginDto loginDto;
|
||||
|
||||
public TokenLoginFilterService(AuthenticationConfiguration authenticationConfiguration, RedisTemplate<String, Object> redisTemplate, CustomUserDetailsService customUserDetailsService) throws Exception {
|
||||
this.setAuthenticationSuccessHandler(new SecurityAuthenticationSuccessHandler());
|
||||
this.setAuthenticationFailureHandler(new SecurityAuthenticationFailureHandler());
|
||||
this.setPostOnly(false);
|
||||
this.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/*/login", RequestMethod.POST.name()));
|
||||
this.setAuthenticationManager(authenticationConfiguration.getAuthenticationManager());
|
||||
this.redisTemplate = redisTemplate;
|
||||
this.customUserDetailsService = customUserDetailsService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
|
||||
loginDto = new LoginDto();
|
||||
loginDto.setUsername("admin");
|
||||
loginDto.setPassword("password");
|
||||
Authentication authenticationToken = new UsernamePasswordAuthenticationToken(loginDto.getUsername(), loginDto.getPassword());
|
||||
return getAuthenticationManager().authenticate(authenticationToken);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication auth) throws IOException, ServletException {
|
||||
LoginVo loginAdminVo = customUserDetailsService.login(loginDto);
|
||||
|
||||
if (loginAdminVo.getStatus()) {
|
||||
out(response, Result.error(ResultCodeEnum.FAIL_NO_ACCESS_DENIED_USER_LOCKED));
|
||||
return;
|
||||
}
|
||||
|
||||
redisTemplate.opsForValue().set(RedisUserConstant.getAdminLoginInfoPrefix(loginAdminVo.getEmail()), loginAdminVo, 15, TimeUnit.DAYS);
|
||||
redisTemplate.delete(RedisUserConstant.getAdminUserEmailCodePrefix(loginAdminVo.getEmail()));
|
||||
|
||||
out(response, Result.success(loginAdminVo));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException {
|
||||
String password = loginDto.getPassword();
|
||||
String username = loginDto.getUsername();
|
||||
|
||||
if (password == null || password.isBlank() || username == null || username.isBlank()) {
|
||||
out(response, Result.error(ResultCodeEnum.USERNAME_OR_PASSWORD_NOT_EMPTY));
|
||||
} else {
|
||||
out(response, Result.error(null, ResultCodeEnum.LOGIN_ERROR));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package cn.bunny.security.handelr;
|
||||
package cn.bunny.service.security.handelr;
|
||||
|
||||
import cn.bunny.pojo.result.Result;
|
||||
import cn.bunny.pojo.result.ResultCodeEnum;
|
|
@ -1,4 +1,4 @@
|
|||
package cn.bunny.security.handelr;
|
||||
package cn.bunny.service.security.handelr;
|
||||
|
||||
import cn.bunny.common.service.utils.ResponseUtil;
|
||||
import cn.bunny.pojo.result.Result;
|
|
@ -1,4 +1,4 @@
|
|||
package cn.bunny.security.handelr;
|
||||
package cn.bunny.service.security.handelr;
|
||||
|
||||
import cn.bunny.pojo.result.Result;
|
||||
import com.alibaba.fastjson2.JSON;
|
|
@ -1,4 +1,4 @@
|
|||
package cn.bunny.security.handelr;
|
||||
package cn.bunny.service.security.handelr;
|
||||
|
||||
import cn.bunny.pojo.result.Result;
|
||||
import com.alibaba.fastjson2.JSON;
|
|
@ -1,4 +1,4 @@
|
|||
package cn.bunny.security.service;
|
||||
package cn.bunny.service.security.service;
|
||||
|
||||
import org.springframework.security.authorization.AuthorizationManager;
|
||||
import org.springframework.security.web.access.intercept.RequestAuthorizationContext;
|
|
@ -1,7 +1,7 @@
|
|||
package cn.bunny.security.service;
|
||||
package cn.bunny.service.security.service;
|
||||
|
||||
import cn.bunny.dto.user.LoginDto;
|
||||
import cn.bunny.vo.system.login.LoginVo;
|
||||
import cn.bunny.vo.user.LoginVo;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
|
@ -1,13 +1,9 @@
|
|||
package cn.bunny.service.security;
|
||||
package cn.bunny.service.security.service.iml;
|
||||
|
||||
import cn.bunny.common.service.utils.JwtHelper;
|
||||
import cn.bunny.entity.system.admin.AdminPower;
|
||||
import cn.bunny.security.service.CustomAuthorizationManagerService;
|
||||
import cn.bunny.service.mapper.AdminPowerMapper;
|
||||
import cn.bunny.service.security.service.CustomAuthorizationManagerService;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.access.AccessDeniedException;
|
||||
import org.springframework.security.authorization.AuthorizationDecision;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
|
@ -25,9 +21,6 @@ import java.util.function.Supplier;
|
|||
@Component
|
||||
@Slf4j
|
||||
public class CustomAuthorizationManagerServiceImpl implements CustomAuthorizationManagerService {
|
||||
@Autowired
|
||||
private AdminPowerMapper adminPowerMapper;
|
||||
|
||||
@Override
|
||||
public void verify(Supplier<Authentication> authentication, RequestAuthorizationContext requestAuthorizationContext) {
|
||||
CustomAuthorizationManagerService.super.verify(authentication, requestAuthorizationContext);
|
||||
|
@ -42,9 +35,6 @@ public class CustomAuthorizationManagerServiceImpl implements CustomAuthorizatio
|
|||
String requestURI = request.getRequestURI();// 请求地址
|
||||
String method = request.getMethod();// 请求方式
|
||||
List<String> roleCodeList = authentication.get().getAuthorities().stream().map(GrantedAuthority::getAuthority).toList();// 角色代码列表
|
||||
if (token == null) {
|
||||
throw new AccessDeniedException("");
|
||||
}
|
||||
|
||||
return new AuthorizationDecision(hasRoleList(requestURI, method, userId));
|
||||
}
|
||||
|
@ -57,16 +47,6 @@ public class CustomAuthorizationManagerServiceImpl implements CustomAuthorizatio
|
|||
* @param userId 用户id
|
||||
*/
|
||||
private Boolean hasRoleList(String requestURI, String method, Long userId) {
|
||||
// 查询用户权限
|
||||
List<AdminPower> powerList = adminPowerMapper.queryByUserIdWithPower(userId);
|
||||
// 如果查询到当前地址符合这个地址
|
||||
for (AdminPower adminPower : powerList) {
|
||||
String description = adminPower.getDescription();
|
||||
if (description.equals(requestURI) || requestURI.matches(description)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue