upd: 编码规范

This commit is contained in:
2025-03-24 20:10:22 +08:00
parent f8410bbee3
commit c3afa4361e
189 changed files with 3415 additions and 763 deletions
+1 -1
View File
@@ -1,4 +1,4 @@
<h1 style="text-align: center">ELADMIN 后台管理系统</h1> <h1 style="text-align: center">CuteJava 后台管理系统</h1>
#### 项目简介 #### 项目简介
@@ -1,4 +1,4 @@
package cn.odboy.annotation.rest; package cn.odboy.annotation;
import java.lang.annotation.*; import java.lang.annotation.*;
@@ -1,4 +1,4 @@
package cn.odboy.annotation.rest; package cn.odboy.annotation;
import org.springframework.core.annotation.AliasFor; import org.springframework.core.annotation.AliasFor;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
@@ -1,4 +1,4 @@
package cn.odboy.annotation.rest; package cn.odboy.annotation;
import org.springframework.core.annotation.AliasFor; import org.springframework.core.annotation.AliasFor;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
@@ -1,4 +1,4 @@
package cn.odboy.annotation.rest; package cn.odboy.annotation;
import org.springframework.core.annotation.AliasFor; import org.springframework.core.annotation.AliasFor;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
@@ -1,4 +1,4 @@
package cn.odboy.annotation.rest; package cn.odboy.annotation;
import org.springframework.core.annotation.AliasFor; import org.springframework.core.annotation.AliasFor;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
@@ -1,4 +1,4 @@
package cn.odboy.annotation.rest; package cn.odboy.annotation;
import org.springframework.core.annotation.AliasFor; import org.springframework.core.annotation.AliasFor;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
@@ -18,7 +18,7 @@ import java.sql.Timestamp;
@Getter @Getter
@Setter @Setter
@EqualsAndHashCode(callSuper = false) @EqualsAndHashCode(callSuper = false)
public class BaseEntity extends MyObject { public class MyEntity extends MyObject {
@CreatedBy @CreatedBy
@TableField(fill = FieldFill.INSERT) @TableField(fill = FieldFill.INSERT)
@@ -33,11 +33,15 @@ public class BaseEntity extends MyObject {
@TableField(fill = FieldFill.INSERT) @TableField(fill = FieldFill.INSERT)
@ApiModelProperty(value = "创建时间: yyyy-MM-dd HH:mm:ss", hidden = true) @ApiModelProperty(value = "创建时间: yyyy-MM-dd HH:mm:ss", hidden = true)
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss") @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss")
// @JSONField(format = "yyyy-MM-dd HH:mm:ss")
// @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Timestamp createTime; private Timestamp createTime;
@TableField(fill = FieldFill.INSERT_UPDATE) @TableField(fill = FieldFill.INSERT_UPDATE)
@ApiModelProperty(value = "更新时间: yyyy-MM-dd HH:mm:ss", hidden = true) @ApiModelProperty(value = "更新时间: yyyy-MM-dd HH:mm:ss", hidden = true)
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss") @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss")
// @JSONField(format = "yyyy-MM-dd HH:mm:ss")
// @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Timestamp updateTime; private Timestamp updateTime;
/* 分组校验 */ /* 分组校验 */
@@ -0,0 +1,72 @@
package cn.odboy.base;
import com.alibaba.fastjson2.annotation.JSONField;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableLogic;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.Setter;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.springframework.data.annotation.CreatedBy;
import org.springframework.data.annotation.LastModifiedBy;
import org.springframework.format.annotation.DateTimeFormat;
import java.lang.reflect.Field;
import java.sql.Timestamp;
/**
* 逻辑删除通用模型
*
* @author odboy
* @date 2025-01-12
*/
@Getter
@Setter
public class MyLogicEntity extends MyObject {
@CreatedBy
@TableField(value = "create_by", fill = FieldFill.INSERT)
@ApiModelProperty(value = "创建人", hidden = true)
private String createBy;
@LastModifiedBy
@TableField(value = "update_by", fill = FieldFill.INSERT_UPDATE)
@ApiModelProperty(value = "更新人", hidden = true)
private String updateBy;
@TableField(value = "create_time", fill = FieldFill.INSERT)
@ApiModelProperty(value = "创建时间", hidden = true)
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Timestamp createTime;
@TableField(value = "update_time", fill = FieldFill.INSERT_UPDATE)
@ApiModelProperty(value = "更新时间", hidden = true)
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Timestamp updateTime;
@ApiModelProperty(value = "数据有效性", hidden = true)
@TableLogic
@TableField("available")
private Integer available;
/* 分组校验 */
public @interface Create {
}
/* 分组校验 */
public @interface Update {
}
@Override
public String toString() {
ToStringBuilder builder = new ToStringBuilder(this);
Field[] fields = this.getClass().getDeclaredFields();
try {
for (Field f : fields) {
f.setAccessible(true);
builder.append(f.getName(), f.get(this)).append("\n");
}
} catch (Exception e) {
builder.append("toString builder encounter an error");
}
return builder.toString();
}
}
@@ -0,0 +1,37 @@
/*
* Copyright 2021-2025 Tian Jun
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.odboy.base;
import lombok.*;
import java.util.Map;
/**
* 元数据选项
*
* @author odboy
* @date 2025-01-13
*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@EqualsAndHashCode(callSuper = false)
public class MyMetaOption extends MyObject {
private String label;
private String value;
private Map<String, Object> ext;
}
@@ -0,0 +1,31 @@
package cn.odboy.base;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
/**
* 数据分页参数
*
* @author odboy
* @date 2025-01-20
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class PageArgs<T> implements Serializable {
@NotNull(message = "参数page不能为空")
@Min(value = 1, message = "参数page最小值为1")
@ApiModelProperty(value = "页码", example = "1")
private Integer page;
@NotNull(message = "参数size不能为空")
@Min(value = 1, message = "参数size最小值为1")
@ApiModelProperty(value = "每页数据量", example = "10")
private Integer size;
private T args;
}
@@ -1,6 +1,5 @@
package cn.odboy.util; package cn.odboy.base;
import cn.odboy.base.MyObject;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
@@ -16,8 +15,6 @@ import java.util.List;
@AllArgsConstructor @AllArgsConstructor
@EqualsAndHashCode(callSuper = false) @EqualsAndHashCode(callSuper = false)
public class PageResult<T> extends MyObject { public class PageResult<T> extends MyObject {
private List<T> content; private List<T> content;
private long totalElements; private long totalElements;
} }
@@ -1,17 +0,0 @@
package cn.odboy.config.webConfig;
import org.apache.catalina.connector.Connector;
import org.springframework.boot.web.embedded.tomcat.TomcatConnectorCustomizer;
import org.springframework.context.annotation.Configuration;
/**
* 允许在查询字符串中使用特定的特殊字符
*/
@Configuration(proxyBeanMethods = false)
public class QueryCustomizer implements TomcatConnectorCustomizer {
@Override
public void customize(Connector connector) {
connector.setProperty("relaxedQueryChars", "[]{}");
}
}
@@ -1,4 +1,4 @@
package cn.odboy.config; package cn.odboy.context;
import cn.odboy.util.SecurityUtil; import cn.odboy.util.SecurityUtil;
import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.GrantedAuthority;
@@ -0,0 +1,36 @@
/*
* Copyright 2021-2025 Tian Jun
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.odboy.context;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;
/**
* Bean加载完毕 监听
*
* @author odboy
* @date 2025-01-16
*/
@Slf4j
@Component
public class BeanLoadFinishListener implements ApplicationListener<ContextRefreshedEvent> {
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
log.info("所有的Bean都加载完毕了");
}
}
@@ -0,0 +1,53 @@
/*
* Copyright 2021-2025 Tian Jun
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.odboy.context;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.core.env.Environment;
import java.net.InetAddress;
import java.net.UnknownHostException;
/**
* 主要目的是输出应用的服务地址
*
* @author odboy
* @date 2024-04-20
*/
@Slf4j
public class BootApplication {
@Bean
public SpringBeanHolder springContextHolder() {
return new SpringBeanHolder();
}
protected static void inited(ConfigurableApplicationContext application) throws UnknownHostException {
Environment env = application.getEnvironment();
String ip = InetAddress.getLocalHost().getHostAddress();
String port = env.getProperty("server.port");
String path = StrUtil.isEmpty(env.getProperty("config.servlet.context-path")) ? "" : env.getProperty("config.servlet.context-path");
log.info(
"\n----------------------------------------------------------\n\t"
+ "Application is running! Access URLs:\n\t"
+ "Local: \t\thttp://localhost:" + port + path + "/\n\t"
+ "External: \thttp://" + ip + ":" + port + path + "/\n\t"
+ "Swagger文档: \thttp://" + ip + ":" + port + path + "/doc.html\n"
+ "----------------------------------------------------------");
}
}
@@ -1,4 +1,4 @@
package cn.odboy.util; package cn.odboy.context;
import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes; import org.springframework.web.context.request.ServletRequestAttributes;
@@ -1,4 +1,4 @@
package cn.odboy.util; package cn.odboy.context;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException; import org.springframework.beans.BeansException;
@@ -3,7 +3,7 @@ package cn.odboy.exception.handler;
import cn.odboy.exception.BadRequestException; import cn.odboy.exception.BadRequestException;
import cn.odboy.exception.EntityExistException; import cn.odboy.exception.EntityExistException;
import cn.odboy.exception.EntityNotFoundException; import cn.odboy.exception.EntityNotFoundException;
import cn.odboy.util.ThrowableUtil; import cn.odboy.exception.util.ThrowableUtil;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
@@ -0,0 +1,47 @@
/*
* Copyright 2021-2025 Tian Jun
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.odboy.exception.util;
/**
* 适配 logger 占位符
*
* @author odboy
* @date 2025-01-13
*/
public class LogFmtUtil {
/**
* 替换字符串中的占位符 {} 为传入的参数
*
* @param message 消息模板
* @param args 替换占位符的参数
* @return 替换后的消息
*/
public static String format(String message, Object... args) {
if (message == null || args == null || args.length == 0) {
return message;
}
// 使用 String.format 替换占位符
return String.format(message.replace("{}", "%s"), args);
}
public static void main(String[] args) {
// 示例用法
String messageTemplate = "获取dingtalk accessToken失败, code={}, message={}";
String formattedMessage = format(messageTemplate, 400, "Bad Request");
// 输出: 获取dingtalk accessToken失败, code=400, message=Bad Request
System.out.println(formattedMessage);
}
}
@@ -1,4 +1,4 @@
package cn.odboy.util; package cn.odboy.exception.util;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.io.StringWriter; import java.io.StringWriter;
@@ -0,0 +1,51 @@
/*
* Copyright 2021-2025 Tian Jun
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.odboy.monitor;
import cn.odboy.annotation.AnonymousGetMapping;
import io.swagger.annotations.Api;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 健康检查接口
*
* @author odboy
* @date 2022-01-06
*/
@RestController
@RequiredArgsConstructor
@RequestMapping("/health")
@Api(tags = "系统:健康检查接口")
public class HealthCheckController {
/**
* 健康检查
*/
@AnonymousGetMapping(value = "/check")
public ResponseEntity<?> doCheck() {
return ResponseEntity.ok().build();
}
/**
* 访问首页提示
*/
@AnonymousGetMapping("/")
public String index() {
return "success";
}
}
@@ -1,7 +1,10 @@
package cn.odboy.config.mybatis; package cn.odboy.mybatis.config;
import cn.odboy.mybatis.context.InsertBatchSqlInjector;
import com.baomidou.mybatisplus.annotation.DbType; import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.BlockAttackInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
@@ -10,18 +13,28 @@ import org.springframework.transaction.annotation.EnableTransactionManagement;
@Configuration @Configuration
@EnableTransactionManagement @EnableTransactionManagement
public class MybatisPlusConfig { public class MybatisPlusConfig {
/**
* MyBatisPlus拦截器(用于分页)
*/
@Bean @Bean
public MybatisPlusInterceptor paginationInterceptor() { public MybatisPlusInterceptor paginationInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// 添加MySQL的分页拦截器 // MySQL的分页拦截器
PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor(DbType.MYSQL); PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor(DbType.MYSQL);
paginationInnerInterceptor.setOptimizeJoin(true);
paginationInnerInterceptor.setMaxLimit(500L); paginationInnerInterceptor.setMaxLimit(500L);
paginationInnerInterceptor.setOverflow(false); /// 这个配置会导致:当分页没数据时,游标从0开始,会导致无论page为什么值,就算分页超出最大页数,依然能够查询到
/// paginationInnerInterceptor.setOverflow(true);
paginationInnerInterceptor.setOptimizeJoin(true);
interceptor.addInnerInterceptor(paginationInnerInterceptor); interceptor.addInnerInterceptor(paginationInnerInterceptor);
// 乐观锁
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
// 防全表更新与删除
interceptor.addInnerInterceptor(new BlockAttackInnerInterceptor());
return interceptor; return interceptor;
} }
/**
* Mapper支持批量插入
*/
@Bean
public InsertBatchSqlInjector insertBatchSqlInjector() {
return new InsertBatchSqlInjector();
}
} }
@@ -1,4 +1,4 @@
package cn.odboy.config; package cn.odboy.mybatis.config;
import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure; import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure;
import com.alibaba.druid.spring.boot.autoconfigure.properties.DruidStatProperties; import com.alibaba.druid.spring.boot.autoconfigure.properties.DruidStatProperties;
@@ -0,0 +1,153 @@
/*
* <<
* Davinci
* ==
* Copyright (C) 2016 - 2019 EDP
* ==
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* >>
*
*/
package cn.odboy.mybatis.constant;
import lombok.extern.slf4j.Slf4j;
/**
* @author /
*/
@Slf4j
@SuppressWarnings({"unchecked", "all"})
public enum DataTypeEnum {
/**
* mysql
*/
MYSQL("mysql", "mysql", "com.mysql.jdbc.Driver", "`", "`", "'", "'"),
/**
* oracle
*/
ORACLE("oracle", "oracle", "oracle.jdbc.driver.OracleDriver", "\"", "\"", "\"", "\""),
/**
* sql config
*/
SQLSERVER("sqlserver", "sqlserver", "com.microsoft.sqlserver.jdbc.SQLServerDriver", "\"", "\"", "\"", "\""),
/**
* h2
*/
H2("h2", "h2", "org.h2.Driver", "`", "`", "\"", "\""),
/**
* phoenix
*/
PHOENIX("phoenix", "hbase phoenix", "org.apache.phoenix.jdbc.PhoenixDriver", "", "", "\"", "\""),
/**
* mongo
*/
MONGODB("mongo", "mongodb", "mongodb.jdbc.MongoDriver", "`", "`", "\"", "\""),
/**
* sql4es
*/
ELASTICSEARCH("sql4es", "elasticsearch", "nl.anchormen.sql4es.jdbc.ESDriver", "", "", "'", "'"),
/**
* presto
*/
PRESTO("presto", "presto", "com.facebook.presto.jdbc.PrestoDriver", "", "", "\"", "\""),
/**
* moonbox
*/
MOONBOX("moonbox", "moonbox", "moonbox.jdbc.MbDriver", "`", "`", "`", "`"),
/**
* cassandra
*/
CASSANDRA("cassandra", "cassandra", "com.github.adejanovski.cassandra.jdbc.CassandraDriver", "", "", "'", "'"),
/**
* click house
*/
CLICKHOUSE("clickhouse", "clickhouse", "ru.yandex.clickhouse.ClickHouseDriver", "", "", "\"", "\""),
/**
* kylin
*/
KYLIN("kylin", "kylin", "org.apache.kylin.jdbc.Driver", "\"", "\"", "\"", "\""),
/**
* vertica
*/
VERTICA("vertica", "vertica", "com.vertica.jdbc.Driver", "", "", "'", "'"),
/**
* sap
*/
HANA("sap", "sap hana", "com.sap.db.jdbc.Driver", "", "", "'", "'"),
/**
* impala
*/
IMPALA("impala", "impala", "com.cloudera.impala.jdbc41.Driver", "", "", "'", "'");
private String feature;
private String desc;
private String driver;
private String keywordPrefix;
private String keywordSuffix;
private String aliasPrefix;
private String aliasSuffix;
private static final String JDBC_URL_PREFIX = "jdbc:";
DataTypeEnum(String feature, String desc, String driver, String keywordPrefix, String keywordSuffix, String aliasPrefix, String aliasSuffix) {
this.feature = feature;
this.desc = desc;
this.driver = driver;
this.keywordPrefix = keywordPrefix;
this.keywordSuffix = keywordSuffix;
this.aliasPrefix = aliasPrefix;
this.aliasSuffix = aliasSuffix;
}
public static DataTypeEnum urlOf(String jdbcUrl) {
String url = jdbcUrl.toLowerCase().trim();
for (DataTypeEnum dataTypeEnum : values()) {
if (url.startsWith(JDBC_URL_PREFIX + dataTypeEnum.feature)) {
try {
Class<?> aClass = Class.forName(dataTypeEnum.getDriver());
if (null == aClass) {
throw new RuntimeException("Unable to get driver instance for jdbcUrl: " + jdbcUrl);
}
} catch (ClassNotFoundException e) {
throw new RuntimeException("Unable to get driver instance: " + jdbcUrl);
}
return dataTypeEnum;
}
}
return null;
}
public String getFeature() {
return feature;
}
public String getDesc() {
return desc;
}
public String getDriver() {
return driver;
}
public String getKeywordPrefix() {
return keywordPrefix;
}
public String getKeywordSuffix() {
return keywordSuffix;
}
public String getAliasPrefix() {
return aliasPrefix;
}
public String getAliasSuffix() {
return aliasSuffix;
}
}
@@ -0,0 +1,58 @@
package cn.odboy.mybatis.constant;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 查询描述
*
* @date 2023-11-25
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MpQuery {
/**
* 基本对象的属性名
*/
String propName() default "";
/**
* 查询方式
*/
QueryTypeEnum type() default QueryTypeEnum.EQUAL;
/**
* 连接查询的属性名, 如User类中的dept
*/
String joinName() default "";
/**
* 默认左连接
*/
Join join() default Join.LEFT;
/**
* 多字段模糊搜索, 仅支持String类型字段, 多个用逗号隔开, 如@MpQuery(blurry = "email,username")
*/
String blurry() default "";
/**
* 适用于简单连接查询, 复杂的请自定义该注解, 或者使用sql查询
*/
enum Join {
/**
* 左连接
*/
LEFT,
/**
* 右连接
*/
RIGHT,
/**
* 内连接
*/
INNER
}
}
@@ -0,0 +1,59 @@
package cn.odboy.mybatis.constant;
/**
* 动态查询 枚举
*/
public enum QueryTypeEnum {
/**
* 相等
*/
EQUAL
/**
* 大于等于
*/
, GREATER_THAN
/**
* 小于等于
*/
, LESS_THAN
/**
* 中模糊查询
*/
, INNER_LIKE
/**
* 左模糊查询
*/
, LEFT_LIKE
/**
* 右模糊查询
*/
, RIGHT_LIKE
/**
* 小于
*/
, LESS_THAN_NQ
/**
* 包含
*/
, IN
/**
* 不包含
*/
, NOT_IN
/**
* 不等于
*/
, NOT_EQUAL
/**
* between(注:被注解的属性一定得是数组或者集合, 长度大于等于2)
*/
, BETWEEN
/**
* 不为空
*/
, NOT_NULL
/**
* 为空
*/
, IS_NULL
}
@@ -1,4 +1,4 @@
package cn.odboy.config.mybatis; package cn.odboy.mybatis.context;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import com.p6spy.engine.spy.appender.MessageFormattingStrategy; import com.p6spy.engine.spy.appender.MessageFormattingStrategy;
@@ -0,0 +1,44 @@
/*
* Copyright 2021-2025 Tian Jun
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.odboy.mybatis.context;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.core.injector.AbstractMethod;
import com.baomidou.mybatisplus.core.injector.DefaultSqlInjector;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.baomidou.mybatisplus.extension.injector.methods.AlwaysUpdateSomeColumnById;
import com.baomidou.mybatisplus.extension.injector.methods.InsertBatchSomeColumn;
import org.apache.ibatis.session.Configuration;
import java.util.List;
/**
* 批量插入SQL注入器
*
* @author odboy
* @date 2025-01-11
*/
public class InsertBatchSqlInjector extends DefaultSqlInjector {
@Override
public List<AbstractMethod> getMethodList(Configuration configuration, Class<?> mapperClass, TableInfo tableInfo) {
List<AbstractMethod> methodList = super.getMethodList(configuration, mapperClass, tableInfo);
// 新增自定义方法, InsertBatchSomeColumn这个方法Mp没有开放出来
methodList.add(new InsertBatchSomeColumn(i -> i.getFieldFill() != FieldFill.UPDATE));
// 全量更新, 包括null字段
methodList.add(new AlwaysUpdateSomeColumnById(i -> i.getFieldFill() != FieldFill.INSERT));
return methodList;
}
}
@@ -1,4 +1,4 @@
package cn.odboy.config.mybatis; package cn.odboy.mybatis.context;
import cn.hutool.core.date.DateTime; import cn.hutool.core.date.DateTime;
import cn.odboy.util.SecurityUtil; import cn.odboy.util.SecurityUtil;
@@ -0,0 +1,204 @@
/*
* Copyright 2021-2025 Tian Jun
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.odboy.mybatis.interfaces;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.odboy.base.PageResult;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.conditions.query.QueryChainWrapper;
import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper;
import com.baomidou.mybatisplus.extension.conditions.update.UpdateChainWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.toolkit.ChainWrappers;
import org.apache.ibatis.annotations.Param;
import org.springframework.data.domain.Pageable;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* 公共抽象Mapper接口类
*
* @author odboy
* @date 2022-04-03
*/
public interface EasyMapper<E> extends BaseMapper<E> {
/**
* 批量插入
*
* @param entityList List<E>
* @return 影响的行数
*/
int insertBatchSomeColumn(List<E> entityList);
/**
* 根据id全量更新
*
* @param entity E
* @return 影响的行数
*/
int alwaysUpdateSomeColumnById(@Param("et") E entity);
default QueryChainWrapper<E> select() {
return ChainWrappers.queryChain(this);
}
default UpdateChainWrapper<E> update() {
return ChainWrappers.updateChain(this);
}
default LambdaQueryChainWrapper<E> lambdaSelect() {
return ChainWrappers.lambdaQueryChain(this);
}
default LambdaUpdateChainWrapper<E> lambdaUpdate() {
return ChainWrappers.lambdaUpdateChain(this);
}
/**
* 获取字典
*
* @param wrapper LambdaQueryWrapper<E>
* @param keyName 键对应的列名称
* @param valueName 值对应的列名称
* @return Map<String, Object>
*/
default Map<String, Object> selectMap(LambdaQueryWrapper<E> wrapper, String keyName, String valueName) {
Map<String, Object> result = new ConcurrentHashMap<>(1);
List<E> list = this.selectList(wrapper);
if (CollUtil.isEmpty(list)) {
return new HashMap<>();
}
E tempObj = list.stream().findFirst().orElse(null);
if (tempObj == null) {
return new HashMap<>();
}
Field[] fields = ReflectUtil.getFields(tempObj.getClass());
for (E e : list) {
Field keyField = null;
Field valueField = null;
for (Field field : fields) {
String fieldName = field.getName();
if (fieldName.equals(keyName)) {
keyField = field;
} else if (fieldName.equals(valueName)) {
valueField = field;
break;
}
}
String fieldKey = String.valueOf(ReflectUtil.getFieldValue(e, keyField));
Object fieldValue = ReflectUtil.getFieldValue(e, valueField);
if (fieldKey != null) {
result.put(fieldKey, fieldValue);
}
}
return result;
}
/**
* 条件查询列表, 并返回期望的对象
*
* @param wrapper LambdaQueryWrapper<E>
* @param clazz 期望的对象类型
* @return List<T>
*/
default <T> List<T> selectList(LambdaQueryWrapper<E> wrapper, Class<T> clazz) {
List<E> list = this.selectList(wrapper);
if (CollUtil.isEmpty(list)) {
return new ArrayList<>();
}
return BeanUtil.copyToList(list, clazz);
}
/**
* 条件查询列表, 并返回期望的对象
*
* @param wrapper LambdaQueryWrapper<E>
* @param clazz 期望的对象类型
* @return List<T>
*/
default <T> List<T> selectList(LambdaQueryChainWrapper<E> wrapper, Class<T> clazz) {
List<E> list = wrapper.list();
if (CollUtil.isEmpty(list)) {
return new ArrayList<>();
}
return BeanUtil.copyToList(list, clazz);
}
/**
* 条件查询分页列表, 并返回期望的对象
*
* @param pageable 分页参数
* @param wrapper LambdaQueryWrapper<E> wrapper
* @param clazz 期望的对象类型
* @return IPage<T>
*/
default <T> PageResult<T> selectPage(Pageable pageable, LambdaQueryWrapper<E> wrapper, Class<T> clazz) {
int pageNumber = pageable.getPageNumber();
int pageSize = pageable.getPageSize();
pageNumber = pageNumber <= 0 ? 1 : pageNumber;
pageSize = pageSize <= 0 ? 10 : pageSize;
IPage<E> pageInfo = this.selectPage(new Page<>(pageNumber, pageSize), wrapper);
if (CollUtil.isEmpty(pageInfo.getRecords())) {
return new PageResult<>(new ArrayList<>(), pageInfo.getTotal());
}
return new PageResult<>(BeanUtil.copyToList(pageInfo.getRecords(), clazz), pageInfo.getTotal());
}
/**
* 条件查询分页列表, 并返回期望的对象
*
* @param pageable 分页参数
* @param wrapper LambdaQueryWrapper<E> wrapper
* @param clazz 期望的对象类型
* @return IPage<T>
*/
default <T> PageResult<T> selectPage(Pageable pageable, LambdaQueryChainWrapper<E> wrapper, Class<T> clazz) {
int pageNumber = pageable.getPageNumber();
int pageSize = pageable.getPageSize();
pageNumber = pageNumber <= 0 ? 1 : pageNumber;
pageSize = pageSize <= 0 ? 10 : pageSize;
IPage<E> pageInfo = wrapper.page(new Page<>(pageNumber, pageSize));
if (CollUtil.isEmpty(pageInfo.getRecords())) {
return new PageResult<>(new ArrayList<>(), pageInfo.getTotal());
}
return new PageResult<>(BeanUtil.copyToList(pageInfo.getRecords(), clazz), pageInfo.getTotal());
}
/**
* 获取目标类
*
* @param wrapper LambdaQueryChainWrapper<E> wrapper
* @param clazz 期望的对象类型
* @return T
*/
default <T> T selectOne(LambdaQueryChainWrapper<E> wrapper, Class<T> clazz) {
E e = this.selectOne(wrapper);
if (e == null) {
return null;
}
return BeanUtil.copyProperties(e, clazz);
}
}
@@ -0,0 +1,72 @@
/*
* Copyright 2021-2025 Tian Jun
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.odboy.mybatis.interfaces;
import cn.odboy.base.PageResult;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.baomidou.mybatisplus.extension.service.IService;
import java.io.Serializable;
import java.util.Collection;
import java.util.List;
/**
* 公共抽象Mapper接口类
*
* @author odboy
* @date 2022-04-03
*/
public interface EasyService<T> extends IService<T> {
LambdaQueryWrapper<T> quick();
<G> int quickSave(G resources);
<G> int quickSaveBatch(List<G> resources);
<G> int quickModifyById(G resources);
<G> boolean quickModifyBatchById(Collection<G> resources, int batchSize);
<G> G quickGetOneById(Serializable id, Class<G> targetClazz);
T quickGetOne(LambdaQueryWrapper<T> wrapper, SFunction<T, ?> orderColumn);
<G> G quickGetOne(LambdaQueryWrapper<T> wrapper, SFunction<T, ?> orderColumn, Class<G> clazz);
<G> List<G> quickListByIds(List<Serializable> ids, Class<G> targetClazz);
<Q> List<T> quickList(Q criteria);
List<T> quickList(LambdaQueryWrapper<T> wrapper);
<G, Q> List<G> quickList(Q criteria, Class<G> targetClazz);
<G> List<G> quickList(LambdaQueryWrapper<T> wrapper, Class<G> targetClazz);
PageResult<T> quickPage(LambdaQueryWrapper<T> wrapper, IPage<T> pageable);
<G> PageResult<G> quickPage(LambdaQueryWrapper<T> wrapper, IPage<T> pageable, Class<G> targetClazz);
<G, Q> PageResult<G> quickPage(Q criteria, IPage<T> pageable, Class<G> targetClazz);
<Q> PageResult<T> quickPage(Q criteria, IPage<T> pageable);
int quickUpdate(LambdaQueryWrapper<T> wrapper, T entity);
int quickDelete(LambdaQueryWrapper<T> wrapper);
}
@@ -0,0 +1,260 @@
/*
* Copyright 2021-2025 Tian Jun
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.odboy.mybatis.interfaces.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.odboy.base.PageResult;
import cn.odboy.exception.BadRequestException;
import cn.odboy.mybatis.interfaces.EasyMapper;
import cn.odboy.mybatis.util.MybatisHelper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.enums.SqlMethod;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.ibatis.binding.MapperMethod;
import java.io.Serializable;
import java.util.Collection;
import java.util.List;
/**
* 公共抽象Mapper接口类
*
* @author odboy
* @date 2022-04-03
*/
public class EasyServiceImpl<M extends EasyMapper<T>, T> extends ServiceImpl<M, T> {
public LambdaQueryWrapper<T> quick() {
return new LambdaQueryWrapper<>();
}
/**
* 快速插入
*
* @param resources /
*/
public <G> int quickSave(G resources) {
return this.getBaseMapper().insert(BeanUtil.copyProperties(resources, this.getEntityClass()));
}
/**
* 快速批量插入
*
* @param resources /
*/
public <G> int quickSaveBatch(List<G> resources) {
return this.getBaseMapper().insertBatchSomeColumn(BeanUtil.copyToList(resources, this.getEntityClass()));
}
/**
* 快速更新
*
* @param resources /
*/
public <G> int quickModifyById(G resources) {
return this.getBaseMapper().updateById(BeanUtil.copyProperties(resources, this.getEntityClass()));
}
/**
* 快速批量更新
*
* @param resources /
* @param batchSize 每批数量
*/
public <G> boolean quickModifyBatchById(Collection<G> resources, int batchSize) {
String sqlStatement = this.getSqlStatement(SqlMethod.UPDATE_BY_ID);
return this.executeBatch(resources, batchSize, (sqlSession, entity) -> {
MapperMethod.ParamMap<T> param = new MapperMethod.ParamMap<>();
param.put("et", BeanUtil.copyProperties(entity, this.getEntityClass()));
sqlSession.update(sqlStatement, param);
});
}
/**
* 通过id查询
*
* @param id /
* @param targetClazz 目标类型
*/
public <G> G quickGetOneById(Serializable id, Class<G> targetClazz) {
T entity = this.getById(id);
return entity == null ? null : BeanUtil.copyProperties(entity, targetClazz);
}
/**
* 查一条数据
*
* @param wrapper 制造条件
*/
public T quickGetOne(LambdaQueryWrapper<T> wrapper, SFunction<T, ?> orderColumn) {
if (orderColumn == null) {
throw new BadRequestException("参数orderColumn(排序的列)必填");
}
if (wrapper == null) {
wrapper = new LambdaQueryWrapper<>();
}
wrapper.last("limit 1");
wrapper.orderByDesc(orderColumn);
List<T> ts = baseMapper.selectList(wrapper);
if (ts.isEmpty()) {
return null;
}
return ts.stream().findFirst().get();
}
public <G> G quickGetOne(LambdaQueryWrapper<T> wrapper, SFunction<T, ?> orderColumn, Class<G> clazz) {
if (orderColumn == null) {
throw new BadRequestException("参数orderColumn(排序的列)必填");
}
if (wrapper == null) {
wrapper = new LambdaQueryWrapper<>();
}
wrapper.last("limit 1");
wrapper.orderByDesc(orderColumn);
List<T> ts = baseMapper.selectList(wrapper);
if (ts.isEmpty()) {
return null;
}
return BeanUtil.copyProperties(ts.stream().findFirst().get(), clazz);
}
/**
* 通过id集合查询
*
* @param ids /
* @param targetClazz 目标类型
*/
public <G> List<G> quickListByIds(List<Serializable> ids, Class<G> targetClazz) {
List<T> entitys = this.listByIds(ids);
return entitys == null || entitys.isEmpty() ? CollUtil.newArrayList() : BeanUtil.copyToList(entitys, targetClazz);
}
/**
* 查有关的数据
*
* @param criteria 动态条件
*/
public <Q> List<T> quickList(Q criteria) {
QueryWrapper<T> predicate = MybatisHelper.build(criteria);
return baseMapper.selectList(predicate);
}
/**
* 查有关的数据
*
* @param wrapper 制造条件
*/
public List<T> quickList(LambdaQueryWrapper<T> wrapper) {
if (wrapper == null) {
wrapper = new LambdaQueryWrapper<>();
}
return baseMapper.selectList(wrapper);
}
/**
* 查有关的数据并转成目标类型的数据
*
* @param criteria 动态条件
* @param targetClazz 目标类型
*/
public <G, Q> List<G> quickList(Q criteria, Class<G> targetClazz) {
QueryWrapper<T> predicate = MybatisHelper.build(criteria);
List<T> data = baseMapper.selectList(predicate);
return BeanUtil.copyToList(data, targetClazz);
}
/**
* 查有关的数据并转换为目标类型
*
* @param wrapper 制造条件
* @param targetClazz 目标类型
*/
public <G> List<G> quickList(LambdaQueryWrapper<T> wrapper, Class<G> targetClazz) {
if (wrapper == null) {
wrapper = new LambdaQueryWrapper<>();
}
return BeanUtil.copyToList(baseMapper.selectList(wrapper), targetClazz);
}
/**
* 查有关的分页数据
*
* @param wrapper 制造条件
* @param pageable 分页参数
*/
public PageResult<T> quickPage(LambdaQueryWrapper<T> wrapper, IPage<T> pageable) {
if (wrapper == null) {
wrapper = new LambdaQueryWrapper<>();
}
IPage<T> originPageData = baseMapper.selectPage(pageable, wrapper);
return new PageResult<>(originPageData.getRecords(), originPageData.getTotal());
}
/**
* 查有关的分页数据
*
* @param wrapper 制造条件
* @param pageable 分页参数
* @param targetClazz 目标类型
*/
public <G> PageResult<G> quickPage(LambdaQueryWrapper<T> wrapper, IPage<T> pageable, Class<G> targetClazz) {
if (wrapper == null) {
wrapper = new LambdaQueryWrapper<>();
}
IPage<T> originPageData = baseMapper.selectPage(pageable, wrapper);
return new PageResult<>(BeanUtil.copyToList(originPageData.getRecords(), targetClazz), originPageData.getTotal());
}
public <G, Q> PageResult<G> quickPage(Q criteria, IPage<T> pageable, Class<G> targetClazz) {
QueryWrapper<T> wrapper = MybatisHelper.build(criteria);
IPage<T> originPageData = baseMapper.selectPage(pageable, wrapper);
return new PageResult<>(BeanUtil.copyToList(originPageData.getRecords(), targetClazz), originPageData.getTotal());
}
public <Q> PageResult<T> quickPage(Q criteria, IPage<T> pageable) {
QueryWrapper<T> wrapper = MybatisHelper.build(criteria);
IPage<T> originPageData = baseMapper.selectPage(pageable, wrapper);
return new PageResult<>(originPageData.getRecords(), originPageData.getTotal());
}
/**
* 条件更新
*
* @param wrapper 制造条件
* @param entity 更新内容
*/
public int quickUpdate(LambdaQueryWrapper<T> wrapper, T entity) {
if (wrapper == null) {
throw new BadRequestException("参数wrapper必填");
}
return baseMapper.update(entity, wrapper);
}
/**
* 条件删除
*
* @param wrapper 制造条件
*/
public int quickDelete(LambdaQueryWrapper<T> wrapper) {
if (wrapper == null) {
throw new BadRequestException("参数wrapper必填");
}
return baseMapper.delete(wrapper);
}
}
@@ -0,0 +1,195 @@
/*
* Copyright 2021-2025 Tian Jun
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.odboy.mybatis.util;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.querys.MySqlQuery;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.DbColumnType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.AbstractTemplateEngine;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import com.baomidou.mybatisplus.generator.keywords.MySqlKeyWordsHandler;
import lombok.Data;
import java.sql.Types;
import java.util.Collections;
import java.util.List;
import java.util.function.Consumer;
/**
* 代码生成器入口
*
* @author odboy
* @date 2025-01-11
*/
@Data
public class CmdGenHelper {
/**
* 数据库类型 MySQL
*/
private static final IDbQuery DB_QUERY = new MySqlQuery();
/**
* 类型转换
*/
private static final String TYPE_TINY_INT = "tinyint";
private static final String TYPE_DATETIME = "datetime";
private static final String TYPE_DATE = "date";
private String databaseUrl;
private String databaseUsername;
private String databasePassword;
private String driverClassName;
private String parentPackageName;
private String parentPackageModuleName;
/**
* 代码生成函数
*
* @param tablePrefix 表前缀(可空)
* @param tableNames 表名称, 多个用逗号分隔
*/
public void gen(String tablePrefix, List<String> tableNames) {
// 1.数据库配置
DataSourceConfig.Builder dataSourceConfigBuilder = new DataSourceConfig
.Builder(this.databaseUrl, this.databaseUsername, this.databasePassword)
.driverClassName(this.driverClassName);
dataSourceConfigBuilder.dbQuery(DB_QUERY);
dataSourceConfigBuilder.keyWordsHandler(new MySqlKeyWordsHandler());
// 1.1.快速生成器
FastAutoGenerator fastAutoGenerator = FastAutoGenerator.create(dataSourceConfigBuilder);
// 2.全局配置
// 自定义类型转换
fastAutoGenerator.dataSourceConfig(getDataSourceConfigConsumer());
// 覆盖已生成文件
// 添加swagger注解
// 设置注释的作者
// 设置注释的日期格式
// 使用java8新的时间类型
fastAutoGenerator.globalConfig(getGlobalConfigConsumer());
// 3.包配置
// 设置父包名
// 设置父包模块名
// 设置MVC下各个模块的包名
// 设置XML资源文件的目录
fastAutoGenerator.packageConfig(getPackageConfigConsumer());
// 4.模板配置
// 使用Freemarker引擎模板, 默认的是Velocity引擎模板
AbstractTemplateEngine templateEngine = new FreemarkerTemplateEngine();
fastAutoGenerator.templateEngine(templateEngine);
// 5.策略配置
// 设置需要生成的表名
// 设置过滤表前缀
fastAutoGenerator.strategyConfig(getStrategyConfigConsumer(tableNames)
);
if (tablePrefix != null) {
// 表前缀, 可多个
fastAutoGenerator.strategyConfig(strategyConfigBuilder -> strategyConfigBuilder.addTablePrefix(tablePrefix));
}
// 5.1.Entity策略配置
// 生成实体时生成字段的注解, 包括@TableId注解等
// 数据库表和字段映射到实体的命名策略, 为下划线转驼峰
// 全局主键类型为None
// 实体名称格式化为XXXEntity
fastAutoGenerator.strategyConfig(getEntityConfigConsumer());
// 5.2.Controller策略配置
// 开启生成@RestController控制器
fastAutoGenerator.strategyConfig(strategyConfigBuilder -> strategyConfigBuilder.controllerBuilder().enableRestStyle());
// 如果不需要生成Controller
// fastAutoGenerator.templateConfig(templateConfig -> templateConfig.controller(""));
// 5.3.Service策略配置
// 格式化service接口和实现类的文件名称, 去掉默认的ServiceName前面的I
fastAutoGenerator.strategyConfig(strategyConfigBuilder -> strategyConfigBuilder
.serviceBuilder()
.formatServiceFileName("%sService")
.formatServiceImplFileName("%sServiceImpl"));
// 5.4.Mapper策略配置
// 格式化 mapper文件名,格式化xml实现类文件名称
fastAutoGenerator.strategyConfig(getStrategyConfigConsumer());
// 6.生成代码
fastAutoGenerator.execute();
}
private static Consumer<StrategyConfig.Builder> getEntityConfigConsumer() {
return strategyConfigBuilder -> strategyConfigBuilder
.entityBuilder()
.enableLombok()
// 如果不需要生成注解, 去掉.enableTableFieldAnnotation()
.enableTableFieldAnnotation()
.enableFileOverride()
.naming(NamingStrategy.underline_to_camel)
.columnNaming(NamingStrategy.underline_to_camel)
.idType(IdType.AUTO);
}
private static Consumer<StrategyConfig.Builder> getStrategyConfigConsumer(List<String> tableNames) {
return strategyConfigBuilder -> strategyConfigBuilder
.enableCapitalMode()
.enableSkipView()
.disableSqlFilter()
.addInclude(tableNames)
.mapperBuilder()
.build();
}
private Consumer<PackageConfig.Builder> getPackageConfigConsumer() {
return packageConfigBuilder -> packageConfigBuilder
.parent(this.parentPackageName == null ? "cn.codegen" : this.parentPackageName)
.moduleName(this.parentPackageModuleName == null ? "moduleName" : this.parentPackageModuleName)
.entity("domain")
.service("service")
.mapper("mapper")
.serviceImpl("service.service")
.controller("rest")
.pathInfo(Collections.singletonMap(OutputFile.xml, (System.getProperty("os.name").toLowerCase().contains("win") ? "C:\\CodeGen\\resources\\mapper" : "/tmp/CodeGen/resources/mapper")));
}
private static Consumer<GlobalConfig.Builder> getGlobalConfigConsumer() {
return globalConfigBuilder -> globalConfigBuilder
.enableSwagger()
.outputDir((System.getProperty("os.name").toLowerCase().contains("win") ? "C:\\CodeGen" : "/tmp/CodeGen"))
.author("codegen")
.commentDate("yyyy-MM-dd")
.dateType(DateType.TIME_PACK);
}
private static Consumer<StrategyConfig.Builder> getStrategyConfigConsumer() {
return strategyConfigBuilder -> strategyConfigBuilder
.mapperBuilder()
.formatMapperFileName("%sMapper")
.formatXmlFileName("%sMapper");
}
private static Consumer<DataSourceConfig.Builder> getDataSourceConfigConsumer() {
return builder -> builder.typeConvertHandler((globalConfig, typeRegistry, metaInfo) -> {
int typeCode = metaInfo.getJdbcType().TYPE_CODE;
if (typeCode == Types.SMALLINT) {
return DbColumnType.INTEGER;
}
if (typeCode == Types.DATE) {
return DbColumnType.DATE;
}
if (typeCode == Types.TIME) {
return DbColumnType.DATE;
}
if (typeCode == Types.TIMESTAMP) {
return DbColumnType.DATE;
}
return typeRegistry.getColumnType(metaInfo);
});
}
}
@@ -0,0 +1,239 @@
package cn.odboy.mybatis.util;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.odboy.base.MyEntity;
import cn.odboy.exception.BadRequestException;
import cn.odboy.mybatis.constant.MpQuery;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.extern.slf4j.Slf4j;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.lang.reflect.Field;
import java.util.*;
import java.util.stream.Collectors;
/**
* 查询条件创建工具
*/
@Slf4j
public class MybatisHelper {
public static <R, Q> QueryWrapper<R> build(Q query) {
QueryWrapper<R> queryWrapper = new QueryWrapper<>();
if (query == null) {
return queryWrapper;
}
Class<?> clazz = query.getClass();
try {
List<Field> fields = getAllFields(clazz, new ArrayList<>());
for (Field field : fields) {
if (!field.canAccess(clazz)) {
field.setAccessible(true);
MpQuery q = field.getAnnotation(MpQuery.class);
if (q != null) {
String propName = q.propName();
String blurry = q.blurry();
String attributeName = StrUtil.isBlank(propName) ? field.getName() : propName;
attributeName = humpToUnderline(attributeName);
Object fieldVal = field.get(query);
if (ObjectUtil.isNull(fieldVal) || "".equals(fieldVal)) {
continue;
}
if (ObjectUtil.isNotEmpty(blurry)) {
handleBlurryQuery(queryWrapper, blurry, fieldVal);
continue;
}
handleWrapper(q, queryWrapper, attributeName, fieldVal);
}
field.setAccessible(false);
}
}
} catch (Exception e) {
log.error("组装SQL失败", e);
}
return queryWrapper;
}
private static <R> void handleWrapper(MpQuery q, QueryWrapper<R> queryWrapper, String attributeName, Object fieldVal) {
switch (q.type()) {
case EQUAL:
queryWrapper.eq(attributeName, fieldVal);
break;
case GREATER_THAN:
queryWrapper.ge(attributeName, fieldVal);
break;
case LESS_THAN:
queryWrapper.le(attributeName, fieldVal);
break;
case LESS_THAN_NQ:
queryWrapper.lt(attributeName, fieldVal);
break;
case INNER_LIKE:
queryWrapper.like(attributeName, fieldVal);
break;
case LEFT_LIKE:
queryWrapper.likeLeft(attributeName, fieldVal);
break;
case RIGHT_LIKE:
queryWrapper.likeRight(attributeName, fieldVal);
break;
case IN:
handleInQuery(queryWrapper, attributeName, fieldVal);
break;
case NOT_IN:
handleNotInQuery(queryWrapper, attributeName, fieldVal);
break;
case NOT_EQUAL:
queryWrapper.ne(attributeName, fieldVal);
break;
case NOT_NULL:
queryWrapper.isNotNull(attributeName);
break;
case IS_NULL:
queryWrapper.isNull(attributeName);
break;
case BETWEEN:
handleBetweenQuery(queryWrapper, fieldVal, attributeName);
break;
default:
break;
}
}
private static <R> void handleBetweenQuery(QueryWrapper<R> queryWrapper, Object fieldVal, String finalAttributeName) {
if (fieldVal instanceof List) {
List<Object> between = new ArrayList<>((List<?>) fieldVal);
if (CollectionUtil.isNotEmpty(between)) {
if (between.size() >= 2) {
queryWrapper.between(finalAttributeName, between.get(0), between.get(1));
} else {
throw new BadRequestException("BETWEEN类型的对象列表长度必须 >= 2");
}
}
} else {
throw new BadRequestException("BETWEEN类型的对象必须是一个List子集合");
}
}
private static <R> void handleNotInQuery(QueryWrapper<R> queryWrapper, String finalAttributeName, Object fieldVal) {
Collection<?> wrapNotInVal = (Collection<?>) fieldVal;
if (CollectionUtil.isNotEmpty(wrapNotInVal)) {
Optional<?> anyValOptional = wrapNotInVal.stream().findAny();
if (anyValOptional.isPresent()) {
Object o = anyValOptional.get();
if (o instanceof Long) {
queryWrapper.notIn(finalAttributeName, fieldVal);
} else if (o instanceof Integer) {
queryWrapper.notIn(finalAttributeName, fieldVal);
} else {
throw new BadRequestException("NOT_IN类型的对象属性值必须是Long/Integer类型集合");
}
}
}
}
/**
* IN查询
*
* @param queryWrapper /
* @param fieldVal /
* @param finalAttributeName /
* @param <R> /
*/
private static <R> void handleInQuery(QueryWrapper<R> queryWrapper, String finalAttributeName, Object fieldVal) {
Collection<?> wrapInVal = (Collection<?>) fieldVal;
if (CollectionUtil.isNotEmpty(wrapInVal)) {
Optional<?> anyValOptional = wrapInVal.stream().findAny();
if (anyValOptional.isPresent()) {
Object o = anyValOptional.get();
if (o instanceof Long) {
queryWrapper.in(finalAttributeName, fieldVal);
} else if (o instanceof Integer) {
queryWrapper.in(finalAttributeName, fieldVal);
} else {
throw new BadRequestException("IN类型的对象属性值必须是Long/Integer类型集合");
}
}
}
}
/**
* 模糊多字段
*
* @param queryWrapper /
* @param blurry /
* @param fieldVal /
* @param <R> /
*/
private static <R> void handleBlurryQuery(QueryWrapper<R> queryWrapper, String blurry, Object fieldVal) {
List<String> blurryList = Arrays.stream(blurry.split(",")).filter(StrUtil::isNotBlank).distinct().collect(Collectors.toList());
queryWrapper.and(wrapper -> {
for (String blurryItem : blurryList) {
String column = humpToUnderline(blurryItem);
wrapper.or();
wrapper.like(column, fieldVal.toString());
}
});
}
public static List<Field> getAllFields(Class<?> clazz, List<Field> fields) {
if (clazz != null) {
fields.addAll(Arrays.asList(clazz.getDeclaredFields()));
getAllFields(clazz.getSuperclass(), fields);
}
return fields;
}
/***
* 驼峰命名转为下划线命名
*
* @param para
* 驼峰命名的字符串
*/
private static String humpToUnderline(String para) {
return StrUtil.toUnderlineCase(para);
}
@TableName("test_domain")
private static class TestDomain {
@NotNull(groups = MyEntity.Update.class)
@TableId(value = "user_id", type = IdType.AUTO)
private Long id;
@TableField(value = "dept_id")
private Long deptId;
@NotBlank
private String username;
@NotBlank
private String nickName;
}
public static void main(String[] args) {
QueryWrapper<TestDomain> query = new QueryWrapper<TestDomain>();
//query.or();
query.or(wrapper -> wrapper.eq("username", 1).or().eq("nickname", 2));
//query.like("a",1);
//query.or();
//query.like("b",2);
//query.and(wrapper->wrapper.eq("c",1));
query.eq("id", 1);
query.orderByDesc("id");
// query.apply("left join student t1 on t1.id = t1.id");
// query.last("left join student t1 on t1.id = t1.id");
System.err.println("getSqlSelect=================================");
System.err.println(query.getSqlSelect());
System.err.println("getSqlSegment=================================");
System.err.println(query.getSqlSegment());
System.err.println("getSqlComment=================================");
System.err.println(query.getSqlComment());
System.err.println("getSqlSet=================================");
System.err.println(query.getSqlSet());
System.err.println("getTargetSql=================================");
System.err.println(query.getTargetSql());
}
}
@@ -1,4 +1,4 @@
package cn.odboy.config.properties; package cn.odboy.properties;
import cn.odboy.constant.SystemConstant; import cn.odboy.constant.SystemConstant;
import lombok.Data; import lombok.Data;
@@ -1,4 +1,4 @@
package cn.odboy.config.properties; package cn.odboy.properties;
import lombok.Data; import lombok.Data;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
@@ -1,4 +1,4 @@
package cn.odboy.config; package cn.odboy.redis;
import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONFactory; import com.alibaba.fastjson2.JSONFactory;
@@ -39,7 +39,10 @@ public class RedisConfiguration extends CachingConfigurerSupport {
/** /**
* 自动识别json对象白名单配置(仅允许解析的包名,范围越小越安全) * 自动识别json对象白名单配置(仅允许解析的包名,范围越小越安全)
*/ */
private static final String[] WHITELIST_STR = {"cn.odboy"}; private static final String[] WHITELIST_STR = {
"org.springframework",
"cn.odboy.model",
};
/** /**
* 设置 redis 数据默认过期时间,默认2小时 * 设置 redis 数据默认过期时间,默认2小时
@@ -158,6 +161,9 @@ public class RedisConfiguration extends CachingConfigurerSupport {
this.clazz = clazz; this.clazz = clazz;
} }
/**
* 序列化
*/
@Override @Override
public byte[] serialize(T t) throws SerializationException { public byte[] serialize(T t) throws SerializationException {
if (t == null) { if (t == null) {
@@ -166,6 +172,9 @@ public class RedisConfiguration extends CachingConfigurerSupport {
return JSON.toJSONString(t, JSONWriter.Feature.WriteClassName).getBytes(StandardCharsets.UTF_8); return JSON.toJSONString(t, JSONWriter.Feature.WriteClassName).getBytes(StandardCharsets.UTF_8);
} }
/**
* 反序列化
*/
@Override @Override
public T deserialize(byte[] bytes) throws SerializationException { public T deserialize(byte[] bytes) throws SerializationException {
if (bytes == null || bytes.length == 0) { if (bytes == null || bytes.length == 0) {
@@ -1,4 +1,4 @@
package cn.odboy.config; package cn.odboy.redis;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import lombok.Data; import lombok.Data;
@@ -1,6 +1,6 @@
package cn.odboy.config.webConfig; package cn.odboy.server;
import cn.odboy.config.properties.FileProperties; import cn.odboy.properties.FileProperties;
import com.alibaba.fastjson2.JSONWriter; import com.alibaba.fastjson2.JSONWriter;
import com.alibaba.fastjson2.support.config.FastJsonConfig; import com.alibaba.fastjson2.support.config.FastJsonConfig;
import com.alibaba.fastjson2.support.spring.http.converter.FastJsonHttpMessageConverter; import com.alibaba.fastjson2.support.spring.http.converter.FastJsonHttpMessageConverter;
@@ -67,7 +67,18 @@ public class ConfigurerAdapter implements WebMvcConfigurer {
config.setDateFormat("yyyy-MM-dd HH:mm:ss"); config.setDateFormat("yyyy-MM-dd HH:mm:ss");
// 开启引用检测,枚举支持 // 开启引用检测,枚举支持
config.setWriterFeatures( config.setWriterFeatures(
// 是否输出值为null的字段
// SerializerFeature.WriteMapNullValue,
// 字段如果为null,输出为false,而非null
// JSONWriter.Feature.WriteNullBooleanAsFalse,
// 字段如果为null,输出为[],而非null
// JSONWriter.Feature.WriteNullListAsEmpty,
// 字符类型字段如果为null,输出为"",而非null
// JSONWriter.Feature.WriteNullStringAsEmpty,
// 太具体的数值会直接影响逻辑本身,所以不要这个
// SerializerFeature.WriteNullNumberAsZero,
JSONWriter.Feature.WriteEnumUsingToString, JSONWriter.Feature.WriteEnumUsingToString,
// SerializerFeature.DisableCircularReferenceDetect
JSONWriter.Feature.ReferenceDetection JSONWriter.Feature.ReferenceDetection
); );
fastJsonConverter.setFastJsonConfig(config); fastJsonConverter.setFastJsonConfig(config);
@@ -1,5 +1,7 @@
package cn.odboy.config.webConfig; package cn.odboy.server;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.servlet.MultipartConfigFactory; import org.springframework.boot.web.servlet.MultipartConfigFactory;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
@@ -8,20 +10,23 @@ import javax.servlet.MultipartConfigElement;
import java.io.File; import java.io.File;
@Slf4j
@Configuration @Configuration
public class MultipartConfig { public class MultipartConfig {
@Value("${spring.application.name}")
private String name;
/** /**
* 文件上传临时路径 * 文件上传临时路径
*/ */
@Bean @Bean
MultipartConfigElement multipartConfigElement() { public MultipartConfigElement multipartConfigElement() {
MultipartConfigFactory factory = new MultipartConfigFactory(); MultipartConfigFactory factory = new MultipartConfigFactory();
String location = System.getProperty("user.home") + "/.eladmin/file/tmp"; String location = System.getProperty("user.home") + "/." + name + "/tmp";
File tmpFile = new File(location); File tmpFile = new File(location);
if (!tmpFile.exists()) { if (!tmpFile.exists()) {
if (!tmpFile.mkdirs()) { if (!tmpFile.mkdirs()) {
System.out.println("create was not successful."); log.error("创建临时文件失败");
} }
} }
factory.setLocation(location); factory.setLocation(location);
@@ -1,4 +1,4 @@
package cn.odboy.config.webConfig; package cn.odboy.server;
import cn.odboy.util.AnonTagUtil; import cn.odboy.util.AnonTagUtil;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
@@ -64,8 +64,8 @@ public class SwaggerConfig {
private ApiInfo apiInfo() { private ApiInfo apiInfo() {
return new ApiInfoBuilder() return new ApiInfoBuilder()
.description("一个简单且易上手的 Spring boot 后台管理框架") .description("一个简单且易上手的 Spring boot 后台管理框架")
.title("ELADMIN 接口文档") .title("CuteJava 接口文档")
.version("1.6") .version("1.3.0")
.build(); .build();
} }
@@ -1,5 +1,6 @@
package cn.odboy.config; package cn.odboy.thread;
import com.alibaba.ttl.TtlRunnable;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
@@ -53,7 +54,7 @@ public class AsyncExecutor implements AsyncConfigurer {
@Override @Override
public Executor getAsyncExecutor() { public Executor getAsyncExecutor() {
// 自定义工厂 // 自定义工厂
ThreadFactory factory = r -> new Thread(r, "el-async-" + new AtomicInteger(1).getAndIncrement()); ThreadFactory factory = r -> new Thread(r, "default-async-" + new AtomicInteger(1).getAndIncrement());
// 自定义线程池 // 自定义线程池
return new ThreadPoolExecutor(corePoolSize, maxPoolSize, keepAliveSeconds, return new ThreadPoolExecutor(corePoolSize, maxPoolSize, keepAliveSeconds,
TimeUnit.SECONDS, new ArrayBlockingQueue<>(queueCapacity), factory, TimeUnit.SECONDS, new ArrayBlockingQueue<>(queueCapacity), factory,
@@ -63,18 +64,23 @@ public class AsyncExecutor implements AsyncConfigurer {
/** /**
* 自定义线程池,用法,注入到类中使用 * 自定义线程池,用法,注入到类中使用
* private ThreadPoolTaskExecutor taskExecutor; * private ThreadPoolTaskExecutor taskExecutor;
*
* @return ThreadPoolTaskExecutor
*/ */
@Bean("taskAsync") @Bean("taskAsync")
public ThreadPoolTaskExecutor taskAsync() { public ThreadPoolTaskExecutor taskAsync() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(2); executor.setCorePoolSize(AsyncExecutor.corePoolSize);
executor.setMaxPoolSize(4); executor.setMaxPoolSize(AsyncExecutor.maxPoolSize);
executor.setQueueCapacity(20); executor.setQueueCapacity(AsyncExecutor.queueCapacity);
executor.setKeepAliveSeconds(60); executor.setThreadNamePrefix("task-async-");
executor.setThreadNamePrefix("el-task-"); executor.setKeepAliveSeconds(AsyncExecutor.keepAliveSeconds);
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); // DiscardOldestPolicy,抛弃最早的任务,将新任务加入队列。
// AbortPolicy,拒绝执行新任务,并抛出异常。
// CallerRunsPolicy,交由调用者线程执行新任务,如果调用者线程已关闭,则抛弃任务。
// DiscardPolicy,直接抛弃新任务。
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy());
// 设置包装器
executor.setTaskDecorator(TtlRunnable::get);
executor.initialize();
return executor; return executor;
} }
} }
@@ -1,6 +1,6 @@
package cn.odboy.util; package cn.odboy.util;
import cn.odboy.annotation.rest.AnonymousAccess; import cn.odboy.annotation.AnonymousAccess;
import cn.odboy.constant.RequestMethodEnum; import cn.odboy.constant.RequestMethodEnum;
import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContext;
import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestMethod;
@@ -0,0 +1,49 @@
/*
* Copyright 2021-2025 Tian Jun
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.odboy.util;
import cn.hutool.core.codec.Base64Encoder;
import cn.hutool.core.util.IdUtil;
import java.nio.charset.StandardCharsets;
/**
* 加密令牌生成工具
*
* @author odboy
* @date 2022-11-16
*/
public class Base64SecretUtil {
private Base64SecretUtil() {
}
public static String build() {
// 128位uuid
return Base64Encoder.encode(getLongUuid(4).getBytes(StandardCharsets.UTF_8));
}
public static String getLongUuid(int bit) {
StringBuilder result = new StringBuilder();
for (int i = 0; i < bit; i++) {
result.append(IdUtil.simpleUUID());
}
return result.toString();
}
public static void main(String[] args) {
System.out.println(build());
}
}
@@ -0,0 +1,279 @@
/*
* Copyright 2021-2025 Tian Jun
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.odboy.util;
import cn.odboy.base.MyMetaOption;
import com.alibaba.fastjson2.JSON;
import com.google.common.base.Joiner;
import com.google.common.base.Splitter;
import com.google.common.collect.Lists;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
/**
* 集合工具
*
* @author odboy
* @date 2022-11-09
*/
public class CollUtil extends cn.hutool.core.collection.CollUtil {
/**
* 连接器
*/
private static final Joiner JOINER = Joiner.on(",").skipNulls();
/**
* 分割器
*/
private static final Splitter SPLITTER = Splitter.on(",").trimResults().omitEmptyStrings();
public static String join(Object[] parts) {
return JOINER.join(parts);
}
public static String join(Iterable<?> parts) {
return JOINER.join(parts);
}
public static String join(Iterator<?> parts) {
return JOINER.join(parts);
}
public static List<String> splitToList(String parts) {
return SPLITTER.splitToList(parts);
}
/**
* 分几份
*
* @param parts /
* @param size /
* @param <T> /
* @return /
*/
public static <T> List<List<T>> splitToSize(List<T> parts, int size) {
return Lists.partition(parts, size);
}
/**
* 一份几个
*
* @param parts /
* @param groupNum /
* @param <T> /
* @return /
*/
public static <T> List<List<T>> splitToSegment(List<T> parts, int groupNum) {
List<List<T>> result = new ArrayList<>(1);
int i = 0;
for (; i < parts.size() / groupNum; i++) {
result.add(parts.subList(i * groupNum, (i + 1) * groupNum));
}
if (parts.size() % groupNum != 0) {
result.add(parts.subList(i * groupNum, i * groupNum + parts.size() % groupNum));
}
return result;
}
private static <T, K> Predicate<T> distinctPredicate(Function<? super T, ? extends K> keyMapper) {
Map<Object, Boolean> map = new HashMap<>();
return (t) -> null == map.putIfAbsent(keyMapper.apply(t), true);
}
/**
* 流根据对象属性去重
* <p>
* 使用方式: list = CollUtil.streamDistinct(list, Object::getXXX)
*/
public static <T, K> List<T> streamDistinct(List<T> data, Function<? super T, ? extends K> keyMapper) {
return data.stream().filter(distinctPredicate(keyMapper)).collect(Collectors.toList());
}
/**
* 流根据对象属性自然排序
* <p>
* 使用方式: list = CollUtil.streamAscSort(list, Object::getXXX)
*
* @param data /
* @param keyExtractor /
* @param <T> /
* @param <U> /
* @return /
*/
public static <T, U extends Comparable<? super U>> List<T> streamAscSort(List<T> data, Function<? super T, ? extends U> keyExtractor) {
return data.stream().sorted(Comparator.comparing(keyExtractor)).collect(Collectors.toList());
}
/**
* 流根据对象属性倒转排序
* <p>
* 使用方式: list = CollUtil.streamDescSort(list, Object::getXXX)
*
* @param data /
* @param keyExtractor /
* @param <T> /
* @param <U> /
* @return /
*/
public static <T, U extends Comparable<? super U>> List<T> streamDescSort(List<T> data, Function<? super T, ? extends U> keyExtractor) {
return data.stream().sorted(Comparator.comparing(keyExtractor).reversed()).collect(Collectors.toList());
}
/**
* 流拆分对象为键值对
* <p>
* 使用方式: map = CollUtil.streamToMap(list, Object::getXXKey, Object::getXXValue)
*
* @param data /
* @param keyMapper /
* @param valueMapper /
* @param <T> /
* @param <K> /
* @param <U> /
* @return /
*/
public static <T, K, U> Map<K, U> streamToMap(List<T> data, Function<? super T, ? extends K> keyMapper, Function<? super T, ? extends U> valueMapper) {
// 根据key去重再并流
return streamDistinct(data, keyMapper).stream().collect(Collectors.toMap(keyMapper, valueMapper));
}
/**
* 流对List<Double>求和
* <p>
* 使用方式: total = CollUtil.streamDoubleAdd(doubleList)
*
* @param data /
* @return /
*/
public static Double streamDoubleAdd(List<Double> data) {
if (CollUtil.isNotEmpty(data)) {
return data.stream().filter(Objects::nonNull).reduce(Double::sum).orElse(0.0);
}
return 0.0;
}
/**
* 流对List<BigDecimal>求和
* <p>
* 使用方式: total = CollUtil.streamBigDecimalAdd(doubleList)
*
* @param data /
* @return /
*/
public static BigDecimal streamBigDecimalAdd(List<BigDecimal> data) {
if (CollUtil.isNotEmpty(data)) {
return data.stream().filter(Objects::nonNull).reduce(BigDecimal::add).orElse(BigDecimal.ZERO);
}
return BigDecimal.ZERO;
}
/**
* 流对List<Object>中的某一BigDecimal属性求和
* <p>
* 使用方式: total = CollUtil.streamBigDecimalAdd(list, XXX)
*
* @param data /
* @return /
*/
public static <T> BigDecimal streamBigDecimalAdd(List<T> data, String elementName) {
return data.stream().filter(Objects::nonNull).map(m -> {
// 反射, 取集合中各元素的某属性
BigDecimal that;
try {
Field field = m.getClass().getDeclaredField(elementName);
field.setAccessible(true);
that = (BigDecimal) field.get(m);
} catch (Exception e) {
// 忽略异常
that = BigDecimal.ZERO;
}
return that;
}).reduce(BigDecimal::add).orElse(BigDecimal.ZERO);
}
/**
* 流对List<BigDecimal>取最大值
* <p>
* 使用方式: max = CollUtil.streamBigDecimalMax(list)
*
* @param data /
* @return /
*/
public static BigDecimal streamBigDecimalMax(List<BigDecimal> data) {
return data.stream()
.filter(Objects::nonNull)
.reduce(BigDecimal::max)
.orElse(null);
}
/**
* 流对List<BigDecimal>取最小值
* <p>
* 使用方式: max = CollUtil.streamBigDecimalMin(list)
*
* @param data /
* @return /
*/
public static BigDecimal streamBigDecimalMin(List<BigDecimal> data) {
return data.stream()
.filter(Objects::nonNull)
.reduce(BigDecimal::min)
.orElse(null);
}
/**
* 流对List<BigDecimal>取平均值
* <p>
* 使用方式: avg = CollUtil.streamBigDecimalAvg(list)
*
* @param data /
* @return /
*/
public static BigDecimal streamBigDecimalAvg(List<BigDecimal> data) {
return data.stream()
.filter(Objects::nonNull)
.reduce(BigDecimal.ZERO, BigDecimal::add)
.divide(BigDecimal.valueOf(data.size()), 6, RoundingMode.FLOOR);
}
public static void main(String[] args) {
List<MyMetaOption> testData = new ArrayList<>();
MyMetaOption selectOption1 = MyMetaOption.builder().label("苹果").value("apple").build();
MyMetaOption selectOption2 = MyMetaOption.builder().label("苹果").value("apple").build();
MyMetaOption selectOption3 = MyMetaOption.builder().label("香蕉").value("banana").build();
MyMetaOption selectOption4 = MyMetaOption.builder().label("猫").value("cat").build();
testData.add(selectOption1);
testData.add(selectOption2);
testData.add(selectOption3);
testData.add(selectOption4);
List<MyMetaOption> selectOptions1 = CollUtil.streamAscSort(testData, MyMetaOption::getValue);
System.out.println(JSON.toJSONString(selectOptions1));
List<MyMetaOption> selectOptions2 = CollUtil.streamDescSort(testData, MyMetaOption::getValue);
System.out.println(JSON.toJSONString(selectOptions2));
List<MyMetaOption> selectOptions3 = CollUtil.streamDistinct(testData, MyMetaOption::getValue);
System.out.println(JSON.toJSONString(selectOptions3));
Map<String, String> selectMap1 = CollUtil.streamToMap(testData, MyMetaOption::getValue, MyMetaOption::getLabel);
System.out.println(JSON.toJSONString(selectMap1));
// 这只是一个示范
BigDecimal total1 = CollUtil.streamBigDecimalAdd(testData, "value");
System.out.println(total1);
}
}
@@ -0,0 +1,47 @@
/*
* Copyright 2021-2025 Tian Jun
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.odboy.util;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.TypeReference;
import java.util.List;
import java.util.Map;
/**
* Json工具
*
* @author odboy
* @date 2024-10-01
*/
public class JsonUtil {
public static <K, V> Map<K, V> toMap(String jsonStr, Class<K> kClass, Class<V> vClass) {
return JSON.parseObject(jsonStr, new TypeReference<Map<K, V>>() {
});
}
public static <V> List<V> toList(String jsonStr, Class<V> vClass) {
return JSON.parseObject(jsonStr, new TypeReference<List<V>>() {
});
}
public static void main(String[] args) {
String mapStr = "{\"key1\":\"value1\", \"key2\":\"value2\"}";
System.err.println(JsonUtil.toMap(mapStr, String.class, String.class));
String listStr = "[\"value1\", \"value2\"]";
System.err.println(JsonUtil.toList(listStr, String.class));
}
}
@@ -0,0 +1,68 @@
/*
* Copyright 2021-2025 Tian Jun
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.odboy.util;
import cn.hutool.core.date.DateTime;
import cn.odboy.base.MyEntity;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* List 工具
*
* @author odboy
* @date 2024-10-01
*/
public class ListUtil {
/**
* 根据对象T的属性去重
*
* @param items 对象T集合
* @param classifier 对象T属性表达式, 比如: User::getName
*/
public static <T, K> List<T> distinctByArgs(List<T> items, Function<? super T, ? extends K> classifier) {
return items.stream()
.collect(Collectors.groupingBy(classifier))
.values().stream()
.map(monitorItem -> monitorItem.iterator().next())
.collect(Collectors.toList());
}
/**
* list转map,保留新值 -> Map<String, User> userMap = items.stream().collect(Collectors.toMap(User::getName, user -> user)) <br>
* list转map,保留旧值 -> Map<String, User> userMap = users.stream().collect(Collectors.toMap(User::getName, user -> user, (existing, replacement) -> existing));
*/
public static void main(String[] args) {
List<MyEntity> entities = new ArrayList<>();
for (int i = 0; i < 50; i++) {
MyEntity entity = new MyEntity();
if (i % 2 == 0) {
entity.setCreateBy("odboy");
} else {
entity.setCreateBy("admin");
}
entity.setUpdateBy("admin");
entity.setCreateTime(DateTime.now().toTimestamp());
entity.setUpdateTime(DateTime.now().toTimestamp());
entities.add(entity);
}
List<MyEntity> entities1 = ListUtil.distinctByArgs(entities, MyEntity::getCreateBy);
System.err.println(entities1);
}
}
@@ -1,5 +1,6 @@
package cn.odboy.util; package cn.odboy.util;
import cn.odboy.base.PageResult;
import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.metadata.IPage;
import java.util.Collections; import java.util.Collections;
@@ -0,0 +1,105 @@
/*
* Copyright 2021-2025 Tian Jun
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.odboy.util;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.script.ScriptRuntimeException;
import org.springframework.stereotype.Component;
import javax.script.*;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/**
* 脚本工具
*
* @author odboy
* @date 2023-12-05
*/
@Component
public class ScriptUtil {
private static final String FUNCTION_TAG = "function";
private final ScriptEngine engine = new ScriptEngineManager().getEngineByName("JavaScript");
/**
* @param script 函数表达式
* @return 返回值
*/
public Object evalObj(String script, Object compareObj) {
try {
if (script.contains(FUNCTION_TAG)) {
throw new RuntimeException("script格式异常");
}
// 构建一个不同的脚本上下文
ScriptContext newContext = new SimpleScriptContext();
if (compareObj != null) {
Field[] fields = ReflectUtil.getFields(compareObj.getClass());
Map<String, Object> filedNameValueMap = new HashMap<>();
Arrays.stream(fields).parallel().forEach(f -> filedNameValueMap.put(f.getName(), ReflectUtil.getFieldValue(compareObj, f)));
Set<Map.Entry<String, Object>> entries = filedNameValueMap.entrySet();
long count = entries.stream().filter(f -> f.getValue() != null).count();
if (count == 0) {
throw new RuntimeException("比较对象中没有有效值");
}
Bindings engineScope = engine.createBindings();
entries.forEach(f -> {
// 在新的执行引擎作用域中添加与上面相同名称的变量
engineScope.put(f.getKey(), f.getValue());
});
newContext.setBindings(engineScope, ScriptContext.ENGINE_SCOPE);
}
if (script.contains(FUNCTION_TAG)) {
// 由ScriptEngines实现的接口, 其方法允许调用以前已执行的脚本中的过程
Invocable inv = (Invocable) engine;
// 调用全局函数, 并传入参数
inv.invokeFunction("hello", "测试");
}
// 执行脚本, 注意这里指定新的执行作用域上下文
return engine.eval(script, newContext);
} catch (ScriptException e) {
throw new ScriptRuntimeException(e);
} catch (NoSuchMethodException e) {
throw new ScriptRuntimeException(e);
}
}
/**
* @param script 函数表达式, 例如: function hello(name) { print('Hello, ' + name); }
* @param functionName 函数名称, 例如: "hello"
* @param args 函数参数, 例如: "小明"
* @return 返回值
*/
public Object evalFunction(String script, String functionName, Object... args) {
if (!script.contains(FUNCTION_TAG)) {
throw new RuntimeException("script格式异常");
}
try {
// 执行脚本
engine.eval(script);
// 由ScriptEngines实现的接口,其方法允许调用以前已执行的脚本中的过程。
Invocable inv = (Invocable) engine;
// 调用全局函数,并传入参数
return inv.invokeFunction(functionName, args);
} catch (ScriptException e) {
throw new ScriptRuntimeException(e);
} catch (NoSuchMethodException e) {
throw new ScriptRuntimeException(e);
}
}
}
@@ -4,6 +4,7 @@ import cn.hutool.core.collection.CollUtil;
import cn.hutool.jwt.JWT; import cn.hutool.jwt.JWT;
import cn.hutool.jwt.JWTUtil; import cn.hutool.jwt.JWTUtil;
import cn.odboy.constant.DataScopeEnum; import cn.odboy.constant.DataScopeEnum;
import cn.odboy.context.SpringBeanHolder;
import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray; import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject; import com.alibaba.fastjson2.JSONObject;
@@ -0,0 +1,187 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.odboy.util;
import cn.odboy.mybatis.constant.DataTypeEnum;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.google.common.collect.Lists;
import com.zaxxer.hikari.HikariDataSource;
import lombok.extern.slf4j.Slf4j;
import javax.sql.DataSource;
import java.io.BufferedReader;
import java.io.File;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.List;
/**
* @author /
*/
@Slf4j
public class SqlUtil {
/**
* 获取数据源
*
* @param jdbcUrl /
* @param userName /
* @param password /
* @return DataSource
*/
private static DataSource getDataSource(String jdbcUrl, String userName, String password) {
HikariDataSource druidDataSource = new HikariDataSource();
String className;
try {
className = DriverManager.getDriver(jdbcUrl.trim()).getClass().getName();
} catch (SQLException e) {
throw new RuntimeException("Get class name error: =" + jdbcUrl);
}
if (StringUtils.isEmpty(className)) {
DataTypeEnum dataTypeEnum = DataTypeEnum.urlOf(jdbcUrl);
if (null == dataTypeEnum) {
throw new RuntimeException("Not supported data type: jdbcUrl=" + jdbcUrl);
}
druidDataSource.setDriverClassName(dataTypeEnum.getDriver());
} else {
druidDataSource.setDriverClassName(className);
}
druidDataSource.setJdbcUrl(jdbcUrl);
druidDataSource.setUsername(userName);
druidDataSource.setPassword(password);
druidDataSource.setConnectionTimeout(3000);
return druidDataSource;
}
private static Connection getConnection(String jdbcUrl, String userName, String password) {
DataSource dataSource = getDataSource(jdbcUrl, userName, password);
Connection connection = null;
try {
connection = dataSource.getConnection();
} catch (Exception ignored) {
}
try {
int timeOut = 5;
if (null == connection || connection.isClosed() || !connection.isValid(timeOut)) {
log.info("connection is closed or invalid, retry get connection!");
connection = dataSource.getConnection();
}
} catch (Exception e) {
log.error("create connection error, jdbcUrl: {}", jdbcUrl);
throw new RuntimeException("create connection error, jdbcUrl: " + jdbcUrl);
} finally {
CloseUtil.close(connection);
}
return connection;
}
private static void releaseConnection(Connection connection) {
if (null != connection) {
try {
connection.close();
} catch (Exception e) {
log.error(e.getMessage(), e);
log.error("connection close error:" + e.getMessage());
}
}
}
public static boolean testConnection(String jdbcUrl, String userName, String password) {
Connection connection = null;
try {
connection = getConnection(jdbcUrl, userName, password);
if (null != connection) {
return true;
}
} catch (Exception e) {
log.info("Get connection failed:" + e.getMessage());
} finally {
releaseConnection(connection);
}
return false;
}
public static String executeFile(String jdbcUrl, String userName, String password, File sqlFile) {
Connection connection = getConnection(jdbcUrl, userName, password);
try {
batchExecute(connection, readSqlList(sqlFile));
} catch (Exception e) {
log.error("sql脚本执行发生异常:{}", e.getMessage());
return e.getMessage();
} finally {
releaseConnection(connection);
}
return "success";
}
/**
* 批量执行sql
*
* @param connection /
* @param sqlList /
*/
public static void batchExecute(Connection connection, List<String> sqlList) {
Statement st = null;
try {
st = connection.createStatement();
for (String sql : sqlList) {
if (sql.endsWith(";")) {
sql = sql.substring(0, sql.length() - 1);
}
st.addBatch(sql);
}
st.executeBatch();
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
CloseUtil.close(st);
}
}
/**
* 将文件中的sql语句以;为单位读取到列表中
*
* @param sqlFile /
* @return /
* @throws Exception e
*/
private static List<String> readSqlList(File sqlFile) throws Exception {
List<String> sqlList = Lists.newArrayList();
StringBuilder sb = new StringBuilder();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(
Files.newInputStream(sqlFile.toPath()), StandardCharsets.UTF_8))) {
String tmp;
while ((tmp = reader.readLine()) != null) {
log.info("line:{}", tmp);
if (tmp.endsWith(";")) {
sb.append(tmp);
sqlList.add(sb.toString());
sb.delete(0, sb.length());
} else {
sb.append(tmp);
}
}
if (!"".endsWith(sb.toString().trim())) {
sqlList.add(sb.toString());
}
}
return sqlList;
}
}
@@ -2,6 +2,7 @@ package cn.odboy.util;
import cn.hutool.http.useragent.UserAgent; import cn.hutool.http.useragent.UserAgent;
import cn.hutool.http.useragent.UserAgentUtil; import cn.hutool.http.useragent.UserAgentUtil;
import cn.odboy.context.SpringBeanHolder;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import net.dreamlu.mica.ip2region.core.Ip2regionSearcher; import net.dreamlu.mica.ip2region.core.Ip2regionSearcher;
import net.dreamlu.mica.ip2region.core.IpInfo; import net.dreamlu.mica.ip2region.core.IpInfo;
@@ -0,0 +1,43 @@
/*
* Copyright 2021-2025 Tian Jun
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.odboy.util;
import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.groups.Default;
import java.util.Set;
/**
* Bean验证工具
*
* @author odboy
* @date 2025-01-15
*/
public class ValidationUtil {
private static final Validator VALIDATOR = Validation.buildDefaultValidatorFactory().getValidator();
public static <T> void validate(T object) {
Set<ConstraintViolation<T>> violations = VALIDATOR.validate(object, Default.class);
if (!violations.isEmpty()) {
StringBuilder sb = new StringBuilder();
for (ConstraintViolation<T> violation : violations) {
sb.append(violation.getMessage()).append(", ");
}
throw new IllegalArgumentException(sb.toString());
}
}
}
@@ -1,4 +1,4 @@
package cn.odboy.config.webConfig; package cn.odboy.websocket;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
@@ -0,0 +1,33 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.odboy.websocket;
import lombok.Data;
/**
* @author ZhangHouYing
* @date 2019-08-10 9:55
*/
@Data
public class WebSocketMsg {
private String msg;
private WebSocketMsgTypeEnum msgType;
public WebSocketMsg(String msg, WebSocketMsgTypeEnum msgType) {
this.msg = msg;
this.msgType = msgType;
}
}
@@ -0,0 +1,39 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.odboy.websocket;
/**
* @author ZhangHouYing
* @date 2019-08-10 9:56
*/
public enum WebSocketMsgTypeEnum {
/**
* 连接
*/
CONNECT,
/**
* 关闭
*/
CLOSE,
/**
* 信息
*/
INFO,
/**
* 错误
*/
ERROR
}
@@ -0,0 +1,144 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.odboy.websocket;
import com.alibaba.fastjson2.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author ZhangHouYing
* @date 2019-08-10 15:46
*/
@ServerEndpoint("/webSocket/{sid}")
@Slf4j
@Component
public class WebSocketServer {
/**
* concurrent包的线程安全Map,用来存放每个客户端对应的MyWebSocket对象。(分布式必出问题)
*/
private static final Map<String, WebSocketServer> CLIENT = new ConcurrentHashMap<>();
/**
* 与某个客户端的连接会话,需要通过它来给客户端发送数据
*/
private Session session;
/**
* 接收sid
*/
private String sid = "";
/**
* 连接建立成功调用的方法
*/
@OnOpen
public void onOpen(Session session, @PathParam("sid") String sid) {
this.session = session;
// 如果存在就先删除一个,防止重复推送消息
CLIENT.remove(sid);
CLIENT.put(sid, this);
this.sid = sid;
}
/**
* 连接关闭调用的方法
*/
@OnClose
public void onClose() {
CLIENT.remove(this.sid);
}
/**
* 收到客户端消息后调用的方法
*
* @param message 客户端发送过来的消息
*/
@OnMessage
public void onMessage(String message, Session session) {
log.info("收到来{}的信息:{}", sid, message);
sendToAll(message);
}
/**
* 群发消息
*
* @param message /
*/
private static void sendToAll(String message) {
//
for (WebSocketServer item : CLIENT.values()) {
try {
item.sendMessage(message);
} catch (IOException e) {
log.error("发送消息给{}失败", item.sid, e);
}
}
}
@OnError
public void onError(Session session, Throwable error) {
log.error("发生错误");
error.printStackTrace();
}
/**
* 实现服务器主动推送
*/
private void sendMessage(String message) throws IOException {
this.session.getBasicRemote().sendText(message);
}
/**
* 群发自定义消息
*/
public static void sendInfo(WebSocketMsg webSocketMsg, @PathParam("sid") String sid) throws IOException {
String message = JSON.toJSONString(webSocketMsg);
log.info("推送消息到{},推送内容:{}", sid, message);
try {
if (sid == null) {
sendToAll(message);
} else {
CLIENT.get(sid).sendMessage(message);
}
} catch (IOException ignored) {
}
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
WebSocketServer that = (WebSocketServer) o;
return Objects.equals(session, that.session) &&
Objects.equals(sid, that.sid);
}
@Override
public int hashCode() {
return Objects.hash(session, sid);
}
}
@@ -0,0 +1,29 @@
package cn.odboy.websocket;
import io.undertow.server.DefaultByteBufferPool;
import io.undertow.websockets.jsr.WebSocketDeploymentInfo;
import org.springframework.boot.web.embedded.undertow.UndertowServletWebServerFactory;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.stereotype.Component;
/**
* 解决启动io.undertow.websockets.jsr UT026010: Buffer pool was not
* set on WebSocketDeploymentInfo, the default pool will be used的警告
*
* @date 2024-06-07
*/
@Component
public class WebSocketServerFactory implements WebServerFactoryCustomizer<UndertowServletWebServerFactory> {
@Override
public void customize(UndertowServletWebServerFactory factory) {
factory.addDeploymentInfoCustomizers(deploymentInfo -> {
WebSocketDeploymentInfo webSocketDeploymentInfo = new WebSocketDeploymentInfo();
webSocketDeploymentInfo.setBuffers(
new DefaultByteBufferPool(false, 1024)
// new DefaultByteBufferPool(false, 1024,20,4)
);
deploymentInfo.addServletContextAttribute("io.undertow.websockets.jsr.WebSocketDeploymentInfo", webSocketDeploymentInfo);
});
}
}
+24
View File
@@ -0,0 +1,24 @@
<?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"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>cutejava</artifactId>
<groupId>cn.odboy</groupId>
<version>1.3.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<properties>
<hutool.version>5.8.36</hutool.version>
</properties>
<artifactId>cutejava-domain</artifactId>
<name>模型模块</name>
<dependencies>
<dependency>
<groupId>cn.odboy</groupId>
<artifactId>cutejava-common</artifactId>
<version>1.3.0</version>
</dependency>
</dependencies>
</project>
@@ -1,6 +1,6 @@
package cn.odboy.domain; package cn.odboy.model.job.domain;
import cn.odboy.base.BaseEntity; import cn.odboy.base.MyEntity;
import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableId;
@@ -16,11 +16,11 @@ import javax.validation.constraints.NotNull;
@Getter @Getter
@Setter @Setter
@TableName("sys_quartz_job") @TableName("sys_quartz_job")
public class QuartzJob extends BaseEntity { public class QuartzJob extends MyEntity {
public static final String JOB_KEY = "JOB_KEY"; public static final String JOB_KEY = "JOB_KEY";
@TableId(value = "job_id", type = IdType.AUTO) @TableId(value = "id", type = IdType.AUTO)
@NotNull(groups = {Update.class}) @NotNull(groups = {Update.class})
private Long id; private Long id;
@@ -1,4 +1,4 @@
package cn.odboy.domain; package cn.odboy.model.job.domain;
import cn.odboy.base.MyObject; import cn.odboy.base.MyObject;
import com.baomidou.mybatisplus.annotation.*; import com.baomidou.mybatisplus.annotation.*;
@@ -15,7 +15,7 @@ public class QuartzLog extends MyObject {
@TableId(value = "log_id", type = IdType.AUTO) @TableId(value = "log_id", type = IdType.AUTO)
@ApiModelProperty(value = "ID", hidden = true) @ApiModelProperty(value = "ID", hidden = true)
private Long id; private Long logId;
@ApiModelProperty(value = "任务名称", hidden = true) @ApiModelProperty(value = "任务名称", hidden = true)
private String jobName; private String jobName;
@@ -1,4 +1,4 @@
package cn.odboy.domain.dto; package cn.odboy.model.job.dto;
import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModelProperty;
import lombok.Data; import lombok.Data;
@@ -1,6 +1,6 @@
package cn.odboy.modules.system.domain; package cn.odboy.model.system.domain;
import cn.odboy.base.BaseEntity; import cn.odboy.base.MyEntity;
import com.alibaba.fastjson2.annotation.JSONField; import com.alibaba.fastjson2.annotation.JSONField;
import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableField;
@@ -19,7 +19,7 @@ import java.util.Set;
@Getter @Getter
@Setter @Setter
@TableName("sys_dept") @TableName("sys_dept")
public class Dept extends BaseEntity { public class Dept extends MyEntity {
@NotNull(groups = Update.class) @NotNull(groups = Update.class)
@TableId(value = "dept_id", type = IdType.AUTO) @TableId(value = "dept_id", type = IdType.AUTO)
@@ -1,6 +1,6 @@
package cn.odboy.modules.system.domain; package cn.odboy.model.system.domain;
import cn.odboy.base.BaseEntity; import cn.odboy.base.MyEntity;
import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableName;
@@ -15,7 +15,7 @@ import javax.validation.constraints.NotNull;
@Getter @Getter
@Setter @Setter
@TableName("sys_dict") @TableName("sys_dict")
public class Dict extends BaseEntity { public class Dict extends MyEntity {
@NotNull(groups = Update.class) @NotNull(groups = Update.class)
@ApiModelProperty(value = "ID", hidden = true) @ApiModelProperty(value = "ID", hidden = true)
@@ -1,6 +1,6 @@
package cn.odboy.modules.system.domain; package cn.odboy.model.system.domain;
import cn.odboy.base.BaseEntity; import cn.odboy.base.MyEntity;
import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableId;
@@ -14,7 +14,7 @@ import javax.validation.constraints.NotNull;
@Getter @Getter
@Setter @Setter
@TableName("sys_dict_detail") @TableName("sys_dict_detail")
public class DictDetail extends BaseEntity { public class DictDetail extends MyEntity {
@NotNull(groups = Update.class) @NotNull(groups = Update.class)
@ApiModelProperty(value = "ID", hidden = true) @ApiModelProperty(value = "ID", hidden = true)
@@ -1,6 +1,6 @@
package cn.odboy.modules.system.domain; package cn.odboy.model.system.domain;
import cn.odboy.base.BaseEntity; import cn.odboy.base.MyEntity;
import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableName;
@@ -16,10 +16,10 @@ import java.util.Objects;
@Getter @Getter
@Setter @Setter
@TableName("sys_job") @TableName("sys_job")
public class Job extends BaseEntity { public class Job extends MyEntity {
@NotNull(groups = Update.class) @NotNull(groups = Update.class)
@TableId(value = "job_id", type = IdType.AUTO) @TableId(value = "id", type = IdType.AUTO)
@ApiModelProperty(value = "ID", hidden = true) @ApiModelProperty(value = "ID", hidden = true)
private Long id; private Long id;
@@ -1,6 +1,6 @@
package cn.odboy.modules.system.domain; package cn.odboy.model.system.domain;
import cn.odboy.base.BaseEntity; import cn.odboy.base.MyEntity;
import com.alibaba.fastjson2.annotation.JSONField; import com.alibaba.fastjson2.annotation.JSONField;
import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableField;
@@ -18,7 +18,7 @@ import java.util.Set;
@Getter @Getter
@Setter @Setter
@TableName("sys_menu") @TableName("sys_menu")
public class Menu extends BaseEntity { public class Menu extends MyEntity {
@NotNull(groups = {Update.class}) @NotNull(groups = {Update.class})
@TableId(value = "menu_id", type = IdType.AUTO) @TableId(value = "menu_id", type = IdType.AUTO)
@@ -1,6 +1,6 @@
package cn.odboy.modules.system.domain; package cn.odboy.model.system.domain;
import cn.odboy.base.BaseEntity; import cn.odboy.base.MyEntity;
import cn.odboy.constant.DataScopeEnum; import cn.odboy.constant.DataScopeEnum;
import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableField;
@@ -21,7 +21,7 @@ import java.util.Set;
@Getter @Getter
@Setter @Setter
@TableName("sys_role") @TableName("sys_role")
public class Role extends BaseEntity { public class Role extends MyEntity {
@NotNull(groups = {Update.class}) @NotNull(groups = {Update.class})
@TableId(value = "role_id", type = IdType.AUTO) @TableId(value = "role_id", type = IdType.AUTO)
@@ -1,6 +1,6 @@
package cn.odboy.modules.system.domain; package cn.odboy.model.system.domain;
import cn.odboy.base.BaseEntity; import cn.odboy.base.MyEntity;
import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableId;
@@ -19,7 +19,7 @@ import java.util.Set;
@Getter @Getter
@Setter @Setter
@TableName("sys_user") @TableName("sys_user")
public class User extends BaseEntity { public class User extends MyEntity {
@NotNull(groups = Update.class) @NotNull(groups = Update.class)
@TableId(value = "user_id", type = IdType.AUTO) @TableId(value = "user_id", type = IdType.AUTO)
@@ -1,4 +1,4 @@
package cn.odboy.modules.security.service.dto; package cn.odboy.model.system.dto;
import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModelProperty;
import lombok.Getter; import lombok.Getter;
@@ -1,4 +1,4 @@
package cn.odboy.modules.security.service.dto; package cn.odboy.model.system.dto;
import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
@@ -1,4 +1,4 @@
package cn.odboy.modules.system.domain.dto; package cn.odboy.model.system.dto;
import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModelProperty;
import lombok.Data; import lombok.Data;
@@ -1,4 +1,4 @@
package cn.odboy.modules.system.domain.dto; package cn.odboy.model.system.dto;
import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModelProperty;
import lombok.Data; import lombok.Data;
@@ -1,4 +1,4 @@
package cn.odboy.modules.system.domain.dto; package cn.odboy.model.system.dto;
import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModelProperty;
import lombok.Data; import lombok.Data;
@@ -1,4 +1,4 @@
package cn.odboy.modules.system.domain.dto; package cn.odboy.model.system.dto;
import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModelProperty;
import lombok.Data; import lombok.Data;
@@ -1,6 +1,6 @@
package cn.odboy.modules.security.service.dto; package cn.odboy.model.system.dto;
import cn.odboy.modules.system.domain.User; import cn.odboy.model.system.domain.User;
import com.alibaba.fastjson2.annotation.JSONField; import com.alibaba.fastjson2.annotation.JSONField;
import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
@@ -1,4 +1,4 @@
package cn.odboy.modules.system.domain.dto; package cn.odboy.model.system.dto;
import cn.odboy.base.MyObject; import cn.odboy.base.MyObject;
import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModelProperty;
@@ -1,4 +1,4 @@
package cn.odboy.modules.system.domain.dto; package cn.odboy.model.system.dto;
import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModelProperty;
import lombok.Data; import lombok.Data;
@@ -1,4 +1,4 @@
package cn.odboy.modules.system.domain.dto; package cn.odboy.model.system.dto;
import cn.odboy.base.MyObject; import cn.odboy.base.MyObject;
import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModelProperty;
@@ -1,4 +1,4 @@
package cn.odboy.modules.security.service.dto; package cn.odboy.model.system.dto;
import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
@@ -1,4 +1,4 @@
package cn.odboy.modules.system.domain.dto; package cn.odboy.model.system.dto;
import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModelProperty;
import lombok.Data; import lombok.Data;
@@ -1,4 +1,4 @@
package cn.odboy.modules.system.domain.dto; package cn.odboy.model.system.dto;
import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModelProperty;
import lombok.Data; import lombok.Data;
@@ -1,4 +1,4 @@
package cn.odboy.modules.system.domain.dto; package cn.odboy.model.system.dto;
import cn.odboy.base.MyObject; import cn.odboy.base.MyObject;
import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModelProperty;
@@ -1,4 +1,4 @@
package cn.odboy.domain; package cn.odboy.model.tools.domain;
import cn.odboy.base.MyObject; import cn.odboy.base.MyObject;
import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableId;
@@ -1,8 +1,8 @@
package cn.odboy.domain; package cn.odboy.model.tools.domain;
import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions; import cn.hutool.core.bean.copier.CopyOptions;
import cn.odboy.base.BaseEntity; import cn.odboy.base.MyEntity;
import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableName;
@@ -15,7 +15,7 @@ import lombok.Setter;
@Setter @Setter
@NoArgsConstructor @NoArgsConstructor
@TableName("tool_local_storage") @TableName("tool_local_storage")
public class LocalStorage extends BaseEntity { public class LocalStorage extends MyEntity {
@TableId(value = "storage_id", type = IdType.AUTO) @TableId(value = "storage_id", type = IdType.AUTO)
@ApiModelProperty(value = "ID", hidden = true) @ApiModelProperty(value = "ID", hidden = true)
@@ -1,4 +1,4 @@
package cn.odboy.domain; package cn.odboy.model.tools.domain;
import cn.odboy.base.MyObject; import cn.odboy.base.MyObject;
import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableId;
@@ -1,4 +1,4 @@
package cn.odboy.domain; package cn.odboy.model.tools.domain;
import cn.odboy.base.MyObject; import cn.odboy.base.MyObject;
import com.baomidou.mybatisplus.annotation.*; import com.baomidou.mybatisplus.annotation.*;
@@ -1,4 +1,4 @@
package cn.odboy.domain.dto; package cn.odboy.model.tools.dto;
import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
@@ -1,4 +1,4 @@
package cn.odboy.domain.dto; package cn.odboy.model.tools.dto;
import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModelProperty;
import lombok.Data; import lombok.Data;
@@ -1,4 +1,4 @@
package cn.odboy.domain.dto; package cn.odboy.model.tools.dto;
import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModelProperty;
import lombok.Data; import lombok.Data;
@@ -1,7 +1,7 @@
package cn.odboy.config; package cn.odboy.config;
import cn.odboy.mapper.QuartzJobMapper; import cn.odboy.mapper.QuartzJobMapper;
import cn.odboy.domain.QuartzJob; import cn.odboy.model.job.domain.QuartzJob;
import cn.odboy.util.QuartzManage; import cn.odboy.util.QuartzManage;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.slf4j.Logger; import org.slf4j.Logger;
@@ -1,7 +1,7 @@
package cn.odboy.mapper; package cn.odboy.mapper;
import cn.odboy.domain.dto.QuartzJobQueryCriteria; import cn.odboy.model.job.domain.QuartzJob;
import cn.odboy.domain.QuartzJob; import cn.odboy.model.job.dto.QuartzJobQueryCriteria;
import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
@@ -1,7 +1,7 @@
package cn.odboy.mapper; package cn.odboy.mapper;
import cn.odboy.domain.dto.QuartzJobQueryCriteria; import cn.odboy.model.job.domain.QuartzLog;
import cn.odboy.domain.QuartzLog; import cn.odboy.model.job.dto.QuartzJobQueryCriteria;
import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
@@ -1,12 +1,12 @@
package cn.odboy.rest; package cn.odboy.rest;
import cn.odboy.domain.QuartzJob; import cn.odboy.base.PageResult;
import cn.odboy.domain.QuartzLog;
import cn.odboy.domain.dto.QuartzJobQueryCriteria;
import cn.odboy.exception.BadRequestException; import cn.odboy.exception.BadRequestException;
import cn.odboy.model.job.domain.QuartzJob;
import cn.odboy.model.job.domain.QuartzLog;
import cn.odboy.model.job.dto.QuartzJobQueryCriteria;
import cn.odboy.service.QuartzJobService; import cn.odboy.service.QuartzJobService;
import cn.odboy.util.PageResult; import cn.odboy.context.SpringBeanHolder;
import cn.odboy.util.SpringBeanHolder;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
@@ -1,9 +1,9 @@
package cn.odboy.service; package cn.odboy.service;
import cn.odboy.domain.dto.QuartzJobQueryCriteria; import cn.odboy.base.PageResult;
import cn.odboy.domain.QuartzJob; import cn.odboy.model.job.domain.QuartzJob;
import cn.odboy.domain.QuartzLog; import cn.odboy.model.job.domain.QuartzLog;
import cn.odboy.util.PageResult; import cn.odboy.model.job.dto.QuartzJobQueryCriteria;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService; import com.baomidou.mybatisplus.extension.service.IService;
@@ -2,12 +2,13 @@ package cn.odboy.service.impl;
import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import cn.odboy.domain.dto.QuartzJobQueryCriteria; import cn.odboy.base.PageResult;
import cn.odboy.exception.BadRequestException; import cn.odboy.exception.BadRequestException;
import cn.odboy.mapper.QuartzJobMapper; import cn.odboy.mapper.QuartzJobMapper;
import cn.odboy.mapper.QuartzLogMapper; import cn.odboy.mapper.QuartzLogMapper;
import cn.odboy.domain.QuartzJob; import cn.odboy.model.job.domain.QuartzJob;
import cn.odboy.domain.QuartzLog; import cn.odboy.model.job.domain.QuartzLog;
import cn.odboy.model.job.dto.QuartzJobQueryCriteria;
import cn.odboy.service.QuartzJobService; import cn.odboy.service.QuartzJobService;
import cn.odboy.util.*; import cn.odboy.util.*;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
@@ -4,16 +4,14 @@ import cn.hutool.extra.template.Template;
import cn.hutool.extra.template.TemplateConfig; import cn.hutool.extra.template.TemplateConfig;
import cn.hutool.extra.template.TemplateEngine; import cn.hutool.extra.template.TemplateEngine;
import cn.hutool.extra.template.TemplateUtil; import cn.hutool.extra.template.TemplateUtil;
import cn.odboy.domain.dto.EmailDto; import cn.odboy.context.SpringBeanHolder;
import cn.odboy.exception.util.ThrowableUtil;
import cn.odboy.mapper.QuartzLogMapper; import cn.odboy.mapper.QuartzLogMapper;
import cn.odboy.domain.QuartzJob; import cn.odboy.model.job.domain.QuartzJob;
import cn.odboy.domain.QuartzLog; import cn.odboy.model.job.domain.QuartzLog;
import cn.odboy.service.QuartzJobService; import cn.odboy.model.tools.dto.EmailDto;
import cn.odboy.service.EmailService; import cn.odboy.service.EmailService;
import cn.odboy.util.RedisUtil; import cn.odboy.service.QuartzJobService;
import cn.odboy.util.SpringBeanHolder;
import cn.odboy.util.StringUtil;
import cn.odboy.util.ThrowableUtil;
import org.quartz.JobExecutionContext; import org.quartz.JobExecutionContext;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@@ -27,9 +25,7 @@ import java.util.Map;
import java.util.concurrent.Future; import java.util.concurrent.Future;
public class ExecutionJob extends QuartzJobBean { public class ExecutionJob extends QuartzJobBean {
private final Logger logger = LoggerFactory.getLogger(this.getClass()); private final Logger logger = LoggerFactory.getLogger(this.getClass());
// 此处仅供参考,可根据任务执行情况自定义线程池参数 // 此处仅供参考,可根据任务执行情况自定义线程池参数
private final ThreadPoolTaskExecutor executor = SpringBeanHolder.getBean("taskAsync"); private final ThreadPoolTaskExecutor executor = SpringBeanHolder.getBean("taskAsync");
@@ -1,7 +1,7 @@
package cn.odboy.util; package cn.odboy.util;
import cn.odboy.exception.BadRequestException; import cn.odboy.exception.BadRequestException;
import cn.odboy.domain.QuartzJob; import cn.odboy.model.job.domain.QuartzJob;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.quartz.*; import org.quartz.*;
import org.quartz.impl.triggers.CronTriggerImpl; import org.quartz.impl.triggers.CronTriggerImpl;
@@ -10,8 +10,6 @@ import org.springframework.stereotype.Component;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.util.Date; import java.util.Date;
import static org.quartz.TriggerBuilder.newTrigger;
@Slf4j @Slf4j
@Component @Component
public class QuartzManage { public class QuartzManage {
@@ -1,6 +1,6 @@
package cn.odboy.util; package cn.odboy.util;
import cn.odboy.util.SpringBeanHolder; import cn.odboy.context.SpringBeanHolder;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.springframework.util.ReflectionUtils; import org.springframework.util.ReflectionUtils;

Some files were not shown because too many files have changed in this diff Show More