JFinal极速开发框架使用笔记分享
记录第一次使用jfinal,从简单的框架搭建到增删改查,从自带的方法到正常框架习惯的使用方式。
jfinal官网:http://www.jfinal.com/
jfinal 是基于 java 语言的极速 web + orm 框架,其核心设计目标是开发迅速、代码量少、学习简单、功能强大、轻量级、易扩展、restful。在拥有java语言所有优势的同时再拥有ruby、python、php等动态语言的开发效率。
jfinal有如下主要特点:
mvc架构,设计精巧,使用简单
遵循coc原则,零配置,无xml
独创db + record模式,灵活便利
activerecord支持,使数据库开发极致快速
自动加载修改后的java文件,开发过程中无需重启web server
aop支持,拦截器配置灵活,功能强大
plugin体系结构,扩展性强
多视图支持,支持freemarker、jsp、velocity
强大的validator后端校验功能
功能齐全,拥有struts2的绝大部分功能
体积小仅632k,且无第三方依赖
例子:
本人用的maven,首先创建一个maven项目:
我的项目创建之后首先要设置:
然后点apply
还有其他一些设置等等,我的问题,这里先跳过
然后在pom.xml中引入jar包:
maven搜索jar包:http://mvnrepository.com/
官方demo的pom.xml:
这里没有引入json,我的这个demo最后的方法需要json
<project xmlns="http://maven.apache.org/pom/4.0.0" xmlns:xsi="http://www.w3.org/2001/xmlschema-instance" xsi:schemalocation="http://maven.apache.org/pom/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelversion>4.0.0</modelversion> <groupid>com.demo</groupid> <artifactid>jfinal_demo_for_maven</artifactid> <packaging>war</packaging> <version>3.2</version> <name>jfinal_demo_for_maven maven webapp</name> <url>http://maven.apache.org</url> <properties> <project.build.sourceencoding>utf-8</project.build.sourceencoding> <maven.compiler.encoding>utf-8</maven.compiler.encoding> </properties> <!-- 使用阿里 maven 库 --> <repositories> <repository> <id>ali-maven</id> <url>http://maven.aliyun.com/nexus/content/groups/public</url> <releases> <enabled>true</enabled> </releases> <snapshots> <enabled>true</enabled> <updatepolicy>always</updatepolicy> <checksumpolicy>fail</checksumpolicy> </snapshots> </repository> </repositories> <!-- 添加快照版本库,updatepolicy: always、daily、interval、never --> <!-- repositories> <repository> <id>sonatype-nexus-snapshots</id> <name>sonatype nexus snapshots</name> <url>https://oss.sonatype.org/content/repositories/snapshots/</url> <releases> <enabled>false</enabled> </releases> <snapshots> <enabled>true</enabled> <updatepolicy>daily</updatepolicy> </snapshots> </repository> </repositories --> <dependencies> <dependency> <groupid>junit</groupid> <artifactid>junit</artifactid> <version>3.8.1</version> <scope>test</scope> </dependency> <dependency> <groupid>com.jfinal</groupid> <artifactid>jetty-server</artifactid> <version>8.1.8</version> <!-- 此处的 scope 值为 compile 仅为支持 idea 下启动项目 打 war 包时需要改成 provided,以免将一些无用的 jar 打进去 --> <scope>compile</scope> </dependency> <dependency> <groupid>com.jfinal</groupid> <artifactid>jfinal</artifactid> <version>3.3</version> </dependency> <dependency> <groupid>log4j</groupid> <artifactid>log4j</artifactid> <version>1.2.16</version> </dependency> <dependency> <groupid>mysql</groupid> <artifactid>mysql-connector-java</artifactid> <version>5.1.44</version> </dependency> <dependency> <groupid>com.alibaba</groupid> <artifactid>druid</artifactid> <version>1.0.29</version> </dependency> <dependency> <groupid>com.jfinal</groupid> <artifactid>cos</artifactid> <version>2017.5</version> </dependency> </dependencies> <build> <finalname>jfinal_demo_for_maven</finalname> <plugins> <plugin> <groupid>org.mortbay.jetty</groupid> <artifactid>jetty-maven-plugin</artifactid> <version>8.1.8.v20121106</version> <configuration> <stopkey>stop</stopkey> <stopport>5599</stopport> <webappconfig> <contextpath>/</contextpath> </webappconfig> <scanintervalseconds>5</scanintervalseconds> <connectors> <connector implementation="org.eclipse.jetty.server.nio.selectchannelconnector"> <port>80</port> <maxidletime>60000</maxidletime> </connector> </connectors> </configuration> </plugin> </plugins> </build> </project>
然后是web.xml的配置:
注意:
democonfig.java 文件所在的包以及自身文件名必须与 web.xml 中的 param-value 标签内的配置相一致(在本例中该配置为 demo.democonfig)。
<filter> <filter-name>jfinal</filter-name> <filter-class>com.jfinal.core.jfinalfilter</filter-class> <init-param> <param-name>configclass</param-name> <param-value>demo.democonfig</param-value> </init-param> </filter> <filter-mapping> <filter-name>jfinal</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
接下来创建java文件:
创建democonfig并继承jfinalconfig,democonfig是主文件,运行这个文件启动项目,就像运行普通java文件main一样,同时运行之后如果修改其他代码,并不需要重启,框架会自动修改,直接刷新就可以看到修改后的内容。
这是初始的简单的demo:
package demo; import com.jfinal.config.*; public class democonfig extends jfinalconfig { public void configconstant(constants me) { me.setdevmode(true); } public void configroute(routes me) { me.add("/hello", hellocontroller.class); } public void configengine(engine me) {} public void configplugin(plugins me) {} public void configinterceptor(interceptors me) {} public void confighandler(handlers me) {} }
然后配置controller:
package demo; import com.jfinal.core.controller; public class hellocontroller extends controller { public void index() { rendertext("hello jfinal world."); } }
然后直接打开浏览器输入http://localhost/hello 就可以看到页面输出了 hello jfinal world 。
这是最基本的使用的例子,下面是我的程序:
package demo; import com.jfinal.config.*; import com.jfinal.core.jfinal; import com.jfinal.kit.propkit; import com.jfinal.plugin.activerecord.activerecordplugin; import com.jfinal.plugin.c3p0.c3p0plugin; import com.jfinal.plugin.druid.druidplugin; import com.jfinal.template.engine; import controller.studentcontroller; import demo.model.classes; import demo.model.student; public class democonfig extends jfinalconfig { public static void main(string[] args) { jfinal.start("src/main/webapp", 80, "/", 5); } public void configconstant(constants me) { me.setdevmode(true); //此方法用来配置 jfinal 常量值,如开发模式常量 devmode 的配置,如下代码配置了 jfinal //运行在开发模式:在开发模式下,jfinal 会对每次请求输出报告,如输出本次请求的 url、controller、method //以及请求所携带的参数。 } public void configroute(routes me) { me.add("/", hellocontroller.class); me.add("/test/mytest", hellocontroller.class,"test"); me.add("/student", studentcontroller.class); //me.add("/classes", classescontroller.class); } public void configengine(engine me) { } public void configplugin(plugins me) { // c3p0plugin cp = new c3p0plugin("jdbc:mysql://localhost/db_name", // "username", "password"); // me.add(cp); loadpropertyfile("a_little_config.txt"); druidplugin dp = new druidplugin(getproperty("jdbcurl"), getproperty("user"), getproperty("password")); me.add(dp); activerecordplugin arp = new activerecordplugin(dp); me.add(arp); arp.addmapping("student", "studentid", student.class); arp.addmapping("classes", "classesid", classes.class); // 此方法用来配置jfinal的plugin,如下代码配置了druid数据库连接池插件与activerecord // 数据库访问插件。通过以下的配置,可以在应用中使用 activerecord 非常方便地操作数据库。 } public void configinterceptor(interceptors me) { //me.add(new authinterceptor()); // 此方法用来配置 jfinal 的全局拦截器,全局拦截器将拦截所有 action 请求,除非使用 // @clear 在 controller 中清除,如下代码配置了名为 authinterceptor 的拦截器。 } public void confighandler(handlers me) { } }
这里面各个方法的简单说明都写在注释里了。
然后是controller:
这里虽然声明了service,但是并没有使用的,都是直接在controller方法里使用dao
package controller; import java.util.list; import java.util.map; import com.alibaba.fastjson.jsonobject; import com.jfinal.aop.before; import com.jfinal.core.controller; import studentinterceptor.studentinterceptor; import studentvalidator.studentvalidator; import studentvalidator.studentvalidator2; import demo.model.student; import service.studentservice; public class studentcontroller extends controller { /** * 获取studentid那里有多种方法,这个要和前台传参写法一致,controller 提供了 getpara 系列方法,官网api里很详细 jfinal用的是原生态sql语句,简单,方便,setattr("studentlist", list);把结果集放到request范围里, jfinal也有直接获取表单里分装成对象的方法 getmodel(student.class);就是,和struts2一样,表单name对应上就可以了,非常方便 添加那里对于oracle用序列维护studentid student.set("studentid", "mysequence.nextval").save(); jfinal有多种返回方式,也可以返回json数据,render 系列方法,官网api里很详细 */ static studentservice service = new studentservice(); @before(studentinterceptor.class) public void index() { list<student> list = student.dao.find("select * from student"); setattr("studentlist", list); //注意下面路径的的前面如果带/则从根目录下开始找,也就是说 下代码 = render("/student/index.html"); render("index.html"); } public void add() { render("add.html"); } public void test() { list<student> list = student.dao.find("select * from student"); setattr("studentlist", list); setattr("student", list.get(0)); render("test.jsp"); } public void getlist() { list<student> list = student.dao.find("select * from student"); jsonobject jo = new jsonobject(); jo.put("code", 0); jo.put("msg", true); jo.put("count",list.size()); jo.put("data", list); renderjson(jo); } public void layui() { list<student> list = student.dao.find("select * from student"); setattr("studentlist", list); render("index3.html"); } public void delete() { // 获取表单域名为studentid的值 student.dao.deletebyid(getpara("studentid")); forwardaction("/student"); } public void delete1() { // 获取url请求中第一个值 student.dao.deletebyid(getparatoint()); forwardaction("/student"); } public void update() { student student = getmodel(student.class); student.update(); forwardaction("/student"); } public void get() { student student = student.dao.findbyid(getpara("studentid")); setattr("student", student); render("index2.html"); } public void get1() { student student = student.dao.findbyid(getparatoint()); setattr("student", student); render("index2.html"); } @before(studentvalidator.class) public void save() { /** * getmodel用来接收页面表单域传递过来的model对象,表单域名称以”modelname.attrname” http://www.jfinal.com 方式命名,getmodel 使用的 attrname 必须与数据表字段名完全一样。 getbean 方法用于支持传统 java bean,包括支持使用 jfnal 生成器生成了 getter、setter 方法 的 model,页面表单传参时使用与 setter 方法相一致的 attrname,而非数据表字段名。 getmodel与getbean区别在于前者使用数表字段名而后者使用与setter方法一致的属性名进 行数据注入。建议优先使用 getbean 方法。 */ //getbean(student.class).save(); getmodel(student.class).save(); redirect("/student"); } @before(studentvalidator2.class) public void savebean() { getbean(student.class).save(); redirect("/student"); } }
同样的简单的说明也写在注释里了。
方法基本上都在这里了,下面是其他的一些配置:
这是实体类:
package demo.model; import com.jfinal.plugin.activerecord.model; public class student extends model<student> { public static final student dao = new student(); /** * activerecord 是 jfinal 最核心的组成部分之一,通过 activerecord 来操作数据库,将极大地减少代码量,极大地提升开发效率,配置在后面,我这里用的是model,model 是 activerecord 中最重要的组件之一,它充当 mvc 模式中的 model部分。 以上代码中的 user 通过继承 model,便立即拥有的众多方便的操作数据库的方法。在 user 中声明的 dao 静态对象是为了方便查询操作而定义的,该对象并不是必须的。 基于activerecord 的 model 无需定义属性, 无需定义 getter、 setter方法,无需 xml 配置,无需 annotation 配置,极大降低了代码量。model常见方法见官方api。 jfinal还有 独创 db + record 模式,db 类及其配套的 record 类, 提供了在 model 类之外更为丰富的数据库操作功能。使用 db 与 record 类时,无需对数据库表进行映射,record 相当于一个通用的 model。db常见方法见官方api。 */ }
studentvalidator:
package studentvalidator; import com.jfinal.core.controller; import com.jfinal.validate.validator; public class studentvalidator extends validator { //在校验失败时才会调用 @override protected void handleerror(controller controller) { controller.keeppara("student.studentname");//将提交的值再传回页面以便保持原先输入的值 controller.render("/add.html"); } @override protected void validate(controller controller) { //验证表单域name,返回信息key,返回信息value validaterequiredstring("student.studentname", "studentnamemsg", "请输入学生名称!"); } }
package studentvalidator; import com.jfinal.core.controller; import com.jfinal.validate.validator; public class studentvalidator2 extends validator { //在校验失败时才会调用 @override protected void handleerror(controller controller) { controller.keeppara("studentname");//将提交的值再传回页面以便保持原先输入的值 controller.render("/add.html"); } @override protected void validate(controller controller) { //验证表单域name,返回信息key,返回信息value validaterequiredstring("studentname", "studentnamemsg", "请输入学生名称!"); } }
studentinterceptor:
package studentinterceptor; import com.jfinal.aop.interceptor; import com.jfinal.aop.invocation; public class studentinterceptor implements interceptor { public void intercept(invocation ai) { system.out.println("before action invoking"); ai.invoke(); system.out.println("after action invoking"); } }
然后是前台的显示页面:
关于前台页面,需要看一下文档第六章,jfinal模板引擎的内容,了解jfinal如何在前台显示,这是很重要的
<!doctype html> <html> <head> <meta charset="utf-8"> <title>学生管理</title> <script type="text/javascript" src="/jquery-1.12.4.min.js"></script> </head> <body> <h1><a href="/student/jsp">学生管理</a></h1> <a href="/student/layui">测试layui</a> <a href="/student/test">编辑索引0</a><br> <a href="/student/add">添加</a><br> <form action="/student/get"> id:<input type="text" name="studentid"> <input type="submit" value="查询"> </form> <a href="/student/delete">删除</a> <form action="/student/delete"> id:<input type="text" name="studentid"> <input type="submit" value="删除"> </form> #for(x : [1..10]) #(x) #end <table id="listtable" border="1"> <tbody> <tr> <th>id</th> <th>姓名</th> <th>性别</th> <th>年龄</th> <th>地址</th> <th>邮箱</th> <th>操作</th> </tr> #for(x : studentlist) <tr> <td style="text-align:left;">#(x.studentid)</td> <td style="text-align:left;">#(x.studentname)</td> <td style="text-align:left;">#(x.sex)</td> <td style="text-align:left;">#(x.age)</td> <td style="text-align:left;">#(x.address)</td> <td style="text-align:left;">#(x.email)</td> <td style="text-align:left;"> <a href="/student/delete?studentid=#(x.studentid)">删除</a> <a href="/student/delete1/#(x.studentid)">删除</a> <a href="/student/get?studentid=#(x.studentid)">修改</a> <a href="/student/get1/#(x.studentid)">修改1</a> </td> </tr> #end </tbody> </table> </body> </html>
这就是页面效果,因为没有样式所以看起来比较粗狂,然后下面是用正常使用的layui,加上正常习惯的方法返回数据组成的:
<!doctype html> <html> <head> <meta charset="utf-8"> <title>学生管理layui</title> <script type="text/javascript" src="/layui-v2.2.45/layui/layui.js"></script> <link rel="stylesheet" href="/layui-v2.2.45/layui/css/layui.css" media="all"> </head> <body> <div style="margin: 0px; background-color: white; margin: 0 10px;"> <blockquote class="layui-elem-quote"> <a href="/student/add"><button type="button" id="usersadd_btn" class="layui-btn layui-btn-small"> <i class="fa fa-plus" aria-hidden="true"></i> 添加 </button></a> <form class="layui-form" style="float: right;" onsubmit="return false"> <div class="layui-form-item" style="margin: 0;"> <div class="demotable"> 搜索用户: <div class="layui-inline"> <input class="layui-input" name="name" id="demoreload" autocomplete="off"> </div> <button class="layui-btn" style="transform: translatey(-3px);" data-type="reload">搜索</button> </div> </div> </form> </blockquote> </div> <table class="layui-table" lay-data="{url:'/student/getlist',id:'idtest',height: 'full-60' ,}" lay-filter="demo"> <thead> <tr> <th lay-data="{field:'studentid', width:'20%',}">id</th> <th lay-data="{field:'studentname', width:'20%'}">姓名</th> <th lay-data="{field:'sex', width:'20%'}">性别</th> <th lay-data="{field:'age', width:'20%'}">年龄</th> <th lay-data="{field:'address', width:'20%'}">地址</th> <th lay-data="{fixed: 'right', width:'17%', align:'center', toolbar: '#bardemo1'}"></th> </tr> </thead> </table> <script type="text/html" id="bardemo1"> <a class="layui-btn layui-btn-xs" id="edit" lay-event="edit">修改</a> <a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del">删除</a> </script> </body> <script> layui.use('table', function(){ var table = layui.table, form = layui.form;; //监听表格复选框选择 table.on('checkbox(demo)', function(obj){ console.log(obj) }); //监听工具条 table.on('tool(demo)', function(obj){ var data = obj.data; if(obj.event === 'del'){ layer.confirm('真的删除用户吗', function(index){ $.ajax({ type:"post", url:"/student/delete?studentid="+data.studentid, datatype:"text",//返回的 success:function(returndata) { table.reload("idtest"); }, error:function(msg) { console.log(msg); } }); }); } else if(obj.event === 'edit'){ var index = layui.layer.open({ title : "修改", type : 2, area: ['380px', '80%'], content : "/student/get?studentid="+data.studentid, cancel: function(index, layero){ layer.close(index); table.reload("idtest"); } }) //改变窗口大小时,重置弹窗的高度,防止超出可视区域(如f12调出debug的操作) $(window).resize(function(){ layui.layer.full(index); }) layui.layer.full(index); }else if(obj.event === 'detail'){ layer.confirm('确定通过该用户吗', function(index){ $.ajax({ type:"post", url:"<%=basepath%>/sys/user/passuser", data:{id:data.id}, //datatype:"text",//返回的 success:function(returndata) { layui.use('layer', function() { layer.msg(returndata.msg); }); table.reload('idtest', { page: { curr: 1 //重新从第 1 页开始 }, }); }, error:function(msg) { console.log(msg); } }); }); } }); var $ = layui.$, active = { getcheckdata: function(){ //获取选中数据 var checkstatus = table.checkstatus('idtest'), data = checkstatus.data; layer.alert(json.stringify(data)); } ,getchecklength: function(){ //获取选中数目 var checkstatus = table.checkstatus('idtest') ,data = checkstatus.data; layer.msg('选中了:'+ data.length + ' 个'); } ,isall: function(){ //验证是否全选 var checkstatus = table.checkstatus('idtest'); layer.msg(checkstatus.isall ? '全选': '未全选') } }; $('.demotable .layui-btn').on('click', function(){ var type = $(this).data('type'); active[type] ? active[type].call(this) : ''; }); }); </script> </html>
这样感觉稍微好了一点,因为只是第一次使用,做一个测试,所以还是比较粗犷的。
然后需要注意的是这种方式的数据返回的问题:
public void getlist() { list<student> list = student.dao.find("select * from student"); jsonobject jo = new jsonobject(); jo.put("code", 0); jo.put("msg", true); jo.put("count",list.size()); jo.put("data", list); renderjson(jo); }
这是layui表格url指向的方法,在这里,需要将json数据用renderjson的方式返回。
然后需要 注意的是,我尝试过直接返回list集合,貌似方法是可行的,只是因为layui表格必须是以上格式才能接收数据所以没有显示到页面上,但是当我直接return jo的时候后台报错,这个问题只能等明天在学习并解决了。
以下是返回的render方法的几种使用方式:
然后需要注意的是方法的调用和传参:
如下两种方法和传参的方式:
<a href="/student/delete?studentid=#(x.studentid)">删除</a> <a href="/student/delete1/#(x.studentid)">删除</a> <a href="/student/get?studentid=#(x.studentid)">修改</a> <a href="/student/get1/#(x.studentid)">修改1</a>
下面是controller方法:
public void delete() { // 获取表单域名为studentid的值 student.dao.deletebyid(getpara("studentid")); forwardaction("/student"); } public void delete1() { // 获取url请求中第一个值 student.dao.deletebyid(getparatoint()); forwardaction("/student"); } public void update() { student student = getmodel(student.class); student.update(); forwardaction("/student"); } public void get() { student student = student.dao.findbyid(getpara("studentid")); setattr("student", student); render("index2.html"); } public void get1() { student student = student.dao.findbyid(getparatoint()); setattr("student", student); render("index2.html"); }
最后就是添加接受实体类的两种方式:
@before(studentvalidator.class) public void save() { /** * getmodel用来接收页面表单域传递过来的model对象,表单域名称以”modelname.attrname” http://www.jfinal.com 方式命名,getmodel 使用的 attrname 必须与数据表字段名完全一样。 getbean 方法用于支持传统 java bean,包括支持使用 jfnal 生成器生成了 getter、setter 方法 的 model,页面表单传参时使用与 setter 方法相一致的 attrname,而非数据表字段名。 getmodel与getbean区别在于前者使用数表字段名而后者使用与setter方法一致的属性名进 行数据注入。建议优先使用 getbean 方法。 */ //getbean(student.class).save(); getmodel(student.class).save(); redirect("/student"); } @before(studentvalidator2.class) public void savebean() { getbean(student.class).save(); redirect("/student"); }
其中第二中的getbean方式在我这个demo中,可能由于没有设置getset的原因,添加之后是只有生成了id,没有其他数据的。
如果需要使用。下面是官方demo的写法:
package com.demo.common.model; import com.demo.common.model.base.baseblog; /** * 本 demo 仅表达最为粗浅的 jfinal 用法,更为有价值的实用的企业级用法 * 详见 jfinal 俱乐部: http://jfinal.com/club * * blog model. * 数据库字段名建议使用驼峰命名规则,便于与 java 代码保持一致,如字段名: userid */ @suppresswarnings("serial") public class blog extends baseblog<blog> { }
package com.demo.common.model.base; import com.jfinal.plugin.activerecord.model; import com.jfinal.plugin.activerecord.ibean; /** * generated by jfinal, do not modify this file. */ @suppresswarnings({"serial", "unchecked"}) public abstract class baseblog<m extends baseblog<m>> extends model<m> implements ibean { public m setid(java.lang.integer id) { set("id", id); return (m)this; } public java.lang.integer getid() { return getint("id"); } public m settitle(java.lang.string title) { set("title", title); return (m)this; } public java.lang.string gettitle() { return getstr("title"); } public m setcontent(java.lang.string content) { set("content", content); return (m)this; } public java.lang.string getcontent() { return getstr("content"); } }
以上这篇jfinal极速开发框架使用笔记分享就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持。