fix: 码全代码添加

This commit is contained in:
2024-10-11 15:56:51 +08:00
parent 9a853f40c2
commit 7776e95902
907 changed files with 81296 additions and 324 deletions

View File

@@ -0,0 +1,38 @@
target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**/target/
!**/src/test/**/target/
### IntelliJ IDEA ###
.idea/modules.xml
.idea/jarRepositories.xml
.idea/compiler.xml
.idea/libraries/
*.iws
*.iml
*.ipr
### Eclipse ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
build/
!**/src/main/**/build/
!**/src/test/**/build/
### VS Code ###
.vscode/
### Mac OS ###
.DS_Store

View File

@@ -0,0 +1,84 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright (c) 2023 codvision.com All Rights Reserved.
-->
<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>
<groupId>com.codvision</groupId>
<artifactId>cvbp-public</artifactId>
<version>1.0.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cvbp-web-core</artifactId>
<packaging>jar</packaging>
<version>1.0.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>com.codvision</groupId>
<artifactId>cvbp-common-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<!-- 移除内嵌 tomcat -->
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-juli</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-undertow</artifactId>
</dependency>
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
</dependency>
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
</dependency>
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>swagger-bootstrap-ui</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,15 @@
package com.codvision.webcore.annotation;
import java.lang.annotation.*;
/**
* API接口参数加解密注解
* @author hxl
*/
@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ApiSecret {
boolean ignore() default false;
}

View File

@@ -0,0 +1,27 @@
/*
* Copyright (c) 2023 codvision.com All Rights Reserved.
*/
package com.codvision.webcore.annotation;
import com.codvision.commoncore.enums.SqlOperator;
import java.lang.annotation.*;
/**
* 查询条件
*
* @author lingee
* @date 2023/7/20
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface QueryCondition {
SqlOperator condition() default SqlOperator.EQ;
String column() default "";
String property() default "";
}

View File

@@ -0,0 +1,62 @@
package com.codvision.webcore.bean;
import com.baomidou.mybatisplus.annotation.*;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.util.Date;
/**
* 数据库基础实体类
*
* @author lingee
* @since 2023/7/20
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public abstract class BaseEntity implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(value = "id", type = IdType.AUTO)
@ApiModelProperty(value = "唯一标识")
private Long id;
@TableField(fill = FieldFill.INSERT)
@ApiModelProperty(value = "创建者", hidden = true)
private Long createBy;
@TableField(fill = FieldFill.INSERT)
@ApiModelProperty(value = "创建者名称", hidden = true)
private String createByName;
//@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
//@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@TableField(fill = FieldFill.INSERT)
@ApiModelProperty(value = "创建时间")
private Date createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
@ApiModelProperty(value = "更新者", hidden = true)
private Long updateBy;
@TableField(fill = FieldFill.INSERT_UPDATE)
@ApiModelProperty(value = "更新者名称", hidden = true)
private String updateByName;
//@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
//@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@TableField(fill = FieldFill.INSERT_UPDATE)
@ApiModelProperty(value = "更新时间")
private Date updateTime;
@TableField(fill = FieldFill.INSERT)
@ApiModelProperty(value = "删除标志 true/false 删除/未删除", hidden = true)
private Boolean deleteFlag;
}

View File

@@ -0,0 +1,67 @@
/*
* Copyright (c) 2023 codvision.com All Rights Reserved.
*/
package com.codvision.webcore.bean;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
import java.io.Serializable;
import java.util.Date;
/**
* 完整基础实体类
*
* @author lingee
* @since 2024/4/28
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class BasicEntity implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(value = "id", type = IdType.AUTO)
@ApiModelProperty(value = "唯一标识")
private Integer id;
@TableField(fill = FieldFill.INSERT)
@ApiModelProperty(value = "创建时间")
private Date createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
@ApiModelProperty(value = "更新时间")
private Date updateTime;
@Override
public int hashCode() {
if (this.getId() == null) {
return 0;
}
return this.getId().hashCode();
}
/**
* 读取数据库数据id相等等情况下默认两对象相等
*/
@Override
public boolean equals(Object obj) {
if (obj instanceof BasicEntity) {
if (null == this.getId()) {
return false;
}
return this.getId().equals(((BasicEntity) obj).getId());
}
return false;
}
}

View File

