Commit fb0b2416 authored by 侯力峰's avatar 侯力峰
Browse files

首次开源发布

parent f978a999
Pipeline #2758 canceled with stages
# spatiotemporal-web-core # spatiotemporal-web-core
时空开放平台Web端 核心模块 时空开放平台Web端 核心模块。以下简称Web端核心模块(web-core),提供Web端工程的公共功能。
\ No newline at end of file
## 引用方式
Web端应用工程一般需要引用Web端核心模块(web-core)。可以在POM.xml文件的dependencies中加入以下依赖。
```xml
<dependency>
<groupId>cn.spatiotemporal</groupId>
<artifactId>spatiotemporal-web-core</artifactId>
<version>1.0.0-SNAPSHOT</version>
</dependency>
```
注意选择合适的版本。
## Web端公共功能
### SpringMVC支持
集成SpringMVC,对页面访问参数和返回值自动进行json序列化、反序列化处理等。
### Spring访问安全
基于SpringSecurity,对客户端进行jwt认证拦截,检核jwt的存在性和有效性。
### 权限控制
基于RBCA模型的权限控制。提供注解方式的方法级权限控制,自动匹配用户-角色与所访问的方法的权限是否相符。
### 统一数据访问层
基于MyBatis-Plus,提供统一的数据访问层支持。包括Entity基类、Dao基类等。
支持分布式自动生成主键、逻辑删除、创建/更新信息自动注入、事务管理、乐观锁、基于租户的数据隔离等。
支持多种RDBMS数据库(默认为mysql),支持连接池管理(基于HikariCP连接池)。
### 统一认证支持
支持两种模式的单点登录SSO和统一认证:基于jwt的认证模式和基于CAS的认证模式。
### 前后端通信加密
基于非公开加密算法和密钥管理,增强前后端通信时安全性。
**注:需要客户端与服务端成对使用。**
### 自动化日志
基于AOP模式,提供注解方式的用户操作、系统日志日志自动写入。
### 数据字典支持
通过redis提供数据字典的访问与转换功能。
## 公共工具类
### 用户权限工具类AuthorityUtils
提供与用户、权限相关的公共功能,包括获取当前用户信息等。
### JWT工具类JwtTokenUtils
提供jwt生成、jwt解码等相关的工具类。
### 数据字典工具类DictUtils
提供数据字典的获取、自动翻译等功能。
### IP地址工具类
提供获取客户端IP、服务端IP等功能。
# 版本1.0.0-RELEASE
发布时间: 2023/5/4
更新内容:
- 集成SpringMVC,对页面访问参数和返回值自动进行json序列化、反序列化处理等。
- 基于SpringSecurity,对客户端进行jwt认证拦截,检核jwt的存在性和有效性。
- 基于RBCA模型的权限控制。提供注解方式的方法级权限控制,自动匹配用户-角色与所访问的方法的权限是否相符。
- 基于MyBatis-Plus,提供统一的数据访问层支持。包括Entity基类、Dao基类等。
- 支持分布式自动生成主键、逻辑删除、创建/更新信息自动注入、事务管理、乐观锁、基于租户的数据隔离等。
- 支持多种RDBMS数据库(默认为mysql),支持连接池管理(基于HikariCP连接池)。
- 支持两种模式的单点登录SSO和统一认证:基于jwt的认证模式和基于CAS的认证模式。
- 支持前后端通讯加密。基于非公开加密算法和密钥管理,增强前后端通信时安全性。
**注:需要客户端与服务端成对使用。**
- 基于AOP模式,提供注解方式的用户操作、系统日志日志自动写入。
- 通过redis提供数据字典的访问与转换功能。
- 提供以下公共工具类:
- AuthorityUtils:用户权限工具类
- JwtTokenUtils:JWT工具类
- DictUtils:数据字典工具类
- IPAddressUtils:IP地址工具类
<?xml version="1.0"?>
<project
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<groupId>cn.spatiotemporal</groupId>
<artifactId>spatiotemporal-web-core</artifactId>
<version>1.0.0-RELEASE</version>
<packaging>jar</packaging>
<name>spatiotemporal-web-core</name>
<description>时空开放平台Web端 核心模块</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.12.RELEASE</version>
<relativePath />
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<maven-jar-plugin.version>3.1.1</maven-jar-plugin.version>
<hutool.version>5.8.21</hutool.version>
<mybatis.version>3.5.9</mybatis.version>
<mybatisplus.version>3.5.0</mybatisplus.version>
<oracle.version>12.2.0.1</oracle.version>
<oracle.sdoapi.version>11.2.0</oracle.sdoapi.version>
<curator.version>2.8.0</curator.version>
<guava.version>20.0</guava.version>
<swagger2.version>2.9.2</swagger2.version>
<pagehelper.version>1.2.3</pagehelper.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<!--排除默认的tomcat-jdbc -->
<exclusion>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-jdbc</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<!-- mysql -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--postgresql -->
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>${curator.version}</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>${curator.version}</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>${guava.version}</version>
</dependency>
<!-- swagger2 -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>${swagger2.version}</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>${swagger2.version}</version>
</dependency>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-annotations</artifactId>
<version>1.5.21</version>
</dependency>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-models</artifactId>
<version>1.5.21</version>
</dependency>
<!--lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!--HikariCP连接池 -->
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
</dependency>
<!-- Mybatis-plus 不用再重复引入Mybatis的Starter -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>${mybatisplus.version}</version>
<exclusions>
<exclusion>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>${mybatis.version}</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>${hutool.version}</version>
</dependency>
<!--JSON封装 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.36</version>
</dependency>
<!--jwt工具类 -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
</dependency>
</dependencies>
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.yml</include>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
package cn.spatiotemporal.web.core.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.context.annotation.Import;
/**
* 关闭系统自动日志组件
* @author marquis
*
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
public @interface DisableSysLog {
/**
* 默认属性,与{@link #basePackages()}是同一个属性,简写的时候等同于指定了 {@link #basePackages()}。
* 例如: 可以用{@code @EnableAsyncClients("org.my.pkg")}来替代
* {@code @EnableAsyncClients(basePackages="org.my.pkg")}.
* @return the array of 'basePackages'.
*/
String[] value() default {};
}
package cn.spatiotemporal.web.core.annotation;
/**
* Project Name:spatiotemporal-web-core
* File Name:SysLog.java
* Package cn.spatiotemporal.web.core.annotation
* Date:2021-01-20 13:46:14
* Copyright (c) 2018, inzymeits All Rights Reserved.
*
*/
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @ClassName: SysLog
* @Description: 系统日志注解
* @date 2021-01-20 13:46:14
*
* @author Q.JI
* @version
* @since JDK 1.7
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SysLog {
String value() default "";
}
package cn.spatiotemporal.web.core.annotation;
/**
* Project Name:spatiotemporal-web-core
* File Name:UserLog.java
* Package cn.spatiotemporal.web.core.annotation
* Date:2021-01-20 13:46:14
* Copyright (c) 2018, inzymeits All Rights Reserved.
*
*/
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @ClassName: UserLog
* @Description: 用户操作日志注解
* @date 2021-01-20 13:46:14
*
* @author Q.JI
* @version
* @since JDK 1.7
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface UserLog {
String value() default "";
}
package cn.spatiotemporal.web.core.config.restapi;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;
/**
* REST API调用模板配置
* @author marquis
*
*/
@Configuration
public class RestApiConfig {
@Bean
public RestTemplate restTemplate(ClientHttpRequestFactory factory) {
return new RestTemplate(factory);
}
@Bean
public ClientHttpRequestFactory simpleClientHttpRequestFactory() {
SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
factory.setReadTimeout(5000);//单位为ms
factory.setConnectTimeout(5000);//单位为ms
return factory;
}
}
package cn.spatiotemporal.web.core.config.security;
import org.springframework.boot.context.properties.ConfigurationProperties;
import lombok.Data;
@ConfigurationProperties(prefix = "security")
@Data
public class SecurityProperties {
/**
* 安全模式:
* simple 简答模式,采用内部集成的rbac管理模块
* jwt-redis 采用jwt来验证,获取储存在redis里的用户/权限信息
* disable 关闭安全服务
*/
private String mode = "jwt-redis";
/**
* 允许无需验证即可访问的路径(含通配符)
*/
private String[] permitAccess= {"/admin/sso/**"};
private String[] authAccess= {"/admin/user/**","/admin/role/**","/admin/role/**","/admin/org/**","/admin/menu/**"};
}
package cn.spatiotemporal.web.core.config.thread;
import java.util.concurrent.ThreadPoolExecutor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.TaskExecutor;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
/**
* 异步任务(线程池)配置
* @author marquis
*
*/
@Configuration
@EnableAsync
public class AsyncTaskConfig {
@Bean
public TaskExecutor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
// 设置核心线程数
executor.setCorePoolSize(5);
// 设置最大线程数
executor.setMaxPoolSize(10);
// 设置队列容量
executor.setQueueCapacity(20);
// 设置线程活跃时间(秒)
executor.setKeepAliveSeconds(60);
// 设置默认线程名称
executor.setThreadNamePrefix("async-");
// 设置拒绝策略
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
// 等待所有任务结束后再关闭线程池
executor.setWaitForTasksToCompleteOnShutdown(true);
return executor;
}
}
\ No newline at end of file
package cn.spatiotemporal.web.core.config.web;
import java.util.List;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
/**
* WebMvc配置
* 主要包括:
* 1、替换json序列化工具为fastjson,以解决Long值传到前台丢失精度的问题;
* 2、
* @author marquis
*
*/
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
/**
* 配置消息转换器jackson
* @param converters
*/
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
MappingJackson2HttpMessageConverter jackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter();
ObjectMapper objectMapper = new ObjectMapper();
/**
* 序列换成json时,将所有的long变成string
* 因为js中得数字类型不能包含所有的java long值
*/
SimpleModule simpleModule = new SimpleModule();
simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
simpleModule.addSerializer(Long.TYPE, ToStringSerializer.instance);
objectMapper.registerModule(simpleModule);
jackson2HttpMessageConverter.setObjectMapper(objectMapper);
converters.add(jackson2HttpMessageConverter);
// //1.需要定义一个convert转换消息的对象;
// FastJsonHttpMessageConverter fastJsonHttpMessageConverter = new FastJsonHttpMessageConverter();
// //2.添加fastJson的配置信息,比如:是否要格式化返回的json数据;
// FastJsonConfig fastJsonConfig = new FastJsonConfig();
// JSON.DEFFAULT_DATE_FORMAT = "yyyy-MM-dd HH:mm";
// fastJsonConfig.setSerializerFeatures(SerializerFeature.BrowserCompatible,
// SerializerFeature.WriteNullListAsEmpty,
// SerializerFeature.PrettyFormat,
// SerializerFeature.WriteDateUseDateFormat,
// SerializerFeature.WriteNullStringAsEmpty,
// SerializerFeature.WriteMapNullValue,
// SerializerFeature.DisableCircularReferenceDetect);
// //3.解决Long转json精度丢失的问题
// SerializeConfig serializeConfig = SerializeConfig.globalInstance;
// serializeConfig.put(BigInteger.class, ToStringSerializer.instance);
// serializeConfig.put(Long.class, ToStringSerializer.instance);
// serializeConfig.put(Long.TYPE, ToStringSerializer.instance);
// fastJsonConfig.setSerializeConfig(serializeConfig);
// //4.处理中文乱码问题
// List<MediaType> fastMediaTypes = new ArrayList<>();
// fastMediaTypes.add(MediaType.APPLICATION_JSON_UTF8);
// //5.在convert中添加配置信息.
// fastJsonHttpMessageConverter.setSupportedMediaTypes(fastMediaTypes);
// fastJsonHttpMessageConverter.setFastJsonConfig(fastJsonConfig);
// //6.将convert添加到converters当中.
// converters.add(fastJsonHttpMessageConverter);
}
}
package cn.spatiotemporal.web.core.constants;
/**
* 时空开放平台 公共常量定义
* @author marquis
*
*/
public class Constants {
public static final String FTP_PATH_SEPARATOR ="/";
public static final String EMPTY_STRING="";
/** 默认的字符集编码 **/
public static final String DEFAULT_CHARSET = "utf-8";
/** GBK字符集 **/
public static final String CHARSET_ENCODING_GBK = "GBK";
/** iso-8859-1字符集 **/
public static final String CHARSET_ENCODING_ISO_8859_1 = "iso-8859-1";
/** 数据字典 集合 redis key **/
public static final String REDIS_KEY_DICT= "spatiotemporal\\:dict\\:list";
/** 系统菜单信息集合 redis key */
public static final String REDIS_KEY_MENU = "spatiotemporal\\:menu\\:list";
public static final String REDIS_KEY_USERNAME = "spatiotemporal:username";
public static final String REDIS_KEY_JWT_TOKEN = "spatiotemporal:jwt:token";
public static final String REDIS_KEY_CAS_TOKEN = "spatiotemporal:cas:token";
public static final int REDIS_DEFAULT_EXPIRE = 1800;
/** 单页最大查询行数 */
public static final long MAX_QUERY_SIZE_PER_PAGE = 1000L;
/** 日志:状态 成功 **/
public static final String RETURN_STATUS_SUCCESS = "Success";
/** 日志:状态 失败 **/
public static final String RETURN_STATUS_FAILED = "Fail";
}
package cn.spatiotemporal.web.core.constants.enums;
import lombok.Getter;
import lombok.NoArgsConstructor;
@Getter
@NoArgsConstructor
public enum PermissionType {
MENU(2),
BUTTON(3);
private int value;
private PermissionType(int value) {
this.value = value;
}
}
package cn.spatiotemporal.web.core.constants.enums;
import lombok.Getter;
import lombok.NoArgsConstructor;
/**
* REST服务返回状态/消息枚举
* @author marquis
*
*/
@Getter
@NoArgsConstructor
public enum ReturnEnum {
// 公共返回状态/消息
// 成功
SUCCESS("200","访问成功"),
SUCCESS_CUSTOM("201","调用成功"),//自定义成功状态
// 一般公共错误信息
ERROR_POST_PARAM("400", "请求参数异常"),
ERROR_ACCOUNT_OR_PASSWORD("408","用户名或密码错误"),
ERROR_EXIST_USERNAME("409","用户名已存在,请直接登录"),
ERROR_USER_NOT_ENABLED("410","用户已停用,请联系管理员"),
ERROR_USER_NOT_EXIST("411","用户不存在"),
ERROR_NO_AUTHORITY("401", "用户未登录,需要登录后才能访问"),
ERROR_OTHER_DEVICE("401.1", "用户已在其他设备登录,需要重新登录后才能访问"),
ERROR_TOKEN_EXPIRED("401.2", "用户授权已过期,需要重新登录后才能访问"),
ERROR_PERMISSION_DENIED("403", "无此访问权限"),
ERROR_NOT_FOUND("404", "访问对象不存在"),
ERROR_METHOD_ERROR("405", "访问方式不正确"),
ERROR_USER_NULL("412","用户名参数为空"),
ERROR_MSG_HAS_CHILD("413","操作失败,当前所选栏目有子栏目信息"),
ERROR_CRON("414","cron表达式不正确"),
// 一般公共异常信息
FAILED("500", "服务器内部异常,请稍后重试"),
;
private String code;
private String message;
ReturnEnum(String code, String message) {
this.code = code;
this.message = message;
}
public String getCode() {
return code;
}
public String getMessage() {
return message;
}
}
package cn.spatiotemporal.web.core.dao;
import org.apache.ibatis.annotations.Mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import cn.spatiotemporal.web.core.domain.entity.admin.OperationLog;
/**
* 操作日志表 Dao 接口
*
* @author wenxuan.hu
* @since 2021-01-20
*/
@Mapper
public interface OperationLogDao extends BaseMapper<OperationLog> {
}
package cn.spatiotemporal.web.core.dao;
import org.apache.ibatis.annotations.Mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import cn.spatiotemporal.web.core.domain.entity.admin.ServiceLog;
/**
* 操作日志表 Dao 接口
*
* @author wenxuan.hu
* @since 2021-01-20
*/
@Mapper
public interface ServiceLogDao extends BaseMapper<ServiceLog> {
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.spatiotemporal.web.core.dao.OperationLogDao">
</mapper>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.spatiotemporal.web.core.dao.ServiceLogDao">
</mapper>
package cn.spatiotemporal.web.core.domain;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
/**
* 通用树形数据结构
* @author marquis
*
*/
public interface Treeable<T> {
/**
* 获取当前节点ID
* @return
*/
public Serializable getId();
/**
* 获取父节点ID
* @return
*/
public Serializable getParentId();
/**
* 获取子节点列表
* @return
*/
public List<T> getChildren();
/**
* 设置子节点列表
* @param list
*/
public void setChildren(List<T> list);
/**
* 是否存在子节点
* @return
*/
default boolean hasChildren() {
return getChildren() != null && !getChildren().isEmpty();
}
default void addChild(T child) {
if (!hasChildren()) {
setChildren(new ArrayList<T>());
}
getChildren().add(child);
}
}
package cn.spatiotemporal.web.core.domain.entity;
import java.io.Serializable;
import java.util.Date;
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 com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import lombok.Data;
/**
* 一般持久化实体类的基类
* @author marquis
*
* @param <ID>
*/
@Data
public class BaseEntity implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
/**
* 物理主键,采用mybatis-plus默认主键策略(生成全局唯一主键)
*/
@TableId(value = "id")
@JsonSerialize(using = ToStringSerializer.class)
private Long id;
/**
* 创建者
*/
@TableField(value="create_user", fill=FieldFill.INSERT)
private String createUser;
/**
* 创建时间
*/
@TableField(value="create_time", fill=FieldFill.INSERT)
@JsonFormat(locale="zh", timezone="GMT+8", pattern="yyyy-MM-dd HH:mm:ss")
private Date createTime;
/**
* 更新者
*/
@TableField(value="update_user", fill=FieldFill.INSERT_UPDATE)
private String updateUser;
/**
* 更新时间
*/
@TableField(value="update_time", fill=FieldFill.INSERT_UPDATE)
@JsonFormat(locale="zh", timezone="GMT+8", pattern="yyyy-MM-dd HH:mm:ss")
private Date updateTime;
}
package cn.spatiotemporal.web.core.domain.entity;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.Version;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
/**
* 完整的实体类基类(采用标记删除、乐观锁控制和多租户隔离等)
* @author marquis
*
*/
@Data
@EqualsAndHashCode(callSuper=true)
@ToString(callSuper=true)
public class CommonEntity extends BaseEntity {
/**
*
*/
private static final long serialVersionUID = -1844922701089800582L;
/**
* 逻辑删除标记
*/
@TableField("is_deleted")
@TableLogic
private Integer deleted;
/**
* 版本(用于乐观锁并发控制策略)
*/
@TableField("version")
@Version
private Long version;
/**
* 租户ID(用于多租户数据隔离)
*/
@TableField("tenant_id")
@JsonSerialize(using = ToStringSerializer.class)
private Long tenantId;
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment