快速了解“轻便式BESP.Han(汉)框架”

BESP.Han

BESP.Han是基于java语言并以jfinal框架为基础,优化升级的轻量级动态语言开发框架。

:rocket: 项目特性

  • 模块化架构: 采用 Maven 多模块设计,便于维护和扩展

  • 轻量级框架: 基于 JFinal 5.2.6,性能优异

  • 企业级功能: 集成 Redis、MySQL、瀚高、Quartz、MinIO 等企业级组件

  • 高性能服务器: 基于 Undertow 服务器,支持 WebSocket

  • 代码生成: 提供实体类代码生成器,提高开发效率

  • 多环境支持: 支持 local、dev、prod 多环境配置

:file_folder: 项目结构

BESP.Han/
├── app/                  # 示例模块 - 主启动模块
│   ├── han.sh            # 启动脚本
│   ├── package.xml       # 打包配置
│   ├── pom.xml           # Maven 配置
│   └── src/              # 源代码
│       ├── main/
│       └── test/
├── common/                # 公共模块 - 通用工具类和基础组件
│   ├── pom.xml
│   └── src/
│       ├── main/
│       └── test/
├── core/                  # 核心模块 - 框架核心功能
│   ├── pom.xml
│   └── src/
│       ├── main/
│       └── test/
├── plugin/                # 插件模块 - 各种功能插件
│   ├── launcher/          # 启动器插件
│   ├── log4j2-plugin/     # 日志插件
│   ├── minio/             # MinIO 对象存储插件
│   ├── quartz/            # 定时任务插件
│   ├── hangao/            # 瀚高数据库插件
│   └── ......             # 其他
│   └── pom.xml
├── .gitignore
├── README.md
└── pom.xml               # 父级 Maven 配置

开发指南

参数验证

框架提供了便捷的参数验证功能:

1. 方法级别验证

@NotBlank("name")
public void index(String name){
    System.out.println(name);
}

2. 参数级别验证

public void index(@NotBlank String name){
    System.out.println(name);
}

3. 支持的验证注解

  • @NotBlank: 非空验证
  • @Email: 邮箱验证
  • @Mobile: 手机号验证

参数接收配置

为了正确接收方法参数,需要配置编译器保留参数名:

Eclipse 配置

  1. 打开项目属性 → Java Build Path → Libraries
  2. 确认 Java 版本为 1.8+
  3. 在 Project Facets 中确认 Java 版本配置

IDEA 配置

添加编译参数 -parameters

  1. File → Settings → Build → Compiler → Java Compiler
  2. 在 Additional command line parameters 中添加 -parameters

Maven 配置

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>3.6.1</version>
    <configuration>
        <source>1.8</source>
        <target>1.8</target>
        <encoding>UTF-8</encoding>
        <!-- java8 保留参数名编译参数 -->
        <compilerArgument>-parameters</compilerArgument>
    </configuration>
</plugin>

如果无法配置参数保留,可使用 @Param 注解:

public void index(@Param("name") String name){
    System.out.println(name);
}

:file_cabinet: 数据库配置

基础配置

@Override
public void plugin(Plugins me, List<String> basePackages, ActiveRecordPlugin arp) {
    String user = PropKit.get("jdbc.user");
    String password = PropKit.get("jdbc.password");
    
    // 配置 druid 数据库连接池插件
    DruidPlugin druidPlugin = new DruidPlugin(PropKit.get("jdbc.url"), user, password);
    me.add(druidPlugin);
    
    // 配置ActiveRecord插件
    arp = new ActiveRecordPlugin(druidPlugin);
    basePackages.add("com.xxx.model");
}

多数据源配置

// 数据源2
DruidPlugin druidPlugin2 = new DruidPlugin(PropKit.get("jdbc2.url"), PropKit.get("jdbc2.user"), PropKit.get("jdbc2.password"));
// 数据源3
DruidPlugin druidPlugin3 = new DruidPlugin(PropKit.get("jdbc3.url"), PropKit.get("jdbc3.user"), PropKit.get("jdbc3.password"));

