当前位置:   article > 正文

使用sqlalchemy生成java中的实体类(一)_sql转java实体

sql转java实体

介绍

sqlalchemy

sqlalchemy是python的第三方库,提供了SQL工具和对象关系映射(ORM)工具,类似的还有Django ORM等。

java实体类

比如有个学生类stduent,属性和方法如图所示

可以在IntelliJ IDEA中,通过快捷键alt+insert生成对应的方法。

二者的联系

java的ORM框架,比如Mybatis等,假设现在有张stduent表,定义如下

  1. create table student(
  2. id int primary key auto_increment not null comment '学号',
  3. name varchar(16) not null comment '姓名',
  4. age int not null comment '年龄'
  5. )

如果要通过Mybatis实现CRUD操作,显然需要实体类student,笔者举得例子比较简单,如果表的属性比较多或者表很多,每加入个表都需要实体类,写起来就会繁琐。因此,笔者想法是通过sqlalchemy读取表,然后生成实体类,或者说生成Studnet.java文件。

实现的过程

以student表为例。表中id的类型为int,转换成实体类则id的类型变成Integer或者int。其他也是类似的,而且实体类的实现很相似,先写属性,然后是get方法、set方法,构造函数、toString方法的实现。

既然如此,python可以通过字符串的拼接实现,但可能更繁杂,因此,笔者决定使用模板语法,使用jinja2,当然还有其他模板语法,比如Djang Template Lanage等。jinja2也是python的第三方库。

jinja2

 Jinja是一个基于Python设计语言的“全功能模板引擎”,下面简单的使用一下jinja2

  1. from jinja2 import Template
  2. template = Template('hello {{text}}')
  3. result=template.render(text='jinja2')
  4. print(result)

结果如下。

具体可参考jinja2的官方文件。

欢迎来到 Jinja2 — Jinja2 2.7 documentation (jinkan.org)

正文

写之前先创建一个目录,目录名叫python_sql_java,其中创建一个settings.py文件。代码如下,

  1. from sqlalchemy import create_engine,MetaData
  2. # 数据库、驱动、用户、密码、ip、端口、端口号、数据库
  3. engine=create_engine('mysql+pymysql://root:123456@localhost:3306/sqlalchemy') # 获得engine
  4. # metadata对象
  5. metadata=MetaData()

读取属性及类型

这一步其实可以不通过sqlalchemy,可以用pymysql,但相对来说,用sqlalchemy更好,毕竟已经是封装好的框架,不需要写sql语句

第一种方法

在python_sql_java文件下创建get_sql.py文件。其中代码如下。

  1. from sqlalchemy import Table, inspect
  2. from settings import engine, metadata
  3. sql_java = {
  4. 'Varchar': 'String',
  5. }
  6. def get_sql_word_type(table_name) -> list:
  7. """
  8. :param table: 表名
  9. :return: list
  10. """
  11. inspector = inspect(engine)
  12. columns = inspector.get_columns(table_name)
  13. words = []
  14. for column in columns:
  15. word_type = type(column['type']).__name__.capitalize()
  16. if word_type in sql_java.keys():
  17. word_type = sql_java[word_type]
  18. word_name = column['name']
  19. words.append({'word_name': word_name, 'word_type': word_type})
  20. return words
  21. properties = get_sql_word_type('student')
  22. for property in properties:
  23. print(property)

打印结果如下。

也可以选择把Integer变成int类型的,或者还有其他类型的替换,差不多,具体情况具体分析。

第二种方法

通过pandas的read_sql_table方法,获取类型,实际上查不多,没什么区别,代码如下

  1. import pandas as pd
  2. from settings import engine
  3. sql_java = {
  4. 'int64': 'Integer',
  5. 'object': 'String',
  6. }
  7. def get_sql_word_type(table_name):
  8. df = pd.read_sql_table(table_name, con=engine)
  9. field_info = []
  10. for column in df.columns:
  11. field_name = column
  12. field_type = str(df[column].dtype)
  13. if field_type in sql_java:
  14. field_type = sql_java[field_type]
  15. field_info.append([field_name, field_type])
  16. return field_info
  17. field_info = get_sql_word_type('student')
  18. for i in field_info:
  19. print(i)

结果如下,笔者后面将使用第一种方法

创建jinja2模板

实体类的样子

在写模板之前,先看一下IntelliJ IDEA生成的实体类Student。

  1. public class stduent {
  2. private Integer id;
  3. private String name;
  4. private Integer age;
  5. public stduent() {
  6. }
  7. public stduent(Integer id, String name, Integer age) {
  8. this.id = id;
  9. this.name = name;
  10. this.age = age;
  11. }
  12. public Integer getId() {
  13. return id;
  14. }
  15. public void setId(Integer id) {
  16. this.id = id;
  17. }
  18. public String getName() {
  19. return name;
  20. }
  21. public void setName(String name) {
  22. this.name = name;
  23. }
  24. public Integer getAge() {
  25. return age;
  26. }
  27. public void setAge(Integer age) {
  28. this.age = age;
  29. }
  30. @Override
  31. public String toString() {
  32. return "stduent{" +
  33. "id=" + id +
  34. ", name='" + name + '\'' +
  35. ", age=" + age +
  36. '}';
  37. }
  38. }

