1.JFinal和Spring Boot对比
2.jfinal不兼容的项目下载项目下载浏览器有哪些
3.jfinal什么时候出web版的后台管理
4.jfinal2.3的定时任务如何实现
JFinal和Spring Boot对比
轻量级MVC框架:JFinal与Spring Boot的较量 JFinal,作为一款轻量级的源码源码MVC+ORM集成框架,它的免费设计理念就像简化版的SSH,旨在提供快速开发和简单易学的项目下载项目下载体验。它强调代码量少、源码源码学习简单,免费cca指标源码同时拥有Java语言的项目下载项目下载高效性和动态语言的开发效率。与之相比,源码源码Spring Boot则更像一个自动化配置神器,免费以Spring全家桶的项目下载项目下载集成和配置简化为核心,几行代码就能启动应用,源码源码无需繁冗的免费XML配置。 Spring Boot:简化Spring开发的项目下载项目下载革命 Spring Boot以其一键式创建Spring应用的能力脱颖而出,它内嵌Servlet容器,源码源码提供了Starter简化Maven配置,免费微软泄漏源码通过自动配置尽可能减少开发者的工作量。它的特性包括快速开发、健康检查和外部化配置,无需代码生成,直接上手。 对比:高效与易用的较量 尽管两者都旨在简化开发,但JFinal在上手速度和学习成本上更具优势,其文档简洁明了,一天内就能创建项目。而Spring Boot虽然功能强大,但文档量大且英语依赖性高,对新手而言可能稍显复杂。 JFinal的MVC架构设计精巧,使用简单,巅峰源码教程使开发者能深入理解框架,降低调试成本。而Spring Boot虽然也支持约定优于配置,但在源码阅读和问题定位上,JFinal的精简设计可能更胜一筹。 JFinal的Db + Record模式让数据库操作更灵活,无需繁琐的JavaBean映射。ActiveRecord的全面支持使得数据库开发高效快捷,相比之下,Spring Boot需额外集成SpringDataJPA或MyBatis来实现这些功能。 在插件扩展性上,JFinal的Plugin体系结构简洁易用,自定义插件过程简单,而Spring Boot虽有丰富的源码盒子买卖插件生态,但使用和维护可能较为复杂。 最后,JFinal的体积小巧且无第三方依赖,这反映了其对简洁和可扩展性的追求。而Spring Boot虽功能全面,但其自身重量级的特性可能成为初学者和小型项目的负担。 国内支持:社区力量的差异 JFinal在国内拥有稳定的用户群体,作者直接支持,遇到问题能得到及时解答,而Spring Boot虽然全球范围内应用广泛,但在国内的特定支持可能不如JFinal直接。 总的来说,JFinal凭借其精简的设计和易用性,以及对国内用户的eclipse提示源码贴心支持,在与Spring Boot的竞争中展现出了独特的优势。然而,Spring Boot的全面集成和强大的生态系统,使其在大型项目和复杂需求场景下仍然占据一席之地。开发者应根据项目需求和个人偏好,选择最适合自己的框架。jfinal不兼容的浏览器有哪些
官网介绍:JFinal 是基于 Java 语言的极速 WEB + ORM
框架,其核心设计目标是开发迅速、代码量少、学习简单、功能强大、轻量级、易扩展、Restful。在拥有Java语言所有优势的同时再拥有ruby、python、php等动态语言的开发效率!为您节约更多时间,去陪恋人、家人和朋友
:)
Jfinal是JAVA框架, 不在浏览器上执行的, 是两个方向。
如果你说的是Jfinal做为后台,进行下载文件服务时,是否有浏览器兼容问题,在Jfinal3.0之后的版已经全面兼容了
3.3版的源码中可看到已经有处理:
/*** Copyright (c) -, James Zhan 詹波 (jfinal@.com).
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* .jfinal.render;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import javax.servlet.ServletContext;
import javax.servlet..jfinal.kit.LogKit;
import com.jfinal.kit.StrKit;
/
*** FileRender.
*/
public class FileRender extends Render {
protected static final String DEFAULT_CONTENT_TYPE = "application/octet-stream";
protected static String baseDownloadPath;
protected static ServletContext servletContext;
protected File file;
protected String downloadFileName = null;
public FileRender(File file) {
if (file == null) {
throw new IllegalArgumentException("file can not be null.");
}
this.file = file;
}
public FileRender(File file, String downloadFileName) {
this(file);
if (StrKit.isBlank(downloadFileName)) {
throw new IllegalArgumentException("downloadFileName can not be blank.");
}
this.downloadFileName = downloadFileName;
}
public FileRender(String fileName) {
if (StrKit.isBlank(fileName)) {
throw new IllegalArgumentException("fileName can not be blank.");
}
String fullFileName;
fileName = fileName.trim();
if (fileName.startsWith("/") || fileName.startsWith("\\")) {
if (baseDownloadPath.equals("/")) {
fullFileName = fileName;
} else {
fullFileName = baseDownloadPath + fileName;
}
} else {
fullFileName = baseDownloadPath + File.separator + fileName;
}
this.file = new File(fullFileName);
}
public FileRender(String fileName, String downloadFileName) {
this(fileName);
if (StrKit.isBlank(downloadFileName)) {
throw new IllegalArgumentException("downloadFileName can not be blank.");
}
this.downloadFileName = downloadFileName;
}
static void init(String baseDownloadPath, ServletContext servletContext) {
FileRender.baseDownloadPath = baseDownloadPath;
FileRender.servletContext = servletContext;
}
public void render() {
if (file == null || !file.isFile()) {
RenderManager.me().getRenderFactory().getErrorRender().setContext(request, response).render();
return ;
}
// ---------
response.setHeader("Accept-Ranges", "bytes");
String fn = downloadFileName == null ? file.getName() : downloadFileName;
response.setHeader("Content-disposition", "attachment; " + encodeFileName(request, fn));
String contentType = servletContext.getMimeType(file.getName());
response.setContentType(contentType != null ? contentType : DEFAULT_CONTENT_TYPE);
// ---------
if (StrKit.isBlank(request.getHeader("Range"))) {
normalRender();
} else {
rangeRender();
}
}
protected String encodeFileName(String fileName) {
try {
// return new String(fileName.getBytes("GBK"), "ISO-1");
return new String(fileName.getBytes(getEncoding()), "ISO-1");
} catch (UnsupportedEncodingException e) {
return fileName;
}
}
/
*** 依据浏览器判断编码规则
*/
public String encodeFileName(HttpServletRequest request, String fileName) {
String userAgent = request.getHeader("User-Agent");
try {
String encodedFileName = URLEncoder.encode(fileName, "UTF8");
// 如果没有UA,则默认使用IE的方式进行编码
if (userAgent == null) {
return "filename=\"" + encodedFileName + "\"";
}
userAgent = userAgent.toLowerCase();
// IE浏览器,只能采用URLEncoder编码
if (userAgent.indexOf("msie") != -1) {
return "filename=\"" + encodedFileName + "\"";
}
// Opera浏览器只能采用filename
*if (userAgent.indexOf("opera") != -1) {
return "filename*=UTF-8''" + encodedFileName;
}
// Safari浏览器,只能采用ISO编码的中文输出,Chrome浏览器,只能采用MimeUtility编码或ISO编码的中文输出
if (userAgent.indexOf("safari") != -1 || userAgent.indexOf("applewebkit") != -1 || userAgent.indexOf("chrome") != -1) {
return "filename=\"" + new String(fileName.getBytes("UTF-8"), "ISO-1") + "\"";
}
// FireFox浏览器,可以使用MimeUtility或filename*或ISO编码的中文输出
if (userAgent.indexOf("mozilla") != -1) {
return "filename*=UTF-8''" + encodedFileName;
}
return "filename=\"" + encodedFileName + "\"";
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
}
protected void normalRender() {
response.setHeader("Content-Length", String.valueOf(file.length()));
InputStream inputStream = null;
OutputStream outputStream = null;
try {
inputStream = new BufferedInputStream(new FileInputStream(file));
outputStream = response.getOutputStream();
byte[] buffer = new byte[];
for (int len = -1; (len = inputStream.read(buffer)) != -1;) {
outputStream.write(buffer, 0, len);
}
outputStream.flush();
outputStream.close();
} catch (IOException e) {
String n = e.getClass().getSimpleName();
if (n.equals("ClientAbortException") || n.equals("EofException")) {
} else {
throw new RenderException(e);
}
} catch (Exception e) {
throw new RenderException(e);
} finally {
if (inputStream != null)
try { inputStream.close();} catch (IOException e) { LogKit.error(e.getMessage(), e);}
}
}
protected void rangeRender() {
Long[] range = { null, null};
processRange(range);
String contentLength = String.valueOf(range[1].longValue() - range[0].longValue() + 1);
response.setHeader("Content-Length", contentLength);
response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT); // status =
// Content-Range: bytes 0-/
StringBuilder contentRange = new StringBuilder("bytes ").append(String.valueOf(range[0])).append("-").append(String.valueOf(range[1])).append("/").append(String.valueOf(file.length()));
response.setHeader("Content-Range", contentRange.toString());
InputStream inputStream = null;
OutputStream outputStream = null;
try {
long start = range[0];
long end = range[1];
inputStream = new BufferedInputStream(new FileInputStream(file));
if (inputStream.skip(start) != start)
throw new RuntimeException("File skip error");
outputStream = response.getOutputStream();
byte[] buffer = new byte[];
long position = start;
for (int len; position <= end && (len = inputStream.read(buffer)) != -1;) {
if (position + len <= end) {
outputStream.write(buffer, 0, len);
position += len;
}
else {
for (int i=0; i<len && position <= end; i++) {
outputStream.write(buffer[i]);
position++;
}
}
}
outputStream.flush();
outputStream.close();
}
catch (IOException e) {
String n = e.getClass().getSimpleName();
if (n.equals("ClientAbortException") || n.equals("EofException")) {
} else {
throw new RenderException(e);
}
}
catch (Exception e) {
throw new RenderException(e);
}
finally {
if (inputStream != null)
try { inputStream.close();} catch (IOException e) { LogKit.error(e.getMessage(), e);}
}
}
/
*** Examples of byte-ranges-specifier values (assuming an entity-body of length ):
* The first bytes (byte offsets 0-, inclusive): bytes=0-
* The second bytes (byte offsets -, inclusive): bytes=-
* The final bytes (byte offsets -, inclusive): bytes=-
* Or bytes=-
*/
protected void processRange(Long[] range) {
String rangeStr = request.getHeader("Range");
int index = rangeStr.indexOf(',');
if (index != -1)
rangeStr = rangeStr.substring(0, index);
rangeStr = rangeStr.replace("bytes=", "");
String[] arr = rangeStr.split("-", 2);
if (arr.length < 2)
throw new RuntimeException("Range error");
long fileLength = file.length();
for (int i=0; i<range.length; i++) {
if (StrKit.notBlank(arr[i])) {
range[i] = Long.parseLong(arr[i].trim());
if (range[i] >= fileLength)
range[i] = fileLength - 1;
}
}
// Range format like: -
if (range[0] != null && range[1] == null) {
range[1] = fileLength - 1;
}
// Range format like: -
else if (range[0] == null && range[1] != null) {
range[0] = fileLength - range[1];
range[1] = fileLength - 1;
}
// check final range
if (range[0] == null || range[1] == null || range[0].longValue() > range[1].longValue())
throw new RuntimeException("Range error");
}
}
jfinal什么时候出web版的后台管理
可以加入Jfinal俱乐部,引用官网的:
俱乐部当前发放的福利是本社区 jfinal.com 的源代码,并取名为
jfinal-club。jfinal-club 在核心功能上相当于一个迷你的 OSChina 社区,newsfeed
信息流模块整合了整站动态数据,交互性极好。重要功能:动态消息、@提到我、remind提醒、关注、好友、粉丝、私信、发贴、回贴、点赞、收藏、定时任务等功能。常见的功能也很全面:文件下载、上传、用户头像裁剪、登录、注册、邮件激活、找回密码、XSS过滤、缓存、后台管理、以及一些常用工具类等等。
jfinal-club 是官方出品的唯一 JFinal 最佳实践,绝无仅有的极简设计,获得 jfinal-club 也就获得了作者本人对
JFinal 的使用精髓。基于 jfinal 3.3 开发,获得 jfinal-club 将以令人难以想象的速度掌握新版本功能。
jfinal-club 是一个长期进化的,不断添加实用功能的项目,加入俱乐部以后,将随之长期享受该福利。
---------------
web版的后台管理社区做的比较好的有:
JfinalUIB , EOVA ,JPress, ... 等很多都非常的好
/project 相关项目
/club 俱乐部
jfinal2.3的定时任务如何实现
Cron4jPlugin是JFinal集成的任务调度插件,通过使用Cron4jPlugin可以使用通用的cron表达式极为便利的实现任务调度功能。jfinal2.3 我不记得有Cron4jPlugin没有.
如果没有 你可以把 新版的jfinal更新上来, 或者把Cron4jPlugin的源码拷贝出来放到你的项目中去, 可以单独适用的.
或者直接使用 Cron4j 就可以, 参考: 网页链接