Commit 24efae760546a9f4bf9bd8ba8a986d6795d9cbb1

Authored by 刘基城
0 parents

init

Showing 90 changed files with 6659 additions and 0 deletions
.gitignore 0 → 100644
  1 +++ a/.gitignore
  1 +# Maven #
  2 +target/
  3 +
  4 +# IDEA #
  5 +.idea/
  6 +*.iml
  7 +
  8 +# Eclipse #
  9 +.settings/
  10 +.classpath
  11 +.project
0 \ No newline at end of file 12 \ No newline at end of file
LICENSE 0 → 100644
  1 +++ a/LICENSE
  1 +Apache License
  2 +Version 2.0, January 2004
  3 +http://www.apache.org/licenses/
  4 +
  5 +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
  6 +
  7 +1. Definitions.
  8 +
  9 +"License" shall mean the terms and conditions for use, reproduction, and
  10 +distribution as defined by Sections 1 through 9 of this document.
  11 +
  12 +"Licensor" shall mean the copyright owner or entity authorized by the copyright
  13 +owner that is granting the License.
  14 +
  15 +"Legal Entity" shall mean the union of the acting entity and all other entities
  16 +that control, are controlled by, or are under common control with that entity.
  17 +For the purposes of this definition, "control" means (i) the power, direct or
  18 +indirect, to cause the direction or management of such entity, whether by
  19 +contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the
  20 +outstanding shares, or (iii) beneficial ownership of such entity.
  21 +
  22 +"You" (or "Your") shall mean an individual or Legal Entity exercising
  23 +permissions granted by this License.
  24 +
  25 +"Source" form shall mean the preferred form for making modifications, including
  26 +but not limited to software source code, documentation source, and configuration
  27 +files.
  28 +
  29 +"Object" form shall mean any form resulting from mechanical transformation or
  30 +translation of a Source form, including but not limited to compiled object code,
  31 +generated documentation, and conversions to other media types.
  32 +
  33 +"Work" shall mean the work of authorship, whether in Source or Object form, made
  34 +available under the License, as indicated by a copyright notice that is included
  35 +in or attached to the work (an example is provided in the Appendix below).
  36 +
  37 +"Derivative Works" shall mean any work, whether in Source or Object form, that
  38 +is based on (or derived from) the Work and for which the editorial revisions,
  39 +annotations, elaborations, or other modifications represent, as a whole, an
  40 +original work of authorship. For the purposes of this License, Derivative Works
  41 +shall not include works that remain separable from, or merely link (or bind by
  42 +name) to the interfaces of, the Work and Derivative Works thereof.
  43 +
  44 +"Contribution" shall mean any work of authorship, including the original version
  45 +of the Work and any modifications or additions to that Work or Derivative Works
  46 +thereof, that is intentionally submitted to Licensor for inclusion in the Work
  47 +by the copyright owner or by an individual or Legal Entity authorized to submit
  48 +on behalf of the copyright owner. For the purposes of this definition,
  49 +"submitted" means any form of electronic, verbal, or written communication sent
  50 +to the Licensor or its representatives, including but not limited to
  51 +communication on electronic mailing lists, source code control systems, and
  52 +issue tracking systems that are managed by, or on behalf of, the Licensor for
  53 +the purpose of discussing and improving the Work, but excluding communication
  54 +that is conspicuously marked or otherwise designated in writing by the copyright
  55 +owner as "Not a Contribution."
  56 +
  57 +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf
  58 +of whom a Contribution has been received by Licensor and subsequently
  59 +incorporated within the Work.
  60 +
  61 +2. Grant of Copyright License.
  62 +
  63 +Subject to the terms and conditions of this License, each Contributor hereby
  64 +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
  65 +irrevocable copyright license to reproduce, prepare Derivative Works of,
  66 +publicly display, publicly perform, sublicense, and distribute the Work and such
  67 +Derivative Works in Source or Object form.
  68 +
  69 +3. Grant of Patent License.
  70 +
  71 +Subject to the terms and conditions of this License, each Contributor hereby
  72 +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
  73 +irrevocable (except as stated in this section) patent license to make, have
  74 +made, use, offer to sell, sell, import, and otherwise transfer the Work, where
  75 +such license applies only to those patent claims licensable by such Contributor
  76 +that are necessarily infringed by their Contribution(s) alone or by combination
  77 +of their Contribution(s) with the Work to which such Contribution(s) was
  78 +submitted. If You institute patent litigation against any entity (including a
  79 +cross-claim or counterclaim in a lawsuit) alleging that the Work or a
  80 +Contribution incorporated within the Work constitutes direct or contributory
  81 +patent infringement, then any patent licenses granted to You under this License
  82 +for that Work shall terminate as of the date such litigation is filed.
  83 +
  84 +4. Redistribution.
  85 +
  86 +You may reproduce and distribute copies of the Work or Derivative Works thereof
  87 +in any medium, with or without modifications, and in Source or Object form,
  88 +provided that You meet the following conditions:
  89 +
  90 +You must give any other recipients of the Work or Derivative Works a copy of
  91 +this License; and
  92 +You must cause any modified files to carry prominent notices stating that You
  93 +changed the files; and
  94 +You must retain, in the Source form of any Derivative Works that You distribute,
  95 +all copyright, patent, trademark, and attribution notices from the Source form
  96 +of the Work, excluding those notices that do not pertain to any part of the
  97 +Derivative Works; and
  98 +If the Work includes a "NOTICE" text file as part of its distribution, then any
  99 +Derivative Works that You distribute must include a readable copy of the
  100 +attribution notices contained within such NOTICE file, excluding those notices
  101 +that do not pertain to any part of the Derivative Works, in at least one of the
  102 +following places: within a NOTICE text file distributed as part of the
  103 +Derivative Works; within the Source form or documentation, if provided along
  104 +with the Derivative Works; or, within a display generated by the Derivative
  105 +Works, if and wherever such third-party notices normally appear. The contents of
  106 +the NOTICE file are for informational purposes only and do not modify the
  107 +License. You may add Your own attribution notices within Derivative Works that
  108 +You distribute, alongside or as an addendum to the NOTICE text from the Work,
  109 +provided that such additional attribution notices cannot be construed as
  110 +modifying the License.
  111 +You may add Your own copyright statement to Your modifications and may provide
  112 +additional or different license terms and conditions for use, reproduction, or
  113 +distribution of Your modifications, or for any such Derivative Works as a whole,
  114 +provided Your use, reproduction, and distribution of the Work otherwise complies
  115 +with the conditions stated in this License.
  116 +
  117 +5. Submission of Contributions.
  118 +
  119 +Unless You explicitly state otherwise, any Contribution intentionally submitted
  120 +for inclusion in the Work by You to the Licensor shall be under the terms and
  121 +conditions of this License, without any additional terms or conditions.
  122 +Notwithstanding the above, nothing herein shall supersede or modify the terms of
  123 +any separate license agreement you may have executed with Licensor regarding
  124 +such Contributions.
  125 +
  126 +6. Trademarks.
  127 +
  128 +This License does not grant permission to use the trade names, trademarks,
  129 +service marks, or product names of the Licensor, except as required for
  130 +reasonable and customary use in describing the origin of the Work and
  131 +reproducing the content of the NOTICE file.
  132 +
  133 +7. Disclaimer of Warranty.
  134 +
  135 +Unless required by applicable law or agreed to in writing, Licensor provides the
  136 +Work (and each Contributor provides its Contributions) on an "AS IS" BASIS,
  137 +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
  138 +including, without limitation, any warranties or conditions of TITLE,
  139 +NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are
  140 +solely responsible for determining the appropriateness of using or
  141 +redistributing the Work and assume any risks associated with Your exercise of
  142 +permissions under this License.
  143 +
  144 +8. Limitation of Liability.
  145 +
  146 +In no event and under no legal theory, whether in tort (including negligence),
  147 +contract, or otherwise, unless required by applicable law (such as deliberate
  148 +and grossly negligent acts) or agreed to in writing, shall any Contributor be
  149 +liable to You for damages, including any direct, indirect, special, incidental,
  150 +or consequential damages of any character arising as a result of this License or
  151 +out of the use or inability to use the Work (including but not limited to
  152 +damages for loss of goodwill, work stoppage, computer failure or malfunction, or
  153 +any and all other commercial damages or losses), even if such Contributor has
  154 +been advised of the possibility of such damages.
  155 +
  156 +9. Accepting Warranty or Additional Liability.
  157 +
  158 +While redistributing the Work or Derivative Works thereof, You may choose to
  159 +offer, and charge a fee for, acceptance of support, warranty, indemnity, or
  160 +other liability obligations and/or rights consistent with this License. However,
  161 +in accepting such obligations, You may act only on Your own behalf and on Your
  162 +sole responsibility, not on behalf of any other Contributor, and only if You
  163 +agree to indemnify, defend, and hold each Contributor harmless for any liability
  164 +incurred by, or claims asserted against, such Contributor by reason of your
  165 +accepting any such warranty or additional liability.
  166 +
  167 +END OF TERMS AND CONDITIONS
  168 +
  169 +APPENDIX: How to apply the Apache License to your work
  170 +
  171 +To apply the Apache License to your work, attach the following boilerplate
  172 +notice, with the fields enclosed by brackets "[]" replaced with your own
  173 +identifying information. (Don't include the brackets!) The text should be
  174 +enclosed in the appropriate comment syntax for the file format. We also
  175 +recommend that a file or class name and description of purpose be included on
  176 +the same "printed page" as the copyright notice for easier identification within
  177 +third-party archives.
  178 +
  179 + Copyright [yyyy] [name of copyright owner]
  180 +
  181 + Licensed under the Apache License, Version 2.0 (the "License");
  182 + you may not use this file except in compliance with the License.
  183 + You may obtain a copy of the License at
  184 +
  185 + http://www.apache.org/licenses/LICENSE-2.0
  186 +
  187 + Unless required by applicable law or agreed to in writing, software
  188 + distributed under the License is distributed on an "AS IS" BASIS,
  189 + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  190 + See the License for the specific language governing permissions and
  191 + limitations under the License.
0 \ No newline at end of file 192 \ No newline at end of file
pom.xml 0 → 100644
  1 +++ a/pom.xml
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3 + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
  4 + http://maven.apache.org/xsd/maven-4.0.0.xsd">
  5 + <modelVersion>4.0.0</modelVersion>
  6 + <parent>
  7 + <groupId>org.smart4j</groupId>
  8 + <artifactId>smart-root</artifactId>
  9 + <version>1.0</version>
  10 + </parent>
  11 + <artifactId>smart-framework</artifactId>
  12 + <version>4.0.1</version>
  13 + <name>smart-framework</name>
  14 + <description>Smart Framework is a lightweight Java Web Framework</description>
  15 + <url>http://www.smart4j.org/</url>
  16 + <licenses>
  17 + <license>
  18 + <name>The Apache Software License, Version 2.0</name>
  19 + <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
  20 + </license>
  21 + </licenses>
  22 + <properties>
  23 + <junit.version>4.11</junit.version>
  24 + <slf4j.version>1.7.5</slf4j.version>
  25 + <servlet.version>3.0.1</servlet.version>
  26 + <jackson.version>1.9.13</jackson.version>
  27 + <cglib.version>2.2.2</cglib.version>
  28 + <commons-lang.version>2.5</commons-lang.version>
  29 + <commons-collections.version>3.2</commons-collections.version>
  30 + <commons-beanutils.version>1.8.3</commons-beanutils.version>
  31 + <commons-dbcp.version>1.4</commons-dbcp.version>
  32 + <commons-dbutils.version>1.5.fix</commons-dbutils.version>
  33 + <commons-fileupload.version>1.3</commons-fileupload.version>
  34 + <commons-codec.version>1.8</commons-codec.version>
  35 + </properties>
  36 +
  37 + <dependencies>
  38 + <!-- JUnit -->
  39 + <dependency>
  40 + <groupId>junit</groupId>
  41 + <artifactId>junit</artifactId>
  42 + <version>${junit.version}</version>
  43 + <scope>provided</scope>
  44 + </dependency>
  45 + <!-- SLF4J -->
  46 + <dependency>
  47 + <groupId>org.slf4j</groupId>
  48 + <artifactId>slf4j-log4j12</artifactId>
  49 + <version>${slf4j.version}</version>
  50 + </dependency>
  51 + <!-- Servlet -->
  52 + <dependency>
  53 + <groupId>javax.servlet</groupId>
  54 + <artifactId>javax.servlet-api</artifactId>
  55 + <version>${servlet.version}</version>
  56 + <scope>provided</scope>
  57 + </dependency>
  58 + <!-- Jackson -->
  59 + <dependency>
  60 + <groupId>org.codehaus.jackson</groupId>
  61 + <artifactId>jackson-mapper-asl</artifactId>
  62 + <version>${jackson.version}</version>
  63 + </dependency>
  64 + <dependency>
  65 + <groupId>org.codehaus.jackson</groupId>
  66 + <artifactId>jackson-jaxrs</artifactId>
  67 + <version>${jackson.version}</version>
  68 + </dependency>
  69 + <!-- CGLib -->
  70 + <dependency>
  71 + <groupId>cglib</groupId>
  72 + <artifactId>cglib</artifactId>
  73 + <version>${cglib.version}</version>
  74 + </dependency>
  75 + <!-- Apache Commons -->
  76 + <dependency>
  77 + <groupId>commons-lang</groupId>
  78 + <artifactId>commons-lang</artifactId>
  79 + <version>${commons-lang.version}</version>
  80 + </dependency>
  81 + <dependency>
  82 + <groupId>commons-collections</groupId>
  83 + <artifactId>commons-collections</artifactId>
  84 + <version>${commons-collections.version}</version>
  85 + </dependency>
  86 + <dependency>
  87 + <groupId>commons-beanutils</groupId>
  88 + <artifactId>commons-beanutils</artifactId>
  89 + <version>${commons-beanutils.version}</version>
  90 + </dependency>
  91 + <dependency>
  92 + <groupId>commons-dbcp</groupId>
  93 + <artifactId>commons-dbcp</artifactId>
  94 + <version>${commons-dbcp.version}</version>
  95 + </dependency>
  96 + <dependency>
  97 + <groupId>commons-dbutils</groupId>
  98 + <artifactId>commons-dbutils</artifactId>
  99 + <version>${commons-dbutils.version}</version>
  100 + </dependency>
  101 + <dependency>
  102 + <groupId>commons-fileupload</groupId>
  103 + <artifactId>commons-fileupload</artifactId>
  104 + <version>${commons-fileupload.version}</version>
  105 + </dependency>
  106 + <dependency>
  107 + <groupId>commons-codec</groupId>
  108 + <artifactId>commons-codec</artifactId>
  109 + <version>${commons-codec.version}</version>
  110 + </dependency>
  111 + </dependencies>
  112 +
  113 +</project>
0 \ No newline at end of file 114 \ No newline at end of file
src/main/java/org/smart4j/framework/FrameworkConstant.java 0 → 100644
  1 +++ a/src/main/java/org/smart4j/framework/FrameworkConstant.java
  1 +package org.smart4j.framework;
  2 +
  3 +import org.smart4j.framework.core.ConfigHelper;
  4 +
  5 +public interface FrameworkConstant {
  6 +
  7 + String UTF_8 = "UTF-8";
  8 +
  9 + String CONFIG_PROPS = "smart.properties";
  10 + String SQL_PROPS = "smart-sql.properties";
  11 +
  12 + String PLUGIN_PACKAGE = "org.smart4j.plugin";
  13 +
  14 + String JSP_PATH = ConfigHelper.getString("smart.framework.app.jsp_path", "/WEB-INF/jsp/");
  15 + String WWW_PATH = ConfigHelper.getString("smart.framework.app.www_path", "/www/");
  16 + String HOME_PAGE = ConfigHelper.getString("smart.framework.app.home_page", "/index.html");
  17 + int UPLOAD_LIMIT = ConfigHelper.getInt("smart.framework.app.upload_limit", 10);
  18 +
  19 + String PK_NAME = "id";
  20 +}
src/main/java/org/smart4j/framework/HelperLoader.java 0 → 100644
  1 +++ a/src/main/java/org/smart4j/framework/HelperLoader.java
  1 +package org.smart4j.framework;
  2 +
  3 +import org.smart4j.framework.aop.AopHelper;
  4 +import org.smart4j.framework.dao.DatabaseHelper;
  5 +import org.smart4j.framework.ioc.BeanHelper;
  6 +import org.smart4j.framework.ioc.IocHelper;
  7 +import org.smart4j.framework.mvc.ActionHelper;
  8 +import org.smart4j.framework.orm.EntityHelper;
  9 +import org.smart4j.framework.plugin.PluginHelper;
  10 +import org.smart4j.framework.util.ClassUtil;
  11 +
  12 +/**
  13 + * 加载相应的 Helper 类
  14 + *
  15 + * @author huangyong
  16 + * @since 2.0
  17 + *
  18 + * 执行顺序:1
  19 + */
  20 +public final class HelperLoader {
  21 +
  22 + public static void init() {
  23 + // 定义需要加载的 Helper 类
  24 + Class<?>[] classList = {
  25 + //数据库
  26 + DatabaseHelper.class,
  27 + //表--类 对应关系
  28 + EntityHelper.class,
  29 + //
  30 + ActionHelper.class,
  31 + BeanHelper.class,
  32 + AopHelper.class,
  33 + IocHelper.class,
  34 + PluginHelper.class,
  35 + };
  36 + // 按照顺序加载类
  37 + for (Class<?> cls : classList) {
  38 + ClassUtil.loadClass(cls.getName());
  39 + }
  40 + }
  41 +}
src/main/java/org/smart4j/framework/InstanceFactory.java 0 → 100644
  1 +++ a/src/main/java/org/smart4j/framework/InstanceFactory.java
  1 +package org.smart4j.framework;
  2 +
  3 +import java.util.Map;
  4 +import java.util.concurrent.ConcurrentHashMap;
  5 +import org.smart4j.framework.core.ClassScanner;
  6 +import org.smart4j.framework.core.ConfigHelper;
  7 +import org.smart4j.framework.core.impl.DefaultClassScanner;
  8 +import org.smart4j.framework.dao.DataAccessor;
  9 +import org.smart4j.framework.dao.impl.DefaultDataAccessor;
  10 +import org.smart4j.framework.ds.DataSourceFactory;
  11 +import org.smart4j.framework.ds.impl.DefaultDataSourceFactory;
  12 +import org.smart4j.framework.mvc.HandlerExceptionResolver;
  13 +import org.smart4j.framework.mvc.HandlerInvoker;
  14 +import org.smart4j.framework.mvc.HandlerMapping;
  15 +import org.smart4j.framework.mvc.ViewResolver;
  16 +import org.smart4j.framework.mvc.impl.DefaultHandlerExceptionResolver;
  17 +import org.smart4j.framework.mvc.impl.DefaultHandlerInvoker;
  18 +import org.smart4j.framework.mvc.impl.DefaultHandlerMapping;
  19 +import org.smart4j.framework.mvc.impl.DefaultViewResolver;
  20 +import org.smart4j.framework.util.ObjectUtil;
  21 +import org.smart4j.framework.util.StringUtil;
  22 +
  23 +/**
  24 + * 实例工厂
  25 + *
  26 + * @author huangyong
  27 + * @since 2.3
  28 + */
  29 +public class InstanceFactory {
  30 +
  31 + /**
  32 + * 用于缓存对应的实例
  33 + */
  34 + private static final Map<String, Object> cache = new ConcurrentHashMap<String, Object>();
  35 +
  36 + /**
  37 + * ClassScanner
  38 + */
  39 + private static final String CLASS_SCANNER = "smart.framework.custom.class_scanner";
  40 +
  41 + /**
  42 + * DataSourceFactory
  43 + */
  44 + private static final String DS_FACTORY = "smart.framework.custom.ds_factory";
  45 +
  46 + /**
  47 + * DataAccessor
  48 + */
  49 + private static final String DATA_ACCESSOR = "smart.framework.custom.data_accessor";
  50 +
  51 + /**
  52 + * HandlerMapping
  53 + */
  54 + private static final String HANDLER_MAPPING = "smart.framework.custom.handler_mapping";
  55 +
  56 + /**
  57 + * HandlerInvoker
  58 + */
  59 + private static final String HANDLER_INVOKER = "smart.framework.custom.handler_invoker";
  60 +
  61 + /**
  62 + * HandlerExceptionResolver
  63 + */
  64 + private static final String HANDLER_EXCEPTION_RESOLVER = "smart.framework.custom.handler_exception_resolver";
  65 +
  66 + /**
  67 + * ViewResolver
  68 + */
  69 + private static final String VIEW_RESOLVER = "smart.framework.custom.view_resolver";
  70 +
  71 + /**
  72 + * 获取 ClassScanner
  73 + */
  74 + public static ClassScanner getClassScanner() {
  75 + return getInstance(CLASS_SCANNER, DefaultClassScanner.class);
  76 + }
  77 +
  78 + /**
  79 + * 获取 DataSourceFactory
  80 + */
  81 + public static DataSourceFactory getDataSourceFactory() {
  82 + return getInstance(DS_FACTORY, DefaultDataSourceFactory.class);
  83 + }
  84 +
  85 + /**
  86 + * 获取 DataAccessor
  87 + */
  88 + public static DataAccessor getDataAccessor() {
  89 + return getInstance(DATA_ACCESSOR, DefaultDataAccessor.class);
  90 + }
  91 +
  92 + /**
  93 + * 获取 HandlerMapping
  94 + */
  95 + public static HandlerMapping getHandlerMapping() {
  96 + return getInstance(HANDLER_MAPPING, DefaultHandlerMapping.class);
  97 + }
  98 +
  99 + /**
  100 + * 获取 HandlerInvoker
  101 + */
  102 + public static HandlerInvoker getHandlerInvoker() {
  103 + return getInstance(HANDLER_INVOKER, DefaultHandlerInvoker.class);
  104 + }
  105 +
  106 + /**
  107 + * 获取 HandlerExceptionResolver
  108 + */
  109 + public static HandlerExceptionResolver getHandlerExceptionResolver() {
  110 + return getInstance(HANDLER_EXCEPTION_RESOLVER, DefaultHandlerExceptionResolver.class);
  111 + }
  112 +
  113 + /**
  114 + * 获取 ViewResolver
  115 + */
  116 + public static ViewResolver getViewResolver() {
  117 + return getInstance(VIEW_RESOLVER, DefaultViewResolver.class);
  118 + }
  119 +
  120 + @SuppressWarnings("unchecked")
  121 + public static <T> T getInstance(String cacheKey, Class<T> defaultImplClass) {
  122 + // 若缓存中存在对应的实例,则返回该实例
  123 + if (cache.containsKey(cacheKey)) {
  124 + return (T) cache.get(cacheKey);
  125 + }
  126 + // 从配置文件中获取相应的接口实现类配置
  127 + String implClassName = ConfigHelper.getString(cacheKey);
  128 + // 若实现类配置不存在,则使用默认实现类
  129 + if (StringUtil.isEmpty(implClassName)) {
  130 + implClassName = defaultImplClass.getName();
  131 + }
  132 + // 通过反射创建该实现类对应的实例
  133 + T instance = ObjectUtil.newInstance(implClassName);
  134 + // 若该实例不为空,则将其放入缓存
  135 + if (instance != null) {
  136 + cache.put(cacheKey, instance);
  137 + }
  138 + // 返回该实例
  139 + return instance;
  140 + }
  141 +}
src/main/java/org/smart4j/framework/aop/AopHelper.java 0 → 100644
  1 +++ a/src/main/java/org/smart4j/framework/aop/AopHelper.java
  1 +package org.smart4j.framework.aop;
  2 +
  3 +import java.lang.annotation.Annotation;
  4 +import java.util.ArrayList;
  5 +import java.util.Collections;
  6 +import java.util.Comparator;
  7 +import java.util.HashMap;
  8 +import java.util.LinkedHashMap;
  9 +import java.util.List;
  10 +import java.util.Map;
  11 +import org.smart4j.framework.FrameworkConstant;
  12 +import org.smart4j.framework.InstanceFactory;
  13 +import org.smart4j.framework.aop.annotation.Aspect;
  14 +import org.smart4j.framework.aop.annotation.AspectOrder;
  15 +import org.smart4j.framework.aop.proxy.Proxy;
  16 +import org.smart4j.framework.aop.proxy.ProxyManager;
  17 +import org.smart4j.framework.core.ClassHelper;
  18 +import org.smart4j.framework.core.ClassScanner;
  19 +import org.smart4j.framework.core.fault.InitializationError;
  20 +import org.smart4j.framework.ioc.BeanHelper;
  21 +import org.smart4j.framework.plugin.PluginProxy;
  22 +import org.smart4j.framework.tx.TransactionProxy;
  23 +import org.smart4j.framework.tx.annotation.Service;
  24 +import org.smart4j.framework.util.ClassUtil;
  25 +import org.smart4j.framework.util.CollectionUtil;
  26 +import org.smart4j.framework.util.StringUtil;
  27 +
  28 +/**
  29 + * 初始化 AOP 框架
  30 + *
  31 + * @author huangyong
  32 + * @since 1.0
  33 + */
  34 +public class AopHelper {
  35 +
  36 + /**
  37 + * 获取 ClassScanner
  38 + */
  39 + private static final ClassScanner classScanner = InstanceFactory.getClassScanner();
  40 +
  41 + static {
  42 + try {
  43 + // 创建 Proxy Map(用于 存放代理类 与 目标类列表 的映射关系)
  44 + Map<Class<?>, List<Class<?>>> proxyMap = createProxyMap();
  45 + // 创建 Target Map(用于 存放目标类 与 代理类列表 的映射关系)
  46 + Map<Class<?>, List<Proxy>> targetMap = createTargetMap(proxyMap);
  47 + // 遍历 Target Map
  48 + for (Map.Entry<Class<?>, List<Proxy>> targetEntry : targetMap.entrySet()) {
  49 + // 分别获取 map 中的 key 与 value
  50 + Class<?> targetClass = targetEntry.getKey();
  51 + List<Proxy> proxyList = targetEntry.getValue();
  52 + // 创建代理实例
  53 + Object proxyInstance = ProxyManager.createProxy(targetClass, proxyList);
  54 + // 用代理实例覆盖目标实例,并放入 Bean 容器中
  55 + BeanHelper.setBean(targetClass, proxyInstance);
  56 + }
  57 + } catch (Exception e) {
  58 + throw new InitializationError("初始化 AopHelper 出错!", e);
  59 + }
  60 + }
  61 +
  62 + private static Map<Class<?>, List<Class<?>>> createProxyMap() throws Exception {
  63 + Map<Class<?>, List<Class<?>>> proxyMap = new LinkedHashMap<Class<?>, List<Class<?>>>();
  64 + // 添加相关代理
  65 + addPluginProxy(proxyMap); // 插件代理
  66 + addAspectProxy(proxyMap); // 切面代理
  67 + addTransactionProxy(proxyMap); // 事务代理
  68 + return proxyMap;
  69 + }
  70 +
  71 + private static void addPluginProxy(Map<Class<?>, List<Class<?>>> proxyMap) throws Exception {
  72 + // 获取插件包名下父类为 PluginProxy 的所有类(插件代理类)
  73 + List<Class<?>> pluginProxyClassList = classScanner.getClassListBySuper(FrameworkConstant.PLUGIN_PACKAGE, PluginProxy.class);
  74 + if (CollectionUtil.isNotEmpty(pluginProxyClassList)) {
  75 + // 遍历所有插件代理类
  76 + for (Class<?> pluginProxyClass : pluginProxyClassList) {
  77 + // 创建插件代理类实例
  78 + PluginProxy pluginProxy = (PluginProxy) pluginProxyClass.newInstance();
  79 + // 将插件代理类及其所对应的目标类列表放入 Proxy Map 中
  80 + proxyMap.put(pluginProxyClass, pluginProxy.getTargetClassList());
  81 + }
  82 + }
  83 + }
  84 +
  85 + private static void addAspectProxy(Map<Class<?>, List<Class<?>>> proxyMap) throws Exception {
  86 + // 获取切面类(所有继承于 BaseAspect 的类)
  87 + List<Class<?>> aspectProxyClassList = ClassHelper.getClassListBySuper(AspectProxy.class);
  88 + // 添加插件包下所有的切面类
  89 + aspectProxyClassList.addAll(classScanner.getClassListBySuper(FrameworkConstant.PLUGIN_PACKAGE, AspectProxy.class));
  90 + // 排序切面类
  91 + sortAspectProxyClassList(aspectProxyClassList);
  92 + // 遍历切面类
  93 + for (Class<?> aspectProxyClass : aspectProxyClassList) {
  94 + // 判断 Aspect 注解是否存在
  95 + if (aspectProxyClass.isAnnotationPresent(Aspect.class)) {
  96 + // 获取 Aspect 注解
  97 + Aspect aspect = aspectProxyClass.getAnnotation(Aspect.class);
  98 + // 创建目标类列表
  99 + List<Class<?>> targetClassList = createTargetClassList(aspect);
  100 + // 初始化 Proxy Map
  101 + proxyMap.put(aspectProxyClass, targetClassList);
  102 + }
  103 + }
  104 + }
  105 +
  106 + private static void addTransactionProxy(Map<Class<?>, List<Class<?>>> proxyMap) {
  107 + // 使用 TransactionProxy 代理所有 Service 类
  108 + List<Class<?>> serviceClassList = ClassHelper.getClassListByAnnotation(Service.class);
  109 + proxyMap.put(TransactionProxy.class, serviceClassList);
  110 + }
  111 +
  112 + private static void sortAspectProxyClassList(List<Class<?>> proxyClassList) {
  113 + // 排序代理类列表
  114 + Collections.sort(proxyClassList, new Comparator<Class<?>>() {
  115 + @Override
  116 + public int compare(Class<?> aspect1, Class<?> aspect2) {
  117 + if (aspect1.isAnnotationPresent(AspectOrder.class) || aspect2.isAnnotationPresent(AspectOrder.class)) {
  118 + // 若有 Order 注解,则优先比较(序号的值越小越靠前)
  119 + if (aspect1.isAnnotationPresent(AspectOrder.class)) {
  120 + return getOrderValue(aspect1) - getOrderValue(aspect2);
  121 + } else {
  122 + return getOrderValue(aspect2) - getOrderValue(aspect1);
  123 + }
  124 + } else {
  125 + // 若无 Order 注解,则比较类名(按字母顺序升序排列)
  126 + return aspect1.hashCode() - aspect2.hashCode();
  127 + }
  128 + }
  129 +
  130 + private int getOrderValue(Class<?> aspect) {
  131 + return aspect.getAnnotation(AspectOrder.class) != null ? aspect.getAnnotation(AspectOrder.class).value() : 0;
  132 + }
  133 + });
  134 + }
  135 +
  136 + private static List<Class<?>> createTargetClassList(Aspect aspect) throws Exception {
  137 + List<Class<?>> targetClassList = new ArrayList<Class<?>>();
  138 + // 获取 Aspect 注解的相关属性
  139 + String pkg = aspect.pkg();
  140 + String cls = aspect.cls();
  141 + Class<? extends Annotation> annotation = aspect.annotation();
  142 + // 若包名不为空,则需进一步判断类名是否为空
  143 + if (StringUtil.isNotEmpty(pkg)) {
  144 + if (StringUtil.isNotEmpty(cls)) {
  145 + // 若类名不为空,则仅添加该类
  146 + targetClassList.add(ClassUtil.loadClass(pkg + "." + cls, false));
  147 + } else {
  148 + // 若注解不为空且不是 Aspect 注解,则添加指定包名下带有该注解的所有类
  149 + if (annotation != null && !annotation.equals(Aspect.class)) {
  150 + targetClassList.addAll(classScanner.getClassListByAnnotation(pkg, annotation));
  151 + } else {
  152 + // 否则添加该包名下所有类
  153 + targetClassList.addAll(classScanner.getClassList(pkg));
  154 + }
  155 + }
  156 + } else {
  157 + // 若注解不为空且不是 Aspect 注解,则添加应用包名下带有该注解的所有类
  158 + if (annotation != null && !annotation.equals(Aspect.class)) {
  159 + targetClassList.addAll(ClassHelper.getClassListByAnnotation(annotation));
  160 + }
  161 + }
  162 + return targetClassList;
  163 + }
  164 +
  165 + private static Map<Class<?>, List<Proxy>> createTargetMap(Map<Class<?>, List<Class<?>>> proxyMap) throws Exception {
  166 + Map<Class<?>, List<Proxy>> targetMap = new HashMap<Class<?>, List<Proxy>>();
  167 + // 遍历 Proxy Map
  168 + for (Map.Entry<Class<?>, List<Class<?>>> proxyEntry : proxyMap.entrySet()) {
  169 + // 分别获取 map 中的 key 与 value
  170 + Class<?> proxyClass = proxyEntry.getKey();
  171 + List<Class<?>> targetClassList = proxyEntry.getValue();
  172 + // 遍历目标类列表
  173 + for (Class<?> targetClass : targetClassList) {
  174 + // 创建代理类(切面类)实例
  175 + Proxy baseAspect = (Proxy) proxyClass.newInstance();
  176 + // 初始化 Target Map
  177 + if (targetMap.containsKey(targetClass)) {
  178 + targetMap.get(targetClass).add(baseAspect);
  179 + } else {
  180 + List<Proxy> baseAspectList = new ArrayList<Proxy>();
  181 + baseAspectList.add(baseAspect);
  182 + targetMap.put(targetClass, baseAspectList);
  183 + }
  184 + }
  185 + }
  186 + return targetMap;
  187 + }
  188 +}
src/main/java/org/smart4j/framework/aop/AspectProxy.java 0 → 100644
  1 +++ a/src/main/java/org/smart4j/framework/aop/AspectProxy.java
  1 +package org.smart4j.framework.aop;
  2 +
  3 +import java.lang.reflect.Method;
  4 +import org.slf4j.Logger;
  5 +import org.slf4j.LoggerFactory;
  6 +import org.smart4j.framework.aop.proxy.Proxy;
  7 +import org.smart4j.framework.aop.proxy.ProxyChain;
  8 +
  9 +/**
  10 + * 切面代理
  11 + *
  12 + * @author huangyong
  13 + * @since 2.0
  14 + */
  15 +public abstract class AspectProxy implements Proxy {
  16 +
  17 + private static final Logger logger = LoggerFactory.getLogger(AspectProxy.class);
  18 +
  19 + @Override
  20 + public final Object doProxy(ProxyChain proxyChain) throws Throwable {
  21 + Object result = null;
  22 +
  23 + Class<?> cls = proxyChain.getTargetClass();
  24 + Method method = proxyChain.getTargetMethod();
  25 + Object[] params = proxyChain.getMethodParams();
  26 +
  27 + begin();
  28 + try {
  29 + if (intercept(cls, method, params)) {
  30 + before(cls, method, params);
  31 + result = proxyChain.doProxyChain();
  32 + after(cls, method, params, result);
  33 + } else {
  34 + result = proxyChain.doProxyChain();
  35 + }
  36 + } catch (Exception e) {
  37 + logger.error("AOP 异常", e);
  38 + error(cls, method, params, e);
  39 + throw e;
  40 + } finally {
  41 + end();
  42 + }
  43 +
  44 + return result;
  45 + }
  46 +
  47 + public void begin() {
  48 + }
  49 +
  50 + public boolean intercept(Class<?> cls, Method method, Object[] params) throws Throwable {
  51 + return true;
  52 + }
  53 +
  54 + public void before(Class<?> cls, Method method, Object[] params) throws Throwable {
  55 + }
  56 +
  57 + public void after(Class<?> cls, Method method, Object[] params, Object result) throws Throwable {
  58 + }
  59 +
  60 + public void error(Class<?> cls, Method method, Object[] params, Throwable e) {
  61 + }
  62 +
  63 + public void end() {
  64 + }
  65 +}
src/main/java/org/smart4j/framework/aop/annotation/Aspect.java 0 → 100644
  1 +++ a/src/main/java/org/smart4j/framework/aop/annotation/Aspect.java
  1 +package org.smart4j.framework.aop.annotation;
  2 +
  3 +import java.lang.annotation.Annotation;
  4 +import java.lang.annotation.ElementType;
  5 +import java.lang.annotation.Retention;
  6 +import java.lang.annotation.RetentionPolicy;
  7 +import java.lang.annotation.Target;
  8 +
  9 +/**
  10 + * 定义切面类
  11 + *
  12 + * @author huangyong
  13 + * @since 1.0
  14 + */
  15 +@Target(ElementType.TYPE)
  16 +@Retention(RetentionPolicy.RUNTIME)
  17 +public @interface Aspect {
  18 +
  19 + /**
  20 + * 包名
  21 + */
  22 + String pkg() default "";
  23 +
  24 + /**
  25 + * 类名
  26 + */
  27 + String cls() default "";
  28 +
  29 + /**
  30 + * 注解
  31 + *
  32 + * @since 2.2
  33 + */
  34 + Class<? extends Annotation> annotation() default Aspect.class;
  35 +}
src/main/java/org/smart4j/framework/aop/annotation/AspectOrder.java 0 → 100644
  1 +++ a/src/main/java/org/smart4j/framework/aop/annotation/AspectOrder.java
  1 +package org.smart4j.framework.aop.annotation;
  2 +
  3 +import java.lang.annotation.ElementType;
  4 +import java.lang.annotation.Retention;
  5 +import java.lang.annotation.RetentionPolicy;
  6 +import java.lang.annotation.Target;
  7 +
  8 +/**
  9 + * 定义切面顺序
  10 + *
  11 + * @author huangyong
  12 + * @since 1.0
  13 + */
  14 +@Target(ElementType.TYPE)
  15 +@Retention(RetentionPolicy.RUNTIME)
  16 +public @interface AspectOrder {
  17 +
  18 + int value();
  19 +}
src/main/java/org/smart4j/framework/aop/proxy/Proxy.java 0 → 100644
  1 +++ a/src/main/java/org/smart4j/framework/aop/proxy/Proxy.java
  1 +package org.smart4j.framework.aop.proxy;
  2 +
  3 +/**
  4 + * 代理接口
  5 + *
  6 + * @author huangyong
  7 + * @since 2.0
  8 + */
  9 +public interface Proxy {
  10 +
  11 + /**
  12 + * 执行链式代理
  13 + *
  14 + * @param proxyChain 代理链
  15 + * @return 目标方法返回值
  16 + * @throws Throwable 异常
  17 + */
  18 + Object doProxy(ProxyChain proxyChain) throws Throwable;
  19 +}
src/main/java/org/smart4j/framework/aop/proxy/ProxyChain.java 0 → 100644
  1 +++ a/src/main/java/org/smart4j/framework/aop/proxy/ProxyChain.java
  1 +package org.smart4j.framework.aop.proxy;
  2 +
  3 +import java.lang.reflect.Method;
  4 +import java.util.ArrayList;
  5 +import java.util.List;
  6 +import net.sf.cglib.proxy.MethodProxy;
  7 +
  8 +/**
  9 + * 代理链
  10 + *
  11 + * @author huangyong
  12 + * @since 2.0
  13 + */
  14 +public class ProxyChain {
  15 +
  16 + private final Class<?> targetClass;
  17 + private final Object targetObject;
  18 + private final Method targetMethod;
  19 + private final MethodProxy methodProxy;
  20 + private final Object[] methodParams;
  21 +
  22 + private List<Proxy> proxyList = new ArrayList<Proxy>();
  23 + private int proxyIndex = 0;
  24 +
  25 + public ProxyChain(Class<?> targetClass, Object targetObject, Method targetMethod, MethodProxy methodProxy, Object[] methodParams, List<Proxy> proxyList) {
  26 + this.targetClass = targetClass;
  27 + this.targetObject = targetObject;
  28 + this.targetMethod = targetMethod;
  29 + this.methodProxy = methodProxy;
  30 + this.methodParams = methodParams;
  31 + this.proxyList = proxyList;
  32 + }
  33 +
  34 + public Object[] getMethodParams() {
  35 + return methodParams;
  36 + }
  37 +
  38 + public Class<?> getTargetClass() {
  39 + return targetClass;
  40 + }
  41 +
  42 + public Method getTargetMethod() {
  43 + return targetMethod;
  44 + }
  45 +
  46 + public Object doProxyChain() throws Throwable {
  47 + Object methodResult;
  48 + if (proxyIndex < proxyList.size()) {
  49 + methodResult = proxyList.get(proxyIndex++).doProxy(this);
  50 + } else {
  51 + methodResult = methodProxy.invokeSuper(targetObject, methodParams);
  52 + }
  53 + return methodResult;
  54 + }
  55 +}
src/main/java/org/smart4j/framework/aop/proxy/ProxyManager.java 0 → 100644
  1 +++ a/src/main/java/org/smart4j/framework/aop/proxy/ProxyManager.java
  1 +package org.smart4j.framework.aop.proxy;
  2 +
  3 +import java.lang.reflect.Method;
  4 +import java.util.List;
  5 +import net.sf.cglib.proxy.Enhancer;
  6 +import net.sf.cglib.proxy.MethodInterceptor;
  7 +import net.sf.cglib.proxy.MethodProxy;
  8 +
  9 +/**
  10 + * 代理管理器
  11 + *
  12 + * @author huangyong
  13 + * @since 2.0
  14 + */
  15 +public class ProxyManager {
  16 +
  17 + @SuppressWarnings("unchecked")
  18 + public static <T> T createProxy(final Class<?> targetClass, final List<Proxy> proxyList) {
  19 + return (T) Enhancer.create(targetClass, new MethodInterceptor() {
  20 + @Override
  21 + public Object intercept(Object targetObject, Method targetMethod, Object[] methodParams, MethodProxy methodProxy) throws Throwable {
  22 + return new ProxyChain(targetClass, targetObject, targetMethod, methodProxy, methodParams, proxyList).doProxyChain();
  23 + }
  24 + });
  25 + }
  26 +}
src/main/java/org/smart4j/framework/core/ClassHelper.java 0 → 100644
  1 +++ a/src/main/java/org/smart4j/framework/core/ClassHelper.java
  1 +package org.smart4j.framework.core;
  2 +
  3 +import java.lang.annotation.Annotation;
  4 +import java.util.List;
  5 +import org.smart4j.framework.InstanceFactory;
  6 +
  7 +/**
  8 + * 根据条件获取相关类
  9 + *
  10 + * @author huangyong
  11 + * @since 1.0
  12 + */
  13 +public class ClassHelper {
  14 +
  15 + /**
  16 + * 获取基础包名
  17 + */
  18 + private static final String basePackage = ConfigHelper.getString("smart.framework.app.base_package");
  19 +
  20 + /**
  21 + * 获取 ClassScanner
  22 + */
  23 + private static final ClassScanner classScanner = InstanceFactory.getClassScanner();
  24 +
  25 + /**
  26 + * 获取基础包名中的所有类
  27 + */
  28 + public static List<Class<?>> getClassList() {
  29 + return classScanner.getClassList(basePackage);
  30 + }
  31 +
  32 + /**
  33 + * 获取基础包名中指定父类或接口的相关类
  34 + */
  35 + public static List<Class<?>> getClassListBySuper(Class<?> superClass) {
  36 + return classScanner.getClassListBySuper(basePackage, superClass);
  37 + }
  38 +
  39 + /**
  40 + * 获取基础包名中指定注解的相关类
  41 + */
  42 + public static List<Class<?>> getClassListByAnnotation(Class<? extends Annotation> annotationClass) {
  43 + return classScanner.getClassListByAnnotation(basePackage, annotationClass);
  44 + }
  45 +}
src/main/java/org/smart4j/framework/core/ClassScanner.java 0 → 100644
  1 +++ a/src/main/java/org/smart4j/framework/core/ClassScanner.java
  1 +package org.smart4j.framework.core;
  2 +
  3 +import java.lang.annotation.Annotation;
  4 +import java.util.List;
  5 +
  6 +/**
  7 + * 类扫描器
  8 + *
  9 + * @author huangyong
  10 + * @since 2.3
  11 + */
  12 +public interface ClassScanner {
  13 +
  14 + /**
  15 + * 获取指定包名中的所有类
  16 + */
  17 + List<Class<?>> getClassList(String packageName);
  18 +
  19 + /**
  20 + * 获取指定包名中指定注解的相关类
  21 + */
  22 + List<Class<?>> getClassListByAnnotation(String packageName, Class<? extends Annotation> annotationClass);
  23 +
  24 + /**
  25 + * 获取指定包名中指定父类或接口的相关类
  26 + */
  27 + List<Class<?>> getClassListBySuper(String packageName, Class<?> superClass);
  28 +}
src/main/java/org/smart4j/framework/core/ConfigHelper.java 0 → 100644
  1 +++ a/src/main/java/org/smart4j/framework/core/ConfigHelper.java
  1 +package org.smart4j.framework.core;
  2 +
  3 +import java.util.Map;
  4 +import java.util.Properties;
  5 +import org.smart4j.framework.FrameworkConstant;
  6 +import org.smart4j.framework.util.PropsUtil;
  7 +
  8 +/**
  9 + * 获取属性文件中的属性值
  10 + *
  11 + * @author huangyong
  12 + * @since 1.0
  13 + */
  14 +public class ConfigHelper {
  15 +
  16 + /**
  17 + * 属性文件对象
  18 + */
  19 + private static final Properties configProps = PropsUtil.loadProps(FrameworkConstant.CONFIG_PROPS);
  20 +
  21 + /**
  22 + * 获取 String 类型的属性值
  23 + */
  24 + public static String getString(String key) {
  25 + return PropsUtil.getString(configProps, key);
  26 + }
  27 +
  28 + /**
  29 + * 获取 String 类型的属性值(可指定默认值)
  30 + */
  31 + public static String getString(String key, String defaultValue) {
  32 + return PropsUtil.getString(configProps, key, defaultValue);
  33 + }
  34 +
  35 + /**
  36 + * 获取 int 类型的属性值
  37 + */
  38 + public static int getInt(String key) {
  39 + return PropsUtil.getNumber(configProps, key);
  40 + }
  41 +
  42 + /**
  43 + * 获取 int 类型的属性值(可指定默认值)
  44 + */
  45 + public static int getInt(String key, int defaultValue) {
  46 + return PropsUtil.getNumber(configProps, key, defaultValue);
  47 + }
  48 +
  49 + /**
  50 + * 获取 boolean 类型的属性值
  51 + */
  52 + public static boolean getBoolean(String key) {
  53 + return PropsUtil.getBoolean(configProps, key);
  54 + }
  55 +
  56 + /**
  57 + * 获取 int 类型的属性值(可指定默认值)
  58 + */
  59 + public static boolean getBoolean(String key, boolean defaultValue) {
  60 + return PropsUtil.getBoolean(configProps, key, defaultValue);
  61 + }
  62 +
  63 + /**
  64 + * 获取指定前缀的相关属性
  65 + *
  66 + * @since 2.2
  67 + */
  68 + public static Map<String, Object> getMap(String prefix) {
  69 + return PropsUtil.getMap(configProps, prefix);
  70 + }
  71 +}
src/main/java/org/smart4j/framework/core/bean/BaseBean.java 0 → 100644
  1 +++ a/src/main/java/org/smart4j/framework/core/bean/BaseBean.java
  1 +package org.smart4j.framework.core.bean;
  2 +
  3 +import java.io.Serializable;
  4 +import org.apache.commons.lang.builder.EqualsBuilder;
  5 +import org.apache.commons.lang.builder.HashCodeBuilder;
  6 +import org.apache.commons.lang.builder.ToStringBuilder;
  7 +import org.apache.commons.lang.builder.ToStringStyle;
  8 +
  9 +/**
  10 + * 提供 Bean 类的基础特性
  11 + *
  12 + * @author huangyong
  13 + * @since 1.0
  14 + */
  15 +public abstract class BaseBean implements Serializable {
  16 +
  17 + @Override
  18 + public int hashCode() {
  19 + return HashCodeBuilder.reflectionHashCode(this);
  20 + }
  21 +
  22 + @Override
  23 + public boolean equals(Object obj) {
  24 + return EqualsBuilder.reflectionEquals(this, obj);
  25 + }
  26 +
  27 + @Override
  28 + public String toString() {
  29 + return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE);
  30 + }
  31 +}
