Spring Jpa这个问题怎么解决?

开发 前端
spring jpa是基于Habernate实现,同样我们需要基于接口org.hibernate.integrator.spi.Integrator,在生成ddl时进行扩展。

在使用spring-boot-starter-data-jpa时,通过这样的配置可以在程序启动后实现在指定数据库自动建表。

spring:
  jpa:
    hibernate:
      ddl-auto: update

但是这种方式建表后没办法为每一列增加对应的中文注释,有什么办法可以实现这一需求呢?

后面在网上找到了实现方法:

<dependency>
            <groupId>com.github.biyanwen</groupId>
            <artifactId>jpa-comment-spring-boot-starter</artifactId>
            <version>1.0.2</version>
        </dependency>

但是在当前项目中无效,后面发现部分依赖已经改变,应该是对高版本JPA不支持导致。今天基于该jar重新梳理实现过程。

实现方式

基于自定义注解以及Spring自动配置实现。

  1. 定义注解Comment,该注解定义在字段上,定义该列的中文描述。
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface Comment {
    /**
     * 注释的值
     *
     * @return {@link String}
     */
    String value() default "";
}
  1. spring jpa是基于Habernate实现,同样我们需要基于接口org.hibernate.integrator.spi.Integrator,在生成ddl时进行扩展。
public class CommentIntegrator implements Integrator {
    public static final CommentIntegrator INSTANCE = new CommentIntegrator();

    public CommentIntegrator() {
        super();
    }

    @Override
    public void integrate(Metadata metadata, BootstrapContext bootstrapContext, SessionFactoryImplementor sessionFactory) {
        processComment(metadata);
    }

    /**
     * Not used.
     *
     * @param sessionFactoryImplementor     The session factory being closed.
     * @param sessionFactoryServiceRegistry That session factory's service registry
     */
    @Override
    public void disintegrate(SessionFactoryImplementor sessionFactoryImplementor, SessionFactoryServiceRegistry sessionFactoryServiceRegistry) {
    }

    /**
     * 生成注释代码
     *
     * @param metadata process annotation of this {@code Metadata}.
     */
    protected void processComment(Metadata metadata) {
        for (PersistentClass persistentClass : metadata.getEntityBindings()) {
            Class<?> clz = persistentClass.getMappedClass();
            if (clz.isAnnotationPresent(Comment.class)) {
                Comment comment = clz.getAnnotation(Comment.class);
                persistentClass.getTable().setComment(comment.value());
            }
            Property identifierProperty = persistentClass.getIdentifierProperty();
            if (identifierProperty != null) {
                propertyComment(persistentClass, identifierProperty.getName());
            } else {
                org.hibernate.mapping.Component component = persistentClass.getIdentifierMapper();
                if (component != null) {
                    Iterator<Property> iterator = component.getPropertyIterator();
                    while (iterator.hasNext()) {
                        propertyComment(persistentClass, iterator.next().getName());
                    }
                }
            }
            Iterator<Property> iterator = persistentClass.getProperties().iterator();
            while (iterator.hasNext()) {
                propertyComment(persistentClass, iterator.next().getName());
            }
        }
    }

    /**
     * 为属性生成注释
     *
     * @param persistentClass Hibernate {@code PersistentClass}
     * @param columnName      name of field
     */
    private void propertyComment(PersistentClass persistentClass, String columnName) {
        try {
            String comment = getPropertyComment(persistentClass, columnName);
            Value value = persistentClass.getProperty(columnName).getValue();
            if( value.getColumns().iterator().hasNext() ){
                String sqlColumnName = value.getColumns().iterator().next().getText();
                Iterator<org.hibernate.mapping.Column> columnIterator = persistentClass.getTable().getColumns().iterator();
                while (columnIterator.hasNext()) {
                    org.hibernate.mapping.Column column = columnIterator.next();
                    if (sqlColumnName.equalsIgnoreCase(column.getName())) {
                        column.setComment(comment);
                        break;
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private String getPropertyComment(PersistentClass persistentClass, String columnName) throws Exception {
        String comment = null;

        Field field = ReflectionUtils.findField(persistentClass.getMappedClass(), columnName);
        if (field != null) {
            if (field.isAnnotationPresent(Comment.class)) {
                comment = field.getAnnotation(Comment.class).value();
            } else {
                PropertyDescriptor descriptor = new PropertyDescriptor(field.getName(), persistentClass.getMappedClass());
                Method readMethod = descriptor.getReadMethod();
                Comment comment1 = readMethod.getAnnotation(Comment.class);
                if (comment1 != null) {
                    comment = comment1.value();
                }
            }
        }
        return comment;
    }
}
  1. 定义配置类,对HibernatePropertiesCustomizer进行扩展。
public class HibernateProperties implements HibernatePropertiesCustomizer {
    @Override
    public void customize(Map<String, Object> hibernateProperties) {
        hibernateProperties.put("hibernate.integrator_provider",    (IntegratorProvider) () -> Collections.singletonList(CommentIntegrator.INSTANCE));
    }
}
  1. 定义spring配置,实现自动装配。

在resource目录添加自动注入配置META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports,这样通过引入jar就可以自动使用该配置。

cn.cycad.jpa.comment.config.CommentConfig

应用示例

  1. 比如现在有一个User实体,我们通过继承基类。
@Entity
@Table(name = "t_user")
@Data
public class User extends Domain {

    @Id
    @Comment("业务主键")
    private String id;

    @Comment("用户名称")
    private String caption;

    @Comment("用户年龄")
    private Integer age;
    
}
  1. 启动服务后,可以看到控制台输出的建表语句信息。
Hibernate: 
    create table t_user (
        id varchar(255) not null,
        create_time timestamp(6),
        creator varchar(56),
        modified_time timestamp(6),
        modifier varchar(56),
        age integer,
        caption varchar(255),
        primary key (id)
    )
Hibernate: 
    comment on column t_user.id is
        '业务主键'
Hibernate: 
    comment on column t_user.age is
        '用户年龄'
Hibernate: 
    comment on column t_user.caption is
        '用户名称'

责任编辑:武晓燕 来源: Java技术指北
相关推荐

2012-03-06 11:25:40

ibmdw

2021-10-06 23:31:45

HibernateJPASpring Data

2009-06-01 12:04:38

JPASpringJAVA

2022-04-28 08:05:05

数据库数据库交互

2013-08-01 10:05:54

大数据信息安全

2023-05-23 10:01:51

幂等性抽象代数

2013-09-22 10:15:01

Spring DataJPA

2009-06-18 15:28:08

Glassfish JSpring

2021-06-08 08:38:36

MySQL数据库死锁问题

2009-06-01 16:18:30

SpringJPA集成

2009-06-18 13:44:05

Spring2.0spring2.5

2019-11-26 14:30:20

Spring循环依赖Java

2022-07-13 08:53:28

函数Go语言

2022-08-27 15:15:31

iOS耗电后台

2022-08-01 09:43:19

程序员Googlefacebook

2024-02-26 08:21:51

CPUkafka死循环

2023-12-26 17:07:56

GenAICIO

2024-02-26 08:42:10

乱码UTF-8编码

2024-11-29 07:42:47

2019-07-03 15:01:30

戴尔
点赞
收藏

51CTO技术栈公众号