刘一辰的软件工程随笔
软件构造实验作业
实验名称:
班级:信1905—2 学号:20193897 姓名:刘一辰
一、实验要求
根据参考资料,学习JFinal极速开发框架的使用并如下任务:
任务一:导入JFinal工程
任务二:阅读JFinal的源码并对每一部分的功能进行介绍
任务三:基于JFinal完成一个简单的学生信息管理系统
二、实验步骤
任务一:导入JFinal工程
点击idea菜单File -> new project ,选择java后勾选Web Application,点击next。
输入工程名,点击finish。
三、配置工程目录
1、补全工程目录
2、将所需jar包导入到lib文件夹
3、点击idea 菜单,File -> Project Structure(快捷键ctril + alt + shift + s) -> Module,对该工程目录进行对号操作(这里把res文件夹,对号为Resources资源文件了)。目的是让idea找到对应的文件夹,这样编译和打包时才不会出错。
4、点击左侧Artifacts,配置你的打包文件。将右侧的jar包添加的你的打包文件中(双击)-> 点击ok,就将资源添加到了打包文件中。
四、新建JFinal对应文件
需建立如下结构文件:
1、添加 MainConfig.java
import com.jfinal.config.*;
import com.jfinal.template.Engine;
public class MainConfig extends JFinalConfig {
// /**
// * main Tomcat使用时注释,jetty使用时打开
// */
// public static void main(String[] args) {
// JFinal.start("WebRoot", 81, "/", 5);
System.out.println("Hello World!");
// }
@Override
public void configConstant(Constants me) {
//配置常量
}
@Override
public void configRoute(Routes me) {
// 添加路由
me.add("/",IndexController.class); //添加index界面,路径为 /
}
@Override
public void configEngine(Engine me) {
// 添加模板文件
}
@Override
public void configPlugin(Plugins me) {
//配置插件
}
@Override
public void configInterceptor(Interceptors me) {
//拦截器
}
@Override
public void configHandler(Handlers me) {
// 添加扩展
}
}
2、添加一个对应主界面的 Controller, IndexController.java
import com.jfinal.core.Controller;
public class IndexController extends Controller{
public void index() {
render("index.jsp");
}
}
3、更改 web.xml文件,注意将MainController文件对应src文件路径。
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<filter>
<filter-name>jfinal</filter-name>
<filter-class>com.jfinal.core.JFinalFilter</filter-class>
<init-param>
<param-name>configClass</param-name>
<param-value>MainConfig</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>jfinal</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
4、更改 index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>这是一个标题</title>
</head>
<body>
Hello World!
</body>
</html>
五、运行
右键index.jsp -> 点击run "index.jsp"。
任务二:
本文对Jfinal的启动源码做解释说明。
我从网上中了个比较有参考价值的代码跟着课程学习解读了下
PS:Jfinal启动容器可基于Tomcat/Jetty等web容器启动,本文基于Jetty的启动方式做启动源码的解读和分析,tomcat类似。
入口
JFinalConfig的继承类的Main方法为入口,实例代码继承类为:DemoConfig,Main方法如下:
public static void main(String[] args) {
/**
* 特别注意:Eclipse 之下建议的启动方式
*/
JFinal.start("WebRoot", 80, "/", 5);
}
启动时,从WebRoot-->Web-INF-->web.xml开始
web.xml代码如下:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
<filter>
<filter-name>jfinal</filter-name>
<filter-class>com.jfinal.core.JFinalFilter</filter-class>
<init-param>
<param-name>configClass</param-name>
<param-value>com.demo.common.DemoConfig</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>jfinal</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
JFinalFilter执行源码解读
web容器调用web.xml中的JFinalFilter过滤器,注入:com.demo.common.DemoConfig全路径,JFinalFilter中三个重要的方法分别是:init(FilterConfig filterConfig)、doFilter(ServletRequest req, ServletResponse res, FilterChain chain)、destroy()。
启动入口为init方法,方法截图如下
1 public void init(FilterConfig filterConfig) throws ServletException {
2 createJFinalConfig(filterConfig.getInitParameter("configClass"));//A.解析web.xml中configClass全路径类并初始化
3
4 if (jfinal.init(jfinalConfig, filterConfig.getServletContext()) == false) {//B.基于Jfinal.init加载启动资源,包含控制器、拦截器等
5 throw new RuntimeException("JFinal init error!");
6 }
7
8 handler = jfinal.getHandler();//C.获取处理器
9 constants = Config.getConstants();//D.获取常量
10 encoding = constants.getEncoding();//E.获取编解码器
11 jfinalConfig.afterJFinalStart();//F.启动web容器
12
13 String contextPath = filterConfig.getServletContext().getContextPath();//G.获取server路径
14 contextPathLength = (contextPath == null || "/".equals(contextPath) ? 0 : contextPath.length());//H.对路径特殊处理
15 }
A.解析web.xml中configClass全路径类
createJFinalConfig(filterConfig.getInitParameter("configClass"));
PS:上方法主要是为了实例化web.xml中configClass对象,JVM在装载class时候,基于类加载机制创建configClass对应的对象实例,代码分析如下
private void createJFinalConfig(String configClass) {
if (configClass == null) {
throw new RuntimeException("Please set configClass parameter of JFinalFilter in web.xml");
}
Object temp = null;
try {
temp = Class.forName(configClass).newInstance();//基于类加载机制实例化
} catch (Exception e) {
throw new RuntimeException("Can not create instance of class: " + configClass, e);
}
if (temp instanceof JFinalConfig) {
jfinalConfig = (JFinalConfig)temp;//强制类型转换
} else {
throw new RuntimeException("Can not create instance of class: " + configClass + ". Please check the config in web.xml");
}
//此类创建了一个对象JFinalConfig的继承类对象而已,不做深入追究
}
B.基于Jfinal.init加载启动资源
jfinal.init(jfinalConfig, filterConfig.getServletContext())
boolean init(JFinalConfig jfinalConfig, ServletContext servletContext) {
this.servletContext = servletContext;
this.contextPath = servletContext.getContextPath();
//B1.获取web容器运行的跟目录,并存储到PathKit.webRootPath变量中
initPathUtil();
//B2.初始化constant, route, engine, plugin, interceptor, handler等信息,实际是调用jfinalConfig
Config.configJFinal(jfinalConfig); // start plugin, init log factory and init engine in this method
constants = Config.getConstants();
//B3.初始化映射,包含controller和intercept
initActionMapping();
//B4.初始化Handler
initHandler();
//B5.初始化Render
initRender();
//B6.初始化不知道
initOreillyCos();
//初始化Token
initTokenManager();
return true;
}
B1.获取web容器运行的跟目录,并存储到PathKit.webRootPath变量中
initPathUtil();
/**
* 初始化web根路径
*/
private void initPathUtil() {
String path = servletContext.getRealPath("/");
PathKit.setWebRootPath(path);
}
B2.初始化constant, route, engine, plugin, interceptor, handler等信息
Config.configJFinal(jfinalConfig);
static void configJFinal(JFinalConfig jfinalConfig) {
jfinalConfig.configConstant(constants);//调用 JFinalConfig 子类的 configConstant,自行跟踪
initLogFactory();//B21:初始化日志工厂 基于log4j封装class的getlog方法,不做解释
initEngine();//B22:初始化引擎
jfinalConfig.configRoute(routes);//调用 JFinalConfig 子类的方法,配置用户自定义controller
jfinalConfig.configEngine(engine);//调用 JFinalConfig 子类的方法,配置引擎
jfinalConfig.configPlugin(plugins);//调用 JFinalConfig 子类的方法,配置用户自定义的插件、redis插件、dbcp插件
startPlugins();B23:启动插件 very important!!!
jfinalConfig.configInterceptor(interceptors);//调用 JFinalConfig 子类的方法,配置用户自定义的拦截器
jfinalConfig.configHandler(handlers);//调用 JFinalConfig 子类的方法,配置用户自定义hander
}
B21.初始化log
/**
*初始化log的核心是创建logFactory对象,尝试创建log4j,如果创建失败,则使用JDK默认log工厂,详情省略
*/
static void init() {
if (defaultLogFactory == null) {
try {
Class.forName("org.apache.log4j.Logger");
Class<?> log4jLogFactoryClass = Class.forName("com.jfinal.log.Log4jLogFactory");
defaultLogFactory = (ILogFactory)log4jLogFactoryClass.newInstance(); // return new Log4jLogFactory();
} catch (Exception e) {
defaultLogFactory = new JdkLogFactory();
}
}
}
B22:初始化引擎
initEngine()
/**
* 设置开发模式和模板文件跟目录,这个方法是Jfinal默认调用的,如果要更新engine里面的变量的话,则JFinalConfig继承类可重写configEngine(Engine engine);
*/
private static void initEngine() {
engine.setDevMode(constants.getDevMode());
engine.setBaseTemplatePath(PathKit.getWebRootPath());
}
B23:启动插件
PS:类似dbcp、redis等的初始化在jfinal中被定义成了插件的方式,startPlugins中我们重点强调什么是插件、插件能干啥?
startPlugins()中并没有启动插件,仅仅是在jfinalConfig.configPlugin(plugins)后,设置插件的开发模式
private static void startPlugins() {
//获取插件列表
List<IPlugin> pluginList = plugins.getPluginList();
if (pluginList == null) {
return ;
}
for (IPlugin plugin : pluginList) {
try {
// process ActiveRecordPlugin devMode
if (plugin instanceof com.jfinal.plugin.activerecord.ActiveRecordPlugin) {
com.jfinal.plugin.activerecord.ActiveRecordPlugin arp = (com.jfinal.plugin.activerecord.ActiveRecordPlugin)plugin;
if (arp.getDevMode() == null) {
//基于用户定位设置插件的开发模式
arp.setDevMode(constants.getDevMode());
}
}
//启动插件,这步骤特别的重要,下个博客重点说明启动插件能干啥用。。。。xieyang@163.com/xieyang@e6yun.com
if (plugin.start() == false) {
String message = "Plugin start error: " + plugin.getClass().getName();
log.error(message);
throw new RuntimeException(message);
}
}
catch (Exception e) {
String message = "Plugin start error: " + plugin.getClass().getName() + ". \n" + e.getMessage();
log.error(message, e);
throw new RuntimeException(message, e);
}
}
}
B3.初始化映射,包含controller和intercept
initActionMapping();
PS:initActionMapping方法的本质将controller的映射和拦截器存储到ActionMapping,然后调用ActionMapping.buildActionMapping完成映射关系的初始化,下文对如何进行映射给予分析和说明
void buildActionMapping() {
mapping.clear();
//通过反射获取controller父类的无参数的方法名集合
Set<String> excludedMethodName = buildExcludedMethodName();
//拦截器管理类
InterceptorManager interMan = InterceptorManager.me();
//getRoutesList():获取用户自定义的controller、名字和模板路径及一个空的route,PS后续详解
for (Routes routes : getRoutesList()) {
//遍历routes,获取每一个route对象
for (Route route : routes.getRouteItemList()) {
//获取当前route的class,此class实在route.me.add的时候添加进来的
Class<? extends Controller> controllerClass = route.getControllerClass();
//PS:从拦截器管理器中获取当前controller的拦截器集合,具体实现方式为:获取controller的Before类注解value为Intercept子类的注解值,通过反射初始化全局单例方式的拦截器,并以集合的方式返回,读者自行研读此处代码
Interceptor[] controllerInters = interMan.createControllerInterceptor(controllerClass);
//判断当前controllerClass的超类是不是Controller.class
boolean sonOfController = (controllerClass.getSuperclass() == Controller.class);
//如果是true,则返回当前类的所有的包括public/private/protected/default修饰的方法。否则的话,返回当前类及父类的public方法
Method[] methods = (sonOfController ? controllerClass.getDeclaredMethods() : controllerClass.getMethods());
for (Method method : methods) {
String methodName = method.getName();
//当前方法不在父类的无参方法集合中或者当前方法的参数值不为零,则认为认为是非public方法,不做controller的映射,直接返回
if (excludedMethodName.contains(methodName) || method.getParameterTypes().length != 0)
continue ;
//当前类的是controller的子类,但是方法是非public,则直接返回
if (sonOfController && !Modifier.isPublic(method.getModifiers()))
continue ;
//PS:有点难,
Interceptor[] actionInters = interMan.buildControllerActionInterceptor(routes.getInterceptors(), controllerInters, controllerClass, method);
String controllerKey = route.getControllerKey();
ActionKey ak = method.getAnnotation(ActionKey.class);
String actionKey;
if (ak != null) {
actionKey = ak.value().trim();
if ("".equals(actionKey))
throw new IllegalArgumentException(controllerClass.getName() + "." + methodName + "(): The argument of ActionKey can not be blank.");
if (!actionKey.startsWith(SLASH))
actionKey = SLASH + actionKey;
}
else if (methodName.equals("index")) {
actionKey = controllerKey;
}
else {
//请求的URL路径
actionKey = controllerKey.equals(SLASH) ? SLASH + methodName : controllerKey + SLASH + methodName;
}
//对请求URL的详细介绍
Action action = new Action(controllerKey, actionKey, controllerClass, method, methodName, actionInters, route.getFinalViewPath(routes.getBaseViewPath()));
//配置映射关系
if (mapping.put(actionKey, action) != null) {
throw new RuntimeException(buildMsg(actionKey, controllerClass, method));
}
}
}
}
routes.clear();
// support url = controllerKey + urlParas with "/" of controllerKey
Action action = mapping.get("/");
if (action != null) {
mapping.put("", action);
}
}
B4.初始化Handler
initHandler();
PS:主要是为了初始化链接结构
/**
* Build handler chain
*/
@SuppressWarnings("deprecation")
public static Handler getHandler(List<Handler> handlerList, Handler actionHandler) {
Handler result = actionHandler;
for (int i=handlerList.size()-1; i>=0; i--) {
Handler temp = handlerList.get(i);
temp.next = result;
temp.nextHandler = result;
result = temp;
}
return result;
}
B5.初始化Render
initRender();PS:初始化模板引擎
Render.init(constants.getEncoding(), constants.getDevMode());
initTemplateRender();
initFreeMarkerRender(servletContext);
initVelocityRender(servletContext);
initJspRender(servletContext);
initFileRender(servletContext);
//B6.初始化不知道
initOreillyCos();
//初始化Token
initTokenManager();PS初始化Token
以上完成了server初始化操作,所有请求的封装都是基于server-容器实现。
任务三:
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。
*/
}
package controller;
import java.util.List;
import com.jfinal.aop.Before;
import com.jfinal.core.Controller;
import Validator.StudentValidator;
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("list", list);
//注意下面路径的的前面如果带/则从根目录下开始找,也就是说下代码 = render("/student/index.html");
render("student.html");
}
public void add() {
render("add.html");
}
public void delete() {
// 获取表单域名为studentid的值
Student.dao.deleteById(getPara("id"));
forwardAction("/student");
}
public void delete1(){
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("id"));
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 方法。
*/
getModel(Student.class).save();
redirect("/student");
}
}
package Interceptor;
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");
}
}
package Interceptor;
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");
}
}
package service;
import java.util.List;
import com.jfinal.plugin.activerecord.Page;
import demo.model.Student;
public class StudentService {
/**
* 所有的 dao 对象也放在 Service 中
*/
private static final Student dao = new Student().dao();
public Page<Student> paginate(int pageNumber, int pageSize) {
return dao.paginate(pageNumber, pageSize, "select *", "from student order by id asc");
}
public Student findById(int id) {
return dao.findById(id);
}
public void deleteById(int id) {
dao.deleteById(id);
}
public List<Student> find() {
return dao.find("select * from student order by id asc");
}
}
package Validator;
import com.jfinal.core.Controller;
import com.jfinal.validate.Validator;
public class StudentValidator extends Validator {
//在校验失败时才会调用
@Override
protected void handleError(Controller controller) {
controller.keepPara("student.name");//将提交的值再传回页面以便保持原先输入的值
controller.render("/add.html");
}
@Override
protected void validate(Controller controller) {
//验证表单域name,返回信息key,返回信息value
validateRequiredString("student.name", "name",
"请输入学生名称!");
}
}
package controller;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import com.jfinal.aop.Before;
import com.jfinal.core.Controller;
import Validator.KMValidator;
import demo.model.KM;
import demo.model.Student;
import net.sf.json.JSONObject;
import service.KMService;
import service.StudentService;
public class KMController 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 KMService service = new KMService();
static StudentService s = new StudentService();
/* @Before(StudentInterceptor.class)*/
public void index() {
List<KM> list = KM.dao.find("select * from kemu");
setAttr("list", list);
//注意下面路径的的前面如果带/则从根目录下开始找,也就是说下代码 = render("/student/index.html");
render("kemu.html");
}
public void list() {
List<Student> list = Student.dao.find("select * from student");
List<KM> l = KM.dao.find("select * from kemu k order by k.score asc");
List<Map<String,Object>> list22 = new ArrayList();
List l2 = new ArrayList();
for(Student s : list){
Map m = new HashMap();
m.put("yuwen", 0);
m.put("shuxue", 0);
m.put("yingyu", 0);
int a = 0;
for(KM k : l){
if(s.get("id")==k.get("stu")){
if(k.get("km").equals("语文")){
a+=(Integer)k.get("score");
m.put("yuwen", k.get("score"));
}else if(k.get("km").equals("数学")){
a+=(Integer)k.get("score");
m.put("shuxue", k.get("score"));
}else if(k.get("km").equals("英语")){
a+=(Integer)k.get("score");
m.put("yingyu", k.get("score"));
}
}
}
m.put("score", a);
m.put("stu", s.get("id"));
list22.add(m);
}
Collections.sort(list22,new Comparator<Map<String,Object>>() {
//升序排序
public int compare(Map<String, Object> o1,
Map<String, Object> o2) {
int map1value = (Integer)o1.get("score");
int map2value = (Integer)o2.get("score");
return map2value-map1value;
}
});
setAttr("l",list22);
render("/kemu/ceshi.html");
}
public void add() {
List<Student> list = Student.dao.find("select * from student");
setAttr("list",list);
render("add.html");
}
public void delete1(){
KM.dao.deleteById(getParaToInt());
forwardAction("/kemu");
}
public void get() {
KM kemu = KM.dao.findById(getPara("id"));
setAttr("kemu", kemu);
render("index2.html");
}
public void get1() {
KM kemu = KM.dao.findById(getParaToInt());
setAttr("kemu", kemu);
render("index2.html");
}
@Before(KMValidator.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 方法。
*/
KM st=getModel(KM.class,"");
st.save();
redirect("/kemu");
}
}
package Interceptor;
import com.jfinal.aop.Interceptor;
import com.jfinal.aop.Invocation;
public class KMInterceptor implements Interceptor {
public void intercept(Invocation ai) {
System.out.println("Before action invoking");
ai.invoke();
System.out.println("After action invoking");
}
}
package Interceptor;
import com.jfinal.aop.Interceptor;
import com.jfinal.aop.Invocation;
public class KMInterceptor implements Interceptor {
public void intercept(Invocation ai) {
System.out.println("Before action invoking");
ai.invoke();
System.out.println("After action invoking");
}
}
package service;
import java.util.List;
import com.jfinal.plugin.activerecord.Page;
import demo.model.KM;
import demo.model.Student;
public class KMService {
/**
* 所有的 dao 对象也放在 Service 中
*/
private static final KM dao = new KM().dao();
private static final Student dao1 = new Student().dao();
public Page<KM> paginate(int pageNumber, int pageSize) {
return dao.paginate(pageNumber, pageSize, "select *", "from kemu order by id asc");
}
public Page<Student> paginate1(int pageNumber, int pageSize) {
return dao1.paginate(pageNumber, pageSize, "select *", "from student order by id asc");
}
public KM findById(int id) {
return dao.findById(id);
}
public void deleteById(int id) {
dao.deleteById(id);
}
public List<Student> find1() {
return dao1.find("select * from student order by id asc");
}
public List<KM> find() {
return dao.find("select * from kemu order by id asc");
}
}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<script type="text/javascript" src="/jquery-1.12.4.min.js"></script>
</head>
<body>
<a href="/kemu/add">添加</a><br>
<a href="/student">返回</a><br>
<table id="listtable" border="1">
<tbody>
<tr>
<th>id</th>
<th>学生编号</th>
<th>科目</th>
<th>成绩</th>
<th>操作</th>
</tr>
#for(x : list)
<tr>
<td style="text-align:left;">#(x.id)</td>
<td style="text-align:left;">#(x.stu)</td>
<td style="text-align:left;">#(x.km)</td>
<td style="text-align:left;">#(x.score)</td>
<td style="text-align:left;">
<a href="/kemu/delete1/#(x.id)">删除</a>
</td>
</tr>
#end
</tbody>
</table>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<a href="/student">返回</a><br>
<table id="listtable" border="1">
<tbody>
<tr>
<th>学生编号</th>
<th>语文成绩</th>
<th>英语成绩</th>
<th>数学成绩</th>
<th>总成绩</th>
</tr>
#for(x : l)
<tr>
<td style="text-align:left;">#(x.stu)</td>
<td style="text-align:left;">#(x.yuwen)</td>
<td style="text-align:left;">#(x.yingyu)</td>
<td style="text-align:left;">#(x.shuxue)</td>
<td style="text-align:left;">#(x.score)</td>
</tr>
#end
</tbody>
</table>
</body>
</html>
package demo;
import com.jfinal.config.*;
import com.jfinal.core.JFinal;
import com.jfinal.plugin.activerecord.ActiveRecordPlugin;
import com.jfinal.plugin.druid.DruidPlugin;
import com.jfinal.template.Engine;
import controller.KMController;
import controller.StudentController;
import demo.model.KM;
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("/student", StudentController.class);
me.add("/kemu", KMController.class);
}
public void configEngine(Engine me) {
}
public void configPlugin(Plugins me) {
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", "id", Student.class);
arp.addMapping("kemu", "id", KM.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) {
}
}
三、实验总结
JFinal 是基于 Java 语言的极速 WEB + ORM + AOP + Template Engine 框架,其核心设计目标是开发迅速、代码量少、学习简单、功能强大、轻量级、易扩展、Restful。在拥有Java语言所有优势的同时再拥有ruby、python、php等动态语言的开发效率!为您节约更多时间,去陪恋人、家人和朋友 :)
JFinal有如下主要特点:
MVC架构,设计精巧,使用简单
遵循COC原则,支持零配置,无xml
独创Db + Record模式,灵活便利
ActiveRecord支持,使数据库开发极致快速
自动加载修改后的java文件,开发过程中无需重启web server
AOP支持,拦截器配置灵活,功能强大
Plugin体系结构,扩展性强
多视图支持,支持FreeMarker、JSP、Velocity
强大的Validator后端校验功能
功能齐全,拥有struts2的绝大部分功能
虽然jf语言是java语言的极速版本但是它的难度并不低于Java语言因此我通过两天的学习从网络上跟着一个项目把学生信息管理系统勉勉强强做出了,虽然我不熟练但是也是认真为之,到此我也不能说我对jf语言熟悉,我只是说我写过,读过
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
2020-10-29 2020/10/29 刘一辰的JAVA随笔