src/main/java/org/smart4j/framework/core/fault/InitializationError.java 0 → 100644
  1 +++ a/src/main/java/org/smart4j/framework/core/fault/InitializationError.java
  1 +package org.smart4j.framework.core.fault;
  2 +
  3 +/**
  4 + * 初始化错误
  5 + *
  6 + * @author huangyong
  7 + * @since 2.2
  8 + */
  9 +public class InitializationError extends Error {
  10 +
  11 + public InitializationError() {
  12 + super();
  13 + }
  14 +
  15 + public InitializationError(String message) {
  16 + super(message);
  17 + }
  18 +
  19 + public InitializationError(String message, Throwable cause) {
  20 + super(message, cause);
  21 + }
  22 +
  23 + public InitializationError(Throwable cause) {
  24 + super(cause);
  25 + }
  26 +}
src/main/java/org/smart4j/framework/core/impl/DefaultClassScanner.java 0 → 100644
  1 +++ a/src/main/java/org/smart4j/framework/core/impl/DefaultClassScanner.java
  1 +package org.smart4j.framework.core.impl;
  2 +
  3 +import java.lang.annotation.Annotation;
  4 +import java.util.List;
  5 +import org.smart4j.framework.core.ClassScanner;
  6 +import org.smart4j.framework.core.impl.support.AnnotationClassTemplate;
  7 +import org.smart4j.framework.core.impl.support.ClassTemplate;
  8 +import org.smart4j.framework.core.impl.support.SupperClassTemplate;
  9 +
  10 +/**
  11 + * 默认类扫描器
  12 + *
  13 + * @author huangyong
  14 + * @since 2.3
  15 + */
  16 +public class DefaultClassScanner implements ClassScanner {
  17 +
  18 + @Override
  19 + public List<Class<?>> getClassList(String packageName) {
  20 + return new ClassTemplate(packageName) {
  21 + @Override
  22 + public boolean checkAddClass(Class<?> cls) {
  23 + String className = cls.getName();
  24 + String pkgName = className.substring(0, className.lastIndexOf("."));
  25 + return pkgName.startsWith(packageName);
  26 + }
  27 + }.getClassList();
  28 + }
  29 +
  30 + @Override
  31 + public List<Class<?>> getClassListByAnnotation(String packageName, Class<? extends Annotation> annotationClass) {
  32 + return new AnnotationClassTemplate(packageName, annotationClass) {
  33 + @Override
  34 + public boolean checkAddClass(Class<?> cls) {
  35 + return cls.isAnnotationPresent(annotationClass);
  36 + }
  37 + }.getClassList();
  38 + }
  39 +
  40 + @Override
  41 + public List<Class<?>> getClassListBySuper(String packageName, Class<?> superClass) {
  42 + return new SupperClassTemplate(packageName, superClass) {
  43 + @Override
  44 + public boolean checkAddClass(Class<?> cls) {
  45 + return superClass.isAssignableFrom(cls) && !superClass.equals(cls);
  46 + }
  47 + }.getClassList();
  48 + }
  49 +}
src/main/java/org/smart4j/framework/core/impl/support/AnnotationClassTemplate.java 0 → 100644
  1 +++ a/src/main/java/org/smart4j/framework/core/impl/support/AnnotationClassTemplate.java
  1 +package org.smart4j.framework.core.impl.support;
  2 +
  3 +import java.lang.annotation.Annotation;
  4 +
  5 +/**
  6 + * 用于获取注解类的模板类
  7 + *
  8 + * @author huangyong
  9 + * @since 2.3
  10 + */
  11 +public abstract class AnnotationClassTemplate extends ClassTemplate {
  12 +
  13 + protected final Class<? extends Annotation> annotationClass;
  14 +
  15 + protected AnnotationClassTemplate(String packageName, Class<? extends Annotation> annotationClass) {
  16 + super(packageName);
  17 + this.annotationClass = annotationClass;
  18 + }
  19 +}
src/main/java/org/smart4j/framework/core/impl/support/ClassTemplate.java 0 → 100644
  1 +++ a/src/main/java/org/smart4j/framework/core/impl/support/ClassTemplate.java
  1 +package org.smart4j.framework.core.impl.support;
  2 +
  3 +import java.io.File;
  4 +import java.io.FileFilter;
  5 +import java.net.JarURLConnection;
  6 +import java.net.URL;
  7 +import java.util.ArrayList;
  8 +import java.util.Enumeration;
  9 +import java.util.List;
  10 +import java.util.jar.JarEntry;
  11 +import java.util.jar.JarFile;
  12 +import org.slf4j.Logger;
  13 +import org.slf4j.LoggerFactory;
  14 +import org.smart4j.framework.util.ClassUtil;
  15 +import org.smart4j.framework.util.StringUtil;
  16 +
  17 +/**
  18 + * 用于获取类的模板类
  19 + *
  20 + * @author huangyong
  21 + * @since 2.3
  22 + */
  23 +public abstract class ClassTemplate {
  24 +
  25 + private static final Logger logger = LoggerFactory.getLogger(ClassTemplate.class);
  26 +
  27 + protected final String packageName;
  28 +
  29 + protected ClassTemplate(String packageName) {
  30 + this.packageName = packageName;
  31 + }
  32 +
  33 + public final List<Class<?>> getClassList() {
  34 + List<Class<?>> classList = new ArrayList<Class<?>>();
  35 + try {
  36 + // 从包名获取 URL 类型的资源
  37 + Enumeration<URL> urls = ClassUtil.getClassLoader().getResources(packageName.replace(".", "/"));
  38 + // 遍历 URL 资源
  39 + while (urls.hasMoreElements()) {
  40 + URL url = urls.nextElement();
  41 + if (url != null) {
  42 + // 获取协议名(分为 file 与 jar)
  43 + String protocol = url.getProtocol();
  44 + if (protocol.equals("file")) {
  45 + // 若在 class 目录中,则执行添加类操作
  46 + String packagePath = url.getPath().replaceAll("%20", " ");
  47 + addClass(classList, packagePath, packageName);
  48 + } else if (protocol.equals("jar")) {
  49 + // 若在 jar 包中,则解析 jar 包中的 entry
  50 + JarURLConnection jarURLConnection = (JarURLConnection) url.openConnection();
  51 + JarFile jarFile = jarURLConnection.getJarFile();
  52 + Enumeration<JarEntry> jarEntries = jarFile.entries();
  53 + while (jarEntries.hasMoreElements()) {
  54 + JarEntry jarEntry = jarEntries.nextElement();
  55 + String jarEntryName = jarEntry.getName();
  56 + // 判断该 entry 是否为 class
  57 + if (jarEntryName.endsWith(".class")) {
  58 + // 获取类名
  59 + String className = jarEntryName.substring(0, jarEntryName.lastIndexOf(".")).replaceAll("/", ".");
  60 + // 执行添加类操作
  61 + doAddClass(classList, className);
  62 + }
  63 + }
  64 + }
  65 + }
  66 + }
  67 + } catch (Exception e) {
  68 + logger.error("获取类出错!", e);
  69 + }
  70 + return classList;
  71 + }
  72 +
  73 + private void addClass(List<Class<?>> classList, String packagePath, String packageName) {
  74 + try {
  75 + // 获取包名路径下的 class 文件或目录
  76 + File[] files = new File(packagePath).listFiles(new FileFilter() {
  77 + @Override
  78 + public boolean accept(File file) {
  79 + return (file.isFile() && file.getName().endsWith(".class")) || file.isDirectory();
  80 + }
  81 + });
  82 + // 遍历文件或目录
  83 + for (File file : files) {
  84 + String fileName = file.getName();
  85 + // 判断是否为文件或目录
  86 + if (file.isFile()) {
  87 + // 获取类名
  88 + String className = fileName.substring(0, fileName.lastIndexOf("."));
  89 + if (StringUtil.isNotEmpty(packageName)) {
  90 + className = packageName + "." + className;
  91 + }
  92 + // 执行添加类操作
  93 + doAddClass(classList, className);
  94 + } else {
  95 + // 获取子包
  96 + String subPackagePath = fileName;
  97 + if (StringUtil.isNotEmpty(packagePath)) {
  98 + subPackagePath = packagePath + "/" + subPackagePath;
  99 + }
  100 + // 子包名
  101 + String subPackageName = fileName;
  102 + if (StringUtil.isNotEmpty(packageName)) {
  103 + subPackageName = packageName + "." + subPackageName;
  104 + }
  105 + // 递归调用
  106 + addClass(classList, subPackagePath, subPackageName);
  107 + }
  108 + }
  109 + } catch (Exception e) {
  110 + logger.error("添加类出错!", e);
  111 + }
  112 + }
  113 +
  114 + private void doAddClass(List<Class<?>> classList, String className) {
  115 + // 加载类
  116 + Class<?> cls = ClassUtil.loadClass(className, false);
  117 + // 判断是否可以添加类
  118 + if (checkAddClass(cls)) {
  119 + // 添加类
  120 + classList.add(cls);
  121 + }
  122 + }
  123 +
  124 + /**
  125 + * 验证是否允许添加类
  126 + */
  127 + public abstract boolean checkAddClass(Class<?> cls);
  128 +}
0 \ No newline at end of file 129 \ No newline at end of file
src/main/java/org/smart4j/framework/core/impl/support/SupperClassTemplate.java 0 → 100644
  1 +++ a/src/main/java/org/smart4j/framework/core/impl/support/SupperClassTemplate.java
  1 +package org.smart4j.framework.core.impl.support;
  2 +
  3 +/**
  4 + * 用于获取子类的模板类
  5 + *
  6 + * @author huangyong
  7 + * @since 2.3
  8 + */
  9 +public abstract class SupperClassTemplate extends ClassTemplate {
  10 +
  11 + protected final Class<?> superClass;
  12 +
  13 + protected SupperClassTemplate(String packageName, Class<?> superClass) {
  14 + super(packageName);
  15 + this.superClass = superClass;
  16 + }
  17 +}
src/main/java/org/smart4j/framework/dao/DataAccessor.java 0 → 100644
  1 +++ a/src/main/java/org/smart4j/framework/dao/DataAccessor.java
  1 +package org.smart4j.framework.dao;
  2 +
  3 +import java.io.Serializable;
  4 +import java.util.List;
  5 +import java.util.Map;
  6 +
  7 +/**
  8 + * 数据访问器
  9 + *
  10 + * @author huangyong
  11 + * @since 2.3
  12 + */
  13 +public interface DataAccessor {
  14 +
  15 + /**
  16 + * 查询对应的实体,返回单条记录
  17 + */
  18 + <T> T queryEntity(Class<T> entityClass, String sql, Object... params);
  19 +
  20 + /**
  21 + * 查询对应的实体列表,返回多条记录
  22 + */
  23 + <T> List<T> queryEntityList(Class<T> entityClass, String sql, Object... params);
  24 +
  25 + /**
  26 + * 查询对应的实体列表,返回单条记录(主键 => 实体)
  27 + */
  28 + <K, V> Map<K, V> queryEntityMap(Class<V> entityClass, String sql, Object... params);
  29 +
  30 + /**
  31 + * 查询对应的数据,返回单条记录
  32 + */
  33 + Object[] queryArray(String sql, Object... params);
  34 +
  35 + /**
  36 + * 查询对应的数据,返回多条记录
  37 + */
  38 + List<Object[]> queryArrayList(String sql, Object... params);
  39 +
  40 + /**
  41 + * 查询对应的数据,返回单条记录(列名 => 数据)
  42 + */
  43 + Map<String, Object> queryMap(String sql, Object... params);
  44 +
  45 + /**
  46 + * 查询对应的数据,返回多条记录(列名 => 数据)
  47 + */
  48 + List<Map<String, Object>> queryMapList(String sql, Object... params);
  49 +
  50 + /**
  51 + * 查询对应的数据,返回单条数据(列名 => 数据)
  52 + */
  53 + <T> T queryColumn(String sql, Object... params);
  54 +
  55 + /**
  56 + * 查询对应的数据,返回多条数据(列名 => 数据)
  57 + */
  58 + <T> List<T> queryColumnList(String sql, Object... params);
  59 +
  60 + /**
  61 + * 查询指定列名对应的数据,返回多条数据(列名对应的数据 => 列名与数据的映射关系)
  62 + */
  63 + <T> Map<T, Map<String, Object>> queryColumnMap(String column, String sql, Object... params);
  64 +
  65 + /**
  66 + * 查询记录条数,返回总记录数
  67 + */
  68 + long queryCount(String sql, Object... params);
  69 +
  70 + /**
  71 + * 执行更新操作(包括:update、insert、delete),返回所更新的记录数
  72 + */
  73 + int update(String sql, Object... params);
  74 +
  75 + /**
  76 + * 插入一条记录,返回插入后的主键
  77 + */
  78 + Serializable insertReturnPK(String sql, Object... params);
  79 +}
