diff --git a/.classpath b/.classpath
new file mode 100644
index 000000000..b9ae3af90
--- /dev/null
+++ b/.classpath
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.gitignore b/.gitignore
index 4da2d1bbc..00af05424 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,59 +1,18 @@
-# maven #
-target
-
-logs
-
-# eclipse #
-.settings
-.project
-.classpath
-.log
-
-# windows #
-Thumbs.db
-
-# Mac #
-.DS_Store
-
-# Package Files #
-*.war
-*.ear
-
-# idea #
-.idea
-*.iml
-
-plan.txt
-
-*.class
-
-# Package Files #
-*.jar
-
-
-*.bak
-*.tmp
-*.log
-/bin/
-build.sh
-integration-repo
-/build/
-
-# IDEA metadata and output dirs
-*.ipr
-*.iws
-
-/webapp/WEB-INF/classes/
-/webapp/WEB-INF/test-classes/
-/webapp/WEB-INF/target/
-
-a_little_config_pro.txt
-
-dev_plan.txt
-
-
-
-
-
-
-
+*.bak
+*.class
+*.tmp
+*.log
+/bin/
+build.sh
+integration-repo
+/build/
+
+# IDEA metadata and output dirs
+*.iml
+*.ipr
+*.iws
+out
+
+*.jar
+/webapp/WEB-INF/classes/
+/webapp/WEB-INF/target/
\ No newline at end of file
diff --git a/.project b/.project
new file mode 100644
index 000000000..52a028186
--- /dev/null
+++ b/.project
@@ -0,0 +1,42 @@
+
+
+ jfinal
+
+
+
+
+
+ org.eclipse.wst.jsdt.core.javascriptValidator
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+ org.eclipse.wst.common.project.facet.core.builder
+
+
+
+
+ org.eclipse.m2e.core.maven2Builder
+
+
+
+
+ org.eclipse.wst.validation.validationbuilder
+
+
+
+
+
+ org.eclipse.jem.workbench.JavaEMFNature
+ org.eclipse.wst.common.modulecore.ModuleCoreNature
+ org.eclipse.jdt.core.javanature
+ org.eclipse.m2e.core.maven2Nature
+ org.eclipse.wst.common.project.facet.core.nature
+ org.eclipse.wst.jsdt.core.jsNature
+
+
diff --git a/.settings/.jsdtscope b/.settings/.jsdtscope
new file mode 100644
index 000000000..2f9827748
--- /dev/null
+++ b/.settings/.jsdtscope
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.settings/org.eclipse.core.resources.prefs b/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 000000000..4824b8026
--- /dev/null
+++ b/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+encoding/=UTF-8
diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 000000000..6428c6805
--- /dev/null
+++ b/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,12 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.6
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
+org.eclipse.jdt.core.compiler.source=1.6
diff --git a/.settings/org.eclipse.m2e.core.prefs b/.settings/org.eclipse.m2e.core.prefs
new file mode 100644
index 000000000..14b697b7b
--- /dev/null
+++ b/.settings/org.eclipse.m2e.core.prefs
@@ -0,0 +1,4 @@
+activeProfiles=
+eclipse.preferences.version=1
+resolveWorkspaceProjects=true
+version=1
diff --git a/.settings/org.eclipse.wst.common.component b/.settings/org.eclipse.wst.common.component
new file mode 100644
index 000000000..38666a1e1
--- /dev/null
+++ b/.settings/org.eclipse.wst.common.component
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/.settings/org.eclipse.wst.common.project.facet.core.xml b/.settings/org.eclipse.wst.common.project.facet.core.xml
new file mode 100644
index 000000000..dac75cc64
--- /dev/null
+++ b/.settings/org.eclipse.wst.common.project.facet.core.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/.settings/org.eclipse.wst.jsdt.ui.superType.container b/.settings/org.eclipse.wst.jsdt.ui.superType.container
new file mode 100644
index 000000000..3bd5d0a48
--- /dev/null
+++ b/.settings/org.eclipse.wst.jsdt.ui.superType.container
@@ -0,0 +1 @@
+org.eclipse.wst.jsdt.launching.baseBrowserLibrary
\ No newline at end of file
diff --git a/.settings/org.eclipse.wst.jsdt.ui.superType.name b/.settings/org.eclipse.wst.jsdt.ui.superType.name
new file mode 100644
index 000000000..05bd71b6e
--- /dev/null
+++ b/.settings/org.eclipse.wst.jsdt.ui.superType.name
@@ -0,0 +1 @@
+Window
\ No newline at end of file
diff --git a/.settings/org.eclipse.wst.validation.prefs b/.settings/org.eclipse.wst.validation.prefs
new file mode 100644
index 000000000..6f1cba68d
--- /dev/null
+++ b/.settings/org.eclipse.wst.validation.prefs
@@ -0,0 +1,2 @@
+disabled=06target
+eclipse.preferences.version=1
diff --git a/LICENSE b/LICENSE
deleted file mode 100644
index de0ae3a48..000000000
--- a/LICENSE
+++ /dev/null
@@ -1,196 +0,0 @@
-Apache License
-Version 2.0, January 2004
-http://www.apache.org/licenses/
-
-TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
-1. Definitions.
-
-"License" shall mean the terms and conditions for use, reproduction, and
-distribution as defined by Sections 1 through 9 of this document.
-
-"Licensor" shall mean the copyright owner or entity authorized by the copyright
-owner that is granting the License.
-
-"Legal Entity" shall mean the union of the acting entity and all other entities
-that control, are controlled by, or are under common control with that entity.
-For the purposes of this definition, "control" means (i) the power, direct or
-indirect, to cause the direction or management of such entity, whether by
-contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the
-outstanding shares, or (iii) beneficial ownership of such entity.
-
-"You" (or "Your") shall mean an individual or Legal Entity exercising
-permissions granted by this License.
-
-"Source" form shall mean the preferred form for making modifications, including
-but not limited to software source code, documentation source, and configuration
-files.
-
-"Object" form shall mean any form resulting from mechanical transformation or
-translation of a Source form, including but not limited to compiled object code,
-generated documentation, and conversions to other media types.
-
-"Work" shall mean the work of authorship, whether in Source or Object form, made
-available under the License, as indicated by a copyright notice that is included
-in or attached to the work (an example is provided in the Appendix below).
-
-"Derivative Works" shall mean any work, whether in Source or Object form, that
-is based on (or derived from) the Work and for which the editorial revisions,
-annotations, elaborations, or other modifications represent, as a whole, an
-original work of authorship. For the purposes of this License, Derivative Works
-shall not include works that remain separable from, or merely link (or bind by
-name) to the interfaces of, the Work and Derivative Works thereof.
-
-"Contribution" shall mean any work of authorship, including the original version
-of the Work and any modifications or additions to that Work or Derivative Works
-thereof, that is intentionally submitted to Licensor for inclusion in the Work
-by the copyright owner or by an individual or Legal Entity authorized to submit
-on behalf of the copyright owner. For the purposes of this definition,
-"submitted" means any form of electronic, verbal, or written communication sent
-to the Licensor or its representatives, including but not limited to
-communication on electronic mailing lists, source code control systems, and
-issue tracking systems that are managed by, or on behalf of, the Licensor for
-the purpose of discussing and improving the Work, but excluding communication
-that is conspicuously marked or otherwise designated in writing by the copyright
-owner as "Not a Contribution."
-
-"Contributor" shall mean Licensor and any individual or Legal Entity on behalf
-of whom a Contribution has been received by Licensor and subsequently
-incorporated within the Work.
-
-2. Grant of Copyright License.
-
-Subject to the terms and conditions of this License, each Contributor hereby
-grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
-irrevocable copyright license to reproduce, prepare Derivative Works of,
-publicly display, publicly perform, sublicense, and distribute the Work and such
-Derivative Works in Source or Object form.
-
-3. Grant of Patent License.
-
-Subject to the terms and conditions of this License, each Contributor hereby
-grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
-irrevocable (except as stated in this section) patent license to make, have
-made, use, offer to sell, sell, import, and otherwise transfer the Work, where
-such license applies only to those patent claims licensable by such Contributor
-that are necessarily infringed by their Contribution(s) alone or by combination
-of their Contribution(s) with the Work to which such Contribution(s) was
-submitted. If You institute patent litigation against any entity (including a
-cross-claim or counterclaim in a lawsuit) alleging that the Work or a
-Contribution incorporated within the Work constitutes direct or contributory
-patent infringement, then any patent licenses granted to You under this License
-for that Work shall terminate as of the date such litigation is filed.
-
-4. Redistribution.
-
-You may reproduce and distribute copies of the Work or Derivative Works thereof
-in any medium, with or without modifications, and in Source or Object form,
-provided that You meet the following conditions:
-
-You must give any other recipients of the Work or Derivative Works a copy of
-this License; and
-You must cause any modified files to carry prominent notices stating that You
-changed the files; and
-You must retain, in the Source form of any Derivative Works that You distribute,
-all copyright, patent, trademark, and attribution notices from the Source form
-of the Work, excluding those notices that do not pertain to any part of the
-Derivative Works; and
-If the Work includes a "NOTICE" text file as part of its distribution, then any
-Derivative Works that You distribute must include a readable copy of the
-attribution notices contained within such NOTICE file, excluding those notices
-that do not pertain to any part of the Derivative Works, in at least one of the
-following places: within a NOTICE text file distributed as part of the
-Derivative Works; within the Source form or documentation, if provided along
-with the Derivative Works; or, within a display generated by the Derivative
-Works, if and wherever such third-party notices normally appear. The contents of
-the NOTICE file are for informational purposes only and do not modify the
-License. You may add Your own attribution notices within Derivative Works that
-You distribute, alongside or as an addendum to the NOTICE text from the Work,
-provided that such additional attribution notices cannot be construed as
-modifying the License.
-You may add Your own copyright statement to Your modifications and may provide
-additional or different license terms and conditions for use, reproduction, or
-distribution of Your modifications, or for any such Derivative Works as a whole,
-provided Your use, reproduction, and distribution of the Work otherwise complies
-with the conditions stated in this License.
-
-5. Submission of Contributions.
-
-Unless You explicitly state otherwise, any Contribution intentionally submitted
-for inclusion in the Work by You to the Licensor shall be under the terms and
-conditions of this License, without any additional terms or conditions.
-Notwithstanding the above, nothing herein shall supersede or modify the terms of
-any separate license agreement you may have executed with Licensor regarding
-such Contributions.
-
-6. Trademarks.
-
-This License does not grant permission to use the trade names, trademarks,
-service marks, or product names of the Licensor, except as required for
-reasonable and customary use in describing the origin of the Work and
-reproducing the content of the NOTICE file.
-
-7. Disclaimer of Warranty.
-
-Unless required by applicable law or agreed to in writing, Licensor provides the
-Work (and each Contributor provides its Contributions) on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
-including, without limitation, any warranties or conditions of TITLE,
-NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are
-solely responsible for determining the appropriateness of using or
-redistributing the Work and assume any risks associated with Your exercise of
-permissions under this License.
-
-8. Limitation of Liability.
-
-In no event and under no legal theory, whether in tort (including negligence),
-contract, or otherwise, unless required by applicable law (such as deliberate
-and grossly negligent acts) or agreed to in writing, shall any Contributor be
-liable to You for damages, including any direct, indirect, special, incidental,
-or consequential damages of any character arising as a result of this License or
-out of the use or inability to use the Work (including but not limited to
-damages for loss of goodwill, work stoppage, computer failure or malfunction, or
-any and all other commercial damages or losses), even if such Contributor has
-been advised of the possibility of such damages.
-
-9. Accepting Warranty or Additional Liability.
-
-While redistributing the Work or Derivative Works thereof, You may choose to
-offer, and charge a fee for, acceptance of support, warranty, indemnity, or
-other liability obligations and/or rights consistent with this License. However,
-in accepting such obligations, You may act only on Your own behalf and on Your
-sole responsibility, not on behalf of any other Contributor, and only if You
-agree to indemnify, defend, and hold each Contributor harmless for any liability
-incurred by, or claims asserted against, such Contributor by reason of your
-accepting any such warranty or additional liability.
-
-END OF TERMS AND CONDITIONS
-
-APPENDIX: How to apply the Apache License to your work
-
-To apply the Apache License to your work, attach the following boilerplate
-notice, with the fields enclosed by brackets "{}" replaced with your own
-identifying information. (Don't include the brackets!) The text should be
-enclosed in the appropriate comment syntax for the file format. We also
-recommend that a file or class name and description of purpose be included on
-the same "printed page" as the copyright notice for easier identification within
-third-party archives.
-
- Copyright 2011-2035 詹波 (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
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
-
-
-
-
diff --git a/README.md b/README.md
deleted file mode 100644
index 54f536d71..000000000
--- a/README.md
+++ /dev/null
@@ -1,140 +0,0 @@
-## JAVA 极速WEB+ORM框架 JFinal
-[中文](README.md) [English](README_en.md)
-
-JFinal 是基于 Java 语言的极速 WEB + ORM 框架,其核心设计目标是开发迅速、代码量少、学习简单、功能强大、轻量级、易扩展、Restful。在拥有Java语言所有优势的同时再拥有 ruby、python 等动态语言的开发效率!为您节约更多时间,去陪恋人、家人和朋友 ;)
-
-#### JFinal有如下主要特点
-- MVC 架构,设计精巧,使用简单
-- 遵循 COC 原则,支持零配置,无 XML
-- 独创 Db + Record 模式,灵活便利
-- ActiveRecord 支持,使数据库开发极致快速
-- 极简、强大、高性能模板引擎 Enjoy,十分钟内掌握 90% 用法
-- 自动加载修改后的 Java 文件,开发过程中无需重启服务
-- AOP支持,拦截器配置灵活,功能强大
-- Plugin 体系结构,扩展性强
-- 多视图支持,支持 Enjoy、FreeMarker、JSP
-- 强大的 Validator 后端校验功能
-- 功能齐全,拥有传统 SSH 框架的绝大部分核心功能
-- 体积小仅 832 KB,并且无第三方依赖
-
-**JFinal 极速开发微信公众号欢迎你的加入: JFinal**
-
-## Maven 坐标
-
-```java
-
- com.jfinal
- jfinal
- 5.2.6
-
-```
-
-## 以下是JFinal实现Blog管理的示例:
-
-**1. 控制器(支持 Enjoy、JSP、JSON等等以及自定义视图渲染)**
-
-```java
-@Before(BlogInterceptor.class)
-public class BlogController extends Controller {
-
- @Inject
- BlogService service;
-
- public void index() {
- set("blogPage", service.paginate(getInt(0, 1), 10));
- render("blog.html");
- }
-
- public void add() {
- }
-
- @Before(BlogValidator.class)
- public void save() {
- getModel(Blog.class).save();
- redirect("/blog");
- }
-
- public void edit() {
- set("blog", service.findById(getInt()));
- }
-
- @Before(BlogValidator.class)
- public void update() {
- getModel(Blog.class).update();
- redirect("/blog");
- }
-
- public void delete() {
- service.deleteById(getInt());
- redirect("/blog");
- }
-}
-```
-
-**2.Service所有业务与sql全部放在Service层**
-
-```java
-public class BlogService {
-
- private Blog dao = new Blog().dao();
-
- public Page paginate(int pageNumber, int pageSize) {
- return dao.paginate(pageNumber, pageSize, "select *", "from blog order by id asc");
- }
-
- public Blog findById(int id) {
- return dao.findById(id);
- }
-
- public void deleteById(int id) {
- dao.deleteById(id);
- }
-}
-```
-
-**3.Model(无xml、无annotaion、无attribute)**
-
-```java
-public class Blog extends Model {
-
-}
-```
-
-**4.Validator(API引导式校验,比xml校验方便N倍,有代码检查不易出错)**
-
-```java
-public class BlogValidator extends Validator {
- protected void validate(Controller controller) {
- validateRequiredString("blog.title", "titleMsg", "请输入Blog标题!");
- validateRequiredString("blog.content", "contentMsg", "请输入Blog内容!");
- }
-
- protected void handleError(Controller controller) {
- controller.keepModel(Blog.class);
- }
-}
-```
-
-**5.拦截器(在此demo中仅为示例,本demo不需要此拦截器)**
-
-```java
-public class BlogInterceptor implements Interceptor {
- public void intercept(Invocation inv) {
- System.out.println("Before invoking " + inv.getActionKey());
- inv.invoke();
- System.out.println("After invoking " + inv.getActionKey());
- }
-}
-```
-
-## 更多支持
-- JFinal 官方网站 [https://jfinal.com](https://jfinal.com/)
-- 扫码关注官方微信公众号,第一时间尊享最新动向
-
-
-
-
-
-
-
-
diff --git a/README.rst b/README.rst
new file mode 100644
index 000000000..ed961a45d
--- /dev/null
+++ b/README.rst
@@ -0,0 +1,93 @@
+===========================
+JAVA 极速WEB+ORM框架 JFinal
+===========================
+
+ JFinal 是基于 Java 语言的极速 WEB + ORM 框架,其核心设计目标是开发迅速、代码量少、学习简单、功能强大、轻量级、易扩展、Restful。在拥有Java语言所有优势的同时再拥有ruby、python等动态语言的开发效率!为您节约更多时间,去陪恋人、家人和朋友 ;)
+
+JFinal有如下主要特点
+------------------------
+#. MVC架构,设计精巧,使用简单
+#. 遵循COC原则,零配置,无xml
+#. 独创Db + Record模式,灵活便利
+#. ActiveRecord支持,使数据库开发极致快速
+#. 自动加载修改后的java文件,开发过程中无需重启web server
+#. AOP支持,拦截器配置灵活,功能强大
+#. Plugin体系结构,扩展性强
+#. 多视图支持,支持FreeMarker、JSP、Velocity
+#. 强大的Validator后端校验功能
+#. 功能齐全,拥有struts2的绝大部分功能
+#. 体积小仅218K,且无第三方依赖
+
+**JFinal 极速开发QQ群欢迎您的加入: 222478625、326297041、196337924**
+
+**以下是JFinal实现Blog管理的示例:**
+
+**1. 控制器(支持FreeMarker、JSP、Velocity、JSON等等以及自定义视图渲染)**
+
+::
+
+ @Before(BlogInterceptor.class)
+ public class BlogController extends Controller {
+ public void index() {
+ setAttr("blogList", Blog.dao.find("select * from blog"));
+ }
+ public void add() {
+ }
+
+ @Before(BlogValidator.class)
+ public void save() {
+ getModel(Blog.class).save();
+ }
+
+ public void edit() {
+ setAttr("blog", Blog.dao.findById(getParaToInt()));
+ }
+
+ @Before(BlogValidator.class)
+ public void update() {
+ getModel(Blog.class).update();
+ }
+
+ public void delete() {
+ Blog.dao.deleteById(getParaToInt());
+ }
+ }
+
+**2.Model(无xml、无annotaion、无attribute、无getter、无setter、new
+Blog()这行代码也不是必须)**
+::
+
+ public class Blog extends Model {
+ public static final Blog dao = new Blog();
+ }
+
+**3.Validator(API引导式校验,比xml校验方便N倍,有代码检查不易出错)**
+
+::
+
+ public class BlogValidator extends Validator {
+ protected void validate(Controller controller) {
+ validateRequiredString("blog.title", "titleMsg", "请输入Blog标题!");
+ validateRequiredString("blog.content", "contentMsg", "请输入Blog内容!");
+ }
+
+ protected void handleError(Controller controller) {
+ controller.keepModel(Blog.class);
+ }
+ }
+
+**4.拦截器(在此demo中仅为示例,本demo不需要此拦截器)**
+
+::
+
+ public class BlogInterceptor implements Interceptor {
+ public void intercept(ActionInvocation ai) {
+ System.out.println("Before invoking " + ai.getActionKey());
+ ai.invoke();
+ System.out.println("After invoking " + ai.getActionKey());
+ }
+ }
+
+
+
+**JFinal 官方网站:http://www.jfinal.com**
diff --git a/README_en.md b/README_en.md
deleted file mode 100644
index 794b62adb..000000000
--- a/README_en.md
+++ /dev/null
@@ -1,134 +0,0 @@
-## JAVA Ultra-fast WEB+ORM Framework JFinal
-[中文](README.md) [English](README_en.md)
-
-JFinal is an ultra-fast WEB + ORM framework based on the Java language. Its core design goals are rapid development, minimal code, simple learning, powerful functionality, lightweight, easy to expand, and Restful. While possessing all the advantages of the Java language, it also has the development efficiency of dynamic languages like ruby and python! Save more time for you to spend with your loved ones, family, and friends ;)
-
-#### JFinal has the following key features:
-- MVC architecture, elegantly designed, easy to use.
-- Adheres to the COC principle, supports zero-configuration, and is XML-free.
-- Unique Db + Record mode, flexible and convenient.
-- Supports ActiveRecord, making database development extremely fast.
-- Minimalistic, powerful, high-performance template engine Enjoy. Master 90% of its usage within 10 minutes.
-- Auto-reloads modified Java files, eliminating the need to restart services during development.
-- Supports AOP, flexible interceptor configuration, and robust functionality.
-- Plugin architecture, highly extensible.
-- Supports multiple views, including Enjoy, FreeMarker, and JSP.
-- Powerful Validator for backend validation.
-- Feature-rich, possessing most of the core functionalities of traditional SSH frameworks.
-- Small in size at only 832 KB, with no third-party dependencies.
-
-**Join JFinal's ultra-fast WeChat official account development: JFinal**
-
-## Maven Coordinates
-
-```java
-
- com.jfinal
- jfinal
- 5.2.6
-
-```
-
-## Below is an example of how JFinal implements Blog management:
-
-**1. Controller (Supports Enjoy, JSP, JSON, etc., as well as custom view rendering)**
-
-```java
-@Before(BlogInterceptor.class)
-public class BlogController extends Controller {
-
- @Inject
- BlogService service;
-
- public void index() {
- set("blogPage", service.paginate(getInt(0, 1), 10));
- render("blog.html");
- }
-
- public void add() {
- }
-
- @Before(BlogValidator.class)
- public void save() {
- getModel(Blog.class).save();
- redirect("/blog");
- }
-
- public void edit() {
- set("blog", service.findById(getInt()));
- }
-
- @Before(BlogValidator.class)
- public void update() {
- getModel(Blog.class).update();
- redirect("/blog");
- }
-
- public void delete() {
- service.deleteById(getInt());
- redirect("/blog");
- }
-}
-```
-
-**2. All business and SQL are placed in the Service layer**
-
-```java
-public class BlogService {
-
- private Blog dao = new Blog().dao();
-
- public Page paginate(int pageNumber, int pageSize) {
- return dao.paginate(pageNumber, pageSize, "select *", "from blog order by id asc");
- }
-
- public Blog findById(int id) {
- return dao.findById(id);
- }
-
- public void deleteById(int id) {
- dao.deleteById(id);
- }
-}
-```
-
-**3. Model (No XML, no annotations, no attributes)**
-
-```java
-public class Blog extends Model {
-
-}
-```
-
-**4. Validator (API-guided validation, much more convenient than XML validation, code-checked to minimize errors)**
-
-```java
-public class BlogValidator extends Validator {
- protected void validate(Controller controller) {
- validateRequiredString("blog.title", "titleMsg", "请输入Blog标题!");
- validateRequiredString("blog.content", "contentMsg", "请输入Blog内容!");
- }
-
- protected void handleError(Controller controller) {
- controller.keepModel(Blog.class);
- }
-}
-```
-
-**5. Interceptor (Only for demonstration in this demo, this demo does not require this interceptor)**
-
-```java
-public class BlogInterceptor implements Interceptor {
- public void intercept(Invocation inv) {
- System.out.println("Before invoking " + inv.getActionKey());
- inv.invoke();
- System.out.println("After invoking " + inv.getActionKey());
- }
-}
-```
-
-## More Support:
-- JFinal official website [https://jfinal.com](https://jfinal.com/)
-- Scan to follow the official WeChat official account and enjoy the latest updates first.
-
-
diff --git a/pom.xml b/pom.xml
index 6dbe77cfe..be96ac690 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1,365 +1,179 @@
-
-
- 4.0.0
-
- com.jfinal
- jfinal
- 5.2.6
- jar
-
- JFinal
- JFinal is a simple, light, rapid,independent, extensible Java WEB + ORM framework. The feature of JFinal looks like ruby on rails especially ActiveRecord.
- https://jfinal.com
-
-
- UTF-8
- UTF-8
-
-
-
- Github Issue
- https://gitee.com/jfinal/jfinal/issues
-
-
-
-
- The Apache Software License, Version 2.0
- http://apache.org/licenses/LICENSE-2.0.txt
-
-
-
-
-
- jfinal
- James
- jfinal@126.com
- https://jfinal.com/user/1
-
-
-
-
- scm:git:git@gitee.com:jfinal/jfinal.git
- scm:git:git@gitee.com:jfinal/jfinal.git
- git@gitee.com:jfinal/jfinal.git
-
-
-
-
- jfinal
- https://oss.sonatype.org/content/repositories/snapshots/
-
-
- jfinal
- https://oss.sonatype.org/service/local/staging/deploy/maven2/
-
-
-
-
-
-
-
-
-
- junit
- junit
- 4.13.2
- test
-
-
-
-
- org.slf4j
- slf4j-api
- 2.0.7
- provided
-
-
-
-
- com.jfinal
- jetty-server
- 2019.3
- provided
-
-
-
-
- org.eclipse.jetty
- jetty-jsp
- 9.2.26.v20180806
- provided
-
-
-
-
- com.jfinal
- cos
- 2022.2
- provided
-
-
-
-
- commons-fileupload
- commons-fileupload
- 1.5
- provided
-
-
-
-
- com.alibaba
- druid
- 1.2.4
- provided
-
-
-
-
- com.zaxxer
- HikariCP
- 4.0.3
- provided
-
-
-
-
- com.mchange
- c3p0
- 0.9.5.5
- provided
-
-
-
-
- com.alibaba
- fastjson
- 1.2.83
- provided
-
-
-
-
- net.sf.ehcache
- ehcache-core
- 2.6.11
- provided
-
-
-
-
- org.freemarker
- freemarker
- 2.3.20
- provided
-
-
-
-
- log4j
- log4j
- 1.2.17
- provided
-
-
-
-
- org.apache.logging.log4j
- log4j-core
- 2.20.0
- provided
-
-
-
-
- redis.clients
- jedis
- 3.6.3
- provided
-
-
- de.ruedigermoeller
- fst
- 2.57
- provided
-
-
-
- com.fasterxml.jackson.core
- jackson-core
-
-
-
-
-
- org.apache.fury
- fury-core
- 0.9.0
- provided
-
-
-
-
-
-
- com.fasterxml.jackson.core
- jackson-databind
- 2.11.0
- provided
-
-
-
-
- it.sauronsoftware.cron4j
- cron4j
- 2.2.5
- provided
-
-
-
-
- com.google.zxing
- javase
- 3.4.1
- provided
-
-
-
-
- org.javassist
- javassist
- 3.30.2-GA
- provided
-
-
-
-
- cglib
- cglib-nodep
- 3.3.0
- provided
-
-
-
-
- org.springframework
- spring-webmvc
- 5.3.18
- provided
-
-
-
-
-
-
-
-
- src/main/java
-
-
- **/*.jf
-
- false
-
-
-
-
-
- org.apache.maven.plugins
- maven-compiler-plugin
- 3.8.1
-
- 1.8
- 1.8
- UTF-8
-
-
-
-
-
- org.apache.maven.plugins
- maven-javadoc-plugin
- 2.10.4
-
-
- -Xdoclint:none
- UTF-8
-
-
-
- attach-javadocs
-
- jar
-
-
-
-
-
-
-
- org.apache.maven.plugins
- maven-source-plugin
- 2.1.2
-
-
- attach-sources
- verify
-
- jar-no-fork
-
-
-
-
-
-
- org.apache.maven.plugins
- maven-gpg-plugin
- 1.6
-
-
- sign-artifacts
- verify
-
- sign
-
-
-
-
-
-
-
- org.sonatype.central
- central-publishing-maven-plugin
- 0.7.0
- true
-
-
- jfinal
- true
-
-
-
-
-
-
-
-
+
+ 4.0.0
+ com.jfinal
+ jfinal
+ jar
+ JFinal
+ 1.9-SNAPSHOT
+ http://www.jfinal.com
+ JFinal is a simple, light, rapid,independent, extensible Java WEB + ORM framework. The feature of JFinal looks like ruby on rails especially ActiveRecord.
+
+
+ UTF-8
+
+
+
+ Github Issue
+ http://github.com/jfinal/jfinal/issues
+
+
+
+ The Apache Software License, Version 2.0
+ http://apache.org/licenses/LICENSE-2.0.txt
+
+
+
+
+ jfinal
+ James
+ jfinal@126.com
+ http://weibo.com/jfinal
+
+
+
+ scm:git:git@github.com:jfinal/jfinal.git
+ scm:git:git@github.com:jfinal/jfinal.git
+ git@github.com:jfinal/jfinal.git
+
+
+
+ org.sonatype.oss
+ oss-parent
+ 7
+
+
+
+
+
+
+ junit
+ junit
+ 4.8.2
+ test
+
+
+ com.jfinal
+ jetty-server
+ 8.1.8
+ provided
+
+
+ javax.servlet
+ servlet-api
+ 2.5
+ provided
+
+
+
+ c3p0
+ c3p0
+ 0.9.1.2
+ provided
+
+
+ com.alibaba
+ druid
+ 1.0.5
+ provided
+
+
+ net.sf.ehcache
+ ehcache-core
+ 2.6.6
+ provided
+
+
+ org.freemarker
+ freemarker
+ 2.3.20
+ provided
+
+
+ javax.servlet.jsp.jstl
+ javax.servlet.jsp.jstl-api
+ 1.2.1
+ provided
+
+
+ log4j
+ log4j
+ 1.2.16
+ provided
+
+
+ org.apache.velocity
+ velocity
+ 1.7
+ provided
+
+
+ org.springframework
+ spring-context
+ 3.2.4.RELEASE
+ provided
+
+
+ com.jfinal
+ cos
+ 26Dec2008
+ provided
+
+
+
+
+ ${project.basedir}/src
+ ${project.basedir}/test
+
+
+
+ ${project.basedir}/src
+ false
+
+ **/*.java
+
+
+
+
+
+ ${project.basedir}/test
+ false
+
+ **/*.java
+
+
+
+
+ ${project.basedir}/webapp/WEB-INF/target
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 2.5
+
+ 1.6
+ 1.6
+
+
+
+
+ org.apache.maven.plugins
+ maven-gpg-plugin
+ 1.1
+
+
+ sign-artifacts
+ verify
+
+ sign
+
+
+
+
+ false
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/com/jfinal/aop/ActionInvocationWrapper.java b/src/com/jfinal/aop/ActionInvocationWrapper.java
new file mode 100644
index 000000000..40b20cee4
--- /dev/null
+++ b/src/com/jfinal/aop/ActionInvocationWrapper.java
@@ -0,0 +1,91 @@
+/**
+ * Copyright (c) 2011-2014, James Zhan 詹波 (jfinal@126.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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.jfinal.aop;
+
+import java.lang.reflect.Method;
+import com.jfinal.core.ActionInvocation;
+import com.jfinal.core.Controller;
+
+/**
+ * ActionInvocationWrapper invoke the InterceptorStack.
+ */
+class ActionInvocationWrapper extends ActionInvocation {
+
+ private Interceptor[] inters;
+ private ActionInvocation actionInvocation;
+ private int index = 0;
+
+ ActionInvocationWrapper(ActionInvocation actionInvocation, Interceptor[] inters) {
+ this.actionInvocation = actionInvocation;
+ this.inters = inters;
+ }
+
+ /**
+ * Invoke the action
+ */
+ @Override
+ public final void invoke() {
+ if (index < inters.length)
+ inters[index++].intercept(this);
+ else if (index++ == inters.length)
+ actionInvocation.invoke();
+ }
+
+ @Override
+ public Controller getController() {
+ return actionInvocation.getController();
+ }
+
+ @Override
+ public String getActionKey() {
+ return actionInvocation.getActionKey();
+ }
+
+ @Override
+ public String getControllerKey() {
+ return actionInvocation.getControllerKey();
+ }
+
+ @Override
+ public Method getMethod() {
+ return actionInvocation.getMethod();
+ }
+
+ @Override
+ public String getMethodName() {
+ return actionInvocation.getMethodName();
+ }
+
+ /**
+ * Return view path of this controller
+ */
+ @Override
+ public String getViewPath() {
+ return actionInvocation.getViewPath();
+ }
+
+ /*
+ * It should be added method below when com.jfinal.core.ActionInvocation add method, otherwise null will be returned.
+ */
+}
+
+
+
+
+
+
+
diff --git a/src/main/java/com/jfinal/aop/Before.java b/src/com/jfinal/aop/Before.java
similarity index 84%
rename from src/main/java/com/jfinal/aop/Before.java
rename to src/com/jfinal/aop/Before.java
index b386a8515..c69d3312f 100644
--- a/src/main/java/com/jfinal/aop/Before.java
+++ b/src/com/jfinal/aop/Before.java
@@ -1,37 +1,33 @@
-/**
- * Copyright (c) 2011-2023, James Zhan 詹波 (jfinal@126.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
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.jfinal.aop;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Inherited;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-/**
- * Before is used to configure Interceptor and Validator.
- */
-@Inherited
-@Documented
-@Retention(RetentionPolicy.RUNTIME)
-@Target({ElementType.TYPE, ElementType.METHOD})
-public @interface Before {
- Class extends Interceptor>[] value();
-}
-
-
+/**
+ * Copyright (c) 2011-2014, James Zhan 詹波 (jfinal@126.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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.jfinal.aop;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Before is used to configure Interceptor or Validator.
+ */
+@Inherited
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE, ElementType.METHOD})
+public @interface Before {
+ Class extends Interceptor>[] value();
+}
diff --git a/src/main/java/com/jfinal/aop/Inject.java b/src/com/jfinal/aop/ClearInterceptor.java
similarity index 67%
rename from src/main/java/com/jfinal/aop/Inject.java
rename to src/com/jfinal/aop/ClearInterceptor.java
index 50802e56c..5a3e5482d 100644
--- a/src/main/java/com/jfinal/aop/Inject.java
+++ b/src/com/jfinal/aop/ClearInterceptor.java
@@ -1,40 +1,38 @@
-/**
- * Copyright (c) 2011-2023, James Zhan 詹波 (jfinal@126.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
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.jfinal.aop;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Inherited;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-/**
- * Inject is used to inject dependent object
- */
-@Inherited
-@Documented
-@Retention(RetentionPolicy.RUNTIME)
-@Target({ElementType.FIELD})
-public @interface Inject {
-
- /**
- * 被注入类的类型
- */
- Class> value() default Void.class;
-}
-
+/**
+ * Copyright (c) 2011-2014, James Zhan 詹波 (jfinal@126.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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.jfinal.aop;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * ClearInterceptor is used to clear interceptors of different level.
+ * It clear the upper layer interceptors by default and clear
+ * all layers with parameter ClearLayer.ALL
+ */
+@Inherited
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE, ElementType.METHOD})
+public @interface ClearInterceptor {
+ ClearLayer value() default ClearLayer.UPPER;
+}
+
+
+
diff --git a/src/main/java/com/jfinal/proxy/Proxy.java b/src/com/jfinal/aop/ClearLayer.java
similarity index 58%
rename from src/main/java/com/jfinal/proxy/Proxy.java
rename to src/com/jfinal/aop/ClearLayer.java
index 000396bf5..2c6b2c7f5 100644
--- a/src/main/java/com/jfinal/proxy/Proxy.java
+++ b/src/com/jfinal/aop/ClearLayer.java
@@ -1,38 +1,36 @@
-/**
- * Copyright (c) 2011-2023, James Zhan 詹波 (jfinal@126.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
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.jfinal.proxy;
-
-/**
- * Proxy
- */
-public class Proxy {
-
- static ProxyFactory proxyFactory = new ProxyFactory();
-
- /**
- * 获取代理对象
- * @param target 被代理的类
- * @return 代理对象
- */
- public static T get(Class target) {
- return proxyFactory.get(target);
- }
-}
-
-
-
-
+/**
+ * Copyright (c) 2011-2014, James Zhan 詹波 (jfinal@126.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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.jfinal.aop;
+
+/**
+ * ClearLayer indicates ClearIntercptor which layer of interceptor should be cleared.
+ * The JFinal interceptor has 3 layers, there are Global, Controller and Action.
+ */
+public enum ClearLayer {
+
+ /**
+ * clear the interceptor of upper layer
+ */
+ UPPER,
+
+ /**
+ * clear the interceptor of all layers
+ */
+ ALL;
+}
+
+
diff --git a/src/main/java/com/jfinal/aop/Interceptor.java b/src/com/jfinal/aop/Interceptor.java
similarity index 79%
rename from src/main/java/com/jfinal/aop/Interceptor.java
rename to src/com/jfinal/aop/Interceptor.java
index 4e68ae2d7..f2561c32d 100644
--- a/src/main/java/com/jfinal/aop/Interceptor.java
+++ b/src/com/jfinal/aop/Interceptor.java
@@ -1,25 +1,26 @@
-/**
- * Copyright (c) 2011-2023, James Zhan 詹波 (jfinal@126.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
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.jfinal.aop;
-
-/**
- * Interceptor.
- */
-public interface Interceptor {
- void intercept(Invocation inv);
-}
-
+/**
+ * Copyright (c) 2011-2014, James Zhan 詹波 (jfinal@126.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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.jfinal.aop;
+
+import com.jfinal.core.ActionInvocation;
+
+/**
+ * Interceptor.
+ */
+public interface Interceptor {
+ void intercept(ActionInvocation ai);
+}
diff --git a/src/main/java/com/jfinal/aop/InterceptorStack.java b/src/com/jfinal/aop/InterceptorStack.java
similarity index 73%
rename from src/main/java/com/jfinal/aop/InterceptorStack.java
rename to src/com/jfinal/aop/InterceptorStack.java
index 22f01857a..ad90bdc48 100644
--- a/src/main/java/com/jfinal/aop/InterceptorStack.java
+++ b/src/com/jfinal/aop/InterceptorStack.java
@@ -1,68 +1,63 @@
-/**
- * Copyright (c) 2011-2023, James Zhan 詹波 (jfinal@126.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
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.jfinal.aop;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * InterceptorStack.
- */
-public abstract class InterceptorStack implements Interceptor {
-
- private Interceptor[] inters;
- private List interList;
-
- public InterceptorStack() {
- config();
-
- if (interList == null)
- throw new RuntimeException("You must invoke addInterceptors(...) to config your InterceptorStack");
-
- inters = interList.toArray(new Interceptor[interList.size()]);
- interList.clear();
- interList = null;
- }
-
- protected InterceptorStack addInterceptors(Interceptor... interceptors) {
- if (interceptors == null || interceptors.length == 0) {
- throw new IllegalArgumentException("Interceptors can not be null");
- }
-
- if (interList == null) {
- interList = new ArrayList();
- }
-
- for (Interceptor ref : interceptors) {
- if (AopManager.me().isInjectDependency()) {
- Aop.inject(ref);
- }
- interList.add(ref);
- }
-
- return this;
- }
-
- public final void intercept(Invocation inv) {
- new InvocationWrapper(inv, inters).invoke();
- }
-
- public abstract void config();
-}
-
-
-
+/**
+ * Copyright (c) 2011-2014, James Zhan 詹波 (jfinal@126.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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.jfinal.aop;
+
+import java.util.ArrayList;
+import java.util.List;
+import com.jfinal.core.ActionInvocation;
+
+/**
+ * InterceptorStack.
+ */
+public abstract class InterceptorStack implements Interceptor {
+
+ private Interceptor[] inters;
+ private List interList;
+
+ public InterceptorStack() {
+ config();
+
+ if (interList == null)
+ throw new RuntimeException("You must invoke addInterceptors(...) to config your InterceptorStack");
+
+ inters = interList.toArray(new Interceptor[interList.size()]);
+ interList.clear();
+ interList = null;
+ }
+
+ protected final InterceptorStack addInterceptors(Interceptor... interceptors) {
+ if (interceptors == null || interceptors.length == 0)
+ throw new IllegalArgumentException("Interceptors can not be null");
+
+ if (interList == null)
+ interList = new ArrayList();
+
+ for (Interceptor ref : interceptors)
+ interList.add(ref);
+
+ return this;
+ }
+
+ public final void intercept(ActionInvocation ai) {
+ new ActionInvocationWrapper(ai, inters).invoke();
+ }
+
+ public abstract void config();
+}
+
+
+
diff --git a/src/main/java/com/jfinal/aop/PrototypeInterceptor.java b/src/com/jfinal/aop/PrototypeInterceptor.java
similarity index 73%
rename from src/main/java/com/jfinal/aop/PrototypeInterceptor.java
rename to src/com/jfinal/aop/PrototypeInterceptor.java
index 0675096bc..b787b21c0 100644
--- a/src/main/java/com/jfinal/aop/PrototypeInterceptor.java
+++ b/src/com/jfinal/aop/PrototypeInterceptor.java
@@ -1,35 +1,37 @@
-/**
- * Copyright (c) 2011-2023, James Zhan 詹波 (jfinal@126.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
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.jfinal.aop;
-
-/**
- * PrototypeInterceptor.
- */
-public abstract class PrototypeInterceptor implements Interceptor {
-
- final public void intercept(Invocation inv) {
- try {
- getClass().newInstance().doIntercept(inv);
- } catch (RuntimeException e) {
- throw e;
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- }
-
- abstract public void doIntercept(Invocation inv);
-}
+/**
+ * Copyright (c) 2011-2014, James Zhan 詹波 (jfinal@126.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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.jfinal.aop;
+
+import com.jfinal.core.ActionInvocation;
+
+/**
+ * PrototypeInterceptor.
+ */
+public abstract class PrototypeInterceptor implements Interceptor {
+
+ final public void intercept(ActionInvocation ai) {
+ try {
+ getClass().newInstance().doIntercept(ai);
+ } catch (RuntimeException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ abstract public void doIntercept(ActionInvocation ai);
+}
diff --git a/src/com/jfinal/config/Constants.java b/src/com/jfinal/config/Constants.java
new file mode 100644
index 000000000..2c63bf367
--- /dev/null
+++ b/src/com/jfinal/config/Constants.java
@@ -0,0 +1,329 @@
+/**
+ * Copyright (c) 2011-2014, James Zhan 詹波 (jfinal@126.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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.jfinal.config;
+
+import java.io.File;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+import com.jfinal.core.Const;
+import com.jfinal.kit.PathKit;
+import com.jfinal.kit.StrKit;
+import com.jfinal.log.ILoggerFactory;
+import com.jfinal.log.Logger;
+import com.jfinal.render.IErrorRenderFactory;
+import com.jfinal.render.IMainRenderFactory;
+import com.jfinal.render.RenderFactory;
+import com.jfinal.render.ViewType;
+import com.jfinal.token.ITokenCache;
+
+/**
+ * The constant for JFinal runtime.
+ */
+final public class Constants {
+
+ private String fileRenderPath;
+ private String uploadedFileSaveDirectory;
+
+ private boolean devMode = false;
+ private String encoding = Const.DEFAULT_ENCODING;
+ private String urlParaSeparator = Const.DEFAULT_URL_PARA_SEPARATOR;
+ private ViewType viewType = Const.DEFAULT_VIEW_TYPE;
+ private String jspViewExtension = Const.DEFAULT_JSP_EXTENSION;
+ private String freeMarkerViewExtension = Const.DEFAULT_FREE_MARKER_EXTENSION;
+ private String velocityViewExtension = Const.DEFAULT_VELOCITY_EXTENSION;
+ private Integer maxPostSize = Const.DEFAULT_MAX_POST_SIZE;
+ private int freeMarkerTemplateUpdateDelay = Const.DEFAULT_FREEMARKER_TEMPLATE_UPDATE_DELAY; // just for not devMode
+
+ private ITokenCache tokenCache;
+
+ /**
+ * Set ITokenCache implementation otherwise JFinal will use the HttpSesion to hold the token.
+ * @param tokenCache the token cache
+ */
+ public void setTokenCache(ITokenCache tokenCache) {
+ this.tokenCache = tokenCache;
+ }
+
+ public ITokenCache getTokenCache() {
+ return tokenCache;
+ }
+
+ /**
+ * Set development mode.
+ * @param devMode the development mode
+ */
+ public void setDevMode(boolean devMode) {
+ this.devMode = devMode;
+ }
+
+ /**
+ * Set encoding. The default encoding is UTF-8.
+ * @param encoding the encoding
+ */
+ public void setEncoding(String encoding) {
+ this.encoding = encoding;
+ }
+
+ public String getEncoding() {
+ return encoding;
+ }
+
+ public boolean getDevMode() {
+ return devMode;
+ }
+
+ public String getUrlParaSeparator() {
+ return urlParaSeparator;
+ }
+
+ public ViewType getViewType() {
+ return viewType;
+ }
+
+ /**
+ * Set view type. The default value is ViewType.FREE_MARKER
+ * Controller.render(String view) will use the view type to render the view.
+ * @param viewType the view type
+ */
+ public void setViewType(ViewType viewType) {
+ if (viewType == null)
+ throw new IllegalArgumentException("viewType can not be null");
+
+ if (viewType != ViewType.OTHER) // setMainRenderFactory will set ViewType.OTHER
+ this.viewType = viewType;
+ }
+
+ /**
+ * Set urlPara separator. The default value is "-"
+ * @param urlParaSeparator the urlPara separator
+ */
+ public void setUrlParaSeparator(String urlParaSeparator) {
+ if (StrKit.isBlank(urlParaSeparator) || urlParaSeparator.contains("/"))
+ throw new IllegalArgumentException("urlParaSepartor can not be blank and can not contains \"/\"");
+ this.urlParaSeparator = urlParaSeparator;
+ }
+
+ public String getJspViewExtension() {
+ return jspViewExtension;
+ }
+
+ /**
+ * Set Jsp view extension. The default value is ".jsp"
+ * @param jspViewExtension the Jsp view extension
+ */
+ public void setJspViewExtension(String jspViewExtension) {
+ this.jspViewExtension = jspViewExtension.startsWith(".") ? jspViewExtension : "." + jspViewExtension;
+ }
+
+ public String getFreeMarkerViewExtension() {
+ return freeMarkerViewExtension;
+ }
+
+ /**
+ * Set FreeMarker view extension. The default value is ".html" not ".ftl"
+ * @param freeMarkerViewExtension the FreeMarker view extension
+ */
+ public void setFreeMarkerViewExtension(String freeMarkerViewExtension) {
+ this.freeMarkerViewExtension = freeMarkerViewExtension.startsWith(".") ? freeMarkerViewExtension : "." + freeMarkerViewExtension;
+ }
+
+ public String getVelocityViewExtension() {
+ return velocityViewExtension;
+ }
+
+ /**
+ * Set Velocity view extension. The default value is ".vm"
+ * @param velocityViewExtension the Velocity view extension
+ */
+ public void setVelocityViewExtension(String velocityViewExtension) {
+ this.velocityViewExtension = velocityViewExtension.startsWith(".") ? velocityViewExtension : "." + velocityViewExtension;
+ }
+
+ /**
+ * Set error 404 view.
+ * @param error404View the error 404 view
+ */
+ public void setError404View(String error404View) {
+ errorViewMapping.put(404, error404View);
+ }
+
+ /**
+ * Set error 500 view.
+ * @param error500View the error 500 view
+ */
+ public void setError500View(String error500View) {
+ errorViewMapping.put(500, error500View);
+ }
+
+ /**
+ * Set error 401 view.
+ * @param error401View the error 401 view
+ */
+ public void setError401View(String error401View) {
+ errorViewMapping.put(401, error401View);
+ }
+
+ /**
+ * Set error 403 view.
+ * @param error403View the error 403 view
+ */
+ public void setError403View(String error403View) {
+ errorViewMapping.put(403, error403View);
+ }
+
+ private Map errorViewMapping = new HashMap();
+
+ public void setErrorView(int errorCode, String errorView) {
+ errorViewMapping.put(errorCode, errorView);
+ }
+
+ public String getErrorView(int errorCode) {
+ return errorViewMapping.get(errorCode);
+ }
+
+ public String getFileRenderPath() {
+ return fileRenderPath;
+ }
+
+ /**
+ * Set the path of file render of controller.
+ *
+ * The path is start with root path of this web application.
+ * The default value is "/download" if you do not config this parameter.
+ */
+ public void setFileRenderPath(String fileRenderPath) {
+ if (StrKit.isBlank(fileRenderPath))
+ throw new IllegalArgumentException("The argument fileRenderPath can not be blank");
+
+ if (!fileRenderPath.startsWith("/") && !fileRenderPath.startsWith(File.separator))
+ fileRenderPath = File.separator + fileRenderPath;
+ this.fileRenderPath = PathKit.getWebRootPath() + fileRenderPath;
+ }
+
+ /**
+ * Set the save directory for upload file. You can use PathUtil.getWebRootPath()
+ * to get the web root path of this application, then create a path based on
+ * web root path conveniently.
+ */
+ public void setUploadedFileSaveDirectory(String uploadedFileSaveDirectory) {
+ if (StrKit.isBlank(uploadedFileSaveDirectory))
+ throw new IllegalArgumentException("uploadedFileSaveDirectory can not be blank");
+
+ if (uploadedFileSaveDirectory.endsWith("/") || uploadedFileSaveDirectory.endsWith("\\"))
+ this.uploadedFileSaveDirectory = uploadedFileSaveDirectory;
+ else
+ this.uploadedFileSaveDirectory = uploadedFileSaveDirectory + File.separator;
+ }
+
+ public String getUploadedFileSaveDirectory() {
+ return uploadedFileSaveDirectory;
+ }
+
+ public Integer getMaxPostSize() {
+ return maxPostSize;
+ }
+
+ /**
+ * Set max size of http post. The upload file size depend on this value.
+ */
+ public void setMaxPostSize(Integer maxPostSize) {
+ if (maxPostSize != null && maxPostSize > 0) {
+ this.maxPostSize = maxPostSize;
+ }
+ }
+
+ // i18n -----
+ private String i18nResourceBaseName;
+
+ private Locale defaultLocale;
+
+ private Integer i18nMaxAgeOfCookie;
+
+ public void setI18n(String i18nResourceBaseName, Locale defaultLocale, Integer i18nMaxAgeOfCookie) {
+ this.i18nResourceBaseName = i18nResourceBaseName;
+ this.defaultLocale = defaultLocale;
+ this.i18nMaxAgeOfCookie = i18nMaxAgeOfCookie;
+ }
+
+ public void setI18n(String i18nResourceBaseName) {
+ this.i18nResourceBaseName = i18nResourceBaseName;
+ }
+
+ public String getI18nResourceBaseName() {
+ return i18nResourceBaseName;
+ }
+
+ public Locale getI18nDefaultLocale() {
+ return defaultLocale;
+ }
+
+ public Integer getI18nMaxAgeOfCookie() {
+ return this.i18nMaxAgeOfCookie;
+ }
+ // -----
+
+ /**
+ * FreeMarker template update delay for not devMode.
+ */
+ public void setFreeMarkerTemplateUpdateDelay(int delayInSeconds) {
+ if (delayInSeconds < 0)
+ throw new IllegalArgumentException("template_update_delay must more than -1.");
+ this.freeMarkerTemplateUpdateDelay = delayInSeconds;
+ }
+
+ public int getFreeMarkerTemplateUpdateDelay() {
+ return freeMarkerTemplateUpdateDelay;
+ }
+
+ /**
+ * Set the base path for all views
+ */
+ public void setBaseViewPath(String baseViewPath) {
+ Routes.setBaseViewPath(baseViewPath);
+ }
+
+ /**
+ * Set the mainRenderFactory then your can use your custom render in controller as render(String).
+ */
+ public void setMainRenderFactory(IMainRenderFactory mainRenderFactory) {
+ if (mainRenderFactory == null)
+ throw new IllegalArgumentException("mainRenderFactory can not be null.");
+
+ this.viewType = ViewType.OTHER;
+ RenderFactory.setMainRenderFactory(mainRenderFactory);
+ }
+
+ public void setLoggerFactory(ILoggerFactory loggerFactory) {
+ if (loggerFactory == null)
+ throw new IllegalArgumentException("loggerFactory can not be null.");
+ Logger.setLoggerFactory(loggerFactory);
+ }
+
+ public void setErrorRenderFactory(IErrorRenderFactory errorRenderFactory) {
+ if (errorRenderFactory == null)
+ throw new IllegalArgumentException("errorRenderFactory can not be null.");
+ RenderFactory.setErrorRenderFactory(errorRenderFactory);
+ }
+}
+
+
+
+
+
+
+
diff --git a/src/main/java/com/jfinal/config/Handlers.java b/src/com/jfinal/config/Handlers.java
similarity index 66%
rename from src/main/java/com/jfinal/config/Handlers.java
rename to src/com/jfinal/config/Handlers.java
index ef37e2881..d3d9e87bf 100644
--- a/src/main/java/com/jfinal/config/Handlers.java
+++ b/src/com/jfinal/config/Handlers.java
@@ -1,52 +1,39 @@
-/**
- * Copyright (c) 2011-2023, James Zhan 詹波 (jfinal@126.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
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.jfinal.config;
-
-import java.util.ArrayList;
-import java.util.List;
-import com.jfinal.core.ActionHandler;
-import com.jfinal.handler.Handler;
-
-/**
- * Handlers.
- */
-final public class Handlers {
-
- private ActionHandler actionHandler = null;
- private final List handlerList = new ArrayList();
-
- public Handlers add(Handler handler) {
- if (handler == null) {
- throw new IllegalArgumentException("handler can not be null");
- }
- handlerList.add(handler);
- return this;
- }
-
- public Handlers setActionHandler(ActionHandler actionHandler) {
- this.actionHandler = actionHandler;
- return this;
- }
-
- public List getHandlerList() {
- return handlerList;
- }
-
- public ActionHandler getActionHandler() {
- return actionHandler;
- }
-}
+/**
+ * Copyright (c) 2011-2014, James Zhan 詹波 (jfinal@126.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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.jfinal.config;
+
+import java.util.ArrayList;
+import java.util.List;
+import com.jfinal.handler.Handler;
+
+/**
+ * Handlers.
+ */
+final public class Handlers {
+
+ private final List handlerList = new ArrayList();
+
+ public Handlers add(Handler handler) {
+ if (handler != null)
+ handlerList.add(handler);
+ return this;
+ }
+
+ public List getHandlerList() {
+ return handlerList;
+ }
+}
diff --git a/src/com/jfinal/config/Interceptors.java b/src/com/jfinal/config/Interceptors.java
new file mode 100644
index 000000000..9661949f2
--- /dev/null
+++ b/src/com/jfinal/config/Interceptors.java
@@ -0,0 +1,40 @@
+/**
+ * Copyright (c) 2011-2014, James Zhan 詹波 (jfinal@126.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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.jfinal.config;
+
+import java.util.ArrayList;
+import java.util.List;
+import com.jfinal.aop.Interceptor;
+
+/**
+ * The interceptors applied to all actions.
+ */
+final public class Interceptors {
+
+ private final List interceptorList = new ArrayList();
+
+ public Interceptors add(Interceptor globalInterceptor) {
+ if (globalInterceptor != null)
+ this.interceptorList.add(globalInterceptor);
+ return this;
+ }
+
+ public Interceptor[] getInterceptorArray() {
+ Interceptor[] result = interceptorList.toArray(new Interceptor[interceptorList.size()]);
+ return result == null ? new Interceptor[0] : result;
+ }
+}
diff --git a/src/com/jfinal/config/JFinalConfig.java b/src/com/jfinal/config/JFinalConfig.java
new file mode 100644
index 000000000..9502ae2dc
--- /dev/null
+++ b/src/com/jfinal/config/JFinalConfig.java
@@ -0,0 +1,163 @@
+/**
+ * Copyright (c) 2011-2014, James Zhan 詹波 (jfinal@126.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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.jfinal.config;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Properties;
+import com.jfinal.kit.PathKit;
+import com.jfinal.kit.StrKit;
+
+/**
+ * JFinalConfig.
+ *
+ * Config order: configConstant(), configRoute(), configPlugin(), configInterceptor(), configHandler()
+ */
+public abstract class JFinalConfig {
+
+ /**
+ * Config constant
+ */
+ public abstract void configConstant(Constants me);
+
+ /**
+ * Config route
+ */
+ public abstract void configRoute(Routes me);
+
+ /**
+ * Config plugin
+ */
+ public abstract void configPlugin(Plugins me);
+
+ /**
+ * Config interceptor applied to all actions.
+ */
+ public abstract void configInterceptor(Interceptors me);
+
+ /**
+ * Config handler
+ */
+ public abstract void configHandler(Handlers me);
+
+ /**
+ * Call back after JFinal start
+ */
+ public void afterJFinalStart(){};
+
+ /**
+ * Call back before JFinal stop
+ */
+ public void beforeJFinalStop(){};
+
+ private Properties properties;
+
+ /**
+ * Load property file
+ * Example: loadPropertyFile("db_username_pass.txt");
+ * @param file the file in WEB-INF directory
+ */
+ public Properties loadPropertyFile(String file) {
+ if (StrKit.isBlank(file))
+ throw new IllegalArgumentException("Parameter of file can not be blank");
+ if (file.contains(".."))
+ throw new IllegalArgumentException("Parameter of file can not contains \"..\"");
+
+ InputStream inputStream = null;
+ String fullFile; // String fullFile = PathUtil.getWebRootPath() + file;
+ if (file.startsWith(File.separator))
+ fullFile = PathKit.getWebRootPath() + File.separator + "WEB-INF" + file;
+ else
+ fullFile = PathKit.getWebRootPath() + File.separator + "WEB-INF" + File.separator + file;
+
+ try {
+ inputStream = new FileInputStream(new File(fullFile));
+ Properties p = new Properties();
+ p.load(inputStream);
+ properties = p;
+ } catch (FileNotFoundException e) {
+ throw new IllegalArgumentException("Properties file not found: " + fullFile);
+ } catch (IOException e) {
+ throw new IllegalArgumentException("Properties file can not be loading: " + fullFile);
+ }
+ finally {
+ try {if (inputStream != null) inputStream.close();} catch (IOException e) {e.printStackTrace();}
+ }
+ if (properties == null)
+ throw new RuntimeException("Properties file loading failed: " + fullFile);
+ return properties;
+ }
+
+ public String getProperty(String key) {
+ checkPropertyLoading();
+ return properties.getProperty(key);
+ }
+
+ public String getProperty(String key, String defaultValue) {
+ checkPropertyLoading();
+ return properties.getProperty(key, defaultValue);
+ }
+
+ public Integer getPropertyToInt(String key) {
+ checkPropertyLoading();
+ Integer resultInt = null;
+ String resultStr = properties.getProperty(key);
+ if (resultStr != null)
+ resultInt = Integer.parseInt(resultStr);
+ return resultInt;
+ }
+
+ public Integer getPropertyToInt(String key, Integer defaultValue) {
+ Integer result = getPropertyToInt(key);
+ return result != null ? result : defaultValue;
+ }
+
+ public Boolean getPropertyToBoolean(String key) {
+ checkPropertyLoading();
+ String resultStr = properties.getProperty(key);
+ Boolean resultBool = null;
+ if (resultStr != null) {
+ if (resultStr.trim().equalsIgnoreCase("true"))
+ resultBool = true;
+ else if (resultStr.trim().equalsIgnoreCase("false"))
+ resultBool = false;
+ }
+ return resultBool;
+ }
+
+ public Boolean getPropertyToBoolean(String key, boolean defaultValue) {
+ Boolean result = getPropertyToBoolean(key);
+ return result != null ? result : defaultValue;
+ }
+
+ private void checkPropertyLoading() {
+ if (properties == null)
+ throw new RuntimeException("You must load properties file by invoking loadPropertyFile(String) method in configConstant(Constants) method before.");
+ }
+}
+
+
+
+
+
+
+
+
+
diff --git a/src/main/java/com/jfinal/config/Plugins.java b/src/com/jfinal/config/Plugins.java
similarity index 83%
rename from src/main/java/com/jfinal/config/Plugins.java
rename to src/com/jfinal/config/Plugins.java
index a5daadd4b..a0001f3b1 100644
--- a/src/main/java/com/jfinal/config/Plugins.java
+++ b/src/com/jfinal/config/Plugins.java
@@ -1,41 +1,39 @@
-/**
- * Copyright (c) 2011-2023, James Zhan 詹波 (jfinal@126.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
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.jfinal.config;
-
-import java.util.ArrayList;
-import java.util.List;
-import com.jfinal.plugin.IPlugin;
-
-/**
- * Plugins.
- */
-final public class Plugins {
-
- private final List pluginList = new ArrayList();
-
- public Plugins add(IPlugin plugin) {
- if (plugin == null) {
- throw new IllegalArgumentException("plugin can not be null");
- }
- pluginList.add(plugin);
- return this;
- }
-
- public List getPluginList() {
- return pluginList;
- }
-}
+/**
+ * Copyright (c) 2011-2014, James Zhan 詹波 (jfinal@126.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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.jfinal.config;
+
+import java.util.ArrayList;
+import java.util.List;
+import com.jfinal.plugin.IPlugin;
+
+/**
+ * Plugins.
+ */
+final public class Plugins {
+
+ private final List pluginList = new ArrayList();
+
+ public Plugins add(IPlugin plugin) {
+ if (plugin != null)
+ this.pluginList.add(plugin);
+ return this;
+ }
+
+ public List getPluginList() {
+ return pluginList;
+ }
+}
diff --git a/src/com/jfinal/config/Routes.java b/src/com/jfinal/config/Routes.java
new file mode 100644
index 000000000..710e29e14
--- /dev/null
+++ b/src/com/jfinal/config/Routes.java
@@ -0,0 +1,130 @@
+/**
+ * Copyright (c) 2011-2014, James Zhan 詹波 (jfinal@126.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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.jfinal.config;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import com.jfinal.core.Controller;
+
+/**
+ * Routes.
+ */
+public abstract class Routes {
+
+ private final Map> map = new HashMap>();
+ private final Map viewPathMap = new HashMap();
+
+ /**
+ * you must implement config method and use add method to config route
+ */
+ public abstract void config();
+
+ public Routes add(Routes routes) {
+ if (routes != null) {
+ routes.config(); // very important!!!
+ map.putAll(routes.map);
+ viewPathMap.putAll(routes.viewPathMap);
+ }
+ return this;
+ }
+
+ /**
+ * Add route
+ * @param controllerKey A key can find controller
+ * @param controllerClass Controller Class
+ * @param viewPath View path for this Controller
+ */
+ public Routes add(String controllerKey, Class extends Controller> controllerClass, String viewPath) {
+ if (controllerKey == null)
+ throw new IllegalArgumentException("The controllerKey can not be null");
+ // if (controllerKey.indexOf(".") != -1)
+ // throw new IllegalArgumentException("The controllerKey can not contain dot character: \".\"");
+ controllerKey = controllerKey.trim();
+ if ("".equals(controllerKey))
+ throw new IllegalArgumentException("The controllerKey can not be blank");
+ if (controllerClass == null)
+ throw new IllegalArgumentException("The controllerClass can not be null");
+ if (!controllerKey.startsWith("/"))
+ controllerKey = "/" + controllerKey;
+ if (map.containsKey(controllerKey))
+ throw new IllegalArgumentException("The controllerKey already exists: " + controllerKey);
+
+ map.put(controllerKey, controllerClass);
+
+ if (viewPath == null || "".equals(viewPath.trim())) // view path is controllerKey by default
+ viewPath = controllerKey;
+
+ viewPath = viewPath.trim();
+ if (!viewPath.startsWith("/")) // "/" added to prefix
+ viewPath = "/" + viewPath;
+
+ if (!viewPath.endsWith("/")) // "/" added to postfix
+ viewPath = viewPath + "/";
+
+ if (baseViewPath != null) // support baseViewPath
+ viewPath = baseViewPath + viewPath;
+
+ viewPathMap.put(controllerKey, viewPath);
+ return this;
+ }
+
+ /**
+ * Add url mapping to controller. The view path is controllerKey
+ * @param controllerkey A key can find controller
+ * @param controllerClass Controller Class
+ */
+ public Routes add(String controllerkey, Class extends Controller> controllerClass) {
+ return add(controllerkey, controllerClass, controllerkey);
+ }
+
+ public Set>> getEntrySet() {
+ return map.entrySet();
+ }
+
+ public String getViewPath(String key) {
+ return viewPathMap.get(key);
+ }
+
+ private static String baseViewPath;
+
+ /**
+ * Set the base path for all views
+ */
+ static void setBaseViewPath(String baseViewPath) {
+ if (baseViewPath == null)
+ throw new IllegalArgumentException("The baseViewPath can not be null");
+ baseViewPath = baseViewPath.trim();
+ if ("".equals(baseViewPath))
+ throw new IllegalArgumentException("The baseViewPath can not be blank");
+
+ if (! baseViewPath.startsWith("/")) // add prefix "/"
+ baseViewPath = "/" + baseViewPath;
+
+ if (baseViewPath.endsWith("/")) // remove "/" in the end of baseViewPath
+ baseViewPath = baseViewPath.substring(0, baseViewPath.length() - 1);
+
+ Routes.baseViewPath = baseViewPath;
+ }
+}
+
+
+
+
+
+
diff --git a/src/main/java/com/jfinal/core/Action.java b/src/com/jfinal/core/Action.java
similarity index 62%
rename from src/main/java/com/jfinal/core/Action.java
rename to src/com/jfinal/core/Action.java
index 9b249c497..730c58b2d 100644
--- a/src/main/java/com/jfinal/core/Action.java
+++ b/src/com/jfinal/core/Action.java
@@ -1,106 +1,81 @@
-/**
- * Copyright (c) 2011-2023, James Zhan 詹波 (jfinal@126.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
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.jfinal.core;
-
-import java.lang.reflect.Method;
-import com.jfinal.aop.Interceptor;
-import com.jfinal.core.paragetter.ParaProcessor;
-import com.jfinal.core.paragetter.ParaProcessorBuilder;
-
-/**
- * Action
- */
-public class Action {
-
- private final Class extends Controller> controllerClass;
- private final String controllerPath;
- private final String actionKey;
- private final Method method;
- private final String methodName;
- private final Interceptor[] interceptors;
- private final String viewPath;
-
- private final ParaProcessor parameterGetter;
-
- public Action(String controllerPath, String actionKey, Class extends Controller> controllerClass, Method method, String methodName, Interceptor[] interceptors, String viewPath) {
- this.controllerPath = controllerPath;
- this.actionKey = actionKey;
- this.controllerClass = controllerClass;
- this.method = method;
- this.methodName = methodName;
- this.interceptors = interceptors;
- this.viewPath = viewPath;
-
- this.parameterGetter = ParaProcessorBuilder.me.build(controllerClass, method);
-
- // 支持高版本 JDK 的安全策略
- method.setAccessible(true);
- }
-
- public Class extends Controller> getControllerClass() {
- return controllerClass;
- }
-
- public String getControllerPath() {
- return controllerPath;
- }
-
- /**
- * 该方法已改名为 getControllerPath()
- */
- @Deprecated
- public String getControllerKey() {
- return controllerPath;
- }
-
- public String getActionKey() {
- return actionKey;
- }
-
- public Method getMethod() {
- return method;
- }
-
- public Interceptor[] getInterceptors() {
- return interceptors;
- }
-
- public String getViewPath() {
- return viewPath;
- }
-
- public String getMethodName() {
- return methodName;
- }
-
- public ParaProcessor getParameterGetter() {
- return parameterGetter;
- }
-
- public String toString() {
- return actionKey;
- }
-}
-
-
-
-
-
-
-
-
-
+/**
+ * Copyright (c) 2011-2014, James Zhan 詹波 (jfinal@126.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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.jfinal.core;
+
+import java.lang.reflect.Method;
+import com.jfinal.aop.Interceptor;
+
+/**
+ * Action
+ */
+class Action {
+
+ private final Class extends Controller> controllerClass;
+ private final String controllerKey;
+ private final String actionKey;
+ private final Method method;
+ private final String methodName;
+ private final Interceptor[] interceptors;
+ private final String viewPath;
+
+ public Action(String controllerKey, String actionKey, Class extends Controller> controllerClass, Method method, String methodName, Interceptor[] interceptors, String viewPath) {
+ this.controllerKey = controllerKey;
+ this.actionKey = actionKey;
+ this.controllerClass = controllerClass;
+ this.method = method;
+ this.methodName = methodName;
+ this.interceptors = interceptors;
+ this.viewPath = viewPath;
+ }
+
+ public Class extends Controller> getControllerClass() {
+ return controllerClass;
+ }
+
+ public String getControllerKey() {
+ return controllerKey;
+ }
+
+ public String getActionKey() {
+ return actionKey;
+ }
+
+ public Method getMethod() {
+ return method;
+ }
+
+ public Interceptor[] getInterceptors() {
+ return interceptors;
+ }
+
+ public String getViewPath() {
+ return viewPath;
+ }
+
+ public String getMethodName() {
+ return methodName;
+ }
+}
+
+
+
+
+
+
+
+
+
diff --git a/src/com/jfinal/core/ActionException.java b/src/com/jfinal/core/ActionException.java
new file mode 100644
index 000000000..fcc092f61
--- /dev/null
+++ b/src/com/jfinal/core/ActionException.java
@@ -0,0 +1,57 @@
+/**
+ * Copyright (c) 2011-2014, James Zhan 詹波 (jfinal@126.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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.jfinal.core;
+
+import com.jfinal.kit.StrKit;
+import com.jfinal.render.Render;
+import com.jfinal.render.RenderFactory;
+
+/**
+ * ActionException.
+ */
+public class ActionException extends RuntimeException {
+
+ private static final long serialVersionUID = 1998063243843477017L;
+ private int errorCode;
+ private Render errorRender;
+
+ public ActionException(int errorCode, Render errorRender) {
+ if (errorRender == null)
+ throw new IllegalArgumentException("The parameter errorRender can not be null.");
+
+ this.errorCode = errorCode;
+ this.errorRender = errorRender;
+ }
+
+ public ActionException(int errorCode, String errorView) {
+ if (StrKit.isBlank(errorView))
+ throw new IllegalArgumentException("The parameter errorView can not be blank.");
+
+ this.errorCode = errorCode;
+ this.errorRender = RenderFactory.me().getErrorRender(errorCode, errorView);
+ }
+
+ public int getErrorCode() {
+ return errorCode;
+ }
+
+ public Render getErrorRender() {
+ return errorRender;
+ }
+}
+
+
diff --git a/src/com/jfinal/core/ActionHandler.java b/src/com/jfinal/core/ActionHandler.java
new file mode 100644
index 000000000..b9fd1a401
--- /dev/null
+++ b/src/com/jfinal/core/ActionHandler.java
@@ -0,0 +1,133 @@
+/**
+ * Copyright (c) 2011-2014, James Zhan 詹波 (jfinal@126.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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.jfinal.core;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import com.jfinal.config.Constants;
+import com.jfinal.handler.Handler;
+import com.jfinal.log.Logger;
+import com.jfinal.render.Render;
+import com.jfinal.render.RenderException;
+import com.jfinal.render.RenderFactory;
+
+/**
+ * ActionHandler
+ */
+final class ActionHandler extends Handler {
+
+ private final boolean devMode;
+ private final ActionMapping actionMapping;
+ private static final RenderFactory renderFactory = RenderFactory.me();
+ private static final Logger log = Logger.getLogger(ActionHandler.class);
+
+ public ActionHandler(ActionMapping actionMapping, Constants constants) {
+ this.actionMapping = actionMapping;
+ this.devMode = constants.getDevMode();
+ }
+
+ /**
+ * handle
+ * 1: Action action = actionMapping.getAction(target)
+ * 2: new ActionInvocation(...).invoke()
+ * 3: render(...)
+ */
+ public final void handle(String target, HttpServletRequest request, HttpServletResponse response, boolean[] isHandled) {
+ if (target.indexOf(".") != -1) {
+ return ;
+ }
+
+ isHandled[0] = true;
+ String[] urlPara = {null};
+ Action action = actionMapping.getAction(target, urlPara);
+
+ if (action == null) {
+ if (log.isWarnEnabled()) {
+ String qs = request.getQueryString();
+ log.warn("404 Action Not Found: " + (qs == null ? target : target + "?" + qs));
+ }
+ renderFactory.getErrorRender(404).setContext(request, response).render();
+ return ;
+ }
+
+ try {
+ Controller controller = action.getControllerClass().newInstance();
+ controller.init(request, response, urlPara[0]);
+
+ if (devMode) {
+ boolean isMultipartRequest = ActionReporter.reportCommonRequest(controller, action);
+ new ActionInvocation(action, controller).invoke();
+ if (isMultipartRequest) ActionReporter.reportMultipartRequest(controller, action);
+ }
+ else {
+ new ActionInvocation(action, controller).invoke();
+ }
+
+ Render render = controller.getRender();
+ if (render instanceof ActionRender) {
+ String actionUrl = ((ActionRender)render).getActionUrl();
+ if (target.equals(actionUrl))
+ throw new RuntimeException("The forward action url is the same as before.");
+ else
+ handle(actionUrl, request, response, isHandled);
+ return ;
+ }
+
+ if (render == null)
+ render = renderFactory.getDefaultRender(action.getViewPath() + action.getMethodName());
+ render.setContext(request, response, action.getViewPath()).render();
+ }
+ catch (RenderException e) {
+ if (log.isErrorEnabled()) {
+ String qs = request.getQueryString();
+ log.error(qs == null ? target : target + "?" + qs, e);
+ }
+ }
+ catch (ActionException e) {
+ int errorCode = e.getErrorCode();
+ if (errorCode == 404 && log.isWarnEnabled()) {
+ String qs = request.getQueryString();
+ log.warn("404 Not Found: " + (qs == null ? target : target + "?" + qs));
+ }
+ else if (errorCode == 401 && log.isWarnEnabled()) {
+ String qs = request.getQueryString();
+ log.warn("401 Unauthorized: " + (qs == null ? target : target + "?" + qs));
+ }
+ else if (errorCode == 403 && log.isWarnEnabled()) {
+ String qs = request.getQueryString();
+ log.warn("403 Forbidden: " + (qs == null ? target : target + "?" + qs));
+ }
+ else if (log.isErrorEnabled()) {
+ String qs = request.getQueryString();
+ log.error(qs == null ? target : target + "?" + qs, e);
+ }
+ e.getErrorRender().setContext(request, response).render();
+ }
+ catch (Exception e) {
+ if (log.isErrorEnabled()) {
+ String qs = request.getQueryString();
+ log.error(qs == null ? target : target + "?" + qs, e);
+ }
+ renderFactory.getErrorRender(500).setContext(request, response).render();
+ }
+ }
+}
+
+
+
+
+
diff --git a/src/com/jfinal/core/ActionInvocation.java b/src/com/jfinal/core/ActionInvocation.java
new file mode 100644
index 000000000..9f22af2c1
--- /dev/null
+++ b/src/com/jfinal/core/ActionInvocation.java
@@ -0,0 +1,121 @@
+/**
+ * Copyright (c) 2011-2014, James Zhan 詹波 (jfinal@126.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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.jfinal.core;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import com.jfinal.aop.Interceptor;
+
+/**
+ * ActionInvocation invoke the action
+ */
+public class ActionInvocation {
+
+ private Controller controller;
+ private Interceptor[] inters;
+ private Action action;
+ private int index = 0;
+
+ private static final Object[] NULL_ARGS = new Object[0]; // Prevent new Object[0] by jvm for paras of action invocation.
+
+ // ActionInvocationWrapper need this constructor
+ protected ActionInvocation() {
+
+ }
+
+ ActionInvocation(Action action, Controller controller) {
+ this.controller = controller;
+ this.inters = action.getInterceptors();
+ this.action = action;
+ }
+
+ /**
+ * Invoke the action.
+ */
+ public void invoke() {
+ if (index < inters.length)
+ inters[index++].intercept(this);
+ else if (index++ == inters.length) // index++ ensure invoke action only one time
+ // try {action.getMethod().invoke(controller, NULL_ARGS);} catch (Exception e) {throw new RuntimeException(e);}
+ try {
+ action.getMethod().invoke(controller, NULL_ARGS);
+ }
+ catch (InvocationTargetException e) {
+ Throwable cause = e.getTargetException();
+ if (cause instanceof RuntimeException)
+ throw (RuntimeException)cause;
+ throw new RuntimeException(e);
+ }
+ catch (RuntimeException e) {
+ throw e;
+ }
+ catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Return the controller of this action.
+ */
+ public Controller getController() {
+ return controller;
+ }
+
+ /**
+ * Return the action key.
+ * actionKey = controllerKey + methodName
+ */
+ public String getActionKey() {
+ return action.getActionKey();
+ }
+
+ /**
+ * Return the controller key.
+ */
+ public String getControllerKey() {
+ return action.getControllerKey();
+ }
+
+ /**
+ * Return the method of this action.
+ *
+ * You can getMethod.getAnnotations() to get annotation on action method to do more things
+ */
+ public Method getMethod() {
+ return action.getMethod();
+ /*
+ try {
+ return controller.getClass().getMethod(action.getMethod().getName());
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }*/
+ }
+
+ /**
+ * Return the method name of this action's method.
+ */
+ public String getMethodName() {
+ return action.getMethodName();
+ }
+
+ /**
+ * Return view path of this controller.
+ */
+ public String getViewPath() {
+ return action.getViewPath();
+ }
+}
diff --git a/src/main/java/com/jfinal/core/ActionKey.java b/src/com/jfinal/core/ActionKey.java
similarity index 91%
rename from src/main/java/com/jfinal/core/ActionKey.java
rename to src/com/jfinal/core/ActionKey.java
index 2115cd555..961b3e70c 100644
--- a/src/main/java/com/jfinal/core/ActionKey.java
+++ b/src/com/jfinal/core/ActionKey.java
@@ -1,34 +1,34 @@
-/**
- * Copyright (c) 2011-2023, James Zhan 詹波 (jfinal@126.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
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.jfinal.core;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Inherited;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-/**
- * ActionKey is used to configure actionKey for method of controller.
- */
-@Inherited
-@Retention(RetentionPolicy.RUNTIME)
-@Target(ElementType.METHOD)
-public @interface ActionKey {
- String value();
-}
-
+/**
+ * Copyright (c) 2011-2014, James Zhan 詹波 (jfinal@126.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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.jfinal.core;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * ActionKey is used to configure actionKey for method of controller.
+ */
+@Inherited
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.METHOD)
+public @interface ActionKey {
+ String value();
+}
+
diff --git a/src/com/jfinal/core/ActionMapping.java b/src/com/jfinal/core/ActionMapping.java
new file mode 100644
index 000000000..d1759133a
--- /dev/null
+++ b/src/com/jfinal/core/ActionMapping.java
@@ -0,0 +1,166 @@
+/**
+ * Copyright (c) 2011-2014, James Zhan 詹波 (jfinal@126.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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.jfinal.core;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import com.jfinal.aop.Interceptor;
+import com.jfinal.config.Interceptors;
+import com.jfinal.config.Routes;
+
+/**
+ * ActionMapping
+ */
+final class ActionMapping {
+
+ private static final String SLASH = "/";
+ private Routes routes;
+ private Interceptors interceptors;
+
+ private final Map mapping = new HashMap();
+
+ ActionMapping(Routes routes, Interceptors interceptors) {
+ this.routes = routes;
+ this.interceptors = interceptors;
+ }
+
+ private Set buildExcludedMethodName() {
+ Set excludedMethodName = new HashSet();
+ Method[] methods = Controller.class.getMethods();
+ for (Method m : methods) {
+ if (m.getParameterTypes().length == 0)
+ excludedMethodName.add(m.getName());
+ }
+ return excludedMethodName;
+ }
+
+ void buildActionMapping() {
+ mapping.clear();
+ Set excludedMethodName = buildExcludedMethodName();
+ InterceptorBuilder interceptorBuilder = new InterceptorBuilder();
+ Interceptor[] defaultInters = interceptors.getInterceptorArray();
+ interceptorBuilder.addToInterceptorsMap(defaultInters);
+ for (Entry> entry : routes.getEntrySet()) {
+ Class extends Controller> controllerClass = entry.getValue();
+ Interceptor[] controllerInters = interceptorBuilder.buildControllerInterceptors(controllerClass);
+ Method[] methods = controllerClass.getMethods();
+ for (Method method : methods) {
+ String methodName = method.getName();
+ if (!excludedMethodName.contains(methodName) && method.getParameterTypes().length == 0) {
+ Interceptor[] methodInters = interceptorBuilder.buildMethodInterceptors(method);
+ Interceptor[] actionInters = interceptorBuilder.buildActionInterceptors(defaultInters, controllerInters, controllerClass, methodInters, method);
+ String controllerKey = entry.getKey();
+
+ ActionKey ak = method.getAnnotation(ActionKey.class);
+ if (ak != null) {
+ String 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;
+
+ if (mapping.containsKey(actionKey)) {
+ warnning(actionKey, controllerClass, method);
+ continue;
+ }
+
+ Action action = new Action(controllerKey, actionKey, controllerClass, method, methodName, actionInters, routes.getViewPath(controllerKey));
+ mapping.put(actionKey, action);
+ }
+ else if (methodName.equals("index")) {
+ String actionKey = controllerKey;
+
+ Action action = new Action(controllerKey, actionKey, controllerClass, method, methodName, actionInters, routes.getViewPath(controllerKey));
+ action = mapping.put(actionKey, action);
+
+ if (action != null) {
+ warnning(action.getActionKey(), action.getControllerClass(), action.getMethod());
+ }
+ }
+ else {
+ String actionKey = controllerKey.equals(SLASH) ? SLASH + methodName : controllerKey + SLASH + methodName;
+
+ if (mapping.containsKey(actionKey)) {
+ warnning(actionKey, controllerClass, method);
+ continue;
+ }
+
+ Action action = new Action(controllerKey, actionKey, controllerClass, method, methodName, actionInters, routes.getViewPath(controllerKey));
+ mapping.put(actionKey, action);
+ }
+ }
+ }
+ }
+
+ // support url = controllerKey + urlParas with "/" of controllerKey
+ Action actoin = mapping.get("/");
+ if (actoin != null)
+ mapping.put("", actoin);
+ }
+
+ private static final void warnning(String actionKey, Class extends Controller> controllerClass, Method method) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("--------------------------------------------------------------------------------\nWarnning!!!\n")
+ .append("ActionKey already used: \"").append(actionKey).append("\" \n")
+ .append("Action can not be mapped: \"")
+ .append(controllerClass.getName()).append(".").append(method.getName()).append("()\" \n")
+ .append("--------------------------------------------------------------------------------");
+ System.out.println(sb.toString());
+ }
+
+ /**
+ * Support four types of url
+ * 1: http://abc.com/controllerKey ---> 00
+ * 2: http://abc.com/controllerKey/para ---> 01
+ * 3: http://abc.com/controllerKey/method ---> 10
+ * 4: http://abc.com/controllerKey/method/para ---> 11
+ */
+ Action getAction(String url, String[] urlPara) {
+ Action action = mapping.get(url);
+ if (action != null) {
+ return action;
+ }
+
+ // --------
+ int i = url.lastIndexOf(SLASH);
+ if (i != -1) {
+ action = mapping.get(url.substring(0, i));
+ urlPara[0] = url.substring(i + 1);
+ }
+
+ return action;
+ }
+
+ List getAllActionKeys() {
+ List allActionKeys = new ArrayList(mapping.keySet());
+ Collections.sort(allActionKeys);
+ return allActionKeys;
+ }
+}
+
+
+
+
+
diff --git a/src/main/java/com/jfinal/core/ForwardActionRender.java b/src/com/jfinal/core/ActionRender.java
similarity index 74%
rename from src/main/java/com/jfinal/core/ForwardActionRender.java
rename to src/com/jfinal/core/ActionRender.java
index fbca96350..3e2bb5ed0 100644
--- a/src/main/java/com/jfinal/core/ForwardActionRender.java
+++ b/src/com/jfinal/core/ActionRender.java
@@ -1,39 +1,40 @@
-/**
- * Copyright (c) 2011-2023, James Zhan 詹波 (jfinal@126.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
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.jfinal.core;
-
-import com.jfinal.render.Render;
-
-/**
- * ForwardActionRender
- */
-public class ForwardActionRender extends Render {
-
- private String actionUrl;
-
- public ForwardActionRender(String actionUrl) {
- this.actionUrl = actionUrl.trim();
- }
-
- public String getActionUrl() {
- return actionUrl;
- }
-
- public void render() {
-
- }
-}
+/**
+ * Copyright (c) 2011-2014, James Zhan 詹波 (jfinal@126.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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.jfinal.core;
+
+import com.jfinal.render.Render;
+
+/**
+ * ActionRender
+ */
+final class ActionRender extends Render {
+
+ private static final long serialVersionUID = 3712913909977013446L;
+ private String actionUrl;
+
+ public ActionRender(String actionUrl) {
+ this.actionUrl = actionUrl.trim();
+ }
+
+ public String getActionUrl() {
+ return actionUrl;
+ }
+
+ public void render() {
+
+ }
+}
diff --git a/src/com/jfinal/core/ActionReporter.java b/src/com/jfinal/core/ActionReporter.java
new file mode 100644
index 000000000..187e245d3
--- /dev/null
+++ b/src/com/jfinal/core/ActionReporter.java
@@ -0,0 +1,102 @@
+/**
+ * Copyright (c) 2011-2014, James Zhan 詹波 (jfinal@126.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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.jfinal.core;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Enumeration;
+import javax.servlet.http.HttpServletRequest;
+import com.jfinal.aop.Interceptor;
+
+/**
+ * ActionReporter
+ */
+final class ActionReporter {
+
+ private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+
+ /**
+ * Report action before action invoking when the common request coming
+ */
+ static final boolean reportCommonRequest(Controller controller, Action action) {
+ String content_type = controller.getRequest().getContentType();
+ if (content_type == null || content_type.toLowerCase().indexOf("multipart") == -1) { // if (content_type == null || content_type.indexOf("multipart/form-data") == -1) {
+ doReport(controller, action);
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Report action after action invoking when the multipart request coming
+ */
+ static final void reportMultipartRequest(Controller controller, Action action) {
+ doReport(controller, action);
+ }
+
+ private static final void doReport(Controller controller, Action action) {
+ StringBuilder sb = new StringBuilder("\nJFinal action report -------- ").append(sdf.format(new Date())).append(" ------------------------------\n");
+ Class extends Controller> cc = action.getControllerClass();
+ sb.append("Controller : ").append(cc.getName()).append(".(").append(cc.getSimpleName()).append(".java:1)");
+ sb.append("\nMethod : ").append(action.getMethodName()).append("\n");
+
+ String urlParas = controller.getPara();
+ if (urlParas != null) {
+ sb.append("UrlPara : ").append(urlParas).append("\n");
+ }
+
+ Interceptor[] inters = action.getInterceptors();
+ if (inters.length > 0) {
+ sb.append("Interceptor : ");
+ for (int i=0; i 0)
+ sb.append("\n ");
+ Interceptor inter = inters[i];
+ Class extends Interceptor> ic = inter.getClass();
+ sb.append(ic.getName()).append(".(").append(ic.getSimpleName()).append(".java:1)");
+ }
+ sb.append("\n");
+ }
+
+ // print all parameters
+ HttpServletRequest request = controller.getRequest();
+ Enumeration e = request.getParameterNames();
+ if (e.hasMoreElements()) {
+ sb.append("Parameter : ");
+ while (e.hasMoreElements()) {
+ String name = e.nextElement();
+ String[] values = request.getParameterValues(name);
+ if (values.length == 1) {
+ sb.append(name).append("=").append(values[0]);
+ }
+ else {
+ sb.append(name).append("[]={");
+ for (int i=0; i 0)
+ sb.append(",");
+ sb.append(values[i]);
+ }
+ sb.append("}");
+ }
+ sb.append(" ");
+ }
+ sb.append("\n");
+ }
+ sb.append("--------------------------------------------------------------------------------\n");
+ System.out.print(sb.toString());
+ }
+}
diff --git a/src/com/jfinal/core/Config.java b/src/com/jfinal/core/Config.java
new file mode 100644
index 000000000..2f01189a2
--- /dev/null
+++ b/src/com/jfinal/core/Config.java
@@ -0,0 +1,106 @@
+/**
+ * Copyright (c) 2011-2014, James Zhan 詹波 (jfinal@126.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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.jfinal.core;
+
+import java.util.List;
+import com.jfinal.config.Constants;
+import com.jfinal.config.JFinalConfig;
+import com.jfinal.config.Routes;
+import com.jfinal.config.Plugins;
+import com.jfinal.config.Handlers;
+import com.jfinal.config.Interceptors;
+import com.jfinal.log.Logger;
+import com.jfinal.plugin.IPlugin;
+
+class Config {
+
+ private static final Constants constants = new Constants();
+ private static final Routes routes = new Routes(){public void config() {}};
+ private static final Plugins plugins = new Plugins();
+ private static final Interceptors interceptors = new Interceptors();
+ private static final Handlers handlers = new Handlers();
+ private static Logger log;
+
+ // prevent new Config();
+ private Config() {
+ }
+
+ /*
+ * Config order: constant, route, plugin, interceptor, handler
+ */
+ static void configJFinal(JFinalConfig jfinalConfig) {
+ jfinalConfig.configConstant(constants); initLoggerFactory();
+ jfinalConfig.configRoute(routes);
+ jfinalConfig.configPlugin(plugins); startPlugins(); // very important!!!
+ jfinalConfig.configInterceptor(interceptors);
+ jfinalConfig.configHandler(handlers);
+ }
+
+ public static final Constants getConstants() {
+ return constants;
+ }
+
+ public static final Routes getRoutes() {
+ return routes;
+ }
+
+ public static final Plugins getPlugins() {
+ return plugins;
+ }
+
+ public static final Interceptors getInterceptors() {
+ return interceptors;
+ }
+
+ public static Handlers getHandlers() {
+ return handlers;
+ }
+
+ private static void startPlugins() {
+ List pluginList = plugins.getPluginList();
+ if (pluginList != null) {
+ 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());
+ }
+
+ boolean success = plugin.start();
+ if (!success) {
+ 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);
+ }
+ }
+ }
+ }
+
+ private static void initLoggerFactory() {
+ Logger.init();
+ log = Logger.getLogger(Config.class);
+ JFinalFilter.initLogger();
+ }
+}
diff --git a/src/main/java/com/jfinal/core/Const.java b/src/com/jfinal/core/Const.java
similarity index 56%
rename from src/main/java/com/jfinal/core/Const.java
rename to src/com/jfinal/core/Const.java
index 3651d70d2..f682e2895 100644
--- a/src/main/java/com/jfinal/core/Const.java
+++ b/src/com/jfinal/core/Const.java
@@ -1,62 +1,66 @@
-/**
- * Copyright (c) 2011-2023, James Zhan 詹波 (jfinal@126.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
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.jfinal.core;
-
-import com.jfinal.render.ViewType;
-
-/**
- * Global constants definition
- */
-public interface Const {
-
- String JFINAL_VERSION = "5.2.6";
-
- ViewType DEFAULT_VIEW_TYPE = ViewType.JFINAL_TEMPLATE;
-
- String DEFAULT_BASE_UPLOAD_PATH = "upload";
-
- String DEFAULT_BASE_DOWNLOAD_PATH = "download";
-
- String DEFAULT_ENCODING = "UTF-8";
-
- boolean DEFAULT_DEV_MODE = false;
-
- String DEFAULT_URL_PARA_SEPARATOR = "-";
-
- String DEFAULT_VIEW_EXTENSION = ".html";
-
- int DEFAULT_MAX_POST_SIZE = 1024 * 1024 * 10; // Default max post size of multipart request: 10 Meg
-
- int DEFAULT_I18N_MAX_AGE_OF_COOKIE = 999999999;
-
- int DEFAULT_FREEMARKER_TEMPLATE_UPDATE_DELAY = 3600; // For not devMode only
-
- String DEFAULT_TOKEN_NAME = "_jfinal_token";
-
- int DEFAULT_SECONDS_OF_TOKEN_TIME_OUT = 900; // 900 seconds ---> 15 minutes
-
- int MIN_SECONDS_OF_TOKEN_TIME_OUT = 300; // 300 seconds ---> 5 minutes
-
- int DEFAULT_CONFIG_PLUGIN_ORDER = 3;
-
- ControllerFactory DEFAULT_CONTROLLER_FACTORY = new ControllerFactory();
-
- ActionReporter DEFAULT_ACTION_REPORTER = new ActionReporter();
-
- boolean DEFAULT_INJECT_DEPENDENCY = false;
-}
-
+/**
+ * Copyright (c) 2011-2014, James Zhan 詹波 (jfinal@126.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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.jfinal.core;
+
+import java.io.File;
+import com.jfinal.render.ViewType;
+
+/**
+ * Global constants definition
+ */
+public interface Const {
+
+ String JFINAL_VERSION = "1.8";
+
+ ViewType DEFAULT_VIEW_TYPE = ViewType.FREE_MARKER;
+
+ String DEFAULT_ENCODING = "utf-8";
+
+ String DEFAULT_URL_PARA_SEPARATOR = "-";
+
+ String DEFAULT_FILE_CONTENT_TYPE = "application/octet-stream";
+
+ String DEFAULT_JSP_EXTENSION = ".jsp";
+
+ String DEFAULT_FREE_MARKER_EXTENSION = ".html"; // The original is ".ftl", Recommend ".html"
+
+ String DEFAULT_VELOCITY_EXTENSION = ".vm";
+
+ // "WEB-INF/download" + File.separator maybe better otherwise it can be downloaded by browser directly
+ String DEFAULT_FILE_RENDER_BASE_PATH = File.separator + "download" + File.separator;
+
+ int DEFAULT_MAX_POST_SIZE = 1024 * 1024 * 10; // Default max post size of multipart request: 10 Meg
+
+ String I18N_LOCALE = "__I18N_LOCALE__"; // The i18n name of cookie
+
+ int DEFAULT_I18N_MAX_AGE_OF_COOKIE = 999999999;
+
+ int DEFAULT_FREEMARKER_TEMPLATE_UPDATE_DELAY = 3600; // For not devMode only
+
+ String DEFAULT_TOKEN_NAME = "jfinal_token";
+
+ int DEFAULT_SECONDS_OF_TOKEN_TIME_OUT = 900; // 900 seconds ---> 15 minutes
+
+ int MIN_SECONDS_OF_TOKEN_TIME_OUT = 300; // 300 seconds ---> 5 minutes
+}
+
+
+
+
+
+
+
diff --git a/src/main/java/com/jfinal/core/Controller.java b/src/com/jfinal/core/Controller.java
similarity index 54%
rename from src/main/java/com/jfinal/core/Controller.java
rename to src/com/jfinal/core/Controller.java
index 9e2d98c93..a343fd7bd 100644
--- a/src/main/java/com/jfinal/core/Controller.java
+++ b/src/com/jfinal/core/Controller.java
@@ -1,1514 +1,1087 @@
-/**
- * Copyright (c) 2011-2023, James Zhan 詹波 (jfinal@126.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
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.jfinal.core;
-
-import java.io.File;
-import java.text.ParseException;
-import java.util.Date;
-import java.util.Enumeration;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.function.Consumer;
-import javax.servlet.http.Cookie;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import javax.servlet.http.HttpSession;
-import com.jfinal.core.converter.TypeConverter;
-import com.jfinal.core.paragetter.JsonRequest;
-import com.jfinal.kit.Kv;
-import com.jfinal.kit.StrKit;
-import com.jfinal.render.ContentType;
-import com.jfinal.render.JsonRender;
-import com.jfinal.render.Render;
-import com.jfinal.render.RenderManager;
-import com.jfinal.upload.*;
-
-/**
- * Controller
- *
- * 昨夜西风凋碧树。独上高楼,望尽天涯路。
- * 衣带渐宽终不悔,为伊消得人憔悴。
- * 众里寻她千百度,蓦然回首,那人却在灯火阑珊处。
- */
-@SuppressWarnings({"unchecked", "rawtypes"})
-public abstract class Controller {
-
- // 可通过 CPI.getAction(Controller) 获取
- Action action;
-
- private HttpServletRequest request;
- private HttpServletResponse response;
-
- private String urlPara;
- private String[] urlParaArray;
- private String rawData;
-
- private Render render;
-
- private static final RenderManager renderManager = RenderManager.me();
-
- private static final String[] NULL_URL_PARA_ARRAY = new String[0];
- private static final String URL_PARA_SEPARATOR = Config.getConstants().getUrlParaSeparator();
-
- void _init_(Action action, HttpServletRequest request, HttpServletResponse response, String urlPara) {
- this.action = action;
- this.request = request;
- this.response = response;
- this.urlPara = urlPara;
- urlParaArray = null;
- render = null;
- }
-
- /**
- * 在对 Controller 回收使用场景下,如果继承类中声明了属性,则必须要
- * 覆盖此方法,调用父类的 clear() 方法并清掉自身的属性,例如:
- *
- * super._clear_();
- * this.xxx = null;
- */
- protected void _clear_() {
- action = null;
- request = null;
- response = null;
- urlPara = null;
- urlParaArray = null;
- render = null;
- rawData = null;
- }
-
- /**
- * 判断是否为 json 请求,contentType 包含 "json" 被认定为 json 请求
- */
- public boolean isJsonRequest() {
- if (request instanceof JsonRequest) {
- return true;
- }
- String ct = request.getContentType();
- return ct != null && ct.indexOf("json") != -1;
- }
-
- /**
- * 获取 http 请求 body 中的原始数据,通常用于接收 json String 这类数据
- * 可多次调用此方法,避免掉了 HttpKit.readData(...) 方式获取该数据时多次调用
- * 引发的异常
- * @return http 请求 body 中的原始数据
- */
- public String getRawData() {
- if (rawData == null) {
- rawData = com.jfinal.kit.HttpKit.readData(request);
- }
- return rawData;
- }
-
- public String getControllerPath() {
- return action.getControllerPath();
- }
-
- /**
- * 该方法已改名为 getControllerPath()
- */
- @Deprecated
- public String getControllerKey() {
- return action.getControllerPath();
- }
-
- public String getViewPath() {
- return action.getViewPath();
- }
-
- public void setHttpServletRequest(HttpServletRequest request) {
- this.request = request;
- }
-
- public void setHttpServletResponse(HttpServletResponse response) {
- this.response = response;
- }
-
- public void setUrlPara(String urlPara) {
- this.urlPara = urlPara;
- this.urlParaArray = null;
- }
-
- /**
- * Stores an attribute in this request
- * @param name a String specifying the name of the attribute
- * @param value the Object to be stored
- */
- public Controller setAttr(String name, Object value) {
- request.setAttribute(name, value);
- return this;
- }
-
- /**
- * Removes an attribute from this request
- * @param name a String specifying the name of the attribute to remove
- */
- public Controller removeAttr(String name) {
- request.removeAttribute(name);
- return this;
- }
-
- /**
- * Stores attributes in this request, key of the map as attribute name and value of the map as attribute value
- * @param attrMap key and value as attribute of the map to be stored
- */
- public Controller setAttrs(Map attrMap) {
- for (Map.Entry entry : attrMap.entrySet())
- request.setAttribute(entry.getKey(), entry.getValue());
- return this;
- }
-
- /**
- * Returns the value of a request parameter as a String, or null if the parameter does not exist.
- *
- * You should only use this method when you are sure the parameter has only one value. If the
- * parameter might have more than one value, use getParaValues(java.lang.String).
- *
- * If you use this method with a multivalued parameter, the value returned is equal to the first
- * value in the array returned by getParameterValues.
- * @param name a String specifying the name of the parameter
- * @return a String representing the single value of the parameter
- */
- public String getPara(String name) {
- // return request.getParameter(name);
- String result = request.getParameter(name);
- return result != null && result.length() != 0 ? result : null;
- }
-
- /**
- * Returns the value of a request parameter as a String, or default value if the parameter does not exist.
- * @param name a String specifying the name of the parameter
- * @param defaultValue a String value be returned when the value of parameter is null
- * @return a String representing the single value of the parameter
- */
- public String getPara(String name, String defaultValue) {
- String result = request.getParameter(name);
- return result != null && result.length() != 0 ? result : defaultValue;
- }
-
- /**
- * Returns the values of the request parameters as a Map.
- * @return a Map contains all the parameters name and value
- */
- public Map getParaMap() {
- return request.getParameterMap();
- }
-
- /**
- * Returns an Enumeration of String objects containing the names of the parameters
- * contained in this request. If the request has no parameters, the method returns
- * an empty Enumeration.
- * @return an Enumeration of String objects, each String containing the name of
- * a request parameter; or an empty Enumeration if the request has no parameters
- */
- public Enumeration getParaNames() {
- return request.getParameterNames();
- }
-
- /**
- * Returns an array of String objects containing all of the values the given request
- * parameter has, or null if the parameter does not exist. If the parameter has a
- * single value, the array has a length of 1.
- * @param name a String containing the name of the parameter whose value is requested
- * @return an array of String objects containing the parameter's values
- */
- public String[] getParaValues(String name) {
- return request.getParameterValues(name);
- }
-
- /**
- * Returns an array of Integer objects containing all of the values the given request
- * parameter has, or null if the parameter does not exist. If the parameter has a
- * single value, the array has a length of 1.
- * @param name a String containing the name of the parameter whose value is requested
- * @return an array of Integer objects containing the parameter's values
- */
- public Integer[] getParaValuesToInt(String name) {
- String[] values = request.getParameterValues(name);
- if (values == null || values.length == 0) {
- return null;
- }
- Integer[] result = new Integer[values.length];
- for (int i=0; i getAttrNames() {
- return request.getAttributeNames();
- }
-
- /**
- * Returns the value of the named attribute as an Object, or null if no attribute of the given name exists.
- * @param name a String specifying the name of the attribute
- * @return an Object containing the value of the attribute, or null if the attribute does not exist
- */
- public T getAttr(String name) {
- return (T)request.getAttribute(name);
- }
-
- public T getAttr(String name, T defaultValue) {
- T result = (T)request.getAttribute(name);
- return result != null ? result : defaultValue;
- }
-
- /**
- * Returns the value of the named attribute as an Object, or null if no attribute of the given name exists.
- * @param name a String specifying the name of the attribute
- * @return an String Object containing the value of the attribute, or null if the attribute does not exist
- */
- public String getAttrForStr(String name) {
- return (String)request.getAttribute(name);
- }
-
- /**
- * Returns the value of the named attribute as an Object, or null if no attribute of the given name exists.
- * @param name a String specifying the name of the attribute
- * @return an Integer Object containing the value of the attribute, or null if the attribute does not exist
- */
- public Integer getAttrForInt(String name) {
- return (Integer)request.getAttribute(name);
- }
-
- /**
- * Returns the value of the specified request header as a String.
- */
- public String getHeader(String name) {
- return request.getHeader(name);
- }
-
- private Integer toInt(String value, Integer defaultValue) {
- try {
- if (StrKit.isBlank(value))
- return defaultValue;
- value = value.trim();
- if (value.startsWith("N") || value.startsWith("n"))
- return -Integer.parseInt(value.substring(1));
- return Integer.parseInt(value);
- }
- catch (Exception e) {
- throw new ActionException(400, renderManager.getRenderFactory().getErrorRender(400), "Can not parse the parameter \"" + value + "\" to Integer value.");
- }
- }
-
- /**
- * Returns the value of a request parameter and convert to Integer.
- * @param name a String specifying the name of the parameter
- * @return a Integer representing the single value of the parameter
- */
- public Integer getParaToInt(String name) {
- return toInt(request.getParameter(name), null);
- }
-
- /**
- * Returns the value of a request parameter and convert to Integer with a default value if it is null.
- * @param name a String specifying the name of the parameter
- * @return a Integer representing the single value of the parameter
- */
- public Integer getParaToInt(String name, Integer defaultValue) {
- return toInt(request.getParameter(name), defaultValue);
- }
-
- private Long toLong(String value, Long defaultValue) {
- try {
- if (StrKit.isBlank(value))
- return defaultValue;
- value = value.trim();
- if (value.startsWith("N") || value.startsWith("n"))
- return -Long.parseLong(value.substring(1));
- return Long.parseLong(value);
- }
- catch (Exception e) {
- throw new ActionException(400, renderManager.getRenderFactory().getErrorRender(400), "Can not parse the parameter \"" + value + "\" to Long value.");
- }
- }
-
- /**
- * Returns the value of a request parameter and convert to Long.
- * @param name a String specifying the name of the parameter
- * @return a Integer representing the single value of the parameter
- */
- public Long getParaToLong(String name) {
- return toLong(request.getParameter(name), null);
- }
-
- /**
- * Returns the value of a request parameter and convert to Long with a default value if it is null.
- * @param name a String specifying the name of the parameter
- * @return a Integer representing the single value of the parameter
- */
- public Long getParaToLong(String name, Long defaultValue) {
- return toLong(request.getParameter(name), defaultValue);
- }
-
- private Boolean toBoolean(String value, Boolean defaultValue) {
- if (StrKit.isBlank(value))
- return defaultValue;
- value = value.trim().toLowerCase();
- if ("1".equals(value) || "true".equals(value))
- return Boolean.TRUE;
- else if ("0".equals(value) || "false".equals(value))
- return Boolean.FALSE;
- throw new ActionException(400, renderManager.getRenderFactory().getErrorRender(400), "Can not parse the parameter \"" + value + "\" to Boolean value.");
- }
-
- /**
- * Returns the value of a request parameter and convert to Boolean.
- * @param name a String specifying the name of the parameter
- * @return true if the value of the parameter is "true" or "1", false if it is "false" or "0", null if parameter is not exists
- */
- public Boolean getParaToBoolean(String name) {
- return toBoolean(request.getParameter(name), null);
- }
-
- /**
- * Returns the value of a request parameter and convert to Boolean with a default value if it is null.
- * @param name a String specifying the name of the parameter
- * @return true if the value of the parameter is "true" or "1", false if it is "false" or "0", default value if it is null
- */
- public Boolean getParaToBoolean(String name, Boolean defaultValue) {
- return toBoolean(request.getParameter(name), defaultValue);
- }
-
- /**
- * Get all para from url and convert to Boolean
- */
- public Boolean getParaToBoolean() {
- return toBoolean(getPara(), null);
- }
-
- /**
- * Get para from url and conver to Boolean. The first index is 0
- */
- public Boolean getParaToBoolean(int index) {
- return toBoolean(getPara(index), null);
- }
-
- /**
- * Get para from url and conver to Boolean with default value if it is null.
- */
- public Boolean getParaToBoolean(int index, Boolean defaultValue) {
- return toBoolean(getPara(index), defaultValue);
- }
-
- private Date toDate(String value, Date defaultValue) {
- try {
- if (StrKit.isBlank(value))
- return defaultValue;
-
- // return new java.text.SimpleDateFormat("yyyy-MM-dd").parse(value.trim());
- return (Date)TypeConverter.me().convert(Date.class, value);
-
- } catch (Exception e) {
- throw new ActionException(400, renderManager.getRenderFactory().getErrorRender(400), "Can not parse the parameter \"" + value + "\" to Date value.");
- }
- }
-
- /**
- * Returns the value of a request parameter and convert to Date.
- * @param name a String specifying the name of the parameter
- * @return a Date representing the single value of the parameter
- */
- public Date getParaToDate(String name) {
- return toDate(request.getParameter(name), null);
- }
-
- /**
- * Returns the value of a request parameter and convert to Date with a default value if it is null.
- * @param name a String specifying the name of the parameter
- * @return a Date representing the single value of the parameter
- */
- public Date getParaToDate(String name, Date defaultValue) {
- return toDate(request.getParameter(name), defaultValue);
- }
-
- /**
- * Get all para from url and convert to Date
- */
- public Date getParaToDate() {
- return toDate(getPara(), null);
- }
-
- /**
- * Return HttpServletRequest. Do not use HttpServletRequest Object in constructor of Controller
- */
- public HttpServletRequest getRequest() {
- return request;
- }
-
- /**
- * Return HttpServletResponse. Do not use HttpServletResponse Object in constructor of Controller
- */
- public HttpServletResponse getResponse() {
- return response;
- }
-
- /**
- * Return HttpSession.
- */
- public HttpSession getSession() {
- return request.getSession();
- }
-
- /**
- * Return HttpSession.
- * @param create a boolean specifying create HttpSession if it not exists
- */
- public HttpSession getSession(boolean create) {
- return request.getSession(create);
- }
-
- /**
- * Return a Object from session.
- * @param key a String specifying the key of the Object stored in session
- */
- public T getSessionAttr(String key) {
- HttpSession session = request.getSession(false);
- return session != null ? (T)session.getAttribute(key) : null;
- }
-
- public T getSessionAttr(String key, T defaultValue) {
- T result = getSessionAttr(key);
- return result != null ? result : defaultValue;
- }
-
- /**
- * Store Object to session.
- * @param key a String specifying the key of the Object stored in session
- * @param value a Object specifying the value stored in session
- */
- public Controller setSessionAttr(String key, Object value) {
- request.getSession(true).setAttribute(key, value);
- return this;
- }
-
- /**
- * Remove Object in session.
- * @param key a String specifying the key of the Object stored in session
- */
- public Controller removeSessionAttr(String key) {
- HttpSession session = request.getSession(false);
- if (session != null)
- session.removeAttribute(key);
- return this;
- }
-
- /**
- * Get cookie value by cookie name.
- */
- public String getCookie(String name, String defaultValue) {
- Cookie cookie = getCookieObject(name);
- return cookie != null ? cookie.getValue() : defaultValue;
- }
-
- /**
- * Get cookie value by cookie name.
- */
- public String getCookie(String name) {
- return getCookie(name, null);
- }
-
- /**
- * Get cookie value by cookie name and convert to Integer.
- */
- public Integer getCookieToInt(String name) {
- String result = getCookie(name);
- return result != null ? Integer.parseInt(result) : null;
- }
-
- /**
- * Get cookie value by cookie name and convert to Integer.
- */
- public Integer getCookieToInt(String name, Integer defaultValue) {
- String result = getCookie(name);
- return result != null ? Integer.parseInt(result) : defaultValue;
- }
-
- /**
- * Get cookie value by cookie name and convert to Long.
- */
- public Long getCookieToLong(String name) {
- String result = getCookie(name);
- return result != null ? Long.parseLong(result) : null;
- }
-
- /**
- * Get cookie value by cookie name and convert to Long.
- */
- public Long getCookieToLong(String name, Long defaultValue) {
- String result = getCookie(name);
- return result != null ? Long.parseLong(result) : defaultValue;
- }
-
- /**
- * Get cookie object by cookie name.
- */
- public Cookie getCookieObject(String name) {
- Cookie[] cookies = request.getCookies();
- if (cookies != null)
- for (Cookie cookie : cookies)
- if (cookie.getName().equals(name))
- return cookie;
- return null;
- }
-
- /**
- * Get all cookie objects.
- */
- public Cookie[] getCookieObjects() {
- Cookie[] result = request.getCookies();
- return result != null ? result : new Cookie[0];
- }
-
- /**
- * Set Cookie.
- * @param name cookie name
- * @param value cookie value
- * @param maxAgeInSeconds -1: clear cookie when close browser. 0: clear cookie immediately. n>0 : max age in n seconds.
- * @param isHttpOnly true if this cookie is to be marked as HttpOnly, false otherwise
- */
- public Controller setCookie(String name, String value, int maxAgeInSeconds, boolean isHttpOnly) {
- return doSetCookie(name, value, maxAgeInSeconds, null, null, isHttpOnly);
- }
-
- /**
- * Set Cookie.
- * @param name cookie name
- * @param value cookie value
- * @param maxAgeInSeconds -1: clear cookie when close browser. 0: clear cookie immediately. n>0 : max age in n seconds.
- */
- public Controller setCookie(String name, String value, int maxAgeInSeconds) {
- return doSetCookie(name, value, maxAgeInSeconds, null, null, null);
- }
-
- /**
- * Set Cookie to response.
- */
- public Controller setCookie(Cookie cookie) {
- response.addCookie(cookie);
- return this;
- }
-
- /**
- * Set Cookie to response.
- * @param name cookie name
- * @param value cookie value
- * @param maxAgeInSeconds -1: clear cookie when close browser. 0: clear cookie immediately. n>0 : max age in n seconds.
- * @param path see Cookie.setPath(String)
- * @param isHttpOnly true if this cookie is to be marked as HttpOnly, false otherwise
- */
- public Controller setCookie(String name, String value, int maxAgeInSeconds, String path, boolean isHttpOnly) {
- return doSetCookie(name, value, maxAgeInSeconds, path, null, isHttpOnly);
- }
-
- /**
- * Set Cookie to response.
- * @param name cookie name
- * @param value cookie value
- * @param maxAgeInSeconds -1: clear cookie when close browser. 0: clear cookie immediately. n>0 : max age in n seconds.
- * @param path see Cookie.setPath(String)
- */
- public Controller setCookie(String name, String value, int maxAgeInSeconds, String path) {
- return doSetCookie(name, value, maxAgeInSeconds, path, null, null);
- }
-
- /**
- * Set Cookie to response.
- * @param name cookie name
- * @param value cookie value
- * @param maxAgeInSeconds -1: clear cookie when close browser. 0: clear cookie immediately. n>0 : max age in n seconds.
- * @param path see Cookie.setPath(String)
- * @param domain the domain name within which this cookie is visible; form is according to RFC 2109
- * @param isHttpOnly true if this cookie is to be marked as HttpOnly, false otherwise
- */
- public Controller setCookie(String name, String value, int maxAgeInSeconds, String path, String domain, boolean isHttpOnly) {
- return doSetCookie(name, value, maxAgeInSeconds, path, domain, isHttpOnly);
- }
-
- /**
- * Remove Cookie.
- */
- public Controller removeCookie(String name) {
- return doSetCookie(name, null, 0, null, null, null);
- }
-
- /**
- * Remove Cookie.
- */
- public Controller removeCookie(String name, String path) {
- return doSetCookie(name, null, 0, path, null, null);
- }
-
- /**
- * Remove Cookie.
- */
- public Controller removeCookie(String name, String path, String domain) {
- return doSetCookie(name, null, 0, path, domain, null);
- }
-
- protected Controller doSetCookie(String name, String value, int maxAgeInSeconds, String path, String domain, Boolean isHttpOnly) {
- Cookie cookie = new Cookie(name, value);
- cookie.setMaxAge(maxAgeInSeconds);
- // set the default path value to "/"
- if (StrKit.isBlank(path)) {
- path = "/";
- }
- cookie.setPath(path);
-
- if (domain != null) {
- cookie.setDomain(domain);
- }
- if (isHttpOnly != null) {
- cookie.setHttpOnly(isHttpOnly);
- }
- response.addCookie(cookie);
- return this;
- }
-
- // --------
-
- /**
- * Get all para with separator char from url
- */
- public String getPara() {
- if ("".equals(urlPara)) // urlPara maybe is "" see ActionMapping.getAction(String)
- urlPara = null;
- return urlPara;
- }
-
- /**
- * Get para from url. The index of first url para is 0.
- */
- public String getPara(int index) {
- if (index < 0)
- return getPara();
-
- if (urlParaArray == null) {
- if (urlPara == null || "".equals(urlPara)) // urlPara maybe is "" see ActionMapping.getAction(String)
- urlParaArray = NULL_URL_PARA_ARRAY;
- else
- urlParaArray = urlPara.split(URL_PARA_SEPARATOR);
-
- for (int i=0; i index ? urlParaArray[index] : null;
- }
-
- /**
- * Get para from url with default value if it is null or "".
- */
- public String getPara(int index, String defaultValue) {
- String result = getPara(index);
- return result != null && result.length() != 0 ? result : defaultValue;
- }
-
- /**
- * Get para from url and conver to Integer. The first index is 0
- */
- public Integer getParaToInt(int index) {
- return toInt(getPara(index), null);
- }
-
- /**
- * Get para from url and conver to Integer with default value if it is null.
- */
- public Integer getParaToInt(int index, Integer defaultValue) {
- return toInt(getPara(index), defaultValue);
- }
-
- /**
- * Get para from url and conver to Long.
- */
- public Long getParaToLong(int index) {
- return toLong(getPara(index), null);
- }
-
- /**
- * Get para from url and conver to Long with default value if it is null.
- */
- public Long getParaToLong(int index, Long defaultValue) {
- return toLong(getPara(index), defaultValue);
- }
-
- /**
- * Get all para from url and convert to Integer
- */
- public Integer getParaToInt() {
- return toInt(getPara(), null);
- }
-
- /**
- * Get all para from url and convert to Long
- */
- public Long getParaToLong() {
- return toLong(getPara(), null);
- }
-
- /**
- * Get model from http request.
- */
- public T getModel(Class modelClass) {
- return (T)Injector.injectModel(modelClass, request, false);
- }
-
- public T getModel(Class modelClass, boolean skipConvertError) {
- return (T)Injector.injectModel(modelClass, request, skipConvertError);
- }
-
- /**
- * Get model from http request.
- */
- public T getModel(Class modelClass, String modelName) {
- return (T)Injector.injectModel(modelClass, modelName, request, false);
- }
-
- public T getModel(Class modelClass, String modelName, boolean skipConvertError) {
- return (T)Injector.injectModel(modelClass, modelName, request, skipConvertError);
- }
-
- public T getBean(Class beanClass) {
- return (T)Injector.injectBean(beanClass, request, false);
- }
-
- public T getBean(Class beanClass, boolean skipConvertError) {
- return (T)Injector.injectBean(beanClass, request, skipConvertError);
- }
-
- public T getBean(Class beanClass, String beanName) {
- return (T)Injector.injectBean(beanClass, beanName, request, false);
- }
-
- public T getBean(Class beanClass, String beanName, boolean skipConvertError) {
- return (T)Injector.injectBean(beanClass, beanName, request, skipConvertError);
- }
-
- /**
- * 获取被 Kv 封装后的参数,便于使用 Kv 中的一些工具方法
- *
- * 由于 Kv 继承自 HashMap,也便于需要使用 HashMap 的场景,
- * 例如:
- * Record record = new Record().setColumns(getKv());
- */
- public Kv getKv() {
- Kv kv = new Kv();
- HttpServletRequest req = this.request;
-
- // 优化 json 请求,避免 JsonRequest.createParaMap() 中的数据转换
- if (request instanceof JsonRequest) {
- JsonRequest jsonReq = (JsonRequest)request;
- if (jsonReq.getJSONObject() != null) {
- kv.putAll(jsonReq.getJSONObject());
- }
-
- // json 数据添加完成后再添加内部 HttpServletRequest 对象中的数据
- // 使用 getInnerRequest() 避免调用 JsonRequest.createParaMap() 产生性能损耗
- req = jsonReq.getInnerRequest();
- }
-
- Map paraMap = req.getParameterMap();
- for (Entry entry : paraMap.entrySet()) {
- String[] values = entry.getValue();
- String value = (values != null && values.length > 0) ? values[0] : null;
- kv.put(entry.getKey(), "".equals(value) ? null : value);
- }
- return kv;
- }
-
- // TODO public List getModels(Class modelClass, String modelName) {}
-
- // --------
-
- /**
- * Get upload file from multipart request.
- */
- public List getFiles(String uploadPath, long maxPostSize, String encoding) {
- if (request instanceof MultipartRequest == false)
- request = new MultipartRequest(request, uploadPath, maxPostSize, encoding);
- return ((MultipartRequest)request).getFiles();
- }
-
- public UploadFile getFile(String parameterName, String uploadPath, long maxPostSize, String encoding) {
- getFiles(uploadPath, maxPostSize, encoding);
- return getFile(parameterName);
- }
-
- public List getFiles(String uploadPath, long maxPostSize) {
- if (request instanceof MultipartRequest == false)
- request = new MultipartRequest(request, uploadPath, maxPostSize);
- return ((MultipartRequest)request).getFiles();
- }
-
- public UploadFile getFile(String parameterName, String uploadPath, long maxPostSize) {
- getFiles(uploadPath, maxPostSize);
- return getFile(parameterName);
- }
-
- public List getFiles(String uploadPath) {
- if (request instanceof MultipartRequest == false)
- request = new MultipartRequest(request, uploadPath);
- return ((MultipartRequest)request).getFiles();
- }
-
- public UploadFile getFile(String parameterName, String uploadPath) {
- getFiles(uploadPath);
- return getFile(parameterName);
- }
-
- public List getFiles() {
- if (request instanceof MultipartRequest == false)
- request = new MultipartRequest(request);
- return ((MultipartRequest)request).getFiles();
- }
-
- public UploadFile getFile() {
- List uploadFiles = getFiles();
- return uploadFiles.size() > 0 ? uploadFiles.get(0) : null;
- }
-
- public UploadFile getFile(String parameterName) {
- List uploadFiles = getFiles();
- for (UploadFile uploadFile : uploadFiles) {
- if (uploadFile.getParameterName().equals(parameterName)) {
- return uploadFile;
- }
- }
- return null;
- }
-
- /**
- * Keep all parameter's value except model value
- */
- public Controller keepPara() {
- Map map = request.getParameterMap();
- for (Entry e: map.entrySet()) {
- String[] values = e.getValue();
- if (values != null && values.length == 1)
- request.setAttribute(e.getKey(), values[0]);
- else
- request.setAttribute(e.getKey(), values);
- }
- return this;
- }
-
- /**
- * Keep parameter's value names pointed, model value can not be kept
- */
- public Controller keepPara(String... names) {
- for (String name : names) {
- String[] values = request.getParameterValues(name);
- if (values != null) {
- if (values.length == 1)
- request.setAttribute(name, values[0]);
- else
- request.setAttribute(name, values);
- }
- }
- return this;
- }
-
- /**
- * Convert para to special type and keep it
- */
- public Controller keepPara(Class type, String name) {
- String[] values = request.getParameterValues(name);
- if (values != null) {
- if (values.length == 1)
- try {request.setAttribute(name, TypeConverter.me().convert(type, values[0]));} catch (ParseException e) {com.jfinal.kit.LogKit.logNothing(e);}
- else
- request.setAttribute(name, values);
- }
- return this;
- }
-
- public Controller keepPara(Class type, String... names) {
- if (type == String.class)
- return keepPara(names);
-
- if (names != null)
- for (String name : names)
- keepPara(type, name);
- return this;
- }
-
- public Controller keepModel(Class extends com.jfinal.plugin.activerecord.Model> modelClass, String modelName) {
- if (StrKit.notBlank(modelName)) {
- Object model = Injector.injectModel(modelClass, modelName, request, true);
- request.setAttribute(modelName, model);
- } else {
- keepPara();
- }
- return this;
- }
-
- public Controller keepModel(Class extends com.jfinal.plugin.activerecord.Model> modelClass) {
- String modelName = StrKit.firstCharToLowerCase(modelClass.getSimpleName());
- keepModel(modelClass, modelName);
- return this;
- }
-
- public Controller keepBean(Class> beanClass, String beanName) {
- if (StrKit.notBlank(beanName)) {
- Object bean = Injector.injectBean(beanClass, beanName, request, true);
- request.setAttribute(beanName, bean);
- } else {
- keepPara();
- }
- return this;
- }
-
- public Controller keepBean(Class> beanClass) {
- String beanName = StrKit.firstCharToLowerCase(beanClass.getSimpleName());
- keepBean(beanClass, beanName);
- return this;
- }
-
- /**
- * Create a token.
- * @param tokenName the token name used in view
- * @param secondsOfTimeOut the seconds of time out, secondsOfTimeOut >= Const.MIN_SECONDS_OF_TOKEN_TIME_OUT
- */
- public String createToken(String tokenName, int secondsOfTimeOut) {
- return com.jfinal.token.TokenManager.createToken(this, tokenName, secondsOfTimeOut);
- }
-
- /**
- * Create a token with default token name and with default seconds of time out.
- */
- public String createToken() {
- return createToken(Const.DEFAULT_TOKEN_NAME, Const.DEFAULT_SECONDS_OF_TOKEN_TIME_OUT);
- }
-
- /**
- * Create a token with default seconds of time out.
- * @param tokenName the token name used in view
- */
- public String createToken(String tokenName) {
- return createToken(tokenName, Const.DEFAULT_SECONDS_OF_TOKEN_TIME_OUT);
- }
-
- /**
- * Check token to prevent resubmit.
- * @param tokenName the token name used in view's form
- * @return true if token is correct
- */
- public boolean validateToken(String tokenName) {
- return com.jfinal.token.TokenManager.validateToken(this, tokenName);
- }
-
- /**
- * Check token to prevent resubmit with default token key ---> "JFINAL_TOKEN_KEY"
- * @return true if token is correct
- */
- public boolean validateToken() {
- return validateToken(Const.DEFAULT_TOKEN_NAME);
- }
-
- /**
- * Return true if the para value is blank otherwise return false
- */
- public boolean isParaBlank(String paraName) {
- return StrKit.isBlank(request.getParameter(paraName));
- }
-
- /**
- * Return true if the urlPara value is blank otherwise return false
- */
- public boolean isParaBlank(int index) {
- return StrKit.isBlank(getPara(index));
- }
-
- /**
- * Return true if the para exists otherwise return false
- */
- public boolean isParaExists(String paraName) {
- return request.getParameterMap().containsKey(paraName);
- }
-
- /**
- * Return true if the urlPara exists otherwise return false
- */
- public boolean isParaExists(int index) {
- return getPara(index) != null;
- }
-
- // ----------------
- // render below ---
-
- public Render getRender() {
- return render;
- }
-
- /**
- * Render with any Render which extends Render
- */
- public void render(Render render) {
- this.render = render;
- }
-
- /**
- * Render with view use default type Render configured in JFinalConfig
- */
- public void render(String view) {
- render = renderManager.getRenderFactory().getRender(view);
- }
-
- /**
- * Render template to String content, it is useful for:
- * 1: Generate HTML fragment for AJAX request
- * 2: Generate email, short message and so on
- */
- public String renderToString(String template, Map data) {
- if (template.charAt(0) != '/') {
- template = action.getViewPath() + template;
- }
- return renderManager.getEngine().getTemplate(template).renderToString(data);
- }
-
- /**
- * Render with JFinal template
- */
- public void renderTemplate(String template) {
- render = renderManager.getRenderFactory().getTemplateRender(template);
- }
-
- /**
- * Render with jsp view
- */
- public void renderJsp(String view) {
- render = renderManager.getRenderFactory().getJspRender(view);
- }
-
- /**
- * Render with freemarker view
- */
- public void renderFreeMarker(String view) {
- render = renderManager.getRenderFactory().getFreeMarkerRender(view);
- }
-
- /**
- * Render with json
- *
-
- public T getAopProxy(Class targetClass) {
- return com.jfinal.aop.Aop.get(targetClass);
- } */
-
- // --------------------
-
- /**
- * 为了进一步省代码,创建与 setAttr(...) 功能一模一样的缩短版本 set(...)
- */
- public Controller set(String attributeName, Object attributeValue) {
- request.setAttribute(attributeName, attributeValue);
- return this;
- }
-
- // --- 以下是为了省代码,为 getPara 系列方法创建的缩短版本
-
- public String get(String name) {
- return getPara(name);
- }
-
- public String get(String name, String defaultValue) {
- return getPara(name, defaultValue);
- }
-
- public Integer getInt(String name) {
- return getParaToInt(name);
- }
-
- public Integer getInt(String name, Integer defaultValue) {
- return getParaToInt(name, defaultValue);
- }
-
- public Long getLong(String name) {
- return getParaToLong(name);
- }
-
- public Long getLong(String name, Long defaultValue) {
- return getParaToLong(name, defaultValue);
- }
-
- public Boolean getBoolean(String name) {
- return getParaToBoolean(name);
- }
-
- public Boolean getBoolean(String name, Boolean defaultValue) {
- return getParaToBoolean(name, defaultValue);
- }
-
- public Date getDate(String name) {
- return getParaToDate(name);
- }
-
- public Date getDate(String name, Date defaultValue) {
- return getParaToDate(name, defaultValue);
- }
-
- // --- 以下是 getPara 系列中获取 urlPara 的缩短版本
-
- /* 为了让继承类可以使用名为 get 的 action 注掉此方法,可使用 get(-1) 来实现本方法的功能
- public String get() {
- return getPara();
- } */
-
- public String get(int index) {
- return getPara(index);
- }
-
- public String get(int index, String defaultValue) {
- return getPara(index, defaultValue);
- }
-
- public Integer getInt() {
- return getParaToInt();
- }
-
- public Integer getInt(int index) {
- return getParaToInt(index);
- }
-
- public Integer getInt(int index, Integer defaultValue) {
- return getParaToInt(index, defaultValue);
- }
-
- public Long getLong() {
- return getParaToLong();
- }
-
- public Long getLong(int index) {
- return getParaToLong(index);
- }
-
- public Long getLong(int index, Long defaultValue) {
- return getParaToLong(index, defaultValue);
- }
-
- public Boolean getBoolean() {
- return getParaToBoolean();
- }
-
- public Boolean getBoolean(int index) {
- return getParaToBoolean(index);
- }
-
- public Boolean getBoolean(int index, Boolean defaultValue) {
- return getParaToBoolean(index, defaultValue);
- }
-
- /**
- * 获取带进度上传的 UploadFile,通过 callback 获取上传进度数据
- */
- public UploadFile getProgressFile(Consumer callback) {
- return getProgressFile(null, null, callback);
- }
-
- /**
- * 获取带进度上传的 UploadFile,通过 callback 获取上传进度数据
- */
- public UploadFile getProgressFile(String uploadPath, Consumer callback) {
- return getProgressFile(null, uploadPath, callback);
- }
-
- /**
- * 获取带进度上传的 UploadFile,通过 callback 获取上传进度数据
- * @param parameterName 上传文件对应的参数名称
- * @param uploadPath 上传目录
- * @param callback 回调函数获取上传进度数据
- * @return UploadFile 对象
- */
- public UploadFile getProgressFile(String parameterName, String uploadPath, Consumer callback) {
- return ProgressUploadFileKit.get(getRequest(), parameterName, uploadPath, callback);
- }
-}
-
-
+/**
+ * Copyright (c) 2011-2014, James Zhan 詹波 (jfinal@126.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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.jfinal.core;
+
+import java.io.File;
+import java.text.ParseException;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Map.Entry;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import static com.jfinal.core.Const.I18N_LOCALE;
+import com.jfinal.i18n.I18N;
+import com.jfinal.kit.StrKit;
+import com.jfinal.render.Render;
+import com.jfinal.render.RenderFactory;
+import com.jfinal.upload.MultipartRequest;
+import com.jfinal.upload.UploadFile;
+
+/**
+ * Controller
+ *
+ * 昨夜西风凋碧树。独上高楼,望尽天涯路。
+ * 衣带渐宽终不悔,为伊消得人憔悴。
+ * 众里寻她千百度,蓦然回首,那人却在灯火阑珊处。
+ */
+@SuppressWarnings({"unchecked", "rawtypes"})
+public abstract class Controller {
+
+ private HttpServletRequest request;
+ private HttpServletResponse response;
+
+ private String urlPara;
+ private String[] urlParaArray;
+
+ private static final String[] NULL_URL_PARA_ARRAY = new String[0];
+ private static final String URL_PARA_SEPARATOR = Config.getConstants().getUrlParaSeparator();
+
+ void init(HttpServletRequest request, HttpServletResponse response, String urlPara) {
+ this.request = request;
+ this.response = response;
+ this.urlPara = urlPara;
+ }
+
+ public void setUrlPara(String urlPara) {
+ this.urlPara = urlPara;
+ this.urlParaArray = null;
+ }
+
+ /**
+ * Stores an attribute in this request
+ * @param name a String specifying the name of the attribute
+ * @param value the Object to be stored
+ */
+ public Controller setAttr(String name, Object value) {
+ request.setAttribute(name, value);
+ return this;
+ }
+
+ /**
+ * Removes an attribute from this request
+ * @param name a String specifying the name of the attribute to remove
+ */
+ public Controller removeAttr(String name) {
+ request.removeAttribute(name);
+ return this;
+ }
+
+ /**
+ * Stores attributes in this request, key of the map as attribute name and value of the map as attribute value
+ * @param attrMap key and value as attribute of the map to be stored
+ */
+ public Controller setAttrs(Map attrMap) {
+ for (Map.Entry entry : attrMap.entrySet())
+ request.setAttribute(entry.getKey(), entry.getValue());
+ return this;
+ }
+
+ /**
+ * Returns the value of a request parameter as a String, or null if the parameter does not exist.
+ *
+ * You should only use this method when you are sure the parameter has only one value. If the
+ * parameter might have more than one value, use getParaValues(java.lang.String).
+ *
+ * If you use this method with a multivalued parameter, the value returned is equal to the first
+ * value in the array returned by getParameterValues.
+ * @param name a String specifying the name of the parameter
+ * @return a String representing the single value of the parameter
+ */
+ public String getPara(String name) {
+ return request.getParameter(name);
+ }
+
+ /**
+ * Returns the value of a request parameter as a String, or default value if the parameter does not exist.
+ * @param name a String specifying the name of the parameter
+ * @param defaultValue a String value be returned when the value of parameter is null
+ * @return a String representing the single value of the parameter
+ */
+ public String getPara(String name, String defaultValue) {
+ String result = request.getParameter(name);
+ return result != null && !"".equals(result) ? result : defaultValue;
+ }
+
+ /**
+ * Returns the values of the request parameters as a Map.
+ * @return a Map contains all the parameters name and value
+ */
+ public Map getParaMap() {
+ return request.getParameterMap();
+ }
+
+ /**
+ * Returns an Enumeration of String objects containing the names of the parameters
+ * contained in this request. If the request has no parameters, the method returns
+ * an empty Enumeration.
+ * @return an Enumeration of String objects, each String containing the name of
+ * a request parameter; or an empty Enumeration if the request has no parameters
+ */
+ public Enumeration getParaNames() {
+ return request.getParameterNames();
+ }
+
+ /**
+ * Returns an array of String objects containing all of the values the given request
+ * parameter has, or null if the parameter does not exist. If the parameter has a
+ * single value, the array has a length of 1.
+ * @param name a String containing the name of the parameter whose value is requested
+ * @return an array of String objects containing the parameter's values
+ */
+ public String[] getParaValues(String name) {
+ return request.getParameterValues(name);
+ }
+
+ /**
+ * Returns an array of Integer objects containing all of the values the given request
+ * parameter has, or null if the parameter does not exist. If the parameter has a
+ * single value, the array has a length of 1.
+ * @param name a String containing the name of the parameter whose value is requested
+ * @return an array of Integer objects containing the parameter's values
+ */
+ public Integer[] getParaValuesToInt(String name) {
+ String[] values = request.getParameterValues(name);
+ if (values == null)
+ return null;
+ Integer[] result = new Integer[values.length];
+ for (int i=0; i getAttrNames() {
+ return request.getAttributeNames();
+ }
+
+ /**
+ * Returns the value of the named attribute as an Object, or null if no attribute of the given name exists.
+ * @param name a String specifying the name of the attribute
+ * @return an Object containing the value of the attribute, or null if the attribute does not exist
+ */
+ public T getAttr(String name) {
+ return (T)request.getAttribute(name);
+ }
+
+ /**
+ * Returns the value of the named attribute as an Object, or null if no attribute of the given name exists.
+ * @param name a String specifying the name of the attribute
+ * @return an String Object containing the value of the attribute, or null if the attribute does not exist
+ */
+ public String getAttrForStr(String name) {
+ return (String)request.getAttribute(name);
+ }
+
+ /**
+ * Returns the value of the named attribute as an Object, or null if no attribute of the given name exists.
+ * @param name a String specifying the name of the attribute
+ * @return an Integer Object containing the value of the attribute, or null if the attribute does not exist
+ */
+ public Integer getAttrForInt(String name) {
+ return (Integer)request.getAttribute(name);
+ }
+
+ private Integer toInt(String value, Integer defaultValue) {
+ if (value == null || "".equals(value.trim()))
+ return defaultValue;
+ if (value.startsWith("N") || value.startsWith("n"))
+ return -Integer.parseInt(value.substring(1));
+ return Integer.parseInt(value);
+ }
+
+ /**
+ * Returns the value of a request parameter and convert to Integer.
+ * @param name a String specifying the name of the parameter
+ * @return a Integer representing the single value of the parameter
+ */
+ public Integer getParaToInt(String name) {
+ return toInt(request.getParameter(name), null);
+ }
+
+ /**
+ * Returns the value of a request parameter and convert to Integer with a default value if it is null.
+ * @param name a String specifying the name of the parameter
+ * @return a Integer representing the single value of the parameter
+ */
+ public Integer getParaToInt(String name, Integer defaultValue) {
+ return toInt(request.getParameter(name), defaultValue);
+ }
+
+ private Long toLong(String value, Long defaultValue) {
+ if (value == null || "".equals(value.trim()))
+ return defaultValue;
+ if (value.startsWith("N") || value.startsWith("n"))
+ return -Long.parseLong(value.substring(1));
+ return Long.parseLong(value);
+ }
+
+ /**
+ * Returns the value of a request parameter and convert to Long.
+ * @param name a String specifying the name of the parameter
+ * @return a Integer representing the single value of the parameter
+ */
+ public Long getParaToLong(String name) {
+ return toLong(request.getParameter(name), null);
+ }
+
+ /**
+ * Returns the value of a request parameter and convert to Long with a default value if it is null.
+ * @param name a String specifying the name of the parameter
+ * @return a Integer representing the single value of the parameter
+ */
+ public Long getParaToLong(String name, Long defaultValue) {
+ return toLong(request.getParameter(name), defaultValue);
+ }
+
+ private Boolean toBoolean(String value, Boolean defaultValue) {
+ if (value == null || "".equals(value.trim()))
+ return defaultValue;
+ value = value.trim().toLowerCase();
+ if ("1".equals(value) || "true".equals(value))
+ return Boolean.TRUE;
+ else if ("0".equals(value) || "false".equals(value))
+ return Boolean.FALSE;
+ throw new RuntimeException("Can not parse the parameter \"" + value + "\" to boolean value.");
+ }
+
+ /**
+ * Returns the value of a request parameter and convert to Boolean.
+ * @param name a String specifying the name of the parameter
+ * @return true if the value of the parameter is "true" or "1", false if it is "false" or "0", null if parameter is not exists
+ */
+ public Boolean getParaToBoolean(String name) {
+ return toBoolean(request.getParameter(name), null);
+ }
+
+ /**
+ * Returns the value of a request parameter and convert to Boolean with a default value if it is null.
+ * @param name a String specifying the name of the parameter
+ * @return true if the value of the parameter is "true" or "1", false if it is "false" or "0", default value if it is null
+ */
+ public Boolean getParaToBoolean(String name, Boolean defaultValue) {
+ return toBoolean(request.getParameter(name), defaultValue);
+ }
+
+ /**
+ * Get all para from url and convert to Boolean
+ */
+ public Boolean getParaToBoolean() {
+ return toBoolean(getPara(), null);
+ }
+
+ /**
+ * Get para from url and conver to Boolean. The first index is 0
+ */
+ public Boolean getParaToBoolean(int index) {
+ return toBoolean(getPara(index), null);
+ }
+
+ /**
+ * Get para from url and conver to Boolean with default value if it is null.
+ */
+ public Boolean getParaToBoolean(int index, Boolean defaultValue) {
+ return toBoolean(getPara(index), defaultValue);
+ }
+
+ private Date toDate(String value, Date defaultValue) {
+ if (value == null || "".equals(value.trim()))
+ return defaultValue;
+ try {
+ return new java.text.SimpleDateFormat("yyyy-MM-dd").parse(value);
+ } catch (ParseException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Returns the value of a request parameter and convert to Date.
+ * @param name a String specifying the name of the parameter
+ * @return a Date representing the single value of the parameter
+ */
+ public Date getParaToDate(String name) {
+ return toDate(request.getParameter(name), null);
+ }
+
+ /**
+ * Returns the value of a request parameter and convert to Date with a default value if it is null.
+ * @param name a String specifying the name of the parameter
+ * @return a Date representing the single value of the parameter
+ */
+ public Date getParaToDate(String name, Date defaultValue) {
+ return toDate(request.getParameter(name), defaultValue);
+ }
+
+ /**
+ * Get all para from url and convert to Date
+ */
+ public Date getParaToDate() {
+ return toDate(getPara(), null);
+ }
+
+ /**
+ * Return HttpServletRequest. Do not use HttpServletRequest Object in constructor of Controller
+ */
+ public HttpServletRequest getRequest() {
+ return request;
+ }
+
+ /**
+ * Return HttpServletResponse. Do not use HttpServletResponse Object in constructor of Controller
+ */
+ public HttpServletResponse getResponse() {
+ return response;
+ }
+
+ /**
+ * Return HttpSession.
+ */
+ public HttpSession getSession() {
+ return request.getSession();
+ }
+
+ /**
+ * Return HttpSession.
+ * @param create a boolean specifying create HttpSession if it not exists
+ */
+ public HttpSession getSession(boolean create) {
+ return request.getSession(create);
+ }
+
+ /**
+ * Return a Object from session.
+ * @param key a String specifying the key of the Object stored in session
+ */
+ public T getSessionAttr(String key) {
+ HttpSession session = request.getSession(false);
+ return session != null ? (T)session.getAttribute(key) : null;
+ }
+
+ /**
+ * Store Object to session.
+ * @param key a String specifying the key of the Object stored in session
+ * @param value a Object specifying the value stored in session
+ */
+ public Controller setSessionAttr(String key, Object value) {
+ request.getSession().setAttribute(key, value);
+ return this;
+ }
+
+ /**
+ * Remove Object in session.
+ * @param key a String specifying the key of the Object stored in session
+ */
+ public Controller removeSessionAttr(String key) {
+ HttpSession session = request.getSession(false);
+ if (session != null)
+ session.removeAttribute(key);
+ return this;
+ }
+
+ /**
+ * Get cookie value by cookie name.
+ */
+ public String getCookie(String name, String defaultValue) {
+ Cookie cookie = getCookieObject(name);
+ return cookie != null ? cookie.getValue() : defaultValue;
+ }
+
+ /**
+ * Get cookie value by cookie name.
+ */
+ public String getCookie(String name) {
+ return getCookie(name, null);
+ }
+
+ /**
+ * Get cookie value by cookie name and convert to Integer.
+ */
+ public Integer getCookieToInt(String name) {
+ String result = getCookie(name);
+ return result != null ? Integer.parseInt(result) : null;
+ }
+
+ /**
+ * Get cookie value by cookie name and convert to Integer.
+ */
+ public Integer getCookieToInt(String name, Integer defaultValue) {
+ String result = getCookie(name);
+ return result != null ? Integer.parseInt(result) : defaultValue;
+ }
+
+ /**
+ * Get cookie value by cookie name and convert to Long.
+ */
+ public Long getCookieToLong(String name) {
+ String result = getCookie(name);
+ return result != null ? Long.parseLong(result) : null;
+ }
+
+ /**
+ * Get cookie value by cookie name and convert to Long.
+ */
+ public Long getCookieToLong(String name, Long defaultValue) {
+ String result = getCookie(name);
+ return result != null ? Long.parseLong(result) : defaultValue;
+ }
+
+ /**
+ * Get cookie object by cookie name.
+ */
+ public Cookie getCookieObject(String name) {
+ Cookie[] cookies = request.getCookies();
+ if (cookies != null)
+ for (Cookie cookie : cookies)
+ if (cookie.getName().equals(name))
+ return cookie;
+ return null;
+ }
+
+ /**
+ * Get all cookie objects.
+ */
+ public Cookie[] getCookieObjects() {
+ Cookie[] result = request.getCookies();
+ return result != null ? result : new Cookie[0];
+ }
+
+ /**
+ * Set Cookie to response.
+ */
+ public Controller setCookie(Cookie cookie) {
+ response.addCookie(cookie);
+ return this;
+ }
+
+ /**
+ * Set Cookie to response.
+ * @param name cookie name
+ * @param value cookie value
+ * @param maxAgeInSeconds -1: clear cookie when close browser. 0: clear cookie immediately. n>0 : max age in n seconds.
+ * @param path see Cookie.setPath(String)
+ */
+ public Controller setCookie(String name, String value, int maxAgeInSeconds, String path) {
+ setCookie(name, value, maxAgeInSeconds, path, null);
+ return this;
+ }
+
+ /**
+ * Set Cookie to response.
+ * @param name cookie name
+ * @param value cookie value
+ * @param maxAgeInSeconds -1: clear cookie when close browser. 0: clear cookie immediately. n>0 : max age in n seconds.
+ * @param path see Cookie.setPath(String)
+ * @param domain the domain name within which this cookie is visible; form is according to RFC 2109
+ */
+ public Controller setCookie(String name, String value, int maxAgeInSeconds, String path, String domain) {
+ Cookie cookie = new Cookie(name, value);
+ if (domain != null)
+ cookie.setDomain(domain);
+ cookie.setMaxAge(maxAgeInSeconds);
+ cookie.setPath(path);
+ response.addCookie(cookie);
+ return this;
+ }
+
+ /**
+ * Set Cookie with path = "/".
+ */
+ public Controller setCookie(String name, String value, int maxAgeInSeconds) {
+ setCookie(name, value, maxAgeInSeconds, "/", null);
+ return this;
+ }
+
+ /**
+ * Remove Cookie with path = "/".
+ */
+ public Controller removeCookie(String name) {
+ setCookie(name, null, 0, "/", null);
+ return this;
+ }
+
+ /**
+ * Remove Cookie.
+ */
+ public Controller removeCookie(String name, String path) {
+ setCookie(name, null, 0, path, null);
+ return this;
+ }
+
+ /**
+ * Remove Cookie.
+ */
+ public Controller removeCookie(String name, String path, String domain) {
+ setCookie(name, null, 0, path, domain);
+ return this;
+ }
+
+ // --------
+
+ /**
+ * Get all para with separator char from url
+ */
+ public String getPara() {
+ if ("".equals(urlPara)) // urlPara maybe is "" see ActionMapping.getAction(String)
+ urlPara = null;
+ return urlPara;
+ }
+
+ /**
+ * Get para from url. The index of first url para is 0.
+ */
+ public String getPara(int index) {
+ if (index < 0)
+ return getPara();
+
+ if (urlParaArray == null) {
+ if (urlPara == null || "".equals(urlPara)) // urlPara maybe is "" see ActionMapping.getAction(String)
+ urlParaArray = NULL_URL_PARA_ARRAY;
+ else
+ urlParaArray = urlPara.split(URL_PARA_SEPARATOR);
+
+ for (int i=0; i index ? urlParaArray[index] : null;
+ }
+
+ /**
+ * Get para from url with default value if it is null or "".
+ */
+ public String getPara(int index, String defaultValue) {
+ String result = getPara(index);
+ return result != null && !"".equals(result) ? result : defaultValue;
+ }
+
+ /**
+ * Get para from url and conver to Integer. The first index is 0
+ */
+ public Integer getParaToInt(int index) {
+ return toInt(getPara(index), null);
+ }
+
+ /**
+ * Get para from url and conver to Integer with default value if it is null.
+ */
+ public Integer getParaToInt(int index, Integer defaultValue) {
+ return toInt(getPara(index), defaultValue);
+ }
+
+ /**
+ * Get para from url and conver to Long.
+ */
+ public Long getParaToLong(int index) {
+ return toLong(getPara(index), null);
+ }
+
+ /**
+ * Get para from url and conver to Long with default value if it is null.
+ */
+ public Long getParaToLong(int index, Long defaultValue) {
+ return toLong(getPara(index), defaultValue);
+ }
+
+ /**
+ * Get all para from url and convert to Integer
+ */
+ public Integer getParaToInt() {
+ return toInt(getPara(), null);
+ }
+
+ /**
+ * Get all para from url and convert to Long
+ */
+ public Long getParaToLong() {
+ return toLong(getPara(), null);
+ }
+
+ /**
+ * Get model from http request.
+ */
+ public T getModel(Class modelClass) {
+ return (T)ModelInjector.inject(modelClass, request, false);
+ }
+
+ /**
+ * Get model from http request.
+ */
+ public T getModel(Class modelClass, String modelName) {
+ return (T)ModelInjector.inject(modelClass, modelName, request, false);
+ }
+
+ // TODO public List getModels(Class modelClass, String modelName) {}
+
+ // --------
+
+ /**
+ * Get upload file from multipart request.
+ */
+ public List getFiles(String saveDirectory, Integer maxPostSize, String encoding) {
+ if (request instanceof MultipartRequest == false)
+ request = new MultipartRequest(request, saveDirectory, maxPostSize, encoding);
+ return ((MultipartRequest)request).getFiles();
+ }
+
+ public UploadFile getFile(String parameterName, String saveDirectory, Integer maxPostSize, String encoding) {
+ getFiles(saveDirectory, maxPostSize, encoding);
+ return getFile(parameterName);
+ }
+
+ public List getFiles(String saveDirectory, int maxPostSize) {
+ if (request instanceof MultipartRequest == false)
+ request = new MultipartRequest(request, saveDirectory, maxPostSize);
+ return ((MultipartRequest)request).getFiles();
+ }
+
+ public UploadFile getFile(String parameterName, String saveDirectory, int maxPostSize) {
+ getFiles(saveDirectory, maxPostSize);
+ return getFile(parameterName);
+ }
+
+ public List getFiles(String saveDirectory) {
+ if (request instanceof MultipartRequest == false)
+ request = new MultipartRequest(request, saveDirectory);
+ return ((MultipartRequest)request).getFiles();
+ }
+
+ public UploadFile getFile(String parameterName, String saveDirectory) {
+ getFiles(saveDirectory);
+ return getFile(parameterName);
+ }
+
+ public List getFiles() {
+ if (request instanceof MultipartRequest == false)
+ request = new MultipartRequest(request);
+ return ((MultipartRequest)request).getFiles();
+ }
+
+ public UploadFile getFile() {
+ List uploadFiles = getFiles();
+ return uploadFiles.size() > 0 ? uploadFiles.get(0) : null;
+ }
+
+ public UploadFile getFile(String parameterName) {
+ List uploadFiles = getFiles();
+ for (UploadFile uploadFile : uploadFiles) {
+ if (uploadFile.getParameterName().equals(parameterName)) {
+ return uploadFile;
+ }
+ }
+ return null;
+ }
+
+ // i18n features --------
+ /**
+ * Write Local to cookie
+ */
+ public Controller setLocaleToCookie(Locale locale) {
+ setCookie(I18N_LOCALE, locale.toString(), I18N.getI18nMaxAgeOfCookie());
+ return this;
+ }
+
+ public Controller setLocaleToCookie(Locale locale, int maxAge) {
+ setCookie(I18N_LOCALE, locale.toString(), maxAge);
+ return this;
+ }
+
+ public String getText(String key) {
+ return I18N.getText(key, getLocaleFromCookie());
+ }
+
+ public String getText(String key, String defaultValue) {
+ return I18N.getText(key, defaultValue, getLocaleFromCookie());
+ }
+
+ private Locale getLocaleFromCookie() {
+ Cookie cookie = getCookieObject(I18N_LOCALE);
+ if (cookie != null) {
+ return I18N.localeFromString(cookie.getValue());
+ }
+ else {
+ Locale defaultLocale = I18N.getDefaultLocale();
+ setLocaleToCookie(defaultLocale);
+ return I18N.localeFromString(defaultLocale.toString());
+ }
+ }
+
+ /**
+ * Keep all parameter's value except model value
+ */
+ public Controller keepPara() {
+ Map map = request.getParameterMap();
+ for (Entry e: map.entrySet()) {
+ String[] values = e.getValue();
+ if (values.length == 1)
+ request.setAttribute(e.getKey(), values[0]);
+ else
+ request.setAttribute(e.getKey(), values);
+ }
+ return this;
+ }
+
+ /**
+ * Keep parameter's value names pointed, model value can not be kept
+ */
+ public Controller keepPara(String... names) {
+ for (String name : names) {
+ String[] values = request.getParameterValues(name);
+ if (values != null) {
+ if (values.length == 1)
+ request.setAttribute(name, values[0]);
+ else
+ request.setAttribute(name, values);
+ }
+ }
+ return this;
+ }
+
+ /**
+ * Convert para to special type and keep it
+ */
+ public Controller keepPara(Class type, String name) {
+ String[] values = request.getParameterValues(name);
+ if (values != null) {
+ if (values.length == 1)
+ try {request.setAttribute(name, TypeConverter.convert(type, values[0]));} catch (ParseException e) {}
+ else
+ request.setAttribute(name, values);
+ }
+ return this;
+ }
+
+ public Controller keepPara(Class type, String... names) {
+ if (type == String.class)
+ return keepPara(names);
+
+ if (names != null)
+ for (String name : names)
+ keepPara(type, name);
+ return this;
+ }
+
+ public Controller keepModel(Class modelClass, String modelName) {
+ Object model = ModelInjector.inject(modelClass, modelName, request, true);
+ request.setAttribute(modelName, model);
+ return this;
+ }
+
+ public Controller keepModel(Class modelClass) {
+ String modelName = StrKit.firstCharToLowerCase(modelClass.getSimpleName());
+ keepModel(modelClass, modelName);
+ return this;
+ }
+
+ /**
+ * Create a token.
+ * @param tokenName the token name used in view
+ * @param secondsOfTimeOut the seconds of time out, secondsOfTimeOut >= Const.MIN_SECONDS_OF_TOKEN_TIME_OUT
+ */
+ public void createToken(String tokenName, int secondsOfTimeOut) {
+ com.jfinal.token.TokenManager.createToken(this, tokenName, secondsOfTimeOut);
+ }
+
+ /**
+ * Create a token with default token name and with default seconds of time out.
+ */
+ public void createToken() {
+ createToken(Const.DEFAULT_TOKEN_NAME, Const.DEFAULT_SECONDS_OF_TOKEN_TIME_OUT);
+ }
+
+ /**
+ * Create a token with default seconds of time out.
+ * @param tokenName the token name used in view
+ */
+ public void createToken(String tokenName) {
+ createToken(tokenName, Const.DEFAULT_SECONDS_OF_TOKEN_TIME_OUT);
+ }
+
+ /**
+ * Check token to prevent resubmit.
+ * @param tokenName the token name used in view's form
+ * @return true if token is correct
+ */
+ public boolean validateToken(String tokenName) {
+ return com.jfinal.token.TokenManager.validateToken(this, tokenName);
+ }
+
+ /**
+ * Check token to prevent resubmit with default token key ---> "JFINAL_TOKEN_KEY"
+ * @return true if token is correct
+ */
+ public boolean validateToken() {
+ return validateToken(Const.DEFAULT_TOKEN_NAME);
+ }
+
+ /**
+ * Return true if the para value is blank otherwise return false
+ */
+ public boolean isParaBlank(String paraName) {
+ String value = request.getParameter(paraName);
+ return value == null || value.trim().length() == 0;
+ }
+
+ /**
+ * Return true if the urlPara value is blank otherwise return false
+ */
+ public boolean isParaBlank(int index) {
+ String value = getPara(index);
+ return value == null || value.trim().length() == 0;
+ }
+
+ /**
+ * Return true if the para exists otherwise return false
+ */
+ public boolean isParaExists(String paraName) {
+ return request.getParameterMap().containsKey(paraName);
+ }
+
+ /**
+ * Return true if the urlPara exists otherwise return false
+ */
+ public boolean isParaExists(int index) {
+ return getPara(index) != null;
+ }
+
+ // ----------------
+ // render below ---
+ private static final RenderFactory renderFactory = RenderFactory.me();
+
+ /**
+ * Hold Render object when invoke renderXxx(...)
+ */
+ private Render render;
+
+ public Render getRender() {
+ return render;
+ }
+
+ /**
+ * Render with any Render which extends Render
+ */
+ public void render(Render render) {
+ this.render = render;
+ }
+
+ /**
+ * Render with view use default type Render configured in JFinalConfig
+ */
+ public void render(String view) {
+ render = renderFactory.getRender(view);
+ }
+
+ /**
+ * Render with jsp view
+ */
+ public void renderJsp(String view) {
+ render = renderFactory.getJspRender(view);
+ }
+
+ /**
+ * Render with freemarker view
+ */
+ public void renderFreeMarker(String view) {
+ render = renderFactory.getFreeMarkerRender(view);
+ }
+
+ /**
+ * Render with velocity view
+ */
+ public void renderVelocity(String view) {
+ render = renderFactory.getVelocityRender(view);
+ }
+
+ /**
+ * Render with json
+ *
+ * Example: renderJson(new User().set("name", "JFinal").set("age", 18));
+ */
+ public void renderJson(Object object) {
+ render = renderFactory.getJsonRender(object);
+ }
+
+ /**
+ * Render with text. The contentType is: "text/plain".
+ */
+ public void renderText(String text) {
+ render = renderFactory.getTextRender(text);
+ }
+
+ /**
+ * Render with text and content type.
+ *
+ * Example: renderText("James", "application/xml");
+ */
+ public void renderText(String text, String contentType) {
+ render = renderFactory.getTextRender(text, contentType);
+ }
+
+ /**
+ * Forward to an action
+ */
+ public void forwardAction(String actionUrl) {
+ render = new ActionRender(actionUrl);
+ }
+
+ /**
+ * Render with file
+ */
+ public void renderFile(String fileName) {
+ render = renderFactory.getFileRender(fileName);
+ }
+
+ /**
+ * Render with file
+ */
+ public void renderFile(File file) {
+ render = renderFactory.getFileRender(file);
+ }
+
+ /**
+ * Redirect to url
+ */
+ public void redirect(String url) {
+ render = renderFactory.getRedirectRender(url);
+ }
+
+ /**
+ * Redirect to url
+ */
+ public void redirect(String url, boolean withQueryString) {
+ render = renderFactory.getRedirectRender(url, withQueryString);
+ }
+
+ /**
+ * Render with view and status use default type Render configured in JFinalConfig
+ */
+ public void render(String view, int status) {
+ render = renderFactory.getRender(view);
+ response.setStatus(status);
+ }
+
+ /**
+ * Render with url and 301 status
+ */
+ public void redirect301(String url) {
+ render = renderFactory.getRedirect301Render(url);
+ }
+
+ /**
+ * Render with url and 301 status
+ */
+ public void redirect301(String url, boolean withQueryString) {
+ render = renderFactory.getRedirect301Render(url, withQueryString);
+ }
+
+ /**
+ * Render with view and errorCode status
+ */
+ public void renderError(int errorCode, String view) {
+ throw new ActionException(errorCode, renderFactory.getErrorRender(errorCode, view));
+ }
+
+ /**
+ * Render with render and errorCode status
+ */
+ public void renderError(int errorCode, Render render) {
+ throw new ActionException(errorCode, render);
+ }
+
+ /**
+ * Render with view and errorCode status configured in JFinalConfig
+ */
+ public void renderError(int errorCode) {
+ throw new ActionException(errorCode, renderFactory.getErrorRender(errorCode));
+ }
+
+ /**
+ * Render nothing, no response to browser
+ */
+ public void renderNull() {
+ render = renderFactory.getNullRender();
+ }
+
+ /**
+ * Render with javascript text. The contentType is: "text/javascript".
+ */
+ public void renderJavascript(String javascriptText) {
+ render = renderFactory.getJavascriptRender(javascriptText);
+ }
+
+ /**
+ * Render with html text. The contentType is: "text/html".
+ */
+ public void renderHtml(String htmlText) {
+ render = renderFactory.getHtmlRender(htmlText);
+ }
+}
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/com/jfinal/core/InterceptorBuilder.java b/src/com/jfinal/core/InterceptorBuilder.java
new file mode 100644
index 000000000..56c19d73c
--- /dev/null
+++ b/src/com/jfinal/core/InterceptorBuilder.java
@@ -0,0 +1,130 @@
+/**
+ * Copyright (c) 2011-2014, James Zhan 詹波 (jfinal@126.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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.jfinal.core;
+
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.Map;
+import com.jfinal.aop.Before;
+import com.jfinal.aop.ClearInterceptor;
+import com.jfinal.aop.ClearLayer;
+import com.jfinal.aop.Interceptor;
+
+/**
+ * InterceptorBuilder
+ */
+class InterceptorBuilder {
+
+ private static final Interceptor[] NULL_INTERCEPTOR_ARRAY = new Interceptor[0];
+
+ @SuppressWarnings("unchecked")
+ void addToInterceptorsMap(Interceptor[] defaultInters) {
+ for (Interceptor inter : defaultInters)
+ intersMap.put((Class)inter.getClass(), inter);
+ }
+
+ /**
+ * Build interceptors of Controller
+ */
+ Interceptor[] buildControllerInterceptors(Class extends Controller> controllerClass) {
+ Before before = controllerClass.getAnnotation(Before.class);
+ return before != null ? createInterceptors(before) : NULL_INTERCEPTOR_ARRAY;
+ }
+
+ /**
+ * Build interceptors of Method
+ */
+ Interceptor[] buildMethodInterceptors(Method method) {
+ Before before = method.getAnnotation(Before.class);
+ return before != null ? createInterceptors(before) : NULL_INTERCEPTOR_ARRAY;
+ }
+
+ /**
+ * Build interceptors of Action
+ */
+ Interceptor[] buildActionInterceptors(Interceptor[] defaultInters, Interceptor[] controllerInters, Class extends Controller> controllerClass, Interceptor[] methodInters, Method method) {
+ ClearLayer controllerClearType = getControllerClearType(controllerClass);
+ if (controllerClearType != null) {
+ defaultInters = NULL_INTERCEPTOR_ARRAY;
+ }
+
+ ClearLayer methodClearType = getMethodClearType(method);
+ if (methodClearType != null) {
+ controllerInters = NULL_INTERCEPTOR_ARRAY;
+ if (methodClearType == ClearLayer.ALL) {
+ defaultInters = NULL_INTERCEPTOR_ARRAY;
+ }
+ }
+
+ int size = defaultInters.length + controllerInters.length + methodInters.length;
+ Interceptor[] result = (size == 0 ? NULL_INTERCEPTOR_ARRAY : new Interceptor[size]);
+
+ int index = 0;
+ for (int i=0; i controllerClass) {
+ ClearInterceptor clearInterceptor = controllerClass.getAnnotation(ClearInterceptor.class);
+ return clearInterceptor != null ? clearInterceptor.value() : null ;
+ }
+
+ private Map, Interceptor> intersMap = new HashMap, Interceptor>();
+
+ /**
+ * Create interceptors with Annotation of Before. Singleton version.
+ */
+ private Interceptor[] createInterceptors(Before beforeAnnotation) {
+ Interceptor[] result = null;
+ @SuppressWarnings("unchecked")
+ Class[] interceptorClasses = (Class[]) beforeAnnotation.value();
+ if (interceptorClasses != null && interceptorClasses.length > 0) {
+ result = new Interceptor[interceptorClasses.length];
+ for (int i=0; i plugins = Config.getPlugins().getPluginList();
- if (plugins != null) {
- for (int i=plugins.size()-1; i >= 0; i--) { // stop plugins
- boolean success = false;
- try {
- success = plugins.get(i).stop();
- }
- catch (Exception e) {
- success = false;
- LogKit.error(e.getMessage(), e);
- }
- if (!success) {
- System.err.println("Plugin stop error: " + plugins.get(i).getClass().getName());
- }
- }
- }
- }
-
- Handler getHandler() {
- return handler;
- }
-
- public Constants getConstants() {
- return Config.getConstants();
- }
-
- public String getContextPath() {
- return contextPath;
- }
-
- public ServletContext getServletContext() {
- return this.servletContext;
- }
-
- public Action getAction(String url, String[] urlPara) {
- return actionMapping.getAction(url, urlPara);
- }
-
- public List getAllActionKeys() {
- return actionMapping.getAllActionKeys();
- }
-
- public static void start() {
- server = com.jfinal.server.jetty.ServerFactory.getServer();
- server.start();
- }
-
- /**
- * 用于在 Eclipse 中,通过创建 main 方法的方式启动项目,支持热加载
- */
- public static void start(String webAppDir, int port, String context, int scanIntervalSeconds) {
- server = com.jfinal.server.jetty.ServerFactory.getServer(webAppDir, port, context, scanIntervalSeconds);
- server.start();
- }
-
- /**
- * jfinal 3.5 更新(2018-09-01):
- * 由于 jfinal 3.5 解决了 IDEA 下 JFinal.start(四个参数) 无法启动的问题,
- * 此方法已被废弃,建议使用 JFinal.start(四个参数) 带四个参数的 start()
- * 方法来启动项目,IDEA 下也支持热加载,注意要先配置自动编译,jfinal 是
- * 通过监测被编译的 class 文件的修改来触发热加载的
- *
- *
- *
- * 用于在 IDEA 中,通过创建 main 方法的方式启动项目,不支持热加载
- * 本方法存在的意义在于此方法启动的速度比 maven 下的 jetty 插件要快得多
- *
- * 注意:不支持热加载。建议通过 Ctrl + F5 快捷键,来快速重新启动项目,速度并不会比 eclipse 下的热加载慢多少
- * 实际操作中是先通过按 Alt + 5 打开 debug 窗口,才能按 Ctrl + F5 重启项目
- */
- @Deprecated
- public static void start(String webAppDir, int port, String context) {
- // server = new JettyServerForIDEA(webAppDir, port, context);
- // server.start();
- start(webAppDir, port, context, 0);
- }
-
- public static void stop() {
- server.stop();
- }
-
- /**
- * Run JFinal Server with Debug Configurations or Run Configurations in Eclipse or IDEA
- * Example for Eclipse: src/main/webapp 80 / 5
- * Example for IDEA: src/main/webapp 80 /
- */
- public static void main(String[] args) {
- if (args == null || args.length == 0) {
- server = com.jfinal.server.jetty.ServerFactory.getServer();
- server.start();
- return ;
- }
-
- // for Eclipse
- if (args.length == 4) {
- String webAppDir = args[0];
- int port = Integer.parseInt(args[1]);
- String context = args[2];
- int scanIntervalSeconds = Integer.parseInt(args[3]);
- server = com.jfinal.server.jetty.ServerFactory.getServer(webAppDir, port, context, scanIntervalSeconds);
- server.start();
- return ;
- }
-
- // for IDEA
- if (args.length == 3) {
- start(args[0], Integer.parseInt(args[1]), args[2]);
- return ;
- }
-
- throw new RuntimeException("Boot parameter error. The right parameter like this: src/main/webapp 80 / 5");
- }
-}
-
-
-
-
-
-
-
-
-
-
+/**
+ * Copyright (c) 2011-2014, James Zhan 詹波 (jfinal@126.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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.jfinal.core;
+
+import java.io.File;
+import java.util.List;
+import javax.servlet.ServletContext;
+import com.jfinal.config.Constants;
+import com.jfinal.config.JFinalConfig;
+import com.jfinal.handler.Handler;
+import com.jfinal.handler.HandlerFactory;
+import com.jfinal.i18n.I18N;
+import com.jfinal.kit.PathKit;
+import com.jfinal.plugin.IPlugin;
+import com.jfinal.render.RenderFactory;
+import com.jfinal.server.IServer;
+import com.jfinal.server.ServerFactory;
+import com.jfinal.token.ITokenCache;
+import com.jfinal.token.TokenManager;
+import com.jfinal.upload.OreillyCos;
+
+/**
+ * JFinal
+ */
+public final class JFinal {
+
+ private Constants constants;
+ private ActionMapping actionMapping;
+ private Handler handler;
+ private ServletContext servletContext;
+ private static IServer server;
+ private String contextPath = "";
+
+ Handler getHandler() {
+ return handler;
+ }
+
+ private static final JFinal me = new JFinal();
+
+ private JFinal() {
+ }
+
+ public static JFinal me() {
+ return me;
+ }
+
+ boolean init(JFinalConfig jfinalConfig, ServletContext servletContext) {
+ this.servletContext = servletContext;
+ this.contextPath = servletContext.getContextPath();
+
+ initPathUtil();
+
+ Config.configJFinal(jfinalConfig); // start plugin and init logger factory in this method
+ constants = Config.getConstants();
+
+ initActionMapping();
+ initHandler();
+ initRender();
+ initOreillyCos();
+ initI18n();
+ initTokenManager();
+
+ return true;
+ }
+
+ private void initTokenManager() {
+ ITokenCache tokenCache = constants.getTokenCache();
+ if (tokenCache != null)
+ TokenManager.init(tokenCache);
+ }
+
+ private void initI18n() {
+ String i18nResourceBaseName = constants.getI18nResourceBaseName();
+ if (i18nResourceBaseName != null) {
+ I18N.init(i18nResourceBaseName, constants.getI18nDefaultLocale(), constants.getI18nMaxAgeOfCookie());
+ }
+ }
+
+ private void initHandler() {
+ Handler actionHandler = new ActionHandler(actionMapping, constants);
+ handler = HandlerFactory.getHandler(Config.getHandlers().getHandlerList(), actionHandler);
+ }
+
+ private void initOreillyCos() {
+ Constants ct = constants;
+ if (OreillyCos.isMultipartSupported()) {
+ String uploadedFileSaveDirectory = ct.getUploadedFileSaveDirectory();
+ if (uploadedFileSaveDirectory == null || "".equals(uploadedFileSaveDirectory.trim())) {
+ uploadedFileSaveDirectory = PathKit.getWebRootPath() + File.separator + "upload" + File.separator;
+ ct.setUploadedFileSaveDirectory(uploadedFileSaveDirectory);
+
+ /*File file = new File(uploadedFileSaveDirectory);
+ if (!file.exists())
+ file.mkdirs();*/
+ }
+ OreillyCos.init(uploadedFileSaveDirectory, ct.getMaxPostSize(), ct.getEncoding());
+ }
+ }
+
+ private void initPathUtil() {
+ String path = servletContext.getRealPath("/");
+ PathKit.setWebRootPath(path);
+ }
+
+ private void initRender() {
+ RenderFactory renderFactory = RenderFactory.me();
+ renderFactory.init(constants, servletContext);
+ }
+
+ private void initActionMapping() {
+ actionMapping = new ActionMapping(Config.getRoutes(), Config.getInterceptors());
+ actionMapping.buildActionMapping();
+ }
+
+ void stopPlugins() {
+ List plugins = Config.getPlugins().getPluginList();
+ if (plugins != null) {
+ for (int i=plugins.size()-1; i >= 0; i--) { // stop plugins
+ boolean success = false;
+ try {
+ success = plugins.get(i).stop();
+ }
+ catch (Exception e) {
+ success = false;
+ e.printStackTrace();
+ }
+ if (!success) {
+ System.err.println("Plugin stop error: " + plugins.get(i).getClass().getName());
+ }
+ }
+ }
+ }
+
+ public ServletContext getServletContext() {
+ return this.servletContext;
+ }
+
+ public static void start() {
+ server = ServerFactory.getServer();
+ server.start();
+ }
+
+ public static void start(String webAppDir, int port, String context, int scanIntervalSeconds) {
+ server = ServerFactory.getServer(webAppDir, port, context, scanIntervalSeconds);
+ server.start();
+ }
+
+ public static void stop() {
+ server.stop();
+ }
+
+ /**
+ * Run JFinal Server with Debug Configurations or Run Configurations in Eclipse JavaEE
+ * args example: WebRoot 80 / 5
+ */
+ public static void main(String[] args) {
+ if (args == null || args.length == 0) {
+ server = ServerFactory.getServer();
+ server.start();
+ }
+ else {
+ String webAppDir = args[0];
+ int port = Integer.parseInt(args[1]);
+ String context = args[2];
+ int scanIntervalSeconds = Integer.parseInt(args[3]);
+ server = ServerFactory.getServer(webAppDir, port, context, scanIntervalSeconds);
+ server.start();
+ }
+ }
+
+ public List getAllActionKeys() {
+ return actionMapping.getAllActionKeys();
+ }
+
+ public Constants getConstants() {
+ return Config.getConstants();
+ }
+
+ public Action getAction(String url, String[] urlPara) {
+ return actionMapping.getAction(url, urlPara);
+ }
+
+ public String getContextPath() {
+ return contextPath;
+ }
+}
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/java/com/jfinal/core/JFinalFilter.java b/src/com/jfinal/core/JFinalFilter.java
similarity index 52%
rename from src/main/java/com/jfinal/core/JFinalFilter.java
rename to src/com/jfinal/core/JFinalFilter.java
index d2fd8d4d6..038f03efa 100644
--- a/src/main/java/com/jfinal/core/JFinalFilter.java
+++ b/src/com/jfinal/core/JFinalFilter.java
@@ -1,158 +1,112 @@
-/**
- * Copyright (c) 2011-2023, James Zhan 詹波 (jfinal@126.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
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.jfinal.core;
-
-import java.io.IOException;
-import javax.servlet.Filter;
-import javax.servlet.FilterChain;
-import javax.servlet.FilterConfig;
-import javax.servlet.ServletException;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import com.jfinal.config.Constants;
-import com.jfinal.config.JFinalConfig;
-import com.jfinal.handler.Handler;
-import com.jfinal.log.Log;
-
-/**
- * JFinal framework filter
- */
-public class JFinalFilter implements Filter {
-
- protected JFinalConfig jfinalConfig;
- protected int contextPathLength;
- protected Constants constants;
- protected String encoding;
- protected Handler handler;
- protected static Log log;
-
- protected static final JFinal jfinal = JFinal.me();
-
- public JFinalFilter() {
- this.jfinalConfig = null;
- }
-
- /**
- * 支持 web 项目无需 web.xml 配置文件,便于嵌入式整合 jetty、undertow
- */
- public JFinalFilter(JFinalConfig jfinalConfig) {
- this.jfinalConfig = jfinalConfig;
- }
-
- @SuppressWarnings("deprecation")
- public void init(FilterConfig filterConfig) throws ServletException {
- if (jfinalConfig == null) {
- createJFinalConfig(filterConfig.getInitParameter("configClass"));
- }
-
- jfinal.init(jfinalConfig, filterConfig.getServletContext());
-
- String contextPath = filterConfig.getServletContext().getContextPath();
- contextPathLength = (contextPath == null || "/".equals(contextPath) ? 0 : contextPath.length());
-
- constants = Config.getConstants();
- encoding = constants.getEncoding();
-
- jfinalConfig.onStart();
- jfinalConfig.afterJFinalStart();
-
- handler = jfinal.getHandler(); // 开始接受请求
- }
-
- public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
- HttpServletRequest request = (HttpServletRequest)req;
- HttpServletResponse response = (HttpServletResponse)res;
- request.setCharacterEncoding(encoding);
-
- String target = request.getRequestURI();
- if (contextPathLength != 0) {
- target = target.substring(contextPathLength);
- }
-
- boolean[] isHandled = {false};
- try {
- handler.handle(target, request, response, isHandled);
- }
- catch (Exception e) {
- if (log.isErrorEnabled()) {
- String qs = request.getQueryString();
- log.error(qs == null ? target : target + "?" + qs, e);
- }
- }
-
- if (isHandled[0] == false) {
- // 默认拒绝直接访问 jsp 文件,加固 tomcat、jetty 安全性
- if (constants.getDenyAccessJsp() && isJsp(target)) {
- com.jfinal.kit.HandlerKit.renderError404(request, response, isHandled);
- return ;
- }
-
- chain.doFilter(request, response);
- }
- }
-
- @SuppressWarnings("deprecation")
- public void destroy() {
- handler = null; // 停止接受请求
-
- jfinalConfig.onStop();
- jfinalConfig.beforeJFinalStop();
-
- jfinal.stopPlugins();
- }
-
- protected void createJFinalConfig(String configClass) {
- if (configClass == null) {
- throw new RuntimeException("The configClass parameter of JFinalFilter can not be blank");
- }
-
- try {
- Object temp = Class.forName(configClass).newInstance();
- jfinalConfig = (JFinalConfig)temp;
- } catch (ReflectiveOperationException e) {
- throw new RuntimeException("Can not create instance of class: " + configClass, e);
- }
- }
-
- static void initLog() {
- log = Log.getLog(JFinalFilter.class);
- }
-
- boolean isJsp(String target) {
- int i = target.lastIndexOf('.');
- if (i > -1) {
- int len = target.length();
- i++;
- char c;
- if (i < len && ((c = target.charAt(i++)) == 'j' || c == 'J')) {
- if (i < len && ((c = target.charAt(i++)) == 's' || c == 'S')) {
- if (i < len && ((c = target.charAt(i)) == 'p' || c == 'P')) {
- return true;
- }
- }
- }
- }
- return false;
- }
-}
-
-
-
-
-
+/**
+ * Copyright (c) 2011-2014, James Zhan 詹波 (jfinal@126.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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.jfinal.core;
+
+import java.io.IOException;
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import com.jfinal.config.Constants;
+import com.jfinal.config.JFinalConfig;
+import com.jfinal.handler.Handler;
+import com.jfinal.log.Logger;
+
+/**
+ * JFinal framework filter
+ */
+public final class JFinalFilter implements Filter {
+
+ private Handler handler;
+ private String encoding;
+ private JFinalConfig jfinalConfig;
+ private Constants constants;
+ private static final JFinal jfinal = JFinal.me();
+ private static Logger log;
+ private int contextPathLength;
+
+ public void init(FilterConfig filterConfig) throws ServletException {
+ createJFinalConfig(filterConfig.getInitParameter("configClass"));
+
+ if (jfinal.init(jfinalConfig, filterConfig.getServletContext()) == false)
+ throw new RuntimeException("JFinal init error!");
+
+ handler = jfinal.getHandler();
+ constants = Config.getConstants();
+ encoding = constants.getEncoding();
+ jfinalConfig.afterJFinalStart();
+
+ String contextPath = filterConfig.getServletContext().getContextPath();
+ contextPathLength = (contextPath == null || "/".equals(contextPath) ? 0 : contextPath.length());
+ }
+
+ public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
+ HttpServletRequest request = (HttpServletRequest)req;
+ HttpServletResponse response = (HttpServletResponse)res;
+ request.setCharacterEncoding(encoding);
+
+ String target = request.getRequestURI();
+ if (contextPathLength != 0)
+ target = target.substring(contextPathLength);
+
+ boolean[] isHandled = {false};
+ try {
+ handler.handle(target, request, response, isHandled);
+ }
+ catch (Exception e) {
+ if (log.isErrorEnabled()) {
+ String qs = request.getQueryString();
+ log.error(qs == null ? target : target + "?" + qs, e);
+ }
+ }
+
+ if (isHandled[0] == false)
+ chain.doFilter(request, response);
+ }
+
+ public void destroy() {
+ jfinalConfig.beforeJFinalStop();
+ jfinal.stopPlugins();
+ }
+
+ private void createJFinalConfig(String configClass) {
+ if (configClass == null)
+ throw new RuntimeException("Please set configClass parameter of JFinalFilter in web.xml");
+
+ try {
+ Object temp = Class.forName(configClass).newInstance();
+ 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");
+ } catch (InstantiationException e) {
+ throw new RuntimeException("Can not create instance of class: " + configClass, e);
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException("Can not create instance of class: " + configClass, e);
+ } catch (ClassNotFoundException e) {
+ throw new RuntimeException("Class not found: " + configClass + ". Please config it in web.xml", e);
+ }
+ }
+
+ static void initLogger() {
+ log = Logger.getLogger(JFinalFilter.class);
+ }
+}
diff --git a/src/com/jfinal/core/ModelInjector.java b/src/com/jfinal/core/ModelInjector.java
new file mode 100644
index 000000000..742144662
--- /dev/null
+++ b/src/com/jfinal/core/ModelInjector.java
@@ -0,0 +1,108 @@
+/**
+ * Copyright (c) 2011-2014, James Zhan 詹波 (jfinal@126.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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.jfinal.core;
+
+import java.lang.reflect.Method;
+import java.util.Map;
+import java.util.Map.Entry;
+import javax.servlet.http.HttpServletRequest;
+import com.jfinal.kit.StrKit;
+import com.jfinal.plugin.activerecord.ActiveRecordException;
+import com.jfinal.plugin.activerecord.Model;
+import com.jfinal.plugin.activerecord.Table;
+import com.jfinal.plugin.activerecord.TableMapping;
+
+/**
+ * ModelInjector
+ */
+final class ModelInjector {
+
+ @SuppressWarnings("unchecked")
+ public static T inject(Class> modelClass, HttpServletRequest request, boolean skipConvertError) {
+ String modelName = modelClass.getSimpleName();
+ return (T)inject(modelClass, StrKit.firstCharToLowerCase(modelName), request, skipConvertError);
+ }
+
+ @SuppressWarnings({ "rawtypes", "unchecked" })
+ public static final T inject(Class> modelClass, String modelName, HttpServletRequest request, boolean skipConvertError) {
+ Object model = null;
+ try {
+ model = modelClass.newInstance();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+
+ if (model instanceof Model)
+ injectActiveRecordModel((Model)model, modelName, request, skipConvertError);
+ else
+ injectCommonModel(model, modelName, request, modelClass, skipConvertError);
+
+ return (T)model;
+ }
+
+ private static final void injectCommonModel(Object model, String modelName, HttpServletRequest request, Class> modelClass, boolean skipConvertError) {
+ Method[] methods = modelClass.getMethods();
+ for (Method method : methods) {
+ String methodName = method.getName();
+ if (methodName.startsWith("set") == false) // only setter method
+ continue;
+
+ Class>[] types = method.getParameterTypes();
+ if (types.length != 1) // only one parameter
+ continue;
+
+ String attrName = methodName.substring(3);
+ String value = request.getParameter(modelName + "." + StrKit.firstCharToLowerCase(attrName));
+ if (value != null) {
+ try {
+ method.invoke(model, TypeConverter.convert(types[0], value));
+ } catch (Exception e) {
+ if (skipConvertError == false)
+ throw new RuntimeException(e);
+ }
+ }
+ }
+ }
+
+ @SuppressWarnings("rawtypes")
+ private static final void injectActiveRecordModel(Model> model, String modelName, HttpServletRequest request, boolean skipConvertError) {
+ Table table = TableMapping.me().getTable(model.getClass());
+
+ String modelNameAndDot = modelName + ".";
+
+ Map parasMap = request.getParameterMap();
+ for (Entry e : parasMap.entrySet()) {
+ String paraKey = e.getKey();
+ if (paraKey.startsWith(modelNameAndDot)) {
+ String paraName = paraKey.substring(modelNameAndDot.length());
+ Class colType = table.getColumnType(paraName);
+ if (colType == null)
+ throw new ActiveRecordException("The model attribute " + paraKey + " is not exists.");
+ String[] paraValue = e.getValue();
+ try {
+ // Object value = Converter.convert(colType, paraValue != null ? paraValue[0] : null);
+ Object value = paraValue[0] != null ? TypeConverter.convert(colType, paraValue[0]) : null;
+ model.set(paraName, value);
+ } catch (Exception ex) {
+ if (skipConvertError == false)
+ throw new RuntimeException("Can not convert parameter: " + modelNameAndDot + paraName, ex);
+ }
+ }
+ }
+ }
+}
+
diff --git a/src/com/jfinal/core/TypeConverter.java b/src/com/jfinal/core/TypeConverter.java
new file mode 100644
index 000000000..1e3dae49a
--- /dev/null
+++ b/src/com/jfinal/core/TypeConverter.java
@@ -0,0 +1,129 @@
+/**
+ * Copyright (c) 2011-2014, James Zhan 詹波 (jfinal@126.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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.jfinal.core;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+
+/**
+ * Convert String to other type object.
+ */
+final class TypeConverter {
+
+ private static final int timeStampLen = "2011-01-18 16:18:18".length();
+ private static final String timeStampPattern = "yyyy-MM-dd HH:mm:ss";
+ private static final String datePattern = "yyyy-MM-dd";
+
+ /**
+ * test for all types of mysql
+ *
+ * 表单提交测试结果:
+ * 1: 表单中的域,就算不输入任何内容,也会传过来 "", 也即永远不可能为 null.
+ * 2: 如果输入空格也会提交上来
+ * 3: 需要考 model中的 string属性,在传过来 "" 时是该转成 null还是不该转换,
+ * 我想, 因为用户没有输入那么肯定是 null, 而不该是 ""
+ *
+ * 注意: 1:当clazz参数不为String.class, 且参数s为空串blank的情况,
+ * 此情况下转换结果为 null, 而不应该抛出异常
+ * 2:调用者需要对被转换数据做 null 判断,参见 ModelInjector 的两处调用
+ */
+ public static final Object convert(Class> clazz, String s) throws ParseException {
+ // mysql type: varchar, char, enum, set, text, tinytext, mediumtext, longtext
+ if (clazz == String.class) {
+ return ("".equals(s) ? null : s); // 用户在表单域中没有输入内容时将提交过来 "", 因为没有输入,所以要转成 null.
+ }
+ s = s.trim();
+ if ("".equals(s)) { // 前面的 String跳过以后,所有的空字符串全都转成 null, 这是合理的
+ return null;
+ }
+ // 以上两种情况无需转换,直接返回, 注意, 本方法不接受null为 s 参数(经测试永远不可能传来null, 因为无输入传来的也是"")
+
+ Object result = null;
+ // mysql type: int, integer, tinyint(n) n > 1, smallint, mediumint
+ if (clazz == Integer.class || clazz == int.class) {
+ result = Integer.parseInt(s);
+ }
+ // mysql type: bigint
+ else if (clazz == Long.class || clazz == long.class) {
+ result = Long.parseLong(s);
+ }
+ // 经测试java.util.Data类型不会返回, java.sql.Date, java.sql.Time,java.sql.Timestamp 全部直接继承自 java.util.Data, 所以 getDate可以返回这三类数据
+ else if (clazz == java.util.Date.class) {
+ if (s.length() >= timeStampLen) { // if (x < timeStampLen) 改用 datePattern 转换,更智能
+ // Timestamp format must be yyyy-mm-dd hh:mm:ss[.fffffffff]
+ // result = new java.util.Date(java.sql.Timestamp.valueOf(s).getTime()); // error under jdk 64bit(maybe)
+ result = new SimpleDateFormat(timeStampPattern).parse(s);
+ }
+ else {
+ // result = new java.util.Date(java.sql.Date.valueOf(s).getTime()); // error under jdk 64bit
+ result = new SimpleDateFormat(datePattern).parse(s);
+ }
+ }
+ // mysql type: date, year
+ else if (clazz == java.sql.Date.class) {
+ if (s.length() >= timeStampLen) { // if (x < timeStampLen) 改用 datePattern 转换,更智能
+ // result = new java.sql.Date(java.sql.Timestamp.valueOf(s).getTime()); // error under jdk 64bit(maybe)
+ result = new java.sql.Date(new SimpleDateFormat(timeStampPattern).parse(s).getTime());
+ }
+ else {
+ // result = new java.sql.Date(java.sql.Date.valueOf(s).getTime()); // error under jdk 64bit
+ result = new java.sql.Date(new SimpleDateFormat(datePattern).parse(s).getTime());
+ }
+ }
+ // mysql type: time
+ else if (clazz == java.sql.Time.class) {
+ result = java.sql.Time.valueOf(s);
+ }
+ // mysql type: timestamp, datetime
+ else if (clazz == java.sql.Timestamp.class) {
+ result = java.sql.Timestamp.valueOf(s);
+ }
+ // mysql type: real, double
+ else if (clazz == Double.class) {
+ result = Double.parseDouble(s);
+ }
+ // mysql type: float
+ else if (clazz == Float.class) {
+ result = Float.parseFloat(s);
+ }
+ // mysql type: bit, tinyint(1)
+ else if (clazz == Boolean.class) {
+ result = Boolean.parseBoolean(s) || "1".equals(s);
+ }
+ // mysql type: decimal, numeric
+ else if (clazz == java.math.BigDecimal.class) {
+ result = new java.math.BigDecimal(s);
+ }
+ // mysql type: unsigned bigint
+ else if (clazz == java.math.BigInteger.class) {
+ result = new java.math.BigInteger(s);
+ }
+ // mysql type: binary, varbinary, tinyblob, blob, mediumblob, longblob. I have not finished the test.
+ else if (clazz == byte[].class) {
+ result = s.getBytes();
+ }
+ else {
+ if (Config.getConstants().getDevMode())
+ throw new RuntimeException("Please add code in " + TypeConverter.class + ". The type can't be converted: " + clazz.getName());
+ else
+ throw new RuntimeException(clazz.getName() + " can not be converted, please use other type of attributes in your model!");
+ }
+
+ return result;
+ }
+}
+
diff --git a/src/main/java/com/jfinal/ext/handler/ContextPathHandler.java b/src/com/jfinal/ext/handler/ContextPathHandler.java
similarity index 87%
rename from src/main/java/com/jfinal/ext/handler/ContextPathHandler.java
rename to src/com/jfinal/ext/handler/ContextPathHandler.java
index 59a5b4628..75e9188b3 100644
--- a/src/main/java/com/jfinal/ext/handler/ContextPathHandler.java
+++ b/src/com/jfinal/ext/handler/ContextPathHandler.java
@@ -1,50 +1,49 @@
-/**
- * Copyright (c) 2011-2023, James Zhan 詹波 (jfinal@126.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
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.jfinal.ext.handler;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import com.jfinal.handler.Handler;
-import com.jfinal.kit.StrKit;
-
-/**
- * Provide a context path to view if you need.
- *
- * Example:
- * In JFinalFilter: handlers.add(new ContextPathHandler("CONTEXT_PATH"));
- * in freemarker:
- */
-public class ContextPathHandler extends Handler {
-
- private String contextPathName;
-
- public ContextPathHandler() {
- contextPathName = "CONTEXT_PATH";
- }
-
- public ContextPathHandler(String contextPathName) {
- if (StrKit.isBlank(contextPathName)) {
- throw new IllegalArgumentException("contextPathName can not be blank.");
- }
- this.contextPathName = contextPathName;
- }
-
- public void handle(String target, HttpServletRequest request, HttpServletResponse response, boolean[] isHandled) {
- request.setAttribute(contextPathName, request.getContextPath());
- next.handle(target, request, response, isHandled);
- }
-}
+/**
+ * Copyright (c) 2011-2014, James Zhan 詹波 (jfinal@126.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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.jfinal.ext.handler;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import com.jfinal.handler.Handler;
+import com.jfinal.kit.StrKit;
+
+/**
+ * Provide a context path to view if you need.
+ *
+ * Example:
+ * In JFinalFilter: handlers.add(new ContextPathHandler("CONTEXT_PATH"));
+ * in freemarker:
+ */
+public class ContextPathHandler extends Handler {
+
+ private String contextPathName;
+
+ public ContextPathHandler() {
+ contextPathName = "CONTEXT_PATH";
+ }
+
+ public ContextPathHandler(String contextPathName) {
+ if (StrKit.isBlank(contextPathName))
+ throw new IllegalArgumentException("contextPathName can not be blank.");
+ this.contextPathName = contextPathName;
+ }
+
+ public void handle(String target, HttpServletRequest request, HttpServletResponse response, boolean[] isHandled) {
+ request.setAttribute(contextPathName, request.getContextPath());
+ nextHandler.handle(target, request, response, isHandled);
+ }
+}
diff --git a/src/main/java/com/jfinal/ext/handler/FakeStaticHandler.java b/src/com/jfinal/ext/handler/FakeStaticHandler.java
similarity index 75%
rename from src/main/java/com/jfinal/ext/handler/FakeStaticHandler.java
rename to src/com/jfinal/ext/handler/FakeStaticHandler.java
index dc825b315..e7cf8dfa1 100644
--- a/src/main/java/com/jfinal/ext/handler/FakeStaticHandler.java
+++ b/src/com/jfinal/ext/handler/FakeStaticHandler.java
@@ -1,60 +1,47 @@
-/**
- * Copyright (c) 2011-2023, James Zhan 詹波 (jfinal@126.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
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.jfinal.ext.handler;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import com.jfinal.handler.Handler;
-import com.jfinal.kit.HandlerKit;
-import com.jfinal.kit.StrKit;
-
-/**
- * FakeStaticHandler.
- */
-public class FakeStaticHandler extends Handler {
-
- private String viewPostfix;
-
- public FakeStaticHandler() {
- viewPostfix = ".html";
- }
-
- public FakeStaticHandler(String viewPostfix) {
- if (StrKit.isBlank(viewPostfix)) {
- throw new IllegalArgumentException("viewPostfix can not be blank.");
- }
- this.viewPostfix = viewPostfix;
- }
-
- public void handle(String target, HttpServletRequest request, HttpServletResponse response, boolean[] isHandled) {
- if ("/".equals(target)) {
- next.handle(target, request, response, isHandled);
- return;
- }
-
- if (target.indexOf('.') == -1) {
- HandlerKit.renderError404(request, response, isHandled);
- return ;
- }
-
- int index = target.lastIndexOf(viewPostfix);
- if (index != -1) {
- target = target.substring(0, index);
- }
- next.handle(target, request, response, isHandled);
- }
-}
+/**
+ * Copyright (c) 2011-2014, James Zhan 詹波 (jfinal@126.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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.jfinal.ext.handler;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import com.jfinal.handler.Handler;
+import com.jfinal.kit.StrKit;
+
+/**
+ * FakeStaticHandler.
+ */
+public class FakeStaticHandler extends Handler {
+
+ private String viewPostfix;
+
+ public FakeStaticHandler() {
+ viewPostfix = ".html";
+ }
+
+ public FakeStaticHandler(String viewPostfix) {
+ if (StrKit.isBlank(viewPostfix))
+ throw new IllegalArgumentException("viewPostfix can not be blank.");
+ this.viewPostfix = viewPostfix;
+ }
+
+ public void handle(String target, HttpServletRequest request, HttpServletResponse response, boolean[] isHandled) {
+ int index = target.lastIndexOf(viewPostfix);
+ if (index != -1)
+ target = target.substring(0, index);
+ nextHandler.handle(target, request, response, isHandled);
+ }
+}
diff --git a/src/main/java/com/jfinal/ext/handler/RoutesHandler.java b/src/com/jfinal/ext/handler/RoutesHandler.java
similarity index 84%
rename from src/main/java/com/jfinal/ext/handler/RoutesHandler.java
rename to src/com/jfinal/ext/handler/RoutesHandler.java
index d908f9941..de5cdf19f 100644
--- a/src/main/java/com/jfinal/ext/handler/RoutesHandler.java
+++ b/src/com/jfinal/ext/handler/RoutesHandler.java
@@ -1,46 +1,46 @@
-/**
- * Copyright (c) 2011-2023, James Zhan 詹波 (jfinal@126.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
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.jfinal.ext.handler;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import com.jfinal.core.Controller;
-import com.jfinal.handler.Handler;
-
-/**
- * RoutesHandler. Not finish yet.
- *
- * RoutesHandler convert url to route format that Routes can find Controller and Method
- */
-public class RoutesHandler extends Handler {
-
- public void addRoute(String regex, String controllerPath) {
- throw new RuntimeException("Not finished");
- }
-
- public void addRoute(String regex, String controllerPath, String method) {
- throw new RuntimeException("Not finished");
- }
-
- public void addRoute(String regex, Controller controller, String method) {
- throw new RuntimeException("Not finished");
- }
-
- public void handle(String target, HttpServletRequest request, HttpServletResponse response, boolean[] isHandled) {
- throw new RuntimeException("Not finished");
- }
-}
+/**
+ * Copyright (c) 2011-2014, James Zhan 詹波 (jfinal@126.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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.jfinal.ext.handler;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import com.jfinal.core.Controller;
+import com.jfinal.handler.Handler;
+
+/**
+ * RoutesHandler. Not finish yet.
+ *
+ * RoutesHandler convert url to route format that Routes can find Controller and Method
+ */
+public class RoutesHandler extends Handler {
+
+ public void addRoute(String regex, String controllerKey) {
+ throw new RuntimeException("Not finished");
+ }
+
+ public void addRoute(String regex, String controllerKey, String method) {
+ throw new RuntimeException("Not finished");
+ }
+
+ public void addRoute(String regex, Controller controller, String method) {
+ throw new RuntimeException("Not finished");
+ }
+
+ public void handle(String target, HttpServletRequest request, HttpServletResponse response, boolean[] isHandled) {
+ throw new RuntimeException("Not finished");
+ }
+}
diff --git a/src/main/java/com/jfinal/ext/handler/ServerNameRedirect301Handler.java b/src/com/jfinal/ext/handler/ServerNameRedirect301Handler.java
similarity index 89%
rename from src/main/java/com/jfinal/ext/handler/ServerNameRedirect301Handler.java
rename to src/com/jfinal/ext/handler/ServerNameRedirect301Handler.java
index 66eece4fd..aff5d0e6f 100644
--- a/src/main/java/com/jfinal/ext/handler/ServerNameRedirect301Handler.java
+++ b/src/com/jfinal/ext/handler/ServerNameRedirect301Handler.java
@@ -1,111 +1,107 @@
-/**
- * Copyright (c) 2011-2023, James Zhan 詹波 (jfinal@126.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
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.jfinal.ext.handler;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import com.jfinal.handler.Handler;
-
-/**
- * ServerNameRedirect301Handler redirect to new server name with 301 Moved Permanently.
- */
-public class ServerNameRedirect301Handler extends Handler {
-
- private String originalServerName;
- private String targetServerName;
- private int serverNameLength;
-
- /**
- * Example: new ServerNameRedirectHandler("http://abc.com", "http://www.abc.com")
- * @param originalServerName The original server name that you want be redirect
- * @param targetServerName The target server name that redirect to
- */
- public ServerNameRedirect301Handler(String originalServerName, String targetServerName) {
- this.originalServerName = originalServerName;
- this.targetServerName = targetServerName;
-
- format();
- serverNameLength = this.originalServerName.length();
- }
-
- private final void format() {
- if (originalServerName.endsWith("/")) {
- originalServerName = originalServerName.substring(0, originalServerName.length() - 1);
- }
-
- if (targetServerName.endsWith("/")) {
- targetServerName = targetServerName.substring(0, targetServerName.length() - 1);
- }
-
- // 此处没有考虑 https 的情况, 该情况由用户在 new ServerNameRedirectHandler() 时自行解决
- if (originalServerName.indexOf("://") == -1) {
- originalServerName = "http://" + originalServerName;
- }
-
- if (targetServerName.indexOf("://") == -1) {
- targetServerName = "http://" + targetServerName;
- }
- }
-
- @Override
- public void handle(String target, HttpServletRequest request, HttpServletResponse response, boolean[] isHandled) {
- String url = request.getRequestURL().toString();
- if (url.startsWith(originalServerName)) {
- isHandled[0] = true;
-
- String queryString = request.getQueryString();
- queryString = (queryString == null ? "" : "?" + queryString);
- url = targetServerName + url.substring(serverNameLength) + queryString;
-
- response.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY);
- // response.sendRedirect(url); // always 302
- response.setHeader("Location", url);
- response.setHeader("Connection", "close");
- }
- else {
- next.handle(target, request, response, isHandled);
- }
- }
-}
-
-
-
-
-/*
-
-http://souwangxiao.com redirect 301 to http://www.souwangxiao.com
-
-<%@ page language="java" pageEncoding="utf-8"%>
-<%@taglib prefix="s" uri="/struts-tags"%>
-<%
-if(request.getRequestURL().indexOf("http://souwangxiao.com") >= 0) {
- // String requestURI = request.getRequestURI();
- // String queryString = request.getQueryString();
- // queryString = (queryString == null ? "" : "?" + queryString);
- //attempt to merge non-www urls
- response.setStatus(301); // 301 rewrite
- // response.setHeader("Location", "http://www.souwangxiao.com" + requestURI + queryString);
- response.setHeader("Location", "http://www.souwangxiao.com");
- response.setHeader("Connection", "close");
-}
-else {%>
-
-<%}%>
-
-*/
-
-
+/**
+ * Copyright (c) 2011-2014, James Zhan 詹波 (jfinal@126.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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.jfinal.ext.handler;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import com.jfinal.handler.Handler;
+
+/**
+ * ServerNameRedirect301Handler redirect to new server name with 301 Moved Permanently.
+ */
+public class ServerNameRedirect301Handler extends Handler {
+
+ private String originalServerName;
+ private String targetServerName;
+ private int serverNameLength;
+
+ /**
+ * Example: new ServerNameRedirectHandler("http://abc.com", "http://www.abc.com")
+ * @param originalServerName The original server name that you want be redirect
+ * @param targetServerName The target server name that redirect to
+ */
+ public ServerNameRedirect301Handler(String originalServerName, String targetServerName) {
+ this.originalServerName = originalServerName;
+ this.targetServerName = targetServerName;
+
+ format();
+ serverNameLength = this.originalServerName.length();
+ }
+
+ private final void format() {
+ if (originalServerName.endsWith("/"))
+ originalServerName = originalServerName.substring(0, originalServerName.length() - 1);
+
+ if (targetServerName.endsWith("/"))
+ targetServerName = targetServerName.substring(0, targetServerName.length() - 1);
+
+ // 此处没有考虑 https 的情况, 该情况由用户在 new ServerNameRedirectHandler() 时自行解决
+ if (originalServerName.indexOf("://") == -1)
+ originalServerName = "http://" + originalServerName;
+
+ if (targetServerName.indexOf("://") == -1)
+ targetServerName = "http://" + targetServerName;
+ }
+
+ @Override
+ public void handle(String target, HttpServletRequest request, HttpServletResponse response, boolean[] isHandled) {
+ String url = request.getRequestURL().toString();
+ if (url.startsWith(originalServerName)) {
+ isHandled[0] = true;
+
+ String queryString = request.getQueryString();
+ queryString = (queryString == null ? "" : "?" + queryString);
+ url = targetServerName + url.substring(serverNameLength) + queryString;
+
+ response.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY);
+ // response.sendRedirect(url); // always 302
+ response.setHeader("Location", url);
+ response.setHeader("Connection", "close");
+ }
+ else {
+ nextHandler.handle(target, request, response, isHandled);
+ }
+ }
+}
+
+
+
+
+/*
+
+http://souwangxiao.com redirect 301 to http://www.souwangxiao.com
+
+<%@ page language="java" pageEncoding="utf-8"%>
+<%@taglib prefix="s" uri="/struts-tags"%>
+<%
+if(request.getRequestURL().indexOf("http://souwangxiao.com") >= 0) {
+ // String requestURI = request.getRequestURI();
+ // String queryString = request.getQueryString();
+ // queryString = (queryString == null ? "" : "?" + queryString);
+ //attempt to merge non-www urls
+ response.setStatus(301); // 301 rewrite
+ // response.setHeader("Location", "http://www.souwangxiao.com" + requestURI + queryString);
+ response.setHeader("Location", "http://www.souwangxiao.com");
+ response.setHeader("Connection", "close");
+}
+else {%>
+
+<%}%>
+
+*/
+
+
diff --git a/src/main/java/com/jfinal/ext/handler/UrlSkipHandler.java b/src/com/jfinal/ext/handler/UrlSkipHandler.java
similarity index 84%
rename from src/main/java/com/jfinal/ext/handler/UrlSkipHandler.java
rename to src/com/jfinal/ext/handler/UrlSkipHandler.java
index a8c71990d..5a711d007 100644
--- a/src/main/java/com/jfinal/ext/handler/UrlSkipHandler.java
+++ b/src/com/jfinal/ext/handler/UrlSkipHandler.java
@@ -1,51 +1,49 @@
-/**
- * Copyright (c) 2011-2023, James Zhan 詹波 (jfinal@126.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
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.jfinal.ext.handler;
-
-import java.util.regex.Pattern;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import com.jfinal.handler.Handler;
-import com.jfinal.kit.StrKit;
-
-/**
- * Skip the excluded url request from browser.
- * The skiped url will be handled by next Filter after JFinalFilter
- *
- * Example: me.add(new UrlSkipHandler(".+\\.\\w{1,4}", false));
- */
-public class UrlSkipHandler extends Handler {
-
- private Pattern skipedUrlPattern;
-
- public UrlSkipHandler(String skipedUrlRegx, boolean isCaseSensitive) {
- if (StrKit.isBlank(skipedUrlRegx)) {
- throw new IllegalArgumentException("The para excludedUrlRegx can not be blank.");
- }
- skipedUrlPattern = isCaseSensitive ? Pattern.compile(skipedUrlRegx) : Pattern.compile(skipedUrlRegx, Pattern.CASE_INSENSITIVE);
- }
-
- public void handle(String target, HttpServletRequest request, HttpServletResponse response, boolean[] isHandled) {
- if (skipedUrlPattern.matcher(target).matches()) {
- return ;
- } else {
- next.handle(target, request, response, isHandled);
- }
- }
-}
-
-
+/**
+ * Copyright (c) 2011-2014, James Zhan 詹波 (jfinal@126.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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.jfinal.ext.handler;
+
+import java.util.regex.Pattern;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import com.jfinal.handler.Handler;
+import com.jfinal.kit.StrKit;
+
+/**
+ * Skip the excluded url request from browser.
+ * The skiped url will be handled by next Filter after JFinalFilter
+ *
+ * Example: me.add(new UrlSkipHandler(".+\\.\\w{1,4}", false));
+ */
+public class UrlSkipHandler extends Handler {
+
+ private Pattern skipedUrlPattern;
+
+ public UrlSkipHandler(String skipedUrlRegx, boolean isCaseSensitive) {
+ if (StrKit.isBlank(skipedUrlRegx))
+ throw new IllegalArgumentException("The para excludedUrlRegx can not be blank.");
+ skipedUrlPattern = isCaseSensitive ? Pattern.compile(skipedUrlRegx) : Pattern.compile(skipedUrlRegx, Pattern.CASE_INSENSITIVE);
+ }
+
+ public void handle(String target, HttpServletRequest request, HttpServletResponse response, boolean[] isHandled) {
+ if (skipedUrlPattern.matcher(target).matches())
+ return ;
+ else
+ nextHandler.handle(target, request, response, isHandled);
+ }
+}
+
+
diff --git a/src/main/java/com/jfinal/ext/interceptor/GET.java b/src/com/jfinal/ext/interceptor/GET.java
similarity index 73%
rename from src/main/java/com/jfinal/ext/interceptor/GET.java
rename to src/com/jfinal/ext/interceptor/GET.java
index b447f6f10..09d4e25ad 100644
--- a/src/main/java/com/jfinal/ext/interceptor/GET.java
+++ b/src/com/jfinal/ext/interceptor/GET.java
@@ -1,35 +1,34 @@
-/**
- * Copyright (c) 2011-2023, James Zhan 詹波 (jfinal@126.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
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.jfinal.ext.interceptor;
-
-import com.jfinal.aop.Interceptor;
-import com.jfinal.aop.Invocation;
-import com.jfinal.core.Controller;
-
-/**
- * Accept GET method only.
- */
-public class GET implements Interceptor {
- public void intercept(Invocation inv) {
- Controller controller = inv.getController();
- if ("GET".equalsIgnoreCase(controller.getRequest().getMethod())) {
- inv.invoke();
- } else {
- controller.renderError(405);
- }
- }
-}
+/**
+ * Copyright (c) 2011-2014, James Zhan 詹波 (jfinal@126.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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.jfinal.ext.interceptor;
+
+import com.jfinal.aop.Interceptor;
+import com.jfinal.core.ActionInvocation;
+import com.jfinal.core.Controller;
+
+/**
+ * Accept GET method only.
+ */
+public class GET implements Interceptor {
+ public void intercept(ActionInvocation ai) {
+ Controller controller = ai.getController();
+ if ("GET".equalsIgnoreCase(controller.getRequest().getMethod()))
+ ai.invoke();
+ else
+ controller.renderError(404);
+ }
+}
diff --git a/src/main/java/com/jfinal/ext/interceptor/LogInterceptor.java b/src/com/jfinal/ext/interceptor/LogInterceptor.java
similarity index 81%
rename from src/main/java/com/jfinal/ext/interceptor/LogInterceptor.java
rename to src/com/jfinal/ext/interceptor/LogInterceptor.java
index 46c5ca4f1..e695650a2 100644
--- a/src/main/java/com/jfinal/ext/interceptor/LogInterceptor.java
+++ b/src/com/jfinal/ext/interceptor/LogInterceptor.java
@@ -1,32 +1,32 @@
-/**
- * Copyright (c) 2011-2023, James Zhan 詹波 (jfinal@126.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
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.jfinal.ext.interceptor;
-
-import com.jfinal.aop.Interceptor;
-import com.jfinal.aop.Invocation;
-
-/**
- * LogInterceptor.
- */
-public class LogInterceptor implements Interceptor {
-
- // private FileWriter fw;
-
- public void intercept(Invocation inv) {
- throw new RuntimeException("Not finished");
- }
-}
+/**
+ * Copyright (c) 2011-2014, James Zhan 詹波 (jfinal@126.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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.jfinal.ext.interceptor;
+
+import com.jfinal.aop.Interceptor;
+import com.jfinal.core.ActionInvocation;
+
+/**
+ * LogInterceptor.
+ */
+public class LogInterceptor implements Interceptor {
+
+ // private FileWriter fw;
+
+ public void intercept(ActionInvocation ai) {
+ throw new RuntimeException("Not finished");
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/jfinal/ext/interceptor/NoUrlPara.java b/src/com/jfinal/ext/interceptor/NoUrlPara.java
similarity index 66%
rename from src/main/java/com/jfinal/ext/interceptor/NoUrlPara.java
rename to src/com/jfinal/ext/interceptor/NoUrlPara.java
index f677dc616..c3a6a2279 100644
--- a/src/main/java/com/jfinal/ext/interceptor/NoUrlPara.java
+++ b/src/com/jfinal/ext/interceptor/NoUrlPara.java
@@ -1,35 +1,34 @@
-/**
- * Copyright (c) 2011-2023, James Zhan 詹波 (jfinal@126.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
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.jfinal.ext.interceptor;
-
-import com.jfinal.aop.Interceptor;
-import com.jfinal.aop.Invocation;
-import com.jfinal.core.Controller;
-
-/**
- * Force action no urlPara, otherwise render error 404.
- */
-public class NoUrlPara implements Interceptor {
- public void intercept(Invocation inv) {
- Controller controller = inv.getController();
- if (controller.getPara() == null) {
- inv.invoke();
- } else {
- controller.renderError(404);
- }
- }
-}
+/**
+ * Copyright (c) 2011-2014, James Zhan 詹波 (jfinal@126.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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.jfinal.ext.interceptor;
+
+import com.jfinal.aop.Interceptor;
+import com.jfinal.core.ActionInvocation;
+import com.jfinal.core.Controller;
+
+/**
+ * Force action no urlPara, otherwise render error 404 to client.
+ */
+public class NoUrlPara implements Interceptor {
+ public void intercept(ActionInvocation invocation) {
+ Controller controller = invocation.getController();
+ if (controller.getPara() == null)
+ invocation.invoke();
+ else
+ controller.renderError(404);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/jfinal/ext/interceptor/POST.java b/src/com/jfinal/ext/interceptor/POST.java
similarity index 73%
rename from src/main/java/com/jfinal/ext/interceptor/POST.java
rename to src/com/jfinal/ext/interceptor/POST.java
index 8c06543ff..6892dee56 100644
--- a/src/main/java/com/jfinal/ext/interceptor/POST.java
+++ b/src/com/jfinal/ext/interceptor/POST.java
@@ -1,35 +1,34 @@
-/**
- * Copyright (c) 2011-2023, James Zhan 詹波 (jfinal@126.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
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.jfinal.ext.interceptor;
-
-import com.jfinal.aop.Interceptor;
-import com.jfinal.aop.Invocation;
-import com.jfinal.core.Controller;
-
-/**
- * Accept POST method only.
- */
-public class POST implements Interceptor {
- public void intercept(Invocation inv) {
- Controller controller = inv.getController();
- if ("POST".equalsIgnoreCase(controller.getRequest().getMethod())) {
- inv.invoke();
- } else {
- controller.renderError(405);
- }
- }
-}
+/**
+ * Copyright (c) 2011-2014, James Zhan 詹波 (jfinal@126.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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.jfinal.ext.interceptor;
+
+import com.jfinal.aop.Interceptor;
+import com.jfinal.core.ActionInvocation;
+import com.jfinal.core.Controller;
+
+/**
+ * Accept POST method only.
+ */
+public class POST implements Interceptor {
+ public void intercept(ActionInvocation ai) {
+ Controller controller = ai.getController();
+ if ("POST".equalsIgnoreCase(controller.getRequest().getMethod().toUpperCase()))
+ ai.invoke();
+ else
+ controller.renderError(404);
+ }
+}
diff --git a/src/main/java/com/jfinal/ext/interceptor/Restful.java b/src/com/jfinal/ext/interceptor/Restful.java
similarity index 76%
rename from src/main/java/com/jfinal/ext/interceptor/Restful.java
rename to src/com/jfinal/ext/interceptor/Restful.java
index dc80b9a0e..3fbba0bae 100644
--- a/src/main/java/com/jfinal/ext/interceptor/Restful.java
+++ b/src/com/jfinal/ext/interceptor/Restful.java
@@ -1,115 +1,115 @@
-/**
- * Copyright (c) 2011-2023, James Zhan 詹波 (jfinal@126.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
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.jfinal.ext.interceptor;
-
-import java.util.HashSet;
-import java.util.Set;
-import com.jfinal.aop.Interceptor;
-import com.jfinal.aop.Invocation;
-import com.jfinal.core.Controller;
-
-/**
- * Invocation 中添加 Method method
- *
- The standard definition is as follows:
- index - GET - A view of all (or a selection of) the records
- show - GET - A view of a single record
- add - GET - A form to post to create
- save - POST - Create a new record
- edit - GET - A form to edit a single record
- update - PUT - Update a record
- delete - DELETE - Delete a record
- *
- * GET /user ---> index
- * GET /user/id ---> show
- * GET /user/add ---> add
- * POST /user ---> save
- * GET /user/edit/id ---> edit
- * PUT /user/id ---> update
- * DELETE /user/id ---> delete
- */
-public class Restful implements Interceptor {
-
- private static final String isRestfulForwardKey = "_isRestfulForward";
- private Set set = new HashSet() {
- private static final long serialVersionUID = 2717581127375143508L;{
- // add edit 与 JFinal 原有规则相同
- add("show");
- add("save");
- add("update");
- add("delete");
- }};
-
- /**
- * add edit 无需处理
- *
- * GET /user ---> index
- * GET /user/id ---> show
- * POST /user ---> save
- * PUT /user/id ---> update
- * DELETE /user/id ---> delete
- */
- public void intercept(Invocation inv) {
- // 阻止 JFinal 原有规则 action 请求
- Controller controller = inv.getController();
- Boolean isRestfulForward = controller.getAttr(isRestfulForwardKey);
- String methodName = inv.getMethodName();
- if (set.contains(methodName) && isRestfulForward== null) {
- inv.getController().renderError(404);
- return ;
- }
-
- if (isRestfulForward != null && isRestfulForward) {
- inv.invoke();
- return ;
- }
-
- String controllerPath = inv.getControllerPath();
- String method = controller.getRequest().getMethod().toUpperCase();
- String urlPara = controller.getPara();
- if ("GET".equals(method)) {
- if (urlPara != null && !"edit".equals(methodName)) {
- controller.setAttr(isRestfulForwardKey, Boolean.TRUE);
- controller.forwardAction(controllerPath + "/show/" + urlPara);
- return ;
- }
- }
- else if ("POST".equals(method)) {
- controller.setAttr(isRestfulForwardKey, Boolean.TRUE);
- controller.forwardAction(controllerPath + "/save");
- return ;
- }
- else if ("PUT".equals(method)) {
- controller.setAttr(isRestfulForwardKey, Boolean.TRUE);
- controller.forwardAction(controllerPath + "/update/" + urlPara);
- return ;
- }
- else if ("DELETE".equals(method)) {
- controller.setAttr(isRestfulForwardKey, Boolean.TRUE);
- controller.forwardAction(controllerPath + "/delete/" + urlPara);
- return ;
- }
-
- inv.invoke();
- }
-}
-
-
-
-
-
-
+/**
+ * Copyright (c) 2011-2014, James Zhan 詹波 (jfinal@126.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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.jfinal.ext.interceptor;
+
+import java.util.HashSet;
+import java.util.Set;
+import com.jfinal.aop.Interceptor;
+import com.jfinal.core.ActionInvocation;
+import com.jfinal.core.Controller;
+
+/**
+ * ActionInvocation 中添加 Method method
+ *
+ The standard definition is as follows:
+ index - GET - A view of all (or a selection of) the records
+ show - GET - A view of a single record
+ add - GET - A form to post to create
+ save - POST - Create a new record
+ edit - GET - A form to edit a single record
+ update - PUT - Update a record
+ delete - DELETE - Delete a record
+ *
+ * GET /user ---> index
+ * GET /user/id ---> show
+ * GET /user/add ---> add
+ * POST /user ---> save
+ * GET /user/edit/id ---> edit
+ * PUT /user/id ---> update
+ * DELETE /user/id ---> delete
+ */
+public class Restful implements Interceptor {
+
+ private static final String isRestfulForwardKey = "_isRestfulForward_";
+ private Set set = new HashSet() {
+ private static final long serialVersionUID = 2717581127375143508L;{
+ // add edit 与 JFinal 原有规则相同
+ add("show");
+ add("save");
+ add("update");
+ add("delete");
+ }};
+
+ /**
+ * add edit 无需处理
+ *
+ * GET /user ---> index
+ * GET /user/id ---> show
+ * POST /user ---> save
+ * PUT /user/id ---> update
+ * DELECT /user/id ---> delete
+ */
+ public void intercept(ActionInvocation ai) {
+ // 阻止 JFinal 原有规则 action 请求
+ Controller controller = ai.getController();
+ Boolean isRestfulForward = controller.getAttr(isRestfulForwardKey);
+ String methodName = ai.getMethodName();
+ if (set.contains(methodName) && isRestfulForward== null) {
+ ai.getController().renderError(404);
+ return ;
+ }
+
+ if (isRestfulForward != null && isRestfulForward) {
+ ai.invoke();
+ return ;
+ }
+
+ String controllerKey = ai.getControllerKey();
+ String method = controller.getRequest().getMethod().toUpperCase();
+ String urlPara = controller.getPara();
+ if ("GET".equals(method)) {
+ if (urlPara != null && !"edit".equals(methodName)) {
+ controller.setAttr(isRestfulForwardKey, Boolean.TRUE);
+ controller.forwardAction(controllerKey + "/show/" + urlPara);
+ return ;
+ }
+ }
+ else if ("POST".equals(method)) {
+ controller.setAttr(isRestfulForwardKey, Boolean.TRUE);
+ controller.forwardAction(controllerKey + "/save");
+ return ;
+ }
+ else if ("PUT".equals(method)) {
+ controller.setAttr(isRestfulForwardKey, Boolean.TRUE);
+ controller.forwardAction(controllerKey + "/update/" + urlPara);
+ return ;
+ }
+ else if ("DELETE".equals(method)) {
+ controller.setAttr(isRestfulForwardKey, Boolean.TRUE);
+ controller.forwardAction(controllerKey + "/delete/" + urlPara);
+ return ;
+ }
+
+ ai.invoke();
+ }
+}
+
+
+
+
+
+
diff --git a/src/com/jfinal/ext/interceptor/SessionInViewInterceptor.java b/src/com/jfinal/ext/interceptor/SessionInViewInterceptor.java
new file mode 100644
index 000000000..daaba2e59
--- /dev/null
+++ b/src/com/jfinal/ext/interceptor/SessionInViewInterceptor.java
@@ -0,0 +1,148 @@
+/**
+ * Copyright (c) 2011-2014, James Zhan 詹波 (jfinal@126.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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.jfinal.ext.interceptor;
+
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+import javax.servlet.ServletContext;
+import javax.servlet.http.HttpSession;
+import com.jfinal.aop.Interceptor;
+import com.jfinal.core.ActionInvocation;
+import com.jfinal.core.Controller;
+
+/**
+ * SessionInViewInterceptor.
+ */
+public class SessionInViewInterceptor implements Interceptor {
+
+ private boolean createSession = false;
+
+ public SessionInViewInterceptor() {
+ }
+
+ public SessionInViewInterceptor(boolean createSession) {
+ this.createSession = createSession;
+ }
+
+ @SuppressWarnings({"rawtypes", "unchecked"})
+ public void intercept(ActionInvocation ai) {
+ ai.invoke();
+
+ Controller c = ai.getController();
+ HttpSession hs = c.getSession(createSession);
+ if (hs != null) {
+ Map session = new JFinalSession(hs);
+ for (Enumeration names=hs.getAttributeNames(); names.hasMoreElements();) {
+ String name = names.nextElement();
+ session.put(name, hs.getAttribute(name));
+ }
+ c.setAttr("session", session);
+ }
+ }
+}
+
+@SuppressWarnings({"rawtypes", "deprecation"})
+class JFinalSession extends HashMap implements HttpSession {
+ private static final long serialVersionUID = -6148316613614087335L;
+ private HttpSession session;
+
+ public JFinalSession(HttpSession session) {
+ this.session = session;
+ }
+
+ public Object getAttribute(String key) {
+ return session.getAttribute(key);
+ }
+
+ @SuppressWarnings("unchecked")
+ public Enumeration getAttributeNames() {
+ return session.getAttributeNames();
+ }
+
+ public long getCreationTime() {
+ return session.getCreationTime();
+ }
+
+ public String getId() {
+ return session.getId();
+ }
+
+ public long getLastAccessedTime() {
+ return session.getLastAccessedTime();
+ }
+
+ public int getMaxInactiveInterval() {
+ return session.getMaxInactiveInterval();
+ }
+
+ public ServletContext getServletContext() {
+ return session.getServletContext();
+ }
+
+ public javax.servlet.http.HttpSessionContext getSessionContext() {
+ return session.getSessionContext();
+ }
+
+ public Object getValue(String key) {
+ return session.getValue(key);
+ }
+
+ public String[] getValueNames() {
+ return session.getValueNames();
+ }
+
+ public void invalidate() {
+ session.invalidate();
+ }
+
+ public boolean isNew() {
+ return session.isNew();
+ }
+
+ public void putValue(String key, Object value) {
+ session.putValue(key, value);
+ }
+
+ public void removeAttribute(String key) {
+ session.removeAttribute(key);
+ }
+
+ public void removeValue(String key) {
+ session.removeValue(key);
+ }
+
+ public void setAttribute(String key, Object value) {
+ session.setAttribute(key, value);
+ }
+
+ public void setMaxInactiveInterval(int maxInactiveInterval) {
+ session.setMaxInactiveInterval(maxInactiveInterval);
+ }
+}
+
+/*
+public void intercept(ActionInvocation ai) {
+ ai.invoke();
+
+ Controller c = ai.getController();
+ HttpSession hs = c.getSession(createSession);
+ if (hs != null) {
+ c.setAttr("session", new JFinalSession(hs));
+ }
+}
+*/
diff --git a/src/com/jfinal/ext/kit/DateKit.java b/src/com/jfinal/ext/kit/DateKit.java
new file mode 100644
index 000000000..32e4d5f00
--- /dev/null
+++ b/src/com/jfinal/ext/kit/DateKit.java
@@ -0,0 +1,53 @@
+/**
+ * Copyright (c) 2011-2014, James Zhan 詹波 (jfinal@126.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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.jfinal.ext.kit;
+
+import java.util.Date;
+import com.jfinal.kit.StrKit;
+
+/**
+ * DateKit.
+ */
+public class DateKit {
+
+ public static String dateFormat = "yyyy-MM-dd";
+ public static String timeFormat = "yyyy-MM-dd HH:mm:ss";
+
+ public static void setDateFromat(String dateFormat) {
+ if (StrKit.isBlank(dateFormat))
+ throw new IllegalArgumentException("dateFormat can not be blank.");
+ DateKit.dateFormat = dateFormat;
+ }
+
+ public static void setTimeFromat(String timeFormat) {
+ if (StrKit.isBlank(timeFormat))
+ throw new IllegalArgumentException("timeFormat can not be blank.");
+ DateKit.timeFormat = timeFormat;
+ }
+
+ public static Date toDate(String dateStr) {
+ throw new RuntimeException("Not finish!!!");
+ }
+
+ public static String toStr(Date date) {
+ return toStr(date, DateKit.dateFormat);
+ }
+
+ public static String toStr(Date date, String format) {
+ throw new RuntimeException("Not finish!!!");
+ }
+}
diff --git a/src/main/java/com/jfinal/ext/kit/SessionIdKit.java b/src/com/jfinal/ext/kit/SessionIdKit.java
similarity index 65%
rename from src/main/java/com/jfinal/ext/kit/SessionIdKit.java
rename to src/com/jfinal/ext/kit/SessionIdKit.java
index e1cf56ef7..54fa3a19d 100644
--- a/src/main/java/com/jfinal/ext/kit/SessionIdKit.java
+++ b/src/com/jfinal/ext/kit/SessionIdKit.java
@@ -1,72 +1,70 @@
-/**
- * Copyright (c) 2011-2023, James Zhan 詹波 (jfinal@126.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
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.jfinal.ext.kit;
-
-import java.security.SecureRandom;
-import java.util.Random;
-import javax.servlet.http.HttpServletRequest;
-
-/**
- * SessionIdKit.
- */
-public class SessionIdKit {
-
- protected static Random random;
- private static boolean weakRandom;
-
- /**
- * Lazy initialization holder class pattern
- */
- private static class FieldHolder {
- static final SessionIdKit sessionIdKit = new SessionIdKit();
- }
-
- private SessionIdKit() {
- try {
- // This operation may block on some systems with low entropy. See
- // this page
- // for workaround suggestions:
- // http://docs.codehaus.org/display/JETTY/Connectors+slow+to+startup
- System.out.println("Init SecureRandom.");
- random = new SecureRandom();
- weakRandom = false;
- } catch (Exception e) {
- System.err.println("Could not generate SecureRandom for session-id randomness");
- random = new Random();
- weakRandom = true;
- }
- }
-
- public static final SessionIdKit me() {
- return FieldHolder.sessionIdKit;
- }
-
- public String generate(HttpServletRequest request) {
- String id = null;
- while (id == null || id.length() == 0) { //)||idInUse(id))
- long r0 = weakRandom ? (hashCode()^Runtime.getRuntime().freeMemory()^random.nextInt()^(((long)request.hashCode())<<32)) : random.nextLong();
- long r1 = random.nextLong();
- if (r0<0) r0 = -r0;
- if (r1<0) r1 = -r1;
- id=Long.toString(r0,36)+Long.toString(r1,36);
- }
- return id;
- }
-}
-
-
-
+/**
+ * Copyright (c) 2011-2014, James Zhan 詹波 (jfinal@126.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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.jfinal.ext.kit;
+
+import java.security.SecureRandom;
+import java.util.Random;
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ * SessionIdKit.
+ */
+public class SessionIdKit {
+
+ protected static Random random;
+ private static boolean weakRandom;
+ private static volatile Object lock = new Object();
+
+ private static final SessionIdKit me = new SessionIdKit();
+
+ private SessionIdKit() {
+ try {
+ // This operation may block on some systems with low entropy. See
+ // this page
+ // for workaround suggestions:
+ // http://docs.codehaus.org/display/JETTY/Connectors+slow+to+startup
+ System.out.println("Init SecureRandom.");
+ random = new SecureRandom();
+ weakRandom = false;
+ } catch (Exception e) {
+ System.err.println("Could not generate SecureRandom for session-id randomness");
+ random = new Random();
+ weakRandom = true;
+ }
+ }
+
+ public static final SessionIdKit me() {
+ return me;
+ }
+
+ public String generate(HttpServletRequest request) {
+ synchronized (lock) {
+ String id = null;
+ while (id == null || id.length() == 0) { //)||idInUse(id))
+ long r0 = weakRandom ? (hashCode()^Runtime.getRuntime().freeMemory()^random.nextInt()^(((long)request.hashCode())<<32)) : random.nextLong();
+ long r1 = random.nextLong();
+ if (r0<0) r0 = -r0;
+ if (r1<0) r1 = -r1;
+ id=Long.toString(r0,36)+Long.toString(r1,36);
+ }
+ return id;
+ }
+ }
+}
+
+
+
diff --git a/src/main/java/com/jfinal/ext/render/CaptchaRender.java b/src/com/jfinal/ext/render/CaptchaRender.java
similarity index 52%
rename from src/main/java/com/jfinal/ext/render/CaptchaRender.java
rename to src/com/jfinal/ext/render/CaptchaRender.java
index c36a18ed2..b12435ad7 100644
--- a/src/main/java/com/jfinal/ext/render/CaptchaRender.java
+++ b/src/com/jfinal/ext/render/CaptchaRender.java
@@ -1,152 +1,167 @@
-/**
- * Copyright (c) 2011-2023, James Zhan 詹波 (jfinal@126.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
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.jfinal.ext.render;
-
-import java.awt.Color;
-import java.awt.Font;
-import java.awt.Graphics;
-import java.awt.image.BufferedImage;
-import java.io.IOException;
-import java.util.concurrent.ThreadLocalRandom;
-import javax.imageio.ImageIO;
-import javax.servlet.ServletOutputStream;
-import javax.servlet.http.Cookie;
-import com.jfinal.core.Controller;
-import com.jfinal.kit.HashKit;
-import com.jfinal.kit.LogKit;
-import com.jfinal.kit.StrKit;
-import com.jfinal.render.Render;
-
-/**
- * CaptchaRender.本验证码实现已被 Deprecated 不建使用.
- * 建议使用新版本的 Controller.renderCaptcha() 既简单又美观,并且还提供了
- * Controller.validateCaptcha(para)与 Validator.validateCaptcha(para)支持
- */
-@Deprecated
-public class CaptchaRender extends Render {
-
- private static final int WIDTH = 80, HEIGHT = 26;
- private static final char[] strArr = "3456789ABCDEFGHJKMNPQRSTUVWXYabcdefghjkmnpqrstuvwxy".toCharArray();
-
- private String captchaName;
-
- public CaptchaRender(String captchaName) {
- if (StrKit.isBlank(captchaName)) {
- throw new IllegalArgumentException("captchaName can not be blank");
- }
- this.captchaName = captchaName;
- }
-
- public void render() {
- BufferedImage image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
- String vCode = drawGraphic(image);
- vCode = vCode.toUpperCase();
- vCode = HashKit.md5(vCode);
- Cookie cookie = new Cookie(captchaName, vCode);
- cookie.setMaxAge(-1);
- cookie.setPath("/");
- // cookie.setHttpOnly(true);
- response.addCookie(cookie);
- response.setHeader("Pragma","no-cache");
- response.setHeader("Cache-Control","no-cache");
- response.setDateHeader("Expires", 0);
- response.setContentType("image/jpeg");
-
- ServletOutputStream sos = null;
- try {
- sos = response.getOutputStream();
- ImageIO.write(image, "jpeg",sos);
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- finally {
- if (sos != null) {
- try {sos.close();} catch (IOException e) {LogKit.logNothing(e);}
- }
- }
- }
-
- private String drawGraphic(BufferedImage image) {
- // 获取图形上下文
- Graphics g = image.createGraphics();
- // 生成随机类
- ThreadLocalRandom random = ThreadLocalRandom.current();
- // 设定背景色
- g.setColor(getRandomColor(200, 250, random));
- g.fillRect(0, 0, WIDTH, HEIGHT);
- // 设定字体
- g.setFont(new Font("Times New Roman", Font.PLAIN, 18));
-
- // 随机产生155条干扰线,使图象中的认证码不易被其它程序探测到
- g.setColor(getRandomColor(160, 200, random));
- for (int i = 0; i < 155; i++) {
- int x = random.nextInt(WIDTH);
- int y = random.nextInt(HEIGHT);
- int xl = random.nextInt(12);
- int yl = random.nextInt(12);
- g.drawLine(x, y, x + xl, y + yl);
- }
-
- // 取随机产生的认证码(4位数字)
- String sRand = "";
- for (int i = 0; i < 4; i++) {
- String rand = String.valueOf(strArr[random.nextInt(strArr.length)]);
- sRand += rand;
- // 将认证码显示到图象中
- g.setColor(new Color(20 + random.nextInt(110), 20 + random.nextInt(110), 20 + random.nextInt(110)));
- // 调用函数出来的颜色相同,可能是因为种子太接近,所以只能直接生成
- g.drawString(rand, 16 * i + 11, 19);
- }
-
- // 图象生效
- g.dispose();
-
- return sRand;
- }
-
- /*
- * 给定范围获得随机颜色
- */
- private Color getRandomColor(int fc, int bc, ThreadLocalRandom random) {
- if (fc > 255) {
- fc = 255;
- }
- if (bc > 255) {
- bc = 255;
- }
- int r = fc + random.nextInt(bc - fc);
- int g = fc + random.nextInt(bc - fc);
- int b = fc + random.nextInt(bc - fc);
- return new Color(r, g, b);
- }
-
- public static boolean validate(Controller controller, String userInputCaptcha, String captchaName) {
- if (StrKit.isBlank(userInputCaptcha)) {
- return false;
- }
-
- userInputCaptcha = userInputCaptcha.toUpperCase();
- userInputCaptcha = HashKit.md5(userInputCaptcha);
- boolean result = userInputCaptcha.equals(controller.getCookie(captchaName));
- if (result) {
- controller.removeCookie(captchaName);
- }
- return result;
- }
-}
-
-
+/**
+ * Copyright (c) 2011-2014, James Zhan 詹波 (jfinal@126.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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.jfinal.ext.render;
+
+import java.awt.Color;
+import java.awt.Font;
+import java.awt.Graphics;
+import java.awt.image.BufferedImage;
+import java.io.IOException;
+import java.security.MessageDigest;
+import java.util.Random;
+import javax.imageio.ImageIO;
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.Cookie;
+import com.jfinal.core.Controller;
+import com.jfinal.kit.StrKit;
+import com.jfinal.render.Render;
+
+public class CaptchaRender extends Render {
+
+ private static final long serialVersionUID = -916701543933591834L;
+ private static final int WIDTH = 85, HEIGHT = 20;
+ private static final String[] strArr = {"3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "M", "N", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y"};
+
+ private String randomCodeKey;
+
+ public CaptchaRender(String randomCodeKey) {
+ if (StrKit.isBlank(randomCodeKey))
+ throw new IllegalArgumentException("randomCodeKey can not be blank");
+ this.randomCodeKey = randomCodeKey;
+ }
+
+ public void render() {
+ BufferedImage image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
+ String vCode = drawGraphic(image);
+ vCode = encrypt(vCode);
+ Cookie cookie = new Cookie(randomCodeKey, vCode);
+ cookie.setMaxAge(-1);
+ cookie.setPath("/");
+ response.addCookie(cookie);
+ response.setHeader("Pragma","no-cache");
+ response.setHeader("Cache-Control","no-cache");
+ response.setDateHeader("Expires", 0);
+ response.setContentType("image/jpeg");
+
+ ServletOutputStream sos = null;
+ try {
+ sos = response.getOutputStream();
+ ImageIO.write(image, "jpeg",sos);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ finally {
+ if (sos != null)
+ try {sos.close();} catch (IOException e) {e.printStackTrace();}
+ }
+ }
+
+ private String drawGraphic(BufferedImage image){
+ // 获取图形上下文
+ Graphics g = image.createGraphics();
+ // 生成随机类
+ Random random = new Random();
+ // 设定背景色
+ g.setColor(getRandColor(200, 250));
+ g.fillRect(0, 0, WIDTH, HEIGHT);
+ // 设定字体
+ g.setFont(new Font("Times New Roman", Font.PLAIN, 18));
+
+ // 随机产生155条干扰线,使图象中的认证码不易被其它程序探测到
+ g.setColor(getRandColor(160, 200));
+ for (int i = 0; i < 155; i++) {
+ int x = random.nextInt(WIDTH);
+ int y = random.nextInt(HEIGHT);
+ int xl = random.nextInt(12);
+ int yl = random.nextInt(12);
+ g.drawLine(x, y, x + xl, y + yl);
+ }
+
+ // 取随机产生的认证码(6位数字)
+ String sRand = "";
+ for (int i = 0; i < 6; i++) {
+ String rand = String.valueOf(strArr[random.nextInt(strArr.length)]);
+ sRand += rand;
+ // 将认证码显示到图象中
+ g.setColor(new Color(20 + random.nextInt(110), 20 + random.nextInt(110), 20 + random.nextInt(110)));
+ // 调用函数出来的颜色相同,可能是因为种子太接近,所以只能直接生成
+ g.drawString(rand, 13 * i + 6, 16);
+ }
+
+ // 图象生效
+ g.dispose();
+
+ return sRand;
+ }
+
+ /*
+ * 给定范围获得随机颜色
+ */
+ private Color getRandColor(int fc, int bc) {
+ Random random = new Random();
+ if (fc > 255)
+ fc = 255;
+ if (bc > 255)
+ bc = 255;
+ int r = fc + random.nextInt(bc - fc);
+ int g = fc + random.nextInt(bc - fc);
+ int b = fc + random.nextInt(bc - fc);
+ return new Color(r, g, b);
+ }
+
+ private static final String encrypt(String srcStr) {
+ try {
+ String result = "";
+ MessageDigest md = MessageDigest.getInstance("MD5");
+ byte[] bytes = md.digest(srcStr.getBytes("utf-8"));
+ for(byte b:bytes){
+ String hex = Integer.toHexString(b&0xFF).toUpperCase();
+ result += ((hex.length() ==1 ) ? "0" : "") + hex;
+ }
+ return result;
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+// public static boolean validate(String inputRandomCode, String rightRandomCode){
+// if (StringKit.isBlank(inputRandomCode))
+// return false;
+// try {
+// inputRandomCode = encrypt(inputRandomCode);
+// return inputRandomCode.equals(rightRandomCode);
+// }catch(Exception e){
+// e.printStackTrace();
+// return false;
+// }
+// }
+
+ // TODO 需要改进
+ public static boolean validate(Controller controller, String inputRandomCode, String randomCodeKey) {
+ if (StrKit.isBlank(inputRandomCode))
+ return false;
+ try {
+ inputRandomCode = encrypt(inputRandomCode);
+ return inputRandomCode.equals(controller.getCookie(randomCodeKey));
+ } catch (Exception e) {
+ e.printStackTrace();
+ return false;
+ }
+ }
+}
+
+
diff --git a/src/main/java/com/jfinal/json/JFinalJsonFactory.java b/src/com/jfinal/ext/render/StaticHtmlRender.java
similarity index 61%
rename from src/main/java/com/jfinal/json/JFinalJsonFactory.java
rename to src/com/jfinal/ext/render/StaticHtmlRender.java
index 04b2be5b3..791f873ad 100644
--- a/src/main/java/com/jfinal/json/JFinalJsonFactory.java
+++ b/src/com/jfinal/ext/render/StaticHtmlRender.java
@@ -1,35 +1,31 @@
-/**
- * Copyright (c) 2011-2023, James Zhan 詹波 (jfinal@126.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
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.jfinal.json;
-
-/**
- * IJsonFactory 的 jfinal 实现.
- */
-public class JFinalJsonFactory implements IJsonFactory {
-
- private static final JFinalJsonFactory me = new JFinalJsonFactory();
-
- public static JFinalJsonFactory me() {
- return me;
- }
-
- public Json getJson() {
- return new JFinalJson();
- }
-}
-
-
+/**
+ * Copyright (c) 2011-2014, James Zhan 詹波 (jfinal@126.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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.jfinal.ext.render;
+
+import com.jfinal.render.Render;
+
+/**
+ * 生成静态 html
+ */
+public class StaticHtmlRender extends Render {
+
+ private static final long serialVersionUID = 1438855188898365097L;
+
+ public void render() {
+ throw new RuntimeException("Not finish!!!");
+ }
+}
diff --git a/src/main/java/com/jfinal/handler/Handler.java b/src/com/jfinal/handler/Handler.java
similarity index 84%
rename from src/main/java/com/jfinal/handler/Handler.java
rename to src/com/jfinal/handler/Handler.java
index 01b6a05c7..6c94f5382 100644
--- a/src/main/java/com/jfinal/handler/Handler.java
+++ b/src/com/jfinal/handler/Handler.java
@@ -1,54 +1,45 @@
-/**
- * Copyright (c) 2011-2023, James Zhan 詹波 (jfinal@126.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
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.jfinal.handler;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-/**
- * Handler.
- *
- * You can config Handler in JFinalConfig.configHandler() method,
- * Handler can do anything under the jfinal action.
- */
-public abstract class Handler {
-
- /**
- * The next handler
- */
- protected Handler next;
-
- /**
- * Use next instead of nextHandler
- */
- @Deprecated
- protected Handler nextHandler;
-
- /**
- * Handle target
- * @param target url target of this web http request
- * @param request HttpServletRequest of this http request
- * @param response HttpServletResponse of this http response
- * @param isHandled JFinalFilter will invoke doFilter() method if isHandled[0] == false,
- * it is usually to tell Filter should handle the static resource.
- */
- public abstract void handle(String target, HttpServletRequest request, HttpServletResponse response, boolean[] isHandled);
-}
-
-
-
-
+/**
+ * Copyright (c) 2011-2014, James Zhan 詹波 (jfinal@126.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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.jfinal.handler;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * Handler.
+ *
+ * You can config Handler in JFinalConfig.configHandler() method,
+ * Handler can do anything under the jfinal action.
+ */
+public abstract class Handler {
+
+ protected Handler nextHandler;
+
+ /**
+ * Handle target
+ * @param target url target of this web http request
+ * @param request HttpServletRequest of this http request
+ * @param response HttpServletRequest of this http request
+ * @param isHandled JFinalFilter will invoke doFilter() method if isHandled[0] == false,
+ * it is usually to tell Filter should handle the static resource.
+ */
+ public abstract void handle(String target, HttpServletRequest request, HttpServletResponse response, boolean[] isHandled);
+}
+
+
+
+
diff --git a/src/main/java/com/jfinal/handler/HandlerFactory.java b/src/com/jfinal/handler/HandlerFactory.java
similarity index 89%
rename from src/main/java/com/jfinal/handler/HandlerFactory.java
rename to src/com/jfinal/handler/HandlerFactory.java
index 6020adeb6..455316040 100644
--- a/src/main/java/com/jfinal/handler/HandlerFactory.java
+++ b/src/com/jfinal/handler/HandlerFactory.java
@@ -1,50 +1,48 @@
-/**
- * Copyright (c) 2011-2023, James Zhan 詹波 (jfinal@126.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
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.jfinal.handler;
-
-import java.util.List;
-
-/**
- * HandlerFactory.
- */
-public class HandlerFactory {
-
- private HandlerFactory() {
-
- }
-
- /**
- * Build handler chain
- */
- @SuppressWarnings("deprecation")
- public static Handler getHandler(List 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;
- }
-}
-
-
-
-
+/**
+ * Copyright (c) 2011-2014, James Zhan 詹波 (jfinal@126.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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.jfinal.handler;
+
+import java.util.List;
+
+/**
+ * HandlerFactory.
+ */
+public class HandlerFactory {
+
+ private HandlerFactory() {
+
+ }
+
+ /**
+ * Build handler chain
+ */
+ public static Handler getHandler(List handlerList, Handler actionHandler) {
+ Handler result = actionHandler;
+
+ for (int i=handlerList.size()-1; i>=0; i--) {
+ Handler temp = handlerList.get(i);
+ temp.nextHandler = result;
+ result = temp;
+ }
+
+ return result;
+ }
+}
+
+
+
+
diff --git a/src/com/jfinal/i18n/I18N.java b/src/com/jfinal/i18n/I18N.java
new file mode 100644
index 000000000..11563ae71
--- /dev/null
+++ b/src/com/jfinal/i18n/I18N.java
@@ -0,0 +1,192 @@
+/**
+ * Copyright (c) 2011-2014, James Zhan 詹波 (jfinal@126.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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.jfinal.i18n;
+
+import java.util.Enumeration;
+import java.util.Locale;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import com.jfinal.core.Const;
+
+/**
+ * I18N support.
+ *
+ * 1: Config parameters in JFinalConfig
+ * 2: Init I18N in JFinal
+ * 3: I18N support text with Locale
+ * 4: Controller use I18N.getText(...) with Local setting in I18nInterceptor
+ * 5: The resource file in WEB-INF/classes
+ *
+ * important: Locale can create with language like new Locale("xxx");
+ *
+ * need test
+ * Using String get Locale was learned from Strus2
+ */
+public class I18N {
+
+ private static String baseName;
+ private static Locale defaultLocale = Locale.getDefault();
+ private static int i18nMaxAgeOfCookie = Const.DEFAULT_I18N_MAX_AGE_OF_COOKIE;
+ private static final NullResourceBundle NULL_RESOURCE_BUNDLE = new NullResourceBundle();
+ private static final ConcurrentMap bundlesMap = new ConcurrentHashMap();
+
+ private static volatile I18N me;
+
+ private I18N() {
+ }
+
+ public static I18N me() {
+ if (me == null)
+ synchronized (I18N.class) {
+ if (me == null)
+ me = new I18N();
+ }
+ return me;
+ }
+
+ public static void init(String baseName, Locale defaultLocale, Integer i18nMaxAgeOfCookie) {
+ I18N.baseName = baseName;
+ if (defaultLocale != null)
+ I18N.defaultLocale = defaultLocale;
+ if (i18nMaxAgeOfCookie != null)
+ I18N.i18nMaxAgeOfCookie = i18nMaxAgeOfCookie;
+ }
+
+ public static Locale getDefaultLocale() {
+ return defaultLocale;
+ }
+
+ final static public int getI18nMaxAgeOfCookie() {
+ return i18nMaxAgeOfCookie;
+ }
+
+ private static ResourceBundle getResourceBundle(Locale locale) {
+ String resourceBundleKey = getresourceBundleKey(locale);
+ ResourceBundle resourceBundle = bundlesMap.get(resourceBundleKey);
+ if (resourceBundle == null) {
+ try {
+ resourceBundle = ResourceBundle.getBundle(baseName, locale);
+ bundlesMap.put(resourceBundleKey, resourceBundle);
+ }
+ catch (MissingResourceException e) {
+ resourceBundle = NULL_RESOURCE_BUNDLE;
+ }
+ }
+ return resourceBundle;
+ }
+
+ /**
+ * 将来只改这里就可以了: resourceBundleKey的生成规则
+ */
+ private static String getresourceBundleKey(Locale locale) {
+ // return baseName + "_" + locale.toString(); // "_" 貌似与无关, 为了提升性能, 故去掉
+ return baseName + locale.toString();
+ }
+
+ public static String getText(String key) {
+ return getResourceBundle(defaultLocale).getString(key);
+ }
+
+ public static String getText(String key, String defaultValue) {
+ String result = getResourceBundle(defaultLocale).getString(key);
+ return result != null ? result : defaultValue;
+ }
+
+ public static String getText(String key, Locale locale) {
+ return getResourceBundle(locale).getString(key);
+ }
+
+ public static String getText(String key, String defaultValue, Locale locale) {
+ String result = getResourceBundle(locale).getString(key);
+ return result != null ? result : defaultValue;
+ }
+
+ // public static Locale localeFromString(String localeStr, Locale defaultLocale) {
+ public static Locale localeFromString(String localeStr) {
+ if ((localeStr == null) || (localeStr.trim().length() == 0) || ("_".equals(localeStr))) {
+ // return (defaultLocale != null) ? defaultLocale : Locale.getDefault(); // 原实现被注掉
+ return defaultLocale;
+ }
+
+ int index = localeStr.indexOf('_');
+ if (index < 0) {
+ return new Locale(localeStr);
+ }
+
+ String language = localeStr.substring(0, index);
+ if (index == localeStr.length()) {
+ return new Locale(language);
+ }
+
+ localeStr = localeStr.substring(index + 1);
+ index = localeStr.indexOf('_');
+ if (index < 0) {
+ return new Locale(language, localeStr);
+ }
+
+ String country = localeStr.substring(0, index);
+ if (index == localeStr.length()) {
+ return new Locale(language, country);
+ }
+
+ localeStr = localeStr.substring(index + 1);
+ return new Locale(language, country, localeStr);
+ }
+
+ private static class NullResourceBundle extends ResourceBundle {
+ public Enumeration getKeys() {
+ return null; // dummy
+ }
+ protected Object handleGetObject(String key) {
+ return null; // dummy
+ }
+ }
+
+ // 可惜的是使用Local可以被 new 出来, 造成了无法判断相等,后来测试,可以使用 equals方法来判断是否相等
+ public static void main(String[] args) {
+ // Locale.getDefault();
+ // Locale en = Locale.US;
+ // Locale us = Locale.US;
+ // System.out.println(l.toString());
+ // System.out.println(en == us);
+ // System.out.println(en.equals(us));
+
+ // 下面的 taiwan.getLanguage()值仍为 zh,所以可以确定i18n实现有缺陷,即 language不能唯一确定Local对象
+ // 造成了无法通过 language不好还原
+ System.out.println(Locale.CHINESE.getLanguage());
+ System.out.println(Locale.CHINA.getLanguage());
+ System.out.println(Locale.SIMPLIFIED_CHINESE.getLanguage());
+ System.out.println(Locale.TRADITIONAL_CHINESE.getLanguage());
+ System.out.println(Locale.TAIWAN.getLanguage());
+
+ Locale shoudong = new Locale("en");
+ System.out.println(shoudong.getLanguage().equals(Locale.US.getLanguage()));
+ System.out.println(shoudong.getLanguage().equals(Locale.ENGLISH.getLanguage()));
+ System.out.println(shoudong.getLanguage().equals(Locale.CANADA.getLanguage()));
+ System.out.println(shoudong.getLanguage().equals(Locale.UK.getLanguage()));
+ System.out.println(shoudong.getLanguage().equals(Locale.CANADA_FRENCH.getLanguage()));
+ }
+}
+
+
+
+
+
+
+
diff --git a/src/main/java/com/jfinal/kit/FileKit.java b/src/com/jfinal/kit/FileKit.java
similarity index 55%
rename from src/main/java/com/jfinal/kit/FileKit.java
rename to src/com/jfinal/kit/FileKit.java
index ccd0f7060..c31249ae6 100644
--- a/src/main/java/com/jfinal/kit/FileKit.java
+++ b/src/com/jfinal/kit/FileKit.java
@@ -1,57 +1,39 @@
-/**
- * Copyright (c) 2011-2023, James Zhan 詹波 (jfinal@126.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
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.jfinal.kit;
-
-import java.io.File;
-
-/**
- * FileKit.
- */
-public class FileKit {
- public static void delete(File file) {
- if (file != null && file.exists()) {
- if (file.isFile()) {
- file.delete();
- }
- else if (file.isDirectory()) {
- File files[] = file.listFiles();
- if (files != null) {
- for (int i=0; i= '\u0000' && ch <= '\u001F') || (ch >= '\u007F' && ch <= '\u009F') || (ch >= '\u2000' && ch <= '\u20FF')) {
+ String str = Integer.toHexString(ch);
+ sb.append("\\u");
+ for(int k=0; k<4-str.length(); k++) {
+ sb.append('0');
+ }
+ sb.append(str.toUpperCase());
+ }
+ else{
+ sb.append(ch);
+ }
+ }
+ }
+ }
+
+ public static String toJson(Object value) {
+ return toJson(value, convertDepth);
+ }
+
+ public static String toJson(Object value, int depth) {
+ if(value == null || (depth--) < 0)
+ return "null";
+
+ if(value instanceof String)
+ return "\"" + escape((String)value) + "\"";
+
+ if(value instanceof Double){
+ if(((Double)value).isInfinite() || ((Double)value).isNaN())
+ return "null";
+ else
+ return value.toString();
+ }
+
+ if(value instanceof Float){
+ if(((Float)value).isInfinite() || ((Float)value).isNaN())
+ return "null";
+ else
+ return value.toString();
+ }
+
+ if(value instanceof Number)
+ return value.toString();
+
+ if(value instanceof Boolean)
+ return value.toString();
+
+ if (value instanceof java.util.Date) {
+ if (value instanceof java.sql.Timestamp)
+ return "\"" + new SimpleDateFormat(timestampPattern).format(value) + "\"";
+ if (value instanceof java.sql.Time)
+ return "\"" + value.toString() + "\"";
+ return "\"" + new SimpleDateFormat(datePattern).format(value) + "\"";
+ }
+
+ if(value instanceof Map) {
+ return mapToJson((Map)value, depth);
+ }
+
+ if(value instanceof List) {
+ return listToJson((List)value, depth);
+ }
+
+ String result = otherToJson(value, depth);
+ if (result != null)
+ return result;
+
+ // 类型无法处理时当作字符串处理,否则ajax调用返回时js无法解析
+ // return value.toString();
+ return "\"" + escape(value.toString()) + "\"";
+ }
+
+ private static String otherToJson(Object value, int depth) {
+ if (value instanceof Character) {
+ return "\"" + escape(value.toString()) + "\"";
+ }
+
+ if (value instanceof Model) {
+ Map map = com.jfinal.plugin.activerecord.CPI.getAttrs((Model)value);
+ return mapToJson(map, depth);
+ }
+ if (value instanceof Record) {
+ Map map = ((Record)value).getColumns();
+ return mapToJson(map, depth);
+ }
+ if (value instanceof Object[]) {
+ Object[] arr = (Object[])value;
+ List list = new ArrayList(arr.length);
+ for (int i=0; i 3) { // Only getter
+ String attrName = methodName.substring(3);
+ if (!attrName.equals("Class")) { // Ignore Object.getClass()
+ Class>[] types = m.getParameterTypes();
+ if (types.length == 0) {
+ try {
+ Object value = m.invoke(model);
+ map.put(StrKit.firstCharToLowerCase(attrName), value);
+ } catch (Exception e) {
+ throw new RuntimeException(e.getMessage(), e);
+ }
+ }
+ }
+ }
+ else {
+ int indexOfIs = methodName.indexOf("is");
+ if (indexOfIs == 0 && methodName.length() > 2) {
+ String attrName = methodName.substring(2);
+ Class>[] types = m.getParameterTypes();
+ if (types.length == 0) {
+ try {
+ Object value = m.invoke(model);
+ map.put(StrKit.firstCharToLowerCase(attrName), value);
+ } catch (Exception e) {
+ throw new RuntimeException(e.getMessage(), e);
+ }
+ }
+ }
+ }
+ }
+ return mapToJson(map, depth);
+ }
+}
+
+
+
+
+
diff --git a/src/com/jfinal/kit/PathKit.java b/src/com/jfinal/kit/PathKit.java
new file mode 100644
index 000000000..62c3b067a
--- /dev/null
+++ b/src/com/jfinal/kit/PathKit.java
@@ -0,0 +1,102 @@
+/**
+ * Copyright (c) 2011-2014, James Zhan 詹波 (jfinal@126.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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.jfinal.kit;
+
+import java.io.File;
+
+/**
+ * new File("..\path\abc.txt") 中的三个方法获取路径的方法
+ * 1: getPath() 获取相对路径,例如 ..\path\abc.txt
+ * 2: getAbslutlyPath() 获取绝对路径,但可能包含 ".." 或 "." 字符,例如 D:\otherPath\..\path\abc.txt
+ * 3: getCanonicalPath() 获取绝对路径,但不包含 ".." 或 "." 字符,例如 D:\path\abc.txt
+ */
+public class PathKit {
+
+ private static String webRootPath;
+ private static String rootClassPath;
+
+ @SuppressWarnings("rawtypes")
+ public static String getPath(Class clazz) {
+ String path = clazz.getResource("").getPath();
+ return new File(path).getAbsolutePath();
+ }
+
+ public static String getPath(Object object) {
+ String path = object.getClass().getResource("").getPath();
+ return new File(path).getAbsolutePath();
+ }
+
+ public static String getRootClassPath() {
+ if (rootClassPath == null) {
+ try {
+ String path = PathKit.class.getClassLoader().getResource("").toURI().getPath();
+ rootClassPath = new File(path).getAbsolutePath();
+ }
+ catch (Exception e) {
+ String path = PathKit.class.getClassLoader().getResource("").getPath();
+ rootClassPath = new File(path).getAbsolutePath();
+ }
+ }
+ return rootClassPath;
+ }
+
+ public static String getPackagePath(Object object) {
+ Package p = object.getClass().getPackage();
+ return p != null ? p.getName().replaceAll("\\.", "/") : "";
+ }
+
+ public static File getFileFromJar(String file) {
+ throw new RuntimeException("Not finish. Do not use this method.");
+ }
+
+ public static String getWebRootPath() {
+ if (webRootPath == null)
+ webRootPath = detectWebRootPath();;
+ return webRootPath;
+ }
+
+ public static void setWebRootPath(String webRootPath) {
+ if (webRootPath == null)
+ return ;
+
+ if (webRootPath.endsWith(File.separator))
+ webRootPath = webRootPath.substring(0, webRootPath.length() - 1);
+ PathKit.webRootPath = webRootPath;
+ }
+
+ private static String detectWebRootPath() {
+ try {
+ String path = PathKit.class.getResource("/").toURI().getPath();
+ return new File(path).getParentFile().getParentFile().getCanonicalPath();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /*
+ private static String detectWebRootPath() {
+ try {
+ String path = PathKit.class.getResource("/").getFile();
+ return new File(path).getParentFile().getParentFile().getCanonicalPath();
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ */
+}
+
+
diff --git a/src/com/jfinal/kit/StrKit.java b/src/com/jfinal/kit/StrKit.java
new file mode 100644
index 000000000..ef6e8d2a6
--- /dev/null
+++ b/src/com/jfinal/kit/StrKit.java
@@ -0,0 +1,79 @@
+/**
+ * Copyright (c) 2011-2014, James Zhan 詹波 (jfinal@126.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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.jfinal.kit;
+
+/**
+ * StrKit.
+ */
+public class StrKit {
+
+ /**
+ * 首字母变小写
+ */
+ public static String firstCharToLowerCase(String str) {
+ Character firstChar = str.charAt(0);
+ String tail = str.substring(1);
+ str = Character.toLowerCase(firstChar) + tail;
+ return str;
+ }
+
+ /**
+ * 首字母变大写
+ */
+ public static String firstCharToUpperCase(String str) {
+ Character firstChar = str.charAt(0);
+ String tail = str.substring(1);
+ str = Character.toUpperCase(firstChar) + tail;
+ return str;
+ }
+
+ /**
+ * 字符串为 null 或者为 "" 时返回 true
+ */
+ public static boolean isBlank(String str) {
+ return str == null || "".equals(str.trim()) ? true : false;
+ }
+
+ /**
+ * 字符串不为 null 而且不为 "" 时返回 true
+ */
+ public static boolean notBlank(String str) {
+ return str == null || "".equals(str.trim()) ? false : true;
+ }
+
+ public static boolean notBlank(String... strings) {
+ if (strings == null)
+ return false;
+ for (String str : strings)
+ if (str == null || "".equals(str.trim()))
+ return false;
+ return true;
+ }
+
+ public static boolean notNull(Object... paras) {
+ if (paras == null)
+ return false;
+ for (Object obj : paras)
+ if (obj == null)
+ return false;
+ return true;
+ }
+}
+
+
+
+
diff --git a/src/main/java/com/jfinal/log/LogInfo.java b/src/com/jfinal/kit/StringKit.java
similarity index 70%
rename from src/main/java/com/jfinal/log/LogInfo.java
rename to src/com/jfinal/kit/StringKit.java
index 53fdb5927..c2bf1d430 100644
--- a/src/main/java/com/jfinal/log/LogInfo.java
+++ b/src/com/jfinal/kit/StringKit.java
@@ -1,26 +1,25 @@
-/**
- * Copyright (c) 2011-2023, James Zhan 詹波 (jfinal@126.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
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.jfinal.log;
-
-/**
- * 可变参数最后一个元素为 Throwable 类型时封装为 LogInfo
- */
-public class LogInfo {
- public String message;
- public Throwable throwable;
-}
-
+/**
+ * Copyright (c) 2011-2014, James Zhan 詹波 (jfinal@126.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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.jfinal.kit;
+
+/**
+ * StringKit. This class is Deprecated, useing StrKit instead of StringKit
+ */
+@Deprecated
+public class StringKit extends StrKit {
+
+}
\ No newline at end of file
diff --git a/src/main/java/com/jfinal/log/ILogFactory.java b/src/com/jfinal/log/ILoggerFactory.java
similarity index 74%
rename from src/main/java/com/jfinal/log/ILogFactory.java
rename to src/com/jfinal/log/ILoggerFactory.java
index 3b0f4fb59..5b480cf29 100644
--- a/src/main/java/com/jfinal/log/ILogFactory.java
+++ b/src/com/jfinal/log/ILoggerFactory.java
@@ -1,27 +1,27 @@
-/**
- * Copyright (c) 2011-2023, James Zhan 詹波 (jfinal@126.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
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.jfinal.log;
-
-/**
- * ILogFactory.
- */
-public interface ILogFactory {
-
- Log getLog(Class> clazz);
-
- Log getLog(String name);
-}
+/**
+ * Copyright (c) 2011-2014, James Zhan 詹波 (jfinal@126.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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.jfinal.log;
+
+/**
+ * ILoggerFactory.
+ */
+public interface ILoggerFactory {
+
+ Logger getLogger(Class> clazz);
+
+ Logger getLogger(String name);
+}
diff --git a/src/main/java/com/jfinal/log/JdkLog.java b/src/com/jfinal/log/JdkLogger.java
similarity index 52%
rename from src/main/java/com/jfinal/log/JdkLog.java
rename to src/com/jfinal/log/JdkLogger.java
index cbb3360bb..5c6def1e9 100644
--- a/src/main/java/com/jfinal/log/JdkLog.java
+++ b/src/com/jfinal/log/JdkLogger.java
@@ -1,200 +1,107 @@
-/**
- * Copyright (c) 2011-2023, James Zhan 詹波 (jfinal@126.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
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.jfinal.log;
-
-import java.util.logging.Level;
-
-/**
- * JdkLog.
- */
-public class JdkLog extends Log {
-
- private java.util.logging.Logger log;
- private String clazzName;
-
- JdkLog(Class> clazz) {
- log = java.util.logging.Logger.getLogger(clazz.getName());
- clazzName = clazz.getName();
- }
-
- JdkLog(String name) {
- log = java.util.logging.Logger.getLogger(name);
- clazzName = name;
- }
-
- public static JdkLog getLog(Class> clazz) {
- return new JdkLog(clazz);
- }
-
- public static JdkLog getLog(String name) {
- return new JdkLog(name);
- }
-
- public void trace(String message) {
- log.logp(Level.FINEST, clazzName, Thread.currentThread().getStackTrace()[1].getMethodName(), message);
- }
-
- public void trace(String message, Throwable t) {
- log.logp(Level.FINEST, clazzName, Thread.currentThread().getStackTrace()[1].getMethodName(), message, t);
- }
-
- public void debug(String message) {
- log.logp(Level.FINE, clazzName, Thread.currentThread().getStackTrace()[1].getMethodName(), message);
- }
-
- public void debug(String message, Throwable t) {
- log.logp(Level.FINE, clazzName, Thread.currentThread().getStackTrace()[1].getMethodName(), message, t);
- }
-
- public void info(String message) {
- log.logp(Level.INFO, clazzName, Thread.currentThread().getStackTrace()[1].getMethodName(), message);
- }
-
- public void info(String message, Throwable t) {
- log.logp(Level.INFO, clazzName, Thread.currentThread().getStackTrace()[1].getMethodName(), message, t);
- }
-
- public void warn(String message) {
- log.logp(Level.WARNING, clazzName, Thread.currentThread().getStackTrace()[1].getMethodName(), message);
- }
-
- public void warn(String message, Throwable t) {
- log.logp(Level.WARNING, clazzName, Thread.currentThread().getStackTrace()[1].getMethodName(), message, t);
- }
-
- public void error(String message) {
- log.logp(Level.SEVERE, clazzName, Thread.currentThread().getStackTrace()[1].getMethodName(), message);
- }
-
- public void error(String message, Throwable t) {
- log.logp(Level.SEVERE, clazzName, Thread.currentThread().getStackTrace()[1].getMethodName(), message, t);
- }
-
- /**
- * JdkLog fatal is the same as the error.
- */
- public void fatal(String message) {
- log.logp(Level.SEVERE, clazzName, Thread.currentThread().getStackTrace()[1].getMethodName(), message);
- }
-
- /**
- * JdkLog fatal is the same as the error.
- */
- public void fatal(String message, Throwable t) {
- log.logp(Level.SEVERE, clazzName, Thread.currentThread().getStackTrace()[1].getMethodName(), message, t);
- }
-
- public boolean isTraceEnabled() {
- return log.isLoggable(Level.FINEST);
- }
-
- public boolean isDebugEnabled() {
- return log.isLoggable(Level.FINE);
- }
-
- public boolean isInfoEnabled() {
- return log.isLoggable(Level.INFO);
- }
-
- public boolean isWarnEnabled() {
- return log.isLoggable(Level.WARNING);
- }
-
- public boolean isErrorEnabled() {
- return log.isLoggable(Level.SEVERE);
- }
-
- public boolean isFatalEnabled() {
- return log.isLoggable(Level.SEVERE);
- }
-
- // -------------------------------------------------------
-
- /*
- * 以下方法与前面的两个 trace 方法必须覆盖父类中的实现,否则日志中的类名为
- * com.jfinal.log.Log 而非所需要的日志发生地点的类名
- */
-
- public void trace(String format, Object... args) {
- if (isTraceEnabled()) {
- if (endsWithThrowable(args)) {
- LogInfo li = parse(format, args);
- trace(li.message, li.throwable);
- } else {
- trace(String.format(format, args));
- }
- }
- }
-
- public void debug(String format, Object... args) {
- if (isDebugEnabled()) {
- if (endsWithThrowable(args)) {
- LogInfo li = parse(format, args);
- debug(li.message, li.throwable);
- } else {
- debug(String.format(format, args));
- }
- }
- }
-
- public void info(String format, Object... args) {
- if (isInfoEnabled()) {
- if (endsWithThrowable(args)) {
- LogInfo li = parse(format, args);
- info(li.message, li.throwable);
- } else {
- info(String.format(format, args));
- }
- }
- }
-
- public void warn(String format, Object... args) {
- if (isWarnEnabled()) {
- if (endsWithThrowable(args)) {
- LogInfo li = parse(format, args);
- warn(li.message, li.throwable);
- } else {
- warn(String.format(format, args));
- }
- }
- }
-
- public void error(String format, Object... args) {
- if (isErrorEnabled()) {
- if (endsWithThrowable(args)) {
- LogInfo li = parse(format, args);
- error(li.message, li.throwable);
- } else {
- error(String.format(format, args));
- }
- }
- }
-
- public void fatal(String format, Object... args) {
- if (isFatalEnabled()) {
- if (endsWithThrowable(args)) {
- LogInfo li = parse(format, args);
- fatal(li.message, li.throwable);
- } else {
- fatal(String.format(format, args));
- }
- }
- }
-}
-
-
-
+/**
+ * Copyright (c) 2011-2014, James Zhan 詹波 (jfinal@126.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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.jfinal.log;
+
+import java.util.logging.Level;
+
+/**
+ * JdkLogger.
+ */
+public class JdkLogger extends Logger {
+
+ private java.util.logging.Logger log;
+ private String clazzName;
+
+ JdkLogger(Class> clazz) {
+ log = java.util.logging.Logger.getLogger(clazz.getName());
+ clazzName = clazz.getName();
+ }
+
+ JdkLogger(String name) {
+ log = java.util.logging.Logger.getLogger(name);
+ clazzName = name;
+ }
+
+ public void debug(String message) {
+ log.logp(Level.FINE, clazzName, Thread.currentThread().getStackTrace()[1].getMethodName(), message);
+ }
+
+ public void debug(String message, Throwable t) {
+ log.logp(Level.FINE, clazzName, Thread.currentThread().getStackTrace()[1].getMethodName(), message, t);
+ }
+
+ public void info(String message) {
+ log.logp(Level.INFO, clazzName, Thread.currentThread().getStackTrace()[1].getMethodName(), message);
+ }
+
+ public void info(String message, Throwable t) {
+ log.logp(Level.INFO, clazzName, Thread.currentThread().getStackTrace()[1].getMethodName(), message, t);
+ }
+
+ public void warn(String message) {
+ log.logp(Level.WARNING, clazzName, Thread.currentThread().getStackTrace()[1].getMethodName(), message);
+ }
+
+ public void warn(String message, Throwable t) {
+ log.logp(Level.WARNING, clazzName, Thread.currentThread().getStackTrace()[1].getMethodName(), message, t);
+ }
+
+ public void error(String message) {
+ log.logp(Level.SEVERE, clazzName, Thread.currentThread().getStackTrace()[1].getMethodName(), message);
+ }
+
+ public void error(String message, Throwable t) {
+ log.logp(Level.SEVERE, clazzName, Thread.currentThread().getStackTrace()[1].getMethodName(), message, t);
+ }
+
+ /**
+ * JdkLogger fatal is the same as the error.
+ */
+ public void fatal(String message) {
+ log.logp(Level.SEVERE, clazzName, Thread.currentThread().getStackTrace()[1].getMethodName(), message);
+ }
+
+ /**
+ * JdkLogger fatal is the same as the error.
+ */
+ public void fatal(String message, Throwable t) {
+ log.logp(Level.SEVERE, clazzName, Thread.currentThread().getStackTrace()[1].getMethodName(), message, t);
+ }
+
+ public boolean isDebugEnabled() {
+ return log.isLoggable(Level.FINE);
+ }
+
+ public boolean isInfoEnabled() {
+ return log.isLoggable(Level.INFO);
+ }
+
+ public boolean isWarnEnabled() {
+ return log.isLoggable(Level.WARNING);
+ }
+
+ public boolean isErrorEnabled() {
+ return log.isLoggable(Level.SEVERE);
+ }
+
+ public boolean isFatalEnabled() {
+ return log.isLoggable(Level.SEVERE);
+ }
+}
+
+
+
diff --git a/src/main/java/com/jfinal/log/JdkLogFactory.java b/src/com/jfinal/log/JdkLoggerFactory.java
similarity index 65%
rename from src/main/java/com/jfinal/log/JdkLogFactory.java
rename to src/com/jfinal/log/JdkLoggerFactory.java
index 906263621..130399c01 100644
--- a/src/main/java/com/jfinal/log/JdkLogFactory.java
+++ b/src/com/jfinal/log/JdkLoggerFactory.java
@@ -1,31 +1,31 @@
-/**
- * Copyright (c) 2011-2023, James Zhan 詹波 (jfinal@126.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
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.jfinal.log;
-
-/**
- * JdkLogFactory.
- */
-public class JdkLogFactory implements ILogFactory {
-
- public Log getLog(Class> clazz) {
- return new JdkLog(clazz);
- }
-
- public Log getLog(String name) {
- return new JdkLog(name);
- }
-}
+/**
+ * Copyright (c) 2011-2014, James Zhan 詹波 (jfinal@126.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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.jfinal.log;
+
+/**
+ * JdkLoggerFactory.
+ */
+public class JdkLoggerFactory implements ILoggerFactory {
+
+ public Logger getLogger(Class> clazz) {
+ return new JdkLogger(clazz);
+ }
+
+ public Logger getLogger(String name) {
+ return new JdkLogger(name);
+ }
+}
diff --git a/src/com/jfinal/log/Log4jLogger.java b/src/com/jfinal/log/Log4jLogger.java
new file mode 100644
index 000000000..2a161fea5
--- /dev/null
+++ b/src/com/jfinal/log/Log4jLogger.java
@@ -0,0 +1,97 @@
+/**
+ * Copyright (c) 2011-2014, James Zhan 詹波 (jfinal@126.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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.jfinal.log;
+
+import org.apache.log4j.Level;
+
+/**
+ * Log4jLogger.
+ */
+public class Log4jLogger extends Logger {
+
+ private org.apache.log4j.Logger log;
+ private static final String callerFQCN = Log4jLogger.class.getName();
+
+ Log4jLogger(Class> clazz) {
+ log = org.apache.log4j.Logger.getLogger(clazz);
+ }
+
+ Log4jLogger(String name) {
+ log = org.apache.log4j.Logger.getLogger(name);
+ }
+
+ public void info(String message) {
+ log.log(callerFQCN, Level.INFO, message, null);
+ }
+
+ public void info(String message, Throwable t) {
+ log.log(callerFQCN, Level.INFO, message, t);
+ }
+
+ public void debug(String message) {
+ log.log(callerFQCN, Level.DEBUG, message, null);
+ }
+
+ public void debug(String message, Throwable t) {
+ log.log(callerFQCN, Level.DEBUG, message, t);
+ }
+
+ public void warn(String message) {
+ log.log(callerFQCN, Level.WARN, message, null);
+ }
+
+ public void warn(String message, Throwable t) {
+ log.log(callerFQCN, Level.WARN, message, t);
+ }
+
+ public void error(String message) {
+ log.log(callerFQCN, Level.ERROR, message, null);
+ }
+
+ public void error(String message, Throwable t) {
+ log.log(callerFQCN, Level.ERROR, message, t);
+ }
+
+ public void fatal(String message) {
+ log.log(callerFQCN, Level.FATAL, message, null);
+ }
+
+ public void fatal(String message, Throwable t) {
+ log.log(callerFQCN, Level.FATAL, message, t);
+ }
+
+ public boolean isDebugEnabled() {
+ return log.isDebugEnabled();
+ }
+
+ public boolean isInfoEnabled() {
+ return log.isInfoEnabled();
+ }
+
+ public boolean isWarnEnabled() {
+ return log.isEnabledFor(Level.WARN);
+ }
+
+ public boolean isErrorEnabled() {
+ return log.isEnabledFor(Level.ERROR);
+ }
+
+ public boolean isFatalEnabled() {
+ return log.isEnabledFor(Level.FATAL);
+ }
+}
+
diff --git a/src/main/java/com/jfinal/log/Log4jLogFactory.java b/src/com/jfinal/log/Log4jLoggerFactory.java
similarity index 65%
rename from src/main/java/com/jfinal/log/Log4jLogFactory.java
rename to src/com/jfinal/log/Log4jLoggerFactory.java
index 1e01f9cd9..cad720bba 100644
--- a/src/main/java/com/jfinal/log/Log4jLogFactory.java
+++ b/src/com/jfinal/log/Log4jLoggerFactory.java
@@ -1,31 +1,31 @@
-/**
- * Copyright (c) 2011-2023, James Zhan 詹波 (jfinal@126.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
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.jfinal.log;
-
-/**
- * Log4jLogFactory.
- */
-public class Log4jLogFactory implements ILogFactory {
-
- public Log getLog(Class> clazz) {
- return new Log4jLog(clazz);
- }
-
- public Log getLog(String name) {
- return new Log4jLog(name);
- }
-}
+/**
+ * Copyright (c) 2011-2014, James Zhan 詹波 (jfinal@126.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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.jfinal.log;
+
+/**
+ * Log4jLoggerFactory.
+ */
+public class Log4jLoggerFactory implements ILoggerFactory {
+
+ public Logger getLogger(Class> clazz) {
+ return new Log4jLogger(clazz);
+ }
+
+ public Logger getLogger(String name) {
+ return new Log4jLogger(name);
+ }
+}
diff --git a/src/com/jfinal/log/Logger.java b/src/com/jfinal/log/Logger.java
new file mode 100644
index 000000000..abeb96cb8
--- /dev/null
+++ b/src/com/jfinal/log/Logger.java
@@ -0,0 +1,90 @@
+/**
+ * Copyright (c) 2011-2014, James Zhan 詹波 (jfinal@126.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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.jfinal.log;
+
+/**
+ * The five logging levels used by Log are (in order):
+ * 1. DEBUG (the least serious)
+ * 2. INFO
+ * 3. WARN
+ * 4. ERROR
+ * 5. FATAL (the most serious)
+ */
+public abstract class Logger {
+
+ private static ILoggerFactory factory;
+
+ static {
+ init();
+ }
+
+ public static void setLoggerFactory(ILoggerFactory loggerFactory) {
+ if (loggerFactory != null)
+ Logger.factory = loggerFactory;
+ }
+
+ public static Logger getLogger(Class> clazz) {
+ return factory.getLogger(clazz);
+ }
+
+ public static Logger getLogger(String name) {
+ return factory.getLogger(name);
+ }
+
+ public static void init() {
+ if (factory != null)
+ return ;
+ try {
+ Class.forName("org.apache.log4j.Logger");
+ Class> log4jLoggerFactoryClass = Class.forName("com.jfinal.log.Log4jLoggerFactory");
+ factory = (ILoggerFactory)log4jLoggerFactoryClass.newInstance(); // return new Log4jLoggerFactory();
+ } catch (Exception e) {
+ factory = new JdkLoggerFactory();
+ }
+ }
+
+ public abstract void debug(String message);
+
+ public abstract void debug(String message, Throwable t);
+
+ public abstract void info(String message);
+
+ public abstract void info(String message, Throwable t);
+
+ public abstract void warn(String message);
+
+ public abstract void warn(String message, Throwable t);
+
+ public abstract void error(String message);
+
+ public abstract void error(String message, Throwable t);
+
+ public abstract void fatal(String message);
+
+ public abstract void fatal(String message, Throwable t);
+
+ public abstract boolean isDebugEnabled();
+
+ public abstract boolean isInfoEnabled();
+
+ public abstract boolean isWarnEnabled();
+
+ public abstract boolean isErrorEnabled();
+
+ public abstract boolean isFatalEnabled();
+}
+
diff --git a/src/com/jfinal/log/NullLoggerFactory.java b/src/com/jfinal/log/NullLoggerFactory.java
new file mode 100644
index 000000000..d5ab60968
--- /dev/null
+++ b/src/com/jfinal/log/NullLoggerFactory.java
@@ -0,0 +1,84 @@
+/**
+ * Copyright (c) 2011-2014, James Zhan 詹波 (jfinal@126.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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.jfinal.log;
+
+/**
+ * NullLoggerFactory.
+ */
+public class NullLoggerFactory implements ILoggerFactory {
+
+ public com.jfinal.log.Logger getLogger(Class> clazz) {
+ return INSTANCE;
+ }
+
+ public com.jfinal.log.Logger getLogger(String name) {
+ return INSTANCE;
+ }
+
+ private static final Logger INSTANCE = new Logger() {
+
+ public void debug(String message) {
+ }
+
+ public void debug(String message, Throwable t) {
+ }
+
+ public void error(String message) {
+ }
+
+ public void error(String message, Throwable t) {
+ }
+
+ public void info(String message) {
+ }
+
+ public void info(String message, Throwable t) {
+ }
+
+ public boolean isDebugEnabled() {
+ return false;
+ }
+
+ public boolean isInfoEnabled() {
+ return false;
+ }
+
+ public boolean isWarnEnabled() {
+ return false;
+ }
+
+ public boolean isErrorEnabled() {
+ return false;
+ }
+
+ public boolean isFatalEnabled() {
+ return false;
+ }
+
+ public void warn(String message) {
+ }
+
+ public void warn(String message, Throwable t) {
+ }
+
+ public void fatal(String message) {
+ }
+
+ public void fatal(String message, Throwable t) {
+ }
+ };
+}
diff --git a/src/main/java/com/jfinal/plugin/IPlugin.java b/src/com/jfinal/plugin/IPlugin.java
similarity index 88%
rename from src/main/java/com/jfinal/plugin/IPlugin.java
rename to src/com/jfinal/plugin/IPlugin.java
index 4e5e83bb0..c77a733dd 100644
--- a/src/main/java/com/jfinal/plugin/IPlugin.java
+++ b/src/com/jfinal/plugin/IPlugin.java
@@ -1,25 +1,25 @@
-/**
- * Copyright (c) 2011-2023, James Zhan 詹波 (jfinal@126.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
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.jfinal.plugin;
-
-/**
- * IPlugin
- */
-public interface IPlugin {
- boolean start();
- boolean stop();
-}
+/**
+ * Copyright (c) 2011-2014, James Zhan 詹波 (jfinal@126.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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.jfinal.plugin;
+
+/**
+ * IPlugin
+ */
+public interface IPlugin {
+ boolean start();
+ boolean stop();
+}
\ No newline at end of file
diff --git a/src/main/java/com/jfinal/plugin/activerecord/ActiveRecordException.java b/src/com/jfinal/plugin/activerecord/ActiveRecordException.java
similarity index 90%
rename from src/main/java/com/jfinal/plugin/activerecord/ActiveRecordException.java
rename to src/com/jfinal/plugin/activerecord/ActiveRecordException.java
index 9e73a1afb..cd76fee86 100644
--- a/src/main/java/com/jfinal/plugin/activerecord/ActiveRecordException.java
+++ b/src/com/jfinal/plugin/activerecord/ActiveRecordException.java
@@ -1,47 +1,47 @@
-/**
- * Copyright (c) 2011-2023, James Zhan 詹波 (jfinal@126.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
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.jfinal.plugin.activerecord;
-
-/**
- * ActiveRecordException
- */
-public class ActiveRecordException extends RuntimeException {
-
- private static final long serialVersionUID = 342820722361408621L;
-
- public ActiveRecordException(String message) {
- super(message);
- }
-
- public ActiveRecordException(Throwable cause) {
- super(cause);
- }
-
- public ActiveRecordException(String message, Throwable cause) {
- super(message, cause);
- }
-}
-
-
-
-
-
-
-
-
-
-
+/**
+ * Copyright (c) 2011-2014, James Zhan 詹波 (jfinal@126.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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.jfinal.plugin.activerecord;
+
+/**
+ * ActiveRecordException
+ */
+public class ActiveRecordException extends RuntimeException {
+
+ private static final long serialVersionUID = 342820722361408621L;
+
+ public ActiveRecordException(String message) {
+ super(message);
+ }
+
+ public ActiveRecordException(Throwable cause) {
+ super(cause);
+ }
+
+ public ActiveRecordException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
+
+
+
+
+
+
+
+
+
+
diff --git a/src/com/jfinal/plugin/activerecord/ActiveRecordPlugin.java b/src/com/jfinal/plugin/activerecord/ActiveRecordPlugin.java
new file mode 100644
index 000000000..f792b541a
--- /dev/null
+++ b/src/com/jfinal/plugin/activerecord/ActiveRecordPlugin.java
@@ -0,0 +1,190 @@
+/**
+ * Copyright (c) 2011-2014, James Zhan 詹波 (jfinal@126.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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.jfinal.plugin.activerecord;
+
+import java.sql.Connection;
+import java.util.ArrayList;
+import java.util.List;
+import javax.sql.DataSource;
+import com.jfinal.kit.StrKit;
+import com.jfinal.plugin.IPlugin;
+import com.jfinal.plugin.activerecord.cache.ICache;
+import com.jfinal.plugin.activerecord.dialect.Dialect;
+
+/**
+ * ActiveRecord plugin.
+ *
+ * ActiveRecord plugin not support mysql type year, you can use int instead of year.
+ * Mysql error message for type year when insert a record: Data truncated for column 'xxx' at row 1
+ */
+public class ActiveRecordPlugin implements IPlugin {
+
+ private String configName = DbKit.MAIN_CONFIG_NAME;
+ private Config config = null;
+
+ private DataSource dataSource;
+ private IDataSourceProvider dataSourceProvider;
+ private Integer transactionLevel = null;
+ private ICache cache = null;
+ private Boolean showSql = null;
+ private Boolean devMode = null;
+ private Dialect dialect = null;
+ private IContainerFactory containerFactory = null;
+
+ private boolean isStarted = false;
+ private List
tableList = new ArrayList
();
+
+ public ActiveRecordPlugin(Config config) {
+ if (config == null)
+ throw new IllegalArgumentException("Config can not be null");
+ this.config = config;
+ }
+
+ public ActiveRecordPlugin(DataSource dataSource) {
+ this(DbKit.MAIN_CONFIG_NAME, dataSource);
+ }
+
+ public ActiveRecordPlugin(String configName, DataSource dataSource) {
+ this(configName, dataSource, Connection.TRANSACTION_READ_COMMITTED);
+ }
+
+ public ActiveRecordPlugin(DataSource dataSource, int transactionLevel) {
+ this(DbKit.MAIN_CONFIG_NAME, dataSource, transactionLevel);
+ }
+
+ public ActiveRecordPlugin(String configName, DataSource dataSource, int transactionLevel) {
+ if (StrKit.isBlank(configName))
+ throw new IllegalArgumentException("configName can not be blank");
+ if (dataSource == null)
+ throw new IllegalArgumentException("dataSource can not be null");
+ this.configName = configName.trim();
+ this.dataSource = dataSource;
+ this.setTransactionLevel(transactionLevel);
+ }
+
+ public ActiveRecordPlugin(IDataSourceProvider dataSourceProvider) {
+ this(DbKit.MAIN_CONFIG_NAME, dataSourceProvider);
+ }
+
+ public ActiveRecordPlugin(String configName, IDataSourceProvider dataSourceProvider) {
+ this(configName, dataSourceProvider, Connection.TRANSACTION_READ_COMMITTED);
+ }
+
+ public ActiveRecordPlugin(IDataSourceProvider dataSourceProvider, int transactionLevel) {
+ this(DbKit.MAIN_CONFIG_NAME, dataSourceProvider, transactionLevel);
+ }
+
+ public ActiveRecordPlugin(String configName, IDataSourceProvider dataSourceProvider, int transactionLevel) {
+ if (StrKit.isBlank(configName))
+ throw new IllegalArgumentException("configName can not be blank");
+ if (dataSourceProvider == null)
+ throw new IllegalArgumentException("dataSourceProvider can not be null");
+ this.configName = configName.trim();
+ this.dataSourceProvider = dataSourceProvider;
+ this.setTransactionLevel(transactionLevel);
+ }
+
+ public ActiveRecordPlugin addMapping(String tableName, String primaryKey, Class extends Model>> modelClass) {
+ tableList.add(new Table(tableName, primaryKey, modelClass));
+ return this;
+ }
+
+ public ActiveRecordPlugin addMapping(String tableName, Class extends Model>> modelClass) {
+ tableList.add(new Table(tableName, modelClass));
+ return this;
+ }
+
+ /**
+ * Set transaction level define in java.sql.Connection
+ * @param transactionLevel only be 0, 1, 2, 4, 8
+ */
+ public ActiveRecordPlugin setTransactionLevel(int transactionLevel) {
+ int t = transactionLevel;
+ if (t != 0 && t != 1 && t != 2 && t != 4 && t != 8)
+ throw new IllegalArgumentException("The transactionLevel only be 0, 1, 2, 4, 8");
+ this.transactionLevel = transactionLevel;
+ return this;
+ }
+
+ public ActiveRecordPlugin setCache(ICache cache) {
+ if (cache == null)
+ throw new IllegalArgumentException("cache can not be null");
+ this.cache = cache;
+ return this;
+ }
+
+ public ActiveRecordPlugin setShowSql(boolean showSql) {
+ this.showSql = showSql;
+ return this;
+ }
+
+ public ActiveRecordPlugin setDevMode(boolean devMode) {
+ this.devMode = devMode;
+ return this;
+ }
+
+ public Boolean getDevMode() {
+ return devMode;
+ }
+
+ public ActiveRecordPlugin setDialect(Dialect dialect) {
+ if (dialect == null)
+ throw new IllegalArgumentException("dialect can not be null");
+ this.dialect = dialect;
+ return this;
+ }
+
+ public ActiveRecordPlugin setContainerFactory(IContainerFactory containerFactory) {
+ if (containerFactory == null)
+ throw new IllegalArgumentException("containerFactory can not be null");
+ this.containerFactory = containerFactory;
+ return this;
+ }
+
+ public boolean start() {
+ if (isStarted)
+ return true;
+
+ if (dataSourceProvider != null)
+ dataSource = dataSourceProvider.getDataSource();
+ if (dataSource == null)
+ throw new RuntimeException("ActiveRecord start error: ActiveRecordPlugin need DataSource or DataSourceProvider");
+
+ if (config == null)
+ config = new Config(configName, dataSource, dialect, showSql, devMode, transactionLevel, containerFactory, cache);
+ DbKit.addConfig(config);
+
+ boolean succeed = TableBuilder.build(tableList, config);
+ if (succeed) {
+ Db.init();
+ isStarted = true;
+ }
+ return succeed;
+ }
+
+ public boolean stop() {
+ isStarted = false;
+ return true;
+ }
+}
+
+
+
+
+
+
+
diff --git a/src/main/java/com/jfinal/plugin/activerecord/CPI.java b/src/com/jfinal/plugin/activerecord/CPI.java
similarity index 63%
rename from src/main/java/com/jfinal/plugin/activerecord/CPI.java
rename to src/com/jfinal/plugin/activerecord/CPI.java
index d9c33d1af..9e6c87cdb 100644
--- a/src/main/java/com/jfinal/plugin/activerecord/CPI.java
+++ b/src/com/jfinal/plugin/activerecord/CPI.java
@@ -1,127 +1,79 @@
-/**
- * Copyright (c) 2011-2023, James Zhan 詹波 (jfinal@126.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
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.jfinal.plugin.activerecord;
-
-import java.sql.Connection;
-import java.sql.SQLException;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Cross Package Invoking pattern for package activerecord.
- *
- * 为了避免开发者误用,Model、Db 中的部分方法没有完全开放出来,不能直接调用,
- * 但可以通过 CPI 访问那些未完全开放的方法,对于扩展性开发十分有用
- *
- * 例如:
- * Map attrMap = CPI.getAttrs(user);
- * 以上代码可以获取到 User 这个 model 中的 attrs 属性
- */
-@SuppressWarnings({"unchecked", "rawtypes"})
-public abstract class CPI {
-
- /**
- * Return the attributes map of the model
- * @param model the model extends from class Model
- * @return the attributes map of the model
- */
- public static final Map getAttrs(Model model) {
- return model._getAttrs();
- }
-
- public static final Set getModifyFlag(Model model) {
- return model._getModifyFlag();
- }
-
- public static final Set getModifyFlag(Record record) {
- return record._getModifyFlag();
- }
-
- public static final Table getTable(Model model) {
- return model._getTable();
- }
-
- public static final Config getConfig(Model model) {
- return model._getConfig();
- }
-
- public static final String getConfigName(Model model) {
- return model.configName;
- }
-
- public static final Class extends Model> getUsefulClass(Model model) {
- return model._getUsefulClass();
- }
-
- public static List query(Connection conn, String sql, Object... paras) throws SQLException {
- return Db.query(DbKit.config, conn, sql, paras);
- }
-
- public static List query(String configName, Connection conn, String sql, Object... paras) throws SQLException {
- return Db.query(DbKit.getConfig(configName), conn, sql, paras);
- }
-
- public static List query(Config config, Connection conn, String sql, Object... paras) throws SQLException {
- return Db.query(config, conn, sql, paras);
- }
-
- /**
- * Return the columns map of the record
- * @param record the Record object
- * @return the columns map of the record
- public static final Map getColumns(Record record) {
- return record.getColumns();
- } */
-
- public static void setColumnsMap(Record record, Map columns) {
- record.setColumnsMap(columns);
- }
-
- public static List find(Connection conn, String sql, Object... paras) throws SQLException {
- return Db.find(DbKit.config, conn, sql, paras);
- }
-
- public static List find(String configName, Connection conn, String sql, Object... paras) throws SQLException {
- return Db.find(DbKit.getConfig(configName), conn, sql, paras);
- }
-
- public static Page paginate(Connection conn, int pageNumber, int pageSize, String select, String sqlExceptSelect, Object... paras) throws SQLException {
- return Db.paginate(DbKit.config, conn, pageNumber, pageSize, select, sqlExceptSelect, paras);
- }
-
- public static Page paginate(String configName, Connection conn, int pageNumber, int pageSize, String select, String sqlExceptSelect, Object... paras) throws SQLException {
- return Db.paginate(DbKit.getConfig(configName), conn, pageNumber, pageSize, select, sqlExceptSelect, paras);
- }
-
- public static int update(Connection conn, String sql, Object... paras) throws SQLException {
- return Db.update(DbKit.config, conn, sql, paras);
- }
-
- public static int update(String configName, Connection conn, String sql, Object... paras) throws SQLException {
- return Db.update(DbKit.getConfig(configName), conn, sql, paras);
- }
-
- public static void setTablePrimaryKey(Table table, String primaryKey) {
- table.setPrimaryKey(primaryKey);
- }
-
- public static void addModelToConfigMapping(Class extends Model> modelClass, Config config) {
- DbKit.addModelToConfigMapping(modelClass, config);
- }
-}
-
+/**
+ * Copyright (c) 2011-2014, James Zhan 詹波 (jfinal@126.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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.jfinal.plugin.activerecord;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Cross Package Invoking pattern for package activerecord.
+ */
+public abstract class CPI {
+
+ /**
+ * Return the attributes map of the model
+ * @param model the model extends from class Model
+ * @return the attributes map of the model
+ */
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ public static final Map getAttrs(Model model) {
+ return model.getAttrs();
+ }
+
+ public static List query(Connection conn, String sql, Object... paras) throws SQLException {
+ return Db.query(DbKit.config, conn, sql, paras);
+ }
+
+ public static List query(String configName, Connection conn, String sql, Object... paras) throws SQLException {
+ return Db.query(DbKit.getConfig(configName), conn, sql, paras);
+ }
+
+ /**
+ * Return the columns map of the record
+ * @param record the Record object
+ * @return the columns map of the record
+ public static final Map getColumns(Record record) {
+ return record.getColumns();
+ } */
+
+ public static List find(Connection conn, String sql, Object... paras) throws SQLException {
+ return Db.find(DbKit.config, conn, sql, paras);
+ }
+
+ public static List find(String configName, Connection conn, String sql, Object... paras) throws SQLException {
+ return Db.find(DbKit.getConfig(configName), conn, sql, paras);
+ }
+
+ public static Page paginate(Connection conn, int pageNumber, int pageSize, String select, String sqlExceptSelect, Object... paras) throws SQLException {
+ return Db.paginate(DbKit.config, conn, pageNumber, pageSize, select, sqlExceptSelect, paras);
+ }
+
+ public static Page paginate(String configName, Connection conn, int pageNumber, int pageSize, String select, String sqlExceptSelect, Object... paras) throws SQLException {
+ return Db.paginate(DbKit.getConfig(configName), conn, pageNumber, pageSize, select, sqlExceptSelect, paras);
+ }
+
+ public static int update(Connection conn, String sql, Object... paras) throws SQLException {
+ return Db.update(DbKit.config, conn, sql, paras);
+ }
+
+ public static int update(String configName, Connection conn, String sql, Object... paras) throws SQLException {
+ return Db.update(DbKit.getConfig(configName), conn, sql, paras);
+ }
+}
+
diff --git a/src/main/java/com/jfinal/plugin/activerecord/CaseInsensitiveContainerFactory.java b/src/com/jfinal/plugin/activerecord/CaseInsensitiveContainerFactory.java
similarity index 51%
rename from src/main/java/com/jfinal/plugin/activerecord/CaseInsensitiveContainerFactory.java
rename to src/com/jfinal/plugin/activerecord/CaseInsensitiveContainerFactory.java
index 7df4a4686..1641958a2 100644
--- a/src/main/java/com/jfinal/plugin/activerecord/CaseInsensitiveContainerFactory.java
+++ b/src/com/jfinal/plugin/activerecord/CaseInsensitiveContainerFactory.java
@@ -1,110 +1,113 @@
-/**
- * Copyright (c) 2011-2023, James Zhan 詹波 (jfinal@126.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
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.jfinal.plugin.activerecord;
-
-import java.util.Collection;
-import java.util.Map;
-import java.util.Set;
-import java.util.TreeMap;
-import java.util.TreeSet;
-
-/**
- * CaseInsensitiveContainerFactory.
- */
-public class CaseInsensitiveContainerFactory implements IContainerFactory {
-
- private Boolean toLowerCase = null;
-
- public CaseInsensitiveContainerFactory() {
- }
-
- public CaseInsensitiveContainerFactory(boolean toLowerCase) {
- this.toLowerCase = toLowerCase;
- }
-
- public Map getAttrsMap() {
- return new CaseInsensitiveMap