@@ -0,0 +1,43 @@
/*
* Copyright (c) 2023 codvision.com All Rights Reserved.
*/
package com.codvision.webcore.bean;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
/**
* 完整基础实体类
* @author lingee
* @since 2024/4/28
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class FullBasicEntity extends LogicDeletionEntity {
private static final long serialVersionUID = 1L;
@TableField(fill = FieldFill.INSERT)
@ApiModelProperty(value = "创建者", hidden = true)
private Long createBy;
@TableField(fill = FieldFill.INSERT)
@ApiModelProperty(value = "创建者名称", hidden = true)
private String createByName;
@TableField(fill = FieldFill.INSERT_UPDATE)
@ApiModelProperty(value = "更新者", hidden = true)
private Long updateBy;
@TableField(fill = FieldFill.INSERT_UPDATE)
@ApiModelProperty(value = "更新者名称", hidden = true)
private String updateByName;
}

View File

@@ -0,0 +1,34 @@
/*
* Copyright (c) 2023 codvision.com All Rights Reserved.
*/
package com.codvision.webcore.bean;
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.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
/**
* 包含逻辑删除基础实体
*
* @author lingee
* @since 2024/4/28
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class LogicDeletionEntity extends BasicEntity {
private static final long serialVersionUID = 1L;
@TableField(fill = FieldFill.INSERT)
@TableLogic
@ApiModelProperty(value = "删除标记,1:已删除,0:正常", hidden = true)
private Integer deleteFlag;
}

View File

@@ -0,0 +1,85 @@
/*
* Copyright (c) 2023 codvision.com All Rights Reserved.
*/
package com.codvision.webcore.bean;
import cn.hutool.core.text.CharSequenceUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.codvision.webcore.util.PageUtil;
import com.fasterxml.jackson.annotation.JsonIgnore;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable;
/**
* 查询参数
*
* @author lingee
* @date 2023/7/20
*/
@Data
@ApiModel(value = "QueryPage", description = "分页查询参数")
public class QueryPage<T> implements Serializable {
private static final long serialVersionUID = 1L;
@ApiModelProperty(value = "查询条件")
private T condition;
@ApiModelProperty(value = "分页对象", hidden = true)
private IPage<T> page;
@ApiModelProperty(value = "页号")
private Integer pageNumber = 1;
@ApiModelProperty(value = "页面大小")
private Integer pageSize = 10;
@ApiModelProperty(value = "排序字段")
private String sort;
@ApiModelProperty(value = "排序方式 asc/desc")
private String order;
@ApiModelProperty(value = "需要驼峰转换蛇形", notes = "一般不做处理,如果数据库中就是蛇形,则这块需要处理。")
private Boolean notConvert;
public QueryPage() {
}
public QueryPage(Integer pageNumber, Integer pageSize) {
this.pageNumber = pageNumber;
this.pageSize = pageSize;
}
public QueryPage(T condition, Integer pageNumber, Integer pageSize) {
this.condition = condition;
this.pageNumber = pageNumber;
this.pageSize = pageSize;
}
public IPage<T> getPage() {
return PageUtil.initPage(this);
}
@JsonIgnore
public QueryWrapper<T> getWrapper() {
return PageUtil.initWrapper(condition);
}
public String getSort() {
if (CharSequenceUtil.isNotEmpty(sort)) {
if (notConvert == null || Boolean.FALSE.equals(notConvert)) {
return StringUtils.camelToUnderline(sort);
} else {
return sort;
}
}
return sort;
}
}

View File

@@ -0,0 +1,177 @@
package com.codvision.webcore.config;
import com.codvision.commoncore.common.ResponseEntity;
import com.codvision.commoncore.exception.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.validation.BindException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.multipart.MaxUploadSizeExceededException;
import org.springframework.web.multipart.MultipartException;
import java.util.Arrays;
import java.util.Objects;
import static org.springframework.http.HttpStatus.*;
/**
* @Author huxb
* @description: 全局异常捕获
* @create 2022/11/22 10:30
*/
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {
@Autowired
private Environment environment;
/**
* LimitException
*
* @param e the e
* @return R
*/
@ExceptionHandler(LimitException.class)
@ResponseStatus(TOO_MANY_REQUESTS)
public ResponseEntity<String> handleLimitException(LimitException e) {
ResponseEntity<String> responseEntity = new ResponseEntity<>();
log.error("接口限流ex={}", e.getMessage());
return responseEntity.error(429, e.getMessage());
}
/**
* IdempotentException
*
* @param e the e
* @return R
*/
@ExceptionHandler(IdempotentException.class)
@ResponseStatus(TOO_MANY_REQUESTS)
public ResponseEntity<String> handleIdempotentException(IdempotentException e) {
ResponseEntity<String> responseEntity = new ResponseEntity<>();
log.error("请求频繁异常ex={}", e.getMessage());
return responseEntity.error(429, e.getMessage());
}
/**
* Validation Exception
*
* @param ex
* @return
*/
@ResponseStatus(BAD_REQUEST)
@ExceptionHandler(BindException.class)
public ResponseEntity<Object> handleBodyValidException(BindException ex) {
String errorMsg = Objects.requireNonNull(ex.getBindingResult().getFieldError()).getDefaultMessage();
log.error(errorMsg);
return new ResponseEntity<>().error(30002, errorMsg);
}
/**
* Business Exception
*
* @param ex
* @return
*/
@ExceptionHandler(BusinessException.class)
@ResponseStatus(INTERNAL_SERVER_ERROR)
public ResponseEntity<Object> businessException(BusinessException ex) {
log.error(ex.getMessage(), ex);
if (null == ex.getCode() && null != ex.getMessage()) {
return new ResponseEntity<>().error(10000, ex.getMessage());
}
if (null == ex.getMessage() && null != ex.getCode()) {
return new ResponseEntity<>().error(ex.getCode());
}
return new ResponseEntity<>().error(ex.getCode(), ex.getMessage());
}
/**
* File Upload Exception
*
* @param ex
* @return
*/
@ResponseStatus(INTERNAL_SERVER_ERROR)
@ExceptionHandler(MultipartException.class)
public ResponseEntity<Object> fileUploadException(Exception ex) {
log.error(ex.getMessage(), ex);
if (ex instanceof MaxUploadSizeExceededException) {
return new ResponseEntity<>().error(50002);
}
return new ResponseEntity<>().error(50003);
}
/**
* Shiro AuthorizationException
*
* @param ex
* @return
*/
@ResponseStatus(UNAUTHORIZED)
@ExceptionHandler(AuthException.class)
public ResponseEntity<Object> authorizationException(AuthException ex) {
log.error(ex.getMessage(), ex);
if (null != ex.getCode() && null != ex.getMessage()) {
return new ResponseEntity<>().error(ex.getCode(), ex.getMessage());
}
if (null == ex.getCode() && null != ex.getMessage()) {
return new ResponseEntity<>().error(10002, ex.getMessage());
}
if (null == ex.getMessage() && null != ex.getCode()) {
return new ResponseEntity<>().error(ex.getCode());
}
return new ResponseEntity<>().error(10002);
}
@ResponseStatus(FORBIDDEN)
@ExceptionHandler(PermissionException.class)
public ResponseEntity<Object> permissionException(PermissionException ex) {
log.error(ex.getMessage(), ex);
if (null == ex.getCode()) {
return new ResponseEntity<>().error(20001, ex.getMessage());
}
if (null == ex.getMessage()) {
return new ResponseEntity<>().error(ex.getCode());
}
return new ResponseEntity<>().error(20001);
}
/**
* Shiro AuthorizationException
*
* @param ex
* @return
*/
@ResponseStatus(BAD_REQUEST)
@ExceptionHandler(IllegalArgumentException.class)
public ResponseEntity<Object> illegalArgumentException(Exception ex) {
log.error(ex.getMessage(), ex);
return new ResponseEntity<>().error(30002, ex.getMessage());
}
/**
* RuntimeException
*
* @param ex
* @return
*/
@ResponseStatus(INTERNAL_SERVER_ERROR)
@ExceptionHandler(RuntimeException.class)
public ResponseEntity<Object> runtimeException(RuntimeException ex) {
log.error(ex.getMessage(), ex);
if (Arrays.stream(environment.getActiveProfiles()).filter(item -> item.equals("dev")).count() > 0) {
return new ResponseEntity<>().error(990000).data(ex.getMessage());
}
return new ResponseEntity<>().error(990000);
}
}