src/main/java/org/smart4j/framework/dao/DatabaseHelper.java 0 → 100644
  1 +++ a/src/main/java/org/smart4j/framework/dao/DatabaseHelper.java
  1 +package org.smart4j.framework.dao;
  2 +
  3 +import java.io.File;
  4 +import java.io.Serializable;
  5 +import java.sql.Connection;
  6 +import java.sql.SQLException;
  7 +import java.util.List;
  8 +import java.util.Map;
  9 +import javax.sql.DataSource;
  10 +import org.apache.commons.io.FileUtils;
  11 +import org.slf4j.Logger;
  12 +import org.slf4j.LoggerFactory;
  13 +import org.smart4j.framework.InstanceFactory;
  14 +import org.smart4j.framework.core.ConfigHelper;
  15 +import org.smart4j.framework.ds.DataSourceFactory;
  16 +import org.smart4j.framework.util.ClassUtil;
  17 +
  18 +/**
  19 + * 封装数据库相关操作
  20 + *
  21 + * @author huangyong
  22 + * @since 1.0
  23 + */
  24 +public class DatabaseHelper {
  25 +
  26 + private static final Logger logger = LoggerFactory.getLogger(DatabaseHelper.class);
  27 +
  28 + /**
  29 + * 定义一个局部线程变量(使每个线程都拥有自己的连接)
  30 + */
  31 + private static final ThreadLocal<Connection> connContainer = new ThreadLocal<Connection>();
  32 +
  33 + /**
  34 + * 获取数据源工厂
  35 + */
  36 + private static final DataSourceFactory dataSourceFactory = InstanceFactory.getDataSourceFactory();
  37 +
  38 + /**
  39 + * 获取数据访问器
  40 + */
  41 + private static final DataAccessor dataAccessor = InstanceFactory.getDataAccessor();
  42 +
  43 + /**
  44 + * 数据库类型
  45 + */
  46 + private static final String databaseType = ConfigHelper.getString("smart.framework.jdbc.type");
  47 +
  48 + /**
  49 + * 获取数据库类型
  50 + */
  51 + public static String getDatabaseType() {
  52 + return databaseType;
  53 + }
  54 +
  55 + /**
  56 + * 获取数据源
  57 + */
  58 + public static DataSource getDataSource() {
  59 + return dataSourceFactory.getDataSource();
  60 + }
  61 +
  62 + /**
  63 + * 获取数据库连接
  64 + */
  65 + public static Connection getConnection() {
  66 + Connection conn;
  67 + try {
  68 + // 先从 ThreadLocal 中获取 Connection
  69 + conn = connContainer.get();
  70 + if (conn == null) {
  71 + // 若不存在,则从 DataSource 中获取 Connection
  72 + conn = getDataSource().getConnection();
  73 + // 将 Connection 放入 ThreadLocal 中
  74 + if (conn != null) {
  75 + connContainer.set(conn);
  76 + }
  77 + }
  78 + } catch (SQLException e) {
  79 + logger.error("获取数据库连接出错!", e);
  80 + throw new RuntimeException(e);
  81 + }
  82 + return conn;
  83 + }
  84 +
  85 + /**
  86 + * 开启事务
  87 + */
  88 + public static void beginTransaction() {
  89 + Connection conn = getConnection();
  90 + if (conn != null) {
  91 + try {
  92 + conn.setAutoCommit(false);
  93 + } catch (SQLException e) {
  94 + logger.error("开启事务出错!", e);
  95 + throw new RuntimeException(e);
  96 + } finally {
  97 + connContainer.set(conn);
  98 + }
  99 + }
  100 + }
  101 +
  102 + /**
  103 + * 提交事务
  104 + */
  105 + public static void commitTransaction() {
  106 + Connection conn = getConnection();
  107 + if (conn != null) {
  108 + try {
  109 + conn.commit();
  110 + conn.close();
  111 + } catch (SQLException e) {
  112 + logger.error("提交事务出错!", e);
  113 + throw new RuntimeException(e);
  114 + } finally {
  115 + connContainer.remove();
  116 + }
  117 + }
  118 + }
  119 +
  120 + /**
  121 + * 回滚事务
  122 + */
  123 + public static void rollbackTransaction() {
  124 + Connection conn = getConnection();
  125 + if (conn != null) {
  126 + try {
  127 + conn.rollback();
  128 + conn.close();
  129 + } catch (SQLException e) {
  130 + logger.error("回滚事务出错!", e);
  131 + throw new RuntimeException(e);
  132 + } finally {
  133 + connContainer.remove();
  134 + }
  135 + }
  136 + }
  137 +
  138 + /**
  139 + * 初始化 SQL 脚本
  140 + */
  141 + public static void initSQL(String sqlPath) {
  142 + try {
  143 + File sqlFile = new File(ClassUtil.getClassPath() + sqlPath);
  144 + List<String> sqlList = FileUtils.readLines(sqlFile);
  145 + for (String sql : sqlList) {
  146 + update(sql);
  147 + }
  148 + } catch (Exception e) {
  149 + logger.error("初始化 SQL 脚本出错!", e);
  150 + throw new RuntimeException(e);
  151 + }
  152 + }
  153 +
  154 + /**
  155 + * 根据 SQL 语句查询 Entity
  156 + */
  157 + public static <T> T queryEntity(Class<T> entityClass, String sql, Object... params) {
  158 + return dataAccessor.queryEntity(entityClass, sql, params);
  159 + }
  160 +
  161 + /**
  162 + * 根据 SQL 语句查询 Entity 列表
  163 + */
  164 + public static <T> List<T> queryEntityList(Class<T> entityClass, String sql, Object... params) {
  165 + return dataAccessor.queryEntityList(entityClass, sql, params);
  166 + }
  167 +
  168 + /**
  169 + * 根据 SQL 语句查询 Entity 映射(Field Name => Field Value)
  170 + */
  171 + public static <K, V> Map<K, V> queryEntityMap(Class<V> entityClass, String sql, Object... params) {
  172 + return dataAccessor.queryEntityMap(entityClass, sql, params);
  173 + }
  174 +
  175 + /**
  176 + * 根据 SQL 语句查询 Array 格式的字段(单条记录)
  177 + */
  178 + public static Object[] queryArray(String sql, Object... params) {
  179 + return dataAccessor.queryArray(sql, params);
  180 + }
  181 +
  182 + /**
  183 + * 根据 SQL 语句查询 Array 格式的字段列表(多条记录)
  184 + */
  185 + public static List<Object[]> queryArrayList(String sql, Object... params) {
  186 + return dataAccessor.queryArrayList(sql, params);
  187 + }
  188 +
  189 + /**
  190 + * 根据 SQL 语句查询 Map 格式的字段(单条记录)
  191 + */
  192 + public static Map<String, Object> queryMap(String sql, Object... params) {
  193 + return dataAccessor.queryMap(sql, params);
  194 + }
  195 +
  196 + /**
  197 + * 根据 SQL 语句查询 Map 格式的字段列表(多条记录)
  198 + */
  199 + public static List<Map<String, Object>> queryMapList(String sql, Object... params) {
  200 + return dataAccessor.queryMapList(sql, params);
  201 + }
  202 +
  203 + /**
  204 + * 根据 SQL 语句查询指定字段(单条记录)
  205 + */
  206 + public static <T> T queryColumn(String sql, Object... params) {
  207 + return dataAccessor.queryColumn(sql, params);
  208 + }
  209 +
  210 + /**
  211 + * 根据 SQL 语句查询指定字段列表(多条记录)
  212 + */
  213 + public static <T> List<T> queryColumnList(String sql, Object... params) {
  214 + return dataAccessor.queryColumnList(sql, params);
  215 + }
  216 +
  217 + /**
  218 + * 根据 SQL 语句查询指定字段映射(多条记录)
  219 + */
  220 + public static <T> Map<T, Map<String, Object>> queryColumnMap(String column, String sql, Object... params) {
  221 + return dataAccessor.queryColumnMap(column, sql, params);
  222 + }
  223 +
  224 + /**
  225 + * 根据 SQL 语句查询记录条数
  226 + */
  227 + public static long queryCount(String sql, Object... params) {
  228 + return dataAccessor.queryCount(sql, params);
  229 + }
  230 +
  231 + /**
  232 + * 执行更新语句(包括:update、insert、delete)
  233 + */
  234 + public static int update(String sql, Object... params) {
  235 + return dataAccessor.update(sql, params);
  236 + }
  237 +
  238 + /**
  239 + * 执行插入语句,返回插入后的主键
  240 + */
  241 + public static Serializable insertReturnPK(String sql, Object... params) {
  242 + return dataAccessor.insertReturnPK(sql, params);
  243 + }
  244 +}
src/main/java/org/smart4j/framework/dao/SqlHelper.java 0 → 100644
  1 +++ a/src/main/java/org/smart4j/framework/dao/SqlHelper.java
  1 +package org.smart4j.framework.dao;
  2 +
  3 +import java.util.Collection;
  4 +import java.util.Map;
  5 +import java.util.Properties;
  6 +import org.smart4j.framework.FrameworkConstant;
  7 +import org.smart4j.framework.orm.EntityHelper;
  8 +import org.smart4j.framework.util.CollectionUtil;
  9 +import org.smart4j.framework.util.MapUtil;
  10 +import org.smart4j.framework.util.PropsUtil;
  11 +import org.smart4j.framework.util.StringUtil;
  12 +
  13 +/**
  14 + * 封装 SQL 语句相关操作
  15 + *
  16 + * @author huangyong
  17 + * @since 1.0
  18 + */
  19 +public class SqlHelper {
  20 +
  21 + /**
  22 + * SQL 属性文件对象
  23 + */
  24 + private static final Properties sqlProps = PropsUtil.loadProps(FrameworkConstant.SQL_PROPS);
  25 +
  26 + /**
  27 + * 从 SQL 属性文件中获取相应的 SQL 语句
  28 + */
  29 + public static String getSql(String key) {
  30 + String sql;
  31 + if (sqlProps.containsKey(key)) {
  32 + sql = sqlProps.getProperty(key);
  33 + } else {
  34 + throw new RuntimeException("无法在 " + FrameworkConstant.SQL_PROPS + " 文件中获取属性:" + key);
  35 + }
  36 + return sql;
  37 + }
  38 +
  39 + /**
  40 + * 生成 select 语句
  41 + */
  42 + public static String generateSelectSql(Class<?> entityClass, String condition, String sort) {
  43 + StringBuilder sql = new StringBuilder("select * from ").append(getTable(entityClass));
  44 + sql.append(generateWhere(condition));
  45 + sql.append(generateOrder(sort));
  46 + return sql.toString();
  47 + }
  48 +
  49 + /**
  50 + * 生成 insert 语句
  51 + */
  52 + public static String generateInsertSql(Class<?> entityClass, Collection<String> fieldNames) {
  53 + StringBuilder sql = new StringBuilder("insert into ").append(getTable(entityClass));
  54 + if (CollectionUtil.isNotEmpty(fieldNames)) {
  55 + int i = 0;
  56 + StringBuilder columns = new StringBuilder(" ");
  57 + StringBuilder values = new StringBuilder(" values ");
  58 + for (String fieldName : fieldNames) {
  59 + String columnName = EntityHelper.getColumnName(entityClass, fieldName);
  60 + if (i == 0) {
  61 + columns.append("(").append(columnName);
  62 + values.append("(?");
  63 + } else {
  64 + columns.append(", ").append(columnName);
  65 + values.append(", ?");
  66 + }
  67 + if (i == fieldNames.size() - 1) {
  68 + columns.append(")");
  69 + values.append(")");
  70 + }
  71 + i++;
  72 + }
  73 + sql.append(columns).append(values);
  74 + }
  75 + return sql.toString();
  76 + }
  77 +
  78 + /**
  79 + * 生成 delete 语句
  80 + */
  81 + public static String generateDeleteSql(Class<?> entityClass, String condition) {
  82 + StringBuilder sql = new StringBuilder("delete from ").append(getTable(entityClass));
  83 + sql.append(generateWhere(condition));
  84 + return sql.toString();
  85 + }
  86 +
  87 + /**
  88 + * 生成 update 语句
  89 + */
  90 + public static String generateUpdateSql(Class<?> entityClass, Map<String, Object> fieldMap, String condition) {
  91 + StringBuilder sql = new StringBuilder("update ").append(getTable(entityClass));
  92 + if (MapUtil.isNotEmpty(fieldMap)) {
  93 + sql.append(" set ");
  94 + int i = 0;
  95 + for (Map.Entry<String, Object> fieldEntry : fieldMap.entrySet()) {
  96 + String fieldName = fieldEntry.getKey();
  97 + String columnName = EntityHelper.getColumnName(entityClass, fieldName);
  98 + if (i == 0) {
  99 + sql.append(columnName).append(" = ?");
  100 + } else {
  101 + sql.append(", ").append(columnName).append(" = ?");
  102 + }
  103 + i++;
  104 + }
  105 + }
  106 + sql.append(generateWhere(condition));
  107 + return sql.toString();
  108 + }
  109 +
  110 + /**
  111 + * 生成 select count(*) 语句
  112 + */
  113 + public static String generateSelectSqlForCount(Class<?> entityClass, String condition) {
  114 + StringBuilder sql = new StringBuilder("select count(*) from ").append(getTable(entityClass));
  115 + sql.append(generateWhere(condition));
  116 + return sql.toString();
  117 + }
  118 +
  119 + /**
  120 + * 生成 select 分页语句(数据库类型为:mysql、oracle、mssql)
  121 + */
  122 + public static String generateSelectSqlForPager(int pageNumber, int pageSize, Class<?> entityClass, String condition, String sort) {
  123 + StringBuilder sql = new StringBuilder();
  124 + String table = getTable(entityClass);
  125 + String where = generateWhere(condition);
  126 + String order = generateOrder(sort);
  127 + String dbType = DatabaseHelper.getDatabaseType();
  128 + if (dbType.equalsIgnoreCase("mysql")) {
  129 + int pageStart = (pageNumber - 1) * pageSize;
  130 + appendSqlForMySql(sql, table, where, order, pageStart, pageSize);
  131 + } else if (dbType.equalsIgnoreCase("oracle")) {
  132 + int pageStart = (pageNumber - 1) * pageSize + 1;
  133 + int pageEnd = pageStart + pageSize;
  134 + appendSqlForOracle(sql, table, where, order, pageStart, pageEnd);
  135 + } else if (dbType.equalsIgnoreCase("mssql")) {
  136 + int pageStart = (pageNumber - 1) * pageSize;
  137 + appendSqlForMsSql(sql, table, where, order, pageStart, pageSize);
  138 + }
  139 + return sql.toString();
  140 + }
  141 +
  142 + private static String getTable(Class<?> entityClass) {
  143 + return EntityHelper.getTableName(entityClass);
  144 + }
  145 +
  146 + private static String generateWhere(String condition) {
  147 + String where = "";
  148 + if (StringUtil.isNotEmpty(condition)) {
  149 + where += " where " + condition;
  150 + }
  151 + return where;
  152 + }
  153 +
  154 + private static String generateOrder(String sort) {
  155 + String order = "";
  156 + if (StringUtil.isNotEmpty(sort)) {
  157 + order += " order by " + sort;
  158 + }
  159 + return order;
  160 + }
  161 +
  162 + private static void appendSqlForMySql(StringBuilder sql, String table, String where, String order, int pageStart, int pageEnd) {
  163 + /*
  164 + select * from 表名 where 条件 order by 排序 limit 开始位置, 结束位置
  165 + */
  166 + sql.append("select * from ").append(table);
  167 + sql.append(where);
  168 + sql.append(order);
  169 + sql.append(" limit ").append(pageStart).append(", ").append(pageEnd);
  170 + }
  171 +
  172 + private static void appendSqlForOracle(StringBuilder sql, String table, String where, String order, int pageStart, int pageEnd) {
  173 + /*
  174 + select a.* from (
  175 + select rownum rn, t.* from 表名 t where 条件 order by 排序
  176 + ) a
  177 + where a.rn >= 开始位置 and a.rn < 结束位置
  178 + */
  179 + sql.append("select a.* from (select rownum rn, t.* from ").append(table).append(" t");
  180 + sql.append(where);
  181 + sql.append(order);
  182 + sql.append(") a where a.rn >= ").append(pageStart).append(" and a.rn < ").append(pageEnd);
  183 + }
  184 +
  185 + private static void appendSqlForMsSql(StringBuilder sql, String table, String where, String order, int pageStart, int pageEnd) {
  186 + /*
  187 + select top 结束位置 * from 表名 where 条件 and id not in (
  188 + select top 开始位置 id from 表名 where 条件 order by 排序
  189 + ) order by 排序
  190 + */
  191 + sql.append("select top ").append(pageEnd).append(" * from ").append(table);
  192 + if (StringUtil.isNotEmpty(where)) {
  193 + sql.append(where).append(" and ");
  194 + } else {
  195 + sql.append(" where ");
  196 + }
  197 + sql.append("id not in (select top ").append(pageStart).append(" id from ").append(table);
  198 + sql.append(where);
  199 + sql.append(order);
  200 + sql.append(") ").append(order);
  201 + }
  202 +}
src/main/java/org/smart4j/framework/dao/bean/Pager.java 0 → 100644
  1 +++ a/src/main/java/org/smart4j/framework/dao/bean/Pager.java
  1 +package org.smart4j.framework.dao.bean;
  2 +
  3 +import java.util.List;
  4 +import org.smart4j.framework.core.bean.BaseBean;
  5 +
  6 +/**
  7 + * 分页对象
  8 + *
  9 + * @author huangyong
  10 + * @since 1.0
  11 + */
  12 +public class Pager<T> extends BaseBean {
  13 +
  14 + private int pageNumber; // 页面编号
  15 + private int pageSize; // 每页条数
  16 + private long totalRecord; // 总记录数
  17 + private long totalPage; // 总页面数
  18 + private int next_cursor; // 下一页页标
  19 + private List<T> recordList; // 数据列表
  20 +
  21 + public Pager() {
  22 + }
  23 +
  24 + public Pager(int pageNumber, int pageSize, long totalRecord, List<T> recordList) {
  25 + this.pageNumber = pageNumber;
  26 + this.pageSize = pageSize;
  27 + this.totalRecord = totalRecord;
  28 + this.recordList = recordList;
  29 + if (pageSize != 0) {
  30 + totalPage = totalRecord % pageSize == 0 ? totalRecord / pageSize : totalRecord / pageSize + 1;
  31 + }
  32 + if (pageNumber < totalPage) {
  33 + this.next_cursor = pageNumber + 1;
  34 + }
  35 + }
  36 +
  37 + public int getNext_cursor() {
  38 + return next_cursor;
  39 + }
  40 +
  41 + public int getPageNumber() {
  42 + return pageNumber;
  43 + }
  44 +
  45 + public int getPageSize() {
  46 + return pageSize;
  47 + }
  48 +
  49 + public long getTotalRecord() {
  50 + return totalRecord;
  51 + }
  52 +
  53 + public long getTotalPage() {
  54 + return totalPage;
  55 + }
  56 +
  57 + public List<T> getRecordList() {
  58 + return recordList;
  59 + }
  60 +
  61 + public boolean isFirstPage() {
  62 + return pageNumber == 1;
  63 + }
  64 +
  65 + public boolean isLastPage() {
  66 + return pageNumber == totalPage;
  67 + }
  68 +
  69 + public boolean isPrevPage() {
  70 + return pageNumber > 1 && pageNumber <= totalPage;
  71 + }
  72 +
  73 + public boolean isNextPage() {
  74 + return pageNumber < totalPage;
  75 + }
  76 +}
src/main/java/org/smart4j/framework/dao/impl/DefaultDataAccessor.java 0 → 100644
  1 +++ a/src/main/java/org/smart4j/framework/dao/impl/DefaultDataAccessor.java
  1 +package org.smart4j.framework.dao.impl;
  2 +
  3 +import java.io.Serializable;
  4 +import java.sql.Connection;
  5 +import java.sql.PreparedStatement;
  6 +import java.sql.ResultSet;
  7 +import java.sql.SQLException;
  8 +import java.util.List;
  9 +import java.util.Map;
  10 +
  11 +import javax.sql.DataSource;
  12 +
  13 +import org.apache.commons.dbutils.BasicRowProcessor;
  14 +import org.apache.commons.dbutils.BeanProcessor;
  15 +import org.apache.commons.dbutils.QueryRunner;
  16 +import org.apache.commons.dbutils.handlers.ArrayHandler;
  17 +import org.apache.commons.dbutils.handlers.ArrayListHandler;
  18 +import org.apache.commons.dbutils.handlers.BeanHandler;
  19 +import org.apache.commons.dbutils.handlers.BeanListHandler;
  20 +import org.apache.commons.dbutils.handlers.BeanMapHandler;
  21 +import org.apache.commons.dbutils.handlers.ColumnListHandler;
  22 +import org.apache.commons.dbutils.handlers.KeyedHandler;
  23 +import org.apache.commons.dbutils.handlers.MapHandler;
  24 +import org.apache.commons.dbutils.handlers.MapListHandler;
  25 +import org.apache.commons.dbutils.handlers.ScalarHandler;
  26 +import org.slf4j.Logger;
  27 +import org.slf4j.LoggerFactory;
  28 +import org.smart4j.framework.dao.DataAccessor;
  29 +import org.smart4j.framework.dao.DatabaseHelper;
  30 +import org.smart4j.framework.orm.EntityHelper;
  31 +import org.smart4j.framework.util.ArrayUtil;
  32 +import org.smart4j.framework.util.MapUtil;
  33 +
  34 +/**
  35 + * 默认数据访问器 <br/>
  36 + * 基于 Apache Commons DbUtils 实现
  37 + *
  38 + * @author huangyong
  39 + * @since 2.3
  40 + */
  41 +public class DefaultDataAccessor implements DataAccessor {
  42 +
  43 + private static final Logger logger = LoggerFactory.getLogger(DefaultDataAccessor.class);
  44 +
  45 + private final QueryRunner queryRunner;
  46 +
  47 + public DefaultDataAccessor() {
  48 + DataSource dataSource = DatabaseHelper.getDataSource();
  49 + queryRunner = new QueryRunner(dataSource);
  50 + }
  51 +
  52 + @Override
  53 + public <T> T queryEntity(Class<T> entityClass, String sql, Object... params) {
  54 + T result;
  55 + try {
  56 + Map<String, String> columnMap = EntityHelper.getColumnMap(entityClass);
  57 + if (MapUtil.isNotEmpty(columnMap)) {
  58 + result = queryRunner.query(sql, new BeanHandler<T>(entityClass, new BasicRowProcessor(new BeanProcessor(columnMap))), params);
  59 + } else {
  60 + result = queryRunner.query(sql, new BeanHandler<T>(entityClass), params);
  61 + }
  62 + } catch (SQLException e) {
  63 + logger.error("查询出错!", e);
  64 + throw new RuntimeException(e);
  65 + }
  66 + printSQL(sql);
  67 + return result;
  68 + }
  69 +
  70 + @Override
  71 + public <T> List<T> queryEntityList(Class<T> entityClass, String sql, Object... params) {
  72 + List<T> result;
  73 + try {
  74 + Map<String, String> columnMap = EntityHelper.getColumnMap(entityClass);
  75 + if (MapUtil.isNotEmpty(columnMap)) {
  76 + result = queryRunner.query(sql, new BeanListHandler<T>(entityClass, new BasicRowProcessor(new BeanProcessor(columnMap))), params);
  77 + } else {
  78 + result = queryRunner.query(sql, new BeanListHandler<T>(entityClass), params);
  79 + }
  80 + } catch (SQLException e) {
  81 + logger.error("查询出错!", e);
  82 + throw new RuntimeException(e);
  83 + }
  84 + printSQL(sql);
  85 + return result;
  86 + }
  87 +
  88 + @Override
  89 + public <K, V> Map<K, V> queryEntityMap(Class<V> entityClass, String sql, Object... params) {
  90 + Map<K, V> entityMap;
  91 + try {
  92 + entityMap = queryRunner.query(sql, new BeanMapHandler<K, V>(entityClass), params);
  93 + } catch (SQLException e) {
  94 + logger.error("查询出错!", e);
  95 + throw new RuntimeException(e);
  96 + }
  97 + printSQL(sql);
  98 + return entityMap;
  99 + }
  100 +
  101 + @Override
  102 + public Object[] queryArray(String sql, Object... params) {
  103 + Object[] array;
  104 + try {
  105 + array = queryRunner.query(sql, new ArrayHandler(), params);
  106 + } catch (SQLException e) {
  107 + logger.error("查询出错!", e);
  108 + throw new RuntimeException(e);
  109 + }
  110 + printSQL(sql);
  111 + return array;
  112 + }
  113 +
  114 + @Override
  115 + public List<Object[]> queryArrayList(String sql, Object... params) {
  116 + List<Object[]> arrayList;
  117 + try {
  118 + arrayList = queryRunner.query(sql, new ArrayListHandler(), params);
  119 + } catch (SQLException e) {
  120 + logger.error("查询出错!", e);
  121 + throw new RuntimeException(e);
  122 + }
  123 + printSQL(sql);
  124 + return arrayList;
  125 + }
  126 +
  127 + @Override
  128 + public Map<String, Object> queryMap(String sql, Object... params) {
  129 + Map<String, Object> map;
  130 + try {
  131 + map = queryRunner.query(sql, new MapHandler(), params);
  132 + } catch (SQLException e) {
  133 + logger.error("查询出错!", e);
  134 + throw new RuntimeException(e);
  135 + }
  136 + printSQL(sql);
  137 + return map;
  138 + }
  139 +
  140 + @Override
  141 + public List<Map<String, Object>> queryMapList(String sql, Object... params) {
  142 + List<Map<String, Object>> fieldMapList;
  143 + try {
  144 + fieldMapList = queryRunner.query(sql, new MapListHandler(), params);
  145 + } catch (SQLException e) {
  146 + logger.error("查询出错!", e);
  147 + throw new RuntimeException(e);
  148 + }
  149 + printSQL(sql);
  150 + return fieldMapList;
  151 + }
  152 +
  153 + @Override
  154 + public <T> T queryColumn(String sql, Object... params) {
  155 + T obj;
  156 + try {
  157 + obj = queryRunner.query(sql, new ScalarHandler<T>(), params);
  158 + } catch (SQLException e) {
  159 + logger.error("查询出错!", e);
  160 + throw new RuntimeException(e);
  161 + }
  162 + printSQL(sql);
  163 + return obj;
  164 + }
  165 +
  166 + @Override
  167 + public <T> List<T> queryColumnList(String sql, Object... params) {
  168 + List<T> list;
  169 + try {
  170 + list = queryRunner.query(sql, new ColumnListHandler<T>(), params);
  171 + } catch (SQLException e) {
  172 + logger.error("查询出错!", e);
  173 + throw new RuntimeException(e);
  174 + }
  175 + printSQL(sql);
  176 + return list;
  177 + }
  178 +
  179 + @Override
  180 + public <T> Map<T, Map<String, Object>> queryColumnMap(String column, String sql, Object... params) {
  181 + Map<T, Map<String, Object>> map;
  182 + try {
  183 + map = queryRunner.query(sql, new KeyedHandler<T>(column), params);
  184 + } catch (SQLException e) {
  185 + logger.error("查询出错!", e);
  186 + throw new RuntimeException(e);
  187 + }
  188 + printSQL(sql);
  189 + return map;
  190 + }
  191 +
  192 + @Override
  193 + public long queryCount(String sql, Object... params) {
  194 + long result;
  195 + try {
  196 + result = queryRunner.query(sql, new ScalarHandler<Long>("count(*)"), params);
  197 + } catch (SQLException e) {
  198 + logger.error("查询出错!", e);
  199 + throw new RuntimeException(e);
  200 + }
  201 + printSQL(sql);
  202 + return result;
  203 + }
  204 +
  205 + @Override
  206 + public int update(String sql, Object... params) {
  207 + int result;
  208 + try {
  209 + // Connection conn = DatabaseHelper.getConnection();
  210 + result = queryRunner.update(sql, params);
  211 + } catch (SQLException e) {
  212 + logger.error("更新出错!", e);
  213 + throw new RuntimeException(e);
  214 + }
  215 + printSQL(sql);
  216 + return result;
  217 + }
  218 +
  219 + @Override
  220 + public Serializable insertReturnPK(String sql, Object... params) {
  221 + Serializable key = null;
  222 + ResultSet rs = null;
  223 + Connection conn = null;
  224 + PreparedStatement pstmt = null;
  225 + try {
  226 + conn = DatabaseHelper.getConnection();
  227 + pstmt = conn.prepareStatement(sql, PreparedStatement.RETURN_GENERATED_KEYS);
  228 + if (ArrayUtil.isNotEmpty(params)) {
  229 + for (int i = 0; i < params.length; i++) {
  230 + pstmt.setObject(i + 1, params[i]);
  231 + }
  232 + }
  233 + int rows = pstmt.executeUpdate();
  234 + if (rows == 1) {
  235 + rs = pstmt.getGeneratedKeys();
  236 + if (rs.next()) {
  237 + key = (Serializable) rs.getObject(1);
  238 + }
  239 + }
  240 + } catch (SQLException e) {
  241 + logger.error("插入出错!", e);
  242 + throw new RuntimeException(e);
  243 + } finally {
  244 +// try {
  245 +// if (rs != null) {
  246 +// rs.close();
  247 +// }
  248 +// if (pstmt != null) {
  249 +// pstmt.close();
  250 +// }
  251 +// if (conn != null) {
  252 +// conn.close();
  253 +// }
  254 +// } catch (SQLException e) {
  255 +// e.printStackTrace();
  256 +// }
  257 + }
  258 + printSQL(sql);
  259 + return key;
  260 + }
  261 +
  262 + private static void printSQL(String sql) {
  263 + logger.debug("[Smart] SQL - {}", sql);
  264 + }
  265 +}
src/main/java/org/smart4j/framework/ds/DataSourceFactory.java 0 → 100644
  1 +++ a/src/main/java/org/smart4j/framework/ds/DataSourceFactory.java
  1 +package org.smart4j.framework.ds;
  2 +
  3 +import javax.sql.DataSource;
  4 +
  5 +/**
  6 + * 数据源工厂
  7 + *
  8 + * @author huangyong
  9 + * @since 2.3
  10 + */
  11 +public interface DataSourceFactory {
  12 +
  13 + /**
  14 + * 获取数据源
  15 + *
  16 + * @return 数据源
  17 + */
  18 + DataSource getDataSource();
  19 +}
src/main/java/org/smart4j/framework/ds/impl/AbstractDataSourceFactory.java 0 → 100644
  1 +++ a/src/main/java/org/smart4j/framework/ds/impl/AbstractDataSourceFactory.java
  1 +package org.smart4j.framework.ds.impl;
  2 +
  3 +import javax.sql.DataSource;
  4 +import org.smart4j.framework.core.ConfigHelper;
  5 +import org.smart4j.framework.ds.DataSourceFactory;
  6 +
  7 +/**
  8 + * 抽象数据源工厂
  9 + *
  10 + * @author huangyong
  11 + * @since 2.3
  12 + */
  13 +public abstract class AbstractDataSourceFactory<T extends DataSource> implements DataSourceFactory {
  14 +
  15 + protected final String driver = ConfigHelper.getString("smart.framework.jdbc.driver");
  16 + protected final String url = ConfigHelper.getString("smart.framework.jdbc.url");
  17 + protected final String username = ConfigHelper.getString("smart.framework.jdbc.username");
  18 + protected final String password = ConfigHelper.getString("smart.framework.jdbc.password");
  19 +
  20 + @Override
  21 + public final T getDataSource() {
  22 + // 创建数据源对象
  23 + T ds = createDataSource();
  24 + // 设置基础属性
  25 + setDriver(ds, driver);
  26 + setUrl(ds, url);
  27 + setUsername(ds, username);
  28 + setPassword(ds, password);
  29 + // 设置高级属性
  30 + setAdvancedConfig(ds);
  31 + return ds;
  32 + }
  33 +
  34 + public abstract T createDataSource();
  35 +
  36 + public abstract void setDriver(T ds, String driver);
  37 +
  38 + public abstract void setUrl(T ds, String url);
  39 +
  40 + public abstract void setUsername(T ds, String username);
  41 +
  42 + public abstract void setPassword(T ds, String password);
  43 +
  44 + public abstract void setAdvancedConfig(T ds);
  45 +}
src/main/java/org/smart4j/framework/ds/impl/DefaultDataSourceFactory.java 0 → 100644
  1 +++ a/src/main/java/org/smart4j/framework/ds/impl/DefaultDataSourceFactory.java
  1 +package org.smart4j.framework.ds.impl;
  2 +
  3 +import org.apache.commons.dbcp.BasicDataSource;
  4 +
  5 +/**
  6 + * 默认数据源工厂 <br/>
  7 + * 基于 Apache Commons DBCP 实现
  8 + *
  9 + * @author huangyong
  10 + * @since 2.3
  11 + */
  12 +public class DefaultDataSourceFactory extends AbstractDataSourceFactory<BasicDataSource> {
  13 +
  14 + @Override
  15 + public BasicDataSource createDataSource() {
  16 + return new BasicDataSource();
  17 + }
  18 +
  19 + @Override
  20 + public void setDriver(BasicDataSource ds, String driver) {
  21 + ds.setDriverClassName(driver);
  22 + }
  23 +
  24 + @Override
  25 + public void setUrl(BasicDataSource ds, String url) {
  26 + ds.setUrl(url);
  27 + }
  28 +
  29 + @Override
  30 + public void setUsername(BasicDataSource ds, String username) {
  31 + ds.setUsername(username);
  32 + }
  33 +
  34 + @Override
  35 + public void setPassword(BasicDataSource ds, String password) {
  36 + ds.setPassword(password);
  37 + }
  38 +
  39 + @Override
  40 + public void setAdvancedConfig(BasicDataSource ds) {
  41 + // 解决 java.sql.SQLException: Already closed. 的问题(连接池会自动关闭长时间没有使用的连接)
  42 + // 用于检查connection的sql语句.
  43 + ds.setValidationQuery("select 1 from dual");
  44 + // ds.setTestOnBorrow(true);
  45 + /**
  46 + * :启动connection校验定时器,定时器运行时间间隔就是<br>
  47 + * 这里设定为1小时,只要小于mysql的wait_timeout就可以了
  48 + */
  49 + ds.setTimeBetweenEvictionRunsMillis(3600000);
  50 + // 表示检查idle的connection,false为不检查
  51 + ds.setTestWhileIdle(true);
  52 + }
  53 +}