me.add(druidPlugin2);
me.add(druidPlugin3);

ActiveRecordPlugin arp2 = new ActiveRecordPlugin("db2", druidPlugin2);
me.add(arp2);
ActiveRecordPlugin arp3 = new ActiveRecordPlugin("db3", druidPlugin3);
me.add(arp3);

TableAnnotationScanner.scan(arp2, "com.xxx.model");
TableAnnotationScanner.scan(arp3, "com.xxx.model");

:bar_chart: Redis 配置

String redisHostName = PropKit.get("redis_host");
int redisPort = PropKit.getInt("redis_port");
String redisPassword = PropKit.get("redis_password");

RedisPlugin redisPlugin = null;
try {
    if (StrKit.notBlank(redisPassword)) {
        redisPlugin = new RedisPlugin("redis", redisHostName, redisPort, 30000, redisPassword);
    } else {
        redisPlugin = new RedisPlugin("redis", redisHostName, redisPort, 30000);
    }
    me.add(redisPlugin);
} catch (Exception e) {
    e.printStackTrace();
}

:hammer: 代码生成器

框架提供了强大的实体类代码生成器,可以根据数据库表结构自动生成 Model 类:

使用示例

package com.besp.w.admin.utils;

import com.jfinal.kit.Prop;
import com.jfinal.kit.PropKit;
import com.jfinal.plugin.activerecord.dialect.MysqlDialect;
import com.jfinal.plugin.activerecord.generator.TypeMapping;
import com.jfinal.plugin.druid.DruidPlugin;

import javax.sql.DataSource;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Date;

public class ModelCodeGenerateMysql {
    static Prop p;

    public static DataSource getDataSource() {
        DruidPlugin druidPlugin = createDruidPlugin();
        druidPlugin.start();
        return druidPlugin.getDataSource();
    }

    public static DruidPlugin createDruidPlugin() {
        p = PropKit.use("besp.properties");
        return new DruidPlugin(p.get("jdbc.url"), p.get("jdbc.user"), p.get("jdbc.password"));
    }

    public static void main(String[] args) {
        // model 所使用的包名 (MappingKit 默认使用的包名)
        String modelPackageName = "com.besp.w.model.entity";
        
        // base model 所使用的包名
        String baseModelPackageName = modelPackageName;
        
        // base model 文件保存路径
        String baseModelOutputDir = "E:\\model";

        BespGenerator generator = new BespGenerator(getDataSource(), baseModelPackageName, baseModelOutputDir);
        
        // 指定 MappingKit 文件生成的模板文件
        generator.setModelTemplate("besp_model.jf");
        
        // 配置是否生成备注
        generator.setGenerateRemarks(true);
        
        // 设置数据库方言
        generator.setDialect(new MysqlDialect());
        
        // 设置是否生成链式 setter 方法,强烈建议配置成 false,否则 fastjson 反序列化会跳过有返回值的 setter 方法
        generator.setGenerateChainSetter(false);
        
        // 添加不需要生成的表名到黑名单
        generator.addBlacklist("xxx", "xxx");
        
        // 设置是否在 Model 中生成 dao 对象
        generator.setGenerateDaoInModel(true);
        
        // 设置是否生成字典文件
        generator.setGenerateDataDictionary(false);
        
        // 设置需要被移除的表名前缀用于生成modelName。例如表名 "osc_user",移除前缀 "osc_"后生成的model名为 "User"而非 OscUser
        generator.setRemovedTableNamePrefixes("x_");
        
        // 将 mysql 8 以及其它原因之下生成 jdk 8 日期类型映射为 java.util.Date,便于兼容老项目,也便于习惯使用 java.util.Date 的同学
        TypeMapping tm = new TypeMapping();
        tm.addMapping(LocalDateTime.class, Date.class);
        tm.addMapping(LocalDate.class, Date.class);
        // tm.addMapping(LocalTime.class, LocalTime.class);		// LocalTime 暂时不变
        generator.setTypeMapping(tm);

        // 生成
        generator.generate();
    }
}

BESP.Han - 让 Java Web 开发更简单、更高效!