官方概述:
Controller是JFinal核心类之一,该类作为MVC模式中的控制器。基于JFinal的Web应用的控制器需要继承该类。Controller是定义Action方法的地点,是组织Action的一种方式,一个Controller可以包含多个Action。Controller是线程安全的。
Action
Action定义
Controller就是Action一个叫法
Action 是请求的最小单位
Action 方法必须在 Controller 中定义,且必须是 public 可见性
public class HelloController extends Controller {
//这个就是action 不知道为啥整这样洋气
public void index() {
renderText("此方法是一个action");
}
public String test() {
return "index.html";
}
}
Action可以有返回值,返回值可在拦截器中通过invocation.getReturnValue() 获取到,以便进行render控制。
@NotAction注解
如果希望 controller 中的 public 方法不成为一个 action,可以使用 @NotAction 注解。@NotAction 注解通常用于引入了 BaseController 的中间 Controller,个人理解就是不想被外界看到的方法
例如:
public class BaseController extends Controller {
// 不希望成为 action,仅供子类调用,或拦截器中调用
@NotAction
public void getLoginUser() {
}
}
控制器超类的路由映射
自 jfinal 3.6 开始,控制器超类中的所有方法默认不会被映射为 action。(也就是自 jfinal 3.6 版本开始上例中
BaseController 中的 @NotAction 默认已经不需要了,因为 BaseController 是你最终控制器
XxxController 的超类)
如果希望超类中的方法也被映射为 action 只需添加一行配置:
public void configRoute(Routes me) {
me.setMappingSuperClass(true);
}
Action 参数注入
Action 参数注入是指为 action 方法传入参数,可以省去 getPara(…) 代码直接获得参数值,以下是代码示例:
public class ProjectController extends Controller {
public void index(Project project) {
project.save();
render("index.html");
}
}
如果 action 形参是一个 model 或者 bean,原先通过 getBean(User.class, “”) 获取时第二个参数为空字符串或null,那么与之等价的形参注入只需要用一下 @Para("") 注解即可:
public void action(@Para("")User user) { …. }
使用 Action 参数注入功能需要在开发工具中配置打开编译参数保留住方法参数名称。注意过于老旧的 eclipse 版本不支持 java 8 和该配置项,建议至少使用eclipse mars版本,以下是eclipse中的设置:
检查项目属性配置的Java Build Path菜单下的Libraries下的java版本是否为1.8:
检查项目属性配置的Project Facets菜单下的 java版本配置确定是否为1.8:
get / getPara 系列方法
第一个形参为String的getPara系列方法。
第二种类型为第一个形参为int或无形参的getPara系列方法。该系列方法是去获取urlPara中所带的参数值。getParaMap与getParaNames分别对应HttpServletRequest的getParameterMap与getParameterNames。
getPara使用例子:
// 替代 getPara 的 get 用法
String title = get("title");
// 替代 getParaToInt 的 getInt 用法
Integer age = getInt("age");
// 替代 setAttr 的 set 用法
set("article", article);
String json = getRawData();
User user = FastJson.getJson().parse(json, User.class);
以上代码通过 getRawData() 获取到了客户端传过来的 String 型的 json 数据库。 getRawData() 方法可以在一次请求交互中多次反复调用,不会抛出异常。
这里要注意一个问题:通过 forwardAction(...) 转发到另一个 action 时,getRawData() 无法获取到数据,此时需要使用 setAttr("rawData", getRawData()) 将数据传递给 forward 到的目标 action,然后在目标 action 通过 getAttr("rawData") 获取。一般这种情况很少见。
getBean / getModel 系列
getModel 用来接收页面表单域传递过来的model对象,表单域名称以”modelName.attrName”方式命名,getModel使用的attrName必须与数据表字段名完全一样。
// 定义Model,在此为Blog
public class Blog extends Model<Blog> {
}
// 在页面表单中采用modelName.attrName形式为作为表单域的name
<form action="/blog/save" method="post">
//name="需要取的name(和方法名一直).数据库字段"
<input name="blog.title" type="text">
<input name="blog.content" type="text">
<input value="提交" type="submit">
</form>
public class BlogController extends Controller {
public void save() {
// 页面的modelName正好是Blog类名的首字母小写
Blog blog = getModel(Blog.class);
// 如果表单域的名称为 "otherName.title"可加上一个参数来获取
blog = getModel(Blog.class, "otherName");
}
}
如果方法名 和表域名不一样 那么用getModel(Blog.class, “otherName”)。方法 第二个参数是表的域名
如果希望传参时避免使用modelName前缀,可以使用空串作为
modelName来实现:getModel(Blog.class, “”); 这对开发纯API项目非常有用。(getBean 同样适用)
如果希望在接收时跳过数据转换或者属性名错误异常可以传入true参:getBean(…, true)
set / setAttr 方法
setAttr(String, Object) 转调了 HttpServletRequest.setAttribute(String, Object),该方法可以将各种数据传递给View并在View中显示出来。
为了进一步减少代码量、提升开发效率,jfinal 3.6 新增了 set 方法替代 setAttr,用法如下:
set("article", article);
// 链式用法
set("project", project).set("replyList", replyList).render("index.html");
render 方法
render(String view) 方法将对 view 所指向的模板进行渲染,view 参数最终指向的模板文件规则如下:
ing template = baseViewPath + viewPath + view
其中 view 即为 render(String view) 方法所携带的参数值,而 baseViewPath、viewPath 则是在路由配置时指定的两个值
public void configRoute(Routes me) {
// baseViewPath 为 "/_view",该 Routes 对象之下映射的所有 Controller 都将取这个值
me.setBaseViewPath("/_view");
// basePath 为第三个参数 "/index"
me.add("/", IndexController.class, "/index");
// 第三个参数省略时, basePath 取第一个参数的值 : "/project"
me.add("/project", ProjectController.class);
}
如果配置了这个方法那么 controller 都会在路径前加入“/_view”
比如:
public class IndexController extends Controller {
public void demo() {
// 模板指向 : "/_view/index/abc.html"
render("abc.html");
}
}
上述的 render("abc.html")这个指向"/_view/index/abc.html"
renderFile 文件下载
renderFile 基本用法
// 最终下载文件为:src/main/webapp/download/file.zip
renderFile("file.zip");
// 最终下载文件为:src/main/webapp/download/abc/def/file.zip
renderFile("abc/deb/file.zip");
baseDownloadPath 的存在相当于固定了一个基础路路径。renderFile 总是以该路径为基础路径去寻找文件。
配置 baseDownloadPath
baseDownloadPath 还可以在 configConstant(Constants me) 中自由配置,例如:me.setBaseDownloadPath("files");
也可以跳出项目
// linux、mac 系统以字符 "/" 打头是绝对路径
me.setBaseDownloadPath("/var/download");
// windows 系统以盘符打头也是绝对路径
me.setBaseDownloadPath("D:/download");
renderFile(File file)
renderFile(File file) 方法直接使用 File 参数去获取下载文件,可脱离 baseDownloadPath 的束缚,指向任意地点的文件,例如:
String file = "D:/my-project/share/files/jfinal-all.zip";
renderFile(new File(file));
为下载文件重新命名
如果不想使用下载文件原有的文件名,还可以指定新的下载文件名:
renderFile("老文件名.txt", "新文件名.txt");
renderQrCode 二维码生成
renderQrCode 用法
renderQrCode 生成二维码极其简单方便,常见用法如下:
// 二维码携带的数据
String data = "weixin://wxpay/bizpayurl?appid=xx&mch_id=xx......";
// 渲染二维码图片,长度与宽度为 200 像素
renderQrCode(data, 200, 200);
上例代码中的 data 为该二维码所携带的数据,该数据将被二维码扫描程序读取到。
此外,renderQrCode 还可以指定二维码的 "纠错级别",例如:
// 最后一个参数 'M' 为纠错级别
renderQrCode(data, 200, 200, 'M');
纠错参数可以在二维码图片被遮挡或者被损坏一部分时仍然可以正确读取其中的内容。
纠错级别从高到低可以指定为:'H'、'Q'、'M'、'L',其纠错率分别为:30%、25%、15%、7%。 不指定该参数值默认为 'L'。
maven 依赖
使用 renderQrCode 方法需要引入第三方依赖,其坐标如下:
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>javase</artifactId>
<version>3.2.1</version>
</dependency>
session 操作
- setSessionAttr(key, value)可以想session存放数据
- getSessionAttr(key) 可以从 session 中读取数据
- 还可以通过 getSession()得到 session 对象从而使用全面的session API。
getFile 文件上传
Controller提供了getFile系列方法支持文件上传。
需要引入一个依赖
<dependency>
<groupId>com.jfinal</groupId>
<artifactId>cos</artifactId>
<version>2019.8</version>
</dependency>
keep 系方法
keepPara
当页面提交表单请求到 action,如果提交过来的数据存在错误或者缺失,这时应该让用户继续修改或填写表单数据,这时可以使用 keepPara 方法将用户之前填写过的内容保持住:
// 保持住所有表单域
keepPara()
//指定保持住的表单域,如: nickName、email 等等
keepPara("nickName", "email", ...);
不带存数的方法只能保存String类型,如果想使用带参数的类型的话使用如下:
// 指定 keep 后的类型为 Date
keepPara(Date.class, "createAt");
// 指定 keep 后的类型为 Integer
keepPara(Integer.class, "age");
keepPara 一般用在 Validator 或者拦截器之中
keepModel 与 keepBean
keepModel 可以将以 modelName 前缀的表单域保持住内容与类型,例如:
<input name="blog.title" value="#(blog.title ??)"/>
<input name="blog.content" value="#(blog.content ??)" />