feat(修改): 💄 优化项目模块和依赖

This commit is contained in:
bunny 2024-05-16 08:35:15 +08:00
parent ba874bb530
commit d621865528
98 changed files with 193 additions and 2433 deletions

1
.gitignore vendored
View File

@ -31,3 +31,4 @@ build/
### VS Code ###
.vscode/
logs

View File

@ -1,4 +1,4 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
<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>
@ -18,6 +18,9 @@
</properties>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -10,9 +10,11 @@ public enum ResultCodeEnum {
SUCCESS(200, "操作成功"),
SUCCESS_LOGOUT(200, "退出成功"),
FAIL(201, "失败"),
USERNAME_NOT_EMPTY(201, "用户名不能为空"),
PASSWORD_NOT_EMPTY(201, "密码不能为空"),
SERVICE_ERROR(2012, "服务异常"),
DATA_ERROR(204, "数据异常"),
LOGIN_MOBLE_ERROR(204, "登录错误"),
LOGIN_ERROR(204, "账号或密码错误"),
ILLEGAL_REQUEST(205, "非法请求"),
REPEAT_SUBMIT(206, "重复提交"),
@ -24,7 +26,6 @@ public enum ResultCodeEnum {
FETCH_ACCESSTOKEN_FAILD(218, "获取accessToken失败"),
FETCH_USERINFO_ERROR(219, "获取用户信息失败"),
FAIL_REQUEST_NOT_AUTH(403, "用户未认证"),
FAIL_NO_ACCESS_DENIED(403, "无权访问"),
LOGGED_IN_FROM_ANOTHER_DEVICE(403, "没有权限访问"),

View File

@ -1,71 +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>common</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>common-utils</artifactId>
<packaging>jar</packaging>
<name>common-utils</name>
<url>https://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.14</version>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.1</version>
</dependency>
<!--mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- mysql连接池 -->
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
<version>5.1.0</version>
</dependency>
<!-- mybatis-plus -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
</dependency>
<!-- 数据库代码生成器 - 新版 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.5.6</version>
</dependency>
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
<version>2.3</version>
</dependency>
<!-- 数据库代码生成器 - 旧版 -->
<!-- <dependency> -->
<!-- <groupId>com.baomidou</groupId> -->
<!-- <artifactId>mybatis-plus-generator</artifactId> -->
<!-- <version>3.4.1</version> -->
<!-- </dependency> -->
<!-- <dependency> -->
<!-- <groupId>org.apache.velocity</groupId> -->
<!-- <artifactId>velocity-engine-core</artifactId> -->
<!-- <version>2.0</version> -->
<!-- </dependency> -->
<!-- spring-web -->
</dependencies>
</project>

View File

@ -1,38 +0,0 @@
package cn.bunny.common.constant;
import lombok.Data;
/**
* 信息提示常量类
*/
@Data
public class CommonMessageConstant {
public static final String PASSWORD_ERROR = "密码错误";
public static final String OLD_PASSWORD_ERROR = "旧密码不匹配";
public static final String OLD_PASSWORD_SAME_NEW_PASSWORD = "旧密码与新密码相同";
public static final String ACCOUNT_NOT_FOUND = "账号不存在";
public static final String ACCOUNT_LOCKED = "账号被锁定";
public static final String UNKNOWN_ERROR = "未知错误";
public static final String USER_NOT_LOGIN = "用户未登录";
public static final String USER_TOKEN_OUT_OF_DATE = "用户登录过期";
public static final String LOGIN_FAILED = "登录失败";
public static final String UPLOAD_FAILED = "文件上传失败";
public static final String PASSWORD_EDIT_FAILED = "密码修改失败";
public static final String ALREADY_EXISTS = "已存在";
public static final String REQUEST_NOT_EMPTY = "请求不为空";
public static final String UPDATE_ID_IS_NOT_EMPTY = "删除id不能为空";
public static final String DELETE_ID_IS_NOT_EMPTY = "修改id不能为空";
public static final String MENU_IS_NOT_EXIST = "菜单不存在";
public static final String SAVE_DTO_IS_NULL = "添加参数不能为空";
public static final String UPDATE_DTO_IS_NULL = "修改参数不能为空";
public static final String FIND_ID_IS_NOT_EMPTY = "查询ID不能为空";
public static final String MESSAGE_CODE_NOT_PASS = "短信验证码未过期";
public static final String MESSAGE_CODE_UNAUTHORIZED = "短信验证码未授权,请联系管理员";
public static final String VERIFICATION_CODE_ERROR = "验证码错误";
public static final String USER_DOES_NOT_EXIST = "用户不存在";
public static final String USER_DOES_IS_EXIST = "用户已存在";
public static final String VERIFICATION_CODE_IS_EMPTY = "请先发送验证码";
public static final String LOGIN_DTO_IS_EMPTY = "登录参数不能为空";
public static final String TOKEN_IS_EMPTY = "token为空";
public static final String DATA_IS_EMPTY = "数据为空";
}

View File

@ -1,16 +0,0 @@
package cn.bunny.common.constant;
import lombok.Data;
@Data
public class ExceptionConstant {
public static final String USER_NOT_FOUND = "用户不存在";
public static final String USERNAME_IS_EMPTY = "用户名不能为空";
public static final String PASSWORD_ERROR = "密码错误";
public static final String PASSWORD_IS_EMPTY = "密码不能为空";
public static final String CAPTCHA_IS_EMPTY = "提交验证码不能为空";
public static final String KEY_IS_EMPTY = "验证码key不能为空";
public static final String VERIFICATION_CODE_DOES_NOT_MATCH = "验证码不匹配";
public static final String VERIFICATION_CODE_IS_EMPTY = "验证码失效或不存在";
}

View File

@ -1,11 +0,0 @@
package cn.bunny.common.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";
}

View File

@ -1,14 +0,0 @@
package cn.bunny.common.constant;
import lombok.Data;
/**
* 邮箱消息
*/
@Data
public class MailMessageConstant {
public static final String EMPTY_SEND_OBJECT = "空发送对象";
public static final String ADDRESS_NOT_NULL = "收件人不能为空";
public static final String TITLE_NOT_NULL = "标题不能为空";
public static final String SEND_MESSAGE_NOT_NULL = "发送消息不能为空";
}

View File

@ -1,19 +0,0 @@
package cn.bunny.common.constant;
import lombok.Data;
@Data
public class MinioMessageConstant {
public static final String BUCKET_EXISTS_EXCEPTION = "查询文化部对象失败";
public static final String DELETE_BUCKET_EXCEPTION = "删除文件对象失败";
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 = "启用文件失败";
public static final String DOWNLOAD_BUCKET_EXCEPTION = "下载文件失败";
public static final String UPLOAD_BUCKET_EXCEPTION = "上传文件失败";
}

View File

@ -1,18 +0,0 @@
package cn.bunny.common.constant;
import lombok.Data;
/**
* 密码常量
*/
@Data
public class PasswordConstant {
// 默认密码
public static final String DEFAULT_PASSWORD = "123456";
// JWT密码
public static final String DEFAULT_JWT_PASSWORD = "123456";
// 默认头像
public static final String AVTAR = "https://oss.aliyuncs.com/aliyun_id_photo_bucket/default_handsome.jpg";
// 设置token过期时间
public static final long TOKEN_EXPIRATION = 365L * 24 * 60 * 60 * 1000;
}

View File

@ -1,11 +0,0 @@
package cn.bunny.common.constant;
import lombok.Data;
/**
* Redis用户前缀设置
*/
@Data
public class RedisUserConstant {
public static final String REDIS_CART_KEY = "user::";
}

View File

@ -1,14 +0,0 @@
package cn.bunny.common.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";
}

View File

@ -1,12 +0,0 @@
package cn.bunny.common.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", "/admin/system/index/login", "/favicon.ico", "/swagger-resources/**", "/webjars/**", "/v3/**", "/swagger-ui.html/**", "/doc.html"};
public static List<String> annotationsList = Arrays.asList(annotations);
}

View File

@ -1,14 +0,0 @@
package cn.bunny.common.constant;
import lombok.Data;
/**
* 状态常量启用或者禁用
*/
@Data
public class StatusConstant {
// 启用为1
public static final Integer ENABLE = 1;
// 禁用为0
public static final Integer DISABLE = 0;
}

View File

@ -1,8 +0,0 @@
package cn.bunny.common.constant;
import lombok.Data;
@Data
public class UserConstant {
public static final String USER_AVATAR = "https://thirdwx.qlogo.cn/mmopen/vi_32/DYAIOgq83eoj0hHXhgJNOTSOFsS4uZs8x1ConecaVOB8eIl115xmJZcT4oCicvia7wMEufibKtTLqiaJeanU2Lpg3w/132";
}

View File