写模板前的准备

现在对上面代码进行模仿。

在模仿之前,先在当前目录(python_sql_java)下进行一个包,叫templates,其中放模板

在templates目录下进行一个entity.java文件,作为模板。

在python_sql_java目录新建一个mapper.py和render.py,

模板

根据上面实体类,entity的代码如下

  1. public class {{table_name | capitalize}}{ {#类名#}
  2. {%- for property in properties %} {# 属性 #}
  3. private {{property.word_type}} {{property.word_name}};
  4. {%- endfor %}
  5. public {{table_name | capitalize}}() { {# 无参构造 #}
  6. }
  7. public {{table_name | capitalize}}({# 有参构造 #}
  8. {%- for property in properties -%}
  9. {%- if loop.last -%}
  10. {{property.word_type}} {{property.word_name}}
  11. {%- else -%}
  12. {{property.word_type}} {{property.word_name}},
  13. {%-endif-%}
  14. {% endfor -%}
  15. ) {
  16. {%- for property in properties %}
  17. this.{{property.word_name}} = {{property.word_name}};
  18. {%- endfor %}
  19. }
  20. {% for property in properties %} {# get方法 #}
  21. public {{property.word_type}} get{{property.word_name | capitalize }}() {
  22. return {{property.word_name}};
  23. }
  24. {% endfor%}
  25. {% for property in properties %} {# set方法 #}
  26. public void set{{property.word_name | capitalize }}({{property.word_type}} {{property.word_name}}) {
  27. this.{{property.word_name}}={{property.word_name}};
  28. }
  29. {% endfor%}
  30. @Override
  31. public String toString() { {# toString方法 #}
  32. return "{{table_name | capitalize}}{" +
  33. {% for property in properties %}
  34. {%- if loop.first -%}
  35. "{{property.word_name}}=" + {{property.word_name}} +
  36. {% elif loop.last%}
  37. ",{{property.word_name}}=" + {{property.word_name}} +
  38. {%- else -%}
  39. ", {{property.word_name}}='" + {{property.word_name}} + '\'' +
  40. {%- endif -%}
  41. {% endfor %}
  42. '}';
  43. }
  44. }

渲染

render.py的代码如下

  1. from jinja2 import FileSystemLoader,Environment
  2. def get_mapper(table_name,properties):
  3. loader = FileSystemLoader('./templates')
  4. environment = Environment(loader=loader)
  5. template = environment.get_template('entity.java')
  6. return template.render(
  7. table_name=table_name,
  8. properties=properties
  9. )
  10. properties=[{'word_name': 'id', 'word_type': 'Integer'}, {'word_name': 'name', 'word_type': 'String'}, {'word_name': 'age', 'word_type': 'Integer'}]
  11. java=get_mapper('student',properties)
  12. print(java)

运行后结果如图所示

渲染后的结果还是可以的。

最终的代码

在mapper.py文件中写下最终的代码。

  1. from jinja2 import Template, FileSystemLoader, Environment
  2. from sqlalchemy import Table, inspect
  3. from settings import engine, metadata
  4. import os
  5. class Entity:
  6. def __init__(self, table_name):
  7. self.table_name = table_name
  8. self.sql_java = {
  9. 'Varchar': 'String',
  10. }
  11. def get_sql_word_type(self) -> list:
  12. """
  13. :return: list
  14. """
  15. inspector = inspect(engine)
  16. columns = inspector.get_columns(self.table_name)
  17. words = []
  18. for column in columns:
  19. word_type = type(column['type']).__name__.capitalize()
  20. if word_type in self.sql_java.keys():
  21. word_type = self.sql_java[word_type]
  22. word_name = column['name']
  23. words.append({'word_name': word_name, 'word_type': word_type})
  24. return words
  25. def get_mapper(self)->str:
  26. words = self.get_sql_word_type()
  27. loader = FileSystemLoader('./templates')
  28. environment = Environment(loader=loader)
  29. template = environment.get_template('entity.java')
  30. return template.render(
  31. table_name='student',
  32. properties=words
  33. )
  34. def get_result(self, java_str, file_path=None):
  35. if not file_path:
  36. file_path = f'{self.table_name}.java'
  37. if not os.path.exists(file_path):
  38. open(file_path, 'w').close()
  39. with open(file_path, 'w') as f:
  40. f.write(java_str)
  41. @staticmethod
  42. def start(table_name, file_path=None):
  43. entity = Entity(table_name)
  44. java = entity.get_mapper()
  45. entity.get_result(java)
  46. Entity.start('student')

运行后在当前目录下生成student.java文件,内容和上面的java一样。

因为这个实体的属性比较少,运行没有问题,但不一定全部适用,可以会有问题,后面会继续修改。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/2023面试高手/article/detail/613177
推荐阅读
相关标签
  

闽ICP备14008679号