View File

@@ -0,0 +1,43 @@
/*
* Copyright (c) 2023 codvision.com All Rights Reserved.
*/
package com.codvision.webcore.config;
import com.baomidou.mybatisplus.core.incrementer.IKeyGenerator;
import com.baomidou.mybatisplus.extension.incrementer.H2KeyGenerator;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.codvision.webcore.interceptor.PlatformPaginationInnerInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* mybatis plus 统一配置
*
* @author lingee
* @date 2023-7-13
*/
@Configuration
@MapperScan("com.codvision.**.mapper")
public class MybatisAutoConfiguration {
/**
* 分页插件
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PlatformPaginationInnerInterceptor());
return interceptor;
}
/**
* 主键策略插件
*/
@Bean
public IKeyGenerator keyGenerator() {
return new H2KeyGenerator();
}
}

View File

@@ -0,0 +1,74 @@
/*
* Copyright (c) 2023 codvision.com All Rights Reserved.
*/
package com.codvision.webcore.config;
import com.fasterxml.jackson.databind.SerializationFeature;
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
/**
* web核心配置
*
* @author lingee
* @date 2023/7/21
*/
@Configuration
@ComponentScan("com.codvision.webcore")
@PropertySource(value = {"classpath:web-core.properties", "file:web-core.properties"}, ignoreResourceNotFound = true)
public class WebCoreConfig {
/**
* 序列化配置
*
* @return jackson配置
*/
@Bean
public Jackson2ObjectMapperBuilderCustomizer customizer() {
//final SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return builder -> {
//builder.featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
// .locale(Locale.CHINA)
// .timeZone(TimeZone.getTimeZone("GMT+8"));
//// 序列化
//builder.serializerByType(Date.class, new DateSerializer(false, simpleDateFormat));
//// 反序列化
//builder.deserializerByType(Date.class,
// new DateDeserializers.DateDeserializer(DateDeserializers.DateDeserializer.instance,
// simpleDateFormat, "yyyy-MM-dd HH:mm:ss"));
builder.featuresToEnable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING);
// 属性为空的不序列化
// builder.serializationInclusion(JsonInclude.Include.NON_NULL);
//把java.util.date 序列化为long
//builder.featuresToEnable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
builder.simpleDateFormat("yyyy-MM-dd HH:mm:ss");
};
}
@Bean
public CorsFilter corsFilter () {
CorsConfiguration configuration = new CorsConfiguration();
// 放行所有原始域
configuration.addAllowedOriginPattern("*");
// 设置跨域访问可以携带cookie
configuration.setAllowCredentials(Boolean.TRUE);
// 放行哪些请求方式,*代表所有
configuration.addAllowedMethod("*");
// 允许携带任何头信息
configuration.addAllowedHeader("*");
// 预检请求的有效期,单位为秒。
configuration.setMaxAge(3600L);
// 初始化cors配置源对象
UrlBasedCorsConfigurationSource configurationSource = new UrlBasedCorsConfigurationSource();
configurationSource.registerCorsConfiguration("/**", configuration);
return new CorsFilter(configurationSource);
}
}

View File

@@ -0,0 +1,39 @@
package com.codvision.webcore.config.encrypt;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* @author hxl
*/
@Data
@Component
@ConfigurationProperties(ApiSecretProperties.PREFIX)
public class ApiSecretProperties {
/**
* 前缀
*/
public static final String PREFIX = "security.api.encrypt";
/**
* 固定参数名称
*/
public static final String PARAM_NAME = "encryption";
/**
* 是否启用标志默认false
*/
private boolean enabled = false;
/**
* 是否全局加解密默认false
*/
private boolean globalEnabled = false;
/**
* 秘钥
*/
private String secretKey;
}

View File

@@ -0,0 +1,52 @@
package com.codvision.webcore.config.encrypt;
import com.codvision.webcore.annotation.ApiSecret;
import org.springframework.core.MethodParameter;
import java.util.HashSet;
import java.util.Set;
/**
* @author hxl
*/
public class ApiSecretSupports {
private static final Set<String> IGNORES = new HashSet<>();
static {
IGNORES.add("com.anji.captcha.controller.CaptchaController");
IGNORES.add("springfox.documentation.swagger.web.ApiResourceController");
IGNORES.add("springfox.documentation.swagger2.web.Swagger2Controller");
IGNORES.add("org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController");
}
public static boolean supports(MethodParameter parameter, ApiSecretProperties properties) {
if (IGNORES.contains(parameter.getDeclaringClass().getName())) {
return false;
}
return supports(parameter, properties.isGlobalEnabled());
}
private static boolean supports(MethodParameter parameter, boolean isGlobalEnabled) {
ApiSecret cApiSecret = parameter.getContainingClass().getAnnotation(ApiSecret.class);
if (cApiSecret == null) {
ApiSecret apiSecret = parameter.getMethodAnnotation(ApiSecret.class);
if (apiSecret == null) {
return isGlobalEnabled;
}
return !apiSecret.ignore();
}
if (cApiSecret.ignore()) {
return false;
}
ApiSecret apiSecret = parameter.getMethodAnnotation(ApiSecret.class);
if (apiSecret == null) {
return true;
}
return !apiSecret.ignore();
}
}

View File

@@ -0,0 +1,92 @@
package com.codvision.webcore.config.encrypt.advice;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.Mode;
import cn.hutool.crypto.Padding;
import cn.hutool.crypto.symmetric.AES;
import com.codvision.commoncore.exception.BusinessException;
import com.codvision.webcore.config.encrypt.ApiSecretProperties;
import com.codvision.webcore.config.encrypt.ApiSecretSupports;
import com.codvision.webcore.config.encrypt.bean.ApiSecretHttpInputMessage;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.lang.Nullable;
import org.springframework.util.StreamUtils;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.RequestBodyAdvice;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.lang.reflect.Type;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Map;
/**
* 请求数据解密处理
* 仅对使用{@link org.springframework.web.bind.annotation.RequestBody}进行标记的参数生效
*
* @author hxl
*/
@Slf4j
@ControllerAdvice
@RequiredArgsConstructor
@ConditionalOnProperty(value = ApiSecretProperties.PREFIX + ".enabled", havingValue = "true")
@ConditionalOnExpression("!'${security.api.encrypt.secret-key}'.isEmpty()")
public class ApiSecretRequestBodyAdvice implements RequestBodyAdvice {
private final ObjectMapper objectMapper;
private final ApiSecretProperties properties;
@Override
public boolean supports(MethodParameter methodParameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
return ApiSecretSupports.supports(methodParameter, properties);
}
@Override
@SneakyThrows
@SuppressWarnings("unchecked")
public HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
InputStream messageBody = inputMessage.getBody();
byte[] bodyByteArray = StreamUtils.copyToByteArray(messageBody);
Map<String, Object> dataMap = objectMapper.readValue(bodyByteArray, Map.class);
String content = (String) dataMap.get(ApiSecretProperties.PARAM_NAME);
if (StringUtils.isBlank(content)) {
throw new BusinessException(30001, "API接口加解密场景下encryption参数要求非空");
}
AES aes = new AES(Mode.CBC, Padding.ZeroPadding, new SecretKeySpec(properties.getSecretKey().getBytes(), "AES"),
new IvParameterSpec(properties.getSecretKey().getBytes()));
byte[] decryptedBody;
try {
decryptedBody = aes.decrypt(StrUtil.str(content.getBytes(StandardCharsets.UTF_8), Charset.defaultCharset()));
} catch (Exception e) {
log.error(e.getMessage());
throw new BusinessException(30001, "请检查encryption参数值是否已加密传输");
}
InputStream inputStream = new ByteArrayInputStream(decryptedBody);
return new ApiSecretHttpInputMessage(inputStream, inputMessage.getHeaders());
}
@Override
public Object afterBodyRead(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
return body;
}
@Override
public Object handleEmptyBody(@Nullable Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
return body;
}
}

View File

@@ -0,0 +1,58 @@
package com.codvision.webcore.config.encrypt.advice;
import cn.hutool.crypto.Mode;
import cn.hutool.crypto.Padding;
import cn.hutool.crypto.symmetric.AES;
import com.codvision.commoncore.common.ResponseEntity;
import com.codvision.webcore.config.encrypt.ApiSecretProperties;
import com.codvision.webcore.config.encrypt.ApiSecretSupports;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.lang.Nullable;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
/**
* 响应数据加密处理
* 仅对使用{@link org.springframework.web.bind.annotation.ResponseBody}进行标记的方法生效
*
* @author hxl
*/
@ControllerAdvice
@RequiredArgsConstructor
@ConditionalOnProperty(value = ApiSecretProperties.PREFIX + ".enabled", havingValue = "true")
@ConditionalOnExpression("!'${security.api.encrypt.secret-key}'.isEmpty()")
public class ApiSecretResponseBodyAdvice implements ResponseBodyAdvice<ResponseEntity<Object>> {
private final ObjectMapper objectMapper;
private final ApiSecretProperties properties;
@Override
public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
return ApiSecretSupports.supports(returnType, properties);
}
@Override
@SneakyThrows
public ResponseEntity<Object> beforeBodyWrite(@Nullable ResponseEntity<Object> responseEntity, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
if (responseEntity == null || responseEntity.getData() == null) {
return responseEntity;
}
byte[] bytes = objectMapper.writeValueAsBytes(responseEntity.getData());
AES aes = new AES(Mode.CBC, Padding.ZeroPadding, new SecretKeySpec(properties.getSecretKey().getBytes(), "AES"),
new IvParameterSpec(properties.getSecretKey().getBytes()));
return responseEntity.data(aes.encryptBase64(bytes));
}
}

View File

@@ -0,0 +1,7 @@
@NonNullApi
@NonNullFields
package com.codvision.webcore.config.encrypt.advice;
import org.springframework.lang.NonNullApi;
import org.springframework.lang.NonNullFields;

View File

@@ -0,0 +1,18 @@
package com.codvision.webcore.config.encrypt.bean;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpInputMessage;
import java.io.InputStream;
/**
* @author hxl
*/
@Getter
@RequiredArgsConstructor
public class ApiSecretHttpInputMessage implements HttpInputMessage {
private final InputStream body;
private final HttpHeaders headers;
}

View File

@@ -0,0 +1,162 @@
package com.codvision.webcore.config.encrypt.resolver;
import cn.hutool.crypto.Mode;
import cn.hutool.crypto.Padding;
import cn.hutool.crypto.symmetric.AES;
import com.codvision.commoncore.exception.BusinessException;
import com.codvision.webcore.config.encrypt.ApiSecretProperties;
import com.codvision.webcore.config.encrypt.ApiSecretSupports;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.ConversionNotSupportedException;
import org.springframework.beans.TypeMismatchException;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.core.MethodParameter;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ValueConstants;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.annotation.MethodArgumentConversionNotSupportedException;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
/**
* 请求数据解密处理
* 仅对方法的所有参数均被{@link RequestParam}标记的场景生效,参数类型适用于基本类型(含包装类型)
* 代码参考自{@link org.springframework.web.method.annotation.RequestParamMethodArgumentResolver}
*
* @author hxl
*/
@Slf4j
@Component
@RequiredArgsConstructor
@ConditionalOnProperty(value = ApiSecretProperties.PREFIX + ".enabled", havingValue = "true")
@ConditionalOnExpression("!'${security.api.encrypt.secret-key}'.isEmpty()")
public class ApiSecretRequestParamResolver implements HandlerMethodArgumentResolver {
private final ObjectMapper objectMapper;
private final ApiSecretProperties properties;
@Override
public boolean supportsParameter(MethodParameter parameter) {
// 判断当前方法是否符合要求,不符合则直接过滤
Method method = parameter.getMethod();
if (precondition(method)) {
return false;
}
return ApiSecretSupports.supports(parameter, properties);
}
@Override
@SneakyThrows
@SuppressWarnings("unchecked")
public Object resolveArgument(MethodParameter methodParameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) {
Parameter parameter = methodParameter.getParameter();
String params = webRequest.getParameter(ApiSecretProperties.PARAM_NAME);
if (StringUtils.isBlank(params)) {
return convertIfNecessary(methodParameter, webRequest, binderFactory);
}
AES aes = new AES(Mode.CBC, Padding.ZeroPadding, new SecretKeySpec(properties.getSecretKey().getBytes(), "AES"),
new IvParameterSpec(properties.getSecretKey().getBytes()));
try {
params = aes.decryptStr(params);
} catch (Exception e) {
log.error(e.getMessage());
throw new BusinessException(30001, "请检查encryption参数值是否已加密传输");
}
Map<String, Object> map = objectMapper.readValue(params, Map.class);
Object o = map.get(parameter.getName());
if (o == null) {
o = map.get(methodParameter.getParameterName());
if (o == null) {
return convertIfNecessary(methodParameter, webRequest, binderFactory);
}
}
return o;
}
private Object convertIfNecessary(MethodParameter methodParameter, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
Object o = null;
Parameter parameter = methodParameter.getParameter();
if (parameter.getType().equals(HttpServletRequest.class)) {
return webRequest.getNativeRequest(HttpServletRequest.class);
}
RequestParam requestParam = parameter.getAnnotation(RequestParam.class);
String defaultValue = (ValueConstants.DEFAULT_NONE.equals(requestParam.defaultValue()) ? null : requestParam.defaultValue());
if (StringUtils.isNotBlank(defaultValue)) {
o = defaultValue;
} else if (requestParam.required()) {
throw new MissingServletRequestParameterException(parameter.getName(),
parameter.getType().getSimpleName(), false);
}
o = handleNullValue(parameter.getName(), o, parameter.getType());
if (binderFactory != null) {
WebDataBinder binder = binderFactory.createBinder(webRequest, null, parameter.getName());
try {
o = binder.convertIfNecessary(o, methodParameter.getParameterType(), methodParameter);
} catch (ConversionNotSupportedException ex) {
throw new MethodArgumentConversionNotSupportedException(o, ex.getRequiredType(),
parameter.getName(), methodParameter, ex.getCause());
} catch (TypeMismatchException ex) {
throw new MethodArgumentTypeMismatchException(o, ex.getRequiredType(),
parameter.getName(), methodParameter, ex.getCause());
}
if (o == null && defaultValue == null && requestParam.required()) {
throw new MissingServletRequestParameterException(parameter.getName(),
parameter.getType().getSimpleName(), true);
}
}
return o;
}
private Object handleNullValue(String name, @Nullable Object o, Class<?> paramType) {
if (o == null) {
if (Boolean.TYPE.equals(paramType)) {
return Boolean.FALSE;
} else if (paramType.isPrimitive()) {
throw new IllegalStateException("Optional " + paramType.getSimpleName() + " parameter '" + name +
"' is present but cannot be translated into a null value due to being declared as a " +
"primitive type. Consider declaring it as object wrapper for the corresponding primitive type.");
}
}
return o;
}
private boolean precondition(Method method) {
List<Parameter> parameters = Arrays.stream(Objects.requireNonNull(method).getParameters())
.filter(p -> !p.isAnnotationPresent(RequestParam.class) && !p.getType().equals(HttpServletRequest.class))
.collect(Collectors.toList());
return CollectionUtils.isNotEmpty(parameters);
}
}