@ -1,84 +0,0 @@
package cn.bunny.common.generator;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.OutputFile;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import org.apache.ibatis.annotations.Mapper;
import java.util.Collections;
public class NewCodeGet {
// 数据连接
public static final String sqlHost = "jdbc:mysql://106.15.251.123:3305/guigu-oa?serverTimezone=GMT%2B8&useSSL=false&characterEncoding=utf-8&allowPublicKeyRetrieval=true";
// 作者名称
public static final String author = "Bunny";
// 公共路径
public static final String outputDir = "G:\\web项目\\Bunny-Cli\\Java\\java-template\\service";
// 实体类名称
public static final String entity = "Bunny";
public static void main(String[] args) {
Generation("sys_menu");
}
/**
* 根据表名生成相应结构代码
*
* @param tableName 表名
*/
public static void Generation(String... tableName) {
// TODO 修改数据库路径账户密码
FastAutoGenerator.create(sqlHost, "root", "02120212")
.globalConfig(builder -> {
// 添加作者名称
builder.author(author)
// 启用swagger
.enableSwagger()
// 指定输出目录
.outputDir(outputDir + "/src/main/java");
})
.packageConfig(builder -> {
builder.entity(entity)// 实体类包名
// TODO 父包名如果为空将下面子包名必须写全部 否则就只需写子包名
.parent("cn.bunny.service")
.controller("controller")// 控制层包名
.mapper("mapper")// mapper层包名
.service("service")// service层包名
.serviceImpl("service.impl")// service实现类包名
// 自定义mapper.xml文件输出目录
.pathInfo(Collections.singletonMap(OutputFile.xml, outputDir + "/src/main/resources/mapper"));
})
.strategyConfig(builder -> {
// 设置要生成的表名
builder.addInclude(tableName)
//.addTablePrefix("sys_")// TODO 设置表前缀过滤
.entityBuilder()
.enableLombok()
.enableChainModel()
.naming(NamingStrategy.underline_to_camel)// 数据表映射实体命名策略默认下划线转驼峰underline_to_camel
.columnNaming(NamingStrategy.underline_to_camel)// 表字段映射实体属性命名规则默认null不指定按照naming执行
.idType(IdType.AUTO)// TODO 添加全局主键类型
.formatFileName("%s")// 格式化实体名称%s取消首字母I,
.mapperBuilder()
.mapperAnnotation(Mapper.class)// 开启mapper注解
.enableBaseResultMap()// 启用xml文件中的BaseResultMap 生成
.enableBaseColumnList()// 启用xml文件中的BaseColumnList
.formatMapperFileName("%sMapper")// 格式化Dao类名称
.formatXmlFileName("%sMapper")// 格式化xml文件名称
.serviceBuilder()
.formatServiceFileName("%sService")// 格式化 service 接口文件名称
.formatServiceImplFileName("%sServiceImpl")// 格式化 service 接口文件名称
.controllerBuilder()
.enableRestStyle();
})
// .injectionConfig(consumer -> {
// Map<String, String> customFile = new HashMap<>();
// // 配置DTO需要的话但是需要有能配置Dto的模板引擎比如freemarker但是这里我们用的VelocityEngine因此不多作介绍
// customFile.put(outputDir, "/src/main/resources/templates/entityDTO.java.ftl");
// consumer.customFile(customFile);
// })
.execute();
}
}

View File

@ -1,57 +0,0 @@
package cn.bunny.common.generator;
public class OldCodeGet {
public static void main(String[] args) {
// // 1创建代码生成器
// AutoGenerator mpg = new AutoGenerator();
//
// // 2全局配置
// // 全局配置
// GlobalConfig gc = new GlobalConfig();
// // TODO 需要修改路径名称
// gc.setOutputDir("F:\\web项目\\Bunny-Cli\\Java\\java-template\\service" + "/src/main/java");
// gc.setServiceName("%sService"); // 去掉Service接口的首字母I
// gc.setAuthor("bunny");
// gc.setOpen(false);
// mpg.setGlobalConfig(gc);
//
// // 3数据源配置
// DataSourceConfig dsc = new DataSourceConfig();
// // TODO 需要修改数据库
// dsc.setUrl("jdbc:mysql://106.15.251.123:3305/guigu-oa?serverTimezone=GMT%2B8&useSSL=false&characterEncoding=utf-8&allowPublicKeyRetrieval=true");
// dsc.setDriverName("com.mysql.cj.jdbc.Driver");
// dsc.setUsername("root");
// dsc.setPassword("02120212");
// dsc.setDbType(DbType.MYSQL);
// mpg.setDataSource(dsc);
//
// // 4包配置
// PackageConfig pc = new PackageConfig();
// pc.setParent("cn.bunny");
// // TODO 需要修改模块名
// pc.setModuleName("service");
// pc.setController("controller");
// pc.setService("service");
// pc.setMapper("mapper");
// mpg.setPackageInfo(pc);
//
// // 5策略配置
// StrategyConfig strategy = getStrategyConfig();
// mpg.setStrategy(strategy);
//
// // 6执行
// mpg.execute();
// }
//
// private static StrategyConfig getStrategyConfig() {
// StrategyConfig strategy = new StrategyConfig();
// // TODO 要生成的表
// strategy.setInclude("sys_menu", "sys_role_menu");
// strategy.setNaming(NamingStrategy.underline_to_camel);// 数据库表映射到实体的命名策略
// strategy.setColumnNaming(NamingStrategy.underline_to_camel);// 数据库表字段映射到实体的命名策略
// strategy.setEntityLombokModel(true); // lombok 模型 @Accessors(chain = true) setter链式操作
// strategy.setRestControllerStyle(true); // restful api风格控制器
// strategy.setControllerMappingHyphenStyle(true); // url中驼峰转连字符
// return strategy;
}
}

View File

@ -1,25 +0,0 @@
package cn.bunny.common.properties;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Component
@ConfigurationProperties(prefix = "bunny.snowflake")
@Data
public class SnowflakeProperties {
// 数据中心id
private Long datacenterId;
// 数据中心id位数
private Long datacenterBits;
// 机器id
private Long workerId;
// 机器id位数
private Long workerBits;
// 序列id所占位数
private Long sequenceBits;
// 时间戳起始点毫秒
private Long twepoch;
// 单次批量生成id的最大数量
private Integer maxBatchCount;
}

View File

@ -13,16 +13,15 @@
<url>https://maven.apache.org</url>
<modules>
<module>service-utils</module>
<module>common-utils</module>
<module>spring-security</module>
<module>common-generator</module>
<module>common-result</module>
</modules>
<dependencies>
<dependency>
<groupId>cn.bunny</groupId>
<artifactId>model</artifactId>
<version>0.0.1-SNAPSHOT</version>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>2.17.0</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>

View File

@ -19,7 +19,7 @@
<dependencies>
<dependency>
<groupId>cn.bunny</groupId>
<artifactId>common-utils</artifactId>
<artifactId>common-generator</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
@ -27,6 +27,11 @@
<artifactId>common-result</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<!-- knife4j -->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>

View File