src/main/java/org/smart4j/framework/ioc/BeanHelper.java 0 → 100644
  1 +++ a/src/main/java/org/smart4j/framework/ioc/BeanHelper.java
  1 +package org.smart4j.framework.ioc;
  2 +
  3 +import java.util.HashMap;
  4 +import java.util.List;
  5 +import java.util.Map;
  6 +import org.smart4j.framework.aop.annotation.Aspect;
  7 +import org.smart4j.framework.core.ClassHelper;
  8 +import org.smart4j.framework.core.fault.InitializationError;
  9 +import org.smart4j.framework.ioc.annotation.Bean;
  10 +import org.smart4j.framework.mvc.annotation.Action;
  11 +import org.smart4j.framework.tx.annotation.Service;
  12 +
  13 +/**
  14 + * 初始化相关 Bean 类
  15 + *
  16 + * @author huangyong
  17 + * @since 1.0
  18 + */
  19 +public class BeanHelper {
  20 +
  21 + /**
  22 + * Bean Map(Bean 类 => Bean 实例)
  23 + */
  24 + private static final Map<Class<?>, Object> beanMap = new HashMap<Class<?>, Object>();
  25 +
  26 + static {
  27 + try {
  28 + // 获取应用包路径下所有的类
  29 + List<Class<?>> classList = ClassHelper.getClassList();
  30 + for (Class<?> cls : classList) {
  31 + // 处理带有 Bean/Service/Action/Aspect 注解的类
  32 + if (cls.isAnnotationPresent(Bean.class) ||
  33 + cls.isAnnotationPresent(Service.class) ||
  34 + cls.isAnnotationPresent(Action.class) ||
  35 + cls.isAnnotationPresent(Aspect.class)) {
  36 + // 创建 Bean 实例
  37 + Object beanInstance = cls.newInstance();
  38 + // 将 Bean 实例放入 Bean Map 中(键为 Bean 类,值为 Bean 实例)
  39 + beanMap.put(cls, beanInstance);
  40 + }
  41 + }
  42 + } catch (Exception e) {
  43 + throw new InitializationError("初始化 BeanHelper 出错!", e);
  44 + }
  45 + }
  46 +
  47 + /**
  48 + * 获取 Bean Map
  49 + */
  50 + public static Map<Class<?>, Object> getBeanMap() {
  51 + return beanMap;
  52 + }
  53 +
  54 + /**
  55 + * 获取 Bean 实例
  56 + */
  57 + @SuppressWarnings("unchecked")
  58 + public static <T> T getBean(Class<T> cls) {
  59 + if (!beanMap.containsKey(cls)) {
  60 + throw new RuntimeException("无法根据类名获取实例!" + cls);
  61 + }
  62 + return (T) beanMap.get(cls);
  63 + }
  64 +
  65 + /**
  66 + * 设置 Bean 实例
  67 + */
  68 + public static void setBean(Class<?> cls, Object obj) {
  69 + beanMap.put(cls, obj);
  70 + }
  71 +}
src/main/java/org/smart4j/framework/ioc/IocHelper.java 0 → 100644
  1 +++ a/src/main/java/org/smart4j/framework/ioc/IocHelper.java
  1 +package org.smart4j.framework.ioc;
  2 +
  3 +import java.lang.reflect.Field;
  4 +import java.util.List;
  5 +import java.util.Map;
  6 +import org.smart4j.framework.core.ClassHelper;
  7 +import org.smart4j.framework.core.fault.InitializationError;
  8 +import org.smart4j.framework.ioc.annotation.Impl;
  9 +import org.smart4j.framework.ioc.annotation.Inject;
  10 +import org.smart4j.framework.util.ArrayUtil;
  11 +import org.smart4j.framework.util.CollectionUtil;
  12 +
  13 +/**
  14 + * 初始化 IOC 容器
  15 + *
  16 + * @author huangyong
  17 + * @since 1.0
  18 + */
  19 +public class IocHelper {
  20 +
  21 + static {
  22 + try {
  23 + // 获取并遍历所有的 Bean 类
  24 + Map<Class<?>, Object> beanMap = BeanHelper.getBeanMap();
  25 + for (Map.Entry<Class<?>, Object> beanEntry : beanMap.entrySet()) {
  26 + // 获取 Bean 类与 Bean 实例
  27 + Class<?> beanClass = beanEntry.getKey();
  28 + Object beanInstance = beanEntry.getValue();
  29 + // 获取 Bean 类中所有的字段(不包括父类中的方法)
  30 + Field[] beanFields = beanClass.getDeclaredFields();
  31 + if (ArrayUtil.isNotEmpty(beanFields)) {
  32 + // 遍历所有的 Bean 字段
  33 + for (Field beanField : beanFields) {
  34 + // 判断当前 Bean 字段是否带有 Inject 注解
  35 + if (beanField.isAnnotationPresent(Inject.class)) {
  36 + // 获取 Bean 字段对应的接口
  37 + Class<?> interfaceClass = beanField.getType();
  38 + // 获取 Bean 字段对应的实现类
  39 + Class<?> implementClass = findImplementClass(interfaceClass);
  40 + // 若存在实现类,则执行以下代码
  41 + if (implementClass != null) {
  42 + // 从 Bean Map 中获取该实现类对应的实现类实例
  43 + Object implementInstance = beanMap.get(implementClass);
  44 + // 设置该 Bean 字段的值
  45 + if (implementInstance != null) {
  46 + beanField.setAccessible(true); // 将字段设置为 public
  47 + beanField.set(beanInstance, implementInstance); // 设置字段初始值
  48 + } else {
  49 + throw new InitializationError("依赖注入失败!类名:" + beanClass.getSimpleName() + ",字段名:" + interfaceClass.getSimpleName());
  50 + }
  51 + }
  52 + }
  53 + }
  54 + }
  55 + }
  56 + } catch (Exception e) {
  57 + throw new InitializationError("初始化 IocHelper 出错!", e);
  58 + }
  59 + }
  60 +
  61 + /**
  62 + * 查找实现类
  63 + */
  64 + public static Class<?> findImplementClass(Class<?> interfaceClass) {
  65 + Class<?> implementClass = interfaceClass;
  66 + // 判断接口上是否标注了 Impl 注解
  67 + if (interfaceClass.isAnnotationPresent(Impl.class)) {
  68 + // 获取强制指定的实现类
  69 + implementClass = interfaceClass.getAnnotation(Impl.class).value();
  70 + } else {
  71 + // 获取该接口所有的实现类
  72 + List<Class<?>> implementClassList = ClassHelper.getClassListBySuper(interfaceClass);
  73 + if (CollectionUtil.isNotEmpty(implementClassList)) {
  74 + // 获取第一个实现类
  75 + implementClass = implementClassList.get(0);
  76 + }
  77 + }
  78 + // 返回实现类对象
  79 + return implementClass;
  80 + }
  81 +}
src/main/java/org/smart4j/framework/ioc/annotation/Bean.java 0 → 100644
  1 +++ a/src/main/java/org/smart4j/framework/ioc/annotation/Bean.java
  1 +package org.smart4j.framework.ioc.annotation;
  2 +
  3 +import java.lang.annotation.ElementType;
  4 +import java.lang.annotation.Retention;
  5 +import java.lang.annotation.RetentionPolicy;
  6 +import java.lang.annotation.Target;
  7 +
  8 +/**
  9 + * 定义需要 IOC 容器管理的 Bean 类
  10 + *
  11 + * @author huangyong
  12 + * @since 1.0
  13 + */
  14 +@Target(ElementType.TYPE)
  15 +@Retention(RetentionPolicy.RUNTIME)
  16 +public @interface Bean {
  17 +}
src/main/java/org/smart4j/framework/ioc/annotation/Impl.java 0 → 100644
  1 +++ a/src/main/java/org/smart4j/framework/ioc/annotation/Impl.java
  1 +package org.smart4j.framework.ioc.annotation;
  2 +
  3 +import java.lang.annotation.ElementType;
  4 +import java.lang.annotation.Retention;
  5 +import java.lang.annotation.RetentionPolicy;
  6 +import java.lang.annotation.Target;
  7 +
  8 +/**
  9 + * 指定接口的实现类
  10 + *
  11 + * @author huangyong
  12 + * @since 1.0
  13 + */
  14 +@Target(ElementType.TYPE)
  15 +@Retention(RetentionPolicy.RUNTIME)
  16 +public @interface Impl {
  17 +
  18 + Class<?> value();
  19 +}
src/main/java/org/smart4j/framework/ioc/annotation/Inject.java 0 → 100644
  1 +++ a/src/main/java/org/smart4j/framework/ioc/annotation/Inject.java
  1 +package org.smart4j.framework.ioc.annotation;
  2 +
  3 +import java.lang.annotation.ElementType;
  4 +import java.lang.annotation.Retention;
  5 +import java.lang.annotation.RetentionPolicy;
  6 +import java.lang.annotation.Target;
  7 +
  8 +/**
  9 + * 依赖注入
  10 + *
  11 + * @author huangyong
  12 + * @since 1.0
  13 + */
  14 +@Target(ElementType.FIELD)
  15 +@Retention(RetentionPolicy.RUNTIME)
  16 +public @interface Inject {
  17 +}
src/main/java/org/smart4j/framework/mvc/ActionHelper.java 0 → 100644
  1 +++ a/src/main/java/org/smart4j/framework/mvc/ActionHelper.java
  1 +package org.smart4j.framework.mvc;
  2 +
  3 +import java.lang.reflect.Method;
  4 +import java.util.HashMap;
  5 +import java.util.LinkedHashMap;
  6 +import java.util.List;
  7 +import java.util.Map;
  8 +import org.smart4j.framework.core.ClassHelper;
  9 +import org.smart4j.framework.mvc.annotation.Action;
  10 +import org.smart4j.framework.mvc.annotation.Request;
  11 +import org.smart4j.framework.util.ArrayUtil;
  12 +import org.smart4j.framework.util.CollectionUtil;
  13 +import org.smart4j.framework.util.StringUtil;
  14 +
  15 +/**
  16 + * 初始化 Action 配置
  17 + *
  18 + * @author huangyong
  19 + * @since 1.0
  20 + */
  21 +public class ActionHelper {
  22 +
  23 + /**
  24 + * Action Map(HTTP 请求与 Action 方法的映射)
  25 + */
  26 + private static final Map<Requester, Handler> actionMap = new LinkedHashMap<Requester, Handler>();
  27 +
  28 + static {
  29 + // 获取所有 Action 类
  30 + List<Class<?>> actionClassList = ClassHelper.getClassListByAnnotation(Action.class);
  31 + if (CollectionUtil.isNotEmpty(actionClassList)) {
  32 + // 定义两个 Action Map
  33 + Map<Requester, Handler> commonActionMap = new HashMap<Requester, Handler>(); // 存放普通 Action Map
  34 + Map<Requester, Handler> regexpActionMap = new HashMap<Requester, Handler>(); // 存放带有正则表达式的 Action Map
  35 + // 遍历 Action 类
  36 + for (Class<?> actionClass : actionClassList) {
  37 + // 获取并遍历该 Action 类中所有的方法
  38 + Method[] actionMethods = actionClass.getDeclaredMethods();
  39 + if (ArrayUtil.isNotEmpty(actionMethods)) {
  40 + for (Method actionMethod : actionMethods) {
  41 + // 处理 Action 方法
  42 + handleActionMethod(actionClass, actionMethod, commonActionMap, regexpActionMap);
  43 + }
  44 + }
  45 + }
  46 + // 初始化最终的 Action Map(将 Common 放在 Regexp 前面)
  47 + actionMap.putAll(commonActionMap);
  48 + actionMap.putAll(regexpActionMap);
  49 + }
  50 + }
  51 +
  52 + private static void handleActionMethod(Class<?> actionClass, Method actionMethod, Map<Requester, Handler> commonActionMap, Map<Requester, Handler> regexpActionMap) {
  53 + // 判断当前 Action 方法是否带有 Request 注解
  54 + if (actionMethod.isAnnotationPresent(Request.Get.class)) {
  55 + String requestPath = actionMethod.getAnnotation(Request.Get.class).value();
  56 + putActionMap("GET", requestPath, actionClass, actionMethod, commonActionMap, regexpActionMap);
  57 + } else if (actionMethod.isAnnotationPresent(Request.Post.class)) {
  58 + String requestPath = actionMethod.getAnnotation(Request.Post.class).value();
  59 + putActionMap("POST", requestPath, actionClass, actionMethod, commonActionMap, regexpActionMap);
  60 + } else if (actionMethod.isAnnotationPresent(Request.Put.class)) {
  61 + String requestPath = actionMethod.getAnnotation(Request.Put.class).value();
  62 + putActionMap("PUT", requestPath, actionClass, actionMethod, commonActionMap, regexpActionMap);
  63 + } else if (actionMethod.isAnnotationPresent(Request.Delete.class)) {
  64 + String requestPath = actionMethod.getAnnotation(Request.Delete.class).value();
  65 + putActionMap("DELETE", requestPath, actionClass, actionMethod, commonActionMap, regexpActionMap);
  66 + }
  67 + }
  68 +
  69 + private static void putActionMap(String requestMethod, String requestPath, Class<?> actionClass, Method actionMethod, Map<Requester, Handler> commonActionMap, Map<Requester, Handler> regexpActionMap) {
  70 + // 判断 Request Path 中是否带有占位符
  71 + if (requestPath.matches(".+\\{\\w+\\}.*")) {
  72 + // 将请求路径中的占位符 {\w+} 转换为正则表达式 (\\w+)
  73 + requestPath = StringUtil.replaceAll(requestPath, "\\{\\w+\\}", "(\\\\w+)");
  74 + // 将 Requester 与 Handler 放入 Regexp Action Map 中
  75 + regexpActionMap.put(new Requester(requestMethod, requestPath), new Handler(actionClass, actionMethod));
  76 + } else {
  77 + // 将 Requester 与 Handler 放入 Common Action Map 中
  78 + commonActionMap.put(new Requester(requestMethod, requestPath), new Handler(actionClass, actionMethod));
  79 + }
  80 + }
  81 +
  82 + /**
  83 + * 获取 Action Map
  84 + */
  85 + public static Map<Requester, Handler> getActionMap() {
  86 + return actionMap;
  87 + }
  88 +}
src/main/java/org/smart4j/framework/mvc/ContainerListener.java 0 → 100644
  1 +++ a/src/main/java/org/smart4j/framework/mvc/ContainerListener.java
  1 +package org.smart4j.framework.mvc;
  2 +
  3 +import java.util.List;
  4 +import javax.servlet.ServletContext;
  5 +import javax.servlet.ServletContextEvent;
  6 +import javax.servlet.ServletContextListener;
  7 +import javax.servlet.ServletRegistration;
  8 +import javax.servlet.annotation.WebListener;
  9 +import org.smart4j.framework.FrameworkConstant;
  10 +import org.smart4j.framework.HelperLoader;
  11 +import org.smart4j.framework.plugin.Plugin;
  12 +import org.smart4j.framework.plugin.PluginHelper;
  13 +import org.smart4j.framework.plugin.WebPlugin;
  14 +import org.smart4j.framework.util.StringUtil;
  15 +
  16 +/**
  17 + * 容器监听器 .启动即加载
  18 + */
  19 +@WebListener
  20 +public class ContainerListener implements ServletContextListener {
  21 +
  22 + /**
  23 + * 当容器初始化时调用
  24 + */
  25 + @Override
  26 + public void contextInitialized(ServletContextEvent sce) {
  27 + // 获取 ServletContext
  28 + ServletContext servletContext = sce.getServletContext();
  29 + // 初始化相关 Helper 类
  30 + HelperLoader.init();
  31 + // 添加 Servlet 映射
  32 + addServletMapping(servletContext);
  33 + // 注册 WebPlugin
  34 + registerWebPlugin(servletContext);
  35 + }
  36 +
  37 + /**
  38 + * 当容器销毁时调用
  39 + */
  40 + @Override
  41 + public void contextDestroyed(ServletContextEvent sce) {
  42 + // 销毁插件
  43 + destroyPlugin();
  44 + }
  45 +
  46 + private void addServletMapping(ServletContext context) {
  47 + // 用 DefaultServlet 映射所有静态资源
  48 + registerDefaultServlet(context);
  49 + // 用 JspServlet 映射所有 JSP 请求
  50 + registerJspServlet(context);
  51 + }
  52 +
  53 + private void registerDefaultServlet(ServletContext context) {
  54 + ServletRegistration defaultServlet = context.getServletRegistration("default");
  55 + defaultServlet.addMapping("/index.html");
  56 + defaultServlet.addMapping("/favicon.ico");
  57 + String wwwPath = FrameworkConstant.WWW_PATH;
  58 + if (StringUtil.isNotEmpty(wwwPath)) {
  59 + defaultServlet.addMapping(wwwPath + "*");
  60 + }
  61 + }
  62 +
  63 + private void registerJspServlet(ServletContext context) {
  64 + ServletRegistration jspServlet = context.getServletRegistration("jsp");
  65 + jspServlet.addMapping("/index.jsp");
  66 + String jspPath = FrameworkConstant.JSP_PATH;
  67 + if (StringUtil.isNotEmpty(jspPath)) {
  68 + jspServlet.addMapping(jspPath + "*");
  69 + }
  70 + }
  71 +
  72 + private void registerWebPlugin(ServletContext servletContext) {
  73 + List<Plugin> pluginList = PluginHelper.getPluginList();
  74 + for (Plugin plugin : pluginList) {
  75 + if (plugin instanceof WebPlugin) {
  76 + WebPlugin webPlugin = (WebPlugin) plugin;
  77 + webPlugin.register(servletContext);
  78 + }
  79 + }
  80 + }
  81 +
  82 + private void destroyPlugin() {
  83 + List<Plugin> pluginList = PluginHelper.getPluginList();
  84 + for (Plugin plugin : pluginList) {
  85 + plugin.destroy();
  86 + }
  87 + }
  88 +}
src/main/java/org/smart4j/framework/mvc/DataContext.java 0 → 100644
  1 +++ a/src/main/java/org/smart4j/framework/mvc/DataContext.java
  1 +package org.smart4j.framework.mvc;
  2 +
  3 +import java.util.Enumeration;
  4 +import java.util.HashMap;
  5 +import java.util.Map;
  6 +import javax.servlet.http.HttpServletRequest;
  7 +import javax.servlet.http.HttpServletResponse;
  8 +import javax.servlet.http.HttpSession;
  9 +import org.smart4j.framework.util.ArrayUtil;
  10 +import org.smart4j.framework.util.CastUtil;
  11 +import org.smart4j.framework.util.CodecUtil;
  12 +
  13 +/**
  14 + * 数据上下文
  15 + *
  16 + * @author huangyong
  17 + * @since 1.0
  18 + */
  19 +public class DataContext {
  20 +
  21 + /**
  22 + * 使每个线程拥有各自的 DataContext 实例
  23 + */
  24 + private static final ThreadLocal<DataContext> dataContextContainer = new ThreadLocal<DataContext>();
  25 +
  26 + private HttpServletRequest request;
  27 + private HttpServletResponse response;
  28 +
  29 + /**
  30 + * 初始化
  31 + */
  32 + public static void init(HttpServletRequest request, HttpServletResponse response) {
  33 + DataContext dataContext = new DataContext();
  34 + dataContext.request = request;
  35 + dataContext.response = response;
  36 + dataContextContainer.set(dataContext);
  37 + }
  38 +
  39 + /**
  40 + * 销毁
  41 + */
  42 + public static void destroy() {
  43 + dataContextContainer.remove();
  44 + }
  45 +
  46 + /**
  47 + * 获取 DataContext 实例
  48 + */
  49 + public static DataContext getInstance() {
  50 + return dataContextContainer.get();
  51 + }
  52 +
  53 + /**
  54 + * 获取 Request 对象
  55 + */
  56 + public static HttpServletRequest getRequest() {
  57 + return getInstance().request;
  58 + }
  59 +
  60 + /**
  61 + * 获取 Response 对象
  62 + */
  63 + public static HttpServletResponse getResponse() {
  64 + return getInstance().response;
  65 + }
  66 +
  67 + /**
  68 + * 获取 Session 对象
  69 + */
  70 + public static HttpSession getSession() {
  71 + return getRequest().getSession();
  72 + }
  73 +
  74 + /**
  75 + * 获取 Servlet Context 对象
  76 + */
  77 + public static javax.servlet.ServletContext getServletContext() {
  78 + return getRequest().getServletContext();
  79 + }
  80 +
  81 + /**
  82 + * 封装 Request 相关操作
  83 + */
  84 + public static class Request {
  85 +
  86 + /**
  87 + * 将数据放入 Request 中
  88 + */
  89 + public static void put(String key, Object value) {
  90 + getRequest().setAttribute(key, value);
  91 + }
  92 +
  93 + /**
  94 + * 从 Request 中获取数据
  95 + */
  96 + @SuppressWarnings("unchecked")
  97 + public static <T> T get(String key) {
  98 + return (T) getRequest().getAttribute(key);
  99 + }
  100 +
  101 + /**
  102 + * 移除 Request 中的数据
  103 + */
  104 + public static void remove(String key) {
  105 + getRequest().removeAttribute(key);
  106 + }
  107 +
  108 + /**
  109 + * 从 Request 中获取所有数据
  110 + */
  111 + public static Map<String, Object> getAll() {
  112 + Map<String, Object> map = new HashMap<String, Object>();
  113 + Enumeration<String> names = getRequest().getAttributeNames();
  114 + while (names.hasMoreElements()) {
  115 + String name = names.nextElement();
  116 + map.put(name, getRequest().getAttribute(name));
  117 + }
  118 + return map;
  119 + }
  120 + }
  121 +
  122 + /**
  123 + * 封装 Response 相关操作
  124 + */
  125 + public static class Response {
  126 +
  127 + /**
  128 + * 将数据放入 Response 中
  129 + */
  130 + public static void put(String key, Object value) {
  131 + getResponse().setHeader(key, CastUtil.castString(value));
  132 + }
  133 +
  134 + /**
  135 + * 从 Response 中获取数据
  136 + */
  137 + @SuppressWarnings("unchecked")
  138 + public static <T> T get(String key) {
  139 + return (T) getResponse().getHeader(key);
  140 + }
  141 +
  142 + /**
  143 + * 从 Response 中获取所有数据
  144 + */
  145 + public static Map<String, Object> getAll() {
  146 + Map<String, Object> map = new HashMap<String, Object>();
  147 + for (String name : getResponse().getHeaderNames()) {
  148 + map.put(name, getResponse().getHeader(name));
  149 + }
  150 + return map;
  151 + }
  152 + }
  153 +
  154 + /**
  155 + * 封装 Session 相关操作
  156 + */
  157 + public static class Session {
  158 +
  159 + /**
  160 + * 将数据放入 Session 中
  161 + */
  162 + public static void put(String key, Object value) {
  163 + getSession().setAttribute(key, value);
  164 + }
  165 +
  166 + /**
  167 + * 从 Session 中获取数据
  168 + */
  169 + @SuppressWarnings("unchecked")
  170 + public static <T> T get(String key) {
  171 + return (T) getSession().getAttribute(key);
  172 + }
  173 +
  174 + /**
  175 + * 移除 Session 中的数据
  176 + */
  177 + public static void remove(String key) {
  178 + getSession().removeAttribute(key);
  179 + }
  180 +
  181 + /**
  182 + * 从 Session 中获取所有数据
  183 + */
  184 + public static Map<String, Object> getAll() {
  185 + Map<String, Object> map = new HashMap<String, Object>();
  186 + Enumeration<String> names = getSession().getAttributeNames();
  187 + while (names.hasMoreElements()) {
  188 + String name = names.nextElement();
  189 + map.put(name, getSession().getAttribute(name));
  190 + }
  191 + return map;
  192 + }
  193 +
  194 + /**
  195 + * 移除 Session 中所有的数据
  196 + */
  197 + public static void removeAll() {
  198 + getSession().invalidate();
  199 + }
  200 + }
  201 +
  202 + /**
  203 + * 封装 Cookie 相关操作
  204 + */
  205 + public static class Cookie {
  206 +
  207 + /**
  208 + * 将数据放入 Cookie 中
  209 + */
  210 + public static void put(String key, Object value) {
  211 + String strValue = CodecUtil.encodeURL(CastUtil.castString(value));
  212 + javax.servlet.http.Cookie cookie = new javax.servlet.http.Cookie(key, strValue);
  213 + getResponse().addCookie(cookie);
  214 + }
  215 +
  216 + /**
  217 + * 从 Cookie 中获取数据
  218 + */
  219 + @SuppressWarnings("unchecked")
  220 + public static <T> T get(String key) {
  221 + T value = null;
  222 + javax.servlet.http.Cookie[] cookieArray = getRequest().getCookies();
  223 + if (ArrayUtil.isNotEmpty(cookieArray)) {
  224 + for (javax.servlet.http.Cookie cookie : cookieArray) {
  225 + if (key.equals(cookie.getName())) {
  226 + value = (T) CodecUtil.decodeURL(cookie.getValue());
  227 + break;
  228 + }
  229 + }
  230 + }
  231 + return value;
  232 + }
  233 +
  234 + /**
  235 + * 从 Cookie 中获取所有数据
  236 + */
  237 + public static Map<String, Object> getAll() {
  238 + Map<String, Object> map = new HashMap<String, Object>();
  239 + javax.servlet.http.Cookie[] cookieArray = getRequest().getCookies();
  240 + if (ArrayUtil.isNotEmpty(cookieArray)) {
  241 + for (javax.servlet.http.Cookie cookie : cookieArray) {
  242 + map.put(cookie.getName(), cookie.getValue());
  243 + }
  244 + }
  245 + return map;
  246 + }
  247 + }
  248 +
  249 + /**
  250 + * 封装 ServletContext 相关操作
  251 + */
  252 + public static class ServletContext {
  253 +
  254 + /**
  255 + * 将数据放入 ServletContext 中
  256 + */
  257 + public static void put(String key, Object value) {
  258 + getServletContext().setAttribute(key, value);
  259 + }
  260 +
  261 + /**
  262 + * 从 ServletContext 中获取数据
  263 + */
  264 + @SuppressWarnings("unchecked")
  265 + public static <T> T get(String key) {
  266 + return (T) getServletContext().getAttribute(key);
  267 + }
  268 +
  269 + /**
  270 + * 移除 ServletContext 中的数据
  271 + */
  272 + public static void remove(String key) {
  273 + getServletContext().removeAttribute(key);
  274 + }
  275 +
  276 + /**
  277 + * 从 ServletContext 中获取所有数据
  278 + */
  279 + public static Map<String, Object> getAll() {
  280 + Map<String, Object> map = new HashMap<String, Object>();
  281 + Enumeration<String> names = getServletContext().getAttributeNames();
  282 + while (names.hasMoreElements()) {
  283 + String name = names.nextElement();
  284 + map.put(name, getServletContext().getAttribute(name));
  285 + }
  286 + return map;
  287 + }
  288 + }
  289 +}
src/main/java/org/smart4j/framework/mvc/DispatcherServlet.java 0 → 100644
  1 +++ a/src/main/java/org/smart4j/framework/mvc/DispatcherServlet.java
  1 +package org.smart4j.framework.mvc;
  2 +
  3 +import java.io.IOException;
  4 +
  5 +import javax.servlet.ServletConfig;
  6 +import javax.servlet.ServletContext;
  7 +import javax.servlet.ServletException;
  8 +import javax.servlet.annotation.WebServlet;
  9 +import javax.servlet.http.HttpServlet;
  10 +import javax.servlet.http.HttpServletRequest;
  11 +import javax.servlet.http.HttpServletResponse;
  12 +
  13 +import org.slf4j.Logger;
  14 +import org.slf4j.LoggerFactory;
  15 +import org.smart4j.framework.FrameworkConstant;
  16 +import org.smart4j.framework.InstanceFactory;
  17 +import org.smart4j.framework.util.WebUtil;
  18 +
  19 +@WebServlet(urlPatterns = "/*", loadOnStartup = 0)
  20 +public class DispatcherServlet extends HttpServlet {
  21 +
  22 + private static final Logger logger = LoggerFactory.getLogger(DispatcherServlet.class);
  23 +
  24 + private HandlerMapping handlerMapping = InstanceFactory.getHandlerMapping();
  25 + private HandlerInvoker handlerInvoker = InstanceFactory.getHandlerInvoker();
  26 + private HandlerExceptionResolver handlerExceptionResolver = InstanceFactory.getHandlerExceptionResolver();
  27 +
  28 + @Override
  29 + public void init(ServletConfig config) throws ServletException {
  30 + // 初始化相关配置
  31 + ServletContext servletContext = config.getServletContext();
  32 + UploadHelper.init(servletContext);
  33 + }
  34 +
  35 + @Override
  36 + public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  37 + // 设置请求编码方式
  38 + request.setCharacterEncoding(FrameworkConstant.UTF_8);
  39 + // 获取当前请求相关数据
  40 + String currentRequestMethod = request.getMethod();
  41 + String currentRequestPath = WebUtil.getRequestPath(request);
  42 + logger.debug(getRemoteUserIp(request)+"[Smart] {}:{}", currentRequestMethod, currentRequestPath);
  43 + // 将“/”请求重定向到首页
  44 + if (currentRequestPath.equals("/")) {
  45 + WebUtil.redirectRequest(FrameworkConstant.HOME_PAGE, request, response);
  46 + return;
  47 + }
  48 + // 去掉当前请求路径末尾的“/”
  49 + if (currentRequestPath.endsWith("/")) {
  50 + currentRequestPath = currentRequestPath.substring(0, currentRequestPath.length() - 1);
  51 + }
  52 + // 获取 Handler
  53 + Handler handler = handlerMapping.getHandler(currentRequestMethod, currentRequestPath);
  54 + // 若未找到 Action,则跳转到 404 页面
  55 + if (handler == null) {
  56 + WebUtil.sendError(HttpServletResponse.SC_NOT_FOUND, "", response);
  57 + return;
  58 + }
  59 + // 初始化 DataContext
  60 + DataContext.init(request, response);
  61 + try {
  62 + // 调用 Handler
  63 + handlerInvoker.invokeHandler(request, response, handler);
  64 + } catch (Exception e) {
  65 + // 处理 Action 异常
  66 + handlerExceptionResolver.resolveHandlerException(request, response, e);
  67 + } finally {
  68 + // 销毁 DataContext
  69 + DataContext.destroy();
  70 + }
  71 + }
  72 + private String getRemoteUserIp(HttpServletRequest request) {
  73 + String ip = request.getHeader("x-forwarded-for");
  74 + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
  75 + ip = request.getHeader("Proxy-Client-IP");
  76 + }
  77 + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
  78 + ip = request.getHeader("WL-Proxy-Client-IP");
  79 + }
  80 + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
  81 + ip = request.getRemoteAddr();
  82 + }
  83 + if (ip.contains(",")) {
  84 + ip = ip.split(",")[0];
  85 + }
  86 + if (ip.equals("0:0:0:0:0:0:0:1")) {
  87 + ip = "127.0.0.1";
  88 + }
  89 + return ip;
  90 + }
  91 +}
src/main/java/org/smart4j/framework/mvc/Handler.java 0 → 100644
  1 +++ a/src/main/java/org/smart4j/framework/mvc/Handler.java
  1 +package org.smart4j.framework.mvc;
  2 +
  3 +import java.lang.reflect.Method;
  4 +import java.util.regex.Matcher;
  5 +
  6 +/**
  7 + * 封装 Action 方法相关信息
  8 + *
  9 + * @author huangyong
  10 + * @since 1.0
  11 + */
  12 +public class Handler {
  13 +
  14 + private Class<?> actionClass;
  15 + private Method actionMethod;
  16 + private Matcher requestPathMatcher;
  17 +
  18 + public Handler(Class<?> actionClass, Method actionMethod) {
  19 + this.actionClass = actionClass;
  20 + this.actionMethod = actionMethod;
  21 + }
  22 +
  23 + public Class<?> getActionClass() {
  24 + return actionClass;
  25 + }
  26 +
  27 + public Method getActionMethod() {
  28 + return actionMethod;
  29 + }
  30 +
  31 + public Matcher getRequestPathMatcher() {
  32 + return requestPathMatcher;
  33 + }
  34 +
  35 + public void setRequestPathMatcher(Matcher requestPathMatcher) {
  36 + this.requestPathMatcher = requestPathMatcher;
  37 + }
  38 +}
0 \ No newline at end of file 39 \ No newline at end of file
src/main/java/org/smart4j/framework/mvc/HandlerExceptionResolver.java 0 → 100644
  1 +++ a/src/main/java/org/smart4j/framework/mvc/HandlerExceptionResolver.java
  1 +package org.smart4j.framework.mvc;
  2 +
  3 +import javax.servlet.http.HttpServletRequest;
  4 +import javax.servlet.http.HttpServletResponse;
  5 +
  6 +/**
  7 + * Handler 异常解析器
  8 + *
  9 + * @author huangyong
  10 + * @since 2.3
  11 + */
  12 +public interface HandlerExceptionResolver {
  13 +
  14 + /**
  15 + * 解析 Handler 异常
  16 + *
  17 + * @param request 请求对象
  18 + * @param response 响应对象
  19 + * @param e 异常
  20 + */
  21 + void resolveHandlerException(HttpServletRequest request, HttpServletResponse response, Exception e);
  22 +}