View File

@@ -0,0 +1,45 @@
package com.codvision.webcore.config.encrypt.resolver;
import lombok.RequiredArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Component;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;
import java.util.ArrayList;
import java.util.List;
/**
* 调整自定义参数解析器优先级
* @author hxl
*/
@Component
@RequiredArgsConstructor
@ConditionalOnBean(ApiSecretRequestParamResolver.class)
public class ApiSecretResolverBeanPostProcessor implements BeanPostProcessor {
private final ApiSecretRequestParamResolver requestParamResolver;
private static final String HANDLER_ADAPTER = "requestMappingHandlerAdapter";
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, @Nullable String beanName) throws BeansException {
if (HANDLER_ADAPTER.equals(beanName)) {
RequestMappingHandlerAdapter adapter = (RequestMappingHandlerAdapter) bean;
if (adapter != null) {
List<HandlerMethodArgumentResolver> argumentResolvers = new ArrayList<>();
argumentResolvers.add(requestParamResolver);
if (CollectionUtils.isNotEmpty(adapter.getArgumentResolvers())) {
argumentResolvers.addAll(adapter.getArgumentResolvers());
}
adapter.setArgumentResolvers(argumentResolvers);
}
}
return bean;
}
}

View File

@@ -0,0 +1,35 @@
/*
* Copyright (c) 2024 codvision.com All Rights Reserved.
*/
package com.codvision.webcore.config.swagger;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* @author hxl
*/
@Data
@Component
@ConfigurationProperties(prefix = SwaggerProperties.PREFIX)
public class SwaggerProperties {
public static final String PREFIX ="swagger.basic";
/**
* 是否开启Swagger登陆认证
*/
private boolean enable;
/**
* swagger用户名
*/
private String username;
/**
* swagger用户密码
*/
private String password;
}

View File

@@ -0,0 +1,67 @@
/*
* Copyright (c) 2023 codvision.com All Rights Reserved.
*/
package com.codvision.webcore.interceptor;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.ParameterUtils;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.pagination.dialects.IDialect;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import java.sql.SQLException;
/**
* 分页拦截器
* <p>
* 重构分页插件, 当 size 小于 0 时, 直接设置为 0, 防止错误查询全表
*
* @author lingee
* @date 2023-7-13
*/
@Data
@NoArgsConstructor
public class PlatformPaginationInnerInterceptor extends PaginationInnerInterceptor {
/**
* 数据库类型
* <p>
* 查看 {@link #findIDialect(Executor)} 逻辑
*/
private DbType dbType;
/**
* 方言实现类
* <p>
* 查看 {@link #findIDialect(Executor)} 逻辑
*/
private IDialect dialect;
public PlatformPaginationInnerInterceptor(DbType dbType) {
this.dbType = dbType;
}
public PlatformPaginationInnerInterceptor(IDialect dialect) {
this.dialect = dialect;
}
@Override
public void beforeQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds,
ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
IPage<?> page = ParameterUtils.findPage(parameter).orElse(null);
// size 小于 0 直接设置为 0 , 即不查询任何数据
if (null != page && page.getSize() < 0) {
page.setSize(0);
}
super.beforeQuery(executor, ms, page, rowBounds, resultHandler, boundSql);
}
}

View File

@@ -0,0 +1,9 @@
/*
* Copyright (c) 2023 codvision.com All Rights Reserved.
*/
/**
* @author lingee
* @date 2023/7/13
*/
package com.codvision.webcore;

