环境
- SpringBoot 2.7.4
- JDK15
- 自动依赖(hibernate-core 5.6.11.Final)等
- IDEA2023.2.2 社区版
本地代码目录示例
新增两个文件
- 新增两个文件,org目录与cn目录对齐;
- 文件1:PropertyContainer,修改其中属性集合从TreeMap更改为ListedHashMap;
- 文件2:InheritanceState,兼容当实体继承有父类时,自定义子父类中的表字段顺序(需根据父类属性进行调整)。
yml配置文件中关于jpa配置
spring:
#配置自动建表:update:没有表新建,有表更新操作,控制台显示建表语句
jpa:
hibernate:
ddl-auto: update
naming:
physical-strategy: org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy
show-sql: true
# spring.jpa.open-in-view 属性被默认启用,需要手动配置该属性,去掉这个警告
# open-in-view 是指延时加载的一些属性数据,可以在页面展现的时候,保持session不关闭,从而保证能在页面进行延时加载
open-in-view: false
PropertyContainer.java
示例
package org.hibernate.cfg;
import java.util.*;
import javax.persistence.Access;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import javax.persistence.Transient;
import org.hibernate.AnnotationException;
import org.hibernate.annotations.Any;
import org.hibernate.annotations.ManyToAny;
import org.hibernate.annotations.Target;
import org.hibernate.annotations.Type;
import org.hibernate.annotations.common.reflection.XClass;
import org.hibernate.annotations.common.reflection.XProperty;
import org.hibernate.boot.MappingException;
import org.hibernate.boot.jaxb.Origin;
import org.hibernate.boot.jaxb.SourceType;
import org.hibernate.cfg.annotations.HCANNHelper;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.internal.util.collections.CollectionHelper;
import org.jboss.logging.Logger;
/**
* SpringBoot Jpa按照顺序生成数据库表字段
* 依赖包见:hibernate-core-5.6.11.Final.jar
* 源码参见:org.hibernate.cfg.PropertyContainer
* 修改:将全部TreeMap修改为LinkedHashMap即可。
* 说明:由于Entity存在继承BaseModel基类,数据库表中先以基类后以子类进行排序
*
* @since 2023-09-23
*/
class PropertyContainer
{
private static final CoreMessageLogger LOG = (CoreMessageLogger) Logger.getMessageLogger(CoreMessageLogger.class, PropertyContainer.class.getName());
private final XClass xClass;
private final XClass entityAtStake;
private final AccessType classLevelAccessType;
private final List<XProperty> persistentAttributes;
PropertyContainer(XClass clazz, XClass entityAtStake, AccessType defaultClassLevelAccessType)
{
this.xClass = clazz;
this.entityAtStake = entityAtStake;
if (defaultClassLevelAccessType == AccessType.DEFAULT)
{
defaultClassLevelAccessType = AccessType.PROPERTY;
}
AccessType localClassLevelAccessType = this.determineLocalClassDefinedAccessStrategy();
assert localClassLevelAccessType != null;
this.classLevelAccessType = localClassLevelAccessType != AccessType.DEFAULT ? localClassLevelAccessType : defaultClassLevelAccessType;
assert this.classLevelAccessType == AccessType.FIELD || this.classLevelAccessType == AccessType.PROPERTY;
List<XProperty> fields = this.xClass.getDeclaredProperties(AccessType.FIELD.getType());
List<XProperty> getters = this.xClass.getDeclaredProperties(AccessType.PROPERTY.getType());
this.preFilter(fields, getters);
Map<String, XProperty> persistentAttributesFromGetters = new HashMap();
LinkedHashMap<String, XProperty> localAttributeMap = new LinkedHashMap();
collectPersistentAttributesUsingLocalAccessType(this.xClass, localAttributeMap, persistentAttributesFromGetters, fields, getters);
collectPersistentAttributesUsingClassLevelAccessType(this.xClass, this.classLevelAccessType, localAttributeMap, persistentAttributesFromGetters, fields, getters);
this.persistentAttributes = verifyAndInitializePersistentAttributes(this.xClass, localAttributeMap);
}
private void preFilter(List<XProperty> fields, List<XProperty> getters)
{
Iterator<XProperty> propertyIterator = fields.iterator();
XProperty property;
while (propertyIterator.hasNext())
{
property = (XProperty) propertyIterator.next();
if (mustBeSkipped(property))
{
propertyIterator.remove();
}
}
propertyIterator = getters.iterator();
while (propertyIterator.hasNext())
{
property = (XProperty) propertyIterator.next();
if (mustBeSkipped(property))
{
propertyIterator.remove();
}
}
}
private static void collectPersistentAttributesUsingLocalAccessType(XClass xClass, LinkedHashMap<String, XProperty> persistentAttributeMap, Map<String, XProperty> persistentAttributesFromGetters, List<XProperty> fields, List<XProperty> getters)
{
Iterator<XProperty> propertyIterator = fields.iterator();
XProperty xProperty;
Access localAccessAnnotation;
while (propertyIterator.hasNext())
{
xProperty = (XProperty) propertyIterator.next();
localAccessAnnotation = (Access) xProperty.getAnnotation(Access.class);
if (localAccessAnnotation != null && localAccessAnnotation.value() == javax.persistence.AccessType.FIELD)
{
propertyIterator.remove();
persistentAttributeMap.put(xProperty.getName(), xProperty);
}
}
propertyIterator = getters.iterator();
while (propertyIterator.hasNext())
{
xProperty = (XProperty) propertyIterator.next();
localAccessAnnotation = (Access) xProperty.getAnnotation(Access.class);
if (localAccessAnnotation != null && localAccessAnnotation.value() == javax.persistence.AccessType.PROPERTY)
{
propertyIterator.remove();
String name = xProperty.getName();
XProperty previous = (XProperty) persistentAttributesFromGetters.get(name);
if (previous != null)
{
throw new MappingException(LOG.ambiguousPropertyMethods(xClass.getName(), HCANNHelper.annotatedElementSignature(previous), HCANNHelper.annotatedElementSignature(xProperty)), new Origin(SourceType.ANNOTATION, xClass.getName()));
}
persistentAttributeMap.put(name, xProperty);
persistentAttributesFromGetters.put(name, xProperty);
}
}
}
private static void collectPersistentAttributesUsingClassLevelAccessType(XClass xClass, AccessType classLevelAccessType, LinkedHashMap<String, XProperty> persistentAttributeMap, Map<String, XProperty> persistentAttributesFromGetters, List<XProperty> fields, List<XProperty> getters)
{
Iterator var6;
XProperty getter;
if (classLevelAccessType == AccessType.FIELD)
{
var6 = fields.iterator();
while (var6.hasNext())
{
getter = (XProperty) var6.next();
if (!persistentAttributeMap.containsKey(getter.getName()))
{
persistentAttributeMap.put(getter.getName(), getter);
}
}
}
else
{
var6 = getters.iterator();
while (var6.hasNext())
{
getter = (XProperty) var6.next();
String name = getter.getName();
XProperty previous = (XProperty) persistentAttributesFromGetters.get(name);
if (previous != null)
{
throw new MappingException(LOG.ambiguousPropertyMethods(xClass.getName(), HCANNHelper.annotatedElementSignature(previous), HCANNHelper.annotatedElementSignature(getter)), new Origin(SourceType.ANNOTATION, xClass.getName()));
}
if (!persistentAttributeMap.containsKey(name))
{
persistentAttributeMap.put(getter.getName(), getter);
persistentAttributesFromGetters.put(name, getter);
}
}
}
}
public XClass getEntityAtStake()
{
return this.entityAtStake;
}
public XClass getDeclaringClass()
{
return this.xClass;
}
public AccessType getClassLevelAccessType()
{
return this.classLevelAccessType;
}
/**
* @deprecated
*/
@Deprecated
public Collection<XProperty> getProperties()
{
return Collections.unmodifiableCollection(this.persistentAttributes);
}
public Iterable<XProperty> propertyIterator()
{
return this.persistentAttributes;
}
private static List<XProperty> verifyAndInitializePersistentAttributes(XClass xClass, Map<String, XProperty> localAttributeMap)
{
ArrayList<XProperty> output = new ArrayList(localAttributeMap.size());
Iterator var3 = localAttributeMap.values().iterator();
while (var3.hasNext())
{
XProperty xProperty = (XProperty) var3.next();
if (!xProperty.isTypeResolved() && !discoverTypeWithoutReflection(xProperty))
{
String msg = "Property " + StringHelper.qualify(xClass.getName(), xProperty.getName()) + " has an unbound type and no explicit target entity. Resolve this Generic usage issue or set an explicit target attribute (eg @OneToMany(target=) or use an explicit @Type";
throw new AnnotationException(msg);
}
output.add(xProperty);
}
return CollectionHelper.toSmallList(output);
}
private AccessType determineLocalClassDefinedAccessStrategy()
{
AccessType hibernateDefinedAccessType = AccessType.DEFAULT;
AccessType jpaDefinedAccessType = AccessType.DEFAULT;
org.hibernate.annotations.AccessType accessType = (org.hibernate.annotations.AccessType) this.xClass.getAnnotation(org.hibernate.annotations.AccessType.class);
if (accessType != null)
{
hibernateDefinedAccessType = AccessType.getAccessStrategy(accessType.value());
}
Access access = (Access) this.xClass.getAnnotation(Access.class);
if (access != null)
{
jpaDefinedAccessType = AccessType.getAccessStrategy(access.value());
}
if (hibernateDefinedAccessType != AccessType.DEFAULT && jpaDefinedAccessType != AccessType.DEFAULT && hibernateDefinedAccessType != jpaDefinedAccessType)
{
throw new org.hibernate.MappingException("@AccessType and @Access specified with contradicting values. Use of @Access only is recommended. ");
}
else
{
AccessType classDefinedAccessType;
if (hibernateDefinedAccessType != AccessType.DEFAULT)
{
classDefinedAccessType = hibernateDefinedAccessType;
}
else
{
classDefinedAccessType = jpaDefinedAccessType;
}
return classDefinedAccessType;
}
}
private static boolean discoverTypeWithoutReflection(XProperty p)
{
if (p.isAnnotationPresent(OneToOne.class) && !((OneToOne) p.getAnnotation(OneToOne.class)).targetEntity().equals(Void.TYPE))
{
return true;
}
else if (p.isAnnotationPresent(OneToMany.class) && !((OneToMany) p.getAnnotation(OneToMany.class)).targetEntity().equals(Void.TYPE))
{
return true;
}
else if (p.isAnnotationPresent(ManyToOne.class) && !((ManyToOne) p.getAnnotation(ManyToOne.class)).targetEntity().equals(Void.TYPE))
{
return true;
}
else if (p.isAnnotationPresent(ManyToMany.class) && !((ManyToMany) p.getAnnotation(ManyToMany.class)).targetEntity().equals(Void.TYPE))
{
return true;
}
else if (p.isAnnotationPresent(Any.class))
{
return true;
}
else if (p.isAnnotationPresent(ManyToAny.class))
{
if (!p.isCollection() && !p.isArray())
{
throw new AnnotationException("@ManyToAny used on a non collection non array property: " + p.getName());
}
else
{
return true;
}
}
else if (p.isAnnotationPresent(Type.class))
{
return true;
}
else
{
return p.isAnnotationPresent(Target.class);
}
}
private static boolean mustBeSkipped(XProperty property)
{
return property.isAnnotationPresent(Transient.class) || "net.sf.cglib.transform.impl.InterceptFieldCallback".equals(property.getType().getName());
}
}
InheritanceState.java
示例
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.cfg;
import org.hibernate.AnnotationException;
import org.hibernate.annotations.common.reflection.XAnnotatedElement;
import org.hibernate.annotations.common.reflection.XClass;
import org.hibernate.annotations.common.reflection.XProperty;
import org.hibernate.boot.spi.MetadataBuildingContext;
import org.hibernate.cfg.annotations.EntityBinder;
import org.hibernate.mapping.PersistentClass;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
/**
* SpringBoot Jpa按照顺序生成数据库表字段
* 1.当实体类继承有父类时,重新自定义生成表顺序,配合{@link PropertyContainer}使用!
* 2.此类依赖父类“cn.keyidea.common.bean.BaseModel”全路径地址,移动后请更改!
* <p>
* 依赖包见:hibernate-core-5.6.11.Final.jar
* 源码参见:org.hibernate.cfg.InheritanceState
*
* @since 2023-10-17
*/
public class InheritanceState {
private final static Logger logger = LoggerFactory.getLogger(InheritanceState.class);
private XClass clazz;
/**
* Has sibling (either mappedsuperclass entity)
*/
private boolean hasSiblings = false;
/**
* a mother entity is available
*/
private boolean hasParents = false;
private InheritanceType type;
private boolean isEmbeddableSuperclass = false;
private Map<XClass, InheritanceState> inheritanceStatePerClass;
private List<XClass> classesToProcessForMappedSuperclass = new ArrayList<XClass>();
private MetadataBuildingContext buildingContext;
private AccessType accessType;
private ElementsToProcess elementsToProcess;
private Boolean hasIdClassOrEmbeddedId;
public InheritanceState(
XClass clazz,
Map<XClass, InheritanceState> inheritanceStatePerClass,
MetadataBuildingContext buildingContext) {
this.setClazz(clazz);
this.buildingContext = buildingContext;
this.inheritanceStatePerClass = inheritanceStatePerClass;
extractInheritanceType();
}
private void extractInheritanceType() {
XAnnotatedElement element = getClazz();
Inheritance inhAnn = element.getAnnotation(Inheritance.class);
MappedSuperclass mappedSuperClass = element.getAnnotation(MappedSuperclass.class);
if (mappedSuperClass != null) {
setEmbeddableSuperclass(true);
setType(inhAnn == null ? null : inhAnn.strategy());
} else {
setType(inhAnn == null ? InheritanceType.SINGLE_TABLE : inhAnn.strategy());
}
}
boolean hasTable() {
return !hasParents() || !InheritanceType.SINGLE_TABLE.equals(getType());
}
boolean hasDenormalizedTable() {
return hasParents() && InheritanceType.TABLE_PER_CLASS.equals(getType());
}
public static InheritanceState getInheritanceStateOfSuperEntity(
XClass clazz, Map<XClass, InheritanceState> states
) {
XClass superclass = clazz;
do {
superclass = superclass.getSuperclass();
InheritanceState currentState = states.get(superclass);
if (currentState != null && !currentState.isEmbeddableSuperclass()) {
return currentState;
}
}
while (superclass != null && !Object.class.getName().equals(superclass.getName()));
return null;
}
public static InheritanceState getSuperclassInheritanceState(XClass clazz, Map<XClass, InheritanceState> states) {
XClass superclass = clazz;
do {
superclass = superclass.getSuperclass();
InheritanceState currentState = states.get(superclass);
if (currentState != null) {
return currentState;
}
}
while (superclass != null && !Object.class.getName().equals(superclass.getName()));
return null;
}
public XClass getClazz() {
return clazz;
}
public void setClazz(XClass clazz) {
this.clazz = clazz;
}
public boolean hasSiblings() {
return hasSiblings;
}
public void setHasSiblings(boolean hasSiblings) {
this.hasSiblings = hasSiblings;
}
public boolean hasParents() {
return hasParents;
}
public void setHasParents(boolean hasParents) {
this.hasParents = hasParents;
}
public InheritanceType getType() {
return type;
}
public void setType(InheritanceType type) {
this.type = type;
}
public boolean isEmbeddableSuperclass() {
return isEmbeddableSuperclass;
}
public void setEmbeddableSuperclass(boolean embeddableSuperclass) {
isEmbeddableSuperclass = embeddableSuperclass;
}
void postProcess(PersistentClass persistenceClass, EntityBinder entityBinder) {
//make sure we run elements to process
getElementsToProcess();
addMappedSuperClassInMetadata(persistenceClass);
entityBinder.setPropertyAccessType(accessType);
}
public XClass getClassWithIdClass(boolean evenIfSubclass) {
if (!evenIfSubclass && hasParents()) {
return null;
}
if (clazz.isAnnotationPresent(IdClass.class)) {
return clazz;
} else {
InheritanceState state = InheritanceState.getSuperclassInheritanceState(clazz, inheritanceStatePerClass);
if (state != null) {
return state.getClassWithIdClass(true);
} else {
return null;
}
}
}
public Boolean hasIdClassOrEmbeddedId() {
if (hasIdClassOrEmbeddedId == null) {
hasIdClassOrEmbeddedId = false;
if (getClassWithIdClass(true) != null) {
hasIdClassOrEmbeddedId = true;
} else {
final ElementsToProcess process = getElementsToProcess();
for (PropertyData property : process.getElements()) {
if (property.getProperty().isAnnotationPresent(EmbeddedId.class)) {
hasIdClassOrEmbeddedId = true;
break;
}
}
}
}
return hasIdClassOrEmbeddedId;
}
/*
* Get the annotated elements and determine access type from hierarchy, guessing from @Id or @EmbeddedId presence if not
* specified.
* Change EntityBinder by side effect
*/
public ElementsToProcess getElementsToProcess() {
if (elementsToProcess == null) {
InheritanceState inheritanceState = inheritanceStatePerClass.get(clazz);
assert !inheritanceState.isEmbeddableSuperclass();
getMappedSuperclassesTillNextEntityOrdered();
accessType = determineDefaultAccessType();
ArrayList<PropertyData> elements = new ArrayList<PropertyData>();
int idPropertyCount = 0;
for (XClass classToProcessForMappedSuperclass : classesToProcessForMappedSuperclass) {
PropertyContainer propertyContainer = new PropertyContainer(
classToProcessForMappedSuperclass,
clazz,
accessType
);
int currentIdPropertyCount = AnnotationBinder.addElementsOfClass(
elements,
propertyContainer,
buildingContext
);
idPropertyCount += currentIdPropertyCount;
}
if (idPropertyCount == 0 && !inheritanceState.hasParents()) {
throw new AnnotationException("No identifier specified for entity: " + clazz.getName());
}
elements.trimToSize();
// 自定义排序字段
if (Objects.equals(elements.get(0).getDeclaringClass().toString(), "cn.keyidea.common.bean.BaseModel")) {
// logger.info("此表继承父类:{}", elements.get(5).getDeclaringClass().toString());
for (int i = 0; i < 4; i++) {
// 由于BaseModel父类中有4个元素,因此循环4次,将父类中除id之外的四个属性移到末尾
moveElementToLast(elements, 1);
}
} else {
// logger.info("此表不继承父类:{}", elements.get(5).getDeclaringClass().toString());
}
// logger.info("element={}", elements);
// for (PropertyData element : elements) {
// logger.info("表字段属性:{}", element.getPropertyName());
// }
elementsToProcess = new ElementsToProcess(elements, idPropertyCount);
}
return elementsToProcess;
}
private AccessType determineDefaultAccessType() {
for (XClass xclass = clazz; xclass != null; xclass = xclass.getSuperclass()) {
if ((xclass.getSuperclass() == null || Object.class.getName().equals(xclass.getSuperclass().getName()))
&& (xclass.isAnnotationPresent(Entity.class) || xclass.isAnnotationPresent(MappedSuperclass.class))
&& xclass.isAnnotationPresent(Access.class)) {
return AccessType.getAccessStrategy(xclass.getAnnotation(Access.class).value());
}
}
// Guess from identifier.
// FIX: Shouldn't this be determined by the first attribute (i.e., field or property) with annotations, but without an
// explicit Access annotation, according to JPA 2.0 spec 2.3.1: Default Access Type?
for (XClass xclass = clazz; xclass != null && !Object.class.getName().equals(xclass.getName()); xclass = xclass.getSuperclass()) {
if (xclass.isAnnotationPresent(Entity.class) || xclass.isAnnotationPresent(MappedSuperclass.class)) {
for (XProperty prop : xclass.getDeclaredProperties(AccessType.PROPERTY.getType())) {
final boolean isEmbeddedId = prop.isAnnotationPresent(EmbeddedId.class);
if (prop.isAnnotationPresent(Id.class) || isEmbeddedId) {
return AccessType.PROPERTY;
}
}
for (XProperty prop : xclass.getDeclaredProperties(AccessType.FIELD.getType())) {
final boolean isEmbeddedId = prop.isAnnotationPresent(EmbeddedId.class);
if (prop.isAnnotationPresent(Id.class) || isEmbeddedId) {
return AccessType.FIELD;
}
}
}
}
throw new AnnotationException("No identifier specified for entity: " + clazz);
}
private void getMappedSuperclassesTillNextEntityOrdered() {
//ordered to allow proper messages on properties subclassing
XClass currentClassInHierarchy = clazz;
InheritanceState superclassState;
do {
classesToProcessForMappedSuperclass.add(0, currentClassInHierarchy);
XClass superClass = currentClassInHierarchy;
do {
superClass = superClass.getSuperclass();
superclassState = inheritanceStatePerClass.get(superClass);
}
while (superClass != null
&& !buildingContext.getBootstrapContext().getReflectionManager().equals(superClass, Object.class)
&& superclassState == null);
currentClassInHierarchy = superClass;
}
while (superclassState != null && superclassState.isEmbeddableSuperclass());
}
private void addMappedSuperClassInMetadata(PersistentClass persistentClass) {
//add @MappedSuperclass in the metadata
// classes from 0 to n-1 are @MappedSuperclass and should be linked
org.hibernate.mapping.MappedSuperclass mappedSuperclass = null;
final InheritanceState superEntityState =
InheritanceState.getInheritanceStateOfSuperEntity(clazz, inheritanceStatePerClass);
PersistentClass superEntity =
superEntityState != null ?
buildingContext.getMetadataCollector().getEntityBinding(superEntityState.getClazz().getName()) :
null;
final int lastMappedSuperclass = classesToProcessForMappedSuperclass.size() - 1;
for (int index = 0; index < lastMappedSuperclass; index++) {
org.hibernate.mapping.MappedSuperclass parentSuperclass = mappedSuperclass;
final Class<?> type = buildingContext.getBootstrapContext().getReflectionManager()
.toClass(classesToProcessForMappedSuperclass.get(index));
//add MappedSuperclass if not already there
mappedSuperclass = buildingContext.getMetadataCollector().getMappedSuperclass(type);
if (mappedSuperclass == null) {
mappedSuperclass = new org.hibernate.mapping.MappedSuperclass(parentSuperclass, superEntity);
mappedSuperclass.setMappedClass(type);
buildingContext.getMetadataCollector().addMappedSuperclass(type, mappedSuperclass);
}
}
if (mappedSuperclass != null) {
persistentClass.setSuperMappedSuperclass(mappedSuperclass);
}
}
static final class ElementsToProcess {
private final List<PropertyData> properties;
private final int idPropertyCount;
public List<PropertyData> getElements() {
return properties;
}
public int getIdPropertyCount() {
return idPropertyCount;
}
private ElementsToProcess(List<PropertyData> properties, int idPropertyCount) {
this.properties = properties;
this.idPropertyCount = idPropertyCount;
}
}
/**
* 将List集中中指定元素移动到最后
*
* @param list 集合对象
* @param index 集合序号
* @param <T> 返回集合
*/
public static <T> void moveElementToLast(List<T> list, int index) {
if (list != null && index >= 0 && index < list.size()) {
// 移除指定位置的元素
T element = list.remove(index);
// 添加该元素到列表的末尾
list.add(element);
}
}
}
父类BaseModel示例
package cn.keyidea.common.bean;
import cn.keyidea.common.valid.GroupChangePwd;
import cn.keyidea.common.valid.GroupCustomWithId;
import cn.keyidea.common.valid.GroupStatus;
import cn.keyidea.common.valid.GroupUpdate;
import com.alibaba.fastjson.annotation.JSONField;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.SuperBuilder;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
import javax.persistence.*;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
import java.util.Date;
/**
* 实体父类
* <p>
* 特殊说明:
* 继承此基类的实体类,如果使用lombok的@Data注解时,主要同时添加@EqualsAndHashCode(callSuper = true)注解
* 1)注解@EqualsAndHashCode(callSuper = true),就是用自己的属性和从父类继承的属性来生成hashcode;
* 2)注解@EqualsAndHashCode(callSuper = false),就是只用自己的属性来生成hashcode;
* 3)@Data相当于@Getter @Setter @RequiredArgsConstructor @ToString @EqualsAndHashCode这5个注解的合集, 和@EqualsAndHashCode默认是false。
* <p>
* MappedSuperclass注解说明:
* 1.@MappedSuperclass注解仅仅能标准在类上;这个注解标识在父类上面的,用来标识父类
* 2.标注为@MappedSuperclass的类将不是一个完整的实体类,他将不会映射到数据库表,可是他的属性都将映射到其子类的数据库字段中
* 3.标注为@MappedSuperclass的类不能再标注@Entity或@Table注解
* <p>
* EntityListeners注解及相关说明:
* EntityListeners:该注解用于指定Entity或者superclass上的回调监听类
* AuditingEntityListener:这是一个JPA Entity Listener,用于捕获监听信息,当Entity发生持久化和更新操作时
*
* @date 2022-10-17
*/
@SuperBuilder // @SuperBuilder支持对基类成员属性的构造;如果子类继承了BaseModel,也需要使用该注解
@AllArgsConstructor // 全参构造函数
@NoArgsConstructor // 空参构造函数
@Data
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
public class BaseModel implements Serializable
{
private static final long serialVersionUID = -7321769721953580032L;
@NotNull(message = "ID不能为NUll", groups = {GroupUpdate.class, GroupChangePwd.class, GroupCustomWithId.class, GroupStatus.class})
@ApiModelProperty(value = "主键ID", required = true, example = "1")
@Id
@Column(name = "id", columnDefinition = "int(10) COMMENT '自增长ID'")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@ApiModelProperty(value = "创建时间", required = false)
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@Column(name = "create_time", updatable = false, columnDefinition = "datetime not null COMMENT '创建时间'")
@TableField(value = "create_time", fill = FieldFill.INSERT)
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
private Date createTime;
@ApiModelProperty(value = "创建人ID", required = false)
@Column(name = "create_by", updatable = false, columnDefinition = "int(10) not null COMMENT '创建人ID'")
@TableField(value = "create_by", fill = FieldFill.INSERT)
private Integer createBy;
@ApiModelProperty(value = "更新时间", required = false)
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@Column(name = "update_time", columnDefinition = "datetime COMMENT '更新时间'")
@TableField(value = "update_time", fill = FieldFill.UPDATE)
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
private Date updateTime;
@ApiModelProperty(value = "更新人ID", required = false)
@Column(name = "update_by", columnDefinition = "int(10) COMMENT '更新人ID'")
@TableField(value = "update_by", fill = FieldFill.UPDATE)
private Integer updateBy;
}
系统配置实体类示例
package cn.keyidea.sys.entity;
import cn.keyidea.common.bean.BaseModel;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Table;
import javax.validation.constraints.NotBlank;
/**
* 系统配置表
*
* @date 2022-10-17
*/
@Data
@EqualsAndHashCode(callSuper = true)
@Entity
@TableName("sys_config")
@Table(name = "sys_config")
@ApiModel(value = "SysConfig", description = "系统配置")
@org.hibernate.annotations.Table(appliesTo = "sys_config", comment = "系统配置表")
public class SysConfig extends BaseModel
{
@NotBlank(message = "配置名称不能为空")
@ApiModelProperty(value = "配置名称", required = true, example = "名称1")
@Column(name = "name", columnDefinition = "varchar(50) not null COMMENT '配置名称'")
private String name;
@NotBlank(message = "配置key值为空")
@ApiModelProperty(value = "配置key值", required = true, example = "code1")
@Column(name = "code", columnDefinition = "varchar(50) not null COMMENT '配置key值'")
private String code;
@NotBlank(message = "配置项值为空")
@ApiModelProperty(value = "配置项值", required = true, example = "value1")
@Column(name = "value", columnDefinition = "varchar(50) not null COMMENT '配置项值'")
private String value;
@ApiModelProperty(value = "配置项描述", required = true, example = "说明/描述")
@Column(name = "remark", columnDefinition = "varchar(255) COMMENT '配置项描述'")
private String remark;
}
参考
网友评论