美文网首页
SpringBoot集成Jpa使用Hibernate生成表字段乱

SpringBoot集成Jpa使用Hibernate生成表字段乱

作者: 静美书斋 | 来源:发表于2023-10-16 20:23 被阅读0次

环境

  • 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;

}

参考

相关文章

网友评论

      本文标题:SpringBoot集成Jpa使用Hibernate生成表字段乱

      本文链接:https://www.haomeiwen.com/subject/rzqfidtx.html