src/main/java/org/smart4j/framework/mvc/HandlerInvoker.java 0 → 100644
  1 +++ a/src/main/java/org/smart4j/framework/mvc/HandlerInvoker.java
  1 +package org.smart4j.framework.mvc;
  2 +
  3 +import javax.servlet.http.HttpServletRequest;
  4 +import javax.servlet.http.HttpServletResponse;
  5 +
  6 +/**
  7 + * Handler 调用器
  8 + *
  9 + * @author huangyong
  10 + * @since 2.3
  11 + */
  12 +public interface HandlerInvoker {
  13 +
  14 + /**
  15 + * 调用 Handler
  16 + *
  17 + * @param request 请求对象
  18 + * @param response 响应对象
  19 + * @param handler Handler
  20 + * @throws Exception 异常
  21 + */
  22 + void invokeHandler(HttpServletRequest request, HttpServletResponse response, Handler handler) throws Exception;
  23 +}
src/main/java/org/smart4j/framework/mvc/HandlerMapping.java 0 → 100644
  1 +++ a/src/main/java/org/smart4j/framework/mvc/HandlerMapping.java
  1 +package org.smart4j.framework.mvc;
  2 +
  3 +/**
  4 + * 处理器映射
  5 + *
  6 + * @author huangyong
  7 + * @since 2.3
  8 + */
  9 +public interface HandlerMapping {
  10 +
  11 + /**
  12 + * 获取 Handler
  13 + *
  14 + * @param currentRequestMethod 当前请求方法
  15 + * @param currentRequestPath 当前请求路径
  16 + * @return Handler
  17 + */
  18 + Handler getHandler(String currentRequestMethod, String currentRequestPath);
  19 +}
src/main/java/org/smart4j/framework/mvc/Requester.java 0 → 100644
  1 +++ a/src/main/java/org/smart4j/framework/mvc/Requester.java
  1 +package org.smart4j.framework.mvc;
  2 +
  3 +/**
  4 + * 封装 Request 对象相关信息
  5 + *
  6 + * @author huangyong
  7 + * @since 1.0
  8 + */
  9 +public class Requester {
  10 +
  11 + private String requestMethod;
  12 + private String requestPath;
  13 +
  14 + public Requester(String requestMethod, String requestPath) {
  15 + this.requestMethod = requestMethod;
  16 + this.requestPath = requestPath;
  17 + }
  18 +
  19 + public String getRequestMethod() {
  20 + return requestMethod;
  21 + }
  22 +
  23 + public String getRequestPath() {
  24 + return requestPath;
  25 + }
  26 +}
0 \ No newline at end of file 27 \ No newline at end of file
src/main/java/org/smart4j/framework/mvc/UploadHelper.java 0 → 100644
  1 +++ a/src/main/java/org/smart4j/framework/mvc/UploadHelper.java
  1 +package org.smart4j.framework.mvc;
  2 +
  3 +import java.io.BufferedInputStream;
  4 +import java.io.BufferedOutputStream;
  5 +import java.io.File;
  6 +import java.io.FileOutputStream;
  7 +import java.io.InputStream;
  8 +import java.io.OutputStream;
  9 +import java.util.ArrayList;
  10 +import java.util.HashMap;
  11 +import java.util.List;
  12 +import java.util.Map;
  13 +import javax.servlet.ServletContext;
  14 +import javax.servlet.http.HttpServletRequest;
  15 +import org.apache.commons.fileupload.FileItem;
  16 +import org.apache.commons.fileupload.FileUploadBase;
  17 +import org.apache.commons.fileupload.disk.DiskFileItemFactory;
  18 +import org.apache.commons.fileupload.servlet.ServletFileUpload;
  19 +import org.slf4j.Logger;
  20 +import org.slf4j.LoggerFactory;
  21 +import org.smart4j.framework.FrameworkConstant;
  22 +import org.smart4j.framework.mvc.bean.Multipart;
  23 +import org.smart4j.framework.mvc.bean.Multiparts;
  24 +import org.smart4j.framework.mvc.bean.Params;
  25 +import org.smart4j.framework.mvc.fault.UploadException;
  26 +import org.smart4j.framework.util.FileUtil;
  27 +import org.smart4j.framework.util.StreamUtil;
  28 +import org.smart4j.framework.util.StringUtil;
  29 +
  30 +/**
  31 + * 封装文件上传相关操作
  32 + *
  33 + * @author huangyong
  34 + * @since 2.1
  35 + */
  36 +public class UploadHelper {
  37 +
  38 + private static final Logger logger = LoggerFactory.getLogger(UploadHelper.class);
  39 +
  40 + /**
  41 + * FileUpload 对象(用于解析所上传的文件)
  42 + */
  43 + private static ServletFileUpload fileUpload;
  44 +
  45 + /**
  46 + * 初始化
  47 + */
  48 + public static void init(ServletContext servletContext) {
  49 + // 获取一个临时目录(使用 Tomcat 的 work 目录)
  50 + File repository = (File) servletContext.getAttribute("javax.servlet.context.tempdir");
  51 + // 创建 FileUpload 对象
  52 + fileUpload = new ServletFileUpload(new DiskFileItemFactory(DiskFileItemFactory.DEFAULT_SIZE_THRESHOLD, repository));
  53 + System.out.println("fileUpload.getFileSizeMax()"+fileUpload.getFileSizeMax());
  54 + // 设置上传限制
  55 + int uploadLimit = FrameworkConstant.UPLOAD_LIMIT;
  56 + System.out.println(uploadLimit);
  57 +// if (uploadLimit != 0) {
  58 +// fileUpload.setSizeMax(uploadLimit * 1024 * 1024);
  59 +// fileUpload.setFileSizeMax(uploadLimit * 1024 * 1024); // 单位为 M
  60 +// System.out.println(fileUpload.getFileSizeMax());
  61 +// }
  62 + }
  63 +
  64 + /**
  65 + * 判断请求是否为 multipart 类型
  66 + */
  67 + public static boolean isMultipart(HttpServletRequest request) {
  68 + // 判断上传文件的内容是否为 multipart 类型
  69 + return ServletFileUpload.isMultipartContent(request);
  70 + }
  71 +
  72 + /**
  73 + * 创建 multipart 请求参数列表
  74 + */
  75 + public static List<Object> createMultipartParamList(HttpServletRequest request) throws Exception {
  76 + // 定义参数列表
  77 + List<Object> paramList = new ArrayList<Object>();
  78 + // 创建两个对象,分别对应 普通字段 与 文件字段
  79 + Map<String, Object> fieldMap = new HashMap<String, Object>();
  80 + List<Multipart> multipartList = new ArrayList<Multipart>();
  81 + // 获取并遍历表单项
  82 + List<FileItem> fileItemList=null;
  83 + try {
  84 + fileItemList = fileUpload.parseRequest(request);
  85 + } catch (FileUploadBase.FileSizeLimitExceededException e) {
  86 + e.printStackTrace();
  87 + }
  88 + for (FileItem fileItem : fileItemList) {
  89 + // 分两种情况处理表单项
  90 + String fieldName = fileItem.getFieldName();
  91 + if (fileItem.isFormField()) {
  92 + // 处理普通字段
  93 + String fieldValue = fileItem.getString(FrameworkConstant.UTF_8);
  94 + fieldMap.put(fieldName, fieldValue);
  95 + } else {
  96 + // 处理文件字段
  97 + String fileName = FileUtil.getRealFileName(fileItem.getName());
  98 + if (StringUtil.isNotEmpty(fileName)) {
  99 + long fileSize = fileItem.getSize();
  100 + String contentType = fileItem.getContentType();
  101 + InputStream inputSteam = fileItem.getInputStream();
  102 + // 创建 Multipart 对象,并将其添加到 multipartList 中
  103 + Multipart multipart = new Multipart(fieldName, fileName, fileSize, contentType, inputSteam);
  104 + multipartList.add(multipart);
  105 + }
  106 + }
  107 + }
  108 + // 初始化参数列表
  109 + paramList.add(new Params(fieldMap));
  110 + paramList.add(new Multiparts(multipartList));
  111 + // 返回参数列表
  112 + return paramList;
  113 + }
  114 +
  115 + /**
  116 + * 上传文件
  117 + */
  118 + public static void uploadFile(String basePath, Multipart multipart) {
  119 + try {
  120 + if (multipart != null) {
  121 + // 创建文件路径(绝对路径)
  122 + System.out.println("创建文件路径(绝对路径)创建文件路径(绝对路径)");
  123 + String filePath = basePath + multipart.getFileName();
  124 + FileUtil.createFile(filePath);
  125 + // 执行流复制操作
  126 + InputStream inputStream = new BufferedInputStream(multipart.getInputStream());
  127 + OutputStream outputStream = new BufferedOutputStream(new FileOutputStream(filePath));
  128 + StreamUtil.copyStream(inputStream, outputStream);
  129 + }
  130 + } catch (Exception e) {
  131 + e.printStackTrace();
  132 + logger.error("上传文件出错!", e);
  133 + throw new RuntimeException(e);
  134 + }
  135 + }
  136 +
  137 + /**
  138 + * 批量上传文件
  139 + */
  140 + public static void uploadFiles(String basePath, Multiparts multiparts) {
  141 + for (Multipart multipart : multiparts.getAll()) {
  142 + uploadFile(basePath, multipart);
  143 + }
  144 + }
  145 +}
src/main/java/org/smart4j/framework/mvc/ViewResolver.java 0 → 100644
  1 +++ a/src/main/java/org/smart4j/framework/mvc/ViewResolver.java
  1 +package org.smart4j.framework.mvc;
  2 +
  3 +import javax.servlet.http.HttpServletRequest;
  4 +import javax.servlet.http.HttpServletResponse;
  5 +
  6 +/**
  7 + * 视图解析器
  8 + *
  9 + * @author huangyong
  10 + * @since 2.3
  11 + */
  12 +public interface ViewResolver {
  13 +
  14 + /**
  15 + * 解析视图
  16 + *
  17 + * @param request 请求对象
  18 + * @param response 响应对象
  19 + * @param actionMethodResult Action 方法返回值
  20 + */
  21 + void resolveView(HttpServletRequest request, HttpServletResponse response, Object actionMethodResult);
  22 +}
src/main/java/org/smart4j/framework/mvc/annotation/Action.java 0 → 100644
  1 +++ a/src/main/java/org/smart4j/framework/mvc/annotation/Action.java
  1 +package org.smart4j.framework.mvc.annotation;
  2 +
  3 +import java.lang.annotation.ElementType;
  4 +import java.lang.annotation.Retention;
  5 +import java.lang.annotation.RetentionPolicy;
  6 +import java.lang.annotation.Target;
  7 +
  8 +/**
  9 + * 定义 Action 类
  10 + *
  11 + * @author huangyong
  12 + * @since 1.0
  13 + */
  14 +@Target(ElementType.TYPE)
  15 +@Retention(RetentionPolicy.RUNTIME)
  16 +public @interface Action {
  17 +}
src/main/java/org/smart4j/framework/mvc/annotation/Request.java 0 → 100644
  1 +++ a/src/main/java/org/smart4j/framework/mvc/annotation/Request.java
  1 +package org.smart4j.framework.mvc.annotation;
  2 +
  3 +import java.lang.annotation.ElementType;
  4 +import java.lang.annotation.Retention;
  5 +import java.lang.annotation.RetentionPolicy;
  6 +import java.lang.annotation.Target;
  7 +
  8 +/**
  9 + * 定义请求
  10 + *
  11 + * @author huangyong
  12 + * @since 1.0
  13 + */
  14 +@Target(ElementType.METHOD)
  15 +@Retention(RetentionPolicy.RUNTIME)
  16 +public @interface Request {
  17 +
  18 + /**
  19 + * 定义 GET 请求
  20 + *
  21 + * @author huangyong
  22 + * @since 2.1
  23 + */
  24 + @Target(ElementType.METHOD)
  25 + @Retention(RetentionPolicy.RUNTIME)
  26 + public @interface Get {
  27 +
  28 + String value();
  29 + }
  30 +
  31 + /**
  32 + * 定义 POST 请求
  33 + *
  34 + * @author huangyong
  35 + * @since 2.1
  36 + */
  37 + @Target(ElementType.METHOD)
  38 + @Retention(RetentionPolicy.RUNTIME)
  39 + public @interface Post {
  40 +
  41 + String value();
  42 + }
  43 +
  44 + /**
  45 + * 定义 PUT 请求
  46 + *
  47 + * @author huangyong
  48 + * @since 2.1
  49 + */
  50 + @Target(ElementType.METHOD)
  51 + @Retention(RetentionPolicy.RUNTIME)
  52 + public @interface Put {
  53 +
  54 + String value();
  55 + }
  56 +
  57 + /**
  58 + * 定义 DELETE 请求
  59 + *
  60 + * @author huangyong
  61 + * @since 2.1
  62 + */
  63 + @Target(ElementType.METHOD)
  64 + @Retention(RetentionPolicy.RUNTIME)
  65 + public @interface Delete {
  66 +
  67 + String value();
  68 + }
  69 +}
src/main/java/org/smart4j/framework/mvc/bean/ApiBean.java 0 → 100644
  1 +++ a/src/main/java/org/smart4j/framework/mvc/bean/ApiBean.java
  1 +/**
  2 + * Project Name:smart-framework
  3 + * File Name:ApiBean.java
  4 + * Package Name:org.smart4j.framework.mvc.bean
  5 + * Date:2016年5月24日上午9:17:36
  6 + * Copyright (c) 2016, cnlive.com All Rights Reserved.
  7 + *
  8 + */
  9 +
  10 +package org.smart4j.framework.mvc.bean;
  11 +
  12 +import org.smart4j.framework.core.bean.BaseBean;
  13 +
  14 +/**
  15 + * TODO: 这里用一句话描述当前类的作用 Date: 2016年5月24日 上午9:17:36 <br/>
  16 + *
  17 + * @author liujicheng
  18 + * @version V1.0
  19 + * @since JDK 1.6
  20 + */
  21 +public class ApiBean extends BaseBean {
  22 + private String message;
  23 + private Object data;
  24 + private int code;
  25 + private int next_cursor;
  26 +
  27 + public String getMessage() {
  28 + return message;
  29 + }
  30 +
  31 + public void setMessage(String message) {
  32 + this.message = message;
  33 + }
  34 +
  35 + public Object getData() {
  36 + return data;
  37 + }
  38 +
  39 + public void setData(Object data) {
  40 + this.data = data;
  41 + }
  42 +
  43 + public int getCode() {
  44 + return code;
  45 + }
  46 +
  47 + public void setCode(int code) {
  48 + this.code = code;
  49 + }
  50 +
  51 +}
src/main/java/org/smart4j/framework/mvc/bean/Multipart.java 0 → 100644
  1 +++ a/src/main/java/org/smart4j/framework/mvc/bean/Multipart.java
  1 +package org.smart4j.framework.mvc.bean;
  2 +
  3 +import java.io.InputStream;
  4 +import org.smart4j.framework.core.bean.BaseBean;
  5 +
  6 +/**
  7 + * 封装文件上传对象相关属性
  8 + *
  9 + * @author huangyong
  10 + * @since 1.0
  11 + */
  12 +public class Multipart extends BaseBean {
  13 +
  14 + private String fieldName;
  15 + private String fileName;
  16 + private long fileSize;
  17 + private String contentType;
  18 + private InputStream inputStream;
  19 +
  20 + public Multipart(String fieldName, String fileName, long fileSize, String contentType, InputStream inputStream) {
  21 + this.fieldName = fieldName;
  22 + this.fileName = fileName;
  23 + this.fileSize = fileSize;
  24 + this.contentType = contentType;
  25 + this.inputStream = inputStream;
  26 + }
  27 +
  28 + public String getFieldName() {
  29 + return fieldName;
  30 + }
  31 +
  32 + public String getFileName() {
  33 + return fileName;
  34 + }
  35 +
  36 + public long getFileSize() {
  37 + return fileSize;
  38 + }
  39 +
  40 + public String getContentType() {
  41 + return contentType;
  42 + }
  43 +
  44 + public InputStream getInputStream() {
  45 + return inputStream;
  46 + }
  47 +}
src/main/java/org/smart4j/framework/mvc/bean/Multiparts.java 0 → 100644
  1 +++ a/src/main/java/org/smart4j/framework/mvc/bean/Multiparts.java
  1 +package org.smart4j.framework.mvc.bean;
  2 +
  3 +import java.util.ArrayList;
  4 +import java.util.List;
  5 +import org.smart4j.framework.core.bean.BaseBean;
  6 +
  7 +/**
  8 + * 封装批量文件上传对象
  9 + *
  10 + * @author huangyong
  11 + * @since 1.0
  12 + */
  13 +public class Multiparts extends BaseBean {
  14 +
  15 + private List<Multipart> multipartList = new ArrayList<Multipart>();
  16 +
  17 + public Multiparts(List<Multipart> multipartList) {
  18 + this.multipartList = multipartList;
  19 + }
  20 +
  21 + public int size() {
  22 + return multipartList.size();
  23 + }
  24 +
  25 + public List<Multipart> getAll() {
  26 + return multipartList;
  27 + }
  28 +
  29 + public Multipart getOne() {
  30 + return size() == 1 ? multipartList.get(0) : null;
  31 + }
  32 +}
src/main/java/org/smart4j/framework/mvc/bean/Params.java 0 → 100644
  1 +++ a/src/main/java/org/smart4j/framework/mvc/bean/Params.java
  1 +package org.smart4j.framework.mvc.bean;
  2 +
  3 +import java.util.Map;
  4 +import org.smart4j.framework.core.bean.BaseBean;
  5 +import org.smart4j.framework.util.CastUtil;
  6 +
  7 +/**
  8 + * 封装请求参数
  9 + *
  10 + * @author huangyong
  11 + * @since 2.2
  12 + */
  13 +public class Params extends BaseBean {
  14 +
  15 + private final Map<String, Object> fieldMap;
  16 +
  17 + public Params(Map<String, Object> fieldMap) {
  18 + this.fieldMap = fieldMap;
  19 + }
  20 +
  21 + public Map<String, Object> getFieldMap() {
  22 + return fieldMap;
  23 + }
  24 +
  25 + public String getString(String name) {
  26 + return CastUtil.castString(get(name));
  27 + }
  28 +
  29 + public double getDouble(String name) {
  30 + return CastUtil.castDouble(get(name));
  31 + }
  32 +
  33 + public long getLong(String name) {
  34 + return CastUtil.castLong(get(name));
  35 + }
  36 +
  37 + public int getInt(String name) {
  38 + return CastUtil.castInt(get(name));
  39 + }
  40 +
  41 + private Object get(String name) {
  42 + return fieldMap.get(name);
  43 + }
  44 +}
src/main/java/org/smart4j/framework/mvc/bean/Redirect.java 0 → 100644
  1 +++ a/src/main/java/org/smart4j/framework/mvc/bean/Redirect.java
  1 +package org.smart4j.framework.mvc.bean;
  2 +
  3 +public class Redirect {
  4 + private String redirectUrl;
  5 + private String message;
  6 + private int code;
  7 +
  8 + public String getMessage() {
  9 + return message;
  10 + }
  11 +
  12 + public void setMessage(String message) {
  13 + this.message = message;
  14 + }
  15 +
  16 + public int getCode() {
  17 + return code;
  18 + }
  19 +
  20 + public void setCode(int code) {
  21 + this.code = code;
  22 + }
  23 +
  24 + public String getRedirectUrl() {
  25 + return redirectUrl;
  26 + }
  27 +
  28 + public void setRedirectUrl(String redirectUrl) {
  29 + this.redirectUrl = redirectUrl;
  30 + }
  31 +
  32 +}
src/main/java/org/smart4j/framework/mvc/bean/Result.java 0 → 100644
  1 +++ a/src/main/java/org/smart4j/framework/mvc/bean/Result.java
  1 +package org.smart4j.framework.mvc.bean;
  2 +
  3 +import org.smart4j.framework.core.bean.BaseBean;
  4 +
  5 +/**
  6 + * 封装返回数据
  7 + *
  8 + * @author huangyong
  9 + * @since 1.0
  10 + */
  11 +public class Result extends BaseBean {
  12 +
  13 + private boolean success; // 成功标志
  14 + private int error; // 错误代码
  15 + private Object data; // 相关数据
  16 +
  17 + public Result(boolean success) {
  18 + this.success = success;
  19 + }
  20 +
  21 + public Result error(int error) {
  22 + this.error = error;
  23 + return this;
  24 + }
  25 +
  26 + public Result data(Object data) {
  27 + this.data = data;
  28 + return this;
  29 + }
  30 +
  31 + public boolean isSuccess() {
  32 + return success;
  33 + }
  34 +
  35 + public void setSuccess(boolean success) {
  36 + this.success = success;
  37 + }
  38 +
  39 + public int getError() {
  40 + return error;
  41 + }
  42 +
  43 + public void setError(int error) {
  44 + this.error = error;
  45 + }
  46 +
  47 + public Object getData() {
  48 + return data;
  49 + }
  50 +
  51 + public void setData(Object data) {
  52 + this.data = data;
  53 + }
  54 +}
src/main/java/org/smart4j/framework/mvc/bean/ResultBean.java 0 → 100644
  1 +++ a/src/main/java/org/smart4j/framework/mvc/bean/ResultBean.java
  1 +/**
  2 + * Project Name:smart-framework
  3 + * File Name:ApiBean.java
  4 + * Package Name:org.smart4j.framework.mvc.bean
  5 + * Date:2016年5月24日上午9:17:36
  6 + * Copyright (c) 2016, cnlive.com All Rights Reserved.
  7 + *
  8 + */
  9 +
  10 +package org.smart4j.framework.mvc.bean;
  11 +
  12 +import org.smart4j.framework.core.bean.BaseBean;
  13 +
  14 +
  15 +public class ResultBean extends BaseBean {
  16 + private String errorMessage;
  17 + private Object data;
  18 + private String errorCode;
  19 + public String getErrorMessage() {
  20 + return errorMessage;
  21 + }
  22 + public void setErrorMessage(String errorMessage) {
  23 + this.errorMessage = errorMessage;
  24 + }
  25 + public Object getData() {
  26 + return data;
  27 + }
  28 + public void setData(Object data) {
  29 + this.data = data;
  30 + }
  31 + public String getErrorCode() {
  32 + return errorCode;
  33 + }
  34 + public void setErrorCode(String errorCode) {
  35 + this.errorCode = errorCode;
  36 + }
  37 +
  38 +}
src/main/java/org/smart4j/framework/mvc/bean/View.java 0 → 100644
  1 +++ a/src/main/java/org/smart4j/framework/mvc/bean/View.java
  1 +package org.smart4j.framework.mvc.bean;
  2 +
  3 +import java.util.HashMap;
  4 +import java.util.Map;
  5 +import org.smart4j.framework.core.bean.BaseBean;
  6 +
  7 +/**
  8 + * 封装视图对象
  9 + *
  10 + * @author huangyong
  11 + * @since 1.0
  12 + */
  13 +public class View extends BaseBean {
  14 +
  15 + private String path; // 视图路径
  16 + private Map<String, Object> data; // 相关数据
  17 +
  18 + public View(String path) {
  19 + this.path = path;
  20 + data = new HashMap<String, Object>();
  21 + }
  22 +
  23 + public View data(String key, Object value) {
  24 + data.put(key, value);
  25 + return this;
  26 + }
  27 +
  28 + public boolean isRedirect() {
  29 + return path.startsWith("/");
  30 + }
  31 +
  32 + public String getPath() {
  33 + return path;
  34 + }
  35 +
  36 + public void setPath(String path) {
  37 + this.path = path;
  38 + }
  39 +
  40 + public Map<String, Object> getData() {
  41 + return data;
  42 + }
  43 +
  44 + public void setData(Map<String, Object> data) {
  45 + this.data = data;
  46 + }
  47 +}
src/main/java/org/smart4j/framework/mvc/fault/AuthcException.java 0 → 100644
  1 +++ a/src/main/java/org/smart4j/framework/mvc/fault/AuthcException.java
  1 +package org.smart4j.framework.mvc.fault;
  2 +
  3 +/**
  4 + * 认证异常(当非法访问时抛出)
  5 + *
  6 + * @author huangyong
  7 + * @since 2.1
  8 + */
  9 +public class AuthcException extends RuntimeException {
  10 +
  11 + public AuthcException() {
  12 + super();
  13 + }
  14 +
  15 + public AuthcException(String message) {
  16 + super(message);
  17 + }
  18 +
  19 + public AuthcException(String message, Throwable cause) {
  20 + super(message, cause);
  21 + }
  22 +
  23 + public AuthcException(Throwable cause) {
  24 + super(cause);
  25 + }
  26 +}
src/main/java/org/smart4j/framework/mvc/fault/AuthzException.java 0 → 100644
  1 +++ a/src/main/java/org/smart4j/framework/mvc/fault/AuthzException.java
  1 +package org.smart4j.framework.mvc.fault;
  2 +
  3 +/**
  4 + * 授权异常(当权限无效时抛出)
  5 + *
  6 + * @author huangyong
  7 + * @since 2.1
  8 + */
  9 +public class AuthzException extends RuntimeException {
  10 +
  11 + public AuthzException() {
  12 + super();
  13 + }
  14 +
  15 + public AuthzException(String message) {
  16 + super(message);
  17 + }
  18 +
  19 + public AuthzException(String message, Throwable cause) {
  20 + super(message, cause);
  21 + }
  22 +
  23 + public AuthzException(Throwable cause) {
  24 + super(cause);
  25 + }
  26 +}
src/main/java/org/smart4j/framework/mvc/fault/UploadException.java 0 → 100644
  1 +++ a/src/main/java/org/smart4j/framework/mvc/fault/UploadException.java
  1 +package org.smart4j.framework.mvc.fault;
  2 +
  3 +/**
  4 + * 上传异常(当文件上传失败时抛出)
  5 + *
  6 + * @author huangyong
  7 + * @since 2.1
  8 + */
  9 +public class UploadException extends RuntimeException {
  10 +
  11 + public UploadException() {
  12 + super();
  13 + }
  14 +
  15 + public UploadException(String message) {
  16 + super(message);
  17 + }
  18 +
  19 + public UploadException(String message, Throwable cause) {
  20 + super(message, cause);
  21 + }
  22 +
  23 + public UploadException(Throwable cause) {
  24 + super(cause);
  25 + }
  26 +}
src/main/java/org/smart4j/framework/mvc/impl/DefaultHandlerExceptionResolver.java 0 → 100644
  1 +++ a/src/main/java/org/smart4j/framework/mvc/impl/DefaultHandlerExceptionResolver.java
  1 +package org.smart4j.framework.mvc.impl;
  2 +
  3 +import javax.servlet.http.HttpServletRequest;
  4 +import javax.servlet.http.HttpServletResponse;
  5 +import org.slf4j.Logger;
  6 +import org.slf4j.LoggerFactory;
  7 +import org.smart4j.framework.FrameworkConstant;
  8 +import org.smart4j.framework.mvc.HandlerExceptionResolver;
  9 +import org.smart4j.framework.mvc.fault.AuthcException;
  10 +import org.smart4j.framework.mvc.fault.AuthzException;
  11 +import org.smart4j.framework.util.WebUtil;
  12 +
  13 +/**
  14 + * 默认 Handler 异常解析器
  15 + *
  16 + * @author huangyong
  17 + * @since 2.3
  18 + */
  19 +public class DefaultHandlerExceptionResolver implements HandlerExceptionResolver {
  20 +
  21 + private static final Logger logger = LoggerFactory.getLogger(DefaultHandlerExceptionResolver.class);
  22 +
  23 + @Override
  24 + public void resolveHandlerException(HttpServletRequest request, HttpServletResponse response, Exception e) {
  25 + // 判断异常原因
  26 + e.printStackTrace();
  27 + Throwable cause = e.getCause();
  28 + if (cause == null) {
  29 + logger.error(e.getMessage(), e);
  30 + return;
  31 + }
  32 + if (cause instanceof AuthcException) {
  33 + // 分两种情况进行处理
  34 + if (WebUtil.isAJAX(request)) {
  35 + // 跳转到 403 页面
  36 + WebUtil.sendError(HttpServletResponse.SC_FORBIDDEN, "", response);
  37 + } else {
  38 + // 重定向到首页
  39 + WebUtil.redirectRequest(FrameworkConstant.HOME_PAGE, request, response);
  40 + }
  41 + } else if (cause instanceof AuthzException) {
  42 + // 跳转到 403 页面
  43 + WebUtil.sendError(HttpServletResponse.SC_FORBIDDEN, "", response);
  44 + } else {
  45 + // 跳转到 500 页面
  46 + WebUtil.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, cause.getMessage(), response);
  47 + }
  48 + }
  49 +}
src/main/java/org/smart4j/framework/mvc/impl/DefaultHandlerInvoker.java 0 → 100644
  1 +++ a/src/main/java/org/smart4j/framework/mvc/impl/DefaultHandlerInvoker.java
  1 +package org.smart4j.framework.mvc.impl;
  2 +
  3 +import java.lang.reflect.InvocationTargetException;
  4 +import java.lang.reflect.Method;
  5 +import java.util.ArrayList;
  6 +import java.util.List;
  7 +import java.util.Map;
  8 +import java.util.regex.Matcher;
  9 +import javax.servlet.http.HttpServletRequest;
  10 +import javax.servlet.http.HttpServletResponse;
  11 +import org.smart4j.framework.InstanceFactory;
  12 +import org.smart4j.framework.ioc.BeanHelper;
  13 +import org.smart4j.framework.mvc.Handler;
  14 +import org.smart4j.framework.mvc.HandlerInvoker;
  15 +import org.smart4j.framework.mvc.UploadHelper;
  16 +import org.smart4j.framework.mvc.ViewResolver;
  17 +import org.smart4j.framework.mvc.bean.Params;
  18 +import org.smart4j.framework.util.CastUtil;
  19 +import org.smart4j.framework.util.ClassUtil;
  20 +import org.smart4j.framework.util.MapUtil;
  21 +import org.smart4j.framework.util.WebUtil;
  22 +
  23 +/**
  24 + * 默认 Handler 调用器
  25 + *
  26 + * @author huangyong
  27 + * @since 2.3
  28 + */
  29 +public class DefaultHandlerInvoker implements HandlerInvoker {
  30 +
  31 + private ViewResolver viewResolver = InstanceFactory.getViewResolver();
  32 +
  33 + @Override
  34 + public void invokeHandler(HttpServletRequest request, HttpServletResponse response, Handler handler) throws Exception {
  35 + // 获取 Action 相关信息
  36 + Class<?> actionClass = handler.getActionClass();
  37 + Method actionMethod = handler.getActionMethod();
  38 + // 从 BeanHelper 中创建 Action 实例
  39 + Object actionInstance = BeanHelper.getBean(actionClass);
  40 + // 创建 Action 方法的参数列表
  41 + List<Object> actionMethodParamList = createActionMethodParamList(request, handler);
  42 + // 检查参数列表是否合法
  43 + checkParamList(actionMethod, actionMethodParamList);
  44 + // 调用 Action 方法
  45 + Object actionMethodResult = invokeActionMethod(actionMethod, actionInstance, actionMethodParamList);
  46 + // 解析视图
  47 + viewResolver.resolveView(request, response, actionMethodResult);
  48 + }
  49 +
  50 + public List<Object> createActionMethodParamList(HttpServletRequest request, Handler handler) throws Exception {
  51 + // 定义参数列表
  52 + List<Object> paramList = new ArrayList<Object>();
  53 + // 获取 Action 方法参数类型
  54 + Class<?>[] actionParamTypes = handler.getActionMethod().getParameterTypes();
  55 + // 添加路径参数列表(请求路径中的带占位符参数)
  56 + paramList.addAll(createPathParamList(handler.getRequestPathMatcher(), actionParamTypes));
  57 + // 分两种情况进行处理
  58 + if (UploadHelper.isMultipart(request)) {
  59 + // 添加 Multipart 请求参数列表
  60 + paramList.addAll(UploadHelper.createMultipartParamList(request));
  61 + } else {
  62 + // 添加普通请求参数列表(包括 Query String 与 Form Data)
  63 + Map<String, Object> requestParamMap = WebUtil.getRequestParamMap(request);
  64 + if (MapUtil.isNotEmpty(requestParamMap)) {
  65 + paramList.add(new Params(requestParamMap));
  66 + }
  67 + }
  68 + // 返回参数列表
  69 + return paramList;
  70 + }
  71 +
  72 + private List<Object> createPathParamList(Matcher requestPathMatcher, Class<?>[] actionParamTypes) {
  73 + // 定义参数列表
  74 + List<Object> paramList = new ArrayList<Object>();
  75 + // 遍历正则表达式中所匹配的组
  76 + for (int i = 1; i <= requestPathMatcher.groupCount(); i++) {
  77 + // 获取请求参数
  78 + String param = requestPathMatcher.group(i);
  79 + // 获取参数类型(支持四种类型:int/Integer、long/Long、double/Double、String)
  80 + Class<?> paramType = actionParamTypes[i - 1];
  81 + if (ClassUtil.isInt(paramType)) {
  82 + paramList.add(CastUtil.castInt(param));
  83 + } else if (ClassUtil.isLong(paramType)) {
  84 + paramList.add(CastUtil.castLong(param));
  85 + } else if (ClassUtil.isDouble(paramType)) {
  86 + paramList.add(CastUtil.castDouble(param));
  87 + } else if (ClassUtil.isString(paramType)) {
  88 + paramList.add(param);
  89 + }
  90 + }
  91 + // 返回参数列表
  92 + return paramList;
  93 + }
  94 +
  95 + private Object invokeActionMethod(Method actionMethod, Object actionInstance, List<Object> actionMethodParamList) throws IllegalAccessException, InvocationTargetException {
  96 + // 通过反射调用 Action 方法
  97 + actionMethod.setAccessible(true); // 取消类型安全检测(可提高反射性能)
  98 + return actionMethod.invoke(actionInstance, actionMethodParamList.toArray());
  99 + }
  100 +
  101 + private void checkParamList(Method actionMethod, List<Object> actionMethodParamList) {
  102 + // 判断 Action 方法参数的个数是否匹配
  103 + Class<?>[] actionMethodParameterTypes = actionMethod.getParameterTypes();
  104 + if (actionMethodParameterTypes.length != actionMethodParamList.size()) {
  105 + String message = String.format("因为参数个数不匹配,所以无法调用 Action 方法!原始参数个数:%d,实际参数个数:%d", actionMethodParameterTypes.length, actionMethodParamList.size());
  106 + throw new RuntimeException(message);
  107 + }
  108 + }
  109 +}
src/main/java/org/smart4j/framework/mvc/impl/DefaultHandlerMapping.java 0 → 100644
  1 +++ a/src/main/java/org/smart4j/framework/mvc/impl/DefaultHandlerMapping.java
  1 +package org.smart4j.framework.mvc.impl;
  2 +
  3 +import java.util.Map;
  4 +import java.util.regex.Matcher;
  5 +import java.util.regex.Pattern;
  6 +import org.smart4j.framework.mvc.ActionHelper;
  7 +import org.smart4j.framework.mvc.Handler;
  8 +import org.smart4j.framework.mvc.HandlerMapping;
  9 +import org.smart4j.framework.mvc.Requester;
  10 +
  11 +/**
  12 + * 默认处理器映射,负责处理请求url和action 的方法对应
  13 + *
  14 + * @author huangyong
  15 + * @since 2.3
  16 + */
  17 +public class DefaultHandlerMapping implements HandlerMapping {
  18 +
  19 + @Override
  20 + public Handler getHandler(String currentRequestMethod, String currentRequestPath) {
  21 + // 定义一个 Handler
  22 + Handler handler = null;
  23 + // 获取并遍历 Action 映射
  24 + Map<Requester, Handler> actionMap = ActionHelper.getActionMap();
  25 + for (Map.Entry<Requester, Handler> actionEntry : actionMap.entrySet()) {
  26 + // 从 Requester 中获取 Request 相关属性
  27 + Requester requester = actionEntry.getKey();
  28 + String requestMethod = requester.getRequestMethod();
  29 + String requestPath = requester.getRequestPath(); // 正则表达式
  30 + // 获取请求路径匹配器(使用正则表达式匹配请求路径并从中获取相应的请求参数)
  31 + Matcher requestPathMatcher = Pattern.compile(requestPath).matcher(currentRequestPath);
  32 + // 判断请求方法与请求路径是否同时匹配
  33 + if (requestMethod.equalsIgnoreCase(currentRequestMethod) && requestPathMatcher.matches()) {
  34 + // 获取 Handler 及其相关属性
  35 + handler = actionEntry.getValue();
  36 + // 设置请求路径匹配器
  37 + if (handler != null) {
  38 + handler.setRequestPathMatcher(requestPathMatcher);
  39 + }
  40 + // 若成功匹配,则终止循环
  41 + break;
  42 + }
  43 + }
  44 + // 返回该 Handler
  45 + return handler;
  46 + }
  47 +}
src/main/java/org/smart4j/framework/mvc/impl/DefaultViewResolver.java 0 → 100644
  1 +++ a/src/main/java/org/smart4j/framework/mvc/impl/DefaultViewResolver.java
  1 +package org.smart4j.framework.mvc.impl;
  2 +
  3 +import java.util.Map;
  4 +
  5 +import javax.servlet.http.HttpServletRequest;
  6 +import javax.servlet.http.HttpServletResponse;
  7 +
  8 +import org.smart4j.framework.FrameworkConstant;
  9 +import org.smart4j.framework.mvc.UploadHelper;
  10 +import org.smart4j.framework.mvc.ViewResolver;
  11 +import org.smart4j.framework.mvc.bean.ApiBean;
  12 +import org.smart4j.framework.mvc.bean.Redirect;
  13 +import org.smart4j.framework.mvc.bean.Result;
  14 +import org.smart4j.framework.mvc.bean.ResultBean;
  15 +import org.smart4j.framework.mvc.bean.View;
  16 +import org.smart4j.framework.util.MapUtil;
  17 +import org.smart4j.framework.util.WebUtil;
  18 +
  19 +/**
  20 + * 默认视图解析器
  21 + *
  22 + * @author huangyong
  23 + * @since 2.3
  24 + */
  25 +public class DefaultViewResolver implements ViewResolver {
  26 +
  27 + @Override
  28 + public void resolveView(HttpServletRequest request, HttpServletResponse response, Object actionMethodResult) {
  29 + if (actionMethodResult != null) {
  30 + // Action 返回值可为 View 或 Result
  31 + if (actionMethodResult instanceof View) {
  32 + // 若为 View,则需考虑两种视图类型(重定向 或 转发)
  33 + View view = (View) actionMethodResult;
  34 + if (view.isRedirect()) {
  35 + // 获取路径
  36 + String path = view.getPath();
  37 + // 重定向请求
  38 + WebUtil.redirectRequest(path, request, response);
  39 + } else {
  40 + // 获取路径
  41 + String path = FrameworkConstant.JSP_PATH + view.getPath();
  42 + // 初始化请求属性
  43 + Map<String, Object> data = view.getData();
  44 + if (MapUtil.isNotEmpty(data)) {
  45 + for (Map.Entry<String, Object> entry : data.entrySet()) {
  46 + request.setAttribute(entry.getKey(), entry.getValue());
  47 + }
  48 + }
  49 + // 转发请求
  50 + WebUtil.forwardRequest(path, request, response);
  51 + }
  52 + } else if (actionMethodResult instanceof ApiBean) {
  53 + ApiBean api = (ApiBean) actionMethodResult;
  54 + // 对于其它类型,统一转换为 JSON 格式并写入响应中
  55 + WebUtil.writeJSON(response, api);
  56 + }else if (actionMethodResult instanceof ResultBean) {
  57 + ResultBean api = (ResultBean) actionMethodResult;
  58 + WebUtil.writeJSON(response, api);
  59 + } else if (actionMethodResult instanceof Redirect) {
  60 + Redirect api = (Redirect) actionMethodResult;
  61 + WebUtil.redirect(response, api);
  62 + } else {
  63 + // 若为 Result,则需考虑两种请求类型(文件上传 或 普通请求)
  64 + Result result = (Result) actionMethodResult;
  65 + if (UploadHelper.isMultipart(request)) {
  66 + // 对于 multipart 类型,说明是文件上传,需要转换为 HTML 格式并写入响应中
  67 + WebUtil.writeHTML(response, result);
  68 + } else {
  69 + // 对于其它类型,统一转换为 JSON 格式并写入响应中
  70 + WebUtil.writeJSON(response, result);
  71 + }
  72 + }
  73 + }
  74 + }
  75 +}
src/main/java/org/smart4j/framework/orm/DataSet.java 0 → 100644
  1 +++ a/src/main/java/org/smart4j/framework/orm/DataSet.java
  1 +package org.smart4j.framework.orm;
  2 +
  3 +import java.io.Serializable;
  4 +import java.util.ArrayList;
  5 +import java.util.Iterator;
  6 +import java.util.LinkedHashMap;
  7 +import java.util.List;
  8 +import java.util.Map;
  9 +import java.util.Set;
  10 +
  11 +import org.apache.commons.lang.StringUtils;
  12 +import org.smart4j.framework.FrameworkConstant;
  13 +import org.smart4j.framework.dao.DatabaseHelper;
  14 +import org.smart4j.framework.dao.SqlHelper;
  15 +import org.smart4j.framework.orm.bean.Condition;
  16 +import org.smart4j.framework.util.ArrayUtil;
  17 +import org.smart4j.framework.util.MapUtil;
  18 +import org.smart4j.framework.util.ObjectUtil;
  19 +
  20 +/**
  21 + * 提供与实体相关的数据库操作
  22 + *
  23 + * @author huangyong
  24 + * @since 1.0
  25 + */
  26 +public class DataSet {
  27 +
  28 + /**
  29 + * 查询单条数据,并转为相应类型的实体
  30 + */
  31 + public static <T> T select(Class<T> entityClass, String condition, Object... params) {
  32 + String sql = SqlHelper.generateSelectSql(entityClass, condition, "");
  33 + return DatabaseHelper.queryEntity(entityClass, sql, params);
  34 + }
  35 +
  36 + /**
  37 + * 查询多条数据,并转为相应类型的实体列表
  38 + */
  39 + public static <T> List<T> selectList(Class<T> entityClass) {
  40 + return selectListWithConditionAndSort(entityClass, "", "");
  41 + }
  42 +
  43 + /**
  44 + * 查询多条数据,并转为相应类型的实体列表(带有查询条件与查询参数)
  45 + */
  46 + public static <T> List<T> selectListWithCondition(Class<T> entityClass, String condition, Object... params) {
  47 + return selectListWithConditionAndSort(entityClass, condition, "", params);
  48 + }
  49 +
  50 + /**
  51 + * 查询多条数据,并转为相应类型的实体列表(带有排序方式)
  52 + */
  53 + public static <T> List<T> selectListWithSort(Class<T> entityClass, String sort) {
  54 + return selectListWithConditionAndSort(entityClass, "", sort);
  55 + }
  56 +
  57 + /**
  58 + * 查询多条数据,并转为相应类型的实体列表(带有查询条件、排序方式与查询参数)
  59 + */
  60 + public static <T> List<T> selectListWithConditionAndSort(Class<T> entityClass, String condition, String sort,
  61 + Object... params) {
  62 + String sql = SqlHelper.generateSelectSql(entityClass, condition, sort);
  63 + return DatabaseHelper.queryEntityList(entityClass, sql, params);
  64 + }
  65 +
  66 + /**
  67 + * 查询数据条数
  68 + */
  69 + public static long selectCount(Class<?> entityClass, String condition, Object... params) {
  70 + String sql = SqlHelper.generateSelectSqlForCount(entityClass, condition);
  71 + return DatabaseHelper.queryCount(sql, params);
  72 + }
  73 +
  74 + /**
  75 + * @param sql
  76 + * @param params
  77 + * @return
  78 + */
  79 + public static List<Map<String, Object>> selectMapWithSql(String sql, Object... params) {
  80 + return DatabaseHelper.queryMapList(sql, params);
  81 + }
  82 +
  83 + /**
  84 + * 适合于搜索查询 统计数
  85 + *
  86 + * @param entityClass
  87 + * @param conditions
  88 + * @return
  89 + */
  90 + public static long selectCount(Class<?> entityClass, List<Condition> conditions) {
  91 + String conditionSql = "";
  92 + List<String> list = new ArrayList<String>();
  93 + // 移除值为空的条件
  94 + List<Condition> cons = new ArrayList<Condition>();
  95 + for (int i = 0; i < conditions.size(); i++) {
  96 + Condition con = conditions.get(i);
  97 + String value = con.getValue();
  98 + if (StringUtils.isNotEmpty(value) && StringUtils.isNotEmpty(value.replace("%", ""))) {
  99 + cons.add(con);
  100 + }
  101 + }
  102 + for (int i = 0; i < cons.size(); i++) {
  103 + Condition con = cons.get(i);
  104 + String condition = con.getCondition();
  105 + String operator = con.getOperator();
  106 + String value = con.getValue();
  107 + if (i == cons.size() - 1) {
  108 + conditionSql += condition;
  109 + } else {
  110 + conditionSql += condition + " " + operator + " ";
  111 + }
  112 + list.add(value);
  113 + }
  114 + String sql = SqlHelper.generateSelectSqlForCount(entityClass, conditionSql);
  115 + return DatabaseHelper.queryCount(sql, list.toArray());
  116 + }
  117 +
  118 + /**
  119 + * 适合于搜索查询
  120 + *
  121 + * @param pageNumber
  122 + * @param pageSize
  123 + * @param entityClass
  124 + * @param conditions
  125 + * @param sort
  126 + * @return
  127 + */
  128 + public static <T> List<T> selectListForPager(int pageNumber, int pageSize, Class<T> entityClass,
  129 + List<Condition> conditions, String sort) {
  130 + String conditionSql = "";
  131 + // 移除值为空的条件
  132 + List<Condition> cons = new ArrayList<Condition>();
  133 + for (int i = 0; i < conditions.size(); i++) {
  134 + Condition con = conditions.get(i);
  135 + String value = con.getValue();
  136 + if (StringUtils.isNotEmpty(value) && StringUtils.isNotEmpty(value.replace("%", ""))) {
  137 + cons.add(con);
  138 + }
  139 + }
  140 +
  141 + List<String> list = new ArrayList<String>();
  142 + for (int i = 0; i < cons.size(); i++) {
  143 + Condition con = cons.get(i);
  144 + String condition = con.getCondition();
  145 + String operator = con.getOperator();
  146 + String value = con.getValue();
  147 + if (i == cons.size() - 1) {
  148 + conditionSql += condition;
  149 + } else {
  150 + conditionSql += condition + " " + operator + " ";
  151 + }
  152 + list.add(value);
  153 + }
  154 + String sql = SqlHelper.generateSelectSqlForPager(pageNumber, pageSize, entityClass, conditionSql, sort);
  155 + return DatabaseHelper.queryEntityList(entityClass, sql, list.toArray());
  156 + }
  157 +
  158 + /**
  159 + * 查询多条数据,并转为列表(分页方式)
  160 + */
  161 + public static <T> List<T> selectListForPager(int pageNumber, int pageSize, Class<T> entityClass, String condition,
  162 + String sort, Object... params) {
  163 + String sql = SqlHelper.generateSelectSqlForPager(pageNumber, pageSize, entityClass, condition, sort);
  164 + return DatabaseHelper.queryEntityList(entityClass, sql, params);
  165 + }
  166 +
  167 + /**
  168 + * 查询多条数据,并转为映射
  169 + */
  170 + public static <T> Map<Long, T> selectMap(Class<T> entityClass) {
  171 + return selectMapWithPK(entityClass, FrameworkConstant.PK_NAME, "", "");
  172 + }
  173 +
  174 + /**
  175 + * 查询多条数据,并转为映射(带有查询条件与查询参数)
  176 + */
  177 + public static <T> Map<Long, T> selectMapWithCondition(Class<T> entityClass, String condition, Object... params) {
  178 + return selectMapWithPK(entityClass, FrameworkConstant.PK_NAME, condition, "", params);
  179 + }
  180 +
  181 + /**
  182 + * 查询多条数据,并转为映射(带有排序方式与查询参数)
  183 + *
  184 + * @since 2.3.3
  185 + */
  186 + public static <T> Map<Long, T> selectMapWithSort(Class<T> entityClass, String sort) {
  187 + return selectMapWithPK(entityClass, FrameworkConstant.PK_NAME, "", sort);
  188 + }
  189 +
  190 + /**
  191 + * 查询多条数据,并转为映射(带有查询条件、排序方式与查询参数)
  192 + */
  193 + public static <T> Map<Long, T> selectMapWithConditionAndSort(Class<T> entityClass, String condition, String sort,
  194 + Object... params) {
  195 + return selectMapWithPK(entityClass, FrameworkConstant.PK_NAME, condition, sort, params);
  196 + }
  197 +
  198 + /**
  199 + * 查询多条数据,并转为映射(带有主键名)
  200 + */
  201 + @SuppressWarnings("unchecked")
  202 + public static <PK, T> Map<PK, T> selectMapWithPK(Class<T> entityClass, String pkName, String condition,
  203 + String sort, Object... params) {
  204 + Map<PK, T> map = new LinkedHashMap<PK, T>();
  205 + List<T> list = selectListWithConditionAndSort(entityClass, condition, sort, params);
  206 + for (T obj : list) {
  207 + PK pk = (PK) ObjectUtil.getFieldValue(obj, pkName);
  208 + map.put(pk, obj);
  209 + }
  210 + return map;
  211 + }
  212 +
  213 + /**
  214 + * 根据列名查询单条数据,并转为相应类型的实体
  215 + */
  216 + public static <T> T selectColumn(Class<?> entityClass, String columnName, String condition, Object... params) {
  217 + String sql = SqlHelper.generateSelectSql(entityClass, condition, "");
  218 + sql = sql.replace("*", columnName);
  219 + return DatabaseHelper.queryColumn(sql, params);
  220 + }
  221 +
  222 + /**
  223 + * 根据列名查询多条数据,并转为相应类型的实体列表
  224 + */
  225 + public static <T> List<T> selectColumnList(Class<?> entityClass, String columnName, String condition, String sort,
  226 + Object... params) {
  227 + String sql = SqlHelper.generateSelectSql(entityClass, condition, sort);
  228 + sql = sql.replace("*", columnName);
  229 + return DatabaseHelper.queryColumnList(sql, params);
  230 + }
  231 +
  232 + /**
  233 + * 插入一条数据
  234 + */
  235 + public static boolean insert(Class<?> entityClass, Map<String, Object> fieldMap) {
  236 + if (MapUtil.isEmpty(fieldMap)) {
  237 + return true;
  238 + }
  239 + String sql = SqlHelper.generateInsertSql(entityClass, fieldMap.keySet());
  240 + int rows = DatabaseHelper.update(sql, fieldMap.values().toArray());
  241 + return rows > 0;
  242 + }
  243 +
  244 + /**
  245 + * 插入一条数据
  246 + */
  247 + public static Serializable insertForKeys(Class<?> entityClass, Map<String, Object> fieldMap) {
  248 + if (MapUtil.isEmpty(fieldMap)) {
  249 + return -1;
  250 + }
  251 + String sql = SqlHelper.generateInsertSql(entityClass, fieldMap.keySet());
  252 + return DatabaseHelper.insertReturnPK(sql, fieldMap.values().toArray());
  253 + }
  254 +
  255 + /**
  256 + * 插入一个实体
  257 + */
  258 + public static boolean insert(Object entity) {
  259 + if (entity == null) {
  260 + throw new IllegalArgumentException();
  261 + }
  262 + Class<?> entityClass = entity.getClass();
  263 + Map<String, Object> fieldMap = ObjectUtil.getFieldMap(entity);
  264 + return insert(entityClass, fieldMap);
  265 + }
  266 +
  267 + public static Serializable insertForKeys(Object entity) {
  268 + if (entity == null) {
  269 + throw new IllegalArgumentException();
  270 + }
  271 + Class<?> entityClass = entity.getClass();
  272 + Map<String, Object> fieldMap = ObjectUtil.getFieldMap(entity);
  273 + return insertForKeys(entityClass, fieldMap);
  274 + }
  275 +
  276 + /**
  277 + * 更新相关数据
  278 + */
  279 + public static boolean update(Class<?> entityClass, Map<String, Object> fieldMap, String condition, Object... params) {
  280 + if (MapUtil.isEmpty(fieldMap)) {
  281 + return true;
  282 + }
  283 + String sql = SqlHelper.generateUpdateSql(entityClass, fieldMap, condition);
  284 + int rows = DatabaseHelper.update(sql, ArrayUtil.concat(fieldMap.values().toArray(), params));
  285 + return rows > 0;
  286 + }
  287 +
  288 + /**
  289 + * 更新一个实体
  290 + */
  291 + public static boolean update(Object entity) {
  292 + return update(entity, FrameworkConstant.PK_NAME);
  293 + }
  294 +
  295 + /**
  296 + * 更新一个实体(带有主键名)
  297 + */
  298 + public static boolean update(Object entityObject, String pkName) {
  299 + if (entityObject == null) {
  300 + throw new IllegalArgumentException();
  301 + }
  302 + Class<?> entityClass = entityObject.getClass();
  303 + Map<String, Object> fieldMap = ObjectUtil.getFieldMap(entityObject);
  304 + String condition = pkName + " = ?";
  305 + Object[] params = { ObjectUtil.getFieldValue(entityObject, pkName) };
  306 + return update(entityClass, fieldMap, condition, params);
  307 + }
  308 +
  309 + /**
  310 + * 删除相关数据
  311 + */
  312 + public static boolean delete(Class<?> entityClass, String condition, Object... params) {
  313 + String sql = SqlHelper.generateDeleteSql(entityClass, condition);
  314 + int rows = DatabaseHelper.update(sql, params);
  315 + return rows > 0;
  316 + }
  317 +
  318 + /**
  319 + * 删除一个实体
  320 + */
  321 + public static boolean delete(Object entityObject) {
  322 + return delete(entityObject, FrameworkConstant.PK_NAME);
  323 + }
  324 +
  325 + /**
  326 + * 删除一个实体(可指定主键名)
  327 + */
  328 + public static boolean delete(Object entityObject, String pkName) {
  329 + if (entityObject == null) {
  330 + throw new IllegalArgumentException();
  331 + }
  332 + Class<?> entityClass = entityObject.getClass();
  333 + String condition = pkName + " = ?";
  334 + Object[] params = { ObjectUtil.getFieldValue(entityObject, pkName) };
  335 + return delete(entityClass, condition, params);
  336 + }
  337 +}
src/main/java/org/smart4j/framework/orm/EntityHelper.java 0 → 100644
  1 +++ a/src/main/java/org/smart4j/framework/orm/EntityHelper.java
  1 +package org.smart4j.framework.orm;
  2 +
  3 +import java.lang.reflect.Field;
  4 +import java.util.HashMap;
  5 +import java.util.List;
  6 +import java.util.Map;
  7 +
  8 +import org.smart4j.framework.core.ClassHelper;
  9 +import org.smart4j.framework.orm.annotation.Column;
  10 +import org.smart4j.framework.orm.annotation.Entity;
  11 +import org.smart4j.framework.orm.annotation.Table;
  12 +import org.smart4j.framework.util.ArrayUtil;
  13 +import org.smart4j.framework.util.MapUtil;
  14 +import org.smart4j.framework.util.StringUtil;
  15 +
  16 +/**
  17 + * 负责处理数据库表明和实体类文件的对应</br>
  18 + * 同时也完成数据库字段和类属性的对应map集合中存放map(数据库字段--属性)
  19 + */
  20 +public class EntityHelper {
  21 +
  22 + /**
  23 + * 实体类 => 表名
  24 + */
  25 + private static final Map<Class<?>, String> entityClassTableNameMap = new HashMap<Class<?>, String>();
  26 +
  27 + /**
  28 + * 实体类 => (字段名 => 列名)
  29 + */
  30 + private static final Map<Class<?>, Map<String, String>> entityClassFieldMapMap = new HashMap<Class<?>, Map<String, String>>();
  31 +
  32 + static {
  33 + // 获取并遍历所有实体类
  34 + List<Class<?>> entityClassList = ClassHelper.getClassListByAnnotation(Entity.class);
  35 + for (Class<?> entityClass : entityClassList) {
  36 + initEntityNameMap(entityClass);
  37 + initEntityFieldMapMap(entityClass);
  38 + }
  39 + }
  40 +
  41 + private static void initEntityNameMap(Class<?> entityClass) {
  42 + // 判断该实体类上是否存在 Table 注解
  43 + String tableName;
  44 + if (entityClass.isAnnotationPresent(Table.class)) {
  45 + // 若已存在,则使用该注解中定义的表名
  46 + tableName = entityClass.getAnnotation(Table.class).value();
  47 + } else {
  48 + // 若不存在,则将实体类名转换为下划线风格的表名
  49 + tableName = StringUtil.camelhumpToUnderline(entityClass.getSimpleName());
  50 + }
  51 + entityClassTableNameMap.put(entityClass, tableName);
  52 + }
  53 +
  54 + private static void initEntityFieldMapMap(Class<?> entityClass) {
  55 + // 获取并遍历该实体类中所有的字段(不包括父类中的方法)
  56 + Field[] fields = entityClass.getDeclaredFields();
  57 + if (ArrayUtil.isNotEmpty(fields)) {
  58 + // 创建一个 fieldMap(用于存放列名与字段名的映射关系)
  59 + Map<String, String> fieldMap = new HashMap<String, String>();
  60 + for (Field field : fields) {
  61 + String fieldName = field.getName();
  62 + String columnName;
  63 + // 判断该字段上是否存在 Column 注解
  64 + if (field.isAnnotationPresent(Column.class)) {
  65 + // 若已存在,则使用该注解中定义的列名
  66 + columnName = field.getAnnotation(Column.class).value();
  67 + } else {
  68 + // 若不存在,则将字段名转换为下划线风格的列名
  69 + columnName = StringUtil.camelhumpToUnderline(fieldName);
  70 + }
  71 + fieldMap.put(fieldName, columnName);
  72 + }
  73 + entityClassFieldMapMap.put(entityClass, fieldMap);
  74 + }
  75 + }
  76 +
  77 + public static String getTableName(Class<?> entityClass) {
  78 + return entityClassTableNameMap.get(entityClass);
  79 + }
  80 +
  81 + public static Map<String, String> getFieldMap(Class<?> entityClass) {
  82 + return entityClassFieldMapMap.get(entityClass);
  83 + }
  84 +
  85 + public static Map<String, String> getColumnMap(Class<?> entityClass) {
  86 + return MapUtil.invert(getFieldMap(entityClass));
  87 + }
  88 +
  89 + public static String getColumnName(Class<?> entityClass, String fieldName) {
  90 + String columnName = getFieldMap(entityClass).get(fieldName);
  91 + return StringUtil.isNotEmpty(columnName) ? columnName : fieldName;
  92 + }
  93 +}
src/main/java/org/smart4j/framework/orm/annotation/Column.java 0 → 100644
  1 +++ a/src/main/java/org/smart4j/framework/orm/annotation/Column.java
  1 +package org.smart4j.framework.orm.annotation;
  2 +
  3 +import java.lang.annotation.ElementType;
  4 +import java.lang.annotation.Retention;
  5 +import java.lang.annotation.RetentionPolicy;
  6 +import java.lang.annotation.Target;
  7 +
  8 +/**
  9 + * 定义列名
  10 + *
  11 + * @author huangyong
  12 + * @since 1.0
  13 + */
  14 +@Target(ElementType.FIELD)
  15 +@Retention(RetentionPolicy.RUNTIME)
  16 +public @interface Column {
  17 +
  18 + String value();
  19 +}
src/main/java/org/smart4j/framework/orm/annotation/Entity.java 0 → 100644
  1 +++ a/src/main/java/org/smart4j/framework/orm/annotation/Entity.java
  1 +package org.smart4j.framework.orm.annotation;
  2 +
  3 +import java.lang.annotation.ElementType;
  4 +import java.lang.annotation.Retention;
  5 +import java.lang.annotation.RetentionPolicy;
  6 +import java.lang.annotation.Target;
  7 +
  8 +/**
  9 + * 定义 Entity 类
  10 + *
  11 + * @author huangyong
  12 + * @since 2.3
  13 + */
  14 +@Target(ElementType.TYPE)
  15 +@Retention(RetentionPolicy.RUNTIME)
  16 +public @interface Entity {
  17 +}
src/main/java/org/smart4j/framework/orm/annotation/Table.java 0 → 100644
  1 +++ a/src/main/java/org/smart4j/framework/orm/annotation/Table.java
  1 +package org.smart4j.framework.orm.annotation;
  2 +
  3 +import java.lang.annotation.ElementType;
  4 +import java.lang.annotation.Retention;
  5 +import java.lang.annotation.RetentionPolicy;
  6 +import java.lang.annotation.Target;
  7 +
  8 +/**
  9 + * 定义表名
  10 + *
  11 + * @author huangyong
  12 + * @since 1.0
  13 + */
  14 +@Target(ElementType.TYPE)
  15 +@Retention(RetentionPolicy.RUNTIME)
  16 +public @interface Table {
  17 +
  18 + String value();
  19 +}
src/main/java/org/smart4j/framework/orm/bean/Condition.java 0 → 100644
  1 +++ a/src/main/java/org/smart4j/framework/orm/bean/Condition.java
  1 +/**
  2 + * Project Name:smart-framework
  3 + * File Name:Condition.java
  4 + * Package Name:org.smart4j.framework.orm.bean
  5 + * Date:2016年3月8日下午9:51:05
  6 + * Copyright (c) 2016, cnlive.com All Rights Reserved.
  7 + *
  8 + */
  9 +
  10 +package org.smart4j.framework.orm.bean;
  11 +
  12 +/**
  13 + * TODO: 这里用一句话描述当前类的作用 Date: 2016年3月8日 下午9:51:05 <br/>
  14 + *
  15 + * @author liujicheng
  16 + * @version V1.0
  17 + * @since JDK 1.6
  18 + */
  19 +public class Condition {
  20 + //name=?
  21 + private String condition;
  22 + //and
  23 + private String operator;
  24 + //liujicheng
  25 + private String value;
  26 +
  27 + public Condition(String condition, String value, String operator) {
  28 + this.condition = condition;
  29 + this.value = value;
  30 + this.operator = operator;
  31 +
  32 + }
  33 +
  34 + public String getCondition() {
  35 + return condition;
  36 + }
  37 +
  38 + public void setCondition(String condition) {
  39 + this.condition = condition;
  40 + }
  41 +
  42 + public String getOperator() {
  43 + return operator;
  44 + }
  45 +
  46 + public void setOperator(String operator) {
  47 + this.operator = operator;
  48 + }
  49 +
  50 + public String getValue() {
  51 + return value;
  52 + }
  53 +
  54 + public void setValue(String value) {
  55 + this.value = value;
  56 + }
  57 +
  58 +}
src/main/java/org/smart4j/framework/plugin/Plugin.java 0 → 100644
  1 +++ a/src/main/java/org/smart4j/framework/plugin/Plugin.java
  1 +package org.smart4j.framework.plugin;
  2 +
  3 +/**
  4 + * 插件接口
  5 + *
  6 + * @author huangyong
  7 + * @since 2.0
  8 + */
  9 +public interface Plugin {
  10 +
  11 + /**
  12 + * 初始化插件
  13 + */
  14 + void init();
  15 +
  16 + /**
  17 + * 销毁插件
  18 + */
  19 + void destroy();
  20 +}
src/main/java/org/smart4j/framework/plugin/PluginHelper.java 0 → 100644
  1 +++ a/src/main/java/org/smart4j/framework/plugin/PluginHelper.java
  1 +package org.smart4j.framework.plugin;
  2 +
  3 +import java.util.ArrayList;
  4 +import java.util.List;
  5 +import org.smart4j.framework.FrameworkConstant;
  6 +import org.smart4j.framework.InstanceFactory;
  7 +import org.smart4j.framework.core.ClassScanner;
  8 +import org.smart4j.framework.core.fault.InitializationError;
  9 +
  10 +/**
  11 + * 初始化插件
  12 + *
  13 + * @author huangyong
  14 + * @since 2.0
  15 + */
  16 +public class PluginHelper {
  17 +
  18 + /**
  19 + * 创建一个插件列表(用于存放插件实例)
  20 + */
  21 + private static final List<Plugin> pluginList = new ArrayList<Plugin>();
  22 +
  23 + /**
  24 + * 获取 ClassScanner
  25 + */
  26 + private static final ClassScanner classScanner = InstanceFactory.getClassScanner();
  27 +
  28 + static {
  29 + try {
  30 + // 获取并遍历所有的插件类(实现了 Plugin 接口的类)
  31 + List<Class<?>> pluginClassList = classScanner.getClassListBySuper(FrameworkConstant.PLUGIN_PACKAGE, Plugin.class);
  32 + for (Class<?> pluginClass : pluginClassList) {
  33 + // 创建插件实例
  34 + Plugin plugin = (Plugin) pluginClass.newInstance();
  35 + // 调用初始化方法
  36 + plugin.init();
  37 + // 将插件实例添加到插件列表中
  38 + pluginList.add(plugin);
  39 + }
  40 + } catch (Exception e) {
  41 + throw new InitializationError("初始化 PluginHelper 出错!", e);
  42 + }
  43 + }
  44 +
  45 + /**
  46 + * 获取所有插件
  47 + */
  48 + public static List<Plugin> getPluginList() {
  49 + return pluginList;
  50 + }
  51 +}