View File

@@ -0,0 +1,20 @@
/*
* Copyright (c) 2023 codvision.com All Rights Reserved.
*/
package com.codvision.webcore.service;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* 自定义服务接口
*
* @author lingee
* @date 2023/7/21
*/
public interface IBaseService<T, V> extends IService<T> {
IPage<V> getBasePage(IPage<T> page, Wrapper<T> wrapper);
}

View File

@@ -0,0 +1,47 @@
/*
* Copyright (c) 2023 codvision.com All Rights Reserved.
*/
package com.codvision.webcore.service.impl;
import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.codvision.webcore.service.IBaseService;
import com.codvision.webcore.util.PageUtil;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
/**
* 自定义服务实现
*
* @author lingee
* @date 2023/7/21
*/
public class BaseServiceImpl<M extends BaseMapper<T>, T, V> extends ServiceImpl<M, T> implements IBaseService<T, V> {
@Override
public IPage<V> getBasePage(IPage<T> page, Wrapper<T> wrapper) {
IPage<T> pageResult = this.page(page, wrapper);
List<V> voList = BeanUtil.copyToList(pageResult.getRecords(), getVClass());
return PageUtil.convertPage(pageResult, voList);
}
private Class<V> getVClass() {
Type type = getClass().getGenericSuperclass();
if (!(type instanceof ParameterizedType)) {
throw new IllegalStateException("Type must be a parameterized type");
}
ParameterizedType parameterizedType = (ParameterizedType) type;
// 获取泛型的具体类型 这里是单泛型
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
if (null == actualTypeArguments || actualTypeArguments.length < 1) {
throw new IllegalStateException("Number of type arguments must be 1");
}
return (Class<V>) actualTypeArguments[2];
}
}

View File

@@ -0,0 +1,203 @@
package com.codvision.webcore.util;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.codvision.commoncore.utils.BeanUtil;
import com.codvision.webcore.annotation.QueryCondition;
import com.codvision.webcore.bean.QueryPage;
import org.apache.commons.lang3.ObjectUtils;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
/**
* 分页工具
*
* @author lingee
* @since 2023/7/20
*/
public class PageUtil {
/**
* Mybatis-Plus分页封装
*
* @param page 分页VO
* @param <T> 范型
* @return 分页响应
*/
public static <T> Page<T> initPage(QueryPage page) {
Page<T> p;
int pageNumber = page.getPageNumber();
int pageSize = page.getPageSize();
String sort = page.getSort();
String order = page.getOrder();
if (pageNumber < 1) {
pageNumber = 1;
}
if (pageSize < 1) {
pageSize = 10;
}
if (pageSize > 100000) {
pageSize = 100000;
}
if (StrUtil.isNotBlank(sort)) {
Boolean isAsc = false;
if (StrUtil.isBlank(order)) {
isAsc = false;
} else {
if ("desc".equals(order.toLowerCase())) {
isAsc = false;
} else if ("asc".equals(order.toLowerCase())) {
isAsc = true;
}
}
p = new Page<>(pageNumber, pageSize);
if (isAsc) {
p.addOrder(OrderItem.asc(sort));
} else {
p.addOrder(OrderItem.desc(sort));
}
} else {
p = new Page<>(pageNumber, pageSize);
}
return p;
}
/**
* 生成条件搜索 全对象对比
*
* @param object 对象
* @return 查询wrapper
*/
public static <T> QueryWrapper<T> initWrapper(Object object) {
QueryWrapper<T> queryWrapper = new QueryWrapper<>();
if (ObjectUtils.isNotEmpty(object)) {
Field[] fields = BeanUtil.getFields(object);
if (ArrayUtil.isEmpty(fields)) {
return queryWrapper;
}
for (int j = 0; j < fields.length; j++) {
Field field = fields[j];
if (ObjectUtils.isEmpty(field)) {
continue;
}
field.setAccessible(true);
String key = field.getName();
Object value = BeanUtil.getFieldValueByName(key, object);
if (StrUtil.isEmptyIfStr(value)) {
continue;
}
String columnName = StringUtils.camelToUnderline(key);
if (field.isAnnotationPresent(QueryCondition.class)) {
QueryCondition queryCondition = field.getAnnotation(QueryCondition.class);
if (StrUtil.isNotBlank(queryCondition.column())) {
columnName = queryCondition.column();
}
if (StrUtil.isNotBlank(queryCondition.property())) {
columnName = StringUtils.camelToUnderline(queryCondition.property());
}
switch (queryCondition.condition()) {
case LIKE:
queryWrapper.like(columnName, value);
break;
case IN:
queryWrapper.in(columnName, value);
break;
case LE:
queryWrapper.le(columnName, value);
break;
case GE:
queryWrapper.ge(columnName, value);
break;
case LT:
queryWrapper.lt(columnName, value);
break;
case GT:
queryWrapper.gt(columnName, value);
break;
case NE:
queryWrapper.ne(columnName, value);
break;
case IS_NULL:
queryWrapper.isNull(columnName);
break;
case IS_NOT_NULL:
queryWrapper.isNotNull(columnName);
break;
default:
queryWrapper.eq(columnName, value);
}
continue;
}
queryWrapper.eq(columnName, value);
}
}
return queryWrapper;
}
/**
* List 手动分页
*
* @param page 分页对象
* @param list 分页集合
* @return 范型结果
*/
public static <T> List<T> listToPage(QueryPage page, List<T> list) {
int pageNumber = page.getPageNumber() - 1;
int pageSize = page.getPageSize();
if (pageNumber < 0) {
pageNumber = 0;
}
if (pageSize < 1) {
pageSize = 10;
}
if (pageSize > 100) {
pageSize = 100;
}
int fromIndex = pageNumber * pageSize;
int toIndex = pageNumber * pageSize + pageSize;
if (fromIndex > list.size()) {
return new ArrayList<>();
} else if (toIndex >= list.size()) {
return list.subList(fromIndex, list.size());
} else {
return list.subList(fromIndex, toIndex);
}
}
/**
* 转换分页类型
*
* @param originPage 原分页
* @param records 新分页数据
* @param <T> 新类型
* @return 新类型分页
*/
public static <T> IPage<T> convertPage(IPage originPage, List<T> records) {
IPage<T> resultPage = new Page<>();
if (originPage != null) {
resultPage.setCurrent(originPage.getCurrent());
resultPage.setPages(originPage.getPages());
resultPage.setTotal(originPage.getTotal());
resultPage.setSize(originPage.getSize());
resultPage.setRecords(records);
}
return resultPage;
}
}

