fix: 码全代码添加
This commit is contained in:
38
template/cvbp/cvbp-public/cvbp-web-core/.gitignore
vendored
Normal file
38
template/cvbp/cvbp-public/cvbp-web-core/.gitignore
vendored
Normal 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
|
||||
84
template/cvbp/cvbp-public/cvbp-web-core/pom.xml
Normal file
84
template/cvbp/cvbp-public/cvbp-web-core/pom.xml
Normal 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>
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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 "";
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
|
||||
@NonNullApi
|
||||
@NonNullFields
|
||||
package com.codvision.webcore.config.encrypt.advice;
|
||||
|
||||
import org.springframework.lang.NonNullApi;
|
||||
import org.springframework.lang.NonNullFields;
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
/*
|
||||
* Copyright (c) 2023 codvision.com All Rights Reserved.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @author lingee
|
||||
* @date 2023/7/13
|
||||
*/
|
||||
package com.codvision.webcore;
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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];
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.codvision.webcore.config.WebCoreConfig
|
||||
@@ -0,0 +1,16 @@
|
||||
${AnsiColor.BRIGHT_BLUE}
|
||||
,---, ,--, ,--,
|
||||
,---. ,---.'| ,--.'| ,--.'| ,---. ,---,
|
||||
' ,'\ | | : .---. | |, .--.--. | |, ' ,'\ ,-+-. / |
|
||||
,---. / / | | | | /. ./| `--'_ / / ' `--'_ / / | ,--.'|' |
|
||||
/ \ . ; ,. : ,--.__| | .-' . ' | ,' ,'| | : /`./ ,' ,'| . ; ,. : | | ,"' |
|
||||
/ / ' ' | |: : / ,' | /___/ \: | ' | | | : ;_ ' | | ' | |: : | | / | |
|
||||
. ' / ' | .; : . ' / | . \ ' . | | : \ \ `. | | : ' | .; : | | | | |
|
||||
' ; :__ | : | ' ; |: | \ \ ' ' : |__ `----. \ ' : |__ | : | | | | |/
|
||||
' | '.'| \ \ / | | '/ ' \ \ | | '.'| / /`--' / | | '.'| \ \ / | | |--'
|
||||
| : : `----' | : :| \ \ | ; : ; '--'. / ; : ; `----' | |/
|
||||
\ \ / \ \ / '---" | , / `--'---' | , / '---'
|
||||
`----' `----' ---`-' ---`-'
|
||||
|
||||
杭州码全信息科技有限公司 https://www.codvision.com
|
||||
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user