src/main/java/org/smart4j/framework/plugin/PluginProxy.java 0 → 100644
  1 +++ a/src/main/java/org/smart4j/framework/plugin/PluginProxy.java
  1 +package org.smart4j.framework.plugin;
  2 +
  3 +import java.util.List;
  4 +import org.smart4j.framework.aop.proxy.Proxy;
  5 +
  6 +/**
  7 + * 插件代理
  8 + *
  9 + * @author huangyong
  10 + * @since 2.0
  11 + */
  12 +public abstract class PluginProxy implements Proxy {
  13 +
  14 + public abstract List<Class<?>> getTargetClassList();
  15 +}
src/main/java/org/smart4j/framework/plugin/WebPlugin.java 0 → 100644
  1 +++ a/src/main/java/org/smart4j/framework/plugin/WebPlugin.java
  1 +package org.smart4j.framework.plugin;
  2 +
  3 +import javax.servlet.ServletContext;
  4 +
  5 +/**
  6 + * 基于 Web 的插件抽象实现,拥有 Plugin 接口的所有功能
  7 + * <br/>
  8 + * 可在子类中注册 Servlet、Filter、Listener 等
  9 + *
  10 + * @author huangyong
  11 + * @since 2.3
  12 + */
  13 +public abstract class WebPlugin implements Plugin {
  14 +
  15 + @Override
  16 + public void init() {
  17 + }
  18 +
  19 + @Override
  20 + public void destroy() {
  21 + }
  22 +
  23 + public abstract void register(ServletContext servletContext);
  24 +}
src/main/java/org/smart4j/framework/tx/TransactionProxy.java 0 → 100644
  1 +++ a/src/main/java/org/smart4j/framework/tx/TransactionProxy.java
  1 +package org.smart4j.framework.tx;
  2 +
  3 +import java.lang.reflect.Method;
  4 +import org.slf4j.Logger;
  5 +import org.slf4j.LoggerFactory;
  6 +import org.smart4j.framework.aop.proxy.Proxy;
  7 +import org.smart4j.framework.aop.proxy.ProxyChain;
  8 +import org.smart4j.framework.dao.DatabaseHelper;
  9 +import org.smart4j.framework.tx.annotation.Transaction;
  10 +
  11 +/**
  12 + * 事务代理
  13 + *
  14 + * @author huangyong
  15 + * @since 2.0
  16 + */
  17 +public class TransactionProxy implements Proxy {
  18 +
  19 + private static final Logger logger = LoggerFactory.getLogger(TransactionProxy.class);
  20 +
  21 + /**
  22 + * 定义一个线程局部变量,用于保存当前线程中是否进行了事务处理,默认为 false(未处理)
  23 + */
  24 + private static final ThreadLocal<Boolean> flagContainer = new ThreadLocal<Boolean>() {
  25 + @Override
  26 + protected Boolean initialValue() {
  27 + return false;
  28 + }
  29 + };
  30 +
  31 + @Override
  32 + public Object doProxy(ProxyChain proxyChain) throws Throwable {
  33 + Object result;
  34 + // 判断当前线程是否进行了事务处理
  35 + boolean flag = flagContainer.get();
  36 + // 获取目标方法
  37 + Method method = proxyChain.getTargetMethod();
  38 + // 若当前线程未进行事务处理,且在目标方法上定义了 Transaction 注解,则说明该方法需要进行事务处理
  39 + if (!flag && method.isAnnotationPresent(Transaction.class)) {
  40 + // 设置当前线程已进行事务处理
  41 + flagContainer.set(true);
  42 + try {
  43 + // 开启事务
  44 + DatabaseHelper.beginTransaction();
  45 + logger.debug("[Smart] begin transaction");
  46 + // 执行目标方法
  47 + result = proxyChain.doProxyChain();
  48 + // 提交事务
  49 + DatabaseHelper.commitTransaction();
  50 + logger.debug("[Smart] commit transaction");
  51 + } catch (Exception e) {
  52 + // 回滚事务
  53 + DatabaseHelper.rollbackTransaction();
  54 + logger.debug("[Smart] rollback transaction");
  55 + throw e;
  56 + } finally {
  57 + // 移除线程局部变量
  58 + flagContainer.remove();
  59 + }
  60 + } else {
  61 + // 执行目标方法
  62 + result = proxyChain.doProxyChain();
  63 + }
  64 + return result;
  65 + }
  66 +}
src/main/java/org/smart4j/framework/tx/annotation/Service.java 0 → 100644
  1 +++ a/src/main/java/org/smart4j/framework/tx/annotation/Service.java
  1 +package org.smart4j.framework.tx.annotation;
  2 +
  3 +import java.lang.annotation.ElementType;
  4 +import java.lang.annotation.Retention;
  5 +import java.lang.annotation.RetentionPolicy;
  6 +import java.lang.annotation.Target;
  7 +
  8 +/**
  9 + * 定义 Service 类
  10 + *
  11 + * @author huangyong
  12 + * @since 1.0
  13 + */
  14 +@Target(ElementType.TYPE)
  15 +@Retention(RetentionPolicy.RUNTIME)
  16 +public @interface Service {
  17 +}
src/main/java/org/smart4j/framework/tx/annotation/Transaction.java 0 → 100644
  1 +++ a/src/main/java/org/smart4j/framework/tx/annotation/Transaction.java
  1 +package org.smart4j.framework.tx.annotation;
  2 +
  3 +import java.lang.annotation.ElementType;
  4 +import java.lang.annotation.Retention;
  5 +import java.lang.annotation.RetentionPolicy;
  6 +import java.lang.annotation.Target;
  7 +
  8 +/**
  9 + * 定义需要事务控制的方法
  10 + *
  11 + * @author huangyong
  12 + * @since 1.0
  13 + */
  14 +@Target(ElementType.METHOD)
  15 +@Retention(RetentionPolicy.RUNTIME)
  16 +public @interface Transaction {
  17 +}
src/main/java/org/smart4j/framework/util/ArrayUtil.java 0 → 100644
  1 +++ a/src/main/java/org/smart4j/framework/util/ArrayUtil.java
  1 +package org.smart4j.framework.util;
  2 +
  3 +import org.apache.commons.lang.ArrayUtils;
  4 +
  5 +/**
  6 + * 数组操作工具类
  7 + *
  8 + * @author huangyong
  9 + * @since 1.0
  10 + */
  11 +public class ArrayUtil {
  12 +
  13 + /**
  14 + * 判断数组是否非空
  15 + */
  16 + public static boolean isNotEmpty(Object[] array) {
  17 + return !ArrayUtils.isEmpty(array);
  18 + }
  19 +
  20 + /**
  21 + * 判断数组是否为空
  22 + */
  23 + public static boolean isEmpty(Object[] array) {
  24 + return ArrayUtils.isEmpty(array);
  25 + }
  26 +
  27 + /**
  28 + * 连接数组
  29 + */
  30 + public static Object[] concat(Object[] array1, Object[] array2) {
  31 + return ArrayUtils.addAll(array1, array2);
  32 + }
  33 +
  34 + /**
  35 + * 判断对象是否在数组中
  36 + */
  37 + public static <T> boolean contains(T[] array, T obj) {
  38 + return ArrayUtils.contains(array, obj);
  39 + }
  40 +}
src/main/java/org/smart4j/framework/util/CastUtil.java 0 → 100644
  1 +++ a/src/main/java/org/smart4j/framework/util/CastUtil.java
  1 +package org.smart4j.framework.util;
  2 +
  3 +/**
  4 + * 转型操作工具类
  5 + *
  6 + * @author huangyong
  7 + * @since 1.0
  8 + */
  9 +public class CastUtil {
  10 +
  11 + /**
  12 + * 转为 String 型
  13 + */
  14 + public static String castString(Object obj) {
  15 + return CastUtil.castString(obj, "");
  16 + }
  17 +
  18 + /**
  19 + * 转为 String 型(提供默认值)
  20 + */
  21 + public static String castString(Object obj, String defaultValue) {
  22 + return obj != null ? String.valueOf(obj) : defaultValue;
  23 + }
  24 +
  25 + /**
  26 + * 转为 double 型
  27 + */
  28 + public static double castDouble(Object obj) {
  29 + return CastUtil.castDouble(obj, 0);
  30 + }
  31 +
  32 + /**
  33 + * 转为 double 型(提供默认值)
  34 + */
  35 + public static double castDouble(Object obj, double defaultValue) {
  36 + double doubleValue = defaultValue;
  37 + if (obj != null) {
  38 + String strValue = castString(obj);
  39 + if (StringUtil.isNotEmpty(strValue)) {
  40 + try {
  41 + doubleValue = Double.parseDouble(strValue);
  42 + } catch (NumberFormatException e) {
  43 + doubleValue = defaultValue;
  44 + }
  45 + }
  46 + }
  47 + return doubleValue;
  48 + }
  49 +
  50 + /**
  51 + * 转为 long 型
  52 + */
  53 + public static long castLong(Object obj) {
  54 + return CastUtil.castLong(obj, 0);
  55 + }
  56 +
  57 + /**
  58 + * 转为 long 型(提供默认值)
  59 + */
  60 + public static long castLong(Object obj, long defaultValue) {
  61 + long longValue = defaultValue;
  62 + if (obj != null) {
  63 + String strValue = castString(obj);
  64 + if (StringUtil.isNotEmpty(strValue)) {
  65 + try {
  66 + longValue = Long.parseLong(strValue);
  67 + } catch (NumberFormatException e) {
  68 + longValue = defaultValue;
  69 + }
  70 + }
  71 + }
  72 + return longValue;
  73 + }
  74 +
  75 + /**
  76 + * 转为 int 型
  77 + */
  78 + public static int castInt(Object obj) {
  79 + return CastUtil.castInt(obj, 0);
  80 + }
  81 +
  82 + /**
  83 + * 转为 int 型(提供默认值)
  84 + */
  85 + public static int castInt(Object obj, int defaultValue) {
  86 + int intValue = defaultValue;
  87 + if (obj != null) {
  88 + String strValue = castString(obj);
  89 + if (StringUtil.isNotEmpty(strValue)) {
  90 + try {
  91 + intValue = Integer.parseInt(strValue);
  92 + } catch (NumberFormatException e) {
  93 + intValue = defaultValue;
  94 + }
  95 + }
  96 + }
  97 + return intValue;
  98 + }
  99 +
  100 + /**
  101 + * 转为 boolean 型
  102 + */
  103 + public static boolean castBoolean(Object obj) {
  104 + return CastUtil.castBoolean(obj, false);
  105 + }
  106 +
  107 + /**
  108 + * 转为 boolean 型(提供默认值)
  109 + */
  110 + public static boolean castBoolean(Object obj, boolean defaultValue) {
  111 + boolean booleanValue = defaultValue;
  112 + if (obj != null) {
  113 + booleanValue = Boolean.parseBoolean(castString(obj));
  114 + }
  115 + return booleanValue;
  116 + }
  117 +
  118 + /**
  119 + * 转为 String[] 型
  120 + */
  121 + public static String[] castStringArray(Object[] objArray) {
  122 + if (objArray == null) {
  123 + objArray = new Object[0];
  124 + }
  125 + String[] strArray = new String[objArray.length];
  126 + if (ArrayUtil.isNotEmpty(objArray)) {
  127 + for (int i = 0; i < objArray.length; i++) {
  128 + strArray[i] = castString(objArray[i]);
  129 + }
  130 + }
  131 + return strArray;
  132 + }
  133 +
  134 + /**
  135 + * 转为 double[] 型
  136 + */
  137 + public static double[] castDoubleArray(Object[] objArray) {
  138 + if (objArray == null) {
  139 + objArray = new Object[0];
  140 + }
  141 + double[] doubleArray = new double[objArray.length];
  142 + if (!ArrayUtil.isEmpty(objArray)) {
  143 + for (int i = 0; i < objArray.length; i++) {
  144 + doubleArray[i] = castDouble(objArray[i]);
  145 + }
  146 + }
  147 + return doubleArray;
  148 + }
  149 +
  150 + /**
  151 + * 转为 long[] 型
  152 + */
  153 + public static long[] castLongArray(Object[] objArray) {
  154 + if (objArray == null) {
  155 + objArray = new Object[0];
  156 + }
  157 + long[] longArray = new long[objArray.length];
  158 + if (!ArrayUtil.isEmpty(objArray)) {
  159 + for (int i = 0; i < objArray.length; i++) {
  160 + longArray[i] = castLong(objArray[i]);
  161 + }
  162 + }
  163 + return longArray;
  164 + }
  165 +
  166 + /**
  167 + * 转为 int[] 型
  168 + */
  169 + public static int[] castIntArray(Object[] objArray) {
  170 + if (objArray == null) {
  171 + objArray = new Object[0];
  172 + }
  173 + int[] intArray = new int[objArray.length];
  174 + if (!ArrayUtil.isEmpty(objArray)) {
  175 + for (int i = 0; i < objArray.length; i++) {
  176 + intArray[i] = castInt(objArray[i]);
  177 + }
  178 + }
  179 + return intArray;
  180 + }
  181 +
  182 + /**
  183 + * 转为 boolean[] 型
  184 + */
  185 + public static boolean[] castBooleanArray(Object[] objArray) {
  186 + if (objArray == null) {
  187 + objArray = new Object[0];
  188 + }
  189 + boolean[] booleanArray = new boolean[objArray.length];
  190 + if (!ArrayUtil.isEmpty(objArray)) {
  191 + for (int i = 0; i < objArray.length; i++) {
  192 + booleanArray[i] = castBoolean(objArray[i]);
  193 + }
  194 + }
  195 + return booleanArray;
  196 + }
  197 +}
src/main/java/org/smart4j/framework/util/ClassUtil.java 0 → 100644
  1 +++ a/src/main/java/org/smart4j/framework/util/ClassUtil.java
  1 +package org.smart4j.framework.util;
  2 +
  3 +import java.net.URL;
  4 +import org.slf4j.Logger;
  5 +import org.slf4j.LoggerFactory;
  6 +
  7 +/**
  8 + * 类操作工具类
  9 + *
  10 + * @author huangyong
  11 + * @since 1.0
  12 + */
  13 +public class ClassUtil {
  14 +
  15 + private static final Logger logger = LoggerFactory.getLogger(ClassUtil.class);
  16 +
  17 + /**
  18 + * 获取类加载器
  19 + */
  20 + public static ClassLoader getClassLoader() {
  21 + return Thread.currentThread().getContextClassLoader();
  22 + }
  23 +
  24 + /**
  25 + * 获取类路径
  26 + */
  27 + public static String getClassPath() {
  28 + String classpath = "";
  29 + URL resource = getClassLoader().getResource("");
  30 + if (resource != null) {
  31 + classpath = resource.getPath();
  32 + }
  33 + return classpath;
  34 + }
  35 +
  36 + /**
  37 + * 加载类(将自动初始化)
  38 + */
  39 + public static Class<?> loadClass(String className) {
  40 + return loadClass(className, true);
  41 + }
  42 +
  43 + /**
  44 + * 加载类
  45 + */
  46 + public static Class<?> loadClass(String className, boolean isInitialized) {
  47 + Class<?> cls;
  48 + try {
  49 + cls = Class.forName(className, isInitialized, getClassLoader());
  50 + } catch (ClassNotFoundException e) {
  51 + logger.error("加载类出错!", e);
  52 + throw new RuntimeException(e);
  53 + }
  54 + return cls;
  55 + }
  56 +
  57 + /**
  58 + * 是否为 int 类型(包括 Integer 类型)
  59 + */
  60 + public static boolean isInt(Class<?> type) {
  61 + return type.equals(int.class) || type.equals(Integer.class);
  62 + }
  63 +
  64 + /**
  65 + * 是否为 long 类型(包括 Long 类型)
  66 + */
  67 + public static boolean isLong(Class<?> type) {
  68 + return type.equals(long.class) || type.equals(Long.class);
  69 + }
  70 +
  71 + /**
  72 + * 是否为 double 类型(包括 Double 类型)
  73 + */
  74 + public static boolean isDouble(Class<?> type) {
  75 + return type.equals(double.class) || type.equals(Double.class);
  76 + }
  77 +
  78 + /**
  79 + * 是否为 String 类型
  80 + */
  81 + public static boolean isString(Class<?> type) {
  82 + return type.equals(String.class);
  83 + }
  84 +}
src/main/java/org/smart4j/framework/util/CodecUtil.java 0 → 100644
  1 +++ a/src/main/java/org/smart4j/framework/util/CodecUtil.java
  1 +package org.smart4j.framework.util;
  2 +
  3 +import java.io.UnsupportedEncodingException;
  4 +import java.net.URLDecoder;
  5 +import java.net.URLEncoder;
  6 +import java.util.UUID;
  7 +import org.apache.commons.codec.binary.Base64;
  8 +import org.apache.commons.codec.digest.DigestUtils;
  9 +import org.apache.commons.lang.RandomStringUtils;
  10 +import org.slf4j.Logger;
  11 +import org.slf4j.LoggerFactory;
  12 +import org.smart4j.framework.FrameworkConstant;
  13 +
  14 +/**
  15 + * 编码与解码操作工具类
  16 + *
  17 + * @author huangyong
  18 + * @since 1.0
  19 + */
  20 +public class CodecUtil {
  21 +
  22 + private static final Logger logger = LoggerFactory.getLogger(CodecUtil.class);
  23 +
  24 + /**
  25 + * 将 URL 编码
  26 + */
  27 + public static String encodeURL(String str) {
  28 + String target;
  29 + try {
  30 + target = URLEncoder.encode(str, FrameworkConstant.UTF_8);
  31 + } catch (Exception e) {
  32 + logger.error("编码出错!", e);
  33 + throw new RuntimeException(e);
  34 + }
  35 + return target;
  36 + }
  37 +
  38 + /**
  39 + * 将 URL 解码
  40 + */
  41 + public static String decodeURL(String str) {
  42 + String target;
  43 + try {
  44 + target = URLDecoder.decode(str, FrameworkConstant.UTF_8);
  45 + } catch (Exception e) {
  46 + logger.error("解码出错!", e);
  47 + throw new RuntimeException(e);
  48 + }
  49 + return target;
  50 + }
  51 +
  52 + /**
  53 + * 将字符串 Base64 编码
  54 + */
  55 + public static String encodeBASE64(String str) {
  56 + String target;
  57 + try {
  58 + target = Base64.encodeBase64URLSafeString(str.getBytes(FrameworkConstant.UTF_8));
  59 + } catch (UnsupportedEncodingException e) {
  60 + logger.error("编码出错!", e);
  61 + throw new RuntimeException(e);
  62 + }
  63 + return target;
  64 + }
  65 +
  66 + /**
  67 + * 将字符串 Base64 解码
  68 + */
  69 + public static String decodeBASE64(String str) {
  70 + String target;
  71 + try {
  72 + target = new String(Base64.decodeBase64(str), FrameworkConstant.UTF_8);
  73 + } catch (UnsupportedEncodingException e) {
  74 + logger.error("解码出错!", e);
  75 + throw new RuntimeException(e);
  76 + }
  77 + return target;
  78 + }
  79 +
  80 + /**
  81 + * 将字符串 MD5 加密
  82 + */
  83 + public static String encryptMD5(String str) {
  84 + return DigestUtils.md5Hex(str);
  85 + }
  86 +
  87 + /**
  88 + * 将字符串 SHA 加密
  89 + */
  90 + public static String encryptSHA(String str) {
  91 + return DigestUtils.sha1Hex(str);
  92 + }
  93 +
  94 + /**
  95 + * 创建随机数
  96 + */
  97 + public static String createRandom(int count) {
  98 + return RandomStringUtils.randomNumeric(count);
  99 + }
  100 +
  101 + /**
  102 + * 获取 UUID(32位)
  103 + */
  104 + public static String createUUID() {
  105 + return UUID.randomUUID().toString().replaceAll("-", "");
  106 + }
  107 +}
src/main/java/org/smart4j/framework/util/CollectionUtil.java 0 → 100644
  1 +++ a/src/main/java/org/smart4j/framework/util/CollectionUtil.java
  1 +package org.smart4j.framework.util;
  2 +
  3 +import java.util.Collection;
  4 +import org.apache.commons.collections.CollectionUtils;
  5 +
  6 +/**
  7 + * 集合操作工具类
  8 + *
  9 + * @author huangyong
  10 + * @since 1.0
  11 + */
  12 +public class CollectionUtil {
  13 +
  14 + /**
  15 + * 判断集合是否非空
  16 + */
  17 + public static boolean isNotEmpty(Collection<?> collection) {
  18 + return CollectionUtils.isNotEmpty(collection);
  19 + }
  20 +
  21 + /**
  22 + * 判断集合是否为空
  23 + */
  24 + public static boolean isEmpty(Collection<?> collection) {
  25 + return CollectionUtils.isEmpty(collection);
  26 + }
  27 +}
src/main/java/org/smart4j/framework/util/DateUtil.java 0 → 100644
  1 +++ a/src/main/java/org/smart4j/framework/util/DateUtil.java
  1 +package org.smart4j.framework.util;
  2 +
  3 +import java.text.ParseException;
  4 +import java.text.SimpleDateFormat;
  5 +import java.util.Date;
  6 +import org.slf4j.Logger;
  7 +import org.slf4j.LoggerFactory;
  8 +
  9 +/**
  10 + * 日期操作工具类
  11 + *
  12 + * @author huangyong
  13 + * @since 1.0
  14 + */
  15 +public class DateUtil {
  16 +
  17 + private static final Logger logger = LoggerFactory.getLogger(DateUtil.class);
  18 +
  19 + private static final SimpleDateFormat datetimeFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
  20 + private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
  21 + private static final SimpleDateFormat timeFormat = new SimpleDateFormat("HH:mm:ss");
  22 +
  23 + /**
  24 + * 格式化日期与时间
  25 + */
  26 + public static String formatDatetime(long timestamp) {
  27 + return datetimeFormat.format(new Date(timestamp));
  28 + }
  29 +
  30 + /**
  31 + * 格式化日期
  32 + */
  33 + public static String formatDate(long timestamp) {
  34 + return dateFormat.format(new Date(timestamp));
  35 + }
  36 +
  37 + /**
  38 + * 格式化时间
  39 + */
  40 + public static String formatTime(long timestamp) {
  41 + return timeFormat.format(new Date(timestamp));
  42 + }
  43 +
  44 + /**
  45 + * 获取当前日期与时间
  46 + */
  47 + public static String getCurrentDatetime() {
  48 + return datetimeFormat.format(new Date());
  49 + }
  50 +
  51 + /**
  52 + * 获取当前日期
  53 + */
  54 + public static String getCurrentDate() {
  55 + return dateFormat.format(new Date());
  56 + }
  57 +
  58 + /**
  59 + * 获取当前时间
  60 + */
  61 + public static String getCurrentTime() {
  62 + return timeFormat.format(new Date());
  63 + }
  64 +
  65 + /**
  66 + * 解析日期与时间
  67 + */
  68 + public static Date parseDatetime(String str) {
  69 + Date date = null;
  70 + try {
  71 + date = datetimeFormat.parse(str);
  72 + } catch (ParseException e) {
  73 + logger.error("解析日期字符串出错!格式:yyyy-MM-dd HH:mm:ss", e);
  74 + }
  75 + return date;
  76 + }
  77 +
  78 + /**
  79 + * 解析日期
  80 + */
  81 + public static Date parseDate(String str) {
  82 + Date date = null;
  83 + try {
  84 + date = dateFormat.parse(str);
  85 + } catch (ParseException e) {
  86 + logger.error("解析日期字符串出错!格式:yyyy-MM-dd", e);
  87 + }
  88 + return date;
  89 + }
  90 +
  91 + /**
  92 + * 解析时间
  93 + */
  94 + public static Date parseTime(String str) {
  95 + Date date = null;
  96 + try {
  97 + date = timeFormat.parse(str);
  98 + } catch (ParseException e) {
  99 + logger.error("解析日期字符串出错!格式:HH:mm:ss", e);
  100 + }
  101 + return date;
  102 + }
  103 +}
src/main/java/org/smart4j/framework/util/FileUtil.java 0 → 100644
  1 +++ a/src/main/java/org/smart4j/framework/util/FileUtil.java
  1 +package org.smart4j.framework.util;
  2 +
  3 +import java.io.BufferedOutputStream;
  4 +import java.io.File;
  5 +import java.io.FileOutputStream;
  6 +import java.io.OutputStream;
  7 +import java.io.OutputStreamWriter;
  8 +import java.io.Writer;
  9 +import org.apache.commons.io.FileUtils;
  10 +import org.apache.commons.io.FilenameUtils;
  11 +import org.slf4j.Logger;
  12 +import org.slf4j.LoggerFactory;
  13 +import org.smart4j.framework.FrameworkConstant;
  14 +
  15 +/**
  16 + * 文件操作工具类
  17 + *
  18 + * @author huangyong
  19 + * @since 1.0
  20 + */
  21 +public class FileUtil {
  22 +
  23 + private static final Logger logger = LoggerFactory.getLogger(FileUtil.class);
  24 +
  25 + /**
  26 + * 创建目录
  27 + */
  28 + public static File createDir(String dirPath) {
  29 + File dir;
  30 + try {
  31 + dir = new File(dirPath);
  32 + if (!dir.exists()) {
  33 + FileUtils.forceMkdir(dir);
  34 + }
  35 + } catch (Exception e) {
  36 + logger.error("创建目录出错!", e);
  37 + throw new RuntimeException(e);
  38 + }
  39 + return dir;
  40 + }
  41 +
  42 + /**
  43 + * 创建文件
  44 + */
  45 + public static File createFile(String filePath) {
  46 + File file;
  47 + try {
  48 + file = new File(filePath);
  49 + File parentDir = file.getParentFile();
  50 + if (!parentDir.exists()) {
  51 + FileUtils.forceMkdir(parentDir);
  52 + }
  53 + } catch (Exception e) {
  54 + logger.error("创建文件出错!", e);
  55 + throw new RuntimeException(e);
  56 + }
  57 + return file;
  58 + }
  59 +
  60 + /**
  61 + * 复制目录(不会复制空目录)
  62 + */
  63 + public static void copyDir(String srcPath, String destPath) {
  64 + try {
  65 + File srcDir = new File(srcPath);
  66 + File destDir = new File(destPath);
  67 + if (srcDir.exists() && srcDir.isDirectory()) {
  68 + FileUtils.copyDirectoryToDirectory(srcDir, destDir);
  69 + }
  70 + } catch (Exception e) {
  71 + logger.error("复制目录出错!", e);
  72 + throw new RuntimeException(e);
  73 + }
  74 + }
  75 +
  76 + /**
  77 + * 复制文件
  78 + */
  79 + public static void copyFile(String srcPath, String destPath) {
  80 + try {
  81 + File srcFile = new File(srcPath);
  82 + File destDir = new File(destPath);
  83 + if (srcFile.exists() && srcFile.isFile()) {
  84 + FileUtils.copyFileToDirectory(srcFile, destDir);
  85 + }
  86 + } catch (Exception e) {
  87 + logger.error("复制文件出错!", e);
  88 + throw new RuntimeException(e);
  89 + }
  90 + }
  91 +
  92 + /**
  93 + * 删除目录
  94 + */
  95 + public static void deleteDir(String dirPath) {
  96 + try {
  97 + File dir = new File(dirPath);
  98 + if (dir.exists() && dir.isDirectory()) {
  99 + FileUtils.deleteDirectory(dir);
  100 + }
  101 + } catch (Exception e) {
  102 + logger.error("删除目录出错!", e);
  103 + throw new RuntimeException(e);
  104 + }
  105 + }
  106 +
  107 + /**
  108 + * 删除文件
  109 + */
  110 + public static void deleteFile(String filePath) {
  111 + try {
  112 + File file = new File(filePath);
  113 + if (file.exists() && file.isFile()) {
  114 + FileUtils.forceDelete(file);
  115 + }
  116 + } catch (Exception e) {
  117 + logger.error("删除文件出错!", e);
  118 + throw new RuntimeException(e);
  119 + }
  120 + }
  121 +
  122 + /**
  123 + * 重命名文件
  124 + */
  125 + public static void renameFile(String srcPath, String destPath) {
  126 + File srcFile = new File(srcPath);
  127 + if (srcFile.exists()) {
  128 + File newFile = new File(destPath);
  129 + boolean result = srcFile.renameTo(newFile);
  130 + if (!result) {
  131 + throw new RuntimeException("重命名文件出错!" + newFile);
  132 + }
  133 + }
  134 + }
  135 +
  136 + /**
  137 + * 将字符串写入文件
  138 + */
  139 + public static void writeFile(String filePath, String fileContent) {
  140 + OutputStream os = null;
  141 + Writer w = null;
  142 + try {
  143 + FileUtil.createFile(filePath);
  144 + os = new BufferedOutputStream(new FileOutputStream(filePath));
  145 + w = new OutputStreamWriter(os, FrameworkConstant.UTF_8);
  146 + w.write(fileContent);
  147 + w.flush();
  148 + } catch (Exception e) {
  149 + logger.error("写入文件出错!", e);
  150 + throw new RuntimeException(e);
  151 + } finally {
  152 + try {
  153 + if (os != null) {
  154 + os.close();
  155 + }
  156 + if (w != null) {
  157 + w.close();
  158 + }
  159 + } catch (Exception e) {
  160 + logger.error("释放资源出错!", e);
  161 + }
  162 + }
  163 + }
  164 +
  165 + /**
  166 + * 获取真实文件名(去掉文件路径)
  167 + */
  168 + public static String getRealFileName(String fileName) {
  169 + return FilenameUtils.getName(fileName);
  170 + }
  171 +
  172 + /**
  173 + * 判断文件是否存在
  174 + */
  175 + public static boolean checkFileExists(String filePath) {
  176 + return new File(filePath).exists();
  177 + }
  178 +}
src/main/java/org/smart4j/framework/util/JsonUtil.java 0 → 100644
  1 +++ a/src/main/java/org/smart4j/framework/util/JsonUtil.java
  1 +package org.smart4j.framework.util;
  2 +
  3 +import org.codehaus.jackson.map.ObjectMapper;
  4 +import org.slf4j.Logger;
  5 +import org.slf4j.LoggerFactory;
  6 +
  7 +/**
  8 + * JSON 操作工具类
  9 + *
  10 + * @author huangyong
  11 + * @since 1.0
  12 + */
  13 +public class JsonUtil {
  14 +
  15 + private static final Logger logger = LoggerFactory.getLogger(JsonUtil.class);
  16 +
  17 + private static final ObjectMapper objectMapper = new ObjectMapper();
  18 +
  19 + /**
  20 + * 将 Java 对象转为 JSON 字符串
  21 + */
  22 + public static <T> String toJSON(T obj) {
  23 + String jsonStr;
  24 + try {
  25 + jsonStr = objectMapper.writeValueAsString(obj);
  26 + } catch (Exception e) {
  27 + logger.error("Java 转 JSON 出错!", e);
  28 + throw new RuntimeException(e);
  29 + }
  30 + return jsonStr;
  31 + }
  32 +
  33 + /**
  34 + * 将 JSON 字符串转为 Java 对象
  35 + */
  36 + public static <T> T fromJSON(String json, Class<T> type) {
  37 + T obj;
  38 + try {
  39 + obj = objectMapper.readValue(json, type);
  40 + } catch (Exception e) {
  41 + logger.error("JSON 转 Java 出错!", e);
  42 + throw new RuntimeException(e);
  43 + }
  44 + return obj;
  45 + }
  46 +}
