# SoJpt Boot **Repository Path**: sohnny/SoJpt-Boot ## Basic Information - **Project Name**: SoJpt Boot - **Description**: 在Spring Boot框架下使用Jfinal特性极速开发 可以在Spring Boot中向使用Jfinal一样使用Enjoy, controller的一系列方法(如: getFile(), renderFile....),以及ActiveRecord - **Primary Language**: Java - **License**: Apache-2.0 - **Default Branch**: 2.5.8-4.8 - **Homepage**: http://www.sojpt.com - **GVP Project**: No ## Statistics - **Stars**: 73 - **Forks**: 18 - **Created**: 2019-04-03 - **Last Updated**: 2025-05-14 ## Categories & Tags **Categories**: webframework, spring-boot-ext **Tags**: None ## README # [SoJpt Boot](http://www.sojpt.com/) #### 介绍 ![sojpt-logo](https://images.gitee.com/uploads/images/2019/0413/225742_5630cd4e_415067.png) #### 官方网站: www.sojpt.com 在[**Spring Boot**](http://www.sojpt.com/)框架下使用Jfinal特性极速开发 spring boot 为主, jfinal 为辅的混合双打模式, 既可以享受spring 的生态,又可以体验jfinal的极速开发. 可以在**Spring Boot**中向使用Jfinal一样使用Enjoy, Aop, controller的一系列方法(如: getFile(), renderFile....),以及ActiveRecord, 只有Jfinal的路由被去掉,其他Jfinal特性可以原生使用 **SoJpt-Boot-2.5.8-4.8 changelog** 1.升级为JFinal4.8 **SoJpt-Boot-2.5.8-4.7 changelog** 1.升级为JFinal4.7 **SoJpt-Boot-2.5.8-4.3 changelog** 1.升级为JFinal4.3 2.修复请求不能异步执行的问题 **SoJpt-Boot-2.5.7-4.2 changelog** 1.修复上传文件时不能传其它参数的bug 2.改善接收参数必须在接收文件后的问题, 不在有先后顺序的要求,避免新手入坑 **SoJpt-Boot-2.5.6-4.2 changelog** 1.升级为JFinal4.2 https://www.jfinal.com/ **SoJpt-Boot-2.5.8-3.8 changelog** 1..修复请求不能异步执行的问题 **SoJpt-Boot-2.5.6-3.8 changelog** 1.修复controller return 返回null问题 **SoJpt-Boot-2.5.5-3.8 changelog** 1、可以省去spring boot配置文件 (项目不需要的情况) 2、进一步优化,减少metaspace开销 3、兼容yml文件的配置 **SoJpt-Boot-2.5.4-3.8 changelog** 1、提升Controller并发处理性能 **SoJpt-Boot-2.5.3-3.8 changelog** 1、解决spring cloud 环境下报 UT010005: Cannot call getOutputStream(), getWriter() 2、加入路径容错, 3、修复上传文件报异常的bug 4、JsonRender.exclude方法优化renderJson报异常解决方案 **SoJpt-Boot-2.3-3.8 changelog** 1.加入事务注解,@Tx(value="configName", level=2), 可在servcie层及其他任何地方使用 value 数据源名称 ,默认为当前数据源 level 数据库事务等级配置, 默认为ActiveRecord配置的事务等级 2.优化代码,可使用 sojpt-boot-spring-boot-starter 自动配置 com.gitee.sohnny sojpt-boot-spring-boot-starter 2.3.2-3.8 3、同时发布官方最佳实践 SoJpt-Boot-Staging-mysql-v1.1 4、解决上个版本在内置tomcat环境系下不能启动的问题 **SoJpt-Boot-2.2-3.8 changelog** 1.修复 jfinal handler 配置失效问题, 发布2.2-3.8, 建议升级新版 **SoJpt-Boot-2.1-3.8 changelog** 1.修复 配置 server.servlet.context-path 时配置报空指针的异常。 2.修复 使用Validator时 不能返回请求的bug **SoJpt-Boot-2.0-3.8 changelog** 1. 配置方式,还原Jfinal原生配置,继承SoJptBootConfig即可。 2. 解决undertow并发环境下报异常的问题 3. 加入Aop、configConstant配置、configPlugin配置、configInterceptor全局拦截器配置、configHandler、configEngine、afterJFinalStart等一系列Jfinal原生配置模式。 4. 取消Tx注解、使用原生@Before(Tx.class)即可 5. 取消Jfinal原生包的引入,直接引入sojpt-boot依赖即可 6. 取消SoJptController, 继承Jfinal的Controller即可 总之,2.0+版本,直接引入Jfinal3.8的源代码,修改了其中几行,即实现了Spring Boot与Jfinal的混合双打,使Spring Boot环境下的开发者能够更好的体验Jfinal极速开发的特性,有更多的时间去配恋人或家人。 只要Jfinal有新版发布,SoJpt Boot会直接同步更新,因只修改几行代码,所以不用担心升级的复杂度。 #### 软件架构 基于 JFinal 与 Spring Boot制作, 实现Spring Boot与Jfinal的混合双打,使Spring Boot下的开发者能够体验Jfinal的极速开发特性,有更多的时间去配恋人或家人。 #### 安装教程 1. 在Spring Boot 2.0以上项目中 加入maven坐标 ```xml com.gitee.sohnny sojpt-boot-spring-boot-starter 2.5.8-4.8 ``` 2. 添加 SoJptBootConfig 配置类 ```java package com.sojpt.boot; import java.sql.Connection; import javax.servlet.ServletException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import com.alibaba.druid.filter.stat.StatFilter; import com.alibaba.druid.wall.WallFilter; import com.jfinal.config.Constants; import com.jfinal.config.Handlers; import com.jfinal.config.Interceptors; import com.jfinal.config.Plugins; import com.jfinal.core.JFinal; import com.jfinal.plugin.activerecord.ActiveRecordPlugin; import com.jfinal.plugin.activerecord.dialect.MysqlDialect; import com.jfinal.plugin.druid.DruidPlugin; import com.jfinal.template.Engine; import com.jfinal.template.ext.spring.JFinalViewResolver; import com.jfinal.template.source.ClassPathSourceFactory; import com.sojpt.model._MappingKit; @Configuration(value = "SoJptBootConfig") @EnableConfigurationProperties(ActiveRecordPluginProperties.class) public class SoJptBootConfig extends SoJptConfig { @Autowired private ActiveRecordPluginProperties arpProperties; /** * 配置JFinal常量 */ @Override public void configConstant(Constants me) { // 设置当前是否为开发模式 me.setDevMode(arpProperties.getIsDevMode()); // me.setError404View("/index.html"); } /** * 配置JFinal插件 数据库连接池 ORM 缓存等插件 自定义插件 */ @Override public void configPlugin(Plugins me) { DruidPlugin dp = new DruidPlugin(arpProperties.getJdbcUrl(), arpProperties.getUsername(), arpProperties.getPassword()); dp.addFilter(new StatFilter()); dp.setDriverClass("com.mysql.cj.jdbc.Driver"); WallFilter wall = new WallFilter(); dp.addFilter(wall); me.add(dp); ActiveRecordPlugin arp = new ActiveRecordPlugin(dp); arp.setTransactionLevel(Connection.TRANSACTION_READ_COMMITTED); arp.setShowSql(arpProperties.getIsDevMode()); arp.setDialect(new MysqlDialect()); // ******** 在此添加dao层sql文件 *********//* //arp.addSqlTemplate("sql/all_sqls.sql"); _MappingKit.mapping(arp); // 初始化任务调度插件,参数为配置文件名 // me.add(new Cron4jPlugin(sysProp)); me.add(arp); } /** * 配置全局拦截器 */ @Override public void configInterceptor(Interceptors me) { // me.addGlobalActionInterceptor(new DuplicateLoginInterceptor()); } /** * 配置全局处理器 */ @Override public void configHandler(Handlers me) { // druid 统计页面功能 //me.add(DruidKit.getDruidStatViewHandler()); //me.add(new JavaMelodyHandler("/monitoring.*", true)); } @Override public void beforeJFinalStop() { } /** * * 配置模板引擎 */ @Override public void configEngine(Engine me) { // 这里只有选择JFinal TPL的时候才用 me.addSharedObject("RESOURCE_HOST", JFinal.me().getContextPath()); me.addSharedObject("WEB_HOST", JFinal.me().getContextPath()); // 配置共享函数模板 // me.addSharedFunction("/view/common/layout.html") } @Override public void afterJFinalStart() { System.err.println("SoJpt Boot 启动成功!"); } /** * * 此内部类可选, (默认不建议开启,注释掉即可) * 其作用就是在SpringBoot中可以直接 return"/view/index.html", * 如果习惯render("/view/index.html")用法,可注释此方法 * * @return * @throws ServletException */ @Bean(name = "jfinalViewResolver") public JFinalViewResolver getJFinalViewResolver() throws ServletException { JFinalViewResolver jfr = new JFinalViewResolver(); // setDevMode 配置放在最前面 jfr.setDevMode(true); // 使用 ClassPathSourceFactory 从 class path 与 jar 包中加载模板文件 jfr.setSourceFactory(new ClassPathSourceFactory()); jfr.setSuffix(".html"); jfr.setContentType("text/html;charset=UTF-8"); jfr.setOrder(0); // jfr.addSharedFunction("/view/common/_layout.html"); // jfr.addSharedFunction("/view/common/_paginate.html"); // init("com.sojpt.boot.MainConfig"); return jfr; } } ``` 3. 在 application.properties 配置文件中添加如下 ```properties arp.jdbc-url = jdbc:mysql://127.0.0.1/sojpt?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false arp.username = root arp.password = 123456 arp.is-dev-mode= true ``` 3. 在spring启动类中添加注解 @ComponentScan("com.sojpt"), 如下: ```java @ComponentScan("com.sojpt") //添加你定义的SoJptBootConfig类所在的包名称 @SpringBootApplication public class SoJptSpringbootApplication { public static void main(String[] args) { SpringApplication.run(SoJptSpringbootApplication.class, args); } } ``` #### 使用说明 1. 案例一 返回json ```java @RestController public class HelloController extends Controller { //不继承Controller,就是原生的Spring Boot,Jfinal的Aop也就不能用 @Before(Tx.class) //事务的用法 @RequestMapping("/list/jfinal") public void index() { System.out.println(getPara("id")); //获取参数示例 SqlPara sqlPara = Db.getSqlPara("admin_log.select"); Page page = Db.paginate(1, 10, sqlPara); renderJson(page); } } ``` 2. 案例二 文件下载 ```java @RestController public class HelloPageController extends Controller { @Clear @RequestMapping("/file") public void index() { setAttr("msg", "123123"); renderFile(new File("d://test.txt")); } } ``` 3. 案例三 返回页面 ```java @Controller public class HelloPageController extends Controller { @Before(LoginInterceptor.class) //方法级拦截器 @RequestMapping("/page/jfinal") public void index() { setAttr("msg", "123123"); render("/view/index.html") //放在resources目录下 } } ``` #### 参与贡献 ## [www.sojpt.com](http://www.sojpt.com/) ### 💖💖 If you find this project helpful, maybe you can buy me a coffee. 💖💖