@ -29,6 +29,12 @@ public class Knife4jConfig {
// 管理员相关分类接口
@Bean
public GroupedOpenApi groupedOpenApi() {
return GroupedOpenApi.builder().group("前台接口管理").pathsToMatch("/api/**").build();
}
// 管理员相关分类接口
@Bean
public GroupedOpenApi groupedOpenAdminApi() {
return GroupedOpenApi.builder().group("管理员接口请求").pathsToMatch("/admin/**").build();
}

View File

@ -1,8 +1,8 @@
package cn.bunny.common.service.exception;
import cn.bunny.common.constant.CommonMessageConstant;
import cn.bunny.common.result.utils.Result;
import cn.bunny.common.result.constant.CommonMessageConstant;
import cn.bunny.common.result.enums.ResultCodeEnum;
import cn.bunny.common.result.utils.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

View File

@ -6,13 +6,13 @@ import org.springframework.util.StringUtils;
import java.util.Date;
public class JwtHelper {
private static final long tokenExpiration = 365L * 24 * 60 * 60 * 1000;
private static final long tokenExpiration = 24 * 60 * 60 * 1000;
private static final String tokenSignKey = "Bunny-Java-Template";
public static String createToken(Long userId, String userName) {
public static String createToken(Long userId, String userName, Integer day) {
return Jwts.builder()
.setSubject("Bunny-USER")
.setExpiration(new Date(System.currentTimeMillis() + tokenExpiration))
.setExpiration(new Date(System.currentTimeMillis() + tokenExpiration * day))
.claim("userId", userId)
.claim("userName", userName)
.signWith(SignatureAlgorithm.HS256, tokenSignKey)
@ -25,8 +25,7 @@ public class JwtHelper {
Jws<Claims> claimsJws = Jwts.parser().setSigningKey(tokenSignKey).parseClaimsJws(token);
Claims claims = claimsJws.getBody();
Integer userId = (Integer) claims.get("userId");
return userId.longValue();
return (Long) claims.get("userId");
}
public static String getUserName(String token) {
@ -42,8 +41,8 @@ public class JwtHelper {
}
public static void main(String[] args) {
String token = JwtHelper.createToken(7L, "admin");
System.out.println(token);
String token = JwtHelper.createToken(7L, "admin", 7);
// token = "eyJhbGciOiJIUzI1NiIsInppcCI6IkdaSVAifQ.H4sIAAAAAAAA_6tWKi5NUrJScirNy6vUDQ12DVLSUUqtKFCyMjQ3MTc0NrYwNddRKi1OLfJMUbKyNDIwNLQwMDAzg4j5JeamAjUbGhtaWhoYGJqaOBQW6iXn5yrVAgCrO9jLWAAAAA.DS1wYprXGoIMrjtUWfDSN9AG5gWoRZ17oAgcvC0kwag";
System.out.println(JwtHelper.getUserId(token));
System.out.println(JwtHelper.getUserName(token));
}

View File

@ -2,20 +2,23 @@ package cn.bunny.common.service.utils;
import cn.bunny.common.result.utils.Result;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import java.io.IOException;
public class ResponseUtil {
public static void out(HttpServletResponse response, Result r) {
public static void out(HttpServletResponse response, Result<Object> result) {
ObjectMapper mapper = new ObjectMapper();
// 注册JavaTimeModule模块
mapper.registerModule(new JavaTimeModule());
response.setContentType("application/json;charset=UTF-8");
response.setStatus(HttpStatus.OK.value());
response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
try {
mapper.writeValue(response.getWriter(), r);
mapper.writeValue(response.getWriter(), result);
} catch (IOException e) {
e.printStackTrace();
}

View File

@ -1,7 +1,7 @@
package cn.bunny.common.service.utils;
import cn.bunny.common.properties.SnowflakeProperties;
import cn.bunny.common.service.properties.SnowflakeProperties;
import org.springframework.stereotype.Component;
import java.util.ArrayList;

View File

@ -1,85 +0,0 @@
package cn.bunny.security.config;
import cn.bunny.common.constant.SecurityConstant;
import cn.bunny.security.custom.CustomPasswordEncoder;
import cn.bunny.security.filter.TokenAuthenticationFilter;
import cn.bunny.security.filter.TokenLoginFilter;
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 org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.core.session.SessionRegistry;
import org.springframework.security.core.session.SessionRegistryImpl;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.util.matcher.RegexRequestMatcher;
@Configuration
@EnableWebSecurity
@EnableMethodSecurity
public class WebSecurityConfig {
@Autowired
AuthenticationConfiguration authenticationConfiguration;
@Autowired
private RedisTemplate<String, Object> redisTemplate;
@Autowired
private CustomUserDetailsService customUserDetailsService;
@Autowired
private CustomPasswordEncoder customPasswordEncoder;
@Autowired
private CustomAuthorizationManagerService customAuthorizationManager;
@Bean
public SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception {
httpSecurity
// 前端段分离不需要---禁用明文验证
.httpBasic(AbstractHttpConfigurer::disable)
// 前端段分离不需要---禁用默认登录页
.formLogin(AbstractHttpConfigurer::disable)
// 前端段分离不需要---禁用退出页
.logout(AbstractHttpConfigurer::disable)
// 前端段分离不需要---csrf攻击
.csrf(AbstractHttpConfigurer::disable)
// 跨域访问权限如果需要可以关闭后自己配置跨域访问
.cors(AbstractHttpConfigurer::disable)
// 前后端分离不需要---因为是无状态的
.sessionManagement(AbstractHttpConfigurer::disable)
// 前后端分离不需要---记住我e -> e.rememberMeParameter("rememberBunny").rememberMeCookieName("rememberBunny").key("BunnyKey")
.rememberMe(AbstractHttpConfigurer::disable)
.authorizeHttpRequests(authorize -> {
// 如果访问路径有下面的不需要访问权限
authorize.requestMatchers(SecurityConstant.annotations).permitAll();
// 有样式文件不需要访问权限
authorize.requestMatchers(RegexRequestMatcher.regexMatcher("^\\S*[css|js]$")).permitAll();
// 上面都不是需要鉴权访问
authorize.anyRequest().access(customAuthorizationManager);
})
.exceptionHandling(exception -> {
// 请求未授权接口
exception.authenticationEntryPoint(new SecurityAuthenticationEntryPoint());
// 没有权限访问
exception.accessDeniedHandler(new SecurityAccessDeniedHandler());
})
// 自定义过滤器
.addFilterBefore(new TokenAuthenticationFilter(redisTemplate), UsernamePasswordAuthenticationFilter.class)
.addFilterAt(new TokenLoginFilter(authenticationConfiguration, redisTemplate), UsernamePasswordAuthenticationFilter.class)
// 自定义密码加密器和用户登录
.passwordManagement(customPasswordEncoder).userDetailsService(customUserDetailsService);
return httpSecurity.build();
}
@Bean
public SessionRegistry sessionRegistry() {
return new SessionRegistryImpl();
}
}

View File

@ -1,28 +0,0 @@
package cn.bunny.security.custom;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.PasswordManagementConfigurer;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.util.DigestUtils;
/**
* 自定义密码加密比对
*/
@Configuration
public class CustomPasswordEncoder implements PasswordEncoder, Customizer<PasswordManagementConfigurer<HttpSecurity>> {
@Override
public String encode(CharSequence rawPassword) {
return DigestUtils.md5DigestAsHex(rawPassword.toString().getBytes());
}
@Override
public boolean matches(CharSequence rawPassword, String encodedPassword) {
return encodedPassword.matches(DigestUtils.md5DigestAsHex(rawPassword.toString().getBytes()));
}
@Override
public void customize(PasswordManagementConfigurer<HttpSecurity> httpSecurityPasswordManagementConfigurer) {
}
}

View File

@ -1,23 +0,0 @@
package cn.bunny.security.custom;
import cn.bunny.entity.system.SysUser;
import lombok.Getter;
import lombok.Setter;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.User;
import java.util.Collection;
/**
* 重写自带的User
*/
@Getter
@Setter
public class CustomUser extends User {
private SysUser sysUser;
public CustomUser(SysUser sysUser, Collection<? extends GrantedAuthority> authorities) {
super(sysUser.getUsername(), sysUser.getPassword(), authorities);
this.sysUser = sysUser;
}
}

View File

@ -1,74 +0,0 @@
package cn.bunny.security.filter;
import cn.bunny.common.service.context.BaseContext;
import cn.bunny.common.service.utils.JwtHelper;
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;
import java.util.Map;
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");
// login请求就没token直接放行因为后边有其他的过滤器
if (token == null) {
doFilter(request, response, chain);
return;
}
// 如果是登录接口直接放行
UsernamePasswordAuthenticationToken authentication = getAuthentication(request);
SecurityContextHolder.getContext().setAuthentication(authentication);
chain.doFilter(request, response);
}
private UsernamePasswordAuthenticationToken getAuthentication(HttpServletRequest request) {
// 请求头是否有token
String token = request.getHeader("token");
if (StringUtils.hasText(token)) {
String username = JwtHelper.getUserName(token);
if (StringUtils.hasText(username)) {
// 当前用户信息放到ThreadLocal里面
BaseContext.setUserId(JwtHelper.getUserId(token));
BaseContext.setUsername(username);
// 通过username从redis获取权限数据
String authString = (String) redisTemplate.opsForValue().get(username);
// 把redis获取字符串权限数据转换要求集合类型 List<SimpleGrantedAuthority>
if (StringUtils.hasText(authString)) {
List<Map> maplist = JSON.parseArray(authString, Map.class);
System.out.println(maplist);
List<SimpleGrantedAuthority> authList = new ArrayList<>();
for (Map map : maplist) {
String authority = (String) map.get("authority");
authList.add(new SimpleGrantedAuthority(authority));
}
return new UsernamePasswordAuthenticationToken(username, null, authList);
} else {
return new UsernamePasswordAuthenticationToken(username, null, new ArrayList<>());
}
}
}
return null;
}
}

View File

@ -1,80 +0,0 @@
package cn.bunny.security.filter;
import cn.bunny.common.result.utils.Result;
import cn.bunny.common.service.utils.JwtHelper;
import cn.bunny.common.service.utils.ResponseUtil;
import cn.bunny.entity.system.Login;
import cn.bunny.common.result.enums.ResultCodeEnum;
import cn.bunny.security.custom.CustomUser;
import cn.bunny.security.handelr.SecurityAuthenticationFailureHandler;
import cn.bunny.security.handelr.SecurityAuthenticationSuccessHandler;
import cn.bunny.vo.system.LoginVo;
import com.alibaba.fastjson2.JSON;
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.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 java.io.IOException;
/**
* 由于SpringSecurity的登录只能是表单形式 并且用户名密码需要时usernamepassword,可以通过继承 UsernamePasswordAuthenticationFilter 获取登录请求的参数
* 再去设置到 UsernamePasswordAuthenticationToken 来改变请求传参方式参数名等 或者也可以在登录的时候加入其他参数等等
* 也可以在这里添加验证码短信等的验证
*/
public class TokenLoginFilter extends UsernamePasswordAuthenticationFilter {
private final RedisTemplate<String, Object> redisTemplate;
// 构造方法
public TokenLoginFilter(AuthenticationConfiguration authenticationConfiguration, RedisTemplate<String, Object> redisTemplate) throws Exception {
this.setAuthenticationSuccessHandler(new SecurityAuthenticationSuccessHandler());
this.setAuthenticationFailureHandler(new SecurityAuthenticationFailureHandler());
this.setPostOnly(false);
// 指定登录接口及提交方式可以指定任意路径
this.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/admin/system/index/login", "POST"));
this.setAuthenticationManager(authenticationConfiguration.getAuthenticationManager());
this.redisTemplate = redisTemplate;
}
// 登录认证
// 获取输入的用户名和密码调用方法认证
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
try {
// 获取用户信息
LoginVo loginVo = new ObjectMapper().readValue(request.getInputStream(), LoginVo.class);
// 封装对象
Authentication authenticationToken = new UsernamePasswordAuthenticationToken(loginVo.getUsername(), loginVo.getPassword());
// 调用方法
return this.getAuthenticationManager().authenticate(authenticationToken);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
// 认证成功调用方法
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication auth) {
// 获取当前用户
CustomUser customUser = (CustomUser) auth.getPrincipal();
// 生成token
String token = JwtHelper.createToken(customUser.getSysUser().getId(), customUser.getSysUser().getUsername());
// 获取当前用户权限数据放到Redis里面 keyusername value权限数据
redisTemplate.opsForValue().set(customUser.getUsername(), JSON.toJSONString(customUser.getAuthorities()));
// 返回
Login login = Login.builder().token(token).build();
ResponseUtil.out(response, Result.success(login));
}
// 认证失败调用方法
protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) {
ResponseUtil.out(response, Result.error(null, ResultCodeEnum.LOGIN_MOBLE_ERROR));
}
}

View File

@ -1,23 +0,0 @@
package cn.bunny.security.handelr;
import cn.bunny.common.result.utils.Result;
import cn.bunny.common.result.enums.ResultCodeEnum;
import com.alibaba.fastjson2.JSON;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.SneakyThrows;
import org.springframework.security.access.AccessDeniedException;
public class SecurityAccessDeniedHandler implements org.springframework.security.web.access.AccessDeniedHandler {
@SneakyThrows
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) {
Result<Object> result = Result.error(ResultCodeEnum.FAIL_NO_ACCESS_DENIED);
Object json = JSON.toJSON(result);
// 返回响应
response.setContentType("application/json;charset=UTF-8");
response.getWriter().println(json);
}
}

View File

@ -1,39 +0,0 @@
package cn.bunny.security.handelr;
import cn.bunny.common.result.utils.Result;
import cn.bunny.common.result.enums.ResultCodeEnum;
import com.alibaba.fastjson2.JSON;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import java.io.IOException;
/**
* 请求未认证接口
*/
@Slf4j
public class SecurityAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException {
String token = response.getHeader("token");
String message = authException.getMessage();
// 创建结果对象
Result<Object> result;
if (token == null) {
result = Result.error(new Object(), ResultCodeEnum.LOGIN_AUTH);
log.info("请求未登录接口:{}用户id{}", message, null);
} else {
result = Result.error(new Object(), ResultCodeEnum.LOGGED_IN_FROM_ANOTHER_DEVICE);
log.info("请求未授权接口:{}用户id{}", message, token);
}
// 返回响应
response.setContentType("application/json;charset=UTF-8");
response.getWriter().println(JSON.toJSON(result));
}
}

View File

@ -1,26 +0,0 @@
package cn.bunny.security.handelr;
import cn.bunny.common.result.utils.Result;
import com.alibaba.fastjson2.JSON;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.core.AuthenticationException;
import java.io.IOException;
public class SecurityAuthenticationFailureHandler implements org.springframework.security.web.authentication.AuthenticationFailureHandler {
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
// 错误消息
String localizedMessage = exception.getLocalizedMessage();
Result<String> result = Result.error(localizedMessage);
// 转成JSON
Object json = JSON.toJSON(result);
// 返回响应
response.setContentType("application/json;charset=UTF-8");
response.getWriter().println(json);
}
}

View File

@ -1,29 +0,0 @@
package cn.bunny.security.handelr;
import cn.bunny.common.result.utils.Result;
import com.alibaba.fastjson2.JSON;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import java.io.IOException;
public class SecurityAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
// 获取用户身份信息
Object principal = authentication.getPrincipal();
// 获取用户凭证信息
// Object credentials = authentication.getCredentials();
// 获取用户权限信息
// Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
Result<Object> result = Result.success(principal);
// 返回
response.setContentType("application/json;charset=UTF-8");
response.getWriter().println(JSON.toJSON(result));
}
}