View File

@@ -0,0 +1,20 @@
/*
* Copyright (c) 2023 codvision.com All Rights Reserved.
*/
package com.codvision.webcore.util;
import com.codvision.webcore.bean.QueryPage;
import java.util.HashMap;
import java.util.Map;
/**
* @author hxl
*/
public class QueryPageUtil {
public static Map<String, Object> queryMap(QueryPage<Map<String, Object>> queryPage) {
return queryPage.getCondition() == null ? new HashMap<>(16) : queryPage.getCondition();
}
}

View File

@@ -0,0 +1,59 @@
/*
* Copyright (c) 2023 codvision.com All Rights Reserved.
*/
package com.codvision.webcore.util;
import cn.hutool.core.util.ClassLoaderUtil;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.env.Environment;
import java.net.InetAddress;
import java.net.UnknownHostException;
/**
* WebUtil
*
* @author lingee
* @date 2024/1/23
*/
@Slf4j
public class WebUtil {
/**
* 打印程序相关地址
*
* @param env 当前环境
*/
public static void printWebUrl(Environment env) {
try {
String ip = InetAddress.getLocalHost().getHostAddress();
String applicationName = env.getProperty("spring.application.name");
if (StrUtil.isBlank(applicationName)) {
applicationName = "";
}
String port = env.getProperty("server.port");
String path = env.getProperty("server.servlet.context-path");
if (StrUtil.isBlank(path)) {
path = "";
} else {
if (StrUtil.contains(path, "/")) {
path = "/" + StrUtil.removeAll(path, "/");
}
}
String backend = "";
if (ClassLoaderUtil.isPresent("com.codvision.base.config.BaseConfig")) {
backend = "Backend: \t\thttp://" + ip + ":" + port + path + "/backend/index.html\n\t";
}
log.info("\n----------------------------------------------------------\n\t" +
"Application " + applicationName + " is running! Access URLs:\n\t" +
"Local: \t\thttp://127.0.0.1:" + port + path + "/\n\t" + backend +
"Doc: \t\thttp://" + ip + ":" + port + path + "/doc.html\n" +
"----------------------------------------------------------");
} catch (UnknownHostException e) {
throw new RuntimeException(e);
}
}
}

View File

@@ -0,0 +1 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.codvision.webcore.config.WebCoreConfig

View File

@@ -0,0 +1,16 @@
${AnsiColor.BRIGHT_BLUE}
,---, ,--, ,--,
,---. ,---.'| ,--.'| ,--.'| ,---. ,---,
' ,'\ | | : .---. | |, .--.--. | |, ' ,'\ ,-+-. / |
,---. / / | | | | /. ./| `--'_ / / ' `--'_ / / | ,--.'|' |
/ \ . ; ,. : ,--.__| | .-' . ' | ,' ,'| | : /`./ ,' ,'| . ; ,. : | | ,"' |
/ / ' ' | |: : / ,' | /___/ \: | ' | | | : ;_ ' | | ' | |: : | | / | |
. ' / ' | .; : . ' / | . \ ' . | | : \ \ `. | | : ' | .; : | | | | |
' ; :__ | : | ' ; |: | \ \ ' ' : |__ `----. \ ' : |__ | : | | | | |/
' | '.'| \ \ / | | '/ ' \ \ | | '.'| / /`--' / | | '.'| \ \ / | | |--'
| : : `----' | : :| \ \ | ; : ; '--'. / ; : ; `----' | |/
\ \ / \ \ / '---" | , / `--'---' | , / '---'
`----' `----' ---`-' ---`-'
杭州码全信息科技有限公司 https://www.codvision.com

View File

@@ -0,0 +1,5 @@
spring.mvc.pathmatch.matching-strategy=ANT_PATH_MATCHER
# API?????
security.api.encrypt.enabled=true
security.api.encrypt.secret-key=ms1sn1r3r7tb7wr9
security.api.encrypt.global-enabled=false