Record the first time using JFinal, from simple framework construction to addition, deletion, modification and inspection, from the built-in methods to the usage of normal frameworks.
JFinal official website: http://www.jfinal.com/
JFinal is a fast WEB + ORM framework based on the Java language. Its core design goals are fast development, small code volume, simple learning, powerful functions, lightweight, easy to expand, and Restful. While having all the advantages of Java, it also has the development efficiency of dynamic languages such as ruby, python, and php.
JFinal has the following main features:
MVC architecture, exquisite design and simple use
Follow COC principle, zero configuration, no xml
Original Db + Record mode, flexible and convenient
ActiveRecord support makes database development extremely fast
Automatically load the modified java file, no need to restart the web server during development
AOP supports, flexible interceptor configuration and powerful functions
Plugin architecture, strong scalability
Multi-view support, FreeMarker, JSP, Velocity
Powerful Validator backend verification function
Fully functions, with most of the functions of struts2
Small size is only 632K, and no third-party dependencies
example:
I use maven first, first create a maven project:
After my project is created, I need to set it first:
Then click Apply
There are some other settings, etc. My question is skipped here
Then introduce the jar package in pom.xml:
maven search jar package: http://mvnrepository.com/
The official demo pom.xml:
JSON is not introduced here, my last method of demo requires 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> <!-- Using the Alibaba maven library --> <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> </repository> </repository> <!-- Add snapshot repository, 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> </repository> </repository> </repository> </repository> </repository> </repository> </repository> </repository> </repository> </repository> </repository> </repository> </repository> </repository> </repository> </repository> </repository> </repository> </repository> </repository> </repository> </repository> </repository> </repository> </repository> </repository> </repository> </repository> </repository> </repository> </repository> </repository> </repository> </repository> </repository> </repository> </repository> </repository> </repository> </repository> </repository> </repository> </repository> </repository> </repository> </repository> </repository> </repository> </repository> </repository> </repository> </repository> </repository> </repository <scope>test</scope> </dependency> <dependency> <groupId>com.jfinal</groupId> <artifactId>jetty-server</artifactId> <version>8.1.8</version> <!-- The scope value here is compile. It only needs to be changed to provided when starting the project under IDEA to start the war package to avoid throwing some useless jars in --> <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> <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> </connector> </configuration> </plugin> </plugins> </build></project>
Then there is the configuration of web.xml:
Notice:
The package where the DemoConfig.java file resides and its own file name must be consistent with the configuration in the param-value tag in web.xml (in this case, the configuration is 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>
Next create the java file:
Create DemoConfig and inherit JFinalConfig. DemoConfig is the main file. Run this file to start the project, just like running the normal java file main. If you modify other codes after running at the same time, you do not need to restart. The framework will be automatically modified. You can directly refresh to see the modified content.
Here is the initial simple 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) {}}Then configure the controller:
package demo;import com.jfinal.core.Controller;public class HelloController extends Controller {public void index() {renderText("Hello JFinal World.");}}Then open the browser and enter http://localhost/hello directly and you will see that the page outputs Hello JFinal World.
Here is the most basic example of using it, here is my program:
package demo;import com.jfinal.config.*;import com.jfinal.core.JFinal;import com.jfinal.kit.PropKit;import com.jfinal.plugin.activecord.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); //This method is used to configure JFinal constant value, such as the configuration of the development mode constant devMode, the following code configures JFinal //run in development mode: In development mode, JFinal will output reports for each request, such as outputting the URL, Controller, Method // and the parameters carried by the request. } 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); // This method is used to configure JFinal's Plugin. The following code configures the Druid database connection pool plug-in and ActiveRecord// database access plug-in. With the following configuration, it is very convenient to operate the database in your application using ActiveRecord. } public void configInterceptor(Interceptors me) { //me.add(new AuthInterceptor()); // This method is used to configure the global interceptor of JFinal. The global interceptor will intercept all action requests unless cleared in the Controller using // @Clear. The following code configures an interceptor named AuthInterceptor. } public void configHandler(Handlers me) { }}The simple description of each method here is written in the comments.
Then there is the controller:
Although the service is declared here, it is not used. It is directly used in the controller method.
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 { /** * There are many ways to get studentid, which is consistent with the front-end pass parameter writing method. Controller provides the getPara series methods. The official API is very detailed. jfinal uses original SQL statements, which is simple and convenient. SetAttr("studentList", list); put the result set into the request scope. jfinal also has a method to directly obtain the form to package objects into objects getModel(Student.class); that is, like struts2, the form name corresponds to, which is very convenient to add, studentid student.set("studentid", "mysequence.nextval").save(); jfinal has multiple ways to return, and can also return json data. The render series method is very detailed in the official API*/ static StudentService service = new StudentService(); @Before(StudentInterceptor.class) public void index() { List<Student> list = Student.dao.find("select * from student"); setAttr("studentList", list); //Note that if the path below has /, start looking from the root directory, that is, the code = 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() { // Get the value of the form domain name studentid Student.dao.deleteById(getPara("studentid")); forwardAction("/student"); } public void delete1() { // Get the first value in the url request 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 is used to receive the model object passed from the page form field. The form field name is named "modelName.attrName" http://www.jfinal.com. The attrName used by getModel must be exactly the same as the data table field name. The getBean method is used to support traditional Java Beans, including models that use jfnal generator to generate getter and setter methods. When passing arguments on page forms, use attrName consistent with the setter method, rather than data table field names. The difference between getModel and getBean is that the former uses the number table field name and the latter uses the attribute name consistent with the setter method for data injection. It is recommended to use the getBean method first. */ //getBean(Student.class).save(); getModel(Student.class).save(); redirect("/student"); } @Before(StudentValidator2.class) public void savebean() { getBean(Student.class).save(); redirect("/student"); }}The same simple explanation is also written in the comments.
The methods are basically all here, here are some other configurations:
This is the entity class:
package demo.model;import com.jfinal.plugin.activecord.Model;public class Student extends Model<Student> { public static final Student dao = new Student(); /** * ActiveRecord is one of the most core components of jfinal. Operating the database through ActiveRecord will greatly reduce the amount of code and greatly improve development efficiency. The configuration is at the back. I am using Model here. Model is one of the most important components in ActiveRecord, which acts as the Model part in the MVC mode. The User in the above code immediately has many convenient methods to operate the database by inheriting the Model. The dao static object declared in User is defined for the convenience of query operations, and the object is not necessary. Models based on ActiveRecord do not need to define attributes, getters and setter methods, XML configuration, and Annotation configuration, which greatly reduces the amount of code. Common methods of Model are found in the official API. JFinal also has the original Db + Record mode, the Db class and its accompanying Record class, which provide richer database operation functions outside the Model class. When using the Db and Record classes, there is no need to map database tables, and Record is equivalent to a general model. Common Db methods are found in the official 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");//Pass the submitted value back to the page to maintain the originally entered value controller.render("/add.html"); } @Override protected void validate(Controller controller) { //Verify the form field name, return the information key, return the information value validateRequiredString("student.studentname", "studentnameMsg", "Please enter the student name!"); }} 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");//Pass the submitted value back to the page to maintain the originally entered value controller.render("/add.html"); } @Override protected void validate(Controller controller) { //Verify the form field name, return the information key, return the information value validateRequiredString("studentname", "studentnameMsg", "Please enter the student name!"); }}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"); }}Then the front desk display page:
Regarding the front desk page, you need to look at the sixth chapter of the document, the content of the JFinal template engine, and understand how JFinal is displayed in the front desk. This is very important.
<!DOCTYPE html><html><head><meta charset="UTF-8"><title>Student Management</title><script type="text/javascript" src="/jquery-1.12.4.min.js"></script></head><body> <h1><a href="/student/jsp">Student Management</a></h1> <a href="/student/layui">Test layui</a> <a href="/student/test">Edit index 0</a><br> <a href="/student/add">Add</a><br> <form action="/student/get">id:<input type="text" name="studentid"> <input type="submit" value="query"> </form> <a href="/student/delete">Delete</a> <form action="/student/delete"> id:<input type="text" name="studentid"> <input type="submit" value="delete"> </form> #for(x : [1..10]) #(x) #end <table id="listtable"> <tbody> <tr> <th>id</th> <th>Name</th> <th>Gender</th> <th>Age</th> <th>Address</th> <th>Email</th> <th>Operation</th> </tr> #for(x : studentList) <tr> <td style="text-align:left;">#(x.studentid)</td> <td style="text-align:left;">#(x.studentid)</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)">Delete</a> <a href="/student/delete1/#(x.studentid)">Delete</a> <a href="/student/get?studentid=#(x.studentid)">Modify</a> <a href="/student/get1/#(x.studentid)">Modify</a> <a href="/student/get1/#(x.studentid)">Modify</a> </td> </tr> #end </tbody> </table></body></html>
This is the page effect, because there is no style, it looks rough. Then the following is composed of the normal use of layui and the normal habitual method to return data:
<!DOCTYPE html><html><head><meta charset="UTF-8"><title>Student Management 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> <a href="/student/add"><button type="button" id="usersAdd_btn" > <i aria-hidden="true"></i> Add</button></a> <form style="float: right;" onsubmit="return false"> <div> Search for users: <div> <input name="name" id="demoReload" autocomplete="off"> </div> <button style="transform: translateY(-3px);" data-type="reload">Search</button> </div> </div> </form> </blockquote> </div> <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%'}">Name</th> <th lay-data="{field:'sex', width:'20%'}">Gender</th> <th lay-data="{field:'age', width:'20%'}">Age</th> <th lay-data="{field:'address', width:'20%'}">Address</th> <th lay-data="{fixed: 'right', width:'17%', align:'center', toolbar: '#barDemo1'}"></th> </tr> </tr> </table><script type="text/html" id="barDemo1"><a id="edit" lay-event="edit">Modify</a><a lay-event="del">Delete</a></script></body><script>layui.use('table', function(){ var table = layui.table, form = layui.form;; //Select table.on('checkbox(demo)', function(obj){ console.log(obj) }); //Speak toolbar table.on('tool(demo)', function(obj){ var data = obj.data; if(obj.event === 'del'){ layer.confirm('re really deleting the user', function(index){ $.ajax({ type:"post", url:"/student/delete?studentid="+data.studentid, dataType:"text",//Returned success:function(returndata) { table.reload("idTest"); }, error:function(msg) { console.log(msg); } }); }); } else if(obj.event === 'edit'){ var index = layui.layer.open({ title : "Modify", type : 2, area: ['380px', '80%'], content : "/student/get?studentid="+data.studentid, cancel: function(index, layero){ layer.close(index); table.reload("idTest"); } }) //When changing the window size, reset the height of the pop-up window to prevent it from exceeding the visual area (such as F12 calls out debug) $(window).resize(function(){ layui.layer.full(index); }) layui.layer.full(index); }else if(obj.event === 'detail'){ layer.confirm('Are you sure you pass this user', function(index){ $.ajax({ type:"post", url:"<%=basePath%>/sys/user/passuser", data:{id:data.id}, //dataType:"text",//Return success:function(returndata) { layui.use('layer', function() { layer.msg(returndata.msg); }); table.reload('idTest', { page: { curr: 1 //Restart from page 1}, }); }, error:function(msg) { console.log(msg); } }); }); } }); var $ = layui.$, active = { getCheckData: function(){ //Get selected data var checkStatus = table.checkStatus('idTest'), data = checkStatus.data; layer.alert(JSON.stringify(data)); } ,getCheckLength: function(){ //Get the number of selected var checkStatus = table.checkStatus('idTest') ,data = checkStatus.data; layer.msg('Selected: '+ data.length + ' '); } ,isAll: function(){ //Verify whether all var checkStatus = table.checkStatus('idTest'); layer.msg(checkStatus.isAll ? 'Select all': 'not selected all') } }; $('.demoTable .layui-btn').on('click', function(){ var type = $(this).data('type'); active[type] ? active[type].call(this) : ''; });});</script></html>This feels a little better, because it is only the first time I use it and do a test, so it is still relatively rough.
Then it is important to note the problem of data return in this way:
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); }This is the method pointed to by the Layui table url. Here, you need to return the json data in the renderJson way.
Then it should be noted that I have tried to directly return the list collection. It seems that the method is feasible, but because the layui table must be in the above format to receive data, it is not displayed on the page. However, when I directly return jo, the background error reported, and this problem can only be learned and solved tomorrow.
The following are several ways to use the render method returned:
Then you need to pay attention to the method call and parameter transfer:
There are two methods and parameters transfer methods as follows:
<a href="/student/delete?studentid=#(x.studentid)">Delete</a> <a href="/student/delete1/#(x.studentid)">Delete</a> <a href="/student/get?studentid=#(x.studentid)">Modify</a> <a href="/student/get1/#(x.studentid)">Modify</a> <a href="/student/get1/#(x.studentid)">Modify 1</a>
Here is the controller method:
public void delete() { // Get the value of the form domain name studentid Student.dao.deleteById(getPara("studentid")); forwardAction("/student"); } public void delete1() { // Get the first value in the url request 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"); }Finally, there are two ways to add accepting entity classes:
@Before(StudentValidator.class) public void save() { /** * getModel is used to receive the model object passed from the page form field. The form field name is named "modelName.attrName" http://www.jfinal.com. The attrName used by getModel must be exactly the same as the data table field name. The getBean method is used to support traditional Java Beans, including models that use jfnal generator to generate getter and setter methods. When passing arguments on page forms, use attrName consistent with the setter method, rather than data table field names. The difference between getModel and getBean is that the former uses the number table field name and the latter uses the attribute name consistent with the setter method for data injection. It is recommended to use the getBean method first. */ //getBean(Student.class).save(); getModel(Student.class).save(); redirect("/student"); } @Before(StudentValidator2.class) public void savebean() { getBean(Student.class).save(); redirect("/student"); }The second getBean method in my demo may not be set, and only the ID is generated and no other data is added.
If needed. Here is the official demo:
package com.demo.common.model;import com.demo.common.model.base.BaseBlog;/** * This demo only expresses the most superficial jfinal usage, and is more valuable and practical enterprise-level usage* For details, see JFinal Club: http://jfinal.com/club * * Blog model. * It is recommended to use camel naming rules for database field names to facilitate consistency with java code, such as field names: userId */@SuppressWarnings("serial")public class Blog extends BaseBlog<Blog> { } package com.demo.common.model.base;import com.jfinal.plugin.activecord.Model;import com.jfinal.plugin.activecord.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"); }}The above sharing of the JFinal fast development framework usage notes is all the content I share with you. I hope you can give you a reference and I hope you can support Wulin.com more.