View File

@ -1,7 +0,0 @@
package cn.bunny.security.service;
import org.springframework.security.authorization.AuthorizationManager;
import org.springframework.security.web.access.intercept.RequestAuthorizationContext;
public interface CustomAuthorizationManagerService extends AuthorizationManager<RequestAuthorizationContext> {
}

View File

@ -1,12 +0,0 @@
package cn.bunny.security.service;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
public interface CustomUserDetailsService extends org.springframework.security.core.userdetails.UserDetailsService {
/**
* 根据用户名获取用户对象获取不到直接抛异常
*/
@Override
UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
}

View File

@ -1,3 +0,0 @@
1715325213000|2024-05-10 15:13:33|/favicon.ico|1|0|1|1|14|0|0|1
1715325213000|2024-05-10 15:13:33|/|1|0|1|0|52|0|0|1
1715325213000|2024-05-10 15:13:33|__total_inbound_traffic__|2|0|2|1|33|0|0|0

View File

@ -22,6 +22,12 @@
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!-- hu tool -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
</dependency>
<!-- fastjson2 -->
<dependency>
<groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson2</artifactId>
@ -36,15 +42,6 @@
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId>
</dependency>
<!-- 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>

View File

@ -1,14 +0,0 @@
package cn.bunny.entity.system;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class Login {
private String token;
}

View File

@ -1,17 +0,0 @@
package cn.bunny.entity.system;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class RoleByUser {
private List<SysRole> assginRoleList;
private List<SysRole> allRolesList;
}

View File

@ -1,49 +0,0 @@
package cn.bunny.entity.system;
import cn.bunny.entity.base.BaseEntity;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.util.List;
@Data
@Schema(description = "部门")
@TableName("sys_dept")
public class SysDept extends BaseEntity {
private static final long serialVersionUID = 1L;
@Schema(description = "部门名称")
@TableField("name")
private String name;
@Schema(description = "上级部门id")
@TableField("parent_id")
private Long parentId;
@Schema(description = "树结构")
@TableField("tree_path")
private String treePath;
@Schema(description = "排序")
@TableField("sort_value")
private Integer sortValue;
@Schema(description = "负责人")
@TableField("leader")
private String leader;
@Schema(description = "电话")
@TableField("phone")
private String phone;
@Schema(description = "状态1正常 0停用")
@TableField("status")
private Integer status;
@Schema(description = "下级部门")
@TableField(exist = false)
private List<SysDept> children;
}

View File

@ -1,42 +0,0 @@
package cn.bunny.entity.system;
import cn.bunny.entity.base.BaseEntity;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serial;
import java.util.Date;
@EqualsAndHashCode(callSuper = true)
@Data
@Schema(description = "SysLoginLog")
@TableName("sys_login_log")
public class SysLoginLog extends BaseEntity {
@Serial
private static final long serialVersionUID = 1L;
@Schema(description = "用户账号")
@TableField("username")
private String username;
@Schema(description = "登录IP地址")
@TableField("ipaddr")
private String ipaddr;
@Schema(description = "登录状态0成功 1失败")
@TableField("status")
private Integer status;
@Schema(description = "提示信息")
@TableField("msg")
private String msg;
@Schema(description = "访问时间")
@TableField("access_time")
private Date accessTime;
}

View File

@ -1,65 +0,0 @@
package cn.bunny.entity.system;
import cn.bunny.entity.base.BaseEntity;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serial;
import java.util.List;
@EqualsAndHashCode(callSuper = true)
@Data
@Schema(description = "菜单")
@TableName("sys_menu")
public class SysMenu extends BaseEntity {
@Serial
private static final long serialVersionUID = 1L;
@Schema(description = "所属上级")
@TableField("parent_id")
private Long parentId;
@Schema(description = "名称")
@TableField("name")
private String name;
@Schema(description = "类型(1:菜单,2:按钮)")
@TableField("type")
private Integer type;
@Schema(description = "路由地址")
@TableField("path")
private String path;
@Schema(description = "组件路径")
@TableField("component")
private String component;
@Schema(description = "权限标识")
@TableField("perms")
private String perms;
@Schema(description = "图标")
@TableField("icon")
private String icon;
@Schema(description = "排序")
@TableField("sort_description")
private Integer sortdescription;
@Schema(description = "状态(0:禁止,1:正常)")
@TableField("status")
private Integer status;
// 下级列表
@TableField(exist = false)
private List<SysMenu> children;
// 是否选中
@TableField(exist = false)
private boolean isSelect;
}

View File

@ -1,34 +0,0 @@
package cn.bunny.entity.system;
import cn.bunny.entity.base.BaseEntity;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serial;
@EqualsAndHashCode(callSuper = true)
@Data
@Schema(description = "角色")
@TableName("sys_role")
public class SysRole extends BaseEntity {
@Serial
private static final long serialVersionUID = 1L;
//@NotBlank(message = "角色名称不能为空")
@Schema(description = "角色名称")
@TableField("role_name")
private String roleName;
@Schema(description = "角色编码")
@TableField("role_code")
private String roleCode;
@Schema(description = "描述")
@TableField("description")
private String description;
}

View File