src/main/java/org/smart4j/framework/util/MapUtil.java 0 → 100644
  1 +++ a/src/main/java/org/smart4j/framework/util/MapUtil.java
  1 +package org.smart4j.framework.util;
  2 +
  3 +import java.util.LinkedHashMap;
  4 +import java.util.Map;
  5 +import org.apache.commons.collections.MapUtils;
  6 +
  7 +/**
  8 + * 映射操作工具类
  9 + *
  10 + * @author huangyong
  11 + * @since 1.0
  12 + */
  13 +public class MapUtil {
  14 +
  15 + /**
  16 + * 判断 Map 是否非空
  17 + */
  18 + public static boolean isNotEmpty(Map<?, ?> map) {
  19 + return MapUtils.isNotEmpty(map);
  20 + }
  21 +
  22 + /**
  23 + * 判断 Map 是否为空
  24 + */
  25 + public static boolean isEmpty(Map<?, ?> map) {
  26 + return MapUtils.isEmpty(map);
  27 + }
  28 +
  29 + /**
  30 + * 转置 Map
  31 + */
  32 + public static <K, V> Map<V, K> invert(Map<K, V> source) {
  33 + Map<V, K> target = null;
  34 + if (isNotEmpty(source)) {
  35 + target = new LinkedHashMap<V, K>(source.size());
  36 + for (Map.Entry<K, V> entry : source.entrySet()) {
  37 + target.put(entry.getValue(), entry.getKey());
  38 + }
  39 + }
  40 + return target;
  41 + }
  42 +}
src/main/java/org/smart4j/framework/util/ObjectUtil.java 0 → 100644
  1 +++ a/src/main/java/org/smart4j/framework/util/ObjectUtil.java
  1 +package org.smart4j.framework.util;
  2 +
  3 +import java.lang.reflect.Field;
  4 +import java.lang.reflect.Modifier;
  5 +import java.util.LinkedHashMap;
  6 +import java.util.Map;
  7 +import org.apache.commons.beanutils.PropertyUtils;
  8 +import org.slf4j.Logger;
  9 +import org.slf4j.LoggerFactory;
  10 +
  11 +/**
  12 + * 对象操作工具类
  13 + *
  14 + * @author huangyong
  15 + * @since 1.0
  16 + */
  17 +public class ObjectUtil {
  18 +
  19 + private static final Logger logger = LoggerFactory.getLogger(ObjectUtil.class);
  20 +
  21 + /**
  22 + * 设置成员变量
  23 + */
  24 + public static void setField(Object obj, String fieldName, Object fieldValue) {
  25 + try {
  26 + if (PropertyUtils.isWriteable(obj, fieldName)) {
  27 + PropertyUtils.setProperty(obj, fieldName, fieldValue);
  28 + }
  29 + } catch (Exception e) {
  30 + logger.error("设置成员变量出错!", e);
  31 + throw new RuntimeException(e);
  32 + }
  33 + }
  34 +
  35 + /**
  36 + * 获取成员变量
  37 + */
  38 + public static Object getFieldValue(Object obj, String fieldName) {
  39 + Object propertyValue = null;
  40 + try {
  41 + if (PropertyUtils.isReadable(obj, fieldName)) {
  42 + propertyValue = PropertyUtils.getProperty(obj, fieldName);
  43 + }
  44 + } catch (Exception e) {
  45 + logger.error("获取成员变量出错!", e);
  46 + throw new RuntimeException(e);
  47 + }
  48 + return propertyValue;
  49 + }
  50 +
  51 + /**
  52 + * 复制所有成员变量
  53 + */
  54 + public static void copyFields(Object source, Object target) {
  55 + try {
  56 + for (Field field : source.getClass().getDeclaredFields()) {
  57 + // 若不为 static 成员变量,则进行复制操作
  58 + if (!Modifier.isStatic(field.getModifiers())) {
  59 + field.setAccessible(true); // 可操作私有成员变量
  60 + field.set(target, field.get(source));
  61 + }
  62 + }
  63 + } catch (Exception e) {
  64 + logger.error("复制成员变量出错!", e);
  65 + throw new RuntimeException(e);
  66 + }
  67 + }
  68 +
  69 + /**
  70 + * 通过反射创建实例
  71 + */
  72 + @SuppressWarnings("unchecked")
  73 + public static <T> T newInstance(String className) {
  74 + T instance;
  75 + try {
  76 + Class<?> commandClass = ClassUtil.loadClass(className);
  77 + instance = (T) commandClass.newInstance();
  78 + } catch (Exception e) {
  79 + logger.error("创建实例出错!", e);
  80 + throw new RuntimeException(e);
  81 + }
  82 + return instance;
  83 + }
  84 +
  85 + /**
  86 + * 获取对象的字段映射(字段名 => 字段值),忽略 static 字段
  87 + */
  88 + public static Map<String, Object> getFieldMap(Object obj) {
  89 + return getFieldMap(obj, true);
  90 + }
  91 +
  92 + /**
  93 + * 获取对象的字段映射(字段名 => 字段值)
  94 + */
  95 + public static Map<String, Object> getFieldMap(Object obj, boolean isStaticIgnored) {
  96 + Map<String, Object> fieldMap = new LinkedHashMap<String, Object>();
  97 + Field[] fields = obj.getClass().getDeclaredFields();
  98 + for (Field field : fields) {
  99 + if (isStaticIgnored && Modifier.isStatic(field.getModifiers())) {
  100 + continue;
  101 + }
  102 + String fieldName = field.getName();
  103 + Object fieldValue = ObjectUtil.getFieldValue(obj, fieldName);
  104 + fieldMap.put(fieldName, fieldValue);
  105 + }
  106 + return fieldMap;
  107 + }
  108 +}
src/main/java/org/smart4j/framework/util/PropsUtil.java 0 → 100644
  1 +++ a/src/main/java/org/smart4j/framework/util/PropsUtil.java
  1 +package org.smart4j.framework.util;
  2 +
  3 +import java.io.IOException;
  4 +import java.io.InputStream;
  5 +import java.util.HashMap;
  6 +import java.util.LinkedHashMap;
  7 +import java.util.Map;
  8 +import java.util.Properties;
  9 +import java.util.Set;
  10 +import org.slf4j.Logger;
  11 +import org.slf4j.LoggerFactory;
  12 +
  13 +/**
  14 + * 属性文件操作工具类
  15 + *
  16 + * @author huangyong
  17 + * @since 1.0
  18 + */
  19 +public class PropsUtil {
  20 +
  21 + private static final Logger logger = LoggerFactory.getLogger(PropsUtil.class);
  22 +
  23 + /**
  24 + * 加载属性文件
  25 + */
  26 + public static Properties loadProps(String propsPath) {
  27 + Properties props = new Properties();
  28 + InputStream is = null;
  29 + try {
  30 + if (StringUtil.isEmpty(propsPath)) {
  31 + throw new IllegalArgumentException();
  32 + }
  33 + String suffix = ".properties";
  34 + if (propsPath.lastIndexOf(suffix) == -1) {
  35 + propsPath += suffix;
  36 + }
  37 + is = ClassUtil.getClassLoader().getResourceAsStream(propsPath);
  38 + if (is != null) {
  39 + props.load(is);
  40 + }
  41 + } catch (Exception e) {
  42 + logger.error("加载属性文件出错!", e);
  43 + throw new RuntimeException(e);
  44 + } finally {
  45 + try {
  46 + if (is != null) {
  47 + is.close();
  48 + }
  49 + } catch (IOException e) {
  50 + logger.error("释放资源出错!", e);
  51 + }
  52 + }
  53 + return props;
  54 + }
  55 +
  56 + /**
  57 + * 加载属性文件,并转为 Map
  58 + */
  59 + public static Map<String, String> loadPropsToMap(String propsPath) {
  60 + Map<String, String> map = new HashMap<String, String>();
  61 + Properties props = loadProps(propsPath);
  62 + for (String key : props.stringPropertyNames()) {
  63 + map.put(key, props.getProperty(key));
  64 + }
  65 + return map;
  66 + }
  67 +
  68 + /**
  69 + * 获取字符型属性
  70 + */
  71 + public static String getString(Properties props, String key) {
  72 + String value = "";
  73 + if (props.containsKey(key)) {
  74 + value = props.getProperty(key);
  75 + }
  76 + return value;
  77 + }
  78 +
  79 + /**
  80 + * 获取字符型属性(带有默认值)
  81 + */
  82 + public static String getString(Properties props, String key, String defalutValue) {
  83 + String value = defalutValue;
  84 + if (props.containsKey(key)) {
  85 + value = props.getProperty(key);
  86 + }
  87 + return value;
  88 + }
  89 +
  90 + /**
  91 + * 获取数值型属性
  92 + */
  93 + public static int getNumber(Properties props, String key) {
  94 + int value = 0;
  95 + if (props.containsKey(key)) {
  96 + value = CastUtil.castInt(props.getProperty(key));
  97 + }
  98 + return value;
  99 + }
  100 +
  101 + // 获取数值型属性(带有默认值)
  102 + public static int getNumber(Properties props, String key, int defaultValue) {
  103 + int value = defaultValue;
  104 + if (props.containsKey(key)) {
  105 + value = CastUtil.castInt(props.getProperty(key));
  106 + }
  107 + return value;
  108 + }
  109 +
  110 + /**
  111 + * 获取布尔型属性
  112 + */
  113 + public static boolean getBoolean(Properties props, String key) {
  114 + return getBoolean(props, key, false);
  115 + }
  116 +
  117 + /**
  118 + * 获取布尔型属性(带有默认值)
  119 + */
  120 + public static boolean getBoolean(Properties props, String key, boolean defalutValue) {
  121 + boolean value = defalutValue;
  122 + if (props.containsKey(key)) {
  123 + value = CastUtil.castBoolean(props.getProperty(key));
  124 + }
  125 + return value;
  126 + }
  127 +
  128 + /**
  129 + * 获取指定前缀的相关属性
  130 + */
  131 + public static Map<String, Object> getMap(Properties props, String prefix) {
  132 + Map<String, Object> kvMap = new LinkedHashMap<String, Object>();
  133 + Set<String> keySet = props.stringPropertyNames();
  134 + if (CollectionUtil.isNotEmpty(keySet)) {
  135 + for (String key : keySet) {
  136 + if (key.startsWith(prefix)) {
  137 + String value = props.getProperty(key);
  138 + kvMap.put(key, value);
  139 + }
  140 + }
  141 + }
  142 + return kvMap;
  143 + }
  144 +}
src/main/java/org/smart4j/framework/util/StreamUtil.java 0 → 100644
  1 +++ a/src/main/java/org/smart4j/framework/util/StreamUtil.java
  1 +package org.smart4j.framework.util;
  2 +
  3 +import java.io.BufferedReader;
  4 +import java.io.InputStream;
  5 +import java.io.InputStreamReader;
  6 +import java.io.OutputStream;
  7 +import org.slf4j.Logger;
  8 +import org.slf4j.LoggerFactory;
  9 +
  10 +/**
  11 + * 流操作工具类
  12 + *
  13 + * @author huangyong
  14 + * @since 1.0
  15 + */
  16 +public class StreamUtil {
  17 +
  18 + private static final Logger logger = LoggerFactory.getLogger(StreamUtil.class);
  19 +
  20 + /**
  21 + * 将输入流复制到输出流
  22 + */
  23 + public static void copyStream(InputStream inputStream, OutputStream outputStream) {
  24 + try {
  25 + int length;
  26 + byte[] buffer = new byte[4 * 1024];
  27 + while ((length = inputStream.read(buffer, 0, buffer.length)) != -1) {
  28 + outputStream.write(buffer, 0, length);
  29 + }
  30 + outputStream.flush();
  31 + } catch (Exception e) {
  32 + logger.error("复制流出错!", e);
  33 + throw new RuntimeException(e);
  34 + } finally {
  35 + try {
  36 + inputStream.close();
  37 + outputStream.close();
  38 + } catch (Exception e) {
  39 + e.printStackTrace();
  40 + logger.error("释放资源出错!", e);
  41 + }
  42 + }
  43 + }
  44 +
  45 + /**
  46 + * 从输入流中获取字符串
  47 + */
  48 + public static String getString(InputStream is) {
  49 + StringBuilder sb = new StringBuilder();
  50 + try {
  51 + BufferedReader reader = new BufferedReader(new InputStreamReader(is));
  52 + String line;
  53 + while ((line = reader.readLine()) != null) {
  54 + sb.append(line);
  55 + }
  56 + } catch (Exception e) {
  57 + logger.error("Stream 转 String 出错!", e);
  58 + throw new RuntimeException(e);
  59 + }
  60 + return sb.toString();
  61 + }
  62 +}
src/main/java/org/smart4j/framework/util/StringUtil.java 0 → 100644
  1 +++ a/src/main/java/org/smart4j/framework/util/StringUtil.java
  1 +package org.smart4j.framework.util;
  2 +
  3 +import java.util.regex.Matcher;
  4 +import java.util.regex.Pattern;
  5 +import org.apache.commons.lang.StringUtils;
  6 +import org.apache.commons.lang.math.NumberUtils;
  7 +
  8 +/**
  9 + * 字符串操作工具类
  10 + *
  11 + * @author huangyong
  12 + * @since 1.0
  13 + */
  14 +public class StringUtil {
  15 +
  16 + /**
  17 + * 字符串分隔符
  18 + */
  19 + public static final String SEPARATOR = String.valueOf((char) 29);
  20 +
  21 + /**
  22 + * 判断字符串是否非空
  23 + */
  24 + public static boolean isNotEmpty(String str) {
  25 + return StringUtils.isNotEmpty(str);
  26 + }
  27 +
  28 + /**
  29 + * 判断字符串是否为空
  30 + */
  31 + public static boolean isEmpty(String str) {
  32 + return StringUtils.isEmpty(str);
  33 + }
  34 +
  35 + /**
  36 + * 若字符串为空,则取默认值
  37 + */
  38 + public static String defaultIfEmpty(String str, String defaultValue) {
  39 + return StringUtils.defaultIfEmpty(str, defaultValue);
  40 + }
  41 +
  42 + /**
  43 + * 替换固定格式的字符串(支持正则表达式)
  44 + */
  45 + public static String replaceAll(String str, String regex, String replacement) {
  46 + Pattern p = Pattern.compile(regex);
  47 + Matcher m = p.matcher(str);
  48 + StringBuffer sb = new StringBuffer();
  49 + while (m.find()) {
  50 + m.appendReplacement(sb, replacement);
  51 + }
  52 + m.appendTail(sb);
  53 + return sb.toString();
  54 + }
  55 +
  56 + /**
  57 + * 是否为数字(整数或小数)
  58 + */
  59 + public static boolean isNumber(String str) {
  60 + return NumberUtils.isNumber(str);
  61 + }
  62 +
  63 + /**
  64 + * 是否为十进制数(整数)
  65 + */
  66 + public static boolean isDigits(String str) {
  67 + return NumberUtils.isDigits(str);
  68 + }
  69 +
  70 + /**
  71 + * 将驼峰风格替换为下划线风格
  72 + */
  73 + public static String camelhumpToUnderline(String str) {
  74 + Matcher matcher = Pattern.compile("[A-Z]").matcher(str);
  75 + StringBuilder builder = new StringBuilder(str);
  76 + for (int i = 0; matcher.find(); i++) {
  77 + builder.replace(matcher.start() + i, matcher.end() + i, "_" + matcher.group().toLowerCase());
  78 + }
  79 + if (builder.charAt(0) == '_') {
  80 + builder.deleteCharAt(0);
  81 + }
  82 + return builder.toString();
  83 + }
  84 +
  85 + /**
  86 + * 将下划线风格替换为驼峰风格
  87 + */
  88 + public static String underlineToCamelhump(String str) {
  89 + Matcher matcher = Pattern.compile("_[a-z]").matcher(str);
  90 + StringBuilder builder = new StringBuilder(str);
  91 + for (int i = 0; matcher.find(); i++) {
  92 + builder.replace(matcher.start() - i, matcher.end() - i, matcher.group().substring(1).toUpperCase());
  93 + }
  94 + if (Character.isUpperCase(builder.charAt(0))) {
  95 + builder.replace(0, 1, String.valueOf(Character.toLowerCase(builder.charAt(0))));
  96 + }
  97 + return builder.toString();
  98 + }
  99 +
  100 + /**
  101 + * 分割固定格式的字符串
  102 + */
  103 + public static String[] splitString(String str, String separator) {
  104 + return StringUtils.splitByWholeSeparator(str, separator);
  105 + }
  106 +
  107 + /**
  108 + * 将字符串首字母大写
  109 + */
  110 + public static String firstToUpper(String str) {
  111 + return Character.toUpperCase(str.charAt(0)) + str.substring(1);
  112 + }
  113 +
  114 + /**
  115 + * 将字符串首字母小写
  116 + */
  117 + public static String firstToLower(String str) {
  118 + return Character.toLowerCase(str.charAt(0)) + str.substring(1);
  119 + }
  120 +
  121 + /**
  122 + * 转为帕斯卡命名方式(如:FooBar)
  123 + */
  124 + public static String toPascalStyle(String str, String seperator) {
  125 + return StringUtil.firstToUpper(toCamelhumpStyle(str, seperator));
  126 + }
  127 +
  128 + /**
  129 + * 转为驼峰命令方式(如:fooBar)
  130 + */
  131 + public static String toCamelhumpStyle(String str, String seperator) {
  132 + return StringUtil.underlineToCamelhump(toUnderlineStyle(str, seperator));
  133 + }
  134 +
  135 + /**
  136 + * 转为下划线命名方式(如:foo_bar)
  137 + */
  138 + public static String toUnderlineStyle(String str, String seperator) {
  139 + str = str.trim().toLowerCase();
  140 + if (str.contains(seperator)) {
  141 + str = str.replace(seperator, "_");
  142 + }
  143 + return str;
  144 + }
  145 +
  146 + /**
  147 + * 转为显示命名方式(如:Foo Bar)
  148 + */
  149 + public static String toDisplayStyle(String str, String seperator) {
  150 + String displayName = "";
  151 + str = str.trim().toLowerCase();
  152 + if (str.contains(seperator)) {
  153 + String[] words = StringUtil.splitString(str, seperator);
  154 + for (String word : words) {
  155 + displayName += StringUtil.firstToUpper(word) + " ";
  156 + }
  157 + displayName = displayName.trim();
  158 + } else {
  159 + displayName = StringUtil.firstToUpper(str);
  160 + }
  161 + return displayName;
  162 + }
  163 +}
src/main/java/org/smart4j/framework/util/WebUtil.java 0 → 100644
  1 +++ a/src/main/java/org/smart4j/framework/util/WebUtil.java
  1 +package org.smart4j.framework.util;
  2 +
  3 +import java.awt.Color;
  4 +import java.awt.Font;
  5 +import java.awt.Graphics2D;
  6 +import java.awt.image.BufferedImage;
  7 +import java.io.BufferedInputStream;
  8 +import java.io.BufferedOutputStream;
  9 +import java.io.FileInputStream;
  10 +import java.io.InputStream;
  11 +import java.io.OutputStream;
  12 +import java.io.PrintWriter;
  13 +import java.util.Enumeration;
  14 +import java.util.LinkedHashMap;
  15 +import java.util.Map;
  16 +import java.util.Random;
  17 +
  18 +import javax.imageio.ImageIO;
  19 +import javax.servlet.ServletOutputStream;
  20 +import javax.servlet.http.Cookie;
  21 +import javax.servlet.http.HttpServletRequest;
  22 +import javax.servlet.http.HttpServletResponse;
  23 +
  24 +import org.apache.commons.io.FilenameUtils;
  25 +import org.slf4j.Logger;
  26 +import org.slf4j.LoggerFactory;
  27 +import org.smart4j.framework.FrameworkConstant;
  28 +import org.smart4j.framework.mvc.bean.Redirect;
  29 +
  30 +/**
  31 + * Web 操作工具类
  32 + *
  33 + * @author huangyong
  34 + * @since 1.0
  35 + */
  36 +public class WebUtil {
  37 +
  38 + private static final Logger logger = LoggerFactory.getLogger(WebUtil.class);
  39 +
  40 + /**
  41 + * 将数据以 JSON 格式写入响应中
  42 + */
  43 + public static void writeJSON(HttpServletResponse response, Object data) {
  44 + try {
  45 + // 设置响应头
  46 + response.setContentType("application/json"); // 指定内容类型为 JSON 格式
  47 + response.setCharacterEncoding(FrameworkConstant.UTF_8); // 防止中文乱码
  48 + // 向响应中写入数据
  49 + PrintWriter writer = response.getWriter();
  50 + writer.write(JsonUtil.toJSON(data)); // 转为 JSON 字符串
  51 + writer.flush();
  52 + writer.close();
  53 + } catch (Exception e) {
  54 + logger.error("在响应中写数据出错!", e);
  55 + throw new RuntimeException(e);
  56 + }
  57 + }
  58 +
  59 + /**
  60 + * 将数据以 HTML 格式写入响应中(在 JS 中获取的是 JSON 字符串,而不是 JSON 对象)
  61 + */
  62 + public static void writeHTML(HttpServletResponse response, Object data) {
  63 + try {
  64 + // 设置响应头
  65 + response.setContentType("text/html"); // 指定内容类型为 HTML 格式
  66 + response.setCharacterEncoding(FrameworkConstant.UTF_8); // 防止中文乱码
  67 + // 向响应中写入数据
  68 + PrintWriter writer = response.getWriter();
  69 + writer.write(JsonUtil.toJSON(data)); // 转为 JSON 字符串
  70 + writer.flush();
  71 + writer.close();
  72 + } catch (Exception e) {
  73 + logger.error("在响应中写数据出错!", e);
  74 + throw new RuntimeException(e);
  75 + }
  76 + }
  77 +
  78 + public static void redirect(HttpServletResponse response, Redirect api) {
  79 + try {
  80 + String redirectUrl=api.getRedirectUrl();
  81 + response.setContentType("application/mpegurl");
  82 + response.setStatus(301);
  83 + response.setHeader("Location", redirectUrl);
  84 + response.setHeader("message", api.getMessage());
  85 + response.setHeader("Connection", "close");
  86 + } catch (Exception e) {
  87 + logger.error("在响应中写数据出错!", e);
  88 + throw new RuntimeException(e);
  89 + }
  90 + }
  91 +
  92 + /**
  93 + * 从请求中获取所有参数(当参数名重复时,用后者覆盖前者)
  94 + */
  95 + public static Map<String, Object> getRequestParamMap(HttpServletRequest request) {
  96 + Map<String, Object> paramMap = new LinkedHashMap<String, Object>();
  97 + try {
  98 + String method = request.getMethod();
  99 + if (method.equalsIgnoreCase("put") || method.equalsIgnoreCase("delete")) {
  100 + String queryString = CodecUtil.decodeURL(StreamUtil.getString(request.getInputStream()));
  101 + if (StringUtil.isNotEmpty(queryString)) {
  102 + String[] qsArray = StringUtil.splitString(queryString, "&");
  103 + if (ArrayUtil.isNotEmpty(qsArray)) {
  104 + for (String qs : qsArray) {
  105 + String[] array = StringUtil.splitString(qs, "=");
  106 + if (ArrayUtil.isNotEmpty(array) && array.length == 2) {
  107 + String paramName = array[0];
  108 + String paramValue = array[1];
  109 + if (checkParamName(paramName)) {
  110 + if (paramMap.containsKey(paramName)) {
  111 + paramValue = paramMap.get(paramName) + StringUtil.SEPARATOR + paramValue;
  112 + }
  113 + paramMap.put(paramName, paramValue);
  114 + }
  115 + }
  116 + }
  117 + }
  118 + }
  119 + } else {
  120 + Enumeration<String> paramNames = request.getParameterNames();
  121 + while (paramNames.hasMoreElements()) {
  122 + String paramName = paramNames.nextElement();
  123 + if (checkParamName(paramName)) {
  124 + String[] paramValues = request.getParameterValues(paramName);
  125 + if (ArrayUtil.isNotEmpty(paramValues)) {
  126 + if (paramValues.length == 1) {
  127 + paramMap.put(paramName, paramValues[0]);
  128 + } else {
  129 + StringBuilder paramValue = new StringBuilder("");
  130 + for (int i = 0; i < paramValues.length; i++) {
  131 + paramValue.append(paramValues[i]);
  132 + if (i != paramValues.length - 1) {
  133 + paramValue.append(StringUtil.SEPARATOR);
  134 + }
  135 + }
  136 + paramMap.put(paramName, paramValue.toString());
  137 + }
  138 + }
  139 + }
  140 + }
  141 + }
  142 + } catch (Exception e) {
  143 + logger.error("获取请求参数出错!", e);
  144 + throw new RuntimeException(e);
  145 + }
  146 + return paramMap;
  147 + }
  148 +
  149 + /**
  150 + * 跳过参数
  151 + * @param paramName
  152 + * @return
  153 + */
  154 + private static boolean checkParamName(String paramName) {
  155 + // return !paramName.equals("_"); // 忽略 jQuery 缓存参数
  156 + boolean flag=true;
  157 + if (paramName.equals("_")) {
  158 + flag=false;
  159 + }if (paramName.equalsIgnoreCase("ticket")) {
  160 + flag=false;
  161 + }
  162 + return flag;
  163 +
  164 +
  165 + }
  166 +
  167 + /**
  168 + * 转发请求
  169 + */
  170 + public static void forwardRequest(String path, HttpServletRequest request, HttpServletResponse response) {
  171 + try {
  172 + request.getRequestDispatcher(path).forward(request, response);
  173 + } catch (Exception e) {
  174 + logger.error("转发请求出错!", e);
  175 + throw new RuntimeException(e);
  176 + }
  177 + }
  178 +
  179 + /**
  180 + * 重定向请求
  181 + */
  182 + public static void redirectRequest(String path, HttpServletRequest request, HttpServletResponse response) {
  183 + try {
  184 + response.sendRedirect(request.getContextPath() + path);
  185 + } catch (Exception e) {
  186 + logger.error("重定向请求出错!", e);
  187 + throw new RuntimeException(e);
  188 + }
  189 + }
  190 +
  191 + /**
  192 + * 发送错误代码
  193 + */
  194 + public static void sendError(int code, String message, HttpServletResponse response) {
  195 + try {
  196 + response.sendError(code, message);
  197 + } catch (Exception e) {
  198 + logger.error("发送错误代码出错!", e);
  199 + throw new RuntimeException(e);
  200 + }
  201 + }
  202 +
  203 + /**
  204 + * 判断是否为 AJAX 请求
  205 + */
  206 + public static boolean isAJAX(HttpServletRequest request) {
  207 + return request.getHeader("X-Requested-With") != null;
  208 + }
  209 +
  210 + /**
  211 + * 获取请求路径
  212 + */
  213 + public static String getRequestPath(HttpServletRequest request) {
  214 + String servletPath = request.getServletPath();
  215 + String pathInfo = StringUtil.defaultIfEmpty(request.getPathInfo(), "");
  216 + return servletPath + pathInfo;
  217 + }
  218 +
  219 + /**
  220 + * 从 Cookie 中获取数据
  221 + */
  222 + public static String getCookie(HttpServletRequest request, String name) {
  223 + String value = "";
  224 + try {
  225 + Cookie[] cookieArray = request.getCookies();
  226 + if (cookieArray != null) {
  227 + for (Cookie cookie : cookieArray) {
  228 + if (StringUtil.isNotEmpty(name) && name.equals(cookie.getName())) {
  229 + value = CodecUtil.decodeURL(cookie.getValue());
  230 + break;
  231 + }
  232 + }
  233 + }
  234 + } catch (Exception e) {
  235 + logger.error("获取 Cookie 出错!", e);
  236 + throw new RuntimeException(e);
  237 + }
  238 + return value;
  239 + }
  240 +
  241 + /**
  242 + * 下载文件
  243 + */
  244 + public static void downloadFile(HttpServletResponse response, String filePath) {
  245 + try {
  246 + String originalFileName = FilenameUtils.getName(filePath);
  247 + String downloadedFileName = new String(originalFileName.getBytes("GBK"), "ISO8859_1"); // 防止中文乱码
  248 +
  249 + response.setContentType("application/octet-stream");
  250 + response.addHeader("Content-Disposition", "attachment;filename=\"" + downloadedFileName + "\"");
  251 +
  252 + InputStream inputStream = new BufferedInputStream(new FileInputStream(filePath));
  253 + OutputStream outputStream = new BufferedOutputStream(response.getOutputStream());
  254 + StreamUtil.copyStream(inputStream, outputStream);
  255 + } catch (Exception e) {
  256 + logger.error("下载文件出错!", e);
  257 + throw new RuntimeException(e);
  258 + }
  259 + }
  260 +
  261 + /**
  262 + * 设置 Redirect URL 到 Session 中
  263 + */
  264 + public static void setRedirectUrl(HttpServletRequest request, String sessionKey) {
  265 + if (!isAJAX(request)) {
  266 + String requestPath = getRequestPath(request);
  267 + request.getSession().setAttribute(sessionKey, requestPath);
  268 + }
  269 + }
  270 +
  271 + /**
  272 + * 创建验证码
  273 + */
  274 + public static String createCaptcha(HttpServletResponse response) {
  275 + StringBuilder captcha = new StringBuilder();
  276 + try {
  277 + // 参数初始化
  278 + int width = 60; // 验证码图片的宽度
  279 + int height = 25; // 验证码图片的高度
  280 + int codeCount = 4; // 验证码字符个数
  281 + int codeX = width / (codeCount + 1); // 字符横向间距
  282 + int codeY = height - 4; // 字符纵向间距
  283 + int fontHeight = height - 2; // 字体高度
  284 + int randomSeed = 10; // 随机数种子
  285 + char[] codeSequence = { // 验证码中可出现的字符
  286 + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'
  287 + };
  288 + // 创建图像
  289 + BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
  290 + Graphics2D g = bi.createGraphics();
  291 + // 将图像填充为白色
  292 + g.setColor(Color.WHITE);
  293 + g.fillRect(0, 0, width, height);
  294 + // 设置字体
  295 + g.setFont(new Font("Courier New", Font.BOLD, fontHeight));
  296 + // 绘制边框
  297 + g.setColor(Color.BLACK);
  298 + g.drawRect(0, 0, width - 1, height - 1);
  299 + // 产生随机干扰线(160条)
  300 + g.setColor(Color.WHITE);
  301 + // 创建随机数生成器
  302 + Random random = new Random();
  303 + for (int i = 0; i < 160; i++) {
  304 + int x = random.nextInt(width);
  305 + int y = random.nextInt(height);
  306 + int xl = random.nextInt(12);
  307 + int yl = random.nextInt(12);
  308 + g.drawLine(x, y, x + xl, y + yl);
  309 + }
  310 + // 生成随机验证码
  311 + int red, green, blue;
  312 + for (int i = 0; i < codeCount; i++) {
  313 + // 获取随机验证码
  314 + String validateCode = String.valueOf(codeSequence[random.nextInt(randomSeed)]);
  315 + // 随机构造颜色值
  316 + red = random.nextInt(255);
  317 + green = random.nextInt(255);
  318 + blue = random.nextInt(255);
  319 + // 将带有颜色的验证码绘制到图像中
  320 + g.setColor(new Color(red, green, blue));
  321 + g.drawString(validateCode, (i + 1) * codeX - 6, codeY);
  322 + // 将产生的随机数拼接起来
  323 + captcha.append(validateCode);
  324 + }
  325 + // 禁止图像缓存
  326 + response.setHeader("Cache-Control", "no-store");
  327 + response.setHeader("Pragma", "no-cache");
  328 + response.setDateHeader("Expires", 0);
  329 + // 设置响应类型为 JPEG 图片
  330 + response.setContentType("image/jpeg");
  331 + // 将缓冲图像写到 Servlet 输出流中
  332 + ServletOutputStream sos = response.getOutputStream();
  333 + ImageIO.write(bi, "jpeg", sos);
  334 + sos.close();
  335 + } catch (Exception e) {
  336 + logger.error("创建验证码出错!", e);
  337 + throw new RuntimeException(e);
  338 + }
  339 + return captcha.toString();
  340 + }
  341 +
  342 + /**
  343 + * 是否为 IE 浏览器
  344 + */
  345 + public boolean isIE(HttpServletRequest request) {
  346 + String agent = request.getHeader("User-Agent");
  347 + return agent != null && agent.contains("MSIE");
  348 + }
  349 +}