@ -1,71 +0,0 @@
package cn.bunny.entity.system;
import cn.bunny.entity.base.BaseEntity;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serial;
import java.util.List;
@EqualsAndHashCode(callSuper = true)
@Data
@Schema(description = "用户")
@TableName("sys_user")
public class SysUser extends BaseEntity {
@Serial
private static final long serialVersionUID = 1L;
@Schema(description = "用户名")
@TableField("username")
private String username;
@Schema(description = "密码")
@TableField("password")
private String password;
@Schema(description = "姓名")
@TableField("name")
private String name;
@Schema(description = "手机")
@TableField("phone")
private String phone;
@Schema(description = "头像地址")
@TableField("head_url")
private String headUrl;
@Schema(description = "部门id")
@TableField("dept_id")
private Long deptId;
@Schema(description = "岗位id")
@TableField("post_id")
private Long postId;
@Schema(description = "描述")
@TableField("description")
private String description;
@Schema(description = "openId")
@TableField("open_id")
private String openId;
@Schema(description = "状态1正常 0停用")
@TableField("status")
private Integer status;
@TableField(exist = false)
private List<SysRole> roleList;
// 岗位
@TableField(exist = false)
private String postName;
// 部门
@TableField(exist = false)
private String deptName;
}

View File

@ -1,22 +0,0 @@
package cn.bunny.entity.system;
import cn.bunny.vo.system.RouterVo;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.HashSet;
import java.util.List;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class SysUserinfo {
private HashSet<String> roles;
private String name;
private String avatar;
private List<String> buttons;
private List<RouterVo> routers;
}

View File

@ -1,26 +1,34 @@
package cn.bunny.vo.system;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDateTime;
/**
* 登录对象
* 用户登录返回内容
*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class LoginVo {
/**
* 手机号
*/
private String username;
/**
* 密码
*/
private String password;
private String userId;
private String nickName;
private String email;
private Integer sex;
private String personDescription;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime joinTime;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime lastLoginTime;
private String lastLoginIp;
private String lastLoginIpAddress;
private Integer totalIntegral;
private Integer currentIntegral;
private Byte status;
private String token;
}

View File

@ -1,29 +0,0 @@
package cn.bunny.vo.system;
import lombok.Data;
/**
* 路由显示信息
*/
@Data
public class MetaVo {
/**
* 设置该路由在侧边栏和面包屑中展示的名字
*/
private String title;
/**
* 设置该路由的图标对应路径src/assets/icons/svg
*/
private String icon;
public MetaVo() {
}
public MetaVo(String title, String icon) {
this.title = title;
this.icon = icon;
}
}

View File

@ -1,48 +0,0 @@
package cn.bunny.vo.system;
import lombok.Data;
import java.util.List;
/**
* 路由配置信息
*/
@Data
public class RouterVo {
/**
* 路由名字
*/
// private String name;
/**
* 路由地址
*/
private String path;
/**
* 是否隐藏路由当设置 true 的时候该路由不会再侧边栏出现
*/
private boolean hidden;
/**
* 组件地址
*/
private String component;
/**
* 当你一个路由下面的 children 声明的路由大于1个时自动会变成嵌套的模式--如组件页面
*/
private Boolean alwaysShow;
/**
* 其他元素
*/
private MetaVo meta;
/**
* 子路由
*/
private List<RouterVo> children;
}

View File

@ -1,15 +0,0 @@
package cn.bunny.vo.system;
import lombok.Data;
@Data
public class SysOperLogQueryVo {
private String title;
private String operName;
private String createTimeBegin;
private String createTimeEnd;
}

View File

@ -1,19 +0,0 @@
package cn.bunny.vo.system;
import lombok.Data;
@Data
public class SysPostQueryVo {
//@ApiModelProperty(value = "岗位编码")
private String postCode;
//@ApiModelProperty(value = "岗位名称")
private String name;
//@ApiModelProperty(value = "状态1正常 0停用")
private Boolean status;
}

View File

@ -1,6 +1,6 @@
package cn.bunny.module.mail.utils;
import cn.bunny.common.constant.MailMessageConstant;
import cn.bunny.common.result.constant.MailMessageConstant;
import cn.bunny.common.service.utils.EmptyUtil;
import cn.bunny.entity.email.EmailSend;

View File

@ -1,6 +1,6 @@
package cn.bunny.module.minio.utils;
import cn.bunny.common.constant.MinioMessageConstant;
import cn.bunny.common.result.constant.MinioMessageConstant;
import cn.bunny.common.service.exception.BunnyException;
import io.minio.*;
import io.minio.messages.*;

View File

@ -29,7 +29,6 @@
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
<version>2.16.0-rc1</version>
</dependency>
</dependencies>
</project>

View File

@ -3,14 +3,14 @@
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>cn.bunny</groupId>
<artifactId>common</artifactId>
<artifactId>module</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>spring-security</artifactId>
<artifactId>module-websocket</artifactId>
<packaging>jar</packaging>
<name>spring-security</name>
<name>module-websocket</name>
<url>https://maven.apache.org</url>
<properties>
@ -18,10 +18,10 @@
</properties>
<dependencies>
<!-- websocket -->
<dependency>
<groupId>cn.bunny</groupId>
<artifactId>service-utils</artifactId>
<version>0.0.1-SNAPSHOT</version>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -1,4 +1,4 @@
package cn.bunny.service.websocket;
package cn.bunny.module.websocket;
import jakarta.websocket.OnClose;
import jakarta.websocket.OnMessage;

66
pom.xml
View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
@ -30,6 +30,7 @@
<maven.compiler.source>22</maven.compiler.source>
<maven.compiler.target>22</maven.compiler.target>
<java.version>21</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>
<knife4j.version>4.5.0</knife4j.version>
@ -39,10 +40,22 @@
<jwt.version>0.9.1</jwt.version>
<easyexcel.version>3.3.3</easyexcel.version>
<jodatime.version>2.10.1</jodatime.version>
<aspectj>1.9.21</aspectj>
<aspectj.version>1.9.21</aspectj.version>
<cloud.version>2023.0.1</cloud.version>
<jackson-dataformat.version>2.16.0-rc1</jackson-dataformat.version>
<alibaba.version>2023.0.1.0</alibaba.version>
<discovery.version>2023.0.0.0-RC1</discovery.version>
<loadbalancer.version>4.1.2</loadbalancer.version>
<pagehelper.version>6.1.0</pagehelper.version>
</properties>
<dependencyManagement>
<dependencies>
<!-- 单元测试 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
</dependency>
<!-- mybatis-plus -->
<dependency>
<groupId>com.baomidou</groupId>
@ -83,7 +96,7 @@
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.25</version>
<version>5.8.27</version>
</dependency>
<!--jjwt-->
<dependency>
@ -101,19 +114,62 @@
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${aspectj}</version>
<version>${aspectj.version}</version>
</dependency>
<!-- aspectj -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>${aspectj}</version>
<version>${aspectj.version}</version>
</dependency>
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>${jodatime.version}</version>
</dependency>
<!-- jackson-dataformat -->
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
<version>${jackson-dataformat.version}</version>
</dependency>
<!-- 微服务 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${alibaba.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- 服务注册 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<version>${discovery.version}</version>
</dependency>
<!-- loadbalancer依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
<version>${loadbalancer.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>2.12.3</version>
</dependency>
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>${pagehelper.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
</project>

View File

@ -1,4 +1,4 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
<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>
@ -21,6 +21,17 @@
</properties>
<dependencies>
<dependency>
<groupId>cn.bunny</groupId>
<artifactId>common-result</artifactId>
<version>0.0.1-SNAPSHOT</version>
<exclusions>
<exclusion>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- gateway -->
<dependency>
<groupId>org.springframework.cloud</groupId>

View File

@ -4,8 +4,10 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.scheduling.annotation.EnableScheduling;
@SpringBootApplication
@EnableScheduling// 定时任务
@ComponentScan("cn.bunny")
@Slf4j
public class GatewayApplication {

View File

@ -1,6 +1,6 @@
package cn.bunny.service.gateway.controller;
import com.alibaba.nacos.api.model.v2.Result;
import cn.bunny.common.result.utils.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;

View File

@ -2,7 +2,7 @@ bunny:
nacos:
server-addr: z-bunny.cn:8848
discovery:
namespace: spzx
namespace: bunnyBBS
redis:
host: 47.120.65.66

View File

@ -1,14 +1,13 @@
server:
port: 8500
port: 8800
spring:
profiles:
active: dev
application:
name: service-gateway
# main:
# web-application-type: reactive
# allow-bean-definition-overriding: true
main:
web-application-type: reactive
allow-bean-definition-overriding: true
cloud:
sentinel:
log:
@ -24,11 +23,16 @@ spring:
locator:
enabled: true
# 路由
# routes:
# - id: service-product
# uri: lb://service-product
# predicates:
# - Path=/*/product/**
routes:
- id: service-web
uri: lb://service-web
predicates:
- Path=/api/**
- id: service-admin
uri: lb://service-admin
predicates:
- Path=/admin/**
data:
redis:
host: ${bunny.redis.host}

View File

@ -1,38 +0,0 @@
package cn.bunny;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
/**
* Unit test for simple App.
*/
public class AppTest
extends TestCase
{
/**
* Create the test case
*
* @param testName name of the test case
*/
public AppTest( String testName )
{
super( testName );
}
/**
* @return the suite of tests being tested
*/
public static Test suite()
{
return new TestSuite( AppTest.class );
}
/**
* Rigourous Test :-)
*/
public void testApp()
{
assertTrue( true );
}
}

View File

@ -1,4 +1,4 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
<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>
@ -18,6 +18,26 @@
</properties>
<dependencies>
<dependency>
<groupId>cn.bunny</groupId>
<artifactId>model</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>cn.bunny</groupId>
<artifactId>common-result</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<!-- openfeign依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!-- loadbalancer依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-loadbalancer</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -12,7 +12,8 @@
<name>service</name>
<url>https://maven.apache.org</url>
<modules>
<module>service-main</module>
<module>service-web</module>
<module>service-admin</module>
</modules>
<properties>
@ -24,7 +25,6 @@
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
</dependency>
<!-- spring-test -->
<dependency>

View File

@ -1,21 +0,0 @@
FROM openjdk:21
MAINTAINER bunny
#系统编码
ENV LANG=C.UTF-8 LC_ALL=C.UTF-8
# 设置时区,构建镜像时执行的命令
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
RUN echo "Asia/Shanghai" > /etc/timezone
# 设定工作目录
WORKDIR /home/bunny
# 复制jar包
COPY target/*.jar /home/bunny/app.jar
#启动容器时的进程
ENTRYPOINT ["java","-jar","/home/bunny/app.jar"]
#暴露 8800 端口
EXPOSE 8800

View File

@ -1,107 +0,0 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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>service</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>service-main</artifactId>
<packaging>jar</packaging>
<name>service-main</name>
<url>https://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<docker.repostory>192.168.3.98:1100</docker.repostory>
<docker.host>192.168.3.98:2375</docker.host>
<docker.registry.name>bunny-service</docker.registry.name>
</properties>
<dependencies>
<dependency>
<groupId>cn.bunny</groupId>
<artifactId>spring-security</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<!-- service-utils -->
<dependency>
<groupId>cn.bunny</groupId>
<artifactId>service-utils</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>cn.bunny</groupId>
<artifactId>module-mail</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>cn.bunny</groupId>
<artifactId>module-minio</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<!-- websocket -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<!-- asp 切面 -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
<plugin>
<groupId>com.spotify</groupId>
<artifactId>docker-maven-plugin</artifactId>
<version>1.2.2</version>
<!--将插件绑定在某个phase执行-->
<executions>
<execution>
<id>build-image</id>
<!--将插件绑定在package这个phase(阶段)上。也就是说用户只需执行mvn package就会自动执行mvn docker:build-->
<phase>package</phase>
<goals>
<goal>build</goal>
<goal>push</goal>
</goals>
</execution>
</executions>
<configuration>
<serverId>harbor</serverId>
<registryUrl>http://${docker.repostory}</registryUrl>
<!-- 配置docker主机地址 -->
<dockerHost>http://${docker.host}</dockerHost>
<!--指定生成的镜像名-->
<imageName>
${docker.repostory}/${docker.registry.name}/${project.artifactId}:${project.version}
</imageName>
<!-- 指定 dockerfile 路径-->
<dockerDirectory>${project.basedir}</dockerDirectory>
<!-- 是否跳过docker构建 -->
<skipDockerBuild>false</skipDockerBuild>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -1,22 +0,0 @@
package cn.bunny.service;
import lombok.extern.slf4j.Slf4j;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.scheduling.annotation.EnableScheduling;
@ComponentScan(basePackages = {"cn.bunny"})
@MapperScan("cn.bunny.service.mapper")
@EnableScheduling// 定时任务
@EnableCaching// 开启缓存注解
@SpringBootApplication
@Slf4j
public class ServiceApplication {
public static void main(String[] args) {
log.info("ServiceApplication启动...");
SpringApplication.run(ServiceApplication.class, args);
}
}

View File

@ -1,15 +0,0 @@
package cn.bunny.service.aop.annotation;
import cn.bunny.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();
}

View File

@ -1,27 +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.stereotype.Component;
@Aspect
@Component
@Slf4j
public class AutoFillAspect {
@Pointcut("execution(* cn.bunny.service.*.*(..))")
public void autoFillPointcut() {
}
/**
* 之前操作
*
* @param joinPoint 参数
*/
@Before("autoFillPointcut()")
public void autoFill(JoinPoint joinPoint) {
log.info("开始进行自动填充");
}
}

View File

@ -1,59 +0,0 @@
package cn.bunny.service.controller;
import cn.bunny.common.result.utils.Result;
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.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.session.SessionInformation;
import org.springframework.security.core.session.SessionRegistry;
import org.springframework.security.core.userdetails.User;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@Tag(name = "后台登录管理")
@RestController
@RequestMapping("/")
public class BaseController {
@Autowired
private SessionRegistry sessionRegistry;
@GetMapping()
public String index() {
return "欢迎访问";
}
@Operation(summary = "Security上下文对象", description = "Security上下文对象")
@GetMapping("/test/getSecurityHolder")
public Result<Object> getSecurityHolder() {
SecurityContext context = SecurityContextHolder.getContext();
return Result.success(context);
}
@Operation(summary = "当前所有登录的用户", description = "当前所有登录的用户")
@GetMapping("/test/getAllUserLogin")
public Result<Object> getAllUserLogin() {
return Result.success(sessionRegistry.getAllPrincipals());
}
@Operation(summary = "剔除下线", description = "剔除下线")
@GetMapping("/test/killOut")
public Result<Object> killOut(String userId) {
List<Object> allPrincipals = sessionRegistry.getAllPrincipals();
for (Object allPrincipal : allPrincipals) {
// 获取当前所有已经登录session会话未失效的session
List<SessionInformation> allSessions = sessionRegistry.getAllSessions(allPrincipal, false);
User user = (User) allPrincipals;
// 如果用户名匹配将这个用户下线
if (user.getUsername().equals(userId)) {
allSessions.forEach(SessionInformation::expireNow);
}
}
return Result.success();
}
}

View File

@ -1,47 +0,0 @@
package cn.bunny.service.controller;
import cn.bunny.common.result.utils.Result;
import cn.bunny.entity.system.Login;
import cn.bunny.entity.system.SysUserinfo;
import cn.bunny.service.service.SysUserService;
import cn.bunny.vo.system.LoginVo;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.Map;
/**
* <p>
* 后台登录登出
* </p>
*/
@Tag(name = "后台登录管理")
@RestController
@RequestMapping("/admin/system/index")
public class IndexController {
@Autowired
private SysUserService sysUserService;
@Operation(summary = "登录", description = "登录")
@PostMapping("login")
public Result<Login> login(@RequestBody LoginVo loginVo) {
Login login = sysUserService.login(loginVo);
return Result.success(login);
}
@Operation(summary = "获取用户信息", description = "获取用户信息")
@GetMapping("info")
public Result<SysUserinfo> info(HttpServletRequest request) {
SysUserinfo userinfo = sysUserService.getUserinfo(request);
return Result.success(userinfo);
}
@Operation(summary = "退出", description = "退出")
@GetMapping("logout")
public Result<Map<String, Object>> logout() {
return Result.success();
}
}

View File

@ -1,55 +0,0 @@
package cn.bunny.service.controller;
import cn.bunny.common.result.utils.Result;
import cn.bunny.entity.email.EmailSend;
import cn.bunny.service.service.EmailService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
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;
@RestController
@Tag(name = "发送邮件")
@RequestMapping("/test/mail")
@Slf4j
public class MailController {
@Autowired
private EmailService emailService;
@Operation(summary = "发送简单邮件", description = "发送简单邮件")
@PostMapping("/send-text")
public Result<String> sendText(@RequestBody EmailSend emailSend) {
log.info("发送简单邮件");
emailService.sendSimpleEmail(emailSend);
return Result.success();
}
@Operation(summary = "发送带附件邮件", description = "发送带附件邮件")
@PostMapping("send-attachment")
public Result<String> sendAttachment(@RequestBody EmailSend emailSend) {
log.info("发送带附件邮件");
boolean isSuccess = emailService.sendAttachmentEmail(emailSend);
return isSuccess ? Result.success() : Result.error();
}
@Operation(summary = "发送富文本邮件", description = "发送富文本邮件")
@PostMapping("send-rich")
public Result<String> sendRich(@RequestBody EmailSend emailSend) {
log.info("发送富文本邮件");
boolean isSuccess = emailService.sendRich(emailSend);
return isSuccess ? Result.success() : Result.error();
}
@Operation(summary = "发送带抄送的邮件", description = "发送带抄送的邮件")
@PostMapping("send-cc")
public Result<String> sendCC(@RequestBody EmailSend emailSend) {
log.info("发送带抄送的邮件");
boolean isSuccess = emailService.sendCC(emailSend);
return isSuccess ? Result.success() : Result.error();
}
}

View File

@ -1,18 +0,0 @@
package cn.bunny.service.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* <p>
* 菜单表 前端控制器
* </p>
*
* @author Bunny
* @since 2024-05-06
*/
@RestController
@RequestMapping("/sysMenu")
public class SysMenuController {
}

View File

@ -1,16 +0,0 @@
package cn.bunny.service.mapper;
import cn.bunny.entity.system.SysMenu;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* <p>
* 菜单表 Mapper 接口
* </p>
*
* @author Bunny
* @since 2024-05-06
*/
public interface SysMenuMapper extends BaseMapper<SysMenu> {
}

View File

@ -1,7 +0,0 @@
package cn.bunny.service.mapper;
import cn.bunny.entity.system.SysRole;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
public interface SysRoleMapper extends BaseMapper<SysRole> {
}

View File

@ -1,19 +0,0 @@
package cn.bunny.service.mapper;
import cn.bunny.entity.system.SysUser;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
/**
* <p>
* 用户表 Mapper 接口
* </p>
*
* @author bunny
* @since 2024-04-22
*/
@Mapper
public interface SysUserMapper extends BaseMapper<SysUser> {
}

View File

@ -1,36 +0,0 @@
package cn.bunny.service.security;
import cn.bunny.security.service.CustomAuthorizationManagerService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.access.intercept.RequestAuthorizationContext;
import org.springframework.stereotype.Service;
import java.util.function.Supplier;
/**
* 自定义权限判断
* 判断用户有哪些权限
*/
@Service
@Slf4j
public class CustomAuthorizationManagerServiceImpl implements CustomAuthorizationManagerService {
@Override
public void verify(Supplier<Authentication> authentication, RequestAuthorizationContext requestAuthorizationContext) {
CustomAuthorizationManagerService.super.verify(authentication, requestAuthorizationContext);
}
@Override
public AuthorizationDecision check(Supplier<Authentication> authentication, RequestAuthorizationContext object) {
String token = object.getRequest().getHeader("token");
if (token == null) {
throw new AccessDeniedException("");
}
return new AuthorizationDecision(true);
}
}

View File

@ -1,41 +0,0 @@
package cn.bunny.service.security;
import cn.bunny.common.constant.CommonMessageConstant;
import cn.bunny.common.service.exception.BunnyException;
import cn.bunny.entity.system.SysRole;
import cn.bunny.entity.system.SysUser;
import cn.bunny.security.custom.CustomUser;
import cn.bunny.service.mapper.SysRoleMapper;
import cn.bunny.service.mapper.SysUserMapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import java.util.List;
@Configuration
public class CustomUserDetailsService implements cn.bunny.security.service.CustomUserDetailsService {
@Autowired
private SysUserMapper sysUserMapper;
@Autowired
private SysRoleMapper sysRoleMapper;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
SysUser sysUser = sysUserMapper.selectOne(Wrappers.<SysUser>lambdaQuery().eq(SysUser::getUsername, username));
List<SysRole> sysRoleList = sysRoleMapper.selectList(null);
if (sysUser == null) {
throw new UsernameNotFoundException(CommonMessageConstant.USER_DOES_NOT_EXIST);
}
if (sysUser.getStatus() == 0) {
throw new BunnyException(CommonMessageConstant.ACCOUNT_LOCKED);
}
List<String> roleAuthoritieList = sysRoleList.stream().map(SysRole::getRoleCode).toList();
return new CustomUser(sysUser, AuthorityUtils.createAuthorityList(roleAuthoritieList));
}
}

View File

@ -1,37 +0,0 @@
package cn.bunny.service.service;
import cn.bunny.entity.email.EmailSend;
public interface EmailService {
/**
* 发送邮件-简单
*
* @param emailSend 邮件消息
*/
void sendSimpleEmail(EmailSend emailSend);
/**
* 发送带附件邮件
*
* @param emailSend 邮件消息
* @return 是否成功
*/
boolean sendAttachmentEmail(EmailSend emailSend);
/**
* 发送富文本邮件
*
* @param emailSend 邮件消息
* @return 是否成功
*/
boolean sendRich(EmailSend emailSend);
/**
* 发送带抄送的邮件
*
* @param emailSend 邮件消息
* @return 是否成功
*/
boolean sendCC(EmailSend emailSend);
}

View File

@ -1,16 +0,0 @@
package cn.bunny.service.service;
import cn.bunny.entity.system.SysMenu;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* <p>
* 菜单表 服务类
* </p>
*
* @author Bunny
* @since 2024-05-06
*/
public interface SysMenuService extends IService<SysMenu> {
}

View File

@ -1,8 +0,0 @@
package cn.bunny.service.service;
import cn.bunny.entity.system.SysRole;
import com.baomidou.mybatisplus.extension.service.IService;
public interface SysRoleService extends IService<SysRole> {
}

View File

@ -1,43 +0,0 @@
package cn.bunny.service.service;
import cn.bunny.entity.system.Login;
import cn.bunny.entity.system.SysUser;
import cn.bunny.entity.system.SysUserinfo;
import cn.bunny.vo.system.LoginVo;
import com.baomidou.mybatisplus.extension.service.IService;
import jakarta.servlet.http.HttpServletRequest;
/**
* <p>
* 用户表 服务类
* </p>
*
* @author bunny
* @since 2024-04-22
*/
public interface SysUserService extends IService<SysUser> {
/**
* 登录
*
* @param vo 登录条件
* @return 返回token
*/
Login login(LoginVo vo);
/**
* 获取用户信息
*
* @param request 请求头
* @return 用户信息
*/
SysUserinfo getUserinfo(HttpServletRequest request);
/**
* 根据用户名查询用户信息
*
* @param username 用户名
* @return 用户信息
*/
SysUser getByUsername(String username);
}

View File

@ -1,98 +0,0 @@
package cn.bunny.service.service.impl;
import cn.bunny.entity.email.EmailSend;
import cn.bunny.entity.email.EmailSendInit;
import cn.bunny.module.mail.utils.MailSenderUtil;
import cn.bunny.service.service.EmailService;
import jakarta.mail.MessagingException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
@Service
@Slf4j
public class EmailServiceImpl implements EmailService {
/**
* 发送邮件-简单
*
* @param emailSend 邮件消息
*/
@Override
public void sendSimpleEmail(EmailSend emailSend) {
EmailSendInit emailSendInit = new EmailSendInit();
emailSendInit.setHost("smtp.qq.com");
emailSendInit.setPort(465);
emailSendInit.setUsername("3324855376@qq.com");
emailSendInit.setPassword("axyqbvfuxkdqdaai");
MailSenderUtil mailSenderUtil = new MailSenderUtil(emailSendInit);
mailSenderUtil.sendSimpleEmail(emailSend);
}
/**
* 发送带附件邮件
*
* @param emailSend 邮件消息
* @return 是否成功
*/
@Override
public boolean sendAttachmentEmail(EmailSend emailSend) {
try {
EmailSendInit emailSendInit = new EmailSendInit();
emailSendInit.setHost("smtp.qq.com");
emailSendInit.setPort(465);
emailSendInit.setUsername("3324855376@qq.com");
emailSendInit.setPassword("axyqbvfuxkdqdaai");
MailSenderUtil mailSenderUtil = new MailSenderUtil(emailSendInit);
mailSenderUtil.sendEmail(emailSend);
return true;
} catch (MessagingException e) {
return false;
}
}
/**
* 发送富文本邮件
*
* @param emailSend 邮件消息
* @return 是否成功
*/
@Override
public boolean sendRich(EmailSend emailSend) {
try {
EmailSendInit emailSendInit = new EmailSendInit();
emailSendInit.setHost("smtp.qq.com");
emailSendInit.setPort(465);
emailSendInit.setUsername("3324855376@qq.com");
emailSendInit.setPassword("axyqbvfuxkdqdaai");
MailSenderUtil mailSenderUtil = new MailSenderUtil(emailSendInit);
mailSenderUtil.sendRichText(emailSend, true);
return true;
} catch (MessagingException e) {
return false;
}
}
/**
* 发送带抄送的邮件
*
* @param emailSend 邮件消息
*/
@Override
public boolean sendCC(EmailSend emailSend) {
try {
EmailSendInit emailSendInit = new EmailSendInit();
emailSendInit.setHost("smtp.qq.com");
emailSendInit.setPort(465);
emailSendInit.setUsername("3324855376@qq.com");
emailSendInit.setPassword("axyqbvfuxkdqdaai");
MailSenderUtil mailSenderUtil = new MailSenderUtil(emailSendInit);
mailSenderUtil.sendCC(emailSend, true);
return true;
} catch (MessagingException e) {
return false;
}
}
}

View File

@ -1,20 +0,0 @@
package cn.bunny.service.service.impl;
import cn.bunny.entity.system.SysMenu;
import cn.bunny.service.mapper.SysMenuMapper;
import cn.bunny.service.service.SysMenuService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
/**
* <p>
* 菜单表 服务实现类
* </p>
*
* @author Bunny
* @since 2024-05-06
*/
@Service
public class SysMenuServiceImpl extends ServiceImpl<SysMenuMapper, SysMenu> implements SysMenuService {
}

View File

@ -1,11 +0,0 @@
package cn.bunny.service.service.impl;
import cn.bunny.entity.system.SysRole;
import cn.bunny.service.mapper.SysRoleMapper;
import cn.bunny.service.service.SysRoleService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
@Service
public class SysRoleServiceImpl extends ServiceImpl<SysRoleMapper, SysRole> implements SysRoleService {
}

View File

@ -1,91 +0,0 @@
package cn.bunny.service.service.impl;
import cn.bunny.common.constant.CommonMessageConstant;
import cn.bunny.common.service.exception.BunnyException;
import cn.bunny.common.service.utils.JwtHelper;
import cn.bunny.entity.system.Login;
import cn.bunny.entity.system.SysUser;
import cn.bunny.entity.system.SysUserinfo;
import cn.bunny.service.mapper.SysUserMapper;
import cn.bunny.service.service.SysUserService;
import cn.bunny.vo.system.LoginVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;
/**
* <p>
* 用户表 服务实现类
* </p>
*
* @author bunny
* @since 2024-04-22
*/
@Service
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements SysUserService {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
/**
* 登录
*
* @param vo 登录条件
* @return 返回token
*/
@Override
public Login login(LoginVo vo) {
String username = vo.getUsername();
String password = vo.getPassword();
// 查询用户信息
LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(SysUser::getUsername, username);
SysUser sysUser = getOne(wrapper);
// 用户是否存在
if (sysUser == null) {
throw new BunnyException(CommonMessageConstant.ACCOUNT_NOT_FOUND);
}
// 判断是否被禁用
if (sysUser.getStatus() == 0) {
throw new BunnyException(CommonMessageConstant.ACCOUNT_LOCKED);
}
// 判断密码
String md5DigestAsHexPassword = DigestUtils.md5DigestAsHex(password.getBytes());
if (!md5DigestAsHexPassword.equals(sysUser.getPassword())) {
throw new BunnyException(CommonMessageConstant.PASSWORD_ERROR);
}
// 添加token
String token = JwtHelper.createToken(sysUser.getId(), sysUser.getUsername());
return Login.builder().token(token).build();
}
/**
* 获取用户信息
*
* @param request 请求头
* @return 用户信息
*/
@Override
public SysUserinfo getUserinfo(HttpServletRequest request) {
redisTemplate.opsForValue().set("test", "测试");
return null;
}
/**
* 根据用户名查询用户信息
*
* @param username 用户名
* @return 用户信息
*/
@Override
public SysUser getByUsername(String username) {
return getOne(Wrappers.<SysUser>lambdaQuery().eq(SysUser::getUsername, username));
}
}

View File

@ -1,14 +0,0 @@
package cn.bunny.service.task;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@Component
@Slf4j
public class TemplateTask {
@Scheduled(cron = "0/1 5 * * * ?")
public void templateTask() {
log.info("定时任务执行...");
}
}

View File

@ -1,19 +0,0 @@
bunny:
datasource:
host: 106.15.251.123
port: 3305
sqlData: guigu-oa
username: root
password: "02120212"
redis:
host: 47.120.65.66
port: 6379
database: 3
password: "02120212"
minio:
endpointUrl: "http://129.211.31.58:9000"
bucket-name: ssyx
accessKey: bunny
secretKey: "02120212"

View File

@ -1,63 +0,0 @@
server:
port: 8801
spring:
profiles:
active: dev
application:
name: bunny-mirror-server
datasource:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://${bunny.datasource.host}:${bunny.datasource.port}/${bunny.datasource.sqlData}?serverTimezone=GMT%2B8&useSSL=false&characterEncoding=utf-8&allowPublicKeyRetrieval=true
username: ${bunny.datasource.username}
password: ${bunny.datasource.password}
data:
redis:
host: ${bunny.redis.host}
port: ${bunny.redis.port}
database: ${bunny.redis.database}
password: ${bunny.redis.password}
lettuce:
pool:
max-active: 20 #最大连接数
max-wait: -1 #最大阻塞等待时间(负数表示没限制)
max-idle: 5 #最大空闲
min-idle: 0 #最小空闲
jackson:
date-format: yyyy-MM-dd HH:mm:ss
time-zone: GMT+8
mybatis-plus:
mapper-locations: classpath:mapper/*.xml
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 查看日志
logging:
level:
cn.bunny.service.mapper: debug
cn.bunny.service.controller: info
cn.bunny.service.service: info
pattern:
dateformat: HH:mm:ss:SSS
file:
path: "logs/${spring.application.name}"
bunny:
minio:
endpointUrl: ${bunny.minio.endpointUrl}
accessKey: ${bunny.minio.accessKey}
secretKey: ${bunny.minio.secretKey}
bucket-name: ${bunny.minio.bucket-name}
snowflake:
datacenterBits: 5 # 数据中心id位数
workerBits: 5 # 机器id位数
sequenceBits: 12 # 序列id所占位数
datacenterId: 1 # 数据中心id,范围0-2^5-1
workerId: 1 # 机器id,范围0-2^5-1
twepoch: 1704038400000 # 时间戳起始点2024-01-01 00::00:00 的毫秒数)
maxBatchCount: 100000 #单次批量生成id的最大数量 默认10万

View File

@ -1,16 +0,0 @@
-----------------▄██-█▄---------
-----------------███▄██▄--------
-----------------███████--------
-----------------▀███████-------
-------------------██████▄▄-----
-------------------█████████▄---
-------------------██████▄████--
-------▄███████████████████████-
-----▄███████████████████████▀--
---▄██████████████████████------
---███████████████████████------
---███████████████████████------
-▄▄██████████████████████▀------
-█████████████████▀█████--------
-▀██████████████▀▀-▀█████▄------
-------▀▀▀▀▀▀▀▀▀------▀▀▀▀------

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

View File

@ -1,61 +0,0 @@
<?xml version="1.0" encoding="UTF-8" ?>
<configuration debug="false" xmlns="http://ch.qos.logback/xml/ns/logback"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://ch.qos.logback/xml/ns/logback
https://raw.githubusercontent.com/enricopulatzo/logback-XSD/master/src/main/xsd/logback.xsd">
<appender name="STOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>
%cyan([%thread]) %yellow(%-5level) %green(%logger{100}).%boldRed(%method)-%boldMagenta(%line) - %blue(%msg%n)
</pattern>
</encoder>
</appender>
<!-- additivity:false 禁止重复打印日志 -->
<!-- 让SpringBoot内部日志ERROR级别 减少日志输出 -->
<logger name="org.springframework" level="ERROR" additivity="false">
<appender-ref ref="STOUT"/>
</logger>
<!-- 让mybatis整合包日志ERROR 减少日志输出 -->
<logger name="org.mybatis" level="ERROR" additivity="false">
<appender-ref ref="STOUT"/>
</logger>
<!-- 让ibatis 日志ERROR 减少日志输出 -->
<logger name="org.apache.ibatis" level="ERROR" additivity="false">
<appender-ref ref="STOUT"/>
</logger>
<!-- 让 tomcat包打印日志 日志ERROR 减少日志输出 -->
<logger name="org.apache" level="ERROR" additivity="false">
<appender-ref ref="STOUT"/>
</logger>
<!-- 我们自己开发的程序为DEBUG -->
<logger name="com.redpig" level="DEBUG" additivity="false">
<appender-ref ref="STOUT"/>
</logger>
<logger name="com.baomidou" level="ERROR" additivity="false">
<appender-ref ref="STOUT"/>
</logger>
<logger name="com.zaxxer" level="ERROR" additivity="false">
<appender-ref ref="STOUT"/>
</logger>
<!-- Activiti日志 -->
<logger name="org.activiti" level="ERROR" />
<logger name="org.activiti.engine.impl.persistence.entity" level="DEBUG" />
<logger name="_org.springframework" level="ERROR" />
<logger name="springfox.documentation" level="ERROR" />
<!-- root级别开debug 子目录根据需要关闭 -->
<root level="DEBUG">
<appender-ref ref="STOUT"/>
</root>
</configuration>

View File

@ -1,26 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.bunny.service.mapper.SysMenuMapper">
<!-- 通用查询映射结果 -->
<resultMap id="BaseResultMap" type="cn.bunny.entity.system.SysMenu">
<id column="id" property="id"/>
<result column="parent_id" property="parentId"/>
<result column="name" property="name"/>
<result column="type" property="type"/>
<result column="path" property="path"/>
<result column="component" property="component"/>
<result column="perms" property="perms"/>
<result column="icon" property="icon"/>
<result column="status" property="status"/>
<result column="create_time" property="createTime"/>
<result column="update_time" property="updateTime"/>
<result column="is_deleted" property="isDeleted"/>
</resultMap>
<!-- 通用查询结果列 -->
<sql id="Base_Column_List">
id, parent_id, name, type, path, component, perms, icon, sort_value, status, create_time, update_time, is_deleted
</sql>
</mapper>

View File

@ -1,5 +0,0 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="cn.bunny.service.mapper.SysRoleMapper">
</mapper>

View File

@ -1,5 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.bunny.service.mapper.SysUserMapper">
</mapper>

View File

@ -1,27 +0,0 @@
package cn.bunny;
import cn.bunny.security.custom.CustomPasswordEncoder;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.security.crypto.password.PasswordEncoder;
@SpringBootTest(classes = CustomPasswordEncoder.class)
class CustomPasswordEncoderTest {
@Autowired
private CustomPasswordEncoder customPasswordEncoder;
@Autowired
private PasswordEncoder passwordEncoder;
@Test
void testCustomPasswordEncoder() {
String encode = customPasswordEncoder.encode("111111");
System.out.println(encode);
}
@Test
void testPasswordEncoder() {
String encode = passwordEncoder.encode("111111");
System.out.println(encode);
}
}